summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Fasheh <mark.fasheh@oracle.com>2007-07-19 01:47:00 -0700
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-19 10:04:41 -0700
commit6967614761fd305b3414d9485d89dc2e0a407410 (patch)
tree498bd41e9cf8795535f597696dd2c834d79ffb44
parent54cb8821de07f2ffcd28c380ce9b93d5784b40d7 (diff)
downloadop-kernel-dev-6967614761fd305b3414d9485d89dc2e0a407410.zip
op-kernel-dev-6967614761fd305b3414d9485d89dc2e0a407410.tar.gz
ocfs2: release page lock before calling ->page_mkwrite
__do_fault() was calling ->page_mkwrite() with the page lock held, which violates the locking rules for that callback. Release and retake the page lock around the callback to avoid deadlocking file systems which manually take it. Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com> Cc: Nick Piggin <nickpiggin@yahoo.com.au> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/memory.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/mm/memory.c b/mm/memory.c
index eee7fec..7abd389 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2369,11 +2369,14 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
* address space wants to know that the page is about
* to become writable
*/
- if (vma->vm_ops->page_mkwrite &&
- vma->vm_ops->page_mkwrite(vma, page) < 0) {
- fdata.type = VM_FAULT_SIGBUS;
- anon = 1; /* no anon but release faulted_page */
- goto out;
+ if (vma->vm_ops->page_mkwrite) {
+ unlock_page(page);
+ if (vma->vm_ops->page_mkwrite(vma, page) < 0) {
+ fdata.type = VM_FAULT_SIGBUS;
+ anon = 1; /* no anon but release faulted_page */
+ goto out_unlocked;
+ }
+ lock_page(page);
}
}
@@ -2425,6 +2428,7 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
out:
unlock_page(faulted_page);
+out_unlocked:
if (anon)
page_cache_release(faulted_page);
else if (dirty_page) {
OpenPOWER on IntegriCloud