示例#1
0
static int
reclaimer(void *ptr)
{
	struct nlm_host	  *host = (struct nlm_host *) ptr;
	struct nlm_wait	  *block;
	struct list_head *tmp;

	/* This one ensures that our parent doesn't terminate while the
	 * reclaim is in progress */
	lock_kernel();
	lockd_up();

	/* First, reclaim all locks that have been granted previously. */
restart:
	tmp = file_lock_list.next;
	while (tmp != &file_lock_list) {
		struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);
		struct inode *inode = fl->fl_file->f_dentry->d_inode;
		if (inode->i_sb->s_magic == NFS_SUPER_MAGIC &&
				nlm_cmp_addr(NFS_ADDR(inode), &host->h_addr) &&
				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;
			nlmclnt_reclaim(host, fl);	/* This sleeps */
			goto restart;
		}
		tmp = tmp->next;
	}

	host->h_reclaiming = 0;
	wake_up(&host->h_gracewait);

	/* Now, wake up all processes that sleep on a blocked lock */
	for (block = nlm_blocked; block; block = block->b_next) {
		if (block->b_host == host) {
			block->b_status = NLM_LCK_DENIED_GRACE_PERIOD;
			wake_up(&block->b_wait);
		}
	}

	/* Release host handle after use */
	nlm_release_host(host);
	lockd_down();
	unlock_kernel();

	return 0;
}
示例#2
0
/*
 * This is the main entry point for the NLM client.
 */
int
nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
{
	struct nfs_server	*nfssrv = NFS_SERVER(inode);
	struct nlm_host		*host;
	struct nlm_rqst		reqst, *call = &reqst;
	sigset_t		oldset;
	unsigned long		flags;
	int			status;

	/* Always use NLM version 1 over UDP for now... */
	if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), IPPROTO_UDP, 1)))
		return -ENOLCK;

	/* Create RPC client handle if not there, and copy soft
	 * and intr flags from NFS client. */
	if (host->h_rpcclnt == NULL) {
		struct rpc_clnt	*clnt;

		/* Bind an rpc client to this host handle (does not
		 * perform a portmapper lookup) */
		if (!(clnt = nlm_bind_host(host))) {
			status = -ENOLCK;
			goto done;
		}
		clnt->cl_softrtry = nfssrv->client->cl_softrtry;
		clnt->cl_intr     = nfssrv->client->cl_intr;
		clnt->cl_chatty   = nfssrv->client->cl_chatty;
	}

	/* Keep the old signal mask */
	spin_lock_irqsave(&current->sigmask_lock, flags);
	oldset = current->blocked;

	/* If we're cleaning up locks because the process is exiting,
	 * perform the RPC call asynchronously. */
	if ((cmd == F_SETLK || cmd == F_SETLKW)
	    && fl->fl_type == F_UNLCK
	    && (current->flags & PF_EXITING)) {
		sigfillset(&current->blocked);	/* Mask all signals */
		recalc_sigpending(current);
		spin_unlock_irqrestore(&current->sigmask_lock, flags);

		call = nlmclnt_alloc_call();
		call->a_flags = RPC_TASK_ASYNC;
	} else {
		spin_unlock_irqrestore(&current->sigmask_lock, flags);
		call->a_flags = 0;
	}
	call->a_host = host;

	/* Set up the argument struct */
	nlmclnt_setlockargs(call, fl);

	if (cmd == F_GETLK) {
		status = nlmclnt_test(call, fl);
	} else if ((cmd == F_SETLK || cmd == F_SETLKW)
		   && fl->fl_type == F_UNLCK) {
		status = nlmclnt_unlock(call, fl);
	} else if (cmd == F_SETLK || cmd == F_SETLKW) {
		call->a_args.block = (cmd == F_SETLKW)? 1 : 0;
		status = nlmclnt_lock(call, fl);
	} else {
		status = -EINVAL;
	}

	if (status < 0 && (call->a_flags & RPC_TASK_ASYNC))
		rpc_free(call);

	spin_lock_irqsave(&current->sigmask_lock, flags);
	current->blocked = oldset;
	recalc_sigpending(current);
	spin_unlock_irqrestore(&current->sigmask_lock, flags);

done:
	dprintk("lockd: clnt proc returns %d\n", status);
	nlm_release_host(host);
	return status;
}
/*
 * This is the main entry point for the NLM client.
 */
int
nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
{
	struct nfs_server	*nfssrv = NFS_SERVER(inode);
	struct nlm_host		*host;
	struct nlm_rqst		reqst, *call = &reqst;
	sigset_t		oldset;
	unsigned long		flags;
	int			status, proto, vers;

	vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1;
	if (NFS_PROTO(inode)->version > 3) {
		printk(KERN_NOTICE "NFSv4 file locking not implemented!\n");
		return -ENOLCK;
	}

	/* Retrieve transport protocol from NFS client */
	proto = NFS_CLIENT(inode)->cl_xprt->prot;

	if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers)))
		return -ENOLCK;

	/* Create RPC client handle if not there, and copy soft
	 * and intr flags from NFS client. */
	if (host->h_rpcclnt == NULL) {
		struct rpc_clnt	*clnt;

		/* Bind an rpc client to this host handle (does not
		 * perform a portmapper lookup) */
		if (!(clnt = nlm_bind_host(host))) {
			status = -ENOLCK;
			goto done;
		}
		clnt->cl_softrtry = nfssrv->client->cl_softrtry;
		clnt->cl_intr     = nfssrv->client->cl_intr;
		clnt->cl_chatty   = nfssrv->client->cl_chatty;
	}

	/* Keep the old signal mask */
	spin_lock_irqsave(&current->sighand->siglock, flags);
	oldset = current->blocked;

	/* If we're cleaning up locks because the process is exiting,
	 * perform the RPC call asynchronously. */
	if ((IS_SETLK(cmd) || IS_SETLKW(cmd))
	    && fl->fl_type == F_UNLCK
	    && (current->flags & PF_EXITING)) {
		sigfillset(&current->blocked);	/* Mask all signals */
		recalc_sigpending();
		spin_unlock_irqrestore(&current->sighand->siglock, flags);

		call = nlmclnt_alloc_call();
		if (!call) {
			status = -ENOMEM;
			goto out_restore;
		}
		call->a_flags = RPC_TASK_ASYNC;
	} else {
		spin_unlock_irqrestore(&current->sighand->siglock, flags);
		memset(call, 0, sizeof(*call));
		locks_init_lock(&call->a_args.lock.fl);
		locks_init_lock(&call->a_res.lock.fl);
	}
	call->a_host = host;

	/* Set up the argument struct */
	nlmclnt_setlockargs(call, fl);

	if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
		if (fl->fl_type != F_UNLCK) {
			call->a_args.block = IS_SETLKW(cmd) ? 1 : 0;
			status = nlmclnt_lock(call, fl);
		} else
			status = nlmclnt_unlock(call, fl);
	} else if (IS_GETLK(cmd))
		status = nlmclnt_test(call, fl);
	else
		status = -EINVAL;

	if (status < 0 && (call->a_flags & RPC_TASK_ASYNC))
		kfree(call);

 out_restore:
	spin_lock_irqsave(&current->sighand->siglock, flags);
	current->blocked = oldset;
	recalc_sigpending();
	spin_unlock_irqrestore(&current->sighand->siglock, flags);

done:
	dprintk("lockd: clnt proc returns %d\n", status);
	nlm_release_host(host);
	return status;
}