Re: [PATCH] lockd: create NSM handles per net namespace

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

 



On 09/29/2015 09:47 PM, J. Bruce Fields wrote:
> On Wed, Sep 23, 2015 at 03:49:29PM +0300, Andrey Ryabinin wrote:
>> Commit cb7323fffa85 ("lockd: create and use per-net NSM
>>  RPC clients on MON/UNMON requests") introduced per-net
>> NSM RPC clients. Unfortunately this doesn't make any sense
>> without per-net nsm_handle.
> 
> Makes sense to me.  Is anyone doing testing to make sure we've got this
> right now?
> 
> (For example, have you reproduced the below problem and verified that
> it's fixed after this patch?)
> 

Yes, that NULL-ptr was actually hit, so I've fixed it with this patch.

BTW, after this patch we could get rid of that per-net nsm-rpc-clients stuff.
With per-net nsm_handles, rpc clients are already per-net.

AFAIK the only reason for them was introduced is because RPC client need to know 'utsname()->nodename',
but utsname() might be NULL when nsm_unmonitor() called.
So we could just save nodename e.g. in nlm_host struct and pass it to rpc_create(). Thus we don't need
to keep rpc client untill last unmonitor request. We could create/destroy separate RPC client for each
monitor/unmonitor request. IOW, like it was before cb7323fffa85 ("lockd: create and use per-net NSM RPC clients on MON/UNMON requests")

Anyway, this is a subject for a separate patch.



> --b.
> 
>>
>> E.g. the following scenario could happen
>> Two hosts (X and Y) in different namespaces (A and B) share
>> the same nsm struct.
>>
>> 1. nsm_monitor(host_X) called => NSM rpc client created,
>> 	nsm->sm_monitored bit set.
>> 2. nsm_mointor(host-Y) called => nsm->sm_monitored already set,
>> 	we just exit. Thus in namespace B ln->nsm_clnt == NULL.
>> 3. host X destroyed => nsm->sm_count decremented to 1
>> 4. host Y destroyed => nsm_unmonitor() => nsm_mon_unmon() => NULL-ptr
>> 	dereference of *ln->nsm_clnt
>>
>> So this could be fixed by making per-net nsm_handles list,
>> instead of global. Thus different net namespaces will not be able
>> share the same nsm_handle.
>>
>> Signed-off-by: Andrey Ryabinin <aryabinin@xxxxxxxxxxxxx>
>> Cc: <stable@xxxxxxxxxxxxxxx>
>> ---
>>  fs/lockd/host.c             |  7 ++++---
>>  fs/lockd/mon.c              | 36 ++++++++++++++++++++++--------------
>>  fs/lockd/netns.h            |  1 +
>>  fs/lockd/svc.c              |  1 +
>>  fs/lockd/svc4proc.c         |  2 +-
>>  fs/lockd/svcproc.c          |  2 +-
>>  include/linux/lockd/lockd.h |  9 ++++++---
>>  7 files changed, 36 insertions(+), 22 deletions(-)
>>
>> diff --git a/fs/lockd/host.c b/fs/lockd/host.c
>> index 969d589..b5f3c3a 100644
>> --- a/fs/lockd/host.c
>> +++ b/fs/lockd/host.c
>> @@ -116,7 +116,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
>>  		atomic_inc(&nsm->sm_count);
>>  	else {
>>  		host = NULL;
>> -		nsm = nsm_get_handle(ni->sap, ni->salen,
>> +		nsm = nsm_get_handle(ni->net, ni->sap, ni->salen,
>>  					ni->hostname, ni->hostname_len);
>>  		if (unlikely(nsm == NULL)) {
>>  			dprintk("lockd: %s failed; no nsm handle\n",
>> @@ -534,17 +534,18 @@ static struct nlm_host *next_host_state(struct hlist_head *cache,
>>  
>>  /**
>>   * nlm_host_rebooted - Release all resources held by rebooted host
>> + * @net:  network namespace
>>   * @info: pointer to decoded results of NLM_SM_NOTIFY call
>>   *
>>   * We were notified that the specified host has rebooted.  Release
>>   * all resources held by that peer.
>>   */
>> -void nlm_host_rebooted(const struct nlm_reboot *info)
>> +void nlm_host_rebooted(const struct net *net, const struct nlm_reboot *info)
>>  {
>>  	struct nsm_handle *nsm;
>>  	struct nlm_host	*host;
>>  
>> -	nsm = nsm_reboot_lookup(info);
>> +	nsm = nsm_reboot_lookup(net, info);
>>  	if (unlikely(nsm == NULL))
>>  		return;
>>  
>> diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
>> index 47a32b6..6c05cd1 100644
>> --- a/fs/lockd/mon.c
>> +++ b/fs/lockd/mon.c
>> @@ -51,7 +51,6 @@ struct nsm_res {
>>  };
>>  
>>  static const struct rpc_program	nsm_program;
>> -static				LIST_HEAD(nsm_handles);
>>  static				DEFINE_SPINLOCK(nsm_lock);
>>  
>>  /*
>> @@ -264,33 +263,35 @@ void nsm_unmonitor(const struct nlm_host *host)
>>  	}
>>  }
>>  
>> -static struct nsm_handle *nsm_lookup_hostname(const char *hostname,
>> -					      const size_t len)
>> +static struct nsm_handle *nsm_lookup_hostname(const struct list_head *nsm_handles,
>> +					const char *hostname, const size_t len)
>>  {
>>  	struct nsm_handle *nsm;
>>  
>> -	list_for_each_entry(nsm, &nsm_handles, sm_link)
>> +	list_for_each_entry(nsm, nsm_handles, sm_link)
>>  		if (strlen(nsm->sm_name) == len &&
>>  		    memcmp(nsm->sm_name, hostname, len) == 0)
>>  			return nsm;
>>  	return NULL;
>>  }
>>  
>> -static struct nsm_handle *nsm_lookup_addr(const struct sockaddr *sap)
>> +static struct nsm_handle *nsm_lookup_addr(const struct list_head *nsm_handles,
>> +					const struct sockaddr *sap)
>>  {
>>  	struct nsm_handle *nsm;
>>  
>> -	list_for_each_entry(nsm, &nsm_handles, sm_link)
>> +	list_for_each_entry(nsm, nsm_handles, sm_link)
>>  		if (rpc_cmp_addr(nsm_addr(nsm), sap))
>>  			return nsm;
>>  	return NULL;
>>  }
>>  
>> -static struct nsm_handle *nsm_lookup_priv(const struct nsm_private *priv)
>> +static struct nsm_handle *nsm_lookup_priv(const struct list_head *nsm_handles,
>> +					const struct nsm_private *priv)
>>  {
>>  	struct nsm_handle *nsm;
>>  
>> -	list_for_each_entry(nsm, &nsm_handles, sm_link)
>> +	list_for_each_entry(nsm, nsm_handles, sm_link)
>>  		if (memcmp(nsm->sm_priv.data, priv->data,
>>  					sizeof(priv->data)) == 0)
>>  			return nsm;
>> @@ -353,6 +354,7 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
>>  
>>  /**
>>   * nsm_get_handle - Find or create a cached nsm_handle
>> + * @net: network namespace
>>   * @sap: pointer to socket address of handle to find
>>   * @salen: length of socket address
>>   * @hostname: pointer to C string containing hostname to find
>> @@ -365,11 +367,13 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
>>   * @hostname cannot be found in the handle cache.  Returns NULL if
>>   * an error occurs.
>>   */
>> -struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
>> +struct nsm_handle *nsm_get_handle(const struct net *net,
>> +				  const struct sockaddr *sap,
>>  				  const size_t salen, const char *hostname,
>>  				  const size_t hostname_len)
>>  {
>>  	struct nsm_handle *cached, *new = NULL;
>> +	struct lockd_net *ln = net_generic(net, lockd_net_id);
>>  
>>  	if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
>>  		if (printk_ratelimit()) {
>> @@ -384,9 +388,10 @@ retry:
>>  	spin_lock(&nsm_lock);
>>  
>>  	if (nsm_use_hostnames && hostname != NULL)
>> -		cached = nsm_lookup_hostname(hostname, hostname_len);
>> +		cached = nsm_lookup_hostname(&ln->nsm_handles,
>> +					hostname, hostname_len);
>>  	else
>> -		cached = nsm_lookup_addr(sap);
>> +		cached = nsm_lookup_addr(&ln->nsm_handles, sap);
>>  
>>  	if (cached != NULL) {
>>  		atomic_inc(&cached->sm_count);
>> @@ -400,7 +405,7 @@ retry:
>>  	}
>>  
>>  	if (new != NULL) {
>> -		list_add(&new->sm_link, &nsm_handles);
>> +		list_add(&new->sm_link, &ln->nsm_handles);
>>  		spin_unlock(&nsm_lock);
>>  		dprintk("lockd: created nsm_handle for %s (%s)\n",
>>  				new->sm_name, new->sm_addrbuf);
>> @@ -417,19 +422,22 @@ retry:
>>  
>>  /**
>>   * nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle
>> + * @net:  network namespace
>>   * @info: pointer to NLMPROC_SM_NOTIFY arguments
>>   *
>>   * Returns a matching nsm_handle if found in the nsm cache. The returned
>>   * nsm_handle's reference count is bumped. Otherwise returns NULL if some
>>   * error occurred.
>>   */
>> -struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info)
>> +struct nsm_handle *nsm_reboot_lookup(const struct net *net,
>> +				const struct nlm_reboot *info)
>>  {
>>  	struct nsm_handle *cached;
>> +	struct lockd_net *ln = net_generic(net, lockd_net_id);
>>  
>>  	spin_lock(&nsm_lock);
>>  
>> -	cached = nsm_lookup_priv(&info->priv);
>> +	cached = nsm_lookup_priv(&ln->nsm_handles, &info->priv);
>>  	if (unlikely(cached == NULL)) {
>>  		spin_unlock(&nsm_lock);
>>  		dprintk("lockd: never saw rebooted peer '%.*s' before\n",
>> diff --git a/fs/lockd/netns.h b/fs/lockd/netns.h
>> index 097bfa3..89fe011 100644
>> --- a/fs/lockd/netns.h
>> +++ b/fs/lockd/netns.h
>> @@ -15,6 +15,7 @@ struct lockd_net {
>>  	spinlock_t nsm_clnt_lock;
>>  	unsigned int nsm_users;
>>  	struct rpc_clnt *nsm_clnt;
>> +	struct list_head nsm_handles;
>>  };
>>  
>>  extern int lockd_net_id;
>> diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
>> index d678bcc..0dff13f 100644
>> --- a/fs/lockd/svc.c
>> +++ b/fs/lockd/svc.c
>> @@ -593,6 +593,7 @@ static int lockd_init_net(struct net *net)
>>  	INIT_LIST_HEAD(&ln->lockd_manager.list);
>>  	ln->lockd_manager.block_opens = false;
>>  	spin_lock_init(&ln->nsm_clnt_lock);
>> +	INIT_LIST_HEAD(&ln->nsm_handles);
>>  	return 0;
>>  }
>>  
>> diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
>> index b147d1a..09c576f 100644
>> --- a/fs/lockd/svc4proc.c
>> +++ b/fs/lockd/svc4proc.c
>> @@ -421,7 +421,7 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
>>  		return rpc_system_err;
>>  	}
>>  
>> -	nlm_host_rebooted(argp);
>> +	nlm_host_rebooted(SVC_NET(rqstp), argp);
>>  	return rpc_success;
>>  }
>>  
>> diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
>> index 21171f0..fb26b9f 100644
>> --- a/fs/lockd/svcproc.c
>> +++ b/fs/lockd/svcproc.c
>> @@ -464,7 +464,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
>>  		return rpc_system_err;
>>  	}
>>  
>> -	nlm_host_rebooted(argp);
>> +	nlm_host_rebooted(SVC_NET(rqstp), argp);
>>  	return rpc_success;
>>  }
>>  
>> diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
>> index ff82a32..fd3b65b 100644
>> --- a/include/linux/lockd/lockd.h
>> +++ b/include/linux/lockd/lockd.h
>> @@ -235,7 +235,8 @@ void		  nlm_rebind_host(struct nlm_host *);
>>  struct nlm_host * nlm_get_host(struct nlm_host *);
>>  void		  nlm_shutdown_hosts(void);
>>  void		  nlm_shutdown_hosts_net(struct net *net);
>> -void		  nlm_host_rebooted(const struct nlm_reboot *);
>> +void		  nlm_host_rebooted(const struct net *net,
>> +					const struct nlm_reboot *);
>>  
>>  /*
>>   * Host monitoring
>> @@ -243,11 +244,13 @@ void		  nlm_host_rebooted(const struct nlm_reboot *);
>>  int		  nsm_monitor(const struct nlm_host *host);
>>  void		  nsm_unmonitor(const struct nlm_host *host);
>>  
>> -struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
>> +struct nsm_handle *nsm_get_handle(const struct net *net,
>> +					const struct sockaddr *sap,
>>  					const size_t salen,
>>  					const char *hostname,
>>  					const size_t hostname_len);
>> -struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info);
>> +struct nsm_handle *nsm_reboot_lookup(const struct net *net,
>> +					const struct nlm_reboot *info);
>>  void		  nsm_release(struct nsm_handle *nsm);
>>  
>>  /*
>> -- 
>> 2.4.9
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]