linux-nfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v9 0/6] nfsd: overhaul the client name tracking code
@ 2012-03-06 15:28 Jeff Layton
  2012-03-06 15:28 ` [PATCH v9 1/6] nfsd: add nfsd4_client_tracking_ops struct and a way to set it Jeff Layton
                   ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: Jeff Layton @ 2012-03-06 15:28 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, skinsbursky

This is the ninth iteration of this patchset. The primary motivation
for the respin here is to deal with the changes introduced by Stanislav's
"namespacification" of rpc_pipefs. I think this one should be closer
to what Stanislav suggested for this code.

In particular, I've done a bit more work to make this code
container-ready. One could consider this set as the opening salvo in the
effort to containerize nfsd. This one adds an initial per-namespace
nfsd_net object, and the info for the cld upcall is now stored within
that.

I have not attempted to do any work to containerize the legacy client
tracker. I envision us ripping that code out eventually as part of
the containerization effort. But we'll see...

Also, as requested by Bruce, I've broken out the patch to consolidate
the flags field and sent that yesterday in a patchset inappropriately
named:

    "nfsd: bugfixes for"

Mea culpa on that subject line, but this patchset depends on those
patches. I'd like to see these go in for 3.4 if possible.

Jeff Layton (6):
  nfsd: add nfsd4_client_tracking_ops struct and a way to set it
  sunrpc: create nfsd dir in rpc_pipefs
  nfsd: add a per-net-namespace struct for nfsd
  nfsd: add a header describing upcall to nfsdcld
  nfsd: add the infrastructure to handle the cld upcall
  nfsd: add notifier to handle mount/unmount of rpc_pipefs sb

 fs/nfsd/netns.h          |   35 +++
 fs/nfsd/nfs4recover.c    |  617 +++++++++++++++++++++++++++++++++++++++++++++-
 fs/nfsd/nfs4state.c      |   57 ++---
 fs/nfsd/nfsctl.c         |   22 ++-
 fs/nfsd/state.h          |   14 +-
 include/linux/nfsd/cld.h |   56 +++++
 net/sunrpc/rpc_pipe.c    |    5 +
 7 files changed, 750 insertions(+), 56 deletions(-)
 create mode 100644 fs/nfsd/netns.h
 create mode 100644 include/linux/nfsd/cld.h

-- 
1.7.7.6


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v9 1/6] nfsd: add nfsd4_client_tracking_ops struct and a way to set it
  2012-03-06 15:28 [PATCH v9 0/6] nfsd: overhaul the client name tracking code Jeff Layton
@ 2012-03-06 15:28 ` Jeff Layton
  2012-03-06 15:28 ` [PATCH v9 2/6] sunrpc: create nfsd dir in rpc_pipefs Jeff Layton
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Jeff Layton @ 2012-03-06 15:28 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, skinsbursky

Abstract out the mechanism that we use to track clients into a set of
client name tracking functions.

This gives us a mechanism to plug in a new set of client tracking
functions without disturbing the callers. It also gives us a way to
decide on what tracking scheme to use at runtime.

For now, this just looks like pointless abstraction, but later we'll
add a new alternate scheme for tracking clients on stable storage.

Note too that this patch anticipates the eventual containerization
of this code by passing in struct net pointers in places. No attempt
is made to containerize the legacy client tracker however.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/nfsd/nfs4recover.c |  131 ++++++++++++++++++++++++++++++++++++++++++++----
 fs/nfsd/nfs4state.c   |   57 +++++++--------------
 fs/nfsd/state.h       |   14 +++--
 3 files changed, 147 insertions(+), 55 deletions(-)

diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 6523809..bade4a0 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -43,9 +43,20 @@
 
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
+/* Declarations */
+struct nfsd4_client_tracking_ops {
+	int (*init)(struct net *);
+	void (*exit)(struct net *);
+	void (*create)(struct nfs4_client *);
+	void (*remove)(struct nfs4_client *);
+	int (*check)(struct nfs4_client *);
+	void (*grace_done)(struct net *, time_t);
+};
+
 /* Globals */
 static struct file *rec_file;
 static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
+static struct nfsd4_client_tracking_ops *client_tracking_ops;
 
 static int
 nfs4_save_creds(const struct cred **original_creds)
@@ -117,7 +128,8 @@ out_no_tfm:
 	return status;
 }
 
-void nfsd4_create_clid_dir(struct nfs4_client *clp)
+static void
+nfsd4_create_clid_dir(struct nfs4_client *clp)
 {
 	const struct cred *original_cred;
 	char *dname = clp->cl_recdir;
@@ -264,7 +276,7 @@ out_unlock:
 	return status;
 }
 
-void
+static void
 nfsd4_remove_clid_dir(struct nfs4_client *clp)
 {
 	const struct cred *original_cred;
@@ -291,7 +303,6 @@ out:
 	if (status)
 		printk("NFSD: Failed to remove expired client state directory"
 				" %.*s\n", HEXDIR_LEN, clp->cl_recdir);
-	return;
 }
 
 static int
@@ -310,8 +321,9 @@ purge_old(struct dentry *parent, struct dentry *child)
 	return 0;
 }
 
-void
-nfsd4_recdir_purge_old(void) {
+static void
+nfsd4_recdir_purge_old(struct net *net, time_t boot_time)
+{
 	int status;
 
 	if (!rec_file)
@@ -342,7 +354,7 @@ load_recdir(struct dentry *parent, struct dentry *child)
 	return 0;
 }
 
-int
+static int
 nfsd4_recdir_load(void) {
 	int status;
 
@@ -360,8 +372,8 @@ nfsd4_recdir_load(void) {
  * Hold reference to the recovery directory.
  */
 
-void
-nfsd4_init_recdir()
+static int
+nfsd4_init_recdir(void)
 {
 	const struct cred *original_cred;
 	int status;
@@ -376,21 +388,38 @@ nfsd4_init_recdir()
 		printk("NFSD: Unable to change credentials to find recovery"
 		       " directory: error %d\n",
 		       status);
-		return;
+		return status;
 	}
 
 	rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0);
 	if (IS_ERR(rec_file)) {
 		printk("NFSD: unable to find recovery directory %s\n",
 				user_recovery_dirname);
+		status = PTR_ERR(rec_file);
 		rec_file = NULL;
 	}
 
 	nfs4_reset_creds(original_cred);
+	return status;
 }
 
-void
-nfsd4_shutdown_recdir(void)
+static int
+nfsd4_load_reboot_recovery_data(struct net *net)
+{
+	int status;
+
+	nfs4_lock_state();
+	status = nfsd4_init_recdir();
+	if (!status)
+		status = nfsd4_recdir_load();
+	nfs4_unlock_state();
+	if (status)
+		printk(KERN_ERR "NFSD: Failure reading reboot recovery data\n");
+	return status;
+}
+
+static void
+nfsd4_shutdown_recdir(struct net *net)
 {
 	if (!rec_file)
 		return;
@@ -424,3 +453,83 @@ nfs4_recoverydir(void)
 {
 	return user_recovery_dirname;
 }
+
+static int
+nfsd4_check_legacy_client(struct nfs4_client *clp)
+{
+	/* did we already find that this client is stable? */
+	if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
+		return 0;
+
+	/* look for it in the reclaim hashtable otherwise */
+	if (nfsd4_find_reclaim_client(clp)) {
+		set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
+		return 0;
+	}
+
+	return -ENOENT;
+}
+
+static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = {
+	.init		= nfsd4_load_reboot_recovery_data,
+	.exit		= nfsd4_shutdown_recdir,
+	.create		= nfsd4_create_clid_dir,
+	.remove		= nfsd4_remove_clid_dir,
+	.check		= nfsd4_check_legacy_client,
+	.grace_done	= nfsd4_recdir_purge_old,
+};
+
+int
+nfsd4_client_tracking_init(struct net *net)
+{
+	int status;
+
+	client_tracking_ops = &nfsd4_legacy_tracking_ops;
+
+	status = client_tracking_ops->init(net);
+	if (status) {
+		printk(KERN_WARNING "NFSD: Unable to initialize client "
+				    "recovery tracking! (%d)\n", status);
+		client_tracking_ops = NULL;
+	}
+	return status;
+}
+
+void
+nfsd4_client_tracking_exit(struct net *net)
+{
+	if (client_tracking_ops) {
+		client_tracking_ops->exit(net);
+		client_tracking_ops = NULL;
+	}
+}
+
+void
+nfsd4_client_record_create(struct nfs4_client *clp)
+{
+	if (client_tracking_ops)
+		client_tracking_ops->create(clp);
+}
+
+void
+nfsd4_client_record_remove(struct nfs4_client *clp)
+{
+	if (client_tracking_ops)
+		client_tracking_ops->remove(clp);
+}
+
+int
+nfsd4_client_record_check(struct nfs4_client *clp)
+{
+	if (client_tracking_ops)
+		return client_tracking_ops->check(clp);
+
+	return -EOPNOTSUPP;
+}
+
+void
+nfsd4_record_grace_done(struct net *net, time_t boot_time)
+{
+	if (client_tracking_ops)
+		client_tracking_ops->grace_done(net, boot_time);
+}
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 1198fe8..8f42a07 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2046,7 +2046,7 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
 		goto out;
 
 	status = nfs_ok;
-	nfsd4_create_clid_dir(cstate->session->se_client);
+	nfsd4_client_record_create(cstate->session->se_client);
 out:
 	nfs4_unlock_state();
 	return status;
@@ -2241,7 +2241,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
 			conf = find_confirmed_client_by_str(unconf->cl_recdir,
 							    hash);
 			if (conf) {
-				nfsd4_remove_clid_dir(conf);
+				nfsd4_client_record_remove(conf);
 				expire_client(conf);
 			}
 			move_to_confirmed(unconf);
@@ -3066,7 +3066,7 @@ static void
 nfsd4_end_grace(void)
 {
 	dprintk("NFSD: end of grace period\n");
-	nfsd4_recdir_purge_old();
+	nfsd4_record_grace_done(&init_net, boot_time);
 	locks_end_grace(&nfsd4_manager);
 	/*
 	 * Now that every NFSv4 client has had the chance to recover and
@@ -3115,7 +3115,7 @@ nfs4_laundromat(void)
 		clp = list_entry(pos, struct nfs4_client, cl_lru);
 		dprintk("NFSD: purging unused client (clientid %08x)\n",
 			clp->cl_clientid.cl_id);
-		nfsd4_remove_clid_dir(clp);
+		nfsd4_client_record_remove(clp);
 		expire_client(clp);
 	}
 	spin_lock(&recall_lock);
@@ -3539,7 +3539,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
 		__func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));
 
-	nfsd4_create_clid_dir(oo->oo_owner.so_client);
+	nfsd4_client_record_create(oo->oo_owner.so_client);
 	status = nfs_ok;
 out:
 	if (!cstate->replay_owner)
@@ -4397,7 +4397,7 @@ nfs4_release_reclaim(void)
 
 /*
  * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
-static struct nfs4_client_reclaim *
+struct nfs4_client_reclaim *
 nfsd4_find_reclaim_client(struct nfs4_client *clp)
 {
 	unsigned int strhashval;
@@ -4417,22 +4417,6 @@ nfsd4_find_reclaim_client(struct nfs4_client *clp)
 	return NULL;
 }
 
-static int
-nfsd4_client_record_check(struct nfs4_client *clp)
-{
-	/* did we already find that this client is stable? */
-	if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
-		return 0;
-
-	/* look for it in the reclaim hashtable otherwise */
-	if (nfsd4_find_reclaim_client(clp)) {
-		set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
-		return 0;
-	}
-
-	return -ENOENT;
-}
-
 /*
 * Called from OPEN. Look for clientid in reclaim list.
 */
@@ -4593,19 +4577,6 @@ nfs4_state_init(void)
 	reclaim_str_hashtbl_size = 0;
 }
 
-static void
-nfsd4_load_reboot_recovery_data(void)
-{
-	int status;
-
-	nfs4_lock_state();
-	nfsd4_init_recdir();
-	status = nfsd4_recdir_load();
-	nfs4_unlock_state();
-	if (status)
-		printk("NFSD: Failure reading reboot recovery data\n");
-}
-
 /*
  * Since the lifetime of a delegation isn't limited to that of an open, a
  * client may quite reasonably hang on to a delegation as long as it has
@@ -4634,7 +4605,15 @@ nfs4_state_start(void)
 {
 	int ret;
 
-	nfsd4_load_reboot_recovery_data();
+	/*
+	 * FIXME: For now, we hang most of the pernet global stuff off of
+	 * init_net until nfsd is fully containerized. Eventually, we'll
+	 * need to pass a net pointer into this function, take a reference
+	 * to that instead and then do most of the rest of this on a per-net
+	 * basis.
+	 */
+	get_net(&init_net);
+	nfsd4_client_tracking_init(&init_net);
 	boot_time = get_seconds();
 	locks_start_grace(&nfsd4_manager);
 	printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
@@ -4658,7 +4637,8 @@ nfs4_state_start(void)
 out_free_laundry:
 	destroy_workqueue(laundry_wq);
 out_recovery:
-	nfsd4_shutdown_recdir();
+	nfsd4_client_tracking_exit(&init_net);
+	put_net(&init_net);
 	return ret;
 }
 
@@ -4692,7 +4672,8 @@ __nfs4_state_shutdown(void)
 		unhash_delegation(dp);
 	}
 
-	nfsd4_shutdown_recdir();
+	nfsd4_client_tracking_exit(&init_net);
+	put_net(&init_net);
 }
 
 void
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index b9c036d..81d2e63 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -466,6 +466,7 @@ extern __be32 nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
 extern void nfs4_lock_state(void);
 extern void nfs4_unlock_state(void);
 extern int nfs4_in_grace(void);
+extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct nfs4_client *crp);
 extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
 extern void nfs4_free_openowner(struct nfs4_openowner *);
 extern void nfs4_free_lockowner(struct nfs4_lockowner *);
@@ -480,16 +481,17 @@ extern void nfsd4_destroy_callback_queue(void);
 extern void nfsd4_shutdown_callback(struct nfs4_client *);
 extern void nfs4_put_delegation(struct nfs4_delegation *dp);
 extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
-extern void nfsd4_init_recdir(void);
-extern int nfsd4_recdir_load(void);
-extern void nfsd4_shutdown_recdir(void);
 extern int nfs4_client_to_reclaim(const char *name);
 extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id);
-extern void nfsd4_recdir_purge_old(void);
-extern void nfsd4_create_clid_dir(struct nfs4_client *clp);
-extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
 extern void release_session_client(struct nfsd4_session *);
 extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *);
 extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);
 
+/* nfs4recover operations */
+extern int nfsd4_client_tracking_init(struct net *net);
+extern void nfsd4_client_tracking_exit(struct net *net);
+extern void nfsd4_client_record_create(struct nfs4_client *clp);
+extern void nfsd4_client_record_remove(struct nfs4_client *clp);
+extern int nfsd4_client_record_check(struct nfs4_client *clp);
+extern void nfsd4_record_grace_done(struct net *net, time_t boot_time);
 #endif   /* NFSD4_STATE_H */
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v9 2/6] sunrpc: create nfsd dir in rpc_pipefs
  2012-03-06 15:28 [PATCH v9 0/6] nfsd: overhaul the client name tracking code Jeff Layton
  2012-03-06 15:28 ` [PATCH v9 1/6] nfsd: add nfsd4_client_tracking_ops struct and a way to set it Jeff Layton
@ 2012-03-06 15:28 ` Jeff Layton
  2012-03-06 15:28 ` [PATCH v9 3/6] nfsd: add a per-net-namespace struct for nfsd Jeff Layton
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Jeff Layton @ 2012-03-06 15:28 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, skinsbursky

Add a new top-level dir in rpc_pipefs to hold the pipe for the clientid
upcall.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 net/sunrpc/rpc_pipe.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 6873c9b..c81915d 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -992,6 +992,7 @@ enum {
 	RPCAUTH_statd,
 	RPCAUTH_nfsd4_cb,
 	RPCAUTH_cache,
+	RPCAUTH_nfsd,
 	RPCAUTH_RootEOF
 };
 
@@ -1024,6 +1025,10 @@ static const struct rpc_filelist files[] = {
 		.name = "cache",
 		.mode = S_IFDIR | S_IRUGO | S_IXUGO,
 	},
+	[RPCAUTH_nfsd] = {
+		.name = "nfsd",
+		.mode = S_IFDIR | S_IRUGO | S_IXUGO,
+	},
 };
 
 /*
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v9 3/6] nfsd: add a per-net-namespace struct for nfsd
  2012-03-06 15:28 [PATCH v9 0/6] nfsd: overhaul the client name tracking code Jeff Layton
  2012-03-06 15:28 ` [PATCH v9 1/6] nfsd: add nfsd4_client_tracking_ops struct and a way to set it Jeff Layton
  2012-03-06 15:28 ` [PATCH v9 2/6] sunrpc: create nfsd dir in rpc_pipefs Jeff Layton
@ 2012-03-06 15:28 ` Jeff Layton
  2012-03-06 17:43   ` Stanislav Kinsbursky
  2012-03-11  7:44   ` Stanislav Kinsbursky
  2012-03-06 15:28 ` [PATCH v9 4/6] nfsd: add a header describing upcall to nfsdcld Jeff Layton
                   ` (2 subsequent siblings)
  5 siblings, 2 replies; 13+ messages in thread
From: Jeff Layton @ 2012-03-06 15:28 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, skinsbursky

Eventually, we'll need this when nfsd gets containerized fully. For
now, create a struct on a per-net-namespace basis that will just hold
a pointer to the cld_net structure. That struct will hold all of the
per-net data that we need for the cld tracker.

Eventually we can add other pernet objects to struct nfsd_net.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/nfsd/netns.h  |   34 ++++++++++++++++++++++++++++++++++
 fs/nfsd/nfsctl.c |   15 ++++++++++++++-
 2 files changed, 48 insertions(+), 1 deletions(-)
 create mode 100644 fs/nfsd/netns.h

diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
new file mode 100644
index 0000000..12e0cff
--- /dev/null
+++ b/fs/nfsd/netns.h
@@ -0,0 +1,34 @@
+/*
+ * per net namespace data structures for nfsd
+ *
+ * Copyright (C) 2012, Jeff Layton <jlayton@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __NFSD_NETNS_H__
+#define __NFSD_NETNS_H__
+
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+
+struct cld_net;
+
+struct nfsd_net {
+	struct cld_net *cld_net;
+};
+
+extern int nfsd_net_id;
+#endif /* __NFSD_NETNS_H__ */
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 64c24af..141197e 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -19,6 +19,7 @@
 #include "nfsd.h"
 #include "cache.h"
 #include "fault_inject.h"
+#include "netns.h"
 
 /*
  *	We have a single directory with several nodes in it.
@@ -1124,14 +1125,23 @@ static int create_proc_exports_entry(void)
 }
 #endif
 
+int nfsd_net_id;
+static struct pernet_operations nfsd_net_ops = {
+	.id   = &nfsd_net_id,
+	.size = sizeof(struct nfsd_net),
+};
+
 static int __init init_nfsd(void)
 {
 	int retval;
 	printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
 
+	retval = register_pernet_subsys(&nfsd_net_ops);
+	if (retval < 0)
+		return retval;
 	retval = nfsd4_init_slabs();
 	if (retval)
-		return retval;
+		goto out_unregister_pernet;
 	nfs4_state_init();
 	retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */
 	if (retval)
@@ -1169,6 +1179,8 @@ out_free_stat:
 	nfsd_fault_inject_cleanup();
 out_free_slabs:
 	nfsd4_free_slabs();
+out_unregister_pernet:
+	unregister_pernet_subsys(&nfsd_net_ops);
 	return retval;
 }
 
@@ -1184,6 +1196,7 @@ static void __exit exit_nfsd(void)
 	nfsd4_free_slabs();
 	nfsd_fault_inject_cleanup();
 	unregister_filesystem(&nfsd_fs_type);
+	unregister_pernet_subsys(&nfsd_net_ops);
 }
 
 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v9 4/6] nfsd: add a header describing upcall to nfsdcld
  2012-03-06 15:28 [PATCH v9 0/6] nfsd: overhaul the client name tracking code Jeff Layton
                   ` (2 preceding siblings ...)
  2012-03-06 15:28 ` [PATCH v9 3/6] nfsd: add a per-net-namespace struct for nfsd Jeff Layton
@ 2012-03-06 15:28 ` Jeff Layton
  2012-03-06 15:28 ` [PATCH v9 5/6] nfsd: add the infrastructure to handle the cld upcall Jeff Layton
  2012-03-06 15:28 ` [PATCH v9 6/6] nfsd: add notifier to handle mount/unmount of rpc_pipefs sb Jeff Layton
  5 siblings, 0 replies; 13+ messages in thread
From: Jeff Layton @ 2012-03-06 15:28 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, skinsbursky

The daemon takes a versioned binary struct. Hopefully this should allow
us to revise the struct later if it becomes necessary.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 include/linux/nfsd/cld.h |   56 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 56 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/nfsd/cld.h

diff --git a/include/linux/nfsd/cld.h b/include/linux/nfsd/cld.h
new file mode 100644
index 0000000..f14a9ab
--- /dev/null
+++ b/include/linux/nfsd/cld.h
@@ -0,0 +1,56 @@
+/*
+ * Upcall description for nfsdcld communication
+ *
+ * Copyright (c) 2012 Red Hat, Inc.
+ * Author(s): Jeff Layton <jlayton@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _NFSD_CLD_H
+#define _NFSD_CLD_H
+
+/* latest upcall version available */
+#define CLD_UPCALL_VERSION 1
+
+/* defined by RFC3530 */
+#define NFS4_OPAQUE_LIMIT 1024
+
+enum cld_command {
+	Cld_Create,		/* create a record for this cm_id */
+	Cld_Remove,		/* remove record of this cm_id */
+	Cld_Check,		/* is this cm_id allowed? */
+	Cld_GraceDone,		/* grace period is complete */
+};
+
+/* representation of long-form NFSv4 client ID */
+struct cld_name {
+	uint16_t	cn_len;				/* length of cm_id */
+	unsigned char	cn_id[NFS4_OPAQUE_LIMIT];	/* client-provided */
+} __attribute__((packed));
+
+/* message struct for communication with userspace */
+struct cld_msg {
+	uint8_t		cm_vers;		/* upcall version */
+	uint8_t		cm_cmd;			/* upcall command */
+	int16_t		cm_status;		/* return code */
+	uint32_t	cm_xid;			/* transaction id */
+	union {
+		int64_t		cm_gracetime;	/* grace period start time */
+		struct cld_name	cm_name;
+	} __attribute__((packed)) cm_u;
+} __attribute__((packed));
+
+#endif /* !_NFSD_CLD_H */
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v9 5/6] nfsd: add the infrastructure to handle the cld upcall
  2012-03-06 15:28 [PATCH v9 0/6] nfsd: overhaul the client name tracking code Jeff Layton
                   ` (3 preceding siblings ...)
  2012-03-06 15:28 ` [PATCH v9 4/6] nfsd: add a header describing upcall to nfsdcld Jeff Layton
@ 2012-03-06 15:28 ` Jeff Layton
  2012-03-06 15:28 ` [PATCH v9 6/6] nfsd: add notifier to handle mount/unmount of rpc_pipefs sb Jeff Layton
  5 siblings, 0 replies; 13+ messages in thread
From: Jeff Layton @ 2012-03-06 15:28 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, skinsbursky

...and add a mechanism for switching between the "legacy" tracker and
the new one. The decision is made by looking to see whether the
v4recoverydir exists. If it does, then the legacy client tracker is
used.

If it's not, then the kernel will create a "cld" pipe in rpc_pipefs.
That pipe is used to talk to a daemon for handling the upcall.

Most of the data structures for the new client tracker are handled on a
per-namespace basis, so this upcall should be essentially ready for
containerization. For now however, nfsd just starts it by calling the
initialization and exit functions for init_net.

I'm making the assumption that at some point in the future we'll be able
to determine the net namespace from the nfs4_client. Until then, this
patch hardcodes init_net in those places. I've sprinkled some "FIXME"
comments around that code to attempt to make it clear where we'll need
to fix that up later.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/nfsd/nfs4recover.c |  444 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 443 insertions(+), 1 deletions(-)

diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index bade4a0..bc4b189 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -1,5 +1,6 @@
 /*
 *  Copyright (c) 2004 The Regents of the University of Michigan.
+*  Copyright (c) 2012 Jeff Layton <jlayton@redhat.com>
 *  All rights reserved.
 *
 *  Andy Adamson <andros@citi.umich.edu>
@@ -36,10 +37,16 @@
 #include <linux/namei.h>
 #include <linux/crypto.h>
 #include <linux/sched.h>
+#include <linux/fs.h>
+#include <net/net_namespace.h>
+#include <linux/sunrpc/rpc_pipe_fs.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/nfsd/cld.h>
 
 #include "nfsd.h"
 #include "state.h"
 #include "vfs.h"
+#include "netns.h"
 
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
@@ -479,12 +486,447 @@ static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = {
 	.grace_done	= nfsd4_recdir_purge_old,
 };
 
+/* Globals */
+#define NFSD_PIPE_DIR		"nfsd"
+#define NFSD_CLD_PIPE		"cld"
+
+/* per-net-ns structure for holding cld upcall info */
+struct cld_net {
+	struct rpc_pipe		*cn_pipe;
+	spinlock_t		 cn_lock;
+	struct list_head	 cn_list;
+	unsigned int		 cn_xid;
+};
+
+struct cld_upcall {
+	struct list_head	 cu_list;
+	struct cld_net		*cu_net;
+	struct task_struct	*cu_task;
+	struct cld_msg		 cu_msg;
+};
+
+static int
+__cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg)
+{
+	int ret;
+	struct rpc_pipe_msg msg;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.data = cmsg;
+	msg.len = sizeof(*cmsg);
+
+	/*
+	 * Set task state before we queue the upcall. That prevents
+	 * wake_up_process in the downcall from racing with schedule.
+	 */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	ret = rpc_queue_upcall(pipe, &msg);
+	if (ret < 0) {
+		set_current_state(TASK_RUNNING);
+		goto out;
+	}
+
+	schedule();
+	set_current_state(TASK_RUNNING);
+
+	if (msg.errno < 0)
+		ret = msg.errno;
+out:
+	return ret;
+}
+
+static int
+cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg)
+{
+	int ret;
+
+	/*
+	 * -EAGAIN occurs when pipe is closed and reopened while there are
+	 *  upcalls queued.
+	 */
+	do {
+		ret = __cld_pipe_upcall(pipe, cmsg);
+	} while (ret == -EAGAIN);
+
+	return ret;
+}
+
+static ssize_t
+cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
+{
+	struct cld_upcall *tmp, *cup;
+	struct cld_msg *cmsg = (struct cld_msg *)src;
+	uint32_t xid;
+	struct nfsd_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info,
+						nfsd_net_id);
+	struct cld_net *cn = nn->cld_net;
+
+	if (mlen != sizeof(*cmsg)) {
+		dprintk("%s: got %lu bytes, expected %lu\n", __func__, mlen,
+			sizeof(*cmsg));
+		return -EINVAL;
+	}
+
+	/* copy just the xid so we can try to find that */
+	if (copy_from_user(&xid, &cmsg->cm_xid, sizeof(xid)) != 0) {
+		dprintk("%s: error when copying xid from userspace", __func__);
+		return -EFAULT;
+	}
+
+	/* walk the list and find corresponding xid */
+	cup = NULL;
+	spin_lock(&cn->cn_lock);
+	list_for_each_entry(tmp, &cn->cn_list, cu_list) {
+		if (get_unaligned(&tmp->cu_msg.cm_xid) == xid) {
+			cup = tmp;
+			list_del_init(&cup->cu_list);
+			break;
+		}
+	}
+	spin_unlock(&cn->cn_lock);
+
+	/* couldn't find upcall? */
+	if (!cup) {
+		dprintk("%s: couldn't find upcall -- xid=%u\n", __func__,
+			cup->cu_msg.cm_xid);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&cup->cu_msg, src, mlen) != 0)
+		return -EFAULT;
+
+	wake_up_process(cup->cu_task);
+	return mlen;
+}
+
+static void
+cld_pipe_destroy_msg(struct rpc_pipe_msg *msg)
+{
+	struct cld_msg *cmsg = msg->data;
+	struct cld_upcall *cup = container_of(cmsg, struct cld_upcall,
+						 cu_msg);
+
+	/* errno >= 0 means we got a downcall */
+	if (msg->errno >= 0)
+		return;
+
+	wake_up_process(cup->cu_task);
+}
+
+static const struct rpc_pipe_ops cld_upcall_ops = {
+	.upcall		= rpc_pipe_generic_upcall,
+	.downcall	= cld_pipe_downcall,
+	.destroy_msg	= cld_pipe_destroy_msg,
+};
+
+static struct dentry *
+nfsd4_cld_register_sb(struct super_block *sb, struct rpc_pipe *pipe)
+{
+	struct dentry *dir, *dentry;
+
+	dir = rpc_d_lookup_sb(sb, NFSD_PIPE_DIR);
+	if (dir == NULL)
+		return ERR_PTR(-ENOENT);
+	dentry = rpc_mkpipe_dentry(dir, NFSD_CLD_PIPE, NULL, pipe);
+	dput(dir);
+	return dentry;
+}
+
+static void
+nfsd4_cld_unregister_sb(struct rpc_pipe *pipe)
+{
+	if (pipe->dentry)
+		rpc_unlink(pipe->dentry);
+}
+
+static struct dentry *
+nfsd4_cld_register_net(struct net *net, struct rpc_pipe *pipe)
+{
+	struct super_block *sb;
+	struct dentry *dentry;
+
+	sb = rpc_get_sb_net(net);
+	if (!sb)
+		return NULL;
+	dentry = nfsd4_cld_register_sb(sb, pipe);
+	rpc_put_sb_net(net);
+	return dentry;
+}
+
+static void
+nfsd4_cld_unregister_net(struct net *net, struct rpc_pipe *pipe)
+{
+	struct super_block *sb;
+
+	sb = rpc_get_sb_net(net);
+	if (sb) {
+		nfsd4_cld_unregister_sb(pipe);
+		rpc_put_sb_net(net);
+	}
+}
+
+/* Initialize rpc_pipefs pipe for communication with client tracking daemon */
+static int
+nfsd4_init_cld_pipe(struct net *net)
+{
+	int ret;
+	struct dentry *dentry;
+	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+	struct cld_net *cn;
+
+	if (nn->cld_net)
+		return 0;
+
+	cn = kzalloc(sizeof(*cn), GFP_KERNEL);
+	if (!cn) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	cn->cn_pipe = rpc_mkpipe_data(&cld_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
+	if (IS_ERR(cn->cn_pipe)) {
+		ret = PTR_ERR(cn->cn_pipe);
+		goto err;
+	}
+	spin_lock_init(&cn->cn_lock);
+	INIT_LIST_HEAD(&cn->cn_list);
+
+	dentry = nfsd4_cld_register_net(net, cn->cn_pipe);
+	if (IS_ERR(dentry)) {
+		ret = PTR_ERR(dentry);
+		goto err_destroy_data;
+	}
+
+	cn->cn_pipe->dentry = dentry;
+	nn->cld_net = cn;
+	return 0;
+
+err_destroy_data:
+	rpc_destroy_pipe_data(cn->cn_pipe);
+err:
+	kfree(cn);
+	printk(KERN_ERR "NFSD: unable to create nfsdcld upcall pipe (%d)\n",
+			ret);
+	return ret;
+}
+
+static void
+nfsd4_remove_cld_pipe(struct net *net)
+{
+	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+	struct cld_net *cn = nn->cld_net;
+
+	nfsd4_cld_unregister_net(net, cn->cn_pipe);
+	rpc_destroy_pipe_data(cn->cn_pipe);
+	kfree(nn->cld_net);
+	nn->cld_net = NULL;
+}
+
+static struct cld_upcall *
+alloc_cld_upcall(struct cld_net *cn)
+{
+	struct cld_upcall *new, *tmp;
+
+	new = kzalloc(sizeof(*new), GFP_KERNEL);
+	if (!new)
+		return new;
+
+	/* FIXME: hard cap on number in flight? */
+restart_search:
+	spin_lock(&cn->cn_lock);
+	list_for_each_entry(tmp, &cn->cn_list, cu_list) {
+		if (tmp->cu_msg.cm_xid == cn->cn_xid) {
+			cn->cn_xid++;
+			spin_unlock(&cn->cn_lock);
+			goto restart_search;
+		}
+	}
+	new->cu_task = current;
+	new->cu_msg.cm_vers = CLD_UPCALL_VERSION;
+	put_unaligned(cn->cn_xid++, &new->cu_msg.cm_xid);
+	new->cu_net = cn;
+	list_add(&new->cu_list, &cn->cn_list);
+	spin_unlock(&cn->cn_lock);
+
+	dprintk("%s: allocated xid %u\n", __func__, new->cu_msg.cm_xid);
+
+	return new;
+}
+
+static void
+free_cld_upcall(struct cld_upcall *victim)
+{
+	struct cld_net *cn = victim->cu_net;
+
+	spin_lock(&cn->cn_lock);
+	list_del(&victim->cu_list);
+	spin_unlock(&cn->cn_lock);
+	kfree(victim);
+}
+
+/* Ask daemon to create a new record */
+static void
+nfsd4_cld_create(struct nfs4_client *clp)
+{
+	int ret;
+	struct cld_upcall *cup;
+	/* FIXME: determine net from clp */
+	struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+	struct cld_net *cn = nn->cld_net;
+
+	/* Don't upcall if it's already stored */
+	if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
+		return;
+
+	cup = alloc_cld_upcall(cn);
+	if (!cup) {
+		ret = -ENOMEM;
+		goto out_err;
+	}
+
+	cup->cu_msg.cm_cmd = Cld_Create;
+	cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
+	memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
+			clp->cl_name.len);
+
+	ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
+	if (!ret) {
+		ret = cup->cu_msg.cm_status;
+		set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
+	}
+
+	free_cld_upcall(cup);
+out_err:
+	if (ret)
+		printk(KERN_ERR "NFSD: Unable to create client "
+				"record on stable storage: %d\n", ret);
+}
+
+/* Ask daemon to create a new record */
+static void
+nfsd4_cld_remove(struct nfs4_client *clp)
+{
+	int ret;
+	struct cld_upcall *cup;
+	/* FIXME: determine net from clp */
+	struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+	struct cld_net *cn = nn->cld_net;
+
+	/* Don't upcall if it's already removed */
+	if (!test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
+		return;
+
+	cup = alloc_cld_upcall(cn);
+	if (!cup) {
+		ret = -ENOMEM;
+		goto out_err;
+	}
+
+	cup->cu_msg.cm_cmd = Cld_Remove;
+	cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
+	memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
+			clp->cl_name.len);
+
+	ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
+	if (!ret) {
+		ret = cup->cu_msg.cm_status;
+		clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
+	}
+
+	free_cld_upcall(cup);
+out_err:
+	if (ret)
+		printk(KERN_ERR "NFSD: Unable to remove client "
+				"record from stable storage: %d\n", ret);
+}
+
+/* Check for presence of a record, and update its timestamp */
+static int
+nfsd4_cld_check(struct nfs4_client *clp)
+{
+	int ret;
+	struct cld_upcall *cup;
+	/* FIXME: determine net from clp */
+	struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+	struct cld_net *cn = nn->cld_net;
+
+	/* Don't upcall if one was already stored during this grace pd */
+	if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
+		return 0;
+
+	cup = alloc_cld_upcall(cn);
+	if (!cup) {
+		printk(KERN_ERR "NFSD: Unable to check client record on "
+				"stable storage: %d\n", -ENOMEM);
+		return -ENOMEM;
+	}
+
+	cup->cu_msg.cm_cmd = Cld_Check;
+	cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
+	memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
+			clp->cl_name.len);
+
+	ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
+	if (!ret) {
+		ret = cup->cu_msg.cm_status;
+		set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
+	}
+
+	free_cld_upcall(cup);
+	return ret;
+}
+
+static void
+nfsd4_cld_grace_done(struct net *net, time_t boot_time)
+{
+	int ret;
+	struct cld_upcall *cup;
+	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+	struct cld_net *cn = nn->cld_net;
+
+	cup = alloc_cld_upcall(cn);
+	if (!cup) {
+		ret = -ENOMEM;
+		goto out_err;
+	}
+
+	cup->cu_msg.cm_cmd = Cld_GraceDone;
+	cup->cu_msg.cm_u.cm_gracetime = (int64_t)boot_time;
+	ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
+	if (!ret)
+		ret = cup->cu_msg.cm_status;
+
+	free_cld_upcall(cup);
+out_err:
+	if (ret)
+		printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret);
+}
+
+static struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
+	.init		= nfsd4_init_cld_pipe,
+	.exit		= nfsd4_remove_cld_pipe,
+	.create		= nfsd4_cld_create,
+	.remove		= nfsd4_cld_remove,
+	.check		= nfsd4_cld_check,
+	.grace_done	= nfsd4_cld_grace_done,
+};
+
 int
 nfsd4_client_tracking_init(struct net *net)
 {
 	int status;
+	struct path path;
 
-	client_tracking_ops = &nfsd4_legacy_tracking_ops;
+	if (!client_tracking_ops) {
+		client_tracking_ops = &nfsd4_cld_tracking_ops;
+		status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path);
+		if (!status) {
+			if (S_ISDIR(path.dentry->d_inode->i_mode))
+				client_tracking_ops =
+						&nfsd4_legacy_tracking_ops;
+			path_put(&path);
+		}
+	}
 
 	status = client_tracking_ops->init(net);
 	if (status) {
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v9 6/6] nfsd: add notifier to handle mount/unmount of rpc_pipefs sb
  2012-03-06 15:28 [PATCH v9 0/6] nfsd: overhaul the client name tracking code Jeff Layton
                   ` (4 preceding siblings ...)
  2012-03-06 15:28 ` [PATCH v9 5/6] nfsd: add the infrastructure to handle the cld upcall Jeff Layton
@ 2012-03-06 15:28 ` Jeff Layton
  2012-03-11  7:45   ` Stanislav Kinsbursky
  5 siblings, 1 reply; 13+ messages in thread
From: Jeff Layton @ 2012-03-06 15:28 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, skinsbursky

In the event that rpc_pipefs isn't mounted when nfsd starts, we
must register a notifier to handle creating the dentry once it
is mounted, and to remove the dentry on unmount.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/nfsd/netns.h       |    1 +
 fs/nfsd/nfs4recover.c |   44 ++++++++++++++++++++++++++++++++++++++++++++
 fs/nfsd/nfsctl.c      |    9 ++++++++-
 3 files changed, 53 insertions(+), 1 deletions(-)

diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
index 12e0cff..66eac33 100644
--- a/fs/nfsd/netns.h
+++ b/fs/nfsd/netns.h
@@ -31,4 +31,5 @@ struct nfsd_net {
 };
 
 extern int nfsd_net_id;
+extern struct notifier_block nfsd4_cld_block;
 #endif /* __NFSD_NETNS_H__ */
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index bc4b189..d2f3680 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -38,6 +38,7 @@
 #include <linux/crypto.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
+#include <linux/module.h>
 #include <net/net_namespace.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
 #include <linux/sunrpc/clnt.h>
@@ -975,3 +976,46 @@ nfsd4_record_grace_done(struct net *net, time_t boot_time)
 	if (client_tracking_ops)
 		client_tracking_ops->grace_done(net, boot_time);
 }
+
+static int
+rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr)
+{
+	struct super_block *sb = ptr;
+	struct net *net = sb->s_fs_info;
+	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+	struct cld_net *cn = nn->cld_net;
+	struct dentry *dentry;
+	int ret = 0;
+
+	if (!try_module_get(THIS_MODULE))
+		return 0;
+
+	if (!cn) {
+		module_put(THIS_MODULE);
+		return 0;
+	}
+
+	switch (event) {
+	case RPC_PIPEFS_MOUNT:
+		dentry = nfsd4_cld_register_sb(sb, cn->cn_pipe);
+		if (IS_ERR(dentry)) {
+			ret = PTR_ERR(dentry);
+			break;
+		}
+		cn->cn_pipe->dentry = dentry;
+		break;
+	case RPC_PIPEFS_UMOUNT:
+		if (cn->cn_pipe->dentry)
+			nfsd4_cld_unregister_sb(cn->cn_pipe);
+		break;
+	default:
+		ret = -ENOTSUPP;
+		break;
+	}
+	module_put(THIS_MODULE);
+	return ret;
+}
+
+struct notifier_block nfsd4_cld_block = {
+	.notifier_call = rpc_pipefs_event,
+};
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 141197e..dee6c1b 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -13,6 +13,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/gss_api.h>
 #include <linux/sunrpc/gss_krb5_enctypes.h>
+#include <linux/sunrpc/rpc_pipe_fs.h>
 #include <linux/module.h>
 
 #include "idmap.h"
@@ -1136,9 +1137,12 @@ static int __init init_nfsd(void)
 	int retval;
 	printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
 
+	retval = rpc_pipefs_notifier_register(&nfsd4_cld_block);
+	if (retval)
+		return retval;
 	retval = register_pernet_subsys(&nfsd_net_ops);
 	if (retval < 0)
-		return retval;
+		goto out_unregister_notifier;
 	retval = nfsd4_init_slabs();
 	if (retval)
 		goto out_unregister_pernet;
@@ -1181,6 +1185,8 @@ out_free_slabs:
 	nfsd4_free_slabs();
 out_unregister_pernet:
 	unregister_pernet_subsys(&nfsd_net_ops);
+out_unregister_notifier:
+	rpc_pipefs_notifier_unregister(&nfsd4_cld_block);
 	return retval;
 }
 
@@ -1197,6 +1203,7 @@ static void __exit exit_nfsd(void)
 	nfsd_fault_inject_cleanup();
 	unregister_filesystem(&nfsd_fs_type);
 	unregister_pernet_subsys(&nfsd_net_ops);
+	rpc_pipefs_notifier_unregister(&nfsd4_cld_block);
 }
 
 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v9 3/6] nfsd: add a per-net-namespace struct for nfsd
  2012-03-06 15:28 ` [PATCH v9 3/6] nfsd: add a per-net-namespace struct for nfsd Jeff Layton
@ 2012-03-06 17:43   ` Stanislav Kinsbursky
  2012-03-06 18:31     ` Jeff Layton
  2012-03-11  7:44   ` Stanislav Kinsbursky
  1 sibling, 1 reply; 13+ messages in thread
From: Stanislav Kinsbursky @ 2012-03-06 17:43 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields@fieldses.org, linux-nfs@vger.kernel.org

06.03.2012 19:28, Jeff Layton пишет:
> diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
> index 64c24af..141197e 100644
> --- a/fs/nfsd/nfsctl.c
> +++ b/fs/nfsd/nfsctl.c
> @@ -19,6 +19,7 @@
>   #include "nfsd.h"
>   #include "cache.h"
>   #include "fault_inject.h"
> +#include "netns.h"
>
>   /*
>    *	We have a single directory with several nodes in it.
> @@ -1124,14 +1125,23 @@ static int create_proc_exports_entry(void)
>   }
>   #endif
>
> +int nfsd_net_id;
> +static struct pernet_operations nfsd_net_ops = {
> +	.id   =&nfsd_net_id,
> +	.size = sizeof(struct nfsd_net),
> +};
> +
>   static int __init init_nfsd(void)
>   {
>   	int retval;
>   	printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
>
> +	retval = register_pernet_subsys(&nfsd_net_ops);

Hi, Jeff.
You've created per-net structure and operations and that's cool.
But why don't you move nfsd client tracking control into per-net operations?
I.e. add init-exit callbacks in struct pernet_operations and call 
nfsd4_client_tracking_init() and nfsd4_client_tracking_exit() respectively in there?
And since we don't support any other networks namesapce except init_net, then 
just skip all others in these callbacks.


> +	if (retval<  0)
> +		return retval;
>   	retval = nfsd4_init_slabs();
>   	if (retval)
> -		return retval;
> +		goto out_unregister_pernet;
>   	nfs4_state_init();
>   	retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */
>   	if (retval)
> @@ -1169,6 +1179,8 @@ out_free_stat:
>   	nfsd_fault_inject_cleanup();
>   out_free_slabs:
>   	nfsd4_free_slabs();
> +out_unregister_pernet:
> +	unregister_pernet_subsys(&nfsd_net_ops);
>   	return retval;
>   }
>
> @@ -1184,6 +1196,7 @@ static void __exit exit_nfsd(void)
>   	nfsd4_free_slabs();
>   	nfsd_fault_inject_cleanup();
>   	unregister_filesystem(&nfsd_fs_type);
> +	unregister_pernet_subsys(&nfsd_net_ops);
>   }
>
>   MODULE_AUTHOR("Olaf Kirch<okir@monad.swb.de>");


-- 
Best regards,
Stanislav Kinsbursky

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v9 3/6] nfsd: add a per-net-namespace struct for nfsd
  2012-03-06 17:43   ` Stanislav Kinsbursky
@ 2012-03-06 18:31     ` Jeff Layton
  2012-03-06 20:48       ` Jeff Layton
  2012-03-07  8:46       ` Stanislav Kinsbursky
  0 siblings, 2 replies; 13+ messages in thread
From: Jeff Layton @ 2012-03-06 18:31 UTC (permalink / raw)
  To: Stanislav Kinsbursky; +Cc: bfields@fieldses.org, linux-nfs@vger.kernel.org

On Tue, 06 Mar 2012 21:43:41 +0400
Stanislav Kinsbursky <skinsbursky@parallels.com> wrote:

> 06.03.2012 19:28, Jeff Layton пишет:
> > diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
> > index 64c24af..141197e 100644
> > --- a/fs/nfsd/nfsctl.c
> > +++ b/fs/nfsd/nfsctl.c
> > @@ -19,6 +19,7 @@
> >   #include "nfsd.h"
> >   #include "cache.h"
> >   #include "fault_inject.h"
> > +#include "netns.h"
> >
> >   /*
> >    *	We have a single directory with several nodes in it.
> > @@ -1124,14 +1125,23 @@ static int create_proc_exports_entry(void)
> >   }
> >   #endif
> >
> > +int nfsd_net_id;
> > +static struct pernet_operations nfsd_net_ops = {
> > +	.id   =&nfsd_net_id,
> > +	.size = sizeof(struct nfsd_net),
> > +};
> > +
> >   static int __init init_nfsd(void)
> >   {
> >   	int retval;
> >   	printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
> >
> > +	retval = register_pernet_subsys(&nfsd_net_ops);
> 
> Hi, Jeff.
> You've created per-net structure and operations and that's cool.
> But why don't you move nfsd client tracking control into per-net operations?
> I.e. add init-exit callbacks in struct pernet_operations and call 
> nfsd4_client_tracking_init() and nfsd4_client_tracking_exit() respectively in there?
> And since we don't support any other networks namesapce except init_net, then 
> just skip all others in these callbacks.
> 

Well...the way I had envisioned it is that you'd create a new net
namespace container and would then start up nfsd within that container.

Just because we're spawning a new namespace doesn't mean that we'll
necessarily want to serve nfs from it, right? If we do it this way,
then we don't end up allocating resources for containers that aren't
going to use it.

...or do I not understand the "vision" of how all of this is going to
eventually work?

-- 
Jeff Layton <jlayton@redhat.com>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v9 3/6] nfsd: add a per-net-namespace struct for nfsd
  2012-03-06 18:31     ` Jeff Layton
@ 2012-03-06 20:48       ` Jeff Layton
  2012-03-07  8:46       ` Stanislav Kinsbursky
  1 sibling, 0 replies; 13+ messages in thread
From: Jeff Layton @ 2012-03-06 20:48 UTC (permalink / raw)
  To: Stanislav Kinsbursky; +Cc: bfields@fieldses.org, linux-nfs@vger.kernel.org

On Tue, 6 Mar 2012 13:31:24 -0500
Jeff Layton <jlayton@redhat.com> wrote:

> On Tue, 06 Mar 2012 21:43:41 +0400
> Stanislav Kinsbursky <skinsbursky@parallels.com> wrote:
> 
> > 06.03.2012 19:28, Jeff Layton пишет:
> > > diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
> > > index 64c24af..141197e 100644
> > > --- a/fs/nfsd/nfsctl.c
> > > +++ b/fs/nfsd/nfsctl.c
> > > @@ -19,6 +19,7 @@
> > >   #include "nfsd.h"
> > >   #include "cache.h"
> > >   #include "fault_inject.h"
> > > +#include "netns.h"
> > >
> > >   /*
> > >    *	We have a single directory with several nodes in it.
> > > @@ -1124,14 +1125,23 @@ static int create_proc_exports_entry(void)
> > >   }
> > >   #endif
> > >
> > > +int nfsd_net_id;
> > > +static struct pernet_operations nfsd_net_ops = {
> > > +	.id   =&nfsd_net_id,
> > > +	.size = sizeof(struct nfsd_net),
> > > +};
> > > +
> > >   static int __init init_nfsd(void)
> > >   {
> > >   	int retval;
> > >   	printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
> > >
> > > +	retval = register_pernet_subsys(&nfsd_net_ops);
> > 
> > Hi, Jeff.
> > You've created per-net structure and operations and that's cool.
> > But why don't you move nfsd client tracking control into per-net operations?
> > I.e. add init-exit callbacks in struct pernet_operations and call 
> > nfsd4_client_tracking_init() and nfsd4_client_tracking_exit() respectively in there?
> > And since we don't support any other networks namesapce except init_net, then 
> > just skip all others in these callbacks.
> > 
> 
> Well...the way I had envisioned it is that you'd create a new net
> namespace container and would then start up nfsd within that container.
> 
> Just because we're spawning a new namespace doesn't mean that we'll
> necessarily want to serve nfs from it, right? If we do it this way,
> then we don't end up allocating resources for containers that aren't
> going to use it.
> 
> ...or do I not understand the "vision" of how all of this is going to
> eventually work?
> 

To carry this thought a little further...

The pernet operations get registered whenever the module is plugged in.
The reason for doing it the way I did it here is that we don't need or
really want to do the client_tracking_init until we start up nfsd.

This is particularly the case with the legacy client tracker, which
slurps in the contents of v4recoverydir when it initializes. We don't
really want to do that at module plugin, I don't think.

-- 
Jeff Layton <jlayton@redhat.com>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v9 3/6] nfsd: add a per-net-namespace struct for nfsd
  2012-03-06 18:31     ` Jeff Layton
  2012-03-06 20:48       ` Jeff Layton
@ 2012-03-07  8:46       ` Stanislav Kinsbursky
  1 sibling, 0 replies; 13+ messages in thread
From: Stanislav Kinsbursky @ 2012-03-07  8:46 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields@fieldses.org, linux-nfs@vger.kernel.org

06.03.2012 22:31, Jeff Layton пишет:
> On Tue, 06 Mar 2012 21:43:41 +0400
> Stanislav Kinsbursky<skinsbursky@parallels.com>  wrote:
>
>> 06.03.2012 19:28, Jeff Layton пишет:
>>> diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
>>> index 64c24af..141197e 100644
>>> --- a/fs/nfsd/nfsctl.c
>>> +++ b/fs/nfsd/nfsctl.c
>>> @@ -19,6 +19,7 @@
>>>    #include "nfsd.h"
>>>    #include "cache.h"
>>>    #include "fault_inject.h"
>>> +#include "netns.h"
>>>
>>>    /*
>>>     *	We have a single directory with several nodes in it.
>>> @@ -1124,14 +1125,23 @@ static int create_proc_exports_entry(void)
>>>    }
>>>    #endif
>>>
>>> +int nfsd_net_id;
>>> +static struct pernet_operations nfsd_net_ops = {
>>> +	.id   =&nfsd_net_id,
>>> +	.size = sizeof(struct nfsd_net),
>>> +};
>>> +
>>>    static int __init init_nfsd(void)
>>>    {
>>>    	int retval;
>>>    	printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
>>>
>>> +	retval = register_pernet_subsys(&nfsd_net_ops);
>>
>> Hi, Jeff.
>> You've created per-net structure and operations and that's cool.
>> But why don't you move nfsd client tracking control into per-net operations?
>> I.e. add init-exit callbacks in struct pernet_operations and call
>> nfsd4_client_tracking_init() and nfsd4_client_tracking_exit() respectively in there?
>> And since we don't support any other networks namesapce except init_net, then
>> just skip all others in these callbacks.
>>
>
> Well...the way I had envisioned it is that you'd create a new net
> namespace container and would then start up nfsd within that container.
>
> Just because we're spawning a new namespace doesn't mean that we'll
> necessarily want to serve nfs from it, right? If we do it this way,
> then we don't end up allocating resources for containers that aren't
> going to use it.
>
> ...or do I not understand the "vision" of how all of this is going to
> eventually work?
>

You, probably, right.
If this data is allocated and initialized on NFSd start, then per-net operations 
has nothing with it.



-- 
Best regards,
Stanislav Kinsbursky

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v9 3/6] nfsd: add a per-net-namespace struct for nfsd
  2012-03-06 15:28 ` [PATCH v9 3/6] nfsd: add a per-net-namespace struct for nfsd Jeff Layton
  2012-03-06 17:43   ` Stanislav Kinsbursky
@ 2012-03-11  7:44   ` Stanislav Kinsbursky
  1 sibling, 0 replies; 13+ messages in thread
From: Stanislav Kinsbursky @ 2012-03-11  7:44 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields@fieldses.org, linux-nfs@vger.kernel.org


Acked-by: Stanislav Kinsbursky <skinsbursky@parallels.com>

-- 
Best regards,
Stanislav Kinsbursky

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v9 6/6] nfsd: add notifier to handle mount/unmount of rpc_pipefs sb
  2012-03-06 15:28 ` [PATCH v9 6/6] nfsd: add notifier to handle mount/unmount of rpc_pipefs sb Jeff Layton
@ 2012-03-11  7:45   ` Stanislav Kinsbursky
  0 siblings, 0 replies; 13+ messages in thread
From: Stanislav Kinsbursky @ 2012-03-11  7:45 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields@fieldses.org, linux-nfs@vger.kernel.org


Acked-by: Stanislav Kinsbursky <skinsbursky@parallels.com>

-- 
Best regards,
Stanislav Kinsbursky

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2012-03-11  7:46 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-03-06 15:28 [PATCH v9 0/6] nfsd: overhaul the client name tracking code Jeff Layton
2012-03-06 15:28 ` [PATCH v9 1/6] nfsd: add nfsd4_client_tracking_ops struct and a way to set it Jeff Layton
2012-03-06 15:28 ` [PATCH v9 2/6] sunrpc: create nfsd dir in rpc_pipefs Jeff Layton
2012-03-06 15:28 ` [PATCH v9 3/6] nfsd: add a per-net-namespace struct for nfsd Jeff Layton
2012-03-06 17:43   ` Stanislav Kinsbursky
2012-03-06 18:31     ` Jeff Layton
2012-03-06 20:48       ` Jeff Layton
2012-03-07  8:46       ` Stanislav Kinsbursky
2012-03-11  7:44   ` Stanislav Kinsbursky
2012-03-06 15:28 ` [PATCH v9 4/6] nfsd: add a header describing upcall to nfsdcld Jeff Layton
2012-03-06 15:28 ` [PATCH v9 5/6] nfsd: add the infrastructure to handle the cld upcall Jeff Layton
2012-03-06 15:28 ` [PATCH v9 6/6] nfsd: add notifier to handle mount/unmount of rpc_pipefs sb Jeff Layton
2012-03-11  7:45   ` Stanislav Kinsbursky

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).