File: /usr/src/linux/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     	return 0;
114     }
115     
116     /*
117      * Delete a partition given by partition number
118      *
119      * returns: EINVAL: bad parameters
120      *          ENXIO: cannot find partition
121      *          EBUSY: partition is busy
122      *          0: all OK.
123      *
124      * Note that the dev argument refers to the entire disk, not the partition.
125      */
126     int del_partition(kdev_t dev, struct blkpg_partition *p) {
127     	struct gendisk *g;
128     	kdev_t devp;
129     	int drive, first_minor, minor;
130     
131     	/* find the drive major */
132     	g = get_gendisk(dev);
133     	if (!g)
134     		return -ENXIO;
135     
136     	/* drive and partition number OK? */
137     	drive = (MINOR(dev) >> g->minor_shift);
138     	first_minor = (drive << g->minor_shift);
139     	if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
140     		return -EINVAL;
141     
142     	/* existing drive and partition? */
143     	minor = first_minor + p->pno;
144     	if (drive >= g->nr_real || g->part[minor].nr_sects == 0)
145     		return -ENXIO;
146     
147     	/* partition in use? Incomplete check for now. */
148     	devp = MKDEV(MAJOR(dev), minor);
149     	if (is_mounted(devp) || is_swap_partition(devp))
150     		return -EBUSY;
151     
152     	/* all seems OK */
153     	fsync_dev(devp);
154     	invalidate_buffers(devp);
155     
156     	g->part[minor].start_sect = 0;
157     	g->part[minor].nr_sects = 0;
158     	if (g->sizes)
159     		g->sizes[minor] = 0;
160     
161     	return 0;
162     }
163     
164     int blkpg_ioctl(kdev_t dev, struct blkpg_ioctl_arg *arg)
165     {
166     	struct blkpg_ioctl_arg a;
167     	struct blkpg_partition p;
168     	int len;
169     
170     	if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
171     		return -EFAULT;
172     
173     	switch (a.op) {
174     		case BLKPG_ADD_PARTITION:
175     		case BLKPG_DEL_PARTITION:
176     			len = a.datalen;
177     			if (len < sizeof(struct blkpg_partition))
178     				return -EINVAL;
179     			if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
180     				return -EFAULT;
181     			if (!capable(CAP_SYS_ADMIN))
182     				return -EACCES;
183     			if (a.op == BLKPG_ADD_PARTITION)
184     				return add_partition(dev, &p);
185     			else
186     				return del_partition(dev, &p);
187     		default:
188     			return -EINVAL;
189     	}
190     }
191     
192     /*
193      * Common ioctl's for block devices
194      */
195     
196     int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg)
197     {
198     	int intval;
199     
200     	switch (cmd) {
201     		case BLKROSET:
202     			if (!capable(CAP_SYS_ADMIN))
203     				return -EACCES;
204     			if (get_user(intval, (int *)(arg)))
205     				return -EFAULT;
206     			set_device_ro(dev, intval);
207     			return 0;
208     		case BLKROGET:
209     			intval = (is_read_only(dev) != 0);
210     			return put_user(intval, (int *)(arg));
211     
212     		case BLKRASET:
213     			if(!capable(CAP_SYS_ADMIN))
214     				return -EACCES;
215     			if(!dev || arg > 0xff)
216     				return -EINVAL;
217     			read_ahead[MAJOR(dev)] = arg;
218     			return 0;
219     		case BLKRAGET:
220     			if (!arg)
221     				return -EINVAL;
222     			return put_user(read_ahead[MAJOR(dev)], (long *) arg);
223     
224     		case BLKFLSBUF:
225     			if(!capable(CAP_SYS_ADMIN))
226     				return -EACCES;
227     			if (!dev)
228     				return -EINVAL;
229     			fsync_dev(dev);
230     			invalidate_buffers(dev);
231     			return 0;
232     
233     		case BLKSSZGET:
234     			/* get block device sector size as needed e.g. by fdisk */
235     			intval = get_hardsect_size(dev);
236     			return put_user(intval, (int *) arg);
237     
238     #if 0
239     		case BLKGETSIZE:
240     			/* Today get_gendisk() requires a linear scan;
241     			   add this when dev has pointer type. */
242     			/* add BLKGETSIZE64 too */
243     			g = get_gendisk(dev);
244     			if (!g)
245     				longval = 0;
246     			else
247     				longval = g->part[MINOR(dev)].nr_sects;
248     			return put_user(longval, (long *) arg);
249     #endif
250     #if 0
251     		case BLKRRPART: /* Re-read partition tables */
252     			if (!capable(CAP_SYS_ADMIN)) 
253     				return -EACCES;
254     			return reread_partitions(dev, 1);
255     #endif
256     
257     		case BLKPG:
258     			return blkpg_ioctl(dev, (struct blkpg_ioctl_arg *) arg);
259     			
260     		case BLKELVGET:
261     			return blkelvget_ioctl(&blk_get_queue(dev)->elevator,
262     					       (blkelv_ioctl_arg_t *) arg);
263     		case BLKELVSET:
264     			return blkelvset_ioctl(&blk_get_queue(dev)->elevator,
265     					       (blkelv_ioctl_arg_t *) arg);
266     
267     		case BLKBSZGET:
268     			/* get the logical block size (cf. BLKSSZGET) */
269     			intval = BLOCK_SIZE;
270     			if (blksize_size[MAJOR(dev)])
271     				intval = blksize_size[MAJOR(dev)][MINOR(dev)];
272     			return put_user (intval, (int *) arg);
273     
274     		case BLKBSZSET:
275     			/* set the logical block size */
276     			if (!capable (CAP_SYS_ADMIN))
277     				return -EACCES;
278     			if (!dev || !arg)
279     				return -EINVAL;
280     			if (get_user (intval, (int *) arg))
281     				return -EFAULT;
282     			if (intval > PAGE_SIZE || intval < 512 ||
283     			    (intval & (intval - 1)))
284     				return -EINVAL;
285     			if (is_mounted (dev) || is_swap_partition (dev))
286     				return -EBUSY;
287     			set_blocksize (dev, intval);
288     			return 0;
289     
290     		default:
291     			return -EINVAL;
292     	}
293     }
294     
295     EXPORT_SYMBOL(blk_ioctl);
296