diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 74 |
1 files changed, 57 insertions, 17 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 853d6d1cc822..53c15074bb36 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -244,7 +244,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, | |||
244 | xid); | 244 | xid); |
245 | else | 245 | else |
246 | rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, | 246 | rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, |
247 | xid, &fid->netfid); | 247 | xid, fid); |
248 | 248 | ||
249 | out: | 249 | out: |
250 | kfree(buf); | 250 | kfree(buf); |
@@ -2043,7 +2043,8 @@ retry: | |||
2043 | } | 2043 | } |
2044 | wdata->pid = wdata->cfile->pid; | 2044 | wdata->pid = wdata->cfile->pid; |
2045 | server = tlink_tcon(wdata->cfile->tlink)->ses->server; | 2045 | server = tlink_tcon(wdata->cfile->tlink)->ses->server; |
2046 | rc = server->ops->async_writev(wdata); | 2046 | rc = server->ops->async_writev(wdata, |
2047 | cifs_writedata_release); | ||
2047 | } while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN); | 2048 | } while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN); |
2048 | 2049 | ||
2049 | for (i = 0; i < nr_pages; ++i) | 2050 | for (i = 0; i < nr_pages; ++i) |
@@ -2331,9 +2332,20 @@ size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len) | |||
2331 | } | 2332 | } |
2332 | 2333 | ||
2333 | static void | 2334 | static void |
2334 | cifs_uncached_writev_complete(struct work_struct *work) | 2335 | cifs_uncached_writedata_release(struct kref *refcount) |
2335 | { | 2336 | { |
2336 | int i; | 2337 | int i; |
2338 | struct cifs_writedata *wdata = container_of(refcount, | ||
2339 | struct cifs_writedata, refcount); | ||
2340 | |||
2341 | for (i = 0; i < wdata->nr_pages; i++) | ||
2342 | put_page(wdata->pages[i]); | ||
2343 | cifs_writedata_release(refcount); | ||
2344 | } | ||
2345 | |||
2346 | static void | ||
2347 | cifs_uncached_writev_complete(struct work_struct *work) | ||
2348 | { | ||
2337 | struct cifs_writedata *wdata = container_of(work, | 2349 | struct cifs_writedata *wdata = container_of(work, |
2338 | struct cifs_writedata, work); | 2350 | struct cifs_writedata, work); |
2339 | struct inode *inode = wdata->cfile->dentry->d_inode; | 2351 | struct inode *inode = wdata->cfile->dentry->d_inode; |
@@ -2347,12 +2359,7 @@ cifs_uncached_writev_complete(struct work_struct *work) | |||
2347 | 2359 | ||
2348 | complete(&wdata->done); | 2360 | complete(&wdata->done); |
2349 | 2361 | ||
2350 | if (wdata->result != -EAGAIN) { | 2362 | kref_put(&wdata->refcount, cifs_uncached_writedata_release); |
2351 | for (i = 0; i < wdata->nr_pages; i++) | ||
2352 | put_page(wdata->pages[i]); | ||
2353 | } | ||
2354 | |||
2355 | kref_put(&wdata->refcount, cifs_writedata_release); | ||
2356 | } | 2363 | } |
2357 | 2364 | ||
2358 | /* attempt to send write to server, retry on any -EAGAIN errors */ | 2365 | /* attempt to send write to server, retry on any -EAGAIN errors */ |
@@ -2370,7 +2377,8 @@ cifs_uncached_retry_writev(struct cifs_writedata *wdata) | |||
2370 | if (rc != 0) | 2377 | if (rc != 0) |
2371 | continue; | 2378 | continue; |
2372 | } | 2379 | } |
2373 | rc = server->ops->async_writev(wdata); | 2380 | rc = server->ops->async_writev(wdata, |
2381 | cifs_uncached_writedata_release); | ||
2374 | } while (rc == -EAGAIN); | 2382 | } while (rc == -EAGAIN); |
2375 | 2383 | ||
2376 | return rc; | 2384 | return rc; |
@@ -2381,7 +2389,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, | |||
2381 | unsigned long nr_segs, loff_t *poffset) | 2389 | unsigned long nr_segs, loff_t *poffset) |
2382 | { | 2390 | { |
2383 | unsigned long nr_pages, i; | 2391 | unsigned long nr_pages, i; |
2384 | size_t copied, len, cur_len; | 2392 | size_t bytes, copied, len, cur_len; |
2385 | ssize_t total_written = 0; | 2393 | ssize_t total_written = 0; |
2386 | loff_t offset; | 2394 | loff_t offset; |
2387 | struct iov_iter it; | 2395 | struct iov_iter it; |
@@ -2436,14 +2444,45 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, | |||
2436 | 2444 | ||
2437 | save_len = cur_len; | 2445 | save_len = cur_len; |
2438 | for (i = 0; i < nr_pages; i++) { | 2446 | for (i = 0; i < nr_pages; i++) { |
2439 | copied = min_t(const size_t, cur_len, PAGE_SIZE); | 2447 | bytes = min_t(const size_t, cur_len, PAGE_SIZE); |
2440 | copied = iov_iter_copy_from_user(wdata->pages[i], &it, | 2448 | copied = iov_iter_copy_from_user(wdata->pages[i], &it, |
2441 | 0, copied); | 2449 | 0, bytes); |
2442 | cur_len -= copied; | 2450 | cur_len -= copied; |
2443 | iov_iter_advance(&it, copied); | 2451 | iov_iter_advance(&it, copied); |
2452 | /* | ||
2453 | * If we didn't copy as much as we expected, then that | ||
2454 | * may mean we trod into an unmapped area. Stop copying | ||
2455 | * at that point. On the next pass through the big | ||
2456 | * loop, we'll likely end up getting a zero-length | ||
2457 | * write and bailing out of it. | ||
2458 | */ | ||
2459 | if (copied < bytes) | ||
2460 | break; | ||
2444 | } | 2461 | } |
2445 | cur_len = save_len - cur_len; | 2462 | cur_len = save_len - cur_len; |
2446 | 2463 | ||
2464 | /* | ||
2465 | * If we have no data to send, then that probably means that | ||
2466 | * the copy above failed altogether. That's most likely because | ||
2467 | * the address in the iovec was bogus. Set the rc to -EFAULT, | ||
2468 | * free anything we allocated and bail out. | ||
2469 | */ | ||
2470 | if (!cur_len) { | ||
2471 | for (i = 0; i < nr_pages; i++) | ||
2472 | put_page(wdata->pages[i]); | ||
2473 | kfree(wdata); | ||
2474 | rc = -EFAULT; | ||
2475 | break; | ||
2476 | } | ||
2477 | |||
2478 | /* | ||
2479 | * i + 1 now represents the number of pages we actually used in | ||
2480 | * the copy phase above. Bring nr_pages down to that, and free | ||
2481 | * any pages that we didn't use. | ||
2482 | */ | ||
2483 | for ( ; nr_pages > i + 1; nr_pages--) | ||
2484 | put_page(wdata->pages[nr_pages - 1]); | ||
2485 | |||
2447 | wdata->sync_mode = WB_SYNC_ALL; | 2486 | wdata->sync_mode = WB_SYNC_ALL; |
2448 | wdata->nr_pages = nr_pages; | 2487 | wdata->nr_pages = nr_pages; |
2449 | wdata->offset = (__u64)offset; | 2488 | wdata->offset = (__u64)offset; |
@@ -2454,7 +2493,8 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, | |||
2454 | wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE); | 2493 | wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE); |
2455 | rc = cifs_uncached_retry_writev(wdata); | 2494 | rc = cifs_uncached_retry_writev(wdata); |
2456 | if (rc) { | 2495 | if (rc) { |
2457 | kref_put(&wdata->refcount, cifs_writedata_release); | 2496 | kref_put(&wdata->refcount, |
2497 | cifs_uncached_writedata_release); | ||
2458 | break; | 2498 | break; |
2459 | } | 2499 | } |
2460 | 2500 | ||
@@ -2496,7 +2536,7 @@ restart_loop: | |||
2496 | } | 2536 | } |
2497 | } | 2537 | } |
2498 | list_del_init(&wdata->list); | 2538 | list_del_init(&wdata->list); |
2499 | kref_put(&wdata->refcount, cifs_writedata_release); | 2539 | kref_put(&wdata->refcount, cifs_uncached_writedata_release); |
2500 | } | 2540 | } |
2501 | 2541 | ||
2502 | if (total_written > 0) | 2542 | if (total_written > 0) |
@@ -2559,8 +2599,8 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov, | |||
2559 | if (rc > 0) { | 2599 | if (rc > 0) { |
2560 | ssize_t err; | 2600 | ssize_t err; |
2561 | 2601 | ||
2562 | err = generic_write_sync(file, pos, rc); | 2602 | err = generic_write_sync(file, iocb->ki_pos - rc, rc); |
2563 | if (err < 0 && rc > 0) | 2603 | if (err < 0) |
2564 | rc = err; | 2604 | rc = err; |
2565 | } | 2605 | } |
2566 | 2606 | ||