summaryrefslogtreecommitdiffstats
path: root/fs/lockd
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-24 00:12:35 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-24 00:12:35 +0000
commit482368b1a8e45430672c58c9a42e7d2004367126 (patch)
treece2a1a567d4d62dee7c2e71a46a99cf72cf1d606 /fs/lockd
parente4d0251c6f56ab2e191afb70f80f382793e23f74 (diff)
Merge with 2.3.47. Guys, this is buggy as shit. You've been warned.
Diffstat (limited to 'fs/lockd')
-rw-r--r--fs/lockd/Makefile5
-rw-r--r--fs/lockd/clntproc.c2
-rw-r--r--fs/lockd/lockd_syms.c11
-rw-r--r--fs/lockd/svc.c4
-rw-r--r--fs/lockd/svc4proc.c561
-rw-r--r--fs/lockd/svclock.c20
-rw-r--r--fs/lockd/svcproc.c45
-rw-r--r--fs/lockd/svcsubs.c6
-rw-r--r--fs/lockd/xdr.c19
-rw-r--r--fs/lockd/xdr4.c601
10 files changed, 1257 insertions, 17 deletions
diff --git a/fs/lockd/Makefile b/fs/lockd/Makefile
index 7c319ffc3..ceab1f466 100644
--- a/fs/lockd/Makefile
+++ b/fs/lockd/Makefile
@@ -10,6 +10,11 @@
O_TARGET := lockd.o
O_OBJS := clntlock.o clntproc.o host.o svc.o svclock.o svcshare.o \
svcproc.o svcsubs.o mon.o xdr.o
+
+ifdef CONFIG_LOCKD_V4
+ O_OBJS += xdr4.o svc4proc.o
+endif
+
OX_OBJS := lockd_syms.o
M_OBJS := $(O_TARGET)
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 4160bf2e3..517456326 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -69,7 +69,7 @@ nlmclnt_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
call->a_args.lock = *lock;
call->a_args.lock.caller = system_utsname.nodename;
- init_waitqueue_head(&lock->fl.fl_wait);
+ init_waitqueue_head(&call->a_args.lock.fl.fl_wait);
/* set default data area */
call->a_args.lock.oh.data = call->a_owner;
diff --git a/fs/lockd/lockd_syms.c b/fs/lockd/lockd_syms.c
index b3990ed98..db36300ba 100644
--- a/fs/lockd/lockd_syms.c
+++ b/fs/lockd/lockd_syms.c
@@ -39,4 +39,15 @@ EXPORT_SYMBOL(nlmsvc_ops);
EXPORT_SYMBOL(nlmsvc_grace_period);
EXPORT_SYMBOL(nlmsvc_timeout);
+#ifdef CONFIG_LOCKD_V4
+
+/* NLM4 exported symbols */
+EXPORT_SYMBOL(nlm4_rofs);
+EXPORT_SYMBOL(nlm4_stale_fh);
+EXPORT_SYMBOL(nlm4_deadlock);
+EXPORT_SYMBOL(nlm4_failed);
+EXPORT_SYMBOL(nlm4_fbig);
+
+#endif
+
#endif /* CONFIG_MODULES */
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index e22007445..62401adbd 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -343,7 +343,7 @@ static struct svc_version nlmsvc_version1 = {
static struct svc_version nlmsvc_version3 = {
3, 24, nlmsvc_procedures, NULL
};
-#ifdef CONFIG_NFSD_NFS3
+#ifdef CONFIG_LOCKD_V4
static struct svc_version nlmsvc_version4 = {
4, 24, nlmsvc_procedures4, NULL
};
@@ -353,7 +353,7 @@ static struct svc_version * nlmsvc_version[] = {
&nlmsvc_version1,
NULL,
&nlmsvc_version3,
-#ifdef CONFIG_NFSD_NFS3
+#ifdef CONFIG_LOCKD_V4
&nlmsvc_version4,
#endif
};
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
new file mode 100644
index 000000000..b690eb97e
--- /dev/null
+++ b/fs/lockd/svc4proc.c
@@ -0,0 +1,561 @@
+/*
+ * linux/fs/lockd/svc4proc.c
+ *
+ * Lockd server procedures. We don't implement the NLM_*_RES
+ * procedures because we don't use the async procedures.
+ *
+ * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/in.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/nfsd/nfsd.h>
+#include <linux/lockd/lockd.h>
+#include <linux/lockd/share.h>
+#include <linux/lockd/sm_inter.h>
+
+
+#define NLMDBG_FACILITY NLMDBG_CLIENT
+
+static u32 nlm4svc_callback(struct svc_rqst *, u32, struct nlm_res *);
+static void nlm4svc_callback_exit(struct rpc_task *);
+
+/*
+ * Obtain client and file from arguments
+ */
+static u32
+nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_host **hostp, struct nlm_file **filp)
+{
+ struct nlm_host *host = NULL;
+ struct nlm_file *file = NULL;
+ struct nlm_lock *lock = &argp->lock;
+ u32 error = 0;
+
+ /* nfsd callbacks must have been installed for this procedure */
+ if (!nlmsvc_ops)
+ return nlm_lck_denied_nolocks;
+
+ /* Obtain handle for client host */
+ if (rqstp->rq_client == NULL) {
+ printk(KERN_NOTICE
+ "lockd: unauthenticated request from (%08x:%d)\n",
+ ntohl(rqstp->rq_addr.sin_addr.s_addr),
+ ntohs(rqstp->rq_addr.sin_port));
+ return nlm_lck_denied_nolocks;
+ }
+
+ /* Obtain host handle */
+ if (!(host = nlmsvc_lookup_host(rqstp))
+ || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
+ goto no_locks;
+ *hostp = host;
+
+ /* Obtain file pointer. Not used by FREE_ALL call. */
+ if (filp != NULL) {
+ if ((error = nlm_lookup_file(rqstp, &file, &lock->fh)) != 0)
+ goto no_locks;
+ *filp = file;
+
+ /* Set up the missing parts of the file_lock structure */
+ lock->fl.fl_file = &file->f_file;
+ lock->fl.fl_owner = (fl_owner_t) host;
+ }
+
+ return 0;
+
+no_locks:
+ if (host)
+ nlm_release_host(host);
+ if (error)
+ return error;
+ return nlm_lck_denied_nolocks;
+}
+
+/*
+ * NULL: Test for presence of service
+ */
+static int
+nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+{
+ dprintk("lockd: NULL called\n");
+ return rpc_success;
+}
+
+/*
+ * TEST: Check for conflicting lock
+ */
+static int
+nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+{
+ struct nlm_host *host;
+ struct nlm_file *file;
+
+ dprintk("lockd: TEST4 called\n");
+ resp->cookie = argp->cookie;
+
+ /* Don't accept test requests during grace period */
+ if (nlmsvc_grace_period) {
+ resp->status = nlm_lck_denied_grace_period;
+ return rpc_success;
+ }
+
+ /* Obtain client and file */
+ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+ return rpc_success;
+
+ /* Now check for conflicting locks */
+ resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
+
+ dprintk("lockd: TEST4 status %d\n", ntohl(resp->status));
+ nlm_release_host(host);
+ nlm_release_file(file);
+ return rpc_success;
+}
+
+static int
+nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+{
+ struct nlm_host *host;
+ struct nlm_file *file;
+
+ dprintk("lockd: LOCK called\n");
+
+ resp->cookie = argp->cookie;
+
+ /* Don't accept new lock requests during grace period */
+ if (nlmsvc_grace_period && !argp->reclaim) {
+ resp->status = nlm_lck_denied_grace_period;
+ return rpc_success;
+ }
+
+ /* Obtain client and file */
+ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+ return rpc_success;
+
+#if 0
+ /* If supplied state doesn't match current state, we assume it's
+ * an old request that time-warped somehow. Any error return would
+ * do in this case because it's irrelevant anyway.
+ *
+ * NB: We don't retrieve the remote host's state yet.
+ */
+ if (host->h_nsmstate && host->h_nsmstate != argp->state) {
+ resp->status = nlm_lck_denied_nolocks;
+ } else
+#endif
+
+ /* Now try to lock the file */
+ resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
+ argp->block, &argp->cookie);
+
+ dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
+ nlm_release_host(host);
+ nlm_release_file(file);
+ return rpc_success;
+}
+
+static int
+nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+{
+ struct nlm_host *host;
+ struct nlm_file *file;
+
+ dprintk("lockd: CANCEL called\n");
+
+ resp->cookie = argp->cookie;
+
+ /* Don't accept requests during grace period */
+ if (nlmsvc_grace_period) {
+ resp->status = nlm_lck_denied_grace_period;
+ return rpc_success;
+ }
+
+ /* Obtain client and file */
+ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+ return rpc_success;
+
+ /* Try to cancel request. */
+ resp->status = nlmsvc_cancel_blocked(file, &argp->lock);
+
+ dprintk("lockd: CANCEL status %d\n", ntohl(resp->status));
+ nlm_release_host(host);
+ nlm_release_file(file);
+ return rpc_success;
+}
+
+/*
+ * UNLOCK: release a lock
+ */
+static int
+nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+{
+ struct nlm_host *host;
+ struct nlm_file *file;
+
+ dprintk("lockd: UNLOCK called\n");
+
+ resp->cookie = argp->cookie;
+
+ /* Don't accept new lock requests during grace period */
+ if (nlmsvc_grace_period) {
+ resp->status = nlm_lck_denied_grace_period;
+ return rpc_success;
+ }
+
+ /* Obtain client and file */
+ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+ return rpc_success;
+
+ /* Now try to remove the lock */
+ resp->status = nlmsvc_unlock(file, &argp->lock);
+
+ dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status));
+ nlm_release_host(host);
+ nlm_release_file(file);
+ return rpc_success;
+}
+
+/*
+ * GRANTED: A server calls us to tell that a process' lock request
+ * was granted
+ */
+static int
+nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+{
+ resp->cookie = argp->cookie;
+
+ dprintk("lockd: GRANTED called\n");
+ resp->status = nlmclnt_grant(&argp->lock);
+ dprintk("lockd: GRANTED status %d\n", ntohl(resp->status));
+ return rpc_success;
+}
+
+/*
+ * `Async' versions of the above service routines. They aren't really,
+ * because we send the callback before the reply proper. I hope this
+ * doesn't break any clients.
+ */
+static int
+nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+{
+ struct nlm_res res;
+ u32 stat;
+
+ dprintk("lockd: TEST_MSG called\n");
+
+ if ((stat = nlm4svc_proc_test(rqstp, argp, &res)) == 0)
+ stat = nlm4svc_callback(rqstp, NLMPROC_TEST_RES, &res);
+ return stat;
+}
+
+static int
+nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+{
+ struct nlm_res res;
+ u32 stat;
+
+ dprintk("lockd: LOCK_MSG called\n");
+
+ if ((stat = nlm4svc_proc_lock(rqstp, argp, &res)) == 0)
+ stat = nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, &res);
+ return stat;
+}
+
+static int
+nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+{
+ struct nlm_res res;
+ u32 stat;
+
+ dprintk("lockd: CANCEL_MSG called\n");
+
+ if ((stat = nlm4svc_proc_cancel(rqstp, argp, &res)) == 0)
+ stat = nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, &res);
+ return stat;
+}
+
+static int
+nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+{
+ struct nlm_res res;
+ u32 stat;
+
+ dprintk("lockd: UNLOCK_MSG called\n");
+
+ if ((stat = nlm4svc_proc_unlock(rqstp, argp, &res)) == 0)
+ stat = nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, &res);
+ return stat;
+}
+
+static int
+nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+{
+ struct nlm_res res;
+ u32 stat;
+
+ dprintk("lockd: GRANTED_MSG called\n");
+
+ if ((stat = nlm4svc_proc_granted(rqstp, argp, &res)) == 0)
+ stat = nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, &res);
+ return stat;
+}
+
+/*
+ * SHARE: create a DOS share or alter existing share.
+ */
+static int
+nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+{
+ struct nlm_host *host;
+ struct nlm_file *file;
+
+ dprintk("lockd: SHARE called\n");
+
+ resp->cookie = argp->cookie;
+
+ /* Don't accept new lock requests during grace period */
+ if (nlmsvc_grace_period && !argp->reclaim) {
+ resp->status = nlm_lck_denied_grace_period;
+ return rpc_success;
+ }
+
+ /* Obtain client and file */
+ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+ return rpc_success;
+
+ /* Now try to create the share */
+ resp->status = nlmsvc_share_file(host, file, argp);
+
+ dprintk("lockd: SHARE status %d\n", ntohl(resp->status));
+ nlm_release_host(host);
+ nlm_release_file(file);
+ return rpc_success;
+}
+
+/*
+ * UNSHARE: Release a DOS share.
+ */
+static int
+nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+{
+ struct nlm_host *host;
+ struct nlm_file *file;
+
+ dprintk("lockd: UNSHARE called\n");
+
+ resp->cookie = argp->cookie;
+
+ /* Don't accept requests during grace period */
+ if (nlmsvc_grace_period) {
+ resp->status = nlm_lck_denied_grace_period;
+ return rpc_success;
+ }
+
+ /* Obtain client and file */
+ if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+ return rpc_success;
+
+ /* Now try to lock the file */
+ resp->status = nlmsvc_unshare_file(host, file, argp);
+
+ dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status));
+ nlm_release_host(host);
+ nlm_release_file(file);
+ return rpc_success;
+}
+
+/*
+ * NM_LOCK: Create an unmonitored lock
+ */
+static int
+nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
+ struct nlm_res *resp)
+{
+ dprintk("lockd: NM_LOCK called\n");
+
+ argp->monitor = 0; /* just clean the monitor flag */
+ return nlm4svc_proc_lock(rqstp, argp, resp);
+}
+
+/*
+ * FREE_ALL: Release all locks and shares held by client
+ */
+static int
+nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
+ void *resp)
+{
+ struct nlm_host *host;
+
+ /* Obtain client */
+ if (nlm4svc_retrieve_args(rqstp, argp, &host, NULL))
+ return rpc_success;
+
+ nlmsvc_free_host_resources(host);
+ nlm_release_host(host);
+ return rpc_success;
+}
+
+/*
+ * SM_NOTIFY: private callback from statd (not part of official NLM proto)
+ */
+static int
+nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
+ void *resp)
+{
+ struct sockaddr_in saddr = rqstp->rq_addr;
+ struct nlm_host *host;
+
+ dprintk("lockd: SM_NOTIFY called\n");
+ if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
+ || ntohs(saddr.sin_port) >= 1024) {
+ printk(KERN_WARNING
+ "lockd: rejected NSM callback from %08x:%d\n",
+ ntohl(rqstp->rq_addr.sin_addr.s_addr),
+ ntohs(rqstp->rq_addr.sin_port));
+ return rpc_system_err;
+ }
+
+ /* Obtain the host pointer for this NFS server and try to
+ * reclaim all locks we hold on this server.
+ */
+ saddr.sin_addr.s_addr = argp->addr;
+ if ((host = nlm_lookup_host(NULL, &saddr, IPPROTO_UDP, 1)) != NULL) {
+ nlmclnt_recovery(host, argp->state);
+ nlm_release_host(host);
+ }
+
+ /* If we run on an NFS server, delete all locks held by the client */
+ if (nlmsvc_ops != NULL) {
+ struct svc_client *clnt;
+ saddr.sin_addr.s_addr = argp->addr;
+ if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL
+ && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) {
+ nlmsvc_free_host_resources(host);
+ }
+ nlm_release_host(host);
+ }
+
+ return rpc_success;
+}
+
+/*
+ * This is the generic lockd callback for async RPC calls
+ */
+static u32
+nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
+{
+ struct nlm_host *host;
+ struct nlm_rqst *call;
+
+ if (!(call = nlmclnt_alloc_call()))
+ return rpc_system_err;
+
+ host = nlmclnt_lookup_host(&rqstp->rq_addr,
+ rqstp->rq_prot, rqstp->rq_vers);
+ if (!host) {
+ rpc_free(call);
+ return rpc_system_err;
+ }
+
+ call->a_flags = RPC_TASK_ASYNC;
+ call->a_host = host;
+ memcpy(&call->a_args, resp, sizeof(*resp));
+
+/* FIXME this should become nlmSVC_async_call when that code gets
+ merged in XXX */
+ if (nlmclnt_async_call(call, proc, nlm4svc_callback_exit) < 0)
+ return rpc_system_err;
+
+ return rpc_success;
+}
+
+static void
+nlm4svc_callback_exit(struct rpc_task *task)
+{
+ struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata;
+
+ if (task->tk_status < 0) {
+ dprintk("lockd: %4d callback failed (errno = %d)\n",
+ task->tk_pid, -task->tk_status);
+ }
+ nlm_release_host(call->a_host);
+ rpc_free(call);
+}
+
+/*
+ * NLM Server procedures.
+ */
+
+#define nlm4svc_encode_norep nlm4svc_encode_void
+#define nlm4svc_decode_norep nlm4svc_decode_void
+#define nlm4svc_decode_testres nlm4svc_decode_void
+#define nlm4svc_decode_lockres nlm4svc_decode_void
+#define nlm4svc_decode_unlockres nlm4svc_decode_void
+#define nlm4svc_decode_cancelres nlm4svc_decode_void
+#define nlm4svc_decode_grantedres nlm4svc_decode_void
+
+#define nlm4svc_proc_none nlm4svc_proc_null
+#define nlm4svc_proc_test_res nlm4svc_proc_null
+#define nlm4svc_proc_lock_res nlm4svc_proc_null
+#define nlm4svc_proc_cancel_res nlm4svc_proc_null
+#define nlm4svc_proc_unlock_res nlm4svc_proc_null
+#define nlm4svc_proc_granted_res nlm4svc_proc_null
+
+struct nlm_void { int dummy; };
+
+#define PROC(name, xargt, xrest, argt, rest) \
+ { (svc_procfunc) nlm4svc_proc_##name, \
+ (kxdrproc_t) nlm4svc_decode_##xargt, \
+ (kxdrproc_t) nlm4svc_encode_##xrest, \
+ NULL, \
+ sizeof(struct nlm_##argt), \
+ sizeof(struct nlm_##rest), \
+ 0, \
+ 0 \
+ }
+struct svc_procedure nlmsvc_procedures4[] = {
+ PROC(null, void, void, void, void),
+ PROC(test, testargs, testres, args, res),
+ PROC(lock, lockargs, res, args, res),
+ PROC(cancel, cancargs, res, args, res),
+ PROC(unlock, unlockargs, res, args, res),
+ PROC(granted, testargs, res, args, res),
+ PROC(test_msg, testargs, norep, args, void),
+ PROC(lock_msg, lockargs, norep, args, void),
+ PROC(cancel_msg, cancargs, norep, args, void),
+ PROC(unlock_msg, unlockargs, norep, args, void),
+ PROC(granted_msg, testargs, norep, args, void),
+ PROC(test_res, testres, norep, res, void),
+ PROC(lock_res, lockres, norep, res, void),
+ PROC(cancel_res, cancelres, norep, res, void),
+ PROC(unlock_res, unlockres, norep, res, void),
+ PROC(granted_res, grantedres, norep, res, void),
+ PROC(none, void, void, void, void),
+ PROC(none, void, void, void, void),
+ PROC(none, void, void, void, void),
+ PROC(none, void, void, void, void),
+ PROC(share, shareargs, shareres, args, res),
+ PROC(unshare, shareargs, shareres, args, res),
+ PROC(nm_lock, lockargs, res, args, res),
+ PROC(free_all, notify, void, args, void),
+
+ /* statd callback */
+ PROC(sm_notify, reboot, void, reboot, void),
+};
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 73caf6349..1bed616cb 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -20,6 +20,7 @@
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -98,9 +99,10 @@ nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock, int remove)
lock->fl.fl_end, lock->fl.fl_type);
for (head = &nlm_blocked; (block = *head); head = &block->b_next) {
fl = &block->b_call.a_args.lock.fl;
- dprintk(" check f=%p pd=%d %ld-%ld ty=%d\n",
+ dprintk("lockd: check f=%p pd=%d %ld-%ld ty=%d cookie=%x\n",
block->b_file, fl->fl_pid, fl->fl_start,
- fl->fl_end, fl->fl_type);
+ fl->fl_end, fl->fl_type,
+ *(unsigned int*)(block->b_call.a_args.cookie.data));
if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {
if (remove)
*head = block->b_next;
@@ -129,6 +131,8 @@ nlmsvc_find_block(struct nlm_cookie *cookie)
struct nlm_block *block;
for (block = nlm_blocked; block; block = block->b_next) {
+ dprintk("cookie: head of blocked queue %p, block %p\n",
+ nlm_blocked, block);
if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie))
break;
}
@@ -310,7 +314,13 @@ again:
switch(-error) {
case 0:
return nlm_granted;
- case EDEADLK: /* no applicable NLM status */
+ case EDEADLK:
+#ifdef CONFIG_LOCKD_V4
+ return nlm4_deadlock; /* will be downgraded to lck_deined if this
+ * is a NLMv1,3 request */
+#else
+ /* no applicable NLM status */
+#endif
case EAGAIN:
return nlm_lck_denied;
default: /* includes ENOLCK */
@@ -541,6 +551,8 @@ nlmsvc_grant_callback(struct rpc_task *task)
unsigned long timeout;
dprintk("lockd: GRANT_MSG RPC callback\n");
+ dprintk("callback: looking for cookie %x \n",
+ *(unsigned int *)(call->a_args.cookie.data));
if (!(block = nlmsvc_find_block(&call->a_args.cookie))) {
dprintk("lockd: no block for cookie %x\n", *(u32 *)(call->a_args.cookie.data));
return;
@@ -617,7 +629,7 @@ nlmsvc_retry_blocked(void)
dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
nlm_blocked,
nlm_blocked? nlm_blocked->b_when : 0);
- while ((block = nlm_blocked) && block->b_when < jiffies) {
+ while ((block = nlm_blocked) && block->b_when <= jiffies) {
dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n",
block, block->b_when, block->b_done);
if (block->b_done)
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 142d593b2..c92358dec 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -7,6 +7,7 @@
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/malloc.h>
@@ -24,6 +25,31 @@
static u32 nlmsvc_callback(struct svc_rqst *, u32, struct nlm_res *);
static void nlmsvc_callback_exit(struct rpc_task *);
+#ifdef CONFIG_LOCKD_V4
+static u32
+cast_to_nlm(u32 status, u32 vers)
+{
+
+ if (vers != 4){
+ switch(ntohl(status)){
+ case NLM_LCK_GRANTED:
+ case NLM_LCK_DENIED:
+ case NLM_LCK_DENIED_NOLOCKS:
+ case NLM_LCK_BLOCKED:
+ case NLM_LCK_DENIED_GRACE_PERIOD:
+ break;
+ default:
+ status = NLM_LCK_DENIED_NOLOCKS;
+ }
+ }
+
+ return (status);
+}
+#define cast_status(status) (cast_to_nlm(status, rqstp->rq_vers))
+#else
+#define cast_status(status) (status)
+#endif
+
/*
* Obtain client and file from arguments
*/
@@ -108,9 +134,10 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
return rpc_success;
/* Now check for conflicting locks */
- resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
+ resp->status = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock));
- dprintk("lockd: TEST status %d\n", ntohl(resp->status));
+ dprintk("lockd: TEST status %d vers %d\n",
+ ntohl(resp->status), rqstp->rq_vers);
nlm_release_host(host);
nlm_release_file(file);
return rpc_success;
@@ -150,8 +177,8 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
#endif
/* Now try to lock the file */
- resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
- argp->block, &argp->cookie);
+ resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock,
+ argp->block, &argp->cookie));
dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
nlm_release_host(host);
@@ -181,7 +208,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
return rpc_success;
/* Try to cancel request. */
- resp->status = nlmsvc_cancel_blocked(file, &argp->lock);
+ resp->status = cast_status(nlmsvc_cancel_blocked(file, &argp->lock));
dprintk("lockd: CANCEL status %d\n", ntohl(resp->status));
nlm_release_host(host);
@@ -214,7 +241,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
return rpc_success;
/* Now try to remove the lock */
- resp->status = nlmsvc_unlock(file, &argp->lock);
+ resp->status = cast_status(nlmsvc_unlock(file, &argp->lock));
dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status));
nlm_release_host(host);
@@ -338,7 +365,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
return rpc_success;
/* Now try to create the share */
- resp->status = nlmsvc_share_file(host, file, argp);
+ resp->status = cast_status(nlmsvc_share_file(host, file, argp));
dprintk("lockd: SHARE status %d\n", ntohl(resp->status));
nlm_release_host(host);
@@ -370,8 +397,8 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
return rpc_success;
- /* Now try to lock the file */
- resp->status = nlmsvc_unshare_file(host, file, argp);
+ /* Now try to unshare the file */
+ resp->status = cast_status(nlmsvc_unshare_file(host, file, argp));
dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status));
nlm_release_host(host);
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index 8d15cba9a..b3489a88d 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -6,6 +6,7 @@
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/sched.h>
@@ -105,6 +106,11 @@ out_unlock:
out_free:
kfree(file);
+#ifdef CONFIG_LOCKD_V4
+ if (nfserr == 1)
+ nfserr = nlm4_stale_fh;
+ else
+#endif
nfserr = nlm_lck_denied;
goto out_unlock;
}
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index 0902eaa0d..c0797a16f 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -6,6 +6,7 @@
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/utsname.h>
@@ -47,6 +48,14 @@ nlmxdr_init(void)
nlm_lck_blocked = htonl(NLM_LCK_BLOCKED);
nlm_lck_denied_grace_period = htonl(NLM_LCK_DENIED_GRACE_PERIOD);
+#ifdef CONFIG_LOCKD_V4
+ nlm4_deadlock = htonl(NLM_DEADLCK);
+ nlm4_rofs = htonl(NLM_ROFS);
+ nlm4_stale_fh = htonl(NLM_STALE_FH);
+ nlm4_fbig = htonl(NLM_FBIG);
+ nlm4_failed = htonl(NLM_FAILED);
+#endif
+
inited = 1;
}
@@ -541,7 +550,8 @@ nlmclt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
{ "nlm_" #proc, \
(kxdrproc_t) nlmclt_encode_##argtype, \
(kxdrproc_t) nlmclt_decode_##restype, \
- MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2 \
+ MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2, \
+ 0 \
}
static struct rpc_procinfo nlm_procedures[] = {
@@ -586,11 +596,18 @@ static struct rpc_version nlm_version3 = {
3, 24, nlm_procedures,
};
+#ifdef CONFIG_LOCKD_V4
+extern struct rpc_version nlm_version4;
+#endif
+
static struct rpc_version * nlm_versions[] = {
NULL,
&nlm_version1,
NULL,
&nlm_version3,
+#ifdef CONFIG_LOCKD_V4
+ &nlm_version4,
+#endif
};
static struct rpc_stat nlm_stats;
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
new file mode 100644
index 000000000..7cedcd849
--- /dev/null
+++ b/fs/lockd/xdr4.c
@@ -0,0 +1,601 @@
+/*
+ * linux/fs/lockd/xdr4.c
+ *
+ * XDR support for lockd and the lock client.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1999, Trond Myklebust <trond.myklebust@fys.uio.no>
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/utsname.h>
+#include <linux/nfs.h>
+
+#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/stats.h>
+#include <linux/lockd/lockd.h>
+#include <linux/lockd/sm_inter.h>
+
+#define NLMDBG_FACILITY NLMDBG_XDR
+#define NLM_MAXSTRLEN 1024
+#define OFFSET_MAX ((off_t)LONG_MAX)
+
+#define QUADLEN(len) (((len) + 3) >> 2)
+
+u32 nlm4_deadlock, nlm4_rofs, nlm4_stale_fh, nlm4_fbig,
+ nlm4_failed;
+
+
+typedef struct nlm_args nlm_args;
+
+static inline off_t
+size_to_off_t(__s64 size)
+{
+ size = (size > (__s64)LONG_MAX) ? (off_t)LONG_MAX : (off_t) size;
+ return (size < (__s64)-LONG_MAX) ? (off_t)-LONG_MAX : (off_t) size;
+}
+
+/*
+ * XDR functions for basic NLM types
+ */
+static u32 *
+nlm4_decode_cookie(u32 *p, struct nlm_cookie *c)
+{
+ unsigned int len;
+
+ len = ntohl(*p++);
+
+ if(len==0)
+ {
+ c->len=4;
+ memset(c->data, 0, 4); /* hockeypux brain damage */
+ }
+ else if(len<=8)
+ {
+ c->len=len;
+ memcpy(c->data, p, len);
+ p+=(len+3)>>2;
+ }
+ else
+ {
+ printk(KERN_NOTICE
+ "lockd: bad cookie size %d (only cookies under 8 bytes are supported.)\n", len);
+ return NULL;
+ }
+ return p;
+}
+
+static u32 *
+nlm4_encode_cookie(u32 *p, struct nlm_cookie *c)
+{
+ *p++ = htonl(c->len);
+ memcpy(p, c->data, c->len);
+ p+=(c->len+3)>>2;
+ return p;
+}
+
+static u32 *
+nlm4_decode_fh(u32 *p, struct nfs_fh *f)
+{
+ memset(f->data, 0, sizeof(f->data));
+#ifdef NFS_MAXFHSIZE
+ f->size = ntohl(*p++);
+ if (f->size > NFS_MAXFHSIZE) {
+ printk(KERN_NOTICE
+ "lockd: bad fhandle size %x (should be %d)\n",
+ f->size, NFS_MAXFHSIZE);
+ return NULL;
+ }
+ memcpy(f->data, p, f->size);
+ return p + XDR_QUADLEN(f->size);
+#else
+ if (ntohl(*p++) != NFS_FHSIZE)
+ return NULL; /* for now, all filehandles are 32 bytes */
+ memcpy(f->data, p, NFS_FHSIZE);
+ return p + XDR_QUADLEN(NFS_FHSIZE);
+#endif
+}
+
+static u32 *
+nlm4_encode_fh(u32 *p, struct nfs_fh *f)
+{
+#ifdef NFS_MAXFHSIZE
+ *p++ = htonl(f->size);
+ memcpy(p, f->data, f->size);
+ return p + XDR_QUADLEN(f->size);
+#else
+ *p++ = htonl(NFS_FHSIZE);
+ memcpy(p, f->data, NFS_FHSIZE);
+ return p + XDR_QUADLEN(NFS_FHSIZE);
+#endif
+}
+
+/*
+ * Encode and decode owner handle
+ */
+static u32 *
+nlm4_decode_oh(u32 *p, struct xdr_netobj *oh)
+{
+ return xdr_decode_netobj(p, oh);
+}
+
+static u32 *
+nlm4_encode_oh(u32 *p, struct xdr_netobj *oh)
+{
+ return xdr_encode_netobj(p, oh);
+}
+
+static u32 *
+nlm4_decode_lock(u32 *p, struct nlm_lock *lock)
+{
+ struct file_lock *fl = &lock->fl;
+ __s64 len, start, end;
+ int tmp;
+
+ if (!(p = xdr_decode_string(p, &lock->caller, &tmp, NLM_MAXSTRLEN))
+ || !(p = nlm4_decode_fh(p, &lock->fh))
+ || !(p = nlm4_decode_oh(p, &lock->oh)))
+ return NULL;
+
+ memset(fl, 0, sizeof(*fl));
+ fl->fl_owner = current->files;
+ fl->fl_pid = ntohl(*p++);
+ fl->fl_flags = FL_POSIX;
+ fl->fl_type = F_RDLCK; /* as good as anything else */
+ p = xdr_decode_hyper(p, &start);
+ p = xdr_decode_hyper(p, &len);
+ end = start + len - 1;
+
+ fl->fl_start = size_to_off_t(start);
+ fl->fl_end = size_to_off_t(end);
+
+ if (len == 0 || fl->fl_end < 0)
+ fl->fl_end = OFFSET_MAX;
+ return p;
+}
+
+/*
+ * Encode a lock as part of an NLM call
+ */
+static u32 *
+nlm4_encode_lock(u32 *p, struct nlm_lock *lock)
+{
+ struct file_lock *fl = &lock->fl;
+
+ if (!(p = xdr_encode_string(p, lock->caller))
+ || !(p = nlm4_encode_fh(p, &lock->fh))
+ || !(p = nlm4_encode_oh(p, &lock->oh)))
+ return NULL;
+
+ *p++ = htonl(fl->fl_pid);
+ p = xdr_encode_hyper(p, fl->fl_start);
+ if (fl->fl_end == OFFSET_MAX)
+ p = xdr_encode_hyper(p, 0);
+ else
+ p = xdr_encode_hyper(p, fl->fl_end - fl->fl_start + 1);
+
+ return p;
+}
+
+/*
+ * Encode result of a TEST/TEST_MSG call
+ */
+static u32 *
+nlm4_encode_testres(u32 *p, struct nlm_res *resp)
+{
+ dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp);
+ if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
+ return 0;
+ *p++ = resp->status;
+
+ if (resp->status == nlm_lck_denied) {
+ struct file_lock *fl = &resp->lock.fl;
+
+ *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
+ *p++ = htonl(fl->fl_pid);
+
+ /* Encode owner handle. */
+ if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
+ return 0;
+
+ p = xdr_encode_hyper(p, fl->fl_start);
+ if (fl->fl_end == OFFSET_MAX)
+ p = xdr_encode_hyper(p, 0);
+ else
+ p = xdr_encode_hyper(p, fl->fl_end - fl->fl_start + 1);
+ dprintk("xdr: encode_testres (status %d pid %d type %d start %ld end %ld)\n", resp->status, fl->fl_pid, fl->fl_type, fl->fl_start, fl->fl_end);
+ }
+
+ dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp);
+ return p;
+}
+
+
+/*
+ * Check buffer bounds after decoding arguments
+ */
+static int
+xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
+{
+ struct svc_buf *buf = &rqstp->rq_argbuf;
+
+ return p - buf->base <= buf->buflen;
+}
+
+static int
+xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
+{
+ struct svc_buf *buf = &rqstp->rq_resbuf;
+
+ buf->len = p - buf->base;
+ return (buf->len <= buf->buflen);
+}
+
+/*
+ * First, the server side XDR functions
+ */
+int
+nlm4svc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+{
+ u32 exclusive;
+
+ if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
+ return 0;
+
+ exclusive = ntohl(*p++);
+ if (!(p = nlm4_decode_lock(p, &argp->lock)))
+ return 0;
+ if (exclusive)
+ argp->lock.fl.fl_type = F_WRLCK;
+
+ return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+{
+ if (!(p = nlm4_encode_testres(p, resp)))
+ return 0;
+ return xdr_ressize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+{
+ u32 exclusive;
+
+ if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
+ return 0;
+ argp->block = ntohl(*p++);
+ exclusive = ntohl(*p++);
+ if (!(p = nlm4_decode_lock(p, &argp->lock)))
+ return 0;
+ if (exclusive)
+ argp->lock.fl.fl_type = F_WRLCK;
+ argp->reclaim = ntohl(*p++);
+ argp->state = ntohl(*p++);
+ argp->monitor = 1; /* monitor client by default */
+
+ return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+{
+ u32 exclusive;
+
+ if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
+ return 0;
+ argp->block = ntohl(*p++);
+ exclusive = ntohl(*p++);
+ if (!(p = nlm4_decode_lock(p, &argp->lock)))
+ return 0;
+ if (exclusive)
+ argp->lock.fl.fl_type = F_WRLCK;
+ return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+{
+ if (!(p = nlm4_decode_cookie(p, &argp->cookie))
+ || !(p = nlm4_decode_lock(p, &argp->lock)))
+ return 0;
+ argp->lock.fl.fl_type = F_UNLCK;
+ return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+{
+ struct nlm_lock *lock = &argp->lock;
+ int len;
+
+ memset(lock, 0, sizeof(*lock));
+ lock->fl.fl_pid = ~(u32) 0;
+
+ if (!(p = nlm4_decode_cookie(p, &argp->cookie))
+ || !(p = xdr_decode_string(p, &lock->caller, &len, NLM_MAXSTRLEN))
+ || !(p = nlm4_decode_fh(p, &lock->fh))
+ || !(p = nlm4_decode_oh(p, &lock->oh)))
+ return 0;
+ argp->fsm_mode = ntohl(*p++);
+ argp->fsm_access = ntohl(*p++);
+ return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+{
+ if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
+ return 0;
+ *p++ = resp->status;
+ *p++ = xdr_zero; /* sequence argument */
+ return xdr_ressize_check(rqstp, p);
+}
+
+int
+nlm4svc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+{
+ if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
+ return 0;
+ *p++ = resp->status;
+ return xdr_ressize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp)
+{
+ struct nlm_lock *lock = &argp->lock;
+ int len;
+
+ if (!(p = xdr_decode_string(p, &lock->caller, &len, NLM_MAXSTRLEN)))
+ return 0;
+ argp->state = ntohl(*p++);
+ return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
+{
+ if (!(p = xdr_decode_string(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
+ return 0;
+ argp->state = ntohl(*p++);
+ argp->addr = ntohl(*p++);
+ return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+{
+ if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
+ return 0;
+ resp->status = ntohl(*p++);
+ return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+{
+ return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+{
+ return xdr_ressize_check(rqstp, p);
+}
+
+/*
+ * Now, the client side XDR functions
+ */
+static int
+nlm4clt_encode_void(struct rpc_rqst *req, u32 *p, void *ptr)
+{
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ return 0;
+}
+
+static int
+nlm4clt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr)
+{
+ return 0;
+}
+
+static int
+nlm4clt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+{
+ struct nlm_lock *lock = &argp->lock;
+
+ if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
+ return -EIO;
+ *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
+ if (!(p = nlm4_encode_lock(p, lock)))
+ return -EIO;
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ return 0;
+}
+
+static int
+nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+{
+ if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
+ return -EIO;
+ resp->status = ntohl(*p++);
+ if (resp->status == NLM_LCK_DENIED) {
+ struct file_lock *fl = &resp->lock.fl;
+ u32 excl;
+ s64 start, end, len;
+
+ memset(&resp->lock, 0, sizeof(resp->lock));
+ excl = ntohl(*p++);
+ fl->fl_pid = ntohl(*p++);
+ if (!(p = nlm4_decode_oh(p, &resp->lock.oh)))
+ return -EIO;
+
+ fl->fl_flags = FL_POSIX;
+ fl->fl_type = excl? F_WRLCK : F_RDLCK;
+ p = xdr_decode_hyper(p, &start);
+ p = xdr_decode_hyper(p, &len);
+ end = start + len - 1;
+
+ fl->fl_start = size_to_off_t(start);
+ fl->fl_end = size_to_off_t(end);
+ if (len == 0 || fl->fl_end < 0)
+ fl->fl_end = OFFSET_MAX;
+ }
+ return 0;
+}
+
+
+static int
+nlm4clt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+{
+ struct nlm_lock *lock = &argp->lock;
+
+ if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
+ return -EIO;
+ *p++ = argp->block? xdr_one : xdr_zero;
+ *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
+ if (!(p = nlm4_encode_lock(p, lock)))
+ return -EIO;
+ *p++ = argp->reclaim? xdr_one : xdr_zero;
+ *p++ = htonl(argp->state);
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ return 0;
+}
+
+static int
+nlm4clt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+{
+ struct nlm_lock *lock = &argp->lock;
+
+ if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
+ return -EIO;
+ *p++ = argp->block? xdr_one : xdr_zero;
+ *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
+ if (!(p = nlm4_encode_lock(p, lock)))
+ return -EIO;
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ return 0;
+}
+
+static int
+nlm4clt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+{
+ struct nlm_lock *lock = &argp->lock;
+
+ if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
+ return -EIO;
+ if (!(p = nlm4_encode_lock(p, lock)))
+ return -EIO;
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ return 0;
+}
+
+static int
+nlm4clt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+{
+ if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
+ return -EIO;
+ *p++ = resp->status;
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ return 0;
+}
+
+static int
+nlm4clt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+{
+ if (!(p = nlm4_encode_testres(p, resp)))
+ return -EIO;
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ return 0;
+}
+
+static int
+nlm4clt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+{
+ if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
+ return -EIO;
+ resp->status = ntohl(*p++);
+ return 0;
+}
+
+/*
+ * Buffer requirements for NLM
+ */
+#define NLM4_void_sz 0
+#define NLM4_cookie_sz 3 /* 1 len , 2 data */
+#define NLM4_caller_sz 1+XDR_QUADLEN(NLM_MAXSTRLEN)
+#define NLM4_netobj_sz 1+XDR_QUADLEN(XDR_MAX_NETOBJ)
+/* #define NLM4_owner_sz 1+XDR_QUADLEN(NLM4_MAXOWNER) */
+#define NLM4_fhandle_sz 1+XDR_QUADLEN(NFS3_FHSIZE)
+#define NLM4_lock_sz 5+NLM4_caller_sz+NLM4_netobj_sz+NLM4_fhandle_sz
+#define NLM4_holder_sz 6+NLM4_netobj_sz
+
+#define NLM4_testargs_sz NLM4_cookie_sz+1+NLM4_lock_sz
+#define NLM4_lockargs_sz NLM4_cookie_sz+4+NLM4_lock_sz
+#define NLM4_cancargs_sz NLM4_cookie_sz+2+NLM4_lock_sz
+#define NLM4_unlockargs_sz NLM4_cookie_sz+NLM4_lock_sz
+
+#define NLM4_testres_sz NLM4_cookie_sz+1+NLM4_holder_sz
+#define NLM4_res_sz NLM4_cookie_sz+1
+#define NLM4_norep_sz 0
+
+#ifndef MAX
+# define MAX(a,b) (((a) > (b))? (a) : (b))
+#endif
+
+/*
+ * For NLM, a void procedure really returns nothing
+ */
+#define nlm4clt_decode_norep NULL
+
+#define PROC(proc, argtype, restype) \
+ { "nlm4_" #proc, \
+ (kxdrproc_t) nlm4clt_encode_##argtype, \
+ (kxdrproc_t) nlm4clt_decode_##restype, \
+ MAX(NLM4_##argtype##_sz, NLM4_##restype##_sz) << 2, \
+ 0 \
+ }
+
+static struct rpc_procinfo nlm4_procedures[] = {
+ PROC(null, void, void),
+ PROC(test, testargs, testres),
+ PROC(lock, lockargs, res),
+ PROC(canc, cancargs, res),
+ PROC(unlock, unlockargs, res),
+ PROC(granted, testargs, res),
+ PROC(test_msg, testargs, norep),
+ PROC(lock_msg, lockargs, norep),
+ PROC(canc_msg, cancargs, norep),
+ PROC(unlock_msg, unlockargs, norep),
+ PROC(granted_msg, testargs, norep),
+ PROC(test_res, testres, norep),
+ PROC(lock_res, res, norep),
+ PROC(canc_res, res, norep),
+ PROC(unlock_res, res, norep),
+ PROC(granted_res, res, norep),
+ PROC(undef, void, void),
+ PROC(undef, void, void),
+ PROC(undef, void, void),
+ PROC(undef, void, void),
+#ifdef NLMCLNT_SUPPORT_SHARES
+ PROC(share, shareargs, shareres),
+ PROC(unshare, shareargs, shareres),
+ PROC(nm_lock, lockargs, res),
+ PROC(free_all, notify, void),
+#else
+ PROC(undef, void, void),
+ PROC(undef, void, void),
+ PROC(undef, void, void),
+ PROC(undef, void, void),
+#endif
+};
+
+struct rpc_version nlm_version4 = {
+ 4, 24, nlm4_procedures,
+};