Pull cifs fixes from Steve French: - one smb3 (ACL related) fix for stable - one SMB3 security enhancement (when mounting -t smb3 forbid less secure dialects) - some RDMA and compounding fixes * tag '4.18-fixes-smb3' of git://git.samba.org/sfrench/cifs-2.6: cifs: fix a buffer leak in smb2_query_symlink smb3: do not allow insecure cifs mounts when using smb3 CIFS: Fix NULL ptr deref CIFS: fix encryption in SMB3.1.1 CIFS: Pass page offset for encrypting CIFS: Pass page offset for calculating signature CIFS: SMBD: Support page offset in memory registration CIFS: SMBD: Support page offset in RDMA recv CIFS: SMBD: Support page offset in RDMA send CIFS: When sending data on socket, pass the correct page offset CIFS: Introduce helper function to get page offset and length in smb_rqst CIFS: Calculate the correct request length based on page offset and tail size cifs: For SMB2 security informaion query, check for minimum sized security descriptor instead of sizeof FileAllInformation class CIFS: Fix signing for SMB2/3
Unified · Split
| @@ -98,4 +98,18 @@ struct cifs_ace { · 97 unmodified lines | ||
| 98 | 98 | struct cifs_sid sid; /* ie UUID of user or group who gets these perms */ |
| 99 | 99 | } __attribute__((packed)); |
| 100 | 100 | |
| 101 | +/* | |
| 102 | + * Minimum security identifier can be one for system defined Users | |
| 103 | + * and Groups such as NULL SID and World or Built-in accounts such | |
| 104 | + * as Administrator and Guest and consists of | |
| 105 | + * Revision + Num (Sub)Auths + Authority + Domain (one Subauthority) | |
| 106 | + */ | |
| 107 | +#define MIN_SID_LEN (1 + 1 + 6 + 4) /* in bytes */ | |
| 108 | + | |
| 109 | +/* | |
| 110 | + * Minimum security descriptor can be one without any SACL and DACL and can | |
| 111 | + * consist of revision, type, and two sids of minimum size for owner and group | |
| 112 | + */ | |
| 113 | +#define MIN_SEC_DESC_LEN (sizeof(struct cifs_ntsd) + (2 * MIN_SID_LEN)) | |
| 114 | + | |
| 101 | 115 | #endif /* _CIFSACL_H */ |
| @@ -37,6 +37,7 @@ · 36 unmodified lines | ||
| 37 | 37 | #include <crypto/aead.h> |
| 38 | 38 | |
| 39 | 39 | int __cifs_calc_signature(struct smb_rqst *rqst, |
| 40 | + int start, | |
| 40 | 41 | struct TCP_Server_Info *server, char *signature, |
| 41 | 42 | struct shash_desc *shash) |
| 42 | 43 | { |
| @@ -45,10 +46,7 @@ int __cifs_calc_signature(struct smb_rqst *rqst, · 2 unmodified lines | ||
| 45 | 46 | struct kvec *iov = rqst->rq_iov; |
| 46 | 47 | int n_vec = rqst->rq_nvec; |
| 47 | 48 | |
| 48 | − if (n_vec < 2 || iov[0].iov_len != 4) | |
| 49 | − return -EIO; | |
| 50 | − | |
| 51 | − for (i = 1; i < n_vec; i++) { | |
| 49 | + for (i = start; i < n_vec; i++) { | |
| 52 | 50 | if (iov[i].iov_len == 0) |
| 53 | 51 | continue; |
| 54 | 52 | if (iov[i].iov_base == NULL) { |
| @@ -68,11 +66,12 @@ int __cifs_calc_signature(struct smb_rqst *rqst, · 13 unmodified lines | ||
| 68 | 66 | |
| 69 | 67 | /* now hash over the rq_pages array */ |
| 70 | 68 | for (i = 0; i < rqst->rq_npages; i++) { |
| 71 | − void *kaddr = kmap(rqst->rq_pages[i]); | |
| 72 | − size_t len = rqst->rq_pagesz; | |
| 69 | + void *kaddr; | |
| 70 | + unsigned int len, offset; | |
| 71 | + | |
| 72 | + rqst_page_get_length(rqst, i, &len, &offset); | |
| 73 | 73 | |
| 74 | − if (i == rqst->rq_npages - 1) | |
| 75 | − len = rqst->rq_tailsz; | |
| 74 | + kaddr = (char *) kmap(rqst->rq_pages[i]) + offset; | |
| 76 | 75 | |
| 77 | 76 | crypto_shash_update(shash, kaddr, len); |
| 78 | 77 | |
| @@ -119,7 +118,7 @@ static int cifs_calc_signature(struct smb_rqst *rqst, · 40 unmodified lines | ||
| 119 | 118 | return rc; |
| 120 | 119 | } |
| 121 | 120 | |
| 122 | − return __cifs_calc_signature(rqst, server, signature, | |
| 121 | + return __cifs_calc_signature(rqst, 1, server, signature, | |
| 123 | 122 | &server->secmech.sdescmd5->shash); |
| 124 | 123 | } |
| 125 | 124 | |
| @@ -698,8 +698,8 @@ static int cifs_set_super(struct super_block *sb, void *data) · 697 unmodified lines | ||
| 698 | 698 | } |
| 699 | 699 | |
| 700 | 700 | static struct dentry * |
| 701 | −cifs_do_mount(struct file_system_type *fs_type, | |
| 702 | − int flags, const char *dev_name, void *data) | |
| 701 | +cifs_smb3_do_mount(struct file_system_type *fs_type, | |
| 702 | + int flags, const char *dev_name, void *data, bool is_smb3) | |
| 703 | 703 | { |
| 704 | 704 | int rc; |
| 705 | 705 | struct super_block *sb; |
| @@ -710,7 +710,7 @@ cifs_do_mount(struct file_system_type *fs_type, · 4 unmodified lines | ||
| 710 | 710 | |
| 711 | 711 | cifs_dbg(FYI, "Devname: %s flags: %d\n", dev_name, flags); |
| 712 | 712 | |
| 713 | − volume_info = cifs_get_volume_info((char *)data, dev_name); | |
| 713 | + volume_info = cifs_get_volume_info((char *)data, dev_name, is_smb3); | |
| 714 | 714 | if (IS_ERR(volume_info)) |
| 715 | 715 | return ERR_CAST(volume_info); |
| 716 | 716 | |
| @@ -790,6 +790,20 @@ out_nls: · 73 unmodified lines | ||
| 790 | 790 | goto out; |
| 791 | 791 | } |
| 792 | 792 | |
| 793 | +static struct dentry * | |
| 794 | +smb3_do_mount(struct file_system_type *fs_type, | |
| 795 | + int flags, const char *dev_name, void *data) | |
| 796 | +{ | |
| 797 | + return cifs_smb3_do_mount(fs_type, flags, dev_name, data, true); | |
| 798 | +} | |
| 799 | + | |
| 800 | +static struct dentry * | |
| 801 | +cifs_do_mount(struct file_system_type *fs_type, | |
| 802 | + int flags, const char *dev_name, void *data) | |
| 803 | +{ | |
| 804 | + return cifs_smb3_do_mount(fs_type, flags, dev_name, data, false); | |
| 805 | +} | |
| 806 | + | |
| 793 | 807 | static ssize_t |
| 794 | 808 | cifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter) |
| 795 | 809 | { |
| @@ -925,7 +939,7 @@ MODULE_ALIAS_FS("cifs"); · 129 unmodified lines | ||
| 925 | 939 | static struct file_system_type smb3_fs_type = { |
| 926 | 940 | .owner = THIS_MODULE, |
| 927 | 941 | .name = "smb3", |
| 928 | − .mount = cifs_do_mount, | |
| 942 | + .mount = smb3_do_mount, | |
| 929 | 943 | .kill_sb = cifs_kill_sb, |
| 930 | 944 | /* .fs_flags */ |
| 931 | 945 | }; |
| @@ -1019,6 +1019,12 @@ tlink_tcon(struct tcon_link *tlink) · 1018 unmodified lines | ||
| 1019 | 1019 | return tlink->tl_tcon; |
| 1020 | 1020 | } |
| 1021 | 1021 | |
| 1022 | +static inline struct tcon_link * | |
| 1023 | +cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb) | |
| 1024 | +{ | |
| 1025 | + return cifs_sb->master_tlink; | |
| 1026 | +} | |
| 1027 | + | |
| 1022 | 1028 | extern void cifs_put_tlink(struct tcon_link *tlink); |
| 1023 | 1029 | |
| 1024 | 1030 | static inline struct tcon_link * |
| @@ -211,7 +211,7 @@ extern int cifs_setup_cifs_sb(struct smb_vol *pvolume_info, · 210 unmodified lines | ||
| 211 | 211 | extern int cifs_match_super(struct super_block *, void *); |
| 212 | 212 | extern void cifs_cleanup_volume_info(struct smb_vol *pvolume_info); |
| 213 | 213 | extern struct smb_vol *cifs_get_volume_info(char *mount_data, |
| 214 | − const char *devname); | |
| 214 | + const char *devname, bool is_smb3); | |
| 215 | 215 | extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *); |
| 216 | 216 | extern void cifs_umount(struct cifs_sb_info *); |
| 217 | 217 | extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon); |
| @@ -544,7 +544,7 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, · 326 unmodified lines | ||
| 544 | 544 | struct cifs_sb_info *cifs_sb, |
| 545 | 545 | const unsigned char *path, char *pbuf, |
| 546 | 546 | unsigned int *pbytes_written); |
| 547 | −int __cifs_calc_signature(struct smb_rqst *rqst, | |
| 547 | +int __cifs_calc_signature(struct smb_rqst *rqst, int start, | |
| 548 | 548 | struct TCP_Server_Info *server, char *signature, |
| 549 | 549 | struct shash_desc *shash); |
| 550 | 550 | enum securityEnum cifs_select_sectype(struct TCP_Server_Info *, |
| @@ -557,4 +557,7 @@ int cifs_alloc_hash(const char *name, struct crypto_shash **shash, · 6 unmodified lines | ||
| 557 | 557 | struct sdesc **sdesc); |
| 558 | 558 | void cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc); |
| 559 | 559 | |
| 560 | +extern void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page, | |
| 561 | + unsigned int *len, unsigned int *offset); | |
| 562 | + | |
| 560 | 563 | #endif /* _CIFSPROTO_H */ |
| @@ -320,7 +320,7 @@ static int generic_ip_connect(struct TCP_Server_Info *server); · 319 unmodified lines | ||
| 320 | 320 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); |
| 321 | 321 | static void cifs_prune_tlinks(struct work_struct *work); |
| 322 | 322 | static int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, |
| 323 | − const char *devname); | |
| 323 | + const char *devname, bool is_smb3); | |
| 324 | 324 | |
| 325 | 325 | /* |
| 326 | 326 | * cifs tcp session reconnection |
| @@ -1166,7 +1166,7 @@ cifs_parse_cache_flavor(char *value, struct smb_vol *vol) · 839 unmodified lines | ||
| 1166 | 1166 | } |
| 1167 | 1167 | |
| 1168 | 1168 | static int |
| 1169 | −cifs_parse_smb_version(char *value, struct smb_vol *vol) | |
| 1169 | +cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3) | |
| 1170 | 1170 | { |
| 1171 | 1171 | substring_t args[MAX_OPT_ARGS]; |
| 1172 | 1172 | |
| @@ -1176,6 +1176,10 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol) · 3 unmodified lines | ||
| 1176 | 1176 | cifs_dbg(VFS, "mount with legacy dialect disabled\n"); |
| 1177 | 1177 | return 1; |
| 1178 | 1178 | } |
| 1179 | + if (is_smb3) { | |
| 1180 | + cifs_dbg(VFS, "vers=1.0 (cifs) not permitted when mounting with smb3\n"); | |
| 1181 | + return 1; | |
| 1182 | + } | |
| 1179 | 1183 | vol->ops = &smb1_operations; |
| 1180 | 1184 | vol->vals = &smb1_values; |
| 1181 | 1185 | break; |
| @@ -1184,6 +1188,10 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol) · 2 unmodified lines | ||
| 1184 | 1188 | cifs_dbg(VFS, "mount with legacy dialect disabled\n"); |
| 1185 | 1189 | return 1; |
| 1186 | 1190 | } |
| 1191 | + if (is_smb3) { | |
| 1192 | + cifs_dbg(VFS, "vers=2.0 not permitted when mounting with smb3\n"); | |
| 1193 | + return 1; | |
| 1194 | + } | |
| 1187 | 1195 | vol->ops = &smb20_operations; |
| 1188 | 1196 | vol->vals = &smb20_values; |
| 1189 | 1197 | break; |
| @@ -1272,7 +1280,7 @@ cifs_parse_devname(const char *devname, struct smb_vol *vol) · 82 unmodified lines | ||
| 1272 | 1280 | |
| 1273 | 1281 | static int |
| 1274 | 1282 | cifs_parse_mount_options(const char *mountdata, const char *devname, |
| 1275 | − struct smb_vol *vol) | |
| 1283 | + struct smb_vol *vol, bool is_smb3) | |
| 1276 | 1284 | { |
| 1277 | 1285 | char *data, *end; |
| 1278 | 1286 | char *mountdata_copy = NULL, *options; |
| @@ -1985,7 +1993,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, · 706 unmodified lines | ||
| 1985 | 1993 | if (string == NULL) |
| 1986 | 1994 | goto out_nomem; |
| 1987 | 1995 | |
| 1988 | − if (cifs_parse_smb_version(string, vol) != 0) | |
| 1996 | + if (cifs_parse_smb_version(string, vol, is_smb3) != 0) | |
| 1989 | 1997 | goto cifs_parse_mount_err; |
| 1990 | 1998 | got_version = true; |
| 1991 | 1999 | break; |
| @@ -3116,12 +3124,6 @@ cifs_put_tlink(struct tcon_link *tlink) · 1124 unmodified lines | ||
| 3116 | 3124 | return; |
| 3117 | 3125 | } |
| 3118 | 3126 | |
| 3119 | −static inline struct tcon_link * | |
| 3120 | −cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb) | |
| 3121 | −{ | |
| 3122 | − return cifs_sb->master_tlink; | |
| 3123 | −} | |
| 3124 | − | |
| 3125 | 3127 | static int |
| 3126 | 3128 | compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data) |
| 3127 | 3129 | { |
| @@ -3803,7 +3805,7 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, · 675 unmodified lines | ||
| 3803 | 3805 | } else { |
| 3804 | 3806 | cleanup_volume_info_contents(volume_info); |
| 3805 | 3807 | rc = cifs_setup_volume_info(volume_info, mdata, |
| 3806 | − fake_devname); | |
| 3808 | + fake_devname, false); | |
| 3807 | 3809 | } |
| 3808 | 3810 | kfree(fake_devname); |
| 3809 | 3811 | kfree(cifs_sb->mountdata); |
| @@ -3816,11 +3818,11 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, · 6 unmodified lines | ||
| 3816 | 3818 | |
| 3817 | 3819 | static int |
| 3818 | 3820 | cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, |
| 3819 | − const char *devname) | |
| 3821 | + const char *devname, bool is_smb3) | |
| 3820 | 3822 | { |
| 3821 | 3823 | int rc = 0; |
| 3822 | 3824 | |
| 3823 | − if (cifs_parse_mount_options(mount_data, devname, volume_info)) | |
| 3825 | + if (cifs_parse_mount_options(mount_data, devname, volume_info, is_smb3)) | |
| 3824 | 3826 | return -EINVAL; |
| 3825 | 3827 | |
| 3826 | 3828 | if (volume_info->nullauth) { |
| @@ -3854,7 +3856,7 @@ cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, · 27 unmodified lines | ||
| 3854 | 3856 | } |
| 3855 | 3857 | |
| 3856 | 3858 | struct smb_vol * |
| 3857 | −cifs_get_volume_info(char *mount_data, const char *devname) | |
| 3859 | +cifs_get_volume_info(char *mount_data, const char *devname, bool is_smb3) | |
| 3858 | 3860 | { |
| 3859 | 3861 | int rc; |
| 3860 | 3862 | struct smb_vol *volume_info; |
| @@ -3863,7 +3865,7 @@ cifs_get_volume_info(char *mount_data, const char *devname) · 2 unmodified lines | ||
| 3863 | 3865 | if (!volume_info) |
| 3864 | 3866 | return ERR_PTR(-ENOMEM); |
| 3865 | 3867 | |
| 3866 | − rc = cifs_setup_volume_info(volume_info, mount_data, devname); | |
| 3868 | + rc = cifs_setup_volume_info(volume_info, mount_data, devname, is_smb3); | |
| 3867 | 3869 | if (rc) { |
| 3868 | 3870 | cifs_cleanup_volume_info(volume_info); |
| 3869 | 3871 | volume_info = ERR_PTR(rc); |
| @@ -421,7 +421,8 @@ smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, · 420 unmodified lines | ||
| 421 | 421 | return -ENOMEM; |
| 422 | 422 | } |
| 423 | 423 | |
| 424 | − rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL); | |
| 424 | + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL, | |
| 425 | + NULL); | |
| 425 | 426 | if (rc) |
| 426 | 427 | goto qmf_out_open_fail; |
| 427 | 428 | |
| @@ -478,7 +479,8 @@ smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, · 50 unmodified lines | ||
| 478 | 479 | oparms.fid = &fid; |
| 479 | 480 | oparms.reconnect = false; |
| 480 | 481 | |
| 481 | − rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL); | |
| 482 | + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, | |
| 483 | + NULL); | |
| 482 | 484 | if (rc) { |
| 483 | 485 | kfree(utf16_path); |
| 484 | 486 | return rc; |
| @@ -905,3 +905,20 @@ cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc) · 904 unmodified lines | ||
| 905 | 905 | crypto_free_shash(*shash); |
| 906 | 906 | *shash = NULL; |
| 907 | 907 | } |
| 908 | + | |
| 909 | +/** | |
| 910 | + * rqst_page_get_length - obtain the length and offset for a page in smb_rqst | |
| 911 | + * Input: rqst - a smb_rqst, page - a page index for rqst | |
| 912 | + * Output: *len - the length for this page, *offset - the offset for this page | |
| 913 | + */ | |
| 914 | +void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page, | |
| 915 | + unsigned int *len, unsigned int *offset) | |
| 916 | +{ | |
| 917 | + *len = rqst->rq_pagesz; | |
| 918 | + *offset = (page == 0) ? rqst->rq_offset : 0; | |
| 919 | + | |
| 920 | + if (rqst->rq_npages == 1 || page == rqst->rq_npages-1) | |
| 921 | + *len = rqst->rq_tailsz; | |
| 922 | + else if (page == 0) | |
| 923 | + *len = rqst->rq_pagesz - rqst->rq_offset; | |
| 924 | +} | |
| @@ -64,7 +64,8 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, · 63 unmodified lines | ||
| 64 | 64 | if (oparms->tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING) |
| 65 | 65 | memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE); |
| 66 | 66 | |
| 67 | − rc = SMB2_open(xid, oparms, smb2_path, smb2_oplock, smb2_data, NULL); | |
| 67 | + rc = SMB2_open(xid, oparms, smb2_path, smb2_oplock, smb2_data, NULL, | |
| 68 | + NULL); | |
| 68 | 69 | if (rc) |
| 69 | 70 | goto out; |
| 70 | 71 | |
| @@ -71,7 +71,8 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon, · 70 unmodified lines | ||
| 71 | 71 | oparms.fid = &fid; |
| 72 | 72 | oparms.reconnect = false; |
| 73 | 73 | |
| 74 | − rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL); | |
| 74 | + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, | |
| 75 | + NULL); | |
| 75 | 76 | if (rc) { |
| 76 | 77 | kfree(utf16_path); |
| 77 | 78 | return rc; |
| @@ -453,8 +453,10 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb) · 452 unmodified lines | ||
| 453 | 453 | start_of_path = from + 1; |
| 454 | 454 | #ifdef CONFIG_CIFS_SMB311 |
| 455 | 455 | /* SMB311 POSIX extensions paths do not include leading slash */ |
| 456 | − else if (cifs_sb_master_tcon(cifs_sb)->posix_extensions) | |
| 456 | + else if (cifs_sb_master_tlink(cifs_sb) && | |
| 457 | + cifs_sb_master_tcon(cifs_sb)->posix_extensions) { | |
| 457 | 458 | start_of_path = from + 1; |
| 459 | + } | |
| 458 | 460 | #endif /* 311 */ |
| 459 | 461 | else |
| 460 | 462 | start_of_path = from; |
| @@ -348,7 +348,7 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid) · 347 unmodified lines | ||
| 348 | 348 | oparams.fid = pfid; |
| 349 | 349 | oparams.reconnect = false; |
| 350 | 350 | |
| 351 | − rc = SMB2_open(xid, &oparams, &srch_path, &oplock, NULL, NULL); | |
| 351 | + rc = SMB2_open(xid, &oparams, &srch_path, &oplock, NULL, NULL, NULL); | |
| 352 | 352 | if (rc == 0) { |
| 353 | 353 | memcpy(tcon->prfid, pfid, sizeof(struct cifs_fid)); |
| 354 | 354 | tcon->valid_root_fid = true; |
| @@ -375,7 +375,8 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon) · 20 unmodified lines | ||
| 375 | 375 | oparms.reconnect = false; |
| 376 | 376 | |
| 377 | 377 | if (no_cached_open) |
| 378 | − rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL); | |
| 378 | + rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, | |
| 379 | + NULL); | |
| 379 | 380 | else |
| 380 | 381 | rc = open_shroot(xid, tcon, &fid); |
| 381 | 382 | |
| @@ -413,7 +414,7 @@ smb2_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon) · 31 unmodified lines | ||
| 413 | 414 | oparms.fid = &fid; |
| 414 | 415 | oparms.reconnect = false; |
| 415 | 416 | |
| 416 | − rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL); | |
| 417 | + rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, NULL); | |
| 417 | 418 | if (rc) |
| 418 | 419 | return; |
| 419 | 420 | |
| @@ -449,7 +450,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, · 29 unmodified lines | ||
| 449 | 450 | oparms.fid = &fid; |
| 450 | 451 | oparms.reconnect = false; |
| 451 | 452 | |
| 452 | − rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL); | |
| 453 | + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL); | |
| 453 | 454 | if (rc) { |
| 454 | 455 | kfree(utf16_path); |
| 455 | 456 | return rc; |
| @@ -598,7 +599,7 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon, · 142 unmodified lines | ||
| 598 | 599 | oparms.fid = &fid; |
| 599 | 600 | oparms.reconnect = false; |
| 600 | 601 | |
| 601 | − rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL); | |
| 602 | + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL); | |
| 602 | 603 | kfree(utf16_path); |
| 603 | 604 | if (rc) { |
| 604 | 605 | cifs_dbg(FYI, "open failed rc=%d\n", rc); |
| @@ -677,7 +678,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, · 72 unmodified lines | ||
| 677 | 678 | oparms.fid = &fid; |
| 678 | 679 | oparms.reconnect = false; |
| 679 | 680 | |
| 680 | − rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL); | |
| 681 | + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL); | |
| 681 | 682 | kfree(utf16_path); |
| 682 | 683 | if (rc) { |
| 683 | 684 | cifs_dbg(FYI, "open failed rc=%d\n", rc); |
| @@ -1261,7 +1262,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, · 577 unmodified lines | ||
| 1261 | 1262 | oparms.fid = fid; |
| 1262 | 1263 | oparms.reconnect = false; |
| 1263 | 1264 | |
| 1264 | − rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL); | |
| 1265 | + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL); | |
| 1265 | 1266 | kfree(utf16_path); |
| 1266 | 1267 | if (rc) { |
| 1267 | 1268 | cifs_dbg(FYI, "open dir failed rc=%d\n", rc); |
| @@ -1361,7 +1362,7 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon, · 93 unmodified lines | ||
| 1361 | 1362 | oparms.fid = &fid; |
| 1362 | 1363 | oparms.reconnect = false; |
| 1363 | 1364 | |
| 1364 | − rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL); | |
| 1365 | + rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, NULL); | |
| 1365 | 1366 | if (rc) |
| 1366 | 1367 | return rc; |
| 1367 | 1368 | buf->f_type = SMB2_MAGIC_NUMBER; |
| @@ -1515,7 +1516,8 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, · 147 unmodified lines | ||
| 1515 | 1516 | struct cifs_open_parms oparms; |
| 1516 | 1517 | struct cifs_fid fid; |
| 1517 | 1518 | struct kvec err_iov = {NULL, 0}; |
| 1518 | − struct smb2_err_rsp *err_buf; | |
| 1519 | + struct smb2_err_rsp *err_buf = NULL; | |
| 1520 | + int resp_buftype; | |
| 1519 | 1521 | struct smb2_symlink_err_rsp *symlink; |
| 1520 | 1522 | unsigned int sub_len; |
| 1521 | 1523 | unsigned int sub_offset; |
| @@ -1535,18 +1537,18 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, · 13 unmodified lines | ||
| 1535 | 1537 | oparms.fid = &fid; |
| 1536 | 1538 | oparms.reconnect = false; |
| 1537 | 1539 | |
| 1538 | − rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, &err_iov); | |
| 1539 | − | |
| 1540 | + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, &err_iov, | |
| 1541 | + &resp_buftype); | |
| 1540 | 1542 | if (!rc || !err_iov.iov_base) { |
| 1541 | − kfree(utf16_path); | |
| 1542 | − return -ENOENT; | |
| 1543 | + rc = -ENOENT; | |
| 1544 | + goto querty_exit; | |
| 1543 | 1545 | } |
| 1544 | 1546 | |
| 1545 | 1547 | err_buf = err_iov.iov_base; |
| 1546 | 1548 | if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct smb2_symlink_err_rsp) || |
| 1547 | 1549 | err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE) { |
| 1548 | − kfree(utf16_path); | |
| 1549 | − return -ENOENT; | |
| 1550 | + rc = -ENOENT; | |
| 1551 | + goto querty_exit; | |
| 1550 | 1552 | } |
| 1551 | 1553 | |
| 1552 | 1554 | /* open must fail on symlink - reset rc */ |
| @@ -1558,25 +1560,28 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, · 5 unmodified lines | ||
| 1558 | 1560 | print_offset = le16_to_cpu(symlink->PrintNameOffset); |
| 1559 | 1561 | |
| 1560 | 1562 | if (err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) { |
| 1561 | − kfree(utf16_path); | |
| 1562 | − return -ENOENT; | |
| 1563 | + rc = -ENOENT; | |
| 1564 | + goto querty_exit; | |
| 1563 | 1565 | } |
| 1564 | 1566 | |
| 1565 | 1567 | if (err_iov.iov_len < |
| 1566 | 1568 | SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) { |
| 1567 | − kfree(utf16_path); | |
| 1568 | − return -ENOENT; | |
| 1569 | + rc = -ENOENT; | |
| 1570 | + goto querty_exit; | |
| 1569 | 1571 | } |
| 1570 | 1572 | |
| 1571 | 1573 | *target_path = cifs_strndup_from_utf16( |
| 1572 | 1574 | (char *)symlink->PathBuffer + sub_offset, |
| 1573 | 1575 | sub_len, true, cifs_sb->local_nls); |
| 1574 | 1576 | if (!(*target_path)) { |
| 1575 | − kfree(utf16_path); | |
| 1576 | − return -ENOMEM; | |
| 1577 | + rc = -ENOMEM; | |
| 1578 | + goto querty_exit; | |
| 1577 | 1579 | } |
| 1578 | 1580 | convert_delimiter(*target_path, '/'); |
| 1579 | 1581 | cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); |
| 1582 | + | |
| 1583 | + querty_exit: | |
| 1584 | + free_rsp_buf(resp_buftype, err_buf); | |
| 1580 | 1585 | kfree(utf16_path); |
| 1581 | 1586 | return rc; |
| 1582 | 1587 | } |
| @@ -1649,7 +1654,7 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb, · 66 unmodified lines | ||
| 1649 | 1654 | oparms.fid = &fid; |
| 1650 | 1655 | oparms.reconnect = false; |
| 1651 | 1656 | |
| 1652 | − rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL); | |
| 1657 | + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL); | |
| 1653 | 1658 | kfree(utf16_path); |
| 1654 | 1659 | if (!rc) { |
| 1655 | 1660 | rc = SMB2_query_acl(xid, tlink_tcon(tlink), fid.persistent_fid, |
| @@ -1712,7 +1717,7 @@ set_smb2_acl(struct cifs_ntsd *pnntsd, __u32 acllen, · 56 unmodified lines | ||
| 1712 | 1717 | oparms.fid = &fid; |
| 1713 | 1718 | oparms.reconnect = false; |
| 1714 | 1719 | |
| 1715 | − rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL); | |
| 1720 | + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL); | |
| 1716 | 1721 | kfree(utf16_path); |
| 1717 | 1722 | if (!rc) { |
| 1718 | 1723 | rc = SMB2_set_acl(xid, tlink_tcon(tlink), fid.persistent_fid, |
| @@ -2189,9 +2194,10 @@ init_sg(struct smb_rqst *rqst, u8 *sign) · 470 unmodified lines | ||
| 2189 | 2194 | smb2_sg_set_buf(&sg[i], rqst->rq_iov[i+1].iov_base, |
| 2190 | 2195 | rqst->rq_iov[i+1].iov_len); |
| 2191 | 2196 | for (j = 0; i < sg_len - 1; i++, j++) { |
| 2192 | − unsigned int len = (j < rqst->rq_npages - 1) ? rqst->rq_pagesz | |
| 2193 | − : rqst->rq_tailsz; | |
| 2194 | − sg_set_page(&sg[i], rqst->rq_pages[j], len, 0); | |
| 2197 | + unsigned int len, offset; | |
| 2198 | + | |
| 2199 | + rqst_page_get_length(rqst, j, &len, &offset); | |
| 2200 | + sg_set_page(&sg[i], rqst->rq_pages[j], len, offset); | |
| 2195 | 2201 | } |
| 2196 | 2202 | smb2_sg_set_buf(&sg[sg_len - 1], sign, SMB2_SIGNATURE_SIZE); |
| 2197 | 2203 | return sg; |
| @@ -2229,7 +2235,7 @@ static int · 31 unmodified lines | ||
| 2229 | 2235 | crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) |
| 2230 | 2236 | { |
| 2231 | 2237 | struct smb2_transform_hdr *tr_hdr = |
| 2232 | − (struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base; | |
| 2238 | + (struct smb2_transform_hdr *)rqst->rq_iov[1].iov_base; | |
| 2233 | 2239 | unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; |
| 2234 | 2240 | int rc = 0; |
| 2235 | 2241 | struct scatterlist *sg; |
| @@ -2338,6 +2344,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, · 102 unmodified lines | ||
| 2338 | 2344 | return rc; |
| 2339 | 2345 | |
| 2340 | 2346 | new_rq->rq_pages = pages; |
| 2347 | + new_rq->rq_offset = old_rq->rq_offset; | |
| 2341 | 2348 | new_rq->rq_npages = old_rq->rq_npages; |
| 2342 | 2349 | new_rq->rq_pagesz = old_rq->rq_pagesz; |
| 2343 | 2350 | new_rq->rq_tailsz = old_rq->rq_tailsz; |
| @@ -2379,10 +2386,14 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, · 35 unmodified lines | ||
| 2379 | 2386 | |
| 2380 | 2387 | /* copy pages form the old */ |
| 2381 | 2388 | for (i = 0; i < npages; i++) { |
| 2382 | − char *dst = kmap(new_rq->rq_pages[i]); | |
| 2383 | − char *src = kmap(old_rq->rq_pages[i]); | |
| 2384 | − unsigned int len = (i < npages - 1) ? new_rq->rq_pagesz : | |
| 2385 | − new_rq->rq_tailsz; | |
| 2389 | + char *dst, *src; | |
| 2390 | + unsigned int offset, len; | |
| 2391 | + | |
| 2392 | + rqst_page_get_length(new_rq, i, &len, &offset); | |
| 2393 | + | |
| 2394 | + dst = (char *) kmap(new_rq->rq_pages[i]) + offset; | |
| 2395 | + src = (char *) kmap(old_rq->rq_pages[i]) + offset; | |
| 2396 | + | |
| 2386 | 2397 | memcpy(dst, src, len); |
| 2387 | 2398 | kunmap(new_rq->rq_pages[i]); |
| 2388 | 2399 | kunmap(old_rq->rq_pages[i]); |
| @@ -1889,7 +1889,7 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len, · 1888 unmodified lines | ||
| 1889 | 1889 | int |
| 1890 | 1890 | SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, |
| 1891 | 1891 | __u8 *oplock, struct smb2_file_all_info *buf, |
| 1892 | − struct kvec *err_iov) | |
| 1892 | + struct kvec *err_iov, int *buftype) | |
| 1893 | 1893 | { |
| 1894 | 1894 | struct smb2_create_req *req; |
| 1895 | 1895 | struct smb2_create_rsp *rsp; |
| @@ -2052,6 +2052,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, · 156 unmodified lines | ||
| 2052 | 2052 | cifs_stats_fail_inc(tcon, SMB2_CREATE_HE); |
| 2053 | 2053 | if (err_iov && rsp) { |
| 2054 | 2054 | *err_iov = rsp_iov; |
| 2055 | + *buftype = resp_buftype; | |
| 2055 | 2056 | resp_buftype = CIFS_NO_BUFFER; |
| 2056 | 2057 | rsp = NULL; |
| 2057 | 2058 | } |
| @@ -2492,8 +2493,7 @@ SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon, · 434 unmodified lines | ||
| 2492 | 2493 | |
| 2493 | 2494 | return query_info(xid, tcon, persistent_fid, volatile_fid, |
| 2494 | 2495 | 0, SMB2_O_INFO_SECURITY, additional_info, |
| 2495 | − SMB2_MAX_BUFFER_SIZE, | |
| 2496 | − sizeof(struct smb2_file_all_info), data, plen); | |
| 2496 | + SMB2_MAX_BUFFER_SIZE, MIN_SEC_DESC_LEN, data, plen); | |
| 2497 | 2497 | } |
| 2498 | 2498 | |
| 2499 | 2499 | int |
| @@ -2721,8 +2721,8 @@ smb2_new_read_req(void **buf, unsigned int *total_len, · 221 unmodified lines | ||
| 2721 | 2721 | |
| 2722 | 2722 | rdata->mr = smbd_register_mr( |
| 2723 | 2723 | server->smbd_conn, rdata->pages, |
| 2724 | − rdata->nr_pages, rdata->tailsz, | |
| 2725 | − true, need_invalidate); | |
| 2724 | + rdata->nr_pages, rdata->page_offset, | |
| 2725 | + rdata->tailsz, true, need_invalidate); | |
| 2726 | 2726 | if (!rdata->mr) |
| 2727 | 2727 | return -ENOBUFS; |
| 2728 | 2728 | |
| @@ -3108,16 +3108,22 @@ smb2_async_writev(struct cifs_writedata *wdata, · 379 unmodified lines | ||
| 3108 | 3108 | |
| 3109 | 3109 | wdata->mr = smbd_register_mr( |
| 3110 | 3110 | server->smbd_conn, wdata->pages, |
| 3111 | − wdata->nr_pages, wdata->tailsz, | |
| 3112 | − false, need_invalidate); | |
| 3111 | + wdata->nr_pages, wdata->page_offset, | |
| 3112 | + wdata->tailsz, false, need_invalidate); | |
| 3113 | 3113 | if (!wdata->mr) { |
| 3114 | 3114 | rc = -ENOBUFS; |
| 3115 | 3115 | goto async_writev_out; |
| 3116 | 3116 | } |
| 3117 | 3117 | req->Length = 0; |
| 3118 | 3118 | req->DataOffset = 0; |
| 3119 | − req->RemainingBytes = | |
| 3120 | − cpu_to_le32((wdata->nr_pages-1)*PAGE_SIZE + wdata->tailsz); | |
| 3119 | + if (wdata->nr_pages > 1) | |
| 3120 | + req->RemainingBytes = | |
| 3121 | + cpu_to_le32( | |
| 3122 | + (wdata->nr_pages - 1) * wdata->pagesz - | |
| 3123 | + wdata->page_offset + wdata->tailsz | |
| 3124 | + ); | |
| 3125 | + else | |
| 3126 | + req->RemainingBytes = cpu_to_le32(wdata->tailsz); | |
| 3121 | 3127 | req->Channel = SMB2_CHANNEL_RDMA_V1_INVALIDATE; |
| 3122 | 3128 | if (need_invalidate) |
| 3123 | 3129 | req->Channel = SMB2_CHANNEL_RDMA_V1; |
| @@ -125,7 +125,7 @@ extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon); · 124 unmodified lines | ||
| 125 | 125 | extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, |
| 126 | 126 | __le16 *path, __u8 *oplock, |
| 127 | 127 | struct smb2_file_all_info *buf, |
| 128 | − struct kvec *err_iov); | |
| 128 | + struct kvec *err_iov, int *resp_buftype); | |
| 129 | 129 | extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, |
| 130 | 130 | u64 persistent_fid, u64 volatile_fid, u32 opcode, |
| 131 | 131 | bool is_fsctl, char *in_data, u32 indatalen, |
| @@ -171,7 +171,9 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) · 170 unmodified lines | ||
| 171 | 171 | unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; |
| 172 | 172 | unsigned char *sigptr = smb2_signature; |
| 173 | 173 | struct kvec *iov = rqst->rq_iov; |
| 174 | − struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base; | |
| 174 | + int iov_hdr_index = rqst->rq_nvec > 1 ? 1 : 0; | |
| 175 | + struct smb2_sync_hdr *shdr = | |
| 176 | + (struct smb2_sync_hdr *)iov[iov_hdr_index].iov_base; | |
| 175 | 177 | struct cifs_ses *ses; |
| 176 | 178 | |
| 177 | 179 | ses = smb2_find_smb_ses(server, shdr->SessionId); |
| @@ -202,7 +204,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) · 24 unmodified lines | ||
| 202 | 204 | return rc; |
| 203 | 205 | } |
| 204 | 206 | |
| 205 | − rc = __cifs_calc_signature(rqst, server, sigptr, | |
| 207 | + rc = __cifs_calc_signature(rqst, iov_hdr_index, server, sigptr, | |
| 206 | 208 | &server->secmech.sdeschmacsha256->shash); |
| 207 | 209 | |
| 208 | 210 | if (!rc) |
| @@ -412,7 +414,9 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) · 203 unmodified lines | ||
| 412 | 414 | unsigned char smb3_signature[SMB2_CMACAES_SIZE]; |
| 413 | 415 | unsigned char *sigptr = smb3_signature; |
| 414 | 416 | struct kvec *iov = rqst->rq_iov; |
| 415 | − struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base; | |
| 417 | + int iov_hdr_index = rqst->rq_nvec > 1 ? 1 : 0; | |
| 418 | + struct smb2_sync_hdr *shdr = | |
| 419 | + (struct smb2_sync_hdr *)iov[iov_hdr_index].iov_base; | |
| 416 | 420 | struct cifs_ses *ses; |
| 417 | 421 | |
| 418 | 422 | ses = smb2_find_smb_ses(server, shdr->SessionId); |
| @@ -443,7 +447,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) · 24 unmodified lines | ||
| 443 | 447 | return rc; |
| 444 | 448 | } |
| 445 | 449 | |
| 446 | − rc = __cifs_calc_signature(rqst, server, sigptr, | |
| 450 | + rc = __cifs_calc_signature(rqst, iov_hdr_index, server, sigptr, | |
| 447 | 451 | &server->secmech.sdesccmacaes->shash); |
| 448 | 452 | |
| 449 | 453 | if (!rc) |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/highmem.h> |
| 18 | 18 | #include "smbdirect.h" |
| 19 | 19 | #include "cifs_debug.h" |
| 20 | +#include "cifsproto.h" | |
| 20 | 21 | |
| 21 | 22 | static struct smbd_response *get_empty_queue_buffer( |
| 22 | 23 | struct smbd_connection *info); |
| @@ -2003,10 +2004,12 @@ read_rfc1002_done: · 1980 unmodified lines | ||
| 2003 | 2004 | * return value: actual data read |
| 2004 | 2005 | */ |
| 2005 | 2006 | static int smbd_recv_page(struct smbd_connection *info, |
| 2006 | − struct page *page, unsigned int to_read) | |
| 2007 | + struct page *page, unsigned int page_offset, | |
| 2008 | + unsigned int to_read) | |
| 2007 | 2009 | { |
| 2008 | 2010 | int ret; |
| 2009 | 2011 | char *to_address; |
| 2012 | + void *page_address; | |
| 2010 | 2013 | |
| 2011 | 2014 | /* make sure we have the page ready for read */ |
| 2012 | 2015 | ret = wait_event_interruptible( |
| @@ -2014,16 +2017,17 @@ static int smbd_recv_page(struct smbd_connection *info, · 1 unmodified line | ||
| 2014 | 2017 | info->reassembly_data_length >= to_read || |
| 2015 | 2018 | info->transport_status != SMBD_CONNECTED); |
| 2016 | 2019 | if (ret) |
| 2017 | − return 0; | |
| 2020 | + return ret; | |
| 2018 | 2021 | |
| 2019 | 2022 | /* now we can read from reassembly queue and not sleep */ |
| 2020 | − to_address = kmap_atomic(page); | |
| 2023 | + page_address = kmap_atomic(page); | |
| 2024 | + to_address = (char *) page_address + page_offset; | |
| 2021 | 2025 | |
| 2022 | 2026 | log_read(INFO, "reading from page=%p address=%p to_read=%d\n", |
| 2023 | 2027 | page, to_address, to_read); |
| 2024 | 2028 | |
| 2025 | 2029 | ret = smbd_recv_buf(info, to_address, to_read); |
| 2026 | − kunmap_atomic(to_address); | |
| 2030 | + kunmap_atomic(page_address); | |
| 2027 | 2031 | |
| 2028 | 2032 | return ret; |
| 2029 | 2033 | } |
| @@ -2037,7 +2041,7 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg) · 7 unmodified lines | ||
| 2037 | 2041 | { |
| 2038 | 2042 | char *buf; |
| 2039 | 2043 | struct page *page; |
| 2040 | − unsigned int to_read; | |
| 2044 | + unsigned int to_read, page_offset; | |
| 2041 | 2045 | int rc; |
| 2042 | 2046 | |
| 2043 | 2047 | info->smbd_recv_pending++; |
| @@ -2051,15 +2055,16 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg) · 7 unmodified lines | ||
| 2051 | 2055 | |
| 2052 | 2056 | case READ | ITER_BVEC: |
| 2053 | 2057 | page = msg->msg_iter.bvec->bv_page; |
| 2058 | + page_offset = msg->msg_iter.bvec->bv_offset; | |
| 2054 | 2059 | to_read = msg->msg_iter.bvec->bv_len; |
| 2055 | − rc = smbd_recv_page(info, page, to_read); | |
| 2060 | + rc = smbd_recv_page(info, page, page_offset, to_read); | |
| 2056 | 2061 | break; |
| 2057 | 2062 | |
| 2058 | 2063 | default: |
| 2059 | 2064 | /* It's a bug in upper layer to get there */ |
| 2060 | 2065 | cifs_dbg(VFS, "CIFS: invalid msg type %d\n", |
| 2061 | 2066 | msg->msg_iter.type); |
| 2062 | − rc = -EIO; | |
| 2067 | + rc = -EINVAL; | |
| 2063 | 2068 | } |
| 2064 | 2069 | |
| 2065 | 2070 | info->smbd_recv_pending--; |
| @@ -2082,7 +2087,7 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) · 16 unmodified lines | ||
| 2082 | 2087 | struct kvec vec; |
| 2083 | 2088 | int nvecs; |
| 2084 | 2089 | int size; |
| 2085 | − int buflen = 0, remaining_data_length; | |
| 2090 | + unsigned int buflen = 0, remaining_data_length; | |
| 2086 | 2091 | int start, i, j; |
| 2087 | 2092 | int max_iov_size = |
| 2088 | 2093 | info->max_send_size - sizeof(struct smbd_data_transfer); |
| @@ -2113,10 +2118,17 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) · 24 unmodified lines | ||
| 2113 | 2118 | buflen += iov[i].iov_len; |
| 2114 | 2119 | } |
| 2115 | 2120 | |
| 2116 | − /* add in the page array if there is one */ | |
| 2121 | + /* | |
| 2122 | + * Add in the page array if there is one. The caller needs to set | |
| 2123 | + * rq_tailsz to PAGE_SIZE when the buffer has multiple pages and | |
| 2124 | + * ends at page boundary | |
| 2125 | + */ | |
| 2117 | 2126 | if (rqst->rq_npages) { |
| 2118 | − buflen += rqst->rq_pagesz * (rqst->rq_npages - 1); | |
| 2119 | − buflen += rqst->rq_tailsz; | |
| 2127 | + if (rqst->rq_npages == 1) | |
| 2128 | + buflen += rqst->rq_tailsz; | |
| 2129 | + else | |
| 2130 | + buflen += rqst->rq_pagesz * (rqst->rq_npages - 1) - | |
| 2131 | + rqst->rq_offset + rqst->rq_tailsz; | |
| 2120 | 2132 | } |
| 2121 | 2133 | |
| 2122 | 2134 | if (buflen + sizeof(struct smbd_data_transfer) > |
| @@ -2213,8 +2225,9 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) · 90 unmodified lines | ||
| 2213 | 2225 | |
| 2214 | 2226 | /* now sending pages if there are any */ |
| 2215 | 2227 | for (i = 0; i < rqst->rq_npages; i++) { |
| 2216 | − buflen = (i == rqst->rq_npages-1) ? | |
| 2217 | − rqst->rq_tailsz : rqst->rq_pagesz; | |
| 2228 | + unsigned int offset; | |
| 2229 | + | |
| 2230 | + rqst_page_get_length(rqst, i, &buflen, &offset); | |
| 2218 | 2231 | nvecs = (buflen + max_iov_size - 1) / max_iov_size; |
| 2219 | 2232 | log_write(INFO, "sending pages buflen=%d nvecs=%d\n", |
| 2220 | 2233 | buflen, nvecs); |
| @@ -2225,9 +2238,11 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) · 4 unmodified lines | ||
| 2225 | 2238 | remaining_data_length -= size; |
| 2226 | 2239 | log_write(INFO, "sending pages i=%d offset=%d size=%d" |
| 2227 | 2240 | " remaining_data_length=%d\n", |
| 2228 | − i, j*max_iov_size, size, remaining_data_length); | |
| 2241 | + i, j*max_iov_size+offset, size, | |
| 2242 | + remaining_data_length); | |
| 2229 | 2243 | rc = smbd_post_send_page( |
| 2230 | − info, rqst->rq_pages[i], j*max_iov_size, | |
| 2244 | + info, rqst->rq_pages[i], | |
| 2245 | + j*max_iov_size + offset, | |
| 2231 | 2246 | size, remaining_data_length); |
| 2232 | 2247 | if (rc) |
| 2233 | 2248 | goto done; |
| @@ -2284,37 +2299,37 @@ static void smbd_mr_recovery_work(struct work_struct *work) · 50 unmodified lines | ||
| 2284 | 2299 | if (smbdirect_mr->state == MR_INVALIDATED || |
| 2285 | 2300 | smbdirect_mr->state == MR_ERROR) { |
| 2286 | 2301 | |
| 2287 | − if (smbdirect_mr->state == MR_INVALIDATED) { | |
| 2302 | + /* recover this MR entry */ | |
| 2303 | + rc = ib_dereg_mr(smbdirect_mr->mr); | |
| 2304 | + if (rc) { | |
| 2305 | + log_rdma_mr(ERR, | |
| 2306 | + "ib_dereg_mr failed rc=%x\n", | |
| 2307 | + rc); | |
| 2308 | + smbd_disconnect_rdma_connection(info); | |
| 2309 | + continue; | |
| 2310 | + } | |
| 2311 | + | |
| 2312 | + smbdirect_mr->mr = ib_alloc_mr( | |
| 2313 | + info->pd, info->mr_type, | |
| 2314 | + info->max_frmr_depth); | |
| 2315 | + if (IS_ERR(smbdirect_mr->mr)) { | |
| 2316 | + log_rdma_mr(ERR, | |
| 2317 | + "ib_alloc_mr failed mr_type=%x " | |
| 2318 | + "max_frmr_depth=%x\n", | |
| 2319 | + info->mr_type, | |
| 2320 | + info->max_frmr_depth); | |
| 2321 | + smbd_disconnect_rdma_connection(info); | |
| 2322 | + continue; | |
| 2323 | + } | |
| 2324 | + | |
| 2325 | + if (smbdirect_mr->state == MR_INVALIDATED) | |
| 2288 | 2326 | ib_dma_unmap_sg( |
| 2289 | 2327 | info->id->device, smbdirect_mr->sgl, |
| 2290 | 2328 | smbdirect_mr->sgl_count, |
| 2291 | 2329 | smbdirect_mr->dir); |
| 2292 | − smbdirect_mr->state = MR_READY; | |
| 2293 | − } else if (smbdirect_mr->state == MR_ERROR) { | |
| 2294 | − | |
| 2295 | − /* recover this MR entry */ | |
| 2296 | − rc = ib_dereg_mr(smbdirect_mr->mr); | |
| 2297 | − if (rc) { | |
| 2298 | − log_rdma_mr(ERR, | |
| 2299 | − "ib_dereg_mr failed rc=%x\n", | |
| 2300 | − rc); | |
| 2301 | − smbd_disconnect_rdma_connection(info); | |
| 2302 | − } | |
| 2303 | 2330 | |
| 2304 | − smbdirect_mr->mr = ib_alloc_mr( | |
| 2305 | − info->pd, info->mr_type, | |
| 2306 | − info->max_frmr_depth); | |
| 2307 | − if (IS_ERR(smbdirect_mr->mr)) { | |
| 2308 | − log_rdma_mr(ERR, | |
| 2309 | − "ib_alloc_mr failed mr_type=%x " | |
| 2310 | − "max_frmr_depth=%x\n", | |
| 2311 | − info->mr_type, | |
| 2312 | − info->max_frmr_depth); | |
| 2313 | − smbd_disconnect_rdma_connection(info); | |
| 2314 | − } | |
| 2331 | + smbdirect_mr->state = MR_READY; | |
| 2315 | 2332 | |
| 2316 | − smbdirect_mr->state = MR_READY; | |
| 2317 | − } | |
| 2318 | 2333 | /* smbdirect_mr->state is updated by this function |
| 2319 | 2334 | * and is read and updated by I/O issuing CPUs trying |
| 2320 | 2335 | * to get a MR, the call to atomic_inc_return |
| @@ -2460,7 +2475,7 @@ again: · 139 unmodified lines | ||
| 2460 | 2475 | */ |
| 2461 | 2476 | struct smbd_mr *smbd_register_mr( |
| 2462 | 2477 | struct smbd_connection *info, struct page *pages[], int num_pages, |
| 2463 | − int tailsz, bool writing, bool need_invalidate) | |
| 2478 | + int offset, int tailsz, bool writing, bool need_invalidate) | |
| 2464 | 2479 | { |
| 2465 | 2480 | struct smbd_mr *smbdirect_mr; |
| 2466 | 2481 | int rc, i; |
| @@ -2483,17 +2498,31 @@ struct smbd_mr *smbd_register_mr( · 16 unmodified lines | ||
| 2483 | 2498 | smbdirect_mr->sgl_count = num_pages; |
| 2484 | 2499 | sg_init_table(smbdirect_mr->sgl, num_pages); |
| 2485 | 2500 | |
| 2486 | − for (i = 0; i < num_pages - 1; i++) | |
| 2487 | − sg_set_page(&smbdirect_mr->sgl[i], pages[i], PAGE_SIZE, 0); | |
| 2501 | + log_rdma_mr(INFO, "num_pages=0x%x offset=0x%x tailsz=0x%x\n", | |
| 2502 | + num_pages, offset, tailsz); | |
| 2503 | + | |
| 2504 | + if (num_pages == 1) { | |
| 2505 | + sg_set_page(&smbdirect_mr->sgl[0], pages[0], tailsz, offset); | |
| 2506 | + goto skip_multiple_pages; | |
| 2507 | + } | |
| 2488 | 2508 | |
| 2509 | + /* We have at least two pages to register */ | |
| 2510 | + sg_set_page( | |
| 2511 | + &smbdirect_mr->sgl[0], pages[0], PAGE_SIZE - offset, offset); | |
| 2512 | + i = 1; | |
| 2513 | + while (i < num_pages - 1) { | |
| 2514 | + sg_set_page(&smbdirect_mr->sgl[i], pages[i], PAGE_SIZE, 0); | |
| 2515 | + i++; | |
| 2516 | + } | |
| 2489 | 2517 | sg_set_page(&smbdirect_mr->sgl[i], pages[i], |
| 2490 | 2518 | tailsz ? tailsz : PAGE_SIZE, 0); |
| 2491 | 2519 | |
| 2520 | +skip_multiple_pages: | |
| 2492 | 2521 | dir = writing ? DMA_FROM_DEVICE : DMA_TO_DEVICE; |
| 2493 | 2522 | smbdirect_mr->dir = dir; |
| 2494 | 2523 | rc = ib_dma_map_sg(info->id->device, smbdirect_mr->sgl, num_pages, dir); |
| 2495 | 2524 | if (!rc) { |
| 2496 | − log_rdma_mr(INFO, "ib_dma_map_sg num_pages=%x dir=%x rc=%x\n", | |
| 2525 | + log_rdma_mr(ERR, "ib_dma_map_sg num_pages=%x dir=%x rc=%x\n", | |
| 2497 | 2526 | num_pages, dir, rc); |
| 2498 | 2527 | goto dma_map_error; |
| 2499 | 2528 | } |
| @@ -2501,8 +2530,8 @@ struct smbd_mr *smbd_register_mr( · 1 unmodified line | ||
| 2501 | 2530 | rc = ib_map_mr_sg(smbdirect_mr->mr, smbdirect_mr->sgl, num_pages, |
| 2502 | 2531 | NULL, PAGE_SIZE); |
| 2503 | 2532 | if (rc != num_pages) { |
| 2504 | − log_rdma_mr(INFO, | |
| 2505 | − "ib_map_mr_sg failed rc = %x num_pages = %x\n", | |
| 2533 | + log_rdma_mr(ERR, | |
| 2534 | + "ib_map_mr_sg failed rc = %d num_pages = %x\n", | |
| 2506 | 2535 | rc, num_pages); |
| 2507 | 2536 | goto map_mr_error; |
| 2508 | 2537 | } |
| @@ -321,7 +321,7 @@ struct smbd_mr { · 320 unmodified lines | ||
| 321 | 321 | /* Interfaces to register and deregister MR for RDMA read/write */ |
| 322 | 322 | struct smbd_mr *smbd_register_mr( |
| 323 | 323 | struct smbd_connection *info, struct page *pages[], int num_pages, |
| 324 | − int tailsz, bool writing, bool need_invalidate); | |
| 324 | + int offset, int tailsz, bool writing, bool need_invalidate); | |
| 325 | 325 | int smbd_deregister_mr(struct smbd_mr *mr); |
| 326 | 326 | |
| 327 | 327 | #else |
| @@ -212,10 +212,24 @@ rqst_len(struct smb_rqst *rqst) · 211 unmodified lines | ||
| 212 | 212 | for (i = 0; i < rqst->rq_nvec; i++) |
| 213 | 213 | buflen += iov[i].iov_len; |
| 214 | 214 | |
| 215 | − /* add in the page array if there is one */ | |
| 215 | + /* | |
| 216 | + * Add in the page array if there is one. The caller needs to make | |
| 217 | + * sure rq_offset and rq_tailsz are set correctly. If a buffer of | |
| 218 | + * multiple pages ends at page boundary, rq_tailsz needs to be set to | |
| 219 | + * PAGE_SIZE. | |
| 220 | + */ | |
| 216 | 221 | if (rqst->rq_npages) { |
| 217 | − buflen += rqst->rq_pagesz * (rqst->rq_npages - 1); | |
| 218 | − buflen += rqst->rq_tailsz; | |
| 222 | + if (rqst->rq_npages == 1) | |
| 223 | + buflen += rqst->rq_tailsz; | |
| 224 | + else { | |
| 225 | + /* | |
| 226 | + * If there is more than one page, calculate the | |
| 227 | + * buffer length based on rq_offset and rq_tailsz | |
| 228 | + */ | |
| 229 | + buflen += rqst->rq_pagesz * (rqst->rq_npages - 1) - | |
| 230 | + rqst->rq_offset; | |
| 231 | + buflen += rqst->rq_tailsz; | |
| 232 | + } | |
| 219 | 233 | } |
| 220 | 234 | |
| 221 | 235 | return buflen; |
| @@ -274,15 +288,13 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) · 52 unmodified lines | ||
| 274 | 288 | |
| 275 | 289 | /* now walk the page array and send each page in it */ |
| 276 | 290 | for (i = 0; i < rqst->rq_npages; i++) { |
| 277 | − size_t len = i == rqst->rq_npages - 1 | |
| 278 | − ? rqst->rq_tailsz | |
| 279 | − : rqst->rq_pagesz; | |
| 280 | − struct bio_vec bvec = { | |
| 281 | − .bv_page = rqst->rq_pages[i], | |
| 282 | − .bv_len = len | |
| 283 | − }; | |
| 291 | + struct bio_vec bvec; | |
| 292 | + | |
| 293 | + bvec.bv_page = rqst->rq_pages[i]; | |
| 294 | + rqst_page_get_length(rqst, i, &bvec.bv_len, &bvec.bv_offset); | |
| 295 | + | |
| 284 | 296 | iov_iter_bvec(&smb_msg.msg_iter, WRITE | ITER_BVEC, |
| 285 | − &bvec, 1, len); | |
| 297 | + &bvec, 1, bvec.bv_len); | |
| 286 | 298 | rc = smb_send_kvec(server, &smb_msg, &sent); |
| 287 | 299 | if (rc < 0) |
| 288 | 300 | break; |