@@ -36,9 +36,8 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
3636 * fully cached or it may be in the process of
3737 * being deleted due to a lease break.
3838 */
39- if (!cfid -> time || ! cfid -> has_lease ) {
39+ if (!is_valid_cached_dir ( cfid ))
4040 return NULL ;
41- }
4241 kref_get (& cfid -> refcount );
4342 return cfid ;
4443 }
@@ -193,7 +192,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
193192 * Otherwise, it is either a new entry or laundromat worker removed it
194193 * from @cfids->entries. Caller will put last reference if the latter.
195194 */
196- if (cfid -> has_lease && cfid -> time ) {
195+ if (is_valid_cached_dir ( cfid ) ) {
197196 cfid -> last_access_time = jiffies ;
198197 spin_unlock (& cfids -> cfid_list_lock );
199198 * ret_cfid = cfid ;
@@ -232,7 +231,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
232231 list_for_each_entry (parent_cfid , & cfids -> entries , entry ) {
233232 if (parent_cfid -> dentry == dentry -> d_parent ) {
234233 cifs_dbg (FYI , "found a parent cached file handle\n" );
235- if (parent_cfid -> has_lease && parent_cfid -> time ) {
234+ if (is_valid_cached_dir ( parent_cfid ) ) {
236235 lease_flags
237236 |= SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE ;
238237 memcpy (pfid -> parent_lease_key ,
@@ -388,11 +387,11 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
388387 * lease. Release one here, and the second below.
389388 */
390389 cfid -> has_lease = false;
391- kref_put ( & cfid -> refcount , smb2_close_cached_fid );
390+ close_cached_dir ( cfid );
392391 }
393392 spin_unlock (& cfids -> cfid_list_lock );
394393
395- kref_put ( & cfid -> refcount , smb2_close_cached_fid );
394+ close_cached_dir ( cfid );
396395 } else {
397396 * ret_cfid = cfid ;
398397 atomic_inc (& tcon -> num_remote_opens );
@@ -416,12 +415,18 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
416415 if (cfids == NULL )
417416 return - EOPNOTSUPP ;
418417
418+ if (!dentry )
419+ return - ENOENT ;
420+
419421 spin_lock (& cfids -> cfid_list_lock );
420422 list_for_each_entry (cfid , & cfids -> entries , entry ) {
421- if (dentry && cfid -> dentry == dentry ) {
423+ if (cfid -> dentry == dentry ) {
424+ if (!is_valid_cached_dir (cfid ))
425+ break ;
422426 cifs_dbg (FYI , "found a cached file handle by dentry\n" );
423427 kref_get (& cfid -> refcount );
424428 * ret_cfid = cfid ;
429+ cfid -> last_access_time = jiffies ;
425430 spin_unlock (& cfids -> cfid_list_lock );
426431 return 0 ;
427432 }
@@ -432,12 +437,14 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
432437
433438static void
434439smb2_close_cached_fid (struct kref * ref )
440+ __releases (& cfid - > cfids - > cfid_list_lock )
435441{
436442 struct cached_fid * cfid = container_of (ref , struct cached_fid ,
437443 refcount );
438444 int rc ;
439445
440- spin_lock (& cfid -> cfids -> cfid_list_lock );
446+ lockdep_assert_held (& cfid -> cfids -> cfid_list_lock );
447+
441448 if (cfid -> on_list ) {
442449 list_del (& cfid -> entry );
443450 cfid -> on_list = false;
@@ -472,7 +479,7 @@ void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon,
472479 spin_lock (& cfid -> cfids -> cfid_list_lock );
473480 if (cfid -> has_lease ) {
474481 cfid -> has_lease = false;
475- kref_put ( & cfid -> refcount , smb2_close_cached_fid );
482+ close_cached_dir ( cfid );
476483 }
477484 spin_unlock (& cfid -> cfids -> cfid_list_lock );
478485 close_cached_dir (cfid );
@@ -481,7 +488,7 @@ void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon,
481488
482489void close_cached_dir (struct cached_fid * cfid )
483490{
484- kref_put (& cfid -> refcount , smb2_close_cached_fid );
491+ kref_put_lock (& cfid -> refcount , smb2_close_cached_fid , & cfid -> cfids -> cfid_list_lock );
485492}
486493
487494/*
@@ -521,10 +528,9 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
521528 spin_unlock (& cifs_sb -> tlink_tree_lock );
522529 goto done ;
523530 }
524- spin_lock ( & cfid -> fid_lock );
531+
525532 tmp_list -> dentry = cfid -> dentry ;
526533 cfid -> dentry = NULL ;
527- spin_unlock (& cfid -> fid_lock );
528534
529535 list_add_tail (& tmp_list -> entry , & entry );
530536 }
@@ -557,8 +563,8 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
557563
558564 /*
559565 * Mark all the cfids as closed, and move them to the cfids->dying list.
560- * They'll be cleaned up later by cfids_invalidation_worker. Take
561- * a reference to each cfid during this process.
566+ * They'll be cleaned up by laundromat. Take a reference to each cfid
567+ * during this process.
562568 */
563569 spin_lock (& cfids -> cfid_list_lock );
564570 list_for_each_entry_safe (cfid , q , & cfids -> entries , entry ) {
@@ -575,12 +581,11 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
575581 } else
576582 kref_get (& cfid -> refcount );
577583 }
578- /*
579- * Queue dropping of the dentries once locks have been dropped
580- */
581- if (!list_empty (& cfids -> dying ))
582- queue_work (cfid_put_wq , & cfids -> invalidation_work );
583584 spin_unlock (& cfids -> cfid_list_lock );
585+
586+ /* run laundromat unconditionally now as there might have been previously queued work */
587+ mod_delayed_work (cfid_put_wq , & cfids -> laundromat_work , 0 );
588+ flush_delayed_work (& cfids -> laundromat_work );
584589}
585590
586591static void
@@ -592,7 +597,7 @@ cached_dir_offload_close(struct work_struct *work)
592597
593598 WARN_ON (cfid -> on_list );
594599
595- kref_put ( & cfid -> refcount , smb2_close_cached_fid );
600+ close_cached_dir ( cfid );
596601 cifs_put_tcon (tcon , netfs_trace_tcon_ref_put_cached_close );
597602}
598603
@@ -607,14 +612,9 @@ static void cached_dir_put_work(struct work_struct *work)
607612{
608613 struct cached_fid * cfid = container_of (work , struct cached_fid ,
609614 put_work );
610- struct dentry * dentry ;
611-
612- spin_lock (& cfid -> fid_lock );
613- dentry = cfid -> dentry ;
615+ dput (cfid -> dentry );
614616 cfid -> dentry = NULL ;
615- spin_unlock (& cfid -> fid_lock );
616617
617- dput (dentry );
618618 queue_work (serverclose_wq , & cfid -> close_work );
619619}
620620
@@ -672,7 +672,6 @@ static struct cached_fid *init_cached_dir(const char *path)
672672 INIT_LIST_HEAD (& cfid -> entry );
673673 INIT_LIST_HEAD (& cfid -> dirents .entries );
674674 mutex_init (& cfid -> dirents .de_mutex );
675- spin_lock_init (& cfid -> fid_lock );
676675 kref_init (& cfid -> refcount );
677676 return cfid ;
678677}
@@ -696,40 +695,38 @@ static void free_cached_dir(struct cached_fid *cfid)
696695 kfree (dirent );
697696 }
698697
698+ /* adjust tcon-level counters and reset per-dir accounting */
699+ if (cfid -> cfids ) {
700+ if (cfid -> dirents .entries_count )
701+ atomic_long_sub ((long )cfid -> dirents .entries_count ,
702+ & cfid -> cfids -> total_dirents_entries );
703+ if (cfid -> dirents .bytes_used ) {
704+ atomic64_sub ((long long )cfid -> dirents .bytes_used ,
705+ & cfid -> cfids -> total_dirents_bytes );
706+ atomic64_sub ((long long )cfid -> dirents .bytes_used ,
707+ & cifs_dircache_bytes_used );
708+ }
709+ }
710+ cfid -> dirents .entries_count = 0 ;
711+ cfid -> dirents .bytes_used = 0 ;
712+
699713 kfree (cfid -> path );
700714 cfid -> path = NULL ;
701715 kfree (cfid );
702716}
703717
704- static void cfids_invalidation_worker (struct work_struct * work )
705- {
706- struct cached_fids * cfids = container_of (work , struct cached_fids ,
707- invalidation_work );
708- struct cached_fid * cfid , * q ;
709- LIST_HEAD (entry );
710-
711- spin_lock (& cfids -> cfid_list_lock );
712- /* move cfids->dying to the local list */
713- list_cut_before (& entry , & cfids -> dying , & cfids -> dying );
714- spin_unlock (& cfids -> cfid_list_lock );
715-
716- list_for_each_entry_safe (cfid , q , & entry , entry ) {
717- list_del (& cfid -> entry );
718- /* Drop the ref-count acquired in invalidate_all_cached_dirs */
719- kref_put (& cfid -> refcount , smb2_close_cached_fid );
720- }
721- }
722-
723718static void cfids_laundromat_worker (struct work_struct * work )
724719{
725720 struct cached_fids * cfids ;
726721 struct cached_fid * cfid , * q ;
727- struct dentry * dentry ;
728722 LIST_HEAD (entry );
729723
730724 cfids = container_of (work , struct cached_fids , laundromat_work .work );
731725
732726 spin_lock (& cfids -> cfid_list_lock );
727+ /* move cfids->dying to the local list */
728+ list_cut_before (& entry , & cfids -> dying , & cfids -> dying );
729+
733730 list_for_each_entry_safe (cfid , q , & cfids -> entries , entry ) {
734731 if (cfid -> last_access_time &&
735732 time_after (jiffies , cfid -> last_access_time + HZ * dir_cache_timeout )) {
@@ -751,12 +748,9 @@ static void cfids_laundromat_worker(struct work_struct *work)
751748 list_for_each_entry_safe (cfid , q , & entry , entry ) {
752749 list_del (& cfid -> entry );
753750
754- spin_lock (& cfid -> fid_lock );
755- dentry = cfid -> dentry ;
751+ dput (cfid -> dentry );
756752 cfid -> dentry = NULL ;
757- spin_unlock (& cfid -> fid_lock );
758753
759- dput (dentry );
760754 if (cfid -> is_open ) {
761755 spin_lock (& cifs_tcp_ses_lock );
762756 ++ cfid -> tcon -> tc_count ;
@@ -769,7 +763,7 @@ static void cfids_laundromat_worker(struct work_struct *work)
769763 * Drop the ref-count from above, either the lease-ref (if there
770764 * was one) or the extra one acquired.
771765 */
772- kref_put ( & cfid -> refcount , smb2_close_cached_fid );
766+ close_cached_dir ( cfid );
773767 }
774768 queue_delayed_work (cfid_put_wq , & cfids -> laundromat_work ,
775769 dir_cache_timeout * HZ );
@@ -786,11 +780,13 @@ struct cached_fids *init_cached_dirs(void)
786780 INIT_LIST_HEAD (& cfids -> entries );
787781 INIT_LIST_HEAD (& cfids -> dying );
788782
789- INIT_WORK (& cfids -> invalidation_work , cfids_invalidation_worker );
790783 INIT_DELAYED_WORK (& cfids -> laundromat_work , cfids_laundromat_worker );
791784 queue_delayed_work (cfid_put_wq , & cfids -> laundromat_work ,
792785 dir_cache_timeout * HZ );
793786
787+ atomic_long_set (& cfids -> total_dirents_entries , 0 );
788+ atomic64_set (& cfids -> total_dirents_bytes , 0 );
789+
794790 return cfids ;
795791}
796792
@@ -807,7 +803,6 @@ void free_cached_dirs(struct cached_fids *cfids)
807803 return ;
808804
809805 cancel_delayed_work_sync (& cfids -> laundromat_work );
810- cancel_work_sync (& cfids -> invalidation_work );
811806
812807 spin_lock (& cfids -> cfid_list_lock );
813808 list_for_each_entry_safe (cfid , q , & cfids -> entries , entry ) {
0 commit comments