dm thin metadata: use pool locking at end of dm_pool_metadata_close
authorMike Snitzer <snitzer@redhat.com>
Mon, 13 Jan 2020 16:18:51 +0000 (11:18 -0500)
committerMike Snitzer <snitzer@redhat.com>
Wed, 15 Jan 2020 01:22:49 +0000 (20:22 -0500)
Ensure that the pool is locked during calls to __commit_transaction and
__destroy_persistent_data_objects.  Just being consistent with locking,
but reality is dm_pool_metadata_close is called once pool is being
destroyed so access to pool shouldn't be contended.

Also, use pmd_write_lock_in_core rather than __pmd_write_lock in
dm_pool_commit_metadata and rename __pmd_write_lock to
pmd_write_lock_in_core -- there was no need for the alias.

In addition, verify that the pool is locked in __commit_transaction().

Fixes: 873f258becca ("dm thin metadata: do not write metadata if no changes occurred")
Cc: stable@vger.kernel.org
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
drivers/md/dm-thin-metadata.c

index 4e44274..fc9947d 100644 (file)
@@ -387,16 +387,15 @@ static int subtree_equal(void *context, const void *value1_le, const void *value
  * Variant that is used for in-core only changes or code that
  * shouldn't put the pool in service on its own (e.g. commit).
  */
-static inline void __pmd_write_lock(struct dm_pool_metadata *pmd)
+static inline void pmd_write_lock_in_core(struct dm_pool_metadata *pmd)
        __acquires(pmd->root_lock)
 {
        down_write(&pmd->root_lock);
 }
-#define pmd_write_lock_in_core(pmd) __pmd_write_lock((pmd))
 
 static inline void pmd_write_lock(struct dm_pool_metadata *pmd)
 {
-       __pmd_write_lock(pmd);
+       pmd_write_lock_in_core(pmd);
        if (unlikely(!pmd->in_service))
                pmd->in_service = true;
 }
@@ -831,6 +830,7 @@ static int __commit_transaction(struct dm_pool_metadata *pmd)
         * We need to know if the thin_disk_superblock exceeds a 512-byte sector.
         */
        BUILD_BUG_ON(sizeof(struct thin_disk_superblock) > 512);
+       BUG_ON(!rwsem_is_locked(&pmd->root_lock));
 
        if (unlikely(!pmd->in_service))
                return 0;
@@ -953,6 +953,7 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
                return -EBUSY;
        }
 
+       pmd_write_lock_in_core(pmd);
        if (!dm_bm_is_read_only(pmd->bm) && !pmd->fail_io) {
                r = __commit_transaction(pmd);
                if (r < 0)
@@ -961,6 +962,7 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
        }
        if (!pmd->fail_io)
                __destroy_persistent_data_objects(pmd);
+       pmd_write_unlock(pmd);
 
        kfree(pmd);
        return 0;
@@ -1841,7 +1843,7 @@ int dm_pool_commit_metadata(struct dm_pool_metadata *pmd)
         * Care is taken to not have commit be what
         * triggers putting the thin-pool in-service.
         */
-       __pmd_write_lock(pmd);
+       pmd_write_lock_in_core(pmd);
        if (pmd->fail_io)
                goto out;