]>
Commit | Line | Data |
---|---|---|
95e83f51 JR |
1 | --- linux/include/linux/fs.h.sector Mon Feb 26 23:48:46 2001 |
2 | +++ linux/include/linux/fs.h Mon Feb 26 23:53:57 2001 | |
3 | @@ -187,6 +187,8 @@ | |
4 | /* This was here just to show that the number is taken - | |
5 | probably all these _IO(0x12,*) ioctls should be moved to blkpg.h. */ | |
6 | #endif | |
7 | +#define BLKGETLASTSECT _IO(0x12,108) /* get last sector of block device */ | |
8 | +#define BLKSETLASTSECT _IO(0x12,109) /* get last sector of block device */ | |
9 | ||
10 | ||
11 | #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ | |
12 | --- linux/drivers/block/blkpg.c.sector Fri Oct 27 02:35:47 2000 | |
13 | +++ linux/drivers/block/blkpg.c Mon Feb 26 23:53:57 2001 | |
14 | @@ -39,6 +39,9 @@ | |
15 | ||
16 | #include <asm/uaccess.h> | |
17 | ||
18 | +static int set_last_sector( kdev_t dev, const void *param ); | |
19 | +static int get_last_sector( kdev_t dev, const void *param ); | |
20 | + | |
21 | /* | |
22 | * What is the data describing a partition? | |
23 | * | |
24 | @@ -210,6 +213,16 @@ | |
25 | int intval; | |
26 | ||
27 | switch (cmd) { | |
28 | + case BLKGETLASTSECT: | |
29 | + return get_last_sector(dev, (char *)(arg)); | |
30 | + | |
31 | + case BLKSETLASTSECT: | |
32 | + if( is_read_only(dev) ) | |
33 | + return -EACCES; | |
34 | + if (!capable(CAP_SYS_ADMIN)) | |
35 | + return -EACCES; | |
36 | + return set_last_sector(dev, (char *)(arg)); | |
37 | + | |
38 | case BLKROSET: | |
39 | if (!capable(CAP_SYS_ADMIN)) | |
40 | return -EACCES; | |
41 | @@ -281,3 +294,209 @@ | |
42 | } | |
43 | ||
44 | EXPORT_SYMBOL(blk_ioctl); | |
45 | + | |
46 | + /********************* | |
47 | + * get_last_sector() | |
48 | + * | |
49 | + * Description: This function will read any inaccessible blocks at the end | |
50 | + * of a device | |
51 | + * Why: Normal read/write calls through the block layer will not read the | |
52 | + * last sector of an odd-size disk. | |
53 | + * parameters: | |
54 | + * dev: kdev_t -- which device to read | |
55 | + * param: a pointer to a userspace struct. The struct has these members: | |
56 | + * block: an int which denotes which block to return: | |
57 | + * 0 == Last block | |
58 | + * 1 == Last block - 1 | |
59 | + * n == Last block - n | |
60 | + * This is validated so that only values of | |
61 | + * <= ((total_sects + 1) % logical_block_size) || 0 | |
62 | + * are allowed. | |
63 | + * block_contents: a pointer to userspace char*, this is where we write | |
64 | + * returned blocks to. | |
65 | + * content_length: How big the userspace buffer is. | |
66 | + * return: | |
67 | + * 0 on success | |
68 | + * -ERRVAL on error. | |
69 | + *********************/ | |
70 | +int get_last_sector( kdev_t dev, const void *param ) | |
71 | +{ | |
72 | + struct buffer_head *bh; | |
73 | + struct gendisk *g; | |
74 | + int rc = 0; | |
75 | + unsigned int lastlba, readlba; | |
76 | + int orig_blksize = BLOCK_SIZE; | |
77 | + int hardblocksize; | |
78 | + | |
79 | + struct { | |
80 | + unsigned int block; | |
81 | + size_t content_length; | |
82 | + char *block_contents; | |
83 | + } blk_ioctl_parameter; | |
84 | + | |
85 | + if( !dev ) return -EINVAL; | |
86 | + | |
87 | + if(copy_from_user(&blk_ioctl_parameter, param, sizeof(blk_ioctl_parameter))) | |
88 | + return -EFAULT; | |
89 | + | |
90 | + g = get_gendisk( dev ); | |
91 | + | |
92 | + if( !g ) return -EINVAL; | |
93 | + | |
94 | + lastlba = g->part[MINOR(dev)].nr_sects; | |
95 | + | |
96 | + if( !lastlba ) return -EINVAL; | |
97 | + | |
c51d8a39 | 98 | + hardblocksize = get_hardsect_size(dev); |
95e83f51 JR |
99 | + if( ! hardblocksize ) hardblocksize = 512; |
100 | + | |
101 | + /* Need to change the block size that the block layer uses */ | |
102 | + if (blksize_size[MAJOR(dev)]){ | |
103 | + orig_blksize = blksize_size[MAJOR(dev)][MINOR(dev)]; | |
104 | + } | |
105 | + | |
106 | + /* validate userspace input */ | |
107 | + if( blk_ioctl_parameter.block == 0 ) | |
108 | + goto good_params; | |
109 | + | |
110 | + /* so we don't divide by zero below */ | |
111 | + if(orig_blksize == 0) | |
112 | + return -EINVAL; | |
113 | + | |
114 | + if( blk_ioctl_parameter.block <= (lastlba % (orig_blksize / hardblocksize))) | |
115 | + goto good_params; | |
116 | + | |
117 | + return -EINVAL; | |
118 | + | |
119 | +good_params: | |
120 | + readlba = lastlba - blk_ioctl_parameter.block - 1; | |
121 | + | |
122 | + if (orig_blksize != hardblocksize) | |
123 | + set_blocksize(dev, hardblocksize); | |
124 | + | |
125 | + bh = bread(dev, readlba, hardblocksize); | |
126 | + if (!bh) { | |
127 | + /* We hit the end of the disk */ | |
128 | + printk(KERN_WARNING | |
129 | + "get_last_sector ioctl: bread returned NULL.\n"); | |
130 | + return -1; | |
131 | + } | |
132 | + | |
133 | + rc = copy_to_user(blk_ioctl_parameter.block_contents, bh->b_data, | |
134 | + (bh->b_size > blk_ioctl_parameter.content_length) ? | |
135 | + blk_ioctl_parameter.content_length : bh->b_size); | |
136 | + | |
137 | + brelse(bh); | |
138 | + | |
139 | + /* change block size back */ | |
140 | + if (orig_blksize != hardblocksize) | |
141 | + set_blocksize(dev, orig_blksize); | |
142 | + | |
143 | + return rc; | |
144 | +} | |
145 | + | |
146 | + /********************* | |
147 | + * set_last_sector() | |
148 | + * | |
149 | + * Description: This function will write to any inaccessible blocks at the end | |
150 | + * of a device | |
151 | + * Why: Normal read/write calls through the block layer will not read the | |
152 | + * last sector of an odd-size disk. | |
153 | + * parameters: | |
154 | + * dev: kdev_t -- which device to read | |
155 | + * sect: a pointer to a userspace struct. The struct has these members: | |
156 | + * block: an int which denotes which block to return: | |
157 | + * 0 == Last block | |
158 | + * 1 == Last block - 1 | |
159 | + * n == Last block - n | |
160 | + * This is validated so that only values of | |
161 | + * <= ((total_sects + 1) % logical_block_size) || 0 | |
162 | + * are allowed. | |
163 | + * block_contents: a pointer to userspace char*, this is where we write | |
164 | + * returned blocks to. | |
165 | + * content_length: How big the userspace buffer is. | |
166 | + * return: | |
167 | + * 0 on success | |
168 | + * -ERRVAL on error. | |
169 | + *********************/ | |
170 | +int set_last_sector( kdev_t dev, const void *param ) | |
171 | +{ | |
172 | + struct buffer_head *bh; | |
173 | + struct gendisk *g; | |
174 | + int rc = 0; | |
175 | + unsigned int lastlba, writelba; | |
176 | + int orig_blksize = BLOCK_SIZE; | |
177 | + int hardblocksize; | |
178 | + | |
179 | + struct { | |
180 | + unsigned int block; | |
181 | + size_t content_length; | |
182 | + char *block_contents; | |
183 | + } blk_ioctl_parameter; | |
184 | + | |
185 | + if( !dev ) return -EINVAL; | |
186 | + | |
187 | + if(copy_from_user(&blk_ioctl_parameter, param, sizeof(blk_ioctl_parameter))) | |
188 | + return -EFAULT; | |
189 | + | |
190 | + g = get_gendisk( dev ); | |
191 | + | |
192 | + if( !g ) return -EINVAL; | |
193 | + | |
194 | + lastlba = g->part[MINOR(dev)].nr_sects ; | |
195 | + | |
196 | + if( !lastlba ) return -EINVAL; | |
197 | + | |
c51d8a39 | 198 | + hardblocksize = get_hardsect_size(dev); |
95e83f51 JR |
199 | + if( ! hardblocksize ) hardblocksize = 512; |
200 | + | |
201 | + /* Need to change the block size that the block layer uses */ | |
202 | + if (blksize_size[MAJOR(dev)]){ | |
203 | + orig_blksize = blksize_size[MAJOR(dev)][MINOR(dev)]; | |
204 | + } | |
205 | + | |
206 | + /* validate userspace input */ | |
207 | + if( blk_ioctl_parameter.block == 0 ) | |
208 | + goto good_params; | |
209 | + | |
210 | + /* so we don't divide by zero below */ | |
211 | + if(orig_blksize == 0) | |
212 | + return -EINVAL; | |
213 | + | |
214 | + if( blk_ioctl_parameter.block <= (lastlba % (orig_blksize / hardblocksize))) | |
215 | + goto good_params; | |
216 | + | |
217 | + return -EINVAL; | |
218 | + | |
219 | +good_params: | |
220 | + writelba = lastlba - blk_ioctl_parameter.block - 1; | |
221 | + | |
222 | + if (orig_blksize != hardblocksize) | |
223 | + set_blocksize(dev, hardblocksize); | |
224 | + | |
225 | + bh = bread(dev, writelba, hardblocksize); | |
226 | + if (!bh) { | |
227 | + /* We hit the end of the disk */ | |
228 | + printk(KERN_WARNING | |
229 | + "get_last_sector ioctl: getblk returned NULL.\n"); | |
230 | + return -1; | |
231 | + } | |
232 | + | |
233 | + copy_from_user(bh->b_data, blk_ioctl_parameter.block_contents, | |
234 | + (bh->b_size > blk_ioctl_parameter.content_length) ? | |
235 | + blk_ioctl_parameter.content_length : bh->b_size); | |
236 | + | |
237 | + mark_buffer_dirty(bh); | |
238 | + ll_rw_block (WRITE, 1, &bh); | |
239 | + wait_on_buffer (bh); | |
240 | + if (!buffer_uptodate(bh)) | |
241 | + rc=-1; | |
242 | + | |
243 | + brelse(bh); | |
244 | + | |
245 | + /* change block size back */ | |
246 | + if (orig_blksize != hardblocksize) | |
247 | + set_blocksize(dev, orig_blksize); | |
248 | + | |
249 | + return rc; | |
250 | +} | |
251 | --- linux/drivers/scsi/sd.c.sector Mon Feb 26 23:48:45 2001 | |
252 | +++ linux/drivers/scsi/sd.c Mon Feb 26 23:53:57 2001 | |
253 | @@ -228,6 +228,8 @@ | |
a4d4e290 | 254 | } |
255 | case BLKGETSIZE: | |
256 | case BLKGETSIZE64: | |
95e83f51 JR |
257 | + case BLKGETLASTSECT: |
258 | + case BLKSETLASTSECT: | |
259 | case BLKROSET: | |
260 | case BLKROGET: | |
261 | case BLKRASET: | |
262 | --- linux/drivers/ide/ide.c.sector Mon Feb 26 23:48:49 2001 | |
263 | +++ linux/drivers/ide/ide.c Mon Feb 26 23:53:57 2001 | |
264 | @@ -2664,6 +2664,8 @@ | |
265 | } | |
266 | return 0; | |
a4d4e290 | 267 | } |
95e83f51 JR |
268 | + case BLKGETLASTSECT: |
269 | + case BLKSETLASTSECT: | |
270 | case BLKROSET: | |
271 | case BLKROGET: | |
272 | case BLKFLSBUF: |