The Linux NSM implementation currently does nothing to prevent concurrent SM_MON and SM_UNMON upcalls regarding the same peer. Races could cause duplicate SM_MON upcalls for the same peer, or locking activity during server shutdown might cause SM_MON and SM_UNMON upcalls to occur in an arbitrary order. To avoid confusing rpc.statd, add a per-nsm_handle mutex to serialize the upcalls. To prevent duplicate upcalls, the mutex is held while the upcall is outstanding, and is not released until we can tell if the upcall succeeded. The nsm_monitor() function is called frequently. The extra inline function mitigates the overhead of taking the mutex. It is only taken if the nsm_handle is not already monitored. Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx> --- fs/lockd/host.c | 1 + fs/lockd/mon.c | 23 ++++++++++++++++------- include/linux/lockd/lockd.h | 12 +++++++++++- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 8d26d0c..bf705d0 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -697,6 +697,7 @@ retry: nsm->sm_name = (char *) (nsm + 1); memcpy(nsm->sm_name, hostname, hostname_len); nsm->sm_name[hostname_len] = '\0'; + mutex_init(&nsm->sm_mutex); nlm_display_address((struct sockaddr *)&nsm->sm_addr, nsm->sm_addrbuf, sizeof(nsm->sm_addrbuf)); atomic_set(&nsm->sm_count, 1); diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index b76d9b2..301aeb7 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -70,8 +70,8 @@ nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) } /** - * nsm_monitor - Notify a peer in case we reboot - * @host: pointer to nlm_host of peer to notify + * __nsm_monitor - Notify a peer in case we reboot + * @nsm: pointer to nsm_handle of peer to notify * * If this peer is not already monitored, this function sends an * upcall to the local rpc.statd to record the name/address of @@ -80,16 +80,17 @@ nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) * Returns zero if the peer is monitored by the local rpc.statd; * otherwise a negative errno value is returned. */ -int nsm_monitor(const struct nlm_host *host) +int __nsm_monitor(struct nsm_handle *nsm) { - struct nsm_handle *nsm = host->h_nsmhandle; struct nsm_res res; - int status; + int status = 0; dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name); + mutex_lock(&nsm->sm_mutex); + if (nsm->sm_monitored) - return 0; + goto out; /* * Choose whether to record the caller_name or IP address of @@ -104,6 +105,9 @@ int nsm_monitor(const struct nlm_host *host) printk(KERN_NOTICE "lockd: cannot monitor %s\n", nsm->sm_name); else nsm->sm_monitored = 1; + +out: + mutex_unlock(&nsm->sm_mutex); return status; } @@ -121,8 +125,10 @@ void nsm_unmonitor(struct nsm_handle *nsm) dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name); + mutex_lock(&nsm->sm_mutex); + if (!nsm->sm_monitored) - return; + goto out; if (atomic_read(&nsm->sm_count) == 1 && !nsm->sm_sticky) { if (nsm_mon_unmon(nsm, SM_UNMON, &res) < 0) @@ -131,6 +137,9 @@ void nsm_unmonitor(struct nsm_handle *nsm) else nsm->sm_monitored = 0; } + +out: + mutex_unlock(&nsm->sm_mutex); } /* diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index e2fa968..bf6c1c1 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -76,6 +76,7 @@ struct nsm_handle { char * sm_mon_name; unsigned int sm_monitored : 1, sm_sticky : 1; /* don't unmonitor */ + struct mutex sm_mutex; char sm_addrbuf[63]; /* presentation address */ }; @@ -236,9 +237,18 @@ void nsm_release(struct nsm_handle *); /* * Host monitoring */ -int nsm_monitor(const struct nlm_host *host); +int __nsm_monitor(struct nsm_handle *nsm); void nsm_unmonitor(struct nsm_handle *nsm); +static inline int nsm_monitor(const struct nlm_host *host) +{ + struct nsm_handle *nsm = host->h_nsmhandle; + + if (likely(nsm->sm_monitored)) + return 0; + return __nsm_monitor(nsm); +} + /* * This is used in garbage collection and resource reclaim * A return value != 0 means destroy the lock/block/share -- 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