added a lot of printk output to ease writing of emulator
[linux-2.4.21-pre4.git] / drivers / block / blkpg.c
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  */
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  */
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
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
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);