~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/block/blkpg.c

Version: ~ [ 2.2.5 ] ~ [ 2.4.1 ] ~ [ 2.4.9 ] ~ [ 2.6.17.10 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.