aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2012-03-23 14:40:56 -0400
committerJeff Layton <jlayton@redhat.com>2012-03-23 14:40:56 -0400
commitda82f7e755d2808ba726c9b23267d5bb23980e94 (patch)
tree16fe36b382416b4bc01edd886f3f1670c3aac4db
parent597b027f694481ffeebcffe634c24b807198d46c (diff)
cifs: convert cifs_iovec_write to use async writes
Signed-off-by: Jeff Layton <jlayton@redhat.com> Reviewed-by: Pavel Shilovsky <piastry@etersoft.ru>
-rw-r--r--fs/cifs/cifsproto.h2
-rw-r--r--fs/cifs/cifssmb.c4
-rw-r--r--fs/cifs/file.c223
3 files changed, 143 insertions, 86 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 57ce6f834220..96192c1e380a 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -483,6 +483,8 @@ int cifs_async_readv(struct cifs_readdata *rdata);
483/* asynchronous write support */ 483/* asynchronous write support */
484struct cifs_writedata { 484struct cifs_writedata {
485 struct kref refcount; 485 struct kref refcount;
486 struct list_head list;
487 struct completion done;
486 enum writeback_sync_modes sync_mode; 488 enum writeback_sync_modes sync_mode;
487 struct work_struct work; 489 struct work_struct work;
488 struct cifsFileInfo *cfile; 490 struct cifsFileInfo *cfile;
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index b63bf5f0698a..8fecc99be344 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2081,8 +2081,10 @@ cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
2081 wdata = kzalloc(sizeof(*wdata) + 2081 wdata = kzalloc(sizeof(*wdata) +
2082 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS); 2082 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
2083 if (wdata != NULL) { 2083 if (wdata != NULL) {
2084 INIT_WORK(&wdata->work, complete);
2085 kref_init(&wdata->refcount); 2084 kref_init(&wdata->refcount);
2085 INIT_LIST_HEAD(&wdata->list);
2086 init_completion(&wdata->done);
2087 INIT_WORK(&wdata->work, complete);
2086 } 2088 }
2087 return wdata; 2089 return wdata;
2088} 2090}
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 6883b08f848c..daaaca82eeb2 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2106,24 +2106,79 @@ size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len)
2106 return num_pages; 2106 return num_pages;
2107} 2107}
2108 2108
2109static void
2110cifs_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(bytes, PAGE_SIZE);
2118 iov[i + 1].iov_base = kmap(wdata->pages[i]);
2119 bytes -= iov[i + 1].iov_len;
2120 }
2121}
2122
2123static void
2124cifs_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 */
2149static int
2150cifs_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
2109static ssize_t 2166static ssize_t
2110cifs_iovec_write(struct file *file, const struct iovec *iov, 2167cifs_iovec_write(struct file *file, const struct iovec *iov,
2111 unsigned long nr_segs, loff_t *poffset) 2168 unsigned long nr_segs, loff_t *poffset)
2112{ 2169{
2113 unsigned int written; 2170 unsigned long nr_pages, i;
2114 unsigned long num_pages, npages, i;
2115 size_t copied, len, cur_len; 2171 size_t copied, len, cur_len;
2116 ssize_t total_written = 0; 2172 ssize_t total_written = 0;
2117 struct kvec *to_send; 2173 loff_t offset = *poffset;
2118 struct page **pages;
2119 struct iov_iter it; 2174 struct iov_iter it;
2120 struct inode *inode;
2121 struct cifsFileInfo *open_file; 2175 struct cifsFileInfo *open_file;
2122 struct cifs_tcon *pTcon; 2176 struct cifs_tcon *tcon;
2123 struct cifs_sb_info *cifs_sb; 2177 struct cifs_sb_info *cifs_sb;
2124 struct cifs_io_parms io_parms; 2178 struct cifs_writedata *wdata, *tmp;
2125 int xid, rc; 2179 struct list_head wdata_list;
2126 __u32 pid; 2180 int rc;
2181 pid_t pid;
2127 2182
2128 len = iov_length(iov, nr_segs); 2183 len = iov_length(iov, nr_segs);
2129 if (!len) 2184 if (!len)
@@ -2133,105 +2188,103 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
2133 if (rc) 2188 if (rc)
2134 return rc; 2189 return rc;
2135 2190
2191 INIT_LIST_HEAD(&wdata_list);
2136 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); 2192 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
2137 num_pages = get_numpages(cifs_sb->wsize, len, &cur_len);
2138
2139 pages = kmalloc(sizeof(struct pages *)*num_pages, GFP_KERNEL);
2140 if (!pages)
2141 return -ENOMEM;
2142
2143 to_send = kmalloc(sizeof(struct kvec)*(num_pages + 1), GFP_KERNEL);
2144 if (!to_send) {
2145 kfree(pages);
2146 return -ENOMEM;
2147 }
2148
2149 rc = cifs_write_allocate_pages(pages, num_pages);
2150 if (rc) {
2151 kfree(pages);
2152 kfree(to_send);
2153 return rc;
2154 }
2155
2156 xid = GetXid();
2157 open_file = file->private_data; 2193 open_file = file->private_data;
2194 tcon = tlink_tcon(open_file->tlink);
2158 2195
2159 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) 2196 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
2160 pid = open_file->pid; 2197 pid = open_file->pid;
2161 else 2198 else
2162 pid = current->tgid; 2199 pid = current->tgid;
2163 2200
2164 pTcon = tlink_tcon(open_file->tlink);
2165 inode = file->f_path.dentry->d_inode;
2166
2167 iov_iter_init(&it, iov, nr_segs, len, 0); 2201 iov_iter_init(&it, iov, nr_segs, len, 0);
2168 npages = num_pages;
2169
2170 do { 2202 do {
2171 size_t save_len = cur_len; 2203 size_t save_len;
2172 for (i = 0; i < npages; i++) { 2204
2173 copied = min_t(const size_t, cur_len, PAGE_CACHE_SIZE); 2205 nr_pages = get_numpages(cifs_sb->wsize, len, &cur_len);
2174 copied = iov_iter_copy_from_user(pages[i], &it, 0, 2206 wdata = cifs_writedata_alloc(nr_pages,
2175 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);
2176 cur_len -= copied; 2224 cur_len -= copied;
2177 iov_iter_advance(&it, copied); 2225 iov_iter_advance(&it, copied);
2178 to_send[i+1].iov_base = kmap(pages[i]);
2179 to_send[i+1].iov_len = copied;
2180 } 2226 }
2181
2182 cur_len = save_len - cur_len; 2227 cur_len = save_len - cur_len;
2183 2228
2184 do { 2229 wdata->sync_mode = WB_SYNC_ALL;
2185 if (open_file->invalidHandle) { 2230 wdata->nr_pages = nr_pages;
2186 rc = cifs_reopen_file(open_file, false); 2231 wdata->offset = (__u64)offset;
2187 if (rc != 0) 2232 wdata->cfile = cifsFileInfo_get(open_file);
2188 break; 2233 wdata->pid = pid;
2189 } 2234 wdata->bytes = cur_len;
2190 io_parms.netfid = open_file->netfid; 2235 wdata->marshal_iov = cifs_uncached_marshal_iov;
2191 io_parms.pid = pid; 2236 rc = cifs_uncached_retry_writev(wdata);
2192 io_parms.tcon = pTcon; 2237 if (rc) {
2193 io_parms.offset = *poffset; 2238 kref_put(&wdata->refcount, cifs_writedata_release);
2194 io_parms.length = cur_len;
2195 rc = CIFSSMBWrite2(xid, &io_parms, &written, to_send,
2196 npages, 0);
2197 } while (rc == -EAGAIN);
2198
2199 for (i = 0; i < npages; i++)
2200 kunmap(pages[i]);
2201
2202 if (written) {
2203 len -= written;
2204 total_written += written;
2205 spin_lock(&inode->i_lock);
2206 cifs_update_eof(CIFS_I(inode), *poffset, written);
2207 spin_unlock(&inode->i_lock);
2208 *poffset += written;
2209 } else if (rc < 0) {
2210 if (!total_written)
2211 total_written = rc;
2212 break; 2239 break;
2213 } 2240 }
2214 2241
2215 /* get length and number of kvecs of the next write */ 2242 list_add_tail(&wdata->list, &wdata_list);
2216 npages = get_numpages(cifs_sb->wsize, len, &cur_len); 2243 offset += cur_len;
2244 len -= cur_len;
2217 } while (len > 0); 2245 } while (len > 0);
2218 2246
2219 if (total_written > 0) { 2247 /*
2220 spin_lock(&inode->i_lock); 2248 * If at least one write was successfully sent, then discard any rc
2221 if (*poffset > inode->i_size) 2249 * value from the later writes. If the other write succeeds, then
2222 i_size_write(inode, *poffset); 2250 * we'll end up returning whatever was written. If it fails, then
2223 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 */
2261restart_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);
2224 } 2281 }
2225 2282
2226 cifs_stats_bytes_written(pTcon, total_written); 2283 if (total_written > 0)
2227 mark_inode_dirty_sync(inode); 2284 *poffset += total_written;
2228 2285
2229 for (i = 0; i < num_pages; i++) 2286 cifs_stats_bytes_written(tcon, total_written);
2230 put_page(pages[i]); 2287 return total_written ? total_written : (ssize_t)rc;
2231 kfree(to_send);
2232 kfree(pages);
2233 FreeXid(xid);
2234 return total_written;
2235} 2288}
2236 2289
2237ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, 2290ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,