@@ -17,6 +17,11 @@ static void free_cached_dir(struct cached_fid *cfid);
17
17
static void smb2_close_cached_fid (struct kref * ref );
18
18
static void cfids_laundromat_worker (struct work_struct * work );
19
19
20
+ struct cached_dir_dentry {
21
+ struct list_head entry ;
22
+ struct dentry * dentry ;
23
+ };
24
+
20
25
static struct cached_fid * find_or_create_cached_dir (struct cached_fids * cfids ,
21
26
const char * path ,
22
27
bool lookup_only ,
@@ -157,15 +162,17 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
157
162
const char * npath ;
158
163
int retries = 0 , cur_sleep = 1 ;
159
164
160
- if (tcon == NULL || tcon -> cfids == NULL || tcon -> nohandlecache ||
161
- is_smb1_server (tcon -> ses -> server ) || (dir_cache_timeout == 0 ))
165
+ if (cifs_sb -> root == NULL )
166
+ return - ENOENT ;
167
+
168
+ if (tcon == NULL )
162
169
return - EOPNOTSUPP ;
163
170
164
171
ses = tcon -> ses ;
165
172
cfids = tcon -> cfids ;
166
173
167
- if (cifs_sb -> root == NULL )
168
- return - ENOENT ;
174
+ if (cfids == NULL )
175
+ return - EOPNOTSUPP ;
169
176
170
177
replay_again :
171
178
/* reinitialize for possible replay */
@@ -222,6 +229,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
222
229
}
223
230
}
224
231
cfid -> dentry = dentry ;
232
+ cfid -> tcon = tcon ;
225
233
226
234
/*
227
235
* We do not hold the lock for the open because in case
@@ -293,7 +301,6 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
293
301
}
294
302
goto oshr_free ;
295
303
}
296
- cfid -> tcon = tcon ;
297
304
cfid -> is_open = true;
298
305
299
306
spin_lock (& cfids -> cfid_list_lock );
@@ -389,7 +396,7 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
389
396
struct cached_fids * cfids = tcon -> cfids ;
390
397
391
398
if (cfids == NULL )
392
- return - ENOENT ;
399
+ return - EOPNOTSUPP ;
393
400
394
401
spin_lock (& cfids -> cfid_list_lock );
395
402
list_for_each_entry (cfid , & cfids -> entries , entry ) {
@@ -470,7 +477,10 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
470
477
struct cifs_tcon * tcon ;
471
478
struct tcon_link * tlink ;
472
479
struct cached_fids * cfids ;
480
+ struct cached_dir_dentry * tmp_list , * q ;
481
+ LIST_HEAD (entry );
473
482
483
+ spin_lock (& cifs_sb -> tlink_tree_lock );
474
484
for (node = rb_first (root ); node ; node = rb_next (node )) {
475
485
tlink = rb_entry (node , struct tcon_link , tl_rbnode );
476
486
tcon = tlink_tcon (tlink );
@@ -479,11 +489,30 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
479
489
cfids = tcon -> cfids ;
480
490
if (cfids == NULL )
481
491
continue ;
492
+ spin_lock (& cfids -> cfid_list_lock );
482
493
list_for_each_entry (cfid , & cfids -> entries , entry ) {
483
- dput (cfid -> dentry );
494
+ tmp_list = kmalloc (sizeof (* tmp_list ), GFP_ATOMIC );
495
+ if (tmp_list == NULL )
496
+ break ;
497
+ spin_lock (& cfid -> fid_lock );
498
+ tmp_list -> dentry = cfid -> dentry ;
484
499
cfid -> dentry = NULL ;
500
+ spin_unlock (& cfid -> fid_lock );
501
+
502
+ list_add_tail (& tmp_list -> entry , & entry );
485
503
}
504
+ spin_unlock (& cfids -> cfid_list_lock );
486
505
}
506
+ spin_unlock (& cifs_sb -> tlink_tree_lock );
507
+
508
+ list_for_each_entry_safe (tmp_list , q , & entry , entry ) {
509
+ list_del (& tmp_list -> entry );
510
+ dput (tmp_list -> dentry );
511
+ kfree (tmp_list );
512
+ }
513
+
514
+ /* Flush any pending work that will drop dentries */
515
+ flush_workqueue (cfid_put_wq );
487
516
}
488
517
489
518
/*
@@ -494,14 +523,18 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
494
523
{
495
524
struct cached_fids * cfids = tcon -> cfids ;
496
525
struct cached_fid * cfid , * q ;
497
- LIST_HEAD (entry );
498
526
499
527
if (cfids == NULL )
500
528
return ;
501
529
530
+ /*
531
+ * Mark all the cfids as closed, and move them to the cfids->dying list.
532
+ * They'll be cleaned up later by cfids_invalidation_worker. Take
533
+ * a reference to each cfid during this process.
534
+ */
502
535
spin_lock (& cfids -> cfid_list_lock );
503
536
list_for_each_entry_safe (cfid , q , & cfids -> entries , entry ) {
504
- list_move (& cfid -> entry , & entry );
537
+ list_move (& cfid -> entry , & cfids -> dying );
505
538
cfids -> num_entries -- ;
506
539
cfid -> is_open = false;
507
540
cfid -> on_list = false;
@@ -514,26 +547,47 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
514
547
} else
515
548
kref_get (& cfid -> refcount );
516
549
}
550
+ /*
551
+ * Queue dropping of the dentries once locks have been dropped
552
+ */
553
+ if (!list_empty (& cfids -> dying ))
554
+ queue_work (cfid_put_wq , & cfids -> invalidation_work );
517
555
spin_unlock (& cfids -> cfid_list_lock );
518
-
519
- list_for_each_entry_safe (cfid , q , & entry , entry ) {
520
- list_del (& cfid -> entry );
521
- cancel_work_sync (& cfid -> lease_break );
522
- /*
523
- * Drop the ref-count from above, either the lease-ref (if there
524
- * was one) or the extra one acquired.
525
- */
526
- kref_put (& cfid -> refcount , smb2_close_cached_fid );
527
- }
528
556
}
529
557
530
558
static void
531
- smb2_cached_lease_break (struct work_struct * work )
559
+ cached_dir_offload_close (struct work_struct * work )
532
560
{
533
561
struct cached_fid * cfid = container_of (work ,
534
- struct cached_fid , lease_break );
562
+ struct cached_fid , close_work );
563
+ struct cifs_tcon * tcon = cfid -> tcon ;
564
+
565
+ WARN_ON (cfid -> on_list );
535
566
536
567
kref_put (& cfid -> refcount , smb2_close_cached_fid );
568
+ cifs_put_tcon (tcon , netfs_trace_tcon_ref_put_cached_close );
569
+ }
570
+
571
+ /*
572
+ * Release the cached directory's dentry, and then queue work to drop cached
573
+ * directory itself (closing on server if needed).
574
+ *
575
+ * Must be called with a reference to the cached_fid and a reference to the
576
+ * tcon.
577
+ */
578
+ static void cached_dir_put_work (struct work_struct * work )
579
+ {
580
+ struct cached_fid * cfid = container_of (work , struct cached_fid ,
581
+ put_work );
582
+ struct dentry * dentry ;
583
+
584
+ spin_lock (& cfid -> fid_lock );
585
+ dentry = cfid -> dentry ;
586
+ cfid -> dentry = NULL ;
587
+ spin_unlock (& cfid -> fid_lock );
588
+
589
+ dput (dentry );
590
+ queue_work (serverclose_wq , & cfid -> close_work );
537
591
}
538
592
539
593
int cached_dir_lease_break (struct cifs_tcon * tcon , __u8 lease_key [16 ])
@@ -560,8 +614,10 @@ int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16])
560
614
cfid -> on_list = false;
561
615
cfids -> num_entries -- ;
562
616
563
- queue_work (cifsiod_wq ,
564
- & cfid -> lease_break );
617
+ ++ tcon -> tc_count ;
618
+ trace_smb3_tcon_ref (tcon -> debug_id , tcon -> tc_count ,
619
+ netfs_trace_tcon_ref_get_cached_lease_break );
620
+ queue_work (cfid_put_wq , & cfid -> put_work );
565
621
spin_unlock (& cfids -> cfid_list_lock );
566
622
return true;
567
623
}
@@ -583,7 +639,8 @@ static struct cached_fid *init_cached_dir(const char *path)
583
639
return NULL ;
584
640
}
585
641
586
- INIT_WORK (& cfid -> lease_break , smb2_cached_lease_break );
642
+ INIT_WORK (& cfid -> close_work , cached_dir_offload_close );
643
+ INIT_WORK (& cfid -> put_work , cached_dir_put_work );
587
644
INIT_LIST_HEAD (& cfid -> entry );
588
645
INIT_LIST_HEAD (& cfid -> dirents .entries );
589
646
mutex_init (& cfid -> dirents .de_mutex );
@@ -596,6 +653,9 @@ static void free_cached_dir(struct cached_fid *cfid)
596
653
{
597
654
struct cached_dirent * dirent , * q ;
598
655
656
+ WARN_ON (work_pending (& cfid -> close_work ));
657
+ WARN_ON (work_pending (& cfid -> put_work ));
658
+
599
659
dput (cfid -> dentry );
600
660
cfid -> dentry = NULL ;
601
661
@@ -613,10 +673,30 @@ static void free_cached_dir(struct cached_fid *cfid)
613
673
kfree (cfid );
614
674
}
615
675
676
+ static void cfids_invalidation_worker (struct work_struct * work )
677
+ {
678
+ struct cached_fids * cfids = container_of (work , struct cached_fids ,
679
+ invalidation_work );
680
+ struct cached_fid * cfid , * q ;
681
+ LIST_HEAD (entry );
682
+
683
+ spin_lock (& cfids -> cfid_list_lock );
684
+ /* move cfids->dying to the local list */
685
+ list_cut_before (& entry , & cfids -> dying , & cfids -> dying );
686
+ spin_unlock (& cfids -> cfid_list_lock );
687
+
688
+ list_for_each_entry_safe (cfid , q , & entry , entry ) {
689
+ list_del (& cfid -> entry );
690
+ /* Drop the ref-count acquired in invalidate_all_cached_dirs */
691
+ kref_put (& cfid -> refcount , smb2_close_cached_fid );
692
+ }
693
+ }
694
+
616
695
static void cfids_laundromat_worker (struct work_struct * work )
617
696
{
618
697
struct cached_fids * cfids ;
619
698
struct cached_fid * cfid , * q ;
699
+ struct dentry * dentry ;
620
700
LIST_HEAD (entry );
621
701
622
702
cfids = container_of (work , struct cached_fids , laundromat_work .work );
@@ -642,18 +722,28 @@ static void cfids_laundromat_worker(struct work_struct *work)
642
722
643
723
list_for_each_entry_safe (cfid , q , & entry , entry ) {
644
724
list_del (& cfid -> entry );
645
- /*
646
- * Cancel and wait for the work to finish in case we are racing
647
- * with it.
648
- */
649
- cancel_work_sync (& cfid -> lease_break );
650
- /*
651
- * Drop the ref-count from above, either the lease-ref (if there
652
- * was one) or the extra one acquired.
653
- */
654
- kref_put (& cfid -> refcount , smb2_close_cached_fid );
725
+
726
+ spin_lock (& cfid -> fid_lock );
727
+ dentry = cfid -> dentry ;
728
+ cfid -> dentry = NULL ;
729
+ spin_unlock (& cfid -> fid_lock );
730
+
731
+ dput (dentry );
732
+ if (cfid -> is_open ) {
733
+ spin_lock (& cifs_tcp_ses_lock );
734
+ ++ cfid -> tcon -> tc_count ;
735
+ trace_smb3_tcon_ref (cfid -> tcon -> debug_id , cfid -> tcon -> tc_count ,
736
+ netfs_trace_tcon_ref_get_cached_laundromat );
737
+ spin_unlock (& cifs_tcp_ses_lock );
738
+ queue_work (serverclose_wq , & cfid -> close_work );
739
+ } else
740
+ /*
741
+ * Drop the ref-count from above, either the lease-ref (if there
742
+ * was one) or the extra one acquired.
743
+ */
744
+ kref_put (& cfid -> refcount , smb2_close_cached_fid );
655
745
}
656
- queue_delayed_work (cifsiod_wq , & cfids -> laundromat_work ,
746
+ queue_delayed_work (cfid_put_wq , & cfids -> laundromat_work ,
657
747
dir_cache_timeout * HZ );
658
748
}
659
749
@@ -666,9 +756,11 @@ struct cached_fids *init_cached_dirs(void)
666
756
return NULL ;
667
757
spin_lock_init (& cfids -> cfid_list_lock );
668
758
INIT_LIST_HEAD (& cfids -> entries );
759
+ INIT_LIST_HEAD (& cfids -> dying );
669
760
761
+ INIT_WORK (& cfids -> invalidation_work , cfids_invalidation_worker );
670
762
INIT_DELAYED_WORK (& cfids -> laundromat_work , cfids_laundromat_worker );
671
- queue_delayed_work (cifsiod_wq , & cfids -> laundromat_work ,
763
+ queue_delayed_work (cfid_put_wq , & cfids -> laundromat_work ,
672
764
dir_cache_timeout * HZ );
673
765
674
766
return cfids ;
@@ -687,13 +779,19 @@ void free_cached_dirs(struct cached_fids *cfids)
687
779
return ;
688
780
689
781
cancel_delayed_work_sync (& cfids -> laundromat_work );
782
+ cancel_work_sync (& cfids -> invalidation_work );
690
783
691
784
spin_lock (& cfids -> cfid_list_lock );
692
785
list_for_each_entry_safe (cfid , q , & cfids -> entries , entry ) {
693
786
cfid -> on_list = false;
694
787
cfid -> is_open = false;
695
788
list_move (& cfid -> entry , & entry );
696
789
}
790
+ list_for_each_entry_safe (cfid , q , & cfids -> dying , entry ) {
791
+ cfid -> on_list = false;
792
+ cfid -> is_open = false;
793
+ list_move (& cfid -> entry , & entry );
794
+ }
697
795
spin_unlock (& cfids -> cfid_list_lock );
698
796
699
797
list_for_each_entry_safe (cfid , q , & entry , entry ) {
0 commit comments