1 /*
2 * Partition table and disk geometry handling
3 *
4 * This obsoletes the partition-handling code in genhd.c:
5 * Userspace can look at a disk in arbitrary format and tell
6 * the kernel what partitions there are on the disk, and how
7 * these should be numbered.
8 * It also allows one to repartition a disk that is being used.
9 *
10 * A single ioctl with lots of subfunctions:
11 *
12 * Device number stuff:
13 * get_whole_disk() (given the device number of a partition, find
14 * the device number of the encompassing disk)
15 * get_all_partitions() (given the device number of a disk, return the
16 * device numbers of all its known partitions)
17 *
18 * Partition stuff:
19 * add_partition()
20 * delete_partition()
21 * test_partition_in_use() (also for test_disk_in_use)
22 *
23 * Geometry stuff:
24 * get_geometry()
25 * set_geometry()
26 * get_bios_drivedata()
27 *
28 * For today, only the partition stuff - aeb, 990515
29 */
30
31 #include <linux/errno.h>
32 #include <linux/fs.h> /* for BLKRASET, ... */
33 #include <linux/sched.h> /* for capable() */
34 #include <linux/blk.h> /* for set_device_ro() */
35 #include <linux/blkpg.h>
36 #include <linux/genhd.h>
37 #include <linux/swap.h> /* for is_swap_partition() */
38 #include <linux/module.h> /* for EXPORT_SYMBOL */
39
40 #include <asm/uaccess.h>
41
42 /*
43 * What is the data describing a partition?
44 *
45 * 1. a device number (kdev_t)
46 * 2. a starting sector and number of sectors (hd_struct)
47 * given in the part[] array of the gendisk structure for the drive.
48 *
49 * The number of sectors is replicated in the sizes[] array of
50 * the gendisk structure for the major, which again is copied to
51 * the blk_size[][] array.
52 * (However, hd_struct has the number of 512-byte sectors,
53 * g->sizes[] and blk_size[][] have the number of 1024-byte blocks.)
54 * Note that several drives may have the same major.
55 */
56
57 /*
58 * Add a partition.
59 *
60 * returns: EINVAL: bad parameters
61 * ENXIO: cannot find drive
62 * EBUSY: proposed partition overlaps an existing one
63 * or has the same number as an existing one
64 * 0: all OK.
65 */
add_partition(kdev_t dev,struct blkpg_partition * p)66 int add_partition(kdev_t dev, struct blkpg_partition *p) {
67 struct gendisk *g;
68 long long ppstart, pplength;
69 long pstart, plength;
70 int i, drive, first_minor, end_minor, minor;
71
72 /* convert bytes to sectors, check for fit in a hd_struct */
73 ppstart = (p->start >> 9);
74 pplength = (p->length >> 9);
75 pstart = ppstart;
76 plength = pplength;
77 if (pstart != ppstart || plength != pplength
78 || pstart < 0 || plength < 0)
79 return -EINVAL;
80
81 /* find the drive major */
82 g = get_gendisk(dev);
83 if (!g)
84 return -ENXIO;
85
86 /* existing drive? */
87 drive = (MINOR(dev) >> g->minor_shift);
88 first_minor = (drive << g->minor_shift);
89 end_minor = first_minor + g->max_p;
90 if (drive >= g->nr_real)
91 return -ENXIO;
92
93 /* drive and partition number OK? */
94 if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
95 return -EINVAL;
96
97 /* partition number in use? */
98 minor = first_minor + p->pno;
99 if (g->part[minor].nr_sects != 0)
100 return -EBUSY;
101
102 /* overlap? */
103 for (i=first_minor+1; i<end_minor; i++)
104 if (!(pstart+plength <= g->part[i].start_sect ||
105 pstart >= g->part[i].start_sect + g->part[i].nr_sects))
106 return -EBUSY;
107
108 /* all seems OK */
109 g->part[minor].start_sect = pstart;
110 g->part[minor].nr_sects = plength;
111 if (g->sizes)
112 g->sizes[minor] = (plength >> (BLOCK_SIZE_BITS - 9));
113 devfs_register_partitions (g, first_minor, 0);
114 return 0;
115 }
116
117 /*
118 * Delete a partition given by partition number
119 *
120 * returns: EINVAL: bad parameters
121 * ENXIO: cannot find partition
122 * EBUSY: partition is busy
123 * 0: all OK.
124 *
125 * Note that the dev argument refers to the entire disk, not the partition.
126 */
del_partition(kdev_t dev,struct blkpg_partition * p)127 int del_partition(kdev_t dev, struct blkpg_partition *p) {
128 struct gendisk *g;
129 kdev_t devp;
130 int drive, first_minor, minor;
131
132 /* find the drive major */
133 g = get_gendisk(dev);
134 if (!g)
135 return -ENXIO;
136
137 /* drive and partition number OK? */
138 drive = (MINOR(dev) >> g->minor_shift);
139 first_minor = (drive << g->minor_shift);
140 if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
141 return -EINVAL;
142
143 /* existing drive and partition? */
144 minor = first_minor + p->pno;
145 if (drive >= g->nr_real || g->part[minor].nr_sects == 0)
146 return -ENXIO;
147
148 /* partition in use? Incomplete check for now. */
149 devp = MKDEV(MAJOR(dev), minor);
150 if (is_mounted(devp) || is_swap_partition(devp))
151 return -EBUSY;
152
153 /* all seems OK */
154 fsync_dev(devp);
155 invalidate_buffers(devp);
156
157 g->part[minor].start_sect = 0;
158 g->part[minor].nr_sects = 0;
159 if (g->sizes)
160 g->sizes[minor] = 0;
161 devfs_register_partitions (g, first_minor, 0);
162
163 return 0;
164 }
165
blkpg_ioctl(kdev_t dev,struct blkpg_ioctl_arg * arg)166 int blkpg_ioctl(kdev_t dev, struct blkpg_ioctl_arg *arg)
167 {
168 struct blkpg_ioctl_arg a;
169 struct blkpg_partition p;
170 int len;
171
172 if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
173 return -EFAULT;
174
175 switch (a.op) {
176 case BLKPG_ADD_PARTITION:
177 case BLKPG_DEL_PARTITION:
178 len = a.datalen;
179 if (len < sizeof(struct blkpg_partition))
180 return -EINVAL;
181 if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
182 return -EFAULT;
183 if (!capable(CAP_SYS_ADMIN))
184 return -EACCES;
185 if (a.op == BLKPG_ADD_PARTITION)
186 return add_partition(dev, &p);
187 else
188 return del_partition(dev, &p);
189 default:
190 return -EINVAL;
191 }
192 }
193
194 /*
195 * Common ioctl's for block devices
196 */
197
blk_ioctl(kdev_t dev,unsigned int cmd,unsigned long arg)198 int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg)
199 {
200 struct gendisk *g;
201 u64 ullval = 0;
202 int intval;
203
204 if (!dev)
205 return -EINVAL;
206
207 switch (cmd) {
208 case BLKROSET:
209 if (!capable(CAP_SYS_ADMIN))
210 return -EACCES;
211 if (get_user(intval, (int *)(arg)))
212 return -EFAULT;
213 set_device_ro(dev, intval);
214 return 0;
215 case BLKROGET:
216 intval = (is_read_only(dev) != 0);
217 return put_user(intval, (int *)(arg));
218
219 case BLKRASET:
220 if(!capable(CAP_SYS_ADMIN))
221 return -EACCES;
222 if(arg > 0xff)
223 return -EINVAL;
224 read_ahead[MAJOR(dev)] = arg;
225 return 0;
226 case BLKRAGET:
227 if (!arg)
228 return -EINVAL;
229 return put_user(read_ahead[MAJOR(dev)], (long *) arg);
230
231 case BLKFLSBUF:
232 if(!capable(CAP_SYS_ADMIN))
233 return -EACCES;
234 fsync_dev(dev);
235 invalidate_buffers(dev);
236 return 0;
237
238 case BLKSSZGET:
239 /* get block device sector size as needed e.g. by fdisk */
240 intval = get_hardsect_size(dev);
241 return put_user(intval, (int *) arg);
242
243 case BLKGETSIZE:
244 case BLKGETSIZE64:
245 g = get_gendisk(dev);
246 if (g)
247 ullval = g->part[MINOR(dev)].nr_sects;
248
249 if (cmd == BLKGETSIZE)
250 return put_user((unsigned long)ullval, (unsigned long *)arg);
251 else
252 return put_user(ullval << 9, (u64 *)arg);
253 #if 0
254 case BLKRRPART: /* Re-read partition tables */
255 if (!capable(CAP_SYS_ADMIN))
256 return -EACCES;
257 return reread_partitions(dev, 1);
258 #endif
259
260 case BLKPG:
261 return blkpg_ioctl(dev, (struct blkpg_ioctl_arg *) arg);
262
263 case BLKELVGET:
264 return blkelvget_ioctl(&blk_get_queue(dev)->elevator,
265 (blkelv_ioctl_arg_t *) arg);
266 case BLKELVSET:
267 return blkelvset_ioctl(&blk_get_queue(dev)->elevator,
268 (blkelv_ioctl_arg_t *) arg);
269
270 case BLKBSZGET:
271 /* get the logical block size (cf. BLKSSZGET) */
272 intval = BLOCK_SIZE;
273 if (blksize_size[MAJOR(dev)])
274 intval = blksize_size[MAJOR(dev)][MINOR(dev)];
275 return put_user (intval, (int *) arg);
276
277 case BLKBSZSET:
278 /* set the logical block size */
279 if (!capable (CAP_SYS_ADMIN))
280 return -EACCES;
281 if (!dev || !arg)
282 return -EINVAL;
283 if (get_user (intval, (int *) arg))
284 return -EFAULT;
285 if (intval > PAGE_SIZE || intval < 512 ||
286 (intval & (intval - 1)))
287 return -EINVAL;
288 if (is_mounted (dev) || is_swap_partition (dev))
289 return -EBUSY;
290 set_blocksize (dev, intval);
291 return 0;
292
293 default:
294 return -EINVAL;
295 }
296 }
297
298 EXPORT_SYMBOL(blk_ioctl);
299