patch-2.3.99-pre4 linux/fs/lockd/clntproc.c

Next file: linux/fs/lockd/host.c
Previous file: linux/fs/lockd/clntlock.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.99-pre3/linux/fs/lockd/clntproc.c linux/fs/lockd/clntproc.c
@@ -106,10 +106,18 @@
 	struct nlm_rqst		reqst, *call = &reqst;
 	sigset_t		oldset;
 	unsigned long		flags;
-	int			status;
+	int			status, proto, vers;
 
-	/* Always use NLM version 1 over UDP for now... */
-	if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), IPPROTO_UDP, 1)))
+	vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1;
+	if (NFS_PROTO(inode)->version > 3) {
+		printk(KERN_NOTICE "NFSv4 file locking not implemented!\n");
+		return -ENOLCK;
+	}
+
+	/* Retrieve transport protocol from NFS client */
+	proto = NFS_CLIENT(inode)->cl_xprt->prot;
+
+	if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers)))
 		return -ENOLCK;
 
 	/* Create RPC client handle if not there, and copy soft
@@ -142,6 +150,10 @@
 		spin_unlock_irqrestore(&current->sigmask_lock, flags);
 
 		call = nlmclnt_alloc_call();
+		if (!call) {
+			status = -ENOMEM;
+			goto out_restore;
+		}
 		call->a_flags = RPC_TASK_ASYNC;
 	} else {
 		spin_unlock_irqrestore(&current->sigmask_lock, flags);
@@ -165,8 +177,9 @@
 	}
 
 	if (status < 0 && (call->a_flags & RPC_TASK_ASYNC))
-		rpc_free(call);
+		kfree(call);
 
+ out_restore:
 	spin_lock_irqsave(&current->sigmask_lock, flags);
 	current->blocked = oldset;
 	recalc_sigpending(current);
@@ -200,8 +213,7 @@
 	struct nlm_rqst	*call;
 
 	while (!signalled()) {
-		call = (struct nlm_rqst *) rpc_allocate(RPC_TASK_ASYNC,
-					sizeof(struct nlm_rqst));
+		call = (struct nlm_rqst *) kmalloc(sizeof(struct nlm_rqst), GFP_KERNEL);
 		if (call)
 			return call;
 		printk("nlmclnt_alloc_call: failed, waiting for memory\n");
@@ -246,6 +258,7 @@
 			case -ECONNREFUSED:
 			case -ETIMEDOUT:
 			case -ENOTCONN:
+				nlm_rebind_host(host);
 				status = -EAGAIN;
 				break;
 			case -ERESTARTSYS:
@@ -253,10 +266,7 @@
 			default:
 				break;
 			}
-			if (req->a_args.block)
-				nlm_rebind_host(host);
-			else
-				break;
+			break;
 		} else
 		if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) {
 			dprintk("lockd: server in grace period\n");
@@ -290,7 +300,7 @@
  * Generic NLM call, async version.
  */
 int
-nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
+nlmsvc_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
 {
 	struct nlm_host	*host = req->a_host;
 	struct rpc_clnt	*clnt;
@@ -313,9 +323,20 @@
 	msg.rpc_cred = NULL;	
         status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, callback, req);
 
-	/* If the async call is proceeding, increment host refcount */
-        if (status >= 0 && (req->a_flags & RPC_TASK_ASYNC))
-                host->h_count++;
+	return status;
+}
+
+int
+nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
+{
+	struct nlm_host	*host = req->a_host;
+	int status;
+
+	/* Increment host refcount */
+	nlm_get_host(host);
+	status = nlmsvc_async_call(req, proc, callback);
+	if (status < 0)
+		nlm_release_host(host);
 	return status;
 }
 
@@ -347,6 +368,20 @@
 	return 0;
 }
 
+static
+void nlmclnt_insert_lock_callback(struct file_lock *fl)
+{
+	nlm_get_host(fl->fl_u.nfs_fl.host);
+}
+static
+void nlmclnt_remove_lock_callback(struct file_lock *fl)
+{
+	if (fl->fl_u.nfs_fl.host) {
+		nlm_release_host(fl->fl_u.nfs_fl.host);
+		fl->fl_u.nfs_fl.host = NULL;
+	}
+}
+
 /*
  * LOCK: Try to create a lock
  *
@@ -380,7 +415,7 @@
 		return -ENOLCK;
 	}
 
-	while (1) {
+	do {
 		if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0) {
 			if (resp->status != NLM_LCK_BLOCKED)
 				break;
@@ -388,11 +423,14 @@
 		}
 		if (status < 0)
 			return status;
-	}
+	} while (resp->status == NLM_LCK_BLOCKED);
 
 	if (resp->status == NLM_LCK_GRANTED) {
 		fl->fl_u.nfs_fl.state = host->h_state;
 		fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED;
+		fl->fl_u.nfs_fl.host = host;
+		fl->fl_insert = nlmclnt_insert_lock_callback;
+		fl->fl_remove = nlmclnt_remove_lock_callback;
 	}
 
 	return nlm_stat_to_errno(resp->status);
@@ -444,15 +482,9 @@
 static int
 nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
 {
-	struct nlm_host	*host = req->a_host;
 	struct nlm_res	*resp = &req->a_res;
 	int		status;
 
-	/* No monitor, no lock: see nlmclnt_lock().
-	 * Since this is an UNLOCK, don't try to setup monitoring here. */
-	if (!host->h_monitored)
-		return -ENOLCK;
-
 	/* Clean the GRANTED flag now so the lock doesn't get
 	 * reclaimed while we're stuck in the unlock call. */
 	fl->fl_u.nfs_fl.flags &= ~NFS_LCK_GRANTED;
@@ -487,9 +519,7 @@
 
 	if (task->tk_status < 0) {
 		dprintk("lockd: unlock failed (err = %d)\n", -task->tk_status);
-		nlm_rebind_host(req->a_host);
-		rpc_restart_call(task);
-		return;
+		goto retry_unlock;
 	}
 	if (status != NLM_LCK_GRANTED
 	 && status != NLM_LCK_DENIED_GRACE_PERIOD) {
@@ -497,7 +527,12 @@
 	}
 
 die:
-	rpc_release_task(task);
+	nlm_release_host(req->a_host);
+	kfree(req);
+	return;
+ retry_unlock:
+	nlm_rebind_host(req->a_host);
+	rpc_restart_call(task);
 }
 
 /*
@@ -520,10 +555,9 @@
 	recalc_sigpending(current);
 	spin_unlock_irqrestore(&current->sigmask_lock, flags);
 
-	do {
-		req = (struct nlm_rqst *) rpc_allocate(RPC_TASK_ASYNC,
-							sizeof(*req));
-	} while (req == NULL);
+	req = nlmclnt_alloc_call();
+	if (!req)
+		return -ENOMEM;
 	req->a_host  = host;
 	req->a_flags = RPC_TASK_ASYNC;
 
@@ -532,7 +566,7 @@
 	status = nlmclnt_async_call(req, NLMPROC_CANCEL,
 					nlmclnt_cancel_callback);
 	if (status < 0)
-		rpc_free(req);
+		kfree(req);
 
 	spin_lock_irqsave(&current->sigmask_lock, flags);
 	current->blocked = oldset;
@@ -573,7 +607,6 @@
 	}
 
 die:
-	rpc_release_task(task);
 	nlm_release_host(req->a_host);
 	kfree(req);
 	return;
@@ -582,7 +615,6 @@
 	nlm_rebind_host(req->a_host);
 	rpc_restart_call(task);
 	rpc_delay(task, 30 * HZ);
-	return;
 }
 
 /*

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)