Blame view

block/ioctl.c 7.01 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
  #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;
04ebd4aee   Abdel Benamrouche   block/ioctl.c and...
20
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
46
  
  	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...
47
  			mutex_lock(&bdev->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
  			if (disk->part[part - 1]) {
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
49
  				mutex_unlock(&bdev->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
53
54
55
56
57
58
59
  				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...
60
  					mutex_unlock(&bdev->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
63
64
  					return -EBUSY;
  				}
  			}
  			/* all seems OK */
04ebd4aee   Abdel Benamrouche   block/ioctl.c and...
65
  			err = add_partition(disk, part, start, length, ADDPART_FLAG_NONE);
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
66
  			mutex_unlock(&bdev->bd_mutex);
04ebd4aee   Abdel Benamrouche   block/ioctl.c and...
67
  			return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
71
72
73
74
75
  		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...
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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
  			delete_partition(disk, part);
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
102
103
104
105
106
  			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...
107
  	if (!mutex_trylock(&bdev->bd_mutex))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
  		return -EBUSY;
  	res = rescan_partitions(disk, bdev);
c039e3134   Arjan van de Ven   [PATCH] sem2mutex...
110
  	mutex_unlock(&bdev->bd_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
  	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...
138
139
  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
140
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
192
  	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...
193
194
195
196
197
  	case BLKTRACESTART:
  	case BLKTRACESTOP:
  	case BLKTRACESETUP:
  	case BLKTRACETEARDOWN:
  		return blk_trace_ioctl(bdev, cmd, (char __user *) arg);
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
198
199
200
  	}
  	return -ENOIOCTLCMD;
  }
7006f6eca   Alasdair G Kergon   [PATCH] dm: expor...
201
202
  int blkdev_driver_ioctl(struct inode *inode, struct file *file,
  			struct gendisk *disk, unsigned cmd, unsigned long arg)
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
  {
  	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...
217
  EXPORT_SYMBOL_GPL(blkdev_driver_ioctl);
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
218

f58c4c0a1   Arnd Bergmann   compat_ioctl: mov...
219
220
221
222
  /*
   * always keep this in sync with compat_blkdev_ioctl() and
   * compat_blkdev_locked_ioctl()
   */
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
223
224
225
226
227
228
229
230
  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
231
232
233
  	case BLKFLSBUF:
  		if (!capable(CAP_SYS_ADMIN))
  			return -EACCES;
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
234
235
236
237
238
239
240
  
  		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
241
  		fsync_bdev(bdev);
f98393a64   Peter Zijlstra   mm: remove destro...
242
  		invalidate_bdev(bdev);
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
243
  		unlock_kernel();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
  		return 0;
bb93e3a52   Arnd Bergmann   [PATCH] block: ad...
245

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