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

Commit 53846a21 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.linux-nfs.org/pub/linux/nfs-2.6: (103 commits)
  SUNRPC,RPCSEC_GSS: spkm3--fix config dependencies
  SUNRPC,RPCSEC_GSS: spkm3: import contexts using NID_cast5_cbc
  LOCKD: Make nlmsvc_traverse_shares return void
  LOCKD: nlmsvc_traverse_blocks return is unused
  SUNRPC,RPCSEC_GSS: fix krb5 sequence numbers.
  NFSv4: Dont list system.nfs4_acl for filesystems that don't support it.
  SUNRPC,RPCSEC_GSS: remove unnecessary kmalloc of a checksum
  SUNRPC: Ensure rpc_call_async() always calls tk_ops->rpc_release()
  SUNRPC: Fix memory barriers for req->rq_received
  NFS: Fix a race in nfs_sync_inode()
  NFS: Clean up nfs_flush_list()
  NFS: Fix a race with PG_private and nfs_release_page()
  NFSv4: Ensure the callback daemon flushes signals
  SUNRPC: Fix a 'Busy inodes' error in rpc_pipefs
  NFS, NLM: Allow blocking locks to respect signals
  NFS: Make nfs_fhget() return appropriate error values
  NFSv4: Fix an oops in nfs4_fill_super
  lockd: blocks should hold a reference to the nlm_file
  NFSv4: SETCLIENTID_CONFIRM should handle NFS4ERR_DELAY/NFS4ERR_RESOURCE
  NFSv4: Send the delegation stateid for SETATTR calls
  ...
parents 2e9abdd9 1ebbe2b2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1555,6 +1555,7 @@ config RPCSEC_GSS_SPKM3
	select CRYPTO
	select CRYPTO_MD5
	select CRYPTO_DES
	select CRYPTO_CAST5
	help
	  Provides for secure RPC calls by means of a gss-api
	  mechanism based on the SPKM3 public-key mechanism.
+37 −75
Original line number Diff line number Diff line
@@ -44,32 +44,25 @@ static LIST_HEAD(nlm_blocked);
/*
 * Queue up a lock for blocking so that the GRANTED request can see it
 */
int nlmclnt_prepare_block(struct nlm_rqst *req, struct nlm_host *host, struct file_lock *fl)
struct nlm_wait *nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl)
{
	struct nlm_wait *block;

	BUG_ON(req->a_block != NULL);
	block = kmalloc(sizeof(*block), GFP_KERNEL);
	if (block == NULL)
		return -ENOMEM;
	if (block != NULL) {
		block->b_host = host;
		block->b_lock = fl;
		init_waitqueue_head(&block->b_wait);
		block->b_status = NLM_LCK_BLOCKED;

		list_add(&block->b_list, &nlm_blocked);
	req->a_block = block;

	return 0;
	}
	return block;
}

void nlmclnt_finish_block(struct nlm_rqst *req)
void nlmclnt_finish_block(struct nlm_wait *block)
{
	struct nlm_wait *block = req->a_block;

	if (block == NULL)
		return;
	req->a_block = NULL;
	list_del(&block->b_list);
	kfree(block);
}
@@ -77,15 +70,14 @@ void nlmclnt_finish_block(struct nlm_rqst *req)
/*
 * Block on a lock
 */
long nlmclnt_block(struct nlm_rqst *req, long timeout)
int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
{
	struct nlm_wait	*block = req->a_block;
	long ret;

	/* A borken server might ask us to block even if we didn't
	 * request it. Just say no!
	 */
	if (!req->a_args.block)
	if (block == NULL)
		return -EAGAIN;

	/* Go to sleep waiting for GRANT callback. Some servers seem
@@ -99,13 +91,10 @@ long nlmclnt_block(struct nlm_rqst *req, long timeout)
	ret = wait_event_interruptible_timeout(block->b_wait,
			block->b_status != NLM_LCK_BLOCKED,
			timeout);

	if (block->b_status != NLM_LCK_BLOCKED) {
	if (ret < 0)
		return -ERESTARTSYS;
	req->a_res.status = block->b_status;
		block->b_status = NLM_LCK_BLOCKED;
	}

	return ret;
	return 0;
}

/*
@@ -125,7 +114,15 @@ u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
	list_for_each_entry(block, &nlm_blocked, b_list) {
		struct file_lock *fl_blocked = block->b_lock;

		if (!nlm_compare_locks(fl_blocked, fl))
		if (fl_blocked->fl_start != fl->fl_start)
			continue;
		if (fl_blocked->fl_end != fl->fl_end)
			continue;
		/*
		 * Careful! The NLM server will return the 32-bit "pid" that
		 * we put on the wire: in this case the lockowner "pid".
		 */
		if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid)
			continue;
		if (!nlm_cmp_addr(&block->b_host->h_addr, addr))
			continue;
@@ -146,34 +143,6 @@ u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
 * server crash.
 */

/*
 * Mark the locks for reclaiming.
 * FIXME: In 2.5 we don't want to iterate through any global file_lock_list.
 *        Maintain NLM lock reclaiming lists in the nlm_host instead.
 */
static
void nlmclnt_mark_reclaim(struct nlm_host *host)
{
	struct file_lock *fl;
	struct inode *inode;
	struct list_head *tmp;

	list_for_each(tmp, &file_lock_list) {
		fl = list_entry(tmp, struct file_lock, fl_link);

		inode = fl->fl_file->f_dentry->d_inode;
		if (inode->i_sb->s_magic != NFS_SUPER_MAGIC)
			continue;
		if (fl->fl_u.nfs_fl.owner == NULL)
			continue;
		if (fl->fl_u.nfs_fl.owner->host != host)
			continue;
		if (!(fl->fl_u.nfs_fl.flags & NFS_LCK_GRANTED))
			continue;
		fl->fl_u.nfs_fl.flags |= NFS_LCK_RECLAIM;
	}
}

/*
 * Someone has sent us an SM_NOTIFY. Ensure we bind to the new port number,
 * that we mark locks for reclaiming, and that we bump the pseudo NSM state.
@@ -186,7 +155,12 @@ void nlmclnt_prepare_reclaim(struct nlm_host *host, u32 newstate)
	host->h_state++;
	host->h_nextrebind = 0;
	nlm_rebind_host(host);
	nlmclnt_mark_reclaim(host);

	/*
	 * Mark the locks for reclaiming.
	 */
	list_splice_init(&host->h_granted, &host->h_reclaim);

	dprintk("NLM: reclaiming locks for host %s", host->h_name);
}

@@ -215,9 +189,7 @@ reclaimer(void *ptr)
{
	struct nlm_host	  *host = (struct nlm_host *) ptr;
	struct nlm_wait	  *block;
	struct list_head *tmp;
	struct file_lock *fl;
	struct inode *inode;
	struct file_lock *fl, *next;

	daemonize("%s-reclaim", host->h_name);
	allow_signal(SIGKILL);
@@ -229,23 +201,13 @@ reclaimer(void *ptr)

	/* First, reclaim all locks that have been marked. */
restart:
	list_for_each(tmp, &file_lock_list) {
		fl = list_entry(tmp, struct file_lock, fl_link);

		inode = fl->fl_file->f_dentry->d_inode;
		if (inode->i_sb->s_magic != NFS_SUPER_MAGIC)
			continue;
		if (fl->fl_u.nfs_fl.owner == NULL)
			continue;
		if (fl->fl_u.nfs_fl.owner->host != host)
			continue;
		if (!(fl->fl_u.nfs_fl.flags & NFS_LCK_RECLAIM))
			continue;
	list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) {
		list_del_init(&fl->fl_u.nfs_fl.list);

		fl->fl_u.nfs_fl.flags &= ~NFS_LCK_RECLAIM;
		nlmclnt_reclaim(host, fl);
		if (signalled())
			break;
			continue;
		if (nlmclnt_reclaim(host, fl) == 0)
			list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
		goto restart;
	}

+119 −198
Original line number Diff line number Diff line
@@ -132,59 +132,18 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
	memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh));
	lock->caller  = system_utsname.nodename;
	lock->oh.data = req->a_owner;
	lock->oh.len  = sprintf(req->a_owner, "%d@%s",
				current->pid, system_utsname.nodename);
	locks_copy_lock(&lock->fl, fl);
	lock->oh.len  = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s",
				(unsigned int)fl->fl_u.nfs_fl.owner->pid,
				system_utsname.nodename);
	lock->svid = fl->fl_u.nfs_fl.owner->pid;
	lock->fl.fl_start = fl->fl_start;
	lock->fl.fl_end = fl->fl_end;
	lock->fl.fl_type = fl->fl_type;
}

static void nlmclnt_release_lockargs(struct nlm_rqst *req)
{
	struct file_lock *fl = &req->a_args.lock.fl;

	if (fl->fl_ops && fl->fl_ops->fl_release_private)
		fl->fl_ops->fl_release_private(fl);
}

/*
 * Initialize arguments for GRANTED call. The nlm_rqst structure
 * has been cleared already.
 */
int
nlmclnt_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
{
	locks_copy_lock(&call->a_args.lock.fl, &lock->fl);
	memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh));
	call->a_args.lock.caller = system_utsname.nodename;
	call->a_args.lock.oh.len = lock->oh.len;

	/* set default data area */
	call->a_args.lock.oh.data = call->a_owner;

	if (lock->oh.len > NLMCLNT_OHSIZE) {
		void *data = kmalloc(lock->oh.len, GFP_KERNEL);
		if (!data) {
			nlmclnt_freegrantargs(call);
			return 0;
		}
		call->a_args.lock.oh.data = (u8 *) data;
	}

	memcpy(call->a_args.lock.oh.data, lock->oh.data, lock->oh.len);
	return 1;
}

void
nlmclnt_freegrantargs(struct nlm_rqst *call)
{
	struct file_lock *fl = &call->a_args.lock.fl;
	/*
	 * Check whether we allocated memory for the owner.
	 */
	if (call->a_args.lock.oh.data != (u8 *) call->a_owner) {
		kfree(call->a_args.lock.oh.data);
	}
	if (fl->fl_ops && fl->fl_ops->fl_release_private)
		fl->fl_ops->fl_release_private(fl);
	BUG_ON(req->a_args.lock.fl.fl_ops != NULL);
}

/*
@@ -193,9 +152,8 @@ nlmclnt_freegrantargs(struct nlm_rqst *call)
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;
	struct nlm_rqst		*call;
	sigset_t		oldset;
	unsigned long		flags;
	int			status, proto, vers;
@@ -209,23 +167,17 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
	/* Retrieve transport protocol from NFS client */
	proto = NFS_CLIENT(inode)->cl_xprt->prot;

	if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers)))
	host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers);
	if (host == NULL)
		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;
	call = nlm_alloc_call(host);
	if (call == NULL)
		return -ENOMEM;

		/* 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;
	}
	nlmclnt_locks_init_private(fl, host);
	/* Set up the argument struct */
	nlmclnt_setlockargs(call, fl);

	/* Keep the old signal mask */
	spin_lock_irqsave(&current->sighand->siglock, flags);
@@ -238,26 +190,10 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
	    && (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;

	nlmclnt_locks_init_private(fl, host);

	/* Set up the argument struct */
	nlmclnt_setlockargs(call, fl);
	spin_unlock_irqrestore(&current->sighand->siglock, flags);

	if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
		if (fl->fl_type != F_UNLCK) {
@@ -270,41 +206,58 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
	else
		status = -EINVAL;

 out_restore:
	fl->fl_ops->fl_release_private(fl);
	fl->fl_ops = NULL;

	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;
}
EXPORT_SYMBOL(nlmclnt_proc);

/*
 * Allocate an NLM RPC call struct
 *
 * Note: the caller must hold a reference to host. In case of failure,
 * this reference will be released.
 */
struct nlm_rqst *
nlmclnt_alloc_call(void)
struct nlm_rqst *nlm_alloc_call(struct nlm_host *host)
{
	struct nlm_rqst	*call;

	while (!signalled()) {
		call = (struct nlm_rqst *) kmalloc(sizeof(struct nlm_rqst), GFP_KERNEL);
		if (call) {
			memset(call, 0, sizeof(*call));
	for(;;) {
		call = kzalloc(sizeof(*call), GFP_KERNEL);
		if (call != NULL) {
			locks_init_lock(&call->a_args.lock.fl);
			locks_init_lock(&call->a_res.lock.fl);
			call->a_host = host;
			return call;
		}
		printk("nlmclnt_alloc_call: failed, waiting for memory\n");
		if (signalled())
			break;
		printk("nlm_alloc_call: failed, waiting for memory\n");
		schedule_timeout_interruptible(5*HZ);
	}
	nlm_release_host(host);
	return NULL;
}

void nlm_release_call(struct nlm_rqst *call)
{
	nlm_release_host(call->a_host);
	nlmclnt_release_lockargs(call);
	kfree(call);
}

static void nlmclnt_rpc_release(void *data)
{
	return nlm_release_call(data);
}

static int nlm_wait_on_grace(wait_queue_head_t *queue)
{
	DEFINE_WAIT(wait);
@@ -401,57 +354,45 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
/*
 * Generic NLM call, async version.
 */
int nlmsvc_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops)
{
	struct nlm_host	*host = req->a_host;
	struct rpc_clnt	*clnt;
	struct rpc_message msg = {
		.rpc_argp	= &req->a_args,
		.rpc_resp	= &req->a_res,
	};
	int		status;
	int status = -ENOLCK;

	dprintk("lockd: call procedure %d on %s (async)\n",
			(int)proc, host->h_name);

	/* If we have no RPC client yet, create one. */
	if ((clnt = nlm_bind_host(host)) == NULL)
		return -ENOLCK;
	msg.rpc_proc = &clnt->cl_procinfo[proc];
	clnt = nlm_bind_host(host);
	if (clnt == NULL)
		goto out_err;
	msg->rpc_proc = &clnt->cl_procinfo[proc];

        /* bootstrap and kick off the async RPC call */
        status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, tk_ops, req);

        status = rpc_call_async(clnt, msg, RPC_TASK_ASYNC, tk_ops, req);
	if (status == 0)
		return 0;
out_err:
	nlm_release_call(req);
	return status;
}

static int nlmclnt_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
{
	struct nlm_host	*host = req->a_host;
	struct rpc_clnt	*clnt;
	struct nlm_args	*argp = &req->a_args;
	struct nlm_res	*resp = &req->a_res;
	struct rpc_message msg = {
		.rpc_argp	= argp,
		.rpc_resp	= resp,
		.rpc_argp	= &req->a_args,
		.rpc_resp	= &req->a_res,
	};
	int		status;

	dprintk("lockd: call procedure %d on %s (async)\n",
			(int)proc, host->h_name);

	/* If we have no RPC client yet, create one. */
	if ((clnt = nlm_bind_host(host)) == NULL)
		return -ENOLCK;
	msg.rpc_proc = &clnt->cl_procinfo[proc];
	return __nlm_async_call(req, proc, &msg, tk_ops);
}

	/* Increment host refcount */
	nlm_get_host(host);
        /* bootstrap and kick off the async RPC call */
        status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, tk_ops, req);
	if (status < 0)
		nlm_release_host(host);
	return status;
int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
{
	struct rpc_message msg = {
		.rpc_argp	= &req->a_res,
	};
	return __nlm_async_call(req, proc, &msg, tk_ops);
}

/*
@@ -463,36 +404,41 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
	int	status;

	status = nlmclnt_call(req, NLMPROC_TEST);
	nlmclnt_release_lockargs(req);
	if (status < 0)
		return status;
		goto out;

	status = req->a_res.status;
	if (status == NLM_LCK_GRANTED) {
	switch (req->a_res.status) {
		case NLM_LCK_GRANTED:
			fl->fl_type = F_UNLCK;
	} if (status == NLM_LCK_DENIED) {
			break;
		case NLM_LCK_DENIED:
			/*
			 * Report the conflicting lock back to the application.
			 */
		locks_copy_lock(fl, &req->a_res.lock.fl);
			fl->fl_start = req->a_res.lock.fl.fl_start;
			fl->fl_end = req->a_res.lock.fl.fl_start;
			fl->fl_type = req->a_res.lock.fl.fl_type;
			fl->fl_pid = 0;
	} else {
		return nlm_stat_to_errno(req->a_res.status);
			break;
		default:
			status = nlm_stat_to_errno(req->a_res.status);
	}

	return 0;
out:
	nlm_release_call(req);
	return status;
}

static void nlmclnt_locks_copy_lock(struct file_lock *new, struct file_lock *fl)
{
	memcpy(&new->fl_u.nfs_fl, &fl->fl_u.nfs_fl, sizeof(new->fl_u.nfs_fl));
	nlm_get_lockowner(new->fl_u.nfs_fl.owner);
	new->fl_u.nfs_fl.state = fl->fl_u.nfs_fl.state;
	new->fl_u.nfs_fl.owner = nlm_get_lockowner(fl->fl_u.nfs_fl.owner);
	list_add_tail(&new->fl_u.nfs_fl.list, &fl->fl_u.nfs_fl.owner->host->h_granted);
}

static void nlmclnt_locks_release_private(struct file_lock *fl)
{
	list_del(&fl->fl_u.nfs_fl.list);
	nlm_put_lockowner(fl->fl_u.nfs_fl.owner);
	fl->fl_ops = NULL;
}

static struct file_lock_operations nlmclnt_lock_ops = {
@@ -504,8 +450,8 @@ static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *ho
{
	BUG_ON(fl->fl_ops != NULL);
	fl->fl_u.nfs_fl.state = 0;
	fl->fl_u.nfs_fl.flags = 0;
	fl->fl_u.nfs_fl.owner = nlm_find_lockowner(host, fl->fl_owner);
	INIT_LIST_HEAD(&fl->fl_u.nfs_fl.list);
	fl->fl_ops = &nlmclnt_lock_ops;
}

@@ -552,57 +498,52 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
{
	struct nlm_host	*host = req->a_host;
	struct nlm_res	*resp = &req->a_res;
	long timeout;
	int status;
	struct nlm_wait *block = NULL;
	int status = -ENOLCK;

	if (!host->h_monitored && nsm_monitor(host) < 0) {
		printk(KERN_NOTICE "lockd: failed to monitor %s\n",
					host->h_name);
		status = -ENOLCK;
		goto out;
	}

	if (req->a_args.block) {
		status = nlmclnt_prepare_block(req, host, fl);
		if (status < 0)
			goto out;
	}
	block = nlmclnt_prepare_block(host, fl);
	for(;;) {
		status = nlmclnt_call(req, NLMPROC_LOCK);
		if (status < 0)
			goto out_unblock;
		if (resp->status != NLM_LCK_BLOCKED)
		if (!req->a_args.block)
			break;
		/* Wait on an NLM blocking lock */
		timeout = nlmclnt_block(req, NLMCLNT_POLL_TIMEOUT);
		/* Did a reclaimer thread notify us of a server reboot? */
		if (resp->status ==  NLM_LCK_DENIED_GRACE_PERIOD)
			continue;
		if (resp->status != NLM_LCK_BLOCKED)
			break;
		if (timeout >= 0)
			continue;
		/* We were interrupted. Send a CANCEL request to the server
		/* Wait on an NLM blocking lock */
		status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT);
		/* if we were interrupted. Send a CANCEL request to the server
		 * and exit
		 */
		status = (int)timeout;
		if (status < 0)
			goto out_unblock;
		if (resp->status != NLM_LCK_BLOCKED)
			break;
	}

	if (resp->status == NLM_LCK_GRANTED) {
		fl->fl_u.nfs_fl.state = host->h_state;
		fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED;
		fl->fl_flags |= FL_SLEEP;
		/* Ensure the resulting lock will get added to granted list */
		do_vfs_lock(fl);
	}
	status = nlm_stat_to_errno(resp->status);
out_unblock:
	nlmclnt_finish_block(req);
	nlmclnt_finish_block(block);
	/* Cancel the blocked request if it is still pending */
	if (resp->status == NLM_LCK_BLOCKED)
		nlmclnt_cancel(host, req->a_args.block, fl);
out:
	nlmclnt_release_lockargs(req);
	nlm_release_call(req);
	return status;
}

@@ -658,10 +599,6 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
	struct nlm_res	*resp = &req->a_res;
	int		status;

	/* Clean the GRANTED flag now so the lock doesn't get
	 * reclaimed while we're stuck in the unlock call. */
	fl->fl_u.nfs_fl.flags &= ~NFS_LCK_GRANTED;

	/*
	 * Note: the server is supposed to either grant us the unlock
	 * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
@@ -669,32 +606,24 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
	 */
	do_vfs_lock(fl);

	if (req->a_flags & RPC_TASK_ASYNC) {
		status = nlmclnt_async_call(req, NLMPROC_UNLOCK,
					&nlmclnt_unlock_ops);
		/* Hrmf... Do the unlock early since locks_remove_posix()
		 * really expects us to free the lock synchronously */
		if (status < 0) {
			nlmclnt_release_lockargs(req);
			kfree(req);
		}
		return status;
	}
	if (req->a_flags & RPC_TASK_ASYNC)
		return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);

	status = nlmclnt_call(req, NLMPROC_UNLOCK);
	nlmclnt_release_lockargs(req);
	if (status < 0)
		return status;
		goto out;

	status = 0;
	if (resp->status == NLM_LCK_GRANTED)
		return 0;
		goto out;

	if (resp->status != NLM_LCK_DENIED_NOLOCKS)
		printk("lockd: unexpected unlock status: %d\n", resp->status);

	/* What to do now? I'm out of my depth... */

	return -ENOLCK;
	status = -ENOLCK;
out:
	nlm_release_call(req);
	return status;
}

static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
@@ -716,9 +645,6 @@ static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
	if (status != NLM_LCK_GRANTED)
		printk(KERN_WARNING "lockd: unexpected unlock status: %d\n", status);
die:
	nlm_release_host(req->a_host);
	nlmclnt_release_lockargs(req);
	kfree(req);
	return;
 retry_rebind:
	nlm_rebind_host(req->a_host);
@@ -728,6 +654,7 @@ static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)

static const struct rpc_call_ops nlmclnt_unlock_ops = {
	.rpc_call_done = nlmclnt_unlock_callback,
	.rpc_release = nlmclnt_rpc_release,
};

/*
@@ -749,20 +676,15 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl
	recalc_sigpending();
	spin_unlock_irqrestore(&current->sighand->siglock, flags);

	req = nlmclnt_alloc_call();
	req = nlm_alloc_call(nlm_get_host(host));
	if (!req)
		return -ENOMEM;
	req->a_host  = host;
	req->a_flags = RPC_TASK_ASYNC;

	nlmclnt_setlockargs(req, fl);
	req->a_args.block = block;

	status = nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);
	if (status < 0) {
		nlmclnt_release_lockargs(req);
		kfree(req);
	}
	status = nlm_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);

	spin_lock_irqsave(&current->sighand->siglock, flags);
	current->blocked = oldset;
@@ -791,6 +713,7 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data)
	switch (req->a_res.status) {
	case NLM_LCK_GRANTED:
	case NLM_LCK_DENIED_GRACE_PERIOD:
	case NLM_LCK_DENIED:
		/* Everything's good */
		break;
	case NLM_LCK_DENIED_NOLOCKS:
@@ -802,9 +725,6 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data)
	}

die:
	nlm_release_host(req->a_host);
	nlmclnt_release_lockargs(req);
	kfree(req);
	return;

retry_cancel:
@@ -818,6 +738,7 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data)

static const struct rpc_call_ops nlmclnt_cancel_ops = {
	.rpc_call_done = nlmclnt_cancel_callback,
	.rpc_release = nlmclnt_rpc_release,
};

/*
+9 −3
Original line number Diff line number Diff line
@@ -123,6 +123,8 @@ nlm_lookup_host(int server, struct sockaddr_in *sin,
	nlm_hosts[hash]    = host;
	INIT_LIST_HEAD(&host->h_lockowners);
	spin_lock_init(&host->h_lock);
	INIT_LIST_HEAD(&host->h_granted);
	INIT_LIST_HEAD(&host->h_reclaim);

	if (++nrhosts > NLM_HOST_MAX)
		next_gc = 0;
@@ -191,11 +193,12 @@ nlm_bind_host(struct nlm_host *host)
		xprt->resvport = 1;	/* NLM requires a reserved port */

		/* Existing NLM servers accept AUTH_UNIX only */
		clnt = rpc_create_client(xprt, host->h_name, &nlm_program,
		clnt = rpc_new_client(xprt, host->h_name, &nlm_program,
					host->h_version, RPC_AUTH_UNIX);
		if (IS_ERR(clnt))
			goto forgetit;
		clnt->cl_autobind = 1;	/* turn on pmap queries */
		clnt->cl_softrtry = 1; /* All queries are soft */

		host->h_rpcclnt = clnt;
	}
@@ -242,8 +245,12 @@ void nlm_release_host(struct nlm_host *host)
{
	if (host != NULL) {
		dprintk("lockd: release host %s\n", host->h_name);
		atomic_dec(&host->h_count);
		BUG_ON(atomic_read(&host->h_count) < 0);
		if (atomic_dec_and_test(&host->h_count)) {
			BUG_ON(!list_empty(&host->h_lockowners));
			BUG_ON(!list_empty(&host->h_granted));
			BUG_ON(!list_empty(&host->h_reclaim));
		}
	}
}

@@ -331,7 +338,6 @@ nlm_gc_hosts(void)
					rpc_destroy_client(host->h_rpcclnt);
				}
			}
			BUG_ON(!list_empty(&host->h_lockowners));
			kfree(host);
			nrhosts--;
		}
+10 −1
Original line number Diff line number Diff line
@@ -35,6 +35,10 @@ nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res)
	struct rpc_clnt	*clnt;
	int		status;
	struct nsm_args	args;
	struct rpc_message msg = {
		.rpc_argp	= &args,
		.rpc_resp	= res,
	};

	clnt = nsm_create();
	if (IS_ERR(clnt)) {
@@ -49,7 +53,8 @@ nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res)
	args.proc = NLMPROC_NSM_NOTIFY;
	memset(res, 0, sizeof(*res));

	status = rpc_call(clnt, proc, &args, res, 0);
	msg.rpc_proc = &clnt->cl_procinfo[proc];
	status = rpc_call_sync(clnt, &msg, 0);
	if (status < 0)
		printk(KERN_DEBUG "nsm_mon_unmon: rpc failed, status=%d\n",
			status);
@@ -214,12 +219,16 @@ static struct rpc_procinfo nsm_procedures[] = {
		.p_encode	= (kxdrproc_t) xdr_encode_mon,
		.p_decode	= (kxdrproc_t) xdr_decode_stat_res,
		.p_bufsiz	= MAX(SM_mon_sz, SM_monres_sz) << 2,
		.p_statidx	= SM_MON,
		.p_name		= "MONITOR",
	},
[SM_UNMON] = {
		.p_proc		= SM_UNMON,
		.p_encode	= (kxdrproc_t) xdr_encode_unmon,
		.p_decode	= (kxdrproc_t) xdr_decode_stat,
		.p_bufsiz	= MAX(SM_mon_id_sz, SM_unmonres_sz) << 2,
		.p_statidx	= SM_UNMON,
		.p_name		= "UNMONITOR",
	},
};

Loading