If call to ext4_init_io_end() is failed under memory pressure,
mpage_da_submit_io() just returns -ENOMEM and left all pages
from the extent locked. That leads to a deadlock as soon as
callers of mpage_da_submit_io() expect it unlocks all the pages.

Found by Linux File System Verification project (linuxtesting.org).

Signed-off-by: Alexey Khoroshilov <khoroshi...@ispras.ru>
---
 fs/ext4/inode.c |   16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 793d44b..aeca439 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1489,8 +1489,9 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd,
        BUG_ON(mpd->next_page <= mpd->first_page);
        ext4_io_submit_init(&io_submit, mpd->wbc);
        io_submit.io_end = ext4_init_io_end(inode, GFP_NOFS);
+       /* In case of error we still have to unlock pages */
        if (!io_submit.io_end)
-               return -ENOMEM;
+               ret = -ENOMEM;
        /*
         * We need to start from the first_page to the next_page - 1
         * to make sure we also write the mapped dirty buffer_heads.
@@ -1512,6 +1513,11 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd,
                        index = page->index;
                        if (index > end)
                                break;
+                       if (!io_submit.io_end) {
+                               unlock_page(page);
+                               index++;
+                               continue;
+                       }
 
                        if (index == size >> PAGE_CACHE_SHIFT)
                                len = size & ~PAGE_CACHE_MASK;
@@ -1577,9 +1583,11 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd,
                }
                pagevec_release(&pvec);
        }
-       ext4_io_submit(&io_submit);
-       /* Drop io_end reference we got from init */
-       ext4_put_io_end_defer(io_submit.io_end);
+       if (io_submit.io_end) {
+               ext4_io_submit(&io_submit);
+               /* Drop io_end reference we got from init */
+               ext4_put_io_end_defer(io_submit.io_end);
+       }
        return ret;
 }
 
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to