diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 98 |
1 files changed, 70 insertions, 28 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 6449e1aae621..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->need_reconnect) { | 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")); |
@@ -1468,7 +1475,11 @@ static int cifs_write_end(struct file *file, struct address_space *mapping, | |||
1468 | 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", |
1469 | page, pos, copied)); | 1476 | page, pos, copied)); |
1470 | 1477 | ||
1471 | 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) | ||
1472 | SetPageUptodate(page); | 1483 | SetPageUptodate(page); |
1473 | 1484 | ||
1474 | if (!PageUptodate(page)) { | 1485 | if (!PageUptodate(page)) { |
@@ -2055,39 +2066,70 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping, | |||
2055 | { | 2066 | { |
2056 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; | 2067 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; |
2057 | 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; | ||
2058 | 2073 | ||
2059 | 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)); |
2060 | 2075 | ||
2061 | *pagep = __grab_cache_page(mapping, index); | 2076 | page = __grab_cache_page(mapping, index); |
2062 | if (!*pagep) | 2077 | if (!page) { |
2063 | return -ENOMEM; | 2078 | rc = -ENOMEM; |
2064 | 2079 | goto out; | |
2065 | if (PageUptodate(*pagep)) | 2080 | } |
2066 | return 0; | ||
2067 | 2081 | ||
2068 | /* If we are writing a full page it will be up to date, | 2082 | if (PageUptodate(page)) |
2069 | no need to read from the server */ | 2083 | goto out; |
2070 | if (len == PAGE_CACHE_SIZE && flags & AOP_FLAG_UNINTERRUPTIBLE) | ||
2071 | return 0; | ||
2072 | 2084 | ||
2073 | if ((file->f_flags & O_ACCMODE) != O_WRONLY) { | 2085 | /* |
2074 | 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; | ||
2075 | 2092 | ||
2076 | /* might as well read a page, it is fast enough */ | 2093 | /* |
2077 | 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 | } | ||
2078 | 2116 | ||
2079 | /* we do not need to pass errors back | 2117 | if ((file->f_flags & O_ACCMODE) != O_WRONLY) { |
2080 | e.g. if we do not have read access to the file | 2118 | /* |
2081 | because cifs_write_end will attempt synchronous writes | 2119 | * might as well read a page, it is fast enough. If we get |
2082 | -- 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); | ||
2083 | } else { | 2124 | } else { |
2084 | /* we could try using another file handle if there is one - | 2125 | /* we could try using another file handle if there is one - |
2085 | 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 |
2086 | racing with this read? In any case | 2127 | racing with this read? In any case |
2087 | this will be written out by write_end so is fine */ | 2128 | this will be written out by write_end so is fine */ |
2088 | } | 2129 | } |
2089 | 2130 | out: | |
2090 | return 0; | 2131 | *pagep = page; |
2132 | return rc; | ||
2091 | } | 2133 | } |
2092 | 2134 | ||
2093 | const struct address_space_operations cifs_addr_ops = { | 2135 | const struct address_space_operations cifs_addr_ops = { |