diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-10 13:53:31 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-10 13:53:31 -0400 |
| commit | 0c14e43a42e4e44f70963f8ccf89461290c4e4da (patch) | |
| tree | e747675cc238a22995bcddc08a32035bd2bd7823 | |
| parent | bbaa10130301a5fba168df71c31e8d0eef967182 (diff) | |
| parent | 9d874c36552afbd08778687aeaff24a8a7260f20 (diff) | |
Merge tag '4.18-fixes-smb3' of git://git.samba.org/sfrench/cifs-2.6
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
| -rw-r--r-- | fs/cifs/cifsacl.h | 14 | ||||
| -rw-r--r-- | fs/cifs/cifsencrypt.c | 17 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.c | 22 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 6 | ||||
| -rw-r--r-- | fs/cifs/cifsproto.h | 7 | ||||
| -rw-r--r-- | fs/cifs/connect.c | 32 | ||||
| -rw-r--r-- | fs/cifs/link.c | 6 | ||||
| -rw-r--r-- | fs/cifs/misc.c | 17 | ||||
| -rw-r--r-- | fs/cifs/smb2file.c | 3 | ||||
| -rw-r--r-- | fs/cifs/smb2inode.c | 3 | ||||
| -rw-r--r-- | fs/cifs/smb2misc.c | 4 | ||||
| -rw-r--r-- | fs/cifs/smb2ops.c | 73 | ||||
| -rw-r--r-- | fs/cifs/smb2pdu.c | 24 | ||||
| -rw-r--r-- | fs/cifs/smb2proto.h | 2 | ||||
| -rw-r--r-- | fs/cifs/smb2transport.c | 12 | ||||
| -rw-r--r-- | fs/cifs/smbdirect.c | 121 | ||||
| -rw-r--r-- | fs/cifs/smbdirect.h | 2 | ||||
| -rw-r--r-- | fs/cifs/transport.c | 34 |
18 files changed, 261 insertions, 138 deletions
diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 4f3884835267..dd95a6fa24bf 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h | |||
| @@ -98,4 +98,18 @@ struct cifs_ace { | |||
| 98 | struct cifs_sid sid; /* ie UUID of user or group who gets these perms */ | 98 | struct cifs_sid sid; /* ie UUID of user or group who gets these perms */ |
| 99 | } __attribute__((packed)); | 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 | #endif /* _CIFSACL_H */ | 115 | #endif /* _CIFSACL_H */ |
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index a6ef088e057b..937251cc61c0 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include <crypto/aead.h> | 37 | #include <crypto/aead.h> |
| 38 | 38 | ||
| 39 | int __cifs_calc_signature(struct smb_rqst *rqst, | 39 | int __cifs_calc_signature(struct smb_rqst *rqst, |
| 40 | int start, | ||
| 40 | struct TCP_Server_Info *server, char *signature, | 41 | struct TCP_Server_Info *server, char *signature, |
| 41 | struct shash_desc *shash) | 42 | struct shash_desc *shash) |
| 42 | { | 43 | { |
| @@ -45,10 +46,7 @@ int __cifs_calc_signature(struct smb_rqst *rqst, | |||
| 45 | struct kvec *iov = rqst->rq_iov; | 46 | struct kvec *iov = rqst->rq_iov; |
| 46 | int n_vec = rqst->rq_nvec; | 47 | int n_vec = rqst->rq_nvec; |
| 47 | 48 | ||
| 48 | if (n_vec < 2 || iov[0].iov_len != 4) | 49 | for (i = start; i < n_vec; i++) { |
| 49 | return -EIO; | ||
| 50 | |||
| 51 | for (i = 1; i < n_vec; i++) { | ||
| 52 | if (iov[i].iov_len == 0) | 50 | if (iov[i].iov_len == 0) |
| 53 | continue; | 51 | continue; |
| 54 | if (iov[i].iov_base == NULL) { | 52 | if (iov[i].iov_base == NULL) { |
| @@ -68,11 +66,12 @@ int __cifs_calc_signature(struct smb_rqst *rqst, | |||
| 68 | 66 | ||
| 69 | /* now hash over the rq_pages array */ | 67 | /* now hash over the rq_pages array */ |
| 70 | for (i = 0; i < rqst->rq_npages; i++) { | 68 | for (i = 0; i < rqst->rq_npages; i++) { |
| 71 | void *kaddr = kmap(rqst->rq_pages[i]); | 69 | void *kaddr; |
| 72 | size_t len = rqst->rq_pagesz; | 70 | unsigned int len, offset; |
| 71 | |||
| 72 | rqst_page_get_length(rqst, i, &len, &offset); | ||
| 73 | 73 | ||
| 74 | if (i == rqst->rq_npages - 1) | 74 | kaddr = (char *) kmap(rqst->rq_pages[i]) + offset; |
| 75 | len = rqst->rq_tailsz; | ||
| 76 | 75 | ||
| 77 | crypto_shash_update(shash, kaddr, len); | 76 | crypto_shash_update(shash, kaddr, len); |
| 78 | 77 | ||
| @@ -119,7 +118,7 @@ static int cifs_calc_signature(struct smb_rqst *rqst, | |||
| 119 | return rc; | 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 | &server->secmech.sdescmd5->shash); | 122 | &server->secmech.sdescmd5->shash); |
| 124 | } | 123 | } |
| 125 | 124 | ||
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index eb7b6573f322..d5aa7ae917bf 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -698,8 +698,8 @@ static int cifs_set_super(struct super_block *sb, void *data) | |||
| 698 | } | 698 | } |
| 699 | 699 | ||
| 700 | static struct dentry * | 700 | static struct dentry * |
| 701 | cifs_do_mount(struct file_system_type *fs_type, | 701 | cifs_smb3_do_mount(struct file_system_type *fs_type, |
| 702 | int flags, const char *dev_name, void *data) | 702 | int flags, const char *dev_name, void *data, bool is_smb3) |
| 703 | { | 703 | { |
| 704 | int rc; | 704 | int rc; |
| 705 | struct super_block *sb; | 705 | struct super_block *sb; |
| @@ -710,7 +710,7 @@ cifs_do_mount(struct file_system_type *fs_type, | |||
| 710 | 710 | ||
| 711 | cifs_dbg(FYI, "Devname: %s flags: %d\n", dev_name, flags); | 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 | if (IS_ERR(volume_info)) | 714 | if (IS_ERR(volume_info)) |
| 715 | return ERR_CAST(volume_info); | 715 | return ERR_CAST(volume_info); |
| 716 | 716 | ||
| @@ -790,6 +790,20 @@ out_nls: | |||
| 790 | goto out; | 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 | static ssize_t | 807 | static ssize_t |
| 794 | cifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter) | 808 | cifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter) |
| 795 | { | 809 | { |
| @@ -925,7 +939,7 @@ MODULE_ALIAS_FS("cifs"); | |||
| 925 | static struct file_system_type smb3_fs_type = { | 939 | static struct file_system_type smb3_fs_type = { |
| 926 | .owner = THIS_MODULE, | 940 | .owner = THIS_MODULE, |
| 927 | .name = "smb3", | 941 | .name = "smb3", |
| 928 | .mount = cifs_do_mount, | 942 | .mount = smb3_do_mount, |
| 929 | .kill_sb = cifs_kill_sb, | 943 | .kill_sb = cifs_kill_sb, |
| 930 | /* .fs_flags */ | 944 | /* .fs_flags */ |
| 931 | }; | 945 | }; |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 08d1cdd96701..1efa2e65bc1a 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -1019,6 +1019,12 @@ tlink_tcon(struct tcon_link *tlink) | |||
| 1019 | return tlink->tl_tcon; | 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 | extern void cifs_put_tlink(struct tcon_link *tlink); | 1028 | extern void cifs_put_tlink(struct tcon_link *tlink); |
| 1023 | 1029 | ||
| 1024 | static inline struct tcon_link * | 1030 | static inline struct tcon_link * |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 7933c5f9c076..4e0d183c3d10 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -211,7 +211,7 @@ extern int cifs_setup_cifs_sb(struct smb_vol *pvolume_info, | |||
| 211 | extern int cifs_match_super(struct super_block *, void *); | 211 | extern int cifs_match_super(struct super_block *, void *); |
| 212 | extern void cifs_cleanup_volume_info(struct smb_vol *pvolume_info); | 212 | extern void cifs_cleanup_volume_info(struct smb_vol *pvolume_info); |
| 213 | extern struct smb_vol *cifs_get_volume_info(char *mount_data, | 213 | extern struct smb_vol *cifs_get_volume_info(char *mount_data, |
| 214 | const char *devname); | 214 | const char *devname, bool is_smb3); |
| 215 | extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *); | 215 | extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *); |
| 216 | extern void cifs_umount(struct cifs_sb_info *); | 216 | extern void cifs_umount(struct cifs_sb_info *); |
| 217 | extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon); | 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, | |||
| 544 | struct cifs_sb_info *cifs_sb, | 544 | struct cifs_sb_info *cifs_sb, |
| 545 | const unsigned char *path, char *pbuf, | 545 | const unsigned char *path, char *pbuf, |
| 546 | unsigned int *pbytes_written); | 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 | struct TCP_Server_Info *server, char *signature, | 548 | struct TCP_Server_Info *server, char *signature, |
| 549 | struct shash_desc *shash); | 549 | struct shash_desc *shash); |
| 550 | enum securityEnum cifs_select_sectype(struct TCP_Server_Info *, | 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, | |||
| 557 | struct sdesc **sdesc); | 557 | struct sdesc **sdesc); |
| 558 | void cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc); | 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 | #endif /* _CIFSPROTO_H */ | 563 | #endif /* _CIFSPROTO_H */ |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e5a2fe7f0dd4..96645a7d8f27 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -320,7 +320,7 @@ static int generic_ip_connect(struct TCP_Server_Info *server); | |||
| 320 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); | 320 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); |
| 321 | static void cifs_prune_tlinks(struct work_struct *work); | 321 | static void cifs_prune_tlinks(struct work_struct *work); |
| 322 | static int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, | 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 | * cifs tcp session reconnection | 326 | * cifs tcp session reconnection |
| @@ -1166,7 +1166,7 @@ cifs_parse_cache_flavor(char *value, struct smb_vol *vol) | |||
| 1166 | } | 1166 | } |
| 1167 | 1167 | ||
| 1168 | static int | 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 | substring_t args[MAX_OPT_ARGS]; | 1171 | substring_t args[MAX_OPT_ARGS]; |
| 1172 | 1172 | ||
| @@ -1176,6 +1176,10 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol) | |||
| 1176 | cifs_dbg(VFS, "mount with legacy dialect disabled\n"); | 1176 | cifs_dbg(VFS, "mount with legacy dialect disabled\n"); |
| 1177 | return 1; | 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 | vol->ops = &smb1_operations; | 1183 | vol->ops = &smb1_operations; |
| 1180 | vol->vals = &smb1_values; | 1184 | vol->vals = &smb1_values; |
| 1181 | break; | 1185 | break; |
| @@ -1184,6 +1188,10 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol) | |||
| 1184 | cifs_dbg(VFS, "mount with legacy dialect disabled\n"); | 1188 | cifs_dbg(VFS, "mount with legacy dialect disabled\n"); |
| 1185 | return 1; | 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 | vol->ops = &smb20_operations; | 1195 | vol->ops = &smb20_operations; |
| 1188 | vol->vals = &smb20_values; | 1196 | vol->vals = &smb20_values; |
| 1189 | break; | 1197 | break; |
| @@ -1272,7 +1280,7 @@ cifs_parse_devname(const char *devname, struct smb_vol *vol) | |||
| 1272 | 1280 | ||
| 1273 | static int | 1281 | static int |
| 1274 | cifs_parse_mount_options(const char *mountdata, const char *devname, | 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 | char *data, *end; | 1285 | char *data, *end; |
| 1278 | char *mountdata_copy = NULL, *options; | 1286 | char *mountdata_copy = NULL, *options; |
| @@ -1985,7 +1993,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
| 1985 | if (string == NULL) | 1993 | if (string == NULL) |
| 1986 | goto out_nomem; | 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 | goto cifs_parse_mount_err; | 1997 | goto cifs_parse_mount_err; |
| 1990 | got_version = true; | 1998 | got_version = true; |
| 1991 | break; | 1999 | break; |
| @@ -3116,12 +3124,6 @@ cifs_put_tlink(struct tcon_link *tlink) | |||
| 3116 | return; | 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 | static int | 3127 | static int |
| 3126 | compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data) | 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, | |||
| 3803 | } else { | 3805 | } else { |
| 3804 | cleanup_volume_info_contents(volume_info); | 3806 | cleanup_volume_info_contents(volume_info); |
| 3805 | rc = cifs_setup_volume_info(volume_info, mdata, | 3807 | rc = cifs_setup_volume_info(volume_info, mdata, |
| 3806 | fake_devname); | 3808 | fake_devname, false); |
| 3807 | } | 3809 | } |
| 3808 | kfree(fake_devname); | 3810 | kfree(fake_devname); |
| 3809 | kfree(cifs_sb->mountdata); | 3811 | kfree(cifs_sb->mountdata); |
| @@ -3816,11 +3818,11 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, | |||
| 3816 | 3818 | ||
| 3817 | static int | 3819 | static int |
| 3818 | cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, | 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 | int rc = 0; | 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 | return -EINVAL; | 3826 | return -EINVAL; |
| 3825 | 3827 | ||
| 3826 | if (volume_info->nullauth) { | 3828 | if (volume_info->nullauth) { |
| @@ -3854,7 +3856,7 @@ cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, | |||
| 3854 | } | 3856 | } |
| 3855 | 3857 | ||
| 3856 | struct smb_vol * | 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 | int rc; | 3861 | int rc; |
| 3860 | struct smb_vol *volume_info; | 3862 | struct smb_vol *volume_info; |
| @@ -3863,7 +3865,7 @@ cifs_get_volume_info(char *mount_data, const char *devname) | |||
| 3863 | if (!volume_info) | 3865 | if (!volume_info) |
| 3864 | return ERR_PTR(-ENOMEM); | 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 | if (rc) { | 3869 | if (rc) { |
| 3868 | cifs_cleanup_volume_info(volume_info); | 3870 | cifs_cleanup_volume_info(volume_info); |
| 3869 | volume_info = ERR_PTR(rc); | 3871 | volume_info = ERR_PTR(rc); |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 889a840172eb..de41f96aba49 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
| @@ -421,7 +421,8 @@ smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, | |||
| 421 | return -ENOMEM; | 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 | if (rc) | 426 | if (rc) |
| 426 | goto qmf_out_open_fail; | 427 | goto qmf_out_open_fail; |
| 427 | 428 | ||
| @@ -478,7 +479,8 @@ smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, | |||
| 478 | oparms.fid = &fid; | 479 | oparms.fid = &fid; |
| 479 | oparms.reconnect = false; | 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 | if (rc) { | 484 | if (rc) { |
| 483 | kfree(utf16_path); | 485 | kfree(utf16_path); |
| 484 | return rc; | 486 | return rc; |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index aba3fc3058da..f90d4ad6624c 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
| @@ -905,3 +905,20 @@ cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc) | |||
| 905 | crypto_free_shash(*shash); | 905 | crypto_free_shash(*shash); |
| 906 | *shash = NULL; | 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 | } | ||
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c index 12af5dba742b..788412675723 100644 --- a/fs/cifs/smb2file.c +++ b/fs/cifs/smb2file.c | |||
| @@ -64,7 +64,8 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, | |||
| 64 | if (oparms->tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING) | 64 | if (oparms->tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING) |
| 65 | memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE); | 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 | if (rc) | 69 | if (rc) |
| 69 | goto out; | 70 | goto out; |
| 70 | 71 | ||
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index a6e786e39248..d01ad706d7fc 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c | |||
| @@ -71,7 +71,8 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 71 | oparms.fid = &fid; | 71 | oparms.fid = &fid; |
| 72 | oparms.reconnect = false; | 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 | if (rc) { | 76 | if (rc) { |
| 76 | kfree(utf16_path); | 77 | kfree(utf16_path); |
| 77 | return rc; | 78 | return rc; |
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index cb5728e3d87d..e2bec47c6845 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c | |||
| @@ -453,8 +453,10 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb) | |||
| 453 | start_of_path = from + 1; | 453 | start_of_path = from + 1; |
| 454 | #ifdef CONFIG_CIFS_SMB311 | 454 | #ifdef CONFIG_CIFS_SMB311 |
| 455 | /* SMB311 POSIX extensions paths do not include leading slash */ | 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 | start_of_path = from + 1; | 458 | start_of_path = from + 1; |
| 459 | } | ||
| 458 | #endif /* 311 */ | 460 | #endif /* 311 */ |
| 459 | else | 461 | else |
| 460 | start_of_path = from; | 462 | start_of_path = from; |
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 950d0ab2cc61..b15f5957d645 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
| @@ -348,7 +348,7 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid) | |||
| 348 | oparams.fid = pfid; | 348 | oparams.fid = pfid; |
| 349 | oparams.reconnect = false; | 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 | if (rc == 0) { | 352 | if (rc == 0) { |
| 353 | memcpy(tcon->prfid, pfid, sizeof(struct cifs_fid)); | 353 | memcpy(tcon->prfid, pfid, sizeof(struct cifs_fid)); |
| 354 | tcon->valid_root_fid = true; | 354 | tcon->valid_root_fid = true; |
| @@ -375,7 +375,8 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon) | |||
| 375 | oparms.reconnect = false; | 375 | oparms.reconnect = false; |
| 376 | 376 | ||
| 377 | if (no_cached_open) | 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 | else | 380 | else |
| 380 | rc = open_shroot(xid, tcon, &fid); | 381 | rc = open_shroot(xid, tcon, &fid); |
| 381 | 382 | ||
| @@ -413,7 +414,7 @@ smb2_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon) | |||
| 413 | oparms.fid = &fid; | 414 | oparms.fid = &fid; |
| 414 | oparms.reconnect = false; | 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 | if (rc) | 418 | if (rc) |
| 418 | return; | 419 | return; |
| 419 | 420 | ||
| @@ -449,7 +450,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 449 | oparms.fid = &fid; | 450 | oparms.fid = &fid; |
| 450 | oparms.reconnect = false; | 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 | if (rc) { | 454 | if (rc) { |
| 454 | kfree(utf16_path); | 455 | kfree(utf16_path); |
| 455 | return rc; | 456 | return rc; |
| @@ -598,7 +599,7 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 598 | oparms.fid = &fid; | 599 | oparms.fid = &fid; |
| 599 | oparms.reconnect = false; | 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 | kfree(utf16_path); | 603 | kfree(utf16_path); |
| 603 | if (rc) { | 604 | if (rc) { |
| 604 | cifs_dbg(FYI, "open failed rc=%d\n", rc); | 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, | |||
| 677 | oparms.fid = &fid; | 678 | oparms.fid = &fid; |
| 678 | oparms.reconnect = false; | 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 | kfree(utf16_path); | 682 | kfree(utf16_path); |
| 682 | if (rc) { | 683 | if (rc) { |
| 683 | cifs_dbg(FYI, "open failed rc=%d\n", rc); | 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, | |||
| 1261 | oparms.fid = fid; | 1262 | oparms.fid = fid; |
| 1262 | oparms.reconnect = false; | 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 | kfree(utf16_path); | 1266 | kfree(utf16_path); |
| 1266 | if (rc) { | 1267 | if (rc) { |
| 1267 | cifs_dbg(FYI, "open dir failed rc=%d\n", rc); | 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, | |||
| 1361 | oparms.fid = &fid; | 1362 | oparms.fid = &fid; |
| 1362 | oparms.reconnect = false; | 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 | if (rc) | 1366 | if (rc) |
| 1366 | return rc; | 1367 | return rc; |
| 1367 | buf->f_type = SMB2_MAGIC_NUMBER; | 1368 | buf->f_type = SMB2_MAGIC_NUMBER; |
| @@ -1515,7 +1516,8 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 1515 | struct cifs_open_parms oparms; | 1516 | struct cifs_open_parms oparms; |
| 1516 | struct cifs_fid fid; | 1517 | struct cifs_fid fid; |
| 1517 | struct kvec err_iov = {NULL, 0}; | 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 | struct smb2_symlink_err_rsp *symlink; | 1521 | struct smb2_symlink_err_rsp *symlink; |
| 1520 | unsigned int sub_len; | 1522 | unsigned int sub_len; |
| 1521 | unsigned int sub_offset; | 1523 | unsigned int sub_offset; |
| @@ -1535,18 +1537,18 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 1535 | oparms.fid = &fid; | 1537 | oparms.fid = &fid; |
| 1536 | oparms.reconnect = false; | 1538 | oparms.reconnect = false; |
| 1537 | 1539 | ||
| 1538 | rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, &err_iov); | 1540 | rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, &err_iov, |
| 1539 | 1541 | &resp_buftype); | |
| 1540 | if (!rc || !err_iov.iov_base) { | 1542 | if (!rc || !err_iov.iov_base) { |
| 1541 | kfree(utf16_path); | 1543 | rc = -ENOENT; |
| 1542 | return -ENOENT; | 1544 | goto querty_exit; |
| 1543 | } | 1545 | } |
| 1544 | 1546 | ||
| 1545 | err_buf = err_iov.iov_base; | 1547 | err_buf = err_iov.iov_base; |
| 1546 | if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct smb2_symlink_err_rsp) || | 1548 | if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct smb2_symlink_err_rsp) || |
| 1547 | err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE) { | 1549 | err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE) { |
| 1548 | kfree(utf16_path); | 1550 | rc = -ENOENT; |
| 1549 | return -ENOENT; | 1551 | goto querty_exit; |
| 1550 | } | 1552 | } |
| 1551 | 1553 | ||
| 1552 | /* open must fail on symlink - reset rc */ | 1554 | /* open must fail on symlink - reset rc */ |
| @@ -1558,25 +1560,28 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 1558 | print_offset = le16_to_cpu(symlink->PrintNameOffset); | 1560 | print_offset = le16_to_cpu(symlink->PrintNameOffset); |
| 1559 | 1561 | ||
| 1560 | if (err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) { | 1562 | if (err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) { |
| 1561 | kfree(utf16_path); | 1563 | rc = -ENOENT; |
| 1562 | return -ENOENT; | 1564 | goto querty_exit; |
| 1563 | } | 1565 | } |
| 1564 | 1566 | ||
| 1565 | if (err_iov.iov_len < | 1567 | if (err_iov.iov_len < |
| 1566 | SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) { | 1568 | SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) { |
| 1567 | kfree(utf16_path); | 1569 | rc = -ENOENT; |
| 1568 | return -ENOENT; | 1570 | goto querty_exit; |
| 1569 | } | 1571 | } |
| 1570 | 1572 | ||
| 1571 | *target_path = cifs_strndup_from_utf16( | 1573 | *target_path = cifs_strndup_from_utf16( |
| 1572 | (char *)symlink->PathBuffer + sub_offset, | 1574 | (char *)symlink->PathBuffer + sub_offset, |
| 1573 | sub_len, true, cifs_sb->local_nls); | 1575 | sub_len, true, cifs_sb->local_nls); |
| 1574 | if (!(*target_path)) { | 1576 | if (!(*target_path)) { |
| 1575 | kfree(utf16_path); | 1577 | rc = -ENOMEM; |
| 1576 | return -ENOMEM; | 1578 | goto querty_exit; |
| 1577 | } | 1579 | } |
| 1578 | convert_delimiter(*target_path, '/'); | 1580 | convert_delimiter(*target_path, '/'); |
| 1579 | cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); | 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 | kfree(utf16_path); | 1585 | kfree(utf16_path); |
| 1581 | return rc; | 1586 | return rc; |
| 1582 | } | 1587 | } |
| @@ -1649,7 +1654,7 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb, | |||
| 1649 | oparms.fid = &fid; | 1654 | oparms.fid = &fid; |
| 1650 | oparms.reconnect = false; | 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 | kfree(utf16_path); | 1658 | kfree(utf16_path); |
| 1654 | if (!rc) { | 1659 | if (!rc) { |
| 1655 | rc = SMB2_query_acl(xid, tlink_tcon(tlink), fid.persistent_fid, | 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, | |||
| 1712 | oparms.fid = &fid; | 1717 | oparms.fid = &fid; |
| 1713 | oparms.reconnect = false; | 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 | kfree(utf16_path); | 1721 | kfree(utf16_path); |
| 1717 | if (!rc) { | 1722 | if (!rc) { |
| 1718 | rc = SMB2_set_acl(xid, tlink_tcon(tlink), fid.persistent_fid, | 1723 | rc = SMB2_set_acl(xid, tlink_tcon(tlink), fid.persistent_fid, |
| @@ -2189,9 +2194,10 @@ init_sg(struct smb_rqst *rqst, u8 *sign) | |||
| 2189 | smb2_sg_set_buf(&sg[i], rqst->rq_iov[i+1].iov_base, | 2194 | smb2_sg_set_buf(&sg[i], rqst->rq_iov[i+1].iov_base, |
| 2190 | rqst->rq_iov[i+1].iov_len); | 2195 | rqst->rq_iov[i+1].iov_len); |
| 2191 | for (j = 0; i < sg_len - 1; i++, j++) { | 2196 | for (j = 0; i < sg_len - 1; i++, j++) { |
| 2192 | unsigned int len = (j < rqst->rq_npages - 1) ? rqst->rq_pagesz | 2197 | unsigned int len, offset; |
| 2193 | : rqst->rq_tailsz; | 2198 | |
| 2194 | sg_set_page(&sg[i], rqst->rq_pages[j], len, 0); | 2199 | rqst_page_get_length(rqst, j, &len, &offset); |
| 2200 | sg_set_page(&sg[i], rqst->rq_pages[j], len, offset); | ||
| 2195 | } | 2201 | } |
| 2196 | smb2_sg_set_buf(&sg[sg_len - 1], sign, SMB2_SIGNATURE_SIZE); | 2202 | smb2_sg_set_buf(&sg[sg_len - 1], sign, SMB2_SIGNATURE_SIZE); |
| 2197 | return sg; | 2203 | return sg; |
| @@ -2229,7 +2235,7 @@ static int | |||
| 2229 | crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) | 2235 | crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) |
| 2230 | { | 2236 | { |
| 2231 | struct smb2_transform_hdr *tr_hdr = | 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 | unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; | 2239 | unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; |
| 2234 | int rc = 0; | 2240 | int rc = 0; |
| 2235 | struct scatterlist *sg; | 2241 | struct scatterlist *sg; |
| @@ -2338,6 +2344,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, | |||
| 2338 | return rc; | 2344 | return rc; |
| 2339 | 2345 | ||
| 2340 | new_rq->rq_pages = pages; | 2346 | new_rq->rq_pages = pages; |
| 2347 | new_rq->rq_offset = old_rq->rq_offset; | ||
| 2341 | new_rq->rq_npages = old_rq->rq_npages; | 2348 | new_rq->rq_npages = old_rq->rq_npages; |
| 2342 | new_rq->rq_pagesz = old_rq->rq_pagesz; | 2349 | new_rq->rq_pagesz = old_rq->rq_pagesz; |
| 2343 | new_rq->rq_tailsz = old_rq->rq_tailsz; | 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, | |||
| 2379 | 2386 | ||
| 2380 | /* copy pages form the old */ | 2387 | /* copy pages form the old */ |
| 2381 | for (i = 0; i < npages; i++) { | 2388 | for (i = 0; i < npages; i++) { |
| 2382 | char *dst = kmap(new_rq->rq_pages[i]); | 2389 | char *dst, *src; |
| 2383 | char *src = kmap(old_rq->rq_pages[i]); | 2390 | unsigned int offset, len; |
| 2384 | unsigned int len = (i < npages - 1) ? new_rq->rq_pagesz : | 2391 | |
| 2385 | new_rq->rq_tailsz; | 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 | memcpy(dst, src, len); | 2397 | memcpy(dst, src, len); |
| 2387 | kunmap(new_rq->rq_pages[i]); | 2398 | kunmap(new_rq->rq_pages[i]); |
| 2388 | kunmap(old_rq->rq_pages[i]); | 2399 | kunmap(old_rq->rq_pages[i]); |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 281fbc1dc720..48e2004c75fb 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
| @@ -1889,7 +1889,7 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len, | |||
| 1889 | int | 1889 | int |
| 1890 | SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, | 1890 | SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, |
| 1891 | __u8 *oplock, struct smb2_file_all_info *buf, | 1891 | __u8 *oplock, struct smb2_file_all_info *buf, |
| 1892 | struct kvec *err_iov) | 1892 | struct kvec *err_iov, int *buftype) |
| 1893 | { | 1893 | { |
| 1894 | struct smb2_create_req *req; | 1894 | struct smb2_create_req *req; |
| 1895 | struct smb2_create_rsp *rsp; | 1895 | struct smb2_create_rsp *rsp; |
| @@ -2052,6 +2052,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, | |||
| 2052 | cifs_stats_fail_inc(tcon, SMB2_CREATE_HE); | 2052 | cifs_stats_fail_inc(tcon, SMB2_CREATE_HE); |
| 2053 | if (err_iov && rsp) { | 2053 | if (err_iov && rsp) { |
| 2054 | *err_iov = rsp_iov; | 2054 | *err_iov = rsp_iov; |
| 2055 | *buftype = resp_buftype; | ||
| 2055 | resp_buftype = CIFS_NO_BUFFER; | 2056 | resp_buftype = CIFS_NO_BUFFER; |
| 2056 | rsp = NULL; | 2057 | rsp = NULL; |
| 2057 | } | 2058 | } |
| @@ -2492,8 +2493,7 @@ SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 2492 | 2493 | ||
| 2493 | return query_info(xid, tcon, persistent_fid, volatile_fid, | 2494 | return query_info(xid, tcon, persistent_fid, volatile_fid, |
| 2494 | 0, SMB2_O_INFO_SECURITY, additional_info, | 2495 | 0, SMB2_O_INFO_SECURITY, additional_info, |
| 2495 | SMB2_MAX_BUFFER_SIZE, | 2496 | SMB2_MAX_BUFFER_SIZE, MIN_SEC_DESC_LEN, data, plen); |
| 2496 | sizeof(struct smb2_file_all_info), data, plen); | ||
| 2497 | } | 2497 | } |
| 2498 | 2498 | ||
| 2499 | int | 2499 | int |
| @@ -2721,8 +2721,8 @@ smb2_new_read_req(void **buf, unsigned int *total_len, | |||
| 2721 | 2721 | ||
| 2722 | rdata->mr = smbd_register_mr( | 2722 | rdata->mr = smbd_register_mr( |
| 2723 | server->smbd_conn, rdata->pages, | 2723 | server->smbd_conn, rdata->pages, |
| 2724 | rdata->nr_pages, rdata->tailsz, | 2724 | rdata->nr_pages, rdata->page_offset, |
| 2725 | true, need_invalidate); | 2725 | rdata->tailsz, true, need_invalidate); |
| 2726 | if (!rdata->mr) | 2726 | if (!rdata->mr) |
| 2727 | return -ENOBUFS; | 2727 | return -ENOBUFS; |
| 2728 | 2728 | ||
| @@ -3108,16 +3108,22 @@ smb2_async_writev(struct cifs_writedata *wdata, | |||
| 3108 | 3108 | ||
| 3109 | wdata->mr = smbd_register_mr( | 3109 | wdata->mr = smbd_register_mr( |
| 3110 | server->smbd_conn, wdata->pages, | 3110 | server->smbd_conn, wdata->pages, |
| 3111 | wdata->nr_pages, wdata->tailsz, | 3111 | wdata->nr_pages, wdata->page_offset, |
| 3112 | false, need_invalidate); | 3112 | wdata->tailsz, false, need_invalidate); |
| 3113 | if (!wdata->mr) { | 3113 | if (!wdata->mr) { |
| 3114 | rc = -ENOBUFS; | 3114 | rc = -ENOBUFS; |
| 3115 | goto async_writev_out; | 3115 | goto async_writev_out; |
| 3116 | } | 3116 | } |
| 3117 | req->Length = 0; | 3117 | req->Length = 0; |
| 3118 | req->DataOffset = 0; | 3118 | req->DataOffset = 0; |
| 3119 | req->RemainingBytes = | 3119 | if (wdata->nr_pages > 1) |
| 3120 | cpu_to_le32((wdata->nr_pages-1)*PAGE_SIZE + wdata->tailsz); | 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 | req->Channel = SMB2_CHANNEL_RDMA_V1_INVALIDATE; | 3127 | req->Channel = SMB2_CHANNEL_RDMA_V1_INVALIDATE; |
| 3122 | if (need_invalidate) | 3128 | if (need_invalidate) |
| 3123 | req->Channel = SMB2_CHANNEL_RDMA_V1; | 3129 | req->Channel = SMB2_CHANNEL_RDMA_V1; |
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 908555b1c6b5..c84020057bd8 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h | |||
| @@ -125,7 +125,7 @@ extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon); | |||
| 125 | extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, | 125 | extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, |
| 126 | __le16 *path, __u8 *oplock, | 126 | __le16 *path, __u8 *oplock, |
| 127 | struct smb2_file_all_info *buf, | 127 | struct smb2_file_all_info *buf, |
| 128 | struct kvec *err_iov); | 128 | struct kvec *err_iov, int *resp_buftype); |
| 129 | extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, | 129 | extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, |
| 130 | u64 persistent_fid, u64 volatile_fid, u32 opcode, | 130 | u64 persistent_fid, u64 volatile_fid, u32 opcode, |
| 131 | bool is_fsctl, char *in_data, u32 indatalen, | 131 | bool is_fsctl, char *in_data, u32 indatalen, |
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 2c671123a6bf..349d5ccf854c 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c | |||
| @@ -171,7 +171,9 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | |||
| 171 | unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; | 171 | unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; |
| 172 | unsigned char *sigptr = smb2_signature; | 172 | unsigned char *sigptr = smb2_signature; |
| 173 | struct kvec *iov = rqst->rq_iov; | 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 | struct cifs_ses *ses; | 177 | struct cifs_ses *ses; |
| 176 | 178 | ||
| 177 | ses = smb2_find_smb_ses(server, shdr->SessionId); | 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) | |||
| 202 | return rc; | 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 | &server->secmech.sdeschmacsha256->shash); | 208 | &server->secmech.sdeschmacsha256->shash); |
| 207 | 209 | ||
| 208 | if (!rc) | 210 | if (!rc) |
| @@ -412,7 +414,9 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | |||
| 412 | unsigned char smb3_signature[SMB2_CMACAES_SIZE]; | 414 | unsigned char smb3_signature[SMB2_CMACAES_SIZE]; |
| 413 | unsigned char *sigptr = smb3_signature; | 415 | unsigned char *sigptr = smb3_signature; |
| 414 | struct kvec *iov = rqst->rq_iov; | 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 | struct cifs_ses *ses; | 420 | struct cifs_ses *ses; |
| 417 | 421 | ||
| 418 | ses = smb2_find_smb_ses(server, shdr->SessionId); | 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) | |||
| 443 | return rc; | 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 | &server->secmech.sdesccmacaes->shash); | 451 | &server->secmech.sdesccmacaes->shash); |
| 448 | 452 | ||
| 449 | if (!rc) | 453 | if (!rc) |
diff --git a/fs/cifs/smbdirect.c b/fs/cifs/smbdirect.c index c62f7c95683c..e459c97151b3 100644 --- a/fs/cifs/smbdirect.c +++ b/fs/cifs/smbdirect.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/highmem.h> | 17 | #include <linux/highmem.h> |
| 18 | #include "smbdirect.h" | 18 | #include "smbdirect.h" |
| 19 | #include "cifs_debug.h" | 19 | #include "cifs_debug.h" |
| 20 | #include "cifsproto.h" | ||
| 20 | 21 | ||
| 21 | static struct smbd_response *get_empty_queue_buffer( | 22 | static struct smbd_response *get_empty_queue_buffer( |
| 22 | struct smbd_connection *info); | 23 | struct smbd_connection *info); |
| @@ -2003,10 +2004,12 @@ read_rfc1002_done: | |||
| 2003 | * return value: actual data read | 2004 | * return value: actual data read |
| 2004 | */ | 2005 | */ |
| 2005 | static int smbd_recv_page(struct smbd_connection *info, | 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 | int ret; | 2010 | int ret; |
| 2009 | char *to_address; | 2011 | char *to_address; |
| 2012 | void *page_address; | ||
| 2010 | 2013 | ||
| 2011 | /* make sure we have the page ready for read */ | 2014 | /* make sure we have the page ready for read */ |
| 2012 | ret = wait_event_interruptible( | 2015 | ret = wait_event_interruptible( |
| @@ -2014,16 +2017,17 @@ static int smbd_recv_page(struct smbd_connection *info, | |||
| 2014 | info->reassembly_data_length >= to_read || | 2017 | info->reassembly_data_length >= to_read || |
| 2015 | info->transport_status != SMBD_CONNECTED); | 2018 | info->transport_status != SMBD_CONNECTED); |
| 2016 | if (ret) | 2019 | if (ret) |
| 2017 | return 0; | 2020 | return ret; |
| 2018 | 2021 | ||
| 2019 | /* now we can read from reassembly queue and not sleep */ | 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 | log_read(INFO, "reading from page=%p address=%p to_read=%d\n", | 2026 | log_read(INFO, "reading from page=%p address=%p to_read=%d\n", |
| 2023 | page, to_address, to_read); | 2027 | page, to_address, to_read); |
| 2024 | 2028 | ||
| 2025 | ret = smbd_recv_buf(info, to_address, to_read); | 2029 | ret = smbd_recv_buf(info, to_address, to_read); |
| 2026 | kunmap_atomic(to_address); | 2030 | kunmap_atomic(page_address); |
| 2027 | 2031 | ||
| 2028 | return ret; | 2032 | return ret; |
| 2029 | } | 2033 | } |
| @@ -2037,7 +2041,7 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg) | |||
| 2037 | { | 2041 | { |
| 2038 | char *buf; | 2042 | char *buf; |
| 2039 | struct page *page; | 2043 | struct page *page; |
| 2040 | unsigned int to_read; | 2044 | unsigned int to_read, page_offset; |
| 2041 | int rc; | 2045 | int rc; |
| 2042 | 2046 | ||
| 2043 | info->smbd_recv_pending++; | 2047 | info->smbd_recv_pending++; |
| @@ -2051,15 +2055,16 @@ int smbd_recv(struct smbd_connection *info, struct msghdr *msg) | |||
| 2051 | 2055 | ||
| 2052 | case READ | ITER_BVEC: | 2056 | case READ | ITER_BVEC: |
| 2053 | page = msg->msg_iter.bvec->bv_page; | 2057 | page = msg->msg_iter.bvec->bv_page; |
| 2058 | page_offset = msg->msg_iter.bvec->bv_offset; | ||
| 2054 | to_read = msg->msg_iter.bvec->bv_len; | 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 | break; | 2061 | break; |
| 2057 | 2062 | ||
| 2058 | default: | 2063 | default: |
| 2059 | /* It's a bug in upper layer to get there */ | 2064 | /* It's a bug in upper layer to get there */ |
| 2060 | cifs_dbg(VFS, "CIFS: invalid msg type %d\n", | 2065 | cifs_dbg(VFS, "CIFS: invalid msg type %d\n", |
| 2061 | msg->msg_iter.type); | 2066 | msg->msg_iter.type); |
| 2062 | rc = -EIO; | 2067 | rc = -EINVAL; |
| 2063 | } | 2068 | } |
| 2064 | 2069 | ||
| 2065 | info->smbd_recv_pending--; | 2070 | info->smbd_recv_pending--; |
| @@ -2082,7 +2087,7 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) | |||
| 2082 | struct kvec vec; | 2087 | struct kvec vec; |
| 2083 | int nvecs; | 2088 | int nvecs; |
| 2084 | int size; | 2089 | int size; |
| 2085 | int buflen = 0, remaining_data_length; | 2090 | unsigned int buflen = 0, remaining_data_length; |
| 2086 | int start, i, j; | 2091 | int start, i, j; |
| 2087 | int max_iov_size = | 2092 | int max_iov_size = |
| 2088 | info->max_send_size - sizeof(struct smbd_data_transfer); | 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) | |||
| 2113 | buflen += iov[i].iov_len; | 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 | if (rqst->rq_npages) { | 2126 | if (rqst->rq_npages) { |
| 2118 | buflen += rqst->rq_pagesz * (rqst->rq_npages - 1); | 2127 | if (rqst->rq_npages == 1) |
| 2119 | buflen += rqst->rq_tailsz; | 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 | if (buflen + sizeof(struct smbd_data_transfer) > | 2134 | if (buflen + sizeof(struct smbd_data_transfer) > |
| @@ -2213,8 +2225,9 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) | |||
| 2213 | 2225 | ||
| 2214 | /* now sending pages if there are any */ | 2226 | /* now sending pages if there are any */ |
| 2215 | for (i = 0; i < rqst->rq_npages; i++) { | 2227 | for (i = 0; i < rqst->rq_npages; i++) { |
| 2216 | buflen = (i == rqst->rq_npages-1) ? | 2228 | unsigned int offset; |
| 2217 | rqst->rq_tailsz : rqst->rq_pagesz; | 2229 | |
| 2230 | rqst_page_get_length(rqst, i, &buflen, &offset); | ||
| 2218 | nvecs = (buflen + max_iov_size - 1) / max_iov_size; | 2231 | nvecs = (buflen + max_iov_size - 1) / max_iov_size; |
| 2219 | log_write(INFO, "sending pages buflen=%d nvecs=%d\n", | 2232 | log_write(INFO, "sending pages buflen=%d nvecs=%d\n", |
| 2220 | buflen, nvecs); | 2233 | buflen, nvecs); |
| @@ -2225,9 +2238,11 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) | |||
| 2225 | remaining_data_length -= size; | 2238 | remaining_data_length -= size; |
| 2226 | log_write(INFO, "sending pages i=%d offset=%d size=%d" | 2239 | log_write(INFO, "sending pages i=%d offset=%d size=%d" |
| 2227 | " remaining_data_length=%d\n", | 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 | rc = smbd_post_send_page( | 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 | size, remaining_data_length); | 2246 | size, remaining_data_length); |
| 2232 | if (rc) | 2247 | if (rc) |
| 2233 | goto done; | 2248 | goto done; |
| @@ -2284,37 +2299,37 @@ static void smbd_mr_recovery_work(struct work_struct *work) | |||
| 2284 | if (smbdirect_mr->state == MR_INVALIDATED || | 2299 | if (smbdirect_mr->state == MR_INVALIDATED || |
| 2285 | smbdirect_mr->state == MR_ERROR) { | 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 | ib_dma_unmap_sg( | 2326 | ib_dma_unmap_sg( |
| 2289 | info->id->device, smbdirect_mr->sgl, | 2327 | info->id->device, smbdirect_mr->sgl, |
| 2290 | smbdirect_mr->sgl_count, | 2328 | smbdirect_mr->sgl_count, |
| 2291 | smbdirect_mr->dir); | 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( | 2331 | smbdirect_mr->state = MR_READY; |
| 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 | } | ||
| 2315 | 2332 | ||
| 2316 | smbdirect_mr->state = MR_READY; | ||
| 2317 | } | ||
| 2318 | /* smbdirect_mr->state is updated by this function | 2333 | /* smbdirect_mr->state is updated by this function |
| 2319 | * and is read and updated by I/O issuing CPUs trying | 2334 | * and is read and updated by I/O issuing CPUs trying |
| 2320 | * to get a MR, the call to atomic_inc_return | 2335 | * to get a MR, the call to atomic_inc_return |
| @@ -2460,7 +2475,7 @@ again: | |||
| 2460 | */ | 2475 | */ |
| 2461 | struct smbd_mr *smbd_register_mr( | 2476 | struct smbd_mr *smbd_register_mr( |
| 2462 | struct smbd_connection *info, struct page *pages[], int num_pages, | 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 | struct smbd_mr *smbdirect_mr; | 2480 | struct smbd_mr *smbdirect_mr; |
| 2466 | int rc, i; | 2481 | int rc, i; |
| @@ -2483,17 +2498,31 @@ struct smbd_mr *smbd_register_mr( | |||
| 2483 | smbdirect_mr->sgl_count = num_pages; | 2498 | smbdirect_mr->sgl_count = num_pages; |
| 2484 | sg_init_table(smbdirect_mr->sgl, num_pages); | 2499 | sg_init_table(smbdirect_mr->sgl, num_pages); |
| 2485 | 2500 | ||
| 2486 | for (i = 0; i < num_pages - 1; i++) | 2501 | log_rdma_mr(INFO, "num_pages=0x%x offset=0x%x tailsz=0x%x\n", |
| 2487 | sg_set_page(&smbdirect_mr->sgl[i], pages[i], PAGE_SIZE, 0); | 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 | sg_set_page(&smbdirect_mr->sgl[i], pages[i], | 2517 | sg_set_page(&smbdirect_mr->sgl[i], pages[i], |
| 2490 | tailsz ? tailsz : PAGE_SIZE, 0); | 2518 | tailsz ? tailsz : PAGE_SIZE, 0); |
| 2491 | 2519 | ||
| 2520 | skip_multiple_pages: | ||
| 2492 | dir = writing ? DMA_FROM_DEVICE : DMA_TO_DEVICE; | 2521 | dir = writing ? DMA_FROM_DEVICE : DMA_TO_DEVICE; |
| 2493 | smbdirect_mr->dir = dir; | 2522 | smbdirect_mr->dir = dir; |
| 2494 | rc = ib_dma_map_sg(info->id->device, smbdirect_mr->sgl, num_pages, dir); | 2523 | rc = ib_dma_map_sg(info->id->device, smbdirect_mr->sgl, num_pages, dir); |
| 2495 | if (!rc) { | 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 | num_pages, dir, rc); | 2526 | num_pages, dir, rc); |
| 2498 | goto dma_map_error; | 2527 | goto dma_map_error; |
| 2499 | } | 2528 | } |
| @@ -2501,8 +2530,8 @@ struct smbd_mr *smbd_register_mr( | |||
| 2501 | rc = ib_map_mr_sg(smbdirect_mr->mr, smbdirect_mr->sgl, num_pages, | 2530 | rc = ib_map_mr_sg(smbdirect_mr->mr, smbdirect_mr->sgl, num_pages, |
| 2502 | NULL, PAGE_SIZE); | 2531 | NULL, PAGE_SIZE); |
| 2503 | if (rc != num_pages) { | 2532 | if (rc != num_pages) { |
| 2504 | log_rdma_mr(INFO, | 2533 | log_rdma_mr(ERR, |
| 2505 | "ib_map_mr_sg failed rc = %x num_pages = %x\n", | 2534 | "ib_map_mr_sg failed rc = %d num_pages = %x\n", |
| 2506 | rc, num_pages); | 2535 | rc, num_pages); |
| 2507 | goto map_mr_error; | 2536 | goto map_mr_error; |
| 2508 | } | 2537 | } |
diff --git a/fs/cifs/smbdirect.h b/fs/cifs/smbdirect.h index f9038daea194..1e419c21dc60 100644 --- a/fs/cifs/smbdirect.h +++ b/fs/cifs/smbdirect.h | |||
| @@ -321,7 +321,7 @@ struct smbd_mr { | |||
| 321 | /* Interfaces to register and deregister MR for RDMA read/write */ | 321 | /* Interfaces to register and deregister MR for RDMA read/write */ |
| 322 | struct smbd_mr *smbd_register_mr( | 322 | struct smbd_mr *smbd_register_mr( |
| 323 | struct smbd_connection *info, struct page *pages[], int num_pages, | 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 | int smbd_deregister_mr(struct smbd_mr *mr); | 325 | int smbd_deregister_mr(struct smbd_mr *mr); |
| 326 | 326 | ||
| 327 | #else | 327 | #else |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index e7254e386b79..24887a0898c0 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
| @@ -212,10 +212,24 @@ rqst_len(struct smb_rqst *rqst) | |||
| 212 | for (i = 0; i < rqst->rq_nvec; i++) | 212 | for (i = 0; i < rqst->rq_nvec; i++) |
| 213 | buflen += iov[i].iov_len; | 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 | if (rqst->rq_npages) { | 221 | if (rqst->rq_npages) { |
| 217 | buflen += rqst->rq_pagesz * (rqst->rq_npages - 1); | 222 | if (rqst->rq_npages == 1) |
| 218 | buflen += rqst->rq_tailsz; | 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 | return buflen; | 235 | return buflen; |
| @@ -274,15 +288,13 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |||
| 274 | 288 | ||
| 275 | /* now walk the page array and send each page in it */ | 289 | /* now walk the page array and send each page in it */ |
| 276 | for (i = 0; i < rqst->rq_npages; i++) { | 290 | for (i = 0; i < rqst->rq_npages; i++) { |
| 277 | size_t len = i == rqst->rq_npages - 1 | 291 | struct bio_vec bvec; |
| 278 | ? rqst->rq_tailsz | 292 | |
| 279 | : rqst->rq_pagesz; | 293 | bvec.bv_page = rqst->rq_pages[i]; |
| 280 | struct bio_vec bvec = { | 294 | rqst_page_get_length(rqst, i, &bvec.bv_len, &bvec.bv_offset); |
| 281 | .bv_page = rqst->rq_pages[i], | 295 | |
| 282 | .bv_len = len | ||
| 283 | }; | ||
| 284 | iov_iter_bvec(&smb_msg.msg_iter, WRITE | ITER_BVEC, | 296 | iov_iter_bvec(&smb_msg.msg_iter, WRITE | ITER_BVEC, |
| 285 | &bvec, 1, len); | 297 | &bvec, 1, bvec.bv_len); |
| 286 | rc = smb_send_kvec(server, &smb_msg, &sent); | 298 | rc = smb_send_kvec(server, &smb_msg, &sent); |
| 287 | if (rc < 0) | 299 | if (rc < 0) |
| 288 | break; | 300 | break; |
