block: use disk_part_iter_exit in disk_part_iter_next
[linux-2.6-microblaze.git] / block / genhd.c
index 9387f05..0bd9c41 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/kmod.h>
-#include <linux/kobj_map.h>
 #include <linux/mutex.h>
 #include <linux/idr.h>
 #include <linux/log2.h>
 
 #include "blk.h"
 
-static DEFINE_MUTEX(block_class_lock);
 static struct kobject *block_depr;
 
+static DEFINE_XARRAY(bdev_map);
+static DEFINE_MUTEX(bdev_map_lock);
+
 /* for extended dynamic devt allocation, currently only one major is used */
 #define NR_EXT_DEVT            (1 << MINORBITS)
 
@@ -46,17 +47,15 @@ static void disk_del_events(struct gendisk *disk);
 static void disk_release_events(struct gendisk *disk);
 
 /*
- * Set disk capacity and notify if the size is not currently
- * zero and will not be set to zero
+ * Set disk capacity and notify if the size is not currently zero and will not
+ * be set to zero.  Returns true if a uevent was sent, otherwise false.
  */
-bool set_capacity_revalidate_and_notify(struct gendisk *disk, sector_t size,
-                                       bool update_bdev)
+bool set_capacity_and_notify(struct gendisk *disk, sector_t size)
 {
        sector_t capacity = get_capacity(disk);
 
        set_capacity(disk, size);
-       if (update_bdev)
-               revalidate_disk_size(disk, true);
+       revalidate_disk_size(disk, true);
 
        if (capacity != size && capacity != 0 && size != 0) {
                char *envp[] = { "RESIZE=1", NULL };
@@ -67,8 +66,7 @@ bool set_capacity_revalidate_and_notify(struct gendisk *disk, sector_t size,
 
        return false;
 }
-
-EXPORT_SYMBOL_GPL(set_capacity_revalidate_and_notify);
+EXPORT_SYMBOL_GPL(set_capacity_and_notify);
 
 /*
  * Format the device name of the indicated disk into the supplied buffer and
@@ -229,8 +227,7 @@ struct hd_struct *disk_part_iter_next(struct disk_part_iter *piter)
        int inc, end;
 
        /* put the last partition */
-       disk_put_part(piter->part);
-       piter->part = NULL;
+       disk_part_iter_exit(piter);
 
        /* get part_tbl */
        rcu_read_lock();
@@ -393,7 +390,9 @@ static struct blk_major_name {
        struct blk_major_name *next;
        int major;
        char name[16];
+       void (*probe)(dev_t devt);
 } *major_names[BLKDEV_MAJOR_HASH_SIZE];
+static DEFINE_MUTEX(major_names_lock);
 
 /* index in the above - for now: assume no multimajor ranges */
 static inline int major_to_index(unsigned major)
@@ -406,20 +405,21 @@ void blkdev_show(struct seq_file *seqf, off_t offset)
 {
        struct blk_major_name *dp;
 
-       mutex_lock(&block_class_lock);
+       mutex_lock(&major_names_lock);
        for (dp = major_names[major_to_index(offset)]; dp; dp = dp->next)
                if (dp->major == offset)
                        seq_printf(seqf, "%3d %s\n", dp->major, dp->name);
-       mutex_unlock(&block_class_lock);
+       mutex_unlock(&major_names_lock);
 }
 #endif /* CONFIG_PROC_FS */
 
 /**
- * register_blkdev - register a new block device
+ * __register_blkdev - register a new block device
  *
  * @major: the requested major device number [1..BLKDEV_MAJOR_MAX-1]. If
  *         @major = 0, try to allocate any unused major number.
  * @name: the name of the new block device as a zero terminated string
+ * @probe: allback that is called on access to any minor number of @major
  *
  * The @name must be unique within the system.
  *
@@ -433,13 +433,16 @@ void blkdev_show(struct seq_file *seqf, off_t offset)
  *
  * See Documentation/admin-guide/devices.txt for the list of allocated
  * major numbers.
+ *
+ * Use register_blkdev instead for any new code.
  */
-int register_blkdev(unsigned int major, const char *name)
+int __register_blkdev(unsigned int major, const char *name,
+               void (*probe)(dev_t devt))
 {
        struct blk_major_name **n, *p;
        int index, ret = 0;
 
-       mutex_lock(&block_class_lock);
+       mutex_lock(&major_names_lock);
 
        /* temporary */
        if (major == 0) {
@@ -473,6 +476,7 @@ int register_blkdev(unsigned int major, const char *name)
        }
 
        p->major = major;
+       p->probe = probe;
        strlcpy(p->name, name, sizeof(p->name));
        p->next = NULL;
        index = major_to_index(major);
@@ -492,11 +496,10 @@ int register_blkdev(unsigned int major, const char *name)
                kfree(p);
        }
 out:
-       mutex_unlock(&block_class_lock);
+       mutex_unlock(&major_names_lock);
        return ret;
 }
-
-EXPORT_SYMBOL(register_blkdev);
+EXPORT_SYMBOL(__register_blkdev);
 
 void unregister_blkdev(unsigned int major, const char *name)
 {
@@ -504,7 +507,7 @@ void unregister_blkdev(unsigned int major, const char *name)
        struct blk_major_name *p = NULL;
        int index = major_to_index(major);
 
-       mutex_lock(&block_class_lock);
+       mutex_lock(&major_names_lock);
        for (n = &major_names[index]; *n; n = &(*n)->next)
                if ((*n)->major == major)
                        break;
@@ -514,14 +517,12 @@ void unregister_blkdev(unsigned int major, const char *name)
                p = *n;
                *n = p->next;
        }
-       mutex_unlock(&block_class_lock);
+       mutex_unlock(&major_names_lock);
        kfree(p);
 }
 
 EXPORT_SYMBOL(unregister_blkdev);
 
-static struct kobj_map *bdev_map;
-
 /**
  * blk_mangle_minor - scatter minor numbers apart
  * @minor: minor number to mangle
@@ -639,41 +640,26 @@ static char *bdevt_str(dev_t devt, char *buf)
        return buf;
 }
 
-/*
- * Register device numbers dev..(dev+range-1)
- * range must be nonzero
- * The hash chain is sorted on range, so that subranges can override.
- */
-void blk_register_region(dev_t devt, unsigned long range, struct module *module,
-                        struct kobject *(*probe)(dev_t, int *, void *),
-                        int (*lock)(dev_t, void *), void *data)
-{
-       kobj_map(bdev_map, devt, range, module, probe, lock, data);
-}
-
-EXPORT_SYMBOL(blk_register_region);
-
-void blk_unregister_region(dev_t devt, unsigned long range)
-{
-       kobj_unmap(bdev_map, devt, range);
-}
-
-EXPORT_SYMBOL(blk_unregister_region);
-
-static struct kobject *exact_match(dev_t devt, int *partno, void *data)
+static void blk_register_region(struct gendisk *disk)
 {
-       struct gendisk *p = data;
+       int i;
 
-       return &disk_to_dev(p)->kobj;
+       mutex_lock(&bdev_map_lock);
+       for (i = 0; i < disk->minors; i++) {
+               if (xa_insert(&bdev_map, disk_devt(disk) + i, disk, GFP_KERNEL))
+                       WARN_ON_ONCE(1);
+       }
+       mutex_unlock(&bdev_map_lock);
 }
 
-static int exact_lock(dev_t devt, void *data)
+static void blk_unregister_region(struct gendisk *disk)
 {
-       struct gendisk *p = data;
+       int i;
 
-       if (!get_disk_and_module(p))
-               return -1;
-       return 0;
+       mutex_lock(&bdev_map_lock);
+       for (i = 0; i < disk->minors; i++)
+               xa_erase(&bdev_map, disk_devt(disk) + i);
+       mutex_unlock(&bdev_map_lock);
 }
 
 static void disk_scan_partitions(struct gendisk *disk)
@@ -819,8 +805,7 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk,
                ret = bdi_register(bdi, "%u:%u", MAJOR(devt), MINOR(devt));
                WARN_ON(ret);
                bdi_set_owner(bdi, dev);
-               blk_register_region(disk_devt(disk), disk->minors, NULL,
-                                   exact_match, exact_lock, disk);
+               blk_register_region(disk);
        }
        register_disk(parent, disk, groups);
        if (register_queue)
@@ -895,6 +880,9 @@ void del_gendisk(struct gendisk *disk)
 
        might_sleep();
 
+       if (WARN_ON_ONCE(!disk->queue))
+               return;
+
        blk_integrity_del(disk);
        disk_del_events(disk);
 
@@ -917,22 +905,20 @@ void del_gendisk(struct gendisk *disk)
        disk->flags &= ~GENHD_FL_UP;
        up_write(&disk->lookup_sem);
 
-       if (!(disk->flags & GENHD_FL_HIDDEN))
+       if (!(disk->flags & GENHD_FL_HIDDEN)) {
                sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
-       if (disk->queue) {
+
                /*
                 * Unregister bdi before releasing device numbers (as they can
                 * get reused and we'd get clashes in sysfs).
                 */
-               if (!(disk->flags & GENHD_FL_HIDDEN))
-                       bdi_unregister(disk->queue->backing_dev_info);
-               blk_unregister_queue(disk);
-       } else {
-               WARN_ON(1);
+               bdi_unregister(disk->queue->backing_dev_info);
        }
 
+       blk_unregister_queue(disk);
+       
        if (!(disk->flags & GENHD_FL_HIDDEN))
-               blk_unregister_region(disk_devt(disk), disk->minors);
+               blk_unregister_region(disk);
        /*
         * Remove gendisk pointer from idr so that it cannot be looked up
         * while RCU period before freeing gendisk is running to prevent
@@ -978,6 +964,43 @@ static ssize_t disk_badblocks_store(struct device *dev,
        return badblocks_store(disk->bb, page, len, 0);
 }
 
+static void request_gendisk_module(dev_t devt)
+{
+       unsigned int major = MAJOR(devt);
+       struct blk_major_name **n;
+
+       mutex_lock(&major_names_lock);
+       for (n = &major_names[major_to_index(major)]; *n; n = &(*n)->next) {
+               if ((*n)->major == major && (*n)->probe) {
+                       (*n)->probe(devt);
+                       mutex_unlock(&major_names_lock);
+                       return;
+               }
+       }
+       mutex_unlock(&major_names_lock);
+
+       if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0)
+               /* Make old-style 2.4 aliases work */
+               request_module("block-major-%d", MAJOR(devt));
+}
+
+static bool get_disk_and_module(struct gendisk *disk)
+{
+       struct module *owner;
+
+       if (!disk->fops)
+               return false;
+       owner = disk->fops->owner;
+       if (owner && !try_module_get(owner))
+               return false;
+       if (!kobject_get_unless_zero(&disk_to_dev(disk)->kobj)) {
+               module_put(owner);
+               return false;
+       }
+       return true;
+
+}
+
 /**
  * get_gendisk - get partitioning information for a given device
  * @devt: device to get partitioning information for
@@ -995,11 +1018,19 @@ struct gendisk *get_gendisk(dev_t devt, int *partno)
        might_sleep();
 
        if (MAJOR(devt) != BLOCK_EXT_MAJOR) {
-               struct kobject *kobj;
-
-               kobj = kobj_lookup(bdev_map, devt, partno);
-               if (kobj)
-                       disk = dev_to_disk(kobj_to_dev(kobj));
+               mutex_lock(&bdev_map_lock);
+               disk = xa_load(&bdev_map, devt);
+               if (!disk) {
+                       mutex_unlock(&bdev_map_lock);
+                       request_gendisk_module(devt);
+                       mutex_lock(&bdev_map_lock);
+                       disk = xa_load(&bdev_map, devt);
+               }
+               if (disk && !get_disk_and_module(disk))
+                       disk = NULL;
+               if (disk)
+                       *partno = devt - disk_devt(disk);
+               mutex_unlock(&bdev_map_lock);
        } else {
                struct hd_struct *part;
 
@@ -1203,15 +1234,6 @@ static const struct seq_operations partitions_op = {
 };
 #endif
 
-
-static struct kobject *base_probe(dev_t devt, int *partno, void *data)
-{
-       if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0)
-               /* Make old-style 2.4 aliases work */
-               request_module("block-major-%d", MAJOR(devt));
-       return NULL;
-}
-
 static int __init genhd_device_init(void)
 {
        int error;
@@ -1220,7 +1242,6 @@ static int __init genhd_device_init(void)
        error = class_register(&block_class);
        if (unlikely(error))
                return error;
-       bdev_map = kobj_map_init(base_probe, &block_class_lock);
        blk_dev_init();
 
        register_blkdev(BLOCK_EXT_MAJOR, "blkext");
@@ -1769,35 +1790,6 @@ out_free_disk:
 }
 EXPORT_SYMBOL(__alloc_disk_node);
 
-/**
- * get_disk_and_module - increments the gendisk and gendisk fops module refcount
- * @disk: the struct gendisk to increment the refcount for
- *
- * This increments the refcount for the struct gendisk, and the gendisk's
- * fops module owner.
- *
- * Context: Any context.
- */
-struct kobject *get_disk_and_module(struct gendisk *disk)
-{
-       struct module *owner;
-       struct kobject *kobj;
-
-       if (!disk->fops)
-               return NULL;
-       owner = disk->fops->owner;
-       if (owner && !try_module_get(owner))
-               return NULL;
-       kobj = kobject_get_unless_zero(&disk_to_dev(disk)->kobj);
-       if (kobj == NULL) {
-               module_put(owner);
-               return NULL;
-       }
-       return kobj;
-
-}
-EXPORT_SYMBOL(get_disk_and_module);
-
 /**
  * put_disk - decrements the gendisk refcount
  * @disk: the struct gendisk to decrement the refcount for
@@ -1834,7 +1826,6 @@ void put_disk_and_module(struct gendisk *disk)
                module_put(owner);
        }
 }
-EXPORT_SYMBOL(put_disk_and_module);
 
 static void set_disk_ro_uevent(struct gendisk *gd, int ro)
 {
@@ -1846,13 +1837,6 @@ static void set_disk_ro_uevent(struct gendisk *gd, int ro)
        kobject_uevent_env(&disk_to_dev(gd)->kobj, KOBJ_CHANGE, envp);
 }
 
-void set_device_ro(struct block_device *bdev, int flag)
-{
-       bdev->bd_part->policy = flag;
-}
-
-EXPORT_SYMBOL(set_device_ro);
-
 void set_disk_ro(struct gendisk *disk, int flag)
 {
        struct disk_part_iter piter;