summaryrefslogtreecommitdiff
path: root/fs/smb
diff options
context:
space:
mode:
authorMiquel Raynal <miquel.raynal@bootlin.com>2026-01-29 20:19:44 +0100
committerMiquel Raynal <miquel.raynal@bootlin.com>2026-01-29 20:19:44 +0100
commit1ebbefb73ceba9c913ea42f44db1fe8e4d73cbc0 (patch)
tree6576f576a3acc6ee36bb35b44f95dd93c356b65a /fs/smb
parent5ec64aa7fef37c84507eab43fa29985a17db85ed (diff)
parent8618271887ca10ac5108fe7e1d82ba8f1b152cf9 (diff)
Merge tag 'tags/spi-octal-dtr' into nand/next
spi: Octal DTR support This series adds support for 8D-8D-8D in SPI NAND, which can already be leveraged without any SPI changes as controllers already have this support for some SPI NOR devices. Among the few spi-mem patches, they are needed for building the SPI NAND changes (especially the ODTR introduction at the end) and therefore an immutable tag will be needed for merging in the MTD tree (unless all the series goes through MTD directly ofc).
Diffstat (limited to 'fs/smb')
-rw-r--r--fs/smb/client/cifsfs.h4
-rw-r--r--fs/smb/client/cifspdu.h2
-rw-r--r--fs/smb/client/fs_context.c2
-rw-r--r--fs/smb/client/ioctl.c3
-rw-r--r--fs/smb/client/smb2ops.c6
-rw-r--r--fs/smb/client/trace.h1
-rw-r--r--fs/smb/common/smb1pdu.h56
-rw-r--r--fs/smb/common/smb2pdu.h41
-rw-r--r--fs/smb/common/smbdirect/smbdirect_socket.h12
-rw-r--r--fs/smb/common/smbglob.h2
-rw-r--r--fs/smb/server/auth.c4
-rw-r--r--fs/smb/server/connection.c11
-rw-r--r--fs/smb/server/mgmt/user_session.c4
-rw-r--r--fs/smb/server/oplock.c8
-rw-r--r--fs/smb/server/server.c2
-rw-r--r--fs/smb/server/smb2pdu.c86
-rw-r--r--fs/smb/server/smb2pdu.h9
-rw-r--r--fs/smb/server/smb_common.c26
-rw-r--r--fs/smb/server/smb_common.h10
-rw-r--r--fs/smb/server/smbacl.c3
-rw-r--r--fs/smb/server/transport_rdma.c175
-rw-r--r--fs/smb/server/vfs.c2
22 files changed, 316 insertions, 153 deletions
diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h
index e9534258d1ef..75d372ceb655 100644
--- a/fs/smb/client/cifsfs.h
+++ b/fs/smb/client/cifsfs.h
@@ -145,6 +145,6 @@ extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */
/* when changing internal version - update following two lines at same time */
-#define SMB3_PRODUCT_BUILD 57
-#define CIFS_VERSION "2.57"
+#define SMB3_PRODUCT_BUILD 58
+#define CIFS_VERSION "2.58"
#endif /* _CIFSFS_H */
diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h
index eeb4011cb217..fdd84369e7b8 100644
--- a/fs/smb/client/cifspdu.h
+++ b/fs/smb/client/cifspdu.h
@@ -12,7 +12,7 @@
#include <net/sock.h>
#include <linux/unaligned.h>
#include "../common/smbfsctl.h"
-#include "../common/smb2pdu.h"
+#include "../common/smb1pdu.h"
#define CIFS_PROT 0
#define POSIX_PROT (CIFS_PROT+1)
diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
index c2de97e4ad59..d4291d3a9a48 100644
--- a/fs/smb/client/fs_context.c
+++ b/fs/smb/client/fs_context.c
@@ -1139,6 +1139,8 @@ static int smb3_reconfigure(struct fs_context *fc)
rc = smb3_sync_session_ctx_passwords(cifs_sb, ses);
if (rc) {
mutex_unlock(&ses->session_mutex);
+ kfree_sensitive(new_password);
+ kfree_sensitive(new_password2);
return rc;
}
diff --git a/fs/smb/client/ioctl.c b/fs/smb/client/ioctl.c
index 0a9935ce05a5..d1b153209424 100644
--- a/fs/smb/client/ioctl.c
+++ b/fs/smb/client/ioctl.c
@@ -588,6 +588,9 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
break;
default:
cifs_dbg(FYI, "unsupported ioctl\n");
+ trace_smb3_unsupported_ioctl(xid,
+ pSMBFile ? pSMBFile->fid.persistent_fid : 0,
+ command);
break;
}
cifs_ioc_exit:
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index a16ded46b5a2..c1aaf77e187b 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -1905,6 +1905,12 @@ retry:
src_off_prev = src_off;
dst_off_prev = dst_off;
+ /*
+ * __counted_by_le(ChunkCount): set to allocated chunks before
+ * populating Chunks[]
+ */
+ cc_req->ChunkCount = cpu_to_le32(chunk_count);
+
chunks = 0;
copy_bytes = 0;
copy_bytes_left = umin(total_bytes_left, tcon->max_bytes_copy);
diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h
index b0fbc2df642e..a584a7743113 100644
--- a/fs/smb/client/trace.h
+++ b/fs/smb/client/trace.h
@@ -1579,6 +1579,7 @@ DEFINE_EVENT(smb3_ioctl_class, smb3_##name, \
TP_ARGS(xid, fid, command))
DEFINE_SMB3_IOCTL_EVENT(ioctl);
+DEFINE_SMB3_IOCTL_EVENT(unsupported_ioctl);
DECLARE_EVENT_CLASS(smb3_shutdown_class,
TP_PROTO(__u32 flags,
diff --git a/fs/smb/common/smb1pdu.h b/fs/smb/common/smb1pdu.h
new file mode 100644
index 000000000000..df6d4e11ae92
--- /dev/null
+++ b/fs/smb/common/smb1pdu.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+/*
+ *
+ * Copyright (C) International Business Machines Corp., 2002,2009
+ * 2018 Samsung Electronics Co., Ltd.
+ * Author(s): Steve French <sfrench@us.ibm.com>
+ * Namjae Jeon <linkinjeon@kernel.org>
+ *
+ */
+
+#ifndef _COMMON_SMB1_PDU_H
+#define _COMMON_SMB1_PDU_H
+
+#define SMB1_PROTO_NUMBER cpu_to_le32(0x424d53ff)
+
+/*
+ * See MS-CIFS 2.2.3.1
+ * MS-SMB 2.2.3.1
+ */
+struct smb_hdr {
+ __u8 Protocol[4];
+ __u8 Command;
+ union {
+ struct {
+ __u8 ErrorClass;
+ __u8 Reserved;
+ __le16 Error;
+ } __packed DosError;
+ __le32 CifsError;
+ } __packed Status;
+ __u8 Flags;
+ __le16 Flags2; /* note: le */
+ __le16 PidHigh;
+ union {
+ struct {
+ __le32 SequenceNumber; /* le */
+ __u32 Reserved; /* zero */
+ } __packed Sequence;
+ __u8 SecuritySignature[8]; /* le */
+ } __packed Signature;
+ __u8 pad[2];
+ __u16 Tid;
+ __le16 Pid;
+ __u16 Uid;
+ __le16 Mid;
+ __u8 WordCount;
+} __packed;
+
+/* See MS-CIFS 2.2.4.52.1 */
+typedef struct smb_negotiate_req {
+ struct smb_hdr hdr; /* wct = 0 */
+ __le16 ByteCount;
+ unsigned char DialectsArray[];
+} __packed SMB_NEGOTIATE_REQ;
+
+#endif /* _COMMON_SMB1_PDU_H */
diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h
index 3c8d8a4e7439..f5ebbe31384a 100644
--- a/fs/smb/common/smb2pdu.h
+++ b/fs/smb/common/smb2pdu.h
@@ -1293,6 +1293,7 @@ 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.14.2.12 */
@@ -1985,39 +1986,6 @@ struct smb2_lease_ack {
__le64 LeaseDuration;
} __packed;
-/*
- * See MS-CIFS 2.2.3.1
- * MS-SMB 2.2.3.1
- */
-struct smb_hdr {
- __u8 Protocol[4];
- __u8 Command;
- union {
- struct {
- __u8 ErrorClass;
- __u8 Reserved;
- __le16 Error;
- } __packed DosError;
- __le32 CifsError;
- } __packed Status;
- __u8 Flags;
- __le16 Flags2; /* note: le */
- __le16 PidHigh;
- union {
- struct {
- __le32 SequenceNumber; /* le */
- __u32 Reserved; /* zero */
- } __packed Sequence;
- __u8 SecuritySignature[8]; /* le */
- } __packed Signature;
- __u8 pad[2];
- __u16 Tid;
- __le16 Pid;
- __u16 Uid;
- __le16 Mid;
- __u8 WordCount;
-} __packed;
-
#define OP_BREAK_STRUCT_SIZE_20 24
#define OP_BREAK_STRUCT_SIZE_21 36
@@ -2122,11 +2090,4 @@ struct smb_hdr {
#define SET_MINIMUM_RIGHTS (FILE_READ_EA | FILE_READ_ATTRIBUTES \
| READ_CONTROL | SYNCHRONIZE)
-/* See MS-CIFS 2.2.4.52.1 */
-typedef struct smb_negotiate_req {
- struct smb_hdr hdr; /* wct = 0 */
- __le16 ByteCount;
- unsigned char DialectsArray[];
-} __packed SMB_NEGOTIATE_REQ;
-
#endif /* _COMMON_SMB2PDU_H */
diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h
index 384b19177e1c..ee4c2726771a 100644
--- a/fs/smb/common/smbdirect/smbdirect_socket.h
+++ b/fs/smb/common/smbdirect/smbdirect_socket.h
@@ -133,6 +133,14 @@ struct smbdirect_socket {
struct smbdirect_socket_parameters parameters;
/*
+ * The state for connect/negotiation
+ */
+ struct {
+ spinlock_t lock;
+ struct work_struct work;
+ } connect;
+
+ /*
* The state for keepalive and timeout handling
*/
struct {
@@ -353,6 +361,10 @@ static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc)
INIT_WORK(&sc->disconnect_work, __smbdirect_socket_disabled_work);
disable_work_sync(&sc->disconnect_work);
+ spin_lock_init(&sc->connect.lock);
+ INIT_WORK(&sc->connect.work, __smbdirect_socket_disabled_work);
+ disable_work_sync(&sc->connect.work);
+
INIT_WORK(&sc->idle.immediate_work, __smbdirect_socket_disabled_work);
disable_work_sync(&sc->idle.immediate_work);
INIT_DELAYED_WORK(&sc->idle.timer_work, __smbdirect_socket_disabled_work);
diff --git a/fs/smb/common/smbglob.h b/fs/smb/common/smbglob.h
index 9562845a5617..4e33d91cdc9d 100644
--- a/fs/smb/common/smbglob.h
+++ b/fs/smb/common/smbglob.h
@@ -11,8 +11,6 @@
#ifndef _COMMON_SMB_GLOB_H
#define _COMMON_SMB_GLOB_H
-#define SMB1_PROTO_NUMBER cpu_to_le32(0x424d53ff)
-
struct smb_version_values {
char *version_string;
__u16 protocol_id;
diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c
index f2767c4b5132..09af55b71153 100644
--- a/fs/smb/server/auth.c
+++ b/fs/smb/server/auth.c
@@ -714,7 +714,7 @@ void ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn,
int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf,
__u8 *pi_hash)
{
- struct smb2_hdr *rcv_hdr = smb2_get_msg(buf);
+ struct smb2_hdr *rcv_hdr = smb_get_msg(buf);
char *all_bytes_msg = (char *)&rcv_hdr->ProtocolId;
int msg_size = get_rfc1002_len(buf);
struct sha512_ctx sha_ctx;
@@ -841,7 +841,7 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov,
unsigned int nvec, int enc)
{
struct ksmbd_conn *conn = work->conn;
- struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base);
+ struct smb2_transform_hdr *tr_hdr = smb_get_msg(iov[0].iov_base);
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
int rc;
struct scatterlist *sg;
diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c
index b6b4f1286b9c..6cac48c8fbe8 100644
--- a/fs/smb/server/connection.c
+++ b/fs/smb/server/connection.c
@@ -295,8 +295,9 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn)
return true;
}
-#define SMB1_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb_hdr))
-#define SMB2_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb2_hdr) + 4)
+/* "+2" for BCC field (ByteCount, 2 bytes) */
+#define SMB1_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb_hdr) + 2)
+#define SMB2_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb2_pdu))
/**
* ksmbd_conn_handler_loop() - session thread to listen on new smb requests
@@ -363,7 +364,7 @@ recheck:
if (pdu_size > MAX_STREAM_PROT_LEN)
break;
- if (pdu_size < SMB1_MIN_SUPPORTED_HEADER_SIZE)
+ if (pdu_size < SMB1_MIN_SUPPORTED_PDU_SIZE)
break;
/* 4 for rfc1002 length field */
@@ -394,9 +395,9 @@ recheck:
if (!ksmbd_smb_request(conn))
break;
- if (((struct smb2_hdr *)smb2_get_msg(conn->request_buf))->ProtocolId ==
+ if (((struct smb2_hdr *)smb_get_msg(conn->request_buf))->ProtocolId ==
SMB2_PROTO_NUMBER) {
- if (pdu_size < SMB2_MIN_SUPPORTED_HEADER_SIZE)
+ if (pdu_size < SMB2_MIN_SUPPORTED_PDU_SIZE)
break;
}
diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c
index 1c181ef99929..7d880ff34402 100644
--- a/fs/smb/server/mgmt/user_session.c
+++ b/fs/smb/server/mgmt/user_session.c
@@ -325,8 +325,10 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
sess = ksmbd_session_lookup(conn, id);
if (!sess && conn->binding)
sess = ksmbd_session_lookup_slowpath(id);
- if (sess && sess->state != SMB2_SESSION_VALID)
+ if (sess && sess->state != SMB2_SESSION_VALID) {
+ ksmbd_user_session_put(sess);
sess = NULL;
+ }
return sess;
}
diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
index 1f07ebf431d7..a5967ac46604 100644
--- a/fs/smb/server/oplock.c
+++ b/fs/smb/server/oplock.c
@@ -637,7 +637,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
goto out;
}
- rsp_hdr = smb2_get_msg(work->response_buf);
+ rsp_hdr = smb_get_msg(work->response_buf);
memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
@@ -651,7 +651,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
rsp_hdr->SessionId = 0;
memset(rsp_hdr->Signature, 0, 16);
- rsp = smb2_get_msg(work->response_buf);
+ rsp = smb_get_msg(work->response_buf);
rsp->StructureSize = cpu_to_le16(24);
if (!br_info->open_trunc &&
@@ -744,7 +744,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
goto out;
}
- rsp_hdr = smb2_get_msg(work->response_buf);
+ rsp_hdr = smb_get_msg(work->response_buf);
memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
@@ -758,7 +758,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
rsp_hdr->SessionId = 0;
memset(rsp_hdr->Signature, 0, 16);
- rsp = smb2_get_msg(work->response_buf);
+ rsp = smb_get_msg(work->response_buf);
rsp->StructureSize = cpu_to_le16(44);
rsp->Epoch = br_info->epoch;
rsp->Flags = 0;
diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c
index 3cea16050e4f..554ae90df906 100644
--- a/fs/smb/server/server.c
+++ b/fs/smb/server/server.c
@@ -95,7 +95,7 @@ static inline int check_conn_state(struct ksmbd_work *work)
if (ksmbd_conn_exiting(work->conn) ||
ksmbd_conn_need_reconnect(work->conn)) {
- rsp_hdr = work->response_buf;
+ rsp_hdr = smb_get_msg(work->response_buf);
rsp_hdr->Status.CifsError = STATUS_CONNECTION_DISCONNECTED;
return 1;
}
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 27f87a13f20a..2fcd0d4d1fb0 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -47,8 +47,8 @@ static void __wbuf(struct ksmbd_work *work, void **req, void **rsp)
*req = ksmbd_req_buf_next(work);
*rsp = ksmbd_resp_buf_next(work);
} else {
- *req = smb2_get_msg(work->request_buf);
- *rsp = smb2_get_msg(work->response_buf);
+ *req = smb_get_msg(work->request_buf);
+ *rsp = smb_get_msg(work->response_buf);
}
}
@@ -146,7 +146,7 @@ void smb2_set_err_rsp(struct ksmbd_work *work)
if (work->next_smb2_rcv_hdr_off)
err_rsp = ksmbd_resp_buf_next(work);
else
- err_rsp = smb2_get_msg(work->response_buf);
+ err_rsp = smb_get_msg(work->response_buf);
if (err_rsp->hdr.Status != STATUS_STOPPED_ON_SYMLINK) {
int err;
@@ -172,7 +172,7 @@ void smb2_set_err_rsp(struct ksmbd_work *work)
*/
bool is_smb2_neg_cmd(struct ksmbd_work *work)
{
- struct smb2_hdr *hdr = smb2_get_msg(work->request_buf);
+ struct smb2_hdr *hdr = smb_get_msg(work->request_buf);
/* is it SMB2 header ? */
if (hdr->ProtocolId != SMB2_PROTO_NUMBER)
@@ -196,7 +196,7 @@ bool is_smb2_neg_cmd(struct ksmbd_work *work)
*/
bool is_smb2_rsp(struct ksmbd_work *work)
{
- struct smb2_hdr *hdr = smb2_get_msg(work->response_buf);
+ struct smb2_hdr *hdr = smb_get_msg(work->response_buf);
/* is it SMB2 header ? */
if (hdr->ProtocolId != SMB2_PROTO_NUMBER)
@@ -222,7 +222,7 @@ u16 get_smb2_cmd_val(struct ksmbd_work *work)
if (work->next_smb2_rcv_hdr_off)
rcv_hdr = ksmbd_req_buf_next(work);
else
- rcv_hdr = smb2_get_msg(work->request_buf);
+ rcv_hdr = smb_get_msg(work->request_buf);
return le16_to_cpu(rcv_hdr->Command);
}
@@ -235,7 +235,7 @@ void set_smb2_rsp_status(struct ksmbd_work *work, __le32 err)
{
struct smb2_hdr *rsp_hdr;
- rsp_hdr = smb2_get_msg(work->response_buf);
+ rsp_hdr = smb_get_msg(work->response_buf);
rsp_hdr->Status = err;
work->iov_idx = 0;
@@ -258,7 +258,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work)
struct ksmbd_conn *conn = work->conn;
int err;
- rsp_hdr = smb2_get_msg(work->response_buf);
+ rsp_hdr = smb_get_msg(work->response_buf);
memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
@@ -272,7 +272,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work)
rsp_hdr->SessionId = 0;
memset(rsp_hdr->Signature, 0, 16);
- rsp = smb2_get_msg(work->response_buf);
+ rsp = smb_get_msg(work->response_buf);
WARN_ON(ksmbd_conn_good(conn));
@@ -446,7 +446,7 @@ static void init_chained_smb2_rsp(struct ksmbd_work *work)
*/
bool is_chained_smb2_message(struct ksmbd_work *work)
{
- struct smb2_hdr *hdr = smb2_get_msg(work->request_buf);
+ struct smb2_hdr *hdr = smb_get_msg(work->request_buf);
unsigned int len, next_cmd;
if (hdr->ProtocolId != SMB2_PROTO_NUMBER)
@@ -497,8 +497,8 @@ bool is_chained_smb2_message(struct ksmbd_work *work)
*/
int init_smb2_rsp_hdr(struct ksmbd_work *work)
{
- struct smb2_hdr *rsp_hdr = smb2_get_msg(work->response_buf);
- struct smb2_hdr *rcv_hdr = smb2_get_msg(work->request_buf);
+ struct smb2_hdr *rsp_hdr = smb_get_msg(work->response_buf);
+ struct smb2_hdr *rcv_hdr = smb_get_msg(work->request_buf);
memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
rsp_hdr->ProtocolId = rcv_hdr->ProtocolId;
@@ -527,7 +527,7 @@ int init_smb2_rsp_hdr(struct ksmbd_work *work)
*/
int smb2_allocate_rsp_buf(struct ksmbd_work *work)
{
- struct smb2_hdr *hdr = smb2_get_msg(work->request_buf);
+ struct smb2_hdr *hdr = smb_get_msg(work->request_buf);
size_t small_sz = MAX_CIFS_SMALL_BUFFER_SIZE;
size_t large_sz = small_sz + work->conn->vals->max_trans_size;
size_t sz = small_sz;
@@ -543,7 +543,7 @@ int smb2_allocate_rsp_buf(struct ksmbd_work *work)
offsetof(struct smb2_query_info_req, OutputBufferLength))
return -EINVAL;
- req = smb2_get_msg(work->request_buf);
+ req = smb_get_msg(work->request_buf);
if ((req->InfoType == SMB2_O_INFO_FILE &&
(req->FileInfoClass == FILE_FULL_EA_INFORMATION ||
req->FileInfoClass == FILE_ALL_INFORMATION)) ||
@@ -712,10 +712,10 @@ void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status)
}
in_work->conn = work->conn;
- memcpy(smb2_get_msg(in_work->response_buf), ksmbd_resp_buf_next(work),
+ memcpy(smb_get_msg(in_work->response_buf), ksmbd_resp_buf_next(work),
__SMB2_HEADER_STRUCTURE_SIZE);
- rsp_hdr = smb2_get_msg(in_work->response_buf);
+ rsp_hdr = smb_get_msg(in_work->response_buf);
rsp_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND;
rsp_hdr->Id.AsyncId = cpu_to_le64(work->async_id);
smb2_set_err_rsp(in_work);
@@ -1093,8 +1093,8 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
int smb2_handle_negotiate(struct ksmbd_work *work)
{
struct ksmbd_conn *conn = work->conn;
- struct smb2_negotiate_req *req = smb2_get_msg(work->request_buf);
- struct smb2_negotiate_rsp *rsp = smb2_get_msg(work->response_buf);
+ struct smb2_negotiate_req *req = smb_get_msg(work->request_buf);
+ struct smb2_negotiate_rsp *rsp = smb_get_msg(work->response_buf);
int rc = 0;
unsigned int smb2_buf_len, smb2_neg_size, neg_ctxt_len = 0;
__le32 status;
@@ -2281,7 +2281,7 @@ static noinline int create_smb2_pipe(struct ksmbd_work *work)
{
struct smb2_create_rsp *rsp;
struct smb2_create_req *req;
- int id;
+ int id = -1;
int err;
char *name;
@@ -2338,6 +2338,9 @@ out:
break;
}
+ if (id >= 0)
+ ksmbd_session_rpc_close(work->sess, id);
+
if (!IS_ERR(name))
kfree(name);
@@ -2363,7 +2366,7 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len,
int rc = 0;
unsigned int next = 0;
- if (buf_len < sizeof(struct smb2_ea_info) + eabuf->EaNameLength +
+ if (buf_len < sizeof(struct smb2_ea_info) + eabuf->EaNameLength + 1 +
le16_to_cpu(eabuf->EaValueLength))
return -EINVAL;
@@ -2440,7 +2443,7 @@ next:
break;
}
- if (buf_len < sizeof(struct smb2_ea_info) + eabuf->EaNameLength +
+ if (buf_len < sizeof(struct smb2_ea_info) + eabuf->EaNameLength + 1 +
le16_to_cpu(eabuf->EaValueLength)) {
rc = -EINVAL;
break;
@@ -2809,6 +2812,7 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
SMB2_CLIENT_GUID_SIZE)) {
if (!(req->hdr.Flags & SMB2_FLAGS_REPLAY_OPERATION)) {
err = -ENOEXEC;
+ ksmbd_put_durable_fd(dh_info->fp);
goto out;
}
@@ -3006,10 +3010,10 @@ int smb2_open(struct ksmbd_work *work)
file_info = FILE_OPENED;
rc = ksmbd_vfs_getattr(&fp->filp->f_path, &stat);
+ ksmbd_put_durable_fd(fp);
if (rc)
goto err_out2;
- ksmbd_put_durable_fd(fp);
goto reconnected_fp;
}
} else if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE)
@@ -4923,8 +4927,10 @@ static int get_file_all_info(struct ksmbd_work *work,
ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
AT_STATX_SYNC_AS_STAT);
- if (ret)
+ if (ret) {
+ kfree(filename);
return ret;
+ }
ksmbd_debug(SMB, "filename = %s\n", filename);
delete_pending = ksmbd_inode_pending_delete(fp);
@@ -5967,7 +5973,7 @@ out:
*/
int smb2_echo(struct ksmbd_work *work)
{
- struct smb2_echo_rsp *rsp = smb2_get_msg(work->response_buf);
+ struct smb2_echo_rsp *rsp = smb_get_msg(work->response_buf);
ksmbd_debug(SMB, "Received smb2 echo request\n");
@@ -6520,8 +6526,8 @@ int smb2_set_info(struct ksmbd_work *work)
pid = work->compound_pfid;
}
} else {
- req = smb2_get_msg(work->request_buf);
- rsp = smb2_get_msg(work->response_buf);
+ req = smb_get_msg(work->request_buf);
+ rsp = smb_get_msg(work->response_buf);
}
if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
@@ -6754,8 +6760,8 @@ int smb2_read(struct ksmbd_work *work)
pid = work->compound_pfid;
}
} else {
- req = smb2_get_msg(work->request_buf);
- rsp = smb2_get_msg(work->response_buf);
+ req = smb_get_msg(work->request_buf);
+ rsp = smb_get_msg(work->response_buf);
}
if (!has_file_id(id)) {
@@ -7183,7 +7189,7 @@ out:
int smb2_cancel(struct ksmbd_work *work)
{
struct ksmbd_conn *conn = work->conn;
- struct smb2_hdr *hdr = smb2_get_msg(work->request_buf);
+ struct smb2_hdr *hdr = smb_get_msg(work->request_buf);
struct smb2_hdr *chdr;
struct ksmbd_work *iter;
struct list_head *command_list;
@@ -7200,7 +7206,7 @@ int smb2_cancel(struct ksmbd_work *work)
spin_lock(&conn->request_lock);
list_for_each_entry(iter, command_list,
async_request_entry) {
- chdr = smb2_get_msg(iter->request_buf);
+ chdr = smb_get_msg(iter->request_buf);
if (iter->async_id !=
le64_to_cpu(hdr->Id.AsyncId))
@@ -7221,7 +7227,7 @@ int smb2_cancel(struct ksmbd_work *work)
spin_lock(&conn->request_lock);
list_for_each_entry(iter, command_list, request_entry) {
- chdr = smb2_get_msg(iter->request_buf);
+ chdr = smb_get_msg(iter->request_buf);
if (chdr->MessageId != hdr->MessageId ||
iter == work)
@@ -8151,8 +8157,8 @@ int smb2_ioctl(struct ksmbd_work *work)
id = work->compound_fid;
}
} else {
- req = smb2_get_msg(work->request_buf);
- rsp = smb2_get_msg(work->response_buf);
+ req = smb_get_msg(work->request_buf);
+ rsp = smb_get_msg(work->response_buf);
}
if (!has_file_id(id))
@@ -8817,7 +8823,7 @@ int smb2_notify(struct ksmbd_work *work)
*/
bool smb2_is_sign_req(struct ksmbd_work *work, unsigned int command)
{
- struct smb2_hdr *rcv_hdr2 = smb2_get_msg(work->request_buf);
+ struct smb2_hdr *rcv_hdr2 = smb_get_msg(work->request_buf);
if ((rcv_hdr2->Flags & SMB2_FLAGS_SIGNED) &&
command != SMB2_NEGOTIATE_HE &&
@@ -8842,7 +8848,7 @@ int smb2_check_sign_req(struct ksmbd_work *work)
struct kvec iov[1];
size_t len;
- hdr = smb2_get_msg(work->request_buf);
+ hdr = smb_get_msg(work->request_buf);
if (work->next_smb2_rcv_hdr_off)
hdr = ksmbd_req_buf_next(work);
@@ -8916,7 +8922,7 @@ int smb3_check_sign_req(struct ksmbd_work *work)
struct kvec iov[1];
size_t len;
- hdr = smb2_get_msg(work->request_buf);
+ hdr = smb_get_msg(work->request_buf);
if (work->next_smb2_rcv_hdr_off)
hdr = ksmbd_req_buf_next(work);
@@ -9049,7 +9055,7 @@ void smb3_preauth_hash_rsp(struct ksmbd_work *work)
static void fill_transform_hdr(void *tr_buf, char *old_buf, __le16 cipher_type)
{
struct smb2_transform_hdr *tr_hdr = tr_buf + 4;
- struct smb2_hdr *hdr = smb2_get_msg(old_buf);
+ struct smb2_hdr *hdr = smb_get_msg(old_buf);
unsigned int orig_len = get_rfc1002_len(old_buf);
/* tr_buf must be cleared by the caller */
@@ -9088,7 +9094,7 @@ int smb3_encrypt_resp(struct ksmbd_work *work)
bool smb3_is_transform_hdr(void *buf)
{
- struct smb2_transform_hdr *trhdr = smb2_get_msg(buf);
+ struct smb2_transform_hdr *trhdr = smb_get_msg(buf);
return trhdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM;
}
@@ -9100,7 +9106,7 @@ int smb3_decrypt_req(struct ksmbd_work *work)
unsigned int pdu_length = get_rfc1002_len(buf);
struct kvec iov[2];
int buf_data_size = pdu_length - sizeof(struct smb2_transform_hdr);
- struct smb2_transform_hdr *tr_hdr = smb2_get_msg(buf);
+ struct smb2_transform_hdr *tr_hdr = smb_get_msg(buf);
int rc = 0;
if (pdu_length < sizeof(struct smb2_transform_hdr) ||
@@ -9141,7 +9147,7 @@ bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work)
{
struct ksmbd_conn *conn = work->conn;
struct ksmbd_session *sess = work->sess;
- struct smb2_hdr *rsp = smb2_get_msg(work->response_buf);
+ struct smb2_hdr *rsp = smb_get_msg(work->response_buf);
if (conn->dialect < SMB30_PROT_ID)
return false;
diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h
index 66cdc8e4a648..257c6d26df26 100644
--- a/fs/smb/server/smb2pdu.h
+++ b/fs/smb/server/smb2pdu.h
@@ -383,15 +383,6 @@ int smb2_ioctl(struct ksmbd_work *work);
int smb2_oplock_break(struct ksmbd_work *work);
int smb2_notify(struct ksmbd_work *ksmbd_work);
-/*
- * Get the body of the smb2 message excluding the 4 byte rfc1002 headers
- * from request/response buffer.
- */
-static inline void *smb2_get_msg(void *buf)
-{
- return buf + 4;
-}
-
#define POSIX_TYPE_FILE 0
#define POSIX_TYPE_DIR 1
#define POSIX_TYPE_SYMLINK 2
diff --git a/fs/smb/server/smb_common.c b/fs/smb/server/smb_common.c
index b23203a1c286..1cd7e738434d 100644
--- a/fs/smb/server/smb_common.c
+++ b/fs/smb/server/smb_common.c
@@ -140,7 +140,7 @@ int ksmbd_verify_smb_message(struct ksmbd_work *work)
if (smb2_hdr->ProtocolId == SMB2_PROTO_NUMBER)
return ksmbd_smb2_check_message(work);
- hdr = work->request_buf;
+ hdr = smb_get_msg(work->request_buf);
if (*(__le32 *)hdr->Protocol == SMB1_PROTO_NUMBER &&
hdr->Command == SMB_COM_NEGOTIATE) {
work->conn->outstanding_credits++;
@@ -163,7 +163,7 @@ bool ksmbd_smb_request(struct ksmbd_conn *conn)
if (conn->request_buf[0] != 0)
return false;
- proto = (__le32 *)smb2_get_msg(conn->request_buf);
+ proto = (__le32 *)smb_get_msg(conn->request_buf);
if (*proto == SMB2_COMPRESSION_TRANSFORM_ID) {
pr_err_ratelimited("smb2 compression not support yet");
return false;
@@ -259,14 +259,14 @@ int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count)
static int ksmbd_negotiate_smb_dialect(void *buf)
{
int smb_buf_length = get_rfc1002_len(buf);
- __le32 proto = ((struct smb2_hdr *)smb2_get_msg(buf))->ProtocolId;
+ __le32 proto = ((struct smb2_hdr *)smb_get_msg(buf))->ProtocolId;
if (proto == SMB2_PROTO_NUMBER) {
struct smb2_negotiate_req *req;
int smb2_neg_size =
offsetof(struct smb2_negotiate_req, Dialects);
- req = (struct smb2_negotiate_req *)smb2_get_msg(buf);
+ req = (struct smb2_negotiate_req *)smb_get_msg(buf);
if (smb2_neg_size > smb_buf_length)
goto err_out;
@@ -278,15 +278,14 @@ static int ksmbd_negotiate_smb_dialect(void *buf)
req->DialectCount);
}
- proto = *(__le32 *)((struct smb_hdr *)buf)->Protocol;
if (proto == SMB1_PROTO_NUMBER) {
struct smb_negotiate_req *req;
- req = (struct smb_negotiate_req *)buf;
+ req = (struct smb_negotiate_req *)smb_get_msg(buf);
if (le16_to_cpu(req->ByteCount) < 2)
goto err_out;
- if (offsetof(struct smb_negotiate_req, DialectsArray) - 4 +
+ if (offsetof(struct smb_negotiate_req, DialectsArray) +
le16_to_cpu(req->ByteCount) > smb_buf_length) {
goto err_out;
}
@@ -320,8 +319,8 @@ static u16 get_smb1_cmd_val(struct ksmbd_work *work)
*/
static int init_smb1_rsp_hdr(struct ksmbd_work *work)
{
- struct smb_hdr *rsp_hdr = (struct smb_hdr *)work->response_buf;
- struct smb_hdr *rcv_hdr = (struct smb_hdr *)work->request_buf;
+ struct smb_hdr *rsp_hdr = (struct smb_hdr *)smb_get_msg(work->response_buf);
+ struct smb_hdr *rcv_hdr = (struct smb_hdr *)smb_get_msg(work->request_buf);
rsp_hdr->Command = SMB_COM_NEGOTIATE;
*(__le32 *)rsp_hdr->Protocol = SMB1_PROTO_NUMBER;
@@ -412,9 +411,10 @@ static int init_smb1_server(struct ksmbd_conn *conn)
int ksmbd_init_smb_server(struct ksmbd_conn *conn)
{
+ struct smb_hdr *rcv_hdr = (struct smb_hdr *)smb_get_msg(conn->request_buf);
__le32 proto;
- proto = *(__le32 *)((struct smb_hdr *)conn->request_buf)->Protocol;
+ proto = *(__le32 *)rcv_hdr->Protocol;
if (conn->need_neg == false) {
if (proto == SMB1_PROTO_NUMBER)
return -EINVAL;
@@ -572,12 +572,12 @@ static int __smb2_negotiate(struct ksmbd_conn *conn)
static int smb_handle_negotiate(struct ksmbd_work *work)
{
- struct smb_negotiate_rsp *neg_rsp = work->response_buf;
+ struct smb_negotiate_rsp *neg_rsp = smb_get_msg(work->response_buf);
ksmbd_debug(SMB, "Unsupported SMB1 protocol\n");
- if (ksmbd_iov_pin_rsp(work, (void *)neg_rsp + 4,
- sizeof(struct smb_negotiate_rsp) - 4))
+ if (ksmbd_iov_pin_rsp(work, (void *)neg_rsp,
+ sizeof(struct smb_negotiate_rsp)))
return -ENOMEM;
neg_rsp->hdr.Status.CifsError = STATUS_SUCCESS;
diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h
index 067b45048c73..ddd6867c50b2 100644
--- a/fs/smb/server/smb_common.h
+++ b/fs/smb/server/smb_common.h
@@ -10,6 +10,7 @@
#include "glob.h"
#include "../common/smbglob.h"
+#include "../common/smb1pdu.h"
#include "../common/smb2pdu.h"
#include "../common/fscc.h"
#include "smb2pdu.h"
@@ -202,4 +203,13 @@ unsigned int ksmbd_server_side_copy_max_chunk_size(void);
unsigned int ksmbd_server_side_copy_max_total_size(void);
bool is_asterisk(char *p);
__le32 smb_map_generic_desired_access(__le32 daccess);
+
+/*
+ * Get the body of the smb message excluding the 4 byte rfc1002 headers
+ * from request/response buffer.
+ */
+static inline void *smb_get_msg(void *buf)
+{
+ return buf + 4;
+}
#endif /* __SMB_SERVER_COMMON_H__ */
diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
index 5aa7a66334d9..05598d994a68 100644
--- a/fs/smb/server/smbacl.c
+++ b/fs/smb/server/smbacl.c
@@ -1307,9 +1307,6 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
granted |= le32_to_cpu(ace->access_req);
ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size));
}
-
- if (!pdacl->num_aces)
- granted = GENERIC_ALL_FLAGS;
}
if (!uid)
diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c
index 4e7ab8d9314f..f585359684d4 100644
--- a/fs/smb/server/transport_rdma.c
+++ b/fs/smb/server/transport_rdma.c
@@ -242,6 +242,7 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work)
* disable[_delayed]_work_sync()
*/
disable_work(&sc->disconnect_work);
+ disable_work(&sc->connect.work);
disable_work(&sc->recv_io.posted.refill_work);
disable_delayed_work(&sc->idle.timer_work);
disable_work(&sc->idle.immediate_work);
@@ -297,6 +298,7 @@ smb_direct_disconnect_rdma_connection(struct smbdirect_socket *sc)
* not queued again but here we don't block and avoid
* disable[_delayed]_work_sync()
*/
+ disable_work(&sc->connect.work);
disable_work(&sc->recv_io.posted.refill_work);
disable_work(&sc->idle.immediate_work);
disable_delayed_work(&sc->idle.timer_work);
@@ -467,6 +469,7 @@ static void free_transport(struct smb_direct_transport *t)
*/
smb_direct_disconnect_wake_up_all(sc);
+ disable_work_sync(&sc->connect.work);
disable_work_sync(&sc->recv_io.posted.refill_work);
disable_delayed_work_sync(&sc->idle.timer_work);
disable_work_sync(&sc->idle.immediate_work);
@@ -635,28 +638,8 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
switch (sc->recv_io.expected) {
case SMBDIRECT_EXPECT_NEGOTIATE_REQ:
- if (wc->byte_len < sizeof(struct smbdirect_negotiate_req)) {
- put_recvmsg(sc, recvmsg);
- smb_direct_disconnect_rdma_connection(sc);
- return;
- }
- sc->recv_io.reassembly.full_packet_received = true;
- /*
- * Some drivers (at least mlx5_ib) might post a
- * recv completion before RDMA_CM_EVENT_ESTABLISHED,
- * we need to adjust our expectation in that case.
- */
- if (!sc->first_error && sc->status == SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING)
- sc->status = SMBDIRECT_SOCKET_NEGOTIATE_NEEDED;
- if (SMBDIRECT_CHECK_STATUS_WARN(sc, SMBDIRECT_SOCKET_NEGOTIATE_NEEDED)) {
- put_recvmsg(sc, recvmsg);
- smb_direct_disconnect_rdma_connection(sc);
- return;
- }
- sc->status = SMBDIRECT_SOCKET_NEGOTIATE_RUNNING;
- enqueue_reassembly(sc, recvmsg, 0);
- wake_up(&sc->status_wait);
- return;
+ /* see smb_direct_negotiate_recv_done */
+ break;
case SMBDIRECT_EXPECT_DATA_TRANSFER: {
struct smbdirect_data_transfer *data_transfer =
(struct smbdirect_data_transfer *)recvmsg->packet;
@@ -742,6 +725,126 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
smb_direct_disconnect_rdma_connection(sc);
}
+static void smb_direct_negotiate_recv_work(struct work_struct *work);
+
+static void smb_direct_negotiate_recv_done(struct ib_cq *cq, struct ib_wc *wc)
+{
+ struct smbdirect_recv_io *recv_io =
+ container_of(wc->wr_cqe, struct smbdirect_recv_io, cqe);
+ struct smbdirect_socket *sc = recv_io->socket;
+ unsigned long flags;
+
+ /*
+ * reset the common recv_done for later reuse.
+ */
+ recv_io->cqe.done = recv_done;
+
+ if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_RECV) {
+ put_recvmsg(sc, recv_io);
+ if (wc->status != IB_WC_WR_FLUSH_ERR) {
+ pr_err("Negotiate Recv error. status='%s (%d)' opcode=%d\n",
+ ib_wc_status_msg(wc->status), wc->status,
+ wc->opcode);
+ smb_direct_disconnect_rdma_connection(sc);
+ }
+ return;
+ }
+
+ ksmbd_debug(RDMA, "Negotiate Recv completed. status='%s (%d)', opcode=%d\n",
+ ib_wc_status_msg(wc->status), wc->status,
+ wc->opcode);
+
+ ib_dma_sync_single_for_cpu(sc->ib.dev,
+ recv_io->sge.addr,
+ recv_io->sge.length,
+ DMA_FROM_DEVICE);
+
+ /*
+ * This is an internal error!
+ */
+ if (WARN_ON_ONCE(sc->recv_io.expected != SMBDIRECT_EXPECT_NEGOTIATE_REQ)) {
+ put_recvmsg(sc, recv_io);
+ smb_direct_disconnect_rdma_connection(sc);
+ return;
+ }
+
+ /*
+ * Don't reset timer to the keepalive interval in
+ * this will be done in smb_direct_negotiate_recv_work.
+ */
+
+ /*
+ * Only remember the recv_io if it has enough bytes,
+ * this gives smb_direct_negotiate_recv_work enough
+ * information in order to disconnect if it was not
+ * valid.
+ */
+ sc->recv_io.reassembly.full_packet_received = true;
+ if (wc->byte_len >= sizeof(struct smbdirect_negotiate_req))
+ enqueue_reassembly(sc, recv_io, 0);
+ else
+ put_recvmsg(sc, recv_io);
+
+ /*
+ * Some drivers (at least mlx5_ib and irdma in roce mode)
+ * might post a recv completion before RDMA_CM_EVENT_ESTABLISHED,
+ * we need to adjust our expectation in that case.
+ *
+ * So we defer further processing of the negotiation
+ * to smb_direct_negotiate_recv_work().
+ *
+ * If we are already in SMBDIRECT_SOCKET_NEGOTIATE_NEEDED
+ * we queue the work directly otherwise
+ * smb_direct_cm_handler() will do it, when
+ * RDMA_CM_EVENT_ESTABLISHED arrived.
+ */
+ spin_lock_irqsave(&sc->connect.lock, flags);
+ if (!sc->first_error) {
+ INIT_WORK(&sc->connect.work, smb_direct_negotiate_recv_work);
+ if (sc->status == SMBDIRECT_SOCKET_NEGOTIATE_NEEDED)
+ queue_work(sc->workqueue, &sc->connect.work);
+ }
+ spin_unlock_irqrestore(&sc->connect.lock, flags);
+}
+
+static void smb_direct_negotiate_recv_work(struct work_struct *work)
+{
+ struct smbdirect_socket *sc =
+ container_of(work, struct smbdirect_socket, connect.work);
+ const struct smbdirect_socket_parameters *sp = &sc->parameters;
+ struct smbdirect_recv_io *recv_io;
+
+ if (sc->first_error)
+ return;
+
+ ksmbd_debug(RDMA, "Negotiate Recv Work running\n");
+
+ /*
+ * Reset timer to the keepalive interval in
+ * order to trigger our next keepalive message.
+ */
+ sc->idle.keepalive = SMBDIRECT_KEEPALIVE_NONE;
+ mod_delayed_work(sc->workqueue, &sc->idle.timer_work,
+ msecs_to_jiffies(sp->keepalive_interval_msec));
+
+ /*
+ * If smb_direct_negotiate_recv_done() detected an
+ * invalid request we want to disconnect.
+ */
+ recv_io = get_first_reassembly(sc);
+ if (!recv_io) {
+ smb_direct_disconnect_rdma_connection(sc);
+ return;
+ }
+
+ if (SMBDIRECT_CHECK_STATUS_WARN(sc, SMBDIRECT_SOCKET_NEGOTIATE_NEEDED)) {
+ smb_direct_disconnect_rdma_connection(sc);
+ return;
+ }
+ sc->status = SMBDIRECT_SOCKET_NEGOTIATE_RUNNING;
+ wake_up(&sc->status_wait);
+}
+
static int smb_direct_post_recv(struct smbdirect_socket *sc,
struct smbdirect_recv_io *recvmsg)
{
@@ -758,7 +861,6 @@ static int smb_direct_post_recv(struct smbdirect_socket *sc,
return ret;
recvmsg->sge.length = sp->max_recv_size;
recvmsg->sge.lkey = sc->ib.pd->local_dma_lkey;
- recvmsg->cqe.done = recv_done;
wr.wr_cqe = &recvmsg->cqe;
wr.next = NULL;
@@ -1732,6 +1834,7 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id,
struct rdma_cm_event *event)
{
struct smbdirect_socket *sc = cm_id->context;
+ unsigned long flags;
ksmbd_debug(RDMA, "RDMA CM event. cm_id=%p event=%s (%d)\n",
cm_id, rdma_event_msg(event->event), event->event);
@@ -1739,18 +1842,27 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id,
switch (event->event) {
case RDMA_CM_EVENT_ESTABLISHED: {
/*
- * Some drivers (at least mlx5_ib) might post a
- * recv completion before RDMA_CM_EVENT_ESTABLISHED,
+ * Some drivers (at least mlx5_ib and irdma in roce mode)
+ * might post a recv completion before RDMA_CM_EVENT_ESTABLISHED,
* we need to adjust our expectation in that case.
*
- * As we already started the negotiation, we just
- * ignore RDMA_CM_EVENT_ESTABLISHED here.
+ * If smb_direct_negotiate_recv_done was called first
+ * it initialized sc->connect.work only for us to
+ * start, so that we turned into
+ * SMBDIRECT_SOCKET_NEGOTIATE_NEEDED, before
+ * smb_direct_negotiate_recv_work() runs.
+ *
+ * If smb_direct_negotiate_recv_done didn't happen
+ * yet. sc->connect.work is still be disabled and
+ * queue_work() is a no-op.
*/
- if (!sc->first_error && sc->status > SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING)
- break;
if (SMBDIRECT_CHECK_STATUS_DISCONNECT(sc, SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING))
break;
sc->status = SMBDIRECT_SOCKET_NEGOTIATE_NEEDED;
+ spin_lock_irqsave(&sc->connect.lock, flags);
+ if (!sc->first_error)
+ queue_work(sc->workqueue, &sc->connect.work);
+ spin_unlock_irqrestore(&sc->connect.lock, flags);
wake_up(&sc->status_wait);
break;
}
@@ -1921,6 +2033,7 @@ static int smb_direct_prepare_negotiation(struct smbdirect_socket *sc)
recvmsg = get_free_recvmsg(sc);
if (!recvmsg)
return -ENOMEM;
+ recvmsg->cqe.done = smb_direct_negotiate_recv_done;
ret = smb_direct_post_recv(sc, recvmsg);
if (ret) {
@@ -2339,6 +2452,7 @@ respond:
static int smb_direct_connect(struct smbdirect_socket *sc)
{
+ struct smbdirect_recv_io *recv_io;
int ret;
ret = smb_direct_init_params(sc);
@@ -2353,6 +2467,9 @@ static int smb_direct_connect(struct smbdirect_socket *sc)
return ret;
}
+ list_for_each_entry(recv_io, &sc->recv_io.free.list, list)
+ recv_io->cqe.done = recv_done;
+
ret = smb_direct_create_qpair(sc);
if (ret) {
pr_err("Can't accept RDMA client: %d\n", ret);
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index 98b0eb966d91..f891344bd76b 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -702,7 +702,7 @@ retry:
rd.old_parent = NULL;
rd.new_parent = new_path.dentry;
rd.flags = flags;
- rd.delegated_inode = NULL,
+ rd.delegated_inode = NULL;
err = start_renaming_dentry(&rd, lookup_flags, old_child, &new_last);
if (err)
goto out_drop_write;