From: Nick Piggin Fix buffered writes to handle -EFAULT properly. Also, pass 'seglen' rather than 'bytes' to fault_in_pages_readable in the DEBUG_VM case, which matches !DEBUG_VM and is the correct thing to do. Signed-off-by: Nick Piggin Acked-by: Badari Pulavarty Signed-off-by: Andrew Morton --- include/linux/pagemap.h | 5 +++-- mm/filemap.c | 12 ++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff -puN include/linux/pagemap.h~mm-fix-pagecache-write-deadlocks-mm-pagecache-write-deadlocks-efault-fix include/linux/pagemap.h --- a/include/linux/pagemap.h~mm-fix-pagecache-write-deadlocks-mm-pagecache-write-deadlocks-efault-fix +++ a/include/linux/pagemap.h @@ -217,7 +217,7 @@ static inline int fault_in_pages_writeab return ret; } -static inline void fault_in_pages_readable(const char __user *uaddr, int size) +static inline int fault_in_pages_readable(const char __user *uaddr, int size) { volatile char c; int ret; @@ -228,8 +228,9 @@ static inline void fault_in_pages_readab if (((unsigned long)uaddr & PAGE_MASK) != ((unsigned long)end & PAGE_MASK)) - __get_user(c, end); + ret = __get_user(c, end); } + return ret; } #endif /* _LINUX_PAGEMAP_H */ diff -puN mm/filemap.c~mm-fix-pagecache-write-deadlocks-mm-pagecache-write-deadlocks-efault-fix mm/filemap.c --- a/mm/filemap.c~mm-fix-pagecache-write-deadlocks-mm-pagecache-write-deadlocks-efault-fix +++ a/mm/filemap.c @@ -2110,8 +2110,14 @@ retry_noprogress: * Bring in the user page that we will copy from _first_, this * minimises the chance we have to break into the slowpath * below. + * + * Must check for -EFAULT here, because an unhandled pagefault + * from the atomic copy below may not actually be due to an + * unmapped user region. */ - fault_in_pages_readable(buf, seglen); + status = fault_in_pages_readable(buf, seglen); + if (unlikely(status)) + break; #endif page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec); @@ -2202,7 +2208,9 @@ retry_noprogress: } } else { #ifdef CONFIG_DEBUG_VM - fault_in_pages_readable(buf, bytes); + status = fault_in_pages_readable(buf, seglen); + if (unlikely(status)) + break; #endif /* * OK, we took a fault without making progress. Fall _