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: Weston Andros Adamson <dros@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
committed by
Trond Myklebust
parent
a030889a01
commit
2d3fe01c36
@@ -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)
|
list_for_each_entry(ds, &nfs4_data_server_cache, ds_node)
|
||||||
count1++;
|
if (_same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs))
|
||||||
|
return ds;
|
||||||
list_for_each_entry(da2, dsaddrs2, da_node) {
|
return NULL;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -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);
|
||||||
|
Reference in New Issue
Block a user