Blame view

block/ioctl.c 7 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
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  #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;
  	struct blkpg_ioctl_arg a;
  	struct blkpg_partition p;
  	long long start, length;
  	int part;
  	int i;
  
  	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;
  	part = p.pno;
  	if (part <= 0 || part >= disk->minors)
  		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;
  			}
  			/* partition number in use? */
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
46
  			mutex_lock(&bdev->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  			if (disk->part[part - 1]) {
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
48
  				mutex_unlock(&bdev->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
53
54
55
56
57
58
  				return -EBUSY;
  			}
  			/* overlap? */
  			for (i = 0; i < disk->minors - 1; i++) {
  				struct hd_struct *s = disk->part[i];
  
  				if (!s)
  					continue;
  				if (!(start+length <= s->start_sect ||
  				      start >= s->start_sect + s->nr_sects)) {
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
59
  					mutex_unlock(&bdev->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
63
  					return -EBUSY;
  				}
  			}
  			/* all seems OK */
d18d7682c   Fabio Massimo Di Nitto   [PARTITION]: Add ...
64
  			add_partition(disk, part, start, length, ADDPART_FLAG_NONE);
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
65
  			mutex_unlock(&bdev->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
68
69
70
71
72
73
74
  			return 0;
  		case BLKPG_DEL_PARTITION:
  			if (!disk->part[part-1])
  				return -ENXIO;
  			if (disk->part[part - 1]->nr_sects == 0)
  				return -ENXIO;
  			bdevp = bdget_disk(disk, part);
  			if (!bdevp)
  				return -ENOMEM;
2e7b651df   Peter Zijlstra   [PATCH] remove th...
75
  			mutex_lock(&bdevp->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
  			if (bdevp->bd_openers) {
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
77
  				mutex_unlock(&bdevp->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
80
81
82
  				bdput(bdevp);
  				return -EBUSY;
  			}
  			/* all seems OK */
  			fsync_bdev(bdevp);
f98393a64   Peter Zijlstra   mm: remove destro...
83
  			invalidate_bdev(bdevp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84

6d740cd5b   Peter Zijlstra   [PATCH] lockdep: ...
85
  			mutex_lock_nested(&bdev->bd_mutex, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
  			delete_partition(disk, part);
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
87
88
  			mutex_unlock(&bdev->bd_mutex);
  			mutex_unlock(&bdevp->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  			bdput(bdevp);
  
  			return 0;
  		default:
  			return -EINVAL;
  	}
  }
  
  static int blkdev_reread_part(struct block_device *bdev)
  {
  	struct gendisk *disk = bdev->bd_disk;
  	int res;
  
  	if (disk->minors == 1 || bdev != bdev->bd_contains)
  		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
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
  	return res;
  }
  
  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);
  }
  
  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);
  }
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
137
138
  static int blkdev_locked_ioctl(struct file *file, struct block_device *bdev,
  				unsigned cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
  	struct backing_dev_info *bdi;
  	int ret, n;
  
  	switch (cmd) {
  	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);
  	case BLKBSZGET: /* get the logical block size (cf. BLKSSZGET) */
  		return put_int(arg, block_size(bdev));
  	case BLKSSZGET: /* get block device hardware sector size */
  		return put_int(arg, bdev_hardsect_size(bdev));
  	case BLKSECTGET:
  		return put_ushort(arg, bdev_get_queue(bdev)->max_sectors);
  	case BLKRASET:
  	case BLKFRASET:
  		if(!capable(CAP_SYS_ADMIN))
  			return -EACCES;
  		bdi = blk_get_backing_dev_info(bdev);
  		if (bdi == NULL)
  			return -ENOTTY;
  		bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
  		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;
  		if (bd_claim(bdev, file) < 0)
  			return -EBUSY;
  		ret = set_blocksize(bdev, n);
  		bd_release(bdev);
  		return ret;
  	case BLKPG:
  		return blkpg_ioctl(bdev, (struct blkpg_ioctl_arg __user *) arg);
  	case BLKRRPART:
  		return blkdev_reread_part(bdev);
  	case BLKGETSIZE:
  		if ((bdev->bd_inode->i_size >> 9) > ~0UL)
  			return -EFBIG;
  		return put_ulong(arg, bdev->bd_inode->i_size >> 9);
  	case BLKGETSIZE64:
  		return put_u64(arg, bdev->bd_inode->i_size);
2056a782f   Jens Axboe   [PATCH] Block que...
192
193
194
195
196
  	case BLKTRACESTART:
  	case BLKTRACESTOP:
  	case BLKTRACESETUP:
  	case BLKTRACETEARDOWN:
  		return blk_trace_ioctl(bdev, cmd, (char __user *) arg);
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
197
198
199
  	}
  	return -ENOIOCTLCMD;
  }
7006f6eca   Alasdair G Kergon   [PATCH] dm: expor...
200
201
  int blkdev_driver_ioctl(struct inode *inode, struct file *file,
  			struct gendisk *disk, unsigned cmd, unsigned long arg)
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
  {
  	int ret;
  	if (disk->fops->unlocked_ioctl)
  		return disk->fops->unlocked_ioctl(file, cmd, arg);
  
  	if (disk->fops->ioctl) {
  		lock_kernel();
  		ret = disk->fops->ioctl(inode, file, cmd, arg);
  		unlock_kernel();
  		return ret;
  	}
  
  	return -ENOTTY;
  }
7006f6eca   Alasdair G Kergon   [PATCH] dm: expor...
216
  EXPORT_SYMBOL_GPL(blkdev_driver_ioctl);
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
217

f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
218
219
220
221
  /*
   * always keep this in sync with compat_blkdev_ioctl() and
   * compat_blkdev_locked_ioctl()
   */
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
222
223
224
225
226
227
228
229
  int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
  			unsigned long arg)
  {
  	struct block_device *bdev = inode->i_bdev;
  	struct gendisk *disk = bdev->bd_disk;
  	int ret, n;
  
  	switch(cmd) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
232
  	case BLKFLSBUF:
  		if (!capable(CAP_SYS_ADMIN))
  			return -EACCES;
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
233
234
235
236
237
238
239
  
  		ret = blkdev_driver_ioctl(inode, file, disk, cmd, arg);
  		/* -EINVAL to handle old uncorrected drivers */
  		if (ret != -EINVAL && ret != -ENOTTY)
  			return ret;
  
  		lock_kernel();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  		fsync_bdev(bdev);
f98393a64   Peter Zijlstra   mm: remove destro...
241
  		invalidate_bdev(bdev);
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
242
  		unlock_kernel();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
  		return 0;
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
244

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
  	case BLKROSET:
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
246
247
248
249
  		ret = blkdev_driver_ioctl(inode, file, disk, cmd, arg);
  		/* -EINVAL to handle old uncorrected drivers */
  		if (ret != -EINVAL && ret != -ENOTTY)
  			return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
252
253
  		if (!capable(CAP_SYS_ADMIN))
  			return -EACCES;
  		if (get_user(n, (int __user *)(arg)))
  			return -EFAULT;
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
254
  		lock_kernel();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
  		set_device_ro(bdev, n);
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
256
  		unlock_kernel();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
  		return 0;
a885c8c43   Christoph Hellwig   [PATCH] Add block...
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
  	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;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
  	}
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
280
281
282
283
284
285
286
287
  
  	lock_kernel();
  	ret = blkdev_locked_ioctl(file, bdev, cmd, arg);
  	unlock_kernel();
  	if (ret != -ENOIOCTLCMD)
  		return ret;
  
  	return blkdev_driver_ioctl(inode, file, disk, cmd, arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
  }
68f66feb3   Stephen Tweedie   [PATCH] Fix root ...
289
  EXPORT_SYMBOL_GPL(blkdev_ioctl);