Commit 7a636b4f authored by Khazhismel Kumykov's avatar Khazhismel Kumykov Committed by Mikulas Patocka
Browse files

dm resume: don't return EINVAL when signalled



If the dm_resume method is called on a device that is not suspended, the
method will suspend the device briefly, before resuming it (so that the
table will be swapped).

However, there was a bug that the return value of dm_suspended_md was not
checked. dm_suspended_md may return an error when it is interrupted by a
signal. In this case, do_resume would call dm_swap_table, which would
return -EINVAL.

This commit fixes the logic, so that error returned by dm_suspend is
checked and the resume operation is undone.

Signed-off-by: default avatarMikulas Patocka <mpatocka@redhat.com>
Signed-off-by: default avatarKhazhismel Kumykov <khazhy@google.com>
Cc: stable@vger.kernel.org
parent 1e1fd567
Loading
Loading
Loading
Loading
+20 −2
Original line number Diff line number Diff line
@@ -1181,8 +1181,26 @@ static int do_resume(struct dm_ioctl *param)
			suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG;
		if (param->flags & DM_NOFLUSH_FLAG)
			suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG;
		if (!dm_suspended_md(md))
			dm_suspend(md, suspend_flags);
		if (!dm_suspended_md(md)) {
			r = dm_suspend(md, suspend_flags);
			if (r) {
				down_write(&_hash_lock);
				hc = dm_get_mdptr(md);
				if (hc && !hc->new_map) {
					hc->new_map = new_map;
					new_map = NULL;
				} else {
					r = -ENXIO;
				}
				up_write(&_hash_lock);
				if (new_map) {
					dm_sync_table(md);
					dm_table_destroy(new_map);
				}
				dm_put(md);
				return r;
			}
		}

		old_size = dm_get_size(md);
		old_map = dm_swap_table(md, new_map);