Blame view

block/ioctl.c 8.22 KB
c59ede7b7   Randy.Dunlap   [PATCH] move capa...
1
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
  #include <linux/blkdev.h>
  #include <linux/blkpg.h>
a885c8c43   Christoph Hellwig   [PATCH] Add block...
4
  #include <linux/hdreg.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
  #include <linux/backing-dev.h>
  #include <linux/buffer_head.h>
  #include <linux/smp_lock.h>
2056a782f   Jens Axboe   [PATCH] Block que...
8
  #include <linux/blktrace_api.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
13
14
  #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;
e71bf0d0e   Tejun Heo   block: fix disk->...
15
  	struct hd_struct *part;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
  	struct blkpg_ioctl_arg a;
  	struct blkpg_partition p;
e71bf0d0e   Tejun Heo   block: fix disk->...
18
  	struct disk_part_iter piter;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
  	long long start, length;
cf771cb5a   Tejun Heo   block: make varia...
20
  	int partno;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
24
25
26
27
28
29
30
  
  	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...
31
  	partno = p.pno;
540eed563   Tejun Heo   block: make parti...
32
  	if (partno <= 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
35
36
37
38
39
40
41
42
43
44
45
  		return -EINVAL;
  	switch (a.op) {
  		case BLKPG_ADD_PARTITION:
  			start = p.start >> 9;
  			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;
  			}
88e341261   Tejun Heo   block: update add...
46

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  			/* overlap? */
e71bf0d0e   Tejun Heo   block: fix disk->...
50
51
52
53
54
55
  			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...
56
  					mutex_unlock(&bdev->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
  					return -EBUSY;
  				}
  			}
e71bf0d0e   Tejun Heo   block: fix disk->...
60
  			disk_part_iter_exit(&piter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  			/* all seems OK */
ba32929a9   Tejun Heo   block: make add_p...
62
63
  			part = add_partition(disk, partno, start, length,
  					     ADDPART_FLAG_NONE);
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
64
  			mutex_unlock(&bdev->bd_mutex);
ba32929a9   Tejun Heo   block: make add_p...
65
  			return IS_ERR(part) ? PTR_ERR(part) : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
  		case BLKPG_DEL_PARTITION:
e71bf0d0e   Tejun Heo   block: fix disk->...
67
68
  			part = disk_get_part(disk, partno);
  			if (!part)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  				return -ENXIO;
e71bf0d0e   Tejun Heo   block: fix disk->...
70
71
72
  
  			bdevp = bdget(part_devt(part));
  			disk_put_part(part);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
  			if (!bdevp)
  				return -ENOMEM;
e71bf0d0e   Tejun Heo   block: fix disk->...
75

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

6d740cd5b   Peter Zijlstra   [PATCH] lockdep: ...
86
  			mutex_lock_nested(&bdev->bd_mutex, 1);
cf771cb5a   Tejun Heo   block: make varia...
87
  			delete_partition(disk, partno);
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
88
89
  			mutex_unlock(&bdev->bd_mutex);
  			mutex_unlock(&bdevp->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
92
93
94
95
96
97
98
99
100
101
  			bdput(bdevp);
  
  			return 0;
  		default:
  			return -EINVAL;
  	}
  }
  
  static int blkdev_reread_part(struct block_device *bdev)
  {
  	struct gendisk *disk = bdev->bd_disk;
  	int res;
b5d0b9df0   Tejun Heo   block: introduce ...
102
  	if (!disk_partitionable(disk) || bdev != bdev->bd_contains)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
  		return -EINVAL;
  	if (!capable(CAP_SYS_ADMIN))
  		return -EACCES;
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
106
  	if (!mutex_trylock(&bdev->bd_mutex))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
  		return -EBUSY;
  	res = rescan_partitions(disk, bdev);
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
109
  	mutex_unlock(&bdev->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
  	return res;
  }
d30a2605b   David Woodhouse   Add BLKDISCARD io...
112
113
114
  static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
  			     uint64_t len)
  {
d30a2605b   David Woodhouse   Add BLKDISCARD io...
115
116
117
118
119
120
121
122
123
  	if (start & 511)
  		return -EINVAL;
  	if (len & 511)
  		return -EINVAL;
  	start >>= 9;
  	len >>= 9;
  
  	if (start + len > (bdev->bd_inode->i_size >> 9))
  		return -EINVAL;
746cd1e7e   Christoph Hellwig   block: use blkdev...
124
125
  	return blkdev_issue_discard(bdev, start, len, GFP_KERNEL,
  				    DISCARD_FL_WAIT);
d30a2605b   David Woodhouse   Add BLKDISCARD io...
126
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
131
132
133
134
135
  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...
136
137
138
139
  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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  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...
154
155
156
157
158
  int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
  			unsigned cmd, unsigned long arg)
  {
  	struct gendisk *disk = bdev->bd_disk;
  	int ret;
d4430d62f   Al Viro   [PATCH] beginning...
159
160
161
  
  	if (disk->fops->ioctl)
  		return disk->fops->ioctl(bdev, mode, cmd, arg);
633a08b81   Al Viro   [PATCH] introduce...
162

d4430d62f   Al Viro   [PATCH] beginning...
163
  	if (disk->fops->locked_ioctl) {
633a08b81   Al Viro   [PATCH] introduce...
164
  		lock_kernel();
d4430d62f   Al Viro   [PATCH] beginning...
165
  		ret = disk->fops->locked_ioctl(bdev, mode, cmd, arg);
633a08b81   Al Viro   [PATCH] introduce...
166
167
168
169
170
171
172
173
174
175
176
177
  		unlock_kernel();
  		return ret;
  	}
  
  	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);
f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
178
179
180
181
  /*
   * always keep this in sync with compat_blkdev_ioctl() and
   * compat_blkdev_locked_ioctl()
   */
56b26add0   Al Viro   [PATCH] kill the ...
182
  int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
183
184
  			unsigned long arg)
  {
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
185
  	struct gendisk *disk = bdev->bd_disk;
45048d096   Al Viro   [PATCH] get rid o...
186
187
  	struct backing_dev_info *bdi;
  	loff_t size;
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
188
189
190
  	int ret, n;
  
  	switch(cmd) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
193
  	case BLKFLSBUF:
  		if (!capable(CAP_SYS_ADMIN))
  			return -EACCES;
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
194

e436fdae7   Al Viro   [PATCH] get rid o...
195
  		ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
196
197
198
199
200
  		/* -EINVAL to handle old uncorrected drivers */
  		if (ret != -EINVAL && ret != -ENOTTY)
  			return ret;
  
  		lock_kernel();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
  		fsync_bdev(bdev);
f98393a64   Peter Zijlstra   mm: remove destro...
202
  		invalidate_bdev(bdev);
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
203
  		unlock_kernel();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
  		return 0;
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
205

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
  	case BLKROSET:
e436fdae7   Al Viro   [PATCH] get rid o...
207
  		ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
208
209
210
  		/* -EINVAL to handle old uncorrected drivers */
  		if (ret != -EINVAL && ret != -ENOTTY)
  			return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
214
  		if (!capable(CAP_SYS_ADMIN))
  			return -EACCES;
  		if (get_user(n, (int __user *)(arg)))
  			return -EFAULT;
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
215
  		lock_kernel();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
  		set_device_ro(bdev, n);
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
217
  		unlock_kernel();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  		return 0;
d30a2605b   David Woodhouse   Add BLKDISCARD io...
219
220
221
  
  	case BLKDISCARD: {
  		uint64_t range[2];
e436fdae7   Al Viro   [PATCH] get rid o...
222
  		if (!(mode & FMODE_WRITE))
d30a2605b   David Woodhouse   Add BLKDISCARD io...
223
224
225
226
227
228
229
  			return -EBADF;
  
  		if (copy_from_user(range, (void __user *)arg, sizeof(range)))
  			return -EFAULT;
  
  		return blk_ioctl_discard(bdev, range[0], range[1]);
  	}
a885c8c43   Christoph Hellwig   [PATCH] Add block...
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
  	case HDIO_GETGEO: {
  		struct hd_geometry geo;
  
  		if (!arg)
  			return -EINVAL;
  		if (!disk->fops->getgeo)
  			return -ENOTTY;
  
  		/*
  		 * We need to set the startsect first, the driver may
  		 * want to override it.
  		 */
  		geo.start = get_start_sect(bdev);
  		ret = disk->fops->getgeo(bdev, &geo);
  		if (ret)
  			return ret;
  		if (copy_to_user((struct hd_geometry __user *)arg, &geo,
  					sizeof(geo)))
  			return -EFAULT;
  		return 0;
  	}
45048d096   Al Viro   [PATCH] get rid o...
251
252
253
254
255
256
257
258
259
260
  	case BLKRAGET:
  	case BLKFRAGET:
  		if (!arg)
  			return -EINVAL;
  		bdi = blk_get_backing_dev_info(bdev);
  		if (bdi == NULL)
  			return -ENOTTY;
  		return put_long(arg, (bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
  	case BLKROGET:
  		return put_int(arg, bdev_read_only(bdev) != 0);
ac481c20e   Martin K. Petersen   block: Topology i...
261
  	case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
45048d096   Al Viro   [PATCH] get rid o...
262
  		return put_int(arg, block_size(bdev));
ac481c20e   Martin K. Petersen   block: Topology i...
263
  	case BLKSSZGET: /* get block device logical block size */
e1defc4ff   Martin K. Petersen   block: Do away wi...
264
  		return put_int(arg, bdev_logical_block_size(bdev));
ac481c20e   Martin K. Petersen   block: Topology i...
265
266
267
268
269
270
271
272
  	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...
273
274
  	case BLKDISCARDZEROES:
  		return put_uint(arg, bdev_discard_zeroes_data(bdev));
45048d096   Al Viro   [PATCH] get rid o...
275
  	case BLKSECTGET:
ae03bf639   Martin K. Petersen   block: Use access...
276
  		return put_ushort(arg, queue_max_sectors(bdev_get_queue(bdev)));
45048d096   Al Viro   [PATCH] get rid o...
277
278
279
280
281
282
283
  	case BLKRASET:
  	case BLKFRASET:
  		if(!capable(CAP_SYS_ADMIN))
  			return -EACCES;
  		bdi = blk_get_backing_dev_info(bdev);
  		if (bdi == NULL)
  			return -ENOTTY;
45048d096   Al Viro   [PATCH] get rid o...
284
  		bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
45048d096   Al Viro   [PATCH] get rid o...
285
286
287
288
289
290
291
292
293
  		return 0;
  	case BLKBSZSET:
  		/* set the logical block size */
  		if (!capable(CAP_SYS_ADMIN))
  			return -EACCES;
  		if (!arg)
  			return -EINVAL;
  		if (get_user(n, (int __user *) arg))
  			return -EFAULT;
6af3a56e1   Al Viro   [PATCH] get rid o...
294
  		if (!(mode & FMODE_EXCL) && bd_claim(bdev, &bdev) < 0)
45048d096   Al Viro   [PATCH] get rid o...
295
296
  			return -EBUSY;
  		ret = set_blocksize(bdev, n);
6af3a56e1   Al Viro   [PATCH] get rid o...
297
298
  		if (!(mode & FMODE_EXCL))
  			bd_release(bdev);
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
299
  		return ret;
45048d096   Al Viro   [PATCH] get rid o...
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
  	case BLKPG:
  		lock_kernel();
  		ret = blkpg_ioctl(bdev, (struct blkpg_ioctl_arg __user *) arg);
  		unlock_kernel();
  		break;
  	case BLKRRPART:
  		lock_kernel();
  		ret = blkdev_reread_part(bdev);
  		unlock_kernel();
  		break;
  	case BLKGETSIZE:
  		size = bdev->bd_inode->i_size;
  		if ((size >> 9) > ~0UL)
  			return -EFBIG;
  		return put_ulong(arg, size >> 9);
  	case BLKGETSIZE64:
  		return put_u64(arg, bdev->bd_inode->i_size);
  	case BLKTRACESTART:
  	case BLKTRACESTOP:
  	case BLKTRACESETUP:
  	case BLKTRACETEARDOWN:
  		lock_kernel();
  		ret = blk_trace_ioctl(bdev, cmd, (char __user *) arg);
  		unlock_kernel();
  		break;
  	default:
  		ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
  	}
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
  }
68f66feb3   Stephen Tweedie   [PATCH] Fix root ...
330
  EXPORT_SYMBOL_GPL(blkdev_ioctl);