@@ -146,6 +146,16 @@ cifs_chan_needs_reconnect(struct cifs_ses *ses,
146146 return CIFS_CHAN_NEEDS_RECONNECT (ses , chan_index );
147147}
148148
149+ bool
150+ cifs_chan_is_iface_active (struct cifs_ses * ses ,
151+ struct TCP_Server_Info * server )
152+ {
153+ unsigned int chan_index = cifs_ses_get_chan_index (ses , server );
154+
155+ return ses -> chans [chan_index ].iface &&
156+ ses -> chans [chan_index ].iface -> is_active ;
157+ }
158+
149159/* returns number of channels added */
150160int cifs_try_adding_channels (struct cifs_sb_info * cifs_sb , struct cifs_ses * ses )
151161{
@@ -244,6 +254,75 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
244254 return new_chan_count - old_chan_count ;
245255}
246256
257+ /*
258+ * update the iface for the channel if necessary.
259+ * will return 0 when iface is updated. 1 otherwise
260+ * Must be called with chan_lock held.
261+ */
262+ int
263+ cifs_chan_update_iface (struct cifs_ses * ses , struct TCP_Server_Info * server )
264+ {
265+ unsigned int chan_index = cifs_ses_get_chan_index (ses , server );
266+ struct cifs_server_iface * iface = NULL ;
267+ struct cifs_server_iface * old_iface = NULL ;
268+ int rc = 0 ;
269+
270+ /* primary channel. This can never go away */
271+ if (!chan_index )
272+ return 0 ;
273+
274+ if (ses -> chans [chan_index ].iface ) {
275+ old_iface = ses -> chans [chan_index ].iface ;
276+ if (old_iface -> is_active )
277+ return 1 ;
278+ }
279+
280+ spin_lock (& ses -> iface_lock );
281+
282+ /* then look for a new one */
283+ list_for_each_entry (iface , & ses -> iface_list , iface_head ) {
284+ if (!iface -> is_active ||
285+ (is_ses_using_iface (ses , iface ) &&
286+ !iface -> rss_capable )) {
287+ continue ;
288+ }
289+ kref_get (& iface -> refcount );
290+ }
291+
292+ if (!list_entry_is_head (iface , & ses -> iface_list , iface_head )) {
293+ rc = 1 ;
294+ iface = NULL ;
295+ cifs_dbg (FYI , "unable to find a suitable iface\n" );
296+ }
297+
298+ ses -> chans [chan_index ].iface = iface ;
299+
300+ /* now drop the ref to the current iface */
301+ if (old_iface && iface ) {
302+ kref_put (& old_iface -> refcount , release_iface );
303+ cifs_dbg (FYI , "replacing iface: %pIS with %pIS\n" ,
304+ & old_iface -> sockaddr ,
305+ & iface -> sockaddr );
306+ } else if (old_iface ) {
307+ kref_put (& old_iface -> refcount , release_iface );
308+ cifs_dbg (FYI , "releasing ref to iface: %pIS\n" ,
309+ & old_iface -> sockaddr );
310+ } else {
311+ WARN_ON (!iface );
312+ cifs_dbg (FYI , "adding new iface: %pIS\n" , & iface -> sockaddr );
313+ }
314+
315+ spin_unlock (& ses -> iface_lock );
316+
317+ /* No iface is found. if secondary chan, drop connection */
318+ if (!iface && CIFS_SERVER_IS_CHAN (server )) {
319+ cifs_put_tcp_session (server , false);
320+ ses -> chans [chan_index ].server = NULL ;
321+ }
322+
323+ return rc ;
324+ }
325+
247326/*
248327 * If server is a channel of ses, return the corresponding enclosing
249328 * cifs_chan otherwise return NULL.
0 commit comments