direct-io.hg

view xen/drivers/block/blkpg.c @ 875:ad4db8b417c1

bitkeeper revision 1.547 (3fa3dd2aH8eamu3ONvYovJgq8wBNbQ)

Many files:
Fixes to the DOM0 interface and domain building code. Ready for new save/restore dom0_ops.
author kaf24@scramble.cl.cam.ac.uk
date Sat Nov 01 16:19:54 2003 +0000 (2003-11-01)
parents 170eb7974e43
children 9f85adafc1e1
line source
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 */
31 #include <xeno/config.h>
32 #include <xeno/types.h>
33 #include <xeno/errno.h>
34 /*#include <xeno/fs.h> */ /* for BLKRASET, ... */
35 #include <xeno/sched.h> /* for capable() */
36 #include <xeno/blk.h> /* for set_device_ro() */
37 #include <xeno/blkpg.h>
38 #include <xeno/genhd.h>
39 /*#include <xeno/swap.h>*/ /* for is_swap_partition() */
40 #include <xeno/module.h> /* for EXPORT_SYMBOL */
42 #include <asm/uaccess.h>
44 #define is_mounted(_dev) (0)
45 #define is_swap_partition(_dev) (0)
47 #define fsync_dev(_dev) (panic("fsync_dev???"))
48 #define invalidate_buffers(_dev) (panic("invalidate_buffers???"))
50 /*
51 * What is the data describing a partition?
52 *
53 * 1. a device number (kdev_t)
54 * 2. a starting sector and number of sectors (hd_struct)
55 * given in the part[] array of the gendisk structure for the drive.
56 *
57 * The number of sectors is replicated in the sizes[] array of
58 * the gendisk structure for the major, which again is copied to
59 * the blk_size[][] array.
60 * (However, hd_struct has the number of 512-byte sectors,
61 * g->sizes[] and blk_size[][] have the number of 1024-byte blocks.)
62 * Note that several drives may have the same major.
63 */
65 /*
66 * Add a partition.
67 *
68 * returns: EINVAL: bad parameters
69 * ENXIO: cannot find drive
70 * EBUSY: proposed partition overlaps an existing one
71 * or has the same number as an existing one
72 * 0: all OK.
73 */
74 int add_partition(kdev_t dev, struct blkpg_partition *p) {
75 struct gendisk *g;
76 long long ppstart, pplength;
77 long pstart, plength;
78 int i, drive, first_minor, end_minor, minor;
80 /* convert bytes to sectors, check for fit in a hd_struct */
81 ppstart = (p->start >> 9);
82 pplength = (p->length >> 9);
83 pstart = ppstart;
84 plength = pplength;
85 if (pstart != ppstart || plength != pplength
86 || pstart < 0 || plength < 0)
87 return -EINVAL;
89 /* find the drive major */
90 g = get_gendisk(dev);
91 if (!g)
92 return -ENXIO;
94 /* existing drive? */
95 drive = (MINOR(dev) >> g->minor_shift);
96 first_minor = (drive << g->minor_shift);
97 end_minor = first_minor + g->max_p;
98 if (drive >= g->nr_real)
99 return -ENXIO;
101 /* drive and partition number OK? */
102 if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
103 return -EINVAL;
105 /* partition number in use? */
106 minor = first_minor + p->pno;
107 if (g->part[minor].nr_sects != 0)
108 return -EBUSY;
110 /* overlap? */
111 for (i=first_minor+1; i<end_minor; i++)
112 if (!(pstart+plength <= g->part[i].start_sect ||
113 pstart >= g->part[i].start_sect + g->part[i].nr_sects))
114 return -EBUSY;
116 /* all seems OK */
117 g->part[minor].start_sect = pstart;
118 g->part[minor].nr_sects = plength;
119 if (g->sizes)
120 g->sizes[minor] = (plength >> (BLOCK_SIZE_BITS - 9));
121 #ifdef DEVFS_MUST_DIE
122 devfs_register_partitions (g, first_minor, 0);
123 #endif
124 return 0;
125 }
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;
142 /* find the drive major */
143 g = get_gendisk(dev);
144 if (!g)
145 return -ENXIO;
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;
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;
158 /* partition in use? Incomplete check for now. */
159 devp = MKDEV(MAJOR(dev), minor);
160 if (is_mounted(devp) || is_swap_partition(devp))
161 return -EBUSY;
163 /* all seems OK */
164 fsync_dev(devp);
165 invalidate_buffers(devp);
167 g->part[minor].start_sect = 0;
168 g->part[minor].nr_sects = 0;
169 if (g->sizes)
170 g->sizes[minor] = 0;
171 #ifdef DEVFS_MUST_DIE
172 devfs_register_partitions (g, first_minor, 0);
173 #endif
175 return 0;
176 }
178 int blkpg_ioctl(kdev_t dev, struct blkpg_ioctl_arg *arg)
179 {
180 struct blkpg_ioctl_arg a;
181 struct blkpg_partition p;
182 int len;
184 if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
185 return -EFAULT;
187 switch (a.op) {
188 case BLKPG_ADD_PARTITION:
189 case BLKPG_DEL_PARTITION:
190 len = a.datalen;
191 if (len < sizeof(struct blkpg_partition))
192 return -EINVAL;
193 if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
194 return -EFAULT;
195 if (!capable(CAP_SYS_ADMIN))
196 return -EACCES;
197 if (a.op == BLKPG_ADD_PARTITION)
198 return add_partition(dev, &p);
199 else
200 return del_partition(dev, &p);
201 default:
202 return -EINVAL;
203 }
204 }
206 /*
207 * Common ioctl's for block devices
208 */
210 int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg)
211 {
212 #if 1
213 printk("May want to check out blk_ioctl...\n");
214 return -EINVAL;
215 #else
216 struct gendisk *g;
217 u64 ullval = 0;
218 int intval;
220 if (!dev)
221 return -EINVAL;
223 switch (cmd) {
224 case BLKROSET:
225 if (!capable(CAP_SYS_ADMIN))
226 return -EACCES;
227 if (get_user(intval, (int *)(arg)))
228 return -EFAULT;
229 set_device_ro(dev, intval);
230 return 0;
231 case BLKROGET:
232 intval = (is_read_only(dev) != 0);
233 return put_user(intval, (int *)(arg));
235 case BLKRASET:
236 if(!capable(CAP_SYS_ADMIN))
237 return -EACCES;
238 if(arg > 0xff)
239 return -EINVAL;
240 read_ahead[MAJOR(dev)] = arg;
241 return 0;
242 case BLKRAGET:
243 if (!arg)
244 return -EINVAL;
245 return put_user(read_ahead[MAJOR(dev)], (long *) arg);
247 case BLKFLSBUF:
248 if(!capable(CAP_SYS_ADMIN))
249 return -EACCES;
250 fsync_dev(dev);
251 invalidate_buffers(dev);
252 return 0;
254 case BLKSSZGET:
255 /* get block device sector size as needed e.g. by fdisk */
256 intval = get_hardsect_size(dev);
257 return put_user(intval, (int *) arg);
259 case BLKGETSIZE:
260 case BLKGETSIZE64:
261 g = get_gendisk(dev);
262 if (g)
263 ullval = g->part[MINOR(dev)].nr_sects;
265 if (cmd == BLKGETSIZE)
266 return put_user((unsigned long)ullval, (unsigned long *)arg);
267 else
268 return put_user(ullval << 9, (u64 *)arg);
269 #if 0
270 case BLKRRPART: /* Re-read partition tables */
271 if (!capable(CAP_SYS_ADMIN))
272 return -EACCES;
273 return reread_partitions(dev, 1);
274 #endif
276 case BLKPG:
277 return blkpg_ioctl(dev, (struct blkpg_ioctl_arg *) arg);
279 case BLKELVGET:
280 return blkelvget_ioctl(&blk_get_queue(dev)->elevator,
281 (blkelv_ioctl_arg_t *) arg);
282 case BLKELVSET:
283 return blkelvset_ioctl(&blk_get_queue(dev)->elevator,
284 (blkelv_ioctl_arg_t *) arg);
286 case BLKBSZGET:
287 /* get the logical block size (cf. BLKSSZGET) */
288 intval = BLOCK_SIZE;
289 if (blksize_size[MAJOR(dev)])
290 intval = blksize_size[MAJOR(dev)][MINOR(dev)];
291 return put_user (intval, (int *) arg);
293 case BLKBSZSET:
294 /* set the logical block size */
295 if (!capable (CAP_SYS_ADMIN))
296 return -EACCES;
297 if (!dev || !arg)
298 return -EINVAL;
299 if (get_user (intval, (int *) arg))
300 return -EFAULT;
301 if (intval > PAGE_SIZE || intval < 512 ||
302 (intval & (intval - 1)))
303 return -EINVAL;
304 if (is_mounted (dev) || is_swap_partition (dev))
305 return -EBUSY;
306 set_blocksize (dev, intval);
307 return 0;
309 default:
310 return -EINVAL;
311 }
312 #endif
313 }
315 EXPORT_SYMBOL(blk_ioctl);