8
8
#include <linux/filelock.h>
9
9
#include <linux/slab.h>
10
10
#include <linux/vmalloc.h>
11
+ #include <linux/kthread.h>
12
+ #include <linux/freezer.h>
11
13
12
14
#include "glob.h"
13
15
#include "vfs_cache.h"
17
19
#include "mgmt/tree_connect.h"
18
20
#include "mgmt/user_session.h"
19
21
#include "smb_common.h"
22
+ #include "server.h"
20
23
21
24
#define S_DEL_PENDING 1
22
25
#define S_DEL_ON_CLS 2
@@ -31,6 +34,10 @@ static struct ksmbd_file_table global_ft;
31
34
static atomic_long_t fd_limit ;
32
35
static struct kmem_cache * filp_cache ;
33
36
37
+ static bool durable_scavenger_running ;
38
+ static DEFINE_MUTEX (durable_scavenger_lock );
39
+ static wait_queue_head_t dh_wq ;
40
+
34
41
void ksmbd_set_fd_limit (unsigned long limit )
35
42
{
36
43
limit = min (limit , get_max_files ());
@@ -280,9 +287,16 @@ static void __ksmbd_remove_durable_fd(struct ksmbd_file *fp)
280
287
if (!has_file_id (fp -> persistent_id ))
281
288
return ;
282
289
283
- write_lock (& global_ft .lock );
284
290
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 );
285
297
write_unlock (& global_ft .lock );
298
+ if (waitqueue_active (& dh_wq ))
299
+ wake_up (& dh_wq );
286
300
}
287
301
288
302
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)
305
319
struct ksmbd_lock * smb_lock , * tmp_lock ;
306
320
307
321
fd_limit_close ();
308
- __ksmbd_remove_durable_fd (fp );
322
+ ksmbd_remove_durable_fd (fp );
309
323
if (ft )
310
324
__ksmbd_remove_fd (ft , fp );
311
325
@@ -697,6 +711,142 @@ static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon,
697
711
return fp -> tcon != tcon ;
698
712
}
699
713
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
+
700
850
static bool session_fd_check (struct ksmbd_tree_connect * tcon ,
701
851
struct ksmbd_file * fp )
702
852
{
@@ -757,11 +907,12 @@ void ksmbd_free_global_file_table(void)
757
907
unsigned int id ;
758
908
759
909
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 );
762
912
}
763
913
764
- ksmbd_destroy_file_table (& global_ft );
914
+ idr_destroy (global_ft .idr );
915
+ kfree (global_ft .idr );
765
916
}
766
917
767
918
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)
817
968
}
818
969
up_write (& ci -> m_lock );
819
970
971
+ fp -> f_state = FP_NEW ;
820
972
__open_id (& work -> sess -> file_table , fp , OPEN_ID_TYPE_VOLATILE_ID );
821
973
if (!has_file_id (fp -> volatile_id )) {
822
974
fp -> conn = NULL ;
@@ -856,6 +1008,8 @@ int ksmbd_init_file_cache(void)
856
1008
if (!filp_cache )
857
1009
goto out ;
858
1010
1011
+ init_waitqueue_head (& dh_wq );
1012
+
859
1013
return 0 ;
860
1014
861
1015
out :
0 commit comments