Commit 7a25aba8 authored by Trond Myklebust's avatar Trond Myklebust Committed by Linus Torvalds

[PATCH] Fix posix file locking (4/9)

NLM: fix lockd to use the new posix locking callbacks.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent b427d33f
...@@ -27,6 +27,7 @@ static int nlmclnt_unlock(struct nlm_rqst *, struct file_lock *); ...@@ -27,6 +27,7 @@ static int nlmclnt_unlock(struct nlm_rqst *, struct file_lock *);
static void nlmclnt_unlock_callback(struct rpc_task *); static void nlmclnt_unlock_callback(struct rpc_task *);
static void nlmclnt_cancel_callback(struct rpc_task *); static void nlmclnt_cancel_callback(struct rpc_task *);
static int nlm_stat_to_errno(u32 stat); 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 * Cookie counter for NLM requests
...@@ -44,8 +45,7 @@ static inline void nlmclnt_next_cookie(struct nlm_cookie *c) ...@@ -44,8 +45,7 @@ static inline void nlmclnt_next_cookie(struct nlm_cookie *c)
/* /*
* Initialize arguments for TEST/LOCK/UNLOCK/CANCEL calls * Initialize arguments for TEST/LOCK/UNLOCK/CANCEL calls
*/ */
static inline void static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
{ {
struct nlm_args *argp = &req->a_args; struct nlm_args *argp = &req->a_args;
struct nlm_lock *lock = &argp->lock; struct nlm_lock *lock = &argp->lock;
...@@ -60,6 +60,14 @@ nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) ...@@ -60,6 +60,14 @@ nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
locks_copy_lock(&lock->fl, fl); 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 * Initialize arguments for GRANTED call. The nlm_rqst structure
* has been cleared already. * has been cleared already.
...@@ -77,8 +85,10 @@ nlmclnt_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock) ...@@ -77,8 +85,10 @@ nlmclnt_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
if (lock->oh.len > NLMCLNT_OHSIZE) { if (lock->oh.len > NLMCLNT_OHSIZE) {
void *data = kmalloc(lock->oh.len, GFP_KERNEL); void *data = kmalloc(lock->oh.len, GFP_KERNEL);
if (!data) if (!data) {
nlmclnt_freegrantargs(call);
return 0; return 0;
}
call->a_args.lock.oh.data = (u8 *) data; call->a_args.lock.oh.data = (u8 *) data;
} }
...@@ -89,12 +99,15 @@ nlmclnt_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock) ...@@ -89,12 +99,15 @@ nlmclnt_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
void void
nlmclnt_freegrantargs(struct nlm_rqst *call) nlmclnt_freegrantargs(struct nlm_rqst *call)
{ {
struct file_lock *fl = &call->a_args.lock.fl;
/* /*
* Check whether we allocated memory for the owner. * Check whether we allocated memory for the owner.
*/ */
if (call->a_args.lock.oh.data != (u8 *) call->a_owner) { if (call->a_args.lock.oh.data != (u8 *) call->a_owner) {
kfree(call->a_args.lock.oh.data); 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 cmd, struct file_lock *fl) ...@@ -165,6 +178,8 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
} }
call->a_host = host; call->a_host = host;
nlmclnt_locks_init_private(fl, host);
/* Set up the argument struct */ /* Set up the argument struct */
nlmclnt_setlockargs(call, fl); nlmclnt_setlockargs(call, fl);
...@@ -179,9 +194,6 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) ...@@ -179,9 +194,6 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
else else
status = -EINVAL; status = -EINVAL;
if (status < 0 && (call->a_flags & RPC_TASK_ASYNC))
kfree(call);
out_restore: out_restore:
spin_lock_irqsave(&current->sighand->siglock, flags); spin_lock_irqsave(&current->sighand->siglock, flags);
current->blocked = oldset; current->blocked = oldset;
...@@ -382,7 +394,9 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl) ...@@ -382,7 +394,9 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
{ {
int status; 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; return status;
status = req->a_res.status; status = req->a_res.status;
...@@ -391,10 +405,9 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl) ...@@ -391,10 +405,9 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
} if (status == NLM_LCK_DENIED) { } if (status == NLM_LCK_DENIED) {
/* /*
* Report the conflicting lock back to the application. * 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); locks_copy_lock(fl, &req->a_res.lock.fl);
/* fl->fl_pid = 0; */ fl->fl_pid = 0;
} else { } else {
return nlm_stat_to_errno(req->a_res.status); return nlm_stat_to_errno(req->a_res.status);
} }
...@@ -402,18 +415,30 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl) ...@@ -402,18 +415,30 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
return 0; return 0;
} }
static static void nlmclnt_locks_copy_lock(struct file_lock *new, struct file_lock *fl)
void nlmclnt_insert_lock_callback(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); nlm_release_host(fl->fl_u.nfs_fl.host);
fl->fl_u.nfs_fl.host = NULL; fl->fl_ops = NULL;
} }
static struct file_lock_operations nlmclnt_lock_ops = {
.fl_copy_lock = nlmclnt_locks_copy_lock,
.fl_release_private = nlmclnt_locks_release_private,
};
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 +471,8 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) ...@@ -446,7 +471,8 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
if (!host->h_monitored && nsm_monitor(host) < 0) { if (!host->h_monitored && nsm_monitor(host) < 0) {
printk(KERN_NOTICE "lockd: failed to monitor %s\n", printk(KERN_NOTICE "lockd: failed to monitor %s\n",
host->h_name); host->h_name);
return -ENOLCK; status = -ENOLCK;
goto out;
} }
do { do {
...@@ -456,18 +482,17 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) ...@@ -456,18 +482,17 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
status = nlmclnt_block(host, fl, &resp->status); status = nlmclnt_block(host, fl, &resp->status);
} }
if (status < 0) if (status < 0)
return status; goto out;
} while (resp->status == NLM_LCK_BLOCKED && req->a_args.block); } while (resp->status == NLM_LCK_BLOCKED && req->a_args.block);
if (resp->status == NLM_LCK_GRANTED) { if (resp->status == NLM_LCK_GRANTED) {
fl->fl_u.nfs_fl.state = host->h_state; fl->fl_u.nfs_fl.state = host->h_state;
fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED; 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;
} }
status = nlm_stat_to_errno(resp->status);
return nlm_stat_to_errno(resp->status); out:
nlmclnt_release_lockargs(req);
return status;
} }
/* /*
...@@ -527,11 +552,18 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) ...@@ -527,11 +552,18 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
fl->fl_u.nfs_fl.flags &= ~NFS_LCK_GRANTED; fl->fl_u.nfs_fl.flags &= ~NFS_LCK_GRANTED;
if (req->a_flags & RPC_TASK_ASYNC) { if (req->a_flags & RPC_TASK_ASYNC) {
return nlmclnt_async_call(req, NLMPROC_UNLOCK, status = nlmclnt_async_call(req, NLMPROC_UNLOCK,
nlmclnt_unlock_callback); 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; return status;
if (resp->status == NLM_LCK_GRANTED) if (resp->status == NLM_LCK_GRANTED)
...@@ -567,6 +599,7 @@ nlmclnt_unlock_callback(struct rpc_task *task) ...@@ -567,6 +599,7 @@ nlmclnt_unlock_callback(struct rpc_task *task)
die: die:
nlm_release_host(req->a_host); nlm_release_host(req->a_host);
nlmclnt_release_lockargs(req);
kfree(req); kfree(req);
return; return;
retry_rebind: retry_rebind:
...@@ -605,8 +638,10 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl) ...@@ -605,8 +638,10 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
status = nlmclnt_async_call(req, NLMPROC_CANCEL, status = nlmclnt_async_call(req, NLMPROC_CANCEL,
nlmclnt_cancel_callback); nlmclnt_cancel_callback);
if (status < 0) if (status < 0) {
nlmclnt_release_lockargs(req);
kfree(req); kfree(req);
}
spin_lock_irqsave(&current->sighand->siglock, flags); spin_lock_irqsave(&current->sighand->siglock, flags);
current->blocked = oldset; current->blocked = oldset;
...@@ -648,6 +683,7 @@ nlmclnt_cancel_callback(struct rpc_task *task) ...@@ -648,6 +683,7 @@ nlmclnt_cancel_callback(struct rpc_task *task)
die: die:
nlm_release_host(req->a_host); nlm_release_host(req->a_host);
nlmclnt_release_lockargs(req);
kfree(req); kfree(req);
return; return;
......
...@@ -55,6 +55,7 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -55,6 +55,7 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Set up the missing parts of the file_lock structure */ /* Set up the missing parts of the file_lock structure */
lock->fl.fl_file = file->f_file; lock->fl.fl_file = file->f_file;
lock->fl.fl_owner = (fl_owner_t) host; lock->fl.fl_owner = (fl_owner_t) host;
lock->fl.fl_lmops = &nlmsvc_lock_operations;
} }
return 0; return 0;
......
...@@ -194,6 +194,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, ...@@ -194,6 +194,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
/* Set notifier function for VFS, and init args */ /* 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_notify = nlmsvc_notify_blocked;
block->b_call.a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations;
block->b_call.a_args.cookie = *cookie; /* see above */ block->b_call.a_args.cookie = *cookie; /* see above */
dprintk("lockd: created block %p...\n", block); dprintk("lockd: created block %p...\n", block);
...@@ -479,6 +480,15 @@ nlmsvc_notify_blocked(struct file_lock *fl) ...@@ -479,6 +480,15 @@ nlmsvc_notify_blocked(struct file_lock *fl)
printk(KERN_WARNING "lockd: notification for unknown block!\n"); 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 lock_manager_operations nlmsvc_lock_operations = {
.fl_compare_owner = nlmsvc_same_owner,
};
/* /*
* Try to claim a lock that was previously blocked. * Try to claim a lock that was previously blocked.
* *
......
...@@ -84,6 +84,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -84,6 +84,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Set up the missing parts of the file_lock structure */ /* Set up the missing parts of the file_lock structure */
lock->fl.fl_file = file->f_file; lock->fl.fl_file = file->f_file;
lock->fl.fl_owner = (fl_owner_t) host; lock->fl.fl_owner = (fl_owner_t) host;
lock->fl.fl_lmops = &nlmsvc_lock_operations;
} }
return 0; return 0;
......
...@@ -205,6 +205,8 @@ nlm_compare_locks(struct file_lock *fl1, struct file_lock *fl2) ...@@ -205,6 +205,8 @@ nlm_compare_locks(struct file_lock *fl1, struct file_lock *fl2)
&&(fl1->fl_type == fl2->fl_type || fl2->fl_type == F_UNLCK); &&(fl1->fl_type == fl2->fl_type || fl2->fl_type == F_UNLCK);
} }
extern struct lock_manager_operations nlmsvc_lock_operations;
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* LINUX_LOCKD_LOCKD_H */ #endif /* LINUX_LOCKD_LOCKD_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment