diff mbox

NFSv4.1/pNFS: Fix borken function _same_data_server_addrs_locked()

Message ID 1439480749-54600-1-git-send-email-trond.myklebust@primarydata.com (mailing list archive)
State New, archived
Headers show

Commit Message

Trond Myklebust Aug. 13, 2015, 3:45 p.m. UTC
- Switch back to using list_for_each_entry(). To fix an incorrect test
  for list NULL termination.
- Do not assume that lists are sorted.
- Finally, consider an existing entry to match if it consists of a subset
  of the addresses in the new entry.

Cc: stable@vger.kernel.org # 4.0+
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfs/pnfs_nfs.c | 33 +++++++++++++++++++--------------
 1 file changed, 19 insertions(+), 14 deletions(-)

Comments

Trond Myklebust Aug. 13, 2015, 5:20 p.m. UTC | #1
On Thu, Aug 13, 2015 at 11:45 AM, Trond Myklebust
<trond.myklebust@primarydata.com> wrote:
>
> - Switch back to using list_for_each_entry(). To fix an incorrect test
>   for list NULL termination.
> - Do not assume that lists are sorted.
> - Finally, consider an existing entry to match if it consists of a subset
>   of the addresses in the new entry.
>
> Cc: stable@vger.kernel.org # 4.0+

Note that the bug predates Linux-4.0; it goes all the way back to
February 2012. This patch will not apply to older versions though,
since it used to live in fs/nfs/filelayout/filelayoutdev.c.

Cheers
  Trond
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jeff Layton Aug. 13, 2015, 6:26 p.m. UTC | #2
On Thu, 13 Aug 2015 11:45:49 -0400
Trond Myklebust <trond.myklebust@primarydata.com> wrote:

> - Switch back to using list_for_each_entry(). To fix an incorrect test
>   for list NULL termination.
> - Do not assume that lists are sorted.
> - Finally, consider an existing entry to match if it consists of a subset
>   of the addresses in the new entry.
> 
> Cc: stable@vger.kernel.org # 4.0+
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> ---
>  fs/nfs/pnfs_nfs.c | 33 +++++++++++++++++++--------------
>  1 file changed, 19 insertions(+), 14 deletions(-)
> 
> diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c
> index cd3c0403101b..bbd407b6bc1f 100644
> --- a/fs/nfs/pnfs_nfs.c
> +++ b/fs/nfs/pnfs_nfs.c
> @@ -373,26 +373,31 @@ same_sockaddr(struct sockaddr *addr1, struct sockaddr *addr2)
>  	return false;
>  }
>  
> +/*
> + * Checks if 'dsaddrs1' contains a subset of 'dsaddrs2'. If it does,
> + * declare a match.
> + */
>  static bool
>  _same_data_server_addrs_locked(const struct list_head *dsaddrs1,
>  			       const struct list_head *dsaddrs2)
>  {
>  	struct nfs4_pnfs_ds_addr *da1, *da2;
> -
> -	/* step through both lists, comparing as we go */
> -	for (da1 = list_first_entry(dsaddrs1, typeof(*da1), da_node),
> -	     da2 = list_first_entry(dsaddrs2, typeof(*da2), da_node);
> -	     da1 != NULL && da2 != NULL;
> -	     da1 = list_entry(da1->da_node.next, typeof(*da1), da_node),
> -	     da2 = list_entry(da2->da_node.next, typeof(*da2), da_node)) {
> -		if (!same_sockaddr((struct sockaddr *)&da1->da_addr,
> -				   (struct sockaddr *)&da2->da_addr))
> -			return false;
> +	struct sockaddr *sa1, *sa2;
> +	bool match = false;
> +
> +	list_for_each_entry(da1, dsaddrs1, da_node) {
> +		sa1 = (struct sockaddr *)&da1->da_addr;
> +		match = false;
> +		list_for_each_entry(da2, dsaddrs2, da_node) {
> +			sa2 = (struct sockaddr *)&da2->da_addr;
> +			match = same_sockaddr(sa1, sa2);
> +			if (match)
> +				break;

Sure would be nice to consolidate some of these "same_sockaddr"
functions at some point. We also have nfs_sockaddr_cmp which does the
exact same thing, and probably some similar ones in the RPC layer.

> +		}
> +		if (!match)
> +			break;
>  	}
> -	if (da1 == NULL && da2 == NULL)
> -		return true;
> -
> -	return false;
> +	return match;
>  }
>  
>  /*

Nice catch:

Reviewed-by: Jeff Layton <jeff.layton@primarydata.com>
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c
index cd3c0403101b..bbd407b6bc1f 100644
--- a/fs/nfs/pnfs_nfs.c
+++ b/fs/nfs/pnfs_nfs.c
@@ -373,26 +373,31 @@  same_sockaddr(struct sockaddr *addr1, struct sockaddr *addr2)
 	return false;
 }
 
+/*
+ * Checks if 'dsaddrs1' contains a subset of 'dsaddrs2'. If it does,
+ * declare a match.
+ */
 static bool
 _same_data_server_addrs_locked(const struct list_head *dsaddrs1,
 			       const struct list_head *dsaddrs2)
 {
 	struct nfs4_pnfs_ds_addr *da1, *da2;
-
-	/* step through both lists, comparing as we go */
-	for (da1 = list_first_entry(dsaddrs1, typeof(*da1), da_node),
-	     da2 = list_first_entry(dsaddrs2, typeof(*da2), da_node);
-	     da1 != NULL && da2 != NULL;
-	     da1 = list_entry(da1->da_node.next, typeof(*da1), da_node),
-	     da2 = list_entry(da2->da_node.next, typeof(*da2), da_node)) {
-		if (!same_sockaddr((struct sockaddr *)&da1->da_addr,
-				   (struct sockaddr *)&da2->da_addr))
-			return false;
+	struct sockaddr *sa1, *sa2;
+	bool match = false;
+
+	list_for_each_entry(da1, dsaddrs1, da_node) {
+		sa1 = (struct sockaddr *)&da1->da_addr;
+		match = false;
+		list_for_each_entry(da2, dsaddrs2, da_node) {
+			sa2 = (struct sockaddr *)&da2->da_addr;
+			match = same_sockaddr(sa1, sa2);
+			if (match)
+				break;
+		}
+		if (!match)
+			break;
 	}
-	if (da1 == NULL && da2 == NULL)
-		return true;
-
-	return false;
+	return match;
 }
 
 /*