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 /* a linear search, superfluous when dev is a pointer */
58 static struct gendisk *get_gendisk(kdev_t dev) {
59 struct gendisk *g;
60 int m = MAJOR(dev);
61
62 for (g = gendisk_head; g; g = g->next)
63 if (g->major == m)
64 break;
65 return g;
66 }
67
68 /*
69 * Add a partition.
70 *
71 * returns: EINVAL: bad parameters
72 * ENXIO: cannot find drive
73 * EBUSY: proposed partition overlaps an existing one
74 * or has the same number as an existing one
75 * 0: all OK.
76 */
77 int add_partition(kdev_t dev, struct blkpg_partition *p) {
78 struct gendisk *g;
79 long long ppstart, pplength;
80 long pstart, plength;
81 int i, drive, first_minor, end_minor, minor;
82
83 /* convert bytes to sectors, check for fit in a hd_struct */
84 ppstart = (p->start >> 9);
85 pplength = (p->length >> 9);
86 pstart = ppstart;
87 plength = pplength;
88 if (pstart != ppstart || plength != pplength
89 || pstart < 0 || plength < 0)
90 return -EINVAL;
91
92 /* find the drive major */
93 g = get_gendisk(dev);
94 if (!g)
95 return -ENXIO;
96
97 /* existing drive? */
98 drive = (MINOR(dev) >> g->minor_shift);
99 first_minor = (drive << g->minor_shift);
100 end_minor = first_minor + g->max_p;
101 if (drive >= g->nr_real)
102 return -ENXIO;
103
104 /* drive and partition number OK? */
105 if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
106 return -EINVAL;
107
108 /* partition number in use? */
109 minor = first_minor + p->pno;
110 if (g->part[minor].nr_sects != 0)
111 return -EBUSY;
112
113 /* overlap? */
114 for (i=first_minor+1; i<end_minor; i++)
115 if (!(pstart+plength <= g->part[i].start_sect ||
116 pstart >= g->part[i].start_sect + g->part[i].nr_sects))
117 return -EBUSY;
118
119 /* all seems OK */
120 g->part[minor].start_sect = pstart;
121 g->part[minor].nr_sects = plength;
122 if (g->sizes)
123 g->sizes[minor] = (plength >> (BLOCK_SIZE_BITS - 9));
124 return 0;
125 }
126
127 /*
128 * Delete a partition given by partition number
129 *
130 * returns: EINVAL: bad parameters
131 * ENXIO: cannot find partition
132 * EBUSY: partition is busy
133 * 0: all OK.
134 *
135 * Note that the dev argument refers to the entire disk, not the partition.
136 */
137 int del_partition(kdev_t dev, struct blkpg_partition *p) {
138 struct gendisk *g;
139 kdev_t devp;
140 int drive, first_minor, minor;
141
142 /* find the drive major */
143 g = get_gendisk(dev);
144 if (!g)
145 return -ENXIO;
146
147 /* drive and partition number OK? */
148 drive = (MINOR(dev) >> g->minor_shift);
149 first_minor = (drive << g->minor_shift);
150 if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
151 return -EINVAL;
152
153 /* existing drive and partition? */
154 minor = first_minor + p->pno;
155 if (drive >= g->nr_real || g->part[minor].nr_sects == 0)
156 return -ENXIO;
157
158 /* partition in use? Incomplete check for now. */
159 devp = MKDEV(MAJOR(dev), minor);
160 if (get_super(devp) || /* mounted? */
161 is_swap_partition(devp))
162 return -EBUSY;
163
164 /* all seems OK */
165 fsync_dev(devp);
166 invalidate_buffers(devp);
167
168 g->part[minor].start_sect = 0;
169 g->part[minor].nr_sects = 0;
170 if (g->sizes)
171 g->sizes[minor] = 0;
172
173 return 0;
174 }
175
176 int blkpg_ioctl(kdev_t dev, struct blkpg_ioctl_arg *arg)
177 {
178 struct blkpg_ioctl_arg a;
179 struct blkpg_partition p;
180 int len;
181
182 if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
183 return -EFAULT;
184
185 switch (a.op) {
186 case BLKPG_ADD_PARTITION:
187 case BLKPG_DEL_PARTITION:
188 len = a.datalen;
189 if (len < sizeof(struct blkpg_partition))
190 return -EINVAL;
191 if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
192 return -EFAULT;
193 if (!capable(CAP_SYS_ADMIN))
194 return -EACCES;
195 if (a.op == BLKPG_ADD_PARTITION)
196 return add_partition(dev, &p);
197 else
198 return del_partition(dev, &p);
199 default:
200 return -EINVAL;
201 }
202 }
203
204 /*
205 * Common ioctl's for block devices
206 */
207
208 int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg)
209 {
210 int intval;
211
212 switch (cmd) {
213 case BLKROSET:
214 if (!capable(CAP_SYS_ADMIN))
215 return -EACCES;
216 if (get_user(intval, (int *)(arg)))
217 return -EFAULT;
218 set_device_ro(dev, intval);
219 return 0;
220 case BLKROGET:
221 intval = (is_read_only(dev) != 0);
222 return put_user(intval, (int *)(arg));
223
224 case BLKRASET:
225 if(!capable(CAP_SYS_ADMIN))
226 return -EACCES;
227 if(!dev || arg > 0xff)
228 return -EINVAL;
229 read_ahead[MAJOR(dev)] = arg;
230 return 0;
231 case BLKRAGET:
232 if (!arg)
233 return -EINVAL;
234 return put_user(read_ahead[MAJOR(dev)], (long *) arg);
235
236 case BLKFLSBUF:
237 if(!capable(CAP_SYS_ADMIN))
238 return -EACCES;
239 if (!dev)
240 return -EINVAL;
241 fsync_dev(dev);
242 invalidate_buffers(dev);
243 return 0;
244
245 case BLKSSZGET:
246 /* get block device sector size as needed e.g. by fdisk */
247 intval = get_hardsect_size(dev);
248 return put_user(intval, (int *) arg);
249
250 #if 0
251 case BLKGETSIZE:
252 /* Today get_gendisk() requires a linear scan;
253 add this when dev has pointer type. */
254 g = get_gendisk(dev);
255 if (!g)
256 longval = 0;
257 else
258 longval = g->part[MINOR(dev)].nr_sects;
259 return put_user(longval, (long *) arg);
260 #endif
261 #if 0
262 case BLKRRPART: /* Re-read partition tables */
263 if (!capable(CAP_SYS_ADMIN))
264 return -EACCES;
265 return reread_partitions(dev, 1);
266 #endif
267
268 case BLKPG:
269 return blkpg_ioctl(dev, (struct blkpg_ioctl_arg *) arg);
270
271 case BLKELVGET:
272 return blkelvget_ioctl(&blk_get_queue(dev)->elevator,
273 (blkelv_ioctl_arg_t *) arg);
274 case BLKELVSET:
275 return blkelvset_ioctl(&blk_get_queue(dev)->elevator,
276 (blkelv_ioctl_arg_t *) arg);
277
278 default:
279 return -EINVAL;
280 }
281 }
282
283 EXPORT_SYMBOL(blk_ioctl);
284
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.