Wengang Wang
2010-Nov-18 15:52 UTC
[Ocfs2-devel] [PATCH] ocfs2: lock the page in __ocfs2_page_mkwrite() -v2
Lock the page in __ocfs2_page_mkwrite(). Or we may get -EINVAL error
from ocfs2_grab_pages_for_write() if the page(page cache) gets truncated
while someone is flushing the pagecache. In the original code, we are
checking mapping earlier in __ocfs2_page_mkwrite() but we don't lock it.
so the mapping can change during flushing pagecache.
Signed-off-by: Wengang Wang <wen.gang.wang at oracle.com>
---
fs/ocfs2/aops.c | 10 +++++++---
fs/ocfs2/mmap.c | 10 +++++++---
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index f1e962c..6b7e1f2 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -1130,14 +1130,18 @@ static int ocfs2_grab_pages_for_write(struct
address_space *mapping,
if (index == target_index && mmap_page) {
/*
- * ocfs2_pagemkwrite() is a little different
+ * ocfs2_page_mkwrite() is a little different
* and wants us to directly use the page
* passed in.
+ * So far, only __ocfs2_page_mkwrite() passes in a
+ * non-NULL page. And we locked the page there, so we
+ * just assert the page is locked. If another path will
+ * be passing in a non-NULL page in future, the locking
+ * should be well considered.
*/
- lock_page(mmap_page);
+ BUG_ON(!PageLocked(mmap_page));
if (mmap_page->mapping != mapping) {
- unlock_page(mmap_page);
/*
* Sanity check - the locking in
* ocfs2_pagemkwrite() should ensure
diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c
index 7e32db9..bb29335 100644
--- a/fs/ocfs2/mmap.c
+++ b/fs/ocfs2/mmap.c
@@ -79,9 +79,10 @@ static int __ocfs2_page_mkwrite(struct file *file, struct
buffer_head *di_bh,
* from do_generic_file_read.
*/
last_index = (size - 1) >> PAGE_CACHE_SHIFT;
+ lock_page(page);
if (unlikely(!size || page->index > last_index)) {
ret = -EINVAL;
- goto out;
+ goto out_unlock;
}
/*
@@ -96,7 +97,7 @@ static int __ocfs2_page_mkwrite(struct file *file, struct
buffer_head *di_bh,
* So return 0 here and let VFS retry.
*/
ret = 0;
- goto out;
+ goto out_unlock;
}
/*
@@ -117,7 +118,7 @@ static int __ocfs2_page_mkwrite(struct file *file, struct
buffer_head *di_bh,
if (ret) {
if (ret != -ENOSPC)
mlog_errno(ret);
- goto out;
+ goto out_unlock;
}
ret = ocfs2_write_end_nolock(mapping, pos, len, len, locked_page,
@@ -128,6 +129,9 @@ static int __ocfs2_page_mkwrite(struct file *file, struct
buffer_head *di_bh,
}
BUG_ON(ret != len);
ret = 0;
+ goto out;
+out_unlock:
+ unlock_page(page);
out:
return ret;
}
--
1.7.2.3
Joel Becker
2010-Nov-18 22:05 UTC
[Ocfs2-devel] [PATCH] ocfs2: lock the page in __ocfs2_page_mkwrite() -v2
On Thu, Nov 18, 2010 at 11:52:14PM +0800, Wengang Wang wrote:> Lock the page in __ocfs2_page_mkwrite(). Or we may get -EINVAL error > from ocfs2_grab_pages_for_write() if the page(page cache) gets truncated > while someone is flushing the pagecache. In the original code, we are > checking mapping earlier in __ocfs2_page_mkwrite() but we don't lock it. > so the mapping can change during flushing pagecache.This looks like a good implementation of the concept. I'm still wary of holding the page lock that long, though I *think* it's the right thing. Mark, do you have any thoughts on this? I believe this is originally your code. Joel -- "Not being known doesn't stop the truth from being true." - Richard Bach Joel Becker Senior Development Manager Oracle E-mail: joel.becker at oracle.com Phone: (650) 506-8127
Wengang Wang
2010-Dec-07 01:55 UTC
[Ocfs2-devel] [PATCH] ocfs2: lock the page in __ocfs2_page_mkwrite() -v2
Hi Mark, Do you have any comment on this patch? Seems Joel wants your ACK. regards, wengang. On 10-11-18 14:05, Joel Becker wrote:> On Thu, Nov 18, 2010 at 11:52:14PM +0800, Wengang Wang wrote: > > Lock the page in __ocfs2_page_mkwrite(). Or we may get -EINVAL error > > from ocfs2_grab_pages_for_write() if the page(page cache) gets truncated > > while someone is flushing the pagecache. In the original code, we are > > checking mapping earlier in __ocfs2_page_mkwrite() but we don't lock it. > > so the mapping can change during flushing pagecache. > > This looks like a good implementation of the concept. I'm still > wary of holding the page lock that long, though I *think* it's the right > thing. > Mark, do you have any thoughts on this? I believe this is > originally your code. > > Joel > > -- > > "Not being known doesn't stop the truth from being true." > - Richard Bach > > Joel Becker > Senior Development Manager > Oracle > E-mail: joel.becker at oracle.com > Phone: (650) 506-8127
Mark Fasheh
2010-Dec-14 17:44 UTC
[Ocfs2-devel] [PATCH] ocfs2: lock the page in __ocfs2_page_mkwrite() -v2
Hi Wengang, On Thu, Nov 18, 2010 at 11:52:14PM +0800, Wengang Wang wrote:> Lock the page in __ocfs2_page_mkwrite(). Or we may get -EINVAL error > from ocfs2_grab_pages_for_write() if the page(page cache) gets truncated > while someone is flushing the pagecache. In the original code, we are > checking mapping earlier in __ocfs2_page_mkwrite() but we don't lock it. > so the mapping can change during flushing pagecache.Thanks for doing this work. Review is below.> diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c > index f1e962c..6b7e1f2 100644 > --- a/fs/ocfs2/aops.c > +++ b/fs/ocfs2/aops.c > @@ -1130,14 +1130,18 @@ static int ocfs2_grab_pages_for_write(struct address_space *mapping, > > if (index == target_index && mmap_page) { > /* > - * ocfs2_pagemkwrite() is a little different > + * ocfs2_page_mkwrite() is a little different > * and wants us to directly use the page > * passed in. > + * So far, only __ocfs2_page_mkwrite() passes in a > + * non-NULL page. And we locked the page there, so we > + * just assert the page is locked. If another path will > + * be passing in a non-NULL page in future, the locking > + * should be well considered. > */ > - lock_page(mmap_page); > + BUG_ON(!PageLocked(mmap_page)); > > if (mmap_page->mapping != mapping) { > - unlock_page(mmap_page); > /* > * Sanity check - the locking in > * ocfs2_pagemkwrite() should ensure > diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c > index 7e32db9..bb29335 100644 > --- a/fs/ocfs2/mmap.c > +++ b/fs/ocfs2/mmap.c > @@ -79,9 +79,10 @@ static int __ocfs2_page_mkwrite(struct file *file, struct buffer_head *di_bh, > * from do_generic_file_read. > */ > last_index = (size - 1) >> PAGE_CACHE_SHIFT; > + lock_page(page);This breaks the page lock ordering in ocfs2_grab_pages_for_write() -- note that the call to find_or_create_page() in that function returns pages in a locked state. So roughly, we want to be taking them in index order. --Mark -- Mark Fasheh