[PATCH] knfsd: lockd: Make nlm_host_rebooted use the nsm_handle

This patch makes the SM_NOTIFY handling understand and use the nsm_handle.

To make it a bit clear what is happening:

    nlmclent_prepare_reclaim and nlmclnt_finish_reclaim
    get open-coded into 'reclaimer'

The result is tidied up.

Then some of that functionality is moved out into nlm_host_rebooted (which
calls nlmclnt_recovery which starts a thread which runs reclaimer).

Also host_rebooted now finds an nsm_handle rather than a host, then then
iterates over all hosts and deals with each host that shares that nsm_handle.

Signed-off-by: Olaf Kirch <okir@suse.de>
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 4990223..3cd96e2 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -290,28 +290,57 @@
  * has rebooted.
  * Release all resources held by that peer.
  */
-void nlm_host_rebooted(const struct sockaddr_in *sin, const struct nlm_reboot *argp)
+void nlm_host_rebooted(const struct sockaddr_in *sin,
+				const char *hostname, int hostname_len,
+				u32 new_state)
 {
-	struct nlm_host *host;
-	int server;
+	struct nsm_handle *nsm;
+	struct nlm_host	*host, **hp;
+	int		hash;
 
-	/* Obtain the host pointer for this NFS server and try to
-	 * reclaim all locks we hold on this server.
-	 */
-	server = (argp->proto & 1)? 1 : 0;
-	host = nlm_lookup_host(server, sin, argp->proto >> 1, argp->vers,
-			argp->mon, argp->len);
-	if (host == NULL)
+	dprintk("lockd: nlm_host_rebooted(%s, %u.%u.%u.%u)\n",
+			hostname, NIPQUAD(sin->sin_addr));
+
+	/* Find the NSM handle for this peer */
+	if (!(nsm = __nsm_find(sin, hostname, hostname_len, 0)))
 		return;
 
-	if (server == 0) {
-		/* We are client, he's the server: try to reclaim all locks. */
-		nlmclnt_recovery(host, argp->state);
-	} else {
-		/* He's the client, we're the server: delete all locks held by the client */
-		nlmsvc_free_host_resources(host);
+	/* When reclaiming locks on this peer, make sure that
+	 * we set up a new notification */
+	nsm->sm_monitored = 0;
+
+	/* Mark all hosts tied to this NSM state as having rebooted.
+	 * We run the loop repeatedly, because we drop the host table
+	 * lock for this.
+	 * To avoid processing a host several times, we match the nsmstate.
+	 */
+again:	mutex_lock(&nlm_host_mutex);
+	for (hash = 0; hash < NLM_HOST_NRHASH; hash++) {
+		for (hp = &nlm_hosts[hash]; (host = *hp); hp = &host->h_next) {
+			if (host->h_nsmhandle == nsm
+			 && host->h_nsmstate != new_state) {
+				host->h_nsmstate = new_state;
+				host->h_state++;
+
+				nlm_get_host(host);
+				mutex_unlock(&nlm_host_mutex);
+
+				if (host->h_server) {
+					/* We're server for this guy, just ditch
+					 * all the locks he held. */
+					nlmsvc_free_host_resources(host);
+				} else {
+					/* He's the server, initiate lock recovery. */
+					nlmclnt_recovery(host);
+				}
+
+				nlm_release_host(host);
+				goto again;
+			}
+		}
 	}
-	nlm_release_host(host);
+
+	mutex_unlock(&nlm_host_mutex);
 }
 
 /*