These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / md / dm-thin-metadata.c
index cde1d67..c219a05 100644 (file)
@@ -184,7 +184,6 @@ struct dm_pool_metadata {
        uint64_t trans_id;
        unsigned long flags;
        sector_t data_block_size;
-       bool read_only:1;
 
        /*
         * Set if a transaction has to be aborted but the attempt to roll back
@@ -397,7 +396,9 @@ static int __superblock_all_zeroes(struct dm_block_manager *bm, int *result)
                }
        }
 
-       return dm_bm_unlock(b);
+       dm_bm_unlock(b);
+
+       return 0;
 }
 
 static void __setup_btree_details(struct dm_pool_metadata *pmd)
@@ -651,7 +652,9 @@ static int __open_metadata(struct dm_pool_metadata *pmd)
        }
 
        __setup_btree_details(pmd);
-       return dm_bm_unlock(sblock);
+       dm_bm_unlock(sblock);
+
+       return 0;
 
 bad_cleanup_data_sm:
        dm_sm_destroy(pmd->data_sm);
@@ -836,7 +839,6 @@ struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,
        init_rwsem(&pmd->root_lock);
        pmd->time = 0;
        INIT_LIST_HEAD(&pmd->thin_devices);
-       pmd->read_only = false;
        pmd->fail_io = false;
        pmd->bdev = bdev;
        pmd->data_block_size = data_block_size;
@@ -880,7 +882,7 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
                return -EBUSY;
        }
 
-       if (!pmd->read_only && !pmd->fail_io) {
+       if (!dm_bm_is_read_only(pmd->bm) && !pmd->fail_io) {
                r = __commit_transaction(pmd);
                if (r < 0)
                        DMWARN("%s: __commit_transaction() failed, error = %d",
@@ -1204,6 +1206,12 @@ static int __reserve_metadata_snap(struct dm_pool_metadata *pmd)
        struct dm_block *copy, *sblock;
        dm_block_t held_root;
 
+       /*
+        * We commit to ensure the btree roots which we increment in a
+        * moment are up to date.
+        */
+       __commit_transaction(pmd);
+
        /*
         * Copy the superblock.
         */
@@ -1299,7 +1307,9 @@ static int __release_metadata_snap(struct dm_pool_metadata *pmd)
        dm_btree_del(&pmd->details_info, le64_to_cpu(disk_super->device_details_root));
        dm_sm_dec_block(pmd->metadata_sm, held_root);
 
-       return dm_tm_unlock(pmd->tm, copy);
+       dm_tm_unlock(pmd->tm, copy);
+
+       return 0;
 }
 
 int dm_pool_release_metadata_snap(struct dm_pool_metadata *pmd)
@@ -1329,7 +1339,9 @@ static int __get_metadata_snap(struct dm_pool_metadata *pmd,
        disk_super = dm_block_data(sblock);
        *result = le64_to_cpu(disk_super->held_root);
 
-       return dm_bm_unlock(sblock);
+       dm_bm_unlock(sblock);
+
+       return 0;
 }
 
 int dm_pool_get_metadata_snap(struct dm_pool_metadata *pmd,
@@ -1392,10 +1404,11 @@ int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block,
        dm_block_t keys[2] = { td->id, block };
        struct dm_btree_info *info;
 
-       if (pmd->fail_io)
-               return -EINVAL;
-
        down_read(&pmd->root_lock);
+       if (pmd->fail_io) {
+               up_read(&pmd->root_lock);
+               return -EINVAL;
+       }
 
        if (can_issue_io) {
                info = &pmd->info;
@@ -1419,6 +1432,63 @@ int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block,
        return r;
 }
 
+/* FIXME: write a more efficient one in btree */
+int dm_thin_find_mapped_range(struct dm_thin_device *td,
+                             dm_block_t begin, dm_block_t end,
+                             dm_block_t *thin_begin, dm_block_t *thin_end,
+                             dm_block_t *pool_begin, bool *maybe_shared)
+{
+       int r;
+       dm_block_t pool_end;
+       struct dm_thin_lookup_result lookup;
+
+       if (end < begin)
+               return -ENODATA;
+
+       /*
+        * Find first mapped block.
+        */
+       while (begin < end) {
+               r = dm_thin_find_block(td, begin, true, &lookup);
+               if (r) {
+                       if (r != -ENODATA)
+                               return r;
+               } else
+                       break;
+
+               begin++;
+       }
+
+       if (begin == end)
+               return -ENODATA;
+
+       *thin_begin = begin;
+       *pool_begin = lookup.block;
+       *maybe_shared = lookup.shared;
+
+       begin++;
+       pool_end = *pool_begin + 1;
+       while (begin != end) {
+               r = dm_thin_find_block(td, begin, true, &lookup);
+               if (r) {
+                       if (r == -ENODATA)
+                               break;
+                       else
+                               return r;
+               }
+
+               if ((lookup.block != pool_end) ||
+                   (lookup.shared != *maybe_shared))
+                       break;
+
+               pool_end++;
+               begin++;
+       }
+
+       *thin_end = begin;
+       return 0;
+}
+
 static int __insert(struct dm_thin_device *td, dm_block_t block,
                    dm_block_t data_block)
 {
@@ -1471,6 +1541,65 @@ static int __remove(struct dm_thin_device *td, dm_block_t block)
        return 0;
 }
 
+static int __remove_range(struct dm_thin_device *td, dm_block_t begin, dm_block_t end)
+{
+       int r;
+       unsigned count, total_count = 0;
+       struct dm_pool_metadata *pmd = td->pmd;
+       dm_block_t keys[1] = { td->id };
+       __le64 value;
+       dm_block_t mapping_root;
+
+       /*
+        * Find the mapping tree
+        */
+       r = dm_btree_lookup(&pmd->tl_info, pmd->root, keys, &value);
+       if (r)
+               return r;
+
+       /*
+        * Remove from the mapping tree, taking care to inc the
+        * ref count so it doesn't get deleted.
+        */
+       mapping_root = le64_to_cpu(value);
+       dm_tm_inc(pmd->tm, mapping_root);
+       r = dm_btree_remove(&pmd->tl_info, pmd->root, keys, &pmd->root);
+       if (r)
+               return r;
+
+       /*
+        * Remove leaves stops at the first unmapped entry, so we have to
+        * loop round finding mapped ranges.
+        */
+       while (begin < end) {
+               r = dm_btree_lookup_next(&pmd->bl_info, mapping_root, &begin, &begin, &value);
+               if (r == -ENODATA)
+                       break;
+
+               if (r)
+                       return r;
+
+               if (begin >= end)
+                       break;
+
+               r = dm_btree_remove_leaves(&pmd->bl_info, mapping_root, &begin, end, &mapping_root, &count);
+               if (r)
+                       return r;
+
+               total_count += count;
+       }
+
+       td->mapped_blocks -= total_count;
+       td->changed = 1;
+
+       /*
+        * Reinsert the mapping tree.
+        */
+       value = cpu_to_le64(mapping_root);
+       __dm_bless_for_disk(&value);
+       return dm_btree_insert(&pmd->tl_info, pmd->root, keys, &value, &pmd->root);
+}
+
 int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block)
 {
        int r = -EINVAL;
@@ -1483,6 +1612,19 @@ int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block)
        return r;
 }
 
+int dm_thin_remove_range(struct dm_thin_device *td,
+                        dm_block_t begin, dm_block_t end)
+{
+       int r = -EINVAL;
+
+       down_write(&td->pmd->root_lock);
+       if (!td->pmd->fail_io)
+               r = __remove_range(td, begin, end);
+       up_write(&td->pmd->root_lock);
+
+       return r;
+}
+
 int dm_pool_block_is_used(struct dm_pool_metadata *pmd, dm_block_t b, bool *result)
 {
        int r;
@@ -1739,7 +1881,6 @@ int dm_pool_resize_metadata_dev(struct dm_pool_metadata *pmd, dm_block_t new_cou
 void dm_pool_metadata_read_only(struct dm_pool_metadata *pmd)
 {
        down_write(&pmd->root_lock);
-       pmd->read_only = true;
        dm_bm_set_read_only(pmd->bm);
        up_write(&pmd->root_lock);
 }
@@ -1747,7 +1888,6 @@ void dm_pool_metadata_read_only(struct dm_pool_metadata *pmd)
 void dm_pool_metadata_read_write(struct dm_pool_metadata *pmd)
 {
        down_write(&pmd->root_lock);
-       pmd->read_only = false;
        dm_bm_set_read_write(pmd->bm);
        up_write(&pmd->root_lock);
 }