mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
four ksmbd server fixes
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmadTDUACgkQiiy9cAdy T1Hzugv/UTw9ERSzZNtYOOuM+5EtvYxqxGLiGaaVbQaGzDoNW5hgfIoWwvllaPHP 4lmHH2Nsz0B2Cg0fSKBbTWZ7pxQ4QUuCuwhgcKVZyYnuikf1qSMPgOBb5T2JkuTG qu0GX+dFdoak6RiLZ8vSfUsQ1IzvuyLcXrPDdvwfE/eV3NKGLM8CevkpULSNGKwz P2vpOu9oN0fhrHP8rXWRrNCLma4056TYFYDRpRqWxiTJr12JvXmOyjlovmEBx12K H1plz3ltLQcFj5w0dnYSAY8jijEICITeNBxD0aP6pQ6Ah2C1pUEES2Lr2JG/OYt0 O4nkUGpbWShi70rCTnWbXOWQU7mbmtSqhxob0Z6wUdrHRZUUoWLr3WQaIHJHfOmY 5UgiHoiiV98wtBkrja/Ex/O9GdOKpdEVlM9M3wJR9D6YAeZSYKB2rLweGs6QtgrU HRFCNZmJM0zPpsT2SUQDanOiODShAqoGcPQgBuEAVhs4TqQz2rTlPTrodhXNI5WF RJKin/uq =CggG -----END PGP SIGNATURE----- Merge tag '6.11-rc-smb3-server-fixes' of git://git.samba.org/ksmbd Pull smb server fixes from Steve French: - two durable handle improvements - two small cleanup patches * tag '6.11-rc-smb3-server-fixes' of git://git.samba.org/ksmbd: ksmbd: add durable scavenger timer ksmbd: avoid reclaiming expired durable opens by the client ksmbd: Constify struct ksmbd_transport_ops ksmbd: remove duplicate SMB2 Oplock levels definitions
This commit is contained in:
commit
933069701c
@ -133,8 +133,8 @@ struct ksmbd_transport_ops {
|
||||
};
|
||||
|
||||
struct ksmbd_transport {
|
||||
struct ksmbd_conn *conn;
|
||||
struct ksmbd_transport_ops *ops;
|
||||
struct ksmbd_conn *conn;
|
||||
const struct ksmbd_transport_ops *ops;
|
||||
};
|
||||
|
||||
#define KSMBD_TCP_RECV_TIMEOUT (7 * HZ)
|
||||
|
@ -149,6 +149,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
|
||||
|
||||
ksmbd_tree_conn_session_logoff(sess);
|
||||
ksmbd_destroy_file_table(&sess->file_table);
|
||||
ksmbd_launch_ksmbd_durable_scavenger();
|
||||
ksmbd_session_rpc_clear_list(sess);
|
||||
free_channel_list(sess);
|
||||
kfree(sess->Preauth_HashValue);
|
||||
@ -326,6 +327,7 @@ void destroy_previous_session(struct ksmbd_conn *conn,
|
||||
|
||||
ksmbd_destroy_file_table(&prev_sess->file_table);
|
||||
prev_sess->state = SMB2_SESSION_EXPIRED;
|
||||
ksmbd_launch_ksmbd_durable_scavenger();
|
||||
out:
|
||||
up_write(&conn->session_lock);
|
||||
up_write(&sessions_table_lock);
|
||||
|
@ -11,13 +11,6 @@
|
||||
|
||||
#define OPLOCK_WAIT_TIME (35 * HZ)
|
||||
|
||||
/* SMB2 Oplock levels */
|
||||
#define SMB2_OPLOCK_LEVEL_NONE 0x00
|
||||
#define SMB2_OPLOCK_LEVEL_II 0x01
|
||||
#define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08
|
||||
#define SMB2_OPLOCK_LEVEL_BATCH 0x09
|
||||
#define SMB2_OPLOCK_LEVEL_LEASE 0xFF
|
||||
|
||||
/* Oplock states */
|
||||
#define OPLOCK_STATE_NONE 0x00
|
||||
#define OPLOCK_ACK_WAIT 0x01
|
||||
|
@ -377,6 +377,7 @@ static void server_ctrl_handle_reset(struct server_ctrl_struct *ctrl)
|
||||
{
|
||||
ksmbd_ipc_soft_reset();
|
||||
ksmbd_conn_transport_destroy();
|
||||
ksmbd_stop_durable_scavenger();
|
||||
server_conf_free();
|
||||
server_conf_init();
|
||||
WRITE_ONCE(server_conf.state, SERVER_STATE_STARTING_UP);
|
||||
|
@ -44,6 +44,7 @@ struct ksmbd_server_config {
|
||||
unsigned int max_connections;
|
||||
|
||||
char *conf[SERVER_CONF_WORK_GROUP + 1];
|
||||
struct task_struct *dh_task;
|
||||
};
|
||||
|
||||
extern struct ksmbd_server_config server_conf;
|
||||
|
@ -3526,7 +3526,7 @@ int smb2_open(struct ksmbd_work *work)
|
||||
SMB2_CREATE_GUID_SIZE);
|
||||
if (dh_info.timeout)
|
||||
fp->durable_timeout = min(dh_info.timeout,
|
||||
300000);
|
||||
DURABLE_HANDLE_MAX_TIMEOUT);
|
||||
else
|
||||
fp->durable_timeout = 60;
|
||||
}
|
||||
|
@ -72,6 +72,8 @@ struct create_durable_req_v2 {
|
||||
__u8 CreateGuid[16];
|
||||
} __packed;
|
||||
|
||||
#define DURABLE_HANDLE_MAX_TIMEOUT 300000
|
||||
|
||||
struct create_durable_reconn_req {
|
||||
struct create_context_hdr ccontext;
|
||||
__u8 Name[8];
|
||||
|
@ -164,7 +164,7 @@ enum {
|
||||
SMB_DIRECT_MSG_DATA_TRANSFER
|
||||
};
|
||||
|
||||
static struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops;
|
||||
static const struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops;
|
||||
|
||||
struct smb_direct_send_ctx {
|
||||
struct list_head msg_list;
|
||||
@ -2292,7 +2292,7 @@ out:
|
||||
return rdma_capable;
|
||||
}
|
||||
|
||||
static struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops = {
|
||||
static const struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops = {
|
||||
.prepare = smb_direct_prepare,
|
||||
.disconnect = smb_direct_disconnect,
|
||||
.shutdown = smb_direct_shutdown,
|
||||
|
@ -37,7 +37,7 @@ struct tcp_transport {
|
||||
unsigned int nr_iov;
|
||||
};
|
||||
|
||||
static struct ksmbd_transport_ops ksmbd_tcp_transport_ops;
|
||||
static const struct ksmbd_transport_ops ksmbd_tcp_transport_ops;
|
||||
|
||||
static void tcp_stop_kthread(struct task_struct *kthread);
|
||||
static struct interface *alloc_iface(char *ifname);
|
||||
@ -649,7 +649,7 @@ int ksmbd_tcp_set_interfaces(char *ifc_list, int ifc_list_sz)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ksmbd_transport_ops ksmbd_tcp_transport_ops = {
|
||||
static const struct ksmbd_transport_ops ksmbd_tcp_transport_ops = {
|
||||
.read = ksmbd_tcp_read,
|
||||
.writev = ksmbd_tcp_writev,
|
||||
.disconnect = ksmbd_tcp_disconnect,
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include <linux/filelock.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/freezer.h>
|
||||
|
||||
#include "glob.h"
|
||||
#include "vfs_cache.h"
|
||||
@ -17,6 +19,7 @@
|
||||
#include "mgmt/tree_connect.h"
|
||||
#include "mgmt/user_session.h"
|
||||
#include "smb_common.h"
|
||||
#include "server.h"
|
||||
|
||||
#define S_DEL_PENDING 1
|
||||
#define S_DEL_ON_CLS 2
|
||||
@ -31,6 +34,10 @@ static struct ksmbd_file_table global_ft;
|
||||
static atomic_long_t fd_limit;
|
||||
static struct kmem_cache *filp_cache;
|
||||
|
||||
static bool durable_scavenger_running;
|
||||
static DEFINE_MUTEX(durable_scavenger_lock);
|
||||
static wait_queue_head_t dh_wq;
|
||||
|
||||
void ksmbd_set_fd_limit(unsigned long limit)
|
||||
{
|
||||
limit = min(limit, get_max_files());
|
||||
@ -280,9 +287,16 @@ static void __ksmbd_remove_durable_fd(struct ksmbd_file *fp)
|
||||
if (!has_file_id(fp->persistent_id))
|
||||
return;
|
||||
|
||||
write_lock(&global_ft.lock);
|
||||
idr_remove(global_ft.idr, fp->persistent_id);
|
||||
}
|
||||
|
||||
static void ksmbd_remove_durable_fd(struct ksmbd_file *fp)
|
||||
{
|
||||
write_lock(&global_ft.lock);
|
||||
__ksmbd_remove_durable_fd(fp);
|
||||
write_unlock(&global_ft.lock);
|
||||
if (waitqueue_active(&dh_wq))
|
||||
wake_up(&dh_wq);
|
||||
}
|
||||
|
||||
static void __ksmbd_remove_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
|
||||
@ -305,7 +319,7 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
|
||||
struct ksmbd_lock *smb_lock, *tmp_lock;
|
||||
|
||||
fd_limit_close();
|
||||
__ksmbd_remove_durable_fd(fp);
|
||||
ksmbd_remove_durable_fd(fp);
|
||||
if (ft)
|
||||
__ksmbd_remove_fd(ft, fp);
|
||||
|
||||
@ -477,7 +491,10 @@ struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id)
|
||||
struct ksmbd_file *fp;
|
||||
|
||||
fp = __ksmbd_lookup_fd(&global_ft, id);
|
||||
if (fp && fp->conn) {
|
||||
if (fp && (fp->conn ||
|
||||
(fp->durable_scavenger_timeout &&
|
||||
(fp->durable_scavenger_timeout <
|
||||
jiffies_to_msecs(jiffies))))) {
|
||||
ksmbd_put_durable_fd(fp);
|
||||
fp = NULL;
|
||||
}
|
||||
@ -694,6 +711,142 @@ static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon,
|
||||
return fp->tcon != tcon;
|
||||
}
|
||||
|
||||
static bool ksmbd_durable_scavenger_alive(void)
|
||||
{
|
||||
mutex_lock(&durable_scavenger_lock);
|
||||
if (!durable_scavenger_running) {
|
||||
mutex_unlock(&durable_scavenger_lock);
|
||||
return false;
|
||||
}
|
||||
mutex_unlock(&durable_scavenger_lock);
|
||||
|
||||
if (kthread_should_stop())
|
||||
return false;
|
||||
|
||||
if (idr_is_empty(global_ft.idr))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ksmbd_scavenger_dispose_dh(struct list_head *head)
|
||||
{
|
||||
while (!list_empty(head)) {
|
||||
struct ksmbd_file *fp;
|
||||
|
||||
fp = list_first_entry(head, struct ksmbd_file, node);
|
||||
list_del_init(&fp->node);
|
||||
__ksmbd_close_fd(NULL, fp);
|
||||
}
|
||||
}
|
||||
|
||||
static int ksmbd_durable_scavenger(void *dummy)
|
||||
{
|
||||
struct ksmbd_file *fp = NULL;
|
||||
unsigned int id;
|
||||
unsigned int min_timeout = 1;
|
||||
bool found_fp_timeout;
|
||||
LIST_HEAD(scavenger_list);
|
||||
unsigned long remaining_jiffies;
|
||||
|
||||
__module_get(THIS_MODULE);
|
||||
|
||||
set_freezable();
|
||||
while (ksmbd_durable_scavenger_alive()) {
|
||||
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));
|
||||
if (remaining_jiffies)
|
||||
min_timeout = jiffies_to_msecs(remaining_jiffies);
|
||||
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;
|
||||
|
||||
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 {
|
||||
unsigned long durable_timeout;
|
||||
|
||||
durable_timeout =
|
||||
fp->durable_scavenger_timeout -
|
||||
jiffies_to_msecs(jiffies);
|
||||
|
||||
if (min_timeout > durable_timeout)
|
||||
min_timeout = durable_timeout;
|
||||
}
|
||||
}
|
||||
write_unlock(&global_ft.lock);
|
||||
|
||||
ksmbd_scavenger_dispose_dh(&scavenger_list);
|
||||
|
||||
if (found_fp_timeout == false)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_lock(&durable_scavenger_lock);
|
||||
durable_scavenger_running = false;
|
||||
mutex_unlock(&durable_scavenger_lock);
|
||||
|
||||
module_put(THIS_MODULE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ksmbd_launch_ksmbd_durable_scavenger(void)
|
||||
{
|
||||
if (!(server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE))
|
||||
return;
|
||||
|
||||
mutex_lock(&durable_scavenger_lock);
|
||||
if (durable_scavenger_running == true) {
|
||||
mutex_unlock(&durable_scavenger_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
durable_scavenger_running = true;
|
||||
|
||||
server_conf.dh_task = kthread_run(ksmbd_durable_scavenger,
|
||||
(void *)NULL, "ksmbd-durable-scavenger");
|
||||
if (IS_ERR(server_conf.dh_task))
|
||||
pr_err("cannot start conn thread, err : %ld\n",
|
||||
PTR_ERR(server_conf.dh_task));
|
||||
mutex_unlock(&durable_scavenger_lock);
|
||||
}
|
||||
|
||||
void ksmbd_stop_durable_scavenger(void)
|
||||
{
|
||||
if (!(server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE))
|
||||
return;
|
||||
|
||||
mutex_lock(&durable_scavenger_lock);
|
||||
if (!durable_scavenger_running) {
|
||||
mutex_unlock(&durable_scavenger_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
durable_scavenger_running = false;
|
||||
if (waitqueue_active(&dh_wq))
|
||||
wake_up(&dh_wq);
|
||||
mutex_unlock(&durable_scavenger_lock);
|
||||
kthread_stop(server_conf.dh_task);
|
||||
}
|
||||
|
||||
static bool session_fd_check(struct ksmbd_tree_connect *tcon,
|
||||
struct ksmbd_file *fp)
|
||||
{
|
||||
@ -718,6 +871,10 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon,
|
||||
fp->tcon = NULL;
|
||||
fp->volatile_id = KSMBD_NO_FID;
|
||||
|
||||
if (fp->durable_timeout)
|
||||
fp->durable_scavenger_timeout =
|
||||
jiffies_to_msecs(jiffies) + fp->durable_timeout;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -750,11 +907,12 @@ void ksmbd_free_global_file_table(void)
|
||||
unsigned int id;
|
||||
|
||||
idr_for_each_entry(global_ft.idr, fp, id) {
|
||||
__ksmbd_remove_durable_fd(fp);
|
||||
kmem_cache_free(filp_cache, fp);
|
||||
ksmbd_remove_durable_fd(fp);
|
||||
__ksmbd_close_fd(NULL, fp);
|
||||
}
|
||||
|
||||
ksmbd_destroy_file_table(&global_ft);
|
||||
idr_destroy(global_ft.idr);
|
||||
kfree(global_ft.idr);
|
||||
}
|
||||
|
||||
int ksmbd_validate_name_reconnect(struct ksmbd_share_config *share,
|
||||
@ -810,6 +968,7 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
|
||||
}
|
||||
up_write(&ci->m_lock);
|
||||
|
||||
fp->f_state = FP_NEW;
|
||||
__open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID);
|
||||
if (!has_file_id(fp->volatile_id)) {
|
||||
fp->conn = NULL;
|
||||
@ -849,6 +1008,8 @@ int ksmbd_init_file_cache(void)
|
||||
if (!filp_cache)
|
||||
goto out;
|
||||
|
||||
init_waitqueue_head(&dh_wq);
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
|
@ -101,6 +101,7 @@ struct ksmbd_file {
|
||||
struct list_head lock_list;
|
||||
|
||||
int durable_timeout;
|
||||
int durable_scavenger_timeout;
|
||||
|
||||
/* if ls is happening on directory, below is valid*/
|
||||
struct ksmbd_readdir_data readdir_data;
|
||||
@ -152,6 +153,8 @@ struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid);
|
||||
struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry);
|
||||
unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp);
|
||||
struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp);
|
||||
void ksmbd_launch_ksmbd_durable_scavenger(void);
|
||||
void ksmbd_stop_durable_scavenger(void);
|
||||
void ksmbd_close_tree_conn_fds(struct ksmbd_work *work);
|
||||
void ksmbd_close_session_fds(struct ksmbd_work *work);
|
||||
int ksmbd_close_inode_fds(struct ksmbd_work *work, struct inode *inode);
|
||||
|
Loading…
Reference in New Issue
Block a user