Exemple #1
0
/*
 * Try to claim a lock that was previously blocked.
 *
 * Note that we use both the RPC_GRANTED_MSG call _and_ an async
 * RPC thread when notifying the client. This seems like overkill...
 * Here's why:
 *  -	we don't want to use a synchronous RPC thread, otherwise
 *	we might find ourselves hanging on a dead portmapper.
 *  -	Some lockd implementations (e.g. HP) don't react to
 *	RPC_GRANTED calls; they seem to insist on RPC_GRANTED_MSG calls.
 */
static void
nlmsvc_grant_blocked(struct nlm_block *block)
{
	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);

	/* First thing is lock the file */
	down(&file->f_sema);

	/* Unlink block request from list */
	nlmsvc_remove_block(block);

	/* If b_granted is true this means we've been here before.
	 * Just retry the grant callback, possibly refreshing the RPC
	 * binding */
	if (block->b_granted) {
		nlm_rebind_host(block->b_host);
		goto callback;
	}

	/* Try the lock operation again */
	if ((conflock = posix_test_lock(&file->f_file, &lock->fl)) != NULL) {
		/* Bummer, we blocked again */
		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)) < 0) {
		printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
				-error, __FUNCTION__);
		nlmsvc_insert_block(block, jiffies + 10 * HZ);
		up(&file->f_sema);
		return;
	}

callback:
	/* Lock was granted by VFS. */
	dprintk("lockd: GRANTing blocked lock.\n");
	block->b_granted = 1;
	block->b_incall  = 1;

	/* Schedule next grant callback in 30 seconds */
	nlmsvc_insert_block(block, jiffies + 30 * HZ);

	/* Call the client */
	nlmclnt_async_call(&block->b_call, NLMPROC_GRANTED_MSG,
						nlmsvc_grant_callback);
	up(&file->f_sema);
}
Exemple #2
0
/*
 * Attempt to establish a lock, and if it can't be granted, block it
 * if required.
 */
u32
nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
			struct nlm_lock *lock, int wait, u32 cookie)
{
	struct file_lock	*conflock;
	struct nlm_block	*block;
	int			error;

	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,
				wait);

	/* 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);

	lock->fl.fl_flags |= FL_LOCKD;

again:
	if (!(conflock = posix_test_lock(&file->f_file, &lock->fl))) {
		error = posix_lock_file(&file->f_file, &lock->fl, 0);

		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;
		case EDEADLK:			/* no applicable NLM status */
		case EAGAIN:
			return nlm_lck_denied;
		default:			/* includes ENOLCK */
			return nlm_lck_denied_nolocks;
		}
	}

	if (!wait) {
		up(&file->f_sema);
		return nlm_lck_denied;
	}

	/* If we don't have a block, create and initialize it. Then
	 * retry because we may have slept in kmalloc. */
	if (block == NULL) {
		dprintk("lockd: blocking on this lock (allocating).\n");
		if (!(block = 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);

	/* Now add block to block list of the conflicting lock */
	dprintk("lockd: blocking on this lock.\n");
	posix_block_lock(conflock, &block->b_call.a_args.lock.fl);

	up(&file->f_sema);
	return nlm_lck_blocked;
}
Exemple #3
0
/*
 * Attempt to establish a lock, and if it can't be granted, block it
 * if required.
 */
u32
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, *nblock = NULL;
	int			error;

	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,
				(long long)lock->fl.fl_start,
				(long long)lock->fl.fl_end,
				wait);


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

	lock->fl.fl_flags |= FL_LOCKD;

again:
	/* 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, 0);

		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;
		case EDEADLK:
			return nlm_deadlock;
		case EAGAIN:
			return nlm_lck_denied;
		default:			/* includes ENOLCK */
			return nlm_lck_denied_nolocks;
		}
	}

	if (!wait) {
		up(&file->f_sema);
		return nlm_lck_denied;
	}

	if (posix_locks_deadlock(&lock->fl, conflock)) {
		if (nblock)
			nlmsvc_delete_block(nblock, 0);
		up(&file->f_sema);
		return nlm_deadlock;
	}

	/* 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) {
		up(&file->f_sema);
		dprintk("lockd: blocking on this lock (allocating).\n");
		if (!(block = nlmsvc_create_block(rqstp, file, lock, cookie)))
			return nlm_lck_denied_nolocks;
		nblock = block;
		goto again;
	}

	/* 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);
	}

	up(&file->f_sema);
	return nlm_lck_blocked;
}