diff options
author | Sachin Prabhu <sprabhu@redhat.com> | 2013-09-13 09:11:57 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2013-09-13 17:24:49 -0400 |
commit | 466bd31bbda9e1dd2ace1d72c8de5045bf6f3bf6 (patch) | |
tree | a9f0d34082a17ed39a237dfb843441766c550a08 | |
parent | a9e9b7bc15a32ec5b0679704e70f3ffeecfaadd8 (diff) |
cifs: Avoid calling unlock_page() twice in cifs_readpage() when using fscache
When reading a single page with cifs_readpage(), we make a call to
fscache_read_or_alloc_page() which once done, asynchronously calls
the completion function cifs_readpage_from_fscache_complete(). This
completion function unlocks the page once it has been populated from
cache. The module then attempts to unlock the page a second time in
cifs_readpage() which leads to warning messages.
In case of a successful call to fscache_read_or_alloc_page() we should skip
the second unlock_page() since this will be called by the
cifs_readpage_from_fscache_complete() once the page has been populated by
fscache.
With the modifications to cifs_readpage_worker(), we will need to re-grab the
page lock in cifs_write_begin().
The problem was first noticed when testing new fscache patches for cifs.
https://bugzilla.redhat.com/show_bug.cgi?id=1005737
Signed-off-by: Sachin Prabhu <sprabhu@redhat.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <smfrench@gmail.com>
-rw-r--r-- | fs/cifs/file.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 5f99ee551662..eb955b525e55 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -3419,6 +3419,7 @@ static int cifs_readpage_worker(struct file *file, struct page *page, | |||
3419 | 3419 | ||
3420 | io_error: | 3420 | io_error: |
3421 | kunmap(page); | 3421 | kunmap(page); |
3422 | unlock_page(page); | ||
3422 | 3423 | ||
3423 | read_complete: | 3424 | read_complete: |
3424 | return rc; | 3425 | return rc; |
@@ -3443,8 +3444,6 @@ static int cifs_readpage(struct file *file, struct page *page) | |||
3443 | 3444 | ||
3444 | rc = cifs_readpage_worker(file, page, &offset); | 3445 | rc = cifs_readpage_worker(file, page, &offset); |
3445 | 3446 | ||
3446 | unlock_page(page); | ||
3447 | |||
3448 | free_xid(xid); | 3447 | free_xid(xid); |
3449 | return rc; | 3448 | return rc; |
3450 | } | 3449 | } |
@@ -3498,6 +3497,7 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping, | |||
3498 | loff_t pos, unsigned len, unsigned flags, | 3497 | loff_t pos, unsigned len, unsigned flags, |
3499 | struct page **pagep, void **fsdata) | 3498 | struct page **pagep, void **fsdata) |
3500 | { | 3499 | { |
3500 | int oncethru = 0; | ||
3501 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; | 3501 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; |
3502 | loff_t offset = pos & (PAGE_CACHE_SIZE - 1); | 3502 | loff_t offset = pos & (PAGE_CACHE_SIZE - 1); |
3503 | loff_t page_start = pos & PAGE_MASK; | 3503 | loff_t page_start = pos & PAGE_MASK; |
@@ -3507,6 +3507,7 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping, | |||
3507 | 3507 | ||
3508 | cifs_dbg(FYI, "write_begin from %lld len %d\n", (long long)pos, len); | 3508 | cifs_dbg(FYI, "write_begin from %lld len %d\n", (long long)pos, len); |
3509 | 3509 | ||
3510 | start: | ||
3510 | page = grab_cache_page_write_begin(mapping, index, flags); | 3511 | page = grab_cache_page_write_begin(mapping, index, flags); |
3511 | if (!page) { | 3512 | if (!page) { |
3512 | rc = -ENOMEM; | 3513 | rc = -ENOMEM; |
@@ -3548,13 +3549,16 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping, | |||
3548 | } | 3549 | } |
3549 | } | 3550 | } |
3550 | 3551 | ||
3551 | if ((file->f_flags & O_ACCMODE) != O_WRONLY) { | 3552 | if ((file->f_flags & O_ACCMODE) != O_WRONLY && !oncethru) { |
3552 | /* | 3553 | /* |
3553 | * might as well read a page, it is fast enough. If we get | 3554 | * might as well read a page, it is fast enough. If we get |
3554 | * an error, we don't need to return it. cifs_write_end will | 3555 | * an error, we don't need to return it. cifs_write_end will |
3555 | * do a sync write instead since PG_uptodate isn't set. | 3556 | * do a sync write instead since PG_uptodate isn't set. |
3556 | */ | 3557 | */ |
3557 | cifs_readpage_worker(file, page, &page_start); | 3558 | cifs_readpage_worker(file, page, &page_start); |
3559 | page_cache_release(page); | ||
3560 | oncethru = 1; | ||
3561 | goto start; | ||
3558 | } else { | 3562 | } else { |
3559 | /* we could try using another file handle if there is one - | 3563 | /* we could try using another file handle if there is one - |
3560 | but how would we lock it to prevent close of that handle | 3564 | but how would we lock it to prevent close of that handle |