diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 271 |
1 files changed, 176 insertions, 95 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 159fcc56dc2d..460d87b7cda0 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -1399,7 +1399,10 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock) | |||
1399 | return rc; | 1399 | return rc; |
1400 | } | 1400 | } |
1401 | 1401 | ||
1402 | /* update the file size (if needed) after a write */ | 1402 | /* |
1403 | * update the file size (if needed) after a write. Should be called with | ||
1404 | * the inode->i_lock held | ||
1405 | */ | ||
1403 | void | 1406 | void |
1404 | cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, | 1407 | cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, |
1405 | unsigned int bytes_written) | 1408 | unsigned int bytes_written) |
@@ -1471,7 +1474,9 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid, | |||
1471 | return rc; | 1474 | return rc; |
1472 | } | 1475 | } |
1473 | } else { | 1476 | } else { |
1477 | spin_lock(&dentry->d_inode->i_lock); | ||
1474 | cifs_update_eof(cifsi, *poffset, bytes_written); | 1478 | cifs_update_eof(cifsi, *poffset, bytes_written); |
1479 | spin_unlock(&dentry->d_inode->i_lock); | ||
1475 | *poffset += bytes_written; | 1480 | *poffset += bytes_written; |
1476 | } | 1481 | } |
1477 | } | 1482 | } |
@@ -1648,6 +1653,27 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
1648 | return rc; | 1653 | return rc; |
1649 | } | 1654 | } |
1650 | 1655 | ||
1656 | /* | ||
1657 | * Marshal up the iov array, reserving the first one for the header. Also, | ||
1658 | * set wdata->bytes. | ||
1659 | */ | ||
1660 | static void | ||
1661 | cifs_writepages_marshal_iov(struct kvec *iov, struct cifs_writedata *wdata) | ||
1662 | { | ||
1663 | int i; | ||
1664 | struct inode *inode = wdata->cfile->dentry->d_inode; | ||
1665 | loff_t size = i_size_read(inode); | ||
1666 | |||
1667 | /* marshal up the pages into iov array */ | ||
1668 | wdata->bytes = 0; | ||
1669 | for (i = 0; i < wdata->nr_pages; i++) { | ||
1670 | iov[i + 1].iov_len = min(size - page_offset(wdata->pages[i]), | ||
1671 | (loff_t)PAGE_CACHE_SIZE); | ||
1672 | iov[i + 1].iov_base = kmap(wdata->pages[i]); | ||
1673 | wdata->bytes += iov[i + 1].iov_len; | ||
1674 | } | ||
1675 | } | ||
1676 | |||
1651 | static int cifs_writepages(struct address_space *mapping, | 1677 | static int cifs_writepages(struct address_space *mapping, |
1652 | struct writeback_control *wbc) | 1678 | struct writeback_control *wbc) |
1653 | { | 1679 | { |
@@ -1684,7 +1710,8 @@ retry: | |||
1684 | tofind = min((cifs_sb->wsize / PAGE_CACHE_SIZE) - 1, | 1710 | tofind = min((cifs_sb->wsize / PAGE_CACHE_SIZE) - 1, |
1685 | end - index) + 1; | 1711 | end - index) + 1; |
1686 | 1712 | ||
1687 | wdata = cifs_writedata_alloc((unsigned int)tofind); | 1713 | wdata = cifs_writedata_alloc((unsigned int)tofind, |
1714 | cifs_writev_complete); | ||
1688 | if (!wdata) { | 1715 | if (!wdata) { |
1689 | rc = -ENOMEM; | 1716 | rc = -ENOMEM; |
1690 | break; | 1717 | break; |
@@ -1791,6 +1818,7 @@ retry: | |||
1791 | wdata->sync_mode = wbc->sync_mode; | 1818 | wdata->sync_mode = wbc->sync_mode; |
1792 | wdata->nr_pages = nr_pages; | 1819 | wdata->nr_pages = nr_pages; |
1793 | wdata->offset = page_offset(wdata->pages[0]); | 1820 | wdata->offset = page_offset(wdata->pages[0]); |
1821 | wdata->marshal_iov = cifs_writepages_marshal_iov; | ||
1794 | 1822 | ||
1795 | do { | 1823 | do { |
1796 | if (wdata->cfile != NULL) | 1824 | if (wdata->cfile != NULL) |
@@ -1802,6 +1830,7 @@ retry: | |||
1802 | rc = -EBADF; | 1830 | rc = -EBADF; |
1803 | break; | 1831 | break; |
1804 | } | 1832 | } |
1833 | wdata->pid = wdata->cfile->pid; | ||
1805 | rc = cifs_async_writev(wdata); | 1834 | rc = cifs_async_writev(wdata); |
1806 | } while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN); | 1835 | } while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN); |
1807 | 1836 | ||
@@ -2043,7 +2072,7 @@ cifs_write_allocate_pages(struct page **pages, unsigned long num_pages) | |||
2043 | unsigned long i; | 2072 | unsigned long i; |
2044 | 2073 | ||
2045 | for (i = 0; i < num_pages; i++) { | 2074 | for (i = 0; i < num_pages; i++) { |
2046 | pages[i] = alloc_page(__GFP_HIGHMEM); | 2075 | pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM); |
2047 | if (!pages[i]) { | 2076 | if (!pages[i]) { |
2048 | /* | 2077 | /* |
2049 | * save number of pages we have already allocated and | 2078 | * save number of pages we have already allocated and |
@@ -2051,15 +2080,14 @@ cifs_write_allocate_pages(struct page **pages, unsigned long num_pages) | |||
2051 | */ | 2080 | */ |
2052 | num_pages = i; | 2081 | num_pages = i; |
2053 | rc = -ENOMEM; | 2082 | rc = -ENOMEM; |
2054 | goto error; | 2083 | break; |
2055 | } | 2084 | } |
2056 | } | 2085 | } |
2057 | 2086 | ||
2058 | return rc; | 2087 | if (rc) { |
2059 | 2088 | for (i = 0; i < num_pages; i++) | |
2060 | error: | 2089 | put_page(pages[i]); |
2061 | for (i = 0; i < num_pages; i++) | 2090 | } |
2062 | put_page(pages[i]); | ||
2063 | return rc; | 2091 | return rc; |
2064 | } | 2092 | } |
2065 | 2093 | ||
@@ -2070,9 +2098,7 @@ size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len) | |||
2070 | size_t clen; | 2098 | size_t clen; |
2071 | 2099 | ||
2072 | clen = min_t(const size_t, len, wsize); | 2100 | clen = min_t(const size_t, len, wsize); |
2073 | num_pages = clen / PAGE_CACHE_SIZE; | 2101 | num_pages = DIV_ROUND_UP(clen, PAGE_SIZE); |
2074 | if (clen % PAGE_CACHE_SIZE) | ||
2075 | num_pages++; | ||
2076 | 2102 | ||
2077 | if (cur_len) | 2103 | if (cur_len) |
2078 | *cur_len = clen; | 2104 | *cur_len = clen; |
@@ -2080,24 +2106,79 @@ size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len) | |||
2080 | return num_pages; | 2106 | return num_pages; |
2081 | } | 2107 | } |
2082 | 2108 | ||
2109 | static void | ||
2110 | cifs_uncached_marshal_iov(struct kvec *iov, struct cifs_writedata *wdata) | ||
2111 | { | ||
2112 | int i; | ||
2113 | size_t bytes = wdata->bytes; | ||
2114 | |||
2115 | /* marshal up the pages into iov array */ | ||
2116 | for (i = 0; i < wdata->nr_pages; i++) { | ||
2117 | iov[i + 1].iov_len = min_t(size_t, bytes, PAGE_SIZE); | ||
2118 | iov[i + 1].iov_base = kmap(wdata->pages[i]); | ||
2119 | bytes -= iov[i + 1].iov_len; | ||
2120 | } | ||
2121 | } | ||
2122 | |||
2123 | static void | ||
2124 | cifs_uncached_writev_complete(struct work_struct *work) | ||
2125 | { | ||
2126 | int i; | ||
2127 | struct cifs_writedata *wdata = container_of(work, | ||
2128 | struct cifs_writedata, work); | ||
2129 | struct inode *inode = wdata->cfile->dentry->d_inode; | ||
2130 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | ||
2131 | |||
2132 | spin_lock(&inode->i_lock); | ||
2133 | cifs_update_eof(cifsi, wdata->offset, wdata->bytes); | ||
2134 | if (cifsi->server_eof > inode->i_size) | ||
2135 | i_size_write(inode, cifsi->server_eof); | ||
2136 | spin_unlock(&inode->i_lock); | ||
2137 | |||
2138 | complete(&wdata->done); | ||
2139 | |||
2140 | if (wdata->result != -EAGAIN) { | ||
2141 | for (i = 0; i < wdata->nr_pages; i++) | ||
2142 | put_page(wdata->pages[i]); | ||
2143 | } | ||
2144 | |||
2145 | kref_put(&wdata->refcount, cifs_writedata_release); | ||
2146 | } | ||
2147 | |||
2148 | /* attempt to send write to server, retry on any -EAGAIN errors */ | ||
2149 | static int | ||
2150 | cifs_uncached_retry_writev(struct cifs_writedata *wdata) | ||
2151 | { | ||
2152 | int rc; | ||
2153 | |||
2154 | do { | ||
2155 | if (wdata->cfile->invalidHandle) { | ||
2156 | rc = cifs_reopen_file(wdata->cfile, false); | ||
2157 | if (rc != 0) | ||
2158 | continue; | ||
2159 | } | ||
2160 | rc = cifs_async_writev(wdata); | ||
2161 | } while (rc == -EAGAIN); | ||
2162 | |||
2163 | return rc; | ||
2164 | } | ||
2165 | |||
2083 | static ssize_t | 2166 | static ssize_t |
2084 | cifs_iovec_write(struct file *file, const struct iovec *iov, | 2167 | cifs_iovec_write(struct file *file, const struct iovec *iov, |
2085 | unsigned long nr_segs, loff_t *poffset) | 2168 | unsigned long nr_segs, loff_t *poffset) |
2086 | { | 2169 | { |
2087 | unsigned int written; | 2170 | unsigned long nr_pages, i; |
2088 | unsigned long num_pages, npages, i; | ||
2089 | size_t copied, len, cur_len; | 2171 | size_t copied, len, cur_len; |
2090 | ssize_t total_written = 0; | 2172 | ssize_t total_written = 0; |
2091 | struct kvec *to_send; | 2173 | loff_t offset = *poffset; |
2092 | struct page **pages; | ||
2093 | struct iov_iter it; | 2174 | struct iov_iter it; |
2094 | struct inode *inode; | ||
2095 | struct cifsFileInfo *open_file; | 2175 | struct cifsFileInfo *open_file; |
2096 | struct cifs_tcon *pTcon; | 2176 | struct cifs_tcon *tcon; |
2097 | struct cifs_sb_info *cifs_sb; | 2177 | struct cifs_sb_info *cifs_sb; |
2098 | struct cifs_io_parms io_parms; | 2178 | struct cifs_writedata *wdata, *tmp; |
2099 | int xid, rc; | 2179 | struct list_head wdata_list; |
2100 | __u32 pid; | 2180 | int rc; |
2181 | pid_t pid; | ||
2101 | 2182 | ||
2102 | len = iov_length(iov, nr_segs); | 2183 | len = iov_length(iov, nr_segs); |
2103 | if (!len) | 2184 | if (!len) |
@@ -2107,103 +2188,103 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, | |||
2107 | if (rc) | 2188 | if (rc) |
2108 | return rc; | 2189 | return rc; |
2109 | 2190 | ||
2191 | INIT_LIST_HEAD(&wdata_list); | ||
2110 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 2192 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
2111 | num_pages = get_numpages(cifs_sb->wsize, len, &cur_len); | ||
2112 | |||
2113 | pages = kmalloc(sizeof(struct pages *)*num_pages, GFP_KERNEL); | ||
2114 | if (!pages) | ||
2115 | return -ENOMEM; | ||
2116 | |||
2117 | to_send = kmalloc(sizeof(struct kvec)*(num_pages + 1), GFP_KERNEL); | ||
2118 | if (!to_send) { | ||
2119 | kfree(pages); | ||
2120 | return -ENOMEM; | ||
2121 | } | ||
2122 | |||
2123 | rc = cifs_write_allocate_pages(pages, num_pages); | ||
2124 | if (rc) { | ||
2125 | kfree(pages); | ||
2126 | kfree(to_send); | ||
2127 | return rc; | ||
2128 | } | ||
2129 | |||
2130 | xid = GetXid(); | ||
2131 | open_file = file->private_data; | 2193 | open_file = file->private_data; |
2194 | tcon = tlink_tcon(open_file->tlink); | ||
2132 | 2195 | ||
2133 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) | 2196 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) |
2134 | pid = open_file->pid; | 2197 | pid = open_file->pid; |
2135 | else | 2198 | else |
2136 | pid = current->tgid; | 2199 | pid = current->tgid; |
2137 | 2200 | ||
2138 | pTcon = tlink_tcon(open_file->tlink); | ||
2139 | inode = file->f_path.dentry->d_inode; | ||
2140 | |||
2141 | iov_iter_init(&it, iov, nr_segs, len, 0); | 2201 | iov_iter_init(&it, iov, nr_segs, len, 0); |
2142 | npages = num_pages; | ||
2143 | |||
2144 | do { | 2202 | do { |
2145 | size_t save_len = cur_len; | 2203 | size_t save_len; |
2146 | for (i = 0; i < npages; i++) { | 2204 | |
2147 | copied = min_t(const size_t, cur_len, PAGE_CACHE_SIZE); | 2205 | nr_pages = get_numpages(cifs_sb->wsize, len, &cur_len); |
2148 | copied = iov_iter_copy_from_user(pages[i], &it, 0, | 2206 | wdata = cifs_writedata_alloc(nr_pages, |
2149 | copied); | 2207 | cifs_uncached_writev_complete); |
2208 | if (!wdata) { | ||
2209 | rc = -ENOMEM; | ||
2210 | break; | ||
2211 | } | ||
2212 | |||
2213 | rc = cifs_write_allocate_pages(wdata->pages, nr_pages); | ||
2214 | if (rc) { | ||
2215 | kfree(wdata); | ||
2216 | break; | ||
2217 | } | ||
2218 | |||
2219 | save_len = cur_len; | ||
2220 | for (i = 0; i < nr_pages; i++) { | ||
2221 | copied = min_t(const size_t, cur_len, PAGE_SIZE); | ||
2222 | copied = iov_iter_copy_from_user(wdata->pages[i], &it, | ||
2223 | 0, copied); | ||
2150 | cur_len -= copied; | 2224 | cur_len -= copied; |
2151 | iov_iter_advance(&it, copied); | 2225 | iov_iter_advance(&it, copied); |
2152 | to_send[i+1].iov_base = kmap(pages[i]); | ||
2153 | to_send[i+1].iov_len = copied; | ||
2154 | } | 2226 | } |
2155 | |||
2156 | cur_len = save_len - cur_len; | 2227 | cur_len = save_len - cur_len; |
2157 | 2228 | ||
2158 | do { | 2229 | wdata->sync_mode = WB_SYNC_ALL; |
2159 | if (open_file->invalidHandle) { | 2230 | wdata->nr_pages = nr_pages; |
2160 | rc = cifs_reopen_file(open_file, false); | 2231 | wdata->offset = (__u64)offset; |
2161 | if (rc != 0) | 2232 | wdata->cfile = cifsFileInfo_get(open_file); |
2162 | break; | 2233 | wdata->pid = pid; |
2163 | } | 2234 | wdata->bytes = cur_len; |
2164 | io_parms.netfid = open_file->netfid; | 2235 | wdata->marshal_iov = cifs_uncached_marshal_iov; |
2165 | io_parms.pid = pid; | 2236 | rc = cifs_uncached_retry_writev(wdata); |
2166 | io_parms.tcon = pTcon; | 2237 | if (rc) { |
2167 | io_parms.offset = *poffset; | 2238 | kref_put(&wdata->refcount, cifs_writedata_release); |
2168 | io_parms.length = cur_len; | ||
2169 | rc = CIFSSMBWrite2(xid, &io_parms, &written, to_send, | ||
2170 | npages, 0); | ||
2171 | } while (rc == -EAGAIN); | ||
2172 | |||
2173 | for (i = 0; i < npages; i++) | ||
2174 | kunmap(pages[i]); | ||
2175 | |||
2176 | if (written) { | ||
2177 | len -= written; | ||
2178 | total_written += written; | ||
2179 | cifs_update_eof(CIFS_I(inode), *poffset, written); | ||
2180 | *poffset += written; | ||
2181 | } else if (rc < 0) { | ||
2182 | if (!total_written) | ||
2183 | total_written = rc; | ||
2184 | break; | 2239 | break; |
2185 | } | 2240 | } |
2186 | 2241 | ||
2187 | /* get length and number of kvecs of the next write */ | 2242 | list_add_tail(&wdata->list, &wdata_list); |
2188 | npages = get_numpages(cifs_sb->wsize, len, &cur_len); | 2243 | offset += cur_len; |
2244 | len -= cur_len; | ||
2189 | } while (len > 0); | 2245 | } while (len > 0); |
2190 | 2246 | ||
2191 | if (total_written > 0) { | 2247 | /* |
2192 | spin_lock(&inode->i_lock); | 2248 | * If at least one write was successfully sent, then discard any rc |
2193 | if (*poffset > inode->i_size) | 2249 | * value from the later writes. If the other write succeeds, then |
2194 | i_size_write(inode, *poffset); | 2250 | * we'll end up returning whatever was written. If it fails, then |
2195 | spin_unlock(&inode->i_lock); | 2251 | * we'll get a new rc value from that. |
2252 | */ | ||
2253 | if (!list_empty(&wdata_list)) | ||
2254 | rc = 0; | ||
2255 | |||
2256 | /* | ||
2257 | * Wait for and collect replies for any successful sends in order of | ||
2258 | * increasing offset. Once an error is hit or we get a fatal signal | ||
2259 | * while waiting, then return without waiting for any more replies. | ||
2260 | */ | ||
2261 | restart_loop: | ||
2262 | list_for_each_entry_safe(wdata, tmp, &wdata_list, list) { | ||
2263 | if (!rc) { | ||
2264 | /* FIXME: freezable too? */ | ||
2265 | rc = wait_for_completion_killable(&wdata->done); | ||
2266 | if (rc) | ||
2267 | rc = -EINTR; | ||
2268 | else if (wdata->result) | ||
2269 | rc = wdata->result; | ||
2270 | else | ||
2271 | total_written += wdata->bytes; | ||
2272 | |||
2273 | /* resend call if it's a retryable error */ | ||
2274 | if (rc == -EAGAIN) { | ||
2275 | rc = cifs_uncached_retry_writev(wdata); | ||
2276 | goto restart_loop; | ||
2277 | } | ||
2278 | } | ||
2279 | list_del_init(&wdata->list); | ||
2280 | kref_put(&wdata->refcount, cifs_writedata_release); | ||
2196 | } | 2281 | } |
2197 | 2282 | ||
2198 | cifs_stats_bytes_written(pTcon, total_written); | 2283 | if (total_written > 0) |
2199 | mark_inode_dirty_sync(inode); | 2284 | *poffset += total_written; |
2200 | 2285 | ||
2201 | for (i = 0; i < num_pages; i++) | 2286 | cifs_stats_bytes_written(tcon, total_written); |
2202 | put_page(pages[i]); | 2287 | return total_written ? total_written : (ssize_t)rc; |
2203 | kfree(to_send); | ||
2204 | kfree(pages); | ||
2205 | FreeXid(xid); | ||
2206 | return total_written; | ||
2207 | } | 2288 | } |
2208 | 2289 | ||
2209 | ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, | 2290 | ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, |