Merge tag 'for-5.11/block-2020-12-14' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / block / genhd.c
index 9387f05..b84b867 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;
 
+DECLARE_RWSEM(bdev_lookup_sem);
+
 /* for extended dynamic devt allocation, currently only one major is used */
 #define NR_EXT_DEVT            (1 << MINORBITS)
-
-/* For extended devt allocation.  ext_devt_lock prevents look up
- * results from going away underneath its user.
- */
-static DEFINE_SPINLOCK(ext_devt_lock);
-static DEFINE_IDR(ext_devt_idr);
+static DEFINE_IDA(ext_devt_ida);
 
 static void disk_check_events(struct disk_events *ev,
                              unsigned int *clearing_ptr);
@@ -45,30 +40,49 @@ static void disk_add_events(struct gendisk *disk);
 static void disk_del_events(struct gendisk *disk);
 static void disk_release_events(struct gendisk *disk);
 
+void set_capacity(struct gendisk *disk, sector_t sectors)
+{
+       struct block_device *bdev = disk->part0;
+
+       spin_lock(&bdev->bd_size_lock);
+       i_size_write(bdev->bd_inode, (loff_t)sectors << SECTOR_SHIFT);
+       spin_unlock(&bdev->bd_size_lock);
+}
+EXPORT_SYMBOL(set_capacity);
+
 /*
- * 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);
+       char *envp[] = { "RESIZE=1", NULL };
 
        set_capacity(disk, size);
-       if (update_bdev)
-               revalidate_disk_size(disk, true);
 
-       if (capacity != size && capacity != 0 && size != 0) {
-               char *envp[] = { "RESIZE=1", NULL };
+       /*
+        * Only print a message and send a uevent if the gendisk is user visible
+        * and alive.  This avoids spamming the log and udev when setting the
+        * initial capacity during probing.
+        */
+       if (size == capacity ||
+           (disk->flags & (GENHD_FL_UP | GENHD_FL_HIDDEN)) != GENHD_FL_UP)
+               return false;
 
-               kobject_uevent_env(&disk_to_dev(disk)->kobj, KOBJ_CHANGE, envp);
-               return true;
-       }
+       pr_info("%s: detected capacity change from %lld to %lld\n",
+               disk->disk_name, size, capacity);
 
-       return false;
+       /*
+        * Historically we did not send a uevent for changes to/from an empty
+        * device.
+        */
+       if (!capacity || !size)
+               return false;
+       kobject_uevent_env(&disk_to_dev(disk)->kobj, KOBJ_CHANGE, envp);
+       return true;
 }
-
-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
@@ -92,13 +106,14 @@ const char *bdevname(struct block_device *bdev, char *buf)
 }
 EXPORT_SYMBOL(bdevname);
 
-static void part_stat_read_all(struct hd_struct *part, struct disk_stats *stat)
+static void part_stat_read_all(struct block_device *part,
+               struct disk_stats *stat)
 {
        int cpu;
 
        memset(stat, 0, sizeof(struct disk_stats));
        for_each_possible_cpu(cpu) {
-               struct disk_stats *ptr = per_cpu_ptr(part->dkstats, cpu);
+               struct disk_stats *ptr = per_cpu_ptr(part->bd_stats, cpu);
                int group;
 
                for (group = 0; group < NR_STAT_GROUPS; group++) {
@@ -112,7 +127,7 @@ static void part_stat_read_all(struct hd_struct *part, struct disk_stats *stat)
        }
 }
 
-static unsigned int part_in_flight(struct hd_struct *part)
+static unsigned int part_in_flight(struct block_device *part)
 {
        unsigned int inflight = 0;
        int cpu;
@@ -127,7 +142,8 @@ static unsigned int part_in_flight(struct hd_struct *part)
        return inflight;
 }
 
-static void part_in_flight_rw(struct hd_struct *part, unsigned int inflight[2])
+static void part_in_flight_rw(struct block_device *part,
+               unsigned int inflight[2])
 {
        int cpu;
 
@@ -143,7 +159,7 @@ static void part_in_flight_rw(struct hd_struct *part, unsigned int inflight[2])
                inflight[1] = 0;
 }
 
-struct hd_struct *__disk_get_part(struct gendisk *disk, int partno)
+struct block_device *__disk_get_part(struct gendisk *disk, int partno)
 {
        struct disk_part_tbl *ptbl = rcu_dereference(disk->part_tbl);
 
@@ -152,33 +168,6 @@ struct hd_struct *__disk_get_part(struct gendisk *disk, int partno)
        return rcu_dereference(ptbl->part[partno]);
 }
 
-/**
- * disk_get_part - get partition
- * @disk: disk to look partition from
- * @partno: partition number
- *
- * Look for partition @partno from @disk.  If found, increment
- * reference count and return it.
- *
- * CONTEXT:
- * Don't care.
- *
- * RETURNS:
- * Pointer to the found partition on success, NULL if not found.
- */
-struct hd_struct *disk_get_part(struct gendisk *disk, int partno)
-{
-       struct hd_struct *part;
-
-       rcu_read_lock();
-       part = __disk_get_part(disk, partno);
-       if (part)
-               get_device(part_to_dev(part));
-       rcu_read_unlock();
-
-       return part;
-}
-
 /**
  * disk_part_iter_init - initialize partition iterator
  * @piter: iterator to initialize
@@ -223,14 +212,13 @@ EXPORT_SYMBOL_GPL(disk_part_iter_init);
  * CONTEXT:
  * Don't care.
  */
-struct hd_struct *disk_part_iter_next(struct disk_part_iter *piter)
+struct block_device *disk_part_iter_next(struct disk_part_iter *piter)
 {
        struct disk_part_tbl *ptbl;
        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();
@@ -251,19 +239,20 @@ struct hd_struct *disk_part_iter_next(struct disk_part_iter *piter)
 
        /* iterate to the next partition */
        for (; piter->idx != end; piter->idx += inc) {
-               struct hd_struct *part;
+               struct block_device *part;
 
                part = rcu_dereference(ptbl->part[piter->idx]);
                if (!part)
                        continue;
-               if (!part_nr_sects_read(part) &&
+               if (!bdev_nr_sectors(part) &&
                    !(piter->flags & DISK_PITER_INCL_EMPTY) &&
                    !(piter->flags & DISK_PITER_INCL_EMPTY_PART0 &&
                      piter->idx == 0))
                        continue;
 
-               get_device(part_to_dev(part));
-               piter->part = part;
+               piter->part = bdgrab(part);
+               if (!piter->part)
+                       continue;
                piter->idx += inc;
                break;
        }
@@ -285,15 +274,16 @@ EXPORT_SYMBOL_GPL(disk_part_iter_next);
  */
 void disk_part_iter_exit(struct disk_part_iter *piter)
 {
-       disk_put_part(piter->part);
+       if (piter->part)
+               bdput(piter->part);
        piter->part = NULL;
 }
 EXPORT_SYMBOL_GPL(disk_part_iter_exit);
 
-static inline int sector_in_part(struct hd_struct *part, sector_t sector)
+static inline int sector_in_part(struct block_device *part, sector_t sector)
 {
-       return part->start_sect <= sector &&
-               sector < part->start_sect + part_nr_sects_read(part);
+       return part->bd_start_sect <= sector &&
+               sector < part->bd_start_sect + bdev_nr_sectors(part);
 }
 
 /**
@@ -305,44 +295,34 @@ static inline int sector_in_part(struct hd_struct *part, sector_t sector)
  * primarily used for stats accounting.
  *
  * CONTEXT:
- * RCU read locked.  The returned partition pointer is always valid
- * because its refcount is grabbed except for part0, which lifetime
- * is same with the disk.
+ * RCU read locked.
  *
  * RETURNS:
  * Found partition on success, part0 is returned if no partition matches
  * or the matched partition is being deleted.
  */
-struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector)
+struct block_device *disk_map_sector_rcu(struct gendisk *disk, sector_t sector)
 {
        struct disk_part_tbl *ptbl;
-       struct hd_struct *part;
+       struct block_device *part;
        int i;
 
        rcu_read_lock();
        ptbl = rcu_dereference(disk->part_tbl);
 
        part = rcu_dereference(ptbl->last_lookup);
-       if (part && sector_in_part(part, sector) && hd_struct_try_get(part))
+       if (part && sector_in_part(part, sector))
                goto out_unlock;
 
        for (i = 1; i < ptbl->len; i++) {
                part = rcu_dereference(ptbl->part[i]);
-
                if (part && sector_in_part(part, sector)) {
-                       /*
-                        * only live partition can be cached for lookup,
-                        * so use-after-free on cached & deleting partition
-                        * can be avoided
-                        */
-                       if (!hd_struct_try_get(part))
-                               break;
                        rcu_assign_pointer(ptbl->last_lookup, part);
                        goto out_unlock;
                }
        }
 
-       part = &disk->part0;
+       part = disk->part0;
 out_unlock:
        rcu_read_unlock();
        return part;
@@ -393,7 +373,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 +388,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 +416,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 +459,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 +479,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 +490,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 +500,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
@@ -555,8 +539,8 @@ static int blk_mangle_minor(int minor)
 }
 
 /**
- * blk_alloc_devt - allocate a dev_t for a partition
- * @part: partition to allocate dev_t for
+ * blk_alloc_devt - allocate a dev_t for a block device
+ * @bdev: block device to allocate dev_t for
  * @devt: out parameter for resulting dev_t
  *
  * Allocate a dev_t for block device.
@@ -568,25 +552,18 @@ static int blk_mangle_minor(int minor)
  * CONTEXT:
  * Might sleep.
  */
-int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
+int blk_alloc_devt(struct block_device *bdev, dev_t *devt)
 {
-       struct gendisk *disk = part_to_disk(part);
+       struct gendisk *disk = bdev->bd_disk;
        int idx;
 
        /* in consecutive minor range? */
-       if (part->partno < disk->minors) {
-               *devt = MKDEV(disk->major, disk->first_minor + part->partno);
+       if (bdev->bd_partno < disk->minors) {
+               *devt = MKDEV(disk->major, disk->first_minor + bdev->bd_partno);
                return 0;
        }
 
-       /* allocate ext devt */
-       idr_preload(GFP_KERNEL);
-
-       spin_lock_bh(&ext_devt_lock);
-       idx = idr_alloc(&ext_devt_idr, part, 0, NR_EXT_DEVT, GFP_NOWAIT);
-       spin_unlock_bh(&ext_devt_lock);
-
-       idr_preload_end();
+       idx = ida_alloc_range(&ext_devt_ida, 0, NR_EXT_DEVT, GFP_KERNEL);
        if (idx < 0)
                return idx == -ENOSPC ? -EBUSY : idx;
 
@@ -605,26 +582,8 @@ int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
  */
 void blk_free_devt(dev_t devt)
 {
-       if (devt == MKDEV(0, 0))
-               return;
-
-       if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
-               spin_lock_bh(&ext_devt_lock);
-               idr_remove(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
-               spin_unlock_bh(&ext_devt_lock);
-       }
-}
-
-/*
- * We invalidate devt by assigning NULL pointer for devt in idr.
- */
-void blk_invalidate_devt(dev_t devt)
-{
-       if (MAJOR(devt) == BLOCK_EXT_MAJOR) {
-               spin_lock_bh(&ext_devt_lock);
-               idr_replace(&ext_devt_idr, NULL, blk_mangle_minor(MINOR(devt)));
-               spin_unlock_bh(&ext_devt_lock);
-       }
+       if (MAJOR(devt) == BLOCK_EXT_MAJOR)
+               ida_free(&ext_devt_ida, blk_mangle_minor(MINOR(devt)));
 }
 
 static char *bdevt_str(dev_t devt, char *buf)
@@ -639,43 +598,6 @@ 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)
-{
-       struct gendisk *p = data;
-
-       return &disk_to_dev(p)->kobj;
-}
-
-static int exact_lock(dev_t devt, void *data)
-{
-       struct gendisk *p = data;
-
-       if (!get_disk_and_module(p))
-               return -1;
-       return 0;
-}
-
 static void disk_scan_partitions(struct gendisk *disk)
 {
        struct block_device *bdev;
@@ -694,7 +616,7 @@ static void register_disk(struct device *parent, struct gendisk *disk,
 {
        struct device *ddev = disk_to_dev(disk);
        struct disk_part_iter piter;
-       struct hd_struct *part;
+       struct block_device *part;
        int err;
 
        ddev->parent = parent;
@@ -726,7 +648,8 @@ static void register_disk(struct device *parent, struct gendisk *disk,
         */
        pm_runtime_set_memalloc_noio(ddev, true);
 
-       disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj);
+       disk->part0->bd_holder_dir =
+               kobject_create_and_add("holders", &ddev->kobj);
        disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj);
 
        if (disk->flags & GENHD_FL_HIDDEN) {
@@ -743,7 +666,7 @@ static void register_disk(struct device *parent, struct gendisk *disk,
        /* announce possible partitions */
        disk_part_iter_init(&piter, disk, 0);
        while ((part = disk_part_iter_next(&piter)))
-               kobject_uevent(&part_to_dev(part)->kobj, KOBJ_ADD);
+               kobject_uevent(bdev_kobj(part), KOBJ_ADD);
        disk_part_iter_exit(&piter);
 
        if (disk->queue->backing_dev_info->dev) {
@@ -792,7 +715,7 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk,
 
        disk->flags |= GENHD_FL_UP;
 
-       retval = blk_alloc_devt(&disk->part0, &devt);
+       retval = blk_alloc_devt(disk->part0, &devt);
        if (retval) {
                WARN_ON(1);
                return;
@@ -819,8 +742,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);
+               bdev_add(disk->part0, devt);
        }
        register_disk(parent, disk, groups);
        if (register_queue)
@@ -850,23 +772,16 @@ void device_add_disk_no_queue_reg(struct device *parent, struct gendisk *disk)
 }
 EXPORT_SYMBOL(device_add_disk_no_queue_reg);
 
-static void invalidate_partition(struct gendisk *disk, int partno)
+static void invalidate_partition(struct block_device *bdev)
 {
-       struct block_device *bdev;
-
-       bdev = bdget_disk(disk, partno);
-       if (!bdev)
-               return;
-
        fsync_bdev(bdev);
        __invalidate_device(bdev, true);
 
        /*
-        * Unhash the bdev inode for this device so that it gets evicted as soon
-        * as last inode reference is dropped.
+        * Unhash the bdev inode for this device so that it can't be looked
+        * up any more even if openers still hold references to it.
         */
        remove_inode_hash(bdev->bd_inode);
-       bdput(bdev);
 }
 
 /**
@@ -891,10 +806,13 @@ static void invalidate_partition(struct gendisk *disk, int partno)
 void del_gendisk(struct gendisk *disk)
 {
        struct disk_part_iter piter;
-       struct hd_struct *part;
+       struct block_device *part;
 
        might_sleep();
 
+       if (WARN_ON_ONCE(!disk->queue))
+               return;
+
        blk_integrity_del(disk);
        disk_del_events(disk);
 
@@ -902,50 +820,39 @@ void del_gendisk(struct gendisk *disk)
         * Block lookups of the disk until all bdevs are unhashed and the
         * disk is marked as dead (GENHD_FL_UP cleared).
         */
-       down_write(&disk->lookup_sem);
+       down_write(&bdev_lookup_sem);
+
        /* invalidate stuff */
        disk_part_iter_init(&piter, disk,
                             DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE);
        while ((part = disk_part_iter_next(&piter))) {
-               invalidate_partition(disk, part->partno);
+               invalidate_partition(part);
                delete_partition(part);
        }
        disk_part_iter_exit(&piter);
 
-       invalidate_partition(disk0);
+       invalidate_partition(disk->part0);
        set_capacity(disk, 0);
        disk->flags &= ~GENHD_FL_UP;
-       up_write(&disk->lookup_sem);
+       up_write(&bdev_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);
        }
 
-       if (!(disk->flags & GENHD_FL_HIDDEN))
-               blk_unregister_region(disk_devt(disk), disk->minors);
-       /*
-        * Remove gendisk pointer from idr so that it cannot be looked up
-        * while RCU period before freeing gendisk is running to prevent
-        * use-after-free issues. Note that the device number stays
-        * "in-use" until we really free the gendisk.
-        */
-       blk_invalidate_devt(disk_devt(disk));
+       blk_unregister_queue(disk);
 
-       kobject_put(disk->part0.holder_dir);
+       kobject_put(disk->part0->bd_holder_dir);
        kobject_put(disk->slave_dir);
 
-       part_stat_set_all(&disk->part0, 0);
-       disk->part0.stamp = 0;
+       part_stat_set_all(disk->part0, 0);
+       disk->part0->bd_stamp = 0;
        if (!sysfs_deprecated)
                sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk)));
        pm_runtime_set_memalloc_noio(disk_to_dev(disk), false);
@@ -978,57 +885,24 @@ static ssize_t disk_badblocks_store(struct device *dev,
        return badblocks_store(disk->bb, page, len, 0);
 }
 
-/**
- * get_gendisk - get partitioning information for a given device
- * @devt: device to get partitioning information for
- * @partno: returned partition index
- *
- * This function gets the structure containing partitioning
- * information for the given device @devt.
- *
- * Context: can sleep
- */
-struct gendisk *get_gendisk(dev_t devt, int *partno)
+void blk_request_module(dev_t devt)
 {
-       struct gendisk *disk = NULL;
-
-       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));
-       } else {
-               struct hd_struct *part;
+       unsigned int major = MAJOR(devt);
+       struct blk_major_name **n;
 
-               spin_lock_bh(&ext_devt_lock);
-               part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
-               if (part && get_disk_and_module(part_to_disk(part))) {
-                       *partno = part->partno;
-                       disk = part_to_disk(part);
+       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;
                }
-               spin_unlock_bh(&ext_devt_lock);
        }
+       mutex_unlock(&major_names_lock);
 
-       if (!disk)
-               return NULL;
-
-       /*
-        * Synchronize with del_gendisk() to not return disk that is being
-        * destroyed.
-        */
-       down_read(&disk->lookup_sem);
-       if (unlikely((disk->flags & GENHD_FL_HIDDEN) ||
-                    !(disk->flags & GENHD_FL_UP))) {
-               up_read(&disk->lookup_sem);
-               put_disk_and_module(disk);
-               disk = NULL;
-       } else {
-               up_read(&disk->lookup_sem);
-       }
-       return disk;
+       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));
 }
 
 /**
@@ -1046,17 +920,16 @@ struct gendisk *get_gendisk(dev_t devt, int *partno)
  */
 struct block_device *bdget_disk(struct gendisk *disk, int partno)
 {
-       struct hd_struct *part;
        struct block_device *bdev = NULL;
 
-       part = disk_get_part(disk, partno);
-       if (part)
-               bdev = bdget_part(part);
-       disk_put_part(part);
+       rcu_read_lock();
+       bdev = __disk_get_part(disk, partno);
+       if (bdev && !bdgrab(bdev))
+               bdev = NULL;
+       rcu_read_unlock();
 
        return bdev;
 }
-EXPORT_SYMBOL(bdget_disk);
 
 /*
  * print a full list of all partitions - intended for places where the root
@@ -1072,7 +945,7 @@ void __init printk_all_partitions(void)
        while ((dev = class_dev_iter_next(&iter))) {
                struct gendisk *disk = dev_to_disk(dev);
                struct disk_part_iter piter;
-               struct hd_struct *part;
+               struct block_device *part;
                char name_buf[BDEVNAME_SIZE];
                char devt_buf[BDEVT_SIZE];
 
@@ -1091,13 +964,14 @@ void __init printk_all_partitions(void)
                 */
                disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0);
                while ((part = disk_part_iter_next(&piter))) {
-                       bool is_part0 = part == &disk->part0;
+                       bool is_part0 = part == disk->part0;
 
                        printk("%s%s %10llu %s %s", is_part0 ? "" : "  ",
-                              bdevt_str(part_devt(part), devt_buf),
-                              (unsigned long long)part_nr_sects_read(part) >> 1
-                              , disk_name(disk, part->partno, name_buf),
-                              part->info ? part->info->uuid : "");
+                              bdevt_str(part->bd_dev, devt_buf),
+                              bdev_nr_sectors(part) >> 1,
+                              disk_name(disk, part->bd_partno, name_buf),
+                              part->bd_meta_info ?
+                                       part->bd_meta_info->uuid : "");
                        if (is_part0) {
                                if (dev->parent && dev->parent->driver)
                                        printk(" driver: %s\n",
@@ -1173,7 +1047,7 @@ static int show_partition(struct seq_file *seqf, void *v)
 {
        struct gendisk *sgp = v;
        struct disk_part_iter piter;
-       struct hd_struct *part;
+       struct block_device *part;
        char buf[BDEVNAME_SIZE];
 
        /* Don't show non-partitionable removeable devices or empty devices */
@@ -1187,9 +1061,9 @@ static int show_partition(struct seq_file *seqf, void *v)
        disk_part_iter_init(&piter, sgp, DISK_PITER_INCL_PART0);
        while ((part = disk_part_iter_next(&piter)))
                seq_printf(seqf, "%4d  %7d %10llu %s\n",
-                          MAJOR(part_devt(part)), MINOR(part_devt(part)),
-                          (unsigned long long)part_nr_sects_read(part) >> 1,
-                          disk_name(sgp, part->partno, buf));
+                          MAJOR(part->bd_dev), MINOR(part->bd_dev),
+                          bdev_nr_sectors(part) >> 1,
+                          disk_name(sgp, part->bd_partno, buf));
        disk_part_iter_exit(&piter);
 
        return 0;
@@ -1203,15 +1077,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 +1085,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");
@@ -1278,25 +1142,22 @@ static ssize_t disk_ro_show(struct device *dev,
 ssize_t part_size_show(struct device *dev,
                       struct device_attribute *attr, char *buf)
 {
-       struct hd_struct *p = dev_to_part(dev);
-
-       return sprintf(buf, "%llu\n",
-               (unsigned long long)part_nr_sects_read(p));
+       return sprintf(buf, "%llu\n", bdev_nr_sectors(dev_to_bdev(dev)));
 }
 
 ssize_t part_stat_show(struct device *dev,
                       struct device_attribute *attr, char *buf)
 {
-       struct hd_struct *p = dev_to_part(dev);
-       struct request_queue *q = part_to_disk(p)->queue;
+       struct block_device *bdev = dev_to_bdev(dev);
+       struct request_queue *q = bdev->bd_disk->queue;
        struct disk_stats stat;
        unsigned int inflight;
 
-       part_stat_read_all(p, &stat);
+       part_stat_read_all(bdev, &stat);
        if (queue_is_mq(q))
-               inflight = blk_mq_in_flight(q, p);
+               inflight = blk_mq_in_flight(q, bdev);
        else
-               inflight = part_in_flight(p);
+               inflight = part_in_flight(bdev);
 
        return sprintf(buf,
                "%8lu %8lu %8llu %8u "
@@ -1331,14 +1192,14 @@ ssize_t part_stat_show(struct device *dev,
 ssize_t part_inflight_show(struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
-       struct hd_struct *p = dev_to_part(dev);
-       struct request_queue *q = part_to_disk(p)->queue;
+       struct block_device *bdev = dev_to_bdev(dev);
+       struct request_queue *q = bdev->bd_disk->queue;
        unsigned int inflight[2];
 
        if (queue_is_mq(q))
-               blk_mq_in_flight_rw(q, p, inflight);
+               blk_mq_in_flight_rw(q, bdev, inflight);
        else
-               part_in_flight_rw(p, inflight);
+               part_in_flight_rw(bdev, inflight);
 
        return sprintf(buf, "%8u %8u\n", inflight[0], inflight[1]);
 }
@@ -1386,20 +1247,17 @@ static DEVICE_ATTR(badblocks, 0644, disk_badblocks_show, disk_badblocks_store);
 ssize_t part_fail_show(struct device *dev,
                       struct device_attribute *attr, char *buf)
 {
-       struct hd_struct *p = dev_to_part(dev);
-
-       return sprintf(buf, "%d\n", p->make_it_fail);
+       return sprintf(buf, "%d\n", dev_to_bdev(dev)->bd_make_it_fail);
 }
 
 ssize_t part_fail_store(struct device *dev,
                        struct device_attribute *attr,
                        const char *buf, size_t count)
 {
-       struct hd_struct *p = dev_to_part(dev);
        int i;
 
        if (count > 0 && sscanf(buf, "%d", &i) > 0)
-               p->make_it_fail = (i == 0) ? 0 : 1;
+               dev_to_bdev(dev)->bd_make_it_fail = i;
 
        return count;
 }
@@ -1538,11 +1396,6 @@ int disk_expand_part_tbl(struct gendisk *disk, int partno)
  *
  * This function releases all allocated resources of the gendisk.
  *
- * The struct gendisk refcount is incremented with get_gendisk() or
- * get_disk_and_module(), and its refcount is decremented with
- * put_disk_and_module() or put_disk(). Once the refcount reaches 0 this
- * function is called.
- *
  * Drivers which used __device_add_disk() have a gendisk with a request_queue
  * assigned. Since the request_queue sits on top of the gendisk for these
  * drivers we also call blk_put_queue() for them, and we expect the
@@ -1561,7 +1414,7 @@ static void disk_release(struct device *dev)
        disk_release_events(disk);
        kfree(disk->random);
        disk_replace_part_tbl(disk, NULL);
-       hd_free_part(&disk->part0);
+       bdput(disk->part0);
        if (disk->queue)
                blk_put_queue(disk->queue);
        kfree(disk);
@@ -1599,7 +1452,7 @@ static int diskstats_show(struct seq_file *seqf, void *v)
 {
        struct gendisk *gp = v;
        struct disk_part_iter piter;
-       struct hd_struct *hd;
+       struct block_device *hd;
        char buf[BDEVNAME_SIZE];
        unsigned int inflight;
        struct disk_stats stat;
@@ -1627,8 +1480,8 @@ static int diskstats_show(struct seq_file *seqf, void *v)
                           "%lu %lu %lu %u "
                           "%lu %u"
                           "\n",
-                          MAJOR(part_devt(hd)), MINOR(part_devt(hd)),
-                          disk_name(gp, hd->partno, buf),
+                          MAJOR(hd->bd_dev), MINOR(hd->bd_dev),
+                          disk_name(gp, hd->bd_partno, buf),
                           stat.ios[STAT_READ],
                           stat.merges[STAT_READ],
                           stat.sectors[STAT_READ],
@@ -1686,7 +1539,7 @@ dev_t blk_lookup_devt(const char *name, int partno)
        class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
        while ((dev = class_dev_iter_next(&iter))) {
                struct gendisk *disk = dev_to_disk(dev);
-               struct hd_struct *part;
+               struct block_device *part;
 
                if (strcmp(dev_name(dev), name))
                        continue;
@@ -1699,13 +1552,12 @@ dev_t blk_lookup_devt(const char *name, int partno)
                                     MINOR(dev->devt) + partno);
                        break;
                }
-               part = disk_get_part(disk, partno);
+               part = bdget_disk(disk, partno);
                if (part) {
-                       devt = part_devt(part);
-                       disk_put_part(part);
+                       devt = part->bd_dev;
+                       bdput(part);
                        break;
                }
-               disk_put_part(part);
        }
        class_dev_iter_exit(&iter);
        return devt;
@@ -1727,32 +1579,16 @@ struct gendisk *__alloc_disk_node(int minors, int node_id)
        if (!disk)
                return NULL;
 
-       disk->part0.dkstats = alloc_percpu(struct disk_stats);
-       if (!disk->part0.dkstats)
+       disk->part0 = bdev_alloc(disk, 0);
+       if (!disk->part0)
                goto out_free_disk;
 
-       init_rwsem(&disk->lookup_sem);
        disk->node_id = node_id;
-       if (disk_expand_part_tbl(disk, 0)) {
-               free_percpu(disk->part0.dkstats);
-               goto out_free_disk;
-       }
+       if (disk_expand_part_tbl(disk, 0))
+               goto out_bdput;
 
        ptbl = rcu_dereference_protected(disk->part_tbl, 1);
-       rcu_assign_pointer(ptbl->part[0], &disk->part0);
-
-       /*
-        * set_capacity() and get_capacity() currently don't use
-        * seqcounter to read/update the part0->nr_sects. Still init
-        * the counter as we can read the sectors in IO submission
-        * patch using seqence counters.
-        *
-        * TODO: Ideally set_capacity() and get_capacity() should be
-        * converted to make use of bd_mutex and sequence counters.
-        */
-       hd_sects_seq_init(&disk->part0);
-       if (hd_ref_init(&disk->part0))
-               goto out_free_part0;
+       rcu_assign_pointer(ptbl->part[0], disk->part0);
 
        disk->minors = minors;
        rand_initialize_disk(disk);
@@ -1761,43 +1597,14 @@ struct gendisk *__alloc_disk_node(int minors, int node_id)
        device_initialize(disk_to_dev(disk));
        return disk;
 
-out_free_part0:
-       hd_free_part(&disk->part0);
+out_bdput:
+       bdput(disk->part0);
 out_free_disk:
        kfree(disk);
        return NULL;
 }
 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
@@ -1811,31 +1618,10 @@ EXPORT_SYMBOL(get_disk_and_module);
 void put_disk(struct gendisk *disk)
 {
        if (disk)
-               kobject_put(&disk_to_dev(disk)->kobj);
+               put_device(disk_to_dev(disk));
 }
 EXPORT_SYMBOL(put_disk);
 
-/**
- * put_disk_and_module - decrements the module and gendisk refcount
- * @disk: the struct gendisk to decrement the refcount for
- *
- * This is a counterpart of get_disk_and_module() and thus also of
- * get_gendisk().
- *
- * Context: Any context, but the last reference must not be dropped from
- *          atomic context.
- */
-void put_disk_and_module(struct gendisk *disk)
-{
-       if (disk) {
-               struct module *owner = disk->fops->owner;
-
-               put_disk(disk);
-               module_put(owner);
-       }
-}
-EXPORT_SYMBOL(put_disk_and_module);
-
 static void set_disk_ro_uevent(struct gendisk *gd, int ro)
 {
        char event[] = "DISK_RO=1";
@@ -1846,26 +1632,19 @@ 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;
-       struct hd_struct *part;
+       struct block_device *part;
 
-       if (disk->part0.policy != flag) {
+       if (disk->part0->bd_read_only != flag) {
                set_disk_ro_uevent(disk, flag);
-               disk->part0.policy = flag;
+               disk->part0->bd_read_only = flag;
        }
 
        disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY);
        while ((part = disk_part_iter_next(&piter)))
-               part->policy = flag;
+               part->bd_read_only = flag;
        disk_part_iter_exit(&piter);
 }
 
@@ -1875,7 +1654,7 @@ int bdev_read_only(struct block_device *bdev)
 {
        if (!bdev)
                return 0;
-       return bdev->bd_part->policy;
+       return bdev->bd_read_only;
 }
 
 EXPORT_SYMBOL(bdev_read_only);