Skip to content

Commit d484d62

Browse files
namjaejeonsmfrench
authored andcommitted
ksmbd: add durable scavenger timer
Launch ksmbd-durable-scavenger kernel thread to scan durable fps that have not been reclaimed by a client within the configured time. Signed-off-by: Namjae Jeon <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 520da3c commit d484d62

File tree

7 files changed

+168
-6
lines changed

7 files changed

+168
-6
lines changed

fs/smb/server/mgmt/user_session.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
149149

150150
ksmbd_tree_conn_session_logoff(sess);
151151
ksmbd_destroy_file_table(&sess->file_table);
152+
ksmbd_launch_ksmbd_durable_scavenger();
152153
ksmbd_session_rpc_clear_list(sess);
153154
free_channel_list(sess);
154155
kfree(sess->Preauth_HashValue);
@@ -326,6 +327,7 @@ void destroy_previous_session(struct ksmbd_conn *conn,
326327

327328
ksmbd_destroy_file_table(&prev_sess->file_table);
328329
prev_sess->state = SMB2_SESSION_EXPIRED;
330+
ksmbd_launch_ksmbd_durable_scavenger();
329331
out:
330332
up_write(&conn->session_lock);
331333
up_write(&sessions_table_lock);

fs/smb/server/server.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ static void server_ctrl_handle_reset(struct server_ctrl_struct *ctrl)
377377
{
378378
ksmbd_ipc_soft_reset();
379379
ksmbd_conn_transport_destroy();
380+
ksmbd_stop_durable_scavenger();
380381
server_conf_free();
381382
server_conf_init();
382383
WRITE_ONCE(server_conf.state, SERVER_STATE_STARTING_UP);

fs/smb/server/server.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ struct ksmbd_server_config {
4444
unsigned int max_connections;
4545

4646
char *conf[SERVER_CONF_WORK_GROUP + 1];
47+
struct task_struct *dh_task;
4748
};
4849

4950
extern struct ksmbd_server_config server_conf;

fs/smb/server/smb2pdu.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3526,7 +3526,7 @@ int smb2_open(struct ksmbd_work *work)
35263526
SMB2_CREATE_GUID_SIZE);
35273527
if (dh_info.timeout)
35283528
fp->durable_timeout = min(dh_info.timeout,
3529-
300000);
3529+
DURABLE_HANDLE_MAX_TIMEOUT);
35303530
else
35313531
fp->durable_timeout = 60;
35323532
}

fs/smb/server/smb2pdu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ struct create_durable_req_v2 {
7272
__u8 CreateGuid[16];
7373
} __packed;
7474

75+
#define DURABLE_HANDLE_MAX_TIMEOUT 300000
76+
7577
struct create_durable_reconn_req {
7678
struct create_context_hdr ccontext;
7779
__u8 Name[8];

fs/smb/server/vfs_cache.c

Lines changed: 159 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <linux/filelock.h>
99
#include <linux/slab.h>
1010
#include <linux/vmalloc.h>
11+
#include <linux/kthread.h>
12+
#include <linux/freezer.h>
1113

1214
#include "glob.h"
1315
#include "vfs_cache.h"
@@ -17,6 +19,7 @@
1719
#include "mgmt/tree_connect.h"
1820
#include "mgmt/user_session.h"
1921
#include "smb_common.h"
22+
#include "server.h"
2023

2124
#define S_DEL_PENDING 1
2225
#define S_DEL_ON_CLS 2
@@ -31,6 +34,10 @@ static struct ksmbd_file_table global_ft;
3134
static atomic_long_t fd_limit;
3235
static struct kmem_cache *filp_cache;
3336

37+
static bool durable_scavenger_running;
38+
static DEFINE_MUTEX(durable_scavenger_lock);
39+
static wait_queue_head_t dh_wq;
40+
3441
void ksmbd_set_fd_limit(unsigned long limit)
3542
{
3643
limit = min(limit, get_max_files());
@@ -280,9 +287,16 @@ static void __ksmbd_remove_durable_fd(struct ksmbd_file *fp)
280287
if (!has_file_id(fp->persistent_id))
281288
return;
282289

283-
write_lock(&global_ft.lock);
284290
idr_remove(global_ft.idr, fp->persistent_id);
291+
}
292+
293+
static void ksmbd_remove_durable_fd(struct ksmbd_file *fp)
294+
{
295+
write_lock(&global_ft.lock);
296+
__ksmbd_remove_durable_fd(fp);
285297
write_unlock(&global_ft.lock);
298+
if (waitqueue_active(&dh_wq))
299+
wake_up(&dh_wq);
286300
}
287301

288302
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)
305319
struct ksmbd_lock *smb_lock, *tmp_lock;
306320

307321
fd_limit_close();
308-
__ksmbd_remove_durable_fd(fp);
322+
ksmbd_remove_durable_fd(fp);
309323
if (ft)
310324
__ksmbd_remove_fd(ft, fp);
311325

@@ -697,6 +711,142 @@ static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon,
697711
return fp->tcon != tcon;
698712
}
699713

714+
static bool ksmbd_durable_scavenger_alive(void)
715+
{
716+
mutex_lock(&durable_scavenger_lock);
717+
if (!durable_scavenger_running) {
718+
mutex_unlock(&durable_scavenger_lock);
719+
return false;
720+
}
721+
mutex_unlock(&durable_scavenger_lock);
722+
723+
if (kthread_should_stop())
724+
return false;
725+
726+
if (idr_is_empty(global_ft.idr))
727+
return false;
728+
729+
return true;
730+
}
731+
732+
static void ksmbd_scavenger_dispose_dh(struct list_head *head)
733+
{
734+
while (!list_empty(head)) {
735+
struct ksmbd_file *fp;
736+
737+
fp = list_first_entry(head, struct ksmbd_file, node);
738+
list_del_init(&fp->node);
739+
__ksmbd_close_fd(NULL, fp);
740+
}
741+
}
742+
743+
static int ksmbd_durable_scavenger(void *dummy)
744+
{
745+
struct ksmbd_file *fp = NULL;
746+
unsigned int id;
747+
unsigned int min_timeout = 1;
748+
bool found_fp_timeout;
749+
LIST_HEAD(scavenger_list);
750+
unsigned long remaining_jiffies;
751+
752+
__module_get(THIS_MODULE);
753+
754+
set_freezable();
755+
while (ksmbd_durable_scavenger_alive()) {
756+
if (try_to_freeze())
757+
continue;
758+
759+
found_fp_timeout = false;
760+
761+
remaining_jiffies = wait_event_timeout(dh_wq,
762+
ksmbd_durable_scavenger_alive() == false,
763+
__msecs_to_jiffies(min_timeout));
764+
if (remaining_jiffies)
765+
min_timeout = jiffies_to_msecs(remaining_jiffies);
766+
else
767+
min_timeout = DURABLE_HANDLE_MAX_TIMEOUT;
768+
769+
write_lock(&global_ft.lock);
770+
idr_for_each_entry(global_ft.idr, fp, id) {
771+
if (!fp->durable_timeout)
772+
continue;
773+
774+
if (atomic_read(&fp->refcount) > 1 ||
775+
fp->conn)
776+
continue;
777+
778+
found_fp_timeout = true;
779+
if (fp->durable_scavenger_timeout <=
780+
jiffies_to_msecs(jiffies)) {
781+
__ksmbd_remove_durable_fd(fp);
782+
list_add(&fp->node, &scavenger_list);
783+
} else {
784+
unsigned long durable_timeout;
785+
786+
durable_timeout =
787+
fp->durable_scavenger_timeout -
788+
jiffies_to_msecs(jiffies);
789+
790+
if (min_timeout > durable_timeout)
791+
min_timeout = durable_timeout;
792+
}
793+
}
794+
write_unlock(&global_ft.lock);
795+
796+
ksmbd_scavenger_dispose_dh(&scavenger_list);
797+
798+
if (found_fp_timeout == false)
799+
break;
800+
}
801+
802+
mutex_lock(&durable_scavenger_lock);
803+
durable_scavenger_running = false;
804+
mutex_unlock(&durable_scavenger_lock);
805+
806+
module_put(THIS_MODULE);
807+
808+
return 0;
809+
}
810+
811+
void ksmbd_launch_ksmbd_durable_scavenger(void)
812+
{
813+
if (!(server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE))
814+
return;
815+
816+
mutex_lock(&durable_scavenger_lock);
817+
if (durable_scavenger_running == true) {
818+
mutex_unlock(&durable_scavenger_lock);
819+
return;
820+
}
821+
822+
durable_scavenger_running = true;
823+
824+
server_conf.dh_task = kthread_run(ksmbd_durable_scavenger,
825+
(void *)NULL, "ksmbd-durable-scavenger");
826+
if (IS_ERR(server_conf.dh_task))
827+
pr_err("cannot start conn thread, err : %ld\n",
828+
PTR_ERR(server_conf.dh_task));
829+
mutex_unlock(&durable_scavenger_lock);
830+
}
831+
832+
void ksmbd_stop_durable_scavenger(void)
833+
{
834+
if (!(server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE))
835+
return;
836+
837+
mutex_lock(&durable_scavenger_lock);
838+
if (!durable_scavenger_running) {
839+
mutex_unlock(&durable_scavenger_lock);
840+
return;
841+
}
842+
843+
durable_scavenger_running = false;
844+
if (waitqueue_active(&dh_wq))
845+
wake_up(&dh_wq);
846+
mutex_unlock(&durable_scavenger_lock);
847+
kthread_stop(server_conf.dh_task);
848+
}
849+
700850
static bool session_fd_check(struct ksmbd_tree_connect *tcon,
701851
struct ksmbd_file *fp)
702852
{
@@ -757,11 +907,12 @@ void ksmbd_free_global_file_table(void)
757907
unsigned int id;
758908

759909
idr_for_each_entry(global_ft.idr, fp, id) {
760-
__ksmbd_remove_durable_fd(fp);
761-
kmem_cache_free(filp_cache, fp);
910+
ksmbd_remove_durable_fd(fp);
911+
__ksmbd_close_fd(NULL, fp);
762912
}
763913

764-
ksmbd_destroy_file_table(&global_ft);
914+
idr_destroy(global_ft.idr);
915+
kfree(global_ft.idr);
765916
}
766917

767918
int ksmbd_validate_name_reconnect(struct ksmbd_share_config *share,
@@ -817,6 +968,7 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
817968
}
818969
up_write(&ci->m_lock);
819970

971+
fp->f_state = FP_NEW;
820972
__open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID);
821973
if (!has_file_id(fp->volatile_id)) {
822974
fp->conn = NULL;
@@ -856,6 +1008,8 @@ int ksmbd_init_file_cache(void)
8561008
if (!filp_cache)
8571009
goto out;
8581010

1011+
init_waitqueue_head(&dh_wq);
1012+
8591013
return 0;
8601014

8611015
out:

fs/smb/server/vfs_cache.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid);
153153
struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry);
154154
unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp);
155155
struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp);
156+
void ksmbd_launch_ksmbd_durable_scavenger(void);
157+
void ksmbd_stop_durable_scavenger(void);
156158
void ksmbd_close_tree_conn_fds(struct ksmbd_work *work);
157159
void ksmbd_close_session_fds(struct ksmbd_work *work);
158160
int ksmbd_close_inode_fds(struct ksmbd_work *work, struct inode *inode);

0 commit comments

Comments
 (0)