dm: allow remove to be deferred
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / md / dm-ioctl.c
index afe0814..5152142 100644 (file)
@@ -57,7 +57,7 @@ struct vers_iter {
 static struct list_head _name_buckets[NUM_BUCKETS];
 static struct list_head _uuid_buckets[NUM_BUCKETS];
 
-static void dm_hash_remove_all(int keep_open_devices);
+static void dm_hash_remove_all(bool keep_open_devices, bool mark_deferred, bool only_deferred);
 
 /*
  * Guards access to both hash tables.
@@ -86,7 +86,7 @@ static int dm_hash_init(void)
 
 static void dm_hash_exit(void)
 {
-       dm_hash_remove_all(0);
+       dm_hash_remove_all(false, false, false);
 }
 
 /*-----------------------------------------------------------------
@@ -276,7 +276,7 @@ static struct dm_table *__hash_remove(struct hash_cell *hc)
        return table;
 }
 
-static void dm_hash_remove_all(int keep_open_devices)
+static void dm_hash_remove_all(bool keep_open_devices, bool mark_deferred, bool only_deferred)
 {
        int i, dev_skipped;
        struct hash_cell *hc;
@@ -293,7 +293,8 @@ retry:
                        md = hc->md;
                        dm_get(md);
 
-                       if (keep_open_devices && dm_lock_for_deletion(md)) {
+                       if (keep_open_devices &&
+                           dm_lock_for_deletion(md, mark_deferred, only_deferred)) {
                                dm_put(md);
                                dev_skipped++;
                                continue;
@@ -450,6 +451,11 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
        return md;
 }
 
+void dm_deferred_remove(void)
+{
+       dm_hash_remove_all(true, false, true);
+}
+
 /*-----------------------------------------------------------------
  * Implementation of the ioctl commands
  *---------------------------------------------------------------*/
@@ -461,7 +467,7 @@ typedef int (*ioctl_fn)(struct dm_ioctl *param, size_t param_size);
 
 static int remove_all(struct dm_ioctl *param, size_t param_size)
 {
-       dm_hash_remove_all(1);
+       dm_hash_remove_all(true, !!(param->flags & DM_DEFERRED_REMOVE), false);
        param->data_size = 0;
        return 0;
 }
@@ -683,6 +689,9 @@ static void __dev_status(struct mapped_device *md, struct dm_ioctl *param)
        if (dm_suspended_md(md))
                param->flags |= DM_SUSPEND_FLAG;
 
+       if (dm_test_deferred_remove_flag(md))
+               param->flags |= DM_DEFERRED_REMOVE;
+
        param->dev = huge_encode_dev(disk_devt(disk));
 
        /*
@@ -832,8 +841,13 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
        /*
         * Ensure the device is not open and nothing further can open it.
         */
-       r = dm_lock_for_deletion(md);
+       r = dm_lock_for_deletion(md, !!(param->flags & DM_DEFERRED_REMOVE), false);
        if (r) {
+               if (r == -EBUSY && param->flags & DM_DEFERRED_REMOVE) {
+                       up_write(&_hash_lock);
+                       dm_put(md);
+                       return 0;
+               }
                DMDEBUG_LIMIT("unable to remove open device %s", hc->name);
                up_write(&_hash_lock);
                dm_put(md);
@@ -848,6 +862,8 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
                dm_table_destroy(t);
        }
 
+       param->flags &= ~DM_DEFERRED_REMOVE;
+
        if (!dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr))
                param->flags |= DM_UEVENT_GENERATED_FLAG;
 
@@ -1469,6 +1485,14 @@ static int message_for_md(struct mapped_device *md, unsigned argc, char **argv,
        if (**argv != '@')
                return 2; /* no '@' prefix, deliver to target */
 
+       if (!strcasecmp(argv[0], "@cancel_deferred_remove")) {
+               if (argc != 1) {
+                       DMERR("Invalid arguments for @cancel_deferred_remove");
+                       return -EINVAL;
+               }
+               return dm_cancel_deferred_remove(md);
+       }
+
        r = dm_stats_message(md, argc, argv, result, maxlen);
        if (r < 2)
                return r;