Commit 873f258b authored by Mike Snitzer's avatar Mike Snitzer

dm thin metadata: do not write metadata if no changes occurred

Otherwise, just activating a thin-pool and thin device and then
deactivating them will cause the thin-pool metadata to be changed
(e.g. superblock written) -- even without any metadata being changed.

Add 'in_service' flag to struct dm_pool_metadata and set it in
pmd_write_lock() because all on-disk metadata changes must take a write
lock of pmd->root_lock.  Once 'in_service' is set it is never cleared.
__commit_transaction() will return 0 if 'in_service' is not set.
dm_pool_commit_metadata() is updated to use __pmd_write_lock() so that
it isn't the sole reason for putting a thin-pool in service.

Also fix dm_pool_commit_metadata() to open the next transaction if the
return from __commit_transaction() is 0.  Not seeing why the early
return ever made since for a return of 0 given that dm-io's async_io(),
as used by bufio, always returns 0.
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
parent 6a1b1ddc
...@@ -201,6 +201,13 @@ struct dm_pool_metadata { ...@@ -201,6 +201,13 @@ struct dm_pool_metadata {
*/ */
bool fail_io:1; bool fail_io:1;
/*
* Set once a thin-pool has been accessed through one of the interfaces
* that imply the pool is in-service (e.g. thin devices created/deleted,
* thin-pool message, metadata snapshots, etc).
*/
bool in_service:1;
/* /*
* Reading the space map roots can fail, so we read it into these * Reading the space map roots can fail, so we read it into these
* buffers before the superblock is locked and updated. * buffers before the superblock is locked and updated.
...@@ -367,6 +374,10 @@ static int subtree_equal(void *context, const void *value1_le, const void *value ...@@ -367,6 +374,10 @@ 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(struct dm_pool_metadata *pmd)
__acquires(pmd->root_lock) __acquires(pmd->root_lock)
{ {
...@@ -377,6 +388,8 @@ static inline void __pmd_write_lock(struct dm_pool_metadata *pmd) ...@@ -377,6 +388,8 @@ static inline void __pmd_write_lock(struct dm_pool_metadata *pmd)
static inline void pmd_write_lock(struct dm_pool_metadata *pmd) static inline void pmd_write_lock(struct dm_pool_metadata *pmd)
{ {
__pmd_write_lock(pmd); __pmd_write_lock(pmd);
if (unlikely(!pmd->in_service))
pmd->in_service = true;
} }
static inline void pmd_write_unlock(struct dm_pool_metadata *pmd) static inline void pmd_write_unlock(struct dm_pool_metadata *pmd)
...@@ -810,6 +823,9 @@ static int __commit_transaction(struct dm_pool_metadata *pmd) ...@@ -810,6 +823,9 @@ static int __commit_transaction(struct dm_pool_metadata *pmd)
*/ */
BUILD_BUG_ON(sizeof(struct thin_disk_superblock) > 512); BUILD_BUG_ON(sizeof(struct thin_disk_superblock) > 512);
if (unlikely(!pmd->in_service))
return 0;
r = __write_changed_details(pmd); r = __write_changed_details(pmd);
if (r < 0) if (r < 0)
return r; return r;
...@@ -873,6 +889,7 @@ struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev, ...@@ -873,6 +889,7 @@ struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,
pmd->time = 0; pmd->time = 0;
INIT_LIST_HEAD(&pmd->thin_devices); INIT_LIST_HEAD(&pmd->thin_devices);
pmd->fail_io = false; pmd->fail_io = false;
pmd->in_service = false;
pmd->bdev = bdev; pmd->bdev = bdev;
pmd->data_block_size = data_block_size; pmd->data_block_size = data_block_size;
...@@ -923,7 +940,6 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd) ...@@ -923,7 +940,6 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
DMWARN("%s: __commit_transaction() failed, error = %d", DMWARN("%s: __commit_transaction() failed, error = %d",
__func__, r); __func__, r);
} }
if (!pmd->fail_io) if (!pmd->fail_io)
__destroy_persistent_data_objects(pmd); __destroy_persistent_data_objects(pmd);
...@@ -1802,12 +1818,16 @@ int dm_pool_commit_metadata(struct dm_pool_metadata *pmd) ...@@ -1802,12 +1818,16 @@ int dm_pool_commit_metadata(struct dm_pool_metadata *pmd)
{ {
int r = -EINVAL; int r = -EINVAL;
pmd_write_lock(pmd); /*
* Care is taken to not have commit be what
* triggers putting the thin-pool in-service.
*/
__pmd_write_lock(pmd);
if (pmd->fail_io) if (pmd->fail_io)
goto out; goto out;
r = __commit_transaction(pmd); r = __commit_transaction(pmd);
if (r <= 0) if (r < 0)
goto out; goto out;
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment