Import 2.3.99pre10-3
[davej-history.git] / fs / partitions / check.c
blob4fda5fd5c06e30f767e565bd5d497a9ac244c86d
1 /*
2 * Code extracted from drivers/block/genhd.c
3 * Copyright (C) 1991-1998 Linus Torvalds
4 * Re-organised Feb 1998 Russell King
6 * We now have independent partition support from the
7 * block drivers, which allows all the partition code to
8 * be grouped in one location, and it to be mostly self
9 * contained.
11 * Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl}
14 #include <linux/config.h>
15 #include <linux/fs.h>
16 #include <linux/genhd.h>
17 #include <linux/kernel.h>
18 #include <linux/major.h>
19 #include <linux/blk.h>
20 #include <linux/init.h>
21 #include <linux/raid/md.h>
23 #include "check.h"
25 #include "acorn.h"
26 #include "amiga.h"
27 #include "atari.h"
28 #include "mac.h"
29 #include "msdos.h"
30 #include "osf.h"
31 #include "sgi.h"
32 #include "sun.h"
33 #include "ibm.h"
35 extern void device_init(void);
36 extern void md_setup_drive(void);
37 extern int *blk_size[];
38 extern void rd_load(void);
39 extern void initrd_load(void);
41 struct gendisk *gendisk_head;
42 int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
44 static int (*check_part[])(struct gendisk *hd, kdev_t dev, unsigned long first_sect, int first_minor) = {
45 #ifdef CONFIG_ACORN_PARTITION
46 acorn_partition,
47 #endif
48 #ifdef CONFIG_MSDOS_PARTITION
49 msdos_partition,
50 #endif
51 #ifdef CONFIG_OSF_PARTITION
52 osf_partition,
53 #endif
54 #ifdef CONFIG_SUN_PARTITION
55 sun_partition,
56 #endif
57 #ifdef CONFIG_AMIGA_PARTITION
58 amiga_partition,
59 #endif
60 #ifdef CONFIG_ATARI_PARTITION
61 atari_partition,
62 #endif
63 #ifdef CONFIG_MAC_PARTITION
64 mac_partition,
65 #endif
66 #ifdef CONFIG_SGI_PARTITION
67 sgi_partition,
68 #endif
69 #ifdef CONFIG_ULTRIX_PARTITION
70 ultrix_partition,
71 #endif
72 #ifdef CONFIG_IBM_PARTITION
73 ibm_partition,
74 #endif
75 NULL
79 * disk_name() is used by genhd.c and blkpg.c.
80 * It formats the devicename of the indicated disk into
81 * the supplied buffer (of size at least 32), and returns
82 * a pointer to that same buffer (for convenience).
84 char *disk_name (struct gendisk *hd, int minor, char *buf)
86 unsigned int part;
87 const char *maj = hd->major_name;
88 int unit = (minor >> hd->minor_shift) + 'a';
90 part = minor & ((1 << hd->minor_shift) - 1);
91 if (hd->part[minor].de) {
92 int pos;
94 pos = devfs_generate_path (hd->part[minor].de, buf, 64);
95 if (pos >= 0)
96 return buf + pos;
99 * IDE devices use multiple major numbers, but the drives
100 * are named as: {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}..
101 * This requires special handling here.
103 switch (hd->major) {
104 case IDE9_MAJOR:
105 unit += 2;
106 case IDE8_MAJOR:
107 unit += 2;
108 case IDE7_MAJOR:
109 unit += 2;
110 case IDE6_MAJOR:
111 unit += 2;
112 case IDE5_MAJOR:
113 unit += 2;
114 case IDE4_MAJOR:
115 unit += 2;
116 case IDE3_MAJOR:
117 unit += 2;
118 case IDE2_MAJOR:
119 unit += 2;
120 case IDE1_MAJOR:
121 unit += 2;
122 case IDE0_MAJOR:
123 maj = "hd";
124 break;
125 case MD_MAJOR:
126 unit -= 'a'-'0';
127 break;
129 if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) {
130 unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16;
131 if (unit > 'z') {
132 unit -= 'z' + 1;
133 sprintf(buf, "sd%c%c", 'a' + unit / 26, 'a' + unit % 26);
134 if (part)
135 sprintf(buf + 4, "%d", part);
136 return buf;
139 if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) {
140 int ctlr = hd->major - COMPAQ_SMART2_MAJOR;
141 int disk = minor >> hd->minor_shift;
142 int part = minor & (( 1 << hd->minor_shift) - 1);
143 if (part == 0)
144 sprintf(buf, "%s/c%dd%d", maj, ctlr, disk);
145 else
146 sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, disk, part);
147 return buf;
149 if (hd->major >= DAC960_MAJOR && hd->major <= DAC960_MAJOR+7) {
150 int ctlr = hd->major - DAC960_MAJOR;
151 int disk = minor >> hd->minor_shift;
152 int part = minor & (( 1 << hd->minor_shift) - 1);
153 if (part == 0)
154 sprintf(buf, "%s/c%dd%d", maj, ctlr, disk);
155 else
156 sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, disk, part);
157 return buf;
159 if (part)
160 sprintf(buf, "%s%c%d", maj, unit, part);
161 else
162 sprintf(buf, "%s%c", maj, unit);
163 return buf;
167 * Add a partitions details to the devices partition description.
169 void add_gd_partition(struct gendisk *hd, int minor, int start, int size)
171 #ifndef CONFIG_DEVFS_FS
172 char buf[40];
173 #endif
175 hd->part[minor].start_sect = start;
176 hd->part[minor].nr_sects = size;
177 #ifdef CONFIG_DEVFS_FS
178 printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
179 #else
180 if (hd->major >= COMPAQ_SMART2_MAJOR+0 && hd->major <= COMPAQ_SMART2_MAJOR+7)
181 printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
182 else
183 printk(" %s", disk_name(hd, minor, buf));
184 #endif
187 int get_hardsect_size(kdev_t dev)
189 if (hardsect_size[MAJOR(dev)] != NULL)
190 return hardsect_size[MAJOR(dev)][MINOR(dev)];
191 else
192 return 512;
195 unsigned int get_ptable_blocksize(kdev_t dev)
197 int ret = 1024;
200 * See whether the low-level driver has given us a minumum blocksize.
201 * If so, check to see whether it is larger than the default of 1024.
203 if (!blksize_size[MAJOR(dev)])
204 return ret;
207 * Check for certain special power of two sizes that we allow.
208 * With anything larger than 1024, we must force the blocksize up to
209 * the natural blocksize for the device so that we don't have to try
210 * and read partial sectors. Anything smaller should be just fine.
213 switch (blksize_size[MAJOR(dev)][MINOR(dev)]) {
214 case 2048:
215 ret = 2048;
216 break;
217 case 4096:
218 ret = 4096;
219 break;
220 case 8192:
221 ret = 8192;
222 break;
223 case 1024:
224 case 512:
225 case 256:
226 case 0:
228 * These are all OK.
230 break;
231 default:
232 panic("Strange blocksize for partition table\n");
235 return ret;
238 #ifdef CONFIG_PROC_FS
239 int get_partition_list(char * page)
241 struct gendisk *p;
242 char buf[64];
243 int n, len;
245 len = sprintf(page, "major minor #blocks name\n\n");
246 for (p = gendisk_head; p; p = p->next) {
247 for (n=0; n < (p->nr_real << p->minor_shift); n++) {
248 if (p->part[n].nr_sects && len < PAGE_SIZE - 80) {
249 len += sprintf(page+len,
250 "%4d %4d %10d %s\n",
251 p->major, n, p->sizes[n],
252 disk_name(p, n, buf));
256 return len;
258 #endif
260 static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor)
262 devfs_handle_t de = NULL;
263 static int first_time = 1;
264 unsigned long first_sector;
265 char buf[64];
266 int i;
268 if (first_time)
269 printk(KERN_INFO "Partition check:\n");
270 first_time = 0;
271 first_sector = hd->part[MINOR(dev)].start_sect;
274 * This is a kludge to allow the partition check to be
275 * skipped for specific drives (e.g. IDE CD-ROM drives)
277 if ((int)first_sector == -1) {
278 hd->part[MINOR(dev)].start_sect = 0;
279 return;
282 if (hd->de_arr)
283 de = hd->de_arr[MINOR(dev) >> hd->minor_shift];
284 i = devfs_generate_path (de, buf, sizeof buf);
285 if (i >= 0)
286 printk(KERN_INFO " /dev/%s:", buf + i);
287 else
288 printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf));
289 for (i = 0; check_part[i]; i++)
290 if (check_part[i](hd, dev, first_sector, first_part_minor))
291 goto setup_devfs;
293 printk(" unknown partition table\n");
294 setup_devfs:
295 i = first_part_minor - 1;
296 devfs_register_partitions (hd, i, hd->sizes ? 0 : 1);
299 #ifdef CONFIG_DEVFS_FS
300 static void devfs_register_partition (struct gendisk *dev, int minor, int part)
302 int devnum = minor >> dev->minor_shift;
303 devfs_handle_t dir;
304 unsigned int devfs_flags = DEVFS_FL_DEFAULT;
305 char devname[16];
307 if (dev->part[minor + part].de) return;
308 dir = devfs_get_parent (dev->part[minor].de);
309 if (!dir) return;
310 if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) )
311 devfs_flags |= DEVFS_FL_REMOVABLE;
312 sprintf (devname, "part%d", part);
313 dev->part[minor + part].de =
314 devfs_register (dir, devname, 0, devfs_flags,
315 dev->major, minor + part,
316 S_IFBLK | S_IRUSR | S_IWUSR, 0, 0,
317 dev->fops, NULL);
320 static void devfs_register_disc (struct gendisk *dev, int minor)
322 int pos = 0;
323 int devnum = minor >> dev->minor_shift;
324 devfs_handle_t dir, slave;
325 unsigned int devfs_flags = DEVFS_FL_DEFAULT;
326 char dirname[64], symlink[16];
327 static unsigned int disc_counter = 0;
328 static devfs_handle_t devfs_handle = NULL;
330 if (dev->part[minor].de) return;
331 if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) )
332 devfs_flags |= DEVFS_FL_REMOVABLE;
333 if (dev->de_arr) {
334 dir = dev->de_arr[devnum];
335 if (!dir) /* Aware driver wants to block disc management */
336 return;
337 pos = devfs_generate_path (dir, dirname + 3, sizeof dirname-3);
338 if (pos < 0) return;
339 strncpy (dirname + pos, "../", 3);
341 else {
342 /* Unaware driver: construct "real" directory */
343 sprintf (dirname, "../%s/disc%d", dev->major_name, devnum);
344 dir = devfs_mk_dir (NULL, dirname + 3, 0, NULL);
346 if (!devfs_handle)
347 devfs_handle = devfs_mk_dir (NULL, "discs", 5, NULL);
348 sprintf (symlink, "disc%u", disc_counter++);
349 devfs_mk_symlink (devfs_handle, symlink, 0, DEVFS_FL_DEFAULT,
350 dirname + pos, 0, &slave, NULL);
351 dev->part[minor].de =
352 devfs_register (dir, "disc", 4, devfs_flags, dev->major, minor,
353 S_IFBLK | S_IRUSR | S_IWUSR, 0, 0, dev->fops,NULL);
354 devfs_auto_unregister (dev->part[minor].de, slave);
355 if (!dev->de_arr)
356 devfs_auto_unregister (slave, dir);
358 #endif /* CONFIG_DEVFS_FS */
360 void devfs_register_partitions (struct gendisk *dev, int minor, int unregister)
362 #ifdef CONFIG_DEVFS_FS
363 int part;
365 if (!unregister)
366 devfs_register_disc (dev, minor);
367 for (part = 1; part < dev->max_p; part++) {
368 if ( unregister || (dev->part[part + minor].nr_sects < 1) ) {
369 devfs_unregister (dev->part[part + minor].de);
370 dev->part[part + minor].de = NULL;
371 continue;
373 devfs_register_partition (dev, minor, part);
375 if (unregister) {
376 devfs_unregister (dev->part[minor].de);
377 dev->part[minor].de = NULL;
379 #endif /* CONFIG_DEVFS_FS */
383 * This function will re-read the partition tables for a given device,
384 * and set things back up again. There are some important caveats,
385 * however. You must ensure that no one is using the device, and no one
386 * can start using the device while this function is being executed.
388 * Much of the cleanup from the old partition tables should have already been
389 * done
392 void register_disk(struct gendisk *gdev, kdev_t dev, unsigned minors,
393 struct block_device_operations *ops, long size)
395 if (!gdev)
396 return;
397 grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size);
400 void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size)
402 int i;
403 int first_minor = drive << dev->minor_shift;
404 int end_minor = first_minor + dev->max_p;
406 if(!dev->sizes)
407 blk_size[dev->major] = NULL;
409 dev->part[first_minor].nr_sects = size;
410 /* No Such Agen^Wdevice or no minors to use for partitions */
411 if (!size || minors == 1)
412 return;
414 blk_size[dev->major] = NULL;
415 check_partition(dev, MKDEV(dev->major, first_minor), 1 + first_minor);
418 * We need to set the sizes array before we will be able to access
419 * any of the partitions on this device.
421 if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */
422 for (i = first_minor; i < end_minor; i++)
423 dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
424 blk_size[dev->major] = dev->sizes;
428 int __init partition_setup(void)
430 device_init();
432 #ifdef CONFIG_BLK_DEV_RAM
433 #ifdef CONFIG_BLK_DEV_INITRD
434 if (initrd_start && mount_initrd) initrd_load();
435 else
436 #endif
437 rd_load();
438 #endif
439 #ifdef CONFIG_BLK_DEV_MD
440 autodetect_raid();
441 #endif
442 return 0;
445 __initcall(partition_setup);