OSDN Git Service

net/x25: Fix null-ptr-deref caused by x25_disconnect
[uclinux-h8/linux.git] / block / genhd.c
index 9eca1f7..37eb41e 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/module.h>
 #include <linux/ctype.h>
 #include <linux/fs.h>
-#include <linux/genhd.h>
 #include <linux/kdev_t.h>
 #include <linux/kernel.h>
 #include <linux/blkdev.h>
 #include <linux/pm_runtime.h>
 #include <linux/badblocks.h>
 #include <linux/part_stat.h>
+#include "blk-throttle.h"
 
 #include "blk.h"
 #include "blk-mq-sched.h"
 #include "blk-rq-qos.h"
+#include "blk-cgroup.h"
 
 static struct kobject *block_depr;
 
@@ -185,7 +186,9 @@ static struct blk_major_name {
        struct blk_major_name *next;
        int major;
        char name[16];
+#ifdef CONFIG_BLOCK_LEGACY_AUTOLOAD
        void (*probe)(dev_t devt);
+#endif
 } *major_names[BLKDEV_MAJOR_HASH_SIZE];
 static DEFINE_MUTEX(major_names_lock);
 static DEFINE_SPINLOCK(major_names_spinlock);
@@ -275,7 +278,9 @@ int __register_blkdev(unsigned int major, const char *name,
        }
 
        p->major = major;
+#ifdef CONFIG_BLOCK_LEGACY_AUTOLOAD
        p->probe = probe;
+#endif
        strlcpy(p->name, name, sizeof(p->name));
        p->next = NULL;
        index = major_to_index(major);
@@ -523,6 +528,7 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
 
        disk_update_readahead(disk);
        disk_add_events(disk);
+       set_bit(GD_ADDED, &disk->state);
        return 0;
 
 out_unregister_bdi:
@@ -636,7 +642,8 @@ void del_gendisk(struct gendisk *disk)
 
        blk_mq_freeze_queue_wait(q);
 
-       rq_qos_exit(q);
+       blk_throtl_cancel_bios(disk->queue);
+
        blk_sync_queue(q);
        blk_flush_integrity();
        /*
@@ -693,6 +700,7 @@ static ssize_t disk_badblocks_store(struct device *dev,
        return badblocks_store(disk->bb, page, len, 0);
 }
 
+#ifdef CONFIG_BLOCK_LEGACY_AUTOLOAD
 void blk_request_module(dev_t devt)
 {
        unsigned int major = MAJOR(devt);
@@ -712,6 +720,7 @@ void blk_request_module(dev_t devt)
                /* Make old-style 2.4 aliases work */
                request_module("block-major-%d", MAJOR(devt));
 }
+#endif /* CONFIG_BLOCK_LEGACY_AUTOLOAD */
 
 /*
  * print a full list of all partitions - intended for places where the root
@@ -927,12 +936,17 @@ ssize_t part_stat_show(struct device *dev,
        struct disk_stats stat;
        unsigned int inflight;
 
-       part_stat_read_all(bdev, &stat);
        if (queue_is_mq(q))
                inflight = blk_mq_in_flight(q, bdev);
        else
                inflight = part_in_flight(bdev);
 
+       if (inflight) {
+               part_stat_lock();
+               update_io_ticks(bdev, jiffies, true);
+               part_stat_unlock();
+       }
+       part_stat_read_all(bdev, &stat);
        return sprintf(buf,
                "%8lu %8lu %8llu %8u "
                "%8lu %8lu %8llu %8u "
@@ -1100,6 +1114,31 @@ static const struct attribute_group *disk_attr_groups[] = {
        NULL
 };
 
+static void disk_release_mq(struct request_queue *q)
+{
+       blk_mq_cancel_work_sync(q);
+
+       /*
+        * There can't be any non non-passthrough bios in flight here, but
+        * requests stay around longer, including passthrough ones so we
+        * still need to freeze the queue here.
+        */
+       blk_mq_freeze_queue(q);
+
+       /*
+        * Since the I/O scheduler exit code may access cgroup information,
+        * perform I/O scheduler exit before disassociating from the block
+        * cgroup controller.
+        */
+       if (q->elevator) {
+               mutex_lock(&q->sysfs_lock);
+               elevator_exit(q);
+               mutex_unlock(&q->sysfs_lock);
+       }
+       rq_qos_exit(q);
+       __blk_mq_unfreeze_queue(q, true);
+}
+
 /**
  * disk_release - releases all allocated resources of the gendisk
  * @dev: the device representing this disk
@@ -1121,13 +1160,21 @@ static void disk_release(struct device *dev)
        might_sleep();
        WARN_ON_ONCE(disk_live(disk));
 
-       blk_mq_cancel_work_sync(disk->queue);
+       if (queue_is_mq(disk->queue))
+               disk_release_mq(disk->queue);
+
+       blkcg_exit_queue(disk->queue);
 
        disk_release_events(disk);
        kfree(disk->random);
        xa_destroy(&disk->part_tbl);
+
        disk->queue->disk = NULL;
        blk_put_queue(disk->queue);
+
+       if (test_bit(GD_ADDED, &disk->state) && disk->fops->free_disk)
+               disk->fops->free_disk(disk);
+
        iput(disk->part0->bd_inode);    /* frees the disk */
 }
 
@@ -1188,12 +1235,17 @@ static int diskstats_show(struct seq_file *seqf, void *v)
        xa_for_each(&gp->part_tbl, idx, hd) {
                if (bdev_is_partition(hd) && !bdev_nr_sectors(hd))
                        continue;
-               part_stat_read_all(hd, &stat);
                if (queue_is_mq(gp->queue))
                        inflight = blk_mq_in_flight(gp->queue, hd);
                else
                        inflight = part_in_flight(hd);
 
+               if (inflight) {
+                       part_stat_lock();
+                       update_io_ticks(hd, jiffies, true);
+                       part_stat_unlock();
+               }
+               part_stat_read_all(hd, &stat);
                seq_printf(seqf, "%4d %7d %pg "
                           "%lu %lu %lu %u "
                           "%lu %lu %lu %u "
@@ -1322,6 +1374,9 @@ struct gendisk *__alloc_disk_node(struct request_queue *q, int node_id,
        if (xa_insert(&disk->part_tbl, 0, disk->part0, GFP_KERNEL))
                goto out_destroy_part_tbl;
 
+       if (blkcg_init_queue(q))
+               goto out_erase_part0;
+
        rand_initialize_disk(disk);
        disk_to_dev(disk)->class = &block_class;
        disk_to_dev(disk)->type = &disk_type;
@@ -1334,6 +1389,8 @@ struct gendisk *__alloc_disk_node(struct request_queue *q, int node_id,
 #endif
        return disk;
 
+out_erase_part0:
+       xa_erase(&disk->part_tbl, 0);
 out_destroy_part_tbl:
        xa_destroy(&disk->part_tbl);
        disk->part0->bd_disk = NULL;