@@ -558,7 +558,8 @@ static void remove_oldest_entry_locked(void)
558558}
559559
560560/* Add a new DFS cache entry */
561- static int add_cache_entry_locked (struct dfs_info3_param * refs , int numrefs )
561+ static struct cache_entry * add_cache_entry_locked (struct dfs_info3_param * refs ,
562+ int numrefs )
562563{
563564 int rc ;
564565 struct cache_entry * ce ;
@@ -573,11 +574,11 @@ static int add_cache_entry_locked(struct dfs_info3_param *refs, int numrefs)
573574
574575 rc = cache_entry_hash (refs [0 ].path_name , strlen (refs [0 ].path_name ), & hash );
575576 if (rc )
576- return rc ;
577+ return ERR_PTR ( rc ) ;
577578
578579 ce = alloc_cache_entry (refs , numrefs );
579580 if (IS_ERR (ce ))
580- return PTR_ERR ( ce ) ;
581+ return ce ;
581582
582583 spin_lock (& cache_ttl_lock );
583584 if (!cache_ttl ) {
@@ -594,7 +595,7 @@ static int add_cache_entry_locked(struct dfs_info3_param *refs, int numrefs)
594595
595596 atomic_inc (& cache_count );
596597
597- return 0 ;
598+ return ce ;
598599}
599600
600601/* Check if two DFS paths are equal. @s1 and @s2 are expected to be in @cache_cp's charset */
@@ -767,8 +768,12 @@ static int get_dfs_referral(const unsigned int xid, struct cifs_ses *ses, const
767768 *
768769 * For interlinks, cifs_mount() and expand_dfs_referral() are supposed to
769770 * handle them properly.
771+ *
772+ * On success, return entry with acquired lock for reading, otherwise error ptr.
770773 */
771- static int cache_refresh_path (const unsigned int xid , struct cifs_ses * ses , const char * path )
774+ static struct cache_entry * cache_refresh_path (const unsigned int xid ,
775+ struct cifs_ses * ses ,
776+ const char * path )
772777{
773778 struct dfs_info3_param * refs = NULL ;
774779 struct cache_entry * ce ;
@@ -780,10 +785,9 @@ static int cache_refresh_path(const unsigned int xid, struct cifs_ses *ses, cons
780785 down_read (& htable_rw_lock );
781786
782787 ce = lookup_cache_entry (path );
783- if (!IS_ERR (ce ) && !cache_entry_expired (ce )) {
784- up_read (& htable_rw_lock );
785- return 0 ;
786- }
788+ if (!IS_ERR (ce ) && !cache_entry_expired (ce ))
789+ return ce ;
790+
787791 /*
788792 * Unlock shared access as we don't want to hold any locks while getting
789793 * a new referral. The @ses used for performing the I/O could be
@@ -797,25 +801,35 @@ static int cache_refresh_path(const unsigned int xid, struct cifs_ses *ses, cons
797801 * Request a new DFS referral in order to create or update a cache entry.
798802 */
799803 rc = get_dfs_referral (xid , ses , path , & refs , & numrefs );
800- if (rc )
804+ if (rc ) {
805+ ce = ERR_PTR (rc );
801806 goto out ;
807+ }
802808
803809 dump_refs (refs , numrefs );
804810
805811 down_write (& htable_rw_lock );
806812 /* Re-check as another task might have it added or refreshed already */
807813 ce = lookup_cache_entry (path );
808814 if (!IS_ERR (ce )) {
809- if (cache_entry_expired (ce ))
815+ if (cache_entry_expired (ce )) {
810816 rc = update_cache_entry_locked (ce , refs , numrefs );
817+ if (rc )
818+ ce = ERR_PTR (rc );
819+ }
811820 } else {
812- rc = add_cache_entry_locked (refs , numrefs );
821+ ce = add_cache_entry_locked (refs , numrefs );
813822 }
814823
815- up_write (& htable_rw_lock );
824+ if (IS_ERR (ce )) {
825+ up_write (& htable_rw_lock );
826+ goto out ;
827+ }
828+
829+ downgrade_write (& htable_rw_lock );
816830out :
817831 free_dfs_info_array (refs , numrefs );
818- return rc ;
832+ return ce ;
819833}
820834
821835/*
@@ -935,15 +949,8 @@ int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses, const struct nl
935949 if (IS_ERR (npath ))
936950 return PTR_ERR (npath );
937951
938- rc = cache_refresh_path (xid , ses , npath );
939- if (rc )
940- goto out_free_path ;
941-
942- down_read (& htable_rw_lock );
943-
944- ce = lookup_cache_entry (npath );
952+ ce = cache_refresh_path (xid , ses , npath );
945953 if (IS_ERR (ce )) {
946- up_read (& htable_rw_lock );
947954 rc = PTR_ERR (ce );
948955 goto out_free_path ;
949956 }
@@ -1039,10 +1046,13 @@ int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses,
10391046
10401047 cifs_dbg (FYI , "%s: update target hint - path: %s\n" , __func__ , npath );
10411048
1042- rc = cache_refresh_path (xid , ses , npath );
1043- if (rc )
1049+ ce = cache_refresh_path (xid , ses , npath );
1050+ if (IS_ERR (ce )) {
1051+ rc = PTR_ERR (ce );
10441052 goto out_free_path ;
1053+ }
10451054
1055+ up_read (& htable_rw_lock );
10461056 down_write (& htable_rw_lock );
10471057
10481058 ce = lookup_cache_entry (npath );
0 commit comments