wait: fix false timeouts when using wait_event_timeout()
[firefly-linux-kernel-4.4.55.git] / block / genhd.c
index 3608289c8ecdc0c8506af62421ccaabbae38438b..a1b0b9012cd457acbc78dc67b7f9a1602102096c 100644 (file)
@@ -36,6 +36,7 @@ static DEFINE_IDR(ext_devt_idr);
 
 static struct device_type disk_type;
 
+static void disk_alloc_events(struct gendisk *disk);
 static void disk_add_events(struct gendisk *disk);
 static void disk_del_events(struct gendisk *disk);
 static void disk_release_events(struct gendisk *disk);
@@ -602,6 +603,8 @@ void add_disk(struct gendisk *disk)
        disk->major = MAJOR(devt);
        disk->first_minor = MINOR(devt);
 
+       disk_alloc_events(disk);
+
        /* Register BDI before referencing it from bdev */ 
        bdi = &disk->queue->backing_dev_info;
        bdi_register_dev(bdi, disk_devt(disk));
@@ -611,6 +614,12 @@ void add_disk(struct gendisk *disk)
        register_disk(disk);
        blk_register_queue(disk);
 
+       /*
+        * Take an extra ref on queue which will be put on disk_release()
+        * so that it sticks around as long as @disk is there.
+        */
+       WARN_ON_ONCE(blk_get_queue(disk->queue));
+
        retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj,
                                   "bdi");
        WARN_ON(retval);
@@ -735,7 +744,7 @@ void __init printk_all_partitions(void)
                struct hd_struct *part;
                char name_buf[BDEVNAME_SIZE];
                char devt_buf[BDEVT_SIZE];
-               u8 uuid[PARTITION_META_INFO_UUIDLTH * 2 + 1];
+               char uuid_buf[PARTITION_META_INFO_UUIDLTH * 2 + 5];
 
                /*
                 * Don't show empty devices or things that have been
@@ -754,14 +763,16 @@ void __init printk_all_partitions(void)
                while ((part = disk_part_iter_next(&piter))) {
                        bool is_part0 = part == &disk->part0;
 
-                       uuid[0] = 0;
+                       uuid_buf[0] = '\0';
                        if (part->info)
-                               part_unpack_uuid(part->info->uuid, uuid);
+                               snprintf(uuid_buf, sizeof(uuid_buf), "%pU",
+                                        part->info->uuid);
 
                        printk("%s%s %10llu %s %s", is_part0 ? "" : "  ",
                               bdevt_str(part_devt(part), devt_buf),
                               (unsigned long long)part->nr_sects >> 1,
-                              disk_name(disk, part->partno, name_buf), uuid);
+                              disk_name(disk, part->partno, name_buf),
+                              uuid_buf);
                        if (is_part0) {
                                if (disk->driverfs_dev != NULL &&
                                    disk->driverfs_dev->driver != NULL)
@@ -1103,8 +1114,26 @@ static void disk_release(struct device *dev)
        disk_replace_part_tbl(disk, NULL);
        free_part_stats(&disk->part0);
        free_part_info(&disk->part0);
+       if (disk->queue)
+               blk_put_queue(disk->queue);
        kfree(disk);
 }
+
+static int disk_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct gendisk *disk = dev_to_disk(dev);
+       struct disk_part_iter piter;
+       struct hd_struct *part;
+       int cnt = 0;
+
+       disk_part_iter_init(&piter, disk, 0);
+       while((part = disk_part_iter_next(&piter)))
+               cnt++;
+       disk_part_iter_exit(&piter);
+       add_uevent_var(env, "NPARTS=%u", cnt);
+       return 0;
+}
+
 struct class block_class = {
        .name           = "block",
 };
@@ -1123,6 +1152,7 @@ static struct device_type disk_type = {
        .groups         = disk_attr_groups,
        .release        = disk_release,
        .devnode        = block_devnode,
+       .uevent         = disk_uevent,
 };
 
 #ifdef CONFIG_PROC_FS
@@ -1476,9 +1506,9 @@ static void __disk_unblock_events(struct gendisk *disk, bool check_now)
        intv = disk_events_poll_jiffies(disk);
        set_timer_slack(&ev->dwork.timer, intv / 4);
        if (check_now)
-               queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
+               queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0);
        else if (intv)
-               queue_delayed_work(system_nrt_wq, &ev->dwork, intv);
+               queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, intv);
 out_unlock:
        spin_unlock_irqrestore(&ev->lock, flags);
 }
@@ -1519,7 +1549,7 @@ void disk_check_events(struct gendisk *disk)
        spin_lock_irqsave(&ev->lock, flags);
        if (!ev->block) {
                cancel_delayed_work(&ev->dwork);
-               queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
+               queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0);
        }
        spin_unlock_irqrestore(&ev->lock, flags);
 }
@@ -1557,7 +1587,7 @@ unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
 
        /* uncondtionally schedule event check and wait for it to finish */
        disk_block_events(disk);
-       queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
+       queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0);
        flush_delayed_work(&ev->dwork);
        __disk_unblock_events(disk, false);
 
@@ -1594,7 +1624,7 @@ static void disk_events_workfn(struct work_struct *work)
 
        intv = disk_events_poll_jiffies(disk);
        if (!ev->block && intv)
-               queue_delayed_work(system_nrt_wq, &ev->dwork, intv);
+               queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, intv);
 
        spin_unlock_irq(&ev->lock);
 
@@ -1732,9 +1762,9 @@ module_param_cb(events_dfl_poll_msecs, &disk_events_dfl_poll_msecs_param_ops,
                &disk_events_dfl_poll_msecs, 0644);
 
 /*
- * disk_{add|del|release}_events - initialize and destroy disk_events.
+ * disk_{alloc|add|del|release}_events - initialize and destroy disk_events.
  */
-static void disk_add_events(struct gendisk *disk)
+static void disk_alloc_events(struct gendisk *disk)
 {
        struct disk_events *ev;
 
@@ -1747,16 +1777,6 @@ static void disk_add_events(struct gendisk *disk)
                return;
        }
 
-       if (sysfs_create_files(&disk_to_dev(disk)->kobj,
-                              disk_events_attrs) < 0) {
-               pr_warn("%s: failed to create sysfs files for events\n",
-                       disk->disk_name);
-               kfree(ev);
-               return;
-       }
-
-       disk->ev = ev;
-
        INIT_LIST_HEAD(&ev->node);
        ev->disk = disk;
        spin_lock_init(&ev->lock);
@@ -1765,8 +1785,21 @@ static void disk_add_events(struct gendisk *disk)
        ev->poll_msecs = -1;
        INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn);
 
+       disk->ev = ev;
+}
+
+static void disk_add_events(struct gendisk *disk)
+{
+       if (!disk->ev)
+               return;
+
+       /* FIXME: error handling */
+       if (sysfs_create_files(&disk_to_dev(disk)->kobj, disk_events_attrs) < 0)
+               pr_warn("%s: failed to create sysfs files for events\n",
+                       disk->disk_name);
+
        mutex_lock(&disk_events_mutex);
-       list_add_tail(&ev->node, &disk_events);
+       list_add_tail(&disk->ev->node, &disk_events);
        mutex_unlock(&disk_events_mutex);
 
        /*