static void nlmsvc_insert_block(struct nlm_block *block, unsigned long);
static int nlmsvc_remove_block(struct nlm_block *block);
-static void nlmsvc_grant_callback(struct rpc_task *task);
+
+static const struct rpc_call_ops nlmsvc_grant_ops;
/*
* The list of blocked locks to retry
* It is the caller's responsibility to check whether the file
* can be closed hereafter.
*/
-static void
+static int
nlmsvc_delete_block(struct nlm_block *block, int unlock)
{
struct file_lock *fl = &block->b_call.a_args.lock.fl;
struct nlm_file *file = block->b_file;
struct nlm_block **bp;
+ int status = 0;
dprintk("lockd: deleting block %p...\n", block);
/* Remove block from list */
nlmsvc_remove_block(block);
- if (fl->fl_next)
- posix_unblock_lock(file->f_file, fl);
- if (unlock) {
- fl->fl_type = F_UNLCK;
- posix_lock_file(file->f_file, fl);
- block->b_granted = 0;
- }
+ if (unlock)
+ status = posix_unblock_lock(file->f_file, fl);
/* If the block is in the middle of a GRANT callback,
* don't kill it yet. */
if (block->b_incall) {
nlmsvc_insert_block(block, NLM_NEVER);
block->b_done = 1;
- return;
+ return status;
}
/* Remove block from file's list of blocks */
nlm_release_host(block->b_host);
nlmclnt_freegrantargs(&block->b_call);
kfree(block);
+ return status;
}
/*
nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action)
{
struct nlm_block *block, *next;
+ /* XXX: Will everything get cleaned up if we don't unlock here? */
down(&file->f_sema);
for (block = file->f_blocks; block; block = next) {
nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
struct nlm_lock *lock, int wait, struct nlm_cookie *cookie)
{
- struct file_lock *conflock;
struct nlm_block *block;
int error;
+ u32 ret;
dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
file->f_file->f_dentry->d_inode->i_sb->s_id,
/* Lock file against concurrent access */
down(&file->f_sema);
- if (!(conflock = posix_test_lock(file->f_file, &lock->fl))) {
- error = posix_lock_file(file->f_file, &lock->fl);
+ error = posix_lock_file(file->f_file, &lock->fl);
+
+ dprintk("lockd: posix_lock_file returned %d\n", error);
+ if (error != -EAGAIN) {
if (block)
nlmsvc_delete_block(block, 0);
up(&file->f_sema);
- dprintk("lockd: posix_lock_file returned %d\n", -error);
switch(-error) {
case 0:
- return nlm_granted;
+ ret = nlm_granted;
+ goto out;
case EDEADLK:
- return nlm_deadlock;
- case EAGAIN:
- return nlm_lck_denied;
+ ret = nlm_deadlock;
+ goto out;
default: /* includes ENOLCK */
- return nlm_lck_denied_nolocks;
+ ret = nlm_lck_denied_nolocks;
+ goto out;
}
}
if (!wait) {
- up(&file->f_sema);
- return nlm_lck_denied;
- }
-
- if (posix_locks_deadlock(&lock->fl, conflock)) {
- up(&file->f_sema);
- return nlm_deadlock;
+ ret = nlm_lck_denied;
+ goto out_unlock;
}
/* If we don't have a block, create and initialize it. Then
/* Append to list of blocked */
nlmsvc_insert_block(block, NLM_NEVER);
- if (list_empty(&block->b_call.a_args.lock.fl.fl_block)) {
- /* Now add block to block list of the conflicting lock
- if we haven't done so. */
- dprintk("lockd: blocking on this lock.\n");
- posix_block_lock(conflock, &block->b_call.a_args.lock.fl);
- }
-
+ ret = nlm_lck_blocked;
+out_unlock:
up(&file->f_sema);
- return nlm_lck_blocked;
+out:
+ dprintk("lockd: nlmsvc_lock returned %u\n", ret);
+ return ret;
}
/*
nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
struct nlm_lock *conflock)
{
- struct file_lock *fl;
-
dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
file->f_file->f_dentry->d_inode->i_sb->s_id,
file->f_file->f_dentry->d_inode->i_ino,
(long long)lock->fl.fl_start,
(long long)lock->fl.fl_end);
- if ((fl = posix_test_lock(file->f_file, &lock->fl)) != NULL) {
+ if (posix_test_lock(file->f_file, &lock->fl, &conflock->fl)) {
dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
- fl->fl_type, (long long)fl->fl_start,
- (long long)fl->fl_end);
+ conflock->fl.fl_type,
+ (long long)conflock->fl.fl_start,
+ (long long)conflock->fl.fl_end);
conflock->caller = "somehost"; /* FIXME */
conflock->oh.len = 0; /* don't return OH info */
- conflock->fl = *fl;
+ conflock->svid = conflock->fl.fl_pid;
return nlm_lck_denied;
}
nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
{
struct nlm_block *block;
+ int status = 0;
dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n",
file->f_file->f_dentry->d_inode->i_sb->s_id,
down(&file->f_sema);
if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL)
- nlmsvc_delete_block(block, 1);
+ status = nlmsvc_delete_block(block, 1);
up(&file->f_sema);
- return nlm_granted;
+ return status ? nlm_lck_denied : nlm_granted;
}
/*
{
struct nlm_file *file = block->b_file;
struct nlm_lock *lock = &block->b_call.a_args.lock;
- struct file_lock *conflock;
int error;
dprintk("lockd: grant blocked lock %p\n", block);
}
/* Try the lock operation again */
- if ((conflock = posix_test_lock(file->f_file, &lock->fl)) != NULL) {
- /* Bummer, we blocked again */
+ error = posix_lock_file(file->f_file, &lock->fl);
+ switch (error) {
+ case 0:
+ break;
+ case -EAGAIN:
dprintk("lockd: lock still blocked\n");
nlmsvc_insert_block(block, NLM_NEVER);
- posix_block_lock(conflock, &lock->fl);
- up(&file->f_sema);
- return;
- }
-
- /* Alright, no conflicting lock. Now lock it for real. If the
- * following yields an error, this is most probably due to low
- * memory. Retry the lock in a few seconds.
- */
- if ((error = posix_lock_file(file->f_file, &lock->fl)) < 0) {
+ goto out_unlock;
+ default:
printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
-error, __FUNCTION__);
nlmsvc_insert_block(block, 10 * HZ);
- up(&file->f_sema);
- return;
+ goto out_unlock;
}
callback:
/* Call the client */
nlm_get_host(block->b_call.a_host);
if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG,
- nlmsvc_grant_callback) < 0)
+ &nlmsvc_grant_ops) < 0)
nlm_release_host(block->b_call.a_host);
+out_unlock:
up(&file->f_sema);
}
* chain once more in order to have it removed by lockd itself (which can
* then sleep on the file semaphore without disrupting e.g. the nfs client).
*/
-static void
-nlmsvc_grant_callback(struct rpc_task *task)
+static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
{
- struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata;
+ struct nlm_rqst *call = data;
struct nlm_block *block;
unsigned long timeout;
struct sockaddr_in *peer_addr = RPC_PEERADDR(task->tk_client);
nlm_release_host(call->a_host);
}
+static const struct rpc_call_ops nlmsvc_grant_ops = {
+ .rpc_call_done = nlmsvc_grant_callback,
+};
+
/*
* We received a GRANT_RES callback. Try to find the corresponding
* block.
file->f_count++;
down(&file->f_sema);
- if ((block = nlmsvc_find_block(cookie,&rqstp->rq_addr)) != NULL) {
+ block = nlmsvc_find_block(cookie, &rqstp->rq_addr);
+ if (block) {
if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
/* Try again in a couple of seconds */
nlmsvc_insert_block(block, 10 * HZ);
- block = NULL;
+ up(&file->f_sema);
} else {
/* Lock is now held by client, or has been rejected.
* In both cases, the block should be removed. */
nlmsvc_delete_block(block, 1);
}
}
- if (!block)
- up(&file->f_sema);
nlm_release_file(file);
}