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
@@ -477,7 +491,10 @@ struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id)
477
491
struct ksmbd_file * fp ;
478
492
479
493
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 ))))) {
481
498
ksmbd_put_durable_fd (fp );
482
499
fp = NULL ;
483
500
}
@@ -694,6 +711,142 @@ static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon,
694
711
return fp -> tcon != tcon ;
695
712
}
696
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
+
697
850
static bool session_fd_check (struct ksmbd_tree_connect * tcon ,
698
851
struct ksmbd_file * fp )
699
852
{
@@ -718,6 +871,10 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon,
718
871
fp -> tcon = NULL ;
719
872
fp -> volatile_id = KSMBD_NO_FID ;
720
873
874
+ if (fp -> durable_timeout )
875
+ fp -> durable_scavenger_timeout =
876
+ jiffies_to_msecs (jiffies ) + fp -> durable_timeout ;
877
+
721
878
return true;
722
879
}
723
880
@@ -750,11 +907,12 @@ void ksmbd_free_global_file_table(void)
750
907
unsigned int id ;
751
908
752
909
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 );
755
912
}
756
913
757
- ksmbd_destroy_file_table (& global_ft );
914
+ idr_destroy (global_ft .idr );
915
+ kfree (global_ft .idr );
758
916
}
759
917
760
918
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)
810
968
}
811
969
up_write (& ci -> m_lock );
812
970
971
+ fp -> f_state = FP_NEW ;
813
972
__open_id (& work -> sess -> file_table , fp , OPEN_ID_TYPE_VOLATILE_ID );
814
973
if (!has_file_id (fp -> volatile_id )) {
815
974
fp -> conn = NULL ;
@@ -849,6 +1008,8 @@ int ksmbd_init_file_cache(void)
849
1008
if (!filp_cache )
850
1009
goto out ;
851
1010
1011
+ init_waitqueue_head (& dh_wq );
1012
+
852
1013
return 0 ;
853
1014
854
1015
out :
0 commit comments