From: Trond Myklebust NLM/lockd: Fix up lockd to make use of the new interface. In particular set up fl_compare_owner() methods for both client and server. NLM/lockd: Make the client release all locks in a "steal_locks" situation. NLM/lockd: Fix up copying/release of the file_lock->fl_u.nfs_fl private data. Signed-off-by: Andrew Morton --- 25-akpm/fs/lockd/clntproc.c | 98 +++++++++++++++++++++++++----------- 25-akpm/fs/lockd/svc4proc.c | 1 25-akpm/fs/lockd/svclock.c | 10 +++ 25-akpm/fs/lockd/svcproc.c | 1 25-akpm/include/linux/lockd/lockd.h | 2 5 files changed, 84 insertions(+), 28 deletions(-) diff -puN fs/lockd/clntproc.c~posix-locking-fix-up-lockd fs/lockd/clntproc.c --- 25/fs/lockd/clntproc.c~posix-locking-fix-up-lockd 2004-06-29 22:28:32.834709808 -0700 +++ 25-akpm/fs/lockd/clntproc.c 2004-06-29 22:28:32.845708136 -0700 @@ -27,6 +27,7 @@ static int nlmclnt_unlock(struct nlm_rqs static void nlmclnt_unlock_callback(struct rpc_task *); static void nlmclnt_cancel_callback(struct rpc_task *); static int nlm_stat_to_errno(u32 stat); +static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host); /* * Cookie counter for NLM requests @@ -44,8 +45,7 @@ static inline void nlmclnt_next_cookie(s /* * Initialize arguments for TEST/LOCK/UNLOCK/CANCEL calls */ -static inline void -nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) +static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) { struct nlm_args *argp = &req->a_args; struct nlm_lock *lock = &argp->lock; @@ -60,6 +60,14 @@ nlmclnt_setlockargs(struct nlm_rqst *req locks_copy_lock(&lock->fl, fl); } +static void nlmclnt_release_lockargs(struct nlm_rqst *req) +{ + struct file_lock *fl = &req->a_args.lock.fl; + + if (fl->fl_ops && fl->fl_ops->fl_release_private) + fl->fl_ops->fl_release_private(fl); +} + /* * Initialize arguments for GRANTED call. The nlm_rqst structure * has been cleared already. @@ -77,8 +85,10 @@ nlmclnt_setgrantargs(struct nlm_rqst *ca if (lock->oh.len > NLMCLNT_OHSIZE) { void *data = kmalloc(lock->oh.len, GFP_KERNEL); - if (!data) + if (!data) { + nlmclnt_freegrantargs(call); return 0; + } call->a_args.lock.oh.data = (u8 *) data; } @@ -89,12 +99,15 @@ nlmclnt_setgrantargs(struct nlm_rqst *ca void nlmclnt_freegrantargs(struct nlm_rqst *call) { + struct file_lock *fl = &call->a_args.lock.fl; /* * Check whether we allocated memory for the owner. */ if (call->a_args.lock.oh.data != (u8 *) call->a_owner) { kfree(call->a_args.lock.oh.data); } + if (fl->fl_ops && fl->fl_ops->fl_release_private) + fl->fl_ops->fl_release_private(fl); } /* @@ -165,6 +178,8 @@ nlmclnt_proc(struct inode *inode, int cm } call->a_host = host; + nlmclnt_locks_init_private(fl, host); + /* Set up the argument struct */ nlmclnt_setlockargs(call, fl); @@ -179,9 +194,6 @@ nlmclnt_proc(struct inode *inode, int cm else status = -EINVAL; - if (status < 0 && (call->a_flags & RPC_TASK_ASYNC)) - kfree(call); - out_restore: spin_lock_irqsave(¤t->sighand->siglock, flags); current->blocked = oldset; @@ -382,7 +394,9 @@ nlmclnt_test(struct nlm_rqst *req, struc { int status; - if ((status = nlmclnt_call(req, NLMPROC_TEST)) < 0) + status = nlmclnt_call(req, NLMPROC_TEST); + nlmclnt_release_lockargs(req); + if (status < 0) return status; status = req->a_res.status; @@ -391,10 +405,9 @@ nlmclnt_test(struct nlm_rqst *req, struc } if (status == NLM_LCK_DENIED) { /* * Report the conflicting lock back to the application. - * FIXME: Is it OK to report the pid back as well? */ locks_copy_lock(fl, &req->a_res.lock.fl); - /* fl->fl_pid = 0; */ + fl->fl_pid = 0; } else { return nlm_stat_to_errno(req->a_res.status); } @@ -402,18 +415,36 @@ nlmclnt_test(struct nlm_rqst *req, struc return 0; } -static -void nlmclnt_insert_lock_callback(struct file_lock *fl) +static void nlmclnt_locks_copy_lock(struct file_lock *new, struct file_lock *fl) { - nlm_get_host(fl->fl_u.nfs_fl.host); + memcpy(&new->fl_u.nfs_fl, &fl->fl_u.nfs_fl, sizeof(new->fl_u.nfs_fl)); + nlm_get_host(new->fl_u.nfs_fl.host); } -static -void nlmclnt_remove_lock_callback(struct file_lock *fl) + +static void nlmclnt_locks_release_private(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; - } + nlm_release_host(fl->fl_u.nfs_fl.host); + fl->fl_ops = NULL; +} + +static void nlmclnt_steal_locks(struct file_lock *fl, fl_owner_t owner) +{ + locks_remove_posix(fl->fl_file, owner); +} + +static struct file_lock_operations nlmclnt_lock_ops = { + .fl_copy_lock = nlmclnt_locks_copy_lock, + .fl_release_private = nlmclnt_locks_release_private, + .fl_steal_locks = nlmclnt_steal_locks, +}; + +static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host) +{ + BUG_ON(fl->fl_ops != NULL); + fl->fl_u.nfs_fl.state = 0; + fl->fl_u.nfs_fl.flags = 0; + fl->fl_u.nfs_fl.host = nlm_get_host(host); + fl->fl_ops = &nlmclnt_lock_ops; } /* @@ -446,7 +477,8 @@ nlmclnt_lock(struct nlm_rqst *req, struc if (!host->h_monitored && nsm_monitor(host) < 0) { printk(KERN_NOTICE "lockd: failed to monitor %s\n", host->h_name); - return -ENOLCK; + status = -ENOLCK; + goto out; } do { @@ -456,18 +488,17 @@ nlmclnt_lock(struct nlm_rqst *req, struc status = nlmclnt_block(host, fl, &resp->status); } if (status < 0) - return status; + goto out; } while (resp->status == NLM_LCK_BLOCKED && req->a_args.block); 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); + status = nlm_stat_to_errno(resp->status); +out: + nlmclnt_release_lockargs(req); + return status; } /* @@ -527,11 +558,18 @@ nlmclnt_unlock(struct nlm_rqst *req, str fl->fl_u.nfs_fl.flags &= ~NFS_LCK_GRANTED; if (req->a_flags & RPC_TASK_ASYNC) { - return nlmclnt_async_call(req, NLMPROC_UNLOCK, + status = nlmclnt_async_call(req, NLMPROC_UNLOCK, nlmclnt_unlock_callback); + if (status < 0) { + nlmclnt_release_lockargs(req); + kfree(req); + } + return status; } - if ((status = nlmclnt_call(req, NLMPROC_UNLOCK)) < 0) + status = nlmclnt_call(req, NLMPROC_UNLOCK); + nlmclnt_release_lockargs(req); + if (status < 0) return status; if (resp->status == NLM_LCK_GRANTED) @@ -567,6 +605,7 @@ nlmclnt_unlock_callback(struct rpc_task die: nlm_release_host(req->a_host); + nlmclnt_release_lockargs(req); kfree(req); return; retry_rebind: @@ -605,8 +644,10 @@ nlmclnt_cancel(struct nlm_host *host, st status = nlmclnt_async_call(req, NLMPROC_CANCEL, nlmclnt_cancel_callback); - if (status < 0) + if (status < 0) { + nlmclnt_release_lockargs(req); kfree(req); + } spin_lock_irqsave(¤t->sighand->siglock, flags); current->blocked = oldset; @@ -648,6 +689,7 @@ nlmclnt_cancel_callback(struct rpc_task die: nlm_release_host(req->a_host); + nlmclnt_release_lockargs(req); kfree(req); return; diff -puN fs/lockd/svc4proc.c~posix-locking-fix-up-lockd fs/lockd/svc4proc.c --- 25/fs/lockd/svc4proc.c~posix-locking-fix-up-lockd 2004-06-29 22:28:32.835709656 -0700 +++ 25-akpm/fs/lockd/svc4proc.c 2004-06-29 22:28:32.846707984 -0700 @@ -55,6 +55,7 @@ nlm4svc_retrieve_args(struct svc_rqst *r /* 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; + lock->fl.fl_ops = &nlmsvc_lock_operations; } return 0; diff -puN fs/lockd/svclock.c~posix-locking-fix-up-lockd fs/lockd/svclock.c --- 25/fs/lockd/svclock.c~posix-locking-fix-up-lockd 2004-06-29 22:28:32.837709352 -0700 +++ 25-akpm/fs/lockd/svclock.c 2004-06-29 22:28:32.847707832 -0700 @@ -194,6 +194,7 @@ nlmsvc_create_block(struct svc_rqst *rqs /* Set notifier function for VFS, and init args */ block->b_call.a_args.lock.fl.fl_notify = nlmsvc_notify_blocked; + block->b_call.a_args.lock.fl.fl_ops = &nlmsvc_lock_operations; block->b_call.a_args.cookie = *cookie; /* see above */ dprintk("lockd: created block %p...\n", block); @@ -479,6 +480,15 @@ nlmsvc_notify_blocked(struct file_lock * printk(KERN_WARNING "lockd: notification for unknown block!\n"); } +static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2) +{ + return fl1->fl_owner == fl2->fl_owner && fl1->fl_pid == fl2->fl_pid; +} + +struct file_lock_operations nlmsvc_lock_operations = { + .fl_compare_owner = nlmsvc_same_owner, +}; + /* * Try to claim a lock that was previously blocked. * diff -puN fs/lockd/svcproc.c~posix-locking-fix-up-lockd fs/lockd/svcproc.c --- 25/fs/lockd/svcproc.c~posix-locking-fix-up-lockd 2004-06-29 22:28:32.839709048 -0700 +++ 25-akpm/fs/lockd/svcproc.c 2004-06-29 22:28:32.847707832 -0700 @@ -84,6 +84,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rq /* 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; + lock->fl.fl_ops = &nlmsvc_lock_operations; } return 0; diff -puN include/linux/lockd/lockd.h~posix-locking-fix-up-lockd include/linux/lockd/lockd.h --- 25/include/linux/lockd/lockd.h~posix-locking-fix-up-lockd 2004-06-29 22:28:32.840708896 -0700 +++ 25-akpm/include/linux/lockd/lockd.h 2004-06-29 22:28:32.848707680 -0700 @@ -205,6 +205,8 @@ nlm_compare_locks(struct file_lock *fl1, &&(fl1->fl_type == fl2->fl_type || fl2->fl_type == F_UNLCK); } +extern struct file_lock_operations nlmsvc_lock_operations; + #endif /* __KERNEL__ */ #endif /* LINUX_LOCKD_LOCKD_H */ _