diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 107 |
1 files changed, 76 insertions, 31 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 62d8bd8f14c0..f0a81e631ae6 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -488,12 +488,13 @@ int cifs_close(struct inode *inode, struct file *file) | |||
488 | pTcon = cifs_sb->tcon; | 488 | pTcon = cifs_sb->tcon; |
489 | if (pSMBFile) { | 489 | if (pSMBFile) { |
490 | struct cifsLockInfo *li, *tmp; | 490 | struct cifsLockInfo *li, *tmp; |
491 | 491 | write_lock(&GlobalSMBSeslock); | |
492 | pSMBFile->closePend = true; | 492 | pSMBFile->closePend = true; |
493 | if (pTcon) { | 493 | if (pTcon) { |
494 | /* no sense reconnecting to close a file that is | 494 | /* no sense reconnecting to close a file that is |
495 | already closed */ | 495 | already closed */ |
496 | if (pTcon->tidStatus != CifsNeedReconnect) { | 496 | if (!pTcon->need_reconnect) { |
497 | write_unlock(&GlobalSMBSeslock); | ||
497 | timeout = 2; | 498 | timeout = 2; |
498 | while ((atomic_read(&pSMBFile->wrtPending) != 0) | 499 | while ((atomic_read(&pSMBFile->wrtPending) != 0) |
499 | && (timeout <= 2048)) { | 500 | && (timeout <= 2048)) { |
@@ -510,12 +511,15 @@ int cifs_close(struct inode *inode, struct file *file) | |||
510 | timeout *= 4; | 511 | timeout *= 4; |
511 | } | 512 | } |
512 | if (atomic_read(&pSMBFile->wrtPending)) | 513 | if (atomic_read(&pSMBFile->wrtPending)) |
513 | cERROR(1, | 514 | cERROR(1, ("close with pending write")); |
514 | ("close with pending writes")); | 515 | if (!pTcon->need_reconnect && |
515 | rc = CIFSSMBClose(xid, pTcon, | 516 | !pSMBFile->invalidHandle) |
517 | rc = CIFSSMBClose(xid, pTcon, | ||
516 | pSMBFile->netfid); | 518 | pSMBFile->netfid); |
517 | } | 519 | } else |
518 | } | 520 | write_unlock(&GlobalSMBSeslock); |
521 | } else | ||
522 | write_unlock(&GlobalSMBSeslock); | ||
519 | 523 | ||
520 | /* Delete any outstanding lock records. | 524 | /* Delete any outstanding lock records. |
521 | We'll lose them when the file is closed anyway. */ | 525 | We'll lose them when the file is closed anyway. */ |
@@ -587,15 +591,18 @@ int cifs_closedir(struct inode *inode, struct file *file) | |||
587 | pTcon = cifs_sb->tcon; | 591 | pTcon = cifs_sb->tcon; |
588 | 592 | ||
589 | cFYI(1, ("Freeing private data in close dir")); | 593 | cFYI(1, ("Freeing private data in close dir")); |
594 | write_lock(&GlobalSMBSeslock); | ||
590 | if (!pCFileStruct->srch_inf.endOfSearch && | 595 | if (!pCFileStruct->srch_inf.endOfSearch && |
591 | !pCFileStruct->invalidHandle) { | 596 | !pCFileStruct->invalidHandle) { |
592 | pCFileStruct->invalidHandle = true; | 597 | pCFileStruct->invalidHandle = true; |
598 | write_unlock(&GlobalSMBSeslock); | ||
593 | rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); | 599 | rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); |
594 | cFYI(1, ("Closing uncompleted readdir with rc %d", | 600 | cFYI(1, ("Closing uncompleted readdir with rc %d", |
595 | rc)); | 601 | rc)); |
596 | /* not much we can do if it fails anyway, ignore rc */ | 602 | /* not much we can do if it fails anyway, ignore rc */ |
597 | rc = 0; | 603 | rc = 0; |
598 | } | 604 | } else |
605 | write_unlock(&GlobalSMBSeslock); | ||
599 | ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; | 606 | ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; |
600 | if (ptmp) { | 607 | if (ptmp) { |
601 | cFYI(1, ("closedir free smb buf in srch struct")); | 608 | cFYI(1, ("closedir free smb buf in srch struct")); |
@@ -1404,7 +1411,10 @@ retry: | |||
1404 | if ((wbc->nr_to_write -= n_iov) <= 0) | 1411 | if ((wbc->nr_to_write -= n_iov) <= 0) |
1405 | done = 1; | 1412 | done = 1; |
1406 | index = next; | 1413 | index = next; |
1407 | } | 1414 | } else |
1415 | /* Need to re-find the pages we skipped */ | ||
1416 | index = pvec.pages[0]->index + 1; | ||
1417 | |||
1408 | pagevec_release(&pvec); | 1418 | pagevec_release(&pvec); |
1409 | } | 1419 | } |
1410 | if (!scanned && !done) { | 1420 | if (!scanned && !done) { |
@@ -1465,7 +1475,11 @@ static int cifs_write_end(struct file *file, struct address_space *mapping, | |||
1465 | cFYI(1, ("write_end for page %p from pos %lld with %d bytes", | 1475 | cFYI(1, ("write_end for page %p from pos %lld with %d bytes", |
1466 | page, pos, copied)); | 1476 | page, pos, copied)); |
1467 | 1477 | ||
1468 | if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE) | 1478 | if (PageChecked(page)) { |
1479 | if (copied == len) | ||
1480 | SetPageUptodate(page); | ||
1481 | ClearPageChecked(page); | ||
1482 | } else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE) | ||
1469 | SetPageUptodate(page); | 1483 | SetPageUptodate(page); |
1470 | 1484 | ||
1471 | if (!PageUptodate(page)) { | 1485 | if (!PageUptodate(page)) { |
@@ -1824,7 +1838,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1824 | pTcon = cifs_sb->tcon; | 1838 | pTcon = cifs_sb->tcon; |
1825 | 1839 | ||
1826 | pagevec_init(&lru_pvec, 0); | 1840 | pagevec_init(&lru_pvec, 0); |
1827 | cFYI(DBG2, ("rpages: num pages %d", num_pages)); | 1841 | cFYI(DBG2, ("rpages: num pages %d", num_pages)); |
1828 | for (i = 0; i < num_pages; ) { | 1842 | for (i = 0; i < num_pages; ) { |
1829 | unsigned contig_pages; | 1843 | unsigned contig_pages; |
1830 | struct page *tmp_page; | 1844 | struct page *tmp_page; |
@@ -2052,39 +2066,70 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping, | |||
2052 | { | 2066 | { |
2053 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; | 2067 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; |
2054 | loff_t offset = pos & (PAGE_CACHE_SIZE - 1); | 2068 | loff_t offset = pos & (PAGE_CACHE_SIZE - 1); |
2069 | loff_t page_start = pos & PAGE_MASK; | ||
2070 | loff_t i_size; | ||
2071 | struct page *page; | ||
2072 | int rc = 0; | ||
2055 | 2073 | ||
2056 | cFYI(1, ("write_begin from %lld len %d", (long long)pos, len)); | 2074 | cFYI(1, ("write_begin from %lld len %d", (long long)pos, len)); |
2057 | 2075 | ||
2058 | *pagep = __grab_cache_page(mapping, index); | 2076 | page = __grab_cache_page(mapping, index); |
2059 | if (!*pagep) | 2077 | if (!page) { |
2060 | return -ENOMEM; | 2078 | rc = -ENOMEM; |
2061 | 2079 | goto out; | |
2062 | if (PageUptodate(*pagep)) | 2080 | } |
2063 | return 0; | ||
2064 | 2081 | ||
2065 | /* If we are writing a full page it will be up to date, | 2082 | if (PageUptodate(page)) |
2066 | no need to read from the server */ | 2083 | goto out; |
2067 | if (len == PAGE_CACHE_SIZE && flags & AOP_FLAG_UNINTERRUPTIBLE) | ||
2068 | return 0; | ||
2069 | 2084 | ||
2070 | if ((file->f_flags & O_ACCMODE) != O_WRONLY) { | 2085 | /* |
2071 | int rc; | 2086 | * If we write a full page it will be up to date, no need to read from |
2087 | * the server. If the write is short, we'll end up doing a sync write | ||
2088 | * instead. | ||
2089 | */ | ||
2090 | if (len == PAGE_CACHE_SIZE) | ||
2091 | goto out; | ||
2072 | 2092 | ||
2073 | /* might as well read a page, it is fast enough */ | 2093 | /* |
2074 | rc = cifs_readpage_worker(file, *pagep, &offset); | 2094 | * optimize away the read when we have an oplock, and we're not |
2095 | * expecting to use any of the data we'd be reading in. That | ||
2096 | * is, when the page lies beyond the EOF, or straddles the EOF | ||
2097 | * and the write will cover all of the existing data. | ||
2098 | */ | ||
2099 | if (CIFS_I(mapping->host)->clientCanCacheRead) { | ||
2100 | i_size = i_size_read(mapping->host); | ||
2101 | if (page_start >= i_size || | ||
2102 | (offset == 0 && (pos + len) >= i_size)) { | ||
2103 | zero_user_segments(page, 0, offset, | ||
2104 | offset + len, | ||
2105 | PAGE_CACHE_SIZE); | ||
2106 | /* | ||
2107 | * PageChecked means that the parts of the page | ||
2108 | * to which we're not writing are considered up | ||
2109 | * to date. Once the data is copied to the | ||
2110 | * page, it can be set uptodate. | ||
2111 | */ | ||
2112 | SetPageChecked(page); | ||
2113 | goto out; | ||
2114 | } | ||
2115 | } | ||
2075 | 2116 | ||
2076 | /* we do not need to pass errors back | 2117 | if ((file->f_flags & O_ACCMODE) != O_WRONLY) { |
2077 | e.g. if we do not have read access to the file | 2118 | /* |
2078 | because cifs_write_end will attempt synchronous writes | 2119 | * might as well read a page, it is fast enough. If we get |
2079 | -- shaggy */ | 2120 | * an error, we don't need to return it. cifs_write_end will |
2121 | * do a sync write instead since PG_uptodate isn't set. | ||
2122 | */ | ||
2123 | cifs_readpage_worker(file, page, &page_start); | ||
2080 | } else { | 2124 | } else { |
2081 | /* we could try using another file handle if there is one - | 2125 | /* we could try using another file handle if there is one - |
2082 | but how would we lock it to prevent close of that handle | 2126 | but how would we lock it to prevent close of that handle |
2083 | racing with this read? In any case | 2127 | racing with this read? In any case |
2084 | this will be written out by write_end so is fine */ | 2128 | this will be written out by write_end so is fine */ |
2085 | } | 2129 | } |
2086 | 2130 | out: | |
2087 | return 0; | 2131 | *pagep = page; |
2132 | return rc; | ||
2088 | } | 2133 | } |
2089 | 2134 | ||
2090 | const struct address_space_operations cifs_addr_ops = { | 2135 | const struct address_space_operations cifs_addr_ops = { |