mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 12:21:22 -05:00
Merge tag '6.18-rc1-smb-client-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull smb client fixes from Steve French:
"smb client fixes, security and smbdirect improvements, and some minor cleanup:
- Important OOB DFS fix
- Fix various potential tcon refcount leaks
- smbdirect (RDMA) fixes (following up from test event a few weeks
ago):
- Fixes to improve and simplify handling of memory lifetime of
smbdirect_mr_io structures, when a connection gets disconnected
- Make sure we really wait to reach SMBDIRECT_SOCKET_DISCONNECTED
before destroying resources
- Make sure the send/recv submission/completion queues are large
enough to avoid ib_post_send() from failing under pressure
- convert cifs.ko to use the recommended crypto libraries (instead of
crypto_shash), this also can improve performance
- Three small cleanup patches"
* tag '6.18-rc1-smb-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: (24 commits)
smb: client: Consolidate cmac(aes) shash allocation
smb: client: Remove obsolete crypto_shash allocations
smb: client: Use HMAC-MD5 library for NTLMv2
smb: client: Use MD5 library for SMB1 signature calculation
smb: client: Use MD5 library for M-F symlink hashing
smb: client: Use HMAC-SHA256 library for SMB2 signature calculation
smb: client: Use HMAC-SHA256 library for key generation
smb: client: Use SHA-512 library for SMB3.1.1 preauth hash
cifs: parse_dfs_referrals: prevent oob on malformed input
smb: client: Fix refcount leak for cifs_sb_tlink
smb: client: let smbd_destroy() wait for SMBDIRECT_SOCKET_DISCONNECTED
smb: move some duplicate definitions to common/cifsglob.h
smb: client: let destroy_mr_list() keep smbdirect_mr_io memory if registered
smb: client: let destroy_mr_list() call ib_dereg_mr() before ib_dma_unmap_sg()
smb: client: call ib_dma_unmap_sg if mr->sgt.nents is not 0
smb: client: improve logic in smbd_deregister_mr()
smb: client: improve logic in smbd_register_mr()
smb: client: improve logic in allocate_mr_list()
smb: client: let destroy_mr_list() remove locked from the list
smb: client: let destroy_mr_list() call list_del(&mr->list)
...
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct smb_sid *psid,
|
||||
* 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
|
||||
|
||||
@@ -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 @@ static int set_auth_key_response(struct cifs_ses *ses)
|
||||
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);
|
||||
|
||||
@@ -2139,13 +2139,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");
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "cifsacl.h"
|
||||
#include <crypto/internal/hash.h>
|
||||
#include <uapi/linux/cifs/cifs_mount.h>
|
||||
#include "../common/cifsglob.h"
|
||||
#include "../common/smb2pdu.h"
|
||||
#include "smb2pdu.h"
|
||||
#include <linux/filelock.h>
|
||||
@@ -221,9 +222,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) */
|
||||
@@ -702,12 +700,6 @@ 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;
|
||||
@@ -1021,8 +1013,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 +2138,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;
|
||||
|
||||
|
||||
@@ -632,9 +632,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);
|
||||
|
||||
|
||||
@@ -2431,8 +2431,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,
|
||||
|
||||
@@ -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>
|
||||
@@ -36,23 +37,6 @@
|
||||
#define CIFS_MF_SYMLINK_MD5_FORMAT "%16phN\n"
|
||||
#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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -3212,8 +3212,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 +3244,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 +3285,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 +3306,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;
|
||||
|
||||
@@ -295,10 +295,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,
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -253,10 +215,9 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
|
||||
{
|
||||
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;
|
||||
return rc;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -582,7 +471,6 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
|
||||
{
|
||||
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;
|
||||
@@ -643,9 +531,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)
|
||||
|
||||
@@ -1575,12 +1575,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 +1624,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);
|
||||
@@ -2352,18 +2340,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 +2431,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 +2442,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) {
|
||||
log_rdma_mr(ERR, "failed to allocate sgl\n");
|
||||
ib_dereg_mr(smbdirect_mr->mr);
|
||||
goto out;
|
||||
}
|
||||
smbdirect_mr->state = SMBDIRECT_MR_READY;
|
||||
smbdirect_mr->socket = sc;
|
||||
|
||||
list_add_tail(&smbdirect_mr->list, &sc->mr_io.all.list);
|
||||
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");
|
||||
goto kcalloc_sgl_failed;
|
||||
}
|
||||
mr->state = SMBDIRECT_MR_READY;
|
||||
mr->socket = sc;
|
||||
|
||||
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 +2521,7 @@ static struct smbdirect_mr_io *get_mr(struct smbdirect_socket *sc)
|
||||
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 +2568,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 +2580,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 +2631,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 +2700,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 +2762,23 @@ int smbd_deregister_mr(struct smbdirect_mr_io *smbdirect_mr)
|
||||
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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
30
fs/smb/common/cifsglob.h
Normal file
30
fs/smb/common/cifsglob.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1 */
|
||||
/*
|
||||
*
|
||||
* Copyright (C) International Business Machines Corp., 2002,2008
|
||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||
* Jeremy Allison (jra@samba.org)
|
||||
*
|
||||
*/
|
||||
#ifndef _COMMON_CIFS_GLOB_H
|
||||
#define _COMMON_CIFS_GLOB_H
|
||||
|
||||
static inline void inc_rfc1001_len(void *buf, int count)
|
||||
{
|
||||
be32_add_cpu((__be32 *)buf, count);
|
||||
}
|
||||
|
||||
#define SMB1_VERSION_STRING "1.0"
|
||||
#define SMB20_VERSION_STRING "2.0"
|
||||
#define SMB21_VERSION_STRING "2.1"
|
||||
#define SMBDEFAULT_VERSION_STRING "default"
|
||||
#define SMB3ANY_VERSION_STRING "3"
|
||||
#define SMB30_VERSION_STRING "3.0"
|
||||
#define SMB302_VERSION_STRING "3.02"
|
||||
#define ALT_SMB302_VERSION_STRING "3.0.2"
|
||||
#define SMB311_VERSION_STRING "3.1.1"
|
||||
#define ALT_SMB311_VERSION_STRING "3.11"
|
||||
|
||||
#define CIFS_DEFAULT_IOSIZE (1024 * 1024)
|
||||
|
||||
#endif /* _COMMON_CIFS_GLOB_H */
|
||||
@@ -437,13 +437,22 @@ enum smbdirect_mr_state {
|
||||
SMBDIRECT_MR_READY,
|
||||
SMBDIRECT_MR_REGISTERED,
|
||||
SMBDIRECT_MR_INVALIDATED,
|
||||
SMBDIRECT_MR_ERROR
|
||||
SMBDIRECT_MR_ERROR,
|
||||
SMBDIRECT_MR_DISABLED
|
||||
};
|
||||
|
||||
struct smbdirect_mr_io {
|
||||
struct smbdirect_socket *socket;
|
||||
struct ib_cqe cqe;
|
||||
|
||||
/*
|
||||
* We can have up to two references:
|
||||
* 1. by the connection
|
||||
* 2. by the registration
|
||||
*/
|
||||
struct kref kref;
|
||||
struct mutex mutex;
|
||||
|
||||
struct list_head list;
|
||||
|
||||
enum smbdirect_mr_state state;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "glob.h"
|
||||
#include "nterr.h"
|
||||
#include "../common/cifsglob.h"
|
||||
#include "../common/smb2pdu.h"
|
||||
#include "smb2pdu.h"
|
||||
|
||||
@@ -26,16 +27,8 @@
|
||||
#define SMB311_PROT 6
|
||||
#define BAD_PROT 0xFFFF
|
||||
|
||||
#define SMB1_VERSION_STRING "1.0"
|
||||
#define SMB20_VERSION_STRING "2.0"
|
||||
#define SMB21_VERSION_STRING "2.1"
|
||||
#define SMB30_VERSION_STRING "3.0"
|
||||
#define SMB302_VERSION_STRING "3.02"
|
||||
#define SMB311_VERSION_STRING "3.1.1"
|
||||
|
||||
#define SMB_ECHO_INTERVAL (60 * HZ)
|
||||
|
||||
#define CIFS_DEFAULT_IOSIZE (64 * 1024)
|
||||
#define MAX_CIFS_SMALL_BUFFER_SIZE 448 /* big enough for most */
|
||||
|
||||
#define MAX_STREAM_PROT_LEN 0x00FFFFFF
|
||||
@@ -464,9 +457,4 @@ static inline unsigned int get_rfc1002_len(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);
|
||||
}
|
||||
#endif /* __SMB_COMMON_H__ */
|
||||
|
||||
Reference in New Issue
Block a user