.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
1 | 2 | #include <linux/capability.h> |
---|
| 3 | +#include <linux/compat.h> |
---|
2 | 4 | #include <linux/blkdev.h> |
---|
3 | 5 | #include <linux/export.h> |
---|
4 | 6 | #include <linux/gfp.h> |
---|
.. | .. |
---|
9 | 11 | #include <linux/blktrace_api.h> |
---|
10 | 12 | #include <linux/pr.h> |
---|
11 | 13 | #include <linux/uaccess.h> |
---|
| 14 | +#include "blk.h" |
---|
12 | 15 | |
---|
13 | | -static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg) |
---|
| 16 | +static int blkpg_do_ioctl(struct block_device *bdev, |
---|
| 17 | + struct blkpg_partition __user *upart, int op) |
---|
14 | 18 | { |
---|
15 | | - struct block_device *bdevp; |
---|
16 | | - struct gendisk *disk; |
---|
17 | | - struct hd_struct *part, *lpart; |
---|
18 | | - struct blkpg_ioctl_arg a; |
---|
19 | 19 | struct blkpg_partition p; |
---|
20 | | - struct disk_part_iter piter; |
---|
21 | 20 | long long start, length; |
---|
22 | | - int partno; |
---|
23 | 21 | |
---|
24 | 22 | if (!capable(CAP_SYS_ADMIN)) |
---|
25 | 23 | return -EACCES; |
---|
26 | | - if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg))) |
---|
| 24 | + if (copy_from_user(&p, upart, sizeof(struct blkpg_partition))) |
---|
27 | 25 | return -EFAULT; |
---|
28 | | - if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition))) |
---|
29 | | - return -EFAULT; |
---|
30 | | - disk = bdev->bd_disk; |
---|
31 | | - if (bdev != bdev->bd_contains) |
---|
| 26 | + if (bdev_is_partition(bdev)) |
---|
32 | 27 | return -EINVAL; |
---|
33 | | - partno = p.pno; |
---|
34 | | - if (partno <= 0) |
---|
| 28 | + |
---|
| 29 | + if (p.pno <= 0) |
---|
35 | 30 | return -EINVAL; |
---|
36 | | - switch (a.op) { |
---|
37 | | - case BLKPG_ADD_PARTITION: |
---|
38 | | - start = p.start >> 9; |
---|
39 | | - length = p.length >> 9; |
---|
40 | | - /* check for fit in a hd_struct */ |
---|
41 | | - if (sizeof(sector_t) == sizeof(long) && |
---|
42 | | - sizeof(long long) > sizeof(long)) { |
---|
43 | | - long pstart = start, plength = length; |
---|
44 | | - if (pstart != start || plength != length |
---|
45 | | - || pstart < 0 || plength < 0 || partno > 65535) |
---|
46 | | - return -EINVAL; |
---|
47 | | - } |
---|
48 | | - /* check if partition is aligned to blocksize */ |
---|
49 | | - if (p.start & (bdev_logical_block_size(bdev) - 1)) |
---|
50 | | - return -EINVAL; |
---|
51 | 31 | |
---|
52 | | - mutex_lock(&bdev->bd_mutex); |
---|
| 32 | + if (op == BLKPG_DEL_PARTITION) |
---|
| 33 | + return bdev_del_partition(bdev, p.pno); |
---|
53 | 34 | |
---|
54 | | - /* overlap? */ |
---|
55 | | - disk_part_iter_init(&piter, disk, |
---|
56 | | - DISK_PITER_INCL_EMPTY); |
---|
57 | | - while ((part = disk_part_iter_next(&piter))) { |
---|
58 | | - if (!(start + length <= part->start_sect || |
---|
59 | | - start >= part->start_sect + part->nr_sects)) { |
---|
60 | | - disk_part_iter_exit(&piter); |
---|
61 | | - mutex_unlock(&bdev->bd_mutex); |
---|
62 | | - return -EBUSY; |
---|
63 | | - } |
---|
64 | | - } |
---|
65 | | - disk_part_iter_exit(&piter); |
---|
| 35 | + start = p.start >> SECTOR_SHIFT; |
---|
| 36 | + length = p.length >> SECTOR_SHIFT; |
---|
66 | 37 | |
---|
67 | | - /* all seems OK */ |
---|
68 | | - part = add_partition(disk, partno, start, length, |
---|
69 | | - ADDPART_FLAG_NONE, NULL); |
---|
70 | | - mutex_unlock(&bdev->bd_mutex); |
---|
71 | | - return PTR_ERR_OR_ZERO(part); |
---|
72 | | - case BLKPG_DEL_PARTITION: |
---|
73 | | - part = disk_get_part(disk, partno); |
---|
74 | | - if (!part) |
---|
75 | | - return -ENXIO; |
---|
| 38 | + /* check for fit in a hd_struct */ |
---|
| 39 | + if (sizeof(sector_t) < sizeof(long long)) { |
---|
| 40 | + long pstart = start, plength = length; |
---|
76 | 41 | |
---|
77 | | - bdevp = bdget(part_devt(part)); |
---|
78 | | - disk_put_part(part); |
---|
79 | | - if (!bdevp) |
---|
80 | | - return -ENOMEM; |
---|
81 | | - |
---|
82 | | - mutex_lock(&bdevp->bd_mutex); |
---|
83 | | - if (bdevp->bd_openers) { |
---|
84 | | - mutex_unlock(&bdevp->bd_mutex); |
---|
85 | | - bdput(bdevp); |
---|
86 | | - return -EBUSY; |
---|
87 | | - } |
---|
88 | | - /* all seems OK */ |
---|
89 | | - fsync_bdev(bdevp); |
---|
90 | | - invalidate_bdev(bdevp); |
---|
91 | | - |
---|
92 | | - mutex_lock_nested(&bdev->bd_mutex, 1); |
---|
93 | | - delete_partition(disk, partno); |
---|
94 | | - mutex_unlock(&bdev->bd_mutex); |
---|
95 | | - mutex_unlock(&bdevp->bd_mutex); |
---|
96 | | - bdput(bdevp); |
---|
97 | | - |
---|
98 | | - return 0; |
---|
99 | | - case BLKPG_RESIZE_PARTITION: |
---|
100 | | - start = p.start >> 9; |
---|
101 | | - /* new length of partition in bytes */ |
---|
102 | | - length = p.length >> 9; |
---|
103 | | - /* check for fit in a hd_struct */ |
---|
104 | | - if (sizeof(sector_t) == sizeof(long) && |
---|
105 | | - sizeof(long long) > sizeof(long)) { |
---|
106 | | - long pstart = start, plength = length; |
---|
107 | | - if (pstart != start || plength != length |
---|
108 | | - || pstart < 0 || plength < 0) |
---|
109 | | - return -EINVAL; |
---|
110 | | - } |
---|
111 | | - part = disk_get_part(disk, partno); |
---|
112 | | - if (!part) |
---|
113 | | - return -ENXIO; |
---|
114 | | - bdevp = bdget(part_devt(part)); |
---|
115 | | - if (!bdevp) { |
---|
116 | | - disk_put_part(part); |
---|
117 | | - return -ENOMEM; |
---|
118 | | - } |
---|
119 | | - mutex_lock(&bdevp->bd_mutex); |
---|
120 | | - mutex_lock_nested(&bdev->bd_mutex, 1); |
---|
121 | | - if (start != part->start_sect) { |
---|
122 | | - mutex_unlock(&bdevp->bd_mutex); |
---|
123 | | - mutex_unlock(&bdev->bd_mutex); |
---|
124 | | - bdput(bdevp); |
---|
125 | | - disk_put_part(part); |
---|
126 | | - return -EINVAL; |
---|
127 | | - } |
---|
128 | | - /* overlap? */ |
---|
129 | | - disk_part_iter_init(&piter, disk, |
---|
130 | | - DISK_PITER_INCL_EMPTY); |
---|
131 | | - while ((lpart = disk_part_iter_next(&piter))) { |
---|
132 | | - if (lpart->partno != partno && |
---|
133 | | - !(start + length <= lpart->start_sect || |
---|
134 | | - start >= lpart->start_sect + lpart->nr_sects) |
---|
135 | | - ) { |
---|
136 | | - disk_part_iter_exit(&piter); |
---|
137 | | - mutex_unlock(&bdevp->bd_mutex); |
---|
138 | | - mutex_unlock(&bdev->bd_mutex); |
---|
139 | | - bdput(bdevp); |
---|
140 | | - disk_put_part(part); |
---|
141 | | - return -EBUSY; |
---|
142 | | - } |
---|
143 | | - } |
---|
144 | | - disk_part_iter_exit(&piter); |
---|
145 | | - part_nr_sects_write(part, (sector_t)length); |
---|
146 | | - i_size_write(bdevp->bd_inode, p.length); |
---|
147 | | - mutex_unlock(&bdevp->bd_mutex); |
---|
148 | | - mutex_unlock(&bdev->bd_mutex); |
---|
149 | | - bdput(bdevp); |
---|
150 | | - disk_put_part(part); |
---|
151 | | - return 0; |
---|
152 | | - default: |
---|
| 42 | + if (pstart != start || plength != length || pstart < 0 || |
---|
| 43 | + plength < 0 || p.pno > 65535) |
---|
153 | 44 | return -EINVAL; |
---|
| 45 | + } |
---|
| 46 | + |
---|
| 47 | + switch (op) { |
---|
| 48 | + case BLKPG_ADD_PARTITION: |
---|
| 49 | + /* check if partition is aligned to blocksize */ |
---|
| 50 | + if (p.start & (bdev_logical_block_size(bdev) - 1)) |
---|
| 51 | + return -EINVAL; |
---|
| 52 | + return bdev_add_partition(bdev, p.pno, start, length); |
---|
| 53 | + case BLKPG_RESIZE_PARTITION: |
---|
| 54 | + return bdev_resize_partition(bdev, p.pno, start, length); |
---|
| 55 | + default: |
---|
| 56 | + return -EINVAL; |
---|
154 | 57 | } |
---|
155 | 58 | } |
---|
156 | 59 | |
---|
157 | | -/* |
---|
158 | | - * This is an exported API for the block driver, and will not |
---|
159 | | - * acquire bd_mutex. This API should be used in case that |
---|
160 | | - * caller has held bd_mutex already. |
---|
161 | | - */ |
---|
162 | | -int __blkdev_reread_part(struct block_device *bdev) |
---|
| 60 | +static int blkpg_ioctl(struct block_device *bdev, |
---|
| 61 | + struct blkpg_ioctl_arg __user *arg) |
---|
163 | 62 | { |
---|
164 | | - struct gendisk *disk = bdev->bd_disk; |
---|
| 63 | + struct blkpg_partition __user *udata; |
---|
| 64 | + int op; |
---|
165 | 65 | |
---|
166 | | - if (!disk_part_scan_enabled(disk) || bdev != bdev->bd_contains) |
---|
| 66 | + if (get_user(op, &arg->op) || get_user(udata, &arg->data)) |
---|
| 67 | + return -EFAULT; |
---|
| 68 | + |
---|
| 69 | + return blkpg_do_ioctl(bdev, udata, op); |
---|
| 70 | +} |
---|
| 71 | + |
---|
| 72 | +#ifdef CONFIG_COMPAT |
---|
| 73 | +struct compat_blkpg_ioctl_arg { |
---|
| 74 | + compat_int_t op; |
---|
| 75 | + compat_int_t flags; |
---|
| 76 | + compat_int_t datalen; |
---|
| 77 | + compat_caddr_t data; |
---|
| 78 | +}; |
---|
| 79 | + |
---|
| 80 | +static int compat_blkpg_ioctl(struct block_device *bdev, |
---|
| 81 | + struct compat_blkpg_ioctl_arg __user *arg) |
---|
| 82 | +{ |
---|
| 83 | + compat_caddr_t udata; |
---|
| 84 | + int op; |
---|
| 85 | + |
---|
| 86 | + if (get_user(op, &arg->op) || get_user(udata, &arg->data)) |
---|
| 87 | + return -EFAULT; |
---|
| 88 | + |
---|
| 89 | + return blkpg_do_ioctl(bdev, compat_ptr(udata), op); |
---|
| 90 | +} |
---|
| 91 | +#endif |
---|
| 92 | + |
---|
| 93 | +static int blkdev_reread_part(struct block_device *bdev, fmode_t mode) |
---|
| 94 | +{ |
---|
| 95 | + struct block_device *tmp; |
---|
| 96 | + |
---|
| 97 | + if (!disk_part_scan_enabled(bdev->bd_disk) || bdev_is_partition(bdev)) |
---|
167 | 98 | return -EINVAL; |
---|
168 | 99 | if (!capable(CAP_SYS_ADMIN)) |
---|
169 | 100 | return -EACCES; |
---|
| 101 | + if (bdev->bd_part_count) |
---|
| 102 | + return -EBUSY; |
---|
170 | 103 | |
---|
171 | | - lockdep_assert_held(&bdev->bd_mutex); |
---|
| 104 | + /* |
---|
| 105 | + * Reopen the device to revalidate the driver state and force a |
---|
| 106 | + * partition rescan. |
---|
| 107 | + */ |
---|
| 108 | + mode &= ~FMODE_EXCL; |
---|
| 109 | + set_bit(GD_NEED_PART_SCAN, &bdev->bd_disk->state); |
---|
172 | 110 | |
---|
173 | | - return rescan_partitions(disk, bdev); |
---|
| 111 | + tmp = blkdev_get_by_dev(bdev->bd_dev, mode, NULL); |
---|
| 112 | + if (IS_ERR(tmp)) |
---|
| 113 | + return PTR_ERR(tmp); |
---|
| 114 | + blkdev_put(tmp, mode); |
---|
| 115 | + return 0; |
---|
174 | 116 | } |
---|
175 | | -EXPORT_SYMBOL(__blkdev_reread_part); |
---|
176 | | - |
---|
177 | | -/* |
---|
178 | | - * This is an exported API for the block driver, and will |
---|
179 | | - * try to acquire bd_mutex. If bd_mutex has been held already |
---|
180 | | - * in current context, please call __blkdev_reread_part(). |
---|
181 | | - * |
---|
182 | | - * Make sure the held locks in current context aren't required |
---|
183 | | - * in open()/close() handler and I/O path for avoiding ABBA deadlock: |
---|
184 | | - * - bd_mutex is held before calling block driver's open/close |
---|
185 | | - * handler |
---|
186 | | - * - reading partition table may submit I/O to the block device |
---|
187 | | - */ |
---|
188 | | -int blkdev_reread_part(struct block_device *bdev) |
---|
189 | | -{ |
---|
190 | | - int res; |
---|
191 | | - |
---|
192 | | - mutex_lock(&bdev->bd_mutex); |
---|
193 | | - res = __blkdev_reread_part(bdev); |
---|
194 | | - mutex_unlock(&bdev->bd_mutex); |
---|
195 | | - |
---|
196 | | - return res; |
---|
197 | | -} |
---|
198 | | -EXPORT_SYMBOL(blkdev_reread_part); |
---|
199 | 117 | |
---|
200 | 118 | static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode, |
---|
201 | 119 | unsigned long arg, unsigned long flags) |
---|
.. | .. |
---|
203 | 121 | uint64_t range[2]; |
---|
204 | 122 | uint64_t start, len; |
---|
205 | 123 | struct request_queue *q = bdev_get_queue(bdev); |
---|
206 | | - struct address_space *mapping = bdev->bd_inode->i_mapping; |
---|
207 | | - |
---|
| 124 | + int err; |
---|
208 | 125 | |
---|
209 | 126 | if (!(mode & FMODE_WRITE)) |
---|
210 | 127 | return -EBADF; |
---|
.. | .. |
---|
225 | 142 | |
---|
226 | 143 | if (start + len > i_size_read(bdev->bd_inode)) |
---|
227 | 144 | return -EINVAL; |
---|
228 | | - truncate_inode_pages_range(mapping, start, start + len - 1); |
---|
| 145 | + |
---|
| 146 | + err = truncate_bdev_range(bdev, mode, start, start + len - 1); |
---|
| 147 | + if (err) |
---|
| 148 | + return err; |
---|
| 149 | + |
---|
229 | 150 | return blkdev_issue_discard(bdev, start >> 9, len >> 9, |
---|
230 | 151 | GFP_KERNEL, flags); |
---|
231 | 152 | } |
---|
.. | .. |
---|
234 | 155 | unsigned long arg) |
---|
235 | 156 | { |
---|
236 | 157 | uint64_t range[2]; |
---|
237 | | - struct address_space *mapping; |
---|
238 | 158 | uint64_t start, end, len; |
---|
| 159 | + int err; |
---|
239 | 160 | |
---|
240 | 161 | if (!(mode & FMODE_WRITE)) |
---|
241 | 162 | return -EBADF; |
---|
.. | .. |
---|
257 | 178 | return -EINVAL; |
---|
258 | 179 | |
---|
259 | 180 | /* Invalidate the page cache, including dirty pages */ |
---|
260 | | - mapping = bdev->bd_inode->i_mapping; |
---|
261 | | - truncate_inode_pages_range(mapping, start, end); |
---|
| 181 | + err = truncate_bdev_range(bdev, mode, start, end); |
---|
| 182 | + if (err) |
---|
| 183 | + return err; |
---|
262 | 184 | |
---|
263 | 185 | return blkdev_issue_zeroout(bdev, start >> 9, len >> 9, GFP_KERNEL, |
---|
264 | 186 | BLKDEV_ZERO_NOUNMAP); |
---|
265 | 187 | } |
---|
266 | 188 | |
---|
267 | | -static int put_ushort(unsigned long arg, unsigned short val) |
---|
| 189 | +static int put_ushort(unsigned short __user *argp, unsigned short val) |
---|
268 | 190 | { |
---|
269 | | - return put_user(val, (unsigned short __user *)arg); |
---|
| 191 | + return put_user(val, argp); |
---|
270 | 192 | } |
---|
271 | 193 | |
---|
272 | | -static int put_int(unsigned long arg, int val) |
---|
| 194 | +static int put_int(int __user *argp, int val) |
---|
273 | 195 | { |
---|
274 | | - return put_user(val, (int __user *)arg); |
---|
| 196 | + return put_user(val, argp); |
---|
275 | 197 | } |
---|
276 | 198 | |
---|
277 | | -static int put_uint(unsigned long arg, unsigned int val) |
---|
| 199 | +static int put_uint(unsigned int __user *argp, unsigned int val) |
---|
278 | 200 | { |
---|
279 | | - return put_user(val, (unsigned int __user *)arg); |
---|
| 201 | + return put_user(val, argp); |
---|
280 | 202 | } |
---|
281 | 203 | |
---|
282 | | -static int put_long(unsigned long arg, long val) |
---|
| 204 | +static int put_long(long __user *argp, long val) |
---|
283 | 205 | { |
---|
284 | | - return put_user(val, (long __user *)arg); |
---|
| 206 | + return put_user(val, argp); |
---|
285 | 207 | } |
---|
286 | 208 | |
---|
287 | | -static int put_ulong(unsigned long arg, unsigned long val) |
---|
| 209 | +static int put_ulong(unsigned long __user *argp, unsigned long val) |
---|
288 | 210 | { |
---|
289 | | - return put_user(val, (unsigned long __user *)arg); |
---|
| 211 | + return put_user(val, argp); |
---|
290 | 212 | } |
---|
291 | 213 | |
---|
292 | | -static int put_u64(unsigned long arg, u64 val) |
---|
| 214 | +static int put_u64(u64 __user *argp, u64 val) |
---|
293 | 215 | { |
---|
294 | | - return put_user(val, (u64 __user *)arg); |
---|
| 216 | + return put_user(val, argp); |
---|
295 | 217 | } |
---|
| 218 | + |
---|
| 219 | +#ifdef CONFIG_COMPAT |
---|
| 220 | +static int compat_put_long(compat_long_t __user *argp, long val) |
---|
| 221 | +{ |
---|
| 222 | + return put_user(val, argp); |
---|
| 223 | +} |
---|
| 224 | + |
---|
| 225 | +static int compat_put_ulong(compat_ulong_t __user *argp, compat_ulong_t val) |
---|
| 226 | +{ |
---|
| 227 | + return put_user(val, argp); |
---|
| 228 | +} |
---|
| 229 | +#endif |
---|
296 | 230 | |
---|
297 | 231 | int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode, |
---|
298 | 232 | unsigned cmd, unsigned long arg) |
---|
.. | .. |
---|
310 | 244 | * at all and could be open-coded without any exports by anybody who cares. |
---|
311 | 245 | */ |
---|
312 | 246 | EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl); |
---|
| 247 | + |
---|
| 248 | +#ifdef CONFIG_COMPAT |
---|
| 249 | +/* |
---|
| 250 | + * This is the equivalent of compat_ptr_ioctl(), to be used by block |
---|
| 251 | + * drivers that implement only commands that are completely compatible |
---|
| 252 | + * between 32-bit and 64-bit user space |
---|
| 253 | + */ |
---|
| 254 | +int blkdev_compat_ptr_ioctl(struct block_device *bdev, fmode_t mode, |
---|
| 255 | + unsigned cmd, unsigned long arg) |
---|
| 256 | +{ |
---|
| 257 | + struct gendisk *disk = bdev->bd_disk; |
---|
| 258 | + |
---|
| 259 | + if (disk->fops->ioctl) |
---|
| 260 | + return disk->fops->ioctl(bdev, mode, cmd, |
---|
| 261 | + (unsigned long)compat_ptr(arg)); |
---|
| 262 | + |
---|
| 263 | + return -ENOIOCTLCMD; |
---|
| 264 | +} |
---|
| 265 | +EXPORT_SYMBOL(blkdev_compat_ptr_ioctl); |
---|
| 266 | +#endif |
---|
313 | 267 | |
---|
314 | 268 | static int blkdev_pr_register(struct block_device *bdev, |
---|
315 | 269 | struct pr_registration __user *arg) |
---|
.. | .. |
---|
481 | 435 | return 0; |
---|
482 | 436 | } |
---|
483 | 437 | |
---|
| 438 | +#ifdef CONFIG_COMPAT |
---|
| 439 | +struct compat_hd_geometry { |
---|
| 440 | + unsigned char heads; |
---|
| 441 | + unsigned char sectors; |
---|
| 442 | + unsigned short cylinders; |
---|
| 443 | + u32 start; |
---|
| 444 | +}; |
---|
| 445 | + |
---|
| 446 | +static int compat_hdio_getgeo(struct block_device *bdev, |
---|
| 447 | + struct compat_hd_geometry __user *ugeo) |
---|
| 448 | +{ |
---|
| 449 | + struct gendisk *disk = bdev->bd_disk; |
---|
| 450 | + struct hd_geometry geo; |
---|
| 451 | + int ret; |
---|
| 452 | + |
---|
| 453 | + if (!ugeo) |
---|
| 454 | + return -EINVAL; |
---|
| 455 | + if (!disk->fops->getgeo) |
---|
| 456 | + return -ENOTTY; |
---|
| 457 | + |
---|
| 458 | + memset(&geo, 0, sizeof(geo)); |
---|
| 459 | + /* |
---|
| 460 | + * We need to set the startsect first, the driver may |
---|
| 461 | + * want to override it. |
---|
| 462 | + */ |
---|
| 463 | + geo.start = get_start_sect(bdev); |
---|
| 464 | + ret = disk->fops->getgeo(bdev, &geo); |
---|
| 465 | + if (ret) |
---|
| 466 | + return ret; |
---|
| 467 | + |
---|
| 468 | + ret = copy_to_user(ugeo, &geo, 4); |
---|
| 469 | + ret |= put_user(geo.start, &ugeo->start); |
---|
| 470 | + if (ret) |
---|
| 471 | + ret = -EFAULT; |
---|
| 472 | + |
---|
| 473 | + return ret; |
---|
| 474 | +} |
---|
| 475 | +#endif |
---|
| 476 | + |
---|
484 | 477 | /* set the logical block size */ |
---|
485 | 478 | static int blkdev_bszset(struct block_device *bdev, fmode_t mode, |
---|
486 | 479 | int __user *argp) |
---|
.. | .. |
---|
494 | 487 | if (get_user(n, argp)) |
---|
495 | 488 | return -EFAULT; |
---|
496 | 489 | |
---|
497 | | - if (!(mode & FMODE_EXCL)) { |
---|
498 | | - bdgrab(bdev); |
---|
499 | | - if (blkdev_get(bdev, mode | FMODE_EXCL, &bdev) < 0) |
---|
500 | | - return -EBUSY; |
---|
501 | | - } |
---|
| 490 | + if (mode & FMODE_EXCL) |
---|
| 491 | + return set_blocksize(bdev, n); |
---|
502 | 492 | |
---|
| 493 | + if (IS_ERR(blkdev_get_by_dev(bdev->bd_dev, mode | FMODE_EXCL, &bdev))) |
---|
| 494 | + return -EBUSY; |
---|
503 | 495 | ret = set_blocksize(bdev, n); |
---|
504 | | - if (!(mode & FMODE_EXCL)) |
---|
505 | | - blkdev_put(bdev, mode | FMODE_EXCL); |
---|
| 496 | + blkdev_put(bdev, mode | FMODE_EXCL); |
---|
| 497 | + |
---|
506 | 498 | return ret; |
---|
507 | 499 | } |
---|
508 | 500 | |
---|
509 | 501 | /* |
---|
510 | | - * always keep this in sync with compat_blkdev_ioctl() |
---|
| 502 | + * Common commands that are handled the same way on native and compat |
---|
| 503 | + * user space. Note the separate arg/argp parameters that are needed |
---|
| 504 | + * to deal with the compat_ptr() conversion. |
---|
511 | 505 | */ |
---|
512 | | -int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, |
---|
513 | | - unsigned long arg) |
---|
| 506 | +static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode, |
---|
| 507 | + unsigned cmd, unsigned long arg, void __user *argp) |
---|
514 | 508 | { |
---|
515 | | - void __user *argp = (void __user *)arg; |
---|
516 | | - loff_t size; |
---|
517 | 509 | unsigned int max_sectors; |
---|
518 | 510 | |
---|
519 | 511 | switch (cmd) { |
---|
.. | .. |
---|
531 | 523 | case BLKREPORTZONE: |
---|
532 | 524 | return blkdev_report_zones_ioctl(bdev, mode, cmd, arg); |
---|
533 | 525 | case BLKRESETZONE: |
---|
534 | | - return blkdev_reset_zones_ioctl(bdev, mode, cmd, arg); |
---|
535 | | - case HDIO_GETGEO: |
---|
536 | | - return blkdev_getgeo(bdev, argp); |
---|
537 | | - case BLKRAGET: |
---|
538 | | - case BLKFRAGET: |
---|
539 | | - if (!arg) |
---|
540 | | - return -EINVAL; |
---|
541 | | - return put_long(arg, (bdev->bd_bdi->ra_pages*PAGE_SIZE) / 512); |
---|
| 526 | + case BLKOPENZONE: |
---|
| 527 | + case BLKCLOSEZONE: |
---|
| 528 | + case BLKFINISHZONE: |
---|
| 529 | + return blkdev_zone_mgmt_ioctl(bdev, mode, cmd, arg); |
---|
| 530 | + case BLKGETZONESZ: |
---|
| 531 | + return put_uint(argp, bdev_zone_sectors(bdev)); |
---|
| 532 | + case BLKGETNRZONES: |
---|
| 533 | + return put_uint(argp, blkdev_nr_zones(bdev->bd_disk)); |
---|
542 | 534 | case BLKROGET: |
---|
543 | | - return put_int(arg, bdev_read_only(bdev) != 0); |
---|
544 | | - case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */ |
---|
545 | | - return put_int(arg, block_size(bdev)); |
---|
| 535 | + return put_int(argp, bdev_read_only(bdev) != 0); |
---|
546 | 536 | case BLKSSZGET: /* get block device logical block size */ |
---|
547 | | - return put_int(arg, bdev_logical_block_size(bdev)); |
---|
| 537 | + return put_int(argp, bdev_logical_block_size(bdev)); |
---|
548 | 538 | case BLKPBSZGET: /* get block device physical block size */ |
---|
549 | | - return put_uint(arg, bdev_physical_block_size(bdev)); |
---|
| 539 | + return put_uint(argp, bdev_physical_block_size(bdev)); |
---|
550 | 540 | case BLKIOMIN: |
---|
551 | | - return put_uint(arg, bdev_io_min(bdev)); |
---|
| 541 | + return put_uint(argp, bdev_io_min(bdev)); |
---|
552 | 542 | case BLKIOOPT: |
---|
553 | | - return put_uint(arg, bdev_io_opt(bdev)); |
---|
| 543 | + return put_uint(argp, bdev_io_opt(bdev)); |
---|
554 | 544 | case BLKALIGNOFF: |
---|
555 | | - return put_int(arg, bdev_alignment_offset(bdev)); |
---|
| 545 | + return put_int(argp, bdev_alignment_offset(bdev)); |
---|
556 | 546 | case BLKDISCARDZEROES: |
---|
557 | | - return put_uint(arg, 0); |
---|
| 547 | + return put_uint(argp, 0); |
---|
558 | 548 | case BLKSECTGET: |
---|
559 | 549 | max_sectors = min_t(unsigned int, USHRT_MAX, |
---|
560 | 550 | queue_max_sectors(bdev_get_queue(bdev))); |
---|
561 | | - return put_ushort(arg, max_sectors); |
---|
| 551 | + return put_ushort(argp, max_sectors); |
---|
562 | 552 | case BLKROTATIONAL: |
---|
563 | | - return put_ushort(arg, !blk_queue_nonrot(bdev_get_queue(bdev))); |
---|
| 553 | + return put_ushort(argp, !blk_queue_nonrot(bdev_get_queue(bdev))); |
---|
564 | 554 | case BLKRASET: |
---|
565 | 555 | case BLKFRASET: |
---|
566 | 556 | if(!capable(CAP_SYS_ADMIN)) |
---|
567 | 557 | return -EACCES; |
---|
568 | 558 | bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE; |
---|
569 | 559 | return 0; |
---|
570 | | - case BLKBSZSET: |
---|
571 | | - return blkdev_bszset(bdev, mode, argp); |
---|
572 | | - case BLKPG: |
---|
573 | | - return blkpg_ioctl(bdev, argp); |
---|
574 | 560 | case BLKRRPART: |
---|
575 | | - return blkdev_reread_part(bdev); |
---|
576 | | - case BLKGETSIZE: |
---|
577 | | - size = i_size_read(bdev->bd_inode); |
---|
578 | | - if ((size >> 9) > ~0UL) |
---|
579 | | - return -EFBIG; |
---|
580 | | - return put_ulong(arg, size >> 9); |
---|
581 | | - case BLKGETSIZE64: |
---|
582 | | - return put_u64(arg, i_size_read(bdev->bd_inode)); |
---|
| 561 | + return blkdev_reread_part(bdev, mode); |
---|
583 | 562 | case BLKTRACESTART: |
---|
584 | 563 | case BLKTRACESTOP: |
---|
585 | | - case BLKTRACESETUP: |
---|
586 | 564 | case BLKTRACETEARDOWN: |
---|
587 | 565 | return blk_trace_ioctl(bdev, cmd, argp); |
---|
588 | 566 | case IOC_PR_REGISTER: |
---|
.. | .. |
---|
598 | 576 | case IOC_PR_CLEAR: |
---|
599 | 577 | return blkdev_pr_clear(bdev, argp); |
---|
600 | 578 | default: |
---|
601 | | - return __blkdev_driver_ioctl(bdev, mode, cmd, arg); |
---|
| 579 | + return -ENOIOCTLCMD; |
---|
602 | 580 | } |
---|
603 | 581 | } |
---|
604 | | -EXPORT_SYMBOL_GPL(blkdev_ioctl); |
---|
| 582 | + |
---|
| 583 | +/* |
---|
| 584 | + * Always keep this in sync with compat_blkdev_ioctl() |
---|
| 585 | + * to handle all incompatible commands in both functions. |
---|
| 586 | + * |
---|
| 587 | + * New commands must be compatible and go into blkdev_common_ioctl |
---|
| 588 | + */ |
---|
| 589 | +int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, |
---|
| 590 | + unsigned long arg) |
---|
| 591 | +{ |
---|
| 592 | + int ret; |
---|
| 593 | + loff_t size; |
---|
| 594 | + void __user *argp = (void __user *)arg; |
---|
| 595 | + |
---|
| 596 | + switch (cmd) { |
---|
| 597 | + /* These need separate implementations for the data structure */ |
---|
| 598 | + case HDIO_GETGEO: |
---|
| 599 | + return blkdev_getgeo(bdev, argp); |
---|
| 600 | + case BLKPG: |
---|
| 601 | + return blkpg_ioctl(bdev, argp); |
---|
| 602 | + |
---|
| 603 | + /* Compat mode returns 32-bit data instead of 'long' */ |
---|
| 604 | + case BLKRAGET: |
---|
| 605 | + case BLKFRAGET: |
---|
| 606 | + if (!argp) |
---|
| 607 | + return -EINVAL; |
---|
| 608 | + return put_long(argp, (bdev->bd_bdi->ra_pages*PAGE_SIZE) / 512); |
---|
| 609 | + case BLKGETSIZE: |
---|
| 610 | + size = i_size_read(bdev->bd_inode); |
---|
| 611 | + if ((size >> 9) > ~0UL) |
---|
| 612 | + return -EFBIG; |
---|
| 613 | + return put_ulong(argp, size >> 9); |
---|
| 614 | + |
---|
| 615 | + /* The data is compatible, but the command number is different */ |
---|
| 616 | + case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */ |
---|
| 617 | + return put_int(argp, block_size(bdev)); |
---|
| 618 | + case BLKBSZSET: |
---|
| 619 | + return blkdev_bszset(bdev, mode, argp); |
---|
| 620 | + case BLKGETSIZE64: |
---|
| 621 | + return put_u64(argp, i_size_read(bdev->bd_inode)); |
---|
| 622 | + |
---|
| 623 | + /* Incompatible alignment on i386 */ |
---|
| 624 | + case BLKTRACESETUP: |
---|
| 625 | + return blk_trace_ioctl(bdev, cmd, argp); |
---|
| 626 | + default: |
---|
| 627 | + break; |
---|
| 628 | + } |
---|
| 629 | + |
---|
| 630 | + ret = blkdev_common_ioctl(bdev, mode, cmd, arg, argp); |
---|
| 631 | + if (ret == -ENOIOCTLCMD) |
---|
| 632 | + return __blkdev_driver_ioctl(bdev, mode, cmd, arg); |
---|
| 633 | + |
---|
| 634 | + return ret; |
---|
| 635 | +} |
---|
| 636 | +EXPORT_SYMBOL_GPL(blkdev_ioctl); /* for /dev/raw */ |
---|
| 637 | + |
---|
| 638 | +#ifdef CONFIG_COMPAT |
---|
| 639 | + |
---|
| 640 | +#define BLKBSZGET_32 _IOR(0x12, 112, int) |
---|
| 641 | +#define BLKBSZSET_32 _IOW(0x12, 113, int) |
---|
| 642 | +#define BLKGETSIZE64_32 _IOR(0x12, 114, int) |
---|
| 643 | + |
---|
| 644 | +/* Most of the generic ioctls are handled in the normal fallback path. |
---|
| 645 | + This assumes the blkdev's low level compat_ioctl always returns |
---|
| 646 | + ENOIOCTLCMD for unknown ioctls. */ |
---|
| 647 | +long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) |
---|
| 648 | +{ |
---|
| 649 | + int ret; |
---|
| 650 | + void __user *argp = compat_ptr(arg); |
---|
| 651 | + struct inode *inode = file->f_mapping->host; |
---|
| 652 | + struct block_device *bdev = inode->i_bdev; |
---|
| 653 | + struct gendisk *disk = bdev->bd_disk; |
---|
| 654 | + fmode_t mode = file->f_mode; |
---|
| 655 | + loff_t size; |
---|
| 656 | + |
---|
| 657 | + /* |
---|
| 658 | + * O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have |
---|
| 659 | + * to updated it before every ioctl. |
---|
| 660 | + */ |
---|
| 661 | + if (file->f_flags & O_NDELAY) |
---|
| 662 | + mode |= FMODE_NDELAY; |
---|
| 663 | + else |
---|
| 664 | + mode &= ~FMODE_NDELAY; |
---|
| 665 | + |
---|
| 666 | + switch (cmd) { |
---|
| 667 | + /* These need separate implementations for the data structure */ |
---|
| 668 | + case HDIO_GETGEO: |
---|
| 669 | + return compat_hdio_getgeo(bdev, argp); |
---|
| 670 | + case BLKPG: |
---|
| 671 | + return compat_blkpg_ioctl(bdev, argp); |
---|
| 672 | + |
---|
| 673 | + /* Compat mode returns 32-bit data instead of 'long' */ |
---|
| 674 | + case BLKRAGET: |
---|
| 675 | + case BLKFRAGET: |
---|
| 676 | + if (!argp) |
---|
| 677 | + return -EINVAL; |
---|
| 678 | + return compat_put_long(argp, |
---|
| 679 | + (bdev->bd_bdi->ra_pages * PAGE_SIZE) / 512); |
---|
| 680 | + case BLKGETSIZE: |
---|
| 681 | + size = i_size_read(bdev->bd_inode); |
---|
| 682 | + if ((size >> 9) > ~(compat_ulong_t)0) |
---|
| 683 | + return -EFBIG; |
---|
| 684 | + return compat_put_ulong(argp, size >> 9); |
---|
| 685 | + |
---|
| 686 | + /* The data is compatible, but the command number is different */ |
---|
| 687 | + case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */ |
---|
| 688 | + return put_int(argp, bdev_logical_block_size(bdev)); |
---|
| 689 | + case BLKBSZSET_32: |
---|
| 690 | + return blkdev_bszset(bdev, mode, argp); |
---|
| 691 | + case BLKGETSIZE64_32: |
---|
| 692 | + return put_u64(argp, i_size_read(bdev->bd_inode)); |
---|
| 693 | + |
---|
| 694 | + /* Incompatible alignment on i386 */ |
---|
| 695 | + case BLKTRACESETUP32: |
---|
| 696 | + return blk_trace_ioctl(bdev, cmd, argp); |
---|
| 697 | + default: |
---|
| 698 | + break; |
---|
| 699 | + } |
---|
| 700 | + |
---|
| 701 | + ret = blkdev_common_ioctl(bdev, mode, cmd, arg, argp); |
---|
| 702 | + if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl) |
---|
| 703 | + ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg); |
---|
| 704 | + |
---|
| 705 | + return ret; |
---|
| 706 | +} |
---|
| 707 | +#endif |
---|