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"
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;
3134static atomic_long_t fd_limit ;
3235static 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+
3441void 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
288302static 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
@@ -477,7 +491,10 @@ struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id)
477491 struct ksmbd_file * fp ;
478492
479493 fp = __ksmbd_lookup_fd (& global_ft , id );
480- if (fp && fp -> conn ) {
494+ if (fp && (fp -> conn ||
495+ (fp -> durable_scavenger_timeout &&
496+ (fp -> durable_scavenger_timeout <
497+ jiffies_to_msecs (jiffies ))))) {
481498 ksmbd_put_durable_fd (fp );
482499 fp = NULL ;
483500 }
@@ -694,6 +711,142 @@ static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon,
694711 return fp -> tcon != tcon ;
695712}
696713
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+
697850static bool session_fd_check (struct ksmbd_tree_connect * tcon ,
698851 struct ksmbd_file * fp )
699852{
@@ -718,6 +871,10 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon,
718871 fp -> tcon = NULL ;
719872 fp -> volatile_id = KSMBD_NO_FID ;
720873
874+ if (fp -> durable_timeout )
875+ fp -> durable_scavenger_timeout =
876+ jiffies_to_msecs (jiffies ) + fp -> durable_timeout ;
877+
721878 return true;
722879}
723880
@@ -750,11 +907,12 @@ void ksmbd_free_global_file_table(void)
750907 unsigned int id ;
751908
752909 idr_for_each_entry (global_ft .idr , fp , id ) {
753- __ksmbd_remove_durable_fd (fp );
754- kmem_cache_free ( filp_cache , fp );
910+ ksmbd_remove_durable_fd (fp );
911+ __ksmbd_close_fd ( NULL , fp );
755912 }
756913
757- ksmbd_destroy_file_table (& global_ft );
914+ idr_destroy (global_ft .idr );
915+ kfree (global_ft .idr );
758916}
759917
760918int 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)
810968 }
811969 up_write (& ci -> m_lock );
812970
971+ fp -> f_state = FP_NEW ;
813972 __open_id (& work -> sess -> file_table , fp , OPEN_ID_TYPE_VOLATILE_ID );
814973 if (!has_file_id (fp -> volatile_id )) {
815974 fp -> conn = NULL ;
@@ -849,6 +1008,8 @@ int ksmbd_init_file_cache(void)
8491008 if (!filp_cache )
8501009 goto out ;
8511010
1011+ init_waitqueue_head (& dh_wq );
1012+
8521013 return 0 ;
8531014
8541015out :
0 commit comments