Re: [PATCH] Bug 11061, NFS mounts dropped

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 2009-02-11 at 23:07 +1030, Ian Dall wrote:
> On Mon, 2009-02-09 at 16:11 -0500, Chuck Lever wrote:
> > Hi Ian-
> > 
> > On Feb 8, 2009, at 6:55 AM, Ian Dall wrote:
> > > On Wed, 2009-02-04 at 13:47 -0500, Trond Myklebust wrote:
> > >> On Wed, 2009-02-04 at 13:44 -0500, Chuck Lever wrote:
> > >>> Right.  So, then, can nfs_match_client() use the same address
> > >>> comparison method as nfs_find_client()?  I'm inclined to think
> > >>> nfs_match_client() can use a more straightforward address comparison
> > >>> method.
> 
> > > Log:
> > > ======================
> > > sockaddr structures can't be reliably compared using memcmp()
> > > because there are padding bytes in the structure which can't be
> > > guaranteed to be the same even when the sockaddr structures refer to
> > > the same socket.
> > 
> > It is also the case that IPv6 socket address structures contain other  
> > fields that don't have to match, like sin6_scope_id.  I think that is  
> > worth noting in the patch description.
> > 
> > I don't see anything immediately wrong with this approach, but I made  
> > a couple of additional minor comments below.
> > 
> > > Signed-off-by: Ian Dall <ian@xxxxxxxxxxxxxxxxxxxxx>
> 
> Apparently this should be "From" (for the author) not "Signed-off-by"
> According to Andrew Morton commenting on a completely different patch.

No. Signed-off-by: is correct at the end of the changelog, however a
'From' as the very first line, helps git track who was the original
author.

> > > ======================
> > > diff --git a/fs/nfs/client.c b/fs/nfs/client.c
> > > index 9b728f3..04b11d9 100644
> > > --- a/fs/nfs/client.c
> > > +++ b/fs/nfs/client.c
> > > @@ -272,6 +272,42 @@ static int nfs_sockaddr_match_ipaddr(const  
> > > struct sockaddr *sa1,
> > > }
> > > #endif
> > >
> > > +/* Test if two socket addresses are the same family, ipaddr and  
> > > port */
> > 
> > Instead of repeating what the function does, can this comment explain  
> > why the NFS client needs to match on the address and port, for example?
> > 
> > Explaining why it is different than the existing  
> > nfs_sockaddr_match_ipaddr() function would be helpful for future  
> > generations.
> 
> Wouldn't this be more appropriate where the function is called? I know
> that it is only called from one place, but still, I would have thought
> the obvious thing to do would be document what a function does where you
> define it and document why you are calling it when you are calling it.
> Either way, I don't actually *know* why we need to match on port number!
> I have to confess no deep understanding of the difference between
> nfs_match_client and nfs_find_client. I only did a bisection to find the
> commit which caused the regression, then fixed it.
> 
> If someone who does understand wants to contribute a description, that's
> fine by me! Following the principle of one change per patch, it may as
> well be a different commit since it would relevant regardless of my
> patch. The current code (with the memcmp) compares everything, it's just
> that it compares too much.
> 
> > As a stylistic point, these days we prefer to use a helper function  
> > instead of curly braces inside the arms of the switch.  It will also  
> > remove the need to fold those lines.
> > 
> > I have used this style in the past, but there is general consensus now  
> > that helper functions are easier to read, and are therefore preferred.
> 
> Yes, I blame it on the prevalence of OO programming where it is routine
> to have a helper functions which to do nothing more than get a field out
> of a structure ;-(  
> 
> Here is a new patch with helper functions, improved ipv6 comparison
> (though I can not test this and my understanding of ipv6 is almost
> certainly incomplete), better comments and a better log entry. 
> 
> Log:
> ======================
> sockaddr structures can't be reliably compared using memcmp()
> because there are padding bytes in the structure which can't be
> guaranteed to be the same even when the sockaddr structures refer to
> the same socket. Instead compare all the relevant fields. These are
> sin_addr and sin_port number for IPv4. In the case of IPv6 they are
> sin6_addr, sin6_port and sin6_scope_id, which is relevant for  link
> local addresses. The sin6_flowinfo field only affects QoS and is not
> compared. 
> 
> From: Ian Dall <ian@xxxxxxxxxxxxxxxxxxxxx>
> ======================
> diff --git a/fs/nfs/client.c b/fs/nfs/client.c
> index 9b728f3..efdae09 100644
> --- a/fs/nfs/client.c
> +++ b/fs/nfs/client.c
> @@ -272,6 +272,62 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
>  }
>  #endif
>  
> +/* Test if two ip4 socket addresses have the same ipaddr and port number */
> +static int nfs_sockaddr_cmp_ip4 (const struct sockaddr_in * saddr1,
> +			  const struct sockaddr_in * saddr2)
> +{
> +	/* Compare ip4 address */
> +	if (likely(saddr1->sin_addr.s_addr !=
> +		   saddr2->sin_addr.s_addr)) {

I don't think you really want the 'likely()' here. If you only have one
server, then the resulting "optimisation" would be incorrect. I'd
therefore leave it out.

> +		return 0;
> +	}
> +	/* Compare port */
> +	return (saddr1->sin_port == saddr2->sin_port);
> +}
> +
> +/* Test if two ip6 socket addresses have the same ipaddr, scope_id and
> + * port number.
> + */
> +static int nfs_sockaddr_cmp_ip6 (const struct sockaddr_in6 * saddr1,
> +			  const struct sockaddr_in6 * saddr2)
> +{
> +	/* Compare ip6 address */
> +	if (likely(!ipv6_addr_equal(&saddr1->sin6_addr,
> +				    &saddr1->sin6_addr))) {

Ditto...

> +		return 0;
> +	}
> +
> +	/* Compare scope_id. This may only matter for link local
> +	 * addresses, but it is cheap, and should be harmless, to just
> +	 * compare it anyway.
> +	 */
> +	if (saddr1->sin6_scope_id != saddr2->sin6_scope_id)
> +		return 0;
> +	/* Don't compare sin6_flowinfo since it is to do with QoS, but
> +	 * doesn't effect the packets source or destination.
> +	 */ 
> +	/* Compare ports */
> +	return (saddr1->sin6_port == saddr2->sin6_port);
> +}
> +
> +/* Test if two socket addresses represent the same actual socket */
> +static int nfs_sockaddr_cmp(const struct sockaddr *sa1,
> +			      const struct sockaddr *sa2)
> +{
> +	if (sa1->sa_family != sa2->sa_family)
> +		return 0;
> +  
> +	switch (sa1->sa_family) {
> +	case AF_INET:
> +		return nfs_sockaddr_cmp_ip4 ((const struct sockaddr_in *) sa1,
> +					     (const struct sockaddr_in *) sa2);
> +	case AF_INET6:
> +		return nfs_sockaddr_cmp_ip6 ((const struct sockaddr_in6 *) sa1,
> +					     (const struct sockaddr_in6 *) sa2);
> +	}
> +	return 0;
> +}
> +
>  /*
>   * Find a client by IP address and protocol version
>   * - returns NULL if no such client
> @@ -344,8 +400,10 @@ struct nfs_client *nfs_find_client_next(struct nfs_client *clp)
>  static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *data)
>  {
>  	struct nfs_client *clp;
> +	const struct sockaddr *sap = data->addr;
>  
>  	list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
> +	        const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
>  		/* Don't match clients that failed to initialise properly */
>  		if (clp->cl_cons_state < 0)
>  			continue;
> @@ -358,7 +416,7 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
>  			continue;
>  
>  		/* Match the full socket address */
> -		if (memcmp(&clp->cl_addr, data->addr, sizeof(clp->cl_addr)) != 0)
> +		if (!nfs_sockaddr_cmp(sap, clap))
>  			continue;
>  
>  		atomic_inc(&clp->cl_count);
> 
> 
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux