lkml.org 
[lkml]   [2006]   [Jun]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectSparse minor space in ub
    I wrote a patch which allows to expand the number of partitions in ub
    without breaking compatibility with the existing non-udev based
    distributions.

    I do not know if I want this in the kernel or not. Looks pretty fishy,
    and its reason to exist is my lack of foresight. So far I heard from
    one user only who hit the limit, so obviously it's not something
    vitally important.

    But I thought I'd just throw this out in case anyone wants something
    similar in the future for any reason.

    Here how it looks in shell:

    [zaitcev@lembas ~]$ cat /proc/partitions
    major minor #blocks name

    3 0 39070080 hda
    3 1 5935986 hda1
    3 2 5936017 hda2
    3 3 554242 hda3
    3 4 1 hda4
    3 5 26643771 hda5
    180 0 253440 uba
    180 1 253424 uba1
    180 8 128000 ubb
    180 9 752 ubb1
    180 10 1 ubb2
    180 13 752 ubb5
    180 14 752 ubb6
    180 15 752 ubb7
    180 264 752 ubb8
    180 265 1008 ubb9
    [zaitcev@lembas ~]$ ls -l /dev/ub*
    brw-r----- 1 root disk 180, 0 Jun 14 23:18 /dev/uba
    brw-r----- 1 root disk 180, 1 Jun 14 23:18 /dev/uba1
    brw-r----- 1 root disk 180, 8 Jun 14 23:18 /dev/ubb
    brw-r----- 1 root disk 180, 9 Jun 14 23:18 /dev/ubb1
    brw-r----- 1 root disk 180, 10 Jun 14 23:18 /dev/ubb2
    brw-r----- 1 root disk 180, 13 Jun 14 23:18 /dev/ubb5
    brw-r----- 1 root disk 180, 14 Jun 14 23:18 /dev/ubb6
    brw-r----- 1 root disk 180, 15 Jun 14 23:18 /dev/ubb7
    brw-r----- 1 root disk 180, 264 Jun 14 23:18 /dev/ubb8
    brw-r----- 1 root disk 180, 265 Jun 14 23:18 /dev/ubb9
    [zaitcev@lembas ~]$

    By the way, when I looked at the way things work in kobj_lookup(),
    a thought occured to me. If floppy ever returns NULL from its match
    function floppy_find(), the whole thing is going to loop endlessly.
    This happens because we restart the search, which, I suspect, was
    done to accomodate md. The md_probe() always returns NULL, and
    inserts new arrays into the list of regions. Thus, it needs a rescan.
    Someone needs to think about this mechanism, it seems a little
    underdeveloped. I have no idea if my patch below implements the
    lock/match API correctly, especially in regards to locking.

    -- Pete

    diff -urp -X dontdiff linux-2.6.17-rc5/block/genhd.c linux-2.6.17-rc5-lem/block/genhd.c
    --- linux-2.6.17-rc5/block/genhd.c 2006-05-25 14:03:19.000000000 -0700
    +++ linux-2.6.17-rc5-lem/block/genhd.c 2006-06-14 22:57:28.000000000 -0700
    @@ -183,7 +183,8 @@ static int exact_lock(dev_t dev, void *d
    void add_disk(struct gendisk *disk)
    {
    disk->flags |= GENHD_FL_UP;
    - blk_register_region(MKDEV(disk->major, disk->first_minor),
    + if (!(disk->flags & GENHD_FL_SPARSE_MINORS))
    + blk_register_region(MKDEV(disk->major, disk->first_minor),
    disk->minors, NULL, exact_match, exact_lock, disk);
    register_disk(disk);
    blk_register_queue(disk);
    @@ -195,8 +196,9 @@ EXPORT_SYMBOL(del_gendisk); /* in partit
    void unlink_gendisk(struct gendisk *disk)
    {
    blk_unregister_queue(disk);
    - blk_unregister_region(MKDEV(disk->major, disk->first_minor),
    - disk->minors);
    + if (!(disk->flags & GENHD_FL_SPARSE_MINORS))
    + blk_unregister_region(MKDEV(disk->major, disk->first_minor),
    + disk->minors);
    }

    #define to_disk(obj) container_of(obj,struct gendisk,kobj)
    @@ -268,7 +270,7 @@ static int show_partition(struct seq_fil
    if (sgp->part[n]->nr_sects == 0)
    continue;
    seq_printf(part, "%4d %4d %10llu %s\n",
    - sgp->major, n + 1 + sgp->first_minor,
    + sgp->major, sgp->part[n]->partmin,
    (unsigned long long)sgp->part[n]->nr_sects >> 1 ,
    disk_name(sgp, n + 1, buf));
    }
    @@ -466,8 +468,7 @@ static int block_uevent(struct kset *kse
    disk = container_of(kobj->parent, struct gendisk, kobj);
    part = container_of(kobj, struct hd_struct, kobj);
    add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
    - &length, "MINOR=%u",
    - disk->first_minor + part->partno);
    + &length, "MINOR=%u", part->partmin);
    } else
    return 0;

    @@ -586,7 +587,7 @@ static int diskstats_show(struct seq_fil

    if (hd && hd->nr_sects)
    seq_printf(s, "%4d %4d %s %u %u %u %u\n",
    - gp->major, n + gp->first_minor + 1,
    + gp->major, hd->partmin,
    disk_name(gp, n + 1, buf),
    hd->ios[0], hd->sectors[0],
    hd->ios[1], hd->sectors[1]);
    diff -urp -X dontdiff linux-2.6.17-rc5/Documentation/devices.txt linux-2.6.17-rc5-lem/Documentation/devices.txt
    --- linux-2.6.17-rc5/Documentation/devices.txt 2006-05-25 14:02:59.000000000 -0700
    +++ linux-2.6.17-rc5-lem/Documentation/devices.txt 2006-05-25 15:45:34.000000000 -0700
    @@ -2552,10 +2552,10 @@ Your cooperation is appreciated.
    66 = /dev/usb/cpad0 Synaptics cPad (mouse/LCD)

    180 block USB block devices
    - 0 = /dev/uba First USB block device
    - 8 = /dev/ubb Second USB block device
    - 16 = /dev/ubc Thrid USB block device
    - ...
    + 0 = /dev/uba First USB block device
    + 16 = /dev/ubb Second USB block device
    + 32 = /dev/ubc Third USB block device
    + ...

    181 char Conrad Electronic parallel port radio clocks
    0 = /dev/pcfclock0 First Conrad radio clock
    diff -urp -X dontdiff linux-2.6.17-rc5/drivers/block/ub.c linux-2.6.17-rc5-lem/drivers/block/ub.c
    --- linux-2.6.17-rc5/drivers/block/ub.c 2006-05-25 14:03:20.000000000 -0700
    +++ linux-2.6.17-rc5-lem/drivers/block/ub.c 2006-06-14 23:16:10.000000000 -0700
    @@ -111,9 +107,18 @@
    #define UB_MAX_LUNS 9

    /*
    - */
    + * The minor layout is:
    + * 19 - 11 0xFF800
    + * 10 - 8 0x700 Upper 3 bits of partition number
    + * 7 - 3 0xF8 Host index, or same as "id". UB_MAX_HOSTS fit here.
    + * 2 - 0 0x7 Lower 3 bits of partition number
    + */
    +#define UB_PARTS_PER_LUN 64
    +#define UB_PARTS_LOW 8
    +#define UB_MINORS 2048

    -#define UB_PARTS_PER_LUN 8
    +/*
    + */

    #define UB_MAX_CDB_SIZE 16 /* Corresponds to Bulk */

    @@ -384,6 +389,7 @@ static int ub_submit_clear_stall(struct
    static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd);
    static void ub_reset_enter(struct ub_dev *sc, int try);
    static void ub_reset_task(void *arg);
    +static unsigned int ub_bd_map(struct gendisk *disk, int partno);
    static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun);
    static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
    struct ub_capacity *ret);
    @@ -407,14 +413,10 @@ MODULE_DEVICE_TABLE(usb, ub_usb_ids);
    #endif /* CONFIG_USB_LIBUSUAL */

    /*
    - * Find me a way to identify "next free minor" for add_disk(),
    - * and the array disappears the next day. However, the number of
    - * hosts has something to do with the naming and /proc/partitions.
    - * This has to be thought out in detail before changing.
    - * If UB_MAX_HOST was 1000, we'd use a bitmap. Or a better data structure.
    + * If UB_MAX_HOST were 1000, we'd use a better data structure.
    */
    #define UB_MAX_HOSTS 26
    -static char ub_hostv[UB_MAX_HOSTS];
    +static struct ub_lun *ub_hostv[UB_MAX_HOSTS];

    #define UB_QLOCK_NUM 5
    static spinlock_t ub_qlockv[UB_QLOCK_NUM];
    @@ -434,8 +436,8 @@ static int ub_id_get(void)

    spin_lock_irqsave(&ub_lock, flags);
    for (i = 0; i < UB_MAX_HOSTS; i++) {
    - if (ub_hostv[i] == 0) {
    - ub_hostv[i] = 1;
    + if (ub_hostv[i] == NULL) {
    + ub_hostv[i] = (struct ub_lun *) 1;
    spin_unlock_irqrestore(&ub_lock, flags);
    return i;
    }
    @@ -444,6 +446,15 @@ static int ub_id_get(void)
    return -1;
    }

    +static void ub_id_commit(int id, struct ub_lun *lun)
    +{
    + unsigned long flags;
    +
    + spin_lock_irqsave(&ub_lock, flags);
    + ub_hostv[id] = lun;
    + spin_unlock_irqrestore(&ub_lock, flags);
    +}
    +
    static void ub_id_put(int id)
    {
    unsigned long flags;
    @@ -454,12 +465,12 @@ static void ub_id_put(int id)
    }

    spin_lock_irqsave(&ub_lock, flags);
    - if (ub_hostv[id] == 0) {
    + if (ub_hostv[id] == NULL) {
    spin_unlock_irqrestore(&ub_lock, flags);
    printk(KERN_ERR DRV_NAME ": freeing free host ID %d\n", id);
    return;
    }
    - ub_hostv[id] = 0;
    + ub_hostv[id] = NULL;
    spin_unlock_irqrestore(&ub_lock, flags);
    }

    @@ -1781,9 +1786,80 @@ static struct block_device_operations ub
    .ioctl = ub_bd_ioctl,
    .media_changed = ub_bd_media_changed,
    .revalidate_disk = ub_bd_revalidate,
    + .partmap = ub_bd_map,
    };

    /*
    + * Since we want to remap minor bits, we have to use this weird API.
    + * It consists of two entries: lock and probe. Lock is called first
    + * grabs the relevant gendisk. The probe (usually called "match")
    + * remaps minor bits into an index for the array of partitions.
    + *
    + * The weird part is, if the lock succeeded, the match must not
    + * return NULL, or else kobj_lookup will try to lock again and things
    + * quickly unravel. All those NULL-returning paths are fake.
    + */
    +
    +static int ub_blk_lock(dev_t dev, void *data)
    +{
    + unsigned int minor = MINOR(dev);
    + unsigned int host;
    + struct ub_lun *lun;
    + unsigned long flags;
    +
    + host = (minor >> 3) & 0x1f;
    + if (host >= UB_MAX_HOSTS)
    + return -1;
    +
    + spin_lock_irqsave(&ub_lock, flags);
    + lun = ub_hostv[host];
    + if (lun == NULL || (unsigned long)lun == 1) {
    + spin_unlock_irqrestore(&ub_lock, flags);
    + return -1;
    + }
    + spin_unlock_irqrestore(&ub_lock, flags);
    +
    + if (atomic_read(&lun->udev->poison))
    + return -1;
    +
    + if (!get_disk(lun->disk))
    + return -1;
    + return 0;
    +}
    +
    +static struct kobject *ub_blk_match(dev_t dev, int *part, void *data)
    +{
    + unsigned int minor = MINOR(dev);
    + unsigned int host;
    + struct ub_lun *lun;
    + unsigned long flags;
    +
    + host = (minor >> 3) & 0x1f;
    + if (host >= UB_MAX_HOSTS)
    + return NULL; /* This never happens, no need for a printk */
    +
    + spin_lock_irqsave(&ub_lock, flags);
    + lun = ub_hostv[host];
    + if (lun == NULL || (unsigned long)lun == 1) {
    + spin_unlock_irqrestore(&ub_lock, flags);
    + printk(KERN_ERR DRV_NAME ": NULL lun for %u:%u\n",
    + (unsigned int) MAJOR(dev), minor);
    + return NULL;
    + }
    + spin_unlock_irqrestore(&ub_lock, flags);
    +
    + *part = ((minor & 0x700) >> 5) | (minor & 0x7);
    + return &lun->disk->kobj;
    +}
    +
    +static unsigned int ub_bd_map(struct gendisk *disk, int partno)
    +{
    + struct ub_lun *lun = disk->private_data;
    +
    + return ((partno & 0x38) << 5) | (lun->id << 3) | (partno & 0x7);
    +}
    +
    +/*
    * Common ->done routine for commands executed synchronously.
    */
    static void ub_probe_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
    @@ -2318,7 +2368,6 @@ static int ub_probe_lun(struct ub_dev *s
    goto err_id;

    lun->udev = sc;
    - list_add(&lun->link, &sc->luns);

    snprintf(lun->name, 16, DRV_NAME "%c(%d.%d.%d)",
    lun->id + 'a', sc->dev->bus->busnum, sc->dev->devnum, lun->num);
    @@ -2331,14 +2380,14 @@ static int ub_probe_lun(struct ub_dev *s
    if ((disk = alloc_disk(UB_PARTS_PER_LUN)) == NULL)
    goto err_diskalloc;

    - lun->disk = disk;
    sprintf(disk->disk_name, DRV_NAME "%c", lun->id + 'a');
    sprintf(disk->devfs_name, DEVFS_NAME "/%c", lun->id + 'a');
    disk->major = UB_MAJOR;
    - disk->first_minor = lun->id * UB_PARTS_PER_LUN;
    + disk->first_minor = lun->id * UB_PARTS_LOW;
    disk->fops = &ub_bd_fops;
    disk->private_data = lun;
    disk->driverfs_dev = &sc->intf->dev;
    + disk->flags |= GENHD_FL_SPARSE_MINORS;

    rc = -ENOMEM;
    if ((q = blk_init_queue(ub_request_fn, sc->lock)) == NULL)
    @@ -2353,12 +2402,15 @@ static int ub_probe_lun(struct ub_dev *s
    blk_queue_max_sectors(q, UB_MAX_SECTORS);
    blk_queue_hardsect_size(q, lun->capacity.bsize);

    + lun->disk = disk;
    q->queuedata = lun;
    + list_add(&lun->link, &sc->luns);

    set_capacity(disk, lun->capacity.nsec);
    if (lun->removable)
    disk->flags |= GENHD_FL_REMOVABLE;

    + ub_id_commit(lun->id, lun);
    add_disk(disk);

    return 0;
    @@ -2366,7 +2418,6 @@ static int ub_probe_lun(struct ub_dev *s
    err_blkqinit:
    put_disk(disk);
    err_diskalloc:
    - list_del(&lun->link);
    ub_id_put(lun->id);
    err_id:
    kfree(lun);
    @@ -2487,6 +2535,8 @@ static int __init ub_init(void)
    for (i = 0; i < UB_QLOCK_NUM; i++)
    spin_lock_init(&ub_qlockv[i]);

    + blk_register_region(MKDEV(UB_MAJOR, 0), UB_MINORS, THIS_MODULE,
    + ub_blk_match, ub_blk_lock, NULL);
    if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0)
    goto err_regblkdev;
    devfs_mk_dir(DEVFS_NAME);
    @@ -2501,6 +2551,7 @@ err_register:
    devfs_remove(DEVFS_NAME);
    unregister_blkdev(UB_MAJOR, DRV_NAME);
    err_regblkdev:
    + blk_unregister_region(MKDEV(UB_MAJOR, 0), UB_MINORS);
    return rc;
    }

    @@ -2511,6 +2562,7 @@ static void __exit ub_exit(void)
    devfs_remove(DEVFS_NAME);
    unregister_blkdev(UB_MAJOR, DRV_NAME);
    usb_usual_clear_present(USB_US_TYPE_UB);
    + blk_unregister_region(MKDEV(UB_MAJOR, 0), UB_MINORS);
    }

    module_init(ub_init);
    diff -urp -X dontdiff linux-2.6.17-rc5/fs/partitions/check.c linux-2.6.17-rc5-lem/fs/partitions/check.c
    --- linux-2.6.17-rc5/fs/partitions/check.c 2006-05-25 14:04:00.000000000 -0700
    +++ linux-2.6.17-rc5-lem/fs/partitions/check.c 2006-06-14 22:50:23.000000000 -0700
    @@ -236,7 +236,7 @@ static ssize_t part_uevent_store(struct
    static ssize_t part_dev_read(struct hd_struct * p, char *page)
    {
    struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj);
    - dev_t dev = MKDEV(disk->major, disk->first_minor + p->partno);
    + dev_t dev = MKDEV(disk->major, p->partmin);
    return print_dev_t(page, dev);
    }
    static ssize_t part_start_read(struct hd_struct * p, char *page)
    @@ -347,7 +347,10 @@ void add_partition(struct gendisk *disk,
    memset(p, 0, sizeof(*p));
    p->start_sect = start;
    p->nr_sects = len;
    - p->partno = part;
    + if (disk->fops->partmap)
    + p->partmin = disk->fops->partmap(disk, part);
    + else
    + p->partmin = disk->first_minor + part;

    devfs_mk_bdev(MKDEV(disk->major, disk->first_minor + part),
    S_IFBLK|S_IRUSR|S_IWUSR,
    diff -urp -X dontdiff linux-2.6.17-rc5/include/linux/fs.h linux-2.6.17-rc5-lem/include/linux/fs.h
    --- linux-2.6.17-rc5/include/linux/fs.h 2006-05-25 14:04:10.000000000 -0700
    +++ linux-2.6.17-rc5-lem/include/linux/fs.h 2006-06-14 22:47:23.000000000 -0700
    @@ -977,6 +977,7 @@ struct block_device_operations {
    int (*media_changed) (struct gendisk *);
    int (*revalidate_disk) (struct gendisk *);
    int (*getgeo)(struct block_device *, struct hd_geometry *);
    + unsigned (*partmap)(struct gendisk *, int partno);
    struct module *owner;
    };

    diff -urp -X dontdiff linux-2.6.17-rc5/include/linux/genhd.h linux-2.6.17-rc5-lem/include/linux/genhd.h
    --- linux-2.6.17-rc5/include/linux/genhd.h 2006-05-25 14:04:10.000000000 -0700
    +++ linux-2.6.17-rc5-lem/include/linux/genhd.h 2006-06-14 22:22:37.000000000 -0700
    @@ -80,7 +80,8 @@ struct hd_struct {
    struct kobject kobj;
    struct kobject *holder_dir;
    unsigned ios[2], sectors[2]; /* READs and WRITEs */
    - int policy, partno;
    + int policy;
    + unsigned int partmin;
    };

    #define GENHD_FL_REMOVABLE 1
    @@ -88,6 +89,7 @@ struct hd_struct {
    #define GENHD_FL_CD 8
    #define GENHD_FL_UP 16
    #define GENHD_FL_SUPPRESS_PARTITION_INFO 32
    +#define GENHD_FL_SPARSE_MINORS 64

    struct disk_stats {
    unsigned long sectors[2]; /* READs and WRITEs */
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/
    \
     
     \ /
      Last update: 2006-06-15 08:56    [W:0.054 / U:3.340 seconds]
    ©2003-2017 Jasper Spaans. hosted at Digital OceanAdvertise on this site