diff options
author | Steve French <sfrench@us.ibm.com> | 2007-03-05 19:31:00 -0500 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2007-03-05 19:31:00 -0500 |
commit | 8a236264f7d6db3f52881d37a86c5a5f704072b0 (patch) | |
tree | 2caf0cb67d6986b8e3544405b89135f24c05c137 | |
parent | c7af1857ef74873bf5a9c8fcab0cfd79883492ac (diff) |
[CIFS] cifs_prepare_write was incorrectly rereading page in some cases
Noticed by Shaggy.
Signed-off-by: Shaggy <shaggy@us.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r-- | fs/cifs/CHANGES | 5 | ||||
-rw-r--r-- | fs/cifs/file.c | 62 | ||||
-rw-r--r-- | fs/cifs/transport.c | 6 |
3 files changed, 45 insertions, 28 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index e08a147c09e1..6247628bdaed 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -2,8 +2,9 @@ Verison 1.48 | |||
2 | ------------ | 2 | ------------ |
3 | Fix mtime bouncing around from local idea of last write times to remote time. | 3 | Fix mtime bouncing around from local idea of last write times to remote time. |
4 | Fix hang (in i_size_read) when simultaneous size update of same remote file | 4 | Fix hang (in i_size_read) when simultaneous size update of same remote file |
5 | on smp system corrupts sequence number. | 5 | on smp system corrupts sequence number. Do not reread unnecessarily partial page |
6 | 6 | (which we are about to overwrite anyway) when writing out file opened rw. | |
7 | |||
7 | Version 1.47 | 8 | Version 1.47 |
8 | ------------ | 9 | ------------ |
9 | Fix oops in list_del during mount caused by unaligned string. | 10 | Fix oops in list_del during mount caused by unaligned string. |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index c07ff8317a8b..2d3275bedb55 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -1992,34 +1992,52 @@ static int cifs_prepare_write(struct file *file, struct page *page, | |||
1992 | unsigned from, unsigned to) | 1992 | unsigned from, unsigned to) |
1993 | { | 1993 | { |
1994 | int rc = 0; | 1994 | int rc = 0; |
1995 | loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | 1995 | loff_t i_size; |
1996 | loff_t offset; | ||
1997 | |||
1996 | cFYI(1, ("prepare write for page %p from %d to %d",page,from,to)); | 1998 | cFYI(1, ("prepare write for page %p from %d to %d",page,from,to)); |
1997 | if (!PageUptodate(page)) { | 1999 | if (PageUptodate(page)) |
1998 | /* if (to - from != PAGE_CACHE_SIZE) { | 2000 | return 0; |
1999 | void *kaddr = kmap_atomic(page, KM_USER0); | 2001 | |
2002 | /* If we are writing a full page it will be up to date, | ||
2003 | no need to read from the server */ | ||
2004 | if ((to == PAGE_CACHE_SIZE) && (from == 0)) { | ||
2005 | SetPageUptodate(page); | ||
2006 | return 0; | ||
2007 | } | ||
2008 | |||
2009 | offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | ||
2010 | i_size = i_size_read(page->mapping->host); | ||
2011 | |||
2012 | if ((offset >= i_size) || | ||
2013 | ((from == 0) && (offset + to) >= i_size)) { | ||
2014 | /* | ||
2015 | * We don't need to read data beyond the end of the file. | ||
2016 | * zero it, and set the page uptodate | ||
2017 | */ | ||
2018 | void *kaddr = kmap_atomic(page, KM_USER0); | ||
2019 | |||
2020 | if (from) | ||
2000 | memset(kaddr, 0, from); | 2021 | memset(kaddr, 0, from); |
2022 | if (to < PAGE_CACHE_SIZE) | ||
2001 | memset(kaddr + to, 0, PAGE_CACHE_SIZE - to); | 2023 | memset(kaddr + to, 0, PAGE_CACHE_SIZE - to); |
2002 | flush_dcache_page(page); | 2024 | flush_dcache_page(page); |
2003 | kunmap_atomic(kaddr, KM_USER0); | 2025 | kunmap_atomic(kaddr, KM_USER0); |
2004 | } */ | 2026 | SetPageUptodate(page); |
2005 | /* If we are writing a full page it will be up to date, | 2027 | } else if ((file->f_flags & O_ACCMODE) != O_WRONLY) { |
2006 | no need to read from the server */ | ||
2007 | if ((to == PAGE_CACHE_SIZE) && (from == 0)) | ||
2008 | SetPageUptodate(page); | ||
2009 | |||
2010 | /* might as well read a page, it is fast enough */ | 2028 | /* might as well read a page, it is fast enough */ |
2011 | if ((file->f_flags & O_ACCMODE) != O_WRONLY) { | 2029 | rc = cifs_readpage_worker(file, page, &offset); |
2012 | rc = cifs_readpage_worker(file, page, &offset); | 2030 | } else { |
2013 | } else { | 2031 | /* we could try using another file handle if there is one - |
2014 | /* should we try using another file handle if there is one - | 2032 | but how would we lock it to prevent close of that handle |
2015 | how would we lock it to prevent close of that handle | 2033 | racing with this read? In any case |
2016 | racing with this read? | 2034 | this will be written out by commit_write so is fine */ |
2017 | In any case this will be written out by commit_write */ | ||
2018 | } | ||
2019 | } | 2035 | } |
2020 | 2036 | ||
2021 | /* BB should we pass any errors back? | 2037 | /* we do not need to pass errors back |
2022 | e.g. if we do not have read access to the file */ | 2038 | e.g. if we do not have read access to the file |
2039 | because cifs_commit_write will do the right thing. -- shaggy */ | ||
2040 | |||
2023 | return 0; | 2041 | return 0; |
2024 | } | 2042 | } |
2025 | 2043 | ||
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index f80007eaebf4..5f468459a1e2 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -499,7 +499,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
499 | due to last connection to this server being unmounted */ | 499 | due to last connection to this server being unmounted */ |
500 | if (signal_pending(current)) { | 500 | if (signal_pending(current)) { |
501 | /* if signal pending do not hold up user for full smb timeout | 501 | /* if signal pending do not hold up user for full smb timeout |
502 | but we still give response a change to complete */ | 502 | but we still give response a chance to complete */ |
503 | timeout = 2 * HZ; | 503 | timeout = 2 * HZ; |
504 | } | 504 | } |
505 | 505 | ||
@@ -587,7 +587,6 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
587 | } | 587 | } |
588 | 588 | ||
589 | out: | 589 | out: |
590 | |||
591 | DeleteMidQEntry(midQ); | 590 | DeleteMidQEntry(midQ); |
592 | atomic_dec(&ses->server->inFlight); | 591 | atomic_dec(&ses->server->inFlight); |
593 | wake_up(&ses->server->request_q); | 592 | wake_up(&ses->server->request_q); |
@@ -681,7 +680,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
681 | due to last connection to this server being unmounted */ | 680 | due to last connection to this server being unmounted */ |
682 | if (signal_pending(current)) { | 681 | if (signal_pending(current)) { |
683 | /* if signal pending do not hold up user for full smb timeout | 682 | /* if signal pending do not hold up user for full smb timeout |
684 | but we still give response a change to complete */ | 683 | but we still give response a chance to complete */ |
685 | timeout = 2 * HZ; | 684 | timeout = 2 * HZ; |
686 | } | 685 | } |
687 | 686 | ||
@@ -765,7 +764,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
765 | } | 764 | } |
766 | 765 | ||
767 | out: | 766 | out: |
768 | |||
769 | DeleteMidQEntry(midQ); | 767 | DeleteMidQEntry(midQ); |
770 | atomic_dec(&ses->server->inFlight); | 768 | atomic_dec(&ses->server->inFlight); |
771 | wake_up(&ses->server->request_q); | 769 | wake_up(&ses->server->request_q); |