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

Commit 31c1febd authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'nfsd-4.4' of git://linux-nfs.org/~bfields/linux

Pull nfsd updates from Bruce Fields:
 "Apologies for coming a little late in the merge window.  Fortunately
  this is another fairly quiet one:

  Mainly smaller bugfixes and cleanup.  We're still finding some bugs
  from the breakup of the big NFSv4 state lock in 3.17 -- thanks
  especially to Andrew Elble and Jeff Layton for tracking down some of
  the remaining races"

* tag 'nfsd-4.4' of git://linux-nfs.org/~bfields/linux:
  svcrpc: document lack of some memory barriers
  nfsd: fix race with open / open upgrade stateids
  nfsd: eliminate sending duplicate and repeated delegations
  nfsd: remove recurring workqueue job to clean DRC
  SUNRPC: drop stale comment in svc_setup_socket()
  nfsd: ensure that seqid morphing operations are atomic wrt to copies
  nfsd: serialize layout stateid morphing operations
  nfsd: improve client_has_state to check for unused openowners
  nfsd: fix clid_inuse on mount with security change
  sunrpc/cache: make cache flushing more reliable.
  nfsd: move include of state.h from trace.c to trace.h
  sunrpc: avoid warning in gss_key_timeout
  lockd: get rid of reference-counted NSM RPC clients
  SUNRPC: Use MSG_SENDPAGE_NOTLAST when calling sendpage()
  lockd: create NSM handles per net namespace
  nfsd: switch unsigned char flags in svc_fh to bools
  nfsd: move svc_fh->fh_maxsize to just after fh_handle
  nfsd: drop null test before destroy functions
  nfsd: serialize state seqid morphing operations
parents b4a23759 0442f14b
Loading
Loading
Loading
Loading
+5 −3
Original line number Original line Diff line number Diff line
@@ -116,7 +116,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
		atomic_inc(&nsm->sm_count);
		atomic_inc(&nsm->sm_count);
	else {
	else {
		host = NULL;
		host = NULL;
		nsm = nsm_get_handle(ni->sap, ni->salen,
		nsm = nsm_get_handle(ni->net, ni->sap, ni->salen,
					ni->hostname, ni->hostname_len);
					ni->hostname, ni->hostname_len);
		if (unlikely(nsm == NULL)) {
		if (unlikely(nsm == NULL)) {
			dprintk("lockd: %s failed; no nsm handle\n",
			dprintk("lockd: %s failed; no nsm handle\n",
@@ -161,6 +161,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
	host->h_nsmhandle  = nsm;
	host->h_nsmhandle  = nsm;
	host->h_addrbuf    = nsm->sm_addrbuf;
	host->h_addrbuf    = nsm->sm_addrbuf;
	host->net	   = ni->net;
	host->net	   = ni->net;
	strlcpy(host->nodename, utsname()->nodename, sizeof(host->nodename));


out:
out:
	return host;
	return host;
@@ -534,17 +535,18 @@ static struct nlm_host *next_host_state(struct hlist_head *cache,


/**
/**
 * nlm_host_rebooted - Release all resources held by rebooted host
 * nlm_host_rebooted - Release all resources held by rebooted host
 * @net:  network namespace
 * @info: pointer to decoded results of NLM_SM_NOTIFY call
 * @info: pointer to decoded results of NLM_SM_NOTIFY call
 *
 *
 * We were notified that the specified host has rebooted.  Release
 * We were notified that the specified host has rebooted.  Release
 * all resources held by that peer.
 * all resources held by that peer.
 */
 */
void nlm_host_rebooted(const struct nlm_reboot *info)
void nlm_host_rebooted(const struct net *net, const struct nlm_reboot *info)
{
{
	struct nsm_handle *nsm;
	struct nsm_handle *nsm;
	struct nlm_host	*host;
	struct nlm_host	*host;


	nsm = nsm_reboot_lookup(info);
	nsm = nsm_reboot_lookup(net, info);
	if (unlikely(nsm == NULL))
	if (unlikely(nsm == NULL))
		return;
		return;


+37 −88
Original line number Original line Diff line number Diff line
@@ -42,7 +42,7 @@ struct nsm_args {
	u32			proc;
	u32			proc;


	char			*mon_name;
	char			*mon_name;
	char			*nodename;
	const char		*nodename;
};
};


struct nsm_res {
struct nsm_res {
@@ -51,7 +51,6 @@ struct nsm_res {
};
};


static const struct rpc_program	nsm_program;
static const struct rpc_program	nsm_program;
static				LIST_HEAD(nsm_handles);
static				DEFINE_SPINLOCK(nsm_lock);
static				DEFINE_SPINLOCK(nsm_lock);


/*
/*
@@ -87,69 +86,18 @@ static struct rpc_clnt *nsm_create(struct net *net, const char *nodename)
	return rpc_create(&args);
	return rpc_create(&args);
}
}


static struct rpc_clnt *nsm_client_set(struct lockd_net *ln,
		struct rpc_clnt *clnt)
{
	spin_lock(&ln->nsm_clnt_lock);
	if (ln->nsm_users == 0) {
		if (clnt == NULL)
			goto out;
		ln->nsm_clnt = clnt;
	}
	clnt = ln->nsm_clnt;
	ln->nsm_users++;
out:
	spin_unlock(&ln->nsm_clnt_lock);
	return clnt;
}

static struct rpc_clnt *nsm_client_get(struct net *net, const char *nodename)
{
	struct rpc_clnt	*clnt, *new;
	struct lockd_net *ln = net_generic(net, lockd_net_id);

	clnt = nsm_client_set(ln, NULL);
	if (clnt != NULL)
		goto out;

	clnt = new = nsm_create(net, nodename);
	if (IS_ERR(clnt))
		goto out;

	clnt = nsm_client_set(ln, new);
	if (clnt != new)
		rpc_shutdown_client(new);
out:
	return clnt;
}

static void nsm_client_put(struct net *net)
{
	struct lockd_net *ln = net_generic(net, lockd_net_id);
	struct rpc_clnt	*clnt = NULL;

	spin_lock(&ln->nsm_clnt_lock);
	ln->nsm_users--;
	if (ln->nsm_users == 0) {
		clnt = ln->nsm_clnt;
		ln->nsm_clnt = NULL;
	}
	spin_unlock(&ln->nsm_clnt_lock);
	if (clnt != NULL)
		rpc_shutdown_client(clnt);
}

static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
			 struct rpc_clnt *clnt)
			 const struct nlm_host *host)
{
{
	int		status;
	int		status;
	struct rpc_clnt *clnt;
	struct nsm_args args = {
	struct nsm_args args = {
		.priv		= &nsm->sm_priv,
		.priv		= &nsm->sm_priv,
		.prog		= NLM_PROGRAM,
		.prog		= NLM_PROGRAM,
		.vers		= 3,
		.vers		= 3,
		.proc		= NLMPROC_NSM_NOTIFY,
		.proc		= NLMPROC_NSM_NOTIFY,
		.mon_name	= nsm->sm_mon_name,
		.mon_name	= nsm->sm_mon_name,
		.nodename	= clnt->cl_nodename,
		.nodename	= host->nodename,
	};
	};
	struct rpc_message msg = {
	struct rpc_message msg = {
		.rpc_argp	= &args,
		.rpc_argp	= &args,
@@ -158,6 +106,13 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,


	memset(res, 0, sizeof(*res));
	memset(res, 0, sizeof(*res));


	clnt = nsm_create(host->net, host->nodename);
	if (IS_ERR(clnt)) {
		dprintk("lockd: failed to create NSM upcall transport, "
			"status=%ld, net=%p\n", PTR_ERR(clnt), host->net);
		return PTR_ERR(clnt);
	}

	msg.rpc_proc = &clnt->cl_procinfo[proc];
	msg.rpc_proc = &clnt->cl_procinfo[proc];
	status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFTCONN);
	status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFTCONN);
	if (status == -ECONNREFUSED) {
	if (status == -ECONNREFUSED) {
@@ -171,6 +126,8 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
				status);
				status);
	else
	else
		status = 0;
		status = 0;

	rpc_shutdown_client(clnt);
	return status;
	return status;
}
}


@@ -190,32 +147,19 @@ int nsm_monitor(const struct nlm_host *host)
	struct nsm_handle *nsm = host->h_nsmhandle;
	struct nsm_handle *nsm = host->h_nsmhandle;
	struct nsm_res	res;
	struct nsm_res	res;
	int		status;
	int		status;
	struct rpc_clnt *clnt;
	const char *nodename = NULL;


	dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name);
	dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name);


	if (nsm->sm_monitored)
	if (nsm->sm_monitored)
		return 0;
		return 0;


	if (host->h_rpcclnt)
		nodename = host->h_rpcclnt->cl_nodename;

	/*
	/*
	 * Choose whether to record the caller_name or IP address of
	 * Choose whether to record the caller_name or IP address of
	 * this peer in the local rpc.statd's database.
	 * this peer in the local rpc.statd's database.
	 */
	 */
	nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
	nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;


	clnt = nsm_client_get(host->net, nodename);
	status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, host);
	if (IS_ERR(clnt)) {
		status = PTR_ERR(clnt);
		dprintk("lockd: failed to create NSM upcall transport, "
				"status=%d, net=%p\n", status, host->net);
		return status;
	}

	status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, clnt);
	if (unlikely(res.status != 0))
	if (unlikely(res.status != 0))
		status = -EIO;
		status = -EIO;
	if (unlikely(status < 0)) {
	if (unlikely(status < 0)) {
@@ -247,11 +191,9 @@ void nsm_unmonitor(const struct nlm_host *host)


	if (atomic_read(&nsm->sm_count) == 1
	if (atomic_read(&nsm->sm_count) == 1
	 && nsm->sm_monitored && !nsm->sm_sticky) {
	 && nsm->sm_monitored && !nsm->sm_sticky) {
		struct lockd_net *ln = net_generic(host->net, lockd_net_id);

		dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name);
		dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name);


		status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, ln->nsm_clnt);
		status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, host);
		if (res.status != 0)
		if (res.status != 0)
			status = -EIO;
			status = -EIO;
		if (status < 0)
		if (status < 0)
@@ -259,38 +201,38 @@ void nsm_unmonitor(const struct nlm_host *host)
					nsm->sm_name);
					nsm->sm_name);
		else
		else
			nsm->sm_monitored = 0;
			nsm->sm_monitored = 0;

		nsm_client_put(host->net);
	}
	}
}
}


static struct nsm_handle *nsm_lookup_hostname(const char *hostname,
static struct nsm_handle *nsm_lookup_hostname(const struct list_head *nsm_handles,
					      const size_t len)
					const char *hostname, const size_t len)
{
{
	struct nsm_handle *nsm;
	struct nsm_handle *nsm;


	list_for_each_entry(nsm, &nsm_handles, sm_link)
	list_for_each_entry(nsm, nsm_handles, sm_link)
		if (strlen(nsm->sm_name) == len &&
		if (strlen(nsm->sm_name) == len &&
		    memcmp(nsm->sm_name, hostname, len) == 0)
		    memcmp(nsm->sm_name, hostname, len) == 0)
			return nsm;
			return nsm;
	return NULL;
	return NULL;
}
}


static struct nsm_handle *nsm_lookup_addr(const struct sockaddr *sap)
static struct nsm_handle *nsm_lookup_addr(const struct list_head *nsm_handles,
					const struct sockaddr *sap)
{
{
	struct nsm_handle *nsm;
	struct nsm_handle *nsm;


	list_for_each_entry(nsm, &nsm_handles, sm_link)
	list_for_each_entry(nsm, nsm_handles, sm_link)
		if (rpc_cmp_addr(nsm_addr(nsm), sap))
		if (rpc_cmp_addr(nsm_addr(nsm), sap))
			return nsm;
			return nsm;
	return NULL;
	return NULL;
}
}


static struct nsm_handle *nsm_lookup_priv(const struct nsm_private *priv)
static struct nsm_handle *nsm_lookup_priv(const struct list_head *nsm_handles,
					const struct nsm_private *priv)
{
{
	struct nsm_handle *nsm;
	struct nsm_handle *nsm;


	list_for_each_entry(nsm, &nsm_handles, sm_link)
	list_for_each_entry(nsm, nsm_handles, sm_link)
		if (memcmp(nsm->sm_priv.data, priv->data,
		if (memcmp(nsm->sm_priv.data, priv->data,
					sizeof(priv->data)) == 0)
					sizeof(priv->data)) == 0)
			return nsm;
			return nsm;
@@ -353,6 +295,7 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,


/**
/**
 * nsm_get_handle - Find or create a cached nsm_handle
 * nsm_get_handle - Find or create a cached nsm_handle
 * @net: network namespace
 * @sap: pointer to socket address of handle to find
 * @sap: pointer to socket address of handle to find
 * @salen: length of socket address
 * @salen: length of socket address
 * @hostname: pointer to C string containing hostname to find
 * @hostname: pointer to C string containing hostname to find
@@ -365,11 +308,13 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
 * @hostname cannot be found in the handle cache.  Returns NULL if
 * @hostname cannot be found in the handle cache.  Returns NULL if
 * an error occurs.
 * an error occurs.
 */
 */
struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
struct nsm_handle *nsm_get_handle(const struct net *net,
				  const struct sockaddr *sap,
				  const size_t salen, const char *hostname,
				  const size_t salen, const char *hostname,
				  const size_t hostname_len)
				  const size_t hostname_len)
{
{
	struct nsm_handle *cached, *new = NULL;
	struct nsm_handle *cached, *new = NULL;
	struct lockd_net *ln = net_generic(net, lockd_net_id);


	if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
	if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
		if (printk_ratelimit()) {
		if (printk_ratelimit()) {
@@ -384,9 +329,10 @@ struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
	spin_lock(&nsm_lock);
	spin_lock(&nsm_lock);


	if (nsm_use_hostnames && hostname != NULL)
	if (nsm_use_hostnames && hostname != NULL)
		cached = nsm_lookup_hostname(hostname, hostname_len);
		cached = nsm_lookup_hostname(&ln->nsm_handles,
					hostname, hostname_len);
	else
	else
		cached = nsm_lookup_addr(sap);
		cached = nsm_lookup_addr(&ln->nsm_handles, sap);


	if (cached != NULL) {
	if (cached != NULL) {
		atomic_inc(&cached->sm_count);
		atomic_inc(&cached->sm_count);
@@ -400,7 +346,7 @@ struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
	}
	}


	if (new != NULL) {
	if (new != NULL) {
		list_add(&new->sm_link, &nsm_handles);
		list_add(&new->sm_link, &ln->nsm_handles);
		spin_unlock(&nsm_lock);
		spin_unlock(&nsm_lock);
		dprintk("lockd: created nsm_handle for %s (%s)\n",
		dprintk("lockd: created nsm_handle for %s (%s)\n",
				new->sm_name, new->sm_addrbuf);
				new->sm_name, new->sm_addrbuf);
@@ -417,19 +363,22 @@ struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,


/**
/**
 * nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle
 * nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle
 * @net:  network namespace
 * @info: pointer to NLMPROC_SM_NOTIFY arguments
 * @info: pointer to NLMPROC_SM_NOTIFY arguments
 *
 *
 * Returns a matching nsm_handle if found in the nsm cache. The returned
 * Returns a matching nsm_handle if found in the nsm cache. The returned
 * nsm_handle's reference count is bumped. Otherwise returns NULL if some
 * nsm_handle's reference count is bumped. Otherwise returns NULL if some
 * error occurred.
 * error occurred.
 */
 */
struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info)
struct nsm_handle *nsm_reboot_lookup(const struct net *net,
				const struct nlm_reboot *info)
{
{
	struct nsm_handle *cached;
	struct nsm_handle *cached;
	struct lockd_net *ln = net_generic(net, lockd_net_id);


	spin_lock(&nsm_lock);
	spin_lock(&nsm_lock);


	cached = nsm_lookup_priv(&info->priv);
	cached = nsm_lookup_priv(&ln->nsm_handles, &info->priv);
	if (unlikely(cached == NULL)) {
	if (unlikely(cached == NULL)) {
		spin_unlock(&nsm_lock);
		spin_unlock(&nsm_lock);
		dprintk("lockd: never saw rebooted peer '%.*s' before\n",
		dprintk("lockd: never saw rebooted peer '%.*s' before\n",
+1 −3
Original line number Original line Diff line number Diff line
@@ -12,9 +12,7 @@ struct lockd_net {
	struct delayed_work grace_period_end;
	struct delayed_work grace_period_end;
	struct lock_manager lockd_manager;
	struct lock_manager lockd_manager;


	spinlock_t nsm_clnt_lock;
	struct list_head nsm_handles;
	unsigned int nsm_users;
	struct rpc_clnt *nsm_clnt;
};
};


extern int lockd_net_id;
extern int lockd_net_id;
+1 −1
Original line number Original line Diff line number Diff line
@@ -592,7 +592,7 @@ static int lockd_init_net(struct net *net)
	INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender);
	INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender);
	INIT_LIST_HEAD(&ln->lockd_manager.list);
	INIT_LIST_HEAD(&ln->lockd_manager.list);
	ln->lockd_manager.block_opens = false;
	ln->lockd_manager.block_opens = false;
	spin_lock_init(&ln->nsm_clnt_lock);
	INIT_LIST_HEAD(&ln->nsm_handles);
	return 0;
	return 0;
}
}


+1 −1
Original line number Original line Diff line number Diff line
@@ -421,7 +421,7 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
		return rpc_system_err;
		return rpc_system_err;
	}
	}


	nlm_host_rebooted(argp);
	nlm_host_rebooted(SVC_NET(rqstp), argp);
	return rpc_success;
	return rpc_success;
}
}


Loading