Import 2.3.9pre5
[davej-history.git] / drivers / block / blkpg.c
blob6f56740729220f2fb239f07b62a16ff72383cc4f
1 /*
2 * Partition table and disk geometry handling
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.
10 * A single ioctl with lots of subfunctions:
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)
18 * Partition stuff:
19 * add_partition()
20 * delete_partition()
21 * test_partition_in_use() (also for test_disk_in_use)
23 * Geometry stuff:
24 * get_geometry()
25 * set_geometry()
26 * get_bios_drivedata()
28 * For today, only the partition stuff - aeb, 990515
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 */
40 #include <asm/uaccess.h>
43 * What is the data describing a partition?
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.
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.
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);
62 for (g = gendisk_head; g; g = g->next)
63 if (g->major == m)
64 break;
65 return g;
68 /* moved here from md.c - will be discarded later */
69 char *partition_name (kdev_t dev) {
70 static char name[40]; /* kdevname returns 32 bytes */
71 /* disk_name requires 32 bytes */
72 struct gendisk *hd = get_gendisk (dev);
74 if (!hd) {
75 sprintf (name, "[dev %s]", kdevname(dev));
76 return (name);
79 return disk_name (hd, MINOR(dev), name); /* routine in genhd.c */
83 * Add a partition.
85 * returns: EINVAL: bad parameters
86 * ENXIO: cannot find drive
87 * EBUSY: proposed partition overlaps an existing one
88 * or has the same number as an existing one
89 * 0: all OK.
91 int add_partition(kdev_t dev, struct blkpg_partition *p) {
92 struct gendisk *g;
93 long long ppstart, pplength;
94 long pstart, plength;
95 int i, drive, first_minor, end_minor, minor;
97 /* convert bytes to sectors, check for fit in a hd_struct */
98 ppstart = (p->start >> 9);
99 pplength = (p->length >> 9);
100 pstart = ppstart;
101 plength = pplength;
102 if (pstart != ppstart || plength != pplength
103 || pstart < 0 || plength < 0)
104 return -EINVAL;
106 /* find the drive major */
107 g = get_gendisk(dev);
108 if (!g)
109 return -ENXIO;
111 /* existing drive? */
112 drive = (MINOR(dev) >> g->minor_shift);
113 first_minor = (drive << g->minor_shift);
114 end_minor = first_minor + g->max_p;
115 if (drive >= g->nr_real)
116 return -ENXIO;
118 /* drive and partition number OK? */
119 if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
120 return -EINVAL;
122 /* partition number in use? */
123 minor = first_minor + p->pno;
124 if (g->part[minor].nr_sects != 0)
125 return -EBUSY;
127 /* overlap? */
128 for (i=first_minor+1; i<end_minor; i++)
129 if (!(pstart+plength <= g->part[i].start_sect ||
130 pstart >= g->part[i].start_sect + g->part[i].nr_sects))
131 return -EBUSY;
133 /* all seems OK */
134 g->part[minor].start_sect = pstart;
135 g->part[minor].nr_sects = plength;
136 if (g->sizes)
137 g->sizes[minor] = (plength >> (BLOCK_SIZE_BITS - 9));
138 return 0;
142 * Delete a partition given by partition number
144 * returns: EINVAL: bad parameters
145 * ENXIO: cannot find partition
146 * EBUSY: partition is busy
147 * 0: all OK.
149 * Note that the dev argument refers to the entire disk, not the partition.
151 int del_partition(kdev_t dev, struct blkpg_partition *p) {
152 struct gendisk *g;
153 kdev_t devp;
154 int drive, first_minor, minor;
156 /* find the drive major */
157 g = get_gendisk(dev);
158 if (!g)
159 return -ENXIO;
161 /* drive and partition number OK? */
162 drive = (MINOR(dev) >> g->minor_shift);
163 first_minor = (drive << g->minor_shift);
164 if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
165 return -EINVAL;
167 /* existing drive and partition? */
168 minor = first_minor + p->pno;
169 if (drive >= g->nr_real || g->part[minor].nr_sects == 0)
170 return -ENXIO;
172 /* partition in use? Incomplete check for now. */
173 devp = MKDEV(MAJOR(dev), minor);
174 if (get_super(devp) || /* mounted? */
175 is_swap_partition(devp))
176 return -EBUSY;
178 /* all seems OK */
179 fsync_dev(devp);
180 invalidate_buffers(devp);
182 g->part[minor].start_sect = 0;
183 g->part[minor].nr_sects = 0;
184 if (g->sizes)
185 g->sizes[minor] = 0;
187 return 0;
190 int blkpg_ioctl(kdev_t dev, struct blkpg_ioctl_arg *arg)
192 struct blkpg_ioctl_arg a;
193 struct blkpg_partition p;
194 int len;
196 if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
197 return -EFAULT;
199 switch (a.op) {
200 case BLKPG_ADD_PARTITION:
201 case BLKPG_DEL_PARTITION:
202 len = a.datalen;
203 if (len < sizeof(struct blkpg_partition))
204 return -EINVAL;
205 if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
206 return -EFAULT;
207 if (!capable(CAP_SYS_ADMIN))
208 return -EACCES;
209 if (a.op == BLKPG_ADD_PARTITION)
210 return add_partition(dev, &p);
211 else
212 return del_partition(dev, &p);
213 default:
214 return -EINVAL;
219 * Common ioctl's for block devices
222 int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg)
224 int intval;
226 switch (cmd) {
227 case BLKROSET:
228 if (!capable(CAP_SYS_ADMIN))
229 return -EACCES;
230 if (get_user(intval, (int *)(arg)))
231 return -EFAULT;
232 set_device_ro(dev, intval);
233 return 0;
234 case BLKROGET:
235 intval = (is_read_only(dev) != 0);
236 return put_user(intval, (int *)(arg));
238 case BLKRASET:
239 if(!capable(CAP_SYS_ADMIN))
240 return -EACCES;
241 if(!dev || arg > 0xff)
242 return -EINVAL;
243 read_ahead[MAJOR(dev)] = arg;
244 return 0;
245 case BLKRAGET:
246 if (!arg)
247 return -EINVAL;
248 return put_user(read_ahead[MAJOR(dev)], (long *) arg);
250 case BLKFLSBUF:
251 if(!capable(CAP_SYS_ADMIN))
252 return -EACCES;
253 if (!dev)
254 return -EINVAL;
255 fsync_dev(dev);
256 invalidate_buffers(dev);
257 return 0;
259 case BLKSSZGET:
260 /* get block device sector size as needed e.g. by fdisk */
261 intval = get_hardsect_size(dev);
262 return put_user(intval, (int *) arg);
264 #if 0
265 case BLKGETSIZE:
266 /* Today get_gendisk() requires a linear scan;
267 add this when dev has pointer type. */
268 g = get_gendisk(dev);
269 if (!g)
270 longval = 0;
271 else
272 longval = g->part[MINOR(dev)].nr_sects;
273 return put_user(longval, (long *) arg);
274 #endif
275 #if 0
276 case BLKRRPART: /* Re-read partition tables */
277 if (!capable(CAP_SYS_ADMIN))
278 return -EACCES;
279 return reread_partitions(dev, 1);
280 #endif
282 case BLKPG:
283 return blkpg_ioctl(dev, (struct blkpg_ioctl_arg *) arg);
285 default:
286 return -EINVAL;
290 EXPORT_SYMBOL(blk_ioctl);