Пример #1
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;
}
Пример #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, 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;
}