diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-04-19 04:00:00 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-04-19 04:00:00 +0000 |
commit | 46e045034336a2cc90c1798cd7cc07af744ddfd6 (patch) | |
tree | 3b9b51fc482e729f663d25333e77fbed9aaa939a /fs/lockd | |
parent | 31dc59d503a02e84c4de98826452acaeb56dc15a (diff) |
Merge with Linux 2.3.99-pre4.
Diffstat (limited to 'fs/lockd')
-rw-r--r-- | fs/lockd/clntlock.c | 2 | ||||
-rw-r--r-- | fs/lockd/clntproc.c | 98 | ||||
-rw-r--r-- | fs/lockd/host.c | 35 | ||||
-rw-r--r-- | fs/lockd/mon.c | 44 | ||||
-rw-r--r-- | fs/lockd/svc4proc.c | 14 | ||||
-rw-r--r-- | fs/lockd/svclock.c | 44 | ||||
-rw-r--r-- | fs/lockd/svcproc.c | 9 | ||||
-rw-r--r-- | fs/lockd/svcsubs.c | 4 | ||||
-rw-r--r-- | fs/lockd/xdr.c | 95 | ||||
-rw-r--r-- | fs/lockd/xdr4.c | 82 |
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(¤t->sigmask_lock, flags); call = nlmclnt_alloc_call(); + if (!call) { + status = -ENOMEM; + goto out_restore; + } call->a_flags = RPC_TASK_ASYNC; } else { spin_unlock_irqrestore(¤t->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(¤t->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(¤t->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(¤t->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; } |