@@ -1095,16 +1095,18 @@ int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it,
10951095 return 0 ;
10961096}
10971097
1098- static bool target_share_equal (struct TCP_Server_Info * server , const char * s1 , const char * s2 )
1098+ static bool target_share_equal (struct cifs_tcon * tcon , const char * s1 )
10991099{
1100- char unc [sizeof ("\\\\" ) + SERVER_NAME_LENGTH ] = {0 };
1100+ struct TCP_Server_Info * server = tcon -> ses -> server ;
1101+ struct sockaddr_storage ss ;
11011102 const char * host ;
1103+ const char * s2 = & tcon -> tree_name [1 ];
11021104 size_t hostlen ;
1103- struct sockaddr_storage ss ;
1105+ char unc [ sizeof ( "\\\\" ) + SERVER_NAME_LENGTH ] = { 0 } ;
11041106 bool match ;
11051107 int rc ;
11061108
1107- if (strcasecmp (s1 , s2 ))
1109+ if (strcasecmp (s2 , s1 ))
11081110 return false;
11091111
11101112 /*
@@ -1128,34 +1130,6 @@ static bool target_share_equal(struct TCP_Server_Info *server, const char *s1, c
11281130 return match ;
11291131}
11301132
1131- /*
1132- * Mark dfs tcon for reconnecting when the currently connected tcon does not match any of the new
1133- * target shares in @refs.
1134- */
1135- static void mark_for_reconnect_if_needed (struct TCP_Server_Info * server ,
1136- const char * path ,
1137- struct dfs_cache_tgt_list * old_tl ,
1138- struct dfs_cache_tgt_list * new_tl )
1139- {
1140- struct dfs_cache_tgt_iterator * oit , * nit ;
1141-
1142- for (oit = dfs_cache_get_tgt_iterator (old_tl ); oit ;
1143- oit = dfs_cache_get_next_tgt (old_tl , oit )) {
1144- for (nit = dfs_cache_get_tgt_iterator (new_tl ); nit ;
1145- nit = dfs_cache_get_next_tgt (new_tl , nit )) {
1146- if (target_share_equal (server ,
1147- dfs_cache_get_tgt_name (oit ),
1148- dfs_cache_get_tgt_name (nit ))) {
1149- dfs_cache_noreq_update_tgthint (path , nit );
1150- return ;
1151- }
1152- }
1153- }
1154-
1155- cifs_dbg (FYI , "%s: no cached or matched targets. mark dfs share for reconnect.\n" , __func__ );
1156- cifs_signal_cifsd_for_reconnect (server , true);
1157- }
1158-
11591133static bool is_ses_good (struct cifs_ses * ses )
11601134{
11611135 struct TCP_Server_Info * server = ses -> server ;
@@ -1172,41 +1146,35 @@ static bool is_ses_good(struct cifs_ses *ses)
11721146 return ret ;
11731147}
11741148
1175- /* Refresh dfs referral of @ses and mark it for reconnect if needed */
1176- static void __refresh_ses_referral (struct cifs_ses * ses , bool force_refresh )
1149+ static char * get_ses_refpath (struct cifs_ses * ses )
11771150{
11781151 struct TCP_Server_Info * server = ses -> server ;
1179- DFS_CACHE_TGT_LIST (old_tl );
1180- DFS_CACHE_TGT_LIST (new_tl );
1181- bool needs_refresh = false;
1182- struct cache_entry * ce ;
1183- unsigned int xid ;
1184- char * path = NULL ;
1185- int rc = 0 ;
1186-
1187- xid = get_xid ();
1152+ char * path = ERR_PTR (- ENOENT );
11881153
11891154 mutex_lock (& server -> refpath_lock );
11901155 if (server -> leaf_fullpath ) {
11911156 path = kstrdup (server -> leaf_fullpath + 1 , GFP_ATOMIC );
11921157 if (!path )
1193- rc = - ENOMEM ;
1158+ path = ERR_PTR ( - ENOMEM ) ;
11941159 }
11951160 mutex_unlock (& server -> refpath_lock );
1196- if (! path )
1197- goto out ;
1161+ return path ;
1162+ }
11981163
1199- down_read (& htable_rw_lock );
1200- ce = lookup_cache_entry (path );
1201- needs_refresh = force_refresh || IS_ERR (ce ) || cache_entry_expired (ce );
1202- if (!IS_ERR (ce )) {
1203- rc = get_targets (ce , & old_tl );
1204- cifs_dbg (FYI , "%s: get_targets: %d\n" , __func__ , rc );
1205- }
1206- up_read (& htable_rw_lock );
1164+ /* Refresh dfs referral of @ses */
1165+ static void refresh_ses_referral (struct cifs_ses * ses )
1166+ {
1167+ struct cache_entry * ce ;
1168+ unsigned int xid ;
1169+ char * path ;
1170+ int rc = 0 ;
12071171
1208- if (!needs_refresh ) {
1209- rc = 0 ;
1172+ xid = get_xid ();
1173+
1174+ path = get_ses_refpath (ses );
1175+ if (IS_ERR (path )) {
1176+ rc = PTR_ERR (path );
1177+ path = NULL ;
12101178 goto out ;
12111179 }
12121180
@@ -1217,29 +1185,106 @@ static void __refresh_ses_referral(struct cifs_ses *ses, bool force_refresh)
12171185 goto out ;
12181186 }
12191187
1220- ce = cache_refresh_path (xid , ses , path , true);
1221- if (!IS_ERR (ce )) {
1222- rc = get_targets (ce , & new_tl );
1188+ ce = cache_refresh_path (xid , ses , path , false);
1189+ if (!IS_ERR (ce ))
12231190 up_read (& htable_rw_lock );
1224- cifs_dbg (FYI , "%s: get_targets: %d\n" , __func__ , rc );
1225- mark_for_reconnect_if_needed (server , path , & old_tl , & new_tl );
1226- }
1191+ else
1192+ rc = PTR_ERR (ce );
12271193
12281194out :
12291195 free_xid (xid );
1230- dfs_cache_free_tgts (& old_tl );
1231- dfs_cache_free_tgts (& new_tl );
12321196 kfree (path );
12331197}
12341198
1235- static inline void refresh_ses_referral (struct cifs_ses * ses )
1199+ static int __refresh_tcon_referral (struct cifs_tcon * tcon ,
1200+ const char * path ,
1201+ struct dfs_info3_param * refs ,
1202+ int numrefs , bool force_refresh )
12361203{
1237- __refresh_ses_referral (ses , false);
1204+ struct cache_entry * ce ;
1205+ bool reconnect = force_refresh ;
1206+ int rc = 0 ;
1207+ int i ;
1208+
1209+ if (unlikely (!numrefs ))
1210+ return 0 ;
1211+
1212+ if (force_refresh ) {
1213+ for (i = 0 ; i < numrefs ; i ++ ) {
1214+ /* TODO: include prefix paths in the matching */
1215+ if (target_share_equal (tcon , refs [i ].node_name )) {
1216+ reconnect = false;
1217+ break ;
1218+ }
1219+ }
1220+ }
1221+
1222+ down_write (& htable_rw_lock );
1223+ ce = lookup_cache_entry (path );
1224+ if (!IS_ERR (ce )) {
1225+ if (force_refresh || cache_entry_expired (ce ))
1226+ rc = update_cache_entry_locked (ce , refs , numrefs );
1227+ } else if (PTR_ERR (ce ) == - ENOENT ) {
1228+ ce = add_cache_entry_locked (refs , numrefs );
1229+ }
1230+ up_write (& htable_rw_lock );
1231+
1232+ if (IS_ERR (ce ))
1233+ rc = PTR_ERR (ce );
1234+ if (reconnect ) {
1235+ cifs_tcon_dbg (FYI , "%s: mark for reconnect\n" , __func__ );
1236+ cifs_signal_cifsd_for_reconnect (tcon -> ses -> server , true);
1237+ }
1238+ return rc ;
12381239}
12391240
1240- static inline void force_refresh_ses_referral (struct cifs_ses * ses )
1241+ static void refresh_tcon_referral (struct cifs_tcon * tcon , bool force_refresh )
12411242{
1242- __refresh_ses_referral (ses , true);
1243+ struct dfs_info3_param * refs = NULL ;
1244+ struct cache_entry * ce ;
1245+ struct cifs_ses * ses ;
1246+ unsigned int xid ;
1247+ bool needs_refresh ;
1248+ char * path ;
1249+ int numrefs = 0 ;
1250+ int rc = 0 ;
1251+
1252+ xid = get_xid ();
1253+ ses = tcon -> ses ;
1254+
1255+ path = get_ses_refpath (ses );
1256+ if (IS_ERR (path )) {
1257+ rc = PTR_ERR (path );
1258+ path = NULL ;
1259+ goto out ;
1260+ }
1261+
1262+ down_read (& htable_rw_lock );
1263+ ce = lookup_cache_entry (path );
1264+ needs_refresh = force_refresh || IS_ERR (ce ) || cache_entry_expired (ce );
1265+ if (!needs_refresh ) {
1266+ up_read (& htable_rw_lock );
1267+ goto out ;
1268+ }
1269+ up_read (& htable_rw_lock );
1270+
1271+ ses = CIFS_DFS_ROOT_SES (ses );
1272+ if (!is_ses_good (ses )) {
1273+ cifs_dbg (FYI , "%s: skip cache refresh due to disconnected ipc\n" ,
1274+ __func__ );
1275+ goto out ;
1276+ }
1277+
1278+ rc = get_dfs_referral (xid , ses , path , & refs , & numrefs );
1279+ if (!rc ) {
1280+ rc = __refresh_tcon_referral (tcon , path , refs ,
1281+ numrefs , force_refresh );
1282+ }
1283+
1284+ out :
1285+ free_xid (xid );
1286+ kfree (path );
1287+ free_dfs_info_array (refs , numrefs );
12431288}
12441289
12451290/**
@@ -1280,7 +1325,7 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
12801325 */
12811326 cifs_sb -> mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH ;
12821327
1283- force_refresh_ses_referral (tcon -> ses );
1328+ refresh_tcon_referral (tcon , true );
12841329 return 0 ;
12851330}
12861331
@@ -1291,9 +1336,11 @@ void dfs_cache_refresh(struct work_struct *work)
12911336 struct cifs_ses * ses ;
12921337
12931338 tcon = container_of (work , struct cifs_tcon , dfs_cache_work .work );
1339+ ses = tcon -> ses -> dfs_root_ses ;
12941340
1295- for (ses = tcon -> ses ; ses ; ses = ses -> dfs_root_ses )
1341+ for (; ses ; ses = ses -> dfs_root_ses )
12961342 refresh_ses_referral (ses );
1343+ refresh_tcon_referral (tcon , false);
12971344
12981345 queue_delayed_work (dfscache_wq , & tcon -> dfs_cache_work ,
12991346 atomic_read (& dfs_cache_ttl ) * HZ );
0 commit comments