@@ -82,9 +82,10 @@ struct dm_snapshot {
*
* 'is_handover_destination' is set in snapshot_ctr if an existing
* snapshot has the same cow device. The handover is performed,
- * and 'is_handover_destination' is cleared, when either of the
+ * and 'is_handover_destination' is cleared, when one of the
* following occurs:
* - src (old) snapshot, that is handing over, is destructed
+ * - src (old) snapshot, that is handing over, is resumed
* - dest (new) snapshot, that is accepting the handover, is resumed
*/
int is_handover_destination;
@@ -1379,23 +1380,28 @@ static void snapshot_presuspend(struct dm_target *ti)
static void snapshot_resume(struct dm_target *ti)
{
struct dm_snapshot *s = ti->private;
- struct dm_snapshot *old_snap, *new_snap = NULL;
+ struct dm_snapshot *lock_snap, *old_snap, *new_snap = NULL;
down_write(&s->lock);
if (s->handover_snap) {
- if (!s->is_handover_destination) {
- DMERR("Unable to handover exceptions to "
- "another snapshot on resume.");
- goto out;
- }
- /* Get exception store from another snapshot */
+ /*
+ * Initially assumes this snapshot will get
+ * exception store from another snapshot
+ */
old_snap = s->handover_snap;
new_snap = s;
+ lock_snap = old_snap;
- down_write_nested(&old_snap->lock,
+ if (!s->is_handover_destination) {
+ /* Handover exceptions to another snapshot */
+ old_snap = s;
+ new_snap = s->handover_snap;
+ lock_snap = new_snap;
+ }
+ down_write_nested(&lock_snap->lock,
SINGLE_DEPTH_NESTING);
handover_exceptions(old_snap, new_snap);
- up_write(&old_snap->lock);
+ up_write(&lock_snap->lock);
}
/* An incomplete exception handover is not allowed */
BUG_ON(s->handover_snap);