File: /usr/src/linux/fs/partitions/check.c

1     /*
2      *  Code extracted from drivers/block/genhd.c
3      *  Copyright (C) 1991-1998  Linus Torvalds
4      *  Re-organised Feb 1998 Russell King
5      *
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.
10      *
11      *  Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl}
12      */
13     
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>
22     
23     #include "check.h"
24     
25     #include "acorn.h"
26     #include "amiga.h"
27     #include "atari.h"
28     #include "ldm.h"
29     #include "mac.h"
30     #include "msdos.h"
31     #include "osf.h"
32     #include "sgi.h"
33     #include "sun.h"
34     #include "ibm.h"
35     #include "ultrix.h"
36     
37     extern int *blk_size[];
38     
39     int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
40     
41     static int (*check_part[])(struct gendisk *hd, kdev_t dev, unsigned long first_sect, int first_minor) = {
42     #ifdef CONFIG_ACORN_PARTITION
43     	acorn_partition,
44     #endif
45     #ifdef CONFIG_LDM_PARTITION
46     	ldm_partition,		/* this must come before msdos */
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
76     };
77     
78     /*
79      *	This is ucking fugly but its probably the best thing for 2.4.x
80      *	Take it as a clear reminder than we should put the device name
81      *	generation in the object kdev_t points to in 2.5.
82      */
83      
84     #ifdef CONFIG_ARCH_S390
85     int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL;
86     EXPORT_SYMBOL(genhd_dasd_name);
87     #endif
88     
89     /*
90      * disk_name() is used by partition check code and the md driver.
91      * It formats the devicename of the indicated disk into
92      * the supplied buffer (of size at least 32), and returns
93      * a pointer to that same buffer (for convenience).
94      */
95     
96     char *disk_name (struct gendisk *hd, int minor, char *buf)
97     {
98     	const char *maj = hd->major_name;
99     	unsigned int unit = (minor >> hd->minor_shift);
100     	unsigned int part = (minor & ((1 << hd->minor_shift) -1 ));
101     
102     	if ((unit < hd->nr_real) && hd->part[minor].de) {
103     		int pos;
104     
105     		pos = devfs_generate_path (hd->part[minor].de, buf, 64);
106     		if (pos >= 0)
107     			return buf + pos;
108     	}
109     
110     #ifdef CONFIG_ARCH_S390
111     	if (genhd_dasd_name
112     	    && genhd_dasd_name (buf, unit, part, hd) == 0)
113     		return buf;
114     #endif
115     	/*
116     	 * IDE devices use multiple major numbers, but the drives
117     	 * are named as:  {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}..
118     	 * This requires special handling here.
119     	 */
120     	switch (hd->major) {
121     		case IDE9_MAJOR:
122     			unit += 2;
123     		case IDE8_MAJOR:
124     			unit += 2;
125     		case IDE7_MAJOR:
126     			unit += 2;
127     		case IDE6_MAJOR:
128     			unit += 2;
129     		case IDE5_MAJOR:
130     			unit += 2;
131     		case IDE4_MAJOR:
132     			unit += 2;
133     		case IDE3_MAJOR:
134     			unit += 2;
135     		case IDE2_MAJOR:
136     			unit += 2;
137     		case IDE1_MAJOR:
138     			unit += 2;
139     		case IDE0_MAJOR:
140     			maj = "hd";
141     			break;
142     		case MD_MAJOR:
143     			sprintf(buf, "%s%d", maj, unit);
144     			return buf;
145     	}
146     	if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) {
147     		unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16;
148     		if (unit+'a' > 'z') {
149     			unit -= 26;
150     			sprintf(buf, "sd%c%c", 'a' + unit / 26, 'a' + unit % 26);
151     			if (part)
152     				sprintf(buf + 4, "%d", part);
153     			return buf;
154     		}
155     	}
156     	if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) {
157     		int ctlr = hd->major - COMPAQ_SMART2_MAJOR;
158      		if (part == 0)
159      			sprintf(buf, "%s/c%dd%d", maj, ctlr, unit);
160      		else
161      			sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part);
162      		return buf;
163      	}
164     	if (hd->major >= COMPAQ_CISS_MAJOR && hd->major <= COMPAQ_CISS_MAJOR+7) {
165                     int ctlr = hd->major - COMPAQ_CISS_MAJOR;
166                     if (part == 0)
167                             sprintf(buf, "%s/c%dd%d", maj, ctlr, unit);
168                     else
169                             sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part);
170                     return buf;
171     	}
172     	if (hd->major >= DAC960_MAJOR && hd->major <= DAC960_MAJOR+7) {
173     		int ctlr = hd->major - DAC960_MAJOR;
174      		if (part == 0)
175      			sprintf(buf, "%s/c%dd%d", maj, ctlr, unit);
176      		else
177      			sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part);
178      		return buf;
179      	}
180     	if (part)
181     		sprintf(buf, "%s%c%d", maj, unit+'a', part);
182     	else
183     		sprintf(buf, "%s%c", maj, unit+'a');
184     	return buf;
185     }
186     
187     /*
188      * Add a partitions details to the devices partition description.
189      */
190     void add_gd_partition(struct gendisk *hd, int minor, int start, int size)
191     {
192     #ifndef CONFIG_DEVFS_FS
193     	char buf[40];
194     #endif
195     
196     	hd->part[minor].start_sect = start;
197     	hd->part[minor].nr_sects   = size;
198     #ifdef CONFIG_DEVFS_FS
199     	printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
200     #else
201     	if ((hd->major >= COMPAQ_SMART2_MAJOR+0 && hd->major <= COMPAQ_SMART2_MAJOR+7) ||
202     	    (hd->major >= COMPAQ_CISS_MAJOR+0 && hd->major <= COMPAQ_CISS_MAJOR+7))
203     		printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
204     	else
205     		printk(" %s", disk_name(hd, minor, buf));
206     #endif
207     }
208     
209     unsigned int get_ptable_blocksize(kdev_t dev)
210     {
211     	int ret = 1024;
212     
213     	/*
214     	 * See whether the low-level driver has given us a minumum blocksize.
215     	 * If so, check to see whether it is larger than the default of 1024.
216     	 */
217     	if (!blksize_size[MAJOR(dev)])
218     		return ret;
219     
220     	/*
221     	 * Check for certain special power of two sizes that we allow.
222     	 * With anything larger than 1024, we must force the blocksize up to
223     	 * the natural blocksize for the device so that we don't have to try
224     	 * and read partial sectors.  Anything smaller should be just fine.
225     	 */
226     
227     	switch (blksize_size[MAJOR(dev)][MINOR(dev)]) {
228     		case 2048:
229     			ret = 2048;
230     			break;
231     		case 4096:
232     			ret = 4096;
233     			break;
234     		case 8192:
235     			ret = 8192;
236     			break;
237     		case 1024:
238     		case 512:
239     		case 256:
240     		case 0:
241     			/*
242     			 * These are all OK.
243     			 */
244     			break;
245     		default:
246     			panic("Strange blocksize for partition table\n");
247     	}
248     
249     	return ret;
250     }
251     
252     static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor)
253     {
254     	devfs_handle_t de = NULL;
255     	static int first_time = 1;
256     	unsigned long first_sector;
257     	char buf[64];
258     	int i;
259     
260     	if (first_time)
261     		printk(KERN_INFO "Partition check:\n");
262     	first_time = 0;
263     	first_sector = hd->part[MINOR(dev)].start_sect;
264     
265     	/*
266     	 * This is a kludge to allow the partition check to be
267     	 * skipped for specific drives (e.g. IDE CD-ROM drives)
268     	 */
269     	if ((int)first_sector == -1) {
270     		hd->part[MINOR(dev)].start_sect = 0;
271     		return;
272     	}
273     
274     	if (hd->de_arr)
275     		de = hd->de_arr[MINOR(dev) >> hd->minor_shift];
276     	i = devfs_generate_path (de, buf, sizeof buf);
277     	if (i >= 0)
278     		printk(KERN_INFO " /dev/%s:", buf + i);
279     	else
280     		printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf));
281     	for (i = 0; check_part[i]; i++)
282     		if (check_part[i](hd, dev, first_sector, first_part_minor))
283     			goto setup_devfs;
284     
285     	printk(" unknown partition table\n");
286     setup_devfs:
287     	i = first_part_minor - 1;
288     	devfs_register_partitions (hd, i, hd->sizes ? 0 : 1);
289     }
290     
291     #ifdef CONFIG_DEVFS_FS
292     static void devfs_register_partition (struct gendisk *dev, int minor, int part)
293     {
294     	int devnum = minor >> dev->minor_shift;
295     	devfs_handle_t dir;
296     	unsigned int devfs_flags = DEVFS_FL_DEFAULT;
297     	char devname[16];
298     
299     	if (dev->part[minor + part].de) return;
300     	dir = devfs_get_parent (dev->part[minor].de);
301     	if (!dir) return;
302     	if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) )
303     		devfs_flags |= DEVFS_FL_REMOVABLE;
304     	sprintf (devname, "part%d", part);
305     	dev->part[minor + part].de =
306     	    devfs_register (dir, devname, devfs_flags,
307     			    dev->major, minor + part,
308     			    S_IFBLK | S_IRUSR | S_IWUSR,
309     			    dev->fops, NULL);
310     }
311     
312     static struct unique_numspace disc_numspace = UNIQUE_NUMBERSPACE_INITIALISER;
313     
314     static void devfs_register_disc (struct gendisk *dev, int minor)
315     {
316     	int pos = 0;
317     	int devnum = minor >> dev->minor_shift;
318     	devfs_handle_t dir, slave;
319     	unsigned int devfs_flags = DEVFS_FL_DEFAULT;
320     	char dirname[64], symlink[16];
321     	static devfs_handle_t devfs_handle;
322     
323     	if (dev->part[minor].de) return;
324     	if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) )
325     		devfs_flags |= DEVFS_FL_REMOVABLE;
326     	if (dev->de_arr) {
327     		dir = dev->de_arr[devnum];
328     		if (!dir)  /*  Aware driver wants to block disc management  */
329     			return;
330     		pos = devfs_generate_path (dir, dirname + 3, sizeof dirname-3);
331     		if (pos < 0) return;
332     		strncpy (dirname + pos, "../", 3);
333     	}
334     	else {
335     		/*  Unaware driver: construct "real" directory  */
336     		sprintf (dirname, "../%s/disc%d", dev->major_name, devnum);
337     		dir = devfs_mk_dir (NULL, dirname + 3, NULL);
338     	}
339     	if (!devfs_handle)
340     		devfs_handle = devfs_mk_dir (NULL, "discs", NULL);
341     	dev->part[minor].number = devfs_alloc_unique_number (&disc_numspace);
342     	sprintf (symlink, "disc%d", dev->part[minor].number);
343     	devfs_mk_symlink (devfs_handle, symlink, DEVFS_FL_DEFAULT,
344     			  dirname + pos, &slave, NULL);
345     	dev->part[minor].de =
346     	    devfs_register (dir, "disc", devfs_flags, dev->major, minor,
347     			    S_IFBLK | S_IRUSR | S_IWUSR, dev->fops, NULL);
348     	devfs_auto_unregister (dev->part[minor].de, slave);
349     	if (!dev->de_arr)
350     		devfs_auto_unregister (slave, dir);
351     }
352     #endif  /*  CONFIG_DEVFS_FS  */
353     
354     void devfs_register_partitions (struct gendisk *dev, int minor, int unregister)
355     {
356     #ifdef CONFIG_DEVFS_FS
357     	int part;
358     
359     	if (!unregister)
360     		devfs_register_disc (dev, minor);
361     	for (part = 1; part < dev->max_p; part++) {
362     		if ( unregister || (dev->part[part + minor].nr_sects < 1) ) {
363     			devfs_unregister (dev->part[part + minor].de);
364     			dev->part[part + minor].de = NULL;
365     			continue;
366     		}
367     		devfs_register_partition (dev, minor, part);
368     	}
369     	if (unregister) {
370     		devfs_unregister (dev->part[minor].de);
371     		dev->part[minor].de = NULL;
372     		devfs_dealloc_unique_number (&disc_numspace,
373     					     dev->part[minor].number);
374     	}
375     #endif  /*  CONFIG_DEVFS_FS  */
376     }
377     
378     /*
379      * This function will re-read the partition tables for a given device,
380      * and set things back up again.  There are some important caveats,
381      * however.  You must ensure that no one is using the device, and no one
382      * can start using the device while this function is being executed.
383      *
384      * Much of the cleanup from the old partition tables should have already been
385      * done
386      */
387     
388     void register_disk(struct gendisk *gdev, kdev_t dev, unsigned minors,
389     	struct block_device_operations *ops, long size)
390     {
391     	if (!gdev)
392     		return;
393     	grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size);
394     }
395     
396     void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size)
397     {
398     	int i;
399     	int first_minor	= drive << dev->minor_shift;
400     	int end_minor	= first_minor + dev->max_p;
401     
402     	if(!dev->sizes)
403     		blk_size[dev->major] = NULL;
404     
405     	dev->part[first_minor].nr_sects = size;
406     	/* No such device or no minors to use for partitions */
407     	if (!size || minors == 1)
408     		return;
409     
410     	check_partition(dev, MKDEV(dev->major, first_minor), 1 + first_minor);
411     
412      	/*
413      	 * We need to set the sizes array before we will be able to access
414      	 * any of the partitions on this device.
415      	 */
416     	if (dev->sizes != NULL) {	/* optional safeguard in ll_rw_blk.c */
417     		for (i = first_minor; i < end_minor; i++)
418     			dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
419     		blk_size[dev->major] = dev->sizes;
420     	}
421     }
422