diff options
author | Jan Kara <jack@suse.cz> | 2017-02-08 17:30:53 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-08 18:41:43 -0500 |
commit | 0911d0041c22922228ca52a977d7b0b0159fee4b (patch) | |
tree | ecd0e2bd3ec2f1e934409a43dd3b0798860c7d8b | |
parent | ed5bd7dc88edf4a4a9c67130742b1b59aa017a5f (diff) |
mm: avoid returning VM_FAULT_RETRY from ->page_mkwrite handlers
Some ->page_mkwrite handlers may return VM_FAULT_RETRY as its return
code (GFS2 or Lustre can definitely do this). However VM_FAULT_RETRY
from ->page_mkwrite is completely unhandled by the mm code and results
in locking and writeably mapping the page which definitely is not what
the caller wanted.
Fix Lustre and block_page_mkwrite_ret() used by other filesystems
(notably GFS2) to return VM_FAULT_NOPAGE instead which results in
bailing out from the fault code, the CPU then retries the access, and we
fault again effectively doing what the handler wanted.
Link: http://lkml.kernel.org/r/20170203150729.15863-1-jack@suse.cz
Signed-off-by: Jan Kara <jack@suse.cz>
Reported-by: Al Viro <viro@ZenIV.linux.org.uk>
Reviewed-by: Jinshan Xiong <jinshan.xiong@intel.com>
Cc: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/staging/lustre/lustre/llite/llite_mmap.c | 4 | ||||
-rw-r--r-- | include/linux/buffer_head.h | 4 |
2 files changed, 2 insertions, 6 deletions
diff --git a/drivers/staging/lustre/lustre/llite/llite_mmap.c b/drivers/staging/lustre/lustre/llite/llite_mmap.c index ee01f20d8b11..9afa6bec3e6f 100644 --- a/drivers/staging/lustre/lustre/llite/llite_mmap.c +++ b/drivers/staging/lustre/lustre/llite/llite_mmap.c | |||
@@ -390,15 +390,13 @@ static int ll_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
390 | result = VM_FAULT_LOCKED; | 390 | result = VM_FAULT_LOCKED; |
391 | break; | 391 | break; |
392 | case -ENODATA: | 392 | case -ENODATA: |
393 | case -EAGAIN: | ||
393 | case -EFAULT: | 394 | case -EFAULT: |
394 | result = VM_FAULT_NOPAGE; | 395 | result = VM_FAULT_NOPAGE; |
395 | break; | 396 | break; |
396 | case -ENOMEM: | 397 | case -ENOMEM: |
397 | result = VM_FAULT_OOM; | 398 | result = VM_FAULT_OOM; |
398 | break; | 399 | break; |
399 | case -EAGAIN: | ||
400 | result = VM_FAULT_RETRY; | ||
401 | break; | ||
402 | default: | 400 | default: |
403 | result = VM_FAULT_SIGBUS; | 401 | result = VM_FAULT_SIGBUS; |
404 | break; | 402 | break; |
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index d67ab83823ad..79591c3660cc 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h | |||
@@ -243,12 +243,10 @@ static inline int block_page_mkwrite_return(int err) | |||
243 | { | 243 | { |
244 | if (err == 0) | 244 | if (err == 0) |
245 | return VM_FAULT_LOCKED; | 245 | return VM_FAULT_LOCKED; |
246 | if (err == -EFAULT) | 246 | if (err == -EFAULT || err == -EAGAIN) |
247 | return VM_FAULT_NOPAGE; | 247 | return VM_FAULT_NOPAGE; |
248 | if (err == -ENOMEM) | 248 | if (err == -ENOMEM) |
249 | return VM_FAULT_OOM; | 249 | return VM_FAULT_OOM; |
250 | if (err == -EAGAIN) | ||
251 | return VM_FAULT_RETRY; | ||
252 | /* -ENOSPC, -EDQUOT, -EIO ... */ | 250 | /* -ENOSPC, -EDQUOT, -EIO ... */ |
253 | return VM_FAULT_SIGBUS; | 251 | return VM_FAULT_SIGBUS; |
254 | } | 252 | } |