diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-06 14:51:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-06 14:51:46 -0400 |
commit | fe7a719b30dfdb4d55680461954b99b257ebe671 (patch) | |
tree | 8ca403a39b932c88cfe16f28b78d646fa908746a | |
parent | d484467c860dab3e17893d23b2238e1f581460fa (diff) | |
parent | 85435d7a15294f9f7ef23469e6aaf7c5dfcc54f0 (diff) |
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs fixes from Steve French:
"Various fixes for stable for CIFS/SMB3 especially for better
interoperability for SMB3 to Macs.
It also includes Pavel's improvements to SMB3 async i/o support
(which is much faster now)"
* 'for-next' of git://git.samba.org/sfrench/cifs-2.6:
CIFS: add misssing SFM mapping for doublequote
SMB3: Work around mount failure when using SMB3 dialect to Macs
cifs: fix CIFS_IOC_GET_MNT_INFO oops
CIFS: fix mapping of SFM_SPACE and SFM_PERIOD
CIFS: fix oplock break deadlocks
cifs: fix CIFS_ENUMERATE_SNAPSHOTS oops
cifs: fix leak in FSCTL_ENUM_SNAPS response handling
Set unicode flag on cifs echo request to avoid Mac error
CIFS: Add asynchronous write support through kernel AIO
CIFS: Add asynchronous read support through kernel AIO
CIFS: Add asynchronous context to support kernel AIO
cifs: fix IPv6 link local, with scope id, address parsing
cifs: small underflow in cnvrtDosUnixTm()
-rw-r--r-- | fs/cifs/cifs_unicode.c | 6 | ||||
-rw-r--r-- | fs/cifs/cifs_unicode.h | 5 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 15 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 20 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 3 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 3 | ||||
-rw-r--r-- | fs/cifs/connect.c | 9 | ||||
-rw-r--r-- | fs/cifs/file.c | 357 | ||||
-rw-r--r-- | fs/cifs/ioctl.c | 4 | ||||
-rw-r--r-- | fs/cifs/misc.c | 122 | ||||
-rw-r--r-- | fs/cifs/netmisc.c | 6 | ||||
-rw-r--r-- | fs/cifs/smb2misc.c | 5 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 1 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 14 |
14 files changed, 465 insertions, 105 deletions
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 02b071bf3732..a0b3e7d1be48 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c | |||
@@ -83,6 +83,9 @@ convert_sfm_char(const __u16 src_char, char *target) | |||
83 | case SFM_COLON: | 83 | case SFM_COLON: |
84 | *target = ':'; | 84 | *target = ':'; |
85 | break; | 85 | break; |
86 | case SFM_DOUBLEQUOTE: | ||
87 | *target = '"'; | ||
88 | break; | ||
86 | case SFM_ASTERISK: | 89 | case SFM_ASTERISK: |
87 | *target = '*'; | 90 | *target = '*'; |
88 | break; | 91 | break; |
@@ -418,6 +421,9 @@ static __le16 convert_to_sfm_char(char src_char, bool end_of_string) | |||
418 | case ':': | 421 | case ':': |
419 | dest_char = cpu_to_le16(SFM_COLON); | 422 | dest_char = cpu_to_le16(SFM_COLON); |
420 | break; | 423 | break; |
424 | case '"': | ||
425 | dest_char = cpu_to_le16(SFM_DOUBLEQUOTE); | ||
426 | break; | ||
421 | case '*': | 427 | case '*': |
422 | dest_char = cpu_to_le16(SFM_ASTERISK); | 428 | dest_char = cpu_to_le16(SFM_ASTERISK); |
423 | break; | 429 | break; |
diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h index 3d7298cc0aeb..8a79a34e66b8 100644 --- a/fs/cifs/cifs_unicode.h +++ b/fs/cifs/cifs_unicode.h | |||
@@ -57,6 +57,7 @@ | |||
57 | * not conflict (although almost does) with the mapping above. | 57 | * not conflict (although almost does) with the mapping above. |
58 | */ | 58 | */ |
59 | 59 | ||
60 | #define SFM_DOUBLEQUOTE ((__u16) 0xF020) | ||
60 | #define SFM_ASTERISK ((__u16) 0xF021) | 61 | #define SFM_ASTERISK ((__u16) 0xF021) |
61 | #define SFM_QUESTION ((__u16) 0xF025) | 62 | #define SFM_QUESTION ((__u16) 0xF025) |
62 | #define SFM_COLON ((__u16) 0xF022) | 63 | #define SFM_COLON ((__u16) 0xF022) |
@@ -64,8 +65,8 @@ | |||
64 | #define SFM_LESSTHAN ((__u16) 0xF023) | 65 | #define SFM_LESSTHAN ((__u16) 0xF023) |
65 | #define SFM_PIPE ((__u16) 0xF027) | 66 | #define SFM_PIPE ((__u16) 0xF027) |
66 | #define SFM_SLASH ((__u16) 0xF026) | 67 | #define SFM_SLASH ((__u16) 0xF026) |
67 | #define SFM_PERIOD ((__u16) 0xF028) | 68 | #define SFM_SPACE ((__u16) 0xF028) |
68 | #define SFM_SPACE ((__u16) 0xF029) | 69 | #define SFM_PERIOD ((__u16) 0xF029) |
69 | 70 | ||
70 | /* | 71 | /* |
71 | * Mapping mechanism to use when one of the seven reserved characters is | 72 | * Mapping mechanism to use when one of the seven reserved characters is |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index d0d11b73b2af..9a1667e0e8d6 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -88,6 +88,7 @@ extern mempool_t *cifs_req_poolp; | |||
88 | extern mempool_t *cifs_mid_poolp; | 88 | extern mempool_t *cifs_mid_poolp; |
89 | 89 | ||
90 | struct workqueue_struct *cifsiod_wq; | 90 | struct workqueue_struct *cifsiod_wq; |
91 | struct workqueue_struct *cifsoplockd_wq; | ||
91 | __u32 cifs_lock_secret; | 92 | __u32 cifs_lock_secret; |
92 | 93 | ||
93 | /* | 94 | /* |
@@ -1375,9 +1376,16 @@ init_cifs(void) | |||
1375 | goto out_clean_proc; | 1376 | goto out_clean_proc; |
1376 | } | 1377 | } |
1377 | 1378 | ||
1379 | cifsoplockd_wq = alloc_workqueue("cifsoplockd", | ||
1380 | WQ_FREEZABLE|WQ_MEM_RECLAIM, 0); | ||
1381 | if (!cifsoplockd_wq) { | ||
1382 | rc = -ENOMEM; | ||
1383 | goto out_destroy_cifsiod_wq; | ||
1384 | } | ||
1385 | |||
1378 | rc = cifs_fscache_register(); | 1386 | rc = cifs_fscache_register(); |
1379 | if (rc) | 1387 | if (rc) |
1380 | goto out_destroy_wq; | 1388 | goto out_destroy_cifsoplockd_wq; |
1381 | 1389 | ||
1382 | rc = cifs_init_inodecache(); | 1390 | rc = cifs_init_inodecache(); |
1383 | if (rc) | 1391 | if (rc) |
@@ -1425,7 +1433,9 @@ out_destroy_inodecache: | |||
1425 | cifs_destroy_inodecache(); | 1433 | cifs_destroy_inodecache(); |
1426 | out_unreg_fscache: | 1434 | out_unreg_fscache: |
1427 | cifs_fscache_unregister(); | 1435 | cifs_fscache_unregister(); |
1428 | out_destroy_wq: | 1436 | out_destroy_cifsoplockd_wq: |
1437 | destroy_workqueue(cifsoplockd_wq); | ||
1438 | out_destroy_cifsiod_wq: | ||
1429 | destroy_workqueue(cifsiod_wq); | 1439 | destroy_workqueue(cifsiod_wq); |
1430 | out_clean_proc: | 1440 | out_clean_proc: |
1431 | cifs_proc_clean(); | 1441 | cifs_proc_clean(); |
@@ -1448,6 +1458,7 @@ exit_cifs(void) | |||
1448 | cifs_destroy_mids(); | 1458 | cifs_destroy_mids(); |
1449 | cifs_destroy_inodecache(); | 1459 | cifs_destroy_inodecache(); |
1450 | cifs_fscache_unregister(); | 1460 | cifs_fscache_unregister(); |
1461 | destroy_workqueue(cifsoplockd_wq); | ||
1451 | destroy_workqueue(cifsiod_wq); | 1462 | destroy_workqueue(cifsiod_wq); |
1452 | cifs_proc_clean(); | 1463 | cifs_proc_clean(); |
1453 | } | 1464 | } |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 37f5a41cc50c..8be55be70faf 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -1115,6 +1115,23 @@ struct cifs_io_parms { | |||
1115 | struct cifs_tcon *tcon; | 1115 | struct cifs_tcon *tcon; |
1116 | }; | 1116 | }; |
1117 | 1117 | ||
1118 | struct cifs_aio_ctx { | ||
1119 | struct kref refcount; | ||
1120 | struct list_head list; | ||
1121 | struct mutex aio_mutex; | ||
1122 | struct completion done; | ||
1123 | struct iov_iter iter; | ||
1124 | struct kiocb *iocb; | ||
1125 | struct cifsFileInfo *cfile; | ||
1126 | struct bio_vec *bv; | ||
1127 | loff_t pos; | ||
1128 | unsigned int npages; | ||
1129 | ssize_t rc; | ||
1130 | unsigned int len; | ||
1131 | unsigned int total_len; | ||
1132 | bool should_dirty; | ||
1133 | }; | ||
1134 | |||
1118 | struct cifs_readdata; | 1135 | struct cifs_readdata; |
1119 | 1136 | ||
1120 | /* asynchronous read support */ | 1137 | /* asynchronous read support */ |
@@ -1124,6 +1141,7 @@ struct cifs_readdata { | |||
1124 | struct completion done; | 1141 | struct completion done; |
1125 | struct cifsFileInfo *cfile; | 1142 | struct cifsFileInfo *cfile; |
1126 | struct address_space *mapping; | 1143 | struct address_space *mapping; |
1144 | struct cifs_aio_ctx *ctx; | ||
1127 | __u64 offset; | 1145 | __u64 offset; |
1128 | unsigned int bytes; | 1146 | unsigned int bytes; |
1129 | unsigned int got_bytes; | 1147 | unsigned int got_bytes; |
@@ -1154,6 +1172,7 @@ struct cifs_writedata { | |||
1154 | enum writeback_sync_modes sync_mode; | 1172 | enum writeback_sync_modes sync_mode; |
1155 | struct work_struct work; | 1173 | struct work_struct work; |
1156 | struct cifsFileInfo *cfile; | 1174 | struct cifsFileInfo *cfile; |
1175 | struct cifs_aio_ctx *ctx; | ||
1157 | __u64 offset; | 1176 | __u64 offset; |
1158 | pid_t pid; | 1177 | pid_t pid; |
1159 | unsigned int bytes; | 1178 | unsigned int bytes; |
@@ -1683,6 +1702,7 @@ void cifs_oplock_break(struct work_struct *work); | |||
1683 | 1702 | ||
1684 | extern const struct slow_work_ops cifs_oplock_break_ops; | 1703 | extern const struct slow_work_ops cifs_oplock_break_ops; |
1685 | extern struct workqueue_struct *cifsiod_wq; | 1704 | extern struct workqueue_struct *cifsiod_wq; |
1705 | extern struct workqueue_struct *cifsoplockd_wq; | ||
1686 | extern __u32 cifs_lock_secret; | 1706 | extern __u32 cifs_lock_secret; |
1687 | 1707 | ||
1688 | extern mempool_t *cifs_mid_poolp; | 1708 | extern mempool_t *cifs_mid_poolp; |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 97e5d236d265..e49958c3f8bb 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -535,4 +535,7 @@ int __cifs_calc_signature(struct smb_rqst *rqst, | |||
535 | struct shash_desc *shash); | 535 | struct shash_desc *shash); |
536 | enum securityEnum cifs_select_sectype(struct TCP_Server_Info *, | 536 | enum securityEnum cifs_select_sectype(struct TCP_Server_Info *, |
537 | enum securityEnum); | 537 | enum securityEnum); |
538 | struct cifs_aio_ctx *cifs_aio_ctx_alloc(void); | ||
539 | void cifs_aio_ctx_release(struct kref *refcount); | ||
540 | int setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw); | ||
538 | #endif /* _CIFSPROTO_H */ | 541 | #endif /* _CIFSPROTO_H */ |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 5d21f00ae341..205fd94f52fd 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -718,6 +718,9 @@ CIFSSMBEcho(struct TCP_Server_Info *server) | |||
718 | if (rc) | 718 | if (rc) |
719 | return rc; | 719 | return rc; |
720 | 720 | ||
721 | if (server->capabilities & CAP_UNICODE) | ||
722 | smb->hdr.Flags2 |= SMBFLG2_UNICODE; | ||
723 | |||
721 | /* set up echo request */ | 724 | /* set up echo request */ |
722 | smb->hdr.Tid = 0xffff; | 725 | smb->hdr.Tid = 0xffff; |
723 | smb->hdr.WordCount = 1; | 726 | smb->hdr.WordCount = 1; |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 9bc0b4d6d065..9365c0cf77ad 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -1946,9 +1946,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1946 | } | 1946 | } |
1947 | 1947 | ||
1948 | if (!got_ip) { | 1948 | if (!got_ip) { |
1949 | int len; | ||
1950 | const char *slash; | ||
1951 | |||
1949 | /* No ip= option specified? Try to get it from UNC */ | 1952 | /* No ip= option specified? Try to get it from UNC */ |
1950 | if (!cifs_convert_address(dstaddr, &vol->UNC[2], | 1953 | /* Use the address part of the UNC. */ |
1951 | strlen(&vol->UNC[2]))) { | 1954 | slash = strchr(&vol->UNC[2], '\\'); |
1955 | len = slash - &vol->UNC[2]; | ||
1956 | if (!cifs_convert_address(dstaddr, &vol->UNC[2], len)) { | ||
1952 | pr_err("Unable to determine destination address.\n"); | 1957 | pr_err("Unable to determine destination address.\n"); |
1953 | goto cifs_parse_mount_err; | 1958 | goto cifs_parse_mount_err; |
1954 | } | 1959 | } |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 21d404535739..6ef78ad838e6 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -2458,11 +2458,14 @@ cifs_uncached_writedata_release(struct kref *refcount) | |||
2458 | struct cifs_writedata *wdata = container_of(refcount, | 2458 | struct cifs_writedata *wdata = container_of(refcount, |
2459 | struct cifs_writedata, refcount); | 2459 | struct cifs_writedata, refcount); |
2460 | 2460 | ||
2461 | kref_put(&wdata->ctx->refcount, cifs_aio_ctx_release); | ||
2461 | for (i = 0; i < wdata->nr_pages; i++) | 2462 | for (i = 0; i < wdata->nr_pages; i++) |
2462 | put_page(wdata->pages[i]); | 2463 | put_page(wdata->pages[i]); |
2463 | cifs_writedata_release(refcount); | 2464 | cifs_writedata_release(refcount); |
2464 | } | 2465 | } |
2465 | 2466 | ||
2467 | static void collect_uncached_write_data(struct cifs_aio_ctx *ctx); | ||
2468 | |||
2466 | static void | 2469 | static void |
2467 | cifs_uncached_writev_complete(struct work_struct *work) | 2470 | cifs_uncached_writev_complete(struct work_struct *work) |
2468 | { | 2471 | { |
@@ -2478,7 +2481,8 @@ cifs_uncached_writev_complete(struct work_struct *work) | |||
2478 | spin_unlock(&inode->i_lock); | 2481 | spin_unlock(&inode->i_lock); |
2479 | 2482 | ||
2480 | complete(&wdata->done); | 2483 | complete(&wdata->done); |
2481 | 2484 | collect_uncached_write_data(wdata->ctx); | |
2485 | /* the below call can possibly free the last ref to aio ctx */ | ||
2482 | kref_put(&wdata->refcount, cifs_uncached_writedata_release); | 2486 | kref_put(&wdata->refcount, cifs_uncached_writedata_release); |
2483 | } | 2487 | } |
2484 | 2488 | ||
@@ -2527,7 +2531,8 @@ wdata_fill_from_iovec(struct cifs_writedata *wdata, struct iov_iter *from, | |||
2527 | static int | 2531 | static int |
2528 | cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, | 2532 | cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, |
2529 | struct cifsFileInfo *open_file, | 2533 | struct cifsFileInfo *open_file, |
2530 | struct cifs_sb_info *cifs_sb, struct list_head *wdata_list) | 2534 | struct cifs_sb_info *cifs_sb, struct list_head *wdata_list, |
2535 | struct cifs_aio_ctx *ctx) | ||
2531 | { | 2536 | { |
2532 | int rc = 0; | 2537 | int rc = 0; |
2533 | size_t cur_len; | 2538 | size_t cur_len; |
@@ -2595,6 +2600,8 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, | |||
2595 | wdata->pagesz = PAGE_SIZE; | 2600 | wdata->pagesz = PAGE_SIZE; |
2596 | wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE); | 2601 | wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE); |
2597 | wdata->credits = credits; | 2602 | wdata->credits = credits; |
2603 | wdata->ctx = ctx; | ||
2604 | kref_get(&ctx->refcount); | ||
2598 | 2605 | ||
2599 | if (!wdata->cfile->invalidHandle || | 2606 | if (!wdata->cfile->invalidHandle || |
2600 | !(rc = cifs_reopen_file(wdata->cfile, false))) | 2607 | !(rc = cifs_reopen_file(wdata->cfile, false))) |
@@ -2620,81 +2627,61 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, | |||
2620 | return rc; | 2627 | return rc; |
2621 | } | 2628 | } |
2622 | 2629 | ||
2623 | ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from) | 2630 | static void collect_uncached_write_data(struct cifs_aio_ctx *ctx) |
2624 | { | 2631 | { |
2625 | struct file *file = iocb->ki_filp; | 2632 | struct cifs_writedata *wdata, *tmp; |
2626 | ssize_t total_written = 0; | ||
2627 | struct cifsFileInfo *open_file; | ||
2628 | struct cifs_tcon *tcon; | 2633 | struct cifs_tcon *tcon; |
2629 | struct cifs_sb_info *cifs_sb; | 2634 | struct cifs_sb_info *cifs_sb; |
2630 | struct cifs_writedata *wdata, *tmp; | 2635 | struct dentry *dentry = ctx->cfile->dentry; |
2631 | struct list_head wdata_list; | 2636 | unsigned int i; |
2632 | struct iov_iter saved_from = *from; | ||
2633 | int rc; | 2637 | int rc; |
2634 | 2638 | ||
2635 | /* | 2639 | tcon = tlink_tcon(ctx->cfile->tlink); |
2636 | * BB - optimize the way when signing is disabled. We can drop this | 2640 | cifs_sb = CIFS_SB(dentry->d_sb); |
2637 | * extra memory-to-memory copying and use iovec buffers for constructing | ||
2638 | * write request. | ||
2639 | */ | ||
2640 | |||
2641 | rc = generic_write_checks(iocb, from); | ||
2642 | if (rc <= 0) | ||
2643 | return rc; | ||
2644 | |||
2645 | INIT_LIST_HEAD(&wdata_list); | ||
2646 | cifs_sb = CIFS_FILE_SB(file); | ||
2647 | open_file = file->private_data; | ||
2648 | tcon = tlink_tcon(open_file->tlink); | ||
2649 | |||
2650 | if (!tcon->ses->server->ops->async_writev) | ||
2651 | return -ENOSYS; | ||
2652 | 2641 | ||
2653 | rc = cifs_write_from_iter(iocb->ki_pos, iov_iter_count(from), from, | 2642 | mutex_lock(&ctx->aio_mutex); |
2654 | open_file, cifs_sb, &wdata_list); | ||
2655 | 2643 | ||
2656 | /* | 2644 | if (list_empty(&ctx->list)) { |
2657 | * If at least one write was successfully sent, then discard any rc | 2645 | mutex_unlock(&ctx->aio_mutex); |
2658 | * value from the later writes. If the other write succeeds, then | 2646 | return; |
2659 | * we'll end up returning whatever was written. If it fails, then | 2647 | } |
2660 | * we'll get a new rc value from that. | ||
2661 | */ | ||
2662 | if (!list_empty(&wdata_list)) | ||
2663 | rc = 0; | ||
2664 | 2648 | ||
2649 | rc = ctx->rc; | ||
2665 | /* | 2650 | /* |
2666 | * Wait for and collect replies for any successful sends in order of | 2651 | * Wait for and collect replies for any successful sends in order of |
2667 | * increasing offset. Once an error is hit or we get a fatal signal | 2652 | * increasing offset. Once an error is hit, then return without waiting |
2668 | * while waiting, then return without waiting for any more replies. | 2653 | * for any more replies. |
2669 | */ | 2654 | */ |
2670 | restart_loop: | 2655 | restart_loop: |
2671 | list_for_each_entry_safe(wdata, tmp, &wdata_list, list) { | 2656 | list_for_each_entry_safe(wdata, tmp, &ctx->list, list) { |
2672 | if (!rc) { | 2657 | if (!rc) { |
2673 | /* FIXME: freezable too? */ | 2658 | if (!try_wait_for_completion(&wdata->done)) { |
2674 | rc = wait_for_completion_killable(&wdata->done); | 2659 | mutex_unlock(&ctx->aio_mutex); |
2675 | if (rc) | 2660 | return; |
2676 | rc = -EINTR; | 2661 | } |
2677 | else if (wdata->result) | 2662 | |
2663 | if (wdata->result) | ||
2678 | rc = wdata->result; | 2664 | rc = wdata->result; |
2679 | else | 2665 | else |
2680 | total_written += wdata->bytes; | 2666 | ctx->total_len += wdata->bytes; |
2681 | 2667 | ||
2682 | /* resend call if it's a retryable error */ | 2668 | /* resend call if it's a retryable error */ |
2683 | if (rc == -EAGAIN) { | 2669 | if (rc == -EAGAIN) { |
2684 | struct list_head tmp_list; | 2670 | struct list_head tmp_list; |
2685 | struct iov_iter tmp_from = saved_from; | 2671 | struct iov_iter tmp_from = ctx->iter; |
2686 | 2672 | ||
2687 | INIT_LIST_HEAD(&tmp_list); | 2673 | INIT_LIST_HEAD(&tmp_list); |
2688 | list_del_init(&wdata->list); | 2674 | list_del_init(&wdata->list); |
2689 | 2675 | ||
2690 | iov_iter_advance(&tmp_from, | 2676 | iov_iter_advance(&tmp_from, |
2691 | wdata->offset - iocb->ki_pos); | 2677 | wdata->offset - ctx->pos); |
2692 | 2678 | ||
2693 | rc = cifs_write_from_iter(wdata->offset, | 2679 | rc = cifs_write_from_iter(wdata->offset, |
2694 | wdata->bytes, &tmp_from, | 2680 | wdata->bytes, &tmp_from, |
2695 | open_file, cifs_sb, &tmp_list); | 2681 | ctx->cfile, cifs_sb, &tmp_list, |
2682 | ctx); | ||
2696 | 2683 | ||
2697 | list_splice(&tmp_list, &wdata_list); | 2684 | list_splice(&tmp_list, &ctx->list); |
2698 | 2685 | ||
2699 | kref_put(&wdata->refcount, | 2686 | kref_put(&wdata->refcount, |
2700 | cifs_uncached_writedata_release); | 2687 | cifs_uncached_writedata_release); |
@@ -2705,12 +2692,111 @@ restart_loop: | |||
2705 | kref_put(&wdata->refcount, cifs_uncached_writedata_release); | 2692 | kref_put(&wdata->refcount, cifs_uncached_writedata_release); |
2706 | } | 2693 | } |
2707 | 2694 | ||
2695 | for (i = 0; i < ctx->npages; i++) | ||
2696 | put_page(ctx->bv[i].bv_page); | ||
2697 | |||
2698 | cifs_stats_bytes_written(tcon, ctx->total_len); | ||
2699 | set_bit(CIFS_INO_INVALID_MAPPING, &CIFS_I(dentry->d_inode)->flags); | ||
2700 | |||
2701 | ctx->rc = (rc == 0) ? ctx->total_len : rc; | ||
2702 | |||
2703 | mutex_unlock(&ctx->aio_mutex); | ||
2704 | |||
2705 | if (ctx->iocb && ctx->iocb->ki_complete) | ||
2706 | ctx->iocb->ki_complete(ctx->iocb, ctx->rc, 0); | ||
2707 | else | ||
2708 | complete(&ctx->done); | ||
2709 | } | ||
2710 | |||
2711 | ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from) | ||
2712 | { | ||
2713 | struct file *file = iocb->ki_filp; | ||
2714 | ssize_t total_written = 0; | ||
2715 | struct cifsFileInfo *cfile; | ||
2716 | struct cifs_tcon *tcon; | ||
2717 | struct cifs_sb_info *cifs_sb; | ||
2718 | struct cifs_aio_ctx *ctx; | ||
2719 | struct iov_iter saved_from = *from; | ||
2720 | int rc; | ||
2721 | |||
2722 | /* | ||
2723 | * BB - optimize the way when signing is disabled. We can drop this | ||
2724 | * extra memory-to-memory copying and use iovec buffers for constructing | ||
2725 | * write request. | ||
2726 | */ | ||
2727 | |||
2728 | rc = generic_write_checks(iocb, from); | ||
2729 | if (rc <= 0) | ||
2730 | return rc; | ||
2731 | |||
2732 | cifs_sb = CIFS_FILE_SB(file); | ||
2733 | cfile = file->private_data; | ||
2734 | tcon = tlink_tcon(cfile->tlink); | ||
2735 | |||
2736 | if (!tcon->ses->server->ops->async_writev) | ||
2737 | return -ENOSYS; | ||
2738 | |||
2739 | ctx = cifs_aio_ctx_alloc(); | ||
2740 | if (!ctx) | ||
2741 | return -ENOMEM; | ||
2742 | |||
2743 | ctx->cfile = cifsFileInfo_get(cfile); | ||
2744 | |||
2745 | if (!is_sync_kiocb(iocb)) | ||
2746 | ctx->iocb = iocb; | ||
2747 | |||
2748 | ctx->pos = iocb->ki_pos; | ||
2749 | |||
2750 | rc = setup_aio_ctx_iter(ctx, from, WRITE); | ||
2751 | if (rc) { | ||
2752 | kref_put(&ctx->refcount, cifs_aio_ctx_release); | ||
2753 | return rc; | ||
2754 | } | ||
2755 | |||
2756 | /* grab a lock here due to read response handlers can access ctx */ | ||
2757 | mutex_lock(&ctx->aio_mutex); | ||
2758 | |||
2759 | rc = cifs_write_from_iter(iocb->ki_pos, ctx->len, &saved_from, | ||
2760 | cfile, cifs_sb, &ctx->list, ctx); | ||
2761 | |||
2762 | /* | ||
2763 | * If at least one write was successfully sent, then discard any rc | ||
2764 | * value from the later writes. If the other write succeeds, then | ||
2765 | * we'll end up returning whatever was written. If it fails, then | ||
2766 | * we'll get a new rc value from that. | ||
2767 | */ | ||
2768 | if (!list_empty(&ctx->list)) | ||
2769 | rc = 0; | ||
2770 | |||
2771 | mutex_unlock(&ctx->aio_mutex); | ||
2772 | |||
2773 | if (rc) { | ||
2774 | kref_put(&ctx->refcount, cifs_aio_ctx_release); | ||
2775 | return rc; | ||
2776 | } | ||
2777 | |||
2778 | if (!is_sync_kiocb(iocb)) { | ||
2779 | kref_put(&ctx->refcount, cifs_aio_ctx_release); | ||
2780 | return -EIOCBQUEUED; | ||
2781 | } | ||
2782 | |||
2783 | rc = wait_for_completion_killable(&ctx->done); | ||
2784 | if (rc) { | ||
2785 | mutex_lock(&ctx->aio_mutex); | ||
2786 | ctx->rc = rc = -EINTR; | ||
2787 | total_written = ctx->total_len; | ||
2788 | mutex_unlock(&ctx->aio_mutex); | ||
2789 | } else { | ||
2790 | rc = ctx->rc; | ||
2791 | total_written = ctx->total_len; | ||
2792 | } | ||
2793 | |||
2794 | kref_put(&ctx->refcount, cifs_aio_ctx_release); | ||
2795 | |||
2708 | if (unlikely(!total_written)) | 2796 | if (unlikely(!total_written)) |
2709 | return rc; | 2797 | return rc; |
2710 | 2798 | ||
2711 | iocb->ki_pos += total_written; | 2799 | iocb->ki_pos += total_written; |
2712 | set_bit(CIFS_INO_INVALID_MAPPING, &CIFS_I(file_inode(file))->flags); | ||
2713 | cifs_stats_bytes_written(tcon, total_written); | ||
2714 | return total_written; | 2800 | return total_written; |
2715 | } | 2801 | } |
2716 | 2802 | ||
@@ -2859,6 +2945,7 @@ cifs_uncached_readdata_release(struct kref *refcount) | |||
2859 | struct cifs_readdata, refcount); | 2945 | struct cifs_readdata, refcount); |
2860 | unsigned int i; | 2946 | unsigned int i; |
2861 | 2947 | ||
2948 | kref_put(&rdata->ctx->refcount, cifs_aio_ctx_release); | ||
2862 | for (i = 0; i < rdata->nr_pages; i++) { | 2949 | for (i = 0; i < rdata->nr_pages; i++) { |
2863 | put_page(rdata->pages[i]); | 2950 | put_page(rdata->pages[i]); |
2864 | rdata->pages[i] = NULL; | 2951 | rdata->pages[i] = NULL; |
@@ -2900,6 +2987,8 @@ cifs_readdata_to_iov(struct cifs_readdata *rdata, struct iov_iter *iter) | |||
2900 | return remaining ? -EFAULT : 0; | 2987 | return remaining ? -EFAULT : 0; |
2901 | } | 2988 | } |
2902 | 2989 | ||
2990 | static void collect_uncached_read_data(struct cifs_aio_ctx *ctx); | ||
2991 | |||
2903 | static void | 2992 | static void |
2904 | cifs_uncached_readv_complete(struct work_struct *work) | 2993 | cifs_uncached_readv_complete(struct work_struct *work) |
2905 | { | 2994 | { |
@@ -2907,6 +2996,8 @@ cifs_uncached_readv_complete(struct work_struct *work) | |||
2907 | struct cifs_readdata, work); | 2996 | struct cifs_readdata, work); |
2908 | 2997 | ||
2909 | complete(&rdata->done); | 2998 | complete(&rdata->done); |
2999 | collect_uncached_read_data(rdata->ctx); | ||
3000 | /* the below call can possibly free the last ref to aio ctx */ | ||
2910 | kref_put(&rdata->refcount, cifs_uncached_readdata_release); | 3001 | kref_put(&rdata->refcount, cifs_uncached_readdata_release); |
2911 | } | 3002 | } |
2912 | 3003 | ||
@@ -2973,7 +3064,8 @@ cifs_uncached_copy_into_pages(struct TCP_Server_Info *server, | |||
2973 | 3064 | ||
2974 | static int | 3065 | static int |
2975 | cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, | 3066 | cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, |
2976 | struct cifs_sb_info *cifs_sb, struct list_head *rdata_list) | 3067 | struct cifs_sb_info *cifs_sb, struct list_head *rdata_list, |
3068 | struct cifs_aio_ctx *ctx) | ||
2977 | { | 3069 | { |
2978 | struct cifs_readdata *rdata; | 3070 | struct cifs_readdata *rdata; |
2979 | unsigned int npages, rsize, credits; | 3071 | unsigned int npages, rsize, credits; |
@@ -3020,6 +3112,8 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, | |||
3020 | rdata->read_into_pages = cifs_uncached_read_into_pages; | 3112 | rdata->read_into_pages = cifs_uncached_read_into_pages; |
3021 | rdata->copy_into_pages = cifs_uncached_copy_into_pages; | 3113 | rdata->copy_into_pages = cifs_uncached_copy_into_pages; |
3022 | rdata->credits = credits; | 3114 | rdata->credits = credits; |
3115 | rdata->ctx = ctx; | ||
3116 | kref_get(&ctx->refcount); | ||
3023 | 3117 | ||
3024 | if (!rdata->cfile->invalidHandle || | 3118 | if (!rdata->cfile->invalidHandle || |
3025 | !(rc = cifs_reopen_file(rdata->cfile, true))) | 3119 | !(rc = cifs_reopen_file(rdata->cfile, true))) |
@@ -3042,50 +3136,37 @@ error: | |||
3042 | return rc; | 3136 | return rc; |
3043 | } | 3137 | } |
3044 | 3138 | ||
3045 | ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to) | 3139 | static void |
3140 | collect_uncached_read_data(struct cifs_aio_ctx *ctx) | ||
3046 | { | 3141 | { |
3047 | struct file *file = iocb->ki_filp; | 3142 | struct cifs_readdata *rdata, *tmp; |
3048 | ssize_t rc; | 3143 | struct iov_iter *to = &ctx->iter; |
3049 | size_t len; | ||
3050 | ssize_t total_read = 0; | ||
3051 | loff_t offset = iocb->ki_pos; | ||
3052 | struct cifs_sb_info *cifs_sb; | 3144 | struct cifs_sb_info *cifs_sb; |
3053 | struct cifs_tcon *tcon; | 3145 | struct cifs_tcon *tcon; |
3054 | struct cifsFileInfo *open_file; | 3146 | unsigned int i; |
3055 | struct cifs_readdata *rdata, *tmp; | 3147 | int rc; |
3056 | struct list_head rdata_list; | ||
3057 | |||
3058 | len = iov_iter_count(to); | ||
3059 | if (!len) | ||
3060 | return 0; | ||
3061 | |||
3062 | INIT_LIST_HEAD(&rdata_list); | ||
3063 | cifs_sb = CIFS_FILE_SB(file); | ||
3064 | open_file = file->private_data; | ||
3065 | tcon = tlink_tcon(open_file->tlink); | ||
3066 | |||
3067 | if (!tcon->ses->server->ops->async_readv) | ||
3068 | return -ENOSYS; | ||
3069 | 3148 | ||
3070 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | 3149 | tcon = tlink_tcon(ctx->cfile->tlink); |
3071 | cifs_dbg(FYI, "attempting read on write only file instance\n"); | 3150 | cifs_sb = CIFS_SB(ctx->cfile->dentry->d_sb); |
3072 | 3151 | ||
3073 | rc = cifs_send_async_read(offset, len, open_file, cifs_sb, &rdata_list); | 3152 | mutex_lock(&ctx->aio_mutex); |
3074 | 3153 | ||
3075 | /* if at least one read request send succeeded, then reset rc */ | 3154 | if (list_empty(&ctx->list)) { |
3076 | if (!list_empty(&rdata_list)) | 3155 | mutex_unlock(&ctx->aio_mutex); |
3077 | rc = 0; | 3156 | return; |
3157 | } | ||
3078 | 3158 | ||
3079 | len = iov_iter_count(to); | 3159 | rc = ctx->rc; |
3080 | /* the loop below should proceed in the order of increasing offsets */ | 3160 | /* the loop below should proceed in the order of increasing offsets */ |
3081 | again: | 3161 | again: |
3082 | list_for_each_entry_safe(rdata, tmp, &rdata_list, list) { | 3162 | list_for_each_entry_safe(rdata, tmp, &ctx->list, list) { |
3083 | if (!rc) { | 3163 | if (!rc) { |
3084 | /* FIXME: freezable sleep too? */ | 3164 | if (!try_wait_for_completion(&rdata->done)) { |
3085 | rc = wait_for_completion_killable(&rdata->done); | 3165 | mutex_unlock(&ctx->aio_mutex); |
3086 | if (rc) | 3166 | return; |
3087 | rc = -EINTR; | 3167 | } |
3088 | else if (rdata->result == -EAGAIN) { | 3168 | |
3169 | if (rdata->result == -EAGAIN) { | ||
3089 | /* resend call if it's a retryable error */ | 3170 | /* resend call if it's a retryable error */ |
3090 | struct list_head tmp_list; | 3171 | struct list_head tmp_list; |
3091 | unsigned int got_bytes = rdata->got_bytes; | 3172 | unsigned int got_bytes = rdata->got_bytes; |
@@ -3111,9 +3192,9 @@ again: | |||
3111 | rdata->offset + got_bytes, | 3192 | rdata->offset + got_bytes, |
3112 | rdata->bytes - got_bytes, | 3193 | rdata->bytes - got_bytes, |
3113 | rdata->cfile, cifs_sb, | 3194 | rdata->cfile, cifs_sb, |
3114 | &tmp_list); | 3195 | &tmp_list, ctx); |
3115 | 3196 | ||
3116 | list_splice(&tmp_list, &rdata_list); | 3197 | list_splice(&tmp_list, &ctx->list); |
3117 | 3198 | ||
3118 | kref_put(&rdata->refcount, | 3199 | kref_put(&rdata->refcount, |
3119 | cifs_uncached_readdata_release); | 3200 | cifs_uncached_readdata_release); |
@@ -3131,14 +3212,110 @@ again: | |||
3131 | kref_put(&rdata->refcount, cifs_uncached_readdata_release); | 3212 | kref_put(&rdata->refcount, cifs_uncached_readdata_release); |
3132 | } | 3213 | } |
3133 | 3214 | ||
3134 | total_read = len - iov_iter_count(to); | 3215 | for (i = 0; i < ctx->npages; i++) { |
3216 | if (ctx->should_dirty) | ||
3217 | set_page_dirty(ctx->bv[i].bv_page); | ||
3218 | put_page(ctx->bv[i].bv_page); | ||
3219 | } | ||
3220 | |||
3221 | ctx->total_len = ctx->len - iov_iter_count(to); | ||
3135 | 3222 | ||
3136 | cifs_stats_bytes_read(tcon, total_read); | 3223 | cifs_stats_bytes_read(tcon, ctx->total_len); |
3137 | 3224 | ||
3138 | /* mask nodata case */ | 3225 | /* mask nodata case */ |
3139 | if (rc == -ENODATA) | 3226 | if (rc == -ENODATA) |
3140 | rc = 0; | 3227 | rc = 0; |
3141 | 3228 | ||
3229 | ctx->rc = (rc == 0) ? ctx->total_len : rc; | ||
3230 | |||
3231 | mutex_unlock(&ctx->aio_mutex); | ||
3232 | |||
3233 | if (ctx->iocb && ctx->iocb->ki_complete) | ||
3234 | ctx->iocb->ki_complete(ctx->iocb, ctx->rc, 0); | ||
3235 | else | ||
3236 | complete(&ctx->done); | ||
3237 | } | ||
3238 | |||
3239 | ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to) | ||
3240 | { | ||
3241 | struct file *file = iocb->ki_filp; | ||
3242 | ssize_t rc; | ||
3243 | size_t len; | ||
3244 | ssize_t total_read = 0; | ||
3245 | loff_t offset = iocb->ki_pos; | ||
3246 | struct cifs_sb_info *cifs_sb; | ||
3247 | struct cifs_tcon *tcon; | ||
3248 | struct cifsFileInfo *cfile; | ||
3249 | struct cifs_aio_ctx *ctx; | ||
3250 | |||
3251 | len = iov_iter_count(to); | ||
3252 | if (!len) | ||
3253 | return 0; | ||
3254 | |||
3255 | cifs_sb = CIFS_FILE_SB(file); | ||
3256 | cfile = file->private_data; | ||
3257 | tcon = tlink_tcon(cfile->tlink); | ||
3258 | |||
3259 | if (!tcon->ses->server->ops->async_readv) | ||
3260 | return -ENOSYS; | ||
3261 | |||
3262 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | ||
3263 | cifs_dbg(FYI, "attempting read on write only file instance\n"); | ||
3264 | |||
3265 | ctx = cifs_aio_ctx_alloc(); | ||
3266 | if (!ctx) | ||
3267 | return -ENOMEM; | ||
3268 | |||
3269 | ctx->cfile = cifsFileInfo_get(cfile); | ||
3270 | |||
3271 | if (!is_sync_kiocb(iocb)) | ||
3272 | ctx->iocb = iocb; | ||
3273 | |||
3274 | if (to->type & ITER_IOVEC) | ||
3275 | ctx->should_dirty = true; | ||
3276 | |||
3277 | rc = setup_aio_ctx_iter(ctx, to, READ); | ||
3278 | if (rc) { | ||
3279 | kref_put(&ctx->refcount, cifs_aio_ctx_release); | ||
3280 | return rc; | ||
3281 | } | ||
3282 | |||
3283 | len = ctx->len; | ||
3284 | |||
3285 | /* grab a lock here due to read response handlers can access ctx */ | ||
3286 | mutex_lock(&ctx->aio_mutex); | ||
3287 | |||
3288 | rc = cifs_send_async_read(offset, len, cfile, cifs_sb, &ctx->list, ctx); | ||
3289 | |||
3290 | /* if at least one read request send succeeded, then reset rc */ | ||
3291 | if (!list_empty(&ctx->list)) | ||
3292 | rc = 0; | ||
3293 | |||
3294 | mutex_unlock(&ctx->aio_mutex); | ||
3295 | |||
3296 | if (rc) { | ||
3297 | kref_put(&ctx->refcount, cifs_aio_ctx_release); | ||
3298 | return rc; | ||
3299 | } | ||
3300 | |||
3301 | if (!is_sync_kiocb(iocb)) { | ||
3302 | kref_put(&ctx->refcount, cifs_aio_ctx_release); | ||
3303 | return -EIOCBQUEUED; | ||
3304 | } | ||
3305 | |||
3306 | rc = wait_for_completion_killable(&ctx->done); | ||
3307 | if (rc) { | ||
3308 | mutex_lock(&ctx->aio_mutex); | ||
3309 | ctx->rc = rc = -EINTR; | ||
3310 | total_read = ctx->total_len; | ||
3311 | mutex_unlock(&ctx->aio_mutex); | ||
3312 | } else { | ||
3313 | rc = ctx->rc; | ||
3314 | total_read = ctx->total_len; | ||
3315 | } | ||
3316 | |||
3317 | kref_put(&ctx->refcount, cifs_aio_ctx_release); | ||
3318 | |||
3142 | if (total_read) { | 3319 | if (total_read) { |
3143 | iocb->ki_pos += total_read; | 3320 | iocb->ki_pos += total_read; |
3144 | return total_read; | 3321 | return total_read; |
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 7f4bba574930..76fb0917dc8c 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c | |||
@@ -209,10 +209,14 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) | |||
209 | rc = -EOPNOTSUPP; | 209 | rc = -EOPNOTSUPP; |
210 | break; | 210 | break; |
211 | case CIFS_IOC_GET_MNT_INFO: | 211 | case CIFS_IOC_GET_MNT_INFO: |
212 | if (pSMBFile == NULL) | ||
213 | break; | ||
212 | tcon = tlink_tcon(pSMBFile->tlink); | 214 | tcon = tlink_tcon(pSMBFile->tlink); |
213 | rc = smb_mnt_get_fsinfo(xid, tcon, (void __user *)arg); | 215 | rc = smb_mnt_get_fsinfo(xid, tcon, (void __user *)arg); |
214 | break; | 216 | break; |
215 | case CIFS_ENUMERATE_SNAPSHOTS: | 217 | case CIFS_ENUMERATE_SNAPSHOTS: |
218 | if (pSMBFile == NULL) | ||
219 | break; | ||
216 | if (arg == 0) { | 220 | if (arg == 0) { |
217 | rc = -EINVAL; | 221 | rc = -EINVAL; |
218 | goto cifs_ioc_exit; | 222 | goto cifs_ioc_exit; |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 843787850435..b08531977daa 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/ctype.h> | 23 | #include <linux/ctype.h> |
24 | #include <linux/mempool.h> | 24 | #include <linux/mempool.h> |
25 | #include <linux/vmalloc.h> | ||
25 | #include "cifspdu.h" | 26 | #include "cifspdu.h" |
26 | #include "cifsglob.h" | 27 | #include "cifsglob.h" |
27 | #include "cifsproto.h" | 28 | #include "cifsproto.h" |
@@ -488,7 +489,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv) | |||
488 | CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, | 489 | CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, |
489 | &pCifsInode->flags); | 490 | &pCifsInode->flags); |
490 | 491 | ||
491 | queue_work(cifsiod_wq, | 492 | queue_work(cifsoplockd_wq, |
492 | &netfile->oplock_break); | 493 | &netfile->oplock_break); |
493 | netfile->oplock_break_cancelled = false; | 494 | netfile->oplock_break_cancelled = false; |
494 | 495 | ||
@@ -741,3 +742,122 @@ parse_DFS_referrals_exit: | |||
741 | } | 742 | } |
742 | return rc; | 743 | return rc; |
743 | } | 744 | } |
745 | |||
746 | struct cifs_aio_ctx * | ||
747 | cifs_aio_ctx_alloc(void) | ||
748 | { | ||
749 | struct cifs_aio_ctx *ctx; | ||
750 | |||
751 | ctx = kzalloc(sizeof(struct cifs_aio_ctx), GFP_KERNEL); | ||
752 | if (!ctx) | ||
753 | return NULL; | ||
754 | |||
755 | INIT_LIST_HEAD(&ctx->list); | ||
756 | mutex_init(&ctx->aio_mutex); | ||
757 | init_completion(&ctx->done); | ||
758 | kref_init(&ctx->refcount); | ||
759 | return ctx; | ||
760 | } | ||
761 | |||
762 | void | ||
763 | cifs_aio_ctx_release(struct kref *refcount) | ||
764 | { | ||
765 | struct cifs_aio_ctx *ctx = container_of(refcount, | ||
766 | struct cifs_aio_ctx, refcount); | ||
767 | |||
768 | cifsFileInfo_put(ctx->cfile); | ||
769 | kvfree(ctx->bv); | ||
770 | kfree(ctx); | ||
771 | } | ||
772 | |||
773 | #define CIFS_AIO_KMALLOC_LIMIT (1024 * 1024) | ||
774 | |||
775 | int | ||
776 | setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw) | ||
777 | { | ||
778 | ssize_t rc; | ||
779 | unsigned int cur_npages; | ||
780 | unsigned int npages = 0; | ||
781 | unsigned int i; | ||
782 | size_t len; | ||
783 | size_t count = iov_iter_count(iter); | ||
784 | unsigned int saved_len; | ||
785 | size_t start; | ||
786 | unsigned int max_pages = iov_iter_npages(iter, INT_MAX); | ||
787 | struct page **pages = NULL; | ||
788 | struct bio_vec *bv = NULL; | ||
789 | |||
790 | if (iter->type & ITER_KVEC) { | ||
791 | memcpy(&ctx->iter, iter, sizeof(struct iov_iter)); | ||
792 | ctx->len = count; | ||
793 | iov_iter_advance(iter, count); | ||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | if (max_pages * sizeof(struct bio_vec) <= CIFS_AIO_KMALLOC_LIMIT) | ||
798 | bv = kmalloc_array(max_pages, sizeof(struct bio_vec), | ||
799 | GFP_KERNEL); | ||
800 | |||
801 | if (!bv) { | ||
802 | bv = vmalloc(max_pages * sizeof(struct bio_vec)); | ||
803 | if (!bv) | ||
804 | return -ENOMEM; | ||
805 | } | ||
806 | |||
807 | if (max_pages * sizeof(struct page *) <= CIFS_AIO_KMALLOC_LIMIT) | ||
808 | pages = kmalloc_array(max_pages, sizeof(struct page *), | ||
809 | GFP_KERNEL); | ||
810 | |||
811 | if (!pages) { | ||
812 | pages = vmalloc(max_pages * sizeof(struct page *)); | ||
813 | if (!bv) { | ||
814 | kvfree(bv); | ||
815 | return -ENOMEM; | ||
816 | } | ||
817 | } | ||
818 | |||
819 | saved_len = count; | ||
820 | |||
821 | while (count && npages < max_pages) { | ||
822 | rc = iov_iter_get_pages(iter, pages, count, max_pages, &start); | ||
823 | if (rc < 0) { | ||
824 | cifs_dbg(VFS, "couldn't get user pages (rc=%zd)\n", rc); | ||
825 | break; | ||
826 | } | ||
827 | |||
828 | if (rc > count) { | ||
829 | cifs_dbg(VFS, "get pages rc=%zd more than %zu\n", rc, | ||
830 | count); | ||
831 | break; | ||
832 | } | ||
833 | |||
834 | iov_iter_advance(iter, rc); | ||
835 | count -= rc; | ||
836 | rc += start; | ||
837 | cur_npages = DIV_ROUND_UP(rc, PAGE_SIZE); | ||
838 | |||
839 | if (npages + cur_npages > max_pages) { | ||
840 | cifs_dbg(VFS, "out of vec array capacity (%u vs %u)\n", | ||
841 | npages + cur_npages, max_pages); | ||
842 | break; | ||
843 | } | ||
844 | |||
845 | for (i = 0; i < cur_npages; i++) { | ||
846 | len = rc > PAGE_SIZE ? PAGE_SIZE : rc; | ||
847 | bv[npages + i].bv_page = pages[i]; | ||
848 | bv[npages + i].bv_offset = start; | ||
849 | bv[npages + i].bv_len = len - start; | ||
850 | rc -= len; | ||
851 | start = 0; | ||
852 | } | ||
853 | |||
854 | npages += cur_npages; | ||
855 | } | ||
856 | |||
857 | kvfree(pages); | ||
858 | ctx->bv = bv; | ||
859 | ctx->len = saved_len - count; | ||
860 | ctx->npages = npages; | ||
861 | iov_iter_bvec(&ctx->iter, ITER_BVEC | rw, ctx->bv, npages, ctx->len); | ||
862 | return 0; | ||
863 | } | ||
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index abae6dd2c6b9..cc88f4f0325e 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c | |||
@@ -980,10 +980,10 @@ struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset) | |||
980 | cifs_dbg(VFS, "illegal hours %d\n", st->Hours); | 980 | cifs_dbg(VFS, "illegal hours %d\n", st->Hours); |
981 | days = sd->Day; | 981 | days = sd->Day; |
982 | month = sd->Month; | 982 | month = sd->Month; |
983 | if ((days > 31) || (month > 12)) { | 983 | if (days < 1 || days > 31 || month < 1 || month > 12) { |
984 | cifs_dbg(VFS, "illegal date, month %d day: %d\n", month, days); | 984 | cifs_dbg(VFS, "illegal date, month %d day: %d\n", month, days); |
985 | if (month > 12) | 985 | days = clamp(days, 1, 31); |
986 | month = 12; | 986 | month = clamp(month, 1, 12); |
987 | } | 987 | } |
988 | month -= 1; | 988 | month -= 1; |
989 | days += total_days_of_prev_months[month]; | 989 | days += total_days_of_prev_months[month]; |
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 1a04b3a5beb1..7b08a1446a7f 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c | |||
@@ -499,7 +499,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp, | |||
499 | else | 499 | else |
500 | cfile->oplock_break_cancelled = true; | 500 | cfile->oplock_break_cancelled = true; |
501 | 501 | ||
502 | queue_work(cifsiod_wq, &cfile->oplock_break); | 502 | queue_work(cifsoplockd_wq, &cfile->oplock_break); |
503 | kfree(lw); | 503 | kfree(lw); |
504 | return true; | 504 | return true; |
505 | } | 505 | } |
@@ -643,7 +643,8 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) | |||
643 | CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, | 643 | CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, |
644 | &cinode->flags); | 644 | &cinode->flags); |
645 | spin_unlock(&cfile->file_info_lock); | 645 | spin_unlock(&cfile->file_info_lock); |
646 | queue_work(cifsiod_wq, &cfile->oplock_break); | 646 | queue_work(cifsoplockd_wq, |
647 | &cfile->oplock_break); | ||
647 | 648 | ||
648 | spin_unlock(&tcon->open_file_lock); | 649 | spin_unlock(&tcon->open_file_lock); |
649 | spin_unlock(&cifs_tcp_ses_lock); | 650 | spin_unlock(&cifs_tcp_ses_lock); |
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 152e37f2ad92..c58691834eb2 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
@@ -942,6 +942,7 @@ smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon, | |||
942 | } | 942 | } |
943 | if (snapshot_in.snapshot_array_size < sizeof(struct smb_snapshot_array)) { | 943 | if (snapshot_in.snapshot_array_size < sizeof(struct smb_snapshot_array)) { |
944 | rc = -ERANGE; | 944 | rc = -ERANGE; |
945 | kfree(retbuf); | ||
945 | return rc; | 946 | return rc; |
946 | } | 947 | } |
947 | 948 | ||
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index fb0da096c2ce..48ff7703b919 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -633,8 +633,12 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) | |||
633 | } | 633 | } |
634 | 634 | ||
635 | if (rsplen != sizeof(struct validate_negotiate_info_rsp)) { | 635 | if (rsplen != sizeof(struct validate_negotiate_info_rsp)) { |
636 | cifs_dbg(VFS, "invalid size of protocol negotiate response\n"); | 636 | cifs_dbg(VFS, "invalid protocol negotiate response size: %d\n", |
637 | return -EIO; | 637 | rsplen); |
638 | |||
639 | /* relax check since Mac returns max bufsize allowed on ioctl */ | ||
640 | if (rsplen > CIFSMaxBufSize) | ||
641 | return -EIO; | ||
638 | } | 642 | } |
639 | 643 | ||
640 | /* check validate negotiate info response matches what we got earlier */ | 644 | /* check validate negotiate info response matches what we got earlier */ |
@@ -1854,8 +1858,12 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, | |||
1854 | * than one credit. Windows typically sets this smaller, but for some | 1858 | * than one credit. Windows typically sets this smaller, but for some |
1855 | * ioctls it may be useful to allow server to send more. No point | 1859 | * ioctls it may be useful to allow server to send more. No point |
1856 | * limiting what the server can send as long as fits in one credit | 1860 | * limiting what the server can send as long as fits in one credit |
1861 | * Unfortunately - we can not handle more than CIFS_MAX_MSG_SIZE | ||
1862 | * (by default, note that it can be overridden to make max larger) | ||
1863 | * in responses (except for read responses which can be bigger. | ||
1864 | * We may want to bump this limit up | ||
1857 | */ | 1865 | */ |
1858 | req->MaxOutputResponse = cpu_to_le32(0xFF00); /* < 64K uses 1 credit */ | 1866 | req->MaxOutputResponse = cpu_to_le32(CIFSMaxBufSize); |
1859 | 1867 | ||
1860 | if (is_fsctl) | 1868 | if (is_fsctl) |
1861 | req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL); | 1869 | req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL); |