diff options
Diffstat (limited to 'fs/cifs/file.c')
| -rw-r--r-- | fs/cifs/file.c | 94 |
1 files changed, 61 insertions, 33 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 853d6d1cc822..834fce759d80 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) |
| @@ -2539,31 +2579,19 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov, | |||
| 2539 | struct cifsInodeInfo *cinode = CIFS_I(inode); | 2579 | struct cifsInodeInfo *cinode = CIFS_I(inode); |
| 2540 | struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; | 2580 | struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; |
| 2541 | ssize_t rc = -EACCES; | 2581 | ssize_t rc = -EACCES; |
| 2582 | loff_t lock_pos = pos; | ||
| 2542 | 2583 | ||
| 2543 | BUG_ON(iocb->ki_pos != pos); | 2584 | if (file->f_flags & O_APPEND) |
| 2544 | 2585 | lock_pos = i_size_read(inode); | |
| 2545 | /* | 2586 | /* |
| 2546 | * We need to hold the sem to be sure nobody modifies lock list | 2587 | * We need to hold the sem to be sure nobody modifies lock list |
| 2547 | * with a brlock that prevents writing. | 2588 | * with a brlock that prevents writing. |
| 2548 | */ | 2589 | */ |
| 2549 | down_read(&cinode->lock_sem); | 2590 | down_read(&cinode->lock_sem); |
| 2550 | if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs), | 2591 | if (!cifs_find_lock_conflict(cfile, lock_pos, iov_length(iov, nr_segs), |
| 2551 | server->vals->exclusive_lock_type, NULL, | 2592 | server->vals->exclusive_lock_type, NULL, |
| 2552 | CIFS_WRITE_OP)) { | 2593 | CIFS_WRITE_OP)) |
| 2553 | mutex_lock(&inode->i_mutex); | 2594 | rc = generic_file_aio_write(iocb, iov, nr_segs, pos); |
| 2554 | rc = __generic_file_aio_write(iocb, iov, nr_segs, | ||
| 2555 | &iocb->ki_pos); | ||
| 2556 | mutex_unlock(&inode->i_mutex); | ||
| 2557 | } | ||
| 2558 | |||
| 2559 | if (rc > 0) { | ||
| 2560 | ssize_t err; | ||
| 2561 | |||
| 2562 | err = generic_write_sync(file, pos, rc); | ||
| 2563 | if (err < 0 && rc > 0) | ||
| 2564 | rc = err; | ||
| 2565 | } | ||
| 2566 | |||
| 2567 | up_read(&cinode->lock_sem); | 2595 | up_read(&cinode->lock_sem); |
| 2568 | return rc; | 2596 | return rc; |
| 2569 | } | 2597 | } |
