Blame view

block/ioctl.c 14.6 KB
c59ede7b7   Randy.Dunlap   [PATCH] move capa...
1
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
  #include <linux/blkdev.h>
d5decd3b9   Paul Gortmaker   block: add export...
3
  #include <linux/export.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
4
  #include <linux/gfp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
  #include <linux/blkpg.h>
a885c8c43   Christoph Hellwig   [PATCH] Add block...
6
  #include <linux/hdreg.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
  #include <linux/backing-dev.h>
ff01bb483   Al Viro   fs: move code out...
8
  #include <linux/fs.h>
2056a782f   Jens Axboe   [PATCH] Block que...
9
  #include <linux/blktrace_api.h>
bbd3e0643   Christoph Hellwig   block: add an API...
10
  #include <linux/pr.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
15
16
  #include <asm/uaccess.h>
  
  static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg)
  {
  	struct block_device *bdevp;
  	struct gendisk *disk;
c83f6bf98   Vivek Goyal   block: add partit...
17
  	struct hd_struct *part, *lpart;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
  	struct blkpg_ioctl_arg a;
  	struct blkpg_partition p;
e71bf0d0e   Tejun Heo   block: fix disk->...
20
  	struct disk_part_iter piter;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  	long long start, length;
cf771cb5a   Tejun Heo   block: make varia...
22
  	int partno;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
28
29
30
31
32
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EACCES;
  	if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
  		return -EFAULT;
  	if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
  		return -EFAULT;
  	disk = bdev->bd_disk;
  	if (bdev != bdev->bd_contains)
  		return -EINVAL;
cf771cb5a   Tejun Heo   block: make varia...
33
  	partno = p.pno;
540eed563   Tejun Heo   block: make parti...
34
  	if (partno <= 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
39
  		return -EINVAL;
  	switch (a.op) {
  		case BLKPG_ADD_PARTITION:
  			start = p.start >> 9;
  			length = p.length >> 9;
c83f6bf98   Vivek Goyal   block: add partit...
40
41
  			/* check for fit in a hd_struct */
  			if (sizeof(sector_t) == sizeof(long) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
  			    sizeof(long long) > sizeof(long)) {
  				long pstart = start, plength = length;
  				if (pstart != start || plength != length
2bd6efad2   Alan Cox   blk: add an upper...
45
  				    || pstart < 0 || plength < 0 || partno > 65535)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
  					return -EINVAL;
  			}
88e341261   Tejun Heo   block: update add...
48

c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
49
  			mutex_lock(&bdev->bd_mutex);
88e341261   Tejun Heo   block: update add...
50

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
  			/* overlap? */
e71bf0d0e   Tejun Heo   block: fix disk->...
52
53
54
55
56
57
  			disk_part_iter_init(&piter, disk,
  					    DISK_PITER_INCL_EMPTY);
  			while ((part = disk_part_iter_next(&piter))) {
  				if (!(start + length <= part->start_sect ||
  				      start >= part->start_sect + part->nr_sects)) {
  					disk_part_iter_exit(&piter);
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
58
  					mutex_unlock(&bdev->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
61
  					return -EBUSY;
  				}
  			}
e71bf0d0e   Tejun Heo   block: fix disk->...
62
  			disk_part_iter_exit(&piter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
  			/* all seems OK */
ba32929a9   Tejun Heo   block: make add_p...
64
  			part = add_partition(disk, partno, start, length,
6d1d8050b   Will Drewry   block, partition:...
65
  					     ADDPART_FLAG_NONE, NULL);
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
66
  			mutex_unlock(&bdev->bd_mutex);
c7d1ba417   Duan Jiong   block: replace IS...
67
  			return PTR_ERR_OR_ZERO(part);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
  		case BLKPG_DEL_PARTITION:
e71bf0d0e   Tejun Heo   block: fix disk->...
69
70
  			part = disk_get_part(disk, partno);
  			if (!part)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  				return -ENXIO;
e71bf0d0e   Tejun Heo   block: fix disk->...
72
73
74
  
  			bdevp = bdget(part_devt(part));
  			disk_put_part(part);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
  			if (!bdevp)
  				return -ENOMEM;
e71bf0d0e   Tejun Heo   block: fix disk->...
77

2e7b651df   Peter Zijlstra   [PATCH] remove th...
78
  			mutex_lock(&bdevp->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  			if (bdevp->bd_openers) {
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
80
  				mutex_unlock(&bdevp->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
84
85
  				bdput(bdevp);
  				return -EBUSY;
  			}
  			/* all seems OK */
  			fsync_bdev(bdevp);
f98393a64   Peter Zijlstra   mm: remove destro...
86
  			invalidate_bdev(bdevp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87

6d740cd5b   Peter Zijlstra   [PATCH] lockdep: ...
88
  			mutex_lock_nested(&bdev->bd_mutex, 1);
cf771cb5a   Tejun Heo   block: make varia...
89
  			delete_partition(disk, partno);
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
90
91
  			mutex_unlock(&bdev->bd_mutex);
  			mutex_unlock(&bdevp->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
  			bdput(bdevp);
  
  			return 0;
c83f6bf98   Vivek Goyal   block: add partit...
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  		case BLKPG_RESIZE_PARTITION:
  			start = p.start >> 9;
  			/* new length of partition in bytes */
  			length = p.length >> 9;
  			/* check for fit in a hd_struct */
  			if (sizeof(sector_t) == sizeof(long) &&
  			    sizeof(long long) > sizeof(long)) {
  				long pstart = start, plength = length;
  				if (pstart != start || plength != length
  				    || pstart < 0 || plength < 0)
  					return -EINVAL;
  			}
  			part = disk_get_part(disk, partno);
  			if (!part)
  				return -ENXIO;
  			bdevp = bdget(part_devt(part));
  			if (!bdevp) {
  				disk_put_part(part);
  				return -ENOMEM;
  			}
  			mutex_lock(&bdevp->bd_mutex);
  			mutex_lock_nested(&bdev->bd_mutex, 1);
  			if (start != part->start_sect) {
  				mutex_unlock(&bdevp->bd_mutex);
  				mutex_unlock(&bdev->bd_mutex);
  				bdput(bdevp);
  				disk_put_part(part);
  				return -EINVAL;
  			}
  			/* overlap? */
  			disk_part_iter_init(&piter, disk,
  					    DISK_PITER_INCL_EMPTY);
  			while ((lpart = disk_part_iter_next(&piter))) {
  				if (lpart->partno != partno &&
  				   !(start + length <= lpart->start_sect ||
  				   start >= lpart->start_sect + lpart->nr_sects)
  				   ) {
  					disk_part_iter_exit(&piter);
  					mutex_unlock(&bdevp->bd_mutex);
  					mutex_unlock(&bdev->bd_mutex);
  					bdput(bdevp);
  					disk_put_part(part);
  					return -EBUSY;
  				}
  			}
  			disk_part_iter_exit(&piter);
  			part_nr_sects_write(part, (sector_t)length);
  			i_size_write(bdevp->bd_inode, p.length);
  			mutex_unlock(&bdevp->bd_mutex);
  			mutex_unlock(&bdev->bd_mutex);
  			bdput(bdevp);
  			disk_put_part(part);
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
151
  		default:
  			return -EINVAL;
  	}
  }
be3241779   Jarod Wilson   block: export blk...
152
153
154
155
156
157
  /*
   * This is an exported API for the block driver, and will not
   * acquire bd_mutex. This API should be used in case that
   * caller has held bd_mutex already.
   */
  int __blkdev_reread_part(struct block_device *bdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
  {
  	struct gendisk *disk = bdev->bd_disk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160

d27769ec3   Tejun Heo   block: add GENHD_...
161
  	if (!disk_part_scan_enabled(disk) || bdev != bdev->bd_contains)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
164
  		return -EINVAL;
  	if (!capable(CAP_SYS_ADMIN))
  		return -EACCES;
be3241779   Jarod Wilson   block: export blk...
165
166
167
168
169
170
171
172
173
174
175
  
  	lockdep_assert_held(&bdev->bd_mutex);
  
  	return rescan_partitions(disk, bdev);
  }
  EXPORT_SYMBOL(__blkdev_reread_part);
  
  /*
   * This is an exported API for the block driver, and will
   * try to acquire bd_mutex. If bd_mutex has been held already
   * in current context, please call __blkdev_reread_part().
b04a5636a   Ming Lei   block: replace tr...
176
177
178
179
180
181
   *
   * Make sure the held locks in current context aren't required
   * in open()/close() handler and I/O path for avoiding ABBA deadlock:
   * - bd_mutex is held before calling block driver's open/close
   *   handler
   * - reading partition table may submit I/O to the block device
be3241779   Jarod Wilson   block: export blk...
182
183
184
185
   */
  int blkdev_reread_part(struct block_device *bdev)
  {
  	int res;
b04a5636a   Ming Lei   block: replace tr...
186
  	mutex_lock(&bdev->bd_mutex);
be3241779   Jarod Wilson   block: export blk...
187
  	res = __blkdev_reread_part(bdev);
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
188
  	mutex_unlock(&bdev->bd_mutex);
be3241779   Jarod Wilson   block: export blk...
189

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
  	return res;
  }
be3241779   Jarod Wilson   block: export blk...
192
  EXPORT_SYMBOL(blkdev_reread_part);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193

d8e4bb810   Christoph Hellwig   block: cleanup bl...
194
195
  static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
  		unsigned long arg, unsigned long flags)
d30a2605b   David Woodhouse   Add BLKDISCARD io...
196
  {
d8e4bb810   Christoph Hellwig   block: cleanup bl...
197
198
199
200
201
202
203
204
205
206
207
  	uint64_t range[2];
  	uint64_t start, len;
  
  	if (!(mode & FMODE_WRITE))
  		return -EBADF;
  
  	if (copy_from_user(range, (void __user *)arg, sizeof(range)))
  		return -EFAULT;
  
  	start = range[0];
  	len = range[1];
8d57a98cc   Adrian Hunter   block: add secure...
208

d30a2605b   David Woodhouse   Add BLKDISCARD io...
209
210
211
212
213
214
  	if (start & 511)
  		return -EINVAL;
  	if (len & 511)
  		return -EINVAL;
  	start >>= 9;
  	len >>= 9;
77304d2ab   Mike Snitzer   block: read i_siz...
215
  	if (start + len > (i_size_read(bdev->bd_inode) >> 9))
d30a2605b   David Woodhouse   Add BLKDISCARD io...
216
  		return -EINVAL;
8d57a98cc   Adrian Hunter   block: add secure...
217
  	return blkdev_issue_discard(bdev, start, len, GFP_KERNEL, flags);
d30a2605b   David Woodhouse   Add BLKDISCARD io...
218
  }
d8e4bb810   Christoph Hellwig   block: cleanup bl...
219
220
  static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
  		unsigned long arg)
66ba32dc1   Martin K. Petersen   block: ioctl to z...
221
  {
d8e4bb810   Christoph Hellwig   block: cleanup bl...
222
223
224
225
226
227
228
229
230
231
232
  	uint64_t range[2];
  	uint64_t start, len;
  
  	if (!(mode & FMODE_WRITE))
  		return -EBADF;
  
  	if (copy_from_user(range, (void __user *)arg, sizeof(range)))
  		return -EFAULT;
  
  	start = range[0];
  	len = range[1];
66ba32dc1   Martin K. Petersen   block: ioctl to z...
233
234
235
236
237
238
239
240
241
  	if (start & 511)
  		return -EINVAL;
  	if (len & 511)
  		return -EINVAL;
  	start >>= 9;
  	len >>= 9;
  
  	if (start + len > (i_size_read(bdev->bd_inode) >> 9))
  		return -EINVAL;
d93ba7a5a   Martin K. Petersen   block: Add discar...
242
  	return blkdev_issue_zeroout(bdev, start, len, GFP_KERNEL, false);
66ba32dc1   Martin K. Petersen   block: ioctl to z...
243
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
246
247
248
249
250
251
252
  static int put_ushort(unsigned long arg, unsigned short val)
  {
  	return put_user(val, (unsigned short __user *)arg);
  }
  
  static int put_int(unsigned long arg, int val)
  {
  	return put_user(val, (int __user *)arg);
  }
ac481c20e   Martin K. Petersen   block: Topology i...
253
254
255
256
  static int put_uint(unsigned long arg, unsigned int val)
  {
  	return put_user(val, (unsigned int __user *)arg);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  static int put_long(unsigned long arg, long val)
  {
  	return put_user(val, (long __user *)arg);
  }
  
  static int put_ulong(unsigned long arg, unsigned long val)
  {
  	return put_user(val, (unsigned long __user *)arg);
  }
  
  static int put_u64(unsigned long arg, u64 val)
  {
  	return put_user(val, (u64 __user *)arg);
  }
633a08b81   Al Viro   [PATCH] introduce...
271
272
273
274
  int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
  			unsigned cmd, unsigned long arg)
  {
  	struct gendisk *disk = bdev->bd_disk;
d4430d62f   Al Viro   [PATCH] beginning...
275
276
277
  
  	if (disk->fops->ioctl)
  		return disk->fops->ioctl(bdev, mode, cmd, arg);
633a08b81   Al Viro   [PATCH] introduce...
278

633a08b81   Al Viro   [PATCH] introduce...
279
280
281
282
283
284
285
286
  	return -ENOTTY;
  }
  /*
   * For the record: _GPL here is only because somebody decided to slap it
   * on the previous export.  Sheer idiocy, since it wasn't copyrightable
   * at all and could be open-coded without any exports by anybody who cares.
   */
  EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl);
bbd3e0643   Christoph Hellwig   block: add an API...
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
  static int blkdev_pr_register(struct block_device *bdev,
  		struct pr_registration __user *arg)
  {
  	const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
  	struct pr_registration reg;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  	if (!ops || !ops->pr_register)
  		return -EOPNOTSUPP;
  	if (copy_from_user(&reg, arg, sizeof(reg)))
  		return -EFAULT;
  
  	if (reg.flags & ~PR_FL_IGNORE_KEY)
  		return -EOPNOTSUPP;
  	return ops->pr_register(bdev, reg.old_key, reg.new_key, reg.flags);
  }
  
  static int blkdev_pr_reserve(struct block_device *bdev,
  		struct pr_reservation __user *arg)
  {
  	const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
  	struct pr_reservation rsv;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  	if (!ops || !ops->pr_reserve)
  		return -EOPNOTSUPP;
  	if (copy_from_user(&rsv, arg, sizeof(rsv)))
  		return -EFAULT;
  
  	if (rsv.flags & ~PR_FL_IGNORE_KEY)
  		return -EOPNOTSUPP;
  	return ops->pr_reserve(bdev, rsv.key, rsv.type, rsv.flags);
  }
  
  static int blkdev_pr_release(struct block_device *bdev,
  		struct pr_reservation __user *arg)
  {
  	const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
  	struct pr_reservation rsv;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  	if (!ops || !ops->pr_release)
  		return -EOPNOTSUPP;
  	if (copy_from_user(&rsv, arg, sizeof(rsv)))
  		return -EFAULT;
  
  	if (rsv.flags)
  		return -EOPNOTSUPP;
  	return ops->pr_release(bdev, rsv.key, rsv.type);
  }
  
  static int blkdev_pr_preempt(struct block_device *bdev,
  		struct pr_preempt __user *arg, bool abort)
  {
  	const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
  	struct pr_preempt p;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  	if (!ops || !ops->pr_preempt)
  		return -EOPNOTSUPP;
  	if (copy_from_user(&p, arg, sizeof(p)))
  		return -EFAULT;
  
  	if (p.flags)
  		return -EOPNOTSUPP;
  	return ops->pr_preempt(bdev, p.old_key, p.new_key, p.type, abort);
  }
  
  static int blkdev_pr_clear(struct block_device *bdev,
  		struct pr_clear __user *arg)
  {
  	const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
  	struct pr_clear c;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  	if (!ops || !ops->pr_clear)
  		return -EOPNOTSUPP;
  	if (copy_from_user(&c, arg, sizeof(c)))
  		return -EFAULT;
  
  	if (c.flags)
  		return -EOPNOTSUPP;
  	return ops->pr_clear(bdev, c.key);
  }
f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
376
  /*
07d106d0a   Linus Torvalds   vfs: fix up ENOIO...
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
   * Is it an unrecognized ioctl? The correct returns are either
   * ENOTTY (final) or ENOIOCTLCMD ("I don't know this one, try a
   * fallback"). ENOIOCTLCMD gets turned into ENOTTY by the ioctl
   * code before returning.
   *
   * Confused drivers sometimes return EINVAL, which is wrong. It
   * means "I understood the ioctl command, but the parameters to
   * it were wrong".
   *
   * We should aim to just fix the broken drivers, the EINVAL case
   * should go away.
   */
  static inline int is_unrecognized_ioctl(int ret)
  {
  	return	ret == -EINVAL ||
  		ret == -ENOTTY ||
  		ret == -ENOIOCTLCMD;
  }
d8e4bb810   Christoph Hellwig   block: cleanup bl...
395
396
  static int blkdev_flushbuf(struct block_device *bdev, fmode_t mode,
  		unsigned cmd, unsigned long arg)
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
397
  {
d8e4bb810   Christoph Hellwig   block: cleanup bl...
398
  	int ret;
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
399

d8e4bb810   Christoph Hellwig   block: cleanup bl...
400
401
  	if (!capable(CAP_SYS_ADMIN))
  		return -EACCES;
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
402

d8e4bb810   Christoph Hellwig   block: cleanup bl...
403
404
405
  	ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
  	if (!is_unrecognized_ioctl(ret))
  		return ret;
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
406

d8e4bb810   Christoph Hellwig   block: cleanup bl...
407
408
409
410
  	fsync_bdev(bdev);
  	invalidate_bdev(bdev);
  	return 0;
  }
d30a2605b   David Woodhouse   Add BLKDISCARD io...
411

d8e4bb810   Christoph Hellwig   block: cleanup bl...
412
413
414
415
  static int blkdev_roset(struct block_device *bdev, fmode_t mode,
  		unsigned cmd, unsigned long arg)
  {
  	int ret, n;
d30a2605b   David Woodhouse   Add BLKDISCARD io...
416

d8e4bb810   Christoph Hellwig   block: cleanup bl...
417
418
419
420
421
422
423
424
425
426
  	ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
  	if (!is_unrecognized_ioctl(ret))
  		return ret;
  	if (!capable(CAP_SYS_ADMIN))
  		return -EACCES;
  	if (get_user(n, (int __user *)arg))
  		return -EFAULT;
  	set_device_ro(bdev, n);
  	return 0;
  }
d30a2605b   David Woodhouse   Add BLKDISCARD io...
427

d8e4bb810   Christoph Hellwig   block: cleanup bl...
428
429
430
431
432
433
  static int blkdev_getgeo(struct block_device *bdev,
  		struct hd_geometry __user *argp)
  {
  	struct gendisk *disk = bdev->bd_disk;
  	struct hd_geometry geo;
  	int ret;
d30a2605b   David Woodhouse   Add BLKDISCARD io...
434

d8e4bb810   Christoph Hellwig   block: cleanup bl...
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
  	if (!argp)
  		return -EINVAL;
  	if (!disk->fops->getgeo)
  		return -ENOTTY;
  
  	/*
  	 * We need to set the startsect first, the driver may
  	 * want to override it.
  	 */
  	memset(&geo, 0, sizeof(geo));
  	geo.start = get_start_sect(bdev);
  	ret = disk->fops->getgeo(bdev, &geo);
  	if (ret)
  		return ret;
  	if (copy_to_user(argp, &geo, sizeof(geo)))
  		return -EFAULT;
  	return 0;
  }
66ba32dc1   Martin K. Petersen   block: ioctl to z...
453

d8e4bb810   Christoph Hellwig   block: cleanup bl...
454
455
456
457
458
  /* set the logical block size */
  static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
  		int __user *argp)
  {
  	int ret, n;
66ba32dc1   Martin K. Petersen   block: ioctl to z...
459

d8e4bb810   Christoph Hellwig   block: cleanup bl...
460
461
462
463
464
465
  	if (!capable(CAP_SYS_ADMIN))
  		return -EACCES;
  	if (!argp)
  		return -EINVAL;
  	if (get_user(n, argp))
  		return -EFAULT;
66ba32dc1   Martin K. Petersen   block: ioctl to z...
466

d8e4bb810   Christoph Hellwig   block: cleanup bl...
467
468
469
470
  	if (!(mode & FMODE_EXCL)) {
  		bdgrab(bdev);
  		if (blkdev_get(bdev, mode | FMODE_EXCL, &bdev) < 0)
  			return -EBUSY;
66ba32dc1   Martin K. Petersen   block: ioctl to z...
471
  	}
d30a2605b   David Woodhouse   Add BLKDISCARD io...
472

d8e4bb810   Christoph Hellwig   block: cleanup bl...
473
474
475
476
477
  	ret = set_blocksize(bdev, n);
  	if (!(mode & FMODE_EXCL))
  		blkdev_put(bdev, mode | FMODE_EXCL);
  	return ret;
  }
a885c8c43   Christoph Hellwig   [PATCH] Add block...
478

d8e4bb810   Christoph Hellwig   block: cleanup bl...
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
  /*
   * always keep this in sync with compat_blkdev_ioctl()
   */
  int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
  			unsigned long arg)
  {
  	struct backing_dev_info *bdi;
  	void __user *argp = (void __user *)arg;
  	loff_t size;
  	unsigned int max_sectors;
  
  	switch (cmd) {
  	case BLKFLSBUF:
  		return blkdev_flushbuf(bdev, mode, cmd, arg);
  	case BLKROSET:
  		return blkdev_roset(bdev, mode, cmd, arg);
  	case BLKDISCARD:
  		return blk_ioctl_discard(bdev, mode, arg, 0);
  	case BLKSECDISCARD:
  		return blk_ioctl_discard(bdev, mode, arg,
  				BLKDEV_DISCARD_SECURE);
  	case BLKZEROOUT:
  		return blk_ioctl_zeroout(bdev, mode, arg);
  	case HDIO_GETGEO:
  		return blkdev_getgeo(bdev, argp);
45048d096   Al Viro   [PATCH] get rid o...
504
505
506
507
508
  	case BLKRAGET:
  	case BLKFRAGET:
  		if (!arg)
  			return -EINVAL;
  		bdi = blk_get_backing_dev_info(bdev);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
509
  		return put_long(arg, (bdi->ra_pages * PAGE_SIZE) / 512);
45048d096   Al Viro   [PATCH] get rid o...
510
511
  	case BLKROGET:
  		return put_int(arg, bdev_read_only(bdev) != 0);
ac481c20e   Martin K. Petersen   block: Topology i...
512
  	case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
45048d096   Al Viro   [PATCH] get rid o...
513
  		return put_int(arg, block_size(bdev));
ac481c20e   Martin K. Petersen   block: Topology i...
514
  	case BLKSSZGET: /* get block device logical block size */
e1defc4ff   Martin K. Petersen   block: Do away wi...
515
  		return put_int(arg, bdev_logical_block_size(bdev));
ac481c20e   Martin K. Petersen   block: Topology i...
516
517
518
519
520
521
522
523
  	case BLKPBSZGET: /* get block device physical block size */
  		return put_uint(arg, bdev_physical_block_size(bdev));
  	case BLKIOMIN:
  		return put_uint(arg, bdev_io_min(bdev));
  	case BLKIOOPT:
  		return put_uint(arg, bdev_io_opt(bdev));
  	case BLKALIGNOFF:
  		return put_int(arg, bdev_alignment_offset(bdev));
98262f276   Martin K. Petersen   block: Allow devi...
524
525
  	case BLKDISCARDZEROES:
  		return put_uint(arg, bdev_discard_zeroes_data(bdev));
45048d096   Al Viro   [PATCH] get rid o...
526
  	case BLKSECTGET:
63f264965   Akinobu Mita   block: fix BLKSEC...
527
528
529
  		max_sectors = min_t(unsigned int, USHRT_MAX,
  				    queue_max_sectors(bdev_get_queue(bdev)));
  		return put_ushort(arg, max_sectors);
ef00f59c9   Martin K. Petersen   block: Add BLKROT...
530
531
  	case BLKROTATIONAL:
  		return put_ushort(arg, !blk_queue_nonrot(bdev_get_queue(bdev)));
45048d096   Al Viro   [PATCH] get rid o...
532
533
534
535
536
  	case BLKRASET:
  	case BLKFRASET:
  		if(!capable(CAP_SYS_ADMIN))
  			return -EACCES;
  		bdi = blk_get_backing_dev_info(bdev);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
537
  		bdi->ra_pages = (arg * 512) / PAGE_SIZE;
45048d096   Al Viro   [PATCH] get rid o...
538
539
  		return 0;
  	case BLKBSZSET:
d8e4bb810   Christoph Hellwig   block: cleanup bl...
540
  		return blkdev_bszset(bdev, mode, argp);
45048d096   Al Viro   [PATCH] get rid o...
541
  	case BLKPG:
d8e4bb810   Christoph Hellwig   block: cleanup bl...
542
  		return blkpg_ioctl(bdev, argp);
45048d096   Al Viro   [PATCH] get rid o...
543
  	case BLKRRPART:
d8e4bb810   Christoph Hellwig   block: cleanup bl...
544
  		return blkdev_reread_part(bdev);
45048d096   Al Viro   [PATCH] get rid o...
545
  	case BLKGETSIZE:
77304d2ab   Mike Snitzer   block: read i_siz...
546
  		size = i_size_read(bdev->bd_inode);
45048d096   Al Viro   [PATCH] get rid o...
547
548
549
550
  		if ((size >> 9) > ~0UL)
  			return -EFBIG;
  		return put_ulong(arg, size >> 9);
  	case BLKGETSIZE64:
77304d2ab   Mike Snitzer   block: read i_siz...
551
  		return put_u64(arg, i_size_read(bdev->bd_inode));
45048d096   Al Viro   [PATCH] get rid o...
552
553
554
555
  	case BLKTRACESTART:
  	case BLKTRACESTOP:
  	case BLKTRACESETUP:
  	case BLKTRACETEARDOWN:
d8e4bb810   Christoph Hellwig   block: cleanup bl...
556
  		return blk_trace_ioctl(bdev, cmd, argp);
bbd3e0643   Christoph Hellwig   block: add an API...
557
558
559
560
561
562
563
564
565
566
567
568
  	case IOC_PR_REGISTER:
  		return blkdev_pr_register(bdev, argp);
  	case IOC_PR_RESERVE:
  		return blkdev_pr_reserve(bdev, argp);
  	case IOC_PR_RELEASE:
  		return blkdev_pr_release(bdev, argp);
  	case IOC_PR_PREEMPT:
  		return blkdev_pr_preempt(bdev, argp, false);
  	case IOC_PR_PREEMPT_ABORT:
  		return blkdev_pr_preempt(bdev, argp, true);
  	case IOC_PR_CLEAR:
  		return blkdev_pr_clear(bdev, argp);
45048d096   Al Viro   [PATCH] get rid o...
569
  	default:
d8e4bb810   Christoph Hellwig   block: cleanup bl...
570
  		return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
45048d096   Al Viro   [PATCH] get rid o...
571
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
  }
68f66feb3   Stephen Tweedie   [PATCH] Fix root ...
573
  EXPORT_SYMBOL_GPL(blkdev_ioctl);