diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 39 |
1 files changed, 35 insertions, 4 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 755584684f6c..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); |
@@ -2389,7 +2389,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, | |||
2389 | unsigned long nr_segs, loff_t *poffset) | 2389 | unsigned long nr_segs, loff_t *poffset) |
2390 | { | 2390 | { |
2391 | unsigned long nr_pages, i; | 2391 | unsigned long nr_pages, i; |
2392 | size_t copied, len, cur_len; | 2392 | size_t bytes, copied, len, cur_len; |
2393 | ssize_t total_written = 0; | 2393 | ssize_t total_written = 0; |
2394 | loff_t offset; | 2394 | loff_t offset; |
2395 | struct iov_iter it; | 2395 | struct iov_iter it; |
@@ -2444,14 +2444,45 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, | |||
2444 | 2444 | ||
2445 | save_len = cur_len; | 2445 | save_len = cur_len; |
2446 | for (i = 0; i < nr_pages; i++) { | 2446 | for (i = 0; i < nr_pages; i++) { |
2447 | copied = min_t(const size_t, cur_len, PAGE_SIZE); | 2447 | bytes = min_t(const size_t, cur_len, PAGE_SIZE); |
2448 | copied = iov_iter_copy_from_user(wdata->pages[i], &it, | 2448 | copied = iov_iter_copy_from_user(wdata->pages[i], &it, |
2449 | 0, copied); | 2449 | 0, bytes); |
2450 | cur_len -= copied; | 2450 | cur_len -= copied; |
2451 | 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; | ||
2452 | } | 2461 | } |
2453 | cur_len = save_len - cur_len; | 2462 | cur_len = save_len - cur_len; |
2454 | 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 | |||
2455 | wdata->sync_mode = WB_SYNC_ALL; | 2486 | wdata->sync_mode = WB_SYNC_ALL; |
2456 | wdata->nr_pages = nr_pages; | 2487 | wdata->nr_pages = nr_pages; |
2457 | wdata->offset = (__u64)offset; | 2488 | wdata->offset = (__u64)offset; |