summaryrefslogtreecommitdiffstats
path: root/fs/lockd
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-04-19 04:00:00 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-04-19 04:00:00 +0000
commit46e045034336a2cc90c1798cd7cc07af744ddfd6 (patch)
tree3b9b51fc482e729f663d25333e77fbed9aaa939a /fs/lockd
parent31dc59d503a02e84c4de98826452acaeb56dc15a (diff)
Merge with Linux 2.3.99-pre4.
Diffstat (limited to 'fs/lockd')
-rw-r--r--fs/lockd/clntlock.c2
-rw-r--r--fs/lockd/clntproc.c98
-rw-r--r--fs/lockd/host.c35
-rw-r--r--fs/lockd/mon.c44
-rw-r--r--fs/lockd/svc4proc.c14
-rw-r--r--fs/lockd/svclock.c44
-rw-r--r--fs/lockd/svcproc.c9
-rw-r--r--fs/lockd/svcsubs.c4
-rw-r--r--fs/lockd/xdr.c95
-rw-r--r--fs/lockd/xdr4.c82
10 files changed, 274 insertions, 153 deletions
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index 7a4674d85..f89188d12 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -152,7 +152,7 @@ nlmclnt_recovery(struct nlm_host *host, u32 newstate)
host->h_monitored = 0;
host->h_nsmstate = newstate;
host->h_state++;
- host->h_count++;
+ nlm_get_host(host);
kernel_thread(reclaimer, host, 0);
}
}
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 20b9bb490..376eed9cc 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -106,10 +106,18 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
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 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
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 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
}
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 @@ nlmclnt_alloc_call(void)
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 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
case -ECONNREFUSED:
case -ETIMEDOUT:
case -ENOTCONN:
+ nlm_rebind_host(host);
status = -EAGAIN;
break;
case -ERESTARTSYS:
@@ -253,10 +266,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
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 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
* 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 @@ nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
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 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
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 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
return -ENOLCK;
}
- while (1) {
+ do {
if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0) {
if (resp->status != NLM_LCK_BLOCKED)
break;
@@ -388,11 +423,14 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
}
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 @@ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl)
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 @@ nlmclnt_unlock_callback(struct rpc_task *task)
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 @@ nlmclnt_unlock_callback(struct rpc_task *task)
}
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 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
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 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
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 @@ nlmclnt_cancel_callback(struct rpc_task *task)
}
die:
- rpc_release_task(task);
nlm_release_host(req->a_host);
kfree(req);
return;
@@ -582,7 +615,6 @@ retry_cancel:
nlm_rebind_host(req->a_host);
rpc_restart_call(task);
rpc_delay(task, 30 * HZ);
- return;
}
/*
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 02cfb07f4..dcd33c19b 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -15,6 +15,7 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
#include <linux/lockd/lockd.h>
+#include <linux/lockd/sm_inter.h>
#define NLMDBG_FACILITY NLMDBG_HOSTCACHE
@@ -105,8 +106,7 @@ nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
host->h_next = nlm_hosts[hash];
nlm_hosts[hash] = host;
}
- host->h_expires = jiffies + NLM_HOST_EXPIRE;
- host->h_count++;
+ nlm_get_host(host);
up(&nlm_host_sema);
return host;
}
@@ -172,9 +172,12 @@ nlm_bind_host(struct nlm_host *host)
down(&host->h_sema);
/* If we've already created an RPC client, check whether
- * RPC rebind is required */
+ * RPC rebind is required
+ * Note: why keep rebinding if we're on a tcp connection?
+ */
if ((clnt = host->h_rpcclnt) != NULL) {
- if (time_after_eq(jiffies, host->h_nextrebind)) {
+ xprt = clnt->cl_xprt;
+ if (!xprt->stream && time_after_eq(jiffies, host->h_nextrebind)) {
clnt->cl_port = 0;
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
dprintk("lockd: next rebind in %ld jiffies\n",
@@ -230,13 +233,27 @@ nlm_rebind_host(struct nlm_host *host)
}
/*
+ * Increment NLM host count
+ */
+struct nlm_host * nlm_get_host(struct nlm_host *host)
+{
+ if (host) {
+ dprintk("lockd: get host %s\n", host->h_name);
+ host->h_count ++;
+ host->h_expires = jiffies + NLM_HOST_EXPIRE;
+ }
+ return host;
+}
+
+/*
* Release NLM host after use
*/
-void
-nlm_release_host(struct nlm_host *host)
+void nlm_release_host(struct nlm_host *host)
{
- dprintk("lockd: release host %s\n", host->h_name);
- host->h_count -= 1;
+ if (host && host->h_count) {
+ dprintk("lockd: release host %s\n", host->h_name);
+ host->h_count --;
+ }
}
/*
@@ -308,6 +325,8 @@ nlm_gc_hosts(void)
}
dprintk("lockd: delete host %s\n", host->h_name);
*q = host->h_next;
+ if (host->h_monitored)
+ nsm_unmonitor(host);
if ((clnt = host->h_rpcclnt) != NULL) {
if (clnt->cl_users) {
printk(KERN_WARNING
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index 55dee3886..283d66e97 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -30,14 +30,12 @@ u32 nsm_local_state = 0;
* Common procedure for SM_MON/SM_UNMON calls
*/
static int
-nsm_mon_unmon(struct nlm_host *host, char *what, u32 proc)
+nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res)
{
struct rpc_clnt *clnt;
int status;
struct nsm_args args;
- struct nsm_res res;
- dprintk("lockd: nsm_%s(%s)\n", what, host->h_name);
status = -EACCES;
clnt = nsm_create();
if (!clnt)
@@ -47,23 +45,15 @@ nsm_mon_unmon(struct nlm_host *host, char *what, u32 proc)
args.prog = NLM_PROGRAM;
args.vers = 1;
args.proc = NLMPROC_NSM_NOTIFY;
+ memset(res, 0, sizeof(*res));
- status = rpc_call(clnt, proc, &args, &res, 0);
- if (status < 0) {
+ status = rpc_call(clnt, proc, &args, res, 0);
+ if (status < 0)
printk(KERN_DEBUG "nsm_mon_unmon: rpc failed, status=%d\n",
status);
- goto out;
- }
-
- status = -EACCES;
- if (res.status != 0) {
- printk(KERN_NOTICE "lockd: cannot %s %s\n", what, host->h_name);
- goto out;
- }
-
- nsm_local_state = res.state;
- status = 0;
-out:
+ else
+ status = 0;
+ out:
return status;
}
@@ -73,10 +63,16 @@ out:
int
nsm_monitor(struct nlm_host *host)
{
+ struct nsm_res res;
int status;
- status = nsm_mon_unmon(host, "monitor", SM_MON);
- if (status >= 0)
+ dprintk("lockd: nsm_monitor(%s)\n", host->h_name);
+
+ status = nsm_mon_unmon(host, SM_MON, &res);
+
+ if (status < 0 || res.status != 0)
+ printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name);
+ else
host->h_monitored = 1;
return status;
}
@@ -87,9 +83,15 @@ nsm_monitor(struct nlm_host *host)
int
nsm_unmonitor(struct nlm_host *host)
{
+ struct nsm_res res;
int status;
- if ((status = nsm_mon_unmon(host, "unmonitor", SM_UNMON)) >= 0)
+ dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name);
+
+ status = nsm_mon_unmon(host, SM_UNMON, &res);
+ if (status < 0)
+ printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", host->h_name);
+ else
host->h_monitored = 0;
return status;
}
@@ -187,7 +189,7 @@ xdr_decode_stat_res(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
static int
xdr_decode_stat(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
{
- resp->status = ntohl(*p++);
+ resp->state = ntohl(*p++);
return 0;
}
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index b690eb97e..a1e30454e 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -470,7 +470,7 @@ nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
host = nlmclnt_lookup_host(&rqstp->rq_addr,
rqstp->rq_prot, rqstp->rq_vers);
if (!host) {
- rpc_free(call);
+ kfree(call);
return rpc_system_err;
}
@@ -478,12 +478,14 @@ nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
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;
+ if (nlmsvc_async_call(call, proc, nlm4svc_callback_exit) < 0)
+ goto error;
return rpc_success;
+ error:
+ kfree(call);
+ nlm_release_host(host);
+ return rpc_system_err;
}
static void
@@ -496,7 +498,7 @@ nlm4svc_callback_exit(struct rpc_task *task)
task->tk_pid, -task->tk_status);
}
nlm_release_host(call->a_host);
- rpc_free(call);
+ kfree(call);
}
/*
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 1bed616cb..97a9d27ef 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -94,14 +94,16 @@ nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock, int remove)
struct nlm_block **head, *block;
struct file_lock *fl;
- dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %ld-%ld ty=%d\n",
- file, lock->fl.fl_pid, lock->fl.fl_start,
- lock->fl.fl_end, lock->fl.fl_type);
+ dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n",
+ file, lock->fl.fl_pid,
+ (long long)lock->fl.fl_start,
+ (long long)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("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,
+ dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%x\n",
+ block->b_file, fl->fl_pid,
+ (long long)fl->fl_start,
+ (long long)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)
@@ -286,12 +288,12 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
struct nlm_block *block;
int error;
- dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %ld-%ld, bl=%d)\n",
+ dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
file->f_file.f_dentry->d_inode->i_dev,
file->f_file.f_dentry->d_inode->i_ino,
lock->fl.fl_type, lock->fl.fl_pid,
- lock->fl.fl_start,
- lock->fl.fl_end,
+ (long long)lock->fl.fl_start,
+ (long long)lock->fl.fl_end,
wait);
/* Lock file against concurrent access */
@@ -365,16 +367,17 @@ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
{
struct file_lock *fl;
- dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %ld-%ld)\n",
+ dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %Ld-%Ld)\n",
file->f_file.f_dentry->d_inode->i_dev,
file->f_file.f_dentry->d_inode->i_ino,
lock->fl.fl_type,
- lock->fl.fl_start,
- lock->fl.fl_end);
+ (long long)lock->fl.fl_start,
+ (long long)lock->fl.fl_end);
if ((fl = posix_test_lock(&file->f_file, &lock->fl)) != NULL) {
- dprintk("lockd: conflicting lock(ty=%d, %ld-%ld)\n",
- fl->fl_type, fl->fl_start, fl->fl_end);
+ dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
+ fl->fl_type, (long long)fl->fl_start,
+ (long long)fl->fl_end);
conflock->caller = "somehost"; /* FIXME */
conflock->oh.len = 0; /* don't return OH info */
conflock->fl = *fl;
@@ -396,12 +399,12 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
{
int error;
- dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %ld-%ld)\n",
+ dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %Ld-%Ld)\n",
file->f_file.f_dentry->d_inode->i_dev,
file->f_file.f_dentry->d_inode->i_ino,
lock->fl.fl_pid,
- lock->fl.fl_start,
- lock->fl.fl_end);
+ (long long)lock->fl.fl_start,
+ (long long)lock->fl.fl_end);
/* First, cancel any lock that might be there */
nlmsvc_cancel_blocked(file, lock);
@@ -424,12 +427,12 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
{
struct nlm_block *block;
- dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %ld-%ld)\n",
+ dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %Ld-%Ld)\n",
file->f_file.f_dentry->d_inode->i_dev,
file->f_file.f_dentry->d_inode->i_ino,
lock->fl.fl_pid,
- lock->fl.fl_start,
- lock->fl.fl_end);
+ (long long)lock->fl.fl_start,
+ (long long)lock->fl.fl_end);
down(&file->f_sema);
if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL)
@@ -576,7 +579,6 @@ nlmsvc_grant_callback(struct rpc_task *task)
block->b_incall = 0;
nlm_release_host(call->a_host);
- rpc_release_task(task);
}
/*
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index c92358dec..b0cbd4a50 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -503,10 +503,14 @@ nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
call->a_host = host;
memcpy(&call->a_args, resp, sizeof(*resp));
- if (nlmclnt_async_call(call, proc, nlmsvc_callback_exit) < 0)
- return rpc_system_err;
+ if (nlmsvc_async_call(call, proc, nlmsvc_callback_exit) < 0)
+ goto error;
return rpc_success;
+ error:
+ nlm_release_host(host);
+ kfree(call);
+ return rpc_system_err;
}
static void
@@ -519,7 +523,6 @@ nlmsvc_callback_exit(struct rpc_task *task)
task->tk_pid, -task->tk_status);
}
nlm_release_host(call->a_host);
- rpc_release_task(task);
kfree(call);
}
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index c6395a54f..1d5b5382c 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -34,7 +34,7 @@ static inline unsigned int file_hash(struct nfs_fh *f)
{
unsigned int tmp=0;
int i;
- for (i=0; i<NFS_FHSIZE;i++)
+ for (i=0; i<NFS2_FHSIZE;i++)
tmp += f->data[i];
return tmp & (FILE_NRHASH - 1);
}
@@ -175,7 +175,7 @@ again:
lock.fl_type = F_UNLCK;
lock.fl_start = 0;
- lock.fl_end = NLM_OFFSET_MAX;
+ lock.fl_end = OFFSET_MAX;
if (posix_lock_file(&file->f_file, &lock, 0) < 0) {
printk("lockd: unlock failure in %s:%d\n",
__FILE__, __LINE__);
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index eba3aaef6..9a179d530 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -22,6 +22,25 @@
#define NLMDBG_FACILITY NLMDBG_XDR
+static inline loff_t
+s32_to_loff_t(__s32 offset)
+{
+ return (loff_t)offset;
+}
+
+static inline __s32
+loff_t_to_s32(loff_t offset)
+{
+ __s32 res;
+ if (offset >= NLM_OFFSET_MAX)
+ res = NLM_OFFSET_MAX;
+ else if (offset <= -NLM_OFFSET_MAX)
+ res = -NLM_OFFSET_MAX;
+ else
+ res = offset;
+ return res;
+}
+
/*
* XDR functions for basic NLM types
*/
@@ -65,22 +84,23 @@ nlm_decode_fh(u32 *p, struct nfs_fh *f)
{
unsigned int len;
- if ((len = ntohl(*p++)) != sizeof(*f)) {
+ if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
printk(KERN_NOTICE
"lockd: bad fhandle size %x (should be %Zu)\n",
- len, sizeof(*f));
+ len, NFS2_FHSIZE);
return NULL;
}
- memcpy(f, p, sizeof(*f));
- return p + XDR_QUADLEN(sizeof(*f));
+ f->size = NFS2_FHSIZE;
+ memcpy(f->data, p, NFS2_FHSIZE);
+ return p + XDR_QUADLEN(NFS2_FHSIZE);
}
static inline u32 *
nlm_encode_fh(u32 *p, struct nfs_fh *f)
{
- *p++ = htonl(sizeof(*f));
- memcpy(p, f, sizeof(*f));
- return p + XDR_QUADLEN(sizeof(*f));
+ *p++ = htonl(NFS2_FHSIZE);
+ memcpy(p, f->data, NFS2_FHSIZE);
+ return p + XDR_QUADLEN(NFS2_FHSIZE);
}
/*
@@ -102,7 +122,7 @@ static inline u32 *
nlm_decode_lock(u32 *p, struct nlm_lock *lock)
{
struct file_lock *fl = &lock->fl;
- int len;
+ s32 start, len, end;
if (!(p = xdr_decode_string(p, &lock->caller, &len, NLM_MAXSTRLEN))
|| !(p = nlm_decode_fh(p, &lock->fh))
@@ -114,10 +134,16 @@ nlm_decode_lock(u32 *p, struct nlm_lock *lock)
fl->fl_pid = ntohl(*p++);
fl->fl_flags = FL_POSIX;
fl->fl_type = F_RDLCK; /* as good as anything else */
- fl->fl_start = ntohl(*p++);
+ start = ntohl(*p++);
len = ntohl(*p++);
- if (len == 0 || (fl->fl_end = fl->fl_start + len - 1) < 0)
- fl->fl_end = NLM_OFFSET_MAX;
+ end = start + len - 1;
+
+ fl->fl_start = s32_to_loff_t(start);
+
+ if (len == 0 || end < 0)
+ fl->fl_end = OFFSET_MAX;
+ else
+ fl->fl_end = s32_to_loff_t(end);
return p;
}
@@ -128,18 +154,26 @@ static u32 *
nlm_encode_lock(u32 *p, struct nlm_lock *lock)
{
struct file_lock *fl = &lock->fl;
+ __s32 start, len;
if (!(p = xdr_encode_string(p, lock->caller))
|| !(p = nlm_encode_fh(p, &lock->fh))
|| !(p = nlm_encode_oh(p, &lock->oh)))
return NULL;
- *p++ = htonl(fl->fl_pid);
- *p++ = htonl(lock->fl.fl_start);
- if (lock->fl.fl_end == NLM_OFFSET_MAX)
- *p++ = xdr_zero;
+ if (fl->fl_start > NLM_OFFSET_MAX
+ || (fl->fl_end > NLM_OFFSET_MAX && fl->fl_end != OFFSET_MAX))
+ return NULL;
+
+ start = loff_t_to_s32(fl->fl_start);
+ if (fl->fl_end == OFFSET_MAX)
+ len = 0;
else
- *p++ = htonl(lock->fl.fl_end - lock->fl.fl_start + 1);
+ len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
+
+ *p++ = htonl(fl->fl_pid);
+ *p++ = htonl(start);
+ *p++ = htonl(len);
return p;
}
@@ -150,6 +184,8 @@ nlm_encode_lock(u32 *p, struct nlm_lock *lock)
static u32 *
nlm_encode_testres(u32 *p, struct nlm_res *resp)
{
+ s32 start, len;
+
if (!(p = nlm_encode_cookie(p, &resp->cookie)))
return 0;
*p++ = resp->status;
@@ -164,11 +200,14 @@ nlm_encode_testres(u32 *p, struct nlm_res *resp)
if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
return 0;
- *p++ = htonl(fl->fl_start);
- if (fl->fl_end == NLM_OFFSET_MAX)
- *p++ = xdr_zero;
+ start = loff_t_to_s32(fl->fl_start);
+ if (fl->fl_end == OFFSET_MAX)
+ len = 0;
else
- *p++ = htonl(fl->fl_end - fl->fl_start + 1);
+ len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
+
+ *p++ = htonl(start);
+ *p++ = htonl(len);
}
return p;
@@ -387,7 +426,8 @@ nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
resp->status = ntohl(*p++);
if (resp->status == NLM_LCK_DENIED) {
struct file_lock *fl = &resp->lock.fl;
- u32 excl, len;
+ u32 excl;
+ s32 start, len, end;
memset(&resp->lock, 0, sizeof(resp->lock));
excl = ntohl(*p++);
@@ -397,10 +437,15 @@ nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
fl->fl_flags = FL_POSIX;
fl->fl_type = excl? F_WRLCK : F_RDLCK;
- fl->fl_start = ntohl(*p++);
+ start = ntohl(*p++);
len = ntohl(*p++);
- if (len == 0 || (fl->fl_end = fl->fl_start + len - 1) < 0)
- fl->fl_end = NLM_OFFSET_MAX;
+ end = start + len - 1;
+
+ fl->fl_start = s32_to_loff_t(start);
+ if (len == 0 || end < 0)
+ fl->fl_end = OFFSET_MAX;
+ else
+ fl->fl_end = s32_to_loff_t(end);
}
return 0;
}
@@ -487,7 +532,7 @@ nlmclt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
#define NLM_caller_sz 1+QUADLEN(sizeof(system_utsname.nodename))
#define NLM_netobj_sz 1+QUADLEN(XDR_MAX_NETOBJ)
/* #define NLM_owner_sz 1+QUADLEN(NLM_MAXOWNER) */
-#define NLM_fhandle_sz 1+QUADLEN(NFS_FHSIZE)
+#define NLM_fhandle_sz 1+QUADLEN(NFS2_FHSIZE)
#define NLM_lock_sz 3+NLM_caller_sz+NLM_netobj_sz+NLM_fhandle_sz
#define NLM_holder_sz 4+NLM_netobj_sz
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
index 025e3c5b0..7ffa0a433 100644
--- a/fs/lockd/xdr4.c
+++ b/fs/lockd/xdr4.c
@@ -20,14 +20,25 @@
#include <linux/lockd/sm_inter.h>
#define NLMDBG_FACILITY NLMDBG_XDR
-#define OFFSET_MAX ((off_t)LONG_MAX)
+static inline loff_t
+s64_to_loff_t(__s64 offset)
+{
+ return (loff_t)offset;
+}
-static inline off_t
-size_to_off_t(__s64 size)
+
+static inline s64
+loff_t_to_s64(loff_t offset)
{
- size = (size > (__s64)LONG_MAX) ? (off_t)LONG_MAX : (off_t) size;
- return (size < (__s64)-LONG_MAX) ? (off_t)-LONG_MAX : (off_t) size;
+ s64 res;
+ if (offset > NLM4_OFFSET_MAX)
+ res = NLM4_OFFSET_MAX;
+ else if (offset < -NLM4_OFFSET_MAX)
+ res = -NLM4_OFFSET_MAX;
+ else
+ res = offset;
+ return res;
}
/*
@@ -73,36 +84,24 @@ 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",
+ "lockd: bad fhandle size %d (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);
+ if (f->size) p[XDR_QUADLEN(f->size)-1] = 0; /* don't leak anything */
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
}
/*
@@ -141,11 +140,12 @@ nlm4_decode_lock(u32 *p, struct nlm_lock *lock)
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);
+ fl->fl_start = s64_to_loff_t(start);
- if (len == 0 || fl->fl_end < 0)
+ if (len == 0 || end < 0)
fl->fl_end = OFFSET_MAX;
+ else
+ fl->fl_end = s64_to_loff_t(end);
return p;
}
@@ -156,18 +156,26 @@ static u32 *
nlm4_encode_lock(u32 *p, struct nlm_lock *lock)
{
struct file_lock *fl = &lock->fl;
+ __s64 start, len;
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_start > NLM4_OFFSET_MAX
+ || (fl->fl_end > NLM4_OFFSET_MAX && fl->fl_end != OFFSET_MAX))
+ return NULL;
+
+ start = loff_t_to_s64(fl->fl_start);
if (fl->fl_end == OFFSET_MAX)
- p = xdr_encode_hyper(p, 0);
+ len = 0;
else
- p = xdr_encode_hyper(p, fl->fl_end - fl->fl_start + 1);
+ len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
+
+ *p++ = htonl(fl->fl_pid);
+ p = xdr_encode_hyper(p, start);
+ p = xdr_encode_hyper(p, len);
return p;
}
@@ -178,6 +186,8 @@ nlm4_encode_lock(u32 *p, struct nlm_lock *lock)
static u32 *
nlm4_encode_testres(u32 *p, struct nlm_res *resp)
{
+ s64 start, len;
+
dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp);
if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
return 0;
@@ -193,12 +203,17 @@ nlm4_encode_testres(u32 *p, struct nlm_res *resp)
if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
return 0;
- p = xdr_encode_hyper(p, fl->fl_start);
+ start = loff_t_to_s64(fl->fl_start);
if (fl->fl_end == OFFSET_MAX)
- p = xdr_encode_hyper(p, 0);
+ len = 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);
+ len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
+
+ p = xdr_encode_hyper(p, start);
+ p = xdr_encode_hyper(p, len);
+ dprintk("xdr: encode_testres (status %d pid %d type %d start %Ld end %Ld)\n",
+ resp->status, fl->fl_pid, fl->fl_type,
+ (long long)fl->fl_start, (long long)fl->fl_end);
}
dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp);
@@ -434,10 +449,11 @@ nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
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_start = s64_to_loff_t(start);
+ if (len == 0 || end < 0)
fl->fl_end = OFFSET_MAX;
+ else
+ fl->fl_end = s64_to_loff_t(end);
}
return 0;
}