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)
21 * test_partition_in_use() (also for test_disk_in_use)
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
) {
62 for (g
= gendisk_head
; g
; g
= g
->next
)
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
);
75 sprintf (name
, "[dev %s]", kdevname(dev
));
79 return disk_name (hd
, MINOR(dev
), name
); /* routine in genhd.c */
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
91 int add_partition(kdev_t dev
, struct blkpg_partition
*p
) {
93 long long ppstart
, pplength
;
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);
102 if (pstart
!= ppstart
|| plength
!= pplength
103 || pstart
< 0 || plength
< 0)
106 /* find the drive major */
107 g
= get_gendisk(dev
);
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
)
118 /* drive and partition number OK? */
119 if (first_minor
!= MINOR(dev
) || p
->pno
<= 0 || p
->pno
>= g
->max_p
)
122 /* partition number in use? */
123 minor
= first_minor
+ p
->pno
;
124 if (g
->part
[minor
].nr_sects
!= 0)
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
))
134 g
->part
[minor
].start_sect
= pstart
;
135 g
->part
[minor
].nr_sects
= plength
;
137 g
->sizes
[minor
] = (plength
>> (BLOCK_SIZE_BITS
- 9));
142 * Delete a partition given by partition number
144 * returns: EINVAL: bad parameters
145 * ENXIO: cannot find partition
146 * EBUSY: partition is busy
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
) {
154 int drive
, first_minor
, minor
;
156 /* find the drive major */
157 g
= get_gendisk(dev
);
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
)
167 /* existing drive and partition? */
168 minor
= first_minor
+ p
->pno
;
169 if (drive
>= g
->nr_real
|| g
->part
[minor
].nr_sects
== 0)
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
))
180 invalidate_buffers(devp
);
182 g
->part
[minor
].start_sect
= 0;
183 g
->part
[minor
].nr_sects
= 0;
190 int blkpg_ioctl(kdev_t dev
, struct blkpg_ioctl_arg
*arg
)
192 struct blkpg_ioctl_arg a
;
193 struct blkpg_partition p
;
196 if (copy_from_user(&a
, arg
, sizeof(struct blkpg_ioctl_arg
)))
200 case BLKPG_ADD_PARTITION
:
201 case BLKPG_DEL_PARTITION
:
203 if (len
< sizeof(struct blkpg_partition
))
205 if (copy_from_user(&p
, a
.data
, sizeof(struct blkpg_partition
)))
207 if (!capable(CAP_SYS_ADMIN
))
209 if (a
.op
== BLKPG_ADD_PARTITION
)
210 return add_partition(dev
, &p
);
212 return del_partition(dev
, &p
);
219 * Common ioctl's for block devices
222 int blk_ioctl(kdev_t dev
, unsigned int cmd
, unsigned long arg
)
228 if (!capable(CAP_SYS_ADMIN
))
230 if (get_user(intval
, (int *)(arg
)))
232 set_device_ro(dev
, intval
);
235 intval
= (is_read_only(dev
) != 0);
236 return put_user(intval
, (int *)(arg
));
239 if(!capable(CAP_SYS_ADMIN
))
241 if(!dev
|| arg
> 0xff)
243 read_ahead
[MAJOR(dev
)] = arg
;
248 return put_user(read_ahead
[MAJOR(dev
)], (long *) arg
);
251 if(!capable(CAP_SYS_ADMIN
))
256 invalidate_buffers(dev
);
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
);
266 /* Today get_gendisk() requires a linear scan;
267 add this when dev has pointer type. */
268 g
= get_gendisk(dev
);
272 longval
= g
->part
[MINOR(dev
)].nr_sects
;
273 return put_user(longval
, (long *) arg
);
276 case BLKRRPART
: /* Re-read partition tables */
277 if (!capable(CAP_SYS_ADMIN
))
279 return reread_partitions(dev
, 1);
283 return blkpg_ioctl(dev
, (struct blkpg_ioctl_arg
*) arg
);
290 EXPORT_SYMBOL(blk_ioctl
);