Skip to content

Commit 9ae6e8b

Browse files
ntsironMike Snitzer
authored andcommitted
dm era: commit metadata in postsuspend after worker stops
During postsuspend dm-era does the following: 1. Archives the current era 2. Commits the metadata, as part of the RPC call for archiving the current era 3. Stops the worker Until the worker stops, it might write to the metadata again. Moreover, these writes are not flushed to disk immediately, but are cached by the dm-bufio client, which writes them back asynchronously. As a result, the committed metadata of a suspended dm-era device might not be consistent with the in-core metadata. In some cases, this can result in the corruption of the on-disk metadata. Suppose the following sequence of events: 1. Load a new table, e.g. a snapshot-origin table, to a device with a dm-era table 2. Suspend the device 3. dm-era commits its metadata, but the worker does a few more metadata writes until it stops, as part of digesting an archived writeset 4. These writes are cached by the dm-bufio client 5. Load the dm-era table to another device. 6. The new instance of the dm-era target loads the committed, on-disk metadata, which don't include the extra writes done by the worker after the metadata commit. 7. Resume the new device 8. The new dm-era target instance starts using the metadata 9. Resume the original device 10. The destructor of the old dm-era target instance is called and destroys the dm-bufio client, which results in flushing the cached writes to disk 11. These writes might overwrite the writes done by the new dm-era instance, hence corrupting its metadata. Fix this by committing the metadata after the worker stops running. stop_worker uses flush_workqueue to flush the current work. However, the work item may re-queue itself and flush_workqueue doesn't wait for re-queued works to finish. This could result in the worker changing the metadata after they have been committed, or writing to the metadata concurrently with the commit in the postsuspend thread. Use drain_workqueue instead, which waits until the work and all re-queued works finish. Fixes: eec4057 ("dm: add era target") Cc: [email protected] # v3.15+ Signed-off-by: Nikos Tsironis <[email protected]> Signed-off-by: Mike Snitzer <[email protected]>
1 parent a111daf commit 9ae6e8b

File tree

1 file changed

+7
-1
lines changed

1 file changed

+7
-1
lines changed

drivers/md/dm-era-target.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1400,7 +1400,7 @@ static void start_worker(struct era *era)
14001400
static void stop_worker(struct era *era)
14011401
{
14021402
atomic_set(&era->suspended, 1);
1403-
flush_workqueue(era->wq);
1403+
drain_workqueue(era->wq);
14041404
}
14051405

14061406
/*----------------------------------------------------------------
@@ -1570,6 +1570,12 @@ static void era_postsuspend(struct dm_target *ti)
15701570
}
15711571

15721572
stop_worker(era);
1573+
1574+
r = metadata_commit(era->md);
1575+
if (r) {
1576+
DMERR("%s: metadata_commit failed", __func__);
1577+
/* FIXME: fail mode */
1578+
}
15731579
}
15741580

15751581
static int era_preresume(struct dm_target *ti)

0 commit comments

Comments
 (0)