linux-old/fs/partitions/check.c
<<
>>
Prefs
   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#include "efi.h"
  37
  38extern int *blk_size[];
  39
  40int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
  41
  42static int (*check_part[])(struct gendisk *hd, struct block_device *bdev, unsigned long first_sect, int first_minor) = {
  43#ifdef CONFIG_ACORN_PARTITION
  44        acorn_partition,
  45#endif
  46#ifdef CONFIG_SGI_PARTITION
  47        sgi_partition,
  48#endif
  49#ifdef CONFIG_EFI_PARTITION
  50        efi_partition,          /* this must come before msdos */
  51#endif
  52#ifdef CONFIG_LDM_PARTITION
  53        ldm_partition,          /* this must come before msdos */
  54#endif
  55#ifdef CONFIG_MSDOS_PARTITION
  56        msdos_partition,
  57#endif
  58#ifdef CONFIG_OSF_PARTITION
  59        osf_partition,
  60#endif
  61#ifdef CONFIG_SUN_PARTITION
  62        sun_partition,
  63#endif
  64#ifdef CONFIG_AMIGA_PARTITION
  65        amiga_partition,
  66#endif
  67#ifdef CONFIG_ATARI_PARTITION
  68        atari_partition,
  69#endif
  70#ifdef CONFIG_MAC_PARTITION
  71        mac_partition,
  72#endif
  73#ifdef CONFIG_ULTRIX_PARTITION
  74        ultrix_partition,
  75#endif
  76#ifdef CONFIG_IBM_PARTITION
  77        ibm_partition,
  78#endif
  79        NULL
  80};
  81
  82/*
  83 *      This is ucking fugly but its probably the best thing for 2.4.x
  84 *      Take it as a clear reminder that: 1) we should put the device name
  85 *      generation in the object kdev_t points to in 2.5.
  86 *      and 2) ioctls better work on half-opened devices.
  87 */
  88 
  89#ifdef CONFIG_ARCH_S390
  90int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL;
  91int (*genhd_dasd_ioctl)(struct inode *inp, struct file *filp,
  92                            unsigned int no, unsigned long data);
  93EXPORT_SYMBOL(genhd_dasd_name);
  94EXPORT_SYMBOL(genhd_dasd_ioctl);
  95#endif
  96
  97/*
  98 * disk_name() is used by partition check code and the md driver.
  99 * It formats the devicename of the indicated disk into
 100 * the supplied buffer (of size at least 32), and returns
 101 * a pointer to that same buffer (for convenience).
 102 */
 103
 104char *disk_name (struct gendisk *hd, int minor, char *buf)
 105{
 106        const char *maj = hd->major_name;
 107        unsigned int unit = (minor >> hd->minor_shift);
 108        unsigned int part = (minor & ((1 << hd->minor_shift) -1 ));
 109
 110        if ((unit < hd->nr_real) && hd->part[minor].de) {
 111                int pos;
 112
 113                pos = devfs_generate_path (hd->part[minor].de, buf, 64);
 114                if (pos >= 0)
 115                        return buf + pos;
 116        }
 117
 118#ifdef CONFIG_ARCH_S390
 119        if (genhd_dasd_name
 120            && genhd_dasd_name (buf, unit, part, hd) == 0)
 121                return buf;
 122#endif
 123        /*
 124         * IDE devices use multiple major numbers, but the drives
 125         * are named as:  {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}..
 126         * This requires special handling here.
 127         */
 128        switch (hd->major) {
 129                case IDE9_MAJOR:
 130                        unit += 2;
 131                case IDE8_MAJOR:
 132                        unit += 2;
 133                case IDE7_MAJOR:
 134                        unit += 2;
 135                case IDE6_MAJOR:
 136                        unit += 2;
 137                case IDE5_MAJOR:
 138                        unit += 2;
 139                case IDE4_MAJOR:
 140                        unit += 2;
 141                case IDE3_MAJOR:
 142                        unit += 2;
 143                case IDE2_MAJOR:
 144                        unit += 2;
 145                case IDE1_MAJOR:
 146                        unit += 2;
 147                case IDE0_MAJOR:
 148                        maj = "hd";
 149                        break;
 150                case MD_MAJOR:
 151                        sprintf(buf, "%s%d", maj, unit);
 152                        return buf;
 153        }
 154        if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) {
 155                unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16;
 156                if (unit+'a' > 'z') {
 157                        unit -= 26;
 158                        sprintf(buf, "sd%c%c", 'a' + unit / 26, 'a' + unit % 26);
 159                        if (part)
 160                                sprintf(buf + 4, "%d", part);
 161                        return buf;
 162                }
 163        }
 164        if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) {
 165                int ctlr = hd->major - COMPAQ_SMART2_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 >= COMPAQ_CISS_MAJOR && hd->major <= COMPAQ_CISS_MAJOR+7) {
 173                int ctlr = hd->major - COMPAQ_CISS_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 (hd->major >= DAC960_MAJOR && hd->major <= DAC960_MAJOR+7) {
 181                int ctlr = hd->major - DAC960_MAJOR;
 182                if (part == 0)
 183                        sprintf(buf, "%s/c%dd%d", maj, ctlr, unit);
 184                else
 185                        sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part);
 186                return buf;
 187        }
 188        if (hd->major == ATARAID_MAJOR) {
 189                int disk = minor >> hd->minor_shift;
 190                int part = minor & (( 1 << hd->minor_shift) - 1);
 191                if (part == 0)
 192                        sprintf(buf, "%s/d%d", maj, disk);
 193                else
 194                        sprintf(buf, "%s/d%dp%d", maj, disk, part);
 195                return buf;
 196        }
 197        if (part)
 198                sprintf(buf, "%s%c%d", maj, unit+'a', part);
 199        else
 200                sprintf(buf, "%s%c", maj, unit+'a');
 201        return buf;
 202}
 203
 204/*
 205 * Add a partitions details to the devices partition description.
 206 */
 207void add_gd_partition(struct gendisk *hd, int minor, int start, int size)
 208{
 209#ifndef CONFIG_DEVFS_FS
 210        char buf[40];
 211#endif
 212
 213        hd->part[minor].start_sect = start;
 214        hd->part[minor].nr_sects   = size;
 215#ifdef CONFIG_DEVFS_FS
 216        printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
 217#else
 218        if ((hd->major >= COMPAQ_SMART2_MAJOR+0 && hd->major <= COMPAQ_SMART2_MAJOR+7) ||
 219            (hd->major >= COMPAQ_CISS_MAJOR+0 && hd->major <= COMPAQ_CISS_MAJOR+7))
 220                printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
 221        else
 222                printk(" %s", disk_name(hd, minor, buf));
 223#endif
 224}
 225
 226static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor)
 227{
 228        devfs_handle_t de = NULL;
 229        static int first_time = 1;
 230        unsigned long first_sector;
 231        struct block_device *bdev;
 232        char buf[64];
 233        int i;
 234
 235        if (first_time)
 236                printk(KERN_INFO "Partition check:\n");
 237        first_time = 0;
 238        first_sector = hd->part[MINOR(dev)].start_sect;
 239
 240        /*
 241         * This is a kludge to allow the partition check to be
 242         * skipped for specific drives (e.g. IDE CD-ROM drives)
 243         */
 244        if ((int)first_sector == -1) {
 245                hd->part[MINOR(dev)].start_sect = 0;
 246                return;
 247        }
 248
 249        if (hd->de_arr)
 250                de = hd->de_arr[MINOR(dev) >> hd->minor_shift];
 251        i = devfs_generate_path (de, buf, sizeof buf);
 252        if (i >= 0)
 253                printk(KERN_INFO " /dev/%s:", buf + i);
 254        else
 255                printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf));
 256        bdev = bdget(kdev_t_to_nr(dev));
 257        bdev->bd_inode->i_size = (loff_t)hd->part[MINOR(dev)].nr_sects << 9;
 258        bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev));
 259        for (i = 0; check_part[i]; i++) {
 260                int res;
 261                res = check_part[i](hd, bdev, first_sector, first_part_minor);
 262                if (res) {
 263                        if (res < 0 &&  warn_no_part)
 264                                printk(" unable to read partition table\n");
 265                        goto setup_devfs;
 266                }
 267        }
 268
 269        printk(" unknown partition table\n");
 270setup_devfs:
 271        invalidate_bdev(bdev, 1);
 272        truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
 273        bdput(bdev);
 274        i = first_part_minor - 1;
 275        devfs_register_partitions (hd, i, hd->sizes ? 0 : 1);
 276}
 277
 278#ifdef CONFIG_DEVFS_FS
 279static void devfs_register_partition (struct gendisk *dev, int minor, int part)
 280{
 281        int devnum = minor >> dev->minor_shift;
 282        devfs_handle_t dir;
 283        unsigned int devfs_flags = DEVFS_FL_DEFAULT;
 284        char devname[16];
 285
 286        if (dev->part[minor + part].de) return;
 287        dir = devfs_get_parent (dev->part[minor].de);
 288        if (!dir) return;
 289        if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) )
 290                devfs_flags |= DEVFS_FL_REMOVABLE;
 291        sprintf (devname, "part%d", part);
 292        dev->part[minor + part].de =
 293            devfs_register (dir, devname, devfs_flags,
 294                            dev->major, minor + part,
 295                            S_IFBLK | S_IRUSR | S_IWUSR,
 296                            dev->fops, NULL);
 297}
 298
 299static struct unique_numspace disc_numspace = UNIQUE_NUMBERSPACE_INITIALISER;
 300
 301static void devfs_register_disc (struct gendisk *dev, int minor)
 302{
 303        int pos = 0;
 304        int devnum = minor >> dev->minor_shift;
 305        devfs_handle_t dir, slave;
 306        unsigned int devfs_flags = DEVFS_FL_DEFAULT;
 307        char dirname[64], symlink[16];
 308        static devfs_handle_t devfs_handle;
 309
 310        if (dev->part[minor].de) return;
 311        if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) )
 312                devfs_flags |= DEVFS_FL_REMOVABLE;
 313        if (dev->de_arr) {
 314                dir = dev->de_arr[devnum];
 315                if (!dir)  /*  Aware driver wants to block disc management  */
 316                        return;
 317                pos = devfs_generate_path (dir, dirname + 3, sizeof dirname-3);
 318                if (pos < 0) return;
 319                strncpy (dirname + pos, "../", 3);
 320        }
 321        else {
 322                /*  Unaware driver: construct "real" directory  */
 323                sprintf (dirname, "../%s/disc%d", dev->major_name, devnum);
 324                dir = devfs_mk_dir (NULL, dirname + 3, NULL);
 325        }
 326        if (!devfs_handle)
 327                devfs_handle = devfs_mk_dir (NULL, "discs", NULL);
 328        dev->part[minor].number = devfs_alloc_unique_number (&disc_numspace);
 329        sprintf (symlink, "disc%d", dev->part[minor].number);
 330        devfs_mk_symlink (devfs_handle, symlink, DEVFS_FL_DEFAULT,
 331                          dirname + pos, &slave, NULL);
 332        dev->part[minor].de =
 333            devfs_register (dir, "disc", devfs_flags, dev->major, minor,
 334                            S_IFBLK | S_IRUSR | S_IWUSR, dev->fops, NULL);
 335        devfs_auto_unregister (dev->part[minor].de, slave);
 336        if (!dev->de_arr)
 337                devfs_auto_unregister (slave, dir);
 338}
 339#endif  /*  CONFIG_DEVFS_FS  */
 340
 341void devfs_register_partitions (struct gendisk *dev, int minor, int unregister)
 342{
 343#ifdef CONFIG_DEVFS_FS
 344        int part;
 345
 346        if (!unregister)
 347                devfs_register_disc (dev, minor);
 348        for (part = 1; part < dev->max_p; part++) {
 349                if ( unregister || (dev->part[minor].nr_sects < 1) ||
 350                     (dev->part[part + minor].nr_sects < 1) ) {
 351                        devfs_unregister (dev->part[part + minor].de);
 352                        dev->part[part + minor].de = NULL;
 353                        continue;
 354                }
 355                devfs_register_partition (dev, minor, part);
 356        }
 357        if (unregister) {
 358                devfs_unregister (dev->part[minor].de);
 359                dev->part[minor].de = NULL;
 360                devfs_dealloc_unique_number (&disc_numspace,
 361                                             dev->part[minor].number);
 362        }
 363#endif  /*  CONFIG_DEVFS_FS  */
 364}
 365
 366/*
 367 * This function will re-read the partition tables for a given device,
 368 * and set things back up again.  There are some important caveats,
 369 * however.  You must ensure that no one is using the device, and no one
 370 * can start using the device while this function is being executed.
 371 *
 372 * Much of the cleanup from the old partition tables should have already been
 373 * done
 374 */
 375
 376void register_disk(struct gendisk *gdev, kdev_t dev, unsigned minors,
 377        struct block_device_operations *ops, long size)
 378{
 379        if (!gdev)
 380                return;
 381        grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size);
 382}
 383
 384void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size)
 385{
 386        int i;
 387        int first_minor = drive << dev->minor_shift;
 388        int end_minor   = first_minor + dev->max_p;
 389
 390        if(!dev->sizes)
 391                blk_size[dev->major] = NULL;
 392
 393        dev->part[first_minor].nr_sects = size;
 394        /* No such device or no minors to use for partitions */
 395        if ( !size && dev->flags && (dev->flags[drive] & GENHD_FL_REMOVABLE) )
 396                devfs_register_partitions (dev, first_minor, 0);
 397        if (!size || minors == 1)
 398                return;
 399
 400        if (dev->sizes) {
 401                dev->sizes[first_minor] = size >> (BLOCK_SIZE_BITS - 9);
 402                for (i = first_minor + 1; i < end_minor; i++)
 403                        dev->sizes[i] = 0;
 404        }
 405        blk_size[dev->major] = dev->sizes;
 406        check_partition(dev, MKDEV(dev->major, first_minor), 1 + first_minor);
 407
 408        /*
 409         * We need to set the sizes array before we will be able to access
 410         * any of the partitions on this device.
 411         */
 412        if (dev->sizes != NULL) {       /* optional safeguard in ll_rw_blk.c */
 413                for (i = first_minor; i < end_minor; i++)
 414                        dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
 415        }
 416}
 417
 418unsigned char *read_dev_sector(struct block_device *bdev, unsigned long n, Sector *p)
 419{
 420        struct address_space *mapping = bdev->bd_inode->i_mapping;
 421        int sect = PAGE_CACHE_SIZE / 512;
 422        struct page *page;
 423
 424        page = read_cache_page(mapping, n/sect,
 425                        (filler_t *)mapping->a_ops->readpage, NULL);
 426        if (!IS_ERR(page)) {
 427                wait_on_page(page);
 428                if (!Page_Uptodate(page))
 429                        goto fail;
 430                if (PageError(page))
 431                        goto fail;
 432                p->v = page;
 433                return (unsigned char *)page_address(page) + 512 * (n % sect);
 434fail:
 435                page_cache_release(page);
 436        }
 437        p->v = NULL;
 438        return NULL;
 439}
 440
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.