diff options
Diffstat (limited to 'fs/smb/client')
37 files changed, 917 insertions, 1338 deletions
diff --git a/fs/smb/client/Kconfig b/fs/smb/client/Kconfig index a4c02199fef4..17bd368574e9 100644 --- a/fs/smb/client/Kconfig +++ b/fs/smb/client/Kconfig @@ -5,17 +5,16 @@ config CIFS select NLS select NLS_UCS2_UTILS select CRYPTO - select CRYPTO_MD5 - select CRYPTO_SHA256 - select CRYPTO_SHA512 select CRYPTO_CMAC - select CRYPTO_HMAC select CRYPTO_AEAD2 select CRYPTO_CCM select CRYPTO_GCM select CRYPTO_ECB select CRYPTO_AES select CRYPTO_LIB_ARC4 + select CRYPTO_LIB_MD5 + select CRYPTO_LIB_SHA256 + select CRYPTO_LIB_SHA512 select KEYS select DNS_RESOLVER select ASN1 diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c index b8ac7b7faf61..e3ea6fe7edb4 100644 --- a/fs/smb/client/cached_dir.c +++ b/fs/smb/client/cached_dir.c @@ -16,6 +16,7 @@ static struct cached_fid *init_cached_dir(const char *path); static void free_cached_dir(struct cached_fid *cfid); static void smb2_close_cached_fid(struct kref *ref); static void cfids_laundromat_worker(struct work_struct *work); +static void close_cached_dir_locked(struct cached_fid *cfid); struct cached_dir_dentry { struct list_head entry; @@ -388,11 +389,11 @@ out: * lease. Release one here, and the second below. */ cfid->has_lease = false; - kref_put(&cfid->refcount, smb2_close_cached_fid); + close_cached_dir_locked(cfid); } spin_unlock(&cfids->cfid_list_lock); - kref_put(&cfid->refcount, smb2_close_cached_fid); + close_cached_dir(cfid); } else { *ret_cfid = cfid; atomic_inc(&tcon->num_remote_opens); @@ -438,12 +439,14 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon, static void smb2_close_cached_fid(struct kref *ref) +__releases(&cfid->cfids->cfid_list_lock) { struct cached_fid *cfid = container_of(ref, struct cached_fid, refcount); int rc; - spin_lock(&cfid->cfids->cfid_list_lock); + lockdep_assert_held(&cfid->cfids->cfid_list_lock); + if (cfid->on_list) { list_del(&cfid->entry); cfid->on_list = false; @@ -478,15 +481,49 @@ void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon, spin_lock(&cfid->cfids->cfid_list_lock); if (cfid->has_lease) { cfid->has_lease = false; - kref_put(&cfid->refcount, smb2_close_cached_fid); + close_cached_dir_locked(cfid); } spin_unlock(&cfid->cfids->cfid_list_lock); close_cached_dir(cfid); } - +/** + * close_cached_dir - drop a reference of a cached dir + * + * The release function will be called with cfid_list_lock held to remove the + * cached dirs from the list before any other thread can take another @cfid + * ref. Must not be called with cfid_list_lock held; use + * close_cached_dir_locked() called instead. + * + * @cfid: cached dir + */ void close_cached_dir(struct cached_fid *cfid) { + lockdep_assert_not_held(&cfid->cfids->cfid_list_lock); + kref_put_lock(&cfid->refcount, smb2_close_cached_fid, &cfid->cfids->cfid_list_lock); +} + +/** + * close_cached_dir_locked - put a reference of a cached dir with + * cfid_list_lock held + * + * Calling close_cached_dir() with cfid_list_lock held has the potential effect + * of causing a deadlock if the invariant of refcount >= 2 is false. + * + * This function is used in paths that hold cfid_list_lock and expect at least + * two references. If that invariant is violated, WARNs and returns without + * dropping a reference; the final put must still go through + * close_cached_dir(). + * + * @cfid: cached dir + */ +static void close_cached_dir_locked(struct cached_fid *cfid) +{ + lockdep_assert_held(&cfid->cfids->cfid_list_lock); + + if (WARN_ON(kref_read(&cfid->refcount) < 2)) + return; + kref_put(&cfid->refcount, smb2_close_cached_fid); } @@ -596,7 +633,7 @@ cached_dir_offload_close(struct work_struct *work) WARN_ON(cfid->on_list); - kref_put(&cfid->refcount, smb2_close_cached_fid); + close_cached_dir(cfid); cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cached_close); } @@ -762,7 +799,7 @@ static void cfids_laundromat_worker(struct work_struct *work) * Drop the ref-count from above, either the lease-ref (if there * was one) or the extra one acquired. */ - kref_put(&cfid->refcount, smb2_close_cached_fid); + close_cached_dir(cfid); } queue_delayed_work(cfid_put_wq, &cfids->laundromat_work, dir_cache_timeout * HZ); diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index 1fb71d2d31b5..7fdcaf9feb16 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -249,9 +249,9 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v) seq_puts(m, "# Format:\n"); seq_puts(m, "# <tree id> <ses id> <persistent fid> <flags> <count> <pid> <uid>"); #ifdef CONFIG_CIFS_DEBUG2 - seq_puts(m, " <filename> <lease> <mid>\n"); + seq_puts(m, " <filename> <lease> <lease-key> <mid>\n"); #else - seq_puts(m, " <filename> <lease>\n"); + seq_puts(m, " <filename> <lease> <lease-key>\n"); #endif /* CIFS_DEBUG2 */ spin_lock(&cifs_tcp_ses_lock); list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { @@ -274,6 +274,7 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v) /* Append lease/oplock caching state as RHW letters */ inode = d_inode(cfile->dentry); + cinode = NULL; n = 0; if (inode) { cinode = CIFS_I(inode); @@ -291,6 +292,12 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v) else seq_puts(m, "NONE"); + seq_puts(m, " "); + if (cinode && cinode->lease_granted) + seq_printf(m, "%pUl", cinode->lease_key); + else + seq_puts(m, "-"); + #ifdef CONFIG_CIFS_DEBUG2 seq_printf(m, " %llu", cfile->fid.mid); #endif /* CONFIG_CIFS_DEBUG2 */ @@ -317,7 +324,7 @@ static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v) seq_puts(m, "# Version:1\n"); seq_puts(m, "# Format:\n"); - seq_puts(m, "# <tree id> <sess id> <persistent fid> <path>\n"); + seq_puts(m, "# <tree id> <sess id> <persistent fid> <lease-key> <path>\n"); spin_lock(&cifs_tcp_ses_lock); list_for_each(stmp, &cifs_tcp_ses_list) { @@ -336,11 +343,15 @@ static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v) (unsigned long)atomic_long_read(&cfids->total_dirents_entries), (unsigned long long)atomic64_read(&cfids->total_dirents_bytes)); list_for_each_entry(cfid, &cfids->entries, entry) { - seq_printf(m, "0x%x 0x%llx 0x%llx %s", + seq_printf(m, "0x%x 0x%llx 0x%llx ", tcon->tid, ses->Suid, - cfid->fid.persistent_fid, - cfid->path); + cfid->fid.persistent_fid); + if (cfid->has_lease) + seq_printf(m, "%pUl ", cfid->fid.lease_key); + else + seq_puts(m, "- "); + seq_printf(m, "%s", cfid->path); if (cfid->file_all_info_is_valid) seq_printf(m, "\tvalid file info"); if (cfid->dirents.is_valid) diff --git a/fs/smb/client/cifs_spnego.c b/fs/smb/client/cifs_spnego.c index 9891f55bac1e..da935bd1ce87 100644 --- a/fs/smb/client/cifs_spnego.c +++ b/fs/smb/client/cifs_spnego.c @@ -90,7 +90,6 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo, size_t desc_len; struct key *spnego_key; const char *hostname = server->hostname; - const struct cred *saved_cred; /* length of fields (with semicolons): ver=0xyz ip4=ipaddress host=hostname sec=mechanism uid=0xFF user=username */ @@ -158,9 +157,8 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo, dp += sprintf(dp, ";upcall_target=app"); cifs_dbg(FYI, "key description = %s\n", description); - saved_cred = override_creds(spnego_cred); - spnego_key = request_key(&cifs_spnego_key_type, description, ""); - revert_creds(saved_cred); + scoped_with_creds(spnego_cred) + spnego_key = request_key(&cifs_spnego_key_type, description, ""); #ifdef CONFIG_CIFS_DEBUG2 if (cifsFYI && !IS_ERR(spnego_key)) { diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c index 63b3b1290bed..ce2ebc213a1d 100644 --- a/fs/smb/client/cifsacl.c +++ b/fs/smb/client/cifsacl.c @@ -339,7 +339,6 @@ int sid_to_id(struct cifs_sb_info *cifs_sb, struct smb_sid *psid, struct cifs_fattr *fattr, uint sidtype) { - int rc = 0; struct key *sidkey; char *sidstr; const struct cred *saved_cred; @@ -446,12 +445,12 @@ out_revert_creds: * fails then we just fall back to using the ctx->linux_uid/linux_gid. */ got_valid_id: - rc = 0; if (sidtype == SIDOWNER) fattr->cf_uid = fuid; else fattr->cf_gid = fgid; - return rc; + + return 0; } int diff --git a/fs/smb/client/cifsencrypt.c b/fs/smb/client/cifsencrypt.c index 7b7c8c38fdd0..801824825ecf 100644 --- a/fs/smb/client/cifsencrypt.c +++ b/fs/smb/client/cifsencrypt.c @@ -24,14 +24,43 @@ #include <linux/iov_iter.h> #include <crypto/aead.h> #include <crypto/arc4.h> +#include <crypto/md5.h> +#include <crypto/sha2.h> -static size_t cifs_shash_step(void *iter_base, size_t progress, size_t len, - void *priv, void *priv2) +static int cifs_sig_update(struct cifs_calc_sig_ctx *ctx, + const u8 *data, size_t len) { - struct shash_desc *shash = priv; + if (ctx->md5) { + md5_update(ctx->md5, data, len); + return 0; + } + if (ctx->hmac) { + hmac_sha256_update(ctx->hmac, data, len); + return 0; + } + return crypto_shash_update(ctx->shash, data, len); +} + +static int cifs_sig_final(struct cifs_calc_sig_ctx *ctx, u8 *out) +{ + if (ctx->md5) { + md5_final(ctx->md5, out); + return 0; + } + if (ctx->hmac) { + hmac_sha256_final(ctx->hmac, out); + return 0; + } + return crypto_shash_final(ctx->shash, out); +} + +static size_t cifs_sig_step(void *iter_base, size_t progress, size_t len, + void *priv, void *priv2) +{ + struct cifs_calc_sig_ctx *ctx = priv; int ret, *pret = priv2; - ret = crypto_shash_update(shash, iter_base, len); + ret = cifs_sig_update(ctx, iter_base, len); if (ret < 0) { *pret = ret; return len; @@ -42,21 +71,20 @@ static size_t cifs_shash_step(void *iter_base, size_t progress, size_t len, /* * Pass the data from an iterator into a hash. */ -static int cifs_shash_iter(const struct iov_iter *iter, size_t maxsize, - struct shash_desc *shash) +static int cifs_sig_iter(const struct iov_iter *iter, size_t maxsize, + struct cifs_calc_sig_ctx *ctx) { struct iov_iter tmp_iter = *iter; int err = -EIO; - if (iterate_and_advance_kernel(&tmp_iter, maxsize, shash, &err, - cifs_shash_step) != maxsize) + if (iterate_and_advance_kernel(&tmp_iter, maxsize, ctx, &err, + cifs_sig_step) != maxsize) return err; return 0; } -int __cifs_calc_signature(struct smb_rqst *rqst, - struct TCP_Server_Info *server, char *signature, - struct shash_desc *shash) +int __cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, + char *signature, struct cifs_calc_sig_ctx *ctx) { int i; ssize_t rc; @@ -82,8 +110,7 @@ int __cifs_calc_signature(struct smb_rqst *rqst, return -EIO; } - rc = crypto_shash_update(shash, - iov[i].iov_base, iov[i].iov_len); + rc = cifs_sig_update(ctx, iov[i].iov_base, iov[i].iov_len); if (rc) { cifs_dbg(VFS, "%s: Could not update with payload\n", __func__); @@ -91,11 +118,11 @@ int __cifs_calc_signature(struct smb_rqst *rqst, } } - rc = cifs_shash_iter(&rqst->rq_iter, iov_iter_count(&rqst->rq_iter), shash); + rc = cifs_sig_iter(&rqst->rq_iter, iov_iter_count(&rqst->rq_iter), ctx); if (rc < 0) return rc; - rc = crypto_shash_final(shash, signature); + rc = cifs_sig_final(ctx, signature); if (rc) cifs_dbg(VFS, "%s: Could not generate hash\n", __func__); @@ -112,29 +139,22 @@ int __cifs_calc_signature(struct smb_rqst *rqst, static int cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, char *signature) { - int rc; + struct md5_ctx ctx; if (!rqst->rq_iov || !signature || !server) return -EINVAL; - - rc = cifs_alloc_hash("md5", &server->secmech.md5); - if (rc) - return -1; - - rc = crypto_shash_init(server->secmech.md5); - if (rc) { - cifs_dbg(VFS, "%s: Could not init md5\n", __func__); - return rc; + if (fips_enabled) { + cifs_dbg(VFS, + "MD5 signature support is disabled due to FIPS\n"); + return -EOPNOTSUPP; } - rc = crypto_shash_update(server->secmech.md5, - server->session_key.response, server->session_key.len); - if (rc) { - cifs_dbg(VFS, "%s: Could not update with response\n", __func__); - return rc; - } + md5_init(&ctx); + md5_update(&ctx, server->session_key.response, server->session_key.len); - return __cifs_calc_signature(rqst, server, signature, server->secmech.md5); + return __cifs_calc_signature( + rqst, server, signature, + &(struct cifs_calc_sig_ctx){ .md5 = &ctx }); } /* must be called with server->srv_mutex held */ @@ -405,11 +425,11 @@ static __le64 find_timestamp(struct cifs_ses *ses) } static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, - const struct nls_table *nls_cp, struct shash_desc *hmacmd5) + const struct nls_table *nls_cp) { - int rc = 0; int len; char nt_hash[CIFS_NTHASH_SIZE]; + struct hmac_md5_ctx hmac_ctx; __le16 *user; wchar_t *domain; wchar_t *server; @@ -417,17 +437,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, /* calculate md4 hash of password */ E_md4hash(ses->password, nt_hash, nls_cp); - rc = crypto_shash_setkey(hmacmd5->tfm, nt_hash, CIFS_NTHASH_SIZE); - if (rc) { - cifs_dbg(VFS, "%s: Could not set NT hash as a key, rc=%d\n", __func__, rc); - return rc; - } - - rc = crypto_shash_init(hmacmd5); - if (rc) { - cifs_dbg(VFS, "%s: Could not init HMAC-MD5, rc=%d\n", __func__, rc); - return rc; - } + hmac_md5_init_usingrawkey(&hmac_ctx, nt_hash, CIFS_NTHASH_SIZE); /* convert ses->user_name to unicode */ len = ses->user_name ? strlen(ses->user_name) : 0; @@ -442,12 +452,8 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, *(u16 *)user = 0; } - rc = crypto_shash_update(hmacmd5, (char *)user, 2 * len); + hmac_md5_update(&hmac_ctx, (const u8 *)user, 2 * len); kfree(user); - if (rc) { - cifs_dbg(VFS, "%s: Could not update with user, rc=%d\n", __func__, rc); - return rc; - } /* convert ses->domainName to unicode and uppercase */ if (ses->domainName) { @@ -459,12 +465,8 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len, nls_cp); - rc = crypto_shash_update(hmacmd5, (char *)domain, 2 * len); + hmac_md5_update(&hmac_ctx, (const u8 *)domain, 2 * len); kfree(domain); - if (rc) { - cifs_dbg(VFS, "%s: Could not update with domain, rc=%d\n", __func__, rc); - return rc; - } } else { /* We use ses->ip_addr if no domain name available */ len = strlen(ses->ip_addr); @@ -474,25 +476,16 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, return -ENOMEM; len = cifs_strtoUTF16((__le16 *)server, ses->ip_addr, len, nls_cp); - rc = crypto_shash_update(hmacmd5, (char *)server, 2 * len); + hmac_md5_update(&hmac_ctx, (const u8 *)server, 2 * len); kfree(server); - if (rc) { - cifs_dbg(VFS, "%s: Could not update with server, rc=%d\n", __func__, rc); - return rc; - } } - rc = crypto_shash_final(hmacmd5, ntlmv2_hash); - if (rc) - cifs_dbg(VFS, "%s: Could not generate MD5 hash, rc=%d\n", __func__, rc); - - return rc; + hmac_md5_final(&hmac_ctx, ntlmv2_hash); + return 0; } -static int -CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash, struct shash_desc *hmacmd5) +static void CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash) { - int rc; struct ntlmv2_resp *ntlmv2 = (struct ntlmv2_resp *) (ses->auth_key.response + CIFS_SESS_KEY_SIZE); unsigned int hash_len; @@ -501,35 +494,15 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash, struct shash_ hash_len = ses->auth_key.len - (CIFS_SESS_KEY_SIZE + offsetof(struct ntlmv2_resp, challenge.key[0])); - rc = crypto_shash_setkey(hmacmd5->tfm, ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); - if (rc) { - cifs_dbg(VFS, "%s: Could not set NTLMv2 hash as a key, rc=%d\n", __func__, rc); - return rc; - } - - rc = crypto_shash_init(hmacmd5); - if (rc) { - cifs_dbg(VFS, "%s: Could not init HMAC-MD5, rc=%d\n", __func__, rc); - return rc; - } - if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) memcpy(ntlmv2->challenge.key, ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE); else memcpy(ntlmv2->challenge.key, ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE); - rc = crypto_shash_update(hmacmd5, ntlmv2->challenge.key, hash_len); - if (rc) { - cifs_dbg(VFS, "%s: Could not update with response, rc=%d\n", __func__, rc); - return rc; - } - - /* Note that the MD5 digest over writes anon.challenge_key.key */ - rc = crypto_shash_final(hmacmd5, ntlmv2->ntlmv2_hash); - if (rc) - cifs_dbg(VFS, "%s: Could not generate MD5 hash, rc=%d\n", __func__, rc); - - return rc; + /* Note that the HMAC-MD5 value overwrites ntlmv2->challenge.key */ + hmac_md5_usingrawkey(ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE, + ntlmv2->challenge.key, hash_len, + ntlmv2->ntlmv2_hash); } /* @@ -586,7 +559,6 @@ out: int setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) { - struct shash_desc *hmacmd5 = NULL; unsigned char *tiblob = NULL; /* target info blob */ struct ntlmv2_resp *ntlmv2; char ntlmv2_hash[16]; @@ -657,51 +629,29 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ntlmv2->client_chal = cc; ntlmv2->reserved2 = 0; - rc = cifs_alloc_hash("hmac(md5)", &hmacmd5); - if (rc) { - cifs_dbg(VFS, "Could not allocate HMAC-MD5, rc=%d\n", rc); + if (fips_enabled) { + cifs_dbg(VFS, "NTLMv2 support is disabled due to FIPS\n"); + rc = -EOPNOTSUPP; goto unlock; } /* calculate ntlmv2_hash */ - rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp, hmacmd5); + rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp); if (rc) { cifs_dbg(VFS, "Could not get NTLMv2 hash, rc=%d\n", rc); goto unlock; } /* calculate first part of the client response (CR1) */ - rc = CalcNTLMv2_response(ses, ntlmv2_hash, hmacmd5); - if (rc) { - cifs_dbg(VFS, "Could not calculate CR1, rc=%d\n", rc); - goto unlock; - } + CalcNTLMv2_response(ses, ntlmv2_hash); /* now calculate the session key for NTLMv2 */ - rc = crypto_shash_setkey(hmacmd5->tfm, ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); - if (rc) { - cifs_dbg(VFS, "%s: Could not set NTLMv2 hash as a key, rc=%d\n", __func__, rc); - goto unlock; - } - - rc = crypto_shash_init(hmacmd5); - if (rc) { - cifs_dbg(VFS, "%s: Could not init HMAC-MD5, rc=%d\n", __func__, rc); - goto unlock; - } - - rc = crypto_shash_update(hmacmd5, ntlmv2->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); - if (rc) { - cifs_dbg(VFS, "%s: Could not update with response, rc=%d\n", __func__, rc); - goto unlock; - } - - rc = crypto_shash_final(hmacmd5, ses->auth_key.response); - if (rc) - cifs_dbg(VFS, "%s: Could not generate MD5 hash, rc=%d\n", __func__, rc); + hmac_md5_usingrawkey(ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE, + ntlmv2->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE, + ses->auth_key.response); + rc = 0; unlock: cifs_server_unlock(ses->server); - cifs_free_hash(&hmacmd5); setup_ntlmv2_rsp_ret: kfree_sensitive(tiblob); @@ -743,9 +693,6 @@ void cifs_crypto_secmech_release(struct TCP_Server_Info *server) { cifs_free_hash(&server->secmech.aes_cmac); - cifs_free_hash(&server->secmech.hmacsha256); - cifs_free_hash(&server->secmech.md5); - cifs_free_hash(&server->secmech.sha512); if (server->secmech.enc) { crypto_free_aead(server->secmech.enc); diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index 05b1fa76e8cc..6eccb9ed9daa 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -173,7 +173,7 @@ module_param(enable_oplocks, bool, 0644); MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks. Default: y/Y/1"); module_param(enable_gcm_256, bool, 0644); -MODULE_PARM_DESC(enable_gcm_256, "Enable requesting strongest (256 bit) GCM encryption. Default: y/Y/0"); +MODULE_PARM_DESC(enable_gcm_256, "Enable requesting strongest (256 bit) GCM encryption. Default: y/Y/1"); module_param(require_gcm_256, bool, 0644); MODULE_PARM_DESC(require_gcm_256, "Require strongest (256 bit) GCM encryption. Default: n/N/0"); @@ -500,7 +500,7 @@ cifs_evict_inode(struct inode *inode) { netfs_wait_for_outstanding_io(inode); truncate_inode_pages_final(&inode->i_data); - if (inode->i_state & I_PINNING_NETFS_WB) + if (inode_state_read_once(inode) & I_PINNING_NETFS_WB) cifs_fscache_unuse_inode_cookie(inode, true); cifs_fscache_release_inode_cookie(inode); clear_inode(inode); @@ -1149,6 +1149,9 @@ cifs_setlease(struct file *file, int arg, struct file_lease **lease, void **priv struct inode *inode = file_inode(file); struct cifsFileInfo *cfile = file->private_data; + if (!S_ISREG(inode->i_mode)) + return -EINVAL; + /* Check if file is oplocked if this is request for new lease */ if (arg == F_UNLCK || ((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) || @@ -2139,13 +2142,9 @@ MODULE_DESCRIPTION "also older servers complying with the SNIA CIFS Specification)"); MODULE_VERSION(CIFS_VERSION); MODULE_SOFTDEP("ecb"); -MODULE_SOFTDEP("hmac"); -MODULE_SOFTDEP("md5"); MODULE_SOFTDEP("nls"); MODULE_SOFTDEP("aes"); MODULE_SOFTDEP("cmac"); -MODULE_SOFTDEP("sha256"); -MODULE_SOFTDEP("sha512"); MODULE_SOFTDEP("aead2"); MODULE_SOFTDEP("ccm"); MODULE_SOFTDEP("gcm"); diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 8f6f567d7474..0c76e0a31386 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -24,7 +24,9 @@ #include "cifsacl.h" #include <crypto/internal/hash.h> #include <uapi/linux/cifs/cifs_mount.h> +#include "../common/smbglob.h" #include "../common/smb2pdu.h" +#include "../common/fscc.h" #include "smb2pdu.h" #include <linux/filelock.h> @@ -221,9 +223,6 @@ struct session_key { /* crypto hashing related structure/fields, not specific to a sec mech */ struct cifs_secmech { - struct shash_desc *md5; /* md5 hash function, for CIFS/SMB1 signatures */ - struct shash_desc *hmacsha256; /* hmac-sha256 hash function, for SMB2 signatures */ - struct shash_desc *sha512; /* sha512 hash function, for SMB3.1.1 preauth hash */ struct shash_desc *aes_cmac; /* block-cipher based MAC function, for SMB3 signatures */ struct crypto_aead *enc; /* smb3 encryption AEAD TFM (AES-CCM and AES-GCM) */ @@ -536,8 +535,6 @@ struct smb_version_operations { void (*new_lease_key)(struct cifs_fid *); int (*generate_signingkey)(struct cifs_ses *ses, struct TCP_Server_Info *server); - int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *, - bool allocate_crypto); int (*set_integrity)(const unsigned int, struct cifs_tcon *tcon, struct cifsFileInfo *src_file); int (*enum_snapshots)(const unsigned int xid, struct cifs_tcon *tcon, @@ -637,28 +634,6 @@ struct smb_version_operations { struct kvec *xattr_iov); }; -struct smb_version_values { - char *version_string; - __u16 protocol_id; - __u32 req_capabilities; - __u32 large_lock_type; - __u32 exclusive_lock_type; - __u32 shared_lock_type; - __u32 unlock_lock_type; - size_t header_preamble_size; - size_t header_size; - size_t max_header_size; - size_t read_rsp_size; - __le16 lock_cmd; - unsigned int cap_unix; - unsigned int cap_nt_find; - unsigned int cap_large_files; - unsigned int cap_unicode; - __u16 signing_enabled; - __u16 signing_required; - size_t create_lease_size; -}; - #define HEADER_SIZE(server) (server->vals->header_size) #define MAX_HEADER_SIZE(server) (server->vals->max_header_size) #define HEADER_PREAMBLE_SIZE(server) (server->vals->header_preamble_size) @@ -696,18 +671,6 @@ struct cifs_mnt_data { int flags; }; -static inline unsigned int -get_rfc1002_length(void *buf) -{ - return be32_to_cpu(*((__be32 *)buf)) & 0xffffff; -} - -static inline void -inc_rfc1001_len(void *buf, int count) -{ - be32_add_cpu((__be32 *)buf, count); -} - struct TCP_Server_Info { struct list_head tcp_ses_list; struct list_head smb_ses_list; @@ -740,7 +703,7 @@ struct TCP_Server_Info { bool nosharesock; bool tcp_nodelay; bool terminate; - unsigned int credits; /* send no more requests at once */ + int credits; /* send no more requests at once */ unsigned int max_credits; /* can override large 32000 default at mnt */ unsigned int in_flight; /* number of requests on the wire to server */ unsigned int max_in_flight; /* max number of requests that were on wire */ @@ -1021,8 +984,6 @@ compare_mid(__u16 mid, const struct smb_hdr *smb) #define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ) + 4) #define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP) + 4) -#define CIFS_DEFAULT_IOSIZE (1024 * 1024) - /* * Windows only supports a max of 60kb reads and 65535 byte writes. Default to * those values when posix extensions aren't in force. In actuality here, we @@ -2148,30 +2109,20 @@ extern mempool_t cifs_io_request_pool; extern mempool_t cifs_io_subrequest_pool; /* Operations for different SMB versions */ -#define SMB1_VERSION_STRING "1.0" -#define SMB20_VERSION_STRING "2.0" #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY extern struct smb_version_operations smb1_operations; extern struct smb_version_values smb1_values; extern struct smb_version_operations smb20_operations; extern struct smb_version_values smb20_values; #endif /* CIFS_ALLOW_INSECURE_LEGACY */ -#define SMB21_VERSION_STRING "2.1" extern struct smb_version_operations smb21_operations; extern struct smb_version_values smb21_values; -#define SMBDEFAULT_VERSION_STRING "default" extern struct smb_version_values smbdefault_values; -#define SMB3ANY_VERSION_STRING "3" extern struct smb_version_values smb3any_values; -#define SMB30_VERSION_STRING "3.0" extern struct smb_version_operations smb30_operations; extern struct smb_version_values smb30_values; -#define SMB302_VERSION_STRING "3.02" -#define ALT_SMB302_VERSION_STRING "3.0.2" /*extern struct smb_version_operations smb302_operations;*/ /* not needed yet */ extern struct smb_version_values smb302_values; -#define SMB311_VERSION_STRING "3.1.1" -#define ALT_SMB311_VERSION_STRING "3.11" extern struct smb_version_operations smb311_operations; extern struct smb_version_values smb311_values; diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h index d9cf7db0ac35..49f35cb3cf2e 100644 --- a/fs/smb/client/cifspdu.h +++ b/fs/smb/client/cifspdu.h @@ -12,12 +12,14 @@ #include <net/sock.h> #include <linux/unaligned.h> #include "../common/smbfsctl.h" +#include "../common/smb2pdu.h" #define CIFS_PROT 0 #define POSIX_PROT (CIFS_PROT+1) #define BAD_PROT 0xFFFF /* SMB command codes: + * See MS-CIFS 2.2.2.1 * Note some commands have minimal (wct=0,bcc=0), or uninteresting, responses * (ie which include no useful data other than the SMB error code itself). * This can allow us to avoid response buffer allocations and copy in some cases @@ -86,7 +88,6 @@ #define NT_TRANSACT_GET_USER_QUOTA 0x07 #define NT_TRANSACT_SET_USER_QUOTA 0x08 -#define MAX_CIFS_SMALL_BUFFER_SIZE 448 /* big enough for most */ /* future chained NTCreateXReadX bigger, but for time being NTCreateX biggest */ /* among the requests (NTCreateX response is bigger with wct of 34) */ #define MAX_CIFS_HDR_SIZE 0x58 /* 4 len + 32 hdr + (2*24 wct) + 2 bct + 2 pad */ @@ -152,6 +153,7 @@ /* * SMB flag definitions + * See MS-CIFS 2.2.3.1 */ #define SMBFLG_EXTD_LOCK 0x01 /* server supports lock-read write-unlock smb */ #define SMBFLG_RCV_POSTED 0x02 /* obsolete */ @@ -165,6 +167,8 @@ /* * SMB flag2 definitions + * See MS-CIFS 2.2.3.1 + * MS-SMB 2.2.3.1 */ #define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1) /* can send long (non-8.3) path names in response */ @@ -180,98 +184,7 @@ #define SMBFLG2_ERR_STATUS cpu_to_le16(0x4000) #define SMBFLG2_UNICODE cpu_to_le16(0x8000) -/* - * These are the file access permission bits defined in CIFS for the - * NTCreateAndX as well as the level 0x107 - * TRANS2_QUERY_PATH_INFORMATION API. The level 0x107, SMB_QUERY_FILE_ALL_INFO - * responds with the AccessFlags. - * The AccessFlags specifies the access permissions a caller has to the - * file and can have any suitable combination of the following values: - */ - -#define FILE_READ_DATA 0x00000001 /* Data can be read from the file */ - /* or directory child entries can */ - /* be listed together with the */ - /* associated child attributes */ - /* (so the FILE_READ_ATTRIBUTES on */ - /* the child entry is not needed) */ -#define FILE_WRITE_DATA 0x00000002 /* Data can be written to the file */ - /* or new file can be created in */ - /* the directory */ -#define FILE_APPEND_DATA 0x00000004 /* Data can be appended to the file */ - /* (for non-local files over SMB it */ - /* is same as FILE_WRITE_DATA) */ - /* or new subdirectory can be */ - /* created in the directory */ -#define FILE_READ_EA 0x00000008 /* Extended attributes associated */ - /* with the file can be read */ -#define FILE_WRITE_EA 0x00000010 /* Extended attributes associated */ - /* with the file can be written */ -#define FILE_EXECUTE 0x00000020 /*Data can be read into memory from */ - /* the file using system paging I/O */ - /* for executing the file / script */ - /* or right to traverse directory */ - /* (but by default all users have */ - /* directory bypass traverse */ - /* privilege and do not need this */ - /* permission on directories at all)*/ -#define FILE_DELETE_CHILD 0x00000040 /* Child entry can be deleted from */ - /* the directory (so the DELETE on */ - /* the child entry is not needed) */ -#define FILE_READ_ATTRIBUTES 0x00000080 /* Attributes associated with the */ - /* file or directory can be read */ -#define FILE_WRITE_ATTRIBUTES 0x00000100 /* Attributes associated with the */ - /* file or directory can be written */ -#define DELETE 0x00010000 /* The file or dir can be deleted */ -#define READ_CONTROL 0x00020000 /* The discretionary access control */ - /* list and ownership associated */ - /* with the file or dir can be read */ -#define WRITE_DAC 0x00040000 /* The discretionary access control */ - /* list associated with the file or */ - /* directory can be written */ -#define WRITE_OWNER 0x00080000 /* Ownership information associated */ - /* with the file/dir can be written */ -#define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */ - /* synchronize with the completion */ - /* of an input/output request */ -#define SYSTEM_SECURITY 0x01000000 /* The system access control list */ - /* associated with the file or */ - /* directory can be read or written */ - /* (cannot be in DACL, can in SACL) */ -#define MAXIMUM_ALLOWED 0x02000000 /* Maximal subset of GENERIC_ALL */ - /* permissions which can be granted */ - /* (cannot be in DACL nor SACL) */ -#define GENERIC_ALL 0x10000000 /* Same as: GENERIC_EXECUTE | */ - /* GENERIC_WRITE | */ - /* GENERIC_READ | */ - /* FILE_DELETE_CHILD | */ - /* DELETE | */ - /* WRITE_DAC | */ - /* WRITE_OWNER */ - /* So GENERIC_ALL contains all bits */ - /* mentioned above except these two */ - /* SYSTEM_SECURITY MAXIMUM_ALLOWED */ -#define GENERIC_EXECUTE 0x20000000 /* Same as: FILE_EXECUTE | */ - /* FILE_READ_ATTRIBUTES | */ - /* READ_CONTROL | */ - /* SYNCHRONIZE */ -#define GENERIC_WRITE 0x40000000 /* Same as: FILE_WRITE_DATA | */ - /* FILE_APPEND_DATA | */ - /* FILE_WRITE_EA | */ - /* FILE_WRITE_ATTRIBUTES | */ - /* READ_CONTROL | */ - /* SYNCHRONIZE */ -#define GENERIC_READ 0x80000000 /* Same as: FILE_READ_DATA | */ - /* FILE_READ_EA | */ - /* FILE_READ_ATTRIBUTES | */ - /* READ_CONTROL | */ - /* SYNCHRONIZE */ - -#define FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES) -#define FILE_WRITE_RIGHTS (FILE_WRITE_DATA | FILE_APPEND_DATA \ - | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) -#define FILE_EXEC_RIGHTS (FILE_EXECUTE) - +/* Combinations of file access permission bits */ #define SET_FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA | FILE_WRITE_EA \ | FILE_READ_ATTRIBUTES \ | FILE_WRITE_ATTRIBUTES \ @@ -283,15 +196,6 @@ | FILE_WRITE_ATTRIBUTES \ | DELETE | READ_CONTROL | WRITE_DAC \ | WRITE_OWNER | SYNCHRONIZE) -#define SET_FILE_EXEC_RIGHTS (FILE_READ_EA | FILE_WRITE_EA | FILE_EXECUTE \ - | FILE_READ_ATTRIBUTES \ - | FILE_WRITE_ATTRIBUTES \ - | DELETE | READ_CONTROL | WRITE_DAC \ - | WRITE_OWNER | SYNCHRONIZE) - -#define SET_MINIMUM_RIGHTS (FILE_READ_EA | FILE_READ_ATTRIBUTES \ - | READ_CONTROL | SYNCHRONIZE) - /* * Invalid readdir handle @@ -325,29 +229,30 @@ /* * File Attribute flags */ -#define ATTR_READONLY 0x0001 -#define ATTR_HIDDEN 0x0002 -#define ATTR_SYSTEM 0x0004 -#define ATTR_VOLUME 0x0008 -#define ATTR_DIRECTORY 0x0010 -#define ATTR_ARCHIVE 0x0020 -#define ATTR_DEVICE 0x0040 -#define ATTR_NORMAL 0x0080 -#define ATTR_TEMPORARY 0x0100 -#define ATTR_SPARSE 0x0200 -#define ATTR_REPARSE 0x0400 -#define ATTR_COMPRESSED 0x0800 -#define ATTR_OFFLINE 0x1000 /* ie file not immediately available - - on offline storage */ -#define ATTR_NOT_CONTENT_INDEXED 0x2000 -#define ATTR_ENCRYPTED 0x4000 -#define ATTR_POSIX_SEMANTICS 0x01000000 -#define ATTR_BACKUP_SEMANTICS 0x02000000 -#define ATTR_DELETE_ON_CLOSE 0x04000000 -#define ATTR_SEQUENTIAL_SCAN 0x08000000 -#define ATTR_RANDOM_ACCESS 0x10000000 -#define ATTR_NO_BUFFERING 0x20000000 -#define ATTR_WRITE_THROUGH 0x80000000 +#define ATTR_READONLY 0x0001 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_HIDDEN 0x0002 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_SYSTEM 0x0004 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_VOLUME 0x0008 +#define ATTR_DIRECTORY 0x0010 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_ARCHIVE 0x0020 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_DEVICE 0x0040 +#define ATTR_NORMAL 0x0080 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_TEMPORARY 0x0100 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_SPARSE 0x0200 /* See MS-SMB 2.2.1.2.1 */ +#define ATTR_REPARSE_POINT 0x0400 /* See MS-SMB 2.2.1.2.1 */ +#define ATTR_COMPRESSED 0x0800 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_OFFLINE 0x1000 /* See MS-SMB 2.2.1.2.1 + ie file not immediately available - + on offline storage */ +#define ATTR_NOT_CONTENT_INDEXED 0x2000 /* See MS-SMB 2.2.1.2.1 */ +#define ATTR_ENCRYPTED 0x4000 /* See MS-SMB 2.2.1.2.1 */ +#define ATTR_POSIX_SEMANTICS 0x0100000 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_BACKUP_SEMANTICS 0x0200000 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_DELETE_ON_CLOSE 0x0400000 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_SEQUENTIAL_SCAN 0x0800000 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_RANDOM_ACCESS 0x1000000 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_NO_BUFFERING 0x2000000 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_WRITE_THROUGH 0x8000000 /* See MS-CIFS 2.2.1.2.3 */ /* ShareAccess flags */ #define FILE_NO_SHARE 0x00000000 @@ -417,38 +322,6 @@ #define GETU16(var) (*((__u16 *)var)) /* BB check for endian issues */ #define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */ -struct smb_hdr { - __be32 smb_buf_length; /* BB length is only two (rarely three) bytes, - with one or two byte "type" preceding it that will be - zero - we could mask the type byte off */ - __u8 Protocol[4]; - __u8 Command; - union { - struct { - __u8 ErrorClass; - __u8 Reserved; - __le16 Error; - } __attribute__((packed)) DosError; - __le32 CifsError; - } __attribute__((packed)) Status; - __u8 Flags; - __le16 Flags2; /* note: le */ - __le16 PidHigh; - union { - struct { - __le32 SequenceNumber; /* le */ - __u32 Reserved; /* zero */ - } __attribute__((packed)) Sequence; - __u8 SecuritySignature[8]; /* le */ - } __attribute__((packed)) Signature; - __u8 pad[2]; - __u16 Tid; - __le16 Pid; - __u16 Uid; - __le16 Mid; - __u8 WordCount; -} __attribute__((packed)); - /* given a pointer to an smb_hdr, retrieve a void pointer to the ByteCount */ static inline void * BCC(struct smb_hdr *smb) @@ -520,19 +393,15 @@ put_bcc(__u16 count, struct smb_hdr *hdr) * */ -typedef struct negotiate_req { - struct smb_hdr hdr; /* wct = 0 */ - __le16 ByteCount; - unsigned char DialectsArray[]; -} __attribute__((packed)) NEGOTIATE_REQ; - #define MIN_TZ_ADJ (15 * 60) /* minimum grid for timezones in seconds */ #define READ_RAW_ENABLE 1 #define WRITE_RAW_ENABLE 2 #define RAW_ENABLE (READ_RAW_ENABLE | WRITE_RAW_ENABLE) #define SMB1_CLIENT_GUID_SIZE (16) -typedef struct negotiate_rsp { + +/* See MS-CIFS 2.2.4.52.2 */ +typedef struct smb_negotiate_rsp { struct smb_hdr hdr; /* wct = 17 */ __le16 DialectIndex; /* 0xFFFF = no dialect acceptable */ __u8 SecurityMode; @@ -556,9 +425,9 @@ typedef struct negotiate_rsp { struct { unsigned char GUID[SMB1_CLIENT_GUID_SIZE]; unsigned char SecurityBlob[]; - } __attribute__((packed)) extended_response; - } __attribute__((packed)) u; -} __attribute__((packed)) NEGOTIATE_RSP; + } __packed extended_response; + } __packed u; +} __packed SMB_NEGOTIATE_RSP; /* SecurityMode bits */ #define SECMODE_USER 0x01 /* off indicates share level security */ @@ -605,7 +474,7 @@ typedef union smb_com_session_setup_andx { unsigned char SecurityBlob[]; /* followed by */ /* STRING NativeOS */ /* STRING NativeLanMan */ - } __attribute__((packed)) req; /* NTLM request format (with + } __packed req; /* NTLM request format (with extended security */ struct { /* request format */ @@ -628,7 +497,7 @@ typedef union smb_com_session_setup_andx { /* STRING PrimaryDomain */ /* STRING NativeOS */ /* STRING NativeLanMan */ - } __attribute__((packed)) req_no_secext; /* NTLM request format (without + } __packed req_no_secext; /* NTLM request format (without extended security */ struct { /* default (NTLM) response format */ @@ -643,7 +512,7 @@ typedef union smb_com_session_setup_andx { /* unsigned char * NativeOS; */ /* unsigned char * NativeLanMan; */ /* unsigned char * PrimaryDomain; */ - } __attribute__((packed)) resp; /* NTLM response + } __packed resp; /* NTLM response (with or without extended sec) */ struct { /* request format */ @@ -663,7 +532,7 @@ typedef union smb_com_session_setup_andx { /* STRING PrimaryDomain */ /* STRING NativeOS */ /* STRING NativeLanMan */ - } __attribute__((packed)) old_req; /* pre-NTLM (LANMAN2.1) req format */ + } __packed old_req; /* pre-NTLM (LANMAN2.1) req format */ struct { /* default (NTLM) response format */ struct smb_hdr hdr; /* wct = 3 */ @@ -675,8 +544,8 @@ typedef union smb_com_session_setup_andx { unsigned char NativeOS[]; /* followed by */ /* unsigned char * NativeLanMan; */ /* unsigned char * PrimaryDomain; */ - } __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response */ -} __attribute__((packed)) SESSION_SETUP_ANDX; + } __packed old_resp; /* pre-NTLM (LANMAN2.1) response */ +} __packed SESSION_SETUP_ANDX; /* format of NLTMv2 Response ie "case sensitive password" hash when NTLMv2 */ @@ -690,7 +559,7 @@ struct ntlmssp2_name { __le16 type; __le16 length; __u8 data[]; -} __attribute__((packed)); +} __packed; struct ntlmv2_resp { union { @@ -698,20 +567,25 @@ struct ntlmv2_resp { struct { __u8 reserved[8]; __u8 key[CIFS_SERVER_CHALLENGE_SIZE]; - } __attribute__((packed)) challenge; - } __attribute__((packed)); + } __packed challenge; + } __packed; __le32 blob_signature; __u32 reserved; __le64 time; __u64 client_chal; /* random */ __u32 reserved2; /* array of name entries could follow ending in minimum 4 byte struct */ -} __attribute__((packed)); +} __packed; #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" -/* Capabilities bits (for NTLM SessSetup request) */ + +/* + * Capabilities bits (for NTLM SessSetup request) + * See MS-CIFS 2.2.4.52.2 + * MS-SMB 2.2.4.5.2.1 + */ #define CAP_UNICODE 0x00000004 #define CAP_LARGE_FILES 0x00000008 #define CAP_NT_SMBS 0x00000010 @@ -719,7 +593,7 @@ struct ntlmv2_resp { #define CAP_LEVEL_II_OPLOCKS 0x00000080 #define CAP_NT_FIND 0x00000200 /* reserved should be zero (because NT_SMBs implies the same thing?) */ -#define CAP_BULK_TRANSFER 0x20000000 +#define CAP_BULK_TRANSFER 0x00000400 #define CAP_EXTENDED_SECURITY 0x80000000 /* Action bits */ @@ -736,7 +610,7 @@ typedef struct smb_com_tconx_req { unsigned char Password[]; /* followed by */ /* STRING Path *//* \\server\share name */ /* STRING Service */ -} __attribute__((packed)) TCONX_REQ; +} __packed TCONX_REQ; typedef struct smb_com_tconx_rsp { struct smb_hdr hdr; /* wct = 3 , not extended response */ @@ -747,7 +621,7 @@ typedef struct smb_com_tconx_rsp { __u16 ByteCount; unsigned char Service[]; /* always ASCII, not Unicode */ /* STRING NativeFileSystem */ -} __attribute__((packed)) TCONX_RSP; +} __packed TCONX_RSP; typedef struct smb_com_tconx_rsp_ext { struct smb_hdr hdr; /* wct = 7, extended response */ @@ -760,7 +634,7 @@ typedef struct smb_com_tconx_rsp_ext { __u16 ByteCount; unsigned char Service[]; /* always ASCII, not Unicode */ /* STRING NativeFileSystem */ -} __attribute__((packed)) TCONX_RSP_EXT; +} __packed TCONX_RSP_EXT; /* tree connect Flags */ @@ -796,14 +670,14 @@ typedef struct smb_com_echo_req { __le16 EchoCount; __le16 ByteCount; char Data[]; -} __attribute__((packed)) ECHO_REQ; +} __packed ECHO_REQ; typedef struct smb_com_echo_rsp { struct smb_hdr hdr; __le16 SequenceNumber; __le16 ByteCount; char Data[]; -} __attribute__((packed)) ECHO_RSP; +} __packed ECHO_RSP; typedef struct smb_com_logoff_andx_req { struct smb_hdr hdr; /* wct = 2 */ @@ -811,7 +685,7 @@ typedef struct smb_com_logoff_andx_req { __u8 AndXReserved; __u16 AndXOffset; __u16 ByteCount; -} __attribute__((packed)) LOGOFF_ANDX_REQ; +} __packed LOGOFF_ANDX_REQ; typedef struct smb_com_logoff_andx_rsp { struct smb_hdr hdr; /* wct = 2 */ @@ -819,7 +693,7 @@ typedef struct smb_com_logoff_andx_rsp { __u8 AndXReserved; __u16 AndXOffset; __u16 ByteCount; -} __attribute__((packed)) LOGOFF_ANDX_RSP; +} __packed LOGOFF_ANDX_RSP; typedef union smb_com_tree_disconnect { /* as an alternative can use flag on tree_connect PDU to effect disconnect */ @@ -827,36 +701,36 @@ typedef union smb_com_tree_disconnect { /* as an alternative can use flag on struct { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bcc = 0 */ - } __attribute__((packed)) req; + } __packed req; struct { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bcc = 0 */ - } __attribute__((packed)) resp; -} __attribute__((packed)) TREE_DISCONNECT; + } __packed resp; +} __packed TREE_DISCONNECT; typedef struct smb_com_close_req { struct smb_hdr hdr; /* wct = 3 */ __u16 FileID; __u32 LastWriteTime; /* should be zero or -1 */ __u16 ByteCount; /* 0 */ -} __attribute__((packed)) CLOSE_REQ; +} __packed CLOSE_REQ; typedef struct smb_com_close_rsp { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bct = 0 */ -} __attribute__((packed)) CLOSE_RSP; +} __packed CLOSE_RSP; typedef struct smb_com_flush_req { struct smb_hdr hdr; /* wct = 1 */ __u16 FileID; __u16 ByteCount; /* 0 */ -} __attribute__((packed)) FLUSH_REQ; +} __packed FLUSH_REQ; typedef struct smb_com_findclose_req { struct smb_hdr hdr; /* wct = 1 */ __u16 FileID; __u16 ByteCount; /* 0 */ -} __attribute__((packed)) FINDCLOSE_REQ; +} __packed FINDCLOSE_REQ; /* OpenFlags */ #define REQ_MORE_INFO 0x00000001 /* legacy (OPEN_AND_X) only */ @@ -903,7 +777,7 @@ typedef struct smb_com_open_req { /* also handles create */ __u8 SecurityFlags; __le16 ByteCount; char fileName[]; -} __attribute__((packed)) OPEN_REQ; +} __packed OPEN_REQ; /* open response: oplock levels */ #define OPLOCK_NONE 0 @@ -935,7 +809,7 @@ typedef struct smb_com_open_rsp { __le16 DeviceState; __u8 DirectoryFlag; __u16 ByteCount; /* bct = 0 */ -} __attribute__((packed)) OPEN_RSP; +} __packed OPEN_RSP; typedef struct smb_com_open_rsp_ext { struct smb_hdr hdr; /* wct = 42 but meaningless due to MS bug? */ @@ -960,7 +834,7 @@ typedef struct smb_com_open_rsp_ext { __le32 MaximalAccessRights; __le32 GuestMaximalAccessRights; __u16 ByteCount; /* bct = 0 */ -} __attribute__((packed)) OPEN_RSP_EXT; +} __packed OPEN_RSP_EXT; /* format of legacy open request */ @@ -980,7 +854,7 @@ typedef struct smb_com_openx_req { __le32 Reserved; __le16 ByteCount; /* file name follows */ char fileName[]; -} __attribute__((packed)) OPENX_REQ; +} __packed OPENX_REQ; typedef struct smb_com_openx_rsp { struct smb_hdr hdr; /* wct = 15 */ @@ -998,7 +872,7 @@ typedef struct smb_com_openx_rsp { __u32 FileId; __u16 Reserved; __u16 ByteCount; -} __attribute__((packed)) OPENX_RSP; +} __packed OPENX_RSP; /* For encoding of POSIX Open Request - see trans2 function 0x209 data struct */ @@ -1020,7 +894,7 @@ typedef struct smb_com_writex_req { __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ char Data[]; -} __attribute__((packed)) WRITEX_REQ; +} __packed WRITEX_REQ; typedef struct smb_com_write_req { struct smb_hdr hdr; /* wct = 14 */ @@ -1040,7 +914,7 @@ typedef struct smb_com_write_req { __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ char Data[]; -} __attribute__((packed)) WRITE_REQ; +} __packed WRITE_REQ; typedef struct smb_com_write_rsp { struct smb_hdr hdr; /* wct = 6 */ @@ -1052,7 +926,7 @@ typedef struct smb_com_write_rsp { __le16 CountHigh; __u16 Reserved; __u16 ByteCount; -} __attribute__((packed)) WRITE_RSP; +} __packed WRITE_RSP; /* legacy read request for older servers */ typedef struct smb_com_readx_req { @@ -1067,7 +941,7 @@ typedef struct smb_com_readx_req { __le32 Reserved; __le16 Remaining; __le16 ByteCount; -} __attribute__((packed)) READX_REQ; +} __packed READX_REQ; typedef struct smb_com_read_req { struct smb_hdr hdr; /* wct = 12 */ @@ -1082,7 +956,7 @@ typedef struct smb_com_read_req { __le16 Remaining; __le32 OffsetHigh; __le16 ByteCount; -} __attribute__((packed)) READ_REQ; +} __packed READ_REQ; typedef struct smb_com_read_rsp { struct smb_hdr hdr; /* wct = 12 */ @@ -1098,7 +972,7 @@ typedef struct smb_com_read_rsp { __u64 Reserved2; __u16 ByteCount; /* read response data immediately follows */ -} __attribute__((packed)) READ_RSP; +} __packed READ_RSP; typedef struct locking_andx_range { __le16 Pid; @@ -1107,7 +981,7 @@ typedef struct locking_andx_range { __le32 OffsetLow; __le32 LengthHigh; __le32 LengthLow; -} __attribute__((packed)) LOCKING_ANDX_RANGE; +} __packed LOCKING_ANDX_RANGE; #define LOCKING_ANDX_SHARED_LOCK 0x01 #define LOCKING_ANDX_OPLOCK_RELEASE 0x02 @@ -1128,7 +1002,7 @@ typedef struct smb_com_lock_req { __le16 NumberOfLocks; __le16 ByteCount; LOCKING_ANDX_RANGE Locks[]; -} __attribute__((packed)) LOCK_REQ; +} __packed LOCK_REQ; /* lock type */ #define CIFS_RDLCK 0 @@ -1141,7 +1015,7 @@ typedef struct cifs_posix_lock { __le64 start; __le64 length; /* BB what about additional owner info to identify network client */ -} __attribute__((packed)) CIFS_POSIX_LOCK; +} __packed CIFS_POSIX_LOCK; typedef struct smb_com_lock_rsp { struct smb_hdr hdr; /* wct = 2 */ @@ -1149,7 +1023,7 @@ typedef struct smb_com_lock_rsp { __u8 AndXReserved; __le16 AndXOffset; __u16 ByteCount; -} __attribute__((packed)) LOCK_RSP; +} __packed LOCK_RSP; typedef struct smb_com_rename_req { struct smb_hdr hdr; /* wct = 1 */ @@ -1159,7 +1033,7 @@ typedef struct smb_com_rename_req { unsigned char OldFileName[]; /* followed by __u8 BufferFormat2 */ /* followed by NewFileName */ -} __attribute__((packed)) RENAME_REQ; +} __packed RENAME_REQ; /* copy request flags */ #define COPY_MUST_BE_FILE 0x0001 @@ -1179,7 +1053,7 @@ typedef struct smb_com_copy_req { unsigned char OldFileName[]; /* followed by __u8 BufferFormat2 */ /* followed by NewFileName string */ -} __attribute__((packed)) COPY_REQ; +} __packed COPY_REQ; typedef struct smb_com_copy_rsp { struct smb_hdr hdr; /* wct = 1 */ @@ -1187,7 +1061,7 @@ typedef struct smb_com_copy_rsp { __u16 ByteCount; /* may be zero */ __u8 BufferFormat; /* 0x04 - only present if errored file follows */ unsigned char ErrorFileName[]; /* only present if error in copy */ -} __attribute__((packed)) COPY_RSP; +} __packed COPY_RSP; #define CREATE_HARD_LINK 0x103 #define MOVEFILE_COPY_ALLOWED 0x0002 @@ -1203,12 +1077,12 @@ typedef struct smb_com_nt_rename_req { /* A5 - also used for create hardlink */ unsigned char OldFileName[]; /* followed by __u8 BufferFormat2 */ /* followed by NewFileName */ -} __attribute__((packed)) NT_RENAME_REQ; +} __packed NT_RENAME_REQ; typedef struct smb_com_rename_rsp { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bct = 0 */ -} __attribute__((packed)) RENAME_RSP; +} __packed RENAME_RSP; typedef struct smb_com_delete_file_req { struct smb_hdr hdr; /* wct = 1 */ @@ -1216,43 +1090,43 @@ typedef struct smb_com_delete_file_req { __le16 ByteCount; __u8 BufferFormat; /* 4 = ASCII */ unsigned char fileName[]; -} __attribute__((packed)) DELETE_FILE_REQ; +} __packed DELETE_FILE_REQ; typedef struct smb_com_delete_file_rsp { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bct = 0 */ -} __attribute__((packed)) DELETE_FILE_RSP; +} __packed DELETE_FILE_RSP; typedef struct smb_com_delete_directory_req { struct smb_hdr hdr; /* wct = 0 */ __le16 ByteCount; __u8 BufferFormat; /* 4 = ASCII */ unsigned char DirName[]; -} __attribute__((packed)) DELETE_DIRECTORY_REQ; +} __packed DELETE_DIRECTORY_REQ; typedef struct smb_com_delete_directory_rsp { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bct = 0 */ -} __attribute__((packed)) DELETE_DIRECTORY_RSP; +} __packed DELETE_DIRECTORY_RSP; typedef struct smb_com_create_directory_req { struct smb_hdr hdr; /* wct = 0 */ __le16 ByteCount; __u8 BufferFormat; /* 4 = ASCII */ unsigned char DirName[]; -} __attribute__((packed)) CREATE_DIRECTORY_REQ; +} __packed CREATE_DIRECTORY_REQ; typedef struct smb_com_create_directory_rsp { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bct = 0 */ -} __attribute__((packed)) CREATE_DIRECTORY_RSP; +} __packed CREATE_DIRECTORY_RSP; typedef struct smb_com_query_information_req { struct smb_hdr hdr; /* wct = 0 */ __le16 ByteCount; /* 1 + namelen + 1 */ __u8 BufferFormat; /* 4 = ASCII */ unsigned char FileName[]; -} __attribute__((packed)) QUERY_INFORMATION_REQ; +} __packed QUERY_INFORMATION_REQ; typedef struct smb_com_query_information_rsp { struct smb_hdr hdr; /* wct = 10 */ @@ -1261,7 +1135,7 @@ typedef struct smb_com_query_information_rsp { __le32 size; __u16 reserved[5]; __le16 ByteCount; /* bcc = 0 */ -} __attribute__((packed)) QUERY_INFORMATION_RSP; +} __packed QUERY_INFORMATION_RSP; typedef struct smb_com_setattr_req { struct smb_hdr hdr; /* wct = 8 */ @@ -1271,12 +1145,12 @@ typedef struct smb_com_setattr_req { __le16 ByteCount; __u8 BufferFormat; /* 4 = ASCII */ unsigned char fileName[]; -} __attribute__((packed)) SETATTR_REQ; +} __packed SETATTR_REQ; typedef struct smb_com_setattr_rsp { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bct = 0 */ -} __attribute__((packed)) SETATTR_RSP; +} __packed SETATTR_RSP; /* empty wct response to setattr */ @@ -1304,7 +1178,7 @@ typedef struct smb_com_ntransact_req { __le16 ByteCount; __u8 Pad[3]; __u8 Parms[]; -} __attribute__((packed)) NTRANSACT_REQ; +} __packed NTRANSACT_REQ; typedef struct smb_com_ntransact_rsp { struct smb_hdr hdr; /* wct = 18 */ @@ -1321,15 +1195,7 @@ typedef struct smb_com_ntransact_rsp { __u16 ByteCount; /* __u8 Pad[3]; */ /* parms and data follow */ -} __attribute__((packed)) NTRANSACT_RSP; - -/* See MS-SMB 2.2.7.2.1.1 */ -struct srv_copychunk { - __le64 SourceOffset; - __le64 DestinationOffset; - __le32 CopyLength; - __u32 Reserved; -} __packed; +} __packed NTRANSACT_RSP; typedef struct smb_com_transaction_ioctl_req { struct smb_hdr hdr; /* wct = 23 */ @@ -1353,7 +1219,7 @@ typedef struct smb_com_transaction_ioctl_req { __le16 ByteCount; __u8 Pad[3]; __u8 Data[]; -} __attribute__((packed)) TRANSACT_IOCTL_REQ; +} __packed TRANSACT_IOCTL_REQ; typedef struct smb_com_transaction_compr_ioctl_req { struct smb_hdr hdr; /* wct = 23 */ @@ -1377,7 +1243,7 @@ typedef struct smb_com_transaction_compr_ioctl_req { __le16 ByteCount; __u8 Pad[3]; __le16 compression_state; /* See below for valid flags */ -} __attribute__((packed)) TRANSACT_COMPR_IOCTL_REQ; +} __packed TRANSACT_COMPR_IOCTL_REQ; /* compression state flags */ #define COMPRESSION_FORMAT_NONE 0x0000 @@ -1398,7 +1264,7 @@ typedef struct smb_com_transaction_ioctl_rsp { __u8 SetupCount; /* 1 */ __le16 ReturnedDataLen; __le16 ByteCount; -} __attribute__((packed)) TRANSACT_IOCTL_RSP; +} __packed TRANSACT_IOCTL_RSP; #define CIFS_ACL_OWNER 1 #define CIFS_ACL_GROUP 2 @@ -1425,7 +1291,7 @@ typedef struct smb_com_transaction_qsec_req { __u16 Fid; __u16 Reserved2; __le32 AclFlags; -} __attribute__((packed)) QUERY_SEC_DESC_REQ; +} __packed QUERY_SEC_DESC_REQ; typedef struct smb_com_transaction_ssec_req { @@ -1448,7 +1314,7 @@ typedef struct smb_com_transaction_ssec_req { __u16 Fid; __u16 Reserved2; __le32 AclFlags; -} __attribute__((packed)) SET_SEC_DESC_REQ; +} __packed SET_SEC_DESC_REQ; typedef struct smb_com_transaction_change_notify_req { struct smb_hdr hdr; /* wct = 23 */ @@ -1472,7 +1338,7 @@ typedef struct smb_com_transaction_change_notify_req { __le16 ByteCount; /* __u8 Pad[3];*/ /* __u8 Data[];*/ -} __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_REQ; +} __packed TRANSACT_CHANGE_NOTIFY_REQ; /* BB eventually change to use generic ntransact rsp struct and validation routine */ @@ -1490,7 +1356,7 @@ typedef struct smb_com_transaction_change_notify_rsp { __u8 SetupCount; /* 0 */ __u16 ByteCount; /* __u8 Pad[3]; */ -} __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_RSP; +} __packed TRANSACT_CHANGE_NOTIFY_RSP; /* Completion Filter flags for Notify */ #define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 #define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 @@ -1521,7 +1387,7 @@ struct file_notify_information { __le32 Action; __le32 FileNameLength; __u8 FileName[]; -} __attribute__((packed)); +} __packed; struct cifs_quota_data { __u32 rsrvd1; /* 0 */ @@ -1531,7 +1397,7 @@ struct cifs_quota_data { __u64 soft_limit; __u64 hard_limit; char sid[]; /* variable size? */ -} __attribute__((packed)); +} __packed; /* quota sub commands */ #define QUOTA_LIST_CONTINUE 0 @@ -1557,12 +1423,12 @@ struct trans2_req { __u8 Reserved3; __le16 SubCommand; /* 1st setup word - SetupCount words follow */ __le16 ByteCount; -} __attribute__((packed)); +} __packed; struct smb_t2_req { struct smb_hdr hdr; struct trans2_req t2_req; -} __attribute__((packed)); +} __packed; struct trans2_resp { /* struct smb_hdr hdr precedes. Note wct = 10 + setup count */ @@ -1581,12 +1447,12 @@ struct trans2_resp { __u16 ByteCount; __u16 Reserved2;*/ /* data area follows */ -} __attribute__((packed)); +} __packed; struct smb_t2_rsp { struct smb_hdr hdr; struct trans2_resp t2_rsp; -} __attribute__((packed)); +} __packed; /* PathInfo/FileInfo infolevels */ #define SMB_INFO_STANDARD 1 @@ -1683,14 +1549,14 @@ typedef struct smb_com_transaction2_qpi_req { __le16 InformationLevel; __u32 Reserved4; char FileName[]; -} __attribute__((packed)) TRANSACTION2_QPI_REQ; +} __packed TRANSACTION2_QPI_REQ; typedef struct smb_com_transaction2_qpi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ struct trans2_resp t2; __u16 ByteCount; __u16 Reserved2; /* parameter word is present for infolevels > 100 */ -} __attribute__((packed)) TRANSACTION2_QPI_RSP; +} __packed TRANSACTION2_QPI_RSP; typedef struct smb_com_transaction2_spi_req { struct smb_hdr hdr; /* wct = 15 */ @@ -1716,21 +1582,21 @@ typedef struct smb_com_transaction2_spi_req { __le16 InformationLevel; __u32 Reserved4; char FileName[]; -} __attribute__((packed)) TRANSACTION2_SPI_REQ; +} __packed TRANSACTION2_SPI_REQ; typedef struct smb_com_transaction2_spi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ struct trans2_resp t2; __u16 ByteCount; __u16 Reserved2; /* parameter word is present for infolevels > 100 */ -} __attribute__((packed)) TRANSACTION2_SPI_RSP; +} __packed TRANSACTION2_SPI_RSP; struct set_file_rename { __le32 overwrite; /* 1 = overwrite dest */ __u32 root_fid; /* zero */ __le32 target_name_len; char target_name[]; /* Must be unicode */ -} __attribute__((packed)); +} __packed; struct smb_com_transaction2_sfi_req { struct smb_hdr hdr; /* wct = 15 */ @@ -1757,14 +1623,14 @@ struct smb_com_transaction2_sfi_req { __le16 InformationLevel; __u16 Reserved4; __u8 payload[]; -} __attribute__((packed)); +} __packed; struct smb_com_transaction2_sfi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ struct trans2_resp t2; __u16 ByteCount; __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ -} __attribute__((packed)); +} __packed; struct smb_t2_qfi_req { struct smb_hdr hdr; @@ -1772,14 +1638,14 @@ struct smb_t2_qfi_req { __u8 Pad; __u16 Fid; __le16 InformationLevel; -} __attribute__((packed)); +} __packed; struct smb_t2_qfi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ struct trans2_resp t2; __u16 ByteCount; __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ -} __attribute__((packed)); +} __packed; /* * Flags on T2 FINDFIRST and FINDNEXT @@ -1821,13 +1687,13 @@ typedef struct smb_com_transaction2_ffirst_req { __le16 InformationLevel; __le32 SearchStorageType; char FileName[]; -} __attribute__((packed)) TRANSACTION2_FFIRST_REQ; +} __packed TRANSACTION2_FFIRST_REQ; typedef struct smb_com_transaction2_ffirst_rsp { struct smb_hdr hdr; /* wct = 10 */ struct trans2_resp t2; __u16 ByteCount; -} __attribute__((packed)) TRANSACTION2_FFIRST_RSP; +} __packed TRANSACTION2_FFIRST_RSP; typedef struct smb_com_transaction2_ffirst_rsp_parms { __u16 SearchHandle; @@ -1835,7 +1701,7 @@ typedef struct smb_com_transaction2_ffirst_rsp_parms { __le16 EndofSearch; __le16 EAErrorOffset; __le16 LastNameOffset; -} __attribute__((packed)) T2_FFIRST_RSP_PARMS; +} __packed T2_FFIRST_RSP_PARMS; typedef struct smb_com_transaction2_fnext_req { struct smb_hdr hdr; /* wct = 15 */ @@ -1863,20 +1729,20 @@ typedef struct smb_com_transaction2_fnext_req { __u32 ResumeKey; __le16 SearchFlags; char ResumeFileName[]; -} __attribute__((packed)) TRANSACTION2_FNEXT_REQ; +} __packed TRANSACTION2_FNEXT_REQ; typedef struct smb_com_transaction2_fnext_rsp { struct smb_hdr hdr; /* wct = 10 */ struct trans2_resp t2; __u16 ByteCount; -} __attribute__((packed)) TRANSACTION2_FNEXT_RSP; +} __packed TRANSACTION2_FNEXT_RSP; typedef struct smb_com_transaction2_fnext_rsp_parms { __le16 SearchCount; __le16 EndofSearch; __le16 EAErrorOffset; __le16 LastNameOffset; -} __attribute__((packed)) T2_FNEXT_RSP_PARMS; +} __packed T2_FNEXT_RSP_PARMS; /* QFSInfo Levels */ #define SMB_INFO_ALLOCATION 1 @@ -1920,14 +1786,14 @@ typedef struct smb_com_transaction2_qfsi_req { __le16 ByteCount; __u8 Pad; __le16 InformationLevel; -} __attribute__((packed)) TRANSACTION2_QFSI_REQ; +} __packed TRANSACTION2_QFSI_REQ; typedef struct smb_com_transaction_qfsi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ struct trans2_resp t2; __u16 ByteCount; __u8 Pad; /* may be three bytes? *//* followed by data area */ -} __attribute__((packed)) TRANSACTION2_QFSI_RSP; +} __packed TRANSACTION2_QFSI_RSP; typedef struct whoami_rsp_data { /* Query level 0x202 */ __u32 flags; /* 0 = Authenticated user 1 = GUEST */ @@ -1940,7 +1806,7 @@ typedef struct whoami_rsp_data { /* Query level 0x202 */ __u32 pad; /* reserved - MBZ */ /* __u64 gid_array[0]; */ /* may be empty */ /* __u8 * psid_list */ /* may be empty */ -} __attribute__((packed)) WHOAMI_RSP_DATA; +} __packed WHOAMI_RSP_DATA; /* SETFSInfo Levels */ #define SMB_SET_CIFS_UNIX_INFO 0x200 @@ -1973,7 +1839,7 @@ typedef struct smb_com_transaction2_setfsi_req { __le16 ClientUnixMajor; /* Data start. */ __le16 ClientUnixMinor; __le64 ClientUnixCap; /* Data end */ -} __attribute__((packed)) TRANSACTION2_SETFSI_REQ; +} __packed TRANSACTION2_SETFSI_REQ; /* level 0x203 request structure follows */ typedef struct smb_com_transaction2_setfs_enc_req { @@ -1999,14 +1865,14 @@ typedef struct smb_com_transaction2_setfs_enc_req { __u16 Reserved4; /* Parameters start. */ __le16 InformationLevel;/* Parameters end. */ /* NTLMSSP Blob, Data start. */ -} __attribute__((packed)) TRANSACTION2_SETFSI_ENC_REQ; +} __packed TRANSACTION2_SETFSI_ENC_REQ; /* response for setfsinfo levels 0x200 and 0x203 */ typedef struct smb_com_transaction2_setfsi_rsp { struct smb_hdr hdr; /* wct = 10 */ struct trans2_resp t2; __u16 ByteCount; -} __attribute__((packed)) TRANSACTION2_SETFSI_RSP; +} __packed TRANSACTION2_SETFSI_RSP; typedef struct smb_com_transaction2_get_dfs_refer_req { struct smb_hdr hdr; /* wct = 15 */ @@ -2032,7 +1898,7 @@ typedef struct smb_com_transaction2_get_dfs_refer_req { seem to matter though */ __le16 MaxReferralLevel; char RequestFileName[]; -} __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ; +} __packed TRANSACTION2_GET_DFS_REFER_REQ; #define DFS_VERSION cpu_to_le16(0x0003) @@ -2054,7 +1920,7 @@ typedef struct dfs_referral_level_3 { /* version 4 is same, + one flag bit */ __le16 DfsAlternatePathOffset; __le16 NetworkAddressOffset; /* offset of the link target */ __u8 ServiceSiteGuid[16]; /* MBZ, ignored */ -} __attribute__((packed)) REFERRAL3; +} __packed REFERRAL3; struct get_dfs_referral_rsp { __le16 PathConsumed; @@ -2094,7 +1960,7 @@ struct serverInfo { unsigned char versionMinor; unsigned long type; unsigned int commentOffset; -} __attribute__((packed)); +} __packed; /* * The following structure is the format of the data returned on a NetShareEnum @@ -2106,27 +1972,20 @@ struct shareInfo { char pad; unsigned short type; unsigned int commentOffset; -} __attribute__((packed)); +} __packed; struct aliasInfo { char aliasName[9]; char pad; unsigned int commentOffset; unsigned char type[2]; -} __attribute__((packed)); +} __packed; struct aliasInfo92 { int aliasNameOffset; int serverNameOffset; int shareNameOffset; -} __attribute__((packed)); - -typedef struct { - __le64 TotalAllocationUnits; - __le64 FreeAllocationUnits; - __le32 SectorsPerAllocationUnit; - __le32 BytesPerSector; -} __attribute__((packed)) FILE_SYSTEM_INFO; /* size info, level 0x103 */ +} __packed; typedef struct { __le32 fsid; @@ -2134,13 +1993,13 @@ typedef struct { __le32 TotalAllocationUnits; __le32 FreeAllocationUnits; __le16 BytesPerSector; -} __attribute__((packed)) FILE_SYSTEM_ALLOC_INFO; +} __packed FILE_SYSTEM_ALLOC_INFO; typedef struct { __le16 MajorVersionNumber; __le16 MinorVersionNumber; __le64 Capability; -} __attribute__((packed)) FILE_SYSTEM_UNIX_INFO; /* Unix extension level 0x200*/ +} __packed FILE_SYSTEM_UNIX_INFO; /* Unix extension level 0x200*/ /* Version numbers for CIFS UNIX major and minor. */ #define CIFS_UNIX_MAJOR_VERSION 1 @@ -2175,28 +2034,6 @@ typedef struct { #define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */ -typedef struct { - /* For undefined recommended transfer size return -1 in that field */ - __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ - __le32 BlockSize; - /* The next three fields are in terms of the block size. - (above). If block size is unknown, 4096 would be a - reasonable block size for a server to report. - Note that returning the blocks/blocksavail removes need - to make a second call (to QFSInfo level 0x103 to get this info. - UserBlockAvail is typically less than or equal to BlocksAvail, - if no distinction is made return the same value in each */ - __le64 TotalBlocks; - __le64 BlocksAvail; /* bfree */ - __le64 UserBlocksAvail; /* bavail */ - /* For undefined Node fields or FSID return -1 */ - __le64 TotalFileNodes; - __le64 FreeFileNodes; - __le64 FileSysIdentifier; /* fsid */ - /* NB Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call */ - /* NB flags can come from FILE_SYSTEM_DEVICE_INFO call */ -} __attribute__((packed)) FILE_SYSTEM_POSIX_INFO; - /* DeviceType Flags */ #define FILE_DEVICE_CD_ROM 0x00000002 #define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 @@ -2231,48 +2068,6 @@ typedef struct { #define FILE_PORTABLE_DEVICE 0x00004000 #define FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL 0x00020000 -typedef struct { - __le32 DeviceType; - __le32 DeviceCharacteristics; -} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */ - -/* minimum includes first three fields, and empty FS Name */ -#define MIN_FS_ATTR_INFO_SIZE 12 - - -/* List of FileSystemAttributes - see 2.5.1 of MS-FSCC */ -#define FILE_SUPPORTS_SPARSE_VDL 0x10000000 /* faster nonsparse extend */ -#define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000 /* allow ioctl dup extents */ -#define FILE_SUPPORT_INTEGRITY_STREAMS 0x04000000 -#define FILE_SUPPORTS_USN_JOURNAL 0x02000000 -#define FILE_SUPPORTS_OPEN_BY_FILE_ID 0x01000000 -#define FILE_SUPPORTS_EXTENDED_ATTRIBUTES 0x00800000 -#define FILE_SUPPORTS_HARD_LINKS 0x00400000 -#define FILE_SUPPORTS_TRANSACTIONS 0x00200000 -#define FILE_SEQUENTIAL_WRITE_ONCE 0x00100000 -#define FILE_READ_ONLY_VOLUME 0x00080000 -#define FILE_NAMED_STREAMS 0x00040000 -#define FILE_SUPPORTS_ENCRYPTION 0x00020000 -#define FILE_SUPPORTS_OBJECT_IDS 0x00010000 -#define FILE_VOLUME_IS_COMPRESSED 0x00008000 -#define FILE_SUPPORTS_POSIX_UNLINK_RENAME 0x00000400 -#define FILE_RETURNS_CLEANUP_RESULT_INFO 0x00000200 -#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100 -#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080 -#define FILE_SUPPORTS_SPARSE_FILES 0x00000040 -#define FILE_VOLUME_QUOTAS 0x00000020 -#define FILE_FILE_COMPRESSION 0x00000010 -#define FILE_PERSISTENT_ACLS 0x00000008 -#define FILE_UNICODE_ON_DISK 0x00000004 -#define FILE_CASE_PRESERVED_NAMES 0x00000002 -#define FILE_CASE_SENSITIVE_SEARCH 0x00000001 -typedef struct { - __le32 Attributes; - __le32 MaxPathNameComponentLength; - __le32 FileSystemNameLen; - char FileSystemName[52]; /* do not have to save this - get subset? */ -} __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO; - /******************************************************************************/ /* QueryFileInfo/QueryPathinfo (also for SetPath/SetFile) data buffer formats */ /******************************************************************************/ @@ -2297,7 +2092,7 @@ typedef struct { /* data block encoding of response to level 263 QPathInfo */ char __pad; DECLARE_FLEX_ARRAY(char, FileName); }; -} __attribute__((packed)) FILE_ALL_INFO; /* level 0x107 QPathInfo */ +} __packed FILE_ALL_INFO; /* level 0x107 QPathInfo */ typedef struct { __le64 AllocationSize; @@ -2306,7 +2101,7 @@ typedef struct { __u8 DeletePending; __u8 Directory; __u16 Pad; -} __attribute__((packed)) FILE_STANDARD_INFO; /* level 0x102 QPathInfo */ +} __packed FILE_STANDARD_INFO; /* level 0x102 QPathInfo */ /* defines for enumerating possible values of the Unix type field below */ @@ -2331,11 +2126,11 @@ typedef struct { __le64 UniqueId; __le64 Permissions; __le64 Nlinks; -} __attribute__((packed)) FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ +} __packed FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ typedef struct { DECLARE_FLEX_ARRAY(char, LinkDest); -} __attribute__((packed)) FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */ +} __packed FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */ /* The following three structures are needed only for setting time to NT4 and some older servers via @@ -2344,13 +2139,13 @@ typedef struct { __u16 Day:5; __u16 Month:4; __u16 Year:7; -} __attribute__((packed)) SMB_DATE; +} __packed SMB_DATE; typedef struct { __u16 TwoSeconds:5; __u16 Minutes:6; __u16 Hours:5; -} __attribute__((packed)) SMB_TIME; +} __packed SMB_TIME; typedef struct { __le16 CreationDate; /* SMB Date see above */ @@ -2363,7 +2158,7 @@ typedef struct { __le32 AllocationSize; __le16 Attributes; /* verify not u32 */ __le32 EASize; -} __attribute__((packed)) FILE_INFO_STANDARD; /* level 1 SetPath/FileInfo */ +} __packed FILE_INFO_STANDARD; /* level 1 SetPath/FileInfo */ typedef struct { __le64 CreationTime; @@ -2372,7 +2167,7 @@ typedef struct { __le64 ChangeTime; __le32 Attributes; __u32 Pad; -} __attribute__((packed)) FILE_BASIC_INFO; /* size info, level 0x101 */ +} __packed FILE_BASIC_INFO; /* size info, level 0x101 */ struct file_allocation_info { __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ @@ -2380,11 +2175,11 @@ struct file_allocation_info { struct file_end_of_file_info { __le64 FileSize; /* offset to end of file */ -} __attribute__((packed)); /* size info, level 0x104 for set, 0x106 for query */ +} __packed; /* size info, level 0x104 for set, 0x106 for query */ struct file_alt_name_info { DECLARE_FLEX_ARRAY(__u8, alt_name); -} __attribute__((packed)); /* level 0x0108 */ +} __packed; /* level 0x0108 */ struct file_stream_info { __le32 number_of_streams; /* BB check sizes and verify location */ @@ -2401,7 +2196,7 @@ struct file_compression_info { __u8 ch_shift; __u8 cl_shift; __u8 pad[3]; -} __attribute__((packed)); /* level 0x10b */ +} __packed; /* level 0x10b */ /* POSIX ACL set/query path info structures */ #define CIFS_ACL_VERSION 1 @@ -2409,7 +2204,7 @@ struct cifs_posix_ace { /* access control entry (ACE) */ __u8 cifs_e_tag; __u8 cifs_e_perm; __le64 cifs_uid; /* or gid */ -} __attribute__((packed)); +} __packed; struct cifs_posix_acl { /* access control list (ACL) */ __le16 version; @@ -2417,7 +2212,7 @@ struct cifs_posix_acl { /* access control list (ACL) */ __le16 default_entry_count; /* default ACL - count of entries */ struct cifs_posix_ace ace_array[]; /* followed by struct cifs_posix_ace default_ace_array[] */ -} __attribute__((packed)); /* level 0x204 */ +} __packed; /* level 0x204 */ /* types of access control entries already defined in posix_acl.h */ /* #define CIFS_POSIX_ACL_USER_OBJ 0x01 @@ -2452,7 +2247,7 @@ typedef struct { __le32 PosixOpenFlags; __le64 Permissions; __le16 Level; /* reply level requested (see QPathInfo levels) */ -} __attribute__((packed)) OPEN_PSX_REQ; /* level 0x209 SetPathInfo data */ +} __packed OPEN_PSX_REQ; /* level 0x209 SetPathInfo data */ typedef struct { __le16 OplockFlags; @@ -2461,27 +2256,27 @@ typedef struct { __le16 ReturnedLevel; __le16 Pad; /* struct following varies based on requested level */ -} __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */ +} __packed OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */ #define SMB_POSIX_UNLINK_FILE_TARGET 0 #define SMB_POSIX_UNLINK_DIRECTORY_TARGET 1 struct unlink_psx_rq { /* level 0x20a SetPathInfo */ __le16 type; -} __attribute__((packed)); +} __packed; struct file_internal_info { __le64 UniqueId; /* inode number */ -} __attribute__((packed)); /* level 0x3ee */ +} __packed; /* level 0x3ee */ struct file_mode_info { __le32 Mode; -} __attribute__((packed)); /* level 0x3f8 */ +} __packed; /* level 0x3f8 */ struct file_attrib_tag { __le32 Attribute; __le32 ReparseTag; -} __attribute__((packed)); /* level 0x40b */ +} __packed; /* level 0x40b */ /********************************************************/ @@ -2496,71 +2291,7 @@ typedef struct { char __pad; DECLARE_FLEX_ARRAY(char, FileName); }; -} __attribute__((packed)) FILE_UNIX_INFO; /* level 0x202 */ - -typedef struct { - __le32 NextEntryOffset; - __u32 FileIndex; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 ExtFileAttributes; - __le32 FileNameLength; - char FileName[]; -} __attribute__((packed)) FILE_DIRECTORY_INFO; /* level 0x101 FF resp data */ - -typedef struct { - __le32 NextEntryOffset; - __u32 FileIndex; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 ExtFileAttributes; - __le32 FileNameLength; - __le32 EaSize; /* length of the xattrs */ - char FileName[]; -} __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 rsp data */ - -typedef struct { - __le32 NextEntryOffset; - __u32 FileIndex; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 ExtFileAttributes; - __le32 FileNameLength; - __le32 EaSize; /* EA size */ - __le32 Reserved; - __le64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ - char FileName[]; -} __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF rsp data */ - -typedef struct { - __le32 NextEntryOffset; - __u32 FileIndex; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 ExtFileAttributes; - __le32 FileNameLength; - __le32 EaSize; /* length of the xattrs */ - __u8 ShortNameLength; - __u8 Reserved; - __u8 ShortName[24]; - char FileName[]; -} __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FFrsp data */ +} __packed FILE_UNIX_INFO; /* level 0x202 */ typedef struct { __u32 ResumeKey; @@ -2575,7 +2306,7 @@ typedef struct { __le16 Attributes; /* verify not u32 */ __u8 FileNameLength; char FileName[]; -} __attribute__((packed)) FIND_FILE_STANDARD_INFO; /* level 0x1 FF resp data */ +} __packed FIND_FILE_STANDARD_INFO; /* level 0x1 FF resp data */ struct fea { @@ -2584,21 +2315,21 @@ struct fea { __le16 value_len; char name[]; /* optionally followed by value */ -} __attribute__((packed)); +} __packed; /* flags for _FEA.fEA */ #define FEA_NEEDEA 0x80 /* need EA bit */ struct fealist { __le32 list_len; struct fea list; -} __attribute__((packed)); +} __packed; /* used to hold an arbitrary blob of data */ struct data_blob { __u8 *data; size_t length; void (*free) (struct data_blob *data_blob); -} __attribute__((packed)); +} __packed; #ifdef CONFIG_CIFS_POSIX @@ -2701,7 +2432,7 @@ struct xsymlink { char cr2; /* \n */ /* if room left, then end with \n then 0x20s by convention but not required */ char path[1024]; -} __attribute__((packed)); +} __packed; typedef struct file_xattr_info { /* BB do we need another field for flags? BB */ diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index e8fba98690ce..3528c365a452 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -9,6 +9,7 @@ #define _CIFSPROTO_H #include <linux/nls.h> #include <linux/ctype.h> +#include "cifsglob.h" #include "trace.h" #ifdef CONFIG_CIFS_DFS_UPCALL #include "dfs_cache.h" @@ -615,6 +616,8 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16, extern struct TCP_Server_Info * cifs_find_tcp_session(struct smb3_fs_context *ctx); +struct cifs_tcon *cifs_setup_ipc(struct cifs_ses *ses, bool seal); + void __cifs_put_smb_ses(struct cifs_ses *ses); extern struct cifs_ses * @@ -632,9 +635,13 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, const unsigned char *path, char *pbuf, unsigned int *pbytes_written); -int __cifs_calc_signature(struct smb_rqst *rqst, - struct TCP_Server_Info *server, char *signature, - struct shash_desc *shash); +struct cifs_calc_sig_ctx { + struct md5_ctx *md5; + struct hmac_sha256_ctx *hmac; + struct shash_desc *shash; +}; +int __cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, + char *signature, struct cifs_calc_sig_ctx *ctx); enum securityEnum cifs_select_sectype(struct TCP_Server_Info *, enum securityEnum); diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 2881efcbe09a..428e582e0414 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -361,7 +361,7 @@ vt2_err: } static int -decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr) +decode_ext_sec_blob(struct cifs_ses *ses, SMB_NEGOTIATE_RSP *pSMBr) { int rc = 0; u16 count; @@ -419,8 +419,8 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server) { - NEGOTIATE_REQ *pSMB; - NEGOTIATE_RSP *pSMBr; + SMB_NEGOTIATE_REQ *pSMB; + SMB_NEGOTIATE_RSP *pSMBr; int rc = 0; int bytes_returned; int i; @@ -614,7 +614,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server) iov[0].iov_len = 4; iov[0].iov_base = smb; - iov[1].iov_len = get_rfc1002_length(smb); + iov[1].iov_len = get_rfc1002_len(smb); iov[1].iov_base = (char *)smb + 4; rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL, @@ -1311,6 +1311,8 @@ cifs_readv_callback(struct mid_q_entry *mid) .rreq_debug_id = rdata->rreq->debug_id, .rreq_debug_index = rdata->subreq.debug_index, }; + unsigned int rreq_debug_id = rdata->rreq->debug_id; + unsigned int subreq_debug_index = rdata->subreq.debug_index; cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%zu\n", __func__, mid->mid, mid->mid_state, rdata->result, @@ -1361,6 +1363,14 @@ do_retry: if (rdata->result == -ENODATA) { rdata->result = 0; __set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags); + trace_smb3_read_err(rdata->rreq->debug_id, + rdata->subreq.debug_index, + rdata->xid, + rdata->req->cfile->fid.persistent_fid, + tcon->tid, tcon->ses->Suid, + rdata->subreq.start + rdata->subreq.transferred, + rdata->subreq.len - rdata->subreq.transferred, + rdata->result); } else { size_t trans = rdata->subreq.transferred + rdata->got_bytes; if (trans < rdata->subreq.len && @@ -1372,8 +1382,18 @@ do_retry: } if (rdata->got_bytes) __set_bit(NETFS_SREQ_MADE_PROGRESS, &rdata->subreq.flags); + trace_smb3_read_done(rdata->rreq->debug_id, + rdata->subreq.debug_index, + rdata->xid, + rdata->req->cfile->fid.persistent_fid, + tcon->tid, tcon->ses->Suid, + rdata->subreq.start + rdata->subreq.transferred, + rdata->got_bytes); } + trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, rdata->credits.value, + server->credits, server->in_flight, + 0, cifs_trace_rw_credits_read_response_clear); rdata->credits.value = 0; rdata->subreq.error = rdata->result; rdata->subreq.transferred += rdata->got_bytes; @@ -1381,6 +1401,9 @@ do_retry: netfs_read_subreq_terminated(&rdata->subreq); release_mid(mid); add_credits(server, &credits, 0); + trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0, + server->credits, server->in_flight, + credits.value, cifs_trace_rw_credits_read_response_add); } /* cifs_async_readv - send an async write, and set up mid to handle result */ @@ -1435,7 +1458,14 @@ cifs_async_readv(struct cifs_io_subrequest *rdata) rdata->iov[0].iov_base = smb; rdata->iov[0].iov_len = 4; rdata->iov[1].iov_base = (char *)smb + 4; - rdata->iov[1].iov_len = get_rfc1002_length(smb); + rdata->iov[1].iov_len = get_rfc1002_len(smb); + + trace_smb3_read_enter(rdata->rreq->debug_id, + rdata->subreq.debug_index, + rdata->xid, + rdata->req->cfile->fid.netfid, + tcon->tid, tcon->ses->Suid, + rdata->subreq.start, rdata->subreq.len); rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive, cifs_readv_callback, NULL, rdata, 0, NULL); @@ -1800,7 +1830,7 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) /* 4 for RFC1001 length + 1 for BCC */ iov[0].iov_len = 4; iov[0].iov_base = smb; - iov[1].iov_len = get_rfc1002_length(smb) + 1; + iov[1].iov_len = get_rfc1002_len(smb) + 1; iov[1].iov_base = (char *)smb + 4; rqst.rq_iov = iov; @@ -4716,7 +4746,7 @@ CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; TRANSACTION2_QFSI_RSP *pSMBr = NULL; - FILE_SYSTEM_INFO *response_data; + FILE_SYSTEM_SIZE_INFO *response_data; int rc = 0; int bytes_returned = 0; __u16 params, byte_count; @@ -4764,7 +4794,7 @@ QFSInfoRetry: __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); response_data = - (FILE_SYSTEM_INFO + (FILE_SYSTEM_SIZE_INFO *) (((char *) &pSMBr->hdr.Protocol) + data_offset); FSData->f_bsize = @@ -4781,7 +4811,7 @@ QFSInfoRetry: FSData->f_blocks = le64_to_cpu(response_data->TotalAllocationUnits); FSData->f_bfree = FSData->f_bavail = - le64_to_cpu(response_data->FreeAllocationUnits); + le64_to_cpu(response_data->AvailableAllocationUnits); cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n", (unsigned long long)FSData->f_blocks, (unsigned long long)FSData->f_bfree, diff --git a/fs/smb/client/cifstransport.c b/fs/smb/client/cifstransport.c index e98b95eff8c9..4c4f5befb6d3 100644 --- a/fs/smb/client/cifstransport.c +++ b/fs/smb/client/cifstransport.c @@ -165,7 +165,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses, int resp_buf_type; iov[0].iov_base = in_buf; - iov[0].iov_len = get_rfc1002_length(in_buf) + 4; + iov[0].iov_len = get_rfc1002_len(in_buf) + 4; flags |= CIFS_NO_RSP_BUF; rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov); cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc); @@ -177,7 +177,7 @@ int cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, bool log_error) { - unsigned int len = get_rfc1002_length(mid->resp_buf) + 4; + unsigned int len = get_rfc1002_len(mid->resp_buf) + 4; dump_smb(mid->resp_buf, min_t(u32, 92, len)); @@ -370,7 +370,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, goto out; } - *pbytes_returned = get_rfc1002_length(midQ->resp_buf); + *pbytes_returned = get_rfc1002_len(midQ->resp_buf); memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4); rc = cifs_check_receive(midQ, server, 0); out: @@ -554,7 +554,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, goto out; } - *pbytes_returned = get_rfc1002_length(midQ->resp_buf); + *pbytes_returned = get_rfc1002_len(midQ->resp_buf); memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4); rc = cifs_check_receive(midQ, server, 0); out: diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index dd12f3eb61dc..0049d65de50b 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -310,6 +310,8 @@ cifs_abort_connection(struct TCP_Server_Info *server) server->ssocket->flags); sock_release(server->ssocket); server->ssocket = NULL; + } else if (cifs_rdma_enabled(server)) { + smbd_destroy(server); } server->sequence_number = 0; server->session_estab = false; @@ -338,12 +340,6 @@ cifs_abort_connection(struct TCP_Server_Info *server) mid_execute_callback(mid); release_mid(mid); } - - if (cifs_rdma_enabled(server)) { - cifs_server_lock(server); - smbd_destroy(server); - cifs_server_unlock(server); - } } static bool cifs_tcp_ses_needs_reconnect(struct TCP_Server_Info *server, int num_targets) @@ -1299,7 +1295,7 @@ cifs_demultiplex_thread(void *p) * The right amount was read from socket - 4 bytes, * so we can now interpret the length field. */ - pdu_length = get_rfc1002_length(buf); + pdu_length = get_rfc1002_len(buf); cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length); if (!is_smb_response(server, buf[0])) @@ -2015,39 +2011,31 @@ static int match_session(struct cifs_ses *ses, /** * cifs_setup_ipc - helper to setup the IPC tcon for the session * @ses: smb session to issue the request on - * @ctx: the superblock configuration context to use for building the - * new tree connection for the IPC (interprocess communication RPC) + * @seal: if encryption is requested * * A new IPC connection is made and stored in the session * tcon_ipc. The IPC tcon has the same lifetime as the session. */ -static int -cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx) +struct cifs_tcon *cifs_setup_ipc(struct cifs_ses *ses, bool seal) { int rc = 0, xid; struct cifs_tcon *tcon; char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0}; - bool seal = false; struct TCP_Server_Info *server = ses->server; /* * If the mount request that resulted in the creation of the * session requires encryption, force IPC to be encrypted too. */ - if (ctx->seal) { - if (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) - seal = true; - else { - cifs_server_dbg(VFS, - "IPC: server doesn't support encryption\n"); - return -EOPNOTSUPP; - } + if (seal && !(server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)) { + cifs_server_dbg(VFS, "IPC: server doesn't support encryption\n"); + return ERR_PTR(-EOPNOTSUPP); } /* no need to setup directory caching on IPC share, so pass in false */ tcon = tcon_info_alloc(false, netfs_trace_tcon_ref_new_ipc); if (tcon == NULL) - return -ENOMEM; + return ERR_PTR(-ENOMEM); spin_lock(&server->srv_lock); scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname); @@ -2057,13 +2045,13 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx) tcon->ses = ses; tcon->ipc = true; tcon->seal = seal; - rc = server->ops->tree_connect(xid, ses, unc, tcon, ctx->local_nls); + rc = server->ops->tree_connect(xid, ses, unc, tcon, ses->local_nls); free_xid(xid); if (rc) { - cifs_server_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc); + cifs_server_dbg(VFS | ONCE, "failed to connect to IPC (rc=%d)\n", rc); tconInfoFree(tcon, netfs_trace_tcon_ref_free_ipc_fail); - goto out; + return ERR_PTR(rc); } cifs_dbg(FYI, "IPC tcon rc=%d ipc tid=0x%x\n", rc, tcon->tid); @@ -2071,9 +2059,7 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx) spin_lock(&tcon->tc_lock); tcon->status = TID_GOOD; spin_unlock(&tcon->tc_lock); - ses->tcon_ipc = tcon; -out: - return rc; + return tcon; } static struct cifs_ses * @@ -2326,8 +2312,8 @@ out_err: } #else /* ! CONFIG_KEYS */ static inline int -cifs_set_cifscreds(struct smb3_fs_context *ctx __attribute__((unused)), - struct cifs_ses *ses __attribute__((unused))) +cifs_set_cifscreds(struct smb3_fs_context *ctx __maybe_unused, + struct cifs_ses *ses __maybe_unused) { return -ENOSYS; } @@ -2347,6 +2333,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; + struct cifs_tcon *ipc; struct cifs_ses *ses; unsigned int xid; int retries = 0; @@ -2525,7 +2512,12 @@ retry_new_session: list_add(&ses->smb_ses_list, &server->smb_ses_list); spin_unlock(&cifs_tcp_ses_lock); - cifs_setup_ipc(ses, ctx); + ipc = cifs_setup_ipc(ses, ctx->seal); + spin_lock(&cifs_tcp_ses_lock); + spin_lock(&ses->ses_lock); + ses->tcon_ipc = !IS_ERR(ipc) ? ipc : NULL; + spin_unlock(&ses->ses_lock); + spin_unlock(&cifs_tcp_ses_lock); free_xid(xid); @@ -3112,7 +3104,7 @@ bind_socket(struct TCP_Server_Info *server) struct socket *socket = server->ssocket; rc = kernel_bind(socket, - (struct sockaddr *) &server->srcaddr, + (struct sockaddr_unsized *) &server->srcaddr, sizeof(server->srcaddr)); if (rc < 0) { struct sockaddr_in *saddr4; @@ -3411,7 +3403,7 @@ generic_ip_connect(struct TCP_Server_Info *server) socket->sk->sk_sndbuf, socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo); - rc = kernel_connect(socket, saddr, slen, + rc = kernel_connect(socket, (struct sockaddr_unsized *)saddr, slen, server->noblockcnt ? O_NONBLOCK : 0); /* * When mounting SMB root file systems, we do not want to block in @@ -4459,6 +4451,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) out: kfree(ctx->username); + kfree(ctx->domainname); kfree_sensitive(ctx->password); kfree(origin_fullpath); kfree(ctx); diff --git a/fs/smb/client/dfs_cache.c b/fs/smb/client/dfs_cache.c index 4dada26d56b5..f2ad0ccd08a7 100644 --- a/fs/smb/client/dfs_cache.c +++ b/fs/smb/client/dfs_cache.c @@ -1120,24 +1120,63 @@ static bool target_share_equal(struct cifs_tcon *tcon, const char *s1) return match; } -static bool is_ses_good(struct cifs_ses *ses) +static bool is_ses_good(struct cifs_tcon *tcon, struct cifs_ses *ses) { struct TCP_Server_Info *server = ses->server; - struct cifs_tcon *tcon = ses->tcon_ipc; + struct cifs_tcon *ipc = NULL; bool ret; + spin_lock(&cifs_tcp_ses_lock); spin_lock(&ses->ses_lock); spin_lock(&ses->chan_lock); + ret = !cifs_chan_needs_reconnect(ses, server) && - ses->ses_status == SES_GOOD && - !tcon->need_reconnect; + ses->ses_status == SES_GOOD; + spin_unlock(&ses->chan_lock); + + if (!ret) + goto out; + + if (likely(ses->tcon_ipc)) { + if (ses->tcon_ipc->need_reconnect) { + ret = false; + goto out; + } + } else { + spin_unlock(&ses->ses_lock); + spin_unlock(&cifs_tcp_ses_lock); + + ipc = cifs_setup_ipc(ses, tcon->seal); + + spin_lock(&cifs_tcp_ses_lock); + spin_lock(&ses->ses_lock); + if (!IS_ERR(ipc)) { + if (!ses->tcon_ipc) { + ses->tcon_ipc = ipc; + ipc = NULL; + } + } else { + ret = false; + ipc = NULL; + } + } + +out: spin_unlock(&ses->ses_lock); + spin_unlock(&cifs_tcp_ses_lock); + if (ipc && server->ops->tree_disconnect) { + unsigned int xid = get_xid(); + + (void)server->ops->tree_disconnect(xid, ipc); + _free_xid(xid); + } + tconInfoFree(ipc, netfs_trace_tcon_ref_free_ipc); return ret; } /* Refresh dfs referral of @ses */ -static void refresh_ses_referral(struct cifs_ses *ses) +static void refresh_ses_referral(struct cifs_tcon *tcon, struct cifs_ses *ses) { struct cache_entry *ce; unsigned int xid; @@ -1153,7 +1192,7 @@ static void refresh_ses_referral(struct cifs_ses *ses) } ses = CIFS_DFS_ROOT_SES(ses); - if (!is_ses_good(ses)) { + if (!is_ses_good(tcon, ses)) { cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n", __func__); goto out; @@ -1241,7 +1280,7 @@ static void refresh_tcon_referral(struct cifs_tcon *tcon, bool force_refresh) up_read(&htable_rw_lock); ses = CIFS_DFS_ROOT_SES(ses); - if (!is_ses_good(ses)) { + if (!is_ses_good(tcon, ses)) { cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n", __func__); goto out; @@ -1309,7 +1348,7 @@ void dfs_cache_refresh(struct work_struct *work) tcon = container_of(work, struct cifs_tcon, dfs_cache_work.work); list_for_each_entry(ses, &tcon->dfs_ses_list, dlist) - refresh_ses_referral(ses); + refresh_ses_referral(tcon, ses); refresh_tcon_referral(tcon, false); queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work, diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 474dadeb1593..9dc0a968ec89 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -9,6 +9,7 @@ * */ #include <linux/fs.h> +#include <linux/fs_struct.h> #include <linux/filelock.h> #include <linux/backing-dev.h> #include <linux/stat.h> diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index e60927b2a7c8..2a0d8b87bd8e 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -1435,12 +1435,14 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, cifs_errorf(fc, "Unknown error parsing devname\n"); goto cifs_parse_mount_err; } + kfree(ctx->source); ctx->source = smb3_fs_context_fullpath(ctx, '/'); if (IS_ERR(ctx->source)) { ctx->source = NULL; cifs_errorf(fc, "OOM when copying UNC string\n"); goto cifs_parse_mount_err; } + kfree(fc->source); fc->source = kstrdup(ctx->source, GFP_KERNEL); if (fc->source == NULL) { cifs_errorf(fc, "OOM when copying UNC string\n"); @@ -1468,7 +1470,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, break; } - if (strnlen(param->string, CIFS_MAX_USERNAME_LEN) > + if (strnlen(param->string, CIFS_MAX_USERNAME_LEN) == CIFS_MAX_USERNAME_LEN) { pr_warn("username too long\n"); goto cifs_parse_mount_err; @@ -1832,6 +1834,10 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, ctx->password = NULL; kfree_sensitive(ctx->password2); ctx->password2 = NULL; + kfree(ctx->source); + ctx->source = NULL; + kfree(fc->source); + fc->source = NULL; return -EINVAL; } diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index 239dd84a336f..400e4fbd450f 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -6,6 +6,7 @@ * */ #include <linux/fs.h> +#include <linux/fs_struct.h> #include <linux/stat.h> #include <linux/slab.h> #include <linux/pagemap.h> @@ -101,7 +102,7 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr) cifs_dbg(FYI, "%s: revalidating inode %llu\n", __func__, cifs_i->uniqueid); - if (inode->i_state & I_NEW) { + if (inode_state_read_once(inode) & I_NEW) { cifs_dbg(FYI, "%s: inode %llu is new\n", __func__, cifs_i->uniqueid); return; @@ -146,7 +147,7 @@ cifs_nlink_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) */ if (fattr->cf_flags & CIFS_FATTR_UNKNOWN_NLINK) { /* only provide fake values on a new inode */ - if (inode->i_state & I_NEW) { + if (inode_state_read_once(inode) & I_NEW) { if (fattr->cf_cifsattrs & ATTR_DIRECTORY) set_nlink(inode, 2); else @@ -167,12 +168,12 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr, struct cifsInodeInfo *cifs_i = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - if (!(inode->i_state & I_NEW) && + if (!(inode_state_read_once(inode) & I_NEW) && unlikely(inode_wrong_type(inode, fattr->cf_mode))) { CIFS_I(inode)->time = 0; /* force reval */ return -ESTALE; } - if (inode->i_state & I_NEW) + if (inode_state_read_once(inode) & I_NEW) CIFS_I(inode)->netfs.zero_point = fattr->cf_eof; cifs_revalidate_cache(inode, fattr); @@ -194,7 +195,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr, inode->i_gid = fattr->cf_gid; /* if dynperm is set, don't clobber existing mode */ - if (inode->i_state & I_NEW || + if (inode_state_read(inode) & I_NEW || !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) inode->i_mode = fattr->cf_mode; @@ -236,7 +237,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr, if (fattr->cf_flags & CIFS_FATTR_JUNCTION) inode->i_flags |= S_AUTOMOUNT; - if (inode->i_state & I_NEW) { + if (inode_state_read_once(inode) & I_NEW) { cifs_set_netfs_context(inode); cifs_set_ops(inode); } @@ -1328,7 +1329,7 @@ static int cifs_get_fattr(struct cifs_open_info_data *data, /* for easier reading */ FILE_ALL_INFO *fi; FILE_DIRECTORY_INFO *fdi; - SEARCH_ID_FULL_DIR_INFO *si; + FILE_ID_FULL_DIR_INFO *si; rc = cifs_backup_query_path_info(xid, tcon, sb, full_path, @@ -1339,7 +1340,7 @@ static int cifs_get_fattr(struct cifs_open_info_data *data, move_cifs_info_to_smb2(&data->fi, fi); fdi = (FILE_DIRECTORY_INFO *)fi; - si = (SEARCH_ID_FULL_DIR_INFO *)fi; + si = (FILE_ID_FULL_DIR_INFO *)fi; cifs_dir_info_to_fattr(fattr, fdi, cifs_sb); fattr->cf_uniqueid = le64_to_cpu(si->UniqueId); @@ -1638,7 +1639,7 @@ retry_iget5_locked: cifs_fattr_to_inode(inode, fattr, false); if (sb->s_flags & SB_NOATIME) inode->i_flags |= S_NOATIME | S_NOCMTIME; - if (inode->i_state & I_NEW) { + if (inode_state_read_once(inode) & I_NEW) { inode->i_ino = hash; cifs_fscache_get_inode_cookie(inode); unlock_new_inode(inode); @@ -2431,8 +2432,10 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, tcon = tlink_tcon(tlink); server = tcon->ses->server; - if (!server->ops->rename) - return -ENOSYS; + if (!server->ops->rename) { + rc = -ENOSYS; + goto do_rename_exit; + } /* try path-based rename first */ rc = server->ops->rename(xid, tcon, from_dentry, @@ -2482,11 +2485,8 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry, } #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ do_rename_exit: - if (rc == 0) { + if (rc == 0) d_move(from_dentry, to_dentry); - /* Force a new lookup */ - d_drop(from_dentry); - } cifs_put_tlink(tlink); return rc; } diff --git a/fs/smb/client/link.c b/fs/smb/client/link.c index fe80e711cd75..70f3c0c67eeb 100644 --- a/fs/smb/client/link.c +++ b/fs/smb/client/link.c @@ -5,6 +5,7 @@ * Author(s): Steve French (sfrench@us.ibm.com) * */ +#include <crypto/md5.h> #include <linux/fs.h> #include <linux/stat.h> #include <linux/slab.h> @@ -37,23 +38,6 @@ #define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) md5_hash static int -symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash) -{ - int rc; - struct shash_desc *md5 = NULL; - - rc = cifs_alloc_hash("md5", &md5); - if (rc) - return rc; - - rc = crypto_shash_digest(md5, link_str, link_len, md5_hash); - if (rc) - cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__); - cifs_free_hash(&md5); - return rc; -} - -static int parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len, char **_link_str) { @@ -77,11 +61,7 @@ parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len, if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN) return -EINVAL; - rc = symlink_hash(link_len, link_str, md5_hash); - if (rc) { - cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc); - return rc; - } + md5(link_str, link_len, md5_hash); scnprintf(md5_str2, sizeof(md5_str2), CIFS_MF_SYMLINK_MD5_FORMAT, @@ -103,7 +83,6 @@ parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len, static int format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str) { - int rc; unsigned int link_len; unsigned int ofs; u8 md5_hash[16]; @@ -116,11 +95,7 @@ format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str) if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN) return -ENAMETOOLONG; - rc = symlink_hash(link_len, link_str, md5_hash); - if (rc) { - cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc); - return rc; - } + md5(link_str, link_len, md5_hash); scnprintf(buf, buf_len, CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT, diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c index dda6dece802a..340c44dc7b5b 100644 --- a/fs/smb/client/misc.c +++ b/fs/smb/client/misc.c @@ -318,7 +318,7 @@ static int check_smb_hdr(struct smb_hdr *smb) { /* does it have the right SMB "signature" ? */ - if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) { + if (*(__le32 *) smb->Protocol != SMB1_PROTO_NUMBER) { cifs_dbg(VFS, "Bad protocol string signature header 0x%x\n", *(unsigned int *)smb->Protocol); return 1; @@ -916,6 +916,14 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, char *data_end; struct dfs_referral_level_3 *ref; + if (rsp_size < sizeof(*rsp)) { + cifs_dbg(VFS | ONCE, + "%s: header is malformed (size is %u, must be %zu)\n", + __func__, rsp_size, sizeof(*rsp)); + rc = -EINVAL; + goto parse_DFS_referrals_exit; + } + *num_of_nodes = le16_to_cpu(rsp->NumberOfReferrals); if (*num_of_nodes < 1) { @@ -925,6 +933,15 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, goto parse_DFS_referrals_exit; } + if (sizeof(*rsp) + *num_of_nodes * sizeof(REFERRAL3) > rsp_size) { + cifs_dbg(VFS | ONCE, + "%s: malformed buffer (size is %u, must be at least %zu)\n", + __func__, rsp_size, + sizeof(*rsp) + *num_of_nodes * sizeof(REFERRAL3)); + rc = -EINVAL; + goto parse_DFS_referrals_exit; + } + ref = (struct dfs_referral_level_3 *) &(rsp->referrals); if (ref->VersionNumber != cpu_to_le16(3)) { cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n", diff --git a/fs/smb/client/ntlmssp.h b/fs/smb/client/ntlmssp.h index 875de43b72de..a11fddc321f6 100644 --- a/fs/smb/client/ntlmssp.h +++ b/fs/smb/client/ntlmssp.h @@ -73,7 +73,7 @@ typedef struct _SECURITY_BUFFER { __le16 Length; __le16 MaximumLength; __le32 BufferOffset; /* offset to buffer */ -} __attribute__((packed)) SECURITY_BUFFER; +} __packed SECURITY_BUFFER; typedef struct _NEGOTIATE_MESSAGE { __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; @@ -85,7 +85,7 @@ typedef struct _NEGOTIATE_MESSAGE { do not set the version is present flag */ char DomainString[]; /* followed by WorkstationString */ -} __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; +} __packed NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; #define NTLMSSP_REVISION_W2K3 0x0F @@ -121,7 +121,7 @@ typedef struct _CHALLENGE_MESSAGE { SECURITY_BUFFER TargetInfoArray; /* SECURITY_BUFFER for version info not present since we do not set the version is present flag */ -} __attribute__((packed)) CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; +} __packed CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; typedef struct _AUTHENTICATE_MESSAGE { __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; @@ -136,7 +136,7 @@ typedef struct _AUTHENTICATE_MESSAGE { struct ntlmssp_version Version; /* SECURITY_BUFFER */ char UserString[]; -} __attribute__((packed)) AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; +} __packed AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; /* * Size of the session key (crypto key encrypted with the password diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c index f0ce26622a14..7ff728503ed1 100644 --- a/fs/smb/client/readdir.c +++ b/fs/smb/client/readdir.c @@ -98,7 +98,7 @@ retry: default: break; } - } else if (fattr->cf_cifsattrs & ATTR_REPARSE) { + } else if (fattr->cf_cifsattrs & ATTR_REPARSE_POINT) { reparse_need_reval = true; } @@ -138,7 +138,7 @@ retry: * reparse tag and ctime haven't changed. */ rc = 0; - if (fattr->cf_cifsattrs & ATTR_REPARSE) { + if (fattr->cf_cifsattrs & ATTR_REPARSE_POINT) { if (likely(reparse_inode_match(inode, fattr))) { fattr->cf_mode = inode->i_mode; fattr->cf_rdev = inode->i_rdev; @@ -190,7 +190,7 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) * TODO: go through all documented reparse tags to see if we can * reasonably map some of them to directories vs. files vs. symlinks */ - if ((fattr->cf_cifsattrs & ATTR_REPARSE) && + if ((fattr->cf_cifsattrs & ATTR_REPARSE_POINT) && cifs_reparse_point_to_fattr(cifs_sb, fattr, &data)) goto out_reparse; @@ -258,7 +258,7 @@ cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info, fattr->cf_nlink = le32_to_cpu(info->HardLinks); fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes); - if (fattr->cf_cifsattrs & ATTR_REPARSE) + if (fattr->cf_cifsattrs & ATTR_REPARSE_POINT) fattr->cf_cifstag = le32_to_cpu(info->ReparseTag); /* The Mode field in the response can now include the file type as well */ @@ -316,7 +316,7 @@ static void cifs_fulldir_info_to_fattr(struct cifs_fattr *fattr, __dir_info_to_fattr(fattr, info); /* See MS-FSCC 2.4.14, 2.4.19 */ - if (fattr->cf_cifsattrs & ATTR_REPARSE) + if (fattr->cf_cifsattrs & ATTR_REPARSE_POINT) fattr->cf_cifstag = le32_to_cpu(di->EaSize); cifs_fill_common_info(fattr, cifs_sb); } @@ -548,7 +548,7 @@ static void cifs_fill_dirent_full(struct cifs_dirent *de, } static void cifs_fill_dirent_search(struct cifs_dirent *de, - const SEARCH_ID_FULL_DIR_INFO *info) + const FILE_ID_FULL_DIR_INFO *info) { de->name = &info->FileName[0]; de->namelen = le32_to_cpu(info->FileNameLength); diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h index 66269c10beba..19caab2fd11e 100644 --- a/fs/smb/client/reparse.h +++ b/fs/smb/client/reparse.h @@ -93,7 +93,7 @@ static inline bool reparse_inode_match(struct inode *inode, if (cinode->reparse_tag != IO_REPARSE_TAG_INTERNAL && cinode->reparse_tag != fattr->cf_cifstag) return false; - return (cinode->cifsAttrs & ATTR_REPARSE) && + return (cinode->cifsAttrs & ATTR_REPARSE_POINT) && timespec64_equal(&ctime, &fattr->cf_ctime); } @@ -107,7 +107,7 @@ static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data) attrs = le32_to_cpu(fi->DosAttributes); if (data->reparse_point) { - attrs |= ATTR_REPARSE; + attrs |= ATTR_REPARSE_POINT; fi->DosAttributes = cpu_to_le32(attrs); } @@ -116,12 +116,12 @@ static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data) attrs = le32_to_cpu(fi->Attributes); if (data->reparse_point) { - attrs |= ATTR_REPARSE; + attrs |= ATTR_REPARSE_POINT; fi->Attributes = cpu_to_le32(attrs); } } - ret = attrs & ATTR_REPARSE; + ret = attrs & ATTR_REPARSE_POINT; return ret; } diff --git a/fs/smb/client/rfc1002pdu.h b/fs/smb/client/rfc1002pdu.h index ac82c2f3a4a2..f5b143088b90 100644 --- a/fs/smb/client/rfc1002pdu.h +++ b/fs/smb/client/rfc1002pdu.h @@ -33,17 +33,17 @@ struct rfc1002_session_packet { __u8 calling_len; __u8 calling_name[32]; __u8 scope2; /* null */ - } __attribute__((packed)) session_req; + } __packed session_req; struct { __be32 retarget_ip_addr; __be16 port; - } __attribute__((packed)) retarget_resp; + } __packed retarget_resp; __u8 neg_ses_resp_error_code; /* POSITIVE_SESSION_RESPONSE packet does not include trailer. SESSION_KEEP_ALIVE packet also does not include a trailer. Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */ - } __attribute__((packed)) trailer; -} __attribute__((packed)); + } __packed trailer; +} __packed; /* Negative Session Response error codes */ #define RFC1002_NOT_LISTENING_CALLED 0x80 /* not listening on called name */ diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c index 0a8c2fcc9ded..ef3b498b0a02 100644 --- a/fs/smb/client/sess.c +++ b/fs/smb/client/sess.c @@ -584,7 +584,7 @@ cifs_ses_add_channel(struct cifs_ses *ses, * to sign packets before we generate the channel signing key * (we sign with the session key) */ - rc = smb311_crypto_shash_allocate(chan->server); + rc = smb3_crypto_shash_allocate(chan->server); if (rc) { cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__); mutex_unlock(&ses->session_mutex); diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index ca8f3dd7ff63..a479fe1396c0 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -7,6 +7,7 @@ #include <linux/pagemap.h> #include <linux/vfs.h> +#include <linux/fs_struct.h> #include <uapi/linux/magic.h> #include "cifsglob.h" #include "cifsproto.h" @@ -647,7 +648,7 @@ static int cifs_query_path_info(const unsigned int xid, if (!rc) { move_cifs_info_to_smb2(&data->fi, &fi); - data->reparse_point = le32_to_cpu(fi.Attributes) & ATTR_REPARSE; + data->reparse_point = le32_to_cpu(fi.Attributes) & ATTR_REPARSE_POINT; } #ifdef CONFIG_CIFS_XATTR diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c index 09e3fc81d7cb..d0aad4821ed4 100644 --- a/fs/smb/client/smb2inode.c +++ b/fs/smb/client/smb2inode.c @@ -50,7 +50,7 @@ static inline __u32 file_create_options(struct dentry *dentry) if (dentry) { ci = CIFS_I(d_inode(dentry)); - if (ci->cifsAttrs & ATTR_REPARSE) + if (ci->cifsAttrs & ATTR_REPARSE_POINT) return OPEN_REPARSE_POINT; } return 0; @@ -1294,6 +1294,8 @@ static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon, smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb); if (smb2_to_name == NULL) { rc = -ENOMEM; + if (cfile) + cifsFileInfo_put(cfile); goto smb2_rename_path; } in_iov.iov_base = smb2_to_name; diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c index 89d933b4a8bc..96bfe4c63ccf 100644 --- a/fs/smb/client/smb2misc.c +++ b/fs/smb/client/smb2misc.c @@ -7,6 +7,7 @@ * Pavel Shilovsky (pshilovsky@samba.org) 2012 * */ +#include <crypto/sha2.h> #include <linux/ctype.h> #include "cifsglob.h" #include "cifsproto.h" @@ -888,13 +889,13 @@ smb2_handle_cancelled_mid(struct mid_q_entry *mid, struct TCP_Server_Info *serve * @iov: array containing the SMB request we will send to the server * @nvec: number of array entries for the iov */ -int +void smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server, struct kvec *iov, int nvec) { - int i, rc; + int i; struct smb2_hdr *hdr; - struct shash_desc *sha512 = NULL; + struct sha512_ctx sha_ctx; hdr = (struct smb2_hdr *)iov[0].iov_base; /* neg prot are always taken */ @@ -907,52 +908,22 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server, * and we can test it. Preauth requires 3.1.1 for now. */ if (server->dialect != SMB311_PROT_ID) - return 0; + return; if (hdr->Command != SMB2_SESSION_SETUP) - return 0; + return; /* skip last sess setup response */ if ((hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR) && (hdr->Status == NT_STATUS_OK || (hdr->Status != cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)))) - return 0; + return; ok: - rc = smb311_crypto_shash_allocate(server); - if (rc) - return rc; - - sha512 = server->secmech.sha512; - rc = crypto_shash_init(sha512); - if (rc) { - cifs_dbg(VFS, "%s: Could not init sha512 shash\n", __func__); - return rc; - } - - rc = crypto_shash_update(sha512, ses->preauth_sha_hash, - SMB2_PREAUTH_HASH_SIZE); - if (rc) { - cifs_dbg(VFS, "%s: Could not update sha512 shash\n", __func__); - return rc; - } - - for (i = 0; i < nvec; i++) { - rc = crypto_shash_update(sha512, iov[i].iov_base, iov[i].iov_len); - if (rc) { - cifs_dbg(VFS, "%s: Could not update sha512 shash\n", - __func__); - return rc; - } - } - - rc = crypto_shash_final(sha512, ses->preauth_sha_hash); - if (rc) { - cifs_dbg(VFS, "%s: Could not finalize sha512 shash\n", - __func__); - return rc; - } - - return 0; + sha512_init(&sha_ctx); + sha512_update(&sha_ctx, ses->preauth_sha_hash, SMB2_PREAUTH_HASH_SIZE); + for (i = 0; i < nvec; i++) + sha512_update(&sha_ctx, iov[i].iov_base, iov[i].iov_len); + sha512_final(&sha_ctx, ses->preauth_sha_hash); } diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 7c392cf5940b..7ace6d4d305b 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -624,8 +624,8 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, struct network_interface_info_ioctl_rsp *p; struct sockaddr_in *addr4; struct sockaddr_in6 *addr6; - struct iface_info_ipv4 *p4; - struct iface_info_ipv6 *p6; + struct smb_sockaddr_in *p4; + struct smb_sockaddr_in6 *p6; struct cifs_server_iface *info = NULL, *iface = NULL, *niface = NULL; struct cifs_server_iface tmp_iface; ssize_t bytes_left; @@ -685,7 +685,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, */ case INTERNETWORK: addr4 = (struct sockaddr_in *)&tmp_iface.sockaddr; - p4 = (struct iface_info_ipv4 *)p->Buffer; + p4 = (struct smb_sockaddr_in *)p->Buffer; addr4->sin_family = AF_INET; memcpy(&addr4->sin_addr, &p4->IPv4Address, 4); @@ -697,7 +697,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, break; case INTERNETWORKV6: addr6 = (struct sockaddr_in6 *)&tmp_iface.sockaddr; - p6 = (struct iface_info_ipv6 *)p->Buffer; + p6 = (struct smb_sockaddr_in6 *)p->Buffer; addr6->sin6_family = AF_INET6; memcpy(&addr6->sin6_addr, &p6->IPv6Address, 16); @@ -1524,11 +1524,11 @@ smb2_close_getattr(const unsigned int xid, struct cifs_tcon *tcon, static int SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, - struct copychunk_ioctl *pcchunk) + struct copychunk_ioctl_req *pcchunk) { int rc; unsigned int ret_data_len; - struct resume_key_req *res_key; + struct resume_key_ioctl_rsp *res_key; rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid, FSCTL_SRV_REQUEST_RESUME_KEY, NULL, 0 /* no input */, @@ -1541,7 +1541,7 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon, cifs_tcon_dbg(VFS, "refcpy ioctl error %d getting resume key\n", rc); goto req_res_key_exit; } - if (ret_data_len < sizeof(struct resume_key_req)) { + if (ret_data_len < sizeof(struct resume_key_ioctl_rsp)) { cifs_tcon_dbg(VFS, "Invalid refcopy resume key length\n"); rc = -EINVAL; goto req_res_key_exit; @@ -1857,10 +1857,10 @@ smb2_copychunk_range(const unsigned int xid, { int rc = 0; unsigned int ret_data_len = 0; - struct copychunk_ioctl *cc_req = NULL; + struct copychunk_ioctl_req *cc_req = NULL; struct copychunk_ioctl_rsp *cc_rsp = NULL; struct cifs_tcon *tcon; - struct copychunk *chunk; + struct srv_copychunk *chunk; u32 chunks, chunk_count, chunk_bytes; u32 copy_bytes, copy_bytes_left; u32 chunks_written, bytes_written; @@ -2799,11 +2799,12 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid fid; int rc; __le16 *utf16_path; - struct cached_fid *cfid = NULL; + struct cached_fid *cfid; int retries = 0, cur_sleep = 1; replay_again: /* reinitialize for possible replay */ + cfid = NULL; flags = CIFS_CP_CREATE_CLOSE_OP; oplock = SMB2_OPLOCK_LEVEL_NONE; server = cifs_pick_channel(ses); @@ -3212,8 +3213,7 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb, utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); if (!utf16_path) { rc = -ENOMEM; - free_xid(xid); - return ERR_PTR(rc); + goto put_tlink; } oparms = (struct cifs_open_parms) { @@ -3245,6 +3245,7 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb, SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); } +put_tlink: cifs_put_tlink(tlink); free_xid(xid); @@ -3285,8 +3286,7 @@ set_smb2_acl(struct smb_ntsd *pnntsd, __u32 acllen, utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); if (!utf16_path) { rc = -ENOMEM; - free_xid(xid); - return rc; + goto put_tlink; } oparms = (struct cifs_open_parms) { @@ -3307,6 +3307,7 @@ set_smb2_acl(struct smb_ntsd *pnntsd, __u32 acllen, SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); } +put_tlink: cifs_put_tlink(tlink); free_xid(xid); return rc; @@ -4484,61 +4485,6 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst, } /* - * Clear a read buffer, discarding the folios which have the 1st mark set. - */ -static void cifs_clear_folioq_buffer(struct folio_queue *buffer) -{ - struct folio_queue *folioq; - - while ((folioq = buffer)) { - for (int s = 0; s < folioq_count(folioq); s++) - if (folioq_is_marked(folioq, s)) - folio_put(folioq_folio(folioq, s)); - buffer = folioq->next; - kfree(folioq); - } -} - -/* - * Allocate buffer space into a folio queue. - */ -static struct folio_queue *cifs_alloc_folioq_buffer(ssize_t size) -{ - struct folio_queue *buffer = NULL, *tail = NULL, *p; - struct folio *folio; - unsigned int slot; - - do { - if (!tail || folioq_full(tail)) { - p = kmalloc(sizeof(*p), GFP_NOFS); - if (!p) - goto nomem; - folioq_init(p, 0); - if (tail) { - tail->next = p; - p->prev = tail; - } else { - buffer = p; - } - tail = p; - } - - folio = folio_alloc(GFP_KERNEL|__GFP_HIGHMEM, 0); - if (!folio) - goto nomem; - - slot = folioq_append_mark(tail, folio); - size -= folioq_folio_size(tail, slot); - } while (size > 0); - - return buffer; - -nomem: - cifs_clear_folioq_buffer(buffer); - return NULL; -} - -/* * Copy data from an iterator to the folios in a folio queue buffer. */ static bool cifs_copy_iter_to_folioq(struct iov_iter *iter, size_t size, @@ -4563,7 +4509,7 @@ void smb3_free_compound_rqst(int num_rqst, struct smb_rqst *rqst) { for (int i = 0; i < num_rqst; i++) - cifs_clear_folioq_buffer(rqst[i].rq_buffer); + netfs_free_folioq_buffer(rqst[i].rq_buffer); } /* @@ -4598,8 +4544,10 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst, new->rq_nvec = old->rq_nvec; if (size > 0) { - buffer = cifs_alloc_folioq_buffer(size); - if (!buffer) + size_t cur_size = 0; + rc = netfs_alloc_folioq_buffer(NULL, &buffer, &cur_size, + size, GFP_NOFS); + if (rc < 0) goto err_free; new->rq_buffer = buffer; @@ -4931,7 +4879,7 @@ static void smb2_decrypt_offload(struct work_struct *work) } free_pages: - cifs_clear_folioq_buffer(dw->buffer); + netfs_free_folioq_buffer(dw->buffer); cifs_small_buf_release(dw->buf); kfree(dw); } @@ -4969,9 +4917,9 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, dw->len = len; len = round_up(dw->len, PAGE_SIZE); - rc = -ENOMEM; - dw->buffer = cifs_alloc_folioq_buffer(len); - if (!dw->buffer) + size_t cur_size = 0; + rc = netfs_alloc_folioq_buffer(NULL, &dw->buffer, &cur_size, len, GFP_NOFS); + if (rc < 0) goto discard_data; iov_iter_folio_queue(&iter, ITER_DEST, dw->buffer, 0, 0, len); @@ -5032,7 +4980,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, } free_pages: - cifs_clear_folioq_buffer(dw->buffer); + netfs_free_folioq_buffer(dw->buffer); free_dw: kfree(dw); return rc; @@ -5446,7 +5394,6 @@ struct smb_version_operations smb20_operations = { .get_lease_key = smb2_get_lease_key, .set_lease_key = smb2_set_lease_key, .new_lease_key = smb2_new_lease_key, - .calc_signature = smb2_calc_signature, .is_read_op = smb2_is_read_op, .set_oplock_level = smb2_set_oplock_level, .create_lease_buf = smb2_create_lease_buf, @@ -5550,7 +5497,6 @@ struct smb_version_operations smb21_operations = { .get_lease_key = smb2_get_lease_key, .set_lease_key = smb2_set_lease_key, .new_lease_key = smb2_new_lease_key, - .calc_signature = smb2_calc_signature, .is_read_op = smb21_is_read_op, .set_oplock_level = smb21_set_oplock_level, .create_lease_buf = smb2_create_lease_buf, @@ -5660,7 +5606,6 @@ struct smb_version_operations smb30_operations = { .set_lease_key = smb2_set_lease_key, .new_lease_key = smb2_new_lease_key, .generate_signingkey = generate_smb30signingkey, - .calc_signature = smb3_calc_signature, .set_integrity = smb3_set_integrity, .is_read_op = smb21_is_read_op, .set_oplock_level = smb3_set_oplock_level, @@ -5777,7 +5722,6 @@ struct smb_version_operations smb311_operations = { .set_lease_key = smb2_set_lease_key, .new_lease_key = smb2_new_lease_key, .generate_signingkey = generate_smb311signingkey, - .calc_signature = smb3_calc_signature, .set_integrity = smb3_set_integrity, .is_read_op = smb21_is_read_op, .set_oplock_level = smb3_set_oplock_level, diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index b0739a2661bf..ef2c6ac500f7 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -2229,21 +2229,20 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) return rc; } - -static struct create_durable * +static create_durable_req_t * create_durable_buf(void) { - struct create_durable *buf; + create_durable_req_t *buf; - buf = kzalloc(sizeof(struct create_durable), GFP_KERNEL); + buf = kzalloc(sizeof(create_durable_req_t), GFP_KERNEL); if (!buf) return NULL; buf->ccontext.DataOffset = cpu_to_le16(offsetof - (struct create_durable, Data)); + (create_durable_req_t, Data)); buf->ccontext.DataLength = cpu_to_le32(16); buf->ccontext.NameOffset = cpu_to_le16(offsetof - (struct create_durable, Name)); + (create_durable_req_t, Name)); buf->ccontext.NameLength = cpu_to_le16(4); /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DHnQ" */ buf->Name[0] = 'D'; @@ -2253,20 +2252,20 @@ create_durable_buf(void) return buf; } -static struct create_durable * +static create_durable_req_t * create_reconnect_durable_buf(struct cifs_fid *fid) { - struct create_durable *buf; + create_durable_req_t *buf; - buf = kzalloc(sizeof(struct create_durable), GFP_KERNEL); + buf = kzalloc(sizeof(create_durable_req_t), GFP_KERNEL); if (!buf) return NULL; buf->ccontext.DataOffset = cpu_to_le16(offsetof - (struct create_durable, Data)); + (create_durable_req_t, Data)); buf->ccontext.DataLength = cpu_to_le32(16); buf->ccontext.NameOffset = cpu_to_le16(offsetof - (struct create_durable, Name)); + (create_durable_req_t, Name)); buf->ccontext.NameLength = cpu_to_le16(4); buf->Data.Fid.PersistentFileId = fid->persistent_fid; buf->Data.Fid.VolatileFileId = fid->volatile_fid; @@ -2424,21 +2423,21 @@ add_lease_context(struct TCP_Server_Info *server, return 0; } -static struct create_durable_v2 * +static struct create_durable_req_v2 * create_durable_v2_buf(struct cifs_open_parms *oparms) { struct cifs_fid *pfid = oparms->fid; - struct create_durable_v2 *buf; + struct create_durable_req_v2 *buf; - buf = kzalloc(sizeof(struct create_durable_v2), GFP_KERNEL); + buf = kzalloc(sizeof(struct create_durable_req_v2), GFP_KERNEL); if (!buf) return NULL; buf->ccontext.DataOffset = cpu_to_le16(offsetof - (struct create_durable_v2, dcontext)); - buf->ccontext.DataLength = cpu_to_le32(sizeof(struct durable_context_v2)); + (struct create_durable_req_v2, dcontext)); + buf->ccontext.DataLength = cpu_to_le32(sizeof(struct durable_context_v2_req)); buf->ccontext.NameOffset = cpu_to_le16(offsetof - (struct create_durable_v2, Name)); + (struct create_durable_req_v2, Name)); buf->ccontext.NameLength = cpu_to_le16(4); /* @@ -2508,7 +2507,7 @@ add_durable_v2_context(struct kvec *iov, unsigned int *num_iovec, iov[num].iov_base = create_durable_v2_buf(oparms); if (iov[num].iov_base == NULL) return -ENOMEM; - iov[num].iov_len = sizeof(struct create_durable_v2); + iov[num].iov_len = sizeof(struct create_durable_req_v2); *num_iovec = num + 1; return 0; } @@ -2552,7 +2551,7 @@ add_durable_context(struct kvec *iov, unsigned int *num_iovec, iov[num].iov_base = create_durable_buf(); if (iov[num].iov_base == NULL) return -ENOMEM; - iov[num].iov_len = sizeof(struct create_durable); + iov[num].iov_len = sizeof(create_durable_req_t); *num_iovec = num + 1; return 0; } @@ -4054,9 +4053,12 @@ replay_again: smb_rsp = (struct smb2_change_notify_rsp *)rsp_iov.iov_base; - smb2_validate_iov(le16_to_cpu(smb_rsp->OutputBufferOffset), - le32_to_cpu(smb_rsp->OutputBufferLength), &rsp_iov, + rc = smb2_validate_iov(le16_to_cpu(smb_rsp->OutputBufferOffset), + le32_to_cpu(smb_rsp->OutputBufferLength), + &rsp_iov, sizeof(struct file_notify_information)); + if (rc) + goto cnotify_exit; *out_data = kmemdup((char *)smb_rsp + le16_to_cpu(smb_rsp->OutputBufferOffset), le32_to_cpu(smb_rsp->OutputBufferLength), GFP_KERNEL); @@ -5451,7 +5453,7 @@ smb2_parse_query_directory(struct cifs_tcon *tcon, info_buf_size = sizeof(FILE_DIRECTORY_INFO); break; case SMB_FIND_FILE_ID_FULL_DIR_INFO: - info_buf_size = sizeof(SEARCH_ID_FULL_DIR_INFO); + info_buf_size = sizeof(FILE_ID_FULL_DIR_INFO); break; case SMB_FIND_FILE_POSIX_INFO: /* note that posix payload are variable size */ @@ -5979,8 +5981,8 @@ replay_again: max_len = sizeof(FILE_SYSTEM_DEVICE_INFO); min_len = sizeof(FILE_SYSTEM_DEVICE_INFO); } else if (level == FS_ATTRIBUTE_INFORMATION) { - max_len = sizeof(FILE_SYSTEM_ATTRIBUTE_INFO); - min_len = MIN_FS_ATTR_INFO_SIZE; + max_len = sizeof(FILE_SYSTEM_ATTRIBUTE_INFO) + MAX_FS_NAME_LEN; + min_len = sizeof(FILE_SYSTEM_ATTRIBUTE_INFO); } else if (level == FS_SECTOR_SIZE_INFORMATION) { max_len = sizeof(struct smb3_fs_ss_info); min_len = sizeof(struct smb3_fs_ss_info); @@ -6026,7 +6028,7 @@ replay_again: if (level == FS_ATTRIBUTE_INFORMATION) memcpy(&tcon->fsAttrInfo, offset + (char *)rsp, min_t(unsigned int, - rsp_len, max_len)); + rsp_len, min_len)); else if (level == FS_DEVICE_INFORMATION) memcpy(&tcon->fsDevInfo, offset + (char *)rsp, sizeof(FILE_SYSTEM_DEVICE_INFO)); diff --git a/fs/smb/client/smb2pdu.h b/fs/smb/client/smb2pdu.h index 101024f8f725..78bb99f29d38 100644 --- a/fs/smb/client/smb2pdu.h +++ b/fs/smb/client/smb2pdu.h @@ -133,46 +133,6 @@ struct share_redirect_error_context_rsp { #define SMB2_LEASE_HANDLE_CACHING_HE 0x02 #define SMB2_LEASE_WRITE_CACHING_HE 0x04 - -/* See MS-SMB2 2.2.13.2.11 */ -/* Flags */ -#define SMB2_DHANDLE_FLAG_PERSISTENT 0x00000002 -struct durable_context_v2 { - __le32 Timeout; - __le32 Flags; - __u64 Reserved; - __u8 CreateGuid[16]; -} __packed; - -struct create_durable_v2 { - struct create_context_hdr ccontext; - __u8 Name[8]; - struct durable_context_v2 dcontext; -} __packed; - -/* See MS-SMB2 2.2.13.2.12 */ -struct durable_reconnect_context_v2 { - struct { - __u64 PersistentFileId; - __u64 VolatileFileId; - } Fid; - __u8 CreateGuid[16]; - __le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */ -} __packed; - -/* See MS-SMB2 2.2.14.2.12 */ -struct durable_reconnect_context_v2_rsp { - __le32 Timeout; - __le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */ -} __packed; - -struct create_durable_handle_reconnect_v2 { - struct create_context_hdr ccontext; - __u8 Name[8]; - struct durable_reconnect_context_v2 dcontext; - __u8 Pad[4]; -} __packed; - /* See MS-SMB2 2.2.13.2.5 */ struct crt_twarp_ctxt { struct create_context_hdr ccontext; @@ -193,36 +153,6 @@ struct crt_sd_ctxt { struct smb3_sd sd; } __packed; - -#define COPY_CHUNK_RES_KEY_SIZE 24 -struct resume_key_req { - char ResumeKey[COPY_CHUNK_RES_KEY_SIZE]; - __le32 ContextLength; /* MBZ */ - char Context[]; /* ignored, Windows sets to 4 bytes of zero */ -} __packed; - - -struct copychunk { - __le64 SourceOffset; - __le64 TargetOffset; - __le32 Length; - __le32 Reserved; -} __packed; - -/* this goes in the ioctl buffer when doing a copychunk request */ -struct copychunk_ioctl { - char SourceKey[COPY_CHUNK_RES_KEY_SIZE]; - __le32 ChunkCount; - __le32 Reserved; - struct copychunk Chunks[]; -} __packed; - -struct copychunk_ioctl_rsp { - __le32 ChunksWritten; - __le32 ChunkBytesWritten; - __le32 TotalBytesWritten; -} __packed; - /* See MS-FSCC 2.3.29 and 2.3.30 */ struct get_retrieval_pointer_count_req { __le64 StartingVcn; /* virtual cluster number (signed) */ @@ -263,35 +193,6 @@ struct network_resiliency_req { } __packed; /* There is no buffer for the response ie no struct network_resiliency_rsp */ -#define RSS_CAPABLE cpu_to_le32(0x00000001) -#define RDMA_CAPABLE cpu_to_le32(0x00000002) - -#define INTERNETWORK cpu_to_le16(0x0002) -#define INTERNETWORKV6 cpu_to_le16(0x0017) - -struct network_interface_info_ioctl_rsp { - __le32 Next; /* next interface. zero if this is last one */ - __le32 IfIndex; - __le32 Capability; /* RSS or RDMA Capable */ - __le32 Reserved; - __le64 LinkSpeed; - __le16 Family; - __u8 Buffer[126]; -} __packed; - -struct iface_info_ipv4 { - __be16 Port; - __be32 IPv4Address; - __be64 Reserved; -} __packed; - -struct iface_info_ipv6 { - __be16 Port; - __be32 FlowInfo; - __u8 IPv6Address[16]; - __be32 ScopeId; -} __packed; - #define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */ struct compress_ioctl { @@ -323,19 +224,6 @@ struct smb2_file_reparse_point_info { __le32 Tag; } __packed; -struct smb2_file_network_open_info { - struct_group_attr(network_open_info, __packed, - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 AllocationSize; - __le64 EndOfFile; - __le32 Attributes; - ); - __le32 Reserved; -} __packed; /* level 34 Query also similar returned in close rsp and open rsp */ - /* See MS-FSCC 2.4.21 */ struct smb2_file_id_information { __le64 VolumeSerialNumber; diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h index b3f1398c9f79..5241daaae543 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -39,12 +39,6 @@ extern struct mid_q_entry *smb2_setup_async_request( struct TCP_Server_Info *server, struct smb_rqst *rqst); extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid); -extern int smb2_calc_signature(struct smb_rqst *rqst, - struct TCP_Server_Info *server, - bool allocate_crypto); -extern int smb3_calc_signature(struct smb_rqst *rqst, - struct TCP_Server_Info *server, - bool allocate_crypto); extern void smb2_echo_request(struct work_struct *work); extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode); extern bool smb2_is_valid_oplock_break(char *buffer, @@ -295,10 +289,10 @@ extern int smb2_validate_and_copy_iov(unsigned int offset, 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 TCP_Server_Info *server, - struct kvec *iov, int nvec); +extern int smb3_crypto_shash_allocate(struct TCP_Server_Info *server); +extern void smb311_update_preauth_hash(struct cifs_ses *ses, + struct TCP_Server_Info *server, + struct kvec *iov, int nvec); extern int smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, const char *path, u32 desired_access, diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c index 33f33013b392..6a9b80385b86 100644 --- a/fs/smb/client/smb2transport.c +++ b/fs/smb/client/smb2transport.c @@ -19,6 +19,7 @@ #include <linux/mempool.h> #include <linux/highmem.h> #include <crypto/aead.h> +#include <crypto/sha2.h> #include "cifsglob.h" #include "cifsproto.h" #include "smb2proto.h" @@ -26,53 +27,14 @@ #include "../common/smb2status.h" #include "smb2glob.h" -static int +int smb3_crypto_shash_allocate(struct TCP_Server_Info *server) { struct cifs_secmech *p = &server->secmech; - int rc; - rc = cifs_alloc_hash("hmac(sha256)", &p->hmacsha256); - if (rc) - goto err; - - rc = cifs_alloc_hash("cmac(aes)", &p->aes_cmac); - if (rc) - goto err; - - return 0; -err: - cifs_free_hash(&p->hmacsha256); - return rc; + return cifs_alloc_hash("cmac(aes)", &p->aes_cmac); } -int -smb311_crypto_shash_allocate(struct TCP_Server_Info *server) -{ - struct cifs_secmech *p = &server->secmech; - int rc = 0; - - rc = cifs_alloc_hash("hmac(sha256)", &p->hmacsha256); - if (rc) - return rc; - - rc = cifs_alloc_hash("cmac(aes)", &p->aes_cmac); - if (rc) - goto err; - - rc = cifs_alloc_hash("sha512", &p->sha512); - if (rc) - goto err; - - return 0; - -err: - cifs_free_hash(&p->aes_cmac); - cifs_free_hash(&p->hmacsha256); - return rc; -} - - static int smb3_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key) { @@ -247,16 +209,15 @@ smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid) return tcon; } -int +static int smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, - bool allocate_crypto) + bool allocate_crypto) { int rc; unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; - unsigned char *sigptr = smb2_signature; struct kvec *iov = rqst->rq_iov; struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base; - struct shash_desc *shash = NULL; + struct hmac_sha256_ctx hmac_ctx; struct smb_rqst drqst; __u64 sid = le64_to_cpu(shdr->SessionId); u8 key[SMB2_NTLMV2_SESSKEY_SIZE]; @@ -271,30 +232,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE); memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE); - if (allocate_crypto) { - rc = cifs_alloc_hash("hmac(sha256)", &shash); - if (rc) { - cifs_server_dbg(VFS, - "%s: sha256 alloc failed\n", __func__); - goto out; - } - } else { - shash = server->secmech.hmacsha256; - } - - rc = crypto_shash_setkey(shash->tfm, key, sizeof(key)); - if (rc) { - cifs_server_dbg(VFS, - "%s: Could not update with response\n", - __func__); - goto out; - } - - rc = crypto_shash_init(shash); - if (rc) { - cifs_server_dbg(VFS, "%s: Could not init sha256", __func__); - goto out; - } + hmac_sha256_init_usingrawkey(&hmac_ctx, key, sizeof(key)); /* * For SMB2+, __cifs_calc_signature() expects to sign only the actual @@ -305,25 +243,17 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, */ drqst = *rqst; if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) { - rc = crypto_shash_update(shash, iov[0].iov_base, - iov[0].iov_len); - if (rc) { - cifs_server_dbg(VFS, - "%s: Could not update with payload\n", - __func__); - goto out; - } + hmac_sha256_update(&hmac_ctx, iov[0].iov_base, iov[0].iov_len); drqst.rq_iov++; drqst.rq_nvec--; } - rc = __cifs_calc_signature(&drqst, server, sigptr, shash); + rc = __cifs_calc_signature( + &drqst, server, smb2_signature, + &(struct cifs_calc_sig_ctx){ .hmac = &hmac_ctx }); if (!rc) - memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE); + memcpy(shdr->Signature, smb2_signature, SMB2_SIGNATURE_SIZE); -out: - if (allocate_crypto) - cifs_free_hash(&shash); return rc; } @@ -336,8 +266,8 @@ static int generate_key(struct cifs_ses *ses, struct kvec label, __u8 L256[4] = {0, 0, 1, 0}; int rc = 0; unsigned char prfhash[SMB2_HMACSHA256_SIZE]; - unsigned char *hashptr = prfhash; struct TCP_Server_Info *server = ses->server; + struct hmac_sha256_ctx hmac_ctx; memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); memset(key, 0x0, key_size); @@ -345,67 +275,26 @@ static int generate_key(struct cifs_ses *ses, struct kvec label, rc = smb3_crypto_shash_allocate(server); if (rc) { cifs_server_dbg(VFS, "%s: crypto alloc failed\n", __func__); - goto smb3signkey_ret; - } - - rc = crypto_shash_setkey(server->secmech.hmacsha256->tfm, - ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); - if (rc) { - cifs_server_dbg(VFS, "%s: Could not set with session key\n", __func__); - goto smb3signkey_ret; - } - - rc = crypto_shash_init(server->secmech.hmacsha256); - if (rc) { - cifs_server_dbg(VFS, "%s: Could not init sign hmac\n", __func__); - goto smb3signkey_ret; - } - - rc = crypto_shash_update(server->secmech.hmacsha256, i, 4); - if (rc) { - cifs_server_dbg(VFS, "%s: Could not update with n\n", __func__); - goto smb3signkey_ret; - } - - rc = crypto_shash_update(server->secmech.hmacsha256, label.iov_base, label.iov_len); - if (rc) { - cifs_server_dbg(VFS, "%s: Could not update with label\n", __func__); - goto smb3signkey_ret; + return rc; } - rc = crypto_shash_update(server->secmech.hmacsha256, &zero, 1); - if (rc) { - cifs_server_dbg(VFS, "%s: Could not update with zero\n", __func__); - goto smb3signkey_ret; - } - - rc = crypto_shash_update(server->secmech.hmacsha256, context.iov_base, context.iov_len); - if (rc) { - cifs_server_dbg(VFS, "%s: Could not update with context\n", __func__); - goto smb3signkey_ret; - } + hmac_sha256_init_usingrawkey(&hmac_ctx, ses->auth_key.response, + SMB2_NTLMV2_SESSKEY_SIZE); + hmac_sha256_update(&hmac_ctx, i, 4); + hmac_sha256_update(&hmac_ctx, label.iov_base, label.iov_len); + hmac_sha256_update(&hmac_ctx, &zero, 1); + hmac_sha256_update(&hmac_ctx, context.iov_base, context.iov_len); if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) || (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) { - rc = crypto_shash_update(server->secmech.hmacsha256, L256, 4); + hmac_sha256_update(&hmac_ctx, L256, 4); } else { - rc = crypto_shash_update(server->secmech.hmacsha256, L128, 4); - } - if (rc) { - cifs_server_dbg(VFS, "%s: Could not update with L\n", __func__); - goto smb3signkey_ret; + hmac_sha256_update(&hmac_ctx, L128, 4); } + hmac_sha256_final(&hmac_ctx, prfhash); - rc = crypto_shash_final(server->secmech.hmacsha256, hashptr); - if (rc) { - cifs_server_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__); - goto smb3signkey_ret; - } - - memcpy(key, hashptr, key_size); - -smb3signkey_ret: - return rc; + memcpy(key, prfhash, key_size); + return 0; } struct derivation { @@ -576,19 +465,21 @@ generate_smb311signingkey(struct cifs_ses *ses, return generate_smb3signingkey(ses, server, &triplet); } -int +static int smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, - bool allocate_crypto) + bool allocate_crypto) { int rc; unsigned char smb3_signature[SMB2_CMACAES_SIZE]; - unsigned char *sigptr = smb3_signature; struct kvec *iov = rqst->rq_iov; struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base; struct shash_desc *shash = NULL; struct smb_rqst drqst; u8 key[SMB3_SIGN_KEY_SIZE]; + if (server->vals->protocol_id <= SMB21_PROT_ID) + return smb2_calc_signature(rqst, server, allocate_crypto); + rc = smb3_get_sign_key(le64_to_cpu(shdr->SessionId), server, key); if (unlikely(rc)) { cifs_server_dbg(FYI, "%s: Could not get signing key\n", __func__); @@ -643,9 +534,11 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, drqst.rq_nvec--; } - rc = __cifs_calc_signature(&drqst, server, sigptr, shash); + rc = __cifs_calc_signature( + &drqst, server, smb3_signature, + &(struct cifs_calc_sig_ctx){ .shash = shash }); if (!rc) - memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE); + memcpy(shdr->Signature, smb3_signature, SMB2_SIGNATURE_SIZE); out: if (allocate_crypto) @@ -657,7 +550,6 @@ out: static int smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) { - int rc = 0; struct smb2_hdr *shdr; struct smb2_sess_setup_req *ssr; bool is_binding; @@ -684,9 +576,7 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) return 0; } - rc = server->ops->calc_signature(rqst, server, false); - - return rc; + return smb3_calc_signature(rqst, server, false); } int @@ -722,7 +612,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE); - rc = server->ops->calc_signature(rqst, server, true); + rc = smb3_calc_signature(rqst, server, true); if (rc) return rc; diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 316f398c70f4..788a0670c4a8 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -7,6 +7,7 @@ #include <linux/module.h> #include <linux/highmem.h> #include <linux/folio_queue.h> +#define __SMBDIRECT_SOCKET_DISCONNECT(__sc) smbd_disconnect_rdma_connection(__sc) #include "../common/smbdirect/smbdirect_pdu.h" #include "smbdirect.h" #include "cifs_debug.h" @@ -172,6 +173,7 @@ static void smbd_disconnect_wake_up_all(struct smbdirect_socket *sc) * in order to notice the broken connection. */ wake_up_all(&sc->status_wait); + wake_up_all(&sc->send_io.lcredits.wait_queue); wake_up_all(&sc->send_io.credits.wait_queue); wake_up_all(&sc->send_io.pending.dec_wait_queue); wake_up_all(&sc->send_io.pending.zero_wait_queue); @@ -185,6 +187,9 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) struct smbdirect_socket *sc = container_of(work, struct smbdirect_socket, disconnect_work); + if (sc->first_error == 0) + sc->first_error = -ECONNABORTED; + /* * make sure this and other work is not queued again * but here we don't block and avoid @@ -196,9 +201,6 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) disable_work(&sc->idle.immediate_work); disable_delayed_work(&sc->idle.timer_work); - if (sc->first_error == 0) - sc->first_error = -ECONNABORTED; - switch (sc->status) { case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING: @@ -241,6 +243,9 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) static void smbd_disconnect_rdma_connection(struct smbdirect_socket *sc) { + if (sc->first_error == 0) + sc->first_error = -ECONNABORTED; + /* * make sure other work (than disconnect_work) is * not queued again but here we don't block and avoid @@ -251,9 +256,6 @@ static void smbd_disconnect_rdma_connection(struct smbdirect_socket *sc) disable_work(&sc->idle.immediate_work); disable_delayed_work(&sc->idle.timer_work); - if (sc->first_error == 0) - sc->first_error = -ECONNABORTED; - switch (sc->status) { case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED: case SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED: @@ -289,6 +291,9 @@ static void smbd_disconnect_rdma_connection(struct smbdirect_socket *sc) break; case SMBDIRECT_SOCKET_CREATED: + sc->status = SMBDIRECT_SOCKET_DISCONNECTED; + break; + case SMBDIRECT_SOCKET_CONNECTED: sc->status = SMBDIRECT_SOCKET_ERROR; break; @@ -318,27 +323,27 @@ static int smbd_conn_upcall( switch (event->event) { case RDMA_CM_EVENT_ADDR_RESOLVED: - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING); + if (SMBDIRECT_CHECK_STATUS_DISCONNECT(sc, SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING)) + break; sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED; wake_up(&sc->status_wait); break; case RDMA_CM_EVENT_ROUTE_RESOLVED: - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING); + if (SMBDIRECT_CHECK_STATUS_DISCONNECT(sc, SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING)) + break; sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED; wake_up(&sc->status_wait); break; case RDMA_CM_EVENT_ADDR_ERROR: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING); sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED; smbd_disconnect_rdma_work(&sc->disconnect_work); break; case RDMA_CM_EVENT_ROUTE_ERROR: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING); sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED; smbd_disconnect_rdma_work(&sc->disconnect_work); break; @@ -424,7 +429,8 @@ static int smbd_conn_upcall( min_t(u8, sp->responder_resources, peer_responder_resources); - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); + if (SMBDIRECT_CHECK_STATUS_DISCONNECT(sc, SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING)) + break; sc->status = SMBDIRECT_SOCKET_NEGOTIATE_NEEDED; wake_up(&sc->status_wait); break; @@ -433,7 +439,6 @@ static int smbd_conn_upcall( case RDMA_CM_EVENT_UNREACHABLE: case RDMA_CM_EVENT_REJECTED: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED; smbd_disconnect_rdma_work(&sc->disconnect_work); break; @@ -495,6 +500,7 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc) struct smbdirect_send_io *request = container_of(wc->wr_cqe, struct smbdirect_send_io, cqe); struct smbdirect_socket *sc = request->socket; + int lcredits = 0; log_rdma_send(INFO, "smbdirect_send_io 0x%p completed wc->status=%s\n", request, ib_wc_status_msg(wc->status)); @@ -504,22 +510,24 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc) request->sge[i].addr, request->sge[i].length, DMA_TO_DEVICE); + mempool_free(request, sc->send_io.mem.pool); + lcredits += 1; if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_SEND) { if (wc->status != IB_WC_WR_FLUSH_ERR) log_rdma_send(ERR, "wc->status=%s wc->opcode=%d\n", ib_wc_status_msg(wc->status), wc->opcode); - mempool_free(request, sc->send_io.mem.pool); smbd_disconnect_rdma_connection(sc); return; } + atomic_add(lcredits, &sc->send_io.lcredits.count); + wake_up(&sc->send_io.lcredits.wait_queue); + if (atomic_dec_and_test(&sc->send_io.pending.count)) wake_up(&sc->send_io.pending.zero_wait_queue); wake_up(&sc->send_io.pending.dec_wait_queue); - - mempool_free(request, sc->send_io.mem.pool); } static void dump_smbdirect_negotiate_resp(struct smbdirect_negotiate_resp *resp) @@ -567,6 +575,7 @@ static bool process_negotiation_response( log_rdma_event(ERR, "error: credits_granted==0\n"); return false; } + atomic_set(&sc->send_io.lcredits.count, sp->send_credit_target); atomic_set(&sc->send_io.credits.count, le16_to_cpu(packet->credits_granted)); if (le32_to_cpu(packet->preferred_send_size) > sp->max_recv_size) { @@ -691,7 +700,8 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) negotiate_done = process_negotiation_response(response, wc->byte_len); put_receive_buffer(sc, response); - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_NEGOTIATE_RUNNING); + if (SMBDIRECT_CHECK_STATUS_WARN(sc, SMBDIRECT_SOCKET_NEGOTIATE_RUNNING)) + negotiate_done = false; if (!negotiate_done) { sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; smbd_disconnect_rdma_connection(sc); @@ -1114,6 +1124,24 @@ static int smbd_post_send_iter(struct smbdirect_socket *sc, struct smbdirect_data_transfer *packet; int new_credits = 0; +wait_lcredit: + /* Wait for local send credits */ + rc = wait_event_interruptible(sc->send_io.lcredits.wait_queue, + atomic_read(&sc->send_io.lcredits.count) > 0 || + sc->status != SMBDIRECT_SOCKET_CONNECTED); + if (rc) + goto err_wait_lcredit; + + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) { + log_outgoing(ERR, "disconnected not sending on wait_credit\n"); + rc = -EAGAIN; + goto err_wait_lcredit; + } + if (unlikely(atomic_dec_return(&sc->send_io.lcredits.count) < 0)) { + atomic_inc(&sc->send_io.lcredits.count); + goto wait_lcredit; + } + wait_credit: /* Wait for send credits. A SMBD packet needs one credit */ rc = wait_event_interruptible(sc->send_io.credits.wait_queue, @@ -1132,23 +1160,6 @@ wait_credit: goto wait_credit; } -wait_send_queue: - wait_event(sc->send_io.pending.dec_wait_queue, - atomic_read(&sc->send_io.pending.count) < sp->send_credit_target || - sc->status != SMBDIRECT_SOCKET_CONNECTED); - - if (sc->status != SMBDIRECT_SOCKET_CONNECTED) { - log_outgoing(ERR, "disconnected not sending on wait_send_queue\n"); - rc = -EAGAIN; - goto err_wait_send_queue; - } - - if (unlikely(atomic_inc_return(&sc->send_io.pending.count) > - sp->send_credit_target)) { - atomic_dec(&sc->send_io.pending.count); - goto wait_send_queue; - } - request = mempool_alloc(sc->send_io.mem.pool, GFP_KERNEL); if (!request) { rc = -ENOMEM; @@ -1229,10 +1240,21 @@ wait_send_queue: le32_to_cpu(packet->data_length), le32_to_cpu(packet->remaining_data_length)); + /* + * Now that we got a local and a remote credit + * we add us as pending + */ + atomic_inc(&sc->send_io.pending.count); + rc = smbd_post_send(sc, request); if (!rc) return 0; + if (atomic_dec_and_test(&sc->send_io.pending.count)) + wake_up(&sc->send_io.pending.zero_wait_queue); + + wake_up(&sc->send_io.pending.dec_wait_queue); + err_dma: for (i = 0; i < request->num_sge; i++) if (request->sge[i].addr) @@ -1246,14 +1268,14 @@ err_dma: atomic_sub(new_credits, &sc->recv_io.credits.count); err_alloc: - if (atomic_dec_and_test(&sc->send_io.pending.count)) - wake_up(&sc->send_io.pending.zero_wait_queue); - -err_wait_send_queue: - /* roll back send credits and pending */ atomic_inc(&sc->send_io.credits.count); + wake_up(&sc->send_io.credits.wait_queue); err_wait_credit: + atomic_inc(&sc->send_io.lcredits.count); + wake_up(&sc->send_io.lcredits.wait_queue); + +err_wait_lcredit: return rc; } @@ -1575,12 +1597,12 @@ void smbd_destroy(struct TCP_Server_Info *server) disable_work_sync(&sc->disconnect_work); log_rdma_event(INFO, "destroying rdma session\n"); - if (sc->status < SMBDIRECT_SOCKET_DISCONNECTING) { + if (sc->status < SMBDIRECT_SOCKET_DISCONNECTING) smbd_disconnect_rdma_work(&sc->disconnect_work); + if (sc->status < SMBDIRECT_SOCKET_DISCONNECTED) { log_rdma_event(INFO, "wait for transport being disconnected\n"); - wait_event_interruptible( - sc->status_wait, - sc->status == SMBDIRECT_SOCKET_DISCONNECTED); + wait_event(sc->status_wait, sc->status == SMBDIRECT_SOCKET_DISCONNECTED); + log_rdma_event(INFO, "waited for transport being disconnected\n"); } /* @@ -1624,19 +1646,7 @@ void smbd_destroy(struct TCP_Server_Info *server) log_rdma_event(INFO, "free receive buffers\n"); destroy_receive_buffers(sc); - /* - * For performance reasons, memory registration and deregistration - * are not locked by srv_mutex. It is possible some processes are - * blocked on transport srv_mutex while holding memory registration. - * Release the transport srv_mutex to allow them to hit the failure - * path when sending data, and then release memory registrations. - */ log_rdma_event(INFO, "freeing mr list\n"); - while (atomic_read(&sc->mr_io.used.count)) { - cifs_server_unlock(server); - msleep(1000); - cifs_server_lock(server); - } destroy_mr_list(sc); ib_free_cq(sc->ib.send_cq); @@ -1779,6 +1789,7 @@ static struct smbd_connection *_smbd_get_connection( struct smbdirect_socket *sc; struct smbdirect_socket_parameters *sp; struct rdma_conn_param conn_param; + struct ib_qp_cap qp_cap; struct ib_qp_init_attr qp_attr; struct sockaddr_in *addr_in = (struct sockaddr_in *) dstaddr; struct ib_port_immutable port_immutable; @@ -1850,6 +1861,25 @@ static struct smbd_connection *_smbd_get_connection( goto config_failed; } + sp->responder_resources = + min_t(u8, sp->responder_resources, + sc->ib.dev->attrs.max_qp_rd_atom); + log_rdma_mr(INFO, "responder_resources=%d\n", + sp->responder_resources); + + /* + * We use allocate sp->responder_resources * 2 MRs + * and each MR needs WRs for REG and INV, so + * we use '* 4'. + * + * +1 for ib_drain_qp() + */ + memset(&qp_cap, 0, sizeof(qp_cap)); + qp_cap.max_send_wr = sp->send_credit_target + sp->responder_resources * 4 + 1; + qp_cap.max_recv_wr = sp->recv_credit_max + 1; + qp_cap.max_send_sge = SMBDIRECT_SEND_IO_MAX_SGE; + qp_cap.max_recv_sge = SMBDIRECT_RECV_IO_MAX_SGE; + sc->ib.pd = ib_alloc_pd(sc->ib.dev, 0); if (IS_ERR(sc->ib.pd)) { rc = PTR_ERR(sc->ib.pd); @@ -1860,7 +1890,7 @@ static struct smbd_connection *_smbd_get_connection( sc->ib.send_cq = ib_alloc_cq_any(sc->ib.dev, sc, - sp->send_credit_target, IB_POLL_SOFTIRQ); + qp_cap.max_send_wr, IB_POLL_SOFTIRQ); if (IS_ERR(sc->ib.send_cq)) { sc->ib.send_cq = NULL; goto alloc_cq_failed; @@ -1868,7 +1898,7 @@ static struct smbd_connection *_smbd_get_connection( sc->ib.recv_cq = ib_alloc_cq_any(sc->ib.dev, sc, - sp->recv_credit_max, IB_POLL_SOFTIRQ); + qp_cap.max_recv_wr, IB_POLL_SOFTIRQ); if (IS_ERR(sc->ib.recv_cq)) { sc->ib.recv_cq = NULL; goto alloc_cq_failed; @@ -1877,11 +1907,7 @@ static struct smbd_connection *_smbd_get_connection( memset(&qp_attr, 0, sizeof(qp_attr)); qp_attr.event_handler = smbd_qp_async_error_upcall; qp_attr.qp_context = sc; - qp_attr.cap.max_send_wr = sp->send_credit_target; - qp_attr.cap.max_recv_wr = sp->recv_credit_max; - qp_attr.cap.max_send_sge = SMBDIRECT_SEND_IO_MAX_SGE; - qp_attr.cap.max_recv_sge = SMBDIRECT_RECV_IO_MAX_SGE; - qp_attr.cap.max_inline_data = 0; + qp_attr.cap = qp_cap; qp_attr.sq_sig_type = IB_SIGNAL_REQ_WR; qp_attr.qp_type = IB_QPT_RC; qp_attr.send_cq = sc->ib.send_cq; @@ -1895,12 +1921,6 @@ static struct smbd_connection *_smbd_get_connection( } sc->ib.qp = sc->rdma.cm_id->qp; - sp->responder_resources = - min_t(u8, sp->responder_resources, - sc->ib.dev->attrs.max_qp_rd_atom); - log_rdma_mr(INFO, "responder_resources=%d\n", - sp->responder_resources); - memset(&conn_param, 0, sizeof(conn_param)); conn_param.initiator_depth = sp->initiator_depth; conn_param.responder_resources = sp->responder_resources; @@ -2352,18 +2372,84 @@ static void smbd_mr_recovery_work(struct work_struct *work) } } +static void smbd_mr_disable_locked(struct smbdirect_mr_io *mr) +{ + struct smbdirect_socket *sc = mr->socket; + + lockdep_assert_held(&mr->mutex); + + if (mr->state == SMBDIRECT_MR_DISABLED) + return; + + if (mr->mr) + ib_dereg_mr(mr->mr); + if (mr->sgt.nents) + ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir); + kfree(mr->sgt.sgl); + + mr->mr = NULL; + mr->sgt.sgl = NULL; + mr->sgt.nents = 0; + + mr->state = SMBDIRECT_MR_DISABLED; +} + +static void smbd_mr_free_locked(struct kref *kref) +{ + struct smbdirect_mr_io *mr = + container_of(kref, struct smbdirect_mr_io, kref); + + lockdep_assert_held(&mr->mutex); + + /* + * smbd_mr_disable_locked() should already be called! + */ + if (WARN_ON_ONCE(mr->state != SMBDIRECT_MR_DISABLED)) + smbd_mr_disable_locked(mr); + + mutex_unlock(&mr->mutex); + mutex_destroy(&mr->mutex); + kfree(mr); +} + static void destroy_mr_list(struct smbdirect_socket *sc) { struct smbdirect_mr_io *mr, *tmp; + LIST_HEAD(all_list); + unsigned long flags; disable_work_sync(&sc->mr_io.recovery_work); - list_for_each_entry_safe(mr, tmp, &sc->mr_io.all.list, list) { - if (mr->state == SMBDIRECT_MR_INVALIDATED) - ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl, - mr->sgt.nents, mr->dir); - ib_dereg_mr(mr->mr); - kfree(mr->sgt.sgl); - kfree(mr); + + spin_lock_irqsave(&sc->mr_io.all.lock, flags); + list_splice_tail_init(&sc->mr_io.all.list, &all_list); + spin_unlock_irqrestore(&sc->mr_io.all.lock, flags); + + list_for_each_entry_safe(mr, tmp, &all_list, list) { + mutex_lock(&mr->mutex); + + smbd_mr_disable_locked(mr); + list_del(&mr->list); + mr->socket = NULL; + + /* + * No kref_put_mutex() as it's already locked. + * + * If smbd_mr_free_locked() is called + * and the mutex is unlocked and mr is gone, + * in that case kref_put() returned 1. + * + * If kref_put() returned 0 we know that + * smbd_mr_free_locked() didn't + * run. Not by us nor by anyone else, as we + * still hold the mutex, so we need to unlock. + * + * If the mr is still registered it will + * be dangling (detached from the connection + * waiting for smbd_deregister_mr() to be + * called in order to free the memory. + */ + if (!kref_put(&mr->kref, smbd_mr_free_locked)) + mutex_unlock(&mr->mutex); } } @@ -2377,10 +2463,9 @@ static void destroy_mr_list(struct smbdirect_socket *sc) static int allocate_mr_list(struct smbdirect_socket *sc) { struct smbdirect_socket_parameters *sp = &sc->parameters; - int i; - struct smbdirect_mr_io *smbdirect_mr, *tmp; - - INIT_WORK(&sc->mr_io.recovery_work, smbd_mr_recovery_work); + struct smbdirect_mr_io *mr; + int ret; + u32 i; if (sp->responder_resources == 0) { log_rdma_mr(ERR, "responder_resources negotiated as 0\n"); @@ -2389,42 +2474,52 @@ static int allocate_mr_list(struct smbdirect_socket *sc) /* Allocate more MRs (2x) than hardware responder_resources */ for (i = 0; i < sp->responder_resources * 2; i++) { - smbdirect_mr = kzalloc(sizeof(*smbdirect_mr), GFP_KERNEL); - if (!smbdirect_mr) - goto cleanup_entries; - smbdirect_mr->mr = ib_alloc_mr(sc->ib.pd, sc->mr_io.type, - sp->max_frmr_depth); - if (IS_ERR(smbdirect_mr->mr)) { + mr = kzalloc(sizeof(*mr), GFP_KERNEL); + if (!mr) { + ret = -ENOMEM; + goto kzalloc_mr_failed; + } + + kref_init(&mr->kref); + mutex_init(&mr->mutex); + + mr->mr = ib_alloc_mr(sc->ib.pd, + sc->mr_io.type, + sp->max_frmr_depth); + if (IS_ERR(mr->mr)) { + ret = PTR_ERR(mr->mr); log_rdma_mr(ERR, "ib_alloc_mr failed mr_type=%x max_frmr_depth=%x\n", sc->mr_io.type, sp->max_frmr_depth); - goto out; + goto ib_alloc_mr_failed; } - smbdirect_mr->sgt.sgl = kcalloc(sp->max_frmr_depth, - sizeof(struct scatterlist), - GFP_KERNEL); - if (!smbdirect_mr->sgt.sgl) { + + mr->sgt.sgl = kcalloc(sp->max_frmr_depth, + sizeof(struct scatterlist), + GFP_KERNEL); + if (!mr->sgt.sgl) { + ret = -ENOMEM; log_rdma_mr(ERR, "failed to allocate sgl\n"); - ib_dereg_mr(smbdirect_mr->mr); - goto out; + goto kcalloc_sgl_failed; } - smbdirect_mr->state = SMBDIRECT_MR_READY; - smbdirect_mr->socket = sc; + mr->state = SMBDIRECT_MR_READY; + mr->socket = sc; - list_add_tail(&smbdirect_mr->list, &sc->mr_io.all.list); + list_add_tail(&mr->list, &sc->mr_io.all.list); atomic_inc(&sc->mr_io.ready.count); } + + INIT_WORK(&sc->mr_io.recovery_work, smbd_mr_recovery_work); + return 0; -out: - kfree(smbdirect_mr); -cleanup_entries: - list_for_each_entry_safe(smbdirect_mr, tmp, &sc->mr_io.all.list, list) { - list_del(&smbdirect_mr->list); - ib_dereg_mr(smbdirect_mr->mr); - kfree(smbdirect_mr->sgt.sgl); - kfree(smbdirect_mr); - } - return -ENOMEM; +kcalloc_sgl_failed: + ib_dereg_mr(mr->mr); +ib_alloc_mr_failed: + mutex_destroy(&mr->mutex); + kfree(mr); +kzalloc_mr_failed: + destroy_mr_list(sc); + return ret; } /* @@ -2458,6 +2553,7 @@ again: list_for_each_entry(ret, &sc->mr_io.all.list, list) { if (ret->state == SMBDIRECT_MR_READY) { ret->state = SMBDIRECT_MR_REGISTERED; + kref_get(&ret->kref); spin_unlock_irqrestore(&sc->mr_io.all.lock, flags); atomic_dec(&sc->mr_io.ready.count); atomic_inc(&sc->mr_io.used.count); @@ -2504,9 +2600,8 @@ struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info, { struct smbdirect_socket *sc = &info->socket; struct smbdirect_socket_parameters *sp = &sc->parameters; - struct smbdirect_mr_io *smbdirect_mr; + struct smbdirect_mr_io *mr; int rc, num_pages; - enum dma_data_direction dir; struct ib_reg_wr *reg_wr; num_pages = iov_iter_npages(iter, sp->max_frmr_depth + 1); @@ -2517,49 +2612,47 @@ struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info, return NULL; } - smbdirect_mr = get_mr(sc); - if (!smbdirect_mr) { + mr = get_mr(sc); + if (!mr) { log_rdma_mr(ERR, "get_mr returning NULL\n"); return NULL; } - dir = writing ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - smbdirect_mr->dir = dir; - smbdirect_mr->need_invalidate = need_invalidate; - smbdirect_mr->sgt.nents = 0; - smbdirect_mr->sgt.orig_nents = 0; + mutex_lock(&mr->mutex); + + mr->dir = writing ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + mr->need_invalidate = need_invalidate; + mr->sgt.nents = 0; + mr->sgt.orig_nents = 0; log_rdma_mr(INFO, "num_pages=0x%x count=0x%zx depth=%u\n", num_pages, iov_iter_count(iter), sp->max_frmr_depth); - smbd_iter_to_mr(iter, &smbdirect_mr->sgt, sp->max_frmr_depth); + smbd_iter_to_mr(iter, &mr->sgt, sp->max_frmr_depth); - rc = ib_dma_map_sg(sc->ib.dev, smbdirect_mr->sgt.sgl, - smbdirect_mr->sgt.nents, dir); + rc = ib_dma_map_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir); if (!rc) { log_rdma_mr(ERR, "ib_dma_map_sg num_pages=%x dir=%x rc=%x\n", - num_pages, dir, rc); + num_pages, mr->dir, rc); goto dma_map_error; } - rc = ib_map_mr_sg(smbdirect_mr->mr, smbdirect_mr->sgt.sgl, - smbdirect_mr->sgt.nents, NULL, PAGE_SIZE); - if (rc != smbdirect_mr->sgt.nents) { + rc = ib_map_mr_sg(mr->mr, mr->sgt.sgl, mr->sgt.nents, NULL, PAGE_SIZE); + if (rc != mr->sgt.nents) { log_rdma_mr(ERR, - "ib_map_mr_sg failed rc = %d nents = %x\n", - rc, smbdirect_mr->sgt.nents); + "ib_map_mr_sg failed rc = %d nents = %x\n", + rc, mr->sgt.nents); goto map_mr_error; } - ib_update_fast_reg_key(smbdirect_mr->mr, - ib_inc_rkey(smbdirect_mr->mr->rkey)); - reg_wr = &smbdirect_mr->wr; + ib_update_fast_reg_key(mr->mr, ib_inc_rkey(mr->mr->rkey)); + reg_wr = &mr->wr; reg_wr->wr.opcode = IB_WR_REG_MR; - smbdirect_mr->cqe.done = register_mr_done; - reg_wr->wr.wr_cqe = &smbdirect_mr->cqe; + mr->cqe.done = register_mr_done; + reg_wr->wr.wr_cqe = &mr->cqe; reg_wr->wr.num_sge = 0; reg_wr->wr.send_flags = IB_SEND_SIGNALED; - reg_wr->mr = smbdirect_mr->mr; - reg_wr->key = smbdirect_mr->mr->rkey; + reg_wr->mr = mr->mr; + reg_wr->key = mr->mr->rkey; reg_wr->access = writing ? IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE : IB_ACCESS_REMOTE_READ; @@ -2570,24 +2663,51 @@ struct smbdirect_mr_io *smbd_register_mr(struct smbd_connection *info, * on the next ib_post_send when we actually send I/O to remote peer */ rc = ib_post_send(sc->ib.qp, ®_wr->wr, NULL); - if (!rc) - return smbdirect_mr; + if (!rc) { + /* + * get_mr() gave us a reference + * via kref_get(&mr->kref), we keep that and let + * the caller use smbd_deregister_mr() + * to remove it again. + */ + mutex_unlock(&mr->mutex); + return mr; + } log_rdma_mr(ERR, "ib_post_send failed rc=%x reg_wr->key=%x\n", rc, reg_wr->key); /* If all failed, attempt to recover this MR by setting it SMBDIRECT_MR_ERROR*/ map_mr_error: - ib_dma_unmap_sg(sc->ib.dev, smbdirect_mr->sgt.sgl, - smbdirect_mr->sgt.nents, smbdirect_mr->dir); + ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir); dma_map_error: - smbdirect_mr->state = SMBDIRECT_MR_ERROR; + mr->sgt.nents = 0; + mr->state = SMBDIRECT_MR_ERROR; if (atomic_dec_and_test(&sc->mr_io.used.count)) wake_up(&sc->mr_io.cleanup.wait_queue); smbd_disconnect_rdma_connection(sc); + /* + * get_mr() gave us a reference + * via kref_get(&mr->kref), we need to remove it again + * on error. + * + * No kref_put_mutex() as it's already locked. + * + * If smbd_mr_free_locked() is called + * and the mutex is unlocked and mr is gone, + * in that case kref_put() returned 1. + * + * If kref_put() returned 0 we know that + * smbd_mr_free_locked() didn't + * run. Not by us nor by anyone else, as we + * still hold the mutex, so we need to unlock. + */ + if (!kref_put(&mr->kref, smbd_mr_free_locked)) + mutex_unlock(&mr->mutex); + return NULL; } @@ -2612,44 +2732,55 @@ static void local_inv_done(struct ib_cq *cq, struct ib_wc *wc) * and we have to locally invalidate the buffer to prevent data is being * modified by remote peer after upper layer consumes it */ -int smbd_deregister_mr(struct smbdirect_mr_io *smbdirect_mr) +void smbd_deregister_mr(struct smbdirect_mr_io *mr) { - struct ib_send_wr *wr; - struct smbdirect_socket *sc = smbdirect_mr->socket; - int rc = 0; + struct smbdirect_socket *sc = mr->socket; + + mutex_lock(&mr->mutex); + if (mr->state == SMBDIRECT_MR_DISABLED) + goto put_kref; + + if (sc->status != SMBDIRECT_SOCKET_CONNECTED) { + smbd_mr_disable_locked(mr); + goto put_kref; + } + + if (mr->need_invalidate) { + struct ib_send_wr *wr = &mr->inv_wr; + int rc; - if (smbdirect_mr->need_invalidate) { /* Need to finish local invalidation before returning */ - wr = &smbdirect_mr->inv_wr; wr->opcode = IB_WR_LOCAL_INV; - smbdirect_mr->cqe.done = local_inv_done; - wr->wr_cqe = &smbdirect_mr->cqe; + mr->cqe.done = local_inv_done; + wr->wr_cqe = &mr->cqe; wr->num_sge = 0; - wr->ex.invalidate_rkey = smbdirect_mr->mr->rkey; + wr->ex.invalidate_rkey = mr->mr->rkey; wr->send_flags = IB_SEND_SIGNALED; - init_completion(&smbdirect_mr->invalidate_done); + init_completion(&mr->invalidate_done); rc = ib_post_send(sc->ib.qp, wr, NULL); if (rc) { log_rdma_mr(ERR, "ib_post_send failed rc=%x\n", rc); + smbd_mr_disable_locked(mr); smbd_disconnect_rdma_connection(sc); goto done; } - wait_for_completion(&smbdirect_mr->invalidate_done); - smbdirect_mr->need_invalidate = false; + wait_for_completion(&mr->invalidate_done); + mr->need_invalidate = false; } else /* * For remote invalidation, just set it to SMBDIRECT_MR_INVALIDATED * and defer to mr_recovery_work to recover the MR for next use */ - smbdirect_mr->state = SMBDIRECT_MR_INVALIDATED; + mr->state = SMBDIRECT_MR_INVALIDATED; - if (smbdirect_mr->state == SMBDIRECT_MR_INVALIDATED) { - ib_dma_unmap_sg( - sc->ib.dev, smbdirect_mr->sgt.sgl, - smbdirect_mr->sgt.nents, - smbdirect_mr->dir); - smbdirect_mr->state = SMBDIRECT_MR_READY; + if (mr->sgt.nents) { + ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir); + mr->sgt.nents = 0; + } + + if (mr->state == SMBDIRECT_MR_INVALIDATED) { + mr->state = SMBDIRECT_MR_READY; if (atomic_inc_return(&sc->mr_io.ready.count) == 1) wake_up(&sc->mr_io.ready.wait_queue); } else @@ -2663,7 +2794,23 @@ done: if (atomic_dec_and_test(&sc->mr_io.used.count)) wake_up(&sc->mr_io.cleanup.wait_queue); - return rc; +put_kref: + /* + * No kref_put_mutex() as it's already locked. + * + * If smbd_mr_free_locked() is called + * and the mutex is unlocked and mr is gone, + * in that case kref_put() returned 1. + * + * If kref_put() returned 0 we know that + * smbd_mr_free_locked() didn't + * run. Not by us nor by anyone else, as we + * still hold the mutex, so we need to unlock + * and keep the mr in SMBDIRECT_MR_READY or + * SMBDIRECT_MR_ERROR state. + */ + if (!kref_put(&mr->kref, smbd_mr_free_locked)) + mutex_unlock(&mr->mutex); } static bool smb_set_sge(struct smb_extract_to_rdma *rdma, diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index d67ac5ddaff4..577d37dbeb8a 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -60,7 +60,7 @@ int smbd_send(struct TCP_Server_Info *server, struct smbdirect_mr_io *smbd_register_mr( struct smbd_connection *info, struct iov_iter *iter, bool writing, bool need_invalidate); -int smbd_deregister_mr(struct smbdirect_mr_io *mr); +void smbd_deregister_mr(struct smbdirect_mr_io *mr); #else #define cifs_rdma_enabled(server) 0 diff --git a/fs/smb/client/trace.c b/fs/smb/client/trace.c index 465483787193..16b0e719731f 100644 --- a/fs/smb/client/trace.c +++ b/fs/smb/client/trace.c @@ -4,5 +4,6 @@ * * Author(s): Steve French <stfrench@microsoft.com> */ +#include "cifsglob.h" #define CREATE_TRACE_POINTS #include "trace.h" diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 051cd9dbba13..915cedde5d66 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -830,7 +830,7 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses) if (!server || server->terminate) continue; - if (CIFS_CHAN_NEEDS_RECONNECT(ses, i)) + if (CIFS_CHAN_NEEDS_RECONNECT(ses, cur)) continue; /* diff --git a/fs/smb/client/xattr.c b/fs/smb/client/xattr.c index b88fa04f5792..029910d56c22 100644 --- a/fs/smb/client/xattr.c +++ b/fs/smb/client/xattr.c @@ -178,7 +178,6 @@ static int cifs_xattr_set(const struct xattr_handler *handler, memcpy(pacl, value, size); if (pTcon->ses->server->ops->set_acl) { int aclflags = 0; - rc = 0; switch (handler->flags) { case XATTR_CIFS_NTSD_FULL: |
