Merge tag 'v3.10.99' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / md / dm-thin-metadata.c
index 60bce435f4fa1443c2994bd483e70ea096c7aa92..4bf9211b2740776bddec39ac9ea957825e246048 100644 (file)
@@ -591,6 +591,15 @@ static int __open_metadata(struct dm_pool_metadata *pmd)
 
        disk_super = dm_block_data(sblock);
 
+       /* Verify the data block size hasn't changed */
+       if (le32_to_cpu(disk_super->data_block_size) != pmd->data_block_size) {
+               DMERR("changing the data block size (from %u to %llu) is not supported",
+                     le32_to_cpu(disk_super->data_block_size),
+                     (unsigned long long)pmd->data_block_size);
+               r = -EINVAL;
+               goto bad_unlock_sblock;
+       }
+
        r = __check_incompat_features(disk_super, pmd);
        if (r < 0)
                goto bad_unlock_sblock;
@@ -1181,6 +1190,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.
         */
@@ -1272,8 +1287,8 @@ static int __release_metadata_snap(struct dm_pool_metadata *pmd)
                return r;
 
        disk_super = dm_block_data(copy);
-       dm_sm_dec_block(pmd->metadata_sm, le64_to_cpu(disk_super->data_mapping_root));
-       dm_sm_dec_block(pmd->metadata_sm, le64_to_cpu(disk_super->device_details_root));
+       dm_btree_del(&pmd->info, le64_to_cpu(disk_super->data_mapping_root));
+       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);
@@ -1349,6 +1364,12 @@ dm_thin_id dm_thin_dev_id(struct dm_thin_device *td)
        return td->id;
 }
 
+/*
+ * Check whether @time (of block creation) is older than @td's last snapshot.
+ * If so then the associated block is shared with the last snapshot device.
+ * Any block on a device created *after* the device last got snapshotted is
+ * necessarily not shared.
+ */
 static bool __snapshotted_since(struct dm_thin_device *td, uint32_t time)
 {
        return td->snapshotted_time > time;
@@ -1458,6 +1479,20 @@ int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block)
        return r;
 }
 
+int dm_pool_block_is_used(struct dm_pool_metadata *pmd, dm_block_t b, bool *result)
+{
+       int r;
+       uint32_t ref_count;
+
+       down_read(&pmd->root_lock);
+       r = dm_sm_get_count(pmd->data_sm, b, &ref_count);
+       if (!r)
+               *result = (ref_count != 0);
+       up_read(&pmd->root_lock);
+
+       return r;
+}
+
 bool dm_thin_changed_this_transaction(struct dm_thin_device *td)
 {
        int r;
@@ -1469,6 +1504,23 @@ bool dm_thin_changed_this_transaction(struct dm_thin_device *td)
        return r;
 }
 
+bool dm_pool_changed_this_transaction(struct dm_pool_metadata *pmd)
+{
+       bool r = false;
+       struct dm_thin_device *td, *tmp;
+
+       down_read(&pmd->root_lock);
+       list_for_each_entry_safe(td, tmp, &pmd->thin_devices, list) {
+               if (td->changed) {
+                       r = td->changed;
+                       break;
+               }
+       }
+       up_read(&pmd->root_lock);
+
+       return r;
+}
+
 bool dm_thin_aborted_changes(struct dm_thin_device *td)
 {
        bool r;