Blame view

block/ioctl.c 14.8 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
  	uint64_t range[2];
22dd6d356   Darrick J. Wong   block: invalidate...
223
224
  	struct address_space *mapping;
  	uint64_t start, end, len;
d8e4bb810   Christoph Hellwig   block: cleanup bl...
225
226
227
228
229
230
231
232
233
  
  	if (!(mode & FMODE_WRITE))
  		return -EBADF;
  
  	if (copy_from_user(range, (void __user *)arg, sizeof(range)))
  		return -EFAULT;
  
  	start = range[0];
  	len = range[1];
22dd6d356   Darrick J. Wong   block: invalidate...
234
  	end = start + len - 1;
d8e4bb810   Christoph Hellwig   block: cleanup bl...
235

66ba32dc1   Martin K. Petersen   block: ioctl to z...
236
237
238
239
  	if (start & 511)
  		return -EINVAL;
  	if (len & 511)
  		return -EINVAL;
22dd6d356   Darrick J. Wong   block: invalidate...
240
241
242
  	if (end >= (uint64_t)i_size_read(bdev->bd_inode))
  		return -EINVAL;
  	if (end < start)
66ba32dc1   Martin K. Petersen   block: ioctl to z...
243
  		return -EINVAL;
22dd6d356   Darrick J. Wong   block: invalidate...
244
245
246
247
248
249
  	/* Invalidate the page cache, including dirty pages */
  	mapping = bdev->bd_inode->i_mapping;
  	truncate_inode_pages_range(mapping, start, end);
  
  	return blkdev_issue_zeroout(bdev, start >> 9, len >> 9, GFP_KERNEL,
  				    false);
66ba32dc1   Martin K. Petersen   block: ioctl to z...
250
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
253
254
255
256
257
258
259
  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...
260
261
262
263
  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
264
265
266
267
268
269
270
271
272
273
274
275
276
277
  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...
278
279
280
281
  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...
282
283
284
  
  	if (disk->fops->ioctl)
  		return disk->fops->ioctl(bdev, mode, cmd, arg);
633a08b81   Al Viro   [PATCH] introduce...
285

633a08b81   Al Viro   [PATCH] introduce...
286
287
288
289
290
291
292
293
  	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...
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
376
377
378
379
380
381
382
  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...
383
  /*
07d106d0a   Linus Torvalds   vfs: fix up ENOIO...
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
   * 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...
402
403
  static int blkdev_flushbuf(struct block_device *bdev, fmode_t mode,
  		unsigned cmd, unsigned long arg)
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
404
  {
d8e4bb810   Christoph Hellwig   block: cleanup bl...
405
  	int ret;
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
406

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

d8e4bb810   Christoph Hellwig   block: cleanup bl...
410
411
412
  	ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
  	if (!is_unrecognized_ioctl(ret))
  		return ret;
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
413

d8e4bb810   Christoph Hellwig   block: cleanup bl...
414
415
416
417
  	fsync_bdev(bdev);
  	invalidate_bdev(bdev);
  	return 0;
  }
d30a2605b   David Woodhouse   Add BLKDISCARD io...
418

d8e4bb810   Christoph Hellwig   block: cleanup bl...
419
420
421
422
  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...
423

d8e4bb810   Christoph Hellwig   block: cleanup bl...
424
425
426
427
428
429
430
431
432
433
  	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...
434

d8e4bb810   Christoph Hellwig   block: cleanup bl...
435
436
437
438
439
440
  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...
441

d8e4bb810   Christoph Hellwig   block: cleanup bl...
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
  	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...
460

d8e4bb810   Christoph Hellwig   block: cleanup bl...
461
462
463
464
465
  /* 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...
466

d8e4bb810   Christoph Hellwig   block: cleanup bl...
467
468
469
470
471
472
  	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...
473

d8e4bb810   Christoph Hellwig   block: cleanup bl...
474
475
476
477
  	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...
478
  	}
d30a2605b   David Woodhouse   Add BLKDISCARD io...
479

d8e4bb810   Christoph Hellwig   block: cleanup bl...
480
481
482
483
484
  	ret = set_blocksize(bdev, n);
  	if (!(mode & FMODE_EXCL))
  		blkdev_put(bdev, mode | FMODE_EXCL);
  	return ret;
  }
a885c8c43   Christoph Hellwig   [PATCH] Add block...
485

d8e4bb810   Christoph Hellwig   block: cleanup bl...
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
  /*
   * 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...
511
512
513
514
515
  	case BLKRAGET:
  	case BLKFRAGET:
  		if (!arg)
  			return -EINVAL;
  		bdi = blk_get_backing_dev_info(bdev);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
516
  		return put_long(arg, (bdi->ra_pages * PAGE_SIZE) / 512);
45048d096   Al Viro   [PATCH] get rid o...
517
518
  	case BLKROGET:
  		return put_int(arg, bdev_read_only(bdev) != 0);
ac481c20e   Martin K. Petersen   block: Topology i...
519
  	case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
45048d096   Al Viro   [PATCH] get rid o...
520
  		return put_int(arg, block_size(bdev));
ac481c20e   Martin K. Petersen   block: Topology i...
521
  	case BLKSSZGET: /* get block device logical block size */
e1defc4ff   Martin K. Petersen   block: Do away wi...
522
  		return put_int(arg, bdev_logical_block_size(bdev));
ac481c20e   Martin K. Petersen   block: Topology i...
523
524
525
526
527
528
529
530
  	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...
531
532
  	case BLKDISCARDZEROES:
  		return put_uint(arg, bdev_discard_zeroes_data(bdev));
45048d096   Al Viro   [PATCH] get rid o...
533
  	case BLKSECTGET:
63f264965   Akinobu Mita   block: fix BLKSEC...
534
535
536
  		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...
537
538
  	case BLKROTATIONAL:
  		return put_ushort(arg, !blk_queue_nonrot(bdev_get_queue(bdev)));
45048d096   Al Viro   [PATCH] get rid o...
539
540
541
542
543
  	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...
544
  		bdi->ra_pages = (arg * 512) / PAGE_SIZE;
45048d096   Al Viro   [PATCH] get rid o...
545
546
  		return 0;
  	case BLKBSZSET:
d8e4bb810   Christoph Hellwig   block: cleanup bl...
547
  		return blkdev_bszset(bdev, mode, argp);
45048d096   Al Viro   [PATCH] get rid o...
548
  	case BLKPG:
d8e4bb810   Christoph Hellwig   block: cleanup bl...
549
  		return blkpg_ioctl(bdev, argp);
45048d096   Al Viro   [PATCH] get rid o...
550
  	case BLKRRPART:
d8e4bb810   Christoph Hellwig   block: cleanup bl...
551
  		return blkdev_reread_part(bdev);
45048d096   Al Viro   [PATCH] get rid o...
552
  	case BLKGETSIZE:
77304d2ab   Mike Snitzer   block: read i_siz...
553
  		size = i_size_read(bdev->bd_inode);
45048d096   Al Viro   [PATCH] get rid o...
554
555
556
557
  		if ((size >> 9) > ~0UL)
  			return -EFBIG;
  		return put_ulong(arg, size >> 9);
  	case BLKGETSIZE64:
77304d2ab   Mike Snitzer   block: read i_siz...
558
  		return put_u64(arg, i_size_read(bdev->bd_inode));
45048d096   Al Viro   [PATCH] get rid o...
559
560
561
562
  	case BLKTRACESTART:
  	case BLKTRACESTOP:
  	case BLKTRACESETUP:
  	case BLKTRACETEARDOWN:
d8e4bb810   Christoph Hellwig   block: cleanup bl...
563
  		return blk_trace_ioctl(bdev, cmd, argp);
bbd3e0643   Christoph Hellwig   block: add an API...
564
565
566
567
568
569
570
571
572
573
574
575
  	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...
576
  	default:
d8e4bb810   Christoph Hellwig   block: cleanup bl...
577
  		return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
45048d096   Al Viro   [PATCH] get rid o...
578
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
  }
68f66feb3   Stephen Tweedie   [PATCH] Fix root ...
580
  EXPORT_SYMBOL_GPL(blkdev_ioctl);