Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 09c7938c authored by Trond Myklebust's avatar Trond Myklebust
Browse files

lockd: Fix server-side lock blocking code

parent 0996905f
Loading
Loading
Loading
Loading
+40 −33
Original line number Diff line number Diff line
@@ -193,6 +193,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
		goto failed_free;

	/* Set notifier function for VFS, and init args */
	block->b_call.a_args.lock.fl.fl_flags |= FL_SLEEP;
	block->b_call.a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations;
	block->b_call.a_args.cookie = *cookie;	/* see above */

@@ -228,18 +229,17 @@ failed:
 * can be closed hereafter.
 */
static int
nlmsvc_delete_block(struct nlm_block *block, int unlock)
nlmsvc_delete_block(struct nlm_block *block)
{
	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;
	int status;

	dprintk("lockd: deleting block %p...\n", block);

	/* Remove block from list */
	nlmsvc_remove_block(block);
	if (unlock)
	status = posix_unblock_lock(file->f_file, fl);

	/* If the block is in the middle of a GRANT callback,
@@ -282,7 +282,7 @@ nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action)
			block->b_host->h_inuse = 1;
		else if (action == NLM_ACT_UNLOCK) {
			if (host == NULL || host == block->b_host)
				nlmsvc_delete_block(block, 1);
				nlmsvc_delete_block(block);
		}
	}
	up(&file->f_sema);
@@ -297,7 +297,7 @@ u32
nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
			struct nlm_lock *lock, int wait, struct nlm_cookie *cookie)
{
	struct nlm_block	*block;
	struct nlm_block	*block, *newblock = NULL;
	int			error;
	u32			ret;

@@ -310,59 +310,65 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
				wait);


	/* Get existing block (in case client is busy-waiting) */
	block = nlmsvc_lookup_block(file, lock, 0);

	lock->fl.fl_flags &= ~FL_SLEEP;
again:
	/* Lock file against concurrent access */
	down(&file->f_sema);
	/* Get existing block (in case client is busy-waiting) */
	block = nlmsvc_lookup_block(file, lock, 0);
	if (block == NULL) {
		if (newblock != NULL)
			lock = &newblock->b_call.a_args.lock.fl;
	} else
		lock = &block->b_call.a_args.lock.fl;

	error = posix_lock_file(file->f_file, &lock->fl);
	lock->fl.fl_flags &= ~FL_SLEEP;

	dprintk("lockd: posix_lock_file returned %d\n", error);

	if (error != -EAGAIN) {
		if (block)
			nlmsvc_delete_block(block, 0);
		up(&file->f_sema);

		switch(-error) {
	switch(error) {
		case 0:
			ret = nlm_granted;
			goto out;
		case EDEADLK:
		case -EAGAIN:
			break;
		case -EDEADLK:
			ret = nlm_deadlock;
			goto out;
		default:			/* includes ENOLCK */
			ret = nlm_lck_denied_nolocks;
			goto out;
	}
	}

	if (!wait) {
	ret = nlm_lck_denied;
		goto out_unlock;
	}
	if (!wait)
		goto out;

	ret = nlm_lck_blocked;
	if (block != NULL)
		goto out;

	/* If we don't have a block, create and initialize it. Then
	 * retry because we may have slept in kmalloc. */
	/* We have to release f_sema as nlmsvc_create_block may try to
	 * to claim it while doing host garbage collection */
	if (block == NULL) {
	if (newblock == NULL) {
		up(&file->f_sema);
		dprintk("lockd: blocking on this lock (allocating).\n");
		if (!(block = nlmsvc_create_block(rqstp, file, lock, cookie)))
		if (!(newblock = nlmsvc_create_block(rqstp, file, lock, cookie)))
			return nlm_lck_denied_nolocks;
		goto again;
	}

	/* Append to list of blocked */
	nlmsvc_insert_block(block, NLM_NEVER);
	nlmsvc_insert_block(newblock, NLM_NEVER);
	newblock = NULL;

	ret = nlm_lck_blocked;
out_unlock:
	up(&file->f_sema);
out:
	up(&file->f_sema);
	if (newblock != NULL)
		nlmsvc_delete_block(newblock);
	dprintk("lockd: nlmsvc_lock returned %u\n", ret);
	return ret;
}
@@ -445,7 +451,7 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)

	down(&file->f_sema);
	if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL)
		status = nlmsvc_delete_block(block, 1);
		status = nlmsvc_delete_block(block);
	up(&file->f_sema);
	return status ? nlm_lck_denied : nlm_granted;
}
@@ -519,7 +525,11 @@ nlmsvc_grant_blocked(struct nlm_block *block)
	}

	/* Try the lock operation again */
	posix_unblock_lock(file->f_file, &lock->fl);
	lock->fl.fl_flags |= FL_SLEEP;
	error = posix_lock_file(file->f_file, &lock->fl);
	lock->fl.fl_flags &= ~FL_SLEEP;

	switch (error) {
	case 0:
		break;
@@ -630,11 +640,8 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status
		} else {
			/* Lock is now held by client, or has been rejected.
			 * In both cases, the block should be removed. */
			nlmsvc_delete_block(block);
			up(&file->f_sema);
			if (status == NLM_LCK_GRANTED)
				nlmsvc_delete_block(block, 0);
			else
				nlmsvc_delete_block(block, 1);
		}
	}
	nlm_release_file(file);
@@ -661,7 +668,7 @@ nlmsvc_retry_blocked(void)
		dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n",
			block, block->b_when, block->b_done);
		if (block->b_done)
			nlmsvc_delete_block(block, 0);
			nlmsvc_delete_block(block);
		else
			nlmsvc_grant_blocked(block);
	}