mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-26 13:44:15 +08:00
[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>
This commit is contained in:
parent
c7af1857ef
commit
8a236264f7
@ -2,8 +2,9 @@ Verison 1.48
|
||||
------------
|
||||
Fix mtime bouncing around from local idea of last write times to remote time.
|
||||
Fix hang (in i_size_read) when simultaneous size update of same remote file
|
||||
on smp system corrupts sequence number.
|
||||
|
||||
on smp system corrupts sequence number. Do not reread unnecessarily partial page
|
||||
(which we are about to overwrite anyway) when writing out file opened rw.
|
||||
|
||||
Version 1.47
|
||||
------------
|
||||
Fix oops in list_del during mount caused by unaligned string.
|
||||
|
@ -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;
|
||||
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);
|
||||
memset(kaddr, 0, from);
|
||||
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);
|
||||
loff_t i_size;
|
||||
loff_t offset;
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
cFYI(1, ("prepare write for page %p from %d to %d",page,from,to));
|
||||
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;
|
||||
}
|
||||
|
||||
/* BB should we pass any errors back?
|
||||
e.g. if we do not have read access to the file */
|
||||
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);
|
||||
SetPageUptodate(page);
|
||||
} else if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
|
||||
/* might as well read a page, it is fast enough */
|
||||
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 */
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
@ -499,7 +499,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
due to last connection to this server being unmounted */
|
||||
if (signal_pending(current)) {
|
||||
/* if signal pending do not hold up user for full smb timeout
|
||||
but we still give response a change to complete */
|
||||
but we still give response a chance to complete */
|
||||
timeout = 2 * HZ;
|
||||
}
|
||||
|
||||
@ -587,7 +587,6 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
DeleteMidQEntry(midQ);
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
@ -681,7 +680,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
due to last connection to this server being unmounted */
|
||||
if (signal_pending(current)) {
|
||||
/* if signal pending do not hold up user for full smb timeout
|
||||
but we still give response a change to complete */
|
||||
but we still give response a chance to complete */
|
||||
timeout = 2 * HZ;
|
||||
}
|
||||
|
||||
@ -765,7 +764,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
DeleteMidQEntry(midQ);
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
|
Loading…
Reference in New Issue
Block a user