diff options
author | Steve French <sfrench@us.ibm.com> | 2007-03-06 00:31:00 +0000 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2007-03-06 00:31:00 +0000 |
commit | 8a236264f7d6db3f52881d37a86c5a5f704072b0 (patch) | |
tree | 2caf0cb67d6986b8e3544405b89135f24c05c137 /fs/cifs/file.c | |
parent | c7af1857ef74873bf5a9c8fcab0cfd79883492ac (diff) | |
download | kernel-crypto-8a236264f7d6db3f52881d37a86c5a5f704072b0.tar.gz kernel-crypto-8a236264f7d6db3f52881d37a86c5a5f704072b0.tar.xz kernel-crypto-8a236264f7d6db3f52881d37a86c5a5f704072b0.zip |
[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>
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 62 |
1 files changed, 40 insertions, 22 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index c07ff8317a8..2d3275bedb5 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, unsigned from, unsigned to) { int rc = 0; - loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; + loff_t i_size; + loff_t offset; + cFYI(1, ("prepare write for page %p from %d to %d",page,from,to)); - if (!PageUptodate(page)) { - /* if (to - from != PAGE_CACHE_SIZE) { - void *kaddr = kmap_atomic(page, KM_USER0); + if (PageUptodate(page)) + return 0; + + /* If we are writing a full page it will be up to date, + no need to read from the server */ + if ((to == PAGE_CACHE_SIZE) && (from == 0)) { + SetPageUptodate(page); + return 0; + } + + offset = (loff_t)page->index << PAGE_CACHE_SHIFT; + i_size = i_size_read(page->mapping->host); + + if ((offset >= i_size) || + ((from == 0) && (offset + to) >= i_size)) { + /* + * We don't need to read data beyond the end of the file. + * zero it, and set the page uptodate + */ + void *kaddr = kmap_atomic(page, KM_USER0); + + if (from) memset(kaddr, 0, from); + if (to < PAGE_CACHE_SIZE) memset(kaddr + to, 0, PAGE_CACHE_SIZE - to); - flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); - } */ - /* If we are writing a full page it will be up to date, - no need to read from the server */ - if ((to == PAGE_CACHE_SIZE) && (from == 0)) - SetPageUptodate(page); - + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + SetPageUptodate(page); + } else if ((file->f_flags & O_ACCMODE) != O_WRONLY) { /* might as well read a page, it is fast enough */ - if ((file->f_flags & O_ACCMODE) != O_WRONLY) { - rc = cifs_readpage_worker(file, page, &offset); - } else { - /* should we try using another file handle if there is one - - how would we lock it to prevent close of that handle - racing with this read? - In any case this will be written out by commit_write */ - } + rc = cifs_readpage_worker(file, page, &offset); + } else { + /* we could try using another file handle if there is one - + but how would we lock it to prevent close of that handle + racing with this read? In any case + this will be written out by commit_write so is fine */ } - /* BB should we pass any errors back? - e.g. if we do not have read access to the file */ + /* we do not need to pass errors back + e.g. if we do not have read access to the file + because cifs_commit_write will do the right thing. -- shaggy */ + return 0; } |