@@ -17,6 +17,11 @@ static void free_cached_dir(struct cached_fid *cfid);
1717static void smb2_close_cached_fid (struct kref * ref );
1818static void cfids_laundromat_worker (struct work_struct * work );
1919
20+ struct cached_dir_dentry {
21+ struct list_head entry ;
22+ struct dentry * dentry ;
23+ };
24+
2025static struct cached_fid * find_or_create_cached_dir (struct cached_fids * cfids ,
2126 const char * path ,
2227 bool lookup_only ,
@@ -157,15 +162,17 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
157162 const char * npath ;
158163 int retries = 0 , cur_sleep = 1 ;
159164
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 )
162169 return - EOPNOTSUPP ;
163170
164171 ses = tcon -> ses ;
165172 cfids = tcon -> cfids ;
166173
167- if (cifs_sb -> root == NULL )
168- return - ENOENT ;
174+ if (cfids == NULL )
175+ return - EOPNOTSUPP ;
169176
170177replay_again :
171178 /* reinitialize for possible replay */
@@ -222,6 +229,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
222229 }
223230 }
224231 cfid -> dentry = dentry ;
232+ cfid -> tcon = tcon ;
225233
226234 /*
227235 * 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,
293301 }
294302 goto oshr_free ;
295303 }
296- cfid -> tcon = tcon ;
297304 cfid -> is_open = true;
298305
299306 spin_lock (& cfids -> cfid_list_lock );
@@ -389,7 +396,7 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
389396 struct cached_fids * cfids = tcon -> cfids ;
390397
391398 if (cfids == NULL )
392- return - ENOENT ;
399+ return - EOPNOTSUPP ;
393400
394401 spin_lock (& cfids -> cfid_list_lock );
395402 list_for_each_entry (cfid , & cfids -> entries , entry ) {
@@ -470,7 +477,10 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
470477 struct cifs_tcon * tcon ;
471478 struct tcon_link * tlink ;
472479 struct cached_fids * cfids ;
480+ struct cached_dir_dentry * tmp_list , * q ;
481+ LIST_HEAD (entry );
473482
483+ spin_lock (& cifs_sb -> tlink_tree_lock );
474484 for (node = rb_first (root ); node ; node = rb_next (node )) {
475485 tlink = rb_entry (node , struct tcon_link , tl_rbnode );
476486 tcon = tlink_tcon (tlink );
@@ -479,11 +489,30 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
479489 cfids = tcon -> cfids ;
480490 if (cfids == NULL )
481491 continue ;
492+ spin_lock (& cfids -> cfid_list_lock );
482493 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 ;
484499 cfid -> dentry = NULL ;
500+ spin_unlock (& cfid -> fid_lock );
501+
502+ list_add_tail (& tmp_list -> entry , & entry );
485503 }
504+ spin_unlock (& cfids -> cfid_list_lock );
486505 }
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 );
487516}
488517
489518/*
@@ -494,14 +523,18 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
494523{
495524 struct cached_fids * cfids = tcon -> cfids ;
496525 struct cached_fid * cfid , * q ;
497- LIST_HEAD (entry );
498526
499527 if (cfids == NULL )
500528 return ;
501529
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+ */
502535 spin_lock (& cfids -> cfid_list_lock );
503536 list_for_each_entry_safe (cfid , q , & cfids -> entries , entry ) {
504- list_move (& cfid -> entry , & entry );
537+ list_move (& cfid -> entry , & cfids -> dying );
505538 cfids -> num_entries -- ;
506539 cfid -> is_open = false;
507540 cfid -> on_list = false;
@@ -514,26 +547,47 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
514547 } else
515548 kref_get (& cfid -> refcount );
516549 }
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 );
517555 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- }
528556}
529557
530558static void
531- smb2_cached_lease_break (struct work_struct * work )
559+ cached_dir_offload_close (struct work_struct * work )
532560{
533561 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 );
535566
536567 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 );
537591}
538592
539593int 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])
560614 cfid -> on_list = false;
561615 cfids -> num_entries -- ;
562616
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 );
565621 spin_unlock (& cfids -> cfid_list_lock );
566622 return true;
567623 }
@@ -583,7 +639,8 @@ static struct cached_fid *init_cached_dir(const char *path)
583639 return NULL ;
584640 }
585641
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 );
587644 INIT_LIST_HEAD (& cfid -> entry );
588645 INIT_LIST_HEAD (& cfid -> dirents .entries );
589646 mutex_init (& cfid -> dirents .de_mutex );
@@ -596,6 +653,9 @@ static void free_cached_dir(struct cached_fid *cfid)
596653{
597654 struct cached_dirent * dirent , * q ;
598655
656+ WARN_ON (work_pending (& cfid -> close_work ));
657+ WARN_ON (work_pending (& cfid -> put_work ));
658+
599659 dput (cfid -> dentry );
600660 cfid -> dentry = NULL ;
601661
@@ -613,10 +673,30 @@ static void free_cached_dir(struct cached_fid *cfid)
613673 kfree (cfid );
614674}
615675
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+
616695static void cfids_laundromat_worker (struct work_struct * work )
617696{
618697 struct cached_fids * cfids ;
619698 struct cached_fid * cfid , * q ;
699+ struct dentry * dentry ;
620700 LIST_HEAD (entry );
621701
622702 cfids = container_of (work , struct cached_fids , laundromat_work .work );
@@ -642,18 +722,28 @@ static void cfids_laundromat_worker(struct work_struct *work)
642722
643723 list_for_each_entry_safe (cfid , q , & entry , entry ) {
644724 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 );
655745 }
656- queue_delayed_work (cifsiod_wq , & cfids -> laundromat_work ,
746+ queue_delayed_work (cfid_put_wq , & cfids -> laundromat_work ,
657747 dir_cache_timeout * HZ );
658748}
659749
@@ -666,9 +756,11 @@ struct cached_fids *init_cached_dirs(void)
666756 return NULL ;
667757 spin_lock_init (& cfids -> cfid_list_lock );
668758 INIT_LIST_HEAD (& cfids -> entries );
759+ INIT_LIST_HEAD (& cfids -> dying );
669760
761+ INIT_WORK (& cfids -> invalidation_work , cfids_invalidation_worker );
670762 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 ,
672764 dir_cache_timeout * HZ );
673765
674766 return cfids ;
@@ -687,13 +779,19 @@ void free_cached_dirs(struct cached_fids *cfids)
687779 return ;
688780
689781 cancel_delayed_work_sync (& cfids -> laundromat_work );
782+ cancel_work_sync (& cfids -> invalidation_work );
690783
691784 spin_lock (& cfids -> cfid_list_lock );
692785 list_for_each_entry_safe (cfid , q , & cfids -> entries , entry ) {
693786 cfid -> on_list = false;
694787 cfid -> is_open = false;
695788 list_move (& cfid -> entry , & entry );
696789 }
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+ }
697795 spin_unlock (& cfids -> cfid_list_lock );
698796
699797 list_for_each_entry_safe (cfid , q , & entry , entry ) {
0 commit comments