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