mirror of
https://github.com/torvalds/linux.git
synced 2026-06-04 04:23:35 +02:00
nine ksmbd server fixes
-----BEGIN PGP SIGNATURE-----
iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmn7ZwQACgkQiiy9cAdy
T1E/+wwAuUwfZ/mAp4aPOiwltp8iyGKZ6L1XgG8/i/PjdZQ61yvE8gzHw1ZLm+p+
xL7tkHGE5y1bQei8YI28z/8xLFPGiNuSvz6uKJHvDW5yzJbiuX8Aiit51wmBX1wW
gwdmAoy51np/qCyxfDDv/DM5bdDCtpbYVlnHZf8J1QodNRWuGFWQtJKF9nGZvEdg
oeYtY8b8UZGOKVgx0LjcDpL6fIAuVMBH9qKoH9YTMkFd1pTuI1H21KxMg7ASg48/
JlPepD+XaSQmaFVZiEcFeYxJDxNIknAtYsDSfVgg21j7ovpNmwAsWWiGlW70I7LS
57PQq7DhbWRxepUemH8GguIkX0bVhDmzlTk42VGB6h0HcvAytT6DYtRroBNzK/9G
6PfzVHdqboi340BWu7Ah3wdt/1L88Gl61wcHV4/vPJD94kuujoqgn3t8lEdt35LL
wBaycNJuAy8ICdwH/zhX4GPtY47swKnsS3Yd/g+dzY4Q7gZaH9gUFLnpBfhGIErr
bw6AIwPE
=qpg9
-----END PGP SIGNATURE-----
Merge tag 'v7.1-rc3-ksmbd-server-fixes' of git://git.samba.org/ksmbd
Pull smb server fixes from Steve French:
- Fix memory leak in connection free
- Fix inherited ACL ACE validation
- Minor cleanup
- Fix for share config
- Fix durable handle cleanup race
- Fix close_file_table_ids in session teardown
- smbdirect fixes:
- Fix memory region registration
- Two fixes for out-of-tree builds
* tag 'v7.1-rc3-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
ksmbd: validate inherited ACE SID length
ksmbd: fix kernel-doc warnings from ksmbd_conn_get/put()
ksmbd: fail share config requests when path allocation fails
ksmbd: close durable scavenger races against m_fp_list lookups
ksmbd: harden file lifetime during session teardown
ksmbd: centralize ksmbd_conn final release to plug transport leak
smb: smbdirect: fix MR registration for coalesced SG lists
smb: smbdirect: introduce and use include/linux/smbdirect.h
smb: smbdirect: make use of DEFAULT_SYMBOL_NAMESPACE and EXPORT_SYMBOL_GPL
This commit is contained in:
commit
8ab992f815
|
|
@ -24650,6 +24650,7 @@ S: Maintained
|
|||
F: fs/smb/client/smbdirect.*
|
||||
F: fs/smb/smbdirect/
|
||||
F: fs/smb/server/transport_rdma.*
|
||||
F: include/linux/smbdirect.h
|
||||
|
||||
SMC91x ETHERNET DRIVER
|
||||
M: Nicolas Pitre <nico@fluxnic.net>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
#include "cifs_debug.h"
|
||||
#include "cifsproto.h"
|
||||
#include "smb2proto.h"
|
||||
#include "../smbdirect/public.h"
|
||||
|
||||
/* Port numbers for SMBD transport */
|
||||
#define SMB_PORT 445
|
||||
|
|
@ -558,3 +557,5 @@ void smbd_debug_proc_show(struct TCP_Server_Info *server, struct seq_file *m)
|
|||
server->rdma_readwrite_threshold,
|
||||
m);
|
||||
}
|
||||
|
||||
MODULE_IMPORT_NS("SMBDIRECT");
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
#include "cifsglob.h"
|
||||
|
||||
#include "../smbdirect/smbdirect.h"
|
||||
#include <linux/smbdirect.h>
|
||||
|
||||
extern int rdma_readwrite_threshold;
|
||||
extern int smbd_max_frmr_depth;
|
||||
|
|
|
|||
|
|
@ -79,6 +79,85 @@ static int create_proc_clients(void) { return 0; }
|
|||
static void delete_proc_clients(void) {}
|
||||
#endif
|
||||
|
||||
static struct workqueue_struct *ksmbd_conn_wq;
|
||||
|
||||
int ksmbd_conn_wq_init(void)
|
||||
{
|
||||
ksmbd_conn_wq = alloc_workqueue("ksmbd-conn-release",
|
||||
WQ_UNBOUND | WQ_MEM_RECLAIM, 0);
|
||||
if (!ksmbd_conn_wq)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ksmbd_conn_wq_destroy(void)
|
||||
{
|
||||
if (ksmbd_conn_wq) {
|
||||
destroy_workqueue(ksmbd_conn_wq);
|
||||
ksmbd_conn_wq = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* __ksmbd_conn_release_work() - perform the final, once-per-struct cleanup
|
||||
* of a ksmbd_conn whose refcount has just dropped to zero.
|
||||
*
|
||||
* This is the common release path used by ksmbd_conn_put() for the embedded
|
||||
* state that outlives the connection thread: async_ida and the attached
|
||||
* transport (which owns the socket and iov for TCP). Called from a workqueue
|
||||
* so that sleep-allowed teardown (sock_release -> tcp_close ->
|
||||
* lock_sock_nested) never runs from an RCU softirq callback (free_opinfo_rcu)
|
||||
* or any other non-sleeping putter context.
|
||||
*/
|
||||
static void __ksmbd_conn_release_work(struct work_struct *work)
|
||||
{
|
||||
struct ksmbd_conn *conn =
|
||||
container_of(work, struct ksmbd_conn, release_work);
|
||||
|
||||
ida_destroy(&conn->async_ida);
|
||||
conn->transport->ops->free_transport(conn->transport);
|
||||
kfree(conn);
|
||||
}
|
||||
|
||||
/**
|
||||
* ksmbd_conn_get() - take a reference on @conn and return it.
|
||||
*
|
||||
* @conn: connection instance to get a reference to
|
||||
*
|
||||
* Returns @conn unchanged so callers can write
|
||||
* "fp->conn = ksmbd_conn_get(work->conn);" in one expression. Returns NULL
|
||||
* if @conn is NULL.
|
||||
*/
|
||||
struct ksmbd_conn *ksmbd_conn_get(struct ksmbd_conn *conn)
|
||||
{
|
||||
if (!conn)
|
||||
return NULL;
|
||||
|
||||
atomic_inc(&conn->refcnt);
|
||||
return conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* ksmbd_conn_put() - drop a reference and, if it was the last, queue the
|
||||
* release onto ksmbd_conn_wq so it runs from process context.
|
||||
*
|
||||
* @conn: connection instance to put a reference to
|
||||
*
|
||||
* Callable from any context including RCU softirq callbacks and non-sleeping
|
||||
* locks; the actual release is deferred to the workqueue. ksmbd_conn_wq is
|
||||
* created in ksmbd_server_init() before any conn can be allocated and is
|
||||
* destroyed in ksmbd_server_exit() after rcu_barrier(), so it is always
|
||||
* non-NULL while a conn reference is held.
|
||||
*/
|
||||
void ksmbd_conn_put(struct ksmbd_conn *conn)
|
||||
{
|
||||
if (!conn)
|
||||
return;
|
||||
|
||||
if (atomic_dec_and_test(&conn->refcnt))
|
||||
queue_work(ksmbd_conn_wq, &conn->release_work);
|
||||
}
|
||||
|
||||
/**
|
||||
* ksmbd_conn_free() - free resources of the connection instance
|
||||
*
|
||||
|
|
@ -93,23 +172,19 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)
|
|||
hash_del(&conn->hlist);
|
||||
up_write(&conn_list_lock);
|
||||
|
||||
/*
|
||||
* request_buf / preauth_info / mechToken are only ever accessed by the
|
||||
* connection handler thread that owns @conn. ksmbd_conn_free() is
|
||||
* called from the transport free_transport() path when that thread is
|
||||
* exiting, so it is safe to release them unconditionally even when
|
||||
* ksmbd_conn_put() below is not the final putter (oplock / ksmbd_file
|
||||
* holders only retain the conn pointer, not these per-thread buffers).
|
||||
*/
|
||||
xa_destroy(&conn->sessions);
|
||||
kvfree(conn->request_buf);
|
||||
kfree(conn->preauth_info);
|
||||
kfree(conn->mechToken);
|
||||
if (atomic_dec_and_test(&conn->refcnt)) {
|
||||
/*
|
||||
* async_ida is embedded in struct ksmbd_conn, so pair
|
||||
* ida_destroy() with the final kfree() rather than with
|
||||
* the unconditional field teardown above. This keeps
|
||||
* the IDA valid for the entire lifetime of the struct,
|
||||
* even while other refcount holders (oplock / vfs
|
||||
* durable handles) still reference the connection.
|
||||
*/
|
||||
ida_destroy(&conn->async_ida);
|
||||
conn->transport->ops->free_transport(conn->transport);
|
||||
kfree(conn);
|
||||
}
|
||||
ksmbd_conn_put(conn);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -136,6 +211,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
|
|||
conn->um = ERR_PTR(-EOPNOTSUPP);
|
||||
if (IS_ERR(conn->um))
|
||||
conn->um = NULL;
|
||||
INIT_WORK(&conn->release_work, __ksmbd_conn_release_work);
|
||||
atomic_set(&conn->req_running, 0);
|
||||
atomic_set(&conn->r_count, 0);
|
||||
atomic_set(&conn->refcnt, 1);
|
||||
|
|
@ -512,8 +588,7 @@ void ksmbd_conn_r_count_dec(struct ksmbd_conn *conn)
|
|||
if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
|
||||
wake_up(&conn->r_count_q);
|
||||
|
||||
if (atomic_dec_and_test(&conn->refcnt))
|
||||
kfree(conn);
|
||||
ksmbd_conn_put(conn);
|
||||
}
|
||||
|
||||
int ksmbd_conn_transport_init(void)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/kthread.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/unicode.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "smb_common.h"
|
||||
#include "ksmbd_work.h"
|
||||
|
|
@ -120,6 +121,7 @@ struct ksmbd_conn {
|
|||
bool binding;
|
||||
atomic_t refcnt;
|
||||
bool is_aapl;
|
||||
struct work_struct release_work;
|
||||
};
|
||||
|
||||
struct ksmbd_conn_ops {
|
||||
|
|
@ -164,6 +166,10 @@ void ksmbd_conn_wait_idle(struct ksmbd_conn *conn);
|
|||
int ksmbd_conn_wait_idle_sess_id(struct ksmbd_conn *curr_conn, u64 sess_id);
|
||||
struct ksmbd_conn *ksmbd_conn_alloc(void);
|
||||
void ksmbd_conn_free(struct ksmbd_conn *conn);
|
||||
struct ksmbd_conn *ksmbd_conn_get(struct ksmbd_conn *conn);
|
||||
void ksmbd_conn_put(struct ksmbd_conn *conn);
|
||||
int ksmbd_conn_wq_init(void);
|
||||
void ksmbd_conn_wq_destroy(void);
|
||||
bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c);
|
||||
int ksmbd_conn_write(struct ksmbd_work *work);
|
||||
int ksmbd_conn_rdma_read(struct ksmbd_conn *conn,
|
||||
|
|
|
|||
|
|
@ -167,7 +167,10 @@ static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work,
|
|||
|
||||
share->path = kstrndup(ksmbd_share_config_path(resp), path_len,
|
||||
KSMBD_DEFAULT_GFP);
|
||||
if (share->path) {
|
||||
if (!share->path) {
|
||||
ret = -ENOMEM;
|
||||
} else {
|
||||
ret = 0;
|
||||
share->path_sz = strlen(share->path);
|
||||
while (share->path_sz > 1 &&
|
||||
share->path[share->path_sz - 1] == '/')
|
||||
|
|
@ -179,9 +182,10 @@ static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work,
|
|||
share->force_directory_mode = resp->force_directory_mode;
|
||||
share->force_uid = resp->force_uid;
|
||||
share->force_gid = resp->force_gid;
|
||||
ret = parse_veto_list(share,
|
||||
KSMBD_SHARE_CONFIG_VETO_LIST(resp),
|
||||
resp->veto_list_sz);
|
||||
if (!ret)
|
||||
ret = parse_veto_list(share,
|
||||
KSMBD_SHARE_CONFIG_VETO_LIST(resp),
|
||||
resp->veto_list_sz);
|
||||
if (!ret && share->path) {
|
||||
if (__ksmbd_override_fsids(work, share)) {
|
||||
kill_share(share);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ static DEFINE_RWLOCK(lease_list_lock);
|
|||
static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,
|
||||
u64 id, __u16 Tid)
|
||||
{
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
struct ksmbd_session *sess = work->sess;
|
||||
struct oplock_info *opinfo;
|
||||
|
||||
|
|
@ -39,7 +38,7 @@ static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,
|
|||
return NULL;
|
||||
|
||||
opinfo->sess = sess;
|
||||
opinfo->conn = conn;
|
||||
opinfo->conn = ksmbd_conn_get(work->conn);
|
||||
opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
|
||||
opinfo->op_state = OPLOCK_STATE_NONE;
|
||||
opinfo->pending_break = 0;
|
||||
|
|
@ -50,7 +49,6 @@ static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,
|
|||
init_waitqueue_head(&opinfo->oplock_brk);
|
||||
atomic_set(&opinfo->refcount, 1);
|
||||
atomic_set(&opinfo->breaking_cnt, 0);
|
||||
atomic_inc(&opinfo->conn->refcnt);
|
||||
|
||||
return opinfo;
|
||||
}
|
||||
|
|
@ -132,8 +130,7 @@ static void __free_opinfo(struct oplock_info *opinfo)
|
|||
{
|
||||
if (opinfo->is_lease)
|
||||
free_lease(opinfo);
|
||||
if (opinfo->conn && atomic_dec_and_test(&opinfo->conn->refcnt))
|
||||
kfree(opinfo->conn);
|
||||
ksmbd_conn_put(opinfo->conn);
|
||||
kfree(opinfo);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -596,8 +596,14 @@ static int __init ksmbd_server_init(void)
|
|||
if (ret)
|
||||
goto err_crypto_destroy;
|
||||
|
||||
ret = ksmbd_conn_wq_init();
|
||||
if (ret)
|
||||
goto err_workqueue_destroy;
|
||||
|
||||
return 0;
|
||||
|
||||
err_workqueue_destroy:
|
||||
ksmbd_workqueue_destroy();
|
||||
err_crypto_destroy:
|
||||
ksmbd_crypto_destroy();
|
||||
err_release_inode_hash:
|
||||
|
|
@ -623,6 +629,12 @@ static void __exit ksmbd_server_exit(void)
|
|||
{
|
||||
ksmbd_server_shutdown();
|
||||
rcu_barrier();
|
||||
/*
|
||||
* ksmbd_conn_put() defers the final release onto ksmbd_conn_wq,
|
||||
* so drain it after rcu_barrier() has fired any pending RCU
|
||||
* callbacks that may have queued a release.
|
||||
*/
|
||||
ksmbd_conn_wq_destroy();
|
||||
ksmbd_release_inode_hash();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3767,8 +3767,10 @@ int smb2_open(struct ksmbd_work *work)
|
|||
|
||||
err_out2:
|
||||
if (!rc) {
|
||||
ksmbd_update_fstate(&work->sess->file_table, fp, FP_INITED);
|
||||
rc = ksmbd_iov_pin_rsp(work, (void *)rsp, iov_len);
|
||||
rc = ksmbd_update_fstate(&work->sess->file_table, fp,
|
||||
FP_INITED);
|
||||
if (!rc)
|
||||
rc = ksmbd_iov_pin_rsp(work, (void *)rsp, iov_len);
|
||||
}
|
||||
if (rc) {
|
||||
if (rc == -EINVAL)
|
||||
|
|
|
|||
|
|
@ -1068,7 +1068,26 @@ static void smb_set_ace(struct smb_ace *ace, const struct smb_sid *sid, u8 type,
|
|||
ace->flags = flags;
|
||||
ace->access_req = access_req;
|
||||
smb_copy_sid(&ace->sid, sid);
|
||||
ace->size = cpu_to_le16(1 + 1 + 2 + 4 + 1 + 1 + 6 + (sid->num_subauth * 4));
|
||||
ace->size = cpu_to_le16(1 + 1 + 2 + 4 + 1 + 1 + 6 +
|
||||
(ace->sid.num_subauth * 4));
|
||||
}
|
||||
|
||||
static int smb_append_inherited_ace(struct smb_ace **ace, int *nt_size,
|
||||
u16 *ace_cnt, const struct smb_sid *sid,
|
||||
u8 type, u8 flags, __le32 access_req)
|
||||
{
|
||||
int ace_size;
|
||||
|
||||
smb_set_ace(*ace, sid, type, flags, access_req);
|
||||
ace_size = le16_to_cpu((*ace)->size);
|
||||
/* pdacl->size is __le16 and includes struct smb_acl. */
|
||||
if (check_add_overflow(*nt_size, ace_size, nt_size) ||
|
||||
*nt_size > U16_MAX - (int)sizeof(struct smb_acl))
|
||||
return -EINVAL;
|
||||
|
||||
(*ace_cnt)++;
|
||||
*ace = (struct smb_ace *)((char *)*ace + ace_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smb_inherit_dacl(struct ksmbd_conn *conn,
|
||||
|
|
@ -1157,6 +1176,12 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
|
|||
CIFS_SID_BASE_SIZE)
|
||||
break;
|
||||
|
||||
if (parent_aces->sid.num_subauth > SID_MAX_SUB_AUTHORITIES ||
|
||||
pace_size < offsetof(struct smb_ace, sid) +
|
||||
CIFS_SID_BASE_SIZE +
|
||||
sizeof(__le32) * parent_aces->sid.num_subauth)
|
||||
break;
|
||||
|
||||
aces_size -= pace_size;
|
||||
|
||||
flags = parent_aces->flags;
|
||||
|
|
@ -1186,22 +1211,24 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
|
|||
}
|
||||
|
||||
if (is_dir && creator && flags & CONTAINER_INHERIT_ACE) {
|
||||
smb_set_ace(aces, psid, parent_aces->type, inherited_flags,
|
||||
parent_aces->access_req);
|
||||
nt_size += le16_to_cpu(aces->size);
|
||||
ace_cnt++;
|
||||
aces = (struct smb_ace *)((char *)aces + le16_to_cpu(aces->size));
|
||||
rc = smb_append_inherited_ace(&aces, &nt_size, &ace_cnt,
|
||||
psid, parent_aces->type,
|
||||
inherited_flags,
|
||||
parent_aces->access_req);
|
||||
if (rc)
|
||||
goto free_aces_base;
|
||||
flags |= INHERIT_ONLY_ACE;
|
||||
psid = creator;
|
||||
} else if (is_dir && !(parent_aces->flags & NO_PROPAGATE_INHERIT_ACE)) {
|
||||
psid = &parent_aces->sid;
|
||||
}
|
||||
|
||||
smb_set_ace(aces, psid, parent_aces->type, flags | inherited_flags,
|
||||
parent_aces->access_req);
|
||||
nt_size += le16_to_cpu(aces->size);
|
||||
aces = (struct smb_ace *)((char *)aces + le16_to_cpu(aces->size));
|
||||
ace_cnt++;
|
||||
rc = smb_append_inherited_ace(&aces, &nt_size, &ace_cnt, psid,
|
||||
parent_aces->type,
|
||||
flags | inherited_flags,
|
||||
parent_aces->access_req);
|
||||
if (rc)
|
||||
goto free_aces_base;
|
||||
pass:
|
||||
parent_aces = (struct smb_ace *)((char *)parent_aces + pace_size);
|
||||
}
|
||||
|
|
@ -1211,7 +1238,7 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
|
|||
struct smb_acl *pdacl;
|
||||
struct smb_sid *powner_sid = NULL, *pgroup_sid = NULL;
|
||||
int powner_sid_size = 0, pgroup_sid_size = 0, pntsd_size;
|
||||
int pntsd_alloc_size;
|
||||
size_t pntsd_alloc_size;
|
||||
|
||||
if (parent_pntsd->osidoffset) {
|
||||
powner_sid = (struct smb_sid *)((char *)parent_pntsd +
|
||||
|
|
@ -1224,8 +1251,19 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
|
|||
pgroup_sid_size = 1 + 1 + 6 + (pgroup_sid->num_subauth * 4);
|
||||
}
|
||||
|
||||
pntsd_alloc_size = sizeof(struct smb_ntsd) + powner_sid_size +
|
||||
pgroup_sid_size + sizeof(struct smb_acl) + nt_size;
|
||||
if (check_add_overflow(sizeof(struct smb_ntsd),
|
||||
(size_t)powner_sid_size,
|
||||
&pntsd_alloc_size) ||
|
||||
check_add_overflow(pntsd_alloc_size,
|
||||
(size_t)pgroup_sid_size,
|
||||
&pntsd_alloc_size) ||
|
||||
check_add_overflow(pntsd_alloc_size, sizeof(struct smb_acl),
|
||||
&pntsd_alloc_size) ||
|
||||
check_add_overflow(pntsd_alloc_size, (size_t)nt_size,
|
||||
&pntsd_alloc_size)) {
|
||||
rc = -EINVAL;
|
||||
goto free_aces_base;
|
||||
}
|
||||
|
||||
pntsd = kzalloc(pntsd_alloc_size, KSMBD_DEFAULT_GFP);
|
||||
if (!pntsd) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
#include "smb_common.h"
|
||||
#include "../common/smb2status.h"
|
||||
#include "transport_rdma.h"
|
||||
#include "../smbdirect/public.h"
|
||||
|
||||
|
||||
#define SMB_DIRECT_PORT_IWARP 5445
|
||||
|
|
@ -540,3 +539,5 @@ static const struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops = {
|
|||
.rdma_write = smb_direct_rdma_write,
|
||||
.free_transport = smb_direct_free_transport,
|
||||
};
|
||||
|
||||
MODULE_IMPORT_NS("SMBDIRECT");
|
||||
|
|
|
|||
|
|
@ -25,6 +25,6 @@ static inline void init_smbd_max_io_size(unsigned int sz) { }
|
|||
static inline unsigned int get_smbd_max_read_write_size(struct ksmbd_transport *kt) { return 0; }
|
||||
#endif
|
||||
|
||||
#include "../smbdirect/smbdirect.h"
|
||||
#include <linux/smbdirect.h>
|
||||
|
||||
#endif /* __KSMBD_TRANSPORT_RDMA_H__ */
|
||||
|
|
|
|||
|
|
@ -418,6 +418,14 @@ static void __ksmbd_remove_durable_fd(struct ksmbd_file *fp)
|
|||
return;
|
||||
|
||||
idr_remove(global_ft.idr, fp->persistent_id);
|
||||
/*
|
||||
* Clear persistent_id so a later __ksmbd_close_fd() that runs from a
|
||||
* delayed putter (e.g. when a concurrent ksmbd_lookup_fd_inode()
|
||||
* walker held the final reference) does not re-issue idr_remove() on
|
||||
* an id that idr_alloc_cyclic() may have already handed out to a new
|
||||
* durable handle.
|
||||
*/
|
||||
fp->persistent_id = KSMBD_NO_FID;
|
||||
}
|
||||
|
||||
static void ksmbd_remove_durable_fd(struct ksmbd_file *fp)
|
||||
|
|
@ -431,13 +439,13 @@ static void ksmbd_remove_durable_fd(struct ksmbd_file *fp)
|
|||
|
||||
static void __ksmbd_remove_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
|
||||
{
|
||||
if (!has_file_id(fp->volatile_id))
|
||||
return;
|
||||
|
||||
down_write(&fp->f_ci->m_lock);
|
||||
list_del_init(&fp->node);
|
||||
up_write(&fp->f_ci->m_lock);
|
||||
|
||||
if (!has_file_id(fp->volatile_id))
|
||||
return;
|
||||
|
||||
write_lock(&ft->lock);
|
||||
idr_remove(ft->idr, fp->volatile_id);
|
||||
write_unlock(&ft->lock);
|
||||
|
|
@ -475,6 +483,17 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
|
|||
kfree(smb_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Drop fp's strong reference on conn (taken in ksmbd_open_fd() /
|
||||
* ksmbd_reopen_durable_fd()). Durable fps that reached the
|
||||
* scavenger have already had fp->conn cleared by session_fd_check(),
|
||||
* in which case there is nothing to drop here.
|
||||
*/
|
||||
if (fp->conn) {
|
||||
ksmbd_conn_put(fp->conn);
|
||||
fp->conn = NULL;
|
||||
}
|
||||
|
||||
if (ksmbd_stream_fd(fp))
|
||||
kfree(fp->stream.name);
|
||||
kfree(fp->owner.name);
|
||||
|
|
@ -510,6 +529,20 @@ static struct ksmbd_file *__ksmbd_lookup_fd(struct ksmbd_file_table *ft,
|
|||
|
||||
static void __put_fd_final(struct ksmbd_work *work, struct ksmbd_file *fp)
|
||||
{
|
||||
/*
|
||||
* Detached durable fp -- session_fd_check() cleared fp->conn at
|
||||
* preserve, so this fp is no longer tracked by any conn's
|
||||
* stats.open_files_count. This happens when
|
||||
* ksmbd_scavenger_dispose_dh() hands the final close off to an
|
||||
* m_fp_list walker (e.g. ksmbd_lookup_fd_inode()) whose work->conn
|
||||
* is unrelated to the conn that originally opened the handle; close
|
||||
* via the NULL-ft path so we do not underflow that unrelated
|
||||
* counter.
|
||||
*/
|
||||
if (!fp->conn) {
|
||||
__ksmbd_close_fd(NULL, fp);
|
||||
return;
|
||||
}
|
||||
__ksmbd_close_fd(&work->sess->file_table, fp);
|
||||
atomic_dec(&work->conn->stats.open_files_count);
|
||||
}
|
||||
|
|
@ -752,7 +785,14 @@ struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp)
|
|||
atomic_set(&fp->refcount, 1);
|
||||
|
||||
fp->filp = filp;
|
||||
fp->conn = work->conn;
|
||||
/*
|
||||
* fp owns a strong reference on fp->conn for as long as fp->conn is
|
||||
* non-NULL, so session_fd_check() and __ksmbd_close_fd() never
|
||||
* dereference a dangling pointer. Paired with ksmbd_conn_put() in
|
||||
* session_fd_check() (durable preserve), in __ksmbd_close_fd()
|
||||
* (final close), and on the error paths below.
|
||||
*/
|
||||
fp->conn = ksmbd_conn_get(work->conn);
|
||||
fp->tcon = work->tcon;
|
||||
fp->volatile_id = KSMBD_NO_FID;
|
||||
fp->persistent_id = KSMBD_NO_FID;
|
||||
|
|
@ -774,19 +814,64 @@ struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp)
|
|||
return fp;
|
||||
|
||||
err_out:
|
||||
/* fp->conn was set and refcounted before every branch here. */
|
||||
ksmbd_conn_put(fp->conn);
|
||||
kmem_cache_free(filp_cache, fp);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
|
||||
unsigned int state)
|
||||
/**
|
||||
* ksmbd_update_fstate() - update an fp state under the file-table lock
|
||||
* @ft: file table that publishes @fp's volatile id
|
||||
* @fp: file pointer to update
|
||||
* @state: new state
|
||||
*
|
||||
* Return: 0 on success. The FP_NEW -> FP_INITED transition is special:
|
||||
* -ENOENT if teardown already unpublished @fp by advancing the state or
|
||||
* clearing the volatile id. Other state updates preserve the historical
|
||||
* fire-and-forget behavior.
|
||||
*/
|
||||
int ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
|
||||
unsigned int state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!fp)
|
||||
return;
|
||||
return -ENOENT;
|
||||
|
||||
write_lock(&ft->lock);
|
||||
fp->f_state = state;
|
||||
if (state == FP_INITED &&
|
||||
(fp->f_state != FP_NEW || !has_file_id(fp->volatile_id))) {
|
||||
ret = -ENOENT;
|
||||
} else {
|
||||
fp->f_state = state;
|
||||
ret = 0;
|
||||
}
|
||||
write_unlock(&ft->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* ksmbd_mark_fp_closed() - mark fp closed under ft->lock and return how many
|
||||
* refs the teardown path owns.
|
||||
*
|
||||
* FP_INITED has a normal idr-owned reference, so teardown owns both that
|
||||
* reference and the transient lookup reference. FP_NEW is still owned by the
|
||||
* in-flight opener/reopener, which will drop the original reference after
|
||||
* ksmbd_update_fstate(..., FP_INITED) observes the cleared volatile id.
|
||||
* FP_CLOSED on entry means an earlier ksmbd_close_fd() already consumed the
|
||||
* idr-owned ref.
|
||||
*/
|
||||
static int ksmbd_mark_fp_closed(struct ksmbd_file *fp)
|
||||
{
|
||||
if (fp->f_state == FP_INITED) {
|
||||
set_close_state_blocked_works(fp);
|
||||
fp->f_state = FP_CLOSED;
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -794,7 +879,8 @@ __close_file_table_ids(struct ksmbd_session *sess,
|
|||
struct ksmbd_tree_connect *tcon,
|
||||
bool (*skip)(struct ksmbd_tree_connect *tcon,
|
||||
struct ksmbd_file *fp,
|
||||
struct ksmbd_user *user))
|
||||
struct ksmbd_user *user),
|
||||
bool skip_preserves_fp)
|
||||
{
|
||||
struct ksmbd_file_table *ft = &sess->file_table;
|
||||
struct ksmbd_file *fp;
|
||||
|
|
@ -802,32 +888,120 @@ __close_file_table_ids(struct ksmbd_session *sess,
|
|||
int num = 0;
|
||||
|
||||
while (1) {
|
||||
int n_to_drop;
|
||||
|
||||
write_lock(&ft->lock);
|
||||
fp = idr_get_next(ft->idr, &id);
|
||||
if (!fp) {
|
||||
write_unlock(&ft->lock);
|
||||
break;
|
||||
}
|
||||
|
||||
if (skip(tcon, fp, sess->user) ||
|
||||
!atomic_dec_and_test(&fp->refcount)) {
|
||||
if (!atomic_inc_not_zero(&fp->refcount)) {
|
||||
id++;
|
||||
write_unlock(&ft->lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
set_close_state_blocked_works(fp);
|
||||
idr_remove(ft->idr, fp->volatile_id);
|
||||
fp->volatile_id = KSMBD_NO_FID;
|
||||
write_unlock(&ft->lock);
|
||||
if (skip_preserves_fp) {
|
||||
/*
|
||||
* Session teardown: skip() is session_fd_check(),
|
||||
* which may sleep and mutates fp->conn / fp->tcon /
|
||||
* fp->volatile_id when it chooses to preserve fp
|
||||
* for durable reconnect. Unpublish fp from the
|
||||
* session idr here, under ft->lock, so that
|
||||
* __ksmbd_lookup_fd() through this session cannot
|
||||
* grant a new ksmbd_fp_get() reference to an fp
|
||||
* whose fields are about to be rewritten outside
|
||||
* the lock. Durable reconnect still reaches fp via
|
||||
* global_ft.
|
||||
*/
|
||||
idr_remove(ft->idr, id);
|
||||
fp->volatile_id = KSMBD_NO_FID;
|
||||
write_unlock(&ft->lock);
|
||||
|
||||
if (skip(tcon, fp, sess->user)) {
|
||||
/*
|
||||
* session_fd_check() has converted fp to
|
||||
* durable-preserve state and cleared its
|
||||
* per-conn fields. fp is already unpublished
|
||||
* above; the original idr-owned ref keeps it
|
||||
* alive for the durable scavenger. Drop only
|
||||
* the transient ref. atomic_dec() is safe --
|
||||
* atomic_inc_not_zero() succeeded on a
|
||||
* positive value and we added one more, so
|
||||
* refcount cannot be zero here.
|
||||
*/
|
||||
atomic_dec(&fp->refcount);
|
||||
id++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep the close-state decision under the same lock
|
||||
* observed by ksmbd_update_fstate(), which is how an
|
||||
* in-flight FP_NEW opener learns that teardown has
|
||||
* cleared its volatile id.
|
||||
*/
|
||||
write_lock(&ft->lock);
|
||||
n_to_drop = ksmbd_mark_fp_closed(fp);
|
||||
write_unlock(&ft->lock);
|
||||
} else {
|
||||
/*
|
||||
* Tree teardown: skip() is tree_conn_fd_check(), a
|
||||
* cheap pointer compare that doesn't sleep and has
|
||||
* no side effects, so keep the skip decision plus
|
||||
* the unpublish-and-mark-closed sequence atomic
|
||||
* under ft->lock. fps belonging to other tree
|
||||
* connects (skip() == true) stay fully published in
|
||||
* the session idr with no lock window.
|
||||
*/
|
||||
if (skip(tcon, fp, sess->user)) {
|
||||
atomic_dec(&fp->refcount);
|
||||
write_unlock(&ft->lock);
|
||||
id++;
|
||||
continue;
|
||||
}
|
||||
idr_remove(ft->idr, id);
|
||||
fp->volatile_id = KSMBD_NO_FID;
|
||||
n_to_drop = ksmbd_mark_fp_closed(fp);
|
||||
write_unlock(&ft->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* fp->volatile_id is already cleared to prevent stale idr
|
||||
* removal from a deferred final close. Remove fp from
|
||||
* m_fp_list here because __ksmbd_remove_fd() will skip the
|
||||
* list unlink when volatile_id is KSMBD_NO_FID.
|
||||
*/
|
||||
down_write(&fp->f_ci->m_lock);
|
||||
list_del_init(&fp->node);
|
||||
up_write(&fp->f_ci->m_lock);
|
||||
|
||||
__ksmbd_close_fd(ft, fp);
|
||||
|
||||
num++;
|
||||
/*
|
||||
* Drop the references this iteration owns:
|
||||
*
|
||||
* n_to_drop == 2: we observed FP_INITED and committed
|
||||
* the FP_CLOSED transition ourselves, so we own the
|
||||
* transient (+1) and the still-intact idr-owned ref.
|
||||
*
|
||||
* n_to_drop == 1: either a prior ksmbd_close_fd()
|
||||
* already consumed the idr-owned ref, or fp was still
|
||||
* FP_NEW and the in-flight opener/reopener must keep
|
||||
* the original reference until ksmbd_update_fstate()
|
||||
* observes the cleared volatile id.
|
||||
*
|
||||
* If we end up as the final putter, finalize fp and
|
||||
* account the open_files_count decrement via the caller's
|
||||
* atomic_sub(num, ...). Otherwise the remaining user's
|
||||
* ksmbd_fd_put() reaches __put_fd_final(), which does its
|
||||
* own atomic_dec(&open_files_count), so we must not count
|
||||
* this fp here -- doing so would double-decrement the
|
||||
* connection-wide counter.
|
||||
*/
|
||||
if (atomic_sub_and_test(n_to_drop, &fp->refcount)) {
|
||||
__ksmbd_close_fd(NULL, fp);
|
||||
num++;
|
||||
}
|
||||
id++;
|
||||
}
|
||||
|
||||
|
|
@ -881,24 +1055,37 @@ static bool ksmbd_durable_scavenger_alive(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void ksmbd_scavenger_dispose_dh(struct list_head *head)
|
||||
static void ksmbd_scavenger_dispose_dh(struct ksmbd_file *fp)
|
||||
{
|
||||
while (!list_empty(head)) {
|
||||
struct ksmbd_file *fp;
|
||||
/*
|
||||
* Durable-preserved fp can remain linked on f_ci->m_fp_list for
|
||||
* share-mode checks. Unlink it before final close; fp->node is not
|
||||
* available as a scavenger-private list node because re-adding it to
|
||||
* another list corrupts m_fp_list.
|
||||
*/
|
||||
down_write(&fp->f_ci->m_lock);
|
||||
list_del_init(&fp->node);
|
||||
up_write(&fp->f_ci->m_lock);
|
||||
|
||||
fp = list_first_entry(head, struct ksmbd_file, node);
|
||||
list_del_init(&fp->node);
|
||||
/*
|
||||
* Drop both the durable lifetime reference and the transient reference
|
||||
* taken by the scavenger under global_ft.lock. If a concurrent
|
||||
* ksmbd_lookup_fd_inode() (or any other m_fp_list walker) snatched fp
|
||||
* before the unlink above, that holder owns the final close via
|
||||
* ksmbd_fd_put() -> __ksmbd_close_fd(). Otherwise the scavenger is
|
||||
* the last putter and finalises fp here.
|
||||
*/
|
||||
if (atomic_sub_and_test(2, &fp->refcount))
|
||||
__ksmbd_close_fd(NULL, fp);
|
||||
}
|
||||
}
|
||||
|
||||
static int ksmbd_durable_scavenger(void *dummy)
|
||||
{
|
||||
struct ksmbd_file *fp = NULL;
|
||||
struct ksmbd_file *expired_fp;
|
||||
unsigned int id;
|
||||
unsigned int min_timeout = 1;
|
||||
bool found_fp_timeout;
|
||||
LIST_HEAD(scavenger_list);
|
||||
unsigned long remaining_jiffies;
|
||||
|
||||
__module_get(THIS_MODULE);
|
||||
|
|
@ -908,8 +1095,6 @@ static int ksmbd_durable_scavenger(void *dummy)
|
|||
if (try_to_freeze())
|
||||
continue;
|
||||
|
||||
found_fp_timeout = false;
|
||||
|
||||
remaining_jiffies = wait_event_timeout(dh_wq,
|
||||
ksmbd_durable_scavenger_alive() == false,
|
||||
__msecs_to_jiffies(min_timeout));
|
||||
|
|
@ -918,23 +1103,39 @@ static int ksmbd_durable_scavenger(void *dummy)
|
|||
else
|
||||
min_timeout = DURABLE_HANDLE_MAX_TIMEOUT;
|
||||
|
||||
write_lock(&global_ft.lock);
|
||||
idr_for_each_entry(global_ft.idr, fp, id) {
|
||||
if (!fp->durable_timeout)
|
||||
continue;
|
||||
do {
|
||||
expired_fp = NULL;
|
||||
found_fp_timeout = false;
|
||||
|
||||
if (atomic_read(&fp->refcount) > 1 ||
|
||||
fp->conn)
|
||||
continue;
|
||||
|
||||
found_fp_timeout = true;
|
||||
if (fp->durable_scavenger_timeout <=
|
||||
jiffies_to_msecs(jiffies)) {
|
||||
__ksmbd_remove_durable_fd(fp);
|
||||
list_add(&fp->node, &scavenger_list);
|
||||
} else {
|
||||
write_lock(&global_ft.lock);
|
||||
idr_for_each_entry(global_ft.idr, fp, id) {
|
||||
unsigned long durable_timeout;
|
||||
|
||||
if (!fp->durable_timeout)
|
||||
continue;
|
||||
|
||||
if (atomic_read(&fp->refcount) > 1 ||
|
||||
fp->conn)
|
||||
continue;
|
||||
|
||||
found_fp_timeout = true;
|
||||
if (fp->durable_scavenger_timeout <=
|
||||
jiffies_to_msecs(jiffies)) {
|
||||
__ksmbd_remove_durable_fd(fp);
|
||||
/*
|
||||
* Take a transient reference so fp
|
||||
* cannot be freed by an in-flight
|
||||
* ksmbd_lookup_fd_inode() that found
|
||||
* it through f_ci->m_fp_list while we
|
||||
* drop global_ft.lock and reach the
|
||||
* m_fp_list unlink in
|
||||
* ksmbd_scavenger_dispose_dh().
|
||||
*/
|
||||
atomic_inc(&fp->refcount);
|
||||
expired_fp = fp;
|
||||
break;
|
||||
}
|
||||
|
||||
durable_timeout =
|
||||
fp->durable_scavenger_timeout -
|
||||
jiffies_to_msecs(jiffies);
|
||||
|
|
@ -942,10 +1143,11 @@ static int ksmbd_durable_scavenger(void *dummy)
|
|||
if (min_timeout > durable_timeout)
|
||||
min_timeout = durable_timeout;
|
||||
}
|
||||
}
|
||||
write_unlock(&global_ft.lock);
|
||||
write_unlock(&global_ft.lock);
|
||||
|
||||
ksmbd_scavenger_dispose_dh(&scavenger_list);
|
||||
if (expired_fp)
|
||||
ksmbd_scavenger_dispose_dh(expired_fp);
|
||||
} while (expired_fp);
|
||||
|
||||
if (found_fp_timeout == false)
|
||||
break;
|
||||
|
|
@ -1062,25 +1264,35 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon,
|
|||
if (!is_reconnectable(fp))
|
||||
return false;
|
||||
|
||||
if (fp->f_state != FP_INITED)
|
||||
return false;
|
||||
|
||||
if (WARN_ON_ONCE(!fp->conn))
|
||||
return false;
|
||||
|
||||
if (ksmbd_vfs_copy_durable_owner(fp, user))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* fp owns a strong reference on fp->conn (taken in ksmbd_open_fd()
|
||||
* / ksmbd_reopen_durable_fd()), so conn stays valid for the whole
|
||||
* body of this function regardless of any op->conn puts below.
|
||||
*/
|
||||
conn = fp->conn;
|
||||
ci = fp->f_ci;
|
||||
down_write(&ci->m_lock);
|
||||
list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) {
|
||||
if (op->conn != conn)
|
||||
continue;
|
||||
if (op->conn && atomic_dec_and_test(&op->conn->refcnt))
|
||||
kfree(op->conn);
|
||||
ksmbd_conn_put(op->conn);
|
||||
op->conn = NULL;
|
||||
}
|
||||
up_write(&ci->m_lock);
|
||||
|
||||
list_for_each_entry_safe(smb_lock, tmp_lock, &fp->lock_list, flist) {
|
||||
spin_lock(&fp->conn->llist_lock);
|
||||
spin_lock(&conn->llist_lock);
|
||||
list_del_init(&smb_lock->clist);
|
||||
spin_unlock(&fp->conn->llist_lock);
|
||||
spin_unlock(&conn->llist_lock);
|
||||
}
|
||||
|
||||
fp->conn = NULL;
|
||||
|
|
@ -1091,6 +1303,8 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon,
|
|||
fp->durable_scavenger_timeout =
|
||||
jiffies_to_msecs(jiffies) + fp->durable_timeout;
|
||||
|
||||
/* Drop fp's own reference on conn. */
|
||||
ksmbd_conn_put(conn);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1098,7 +1312,8 @@ void ksmbd_close_tree_conn_fds(struct ksmbd_work *work)
|
|||
{
|
||||
int num = __close_file_table_ids(work->sess,
|
||||
work->tcon,
|
||||
tree_conn_fd_check);
|
||||
tree_conn_fd_check,
|
||||
false);
|
||||
|
||||
atomic_sub(num, &work->conn->stats.open_files_count);
|
||||
}
|
||||
|
|
@ -1107,7 +1322,8 @@ void ksmbd_close_session_fds(struct ksmbd_work *work)
|
|||
{
|
||||
int num = __close_file_table_ids(work->sess,
|
||||
work->tcon,
|
||||
session_fd_check);
|
||||
session_fd_check,
|
||||
true);
|
||||
|
||||
atomic_sub(num, &work->conn->stats.open_files_count);
|
||||
}
|
||||
|
|
@ -1178,15 +1394,27 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
|
|||
|
||||
old_f_state = fp->f_state;
|
||||
fp->f_state = FP_NEW;
|
||||
|
||||
/*
|
||||
* Initialize fp's connection binding before publishing fp into the
|
||||
* session's file table. If __open_id() is ordered first, a
|
||||
* concurrent teardown that iterates the table can observe a valid
|
||||
* volatile_id with fp->conn == NULL and preserve a
|
||||
* partially-initialized fp. fp owns a strong reference on the new
|
||||
* conn (see ksmbd_open_fd()); undo it on __open_id() failure.
|
||||
*/
|
||||
fp->conn = ksmbd_conn_get(conn);
|
||||
fp->tcon = work->tcon;
|
||||
|
||||
__open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID);
|
||||
if (!has_file_id(fp->volatile_id)) {
|
||||
fp->conn = NULL;
|
||||
fp->tcon = NULL;
|
||||
ksmbd_conn_put(conn);
|
||||
fp->f_state = old_f_state;
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
fp->conn = conn;
|
||||
fp->tcon = work->tcon;
|
||||
|
||||
list_for_each_entry(smb_lock, &fp->lock_list, flist) {
|
||||
spin_lock(&conn->llist_lock);
|
||||
list_add_tail(&smb_lock->clist, &conn->lock_list);
|
||||
|
|
@ -1198,8 +1426,7 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
|
|||
list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) {
|
||||
if (op->conn)
|
||||
continue;
|
||||
op->conn = fp->conn;
|
||||
atomic_inc(&op->conn->refcnt);
|
||||
op->conn = ksmbd_conn_get(fp->conn);
|
||||
}
|
||||
up_write(&ci->m_lock);
|
||||
|
||||
|
|
@ -1228,7 +1455,7 @@ void ksmbd_destroy_file_table(struct ksmbd_session *sess)
|
|||
if (!ft->idr)
|
||||
return;
|
||||
|
||||
__close_file_table_ids(sess, NULL, session_fd_check);
|
||||
__close_file_table_ids(sess, NULL, session_fd_check, true);
|
||||
idr_destroy(ft->idr);
|
||||
kfree(ft->idr);
|
||||
ft->idr = NULL;
|
||||
|
|
|
|||
|
|
@ -172,8 +172,8 @@ int ksmbd_close_inode_fds(struct ksmbd_work *work, struct inode *inode);
|
|||
int ksmbd_init_global_file_table(void);
|
||||
void ksmbd_free_global_file_table(void);
|
||||
void ksmbd_set_fd_limit(unsigned long limit);
|
||||
void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
|
||||
unsigned int state);
|
||||
int ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
|
||||
unsigned int state);
|
||||
bool ksmbd_vfs_compare_durable_owner(struct ksmbd_file *fp,
|
||||
struct ksmbd_user *user);
|
||||
|
||||
|
|
|
|||
|
|
@ -854,4 +854,4 @@ struct smbdirect_socket *smbdirect_socket_accept(struct smbdirect_socket *lsc,
|
|||
|
||||
return nsc;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_accept);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_socket_accept);
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ int smbdirect_connect(struct smbdirect_socket *sc, const struct sockaddr *dst)
|
|||
*/
|
||||
return 0;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_connect);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_connect);
|
||||
|
||||
static int smbdirect_connect_setup_connection(struct smbdirect_socket *sc)
|
||||
{
|
||||
|
|
@ -922,4 +922,4 @@ int smbdirect_connect_sync(struct smbdirect_socket *sc,
|
|||
|
||||
return 0;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_connect_sync);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_connect_sync);
|
||||
|
|
|
|||
|
|
@ -706,7 +706,7 @@ bool smbdirect_connection_is_connected(struct smbdirect_socket *sc)
|
|||
return false;
|
||||
return true;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_connection_is_connected);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_connection_is_connected);
|
||||
|
||||
int smbdirect_connection_wait_for_connected(struct smbdirect_socket *sc)
|
||||
{
|
||||
|
|
@ -779,7 +779,7 @@ int smbdirect_connection_wait_for_connected(struct smbdirect_socket *sc)
|
|||
|
||||
return 0;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_connection_wait_for_connected);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_connection_wait_for_connected);
|
||||
|
||||
void smbdirect_connection_idle_timer_work(struct work_struct *work)
|
||||
{
|
||||
|
|
@ -958,7 +958,7 @@ int smbdirect_connection_send_batch_flush(struct smbdirect_socket *sc,
|
|||
|
||||
return ret;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_connection_send_batch_flush);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_connection_send_batch_flush);
|
||||
|
||||
struct smbdirect_send_batch *
|
||||
smbdirect_init_send_batch_storage(struct smbdirect_send_batch_storage *storage,
|
||||
|
|
@ -976,7 +976,7 @@ smbdirect_init_send_batch_storage(struct smbdirect_send_batch_storage *storage,
|
|||
|
||||
return batch;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_init_send_batch_storage);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_init_send_batch_storage);
|
||||
|
||||
static int smbdirect_connection_wait_for_send_bcredit(struct smbdirect_socket *sc,
|
||||
struct smbdirect_send_batch *batch)
|
||||
|
|
@ -1263,7 +1263,7 @@ int smbdirect_connection_send_single_iter(struct smbdirect_socket *sc,
|
|||
bcredit_failed:
|
||||
return ret;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_connection_send_single_iter);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_connection_send_single_iter);
|
||||
|
||||
int smbdirect_connection_send_wait_zero_pending(struct smbdirect_socket *sc)
|
||||
{
|
||||
|
|
@ -1288,7 +1288,7 @@ int smbdirect_connection_send_wait_zero_pending(struct smbdirect_socket *sc)
|
|||
|
||||
return 0;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_connection_send_wait_zero_pending);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_connection_send_wait_zero_pending);
|
||||
|
||||
int smbdirect_connection_send_iter(struct smbdirect_socket *sc,
|
||||
struct iov_iter *iter,
|
||||
|
|
@ -1373,7 +1373,7 @@ int smbdirect_connection_send_iter(struct smbdirect_socket *sc,
|
|||
|
||||
return total_count;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_connection_send_iter);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_connection_send_iter);
|
||||
|
||||
static void smbdirect_connection_send_io_done(struct ib_cq *cq, struct ib_wc *wc)
|
||||
{
|
||||
|
|
@ -1937,7 +1937,7 @@ int smbdirect_connection_recvmsg(struct smbdirect_socket *sc,
|
|||
|
||||
goto again;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_connection_recvmsg);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_connection_recvmsg);
|
||||
|
||||
static bool smbdirect_map_sges_single_page(struct smbdirect_map_sges *state,
|
||||
struct page *page, size_t off, size_t len)
|
||||
|
|
|
|||
|
|
@ -85,4 +85,4 @@ void smbdirect_connection_legacy_debug_proc_show(struct smbdirect_socket *sc,
|
|||
atomic_read(&sc->mr_io.ready.count),
|
||||
atomic_read(&sc->mr_io.used.count));
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_connection_legacy_debug_proc_show);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_connection_legacy_debug_proc_show);
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ u8 smbdirect_netdev_rdma_capable_node_type(struct net_device *netdev)
|
|||
|
||||
return RDMA_NODE_UNSPECIFIED;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_netdev_rdma_capable_node_type);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_netdev_rdma_capable_node_type);
|
||||
|
||||
__init int smbdirect_devices_init(void)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@
|
|||
#ifndef __FS_SMB_COMMON_SMBDIRECT_INTERNAL_H__
|
||||
#define __FS_SMB_COMMON_SMBDIRECT_INTERNAL_H__
|
||||
|
||||
#define DEFAULT_SYMBOL_NAMESPACE "SMBDIRECT"
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include "smbdirect.h"
|
||||
#include <linux/smbdirect.h>
|
||||
#include "pdu.h"
|
||||
#include "public.h"
|
||||
|
||||
#include <linux/mutex.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ int smbdirect_socket_listen(struct smbdirect_socket *sc, int backlog)
|
|||
*/
|
||||
return 0;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_listen);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_socket_listen);
|
||||
|
||||
static int smbdirect_new_rdma_event_handler(struct rdma_cm_id *new_id,
|
||||
struct rdma_cm_event *event)
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ smbdirect_connection_register_mr_io(struct smbdirect_socket *sc,
|
|||
{
|
||||
const struct smbdirect_socket_parameters *sp = &sc->parameters;
|
||||
struct smbdirect_mr_io *mr;
|
||||
int ret, num_pages;
|
||||
int ret, num_pages, num_mapped;
|
||||
struct ib_reg_wr *reg_wr;
|
||||
|
||||
num_pages = iov_iter_npages(iter, sp->max_frmr_depth + 1);
|
||||
|
|
@ -300,19 +300,22 @@ smbdirect_connection_register_mr_io(struct smbdirect_socket *sc,
|
|||
num_pages, iov_iter_count(iter), sp->max_frmr_depth);
|
||||
smbdirect_iter_to_sgt(iter, &mr->sgt, sp->max_frmr_depth);
|
||||
|
||||
ret = ib_dma_map_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir);
|
||||
if (!ret) {
|
||||
num_mapped = ib_dma_map_sg(sc->ib.dev, mr->sgt.sgl, mr->sgt.nents, mr->dir);
|
||||
if (!num_mapped) {
|
||||
smbdirect_log_rdma_mr(sc, SMBDIRECT_LOG_ERR,
|
||||
"ib_dma_map_sg num_pages=%u dir=%x ret=%d (%1pe)\n",
|
||||
num_pages, mr->dir, ret, SMBDIRECT_DEBUG_ERR_PTR(ret));
|
||||
"ib_dma_map_sg num_pages=%u dir=%x num_mapped=%d\n",
|
||||
num_pages, mr->dir, num_mapped);
|
||||
ret = -EIO;
|
||||
goto dma_map_error;
|
||||
}
|
||||
|
||||
ret = ib_map_mr_sg(mr->mr, mr->sgt.sgl, mr->sgt.nents, NULL, PAGE_SIZE);
|
||||
if (ret != mr->sgt.nents) {
|
||||
ret = ib_map_mr_sg(mr->mr, mr->sgt.sgl, num_mapped, NULL, PAGE_SIZE);
|
||||
if (ret != num_mapped) {
|
||||
smbdirect_log_rdma_mr(sc, SMBDIRECT_LOG_ERR,
|
||||
"ib_map_mr_sg failed ret = %d nents = %u\n",
|
||||
ret, mr->sgt.nents);
|
||||
"ib_map_mr_sg failed ret = %d num_mapped = %u\n",
|
||||
ret, num_mapped);
|
||||
if (ret >= 0)
|
||||
ret = -EIO;
|
||||
goto map_mr_error;
|
||||
}
|
||||
|
||||
|
|
@ -380,7 +383,7 @@ smbdirect_connection_register_mr_io(struct smbdirect_socket *sc,
|
|||
mutex_unlock(&mr->mutex);
|
||||
return NULL;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_connection_register_mr_io);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_connection_register_mr_io);
|
||||
|
||||
void smbdirect_mr_io_fill_buffer_descriptor(struct smbdirect_mr_io *mr,
|
||||
struct smbdirect_buffer_descriptor_v1 *v1)
|
||||
|
|
@ -397,7 +400,7 @@ void smbdirect_mr_io_fill_buffer_descriptor(struct smbdirect_mr_io *mr,
|
|||
}
|
||||
mutex_unlock(&mr->mutex);
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_mr_io_fill_buffer_descriptor);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_mr_io_fill_buffer_descriptor);
|
||||
|
||||
/*
|
||||
* Deregister a MR after I/O is done
|
||||
|
|
@ -490,4 +493,4 @@ void smbdirect_connection_deregister_mr_io(struct smbdirect_mr_io *mr)
|
|||
if (!kref_put(&mr->kref, smbdirect_mr_io_free_locked))
|
||||
mutex_unlock(&mr->mutex);
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_connection_deregister_mr_io);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_connection_deregister_mr_io);
|
||||
|
|
|
|||
|
|
@ -252,4 +252,4 @@ int smbdirect_connection_rdma_xmit(struct smbdirect_socket *sc,
|
|||
kfree(msg);
|
||||
goto out;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_connection_rdma_xmit);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_connection_rdma_xmit);
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2025 Stefan Metzmacher
|
||||
*/
|
||||
|
||||
#ifndef __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_H__
|
||||
#define __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* SMB-DIRECT buffer descriptor V1 structure [MS-SMBD] 2.2.3.1 */
|
||||
struct smbdirect_buffer_descriptor_v1 {
|
||||
__le64 offset;
|
||||
__le32 token;
|
||||
__le32 length;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Connection parameters mostly from [MS-SMBD] 3.1.1.1
|
||||
*
|
||||
* These are setup and negotiated at the beginning of a
|
||||
* connection and remain constant unless explicitly changed.
|
||||
*
|
||||
* Some values are important for the upper layer.
|
||||
*/
|
||||
struct smbdirect_socket_parameters {
|
||||
__u64 flags;
|
||||
#define SMBDIRECT_FLAG_PORT_RANGE_ONLY_IB ((__u64)0x1)
|
||||
#define SMBDIRECT_FLAG_PORT_RANGE_ONLY_IW ((__u64)0x2)
|
||||
__u32 resolve_addr_timeout_msec;
|
||||
__u32 resolve_route_timeout_msec;
|
||||
__u32 rdma_connect_timeout_msec;
|
||||
__u32 negotiate_timeout_msec;
|
||||
__u16 initiator_depth; /* limited to U8_MAX */
|
||||
__u16 responder_resources; /* limited to U8_MAX */
|
||||
__u16 recv_credit_max;
|
||||
__u16 send_credit_target;
|
||||
__u32 max_send_size;
|
||||
__u32 max_fragmented_send_size;
|
||||
__u32 max_recv_size;
|
||||
__u32 max_fragmented_recv_size;
|
||||
__u32 max_read_write_size;
|
||||
__u32 max_frmr_depth;
|
||||
__u32 keepalive_interval_msec;
|
||||
__u32 keepalive_timeout_msec;
|
||||
} __packed;
|
||||
|
||||
#define SMBDIRECT_FLAG_PORT_RANGE_MASK ( \
|
||||
SMBDIRECT_FLAG_PORT_RANGE_ONLY_IB | \
|
||||
SMBDIRECT_FLAG_PORT_RANGE_ONLY_IW)
|
||||
|
||||
#endif /* __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_H__ */
|
||||
|
|
@ -20,7 +20,7 @@ bool smbdirect_frwr_is_supported(const struct ib_device_attr *attrs)
|
|||
return false;
|
||||
return true;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_frwr_is_supported);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_frwr_is_supported);
|
||||
|
||||
static void smbdirect_socket_cleanup_work(struct work_struct *work);
|
||||
|
||||
|
|
@ -107,7 +107,7 @@ int smbdirect_socket_create_kern(struct net *net, struct smbdirect_socket **_sc)
|
|||
alloc_failed:
|
||||
return ret;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_create_kern);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_socket_create_kern);
|
||||
|
||||
int smbdirect_socket_init_accepting(struct rdma_cm_id *id, struct smbdirect_socket *sc)
|
||||
{
|
||||
|
|
@ -148,7 +148,7 @@ int smbdirect_socket_create_accepting(struct rdma_cm_id *id, struct smbdirect_so
|
|||
alloc_failed:
|
||||
return ret;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_create_accepting);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_socket_create_accepting);
|
||||
|
||||
int smbdirect_socket_set_initial_parameters(struct smbdirect_socket *sc,
|
||||
const struct smbdirect_socket_parameters *sp)
|
||||
|
|
@ -189,14 +189,14 @@ int smbdirect_socket_set_initial_parameters(struct smbdirect_socket *sc,
|
|||
|
||||
return 0;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_set_initial_parameters);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_socket_set_initial_parameters);
|
||||
|
||||
const struct smbdirect_socket_parameters *
|
||||
smbdirect_socket_get_current_parameters(struct smbdirect_socket *sc)
|
||||
{
|
||||
return &sc->parameters;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_get_current_parameters);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_socket_get_current_parameters);
|
||||
|
||||
int smbdirect_socket_set_kernel_settings(struct smbdirect_socket *sc,
|
||||
enum ib_poll_context poll_ctx,
|
||||
|
|
@ -220,7 +220,7 @@ int smbdirect_socket_set_kernel_settings(struct smbdirect_socket *sc,
|
|||
|
||||
return 0;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_set_kernel_settings);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_socket_set_kernel_settings);
|
||||
|
||||
void smbdirect_socket_set_logging(struct smbdirect_socket *sc,
|
||||
void *private_ptr,
|
||||
|
|
@ -240,7 +240,7 @@ void smbdirect_socket_set_logging(struct smbdirect_socket *sc,
|
|||
sc->logging.needed = needed;
|
||||
sc->logging.vaprintf = vaprintf;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_set_logging);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_socket_set_logging);
|
||||
|
||||
static void smbdirect_socket_wake_up_all(struct smbdirect_socket *sc)
|
||||
{
|
||||
|
|
@ -663,13 +663,13 @@ int smbdirect_socket_bind(struct smbdirect_socket *sc, struct sockaddr *addr)
|
|||
|
||||
return 0;
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_bind);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_socket_bind);
|
||||
|
||||
void smbdirect_socket_shutdown(struct smbdirect_socket *sc)
|
||||
{
|
||||
smbdirect_socket_schedule_cleanup_lvl(sc, SMBDIRECT_LOG_INFO, -ESHUTDOWN);
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_shutdown);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_socket_shutdown);
|
||||
|
||||
static void smbdirect_socket_release_disconnect(struct kref *kref)
|
||||
{
|
||||
|
|
@ -712,7 +712,7 @@ void smbdirect_socket_release(struct smbdirect_socket *sc)
|
|||
*/
|
||||
kref_put(&sc->refs.destroy, smbdirect_socket_release_destroy);
|
||||
}
|
||||
__SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_release);
|
||||
EXPORT_SYMBOL_GPL(smbdirect_socket_release);
|
||||
|
||||
int smbdirect_socket_wait_for_credits(struct smbdirect_socket *sc,
|
||||
enum smbdirect_socket_status expected_status,
|
||||
|
|
|
|||
|
|
@ -3,18 +3,56 @@
|
|||
* Copyright (C) 2025, Stefan Metzmacher
|
||||
*/
|
||||
|
||||
#ifndef __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_PUBLIC_H__
|
||||
#define __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_PUBLIC_H__
|
||||
#ifndef __LINUX_SMBDIRECT_H__
|
||||
#define __LINUX_SMBDIRECT_H__
|
||||
|
||||
struct smbdirect_buffer_descriptor_v1;
|
||||
struct smbdirect_socket_parameters;
|
||||
#include <linux/types.h>
|
||||
|
||||
/* SMB-DIRECT buffer descriptor V1 structure [MS-SMBD] 2.2.3.1 */
|
||||
struct smbdirect_buffer_descriptor_v1 {
|
||||
__le64 offset;
|
||||
__le32 token;
|
||||
__le32 length;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Connection parameters mostly from [MS-SMBD] 3.1.1.1
|
||||
*
|
||||
* These are setup and negotiated at the beginning of a
|
||||
* connection and remain constant unless explicitly changed.
|
||||
*
|
||||
* Some values are important for the upper layer.
|
||||
*/
|
||||
struct smbdirect_socket_parameters {
|
||||
__u64 flags;
|
||||
#define SMBDIRECT_FLAG_PORT_RANGE_ONLY_IB ((__u64)0x1)
|
||||
#define SMBDIRECT_FLAG_PORT_RANGE_ONLY_IW ((__u64)0x2)
|
||||
__u32 resolve_addr_timeout_msec;
|
||||
__u32 resolve_route_timeout_msec;
|
||||
__u32 rdma_connect_timeout_msec;
|
||||
__u32 negotiate_timeout_msec;
|
||||
__u16 initiator_depth; /* limited to U8_MAX */
|
||||
__u16 responder_resources; /* limited to U8_MAX */
|
||||
__u16 recv_credit_max;
|
||||
__u16 send_credit_target;
|
||||
__u32 max_send_size;
|
||||
__u32 max_fragmented_send_size;
|
||||
__u32 max_recv_size;
|
||||
__u32 max_fragmented_recv_size;
|
||||
__u32 max_read_write_size;
|
||||
__u32 max_frmr_depth;
|
||||
__u32 keepalive_interval_msec;
|
||||
__u32 keepalive_timeout_msec;
|
||||
} __packed;
|
||||
|
||||
#define SMBDIRECT_FLAG_PORT_RANGE_MASK ( \
|
||||
SMBDIRECT_FLAG_PORT_RANGE_ONLY_IB | \
|
||||
SMBDIRECT_FLAG_PORT_RANGE_ONLY_IW)
|
||||
|
||||
struct smbdirect_socket;
|
||||
struct smbdirect_send_batch;
|
||||
struct smbdirect_mr_io;
|
||||
|
||||
#define __SMBDIRECT_EXPORT_SYMBOL__(__sym) EXPORT_SYMBOL_FOR_MODULES(__sym, "cifs,ksmbd")
|
||||
|
||||
#include <rdma/rw.h>
|
||||
|
||||
u8 smbdirect_netdev_rdma_capable_node_type(struct net_device *netdev);
|
||||
|
|
@ -145,4 +183,4 @@ void smbdirect_connection_legacy_debug_proc_show(struct smbdirect_socket *sc,
|
|||
unsigned int rdma_readwrite_threshold,
|
||||
struct seq_file *m);
|
||||
|
||||
#endif /* __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_PUBLIC_H__ */
|
||||
#endif /* __LINUX_SMBDIRECT_H__ */
|
||||
Loading…
Reference in New Issue
Block a user