Commit 2d3fe01c authored by Weston Andros Adamson's avatar Weston Andros Adamson Committed by Trond Myklebust

NFS: Fix comparison between DS address lists

data_server_cache entries should only be treated as the same if the address
list hasn't changed.

A new entry will be made when an MDS changes an address list (as seen by
GETDEVINFO). The old entry will be freed once all references are gone.
Signed-off-by: default avatarWeston Andros Adamson <dros@netapp.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent a030889a
...@@ -108,58 +108,40 @@ same_sockaddr(struct sockaddr *addr1, struct sockaddr *addr2) ...@@ -108,58 +108,40 @@ same_sockaddr(struct sockaddr *addr1, struct sockaddr *addr2)
return false; return false;
} }
/* bool
* Lookup DS by addresses. The first matching address returns true. _same_data_server_addrs_locked(const struct list_head *dsaddrs1,
* nfs4_ds_cache_lock is held const struct list_head *dsaddrs2)
*/
static struct nfs4_pnfs_ds *
_data_server_lookup_locked(struct list_head *dsaddrs)
{ {
struct nfs4_pnfs_ds *ds;
struct nfs4_pnfs_ds_addr *da1, *da2; struct nfs4_pnfs_ds_addr *da1, *da2;
list_for_each_entry(da1, dsaddrs, da_node) { /* step through both lists, comparing as we go */
list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) { for (da1 = list_first_entry(dsaddrs1, typeof(*da1), da_node),
list_for_each_entry(da2, &ds->ds_addrs, da_node) { da2 = list_first_entry(dsaddrs2, typeof(*da2), da_node);
if (same_sockaddr( da1 != NULL && da2 != NULL;
(struct sockaddr *)&da1->da_addr, da1 = list_entry(da1->da_node.next, typeof(*da1), da_node),
(struct sockaddr *)&da2->da_addr)) da2 = list_entry(da2->da_node.next, typeof(*da2), da_node)) {
return ds; if (!same_sockaddr((struct sockaddr *)&da1->da_addr,
} (struct sockaddr *)&da2->da_addr))
} return false;
} }
return NULL; if (da1 == NULL && da2 == NULL)
return true;
return false;
} }
/* /*
* Compare two lists of addresses. * Lookup DS by addresses. nfs4_ds_cache_lock is held
*/ */
static bool static struct nfs4_pnfs_ds *
_data_server_match_all_addrs_locked(struct list_head *dsaddrs1, _data_server_lookup_locked(const struct list_head *dsaddrs)
struct list_head *dsaddrs2)
{ {
struct nfs4_pnfs_ds_addr *da1, *da2; struct nfs4_pnfs_ds *ds;
size_t count1 = 0,
count2 = 0;
list_for_each_entry(da1, dsaddrs1, da_node)
count1++;
list_for_each_entry(da2, dsaddrs2, da_node) {
bool found = false;
count2++;
list_for_each_entry(da1, dsaddrs1, da_node) {
if (same_sockaddr((struct sockaddr *)&da1->da_addr,
(struct sockaddr *)&da2->da_addr)) {
found = true;
break;
}
}
if (!found)
return false;
}
return (count1 == count2); list_for_each_entry(ds, &nfs4_data_server_cache, ds_node)
if (_same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs))
return ds;
return NULL;
} }
/* /*
...@@ -356,11 +338,6 @@ nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags) ...@@ -356,11 +338,6 @@ nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags)
dprintk("%s add new data server %s\n", __func__, dprintk("%s add new data server %s\n", __func__,
ds->ds_remotestr); ds->ds_remotestr);
} else { } else {
if (!_data_server_match_all_addrs_locked(&tmp_ds->ds_addrs,
dsaddrs)) {
dprintk("%s: multipath address mismatch: %s != %s",
__func__, tmp_ds->ds_remotestr, remotestr);
}
kfree(remotestr); kfree(remotestr);
kfree(ds); kfree(ds);
atomic_inc(&tmp_ds->ds_count); atomic_inc(&tmp_ds->ds_count);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment