Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Khazhismel Kumykov <khazhy@google.com>
Cc: stable@vger.kernel.org

authored by

Khazhismel Kumykov and committed by
Mikulas Patocka
7a636b4f 1e1fd567

+20 -2
+20 -2
drivers/md/dm-ioctl.c
··· 1181 1181 suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG; 1182 1182 if (param->flags & DM_NOFLUSH_FLAG) 1183 1183 suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG; 1184 - if (!dm_suspended_md(md)) 1185 - dm_suspend(md, suspend_flags); 1184 + if (!dm_suspended_md(md)) { 1185 + r = dm_suspend(md, suspend_flags); 1186 + if (r) { 1187 + down_write(&_hash_lock); 1188 + hc = dm_get_mdptr(md); 1189 + if (hc && !hc->new_map) { 1190 + hc->new_map = new_map; 1191 + new_map = NULL; 1192 + } else { 1193 + r = -ENXIO; 1194 + } 1195 + up_write(&_hash_lock); 1196 + if (new_map) { 1197 + dm_sync_table(md); 1198 + dm_table_destroy(new_map); 1199 + } 1200 + dm_put(md); 1201 + return r; 1202 + } 1203 + } 1186 1204 1187 1205 old_size = dm_get_size(md); 1188 1206 old_map = dm_swap_table(md, new_map);