From ff361fda55fda55031252aca1f8afef735fe057c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 19 Jun 2018 15:25:30 +0300 Subject: cifs: Silence uninitialized variable warning This is not really a runtime issue but Smatch complains that: fs/cifs/smb2ops.c:1740 smb2_query_symlink() error: uninitialized symbol 'resp_buftype'. The warning is right that it can be uninitialized... Also "err_buf" would be NULL at this point and we're not supposed to pass NULLs to free_rsp_buf() or it might trigger some extra output if we turn on debugging. Signed-off-by: Dan Carpenter Reviewed-by: Paulo Alcantara Signed-off-by: Steve French --- fs/cifs/smb2ops.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index ea92a38b2f08..ae64cbef5e07 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1700,7 +1700,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, &resp_buftype); if (!rc || !err_iov.iov_base) { rc = -ENOENT; - goto querty_exit; + goto free_path; } err_buf = err_iov.iov_base; @@ -1741,6 +1741,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, querty_exit: free_rsp_buf(resp_buftype, err_buf); + free_path: kfree(utf16_path); return rc; } -- cgit v1.2.3 From 95390201e7d8dd1eb764a3cbd50ae538a17fcd02 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 19 Jun 2018 17:27:58 +0200 Subject: cifs: use timespec64 internally In cifs, the timestamps are stored in memory in the cifs_fattr structure, which uses the deprecated 'timespec' structure. Now that the VFS code has moved on to 'timespec64', the next step is to change over the fattr as well. This also makes 32-bit and 64-bit systems behave the same way, and no longer overflow the 32-bit time_t in year 2038. Signed-off-by: Arnd Bergmann Reviewed-by: Paulo Alcantara Signed-off-by: Steve French --- fs/cifs/cifsencrypt.c | 4 ++-- fs/cifs/cifsglob.h | 6 +++--- fs/cifs/cifsproto.h | 6 +++--- fs/cifs/cifssmb.c | 12 ++++++------ fs/cifs/inode.c | 34 ++++++++++++++++------------------ fs/cifs/netmisc.c | 19 ++++++++++--------- 6 files changed, 40 insertions(+), 41 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index ee2a8ec70056..b4672eafc5bf 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -452,7 +452,7 @@ find_timestamp(struct cifs_ses *ses) unsigned char *blobptr; unsigned char *blobend; struct ntlmssp2_name *attrptr; - struct timespec ts; + struct timespec64 ts; if (!ses->auth_key.len || !ses->auth_key.response) return 0; @@ -477,7 +477,7 @@ find_timestamp(struct cifs_ses *ses) blobptr += attrsize; /* advance attr value */ } - ktime_get_real_ts(&ts); + ktime_get_real_ts64(&ts); return cpu_to_le64(cifs_UnixTimeToNT(ts)); } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index c923c7854027..b57d1e22ecb5 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1544,9 +1544,9 @@ struct cifs_fattr { dev_t cf_rdev; unsigned int cf_nlink; unsigned int cf_dtype; - struct timespec cf_atime; - struct timespec cf_mtime; - struct timespec cf_ctime; + struct timespec64 cf_atime; + struct timespec64 cf_mtime; + struct timespec64 cf_ctime; }; static inline void free_dfs_info_param(struct dfs_info3_param *param) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 1890f534c88b..7ead1a9ac6fb 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -143,9 +143,9 @@ extern enum securityEnum select_sectype(struct TCP_Server_Info *server, enum securityEnum requested); extern int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses, const struct nls_table *nls_cp); -extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601); -extern u64 cifs_UnixTimeToNT(struct timespec); -extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, +extern struct timespec64 cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601); +extern u64 cifs_UnixTimeToNT(struct timespec64); +extern struct timespec64 cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset); extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock); extern int cifs_get_writer(struct cifsInodeInfo *cinode); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 93408eab92e7..dc2f4cf08fe9 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -508,13 +508,13 @@ decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr) * this requirement. */ int val, seconds, remain, result; - struct timespec ts; - unsigned long utc = ktime_get_real_seconds(); + struct timespec64 ts; + time64_t utc = ktime_get_real_seconds(); ts = cnvrtDosUnixTm(rsp->SrvTime.Date, rsp->SrvTime.Time, 0); - cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n", - (int)ts.tv_sec, (int)utc, - (int)(utc - ts.tv_sec)); + cifs_dbg(FYI, "SrvTime %lld sec since 1970 (utc: %lld) diff: %lld\n", + ts.tv_sec, utc, + utc - ts.tv_sec); val = (int)(utc - ts.tv_sec); seconds = abs(val); result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ; @@ -4082,7 +4082,7 @@ QInfRetry: if (rc) { cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc); } else if (data) { - struct timespec ts; + struct timespec64 ts; __u32 time = le32_to_cpu(pSMBr->last_write_time); /* decode response */ diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index a2cfb33e85c1..f6abf18ca492 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -95,7 +95,6 @@ static void cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr) { struct cifsInodeInfo *cifs_i = CIFS_I(inode); - struct timespec ts; cifs_dbg(FYI, "%s: revalidating inode %llu\n", __func__, cifs_i->uniqueid); @@ -114,8 +113,7 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr) } /* revalidate if mtime or size have changed */ - ts = timespec64_to_timespec(inode->i_mtime); - if (timespec_equal(&ts, &fattr->cf_mtime) && + if (timespec64_equal(&inode->i_mtime, &fattr->cf_mtime) && cifs_i->server_eof == fattr->cf_eof) { cifs_dbg(FYI, "%s: inode %llu is unchanged\n", __func__, cifs_i->uniqueid); @@ -164,9 +162,9 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) cifs_revalidate_cache(inode, fattr); spin_lock(&inode->i_lock); - inode->i_atime = timespec_to_timespec64(fattr->cf_atime); - inode->i_mtime = timespec_to_timespec64(fattr->cf_mtime); - inode->i_ctime = timespec_to_timespec64(fattr->cf_ctime); + inode->i_atime = fattr->cf_atime; + inode->i_mtime = fattr->cf_mtime; + inode->i_ctime = fattr->cf_ctime; inode->i_rdev = fattr->cf_rdev; cifs_nlink_fattr_to_inode(inode, fattr); inode->i_uid = fattr->cf_uid; @@ -327,8 +325,8 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb) fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU; fattr->cf_uid = cifs_sb->mnt_uid; fattr->cf_gid = cifs_sb->mnt_gid; - ktime_get_real_ts(&fattr->cf_mtime); - fattr->cf_mtime = timespec_trunc(fattr->cf_mtime, sb->s_time_gran); + ktime_get_real_ts64(&fattr->cf_mtime); + fattr->cf_mtime = timespec64_trunc(fattr->cf_mtime, sb->s_time_gran); fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime; fattr->cf_nlink = 2; fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL; @@ -604,8 +602,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, if (info->LastAccessTime) fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); else { - ktime_get_real_ts(&fattr->cf_atime); - fattr->cf_atime = timespec_trunc(fattr->cf_atime, sb->s_time_gran); + ktime_get_real_ts64(&fattr->cf_atime); + fattr->cf_atime = timespec64_trunc(fattr->cf_atime, sb->s_time_gran); } fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); @@ -1125,14 +1123,14 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid, if (attrs->ia_valid & ATTR_ATIME) { set_time = true; info_buf.LastAccessTime = - cpu_to_le64(cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_atime))); + cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); } else info_buf.LastAccessTime = 0; if (attrs->ia_valid & ATTR_MTIME) { set_time = true; info_buf.LastWriteTime = - cpu_to_le64(cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_mtime))); + cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); } else info_buf.LastWriteTime = 0; @@ -1145,7 +1143,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid, if (set_time && (attrs->ia_valid & ATTR_CTIME)) { cifs_dbg(FYI, "CIFS - CTIME changed\n"); info_buf.ChangeTime = - cpu_to_le64(cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_ctime))); + cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); } else info_buf.ChangeTime = 0; @@ -2071,8 +2069,8 @@ int cifs_getattr(const struct path *path, struct kstat *stat, /* old CIFS Unix Extensions doesn't return create time */ if (CIFS_I(inode)->createtime) { stat->result_mask |= STATX_BTIME; - stat->btime = timespec_to_timespec64( - cifs_NTtimeToUnix(cpu_to_le64(CIFS_I(inode)->createtime))); + stat->btime = + cifs_NTtimeToUnix(cpu_to_le64(CIFS_I(inode)->createtime)); } stat->attributes_mask |= (STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED); @@ -2278,17 +2276,17 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) args->gid = INVALID_GID; /* no change */ if (attrs->ia_valid & ATTR_ATIME) - args->atime = cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_atime)); + args->atime = cifs_UnixTimeToNT(attrs->ia_atime); else args->atime = NO_CHANGE_64; if (attrs->ia_valid & ATTR_MTIME) - args->mtime = cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_mtime)); + args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime); else args->mtime = NO_CHANGE_64; if (attrs->ia_valid & ATTR_CTIME) - args->ctime = cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_ctime)); + args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime); else args->ctime = NO_CHANGE_64; diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index d7ad0dfe4e68..fdd908e4a26b 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -918,10 +918,10 @@ smbCalcSize(void *buf, struct TCP_Server_Info *server) * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units) * into Unix UTC (based 1970-01-01, in seconds). */ -struct timespec +struct timespec64 cifs_NTtimeToUnix(__le64 ntutc) { - struct timespec ts; + struct timespec64 ts; /* BB what about the timezone? BB */ /* Subtract the NTFS time offset, then convert to 1s intervals. */ @@ -935,12 +935,12 @@ cifs_NTtimeToUnix(__le64 ntutc) */ if (t < 0) { abs_t = -t; - ts.tv_nsec = (long)(do_div(abs_t, 10000000) * 100); + ts.tv_nsec = (time64_t)(do_div(abs_t, 10000000) * 100); ts.tv_nsec = -ts.tv_nsec; ts.tv_sec = -abs_t; } else { abs_t = t; - ts.tv_nsec = (long)do_div(abs_t, 10000000) * 100; + ts.tv_nsec = (time64_t)do_div(abs_t, 10000000) * 100; ts.tv_sec = abs_t; } @@ -949,7 +949,7 @@ cifs_NTtimeToUnix(__le64 ntutc) /* Convert the Unix UTC into NT UTC. */ u64 -cifs_UnixTimeToNT(struct timespec t) +cifs_UnixTimeToNT(struct timespec64 t) { /* Convert to 100ns intervals and then add the NTFS time offset. */ return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET; @@ -959,10 +959,11 @@ static const int total_days_of_prev_months[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; -struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset) +struct timespec64 cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset) { - struct timespec ts; - int sec, min, days, month, year; + struct timespec64 ts; + time64_t sec; + int min, days, month, year; u16 date = le16_to_cpu(le_date); u16 time = le16_to_cpu(le_time); SMB_TIME *st = (SMB_TIME *)&time; @@ -973,7 +974,7 @@ struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset) sec = 2 * st->TwoSeconds; min = st->Minutes; if ((sec > 59) || (min > 59)) - cifs_dbg(VFS, "illegal time min %d sec %d\n", min, sec); + cifs_dbg(VFS, "illegal time min %d sec %lld\n", min, sec); sec += (min * 60); sec += 60 * 60 * st->Hours; if (st->Hours > 24) -- cgit v1.2.3 From cbedeadf9c44a1a135293717d501882f2933a534 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 19 Jun 2018 17:27:59 +0200 Subject: cifs: use 64-bit timestamps for fscache In the fscache, we just need the timestamps as cookies to check for changes, so we don't really care about the overflow, but it's better to stop using the deprecated timespec so we don't have to go through explicit conversion functions. To avoid comparing uninitialized padding values that are copied while assigning the timespec values, this rearranges the members of cifs_fscache_inode_auxdata to avoid padding, and assigns them individually. Signed-off-by: Arnd Bergmann Reviewed-by: Paulo Alcantara Signed-off-by: Steve French --- fs/cifs/cache.c | 6 ++++-- fs/cifs/fscache.c | 12 ++++++++---- fs/cifs/fscache.h | 8 +++++--- 3 files changed, 17 insertions(+), 9 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c index e1553d1e0e50..b7420e605b28 100644 --- a/fs/cifs/cache.c +++ b/fs/cifs/cache.c @@ -128,8 +128,10 @@ fscache_checkaux cifs_fscache_inode_check_aux(void *cookie_netfs_data, memset(&auxdata, 0, sizeof(auxdata)); auxdata.eof = cifsi->server_eof; - auxdata.last_write_time = timespec64_to_timespec(cifsi->vfs_inode.i_mtime); - auxdata.last_change_time = timespec64_to_timespec(cifsi->vfs_inode.i_ctime); + auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec; + auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec; + auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec; + auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec; if (memcmp(data, &auxdata, datalen) != 0) return FSCACHE_CHECKAUX_OBSOLETE; diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c index 85145a763021..ea6ace9c2417 100644 --- a/fs/cifs/fscache.c +++ b/fs/cifs/fscache.c @@ -129,8 +129,10 @@ static void cifs_fscache_acquire_inode_cookie(struct cifsInodeInfo *cifsi, memset(&auxdata, 0, sizeof(auxdata)); auxdata.eof = cifsi->server_eof; - auxdata.last_write_time = timespec64_to_timespec(cifsi->vfs_inode.i_mtime); - auxdata.last_change_time = timespec64_to_timespec(cifsi->vfs_inode.i_ctime); + auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec; + auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec; + auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec; + auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec; cifsi->fscache = fscache_acquire_cookie(tcon->fscache, @@ -166,8 +168,10 @@ void cifs_fscache_release_inode_cookie(struct inode *inode) if (cifsi->fscache) { memset(&auxdata, 0, sizeof(auxdata)); auxdata.eof = cifsi->server_eof; - auxdata.last_write_time = timespec64_to_timespec(cifsi->vfs_inode.i_mtime); - auxdata.last_change_time = timespec64_to_timespec(cifsi->vfs_inode.i_ctime); + auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec; + auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec; + auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec; + auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec; cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache); fscache_relinquish_cookie(cifsi->fscache, &auxdata, false); diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h index c7e3ac251e16..8c0862e41306 100644 --- a/fs/cifs/fscache.h +++ b/fs/cifs/fscache.h @@ -31,9 +31,11 @@ * Auxiliary data attached to CIFS inode within the cache */ struct cifs_fscache_inode_auxdata { - struct timespec last_write_time; - struct timespec last_change_time; - u64 eof; + u64 last_write_time_sec; + u64 last_change_time_sec; + u32 last_write_time_nsec; + u32 last_change_time_nsec; + u64 eof; }; /* -- cgit v1.2.3 From 8505c8bfd85a260c9dc5c47e15bd8c5357fcbcd2 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 18 Jun 2018 14:01:59 -0500 Subject: smb3: if server does not support posix do not allow posix mount option If user specifies "posix" on an SMB3.11 mount, then fail the mount if server does not return the POSIX negotiate context indicating support for posix. Signed-off-by: Steve French Reviewed-by: Aurelien Aptel --- fs/cifs/connect.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 5df2c0698cda..9d02563b2147 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3031,11 +3031,15 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) } #ifdef CONFIG_CIFS_SMB311 - if ((volume_info->linux_ext) && (ses->server->posix_ext_supported)) { - if (ses->server->vals->protocol_id == SMB311_PROT_ID) { + if (volume_info->linux_ext) { + if (ses->server->posix_ext_supported) { tcon->posix_extensions = true; printk_once(KERN_WARNING "SMB3.11 POSIX Extensions are experimental\n"); + } else { + cifs_dbg(VFS, "Server does not support mounting with posix SMB3.11 extensions.\n"); + rc = -EOPNOTSUPP; + goto out_fail; } } #endif /* 311 */ -- cgit v1.2.3 From 7420451f6a109f7f8f1bf283f34d08eba3259fb3 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 19 Jun 2018 14:34:08 -0500 Subject: cifs: allow disabling insecure dialects in the config allow disabling cifs (SMB1 ie vers=1.0) and vers=2.0 in the config for the build of cifs.ko if want to always prevent mounting with these less secure dialects. Signed-off-by: Steve French Reviewed-by: Aurelien Aptel Reviewed-by: Jeremy Allison --- fs/cifs/Kconfig | 17 ++++++++++++++++- fs/cifs/connect.c | 9 +++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 5f132d59dfc2..832eafbf803f 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -66,9 +66,24 @@ config CIFS_STATS2 Unless you are a developer or are doing network performance analysis or tuning, say N. +config CIFS_ALLOW_INSECURE_LEGACY + bool "Support legacy servers which use less secure dialects" + depends on CIFS + default y + help + Modern dialects, SMB2.1 and later (including SMB3 and 3.1.1), have + additional security features, including protection against + man-in-the-middle attacks and stronger crypto hashes, so the use + of legacy dialects (SMB1/CIFS and SMB2.0) is discouraged. + + Disabling this option prevents users from using vers=1.0 or vers=2.0 + on mounts with cifs.ko + + If unsure, say Y. + config CIFS_WEAK_PW_HASH bool "Support legacy servers which use weaker LANMAN security" - depends on CIFS + depends on CIFS && CIFS_ALLOW_INSECURE_LEGACY help Modern CIFS servers including Samba and most Windows versions (since 1997) support stronger NTLM (and even NTLMv2 and Kerberos) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 9d02563b2147..842f45859968 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1174,6 +1174,7 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3) substring_t args[MAX_OPT_ARGS]; switch (match_token(value, cifs_smb_version_tokens, args)) { +#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY case Smb_1: if (disable_legacy_dialects) { cifs_dbg(VFS, "mount with legacy dialect disabled\n"); @@ -1198,6 +1199,14 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3) vol->ops = &smb20_operations; vol->vals = &smb20_values; break; +#else + case Smb_1: + cifs_dbg(VFS, "vers=1.0 (cifs) mount not permitted when legacy dialects disabled\n"); + return 1; + case Smb_20: + cifs_dbg(VFS, "vers=2.0 mount not permitted when legacy dialects disabled\n"); + return 1; +#endif /* CIFS_ALLOW_INSECURE_LEGACY */ case Smb_21: vol->ops = &smb21_operations; vol->vals = &smb21_values; -- cgit v1.2.3 From 256b4c3f03d77d8c0dc69e3a6ceb3afd0d1810bd Mon Sep 17 00:00:00 2001 From: Aurelien Aptel Date: Tue, 19 Jun 2018 15:18:48 -0700 Subject: CIFS: fix memory leak and remove dead code also fixes error code in smb311_posix_mkdir() (where the error assignment needs to go before the goto) a typo that Dan Carpenter and Paulo and Gustavo pointed out. Signed-off-by: Aurelien Aptel Signed-off-by: Dan Carpenter Signed-off-by: Gustavo A. R. Silva Reviewed-by: Paulo Alcantara Signed-off-by: Steve French --- fs/cifs/smb2pdu.c | 101 +++++++++++++++++++++++++++--------------------------- 1 file changed, 50 insertions(+), 51 deletions(-) (limited to 'fs') diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 3c92678cb45b..641fe79708d0 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1928,7 +1928,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, { struct smb_rqst rqst; struct smb2_create_req *req; - struct smb2_create_rsp *rsp; + struct smb2_create_rsp *rsp = NULL; struct TCP_Server_Info *server; struct cifs_ses *ses = tcon->ses; struct kvec iov[3]; /* make sure at least one for each open context */ @@ -1943,27 +1943,31 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, char *pc_buf = NULL; int flags = 0; unsigned int total_len; - __le16 *path = cifs_convert_path_to_utf16(full_path, cifs_sb); - - if (!path) - return -ENOMEM; + __le16 *utf16_path = NULL; cifs_dbg(FYI, "mkdir\n"); + /* resource #1: path allocation */ + utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb); + if (!utf16_path) + return -ENOMEM; + if (ses && (ses->server)) server = ses->server; - else - return -EIO; + else { + rc = -EIO; + goto err_free_path; + } + /* resource #2: request */ rc = smb2_plain_req_init(SMB2_CREATE, tcon, (void **) &req, &total_len); - if (rc) - return rc; + goto err_free_path; + if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; - req->ImpersonationLevel = IL_IMPERSONATION; req->DesiredAccess = cpu_to_le32(FILE_WRITE_ATTRIBUTES); /* File attributes ignored on open (used in create though) */ @@ -1992,50 +1996,44 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, req->sync_hdr.Flags |= SMB2_FLAGS_DFS_OPERATIONS; rc = alloc_path_with_tree_prefix(©_path, ©_size, &name_len, - tcon->treeName, path); - if (rc) { - cifs_small_buf_release(req); - return rc; - } + tcon->treeName, utf16_path); + if (rc) + goto err_free_req; + req->NameLength = cpu_to_le16(name_len * 2); uni_path_len = copy_size; - path = copy_path; + /* free before overwriting resource */ + kfree(utf16_path); + utf16_path = copy_path; } else { - uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2; + uni_path_len = (2 * UniStrnlen((wchar_t *)utf16_path, PATH_MAX)) + 2; /* MUST set path len (NameLength) to 0 opening root of share */ req->NameLength = cpu_to_le16(uni_path_len - 2); if (uni_path_len % 8 != 0) { copy_size = roundup(uni_path_len, 8); copy_path = kzalloc(copy_size, GFP_KERNEL); if (!copy_path) { - cifs_small_buf_release(req); - return -ENOMEM; + rc = -ENOMEM; + goto err_free_req; } - memcpy((char *)copy_path, (const char *)path, + memcpy((char *)copy_path, (const char *)utf16_path, uni_path_len); uni_path_len = copy_size; - path = copy_path; + /* free before overwriting resource */ + kfree(utf16_path); + utf16_path = copy_path; } } iov[1].iov_len = uni_path_len; - iov[1].iov_base = path; + iov[1].iov_base = utf16_path; req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE; if (tcon->posix_extensions) { - if (n_iov > 2) { - struct create_context *ccontext = - (struct create_context *)iov[n_iov-1].iov_base; - ccontext->Next = - cpu_to_le32(iov[n_iov-1].iov_len); - } - + /* resource #3: posix buf */ rc = add_posix_context(iov, &n_iov, mode); - if (rc) { - cifs_small_buf_release(req); - kfree(copy_path); - return rc; - } + if (rc) + goto err_free_req; pc_buf = iov[n_iov-1].iov_base; } @@ -2044,32 +2042,33 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, rqst.rq_iov = iov; rqst.rq_nvec = n_iov; - rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, - &rsp_iov); - - cifs_small_buf_release(req); - rsp = (struct smb2_create_rsp *)rsp_iov.iov_base; - - if (rc != 0) { + /* resource #4: response buffer */ + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); + if (rc) { cifs_stats_fail_inc(tcon, SMB2_CREATE_HE); trace_smb3_posix_mkdir_err(xid, tcon->tid, ses->Suid, - CREATE_NOT_FILE, FILE_WRITE_ATTRIBUTES, rc); - goto smb311_mkdir_exit; - } else - trace_smb3_posix_mkdir_done(xid, rsp->PersistentFileId, tcon->tid, - ses->Suid, CREATE_NOT_FILE, - FILE_WRITE_ATTRIBUTES); + CREATE_NOT_FILE, + FILE_WRITE_ATTRIBUTES, rc); + goto err_free_rsp_buf; + } + + rsp = (struct smb2_create_rsp *)rsp_iov.iov_base; + trace_smb3_posix_mkdir_done(xid, rsp->PersistentFileId, tcon->tid, + ses->Suid, CREATE_NOT_FILE, + FILE_WRITE_ATTRIBUTES); SMB2_close(xid, tcon, rsp->PersistentFileId, rsp->VolatileFileId); /* Eventually save off posix specific response info and timestaps */ -smb311_mkdir_exit: - kfree(copy_path); - kfree(pc_buf); +err_free_rsp_buf: free_rsp_buf(resp_buftype, rsp); + kfree(pc_buf); +err_free_req: + cifs_small_buf_release(req); +err_free_path: + kfree(utf16_path); return rc; - } #endif /* SMB311 */ -- cgit v1.2.3 From a12d0c590cc7ae01892f06c5ad6d19580ecdd0de Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Sat, 23 Jun 2018 14:52:25 -0300 Subject: cifs: Make sure all data pages are signed correctly Check if every data page is signed correctly in sigining helper. Signed-off-by: Paulo Alcantara Reviewed-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cifsencrypt.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index b4672eafc5bf..85b31cfa2f3c 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -83,7 +83,13 @@ int __cifs_calc_signature(struct smb_rqst *rqst, kaddr = (char *) kmap(rqst->rq_pages[i]) + offset; - crypto_shash_update(shash, kaddr, len); + rc = crypto_shash_update(shash, kaddr, len); + if (rc) { + cifs_dbg(VFS, "%s: Could not update with payload\n", + __func__); + kunmap(rqst->rq_pages[i]); + return rc; + } kunmap(rqst->rq_pages[i]); } -- cgit v1.2.3 From 21ba3845b59c733a79ed4fe1c4f3732e7ece9df7 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 24 Jun 2018 23:18:52 -0500 Subject: smb3: fill in statfs fsid and correct namelen Fil in the correct namelen (typically 255 not 4096) in the statfs response and also fill in a reasonably unique fsid (in this case taken from the volume id, and the creation time of the volume). In the case of the POSIX statfs all fields are now filled in, and in the case of non-POSIX mounts, all fields are filled in which can be. Signed-off-by: Steve French CC: Stable Reviewed-by: Aurelien Aptel --- fs/cifs/cifsfs.c | 18 ++++++++++-------- fs/cifs/smb2ops.c | 2 ++ fs/cifs/smb2pdu.c | 8 ++++++++ fs/cifs/smb2pdu.h | 11 +++++++++++ 4 files changed, 31 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index d5aa7ae917bf..69ec5427769c 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -209,14 +209,16 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) xid = get_xid(); - /* - * PATH_MAX may be too long - it would presumably be total path, - * but note that some servers (includinng Samba 3) have a shorter - * maximum path. - * - * Instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO. - */ - buf->f_namelen = PATH_MAX; + if (le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength) > 0) + buf->f_namelen = + le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength); + else + buf->f_namelen = PATH_MAX; + + buf->f_fsid.val[0] = tcon->vol_serial_number; + /* are using part of create time for more randomness, see man statfs */ + buf->f_fsid.val[1] = (int)le64_to_cpu(tcon->vol_create_time); + buf->f_files = 0; /* undefined */ buf->f_ffree = 0; /* unlimited */ diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index ae64cbef5e07..09506d918ecb 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -548,6 +548,8 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon) FS_ATTRIBUTE_INFORMATION); SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid, FS_DEVICE_INFORMATION); + SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid, + FS_VOLUME_INFORMATION); SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid, FS_SECTOR_SIZE_INFORMATION); /* SMB3 specific */ if (no_cached_open) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 641fe79708d0..6852ff5f06be 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -4045,6 +4045,9 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, } else if (level == FS_SECTOR_SIZE_INFORMATION) { max_len = sizeof(struct smb3_fs_ss_info); min_len = sizeof(struct smb3_fs_ss_info); + } else if (level == FS_VOLUME_INFORMATION) { + max_len = sizeof(struct smb3_fs_vol_info) + MAX_VOL_LABEL_LEN; + min_len = sizeof(struct smb3_fs_vol_info); } else { cifs_dbg(FYI, "Invalid qfsinfo level %d\n", level); return -EINVAL; @@ -4089,6 +4092,11 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, tcon->ss_flags = le32_to_cpu(ss_info->Flags); tcon->perf_sector_size = le32_to_cpu(ss_info->PhysicalBytesPerSectorForPerf); + } else if (level == FS_VOLUME_INFORMATION) { + struct smb3_fs_vol_info *vol_info = (struct smb3_fs_vol_info *) + (offset + (char *)rsp); + tcon->vol_serial_number = vol_info->VolumeSerialNumber; + tcon->vol_create_time = vol_info->VolumeCreationTime; } qfsattr_exit: diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index a671adcc44a6..c2a4526512b5 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -1248,6 +1248,17 @@ struct smb3_fs_ss_info { __le32 ByteOffsetForPartitionAlignment; } __packed; +/* volume info struct - see MS-FSCC 2.5.9 */ +#define MAX_VOL_LABEL_LEN 32 +struct smb3_fs_vol_info { + __le64 VolumeCreationTime; + __u32 VolumeSerialNumber; + __le32 VolumeLabelLength; /* includes trailing null */ + __u8 SupportsObjects; /* True if eg like NTFS, supports objects */ + __u8 Reserved; + __u8 VolumeLabel[0]; /* variable len */ +} __packed; + /* partial list of QUERY INFO levels */ #define FILE_DIRECTORY_INFORMATION 1 #define FILE_FULL_DIRECTORY_INFORMATION 2 -- cgit v1.2.3 From 2d304217832ea720337e7a6aa012aa828a77f9d4 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 24 Jun 2018 23:28:12 -0500 Subject: smb3: add support for statfs for smb3.1.1 posix extensions Output now matches expected stat -f output for all fields except for Namelen and ID which were addressed in a companion patch (which retrieves them from existing SMB3 mechanisms and works whether POSIX enabled or not) Signed-off-by: Steve French Reviewed-by: Aurelien Aptel --- fs/cifs/smb2ops.c | 35 +++++++++++++++++++++++++- fs/cifs/smb2pdu.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb2pdu.h | 1 + fs/cifs/smb2proto.h | 3 +++ 4 files changed, 109 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 09506d918ecb..e2a8b9d90ad8 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1533,6 +1533,39 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon, return rc; } +#ifdef CONFIG_CIFS_SMB311 +static int +smb311_queryfs(const unsigned int xid, struct cifs_tcon *tcon, + struct kstatfs *buf) +{ + int rc; + __le16 srch_path = 0; /* Null - open root of share */ + u8 oplock = SMB2_OPLOCK_LEVEL_NONE; + struct cifs_open_parms oparms; + struct cifs_fid fid; + + if (!tcon->posix_extensions) + return smb2_queryfs(xid, tcon, buf); + + oparms.tcon = tcon; + oparms.desired_access = FILE_READ_ATTRIBUTES; + oparms.disposition = FILE_OPEN; + oparms.create_options = 0; + oparms.fid = &fid; + oparms.reconnect = false; + + rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, NULL); + if (rc) + return rc; + + rc = SMB311_posix_qfs_info(xid, tcon, fid.persistent_fid, + fid.volatile_fid, buf); + buf->f_type = SMB2_MAGIC_NUMBER; + SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); + return rc; +} +#endif /* SMB311 */ + static bool smb2_compare_fids(struct cifsFileInfo *ob1, struct cifsFileInfo *ob2) { @@ -3338,7 +3371,7 @@ struct smb_version_operations smb311_operations = { .is_status_pending = smb2_is_status_pending, .is_session_expired = smb2_is_session_expired, .oplock_response = smb2_oplock_response, - .queryfs = smb2_queryfs, + .queryfs = smb311_queryfs, .mand_lock = smb2_mand_lock, .mand_unlock_range = smb2_unlock_range, .push_mand_locks = smb2_push_mandatory_locks, diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 6852ff5f06be..fa9fc3fab60e 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -3938,6 +3938,27 @@ copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf, return; } +#ifdef CONFIG_CIFS_SMB311 +static void +copy_posix_fs_info_to_kstatfs(FILE_SYSTEM_POSIX_INFO *response_data, + struct kstatfs *kst) +{ + kst->f_bsize = le32_to_cpu(response_data->BlockSize); + kst->f_blocks = le64_to_cpu(response_data->TotalBlocks); + kst->f_bfree = le64_to_cpu(response_data->BlocksAvail); + if (response_data->UserBlocksAvail == cpu_to_le64(-1)) + kst->f_bavail = kst->f_bfree; + else + kst->f_bavail = le64_to_cpu(response_data->UserBlocksAvail); + if (response_data->TotalFileNodes != cpu_to_le64(-1)) + kst->f_files = le64_to_cpu(response_data->TotalFileNodes); + if (response_data->FreeFileNodes != cpu_to_le64(-1)) + kst->f_ffree = le64_to_cpu(response_data->FreeFileNodes); + + return; +} +#endif /* SMB311 */ + static int build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level, int outbuf_len, u64 persistent_fid, u64 volatile_fid) @@ -3974,6 +3995,56 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level, return 0; } +#ifdef CONFIG_CIFS_SMB311 +int +SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon, + u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata) +{ + struct smb_rqst rqst; + struct smb2_query_info_rsp *rsp = NULL; + struct kvec iov; + struct kvec rsp_iov; + int rc = 0; + int resp_buftype; + struct cifs_ses *ses = tcon->ses; + FILE_SYSTEM_POSIX_INFO *info = NULL; + int flags = 0; + + rc = build_qfs_info_req(&iov, tcon, FS_POSIX_INFORMATION, + sizeof(FILE_SYSTEM_POSIX_INFO), + persistent_fid, volatile_fid); + if (rc) + return rc; + + if (smb3_encryption_required(tcon)) + flags |= CIFS_TRANSFORM_REQ; + + memset(&rqst, 0, sizeof(struct smb_rqst)); + rqst.rq_iov = &iov; + rqst.rq_nvec = 1; + + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); + cifs_small_buf_release(iov.iov_base); + if (rc) { + cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE); + goto posix_qfsinf_exit; + } + rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; + + info = (FILE_SYSTEM_POSIX_INFO *)( + le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp); + rc = validate_iov(le16_to_cpu(rsp->OutputBufferOffset), + le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, + sizeof(FILE_SYSTEM_POSIX_INFO)); + if (!rc) + copy_posix_fs_info_to_kstatfs(info, fsdata); + +posix_qfsinf_exit: + free_rsp_buf(resp_buftype, rsp_iov.iov_base); + return rc; +} +#endif /* SMB311 */ + int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata) diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index c2a4526512b5..ecb0feeac844 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -1223,6 +1223,7 @@ struct smb2_lease_ack { #define FS_DRIVER_PATH_INFORMATION 9 /* Local only */ #define FS_VOLUME_FLAGS_INFORMATION 10 /* Local only */ #define FS_SECTOR_SIZE_INFORMATION 11 /* SMB3 or later. Query */ +#define FS_POSIX_INFORMATION 100 /* SMB3.1.1 POSIX. Query */ struct smb2_fs_full_size_info { __le64 TotalAllocationUnits; diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 6e6a4f2ec890..7019459c5748 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -197,6 +197,9 @@ void smb2_cancelled_close_fid(struct work_struct *work); extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_file_id, u64 volatile_file_id, struct kstatfs *FSData); +extern int SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon, + u64 persistent_file_id, u64 volatile_file_id, + struct kstatfs *FSData); extern int SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_file_id, u64 volatile_file_id, int lvl); extern int SMB2_lock(const unsigned int xid, struct cifs_tcon *tcon, -- cgit v1.2.3 From 950132afd59385caf6e2b84e5235d069fa10681d Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Jun 2018 18:46:40 -0500 Subject: cifs: add missing debug entries for kconfig options /proc/fs/cifs/DebugData displays the features (Kconfig options) used to build cifs.ko but it was missing some, and needed comma separator. These can be useful in debugging certain problems so we know which optional features were enabled in the user's build. Also clarify them, by making them more closely match the corresponding CONFIG_CIFS_* parm. Old format: Features: dfs fscache posix spnego xattr acl New format: Features: DFS,FSCACHE,SMB_DIRECT,STATS,DEBUG2,ALLOW_INSECURE_LEGACY,CIFS_POSIX,UPCALL(SPNEGO),XATTR,ACL Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg Reviewed-by: Pavel Shilovsky Reviewed-by: Paulo Alcantara CC: Stable --- fs/cifs/cifs_debug.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index bfe999505815..991bfb271908 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -160,25 +160,41 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) seq_printf(m, "CIFS Version %s\n", CIFS_VERSION); seq_printf(m, "Features:"); #ifdef CONFIG_CIFS_DFS_UPCALL - seq_printf(m, " dfs"); + seq_printf(m, " DFS"); #endif #ifdef CONFIG_CIFS_FSCACHE - seq_printf(m, " fscache"); + seq_printf(m, ",FSCACHE"); +#endif +#ifdef CONFIG_CIFS_SMB_DIRECT + seq_printf(m, ",SMB_DIRECT"); +#endif +#ifdef CONFIG_CIFS_STATS2 + seq_printf(m, ",STATS2"); +#elif defined(CONFIG_CIFS_STATS) + seq_printf(m, ",STATS"); +#endif +#ifdef CONFIG_CIFS_DEBUG2 + seq_printf(m, ",DEBUG2"); +#elif defined(CONFIG_CIFS_DEBUG) + seq_printf(m, ",DEBUG"); +#endif +#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY + seq_printf(m, ",ALLOW_INSECURE_LEGACY"); #endif #ifdef CONFIG_CIFS_WEAK_PW_HASH - seq_printf(m, " lanman"); + seq_printf(m, ",WEAK_PW_HASH"); #endif #ifdef CONFIG_CIFS_POSIX - seq_printf(m, " posix"); + seq_printf(m, ",CIFS_POSIX"); #endif #ifdef CONFIG_CIFS_UPCALL - seq_printf(m, " spnego"); + seq_printf(m, ",UPCALL(SPNEGO)"); #endif #ifdef CONFIG_CIFS_XATTR - seq_printf(m, " xattr"); + seq_printf(m, ",XATTR"); #endif #ifdef CONFIG_CIFS_ACL - seq_printf(m, " acl"); + seq_printf(m, ",ACL"); #endif seq_putc(m, '\n'); seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid); -- cgit v1.2.3 From 0fdfef9aa7ee68ddd508aef7c98630cfc054f8d6 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Jun 2018 19:30:23 -0500 Subject: smb3: simplify code by removing CONFIG_CIFS_SMB311 We really, really want to be encouraging use of secure dialects, and SMB3.1.1 offers useful security features, and will soon be the recommended dialect for many use cases. Simplify the code by removing the CONFIG_CIFS_SMB311 ifdef so users don't disable it in the build, and create compatibility and/or security issues with modern servers - many of which have been supporting this dialect for multiple years. Also clarify some of the Kconfig text for cifs.ko about SMB3.1.1 and current supported features in the module. Signed-off-by: Steve French Acked-by: Aurelien Aptel Reviewed-by: Ronnie Sahlberg --- fs/cifs/Kconfig | 33 ++++++++++++++------------------- fs/cifs/cifs_debug.c | 3 +-- fs/cifs/cifsfs.c | 8 -------- fs/cifs/cifsglob.h | 8 -------- fs/cifs/connect.c | 11 +---------- fs/cifs/inode.c | 2 -- fs/cifs/smb2misc.c | 13 +++---------- fs/cifs/smb2ops.c | 6 ------ fs/cifs/smb2pdu.c | 31 +++---------------------------- fs/cifs/smb2proto.h | 2 -- fs/cifs/smb2transport.c | 4 ---- fs/cifs/transport.c | 4 ---- 12 files changed, 22 insertions(+), 103 deletions(-) (limited to 'fs') diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 832eafbf803f..63d0d852998a 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -16,24 +16,28 @@ config CIFS select CRYPTO_DES help This is the client VFS module for the SMB3 family of NAS protocols, - as well as for earlier dialects such as SMB2.1, SMB2 and the + (including support for the most recent, most secure dialect SMB3.1.1) + as well as for earlier dialects such as SMB2.1, SMB2 and the older Common Internet File System (CIFS) protocol. CIFS was the successor to the original dialect, the Server Message Block (SMB) protocol, the native file sharing mechanism for most early PC operating systems. - The SMB3 protocol is supported by most modern operating systems and - NAS appliances (e.g. Samba, Windows 8, Windows 2012, MacOS). + The SMB3 protocol is supported by most modern operating systems + and NAS appliances (e.g. Samba, Windows 10, Windows Server 2016, + MacOS) and even in the cloud (e.g. Microsoft Azure). The older CIFS protocol was included in Windows NT4, 2000 and XP (and later) as well by Samba (which provides excellent CIFS and SMB3 - server support for Linux and many other operating systems). Limited - support for OS/2 and Windows ME and similar very old servers is - provided as well. + server support for Linux and many other operating systems). Use of + dialects older than SMB2.1 is often discouraged on public networks. + This module also provides limited support for OS/2 and Windows ME + and similar very old servers. - The cifs module provides an advanced network file system client + This module provides an advanced network file system client for mounting to SMB3 (and CIFS) compliant servers. It includes support for DFS (hierarchical name space), secure per-user - session establishment via Kerberos or NTLM or NTLMv2, - safe distributed caching (oplock), optional packet + session establishment via Kerberos or NTLM or NTLMv2, RDMA + (smbdirect), advanced security features, per-share encryption, + directory leases, safe distributed caching (oplock), optional packet signing, Unicode and other internationalization improvements. In general, the default dialects, SMB3 and later, enable better @@ -43,7 +47,7 @@ config CIFS than SMB3 mounts. SMB2/SMB3 mount options are also slightly simpler (compared to CIFS) due to protocol improvements. - If you need to mount to Samba, Macs or Windows from this machine, say Y. + If you need to mount to Samba, Azure, Macs or Windows from this machine, say Y. config CIFS_STATS bool "CIFS statistics" @@ -201,15 +205,6 @@ config CIFS_NFSD_EXPORT help Allows NFS server to export a CIFS mounted share (nfsd over cifs) -config CIFS_SMB311 - bool "SMB3.1.1 network file system support" - depends on CIFS - select CRYPTO_SHA512 - - help - This enables support for the newest, and most secure dialect, SMB3.11. - If unsure, say Y - config CIFS_SMB_DIRECT bool "SMB Direct support (Experimental)" depends on CIFS=m && INFINIBAND && INFINIBAND_ADDR_TRANS || CIFS=y && INFINIBAND=y && INFINIBAND_ADDR_TRANS=y diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 991bfb271908..cb516c950438 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -275,10 +275,9 @@ skip_rdma: server->credits, server->dialect); if (server->sign) seq_printf(m, " signed"); -#ifdef CONFIG_CIFS_SMB311 if (server->posix_ext_supported) seq_printf(m, " posix"); -#endif /* 3.1.1 */ + i++; list_for_each(tmp2, &server->smb_ses_list) { ses = list_entry(tmp2, struct cifs_ses, diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 69ec5427769c..c162a416ddbf 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -483,20 +483,12 @@ cifs_show_options(struct seq_file *s, struct dentry *root) seq_puts(s, ",persistenthandles"); else if (tcon->use_resilient) seq_puts(s, ",resilienthandles"); - -#ifdef CONFIG_CIFS_SMB311 if (tcon->posix_extensions) seq_puts(s, ",posix"); else if (tcon->unix_ext) seq_puts(s, ",unix"); else seq_puts(s, ",nounix"); -#else - if (tcon->unix_ext) - seq_puts(s, ",unix"); - else - seq_puts(s, ",nounix"); -#endif /* SMB311 */ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) seq_puts(s, ",posixpaths"); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index b57d1e22ecb5..3ec7e3063865 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -191,9 +191,7 @@ enum smb_version { Smb_21, Smb_30, Smb_302, -#ifdef CONFIG_CIFS_SMB311 Smb_311, -#endif /* SMB311 */ Smb_3any, Smb_default, Smb_version_err @@ -687,12 +685,10 @@ struct TCP_Server_Info { #endif unsigned int max_read; unsigned int max_write; -#ifdef CONFIG_CIFS_SMB311 __le16 cipher_type; /* save initital negprot hash */ __u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE]; bool posix_ext_supported; -#endif /* 3.1.1 */ struct delayed_work reconnect; /* reconnect workqueue job */ struct mutex reconnect_mutex; /* prevent simultaneous reconnects */ unsigned long echo_interval; @@ -886,9 +882,7 @@ struct cifs_ses { __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE]; __u8 smb3encryptionkey[SMB3_SIGN_KEY_SIZE]; __u8 smb3decryptionkey[SMB3_SIGN_KEY_SIZE]; -#ifdef CONFIG_CIFS_SMB311 __u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE]; -#endif /* 3.1.1 */ /* * Network interfaces available on the server this session is @@ -997,9 +991,7 @@ struct cifs_tcon { bool seal:1; /* transport encryption for this mounted share */ bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol for this mount even if server would support */ -#ifdef CONFIG_CIFS_SMB311 bool posix_extensions; /* if true SMB3.11 posix extensions enabled */ -#endif /* CIFS_311 */ bool local_lease:1; /* check leases (only) on local system not remote */ bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */ bool broken_sparse_sup; /* if server or share does not support sparse */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 842f45859968..67f91a6313a0 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -303,10 +303,8 @@ static const match_table_t cifs_smb_version_tokens = { { Smb_21, SMB21_VERSION_STRING }, { Smb_30, SMB30_VERSION_STRING }, { Smb_302, SMB302_VERSION_STRING }, -#ifdef CONFIG_CIFS_SMB311 { Smb_311, SMB311_VERSION_STRING }, { Smb_311, ALT_SMB311_VERSION_STRING }, -#endif /* SMB311 */ { Smb_3any, SMB3ANY_VERSION_STRING }, { Smb_default, SMBDEFAULT_VERSION_STRING }, { Smb_version_err, NULL } @@ -1219,12 +1217,10 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3) vol->ops = &smb30_operations; /* currently identical with 3.0 */ vol->vals = &smb302_values; break; -#ifdef CONFIG_CIFS_SMB311 case Smb_311: vol->ops = &smb311_operations; vol->vals = &smb311_values; break; -#endif /* SMB311 */ case Smb_3any: vol->ops = &smb30_operations; /* currently identical with 3.0 */ vol->vals = &smb3any_values; @@ -3039,7 +3035,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) } } -#ifdef CONFIG_CIFS_SMB311 if (volume_info->linux_ext) { if (ses->server->posix_ext_supported) { tcon->posix_extensions = true; @@ -3051,7 +3046,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) goto out_fail; } } -#endif /* 311 */ /* * BB Do we need to wrap session_mutex around this TCon call and Unix @@ -4005,11 +3999,9 @@ try_mount_again: goto remote_path_check; } -#ifdef CONFIG_CIFS_SMB311 /* if new SMB3.11 POSIX extensions are supported do not remap / and \ */ if (tcon->posix_extensions) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS; -#endif /* SMB3.11 */ /* tell server which Unix caps we support */ if (cap_unix(tcon->ses)) { @@ -4472,11 +4464,10 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) goto out; } -#ifdef CONFIG_CIFS_SMB311 /* if new SMB3.11 POSIX extensions are supported do not remap / and \ */ if (tcon->posix_extensions) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS; -#endif /* SMB3.11 */ + if (cap_unix(ses)) reset_cifs_unix_caps(0, tcon, NULL, vol_info); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index f6abf18ca492..054e880c1dac 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1575,14 +1575,12 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode) server = tcon->ses->server; -#ifdef CONFIG_CIFS_SMB311 if ((server->ops->posix_mkdir) && (tcon->posix_extensions)) { rc = server->ops->posix_mkdir(xid, inode, mode, tcon, full_path, cifs_sb); d_drop(direntry); /* for time being always refresh inode info */ goto mkdir_out; } -#endif /* SMB311 */ if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))) { diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 3ff7cec2da81..303d4592ebe7 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -93,7 +93,6 @@ static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = { /* SMB2_OPLOCK_BREAK */ cpu_to_le16(24) }; -#ifdef CONFIG_CIFS_SMB311 static __u32 get_neg_ctxt_len(struct smb2_sync_hdr *hdr, __u32 len, __u32 non_ctxlen) { @@ -127,7 +126,6 @@ static __u32 get_neg_ctxt_len(struct smb2_sync_hdr *hdr, __u32 len, /* length of negcontexts including pad from end of sec blob to them */ return (len - nc_offset) + size_of_pad_before_neg_ctxts; } -#endif /* CIFS_SMB311 */ int smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *srvr) @@ -222,10 +220,9 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *srvr) clc_len = smb2_calc_size(buf, srvr); -#ifdef CONFIG_CIFS_SMB311 if (shdr->Command == SMB2_NEGOTIATE) clc_len += get_neg_ctxt_len(shdr, len, clc_len); -#endif /* SMB311 */ + if (len != clc_len) { cifs_dbg(FYI, "Calculated size %u length %u mismatch mid %llu\n", clc_len, len, mid); @@ -451,15 +448,13 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb) /* Windows doesn't allow paths beginning with \ */ if (from[0] == '\\') start_of_path = from + 1; -#ifdef CONFIG_CIFS_SMB311 + /* SMB311 POSIX extensions paths do not include leading slash */ else if (cifs_sb_master_tlink(cifs_sb) && cifs_sb_master_tcon(cifs_sb)->posix_extensions && (from[0] == '/')) { start_of_path = from + 1; - } -#endif /* 311 */ - else + } else start_of_path = from; to = cifs_strndup_to_utf16(start_of_path, PATH_MAX, &len, @@ -759,7 +754,6 @@ smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server) return 0; } -#ifdef CONFIG_CIFS_SMB311 /** * smb311_update_preauth_hash - update @ses hash with the packet data in @iov * @@ -821,4 +815,3 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct kvec *iov, int nvec) return 0; } -#endif diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index e2a8b9d90ad8..27b69977809d 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1533,7 +1533,6 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon, return rc; } -#ifdef CONFIG_CIFS_SMB311 static int smb311_queryfs(const unsigned int xid, struct cifs_tcon *tcon, struct kstatfs *buf) @@ -1564,7 +1563,6 @@ smb311_queryfs(const unsigned int xid, struct cifs_tcon *tcon, SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); return rc; } -#endif /* SMB311 */ static bool smb2_compare_fids(struct cifsFileInfo *ob1, struct cifsFileInfo *ob2) @@ -3303,7 +3301,6 @@ struct smb_version_operations smb30_operations = { .next_header = smb2_next_header, }; -#ifdef CONFIG_CIFS_SMB311 struct smb_version_operations smb311_operations = { .compare_fids = smb2_compare_fids, .setup_request = smb2_setup_request, @@ -3404,7 +3401,6 @@ struct smb_version_operations smb311_operations = { #endif /* CIFS_XATTR */ .next_header = smb2_next_header, }; -#endif /* CIFS_SMB311 */ struct smb_version_values smb20_values = { .version_string = SMB20_VERSION_STRING, @@ -3532,7 +3528,6 @@ struct smb_version_values smb302_values = { .create_lease_size = sizeof(struct create_lease_v2), }; -#ifdef CONFIG_CIFS_SMB311 struct smb_version_values smb311_values = { .version_string = SMB311_VERSION_STRING, .protocol_id = SMB311_PROT_ID, @@ -3553,4 +3548,3 @@ struct smb_version_values smb311_values = { .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED, .create_lease_size = sizeof(struct create_lease_v2), }; -#endif /* SMB311 */ diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index fa9fc3fab60e..4ea5528fc15c 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -370,7 +370,7 @@ smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon, return rc; } -#ifdef CONFIG_CIFS_SMB311 + /* offset is sizeof smb2_negotiate_req but rounded up to 8 bytes */ #define OFFSET_OF_NEG_CONTEXT 0x68 /* sizeof(struct smb2_negotiate_req) */ @@ -585,13 +585,6 @@ add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode) return 0; } -#else -static void assemble_neg_contexts(struct smb2_negotiate_req *req, - unsigned int *total_len) -{ - return; -} -#endif /* SMB311 */ /* * @@ -636,10 +629,9 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) return rc; req->sync_hdr.SessionId = 0; -#ifdef CONFIG_CIFS_SMB311 + memset(server->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE); memset(ses->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE); -#endif if (strcmp(ses->server->vals->version_string, SMB3ANY_VERSION_STRING) == 0) { @@ -741,10 +733,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) cifs_dbg(FYI, "negotiated smb3.0 dialect\n"); else if (rsp->DialectRevision == cpu_to_le16(SMB302_PROT_ID)) cifs_dbg(FYI, "negotiated smb3.02 dialect\n"); -#ifdef CONFIG_CIFS_SMB311 else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) cifs_dbg(FYI, "negotiated smb3.1.1 dialect\n"); -#endif /* SMB311 */ else { cifs_dbg(VFS, "Illegal dialect returned by server 0x%x\n", le16_to_cpu(rsp->DialectRevision)); @@ -753,9 +743,6 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) } server->dialect = le16_to_cpu(rsp->DialectRevision); - /* BB: add check that dialect was valid given dialect(s) we asked for */ - -#ifdef CONFIG_CIFS_SMB311 /* * Keep a copy of the hash after negprot. This hash will be * the starting hash value for all sessions made from this @@ -763,7 +750,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) */ memcpy(server->preauth_sha_hash, ses->preauth_sha_hash, SMB2_PREAUTH_HASH_SIZE); -#endif + /* SMB2 only has an extended negflavor */ server->negflavor = CIFS_NEGFLAVOR_EXTENDED; /* set it to the maximum buffer size value we can send with 1 credit */ @@ -804,7 +791,6 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) rc = -EIO; } -#ifdef CONFIG_CIFS_SMB311 if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) { if (rsp->NegotiateContextCount) rc = smb311_decode_neg_context(rsp, server, @@ -812,7 +798,6 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) else cifs_dbg(VFS, "Missing expected negotiate contexts\n"); } -#endif /* CONFIG_CIFS_SMB311 */ neg_exit: free_rsp_buf(resp_buftype, rsp); return rc; @@ -1373,13 +1358,11 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, sess_data->nls_cp = (struct nls_table *) nls_cp; sess_data->previous_session = ses->Suid; -#ifdef CONFIG_CIFS_SMB311 /* * Initialize the session hash with the server one. */ memcpy(ses->preauth_sha_hash, ses->server->preauth_sha_hash, SMB2_PREAUTH_HASH_SIZE); -#endif while (sess_data->func) sess_data->func(sess_data); @@ -1920,7 +1903,6 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len, return 0; } -#ifdef CONFIG_CIFS_SMB311 int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, umode_t mode, struct cifs_tcon *tcon, const char *full_path, @@ -2070,7 +2052,6 @@ err_free_path: kfree(utf16_path); return rc; } -#endif /* SMB311 */ int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, @@ -2210,7 +2191,6 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, dhc_buf = iov[n_iov-1].iov_base; } -#ifdef CONFIG_CIFS_SMB311 if (tcon->posix_extensions) { if (n_iov > 2) { struct create_context *ccontext = @@ -2229,7 +2209,6 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, } pc_buf = iov[n_iov-1].iov_base; } -#endif /* SMB311 */ memset(&rqst, 0, sizeof(struct smb_rqst)); rqst.rq_iov = iov; @@ -3938,7 +3917,6 @@ copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf, return; } -#ifdef CONFIG_CIFS_SMB311 static void copy_posix_fs_info_to_kstatfs(FILE_SYSTEM_POSIX_INFO *response_data, struct kstatfs *kst) @@ -3957,7 +3935,6 @@ copy_posix_fs_info_to_kstatfs(FILE_SYSTEM_POSIX_INFO *response_data, return; } -#endif /* SMB311 */ static int build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level, @@ -3995,7 +3972,6 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level, return 0; } -#ifdef CONFIG_CIFS_SMB311 int SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata) @@ -4043,7 +4019,6 @@ posix_qfsinf_exit: free_rsp_buf(resp_buftype, rsp_iov.iov_base); return rc; } -#endif /* SMB311 */ int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 7019459c5748..98d9b30c16a6 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -216,9 +216,7 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *); extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, enum securityEnum); -#ifdef CONFIG_CIFS_SMB311 extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server); extern int smb311_update_preauth_hash(struct cifs_ses *ses, struct kvec *iov, int nvec); -#endif #endif /* _SMB2PROTO_H */ diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 719d55e63d88..3f778937c0e2 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c @@ -70,7 +70,6 @@ err: return rc; } -#ifdef CONFIG_CIFS_SMB311 int smb311_crypto_shash_allocate(struct TCP_Server_Info *server) { @@ -98,7 +97,6 @@ err: cifs_free_hash(&p->hmacsha256, &p->sdeschmacsha256); return rc; } -#endif static struct cifs_ses * smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id) @@ -395,7 +393,6 @@ generate_smb30signingkey(struct cifs_ses *ses) return generate_smb3signingkey(ses, &triplet); } -#ifdef CONFIG_CIFS_SMB311 int generate_smb311signingkey(struct cifs_ses *ses) @@ -423,7 +420,6 @@ generate_smb311signingkey(struct cifs_ses *ses) return generate_smb3signingkey(ses, &triplet); } -#endif /* 311 */ int smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index a341ec839c83..0f9156af5eb0 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -807,11 +807,9 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, if (rc < 0) goto out; -#ifdef CONFIG_CIFS_SMB311 if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) smb311_update_preauth_hash(ses, rqst->rq_iov, rqst->rq_nvec); -#endif if (timeout == CIFS_ASYNC_OP) goto out; @@ -852,7 +850,6 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, else *resp_buf_type = CIFS_SMALL_BUFFER; -#ifdef CONFIG_CIFS_SMB311 if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) { struct kvec iov = { .iov_base = resp_iov->iov_base, @@ -860,7 +857,6 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, }; smb311_update_preauth_hash(ses, &iov, 1); } -#endif credits = ses->server->ops->get_credits(midQ); -- cgit v1.2.3 From c3ed44026cd07fda5976ecb79225759901a160b4 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Jun 2018 22:53:39 -0500 Subject: smb3: remove noisy warning message on mount Some servers, like Samba, don't support the fsctl for query_network_interface_info so don't log a noisy warning message on mount for this by default unless the error is more serious. Lower the error to an FYI level so it does not get logged by default. Reviewed-by: Ronnie Sahlberg Reviewed-by: Aurelien Aptel Signed-off-by: Steve French --- fs/cifs/smb2ops.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 27b69977809d..4ce72055ca0a 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -444,7 +444,11 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon) FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */, NULL /* no data input */, 0 /* no data input */, (char **)&out_buf, &ret_data_len); - if (rc != 0) { + if (rc == -EOPNOTSUPP) { + cifs_dbg(FYI, + "server does not support query network interfaces\n"); + goto out; + } else if (rc != 0) { cifs_dbg(VFS, "error %d on ioctl to get interface list\n", rc); goto out; } -- cgit v1.2.3 From 8a69e96e610b3ec8a55f6fd4e44363452838caa7 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 29 Jun 2018 16:06:15 -0500 Subject: smb3: snapshot mounts are read-only and make sure info is displayable about the mount snapshot mounts were not marked as read-only and did not display the snapshot time (in /proc/mounts) specified on mount With this patch - note that can not write to the snapshot mount (see "ro" in /proc/mounts line) and also the missing snapshot timewarp token time is dumped. Sample line from /proc/mounts with the patch: //127.0.0.1/scratch /mnt2 smb3 ro,relatime,vers=default,cache=strict,username=testuser,domain=,uid=0,noforceuid,gid=0,noforcegid,addr=127.0.0.1,file_mode=0755,dir_mode=0755,soft,nounix,serverino,mapposix,noperm,rsize=1048576,wsize=1048576,echo_interval=60,snapshot=1234567,actimeo=1 0 0 Signed-off-by: Steve French Reviewed-by: Paulo Alcantara --- fs/cifs/cifsfs.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'fs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index c162a416ddbf..de16078e456b 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -139,6 +139,9 @@ cifs_read_super(struct super_block *sb) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL) sb->s_flags |= SB_POSIXACL; + if (tcon->snapshot_time) + sb->s_flags |= SB_RDONLY; + if (tcon->ses->capabilities & tcon->ses->server->vals->cap_large_files) sb->s_maxbytes = MAX_LFS_FILESIZE; else @@ -540,6 +543,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root) seq_printf(s, ",wsize=%u", cifs_sb->wsize); seq_printf(s, ",echo_interval=%lu", tcon->ses->server->echo_interval / HZ); + if (tcon->snapshot_time) + seq_printf(s, ",snapshot=%llu", tcon->snapshot_time); /* convert actimeo and display it in seconds */ seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ); -- cgit v1.2.3 From 289131e1f1e6ad8c661ec05e176b8f0915672059 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 23 Jul 2018 09:15:18 -0500 Subject: SMB3: Number of requests sent should be displayed for SMB3 not just CIFS For SMB2/SMB3 the number of requests sent was not displayed in /proc/fs/cifs/Stats unless CONFIG_CIFS_STATS2 was enabled (only number of failed requests displayed). As with earlier dialects, we should be displaying these counters if CONFIG_CIFS_STATS is enabled. They are important for debugging. e.g. when you cat /proc/fs/cifs/Stats (before the patch) Resources in use CIFS Session: 1 Share (unique mount targets): 2 SMB Request/Response Buffer: 1 Pool size: 5 SMB Small Req/Resp Buffer: 1 Pool size: 30 Operations (MIDs): 0 0 session 0 share reconnects Total vfs operations: 690 maximum at one time: 2 1) \\localhost\test SMBs: 975 Negotiates: 0 sent 0 failed SessionSetups: 0 sent 0 failed Logoffs: 0 sent 0 failed TreeConnects: 0 sent 0 failed TreeDisconnects: 0 sent 0 failed Creates: 0 sent 2 failed Closes: 0 sent 0 failed Flushes: 0 sent 0 failed Reads: 0 sent 0 failed Writes: 0 sent 0 failed Locks: 0 sent 0 failed IOCTLs: 0 sent 1 failed Cancels: 0 sent 0 failed Echos: 0 sent 0 failed QueryDirectories: 0 sent 63 failed Signed-off-by: Steve French Reviewed-by: Aurelien Aptel Reviewed-by: Pavel Shilovsky --- fs/cifs/smb2pdu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 4ea5528fc15c..0b4d7ebb812d 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -360,7 +360,7 @@ smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon, total_len); if (tcon != NULL) { -#ifdef CONFIG_CIFS_STATS2 +#ifdef CONFIG_CIFS_STATS uint16_t com_code = le16_to_cpu(smb2_command); cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_sent[com_code]); #endif -- cgit v1.2.3 From 1995d28f84b3d2a8f586fcd271207f798b80ccd8 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 27 Jul 2018 15:14:04 -0500 Subject: smb3: remove per-session operations from per-tree connection stats Remove counters from the per-tree connection /proc/fs/cifs/Stats output that will always be zero (since they are not per-tcon ops) ie SMB3 Negotiate, SessionSetup, Logoff, Echo, Cancel. Also clarify "sent" to be "total" per-Pavel's suggestion (since this "total" includes total for all operations that we try to send whether or not succesffully sent). Sample output below: Resources in use CIFS Session: 1 Share (unique mount targets): 2 SMB Request/Response Buffer: 1 Pool size: 5 SMB Small Req/Resp Buffer: 1 Pool size: 30 Operations (MIDs): 0 1 session 2 share reconnects Total vfs operations: 23 maximum at one time: 2 1) \\localhost\test SMBs: 45 TreeConnects: 2 total 0 failed TreeDisconnects: 0 total 0 failed Creates: 13 total 2 failed Closes: 9 total 0 failed Flushes: 0 total 0 failed Reads: 0 total 0 failed Writes: 1 total 0 failed Locks: 0 total 0 failed IOCTLs: 3 total 1 failed QueryDirectories: 4 total 2 failed ChangeNotifies: 0 total 0 failed QueryInfos: 10 total 0 failed SetInfos: 3 total 0 failed OplockBreaks: 0 sent 0 failed Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky --- fs/cifs/smb2ops.c | 46 ++++++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 28 deletions(-) (limited to 'fs') diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 4ce72055ca0a..dad6dc763200 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -927,58 +927,48 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon) #ifdef CONFIG_CIFS_STATS atomic_t *sent = tcon->stats.smb2_stats.smb2_com_sent; atomic_t *failed = tcon->stats.smb2_stats.smb2_com_failed; - seq_printf(m, "\nNegotiates: %d sent %d failed", - atomic_read(&sent[SMB2_NEGOTIATE_HE]), - atomic_read(&failed[SMB2_NEGOTIATE_HE])); - seq_printf(m, "\nSessionSetups: %d sent %d failed", - atomic_read(&sent[SMB2_SESSION_SETUP_HE]), - atomic_read(&failed[SMB2_SESSION_SETUP_HE])); - seq_printf(m, "\nLogoffs: %d sent %d failed", - atomic_read(&sent[SMB2_LOGOFF_HE]), - atomic_read(&failed[SMB2_LOGOFF_HE])); - seq_printf(m, "\nTreeConnects: %d sent %d failed", + + /* + * Can't display SMB2_NEGOTIATE, SESSION_SETUP, LOGOFF, CANCEL and ECHO + * totals (requests sent) since those SMBs are per-session not per tcon + */ + seq_printf(m, "\nTreeConnects: %d total %d failed", atomic_read(&sent[SMB2_TREE_CONNECT_HE]), atomic_read(&failed[SMB2_TREE_CONNECT_HE])); - seq_printf(m, "\nTreeDisconnects: %d sent %d failed", + seq_printf(m, "\nTreeDisconnects: %d total %d failed", atomic_read(&sent[SMB2_TREE_DISCONNECT_HE]), atomic_read(&failed[SMB2_TREE_DISCONNECT_HE])); - seq_printf(m, "\nCreates: %d sent %d failed", + seq_printf(m, "\nCreates: %d total %d failed", atomic_read(&sent[SMB2_CREATE_HE]), atomic_read(&failed[SMB2_CREATE_HE])); - seq_printf(m, "\nCloses: %d sent %d failed", + seq_printf(m, "\nCloses: %d total %d failed", atomic_read(&sent[SMB2_CLOSE_HE]), atomic_read(&failed[SMB2_CLOSE_HE])); - seq_printf(m, "\nFlushes: %d sent %d failed", + seq_printf(m, "\nFlushes: %d total %d failed", atomic_read(&sent[SMB2_FLUSH_HE]), atomic_read(&failed[SMB2_FLUSH_HE])); - seq_printf(m, "\nReads: %d sent %d failed", + seq_printf(m, "\nReads: %d total %d failed", atomic_read(&sent[SMB2_READ_HE]), atomic_read(&failed[SMB2_READ_HE])); - seq_printf(m, "\nWrites: %d sent %d failed", + seq_printf(m, "\nWrites: %d total %d failed", atomic_read(&sent[SMB2_WRITE_HE]), atomic_read(&failed[SMB2_WRITE_HE])); - seq_printf(m, "\nLocks: %d sent %d failed", + seq_printf(m, "\nLocks: %d total %d failed", atomic_read(&sent[SMB2_LOCK_HE]), atomic_read(&failed[SMB2_LOCK_HE])); - seq_printf(m, "\nIOCTLs: %d sent %d failed", + seq_printf(m, "\nIOCTLs: %d total %d failed", atomic_read(&sent[SMB2_IOCTL_HE]), atomic_read(&failed[SMB2_IOCTL_HE])); - seq_printf(m, "\nCancels: %d sent %d failed", - atomic_read(&sent[SMB2_CANCEL_HE]), - atomic_read(&failed[SMB2_CANCEL_HE])); - seq_printf(m, "\nEchos: %d sent %d failed", - atomic_read(&sent[SMB2_ECHO_HE]), - atomic_read(&failed[SMB2_ECHO_HE])); - seq_printf(m, "\nQueryDirectories: %d sent %d failed", + seq_printf(m, "\nQueryDirectories: %d total %d failed", atomic_read(&sent[SMB2_QUERY_DIRECTORY_HE]), atomic_read(&failed[SMB2_QUERY_DIRECTORY_HE])); - seq_printf(m, "\nChangeNotifies: %d sent %d failed", + seq_printf(m, "\nChangeNotifies: %d total %d failed", atomic_read(&sent[SMB2_CHANGE_NOTIFY_HE]), atomic_read(&failed[SMB2_CHANGE_NOTIFY_HE])); - seq_printf(m, "\nQueryInfos: %d sent %d failed", + seq_printf(m, "\nQueryInfos: %d total %d failed", atomic_read(&sent[SMB2_QUERY_INFO_HE]), atomic_read(&failed[SMB2_QUERY_INFO_HE])); - seq_printf(m, "\nSetInfos: %d sent %d failed", + seq_printf(m, "\nSetInfos: %d total %d failed", atomic_read(&sent[SMB2_SET_INFO_HE]), atomic_read(&failed[SMB2_SET_INFO_HE])); seq_printf(m, "\nOplockBreaks: %d sent %d failed", -- cgit v1.2.3 From 22783155f4bf956c346a81624ec9258930a6fe06 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 27 Jul 2018 22:01:49 -0500 Subject: smb3: don't request leases in symlink creation and query Fixes problem pointed out by Pavel in discussions about commit 729c0c9dd55204f0c9a823ac8a7bfa83d36c7e78 Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg CC: Stable # 3.18.x+ --- fs/cifs/link.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/cifs/link.c b/fs/cifs/link.c index de41f96aba49..2148b0f60e5e 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -396,7 +396,7 @@ smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_io_parms io_parms; int buf_type = CIFS_NO_BUFFER; __le16 *utf16_path; - __u8 oplock = SMB2_OPLOCK_LEVEL_II; + __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; struct smb2_file_all_info *pfile_info = NULL; oparms.tcon = tcon; @@ -459,7 +459,7 @@ smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_io_parms io_parms; int create_options = CREATE_NOT_DIR; __le16 *utf16_path; - __u8 oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE; + __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; struct kvec iov[2]; if (backup_cred(cifs_sb)) -- cgit v1.2.3 From 06188fcf9c068a2a8e82ad1e2510a008373150e2 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 29 Jul 2018 17:13:39 -0500 Subject: cifs: remove unused stats These timers were a good idea but weren't used in current code, and the idea was cifs specific. Future patch will add similar timers for SMB2/SMB3, but no sense using memory for cifs timers that aren't used in current code. Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg --- fs/cifs/cifsglob.h | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 3ec7e3063865..8826bc0a9b15 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -961,20 +961,6 @@ struct cifs_tcon { atomic_t smb2_com_failed[NUMBER_OF_SMB2_COMMANDS]; } smb2_stats; } stats; -#ifdef CONFIG_CIFS_STATS2 - unsigned long long time_writes; - unsigned long long time_reads; - unsigned long long time_opens; - unsigned long long time_deletes; - unsigned long long time_closes; - unsigned long long time_mkdirs; - unsigned long long time_rmdirs; - unsigned long long time_renames; - unsigned long long time_t2renames; - unsigned long long time_ffirst; - unsigned long long time_fnext; - unsigned long long time_fclose; -#endif /* CONFIG_CIFS_STATS2 */ __u64 bytes_read; __u64 bytes_written; spinlock_t stat_lock; /* protects the two fields above */ -- cgit v1.2.3 From e68a932b0b8e38eaa2111fc3aab31ff66988f1c4 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 30 Jul 2018 14:23:58 -0500 Subject: smb3: add tracepoint for session expired or deleted In debugging reconnection problems, want to be able to more easily trace cases in which the server has marked the SMB3 session expired or deleted (to distinguish from timeout cases). Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg --- fs/cifs/smb2ops.c | 4 ++++ fs/cifs/trace.h | 1 + 2 files changed, 5 insertions(+) (limited to 'fs') diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index dad6dc763200..314556c083f3 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1483,7 +1483,11 @@ smb2_is_session_expired(char *buf) shdr->Status != STATUS_USER_SESSION_DELETED) return false; + trace_smb3_ses_expired(shdr->TreeId, shdr->SessionId, + le16_to_cpu(shdr->Command), + le64_to_cpu(shdr->MessageId)); cifs_dbg(FYI, "Session expired or deleted\n"); + return true; } diff --git a/fs/cifs/trace.h b/fs/cifs/trace.h index 67e413f6ee4d..0fdf2f5c07ba 100644 --- a/fs/cifs/trace.h +++ b/fs/cifs/trace.h @@ -281,6 +281,7 @@ DEFINE_EVENT(smb3_cmd_done_class, smb3_##name, \ TP_ARGS(tid, sesid, cmd, mid)) DEFINE_SMB3_CMD_DONE_EVENT(cmd_done); +DEFINE_SMB3_CMD_DONE_EVENT(ses_expired); DECLARE_EVENT_CLASS(smb3_exit_err_class, TP_PROTO(unsigned int xid, -- cgit v1.2.3 From bf1fdeb7899a86adfbe0b521bee5cf78bb870a14 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 30 Jul 2018 19:23:09 -0500 Subject: smb3: add reconnect tracepoints Add tracepoints for reconnecting an smb3 session Example output (from trace-cmd) with the patch (showing the session marked for reconnect, the stat failing, and then the subsequent SMB3 commands after the server comes back up). The "smb3_reconnect" event is the new one. cifsd-25993 [000] .... 29635.368265: smb3_reconnect: server=localhost current_mid=0x1e stat-26200 [001] .... 29638.516403: smb3_enter: cifs_revalidate_dentry_attr: xid=22 stat-26200 [001] .... 29648.723296: smb3_exit_err: cifs_revalidate_dentry_attr: xid=22 rc=-112 kworker/0:1-22830 [000] .... 29653.850947: smb3_cmd_done: sid=0x0 tid=0x0 cmd=0 mid=0 kworker/0:1-22830 [000] .... 29653.851191: smb3_cmd_err: sid=0x8ae4683c tid=0x0 cmd=1 mid=1 status=0xc0000016 rc=-5 kworker/0:1-22830 [000] .... 29653.855254: smb3_cmd_done: sid=0x8ae4683c tid=0x0 cmd=1 mid=2 kworker/0:1-22830 [000] .... 29653.855482: smb3_cmd_done: sid=0x8ae4683c tid=0x8084f30d cmd=3 mid=3 Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg Reviewed-by: Aurelien Aptel --- fs/cifs/connect.c | 1 + fs/cifs/trace.h | 26 ++++++++++++++++++++++++++ fs/cifs/transport.c | 2 ++ 3 files changed, 29 insertions(+) (limited to 'fs') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 67f91a6313a0..d9bd10d295a9 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -348,6 +348,7 @@ cifs_reconnect(struct TCP_Server_Info *server) server->max_read = 0; cifs_dbg(FYI, "Reconnecting tcp session\n"); + trace_smb3_reconnect(server->CurrentMid, server->hostname); /* before reconnecting the tcp session, mark the smb session (uid) and the tid bad so they are not used until reconnected */ diff --git a/fs/cifs/trace.h b/fs/cifs/trace.h index 0fdf2f5c07ba..6b50b57e2416 100644 --- a/fs/cifs/trace.h +++ b/fs/cifs/trace.h @@ -423,6 +423,32 @@ DEFINE_EVENT(smb3_open_done_class, smb3_##name, \ DEFINE_SMB3_OPEN_DONE_EVENT(open_done); DEFINE_SMB3_OPEN_DONE_EVENT(posix_mkdir_done); +DECLARE_EVENT_CLASS(smb3_reconnect_class, + TP_PROTO(__u64 currmid, + char *hostname), + TP_ARGS(currmid, hostname), + TP_STRUCT__entry( + __field(__u64, currmid) + __field(char *, hostname) + ), + TP_fast_assign( + __entry->currmid = currmid; + __entry->hostname = hostname; + ), + TP_printk("server=%s current_mid=0x%llx", + __entry->hostname, + __entry->currmid) +) + +#define DEFINE_SMB3_RECONNECT_EVENT(name) \ +DEFINE_EVENT(smb3_reconnect_class, smb3_##name, \ + TP_PROTO(__u64 currmid, \ + char *hostname), \ + TP_ARGS(currmid, hostname)) + +DEFINE_SMB3_RECONNECT_EVENT(reconnect); +DEFINE_SMB3_RECONNECT_EVENT(partial_send_reconnect); + #endif /* _CIFS_TRACE_H */ #undef TRACE_INCLUDE_PATH diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0f9156af5eb0..357d25351ffa 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -361,6 +361,8 @@ uncork: * socket so the server throws away the partial SMB */ server->tcpStatus = CifsNeedReconnect; + trace_smb3_partial_send_reconnect(server->CurrentMid, + server->hostname); } smbd_done: if (rc < 0 && rc != -EINTR) -- cgit v1.2.3 From 9da6ec7775d2cd76df53fbf4f1f35f6d490204f5 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Tue, 31 Jul 2018 08:48:22 +1000 Subject: cifs: use a refcount to protect open/closing the cached file handle Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky Cc: --- fs/cifs/cifsglob.h | 1 + fs/cifs/smb2inode.c | 4 +++- fs/cifs/smb2ops.c | 31 ++++++++++++++++++++++++++----- fs/cifs/smb2proto.h | 1 + 4 files changed, 31 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 8826bc0a9b15..0e6fd5fa4eb6 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -907,6 +907,7 @@ cap_unix(struct cifs_ses *ses) struct cached_fid { bool is_valid:1; /* Do we have a useable root fid */ + struct kref refcount; struct cifs_fid *fid; struct mutex fid_mutex; struct cifs_tcon *tcon; diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index d01ad706d7fc..f22cbc0d1869 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c @@ -120,7 +120,9 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon, break; } - if (use_cached_root_handle == false) + if (use_cached_root_handle) + close_shroot(&tcon->crfid); + else rc = SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); if (tmprc) rc = tmprc; diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 314556c083f3..8929426ddaa6 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -470,21 +470,36 @@ out: return rc; } -void -smb2_cached_lease_break(struct work_struct *work) +static void +smb2_close_cached_fid(struct kref *ref) { - struct cached_fid *cfid = container_of(work, - struct cached_fid, lease_break); - mutex_lock(&cfid->fid_mutex); + struct cached_fid *cfid = container_of(ref, struct cached_fid, + refcount); + if (cfid->is_valid) { cifs_dbg(FYI, "clear cached root file handle\n"); SMB2_close(0, cfid->tcon, cfid->fid->persistent_fid, cfid->fid->volatile_fid); cfid->is_valid = false; } +} + +void close_shroot(struct cached_fid *cfid) +{ + mutex_lock(&cfid->fid_mutex); + kref_put(&cfid->refcount, smb2_close_cached_fid); mutex_unlock(&cfid->fid_mutex); } +void +smb2_cached_lease_break(struct work_struct *work) +{ + struct cached_fid *cfid = container_of(work, + struct cached_fid, lease_break); + + close_shroot(cfid); +} + /* * Open the directory at the root of a share */ @@ -499,6 +514,7 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid) if (tcon->crfid.is_valid) { cifs_dbg(FYI, "found a cached root file handle\n"); memcpy(pfid, tcon->crfid.fid, sizeof(struct cifs_fid)); + kref_get(&tcon->crfid.refcount); mutex_unlock(&tcon->crfid.fid_mutex); return 0; } @@ -515,6 +531,8 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid) memcpy(tcon->crfid.fid, pfid, sizeof(struct cifs_fid)); tcon->crfid.tcon = tcon; tcon->crfid.is_valid = true; + kref_init(&tcon->crfid.refcount); + kref_get(&tcon->crfid.refcount); } mutex_unlock(&tcon->crfid.fid_mutex); return rc; @@ -558,6 +576,9 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon) FS_SECTOR_SIZE_INFORMATION); /* SMB3 specific */ if (no_cached_open) SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); + else + close_shroot(&tcon->crfid); + return; } diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 98d9b30c16a6..19aa483395c7 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -68,6 +68,7 @@ extern int smb3_handle_read_data(struct TCP_Server_Info *server, extern int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid); +extern void close_shroot(struct cached_fid *cfid); extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src); extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, -- cgit v1.2.3 From fcabb89299d79010eb923afdd26de04afcc0527f Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 31 Jul 2018 01:21:37 -0500 Subject: cifs: simple stats should always be enabled CONFIG_CIFS_STATS should always be enabled as Pavel recently noted. Simple statistics are not a significant performance hit, and removing the ifdef simplifies the code slightly. Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg Reviewed-by: Pavel Shilovsky --- fs/cifs/Kconfig | 9 +-------- fs/cifs/cifs_debug.c | 6 ------ fs/cifs/cifsglob.h | 10 ---------- fs/cifs/misc.c | 2 -- fs/cifs/smb1ops.c | 4 ---- fs/cifs/smb2ops.c | 4 ---- fs/cifs/smb2pdu.c | 2 -- 7 files changed, 1 insertion(+), 36 deletions(-) (limited to 'fs') diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 63d0d852998a..35c83fe7dba0 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -49,16 +49,9 @@ config CIFS If you need to mount to Samba, Azure, Macs or Windows from this machine, say Y. -config CIFS_STATS - bool "CIFS statistics" - depends on CIFS - help - Enabling this option will cause statistics for each server share - mounted by the cifs client to be displayed in /proc/fs/cifs/Stats - config CIFS_STATS2 bool "Extended statistics" - depends on CIFS_STATS + depends on CIFS help Enabling this option will allow more detailed statistics on SMB request timing to be displayed in /proc/fs/cifs/DebugData and also diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index cb516c950438..3270d9b74603 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -365,7 +365,6 @@ skip_rdma: return 0; } -#ifdef CONFIG_CIFS_STATS static ssize_t cifs_stats_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { @@ -481,7 +480,6 @@ static const struct file_operations cifs_stats_proc_fops = { .release = single_release, .write = cifs_stats_proc_write, }; -#endif /* STATS */ #ifdef CONFIG_CIFS_SMB_DIRECT #define PROC_FILE_DEFINE(name) \ @@ -539,9 +537,7 @@ cifs_proc_init(void) proc_create_single("DebugData", 0, proc_fs_cifs, cifs_debug_data_proc_show); -#ifdef CONFIG_CIFS_STATS proc_create("Stats", 0644, proc_fs_cifs, &cifs_stats_proc_fops); -#endif /* STATS */ proc_create("cifsFYI", 0644, proc_fs_cifs, &cifsFYI_proc_fops); proc_create("traceSMB", 0644, proc_fs_cifs, &traceSMB_proc_fops); proc_create("LinuxExtensionsEnabled", 0644, proc_fs_cifs, @@ -579,9 +575,7 @@ cifs_proc_clean(void) remove_proc_entry("DebugData", proc_fs_cifs); remove_proc_entry("cifsFYI", proc_fs_cifs); remove_proc_entry("traceSMB", proc_fs_cifs); -#ifdef CONFIG_CIFS_STATS remove_proc_entry("Stats", proc_fs_cifs); -#endif remove_proc_entry("SecurityFlags", proc_fs_cifs); remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs); remove_proc_entry("LookupCacheEnabled", proc_fs_cifs); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 0e6fd5fa4eb6..4a3a737134ea 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -931,7 +931,6 @@ struct cifs_tcon { __u32 tid; /* The 4 byte tree id */ __u16 Flags; /* optional support bits */ enum statusEnum tidStatus; -#ifdef CONFIG_CIFS_STATS atomic_t num_smbs_sent; union { struct { @@ -965,7 +964,6 @@ struct cifs_tcon { __u64 bytes_read; __u64 bytes_written; spinlock_t stat_lock; /* protects the two fields above */ -#endif /* CONFIG_CIFS_STATS */ FILE_SYSTEM_DEVICE_INFO fsDevInfo; FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */ FILE_SYSTEM_UNIX_INFO fsUnixInfo; @@ -1331,7 +1329,6 @@ convert_delimiter(char *path, char delim) *pos = delim; } -#ifdef CONFIG_CIFS_STATS #define cifs_stats_inc atomic_inc static inline void cifs_stats_bytes_written(struct cifs_tcon *tcon, @@ -1351,13 +1348,6 @@ static inline void cifs_stats_bytes_read(struct cifs_tcon *tcon, tcon->bytes_read += bytes; spin_unlock(&tcon->stat_lock); } -#else - -#define cifs_stats_inc(field) do {} while (0) -#define cifs_stats_bytes_written(tcon, bytes) do {} while (0) -#define cifs_stats_bytes_read(tcon, bytes) do {} while (0) - -#endif /* diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 53e8362cbc4a..dacb2c05674c 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -122,9 +122,7 @@ tconInfoAlloc(void) mutex_init(&ret_buf->crfid.fid_mutex); ret_buf->crfid.fid = kzalloc(sizeof(struct cifs_fid), GFP_KERNEL); -#ifdef CONFIG_CIFS_STATS spin_lock_init(&ret_buf->stat_lock); -#endif } return ret_buf; } diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 646dcd149de1..378151e09e91 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -624,7 +624,6 @@ cifs_query_file_info(const unsigned int xid, struct cifs_tcon *tcon, static void cifs_clear_stats(struct cifs_tcon *tcon) { -#ifdef CONFIG_CIFS_STATS atomic_set(&tcon->stats.cifs_stats.num_writes, 0); atomic_set(&tcon->stats.cifs_stats.num_reads, 0); atomic_set(&tcon->stats.cifs_stats.num_flushes, 0); @@ -646,13 +645,11 @@ cifs_clear_stats(struct cifs_tcon *tcon) atomic_set(&tcon->stats.cifs_stats.num_locks, 0); atomic_set(&tcon->stats.cifs_stats.num_acl_get, 0); atomic_set(&tcon->stats.cifs_stats.num_acl_set, 0); -#endif } static void cifs_print_stats(struct seq_file *m, struct cifs_tcon *tcon) { -#ifdef CONFIG_CIFS_STATS seq_printf(m, " Oplocks breaks: %d", atomic_read(&tcon->stats.cifs_stats.num_oplock_brks)); seq_printf(m, "\nReads: %d Bytes: %llu", @@ -684,7 +681,6 @@ cifs_print_stats(struct seq_file *m, struct cifs_tcon *tcon) atomic_read(&tcon->stats.cifs_stats.num_ffirst), atomic_read(&tcon->stats.cifs_stats.num_fnext), atomic_read(&tcon->stats.cifs_stats.num_fclose)); -#endif } static void diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 8929426ddaa6..831249001384 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -900,13 +900,11 @@ smb2_can_echo(struct TCP_Server_Info *server) static void smb2_clear_stats(struct cifs_tcon *tcon) { -#ifdef CONFIG_CIFS_STATS int i; for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) { atomic_set(&tcon->stats.smb2_stats.smb2_com_sent[i], 0); atomic_set(&tcon->stats.smb2_stats.smb2_com_failed[i], 0); } -#endif } static void @@ -945,7 +943,6 @@ smb2_dump_share_caps(struct seq_file *m, struct cifs_tcon *tcon) static void smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon) { -#ifdef CONFIG_CIFS_STATS atomic_t *sent = tcon->stats.smb2_stats.smb2_com_sent; atomic_t *failed = tcon->stats.smb2_stats.smb2_com_failed; @@ -995,7 +992,6 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon) seq_printf(m, "\nOplockBreaks: %d sent %d failed", atomic_read(&sent[SMB2_OPLOCK_BREAK_HE]), atomic_read(&failed[SMB2_OPLOCK_BREAK_HE])); -#endif } static void diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 0b4d7ebb812d..7c0b30321d9a 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -360,10 +360,8 @@ smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon, total_len); if (tcon != NULL) { -#ifdef CONFIG_CIFS_STATS uint16_t com_code = le16_to_cpu(smb2_command); cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_sent[com_code]); -#endif cifs_stats_inc(&tcon->num_smbs_sent); } -- cgit v1.2.3 From 52ce1ac4298309d76859307967c58835c0b2ce3e Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 31 Jul 2018 01:46:47 -0500 Subject: smb3: display bytes_read and bytes_written in smb3 stats We were only displaying bytes_read and bytes_written in cifs stats, fix smb3 stats to also display them. Sample output with this patch: cat /proc/fs/cifs/Stats: CIFS Session: 1 Share (unique mount targets): 2 SMB Request/Response Buffer: 1 Pool size: 5 SMB Small Req/Resp Buffer: 1 Pool size: 30 Operations (MIDs): 0 0 session 0 share reconnects Total vfs operations: 94 maximum at one time: 2 1) \\localhost\test SMBs: 214 Bytes read: 502092 Bytes written: 31457286 TreeConnects: 1 total 0 failed TreeDisconnects: 0 total 0 failed Creates: 52 total 3 failed Closes: 48 total 0 failed Flushes: 0 total 0 failed Reads: 17 total 0 failed Writes: 31 total 0 failed ... Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg --- fs/cifs/smb2ops.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'fs') diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 831249001384..85e848007f91 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -950,6 +950,9 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon) * Can't display SMB2_NEGOTIATE, SESSION_SETUP, LOGOFF, CANCEL and ECHO * totals (requests sent) since those SMBs are per-session not per tcon */ + seq_printf(m, "\nBytes read: %llu Bytes written: %llu", + (long long)(tcon->bytes_read), + (long long)(tcon->bytes_written)); seq_printf(m, "\nTreeConnects: %d total %d failed", atomic_read(&sent[SMB2_TREE_CONNECT_HE]), atomic_read(&failed[SMB2_TREE_CONNECT_HE])); -- cgit v1.2.3 From c281bc0c7412308c7ec0888904f7c99353da4796 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 1 Aug 2018 00:56:12 -0500 Subject: smb3: fix reset of bytes read and written stats echo 0 > /proc/fs/cifs/Stats is supposed to reset the stats but there were four (see example below) that were not reset (bytes read and witten, total vfs ops and max ops at one time). ... 0 session 0 share reconnects Total vfs operations: 100 maximum at one time: 2 1) \\localhost\test SMBs: 0 Bytes read: 502092 Bytes written: 31457286 TreeConnects: 0 total 0 failed TreeDisconnects: 0 total 0 failed ... This patch fixes cifs_stats_proc_write to properly reset those four. Signed-off-by: Steve French Reviewed-by: Aurelien Aptel --- fs/cifs/cifs_debug.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'fs') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 3270d9b74603..e074820bd4ed 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -381,6 +381,10 @@ static ssize_t cifs_stats_proc_write(struct file *file, atomic_set(&totBufAllocCount, 0); atomic_set(&totSmBufAllocCount, 0); #endif /* CONFIG_CIFS_STATS2 */ + spin_lock(&GlobalMid_Lock); + GlobalMaxActiveXid = 0; + GlobalCurrentXid = 0; + spin_unlock(&GlobalMid_Lock); spin_lock(&cifs_tcp_ses_lock); list_for_each(tmp1, &cifs_tcp_ses_list) { server = list_entry(tmp1, struct TCP_Server_Info, @@ -393,6 +397,10 @@ static ssize_t cifs_stats_proc_write(struct file *file, struct cifs_tcon, tcon_list); atomic_set(&tcon->num_smbs_sent, 0); + spin_lock(&tcon->stat_lock); + tcon->bytes_read = 0; + tcon->bytes_written = 0; + spin_unlock(&tcon->stat_lock); if (server->ops->clear_stats) server->ops->clear_stats(tcon); } -- cgit v1.2.3 From b2c96de7fe3cd306df039c89727cb137b89d82ef Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Wed, 1 Aug 2018 09:26:11 +1000 Subject: cifs: update init_sg, crypt_message to take an array of rqst These are used for SMB3 encryption and compounded requests. Update these functions and the other functions related to SMB3 encryption to take an array of requests. Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky --- fs/cifs/cifsglob.h | 7 +- fs/cifs/smb2ops.c | 206 +++++++++++++++++++++++++++------------------------- fs/cifs/transport.c | 27 +++++-- 3 files changed, 131 insertions(+), 109 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 4a3a737134ea..0553929e8339 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -454,10 +454,8 @@ struct smb_version_operations { long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t, loff_t); /* init transform request - used for encryption for now */ - int (*init_transform_rq)(struct TCP_Server_Info *, struct smb_rqst *, - struct smb_rqst *); - /* free transform request */ - void (*free_transform_rq)(struct smb_rqst *); + int (*init_transform_rq)(struct TCP_Server_Info *, int num_rqst, + struct smb_rqst *, struct smb_rqst *); int (*is_transform_hdr)(void *buf); int (*receive_transform)(struct TCP_Server_Info *, struct mid_q_entry **); @@ -1023,6 +1021,7 @@ struct tcon_link { }; extern struct tcon_link *cifs_sb_tlink(struct cifs_sb_info *cifs_sb); +extern void smb3_free_compound_rqst(int num_rqst, struct smb_rqst *rqst); static inline struct cifs_tcon * tlink_tcon(struct tcon_link *tlink) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 85e848007f91..ebc13ebebddf 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -2378,35 +2378,51 @@ static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf, sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf)); } -/* Assumes: - * rqst->rq_iov[0] is transform header - * rqst->rq_iov[1+] data to be encrypted/decrypted +/* Assumes the first rqst has a transform header as the first iov. + * I.e. + * rqst[0].rq_iov[0] is transform header + * rqst[0].rq_iov[1+] data to be encrypted/decrypted + * rqst[1+].rq_iov[0+] data to be encrypted/decrypted */ static struct scatterlist * -init_sg(struct smb_rqst *rqst, u8 *sign) +init_sg(int num_rqst, struct smb_rqst *rqst, u8 *sign) { - unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages + 1; - unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; + unsigned int sg_len; struct scatterlist *sg; unsigned int i; unsigned int j; + unsigned int idx = 0; + int skip; + + sg_len = 1; + for (i = 0; i < num_rqst; i++) + sg_len += rqst[i].rq_nvec + rqst[i].rq_npages; sg = kmalloc_array(sg_len, sizeof(struct scatterlist), GFP_KERNEL); if (!sg) return NULL; sg_init_table(sg, sg_len); - smb2_sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 20, assoc_data_len); - for (i = 1; i < rqst->rq_nvec; i++) - smb2_sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base, - rqst->rq_iov[i].iov_len); - for (j = 0; i < sg_len - 1; i++, j++) { - unsigned int len, offset; + for (i = 0; i < num_rqst; i++) { + for (j = 0; j < rqst[i].rq_nvec; j++) { + /* + * The first rqst has a transform header where the + * first 20 bytes are not part of the encrypted blob + */ + skip = (i == 0) && (j == 0) ? 20 : 0; + smb2_sg_set_buf(&sg[idx++], + rqst[i].rq_iov[j].iov_base + skip, + rqst[i].rq_iov[j].iov_len - skip); + } + + for (j = 0; j < rqst[i].rq_npages; j++) { + unsigned int len, offset; - rqst_page_get_length(rqst, j, &len, &offset); - sg_set_page(&sg[i], rqst->rq_pages[j], len, offset); + rqst_page_get_length(&rqst[i], j, &len, &offset); + sg_set_page(&sg[idx++], rqst[i].rq_pages[j], len, offset); + } } - smb2_sg_set_buf(&sg[sg_len - 1], sign, SMB2_SIGNATURE_SIZE); + smb2_sg_set_buf(&sg[idx], sign, SMB2_SIGNATURE_SIZE); return sg; } @@ -2438,10 +2454,11 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key) * untouched. */ static int -crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) +crypt_message(struct TCP_Server_Info *server, int num_rqst, + struct smb_rqst *rqst, int enc) { struct smb2_transform_hdr *tr_hdr = - (struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base; + (struct smb2_transform_hdr *)rqst[0].rq_iov[0].iov_base; unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; int rc = 0; struct scatterlist *sg; @@ -2492,7 +2509,7 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) crypt_len += SMB2_SIGNATURE_SIZE; } - sg = init_sg(rqst, sign); + sg = init_sg(num_rqst, rqst, sign); if (!sg) { cifs_dbg(VFS, "%s: Failed to init sg", __func__); rc = -ENOMEM; @@ -2529,103 +2546,98 @@ free_req: return rc; } +void +smb3_free_compound_rqst(int num_rqst, struct smb_rqst *rqst) +{ + int i, j; + + for (i = 0; i < num_rqst; i++) { + if (rqst[i].rq_pages) { + for (j = rqst[i].rq_npages - 1; j >= 0; j--) + put_page(rqst[i].rq_pages[j]); + kfree(rqst[i].rq_pages); + } + } +} + +/* + * This function will initialize new_rq and encrypt the content. + * The first entry, new_rq[0], only contains a single iov which contains + * a smb2_transform_hdr and is pre-allocated by the caller. + * This function then populates new_rq[1+] with the content from olq_rq[0+]. + * + * The end result is an array of smb_rqst structures where the first structure + * only contains a single iov for the transform header which we then can pass + * to crypt_message(). + * + * new_rq[0].rq_iov[0] : smb2_transform_hdr pre-allocated by the caller + * new_rq[1+].rq_iov[*] == old_rq[0+].rq_iov[*] : SMB2/3 requests + */ static int -smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq, - struct smb_rqst *old_rq) +smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst, + struct smb_rqst *new_rq, struct smb_rqst *old_rq) { - struct kvec *iov; struct page **pages; - struct smb2_transform_hdr *tr_hdr; - unsigned int npages = old_rq->rq_npages; - unsigned int orig_len; - int i; + struct smb2_transform_hdr *tr_hdr = new_rq[0].rq_iov[0].iov_base; + unsigned int npages; + unsigned int orig_len = 0; + int i, j; int rc = -ENOMEM; - pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); - if (!pages) - return rc; - - new_rq->rq_pages = pages; - new_rq->rq_offset = old_rq->rq_offset; - new_rq->rq_npages = old_rq->rq_npages; - new_rq->rq_pagesz = old_rq->rq_pagesz; - new_rq->rq_tailsz = old_rq->rq_tailsz; - - for (i = 0; i < npages; i++) { - pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM); - if (!pages[i]) - goto err_free_pages; - } - - iov = kmalloc_array(old_rq->rq_nvec + 1, sizeof(struct kvec), - GFP_KERNEL); - if (!iov) - goto err_free_pages; + for (i = 1; i < num_rqst; i++) { + npages = old_rq[i - 1].rq_npages; + pages = kmalloc_array(npages, sizeof(struct page *), + GFP_KERNEL); + if (!pages) + goto err_free; + + new_rq[i].rq_pages = pages; + new_rq[i].rq_npages = npages; + new_rq[i].rq_offset = old_rq[i - 1].rq_offset; + new_rq[i].rq_pagesz = old_rq[i - 1].rq_pagesz; + new_rq[i].rq_tailsz = old_rq[i - 1].rq_tailsz; + new_rq[i].rq_iov = old_rq[i - 1].rq_iov; + new_rq[i].rq_nvec = old_rq[i - 1].rq_nvec; + + orig_len += smb_rqst_len(server, &old_rq[i - 1]); + + for (j = 0; j < npages; j++) { + pages[j] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM); + if (!pages[j]) + goto err_free; + } - /* copy all iovs from the old */ - memcpy(&iov[1], &old_rq->rq_iov[0], - sizeof(struct kvec) * old_rq->rq_nvec); + /* copy pages form the old */ + for (j = 0; j < npages; j++) { + char *dst, *src; + unsigned int offset, len; - new_rq->rq_iov = iov; - new_rq->rq_nvec = old_rq->rq_nvec + 1; + rqst_page_get_length(&new_rq[i], j, &len, &offset); - tr_hdr = kmalloc(sizeof(struct smb2_transform_hdr), GFP_KERNEL); - if (!tr_hdr) - goto err_free_iov; + dst = (char *) kmap(new_rq[i].rq_pages[j]) + offset; + src = (char *) kmap(old_rq[i - 1].rq_pages[j]) + offset; - orig_len = smb_rqst_len(server, old_rq); + memcpy(dst, src, len); + kunmap(new_rq[i].rq_pages[j]); + kunmap(old_rq[i - 1].rq_pages[j]); + } + } - /* fill the 2nd iov with a transform header */ + /* fill the 1st iov with a transform header */ fill_transform_hdr(tr_hdr, orig_len, old_rq); - new_rq->rq_iov[0].iov_base = tr_hdr; - new_rq->rq_iov[0].iov_len = sizeof(struct smb2_transform_hdr); - - /* copy pages form the old */ - for (i = 0; i < npages; i++) { - char *dst, *src; - unsigned int offset, len; - - rqst_page_get_length(new_rq, i, &len, &offset); - dst = (char *) kmap(new_rq->rq_pages[i]) + offset; - src = (char *) kmap(old_rq->rq_pages[i]) + offset; - - memcpy(dst, src, len); - kunmap(new_rq->rq_pages[i]); - kunmap(old_rq->rq_pages[i]); - } - - rc = crypt_message(server, new_rq, 1); + rc = crypt_message(server, num_rqst, new_rq, 1); cifs_dbg(FYI, "encrypt message returned %d", rc); if (rc) - goto err_free_tr_hdr; + goto err_free; return rc; -err_free_tr_hdr: - kfree(tr_hdr); -err_free_iov: - kfree(iov); -err_free_pages: - for (i = i - 1; i >= 0; i--) - put_page(pages[i]); - kfree(pages); +err_free: + smb3_free_compound_rqst(num_rqst - 1, &new_rq[1]); return rc; } -static void -smb3_free_transform_rq(struct smb_rqst *rqst) -{ - int i = rqst->rq_npages - 1; - - for (; i >= 0; i--) - put_page(rqst->rq_pages[i]); - kfree(rqst->rq_pages); - /* free transform header */ - kfree(rqst->rq_iov[0].iov_base); - kfree(rqst->rq_iov); -} - static int smb3_is_transform_hdr(void *buf) { @@ -2655,7 +2667,7 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf, rqst.rq_pagesz = PAGE_SIZE; rqst.rq_tailsz = (page_data_size % PAGE_SIZE) ? : PAGE_SIZE; - rc = crypt_message(server, &rqst, 0); + rc = crypt_message(server, 1, &rqst, 0); cifs_dbg(FYI, "decrypt message returned %d\n", rc); if (rc) @@ -3302,7 +3314,6 @@ struct smb_version_operations smb30_operations = { .fallocate = smb3_fallocate, .enum_snapshots = smb3_enum_snapshots, .init_transform_rq = smb3_init_transform_rq, - .free_transform_rq = smb3_free_transform_rq, .is_transform_hdr = smb3_is_transform_hdr, .receive_transform = smb3_receive_transform, .get_dfs_refer = smb2_get_dfs_refer, @@ -3408,7 +3419,6 @@ struct smb_version_operations smb311_operations = { .fallocate = smb3_fallocate, .enum_snapshots = smb3_enum_snapshots, .init_transform_rq = smb3_init_transform_rq, - .free_transform_rq = smb3_free_transform_rq, .is_transform_hdr = smb3_is_transform_hdr, .receive_transform = smb3_receive_transform, .get_dfs_refer = smb2_get_dfs_refer, diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 357d25351ffa..8039c93ba57a 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -374,27 +374,40 @@ smbd_done: return rc; } +#define MAX_COMPOUND 2 + static int smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags) { - struct smb_rqst cur_rqst; + struct kvec iov; + struct smb2_transform_hdr tr_hdr; + struct smb_rqst cur_rqst[MAX_COMPOUND]; int rc; if (!(flags & CIFS_TRANSFORM_REQ)) return __smb_send_rqst(server, 1, rqst); - if (!server->ops->init_transform_rq || - !server->ops->free_transform_rq) { - cifs_dbg(VFS, "Encryption requested but transform callbacks are missed\n"); + memset(&cur_rqst[0], 0, sizeof(cur_rqst)); + memset(&iov, 0, sizeof(iov)); + memset(&tr_hdr, 0, sizeof(tr_hdr)); + + iov.iov_base = &tr_hdr; + iov.iov_len = sizeof(tr_hdr); + cur_rqst[0].rq_iov = &iov; + cur_rqst[0].rq_nvec = 1; + + if (!server->ops->init_transform_rq) { + cifs_dbg(VFS, "Encryption requested but transform callback " + "is missing\n"); return -EIO; } - rc = server->ops->init_transform_rq(server, &cur_rqst, rqst); + rc = server->ops->init_transform_rq(server, 2, &cur_rqst[0], rqst); if (rc) return rc; - rc = __smb_send_rqst(server, 1, &cur_rqst); - server->ops->free_transform_rq(&cur_rqst); + rc = __smb_send_rqst(server, 2, &cur_rqst[0]); + smb3_free_compound_rqst(1, &cur_rqst[1]); return rc; } -- cgit v1.2.3 From 1f3a8f5f7ac3de4abae9d2c118ffaeed1676fe1c Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Wed, 1 Aug 2018 09:26:12 +1000 Subject: cifs: make smb_send_rqst take an array of requests Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky --- fs/cifs/transport.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 8039c93ba57a..169e767ff57f 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -374,10 +374,11 @@ smbd_done: return rc; } -#define MAX_COMPOUND 2 +#define MAX_COMPOUND 5 static int -smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags) +smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, + struct smb_rqst *rqst, int flags) { struct kvec iov; struct smb2_transform_hdr tr_hdr; @@ -385,7 +386,10 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags) int rc; if (!(flags & CIFS_TRANSFORM_REQ)) - return __smb_send_rqst(server, 1, rqst); + return __smb_send_rqst(server, num_rqst, rqst); + + if (num_rqst > MAX_COMPOUND - 1) + return -ENOMEM; memset(&cur_rqst[0], 0, sizeof(cur_rqst)); memset(&iov, 0, sizeof(iov)); @@ -402,12 +406,13 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags) return -EIO; } - rc = server->ops->init_transform_rq(server, 2, &cur_rqst[0], rqst); + rc = server->ops->init_transform_rq(server, num_rqst + 1, + &cur_rqst[0], rqst); if (rc) return rc; - rc = __smb_send_rqst(server, 2, &cur_rqst[0]); - smb3_free_compound_rqst(1, &cur_rqst[1]); + rc = __smb_send_rqst(server, num_rqst + 1, &cur_rqst[0]); + smb3_free_compound_rqst(num_rqst, &cur_rqst[1]); return rc; } @@ -621,7 +626,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, */ cifs_save_when_sent(mid); cifs_in_send_inc(server); - rc = smb_send_rqst(server, rqst, flags); + rc = smb_send_rqst(server, 1, rqst, flags); cifs_in_send_dec(server); if (rc < 0) { @@ -811,7 +816,7 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, midQ->mid_state = MID_REQUEST_SUBMITTED; cifs_in_send_inc(ses->server); - rc = smb_send_rqst(ses->server, rqst, flags); + rc = smb_send_rqst(ses->server, 1, rqst, flags); cifs_in_send_dec(ses->server); cifs_save_when_sent(midQ); -- cgit v1.2.3 From e0bba0b8548179b696e86c158ea8f45f2ef6ad14 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Wed, 1 Aug 2018 09:26:13 +1000 Subject: cifs: add compound_send_recv() Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky --- fs/cifs/cifsproto.h | 4 ++ fs/cifs/transport.c | 156 ++++++++++++++++++++++++++++++---------------------- 2 files changed, 94 insertions(+), 66 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 7ead1a9ac6fb..20adda4de83b 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -94,6 +94,10 @@ extern int cifs_call_async(struct TCP_Server_Info *server, extern int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, struct smb_rqst *rqst, int *resp_buf_type, const int flags, struct kvec *resp_iov); +extern int compound_send_recv(const unsigned int xid, struct cifs_ses *ses, + const int flags, const int num_rqst, + struct smb_rqst *rqst, int *resp_buf_type, + struct kvec *resp_iov); extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *, struct smb_hdr * /* input */ , struct smb_hdr * /* out */ , diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 169e767ff57f..0b9d0e859f86 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -766,20 +766,21 @@ cifs_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst) } int -cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, - struct smb_rqst *rqst, int *resp_buf_type, const int flags, - struct kvec *resp_iov) +compound_send_recv(const unsigned int xid, struct cifs_ses *ses, + const int flags, const int num_rqst, struct smb_rqst *rqst, + int *resp_buf_type, struct kvec *resp_iov) { - int rc = 0; + int i, j, rc = 0; int timeout, optype; - struct mid_q_entry *midQ; + struct mid_q_entry *midQ[MAX_COMPOUND]; unsigned int credits = 1; char *buf; timeout = flags & CIFS_TIMEOUT_MASK; optype = flags & CIFS_OP_MASK; - *resp_buf_type = CIFS_NO_BUFFER; /* no response buf yet */ + for (i = 0; i < num_rqst; i++) + resp_buf_type[i] = CIFS_NO_BUFFER; /* no response buf yet */ if ((ses == NULL) || (ses->server == NULL)) { cifs_dbg(VFS, "Null session\n"); @@ -806,93 +807,116 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, mutex_lock(&ses->server->srv_mutex); - midQ = ses->server->ops->setup_request(ses, rqst); - if (IS_ERR(midQ)) { - mutex_unlock(&ses->server->srv_mutex); - /* Update # of requests on wire to server */ - add_credits(ses->server, 1, optype); - return PTR_ERR(midQ); + for (i = 0; i < num_rqst; i++) { + midQ[i] = ses->server->ops->setup_request(ses, &rqst[i]); + if (IS_ERR(midQ[i])) { + for (j = 0; j < i; j++) + cifs_delete_mid(midQ[j]); + mutex_unlock(&ses->server->srv_mutex); + /* Update # of requests on wire to server */ + add_credits(ses->server, 1, optype); + return PTR_ERR(midQ[i]); + } + + midQ[i]->mid_state = MID_REQUEST_SUBMITTED; } - midQ->mid_state = MID_REQUEST_SUBMITTED; cifs_in_send_inc(ses->server); - rc = smb_send_rqst(ses->server, 1, rqst, flags); + rc = smb_send_rqst(ses->server, num_rqst, rqst, flags); cifs_in_send_dec(ses->server); - cifs_save_when_sent(midQ); + + for (i = 0; i < num_rqst; i++) + cifs_save_when_sent(midQ[i]); if (rc < 0) ses->server->sequence_number -= 2; + mutex_unlock(&ses->server->srv_mutex); - if (rc < 0) - goto out; + for (i = 0; i < num_rqst; i++) { + if (rc < 0) + goto out; - if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) - smb311_update_preauth_hash(ses, rqst->rq_iov, - rqst->rq_nvec); + if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) + smb311_update_preauth_hash(ses, rqst[i].rq_iov, + rqst[i].rq_nvec); - if (timeout == CIFS_ASYNC_OP) - goto out; + if (timeout == CIFS_ASYNC_OP) + goto out; - rc = wait_for_response(ses->server, midQ); - if (rc != 0) { - cifs_dbg(FYI, "Cancelling wait for mid %llu\n", midQ->mid); - send_cancel(ses->server, rqst, midQ); - spin_lock(&GlobalMid_Lock); - if (midQ->mid_state == MID_REQUEST_SUBMITTED) { - midQ->mid_flags |= MID_WAIT_CANCELLED; - midQ->callback = DeleteMidQEntry; + rc = wait_for_response(ses->server, midQ[i]); + if (rc != 0) { + cifs_dbg(FYI, "Cancelling wait for mid %llu\n", + midQ[i]->mid); + send_cancel(ses->server, &rqst[i], midQ[i]); + spin_lock(&GlobalMid_Lock); + if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) { + midQ[i]->mid_flags |= MID_WAIT_CANCELLED; + midQ[i]->callback = DeleteMidQEntry; + spin_unlock(&GlobalMid_Lock); + add_credits(ses->server, 1, optype); + return rc; + } spin_unlock(&GlobalMid_Lock); + } + + rc = cifs_sync_mid_result(midQ[i], ses->server); + if (rc != 0) { add_credits(ses->server, 1, optype); return rc; } - spin_unlock(&GlobalMid_Lock); - } - - rc = cifs_sync_mid_result(midQ, ses->server); - if (rc != 0) { - add_credits(ses->server, 1, optype); - return rc; - } - if (!midQ->resp_buf || midQ->mid_state != MID_RESPONSE_RECEIVED) { - rc = -EIO; - cifs_dbg(FYI, "Bad MID state?\n"); - goto out; - } - - buf = (char *)midQ->resp_buf; - resp_iov->iov_base = buf; - resp_iov->iov_len = midQ->resp_buf_size + - ses->server->vals->header_preamble_size; - if (midQ->large_buf) - *resp_buf_type = CIFS_LARGE_BUFFER; - else - *resp_buf_type = CIFS_SMALL_BUFFER; + if (!midQ[i]->resp_buf || + midQ[i]->mid_state != MID_RESPONSE_RECEIVED) { + rc = -EIO; + cifs_dbg(FYI, "Bad MID state?\n"); + goto out; + } - if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) { - struct kvec iov = { - .iov_base = resp_iov->iov_base, - .iov_len = resp_iov->iov_len - }; - smb311_update_preauth_hash(ses, &iov, 1); - } + buf = (char *)midQ[i]->resp_buf; + resp_iov[i].iov_base = buf; + resp_iov[i].iov_len = midQ[i]->resp_buf_size + + ses->server->vals->header_preamble_size; + + if (midQ[i]->large_buf) + resp_buf_type[i] = CIFS_LARGE_BUFFER; + else + resp_buf_type[i] = CIFS_SMALL_BUFFER; + + if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) { + struct kvec iov = { + .iov_base = resp_iov[i].iov_base, + .iov_len = resp_iov[i].iov_len + }; + smb311_update_preauth_hash(ses, &iov, 1); + } - credits = ses->server->ops->get_credits(midQ); + credits = ses->server->ops->get_credits(midQ[i]); - rc = ses->server->ops->check_receive(midQ, ses->server, - flags & CIFS_LOG_ERROR); + rc = ses->server->ops->check_receive(midQ[i], ses->server, + flags & CIFS_LOG_ERROR); - /* mark it so buf will not be freed by cifs_delete_mid */ - if ((flags & CIFS_NO_RESP) == 0) - midQ->resp_buf = NULL; + /* mark it so buf will not be freed by cifs_delete_mid */ + if ((flags & CIFS_NO_RESP) == 0) + midQ[i]->resp_buf = NULL; + } out: - cifs_delete_mid(midQ); + for (i = 0; i < num_rqst; i++) + cifs_delete_mid(midQ[i]); add_credits(ses->server, credits, optype); return rc; } +int +cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, + struct smb_rqst *rqst, int *resp_buf_type, const int flags, + struct kvec *resp_iov) +{ + return compound_send_recv(xid, ses, flags, 1, rqst, resp_buf_type, + resp_iov); +} + int SendReceive2(const unsigned int xid, struct cifs_ses *ses, struct kvec *iov, int n_vec, int *resp_buf_type /* ret */, -- cgit v1.2.3 From 020eec5f712ffb4254233490076cc21600b810db Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 1 Aug 2018 16:38:07 -0500 Subject: smb3: add tracepoint for slow responses If responses take longer than one second from the server, we can optionally log them to dmesg in current cifs.ko code (CONFIG_CIFS_STATS2 must be configured and a /proc/fs/cifs/cifsFYI flag must be set), but can be more useful to log these via ftrace (tracepoint is smb3_slow_rsp) which is easier and more granular (still requires CONFIG_CIFS_STATS2 to be configured in the build though). Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky --- fs/cifs/trace.h | 37 +++++++++++++++++++++++++++++++++++++ fs/cifs/transport.c | 8 ++++++-- 2 files changed, 43 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/cifs/trace.h b/fs/cifs/trace.h index 6b50b57e2416..d4aed5217a56 100644 --- a/fs/cifs/trace.h +++ b/fs/cifs/trace.h @@ -283,6 +283,43 @@ DEFINE_EVENT(smb3_cmd_done_class, smb3_##name, \ DEFINE_SMB3_CMD_DONE_EVENT(cmd_done); DEFINE_SMB3_CMD_DONE_EVENT(ses_expired); +DECLARE_EVENT_CLASS(smb3_mid_class, + TP_PROTO(__u16 cmd, + __u64 mid, + __u32 pid, + unsigned long when_sent, + unsigned long when_received), + TP_ARGS(cmd, mid, pid, when_sent, when_received), + TP_STRUCT__entry( + __field(__u16, cmd) + __field(__u64, mid) + __field(__u32, pid) + __field(unsigned long, when_sent) + __field(unsigned long, when_received) + ), + TP_fast_assign( + __entry->cmd = cmd; + __entry->mid = mid; + __entry->pid = pid; + __entry->when_sent = when_sent; + __entry->when_received = when_received; + ), + TP_printk("\tcmd=%u mid=%llu pid=%u, when_sent=%lu when_rcv=%lu", + __entry->cmd, __entry->mid, __entry->pid, __entry->when_sent, + __entry->when_received) +) + +#define DEFINE_SMB3_MID_EVENT(name) \ +DEFINE_EVENT(smb3_mid_class, smb3_##name, \ + TP_PROTO(__u16 cmd, \ + __u64 mid, \ + __u32 pid, \ + unsigned long when_sent, \ + unsigned long when_received), \ + TP_ARGS(cmd, mid, pid, when_sent, when_received)) + +DEFINE_SMB3_MID_EVENT(slow_rsp); + DECLARE_EVENT_CLASS(smb3_exit_err_class, TP_PROTO(unsigned int xid, const char *func_name, diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0b9d0e859f86..92de5c528161 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -115,8 +115,12 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) now = jiffies; /* commands taking longer than one second are indications that something is wrong, unless it is quite a slow link or server */ - if (time_after(now, midEntry->when_alloc + HZ)) { - if ((cifsFYI & CIFS_TIMER) && (midEntry->command != command)) { + if (time_after(now, midEntry->when_alloc + HZ) && + (midEntry->command != command)) { + trace_smb3_slow_rsp(le16_to_cpu(midEntry->command), + midEntry->mid, midEntry->pid, + midEntry->when_sent, midEntry->when_received); + if (cifsFYI & CIFS_TIMER) { pr_debug(" CIFS slow rsp: cmd %d mid %llu", midEntry->command, midEntry->mid); pr_info(" A: 0x%lx S: 0x%lx R: 0x%lx\n", -- cgit v1.2.3 From d258650004617fbd5dfe97d77d26fb37187d06e9 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 1 Aug 2018 22:34:04 -0500 Subject: smb3: fix minor debug output for CONFIG_CIFS_STATS CONFIG_CIFS_STATS is now always enabled (to simplify the code and since the STATS are important for some common customer use cases and also debugging), but needed one minor change so that STATS shows as enabled in the debug output in /proc/fs/cifs/DebugData, otherwise it could get confusing with STATS no longer showing up in the "Features" list in /proc/fs/cifs/DebugData when basic stats were in fact available. Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg --- fs/cifs/cifs_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index e074820bd4ed..748cabd6d20b 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -170,7 +170,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) #endif #ifdef CONFIG_CIFS_STATS2 seq_printf(m, ",STATS2"); -#elif defined(CONFIG_CIFS_STATS) +#else seq_printf(m, ",STATS"); #endif #ifdef CONFIG_CIFS_DEBUG2 -- cgit v1.2.3 From fd09b7d3b352105f08b8e02f7afecf7e816380ef Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 2 Aug 2018 20:28:18 -0500 Subject: smb3: Do not send SMB3 SET_INFO if nothing changed An earlier commit had a typo which prevented the optimization from working: commit 18dd8e1a65dd ("Do not send SMB3 SET_INFO request if nothing is changing") Thank you to Metze for noticing this. Also clear a reserved field in the FILE_BASIC_INFO struct we send that should be zero (all the other fields in that struct were set or cleared explicitly already in cifs_set_file_info). Reviewed-by: Pavel Shilovsky CC: Stable # 4.9.x+ Reported-by: Stefan Metzmacher Signed-off-by: Steve French --- fs/cifs/inode.c | 2 ++ fs/cifs/smb2inode.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 054e880c1dac..d32eaa4b2437 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1120,6 +1120,8 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid, if (!server->ops->set_file_info) return -ENOSYS; + info_buf.Pad = 0; + if (attrs->ia_valid & ATTR_ATIME) { set_time = true; info_buf.LastAccessTime = diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index f22cbc0d1869..1eef1791d0c4 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c @@ -283,7 +283,7 @@ smb2_set_file_info(struct inode *inode, const char *full_path, int rc; if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) && - (buf->LastWriteTime == 0) && (buf->ChangeTime) && + (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) && (buf->Attributes == 0)) return 0; /* would be a no op, no sense sending this */ -- cgit v1.2.3 From a5c62f4833c2c8e6e0f35367b99b717b78f5c029 Mon Sep 17 00:00:00 2001 From: Aurelien Aptel Date: Thu, 2 Aug 2018 16:39:52 +0200 Subject: CIFS: fix uninitialized ptr deref in smb2 signing server->secmech.sdeschmacsha256 is not properly initialized before smb2_shash_allocate(), set shash after that call. also fix typo in error message Fixes: 8de8c4608fe9 ("cifs: Fix validation of signed data in smb2") Signed-off-by: Aurelien Aptel Reviewed-by: Paulo Alcantara Reported-by: Xiaoli Feng Signed-off-by: Steve French CC: Stable --- fs/cifs/smb2transport.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 3f778937c0e2..7b351c65ee46 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c @@ -171,7 +171,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) struct kvec *iov = rqst->rq_iov; struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base; struct cifs_ses *ses; - struct shash_desc *shash = &server->secmech.sdeschmacsha256->shash; + struct shash_desc *shash; struct smb_rqst drqst; ses = smb2_find_smb_ses(server, shdr->SessionId); @@ -185,7 +185,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) rc = smb2_crypto_shash_allocate(server); if (rc) { - cifs_dbg(VFS, "%s: shah256 alloc failed\n", __func__); + cifs_dbg(VFS, "%s: sha256 alloc failed\n", __func__); return rc; } @@ -196,6 +196,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) return rc; } + shash = &server->secmech.sdeschmacsha256->shash; rc = crypto_shash_init(shash); if (rc) { cifs_dbg(VFS, "%s: Could not init sha256", __func__); -- cgit v1.2.3 From 468d677954c0d94fec59275d91222257fe8b4416 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 4 Aug 2018 05:24:34 -0500 Subject: smb3: display stats counters for number of slow commands When CONFIG_CIFS_STATS2 is enabled keep counters for slow commands (ie server took longer than 1 second to respond) by SMB2/SMB3 command code. This can help in diagnosing whether performance problems are on server (instead of client) and which commands are causing the problem. Sample output (the new lines contain words "slow responses ...") $ cat /proc/fs/cifs/Stats Resources in use CIFS Session: 1 Share (unique mount targets): 2 SMB Request/Response Buffer: 1 Pool size: 5 SMB Small Req/Resp Buffer: 1 Pool size: 30 Total Large 10 Small 490 Allocations Operations (MIDs): 0 0 session 0 share reconnects Total vfs operations: 67 maximum at one time: 2 4 slow responses from localhost for command 5 1 slow responses from localhost for command 6 1 slow responses from localhost for command 14 1 slow responses from localhost for command 16 1) \\localhost\test SMBs: 243 Bytes read: 1024000 Bytes written: 104857600 TreeConnects: 1 total 0 failed TreeDisconnects: 0 total 0 failed Creates: 40 total 0 failed Closes: 39 total 0 failed ... Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky Reviewed-by: Aurelien Aptel --- fs/cifs/cifs_debug.c | 19 +++++++++++++++++-- fs/cifs/cifsglob.h | 3 ++- fs/cifs/transport.c | 5 +++++ 3 files changed, 24 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 748cabd6d20b..f1fbea947fef 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -378,6 +378,8 @@ static ssize_t cifs_stats_proc_write(struct file *file, rc = kstrtobool_from_user(buffer, count, &bv); if (rc == 0) { #ifdef CONFIG_CIFS_STATS2 + int i; + atomic_set(&totBufAllocCount, 0); atomic_set(&totSmBufAllocCount, 0); #endif /* CONFIG_CIFS_STATS2 */ @@ -389,6 +391,10 @@ static ssize_t cifs_stats_proc_write(struct file *file, list_for_each(tmp1, &cifs_tcp_ses_list) { server = list_entry(tmp1, struct TCP_Server_Info, tcp_ses_list); +#ifdef CONFIG_CIFS_STATS2 + for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) + atomic_set(&server->smb2slowcmd[i], 0); +#endif /* CONFIG_CIFS_STATS2 */ list_for_each(tmp2, &server->smb_ses_list) { ses = list_entry(tmp2, struct cifs_ses, smb_ses_list); @@ -417,13 +423,15 @@ static ssize_t cifs_stats_proc_write(struct file *file, static int cifs_stats_proc_show(struct seq_file *m, void *v) { int i; +#ifdef CONFIG_CIFS_STATS2 + int j; +#endif /* STATS2 */ struct list_head *tmp1, *tmp2, *tmp3; struct TCP_Server_Info *server; struct cifs_ses *ses; struct cifs_tcon *tcon; - seq_printf(m, - "Resources in use\nCIFS Session: %d\n", + seq_printf(m, "Resources in use\nCIFS Session: %d\n", sesInfoAllocCount.counter); seq_printf(m, "Share (unique mount targets): %d\n", tconInfoAllocCount.counter); @@ -452,6 +460,13 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v) list_for_each(tmp1, &cifs_tcp_ses_list) { server = list_entry(tmp1, struct TCP_Server_Info, tcp_ses_list); +#ifdef CONFIG_CIFS_STATS2 + for (j = 0; j < NUMBER_OF_SMB2_COMMANDS; j++) + if (atomic_read(&server->smb2slowcmd[j])) + seq_printf(m, "%d slow responses from %s for command %d\n", + atomic_read(&server->smb2slowcmd[j]), + server->hostname, j); +#endif /* STATS2 */ list_for_each(tmp2, &server->smb_ses_list) { ses = list_entry(tmp2, struct cifs_ses, smb_ses_list); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 0553929e8339..41803d374da0 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -680,7 +680,8 @@ struct TCP_Server_Info { #ifdef CONFIG_CIFS_STATS2 atomic_t in_send; /* requests trying to send */ atomic_t num_waiters; /* blocked waiting to get in sendrecv */ -#endif + atomic_t smb2slowcmd[NUMBER_OF_SMB2_COMMANDS]; /* count resps > 1 sec */ +#endif /* STATS2 */ unsigned int max_read; unsigned int max_write; __le16 cipher_type; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 92de5c528161..c53c0908d4c6 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -117,6 +117,11 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) something is wrong, unless it is quite a slow link or server */ if (time_after(now, midEntry->when_alloc + HZ) && (midEntry->command != command)) { + /* smb2slowcmd[NUMBER_OF_SMB2_COMMANDS] counts by command */ + if ((le16_to_cpu(midEntry->command) < NUMBER_OF_SMB2_COMMANDS) && + (le16_to_cpu(midEntry->command) >= 0)) + cifs_stats_inc(&midEntry->server->smb2slowcmd[le16_to_cpu(midEntry->command)]); + trace_smb3_slow_rsp(le16_to_cpu(midEntry->command), midEntry->mid, midEntry->pid, midEntry->when_sent, midEntry->when_received); -- cgit v1.2.3 From 8eb4ecfab03d21146e144b0693ce96839d58202d Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Wed, 1 Aug 2018 09:26:16 +1000 Subject: cifs: add SMB2_close_init()/SMB2_close_free() Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky Reviewed-by: Paulo Alcantara --- fs/cifs/smb2pdu.c | 48 ++++++++++++++++++++++++++++++++++-------------- fs/cifs/smb2proto.h | 3 +++ 2 files changed, 37 insertions(+), 14 deletions(-) (limited to 'fs') diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 7c0b30321d9a..78c7190f2295 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2444,44 +2444,63 @@ SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon, return rc; } +int +SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, + u64 persistent_fid, u64 volatile_fid) +{ + struct smb2_close_req *req; + struct kvec *iov = rqst->rq_iov; + unsigned int total_len; + int rc; + + rc = smb2_plain_req_init(SMB2_CLOSE, tcon, (void **) &req, &total_len); + if (rc) + return rc; + + req->PersistentFileId = persistent_fid; + req->VolatileFileId = volatile_fid; + iov[0].iov_base = (char *)req; + iov[0].iov_len = total_len; + + return 0; +} + +void +SMB2_close_free(struct smb_rqst *rqst) +{ + cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */ +} + int SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, int flags) { struct smb_rqst rqst; - struct smb2_close_req *req; - struct smb2_close_rsp *rsp; + struct smb2_close_rsp *rsp = NULL; struct cifs_ses *ses = tcon->ses; struct kvec iov[1]; struct kvec rsp_iov; int resp_buftype; int rc = 0; - unsigned int total_len; cifs_dbg(FYI, "Close\n"); if (!ses || !(ses->server)) return -EIO; - rc = smb2_plain_req_init(SMB2_CLOSE, tcon, (void **) &req, &total_len); - if (rc) - return rc; - if (smb3_encryption_required(tcon)) flags |= CIFS_TRANSFORM_REQ; - req->PersistentFileId = persistent_fid; - req->VolatileFileId = volatile_fid; - - iov[0].iov_base = (char *)req; - iov[0].iov_len = total_len; - memset(&rqst, 0, sizeof(struct smb_rqst)); + memset(&iov, 0, sizeof(iov)); rqst.rq_iov = iov; rqst.rq_nvec = 1; + rc = SMB2_close_init(tcon, &rqst, persistent_fid, volatile_fid); + if (rc) + goto close_exit; + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); - cifs_small_buf_release(req); rsp = (struct smb2_close_rsp *)rsp_iov.iov_base; if (rc != 0) { @@ -2494,6 +2513,7 @@ SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon, /* BB FIXME - decode close response, update inode for caching */ close_exit: + SMB2_close_free(&rqst); free_rsp_buf(resp_buftype, rsp); return rc; } diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 19aa483395c7..fdd8c78648c6 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -141,6 +141,9 @@ extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_file_id, u64 volatile_file_id); extern int SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, int flags); +extern int SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, + u64 persistent_file_id, u64 volatile_file_id); +extern void SMB2_close_free(struct smb_rqst *rqst); extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_file_id, u64 volatile_file_id); extern int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon, -- cgit v1.2.3 From 296ecbae7fdf209b1e0fb08b8bd82e5e9b637439 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Wed, 1 Aug 2018 09:26:17 +1000 Subject: cifs: add SMB2_query_info_[init|free]() Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky Reviewed-by: Paulo Alcantara --- fs/cifs/smb2pdu.c | 68 ++++++++++++++++++++++++++++++++++++----------------- fs/cifs/smb2proto.h | 5 ++++ 2 files changed, 51 insertions(+), 22 deletions(-) (limited to 'fs') diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 78c7190f2295..821f21d4ada7 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2580,36 +2580,22 @@ validate_and_copy_iov(unsigned int offset, unsigned int buffer_length, return 0; } -static int -query_info(const unsigned int xid, struct cifs_tcon *tcon, - u64 persistent_fid, u64 volatile_fid, u8 info_class, u8 info_type, - u32 additional_info, size_t output_len, size_t min_len, void **data, - u32 *dlen) +int +SMB2_query_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, + u64 persistent_fid, u64 volatile_fid, + u8 info_class, u8 info_type, u32 additional_info, + size_t output_len) { - struct smb_rqst rqst; struct smb2_query_info_req *req; - struct smb2_query_info_rsp *rsp = NULL; - struct kvec iov[2]; - struct kvec rsp_iov; - int rc = 0; - int resp_buftype; - struct cifs_ses *ses = tcon->ses; - int flags = 0; + struct kvec *iov = rqst->rq_iov; unsigned int total_len; - - cifs_dbg(FYI, "Query Info\n"); - - if (!ses || !(ses->server)) - return -EIO; + int rc; rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, (void **) &req, &total_len); if (rc) return rc; - if (smb3_encryption_required(tcon)) - flags |= CIFS_TRANSFORM_REQ; - req->InfoType = info_type; req->FileInfoClass = info_class; req->PersistentFileId = persistent_fid; @@ -2626,13 +2612,50 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, iov[0].iov_base = (char *)req; /* 1 for Buffer */ iov[0].iov_len = total_len - 1; + return 0; +} + +void +SMB2_query_info_free(struct smb_rqst *rqst) +{ + cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */ +} + +static int +query_info(const unsigned int xid, struct cifs_tcon *tcon, + u64 persistent_fid, u64 volatile_fid, u8 info_class, u8 info_type, + u32 additional_info, size_t output_len, size_t min_len, void **data, + u32 *dlen) +{ + struct smb_rqst rqst; + struct smb2_query_info_rsp *rsp = NULL; + struct kvec iov[1]; + struct kvec rsp_iov; + int rc = 0; + int resp_buftype; + struct cifs_ses *ses = tcon->ses; + int flags = 0; + + cifs_dbg(FYI, "Query Info\n"); + + if (!ses || !(ses->server)) + return -EIO; + + if (smb3_encryption_required(tcon)) + flags |= CIFS_TRANSFORM_REQ; memset(&rqst, 0, sizeof(struct smb_rqst)); + memset(&iov, 0, sizeof(iov)); rqst.rq_iov = iov; rqst.rq_nvec = 1; + rc = SMB2_query_info_init(tcon, &rqst, persistent_fid, volatile_fid, + info_class, info_type, additional_info, + output_len); + if (rc) + goto qinf_exit; + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); - cifs_small_buf_release(req); rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; if (rc) { @@ -2661,6 +2684,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, &rsp_iov, min_len, *data); qinf_exit: + SMB2_query_info_free(&rqst); free_rsp_buf(resp_buftype, rsp); return rc; } diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index fdd8c78648c6..1255cde5133b 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -153,6 +153,11 @@ extern int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_file_id, u64 volatile_file_id, struct smb2_file_all_info *data); +extern int SMB2_query_info_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, + u64 persistent_fid, u64 volatile_fid, + u8 info_class, u8 info_type, + u32 additional_info, size_t output_len); +extern void SMB2_query_info_free(struct smb_rqst *rqst); extern int SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_file_id, u64 volatile_file_id, void **data, unsigned int *plen); -- cgit v1.2.3 From 1eb9fb52040fc6e5656c277b562229f09467c9f8 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Wed, 8 Aug 2018 15:07:46 +1000 Subject: cifs: create SMB2_open_init()/SMB2_open_free() helpers. Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French Reviewed-by: Paulo Alcantara Reviewed-by: Pavel Shilovsky --- fs/cifs/smb2pdu.c | 145 +++++++++++++++++++++++++++------------------------- fs/cifs/smb2proto.h | 4 ++ 2 files changed, 78 insertions(+), 71 deletions(-) (limited to 'fs') diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 821f21d4ada7..a5009a1c9bce 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2052,43 +2052,27 @@ err_free_path: } int -SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, - __u8 *oplock, struct smb2_file_all_info *buf, - struct kvec *err_iov, int *buftype) +SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock, + struct cifs_open_parms *oparms, __le16 *path) { - struct smb_rqst rqst; + struct TCP_Server_Info *server = tcon->ses->server; struct smb2_create_req *req; - struct smb2_create_rsp *rsp; - struct TCP_Server_Info *server; - struct cifs_tcon *tcon = oparms->tcon; - struct cifs_ses *ses = tcon->ses; - struct kvec iov[5]; /* make sure at least one for each open context */ - struct kvec rsp_iov = {NULL, 0}; - int resp_buftype; - int uni_path_len; - __le16 *copy_path = NULL; - int copy_size; - int rc = 0; unsigned int n_iov = 2; __u32 file_attributes = 0; - char *dhc_buf = NULL, *lc_buf = NULL, *pc_buf = NULL; - int flags = 0; + int copy_size; + int uni_path_len; unsigned int total_len; - - cifs_dbg(FYI, "create/open\n"); - - if (ses && (ses->server)) - server = ses->server; - else - return -EIO; + struct kvec *iov = rqst->rq_iov; + __le16 *copy_path; + int rc; rc = smb2_plain_req_init(SMB2_CREATE, tcon, (void **) &req, &total_len); - if (rc) return rc; - if (smb3_encryption_required(tcon)) - flags |= CIFS_TRANSFORM_REQ; + iov[0].iov_base = (char *)req; + /* -1 since last byte is buf[0] which is sent below (path) */ + iov[0].iov_len = total_len - 1; if (oparms->create_options & CREATE_OPTION_READONLY) file_attributes |= ATTR_READONLY; @@ -2102,11 +2086,6 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, req->ShareAccess = FILE_SHARE_ALL_LE; req->CreateDisposition = cpu_to_le32(oparms->disposition); req->CreateOptions = cpu_to_le32(oparms->create_options & CREATE_OPTIONS_MASK); - - iov[0].iov_base = (char *)req; - /* -1 since last byte is buf[0] which is sent below (path) */ - iov[0].iov_len = total_len - 1; - req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req)); /* [MS-SMB2] 2.2.13 NameOffset: @@ -2124,10 +2103,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, rc = alloc_path_with_tree_prefix(©_path, ©_size, &name_len, tcon->treeName, path); - if (rc) { - cifs_small_buf_release(req); + if (rc) return rc; - } req->NameLength = cpu_to_le16(name_len * 2); uni_path_len = copy_size; path = copy_path; @@ -2135,18 +2112,16 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2; /* MUST set path len (NameLength) to 0 opening root of share */ req->NameLength = cpu_to_le16(uni_path_len - 2); - if (uni_path_len % 8 != 0) { - copy_size = roundup(uni_path_len, 8); - copy_path = kzalloc(copy_size, GFP_KERNEL); - if (!copy_path) { - cifs_small_buf_release(req); - return -ENOMEM; - } - memcpy((char *)copy_path, (const char *)path, - uni_path_len); - uni_path_len = copy_size; - path = copy_path; - } + copy_size = uni_path_len; + if (copy_size % 8 != 0) + copy_size = roundup(copy_size, 8); + copy_path = kzalloc(copy_size, GFP_KERNEL); + if (!copy_path) + return -ENOMEM; + memcpy((char *)copy_path, (const char *)path, + uni_path_len); + uni_path_len = copy_size; + path = copy_path; } iov[1].iov_len = uni_path_len; @@ -2161,12 +2136,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, else { rc = add_lease_context(server, iov, &n_iov, oparms->fid->lease_key, oplock); - if (rc) { - cifs_small_buf_release(req); - kfree(copy_path); + if (rc) return rc; - } - lc_buf = iov[n_iov-1].iov_base; } if (*oplock == SMB2_OPLOCK_LEVEL_BATCH) { @@ -2180,13 +2151,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, rc = add_durable_context(iov, &n_iov, oparms, tcon->use_persistent); - if (rc) { - cifs_small_buf_release(req); - kfree(copy_path); - kfree(lc_buf); + if (rc) return rc; - } - dhc_buf = iov[n_iov-1].iov_base; } if (tcon->posix_extensions) { @@ -2198,23 +2164,63 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, } rc = add_posix_context(iov, &n_iov, oparms->mode); - if (rc) { - cifs_small_buf_release(req); - kfree(copy_path); - kfree(lc_buf); - kfree(dhc_buf); + if (rc) return rc; - } - pc_buf = iov[n_iov-1].iov_base; } + rqst->rq_nvec = n_iov; + return 0; +} + +/* rq_iov[0] is the request and is released by cifs_small_buf_release(). + * All other vectors are freed by kfree(). + */ +void +SMB2_open_free(struct smb_rqst *rqst) +{ + int i; + + cifs_small_buf_release(rqst->rq_iov[0].iov_base); + for (i = 1; i < rqst->rq_nvec; i++) + kfree(rqst->rq_iov[i].iov_base); +} + +int +SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, + __u8 *oplock, struct smb2_file_all_info *buf, + struct kvec *err_iov, int *buftype) +{ + struct smb_rqst rqst; + struct smb2_create_rsp *rsp = NULL; + struct TCP_Server_Info *server; + struct cifs_tcon *tcon = oparms->tcon; + struct cifs_ses *ses = tcon->ses; + struct kvec iov[5]; /* make sure at least one for each open context */ + struct kvec rsp_iov = {NULL, 0}; + int resp_buftype; + int rc = 0; + int flags = 0; + + cifs_dbg(FYI, "create/open\n"); + if (ses && (ses->server)) + server = ses->server; + else + return -EIO; + + if (smb3_encryption_required(tcon)) + flags |= CIFS_TRANSFORM_REQ; + memset(&rqst, 0, sizeof(struct smb_rqst)); + memset(&iov, 0, sizeof(iov)); rqst.rq_iov = iov; - rqst.rq_nvec = n_iov; + rqst.rq_nvec = 5; + + rc = SMB2_open_init(tcon, &rqst, oplock, oparms, path); + if (rc) + goto creat_exit; rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); - cifs_small_buf_release(req); rsp = (struct smb2_create_rsp *)rsp_iov.iov_base; if (rc != 0) { @@ -2251,10 +2257,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, else *oplock = rsp->OplockLevel; creat_exit: - kfree(copy_path); - kfree(lc_buf); - kfree(dhc_buf); - kfree(pc_buf); + SMB2_open_free(&rqst); free_rsp_buf(resp_buftype, rsp); return rc; } diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 1255cde5133b..57bdd2711974 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -133,6 +133,10 @@ extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, __u8 *oplock, struct smb2_file_all_info *buf, struct kvec *err_iov, int *resp_buftype); +extern int SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, + __u8 *oplock, struct cifs_open_parms *oparms, + __le16 *path); +extern void SMB2_open_free(struct smb_rqst *rqst); extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, u32 opcode, bool is_fsctl, char *in_data, u32 indatalen, -- cgit v1.2.3 From b24df3e30cbf48255db866720fb71f14bf9d2f39 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Wed, 8 Aug 2018 15:07:45 +1000 Subject: cifs: update receive_encrypted_standard to handle compounded responses Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French Reviewed-by: Paulo Alcantara Reviewed-by: Pavel Shilovsky --- fs/cifs/cifsglob.h | 5 +++- fs/cifs/connect.c | 82 ++++++++++++++++++++++++++++++++--------------------- fs/cifs/smb2ops.c | 61 +++++++++++++++++++++++++++++++++------ fs/cifs/transport.c | 2 -- 4 files changed, 107 insertions(+), 43 deletions(-) (limited to 'fs') diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 41803d374da0..0c9ab62c3df4 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -76,6 +76,9 @@ #define SMB_ECHO_INTERVAL_MAX 600 #define SMB_ECHO_INTERVAL_DEFAULT 60 +/* maximum number of PDUs in one compound */ +#define MAX_COMPOUND 5 + /* * Default number of credits to keep available for SMB3. * This value is chosen somewhat arbitrarily. The Windows client @@ -458,7 +461,7 @@ struct smb_version_operations { struct smb_rqst *, struct smb_rqst *); int (*is_transform_hdr)(void *buf); int (*receive_transform)(struct TCP_Server_Info *, - struct mid_q_entry **); + struct mid_q_entry **, char **, int *); enum securityEnum (*select_sectype)(struct TCP_Server_Info *, enum securityEnum); int (*next_header)(char *); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index d9bd10d295a9..c832a8a1970a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -850,13 +850,14 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid) static int cifs_demultiplex_thread(void *p) { - int length; + int i, num_mids, length; struct TCP_Server_Info *server = p; unsigned int pdu_length; unsigned int next_offset; char *buf = NULL; struct task_struct *task_to_wake = NULL; - struct mid_q_entry *mid_entry; + struct mid_q_entry *mids[MAX_COMPOUND]; + char *bufs[MAX_COMPOUND]; current->flags |= PF_MEMALLOC; cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current)); @@ -923,58 +924,75 @@ next_pdu: server->pdu_size = next_offset; } - mid_entry = NULL; + memset(mids, 0, sizeof(mids)); + memset(bufs, 0, sizeof(bufs)); + num_mids = 0; + if (server->ops->is_transform_hdr && server->ops->receive_transform && server->ops->is_transform_hdr(buf)) { length = server->ops->receive_transform(server, - &mid_entry); + mids, + bufs, + &num_mids); } else { - mid_entry = server->ops->find_mid(server, buf); + mids[0] = server->ops->find_mid(server, buf); + bufs[0] = buf; + if (mids[0]) + num_mids = 1; - if (!mid_entry || !mid_entry->receive) - length = standard_receive3(server, mid_entry); + if (!mids[0] || !mids[0]->receive) + length = standard_receive3(server, mids[0]); else - length = mid_entry->receive(server, mid_entry); + length = mids[0]->receive(server, mids[0]); } if (length < 0) { - if (mid_entry) - cifs_mid_q_entry_release(mid_entry); + for (i = 0; i < num_mids; i++) + if (mids[i]) + cifs_mid_q_entry_release(mids[i]); continue; } if (server->large_buf) buf = server->bigbuf; + server->lstrp = jiffies; - if (mid_entry != NULL) { - mid_entry->resp_buf_size = server->pdu_size; - if ((mid_entry->mid_flags & MID_WAIT_CANCELLED) && - mid_entry->mid_state == MID_RESPONSE_RECEIVED && - server->ops->handle_cancelled_mid) - server->ops->handle_cancelled_mid( - mid_entry->resp_buf, - server); - if (!mid_entry->multiRsp || mid_entry->multiEnd) - mid_entry->callback(mid_entry); + for (i = 0; i < num_mids; i++) { + if (mids[i] != NULL) { + mids[i]->resp_buf_size = server->pdu_size; + if ((mids[i]->mid_flags & MID_WAIT_CANCELLED) && + mids[i]->mid_state == MID_RESPONSE_RECEIVED && + server->ops->handle_cancelled_mid) + server->ops->handle_cancelled_mid( + mids[i]->resp_buf, + server); - cifs_mid_q_entry_release(mid_entry); - } else if (server->ops->is_oplock_break && - server->ops->is_oplock_break(buf, server)) { - cifs_dbg(FYI, "Received oplock break\n"); - } else { - cifs_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n", - atomic_read(&midCount)); - cifs_dump_mem("Received Data is: ", buf, - HEADER_SIZE(server)); + if (!mids[i]->multiRsp || mids[i]->multiEnd) + mids[i]->callback(mids[i]); + + cifs_mid_q_entry_release(mids[i]); + } else if (server->ops->is_oplock_break && + server->ops->is_oplock_break(bufs[i], + server)) { + cifs_dbg(FYI, "Received oplock break\n"); + } else { + cifs_dbg(VFS, "No task to wake, unknown frame " + "received! NumMids %d\n", + atomic_read(&midCount)); + cifs_dump_mem("Received Data is: ", bufs[i], + HEADER_SIZE(server)); #ifdef CONFIG_CIFS_DEBUG2 - if (server->ops->dump_detail) - server->ops->dump_detail(buf, server); - cifs_dump_mids(server); + if (server->ops->dump_detail) + server->ops->dump_detail(bufs[i], + server); + cifs_dump_mids(server); #endif /* CIFS_DEBUG2 */ + } } + if (pdu_length > server->pdu_size) { if (!allocate_buffers(server)) continue; diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index ebc13ebebddf..d23715062c8e 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -2942,13 +2942,20 @@ discard_data: static int receive_encrypted_standard(struct TCP_Server_Info *server, - struct mid_q_entry **mid) + struct mid_q_entry **mids, char **bufs, + int *num_mids) { - int length; + int ret, length; char *buf = server->smallbuf; + char *tmpbuf; + struct smb2_sync_hdr *shdr; unsigned int pdu_length = server->pdu_size; unsigned int buf_size; struct mid_q_entry *mid_entry; + int next_is_large; + char *next_buffer = NULL; + + *num_mids = 0; /* switch to large buffer if too big for a small one */ if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE) { @@ -2969,24 +2976,61 @@ receive_encrypted_standard(struct TCP_Server_Info *server, if (length) return length; + next_is_large = server->large_buf; + one_more: + shdr = (struct smb2_sync_hdr *)buf; + if (shdr->NextCommand) { + if (next_is_large) { + tmpbuf = server->bigbuf; + next_buffer = (char *)cifs_buf_get(); + } else { + tmpbuf = server->smallbuf; + next_buffer = (char *)cifs_small_buf_get(); + } + memcpy(next_buffer, + tmpbuf + le32_to_cpu(shdr->NextCommand), + pdu_length - le32_to_cpu(shdr->NextCommand)); + } + mid_entry = smb2_find_mid(server, buf); if (mid_entry == NULL) cifs_dbg(FYI, "mid not found\n"); else { cifs_dbg(FYI, "mid found\n"); mid_entry->decrypted = true; + mid_entry->resp_buf_size = server->pdu_size; } - *mid = mid_entry; + if (*num_mids >= MAX_COMPOUND) { + cifs_dbg(VFS, "too many PDUs in compound\n"); + return -1; + } + bufs[*num_mids] = buf; + mids[(*num_mids)++] = mid_entry; if (mid_entry && mid_entry->handle) - return mid_entry->handle(server, mid_entry); + ret = mid_entry->handle(server, mid_entry); + else + ret = cifs_handle_standard(server, mid_entry); + + if (ret == 0 && shdr->NextCommand) { + pdu_length -= le32_to_cpu(shdr->NextCommand); + server->large_buf = next_is_large; + if (next_is_large) + server->bigbuf = next_buffer; + else + server->smallbuf = next_buffer; + + buf += le32_to_cpu(shdr->NextCommand); + goto one_more; + } - return cifs_handle_standard(server, mid_entry); + return ret; } static int -smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid) +smb3_receive_transform(struct TCP_Server_Info *server, + struct mid_q_entry **mids, char **bufs, int *num_mids) { char *buf = server->smallbuf; unsigned int pdu_length = server->pdu_size; @@ -3009,10 +3053,11 @@ smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid) return -ECONNABORTED; } + /* TODO: add support for compounds containing READ. */ if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) - return receive_encrypted_read(server, mid); + return receive_encrypted_read(server, &mids[0]); - return receive_encrypted_standard(server, mid); + return receive_encrypted_standard(server, mids, bufs, num_mids); } int diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index c53c0908d4c6..78f96fa3d7d9 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -383,8 +383,6 @@ smbd_done: return rc; } -#define MAX_COMPOUND 5 - static int smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, struct smb_rqst *rqst, int flags) -- cgit v1.2.3 From 730928c8f4be88e9d6a027a16b1e8fa9c59fc077 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Wed, 8 Aug 2018 15:07:49 +1000 Subject: cifs: update smb2_queryfs() to use compounding Change smb2_queryfs() to use a Create/QueryInfo/Close compound request. Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French Reviewed-by: Paulo Alcantara Reviewed-by: Pavel Shilovsky --- fs/cifs/smb2ops.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++--- fs/cifs/smb2pdu.c | 41 ++++++++++---------- fs/cifs/smb2pdu.h | 4 ++ fs/cifs/smb2proto.h | 6 +++ 4 files changed, 131 insertions(+), 26 deletions(-) (limited to 'fs') diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index d23715062c8e..15c7cbde2f39 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1524,15 +1524,66 @@ smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid, CIFS_CACHE_READ(cinode) ? 1 : 0); } +static void +smb2_set_related(struct smb_rqst *rqst) +{ + struct smb2_sync_hdr *shdr; + + shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base); + shdr->Flags |= SMB2_FLAGS_RELATED_OPERATIONS; +} + +char smb2_padding[7] = {0, 0, 0, 0, 0, 0, 0}; + +static void +smb2_set_next_command(struct TCP_Server_Info *server, struct smb_rqst *rqst) +{ + struct smb2_sync_hdr *shdr; + unsigned long len = smb_rqst_len(server, rqst); + + /* SMB headers in a compound are 8 byte aligned. */ + if (len & 7) { + rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding; + rqst->rq_iov[rqst->rq_nvec].iov_len = 8 - (len & 7); + rqst->rq_nvec++; + len = smb_rqst_len(server, rqst); + } + + shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base); + shdr->NextCommand = cpu_to_le32(len); +} + static int smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon, struct kstatfs *buf) { - int rc; + struct smb2_query_info_rsp *rsp; + struct smb2_fs_full_size_info *info = NULL; + struct smb_rqst rqst[3]; + int resp_buftype[3]; + struct kvec rsp_iov[3]; + struct kvec open_iov[5]; /* 4 + potential padding. */ + struct kvec qi_iov[1]; + struct kvec close_iov[1]; + struct cifs_ses *ses = tcon->ses; + struct TCP_Server_Info *server = ses->server; __le16 srch_path = 0; /* Null - open root of share */ u8 oplock = SMB2_OPLOCK_LEVEL_NONE; struct cifs_open_parms oparms; struct cifs_fid fid; + int flags = 0; + int rc; + + if (smb3_encryption_required(tcon)) + flags |= CIFS_TRANSFORM_REQ; + + memset(rqst, 0, sizeof(rqst)); + memset(resp_buftype, 0, sizeof(resp_buftype)); + memset(rsp_iov, 0, sizeof(rsp_iov)); + + memset(&open_iov, 0, sizeof(open_iov)); + rqst[0].rq_iov = open_iov; + rqst[0].rq_nvec = 4; oparms.tcon = tcon; oparms.desired_access = FILE_READ_ATTRIBUTES; @@ -1541,13 +1592,56 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon, oparms.fid = &fid; oparms.reconnect = false; - rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL, NULL); + rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, &srch_path); if (rc) - return rc; + goto qfs_exit; + smb2_set_next_command(server, &rqst[0]); + + memset(&qi_iov, 0, sizeof(qi_iov)); + rqst[1].rq_iov = qi_iov; + rqst[1].rq_nvec = 1; + + rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID, + FS_FULL_SIZE_INFORMATION, + SMB2_O_INFO_FILESYSTEM, 0, + sizeof(struct smb2_fs_full_size_info)); + if (rc) + goto qfs_exit; + smb2_set_next_command(server, &rqst[1]); + smb2_set_related(&rqst[1]); + + memset(&close_iov, 0, sizeof(close_iov)); + rqst[2].rq_iov = close_iov; + rqst[2].rq_nvec = 1; + + rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID); + if (rc) + goto qfs_exit; + smb2_set_related(&rqst[2]); + + rc = compound_send_recv(xid, ses, flags, 3, rqst, + resp_buftype, rsp_iov); + if (rc) + goto qfs_exit; + + rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; buf->f_type = SMB2_MAGIC_NUMBER; - rc = SMB2_QFS_info(xid, tcon, fid.persistent_fid, fid.volatile_fid, - buf); - SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); + info = (struct smb2_fs_full_size_info *)( + le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp); + rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), + le32_to_cpu(rsp->OutputBufferLength), + &rsp_iov[1], + sizeof(struct smb2_fs_full_size_info)); + if (!rc) + smb2_copy_fs_info_to_kstatfs(info, buf); + +qfs_exit: + SMB2_open_free(&rqst[0]); + SMB2_query_info_free(&rqst[1]); + SMB2_close_free(&rqst[2]); + free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); + free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); + free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); return rc; } diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index a5009a1c9bce..faf2b779e5cb 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -80,7 +80,7 @@ static const int smb2_req_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = { /* SMB2_OPLOCK_BREAK */ 24 /* BB this is 36 for LEASE_BREAK variant */ }; -static int smb3_encryption_required(const struct cifs_tcon *tcon) +int smb3_encryption_required(const struct cifs_tcon *tcon) { if (!tcon) return 0; @@ -2182,7 +2182,8 @@ SMB2_open_free(struct smb_rqst *rqst) cifs_small_buf_release(rqst->rq_iov[0].iov_base); for (i = 1; i < rqst->rq_nvec; i++) - kfree(rqst->rq_iov[i].iov_base); + if (rqst->rq_iov[i].iov_base != smb2_padding) + kfree(rqst->rq_iov[i].iov_base); } int @@ -2528,9 +2529,9 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, return SMB2_close_flags(xid, tcon, persistent_fid, volatile_fid, 0); } -static int -validate_iov(unsigned int offset, unsigned int buffer_length, - struct kvec *iov, unsigned int min_buf_size) +int +smb2_validate_iov(unsigned int offset, unsigned int buffer_length, + struct kvec *iov, unsigned int min_buf_size) { unsigned int smb_len = iov->iov_len; char *end_of_smb = smb_len + (char *)iov->iov_base; @@ -2574,7 +2575,7 @@ validate_and_copy_iov(unsigned int offset, unsigned int buffer_length, if (!data) return -EINVAL; - rc = validate_iov(offset, buffer_length, iov, minbufsize); + rc = smb2_validate_iov(offset, buffer_length, iov, minbufsize); if (rc) return rc; @@ -3646,9 +3647,9 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, goto qdir_exit; } - rc = validate_iov(le16_to_cpu(rsp->OutputBufferOffset), - le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, - info_buf_size); + rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), + le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, + info_buf_size); if (rc) goto qdir_exit; @@ -3950,9 +3951,9 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, return rc; } -static void -copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf, - struct kstatfs *kst) +void +smb2_copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf, + struct kstatfs *kst) { kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) * le32_to_cpu(pfs_inf->SectorsPerAllocationUnit); @@ -4054,9 +4055,9 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon, info = (FILE_SYSTEM_POSIX_INFO *)( le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp); - rc = validate_iov(le16_to_cpu(rsp->OutputBufferOffset), - le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, - sizeof(FILE_SYSTEM_POSIX_INFO)); + rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), + le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, + sizeof(FILE_SYSTEM_POSIX_INFO)); if (!rc) copy_posix_fs_info_to_kstatfs(info, fsdata); @@ -4102,11 +4103,11 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, info = (struct smb2_fs_full_size_info *)( le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp); - rc = validate_iov(le16_to_cpu(rsp->OutputBufferOffset), - le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, - sizeof(struct smb2_fs_full_size_info)); + rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), + le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, + sizeof(struct smb2_fs_full_size_info)); if (!rc) - copy_fs_info_to_kstatfs(info, fsdata); + smb2_copy_fs_info_to_kstatfs(info, fsdata); qfsinf_exit: free_rsp_buf(resp_buftype, rsp_iov.iov_base); @@ -4166,7 +4167,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, rsp_len = le32_to_cpu(rsp->OutputBufferLength); offset = le16_to_cpu(rsp->OutputBufferOffset); - rc = validate_iov(offset, rsp_len, &rsp_iov, min_len); + rc = smb2_validate_iov(offset, rsp_len, &rsp_iov, min_len); if (rc) goto qfsattr_exit; diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index ecb0feeac844..cf37c2f3f3b8 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -153,6 +153,8 @@ struct smb2_transform_hdr { * */ +#define COMPOUND_FID 0xFFFFFFFFFFFFFFFFULL + #define SMB2_ERROR_STRUCTURE_SIZE2 cpu_to_le16(9) struct smb2_err_rsp { @@ -1373,4 +1375,6 @@ struct smb2_file_eof_info { /* encoding of request for level 10 */ __le64 EndOfFile; /* new end of file value */ } __packed; /* level 20 Set */ +extern char smb2_padding[7]; + #endif /* _SMB2PDU_H */ diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 57bdd2711974..b4076577eeb7 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -229,6 +229,12 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *); extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, enum securityEnum); +extern int smb3_encryption_required(const struct cifs_tcon *tcon); +extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length, + struct kvec *iov, unsigned int min_buf_size); +extern void smb2_copy_fs_info_to_kstatfs( + struct smb2_fs_full_size_info *pfs_inf, + struct kstatfs *kst); extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server); extern int smb311_update_preauth_hash(struct cifs_ses *ses, struct kvec *iov, int nvec); -- cgit v1.2.3 From e02789a53d71334b067ad72eee5d4e88a0158083 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 9 Aug 2018 14:33:12 -0500 Subject: smb3: enumerating snapshots was leaving part of the data off end When enumerating snapshots, the last few bytes of the final snapshot could be left off since we were miscalculating the length returned (leaving off the sizeof struct SRV_SNAPSHOT_ARRAY) See MS-SMB2 section 2.2.32.2. In addition fixup the length used to allow smaller buffer to be passed in, in order to allow returning the size of the whole snapshot array more easily. Sample userspace output with a kernel patched with this (mounted to a Windows volume with two snapshots). Before this patch, the second snapshot would be missing a few bytes at the end. ~/cifs-2.6# ~/enum-snapshots /mnt/file press enter to issue the ioctl to retrieve snapshot information ... size of snapshot array = 102 Num snapshots: 2 Num returned: 2 Array Size: 102 Snapshot 0:@GMT-2018.06.30-19.34.17 Snapshot 1:@GMT-2018.06.30-19.33.37 CC: Stable Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky --- fs/cifs/smb2ops.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 15c7cbde2f39..7869ea4f6fab 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1369,6 +1369,13 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon, } +/* GMT Token is @GMT-YYYY.MM.DD-HH.MM.SS Unicode which is 48 bytes + null */ +#define GMT_TOKEN_SIZE 50 + +/* + * Input buffer contains (empty) struct smb_snapshot array with size filled in + * For output see struct SRV_SNAPSHOT_ARRAY in MS-SMB2 section 2.2.32.2 + */ static int smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon, struct cifsFileInfo *cfile, void __user *ioc_buf) @@ -1398,14 +1405,27 @@ smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon, kfree(retbuf); return rc; } - if (snapshot_in.snapshot_array_size < sizeof(struct smb_snapshot_array)) { - rc = -ERANGE; - kfree(retbuf); - return rc; - } - if (ret_data_len > snapshot_in.snapshot_array_size) - ret_data_len = snapshot_in.snapshot_array_size; + /* + * Check for min size, ie not large enough to fit even one GMT + * token (snapshot). On the first ioctl some users may pass in + * smaller size (or zero) to simply get the size of the array + * so the user space caller can allocate sufficient memory + * and retry the ioctl again with larger array size sufficient + * to hold all of the snapshot GMT tokens on the second try. + */ + if (snapshot_in.snapshot_array_size < GMT_TOKEN_SIZE) + ret_data_len = sizeof(struct smb_snapshot_array); + + /* + * We return struct SRV_SNAPSHOT_ARRAY, followed by + * the snapshot array (of 50 byte GMT tokens) each + * representing an available previous version of the data + */ + if (ret_data_len > (snapshot_in.snapshot_array_size + + sizeof(struct smb_snapshot_array))) + ret_data_len = snapshot_in.snapshot_array_size + + sizeof(struct smb_snapshot_array); if (copy_to_user(ioc_buf, retbuf, ret_data_len)) rc = -EFAULT; -- cgit v1.2.3 From c1777df1a5d541cda918ff0450c8adcc8b69c2fd Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Fri, 10 Aug 2018 11:03:55 +1000 Subject: cifs: add missing support for ACLs in SMB 3.11 We were missing the methods for get_acl and friends for the 3.11 dialect. Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French CC: Stable Reviewed-by: Pavel Shilovsky --- fs/cifs/smb2ops.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'fs') diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 7869ea4f6fab..541258447c4c 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -3586,6 +3586,11 @@ struct smb_version_operations smb311_operations = { .query_all_EAs = smb2_query_eas, .set_EA = smb2_set_ea, #endif /* CIFS_XATTR */ +#ifdef CONFIG_CIFS_ACL + .get_acl = get_smb2_acl, + .get_acl_by_fid = get_smb2_acl_by_fid, + .set_acl = set_smb2_acl, +#endif /* CIFS_ACL */ .next_header = smb2_next_header, }; -- cgit v1.2.3 From e55954a5f7ce0e321cea9f91f4ebeb2a4e0165f4 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Fri, 10 Aug 2018 11:31:10 +1000 Subject: cifs: don't show domain= in mount output when domain is empty Reported-by: Xiaoli Feng Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky --- fs/cifs/cifsfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index de16078e456b..7065426b3280 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -432,7 +432,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root) else if (tcon->ses->user_name) seq_show_option(s, "username", tcon->ses->user_name); - if (tcon->ses->domainName) + if (tcon->ses->domainName && tcon->ses->domainName[0] != 0) seq_show_option(s, "domain", tcon->ses->domainName); if (srcaddr->sa_family != AF_UNSPEC) { -- cgit v1.2.3 From cdeaf9d04a5a0f51220d2f025385c553220bfb5c Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 10 Aug 2018 02:25:06 -0500 Subject: smb3: allow previous versions to be mounted with snapshot= mount parm mounting with the "snapshots=" mount parm allows a read-only view of a previous version of a file system (see MS-SMB2 and "timewarp" tokens, section 2.2.13.2.6) based on the timestamp passed in on the snapshots mount parm. Add processing to optionally send this create context. Example output: /mnt1 is mounted with "snapshots=..." and will see an earlier version of the directory, with three fewer files than /mnt2 the current version of the directory. root@Ubuntu-17-Virtual-Machine:~/cifs-2.6# cat /proc/mounts | grep cifs //172.22.149.186/public /mnt1 cifs ro,relatime,vers=default,cache=strict,username=smfrench,uid=0,noforceuid,gid=0,noforcegid,addr=172.22.149.186,file_mode=0755,dir_mode=0755,soft,nounix,mapposix,rsize=1048576,wsize=1048576,echo_interval=60,snapshot=131748608570000000,actimeo=1 //172.22.149.186/public /mnt2 cifs rw,relatime,vers=default,cache=strict,username=smfrench,uid=0,noforceuid,gid=0,noforcegid,addr=172.22.149.186,file_mode=0755,dir_mode=0755,soft,nounix,mapposix,rsize=1048576,wsize=1048576,echo_interval=60,actimeo=1 root@Ubuntu-17-Virtual-Machine:~/cifs-2.6# ls /mnt1 EmptyDir newerdir root@Ubuntu-17-Virtual-Machine:~/cifs-2.6# ls /mnt1/newerdir root@Ubuntu-17-Virtual-Machine:~/cifs-2.6# ls /mnt2 EmptyDir file newerdir newestdir timestamp-trace.cap root@Ubuntu-17-Virtual-Machine:~/cifs-2.6# ls /mnt2/newerdir new-file-not-in-snapshot Snapshots are extremely useful for comparing previous versions of files or directories, and recovering from data corruptions or mistakes. Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg --- fs/cifs/smb2pdu.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb2pdu.h | 8 ++++++++ 2 files changed, 68 insertions(+) (limited to 'fs') diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index faf2b779e5cb..2f1938011395 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1856,6 +1856,51 @@ add_durable_context(struct kvec *iov, unsigned int *num_iovec, return 0; } +/* See MS-SMB2 2.2.13.2.7 */ +static struct crt_twarp_ctxt * +create_twarp_buf(__u64 timewarp) +{ + struct crt_twarp_ctxt *buf; + + buf = kzalloc(sizeof(struct crt_twarp_ctxt), GFP_KERNEL); + if (!buf) + return NULL; + + buf->ccontext.DataOffset = cpu_to_le16(offsetof + (struct crt_twarp_ctxt, Timestamp)); + buf->ccontext.DataLength = cpu_to_le32(8); + buf->ccontext.NameOffset = cpu_to_le16(offsetof + (struct crt_twarp_ctxt, Name)); + buf->ccontext.NameLength = cpu_to_le16(4); + /* SMB2_CREATE_TIMEWARP_TOKEN is "TWrp" */ + buf->Name[0] = 'T'; + buf->Name[1] = 'W'; + buf->Name[2] = 'r'; + buf->Name[3] = 'p'; + buf->Timestamp = cpu_to_le64(timewarp); + return buf; +} + +/* See MS-SMB2 2.2.13.2.7 */ +static int +add_twarp_context(struct kvec *iov, unsigned int *num_iovec, __u64 timewarp) +{ + struct smb2_create_req *req = iov[0].iov_base; + unsigned int num = *num_iovec; + + iov[num].iov_base = create_twarp_buf(timewarp); + if (iov[num].iov_base == NULL) + return -ENOMEM; + iov[num].iov_len = sizeof(struct crt_twarp_ctxt); + if (!req->CreateContextsOffset) + req->CreateContextsOffset = cpu_to_le32( + sizeof(struct smb2_create_req) + + iov[num - 1].iov_len); + le32_add_cpu(&req->CreateContextsLength, sizeof(struct crt_twarp_ctxt)); + *num_iovec = num + 1; + return 0; +} + static int alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len, const char *treename, const __le16 *path) @@ -2168,6 +2213,21 @@ SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock, return rc; } + if (tcon->snapshot_time) { + cifs_dbg(FYI, "adding snapshot context\n"); + if (n_iov > 2) { + struct create_context *ccontext = + (struct create_context *)iov[n_iov-1].iov_base; + ccontext->Next = + cpu_to_le32(iov[n_iov-1].iov_len); + } + + rc = add_twarp_context(iov, &n_iov, tcon->snapshot_time); + if (rc) + return rc; + } + + rqst->rq_nvec = n_iov; return 0; } diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index cf37c2f3f3b8..a2eeae9e0432 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -767,6 +767,14 @@ struct create_durable_handle_reconnect_v2 { struct durable_reconnect_context_v2 dcontext; } __packed; +/* See MS-SMB2 2.2.13.2.5 */ +struct crt_twarp_ctxt { + struct create_context ccontext; + __u8 Name[8]; + __le64 Timestamp; + +} __packed; + #define COPY_CHUNK_RES_KEY_SIZE 24 struct resume_key_req { char ResumeKey[COPY_CHUNK_RES_KEY_SIZE]; -- cgit v1.2.3 From c4f7173ac3b7e22934e51f0121833642a581d723 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 10 Aug 2018 18:46:58 -0500 Subject: smb3: create smb3 equivalent alias for cifs pseudo-xattrs We really, really don't want to be encouraging people to use cifs (the dialect) since it is insecure, so to avoid confusion we want to move them to names which include 'smb3' instead of 'cifs' - so this simply creates an alias for the pseudo-xattrs e.g. can now do: getfattr -n user.smb3.creationtime /mnt1/file and getfattr -n user.smb3.dosattrib /mnt1/file and getfattr -n system.smb3_acl /mnt1/file instead of forcing you to use the string 'cifs' in these (e.g. getfattr -n system.cifs_acl /mnt1/file) Signed-off-by: Steve French --- fs/cifs/xattr.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index 316af84674f1..50ddb795aaeb 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -35,6 +35,14 @@ #define CIFS_XATTR_CIFS_ACL "system.cifs_acl" #define CIFS_XATTR_ATTRIB "cifs.dosattrib" /* full name: user.cifs.dosattrib */ #define CIFS_XATTR_CREATETIME "cifs.creationtime" /* user.cifs.creationtime */ +/* + * Although these three are just aliases for the above, need to move away from + * confusing users and using the 20+ year old term 'cifs' when it is no longer + * secure, replaced by SMB2 (then even more highly secure SMB3) many years ago + */ +#define SMB3_XATTR_CIFS_ACL "system.smb3_acl" +#define SMB3_XATTR_ATTRIB "smb3.dosattrib" /* full name: user.smb3.dosattrib */ +#define SMB3_XATTR_CREATETIME "smb3.creationtime" /* user.smb3.creationtime */ /* BB need to add server (Samba e.g) support for security and trusted prefix */ enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT }; @@ -220,10 +228,12 @@ static int cifs_xattr_get(const struct xattr_handler *handler, switch (handler->flags) { case XATTR_USER: cifs_dbg(FYI, "%s:querying user xattr %s\n", __func__, name); - if (strcmp(name, CIFS_XATTR_ATTRIB) == 0) { + if ((strcmp(name, CIFS_XATTR_ATTRIB) == 0) || + (strcmp(name, SMB3_XATTR_ATTRIB) == 0)) { rc = cifs_attrib_get(dentry, inode, value, size); break; - } else if (strcmp(name, CIFS_XATTR_CREATETIME) == 0) { + } else if ((strcmp(name, CIFS_XATTR_CREATETIME) == 0) || + (strcmp(name, SMB3_XATTR_CREATETIME) == 0)) { rc = cifs_creation_time_get(dentry, inode, value, size); break; } @@ -363,6 +373,19 @@ static const struct xattr_handler cifs_cifs_acl_xattr_handler = { .set = cifs_xattr_set, }; +/* + * Although this is just an alias for the above, need to move away from + * confusing users and using the 20 year old term 'cifs' when it is no + * longer secure and was replaced by SMB2/SMB3 a long time ago, and + * SMB3 and later are highly secure. + */ +static const struct xattr_handler smb3_acl_xattr_handler = { + .name = SMB3_XATTR_CIFS_ACL, + .flags = XATTR_CIFS_ACL, + .get = cifs_xattr_get, + .set = cifs_xattr_set, +}; + static const struct xattr_handler cifs_posix_acl_access_xattr_handler = { .name = XATTR_NAME_POSIX_ACL_ACCESS, .flags = XATTR_ACL_ACCESS, @@ -381,6 +404,7 @@ const struct xattr_handler *cifs_xattr_handlers[] = { &cifs_user_xattr_handler, &cifs_os2_xattr_handler, &cifs_cifs_acl_xattr_handler, + &smb3_acl_xattr_handler, /* alias for above since avoiding "cifs" */ &cifs_posix_acl_access_xattr_handler, &cifs_posix_acl_default_xattr_handler, NULL -- cgit v1.2.3