Skip to content

Commit

Permalink
NFS: Add version registering framework
Browse files Browse the repository at this point in the history
This patch adds in the code to track multiple versions of the NFS
protocol.  I created default structures for v2, v3 and v4 so that each
version can continue to work while I convert them into kernel modules.
I also removed the const parameter from the rpc_version array so that I
can change it at runtime.

Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
Bryan Schumaker authored and Trond Myklebust committed Jul 30, 2012
1 parent a427b9e commit ab7017a
Show file tree
Hide file tree
Showing 12 changed files with 283 additions and 61 deletions.
4 changes: 2 additions & 2 deletions fs/nfs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ nfs-y := client.o dir.o file.o getroot.o inode.o super.o \
write.o namespace.o mount_clnt.o \
dns_resolve.o cache_lib.o
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o
nfs-$(CONFIG_NFS_V2) += proc.o nfs2xdr.o
nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
nfs-$(CONFIG_NFS_V2) += nfs2super.o proc.o nfs2xdr.o
nfs-$(CONFIG_NFS_V3) += nfs3super.o nfs3proc.o nfs3xdr.o
nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
nfs4super.o nfs4file.o delegation.o idmap.o \
Expand Down
147 changes: 112 additions & 35 deletions fs/nfs/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,25 +51,23 @@
#include "internal.h"
#include "fscache.h"
#include "pnfs.h"
#include "nfs.h"
#include "netns.h"

#define NFSDBG_FACILITY NFSDBG_CLIENT

static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
static DEFINE_SPINLOCK(nfs_version_lock);
static DEFINE_MUTEX(nfs_version_mutex);
static LIST_HEAD(nfs_versions);

/*
* RPC cruft for NFS
*/
static const struct rpc_version *nfs_version[5] = {
#ifdef CONFIG_NFS_V2
[2] = &nfs_version2,
#endif
#ifdef CONFIG_NFS_V3
[3] = &nfs_version3,
#endif
#ifdef CONFIG_NFS_V4
[4] = &nfs_version4,
#endif
[2] = NULL,
[3] = NULL,
[4] = NULL,
};

const struct rpc_program nfs_program = {
Expand Down Expand Up @@ -101,6 +99,93 @@ const struct rpc_program nfsacl_program = {
};
#endif /* CONFIG_NFS_V3_ACL */

static struct nfs_subversion *find_nfs_version(unsigned int version)
{
struct nfs_subversion *nfs;
spin_lock(&nfs_version_lock);

list_for_each_entry(nfs, &nfs_versions, list) {
if (nfs->rpc_ops->version == version) {
spin_unlock(&nfs_version_lock);
return nfs;
}
};

spin_unlock(&nfs_version_lock);
return ERR_PTR(-EPROTONOSUPPORT);;
}

struct nfs_subversion *get_nfs_version(unsigned int version)
{
struct nfs_subversion *nfs = find_nfs_version(version);

if (IS_ERR(nfs)) {
mutex_lock(&nfs_version_mutex);
request_module("nfs%d", version);
nfs = find_nfs_version(version);
mutex_unlock(&nfs_version_mutex);
}

if (!IS_ERR(nfs))
try_module_get(nfs->owner);
return nfs;
}

void put_nfs_version(struct nfs_subversion *nfs)
{
module_put(nfs->owner);
}

void register_nfs_version(struct nfs_subversion *nfs)
{
spin_lock(&nfs_version_lock);

list_add(&nfs->list, &nfs_versions);
nfs_version[nfs->rpc_ops->version] = nfs->rpc_vers;

spin_unlock(&nfs_version_lock);
}
EXPORT_SYMBOL_GPL(register_nfs_version);

void unregister_nfs_version(struct nfs_subversion *nfs)
{
spin_lock(&nfs_version_lock);

nfs_version[nfs->rpc_ops->version] = NULL;
list_del(&nfs->list);

spin_unlock(&nfs_version_lock);
}
EXPORT_SYMBOL_GPL(unregister_nfs_version);

/*
* Preload all configured NFS versions during module init.
* This function should be edited after each protocol is converted,
* and eventually removed.
*/
int __init nfs_register_versions(void)
{
int err = init_nfs_v2();
if (err)
return err;

err = init_nfs_v3();
if (err)
return err;

return init_nfs_v4();
}

/*
* Remove each pre-loaded NFS version
*/
void nfs_unregister_versions(void)
{
exit_nfs_v2();
exit_nfs_v3();
exit_nfs_v4();
}

/*
* Allocate a shared client record
*
Expand All @@ -116,7 +201,10 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL)
goto error_0;

clp->rpc_ops = cl_init->rpc_ops;
clp->cl_nfs_mod = cl_init->nfs_mod;
try_module_get(clp->cl_nfs_mod->owner);

clp->rpc_ops = clp->cl_nfs_mod->rpc_ops;

atomic_set(&clp->cl_count, 1);
clp->cl_cons_state = NFS_CS_INITING;
Expand Down Expand Up @@ -145,6 +233,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
return clp;

error_cleanup:
put_nfs_version(clp->cl_nfs_mod);
kfree(clp);
error_0:
return ERR_PTR(err);
Expand Down Expand Up @@ -205,6 +294,7 @@ void nfs_free_client(struct nfs_client *clp)
put_rpccred(clp->cl_machine_cred);

put_net(clp->cl_net);
put_nfs_version(clp->cl_nfs_mod);
kfree(clp->cl_hostname);
kfree(clp);

Expand Down Expand Up @@ -362,7 +452,7 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
continue;

/* Different NFS versions cannot share the same nfs_client */
if (clp->rpc_ops != data->rpc_ops)
if (clp->rpc_ops != data->nfs_mod->rpc_ops)
continue;

if (clp->cl_proto != data->proto)
Expand Down Expand Up @@ -431,9 +521,10 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
{
struct nfs_client *clp, *new = NULL;
struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id);
const struct nfs_rpc_ops *rpc_ops = cl_init->nfs_mod->rpc_ops;

dprintk("--> nfs_get_client(%s,v%u)\n",
cl_init->hostname ?: "", cl_init->rpc_ops->version);
cl_init->hostname ?: "", rpc_ops->version);

/* see if the client already exists */
do {
Expand All @@ -450,14 +541,13 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
list_add(&new->cl_share_link, &nn->nfs_client_list);
spin_unlock(&nn->nfs_client_lock);
new->cl_flags = cl_init->init_flags;
return cl_init->rpc_ops->init_client(new,
timeparms, ip_addr,
authflavour);
return rpc_ops->init_client(new, timeparms, ip_addr,
authflavour);
}

spin_unlock(&nn->nfs_client_lock);

new = cl_init->rpc_ops->alloc_client(cl_init);
new = rpc_ops->alloc_client(cl_init);
} while (!IS_ERR(new));

dprintk("<-- nfs_get_client() Failed to find %s (%ld)\n",
Expand Down Expand Up @@ -714,13 +804,14 @@ struct nfs_client *nfs_init_client(struct nfs_client *clp,
* Create a version 2 or 3 client
*/
static int nfs_init_server(struct nfs_server *server,
const struct nfs_parsed_mount_data *data)
const struct nfs_parsed_mount_data *data,
struct nfs_subversion *nfs_mod)
{
struct nfs_client_initdata cl_init = {
.hostname = data->nfs_server.hostname,
.addr = (const struct sockaddr *)&data->nfs_server.address,
.addrlen = data->nfs_server.addrlen,
.rpc_ops = NULL,
.nfs_mod = nfs_mod,
.proto = data->nfs_server.protocol,
.net = data->net,
};
Expand All @@ -730,21 +821,6 @@ static int nfs_init_server(struct nfs_server *server,

dprintk("--> nfs_init_server()\n");

switch (data->version) {
#ifdef CONFIG_NFS_V2
case 2:
cl_init.rpc_ops = &nfs_v2_clientops;
break;
#endif
#ifdef CONFIG_NFS_V3
case 3:
cl_init.rpc_ops = &nfs_v3_clientops;
break;
#endif
default:
return -EPROTONOSUPPORT;
}

nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
data->timeo, data->retrans);
if (data->flags & NFS_MOUNT_NORESVPORT)
Expand Down Expand Up @@ -1033,7 +1109,8 @@ void nfs_free_server(struct nfs_server *server)
* - keyed on server and FSID
*/
struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data,
struct nfs_fh *mntfh)
struct nfs_fh *mntfh,
struct nfs_subversion *nfs_mod)
{
struct nfs_server *server;
struct nfs_fattr *fattr;
Expand All @@ -1049,7 +1126,7 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data,
goto error;

/* Get a client representation */
error = nfs_init_server(server, data);
error = nfs_init_server(server, data, nfs_mod);
if (error < 0)
goto error;

Expand Down
9 changes: 3 additions & 6 deletions fs/nfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#include "fscache.h"
#include "dns_resolve.h"
#include "pnfs.h"
#include "nfs.h"
#include "netns.h"

#define NFSDBG_FACILITY NFSDBG_VFS
Expand Down Expand Up @@ -1671,21 +1672,17 @@ static int __init init_nfs_fs(void)
rpc_proc_register(&init_net, &nfs_rpcstat);
#endif

#ifdef CONFIG_NFS_V4
err = init_nfs_v4();
err = nfs_register_versions();
if (err)
goto out1;
#endif

if ((err = register_nfs_fs()) != 0)
goto out0;

return 0;
out0:
#ifdef CONFIG_NFS_V4
exit_nfs_v4();
nfs_unregister_versions();
out1:
#endif
#ifdef CONFIG_PROC_FS
rpc_proc_unregister(&init_net, "nfs");
#endif
Expand Down
10 changes: 6 additions & 4 deletions fs/nfs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ struct nfs_client_initdata {
const char *hostname;
const struct sockaddr *addr;
size_t addrlen;
const struct nfs_rpc_ops *rpc_ops;
struct nfs_subversion *nfs_mod;
int proto;
u32 minorversion;
struct net *net;
Expand Down Expand Up @@ -189,7 +189,8 @@ nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
struct nfs4_sessionid *);
extern struct nfs_server *nfs_create_server(
const struct nfs_parsed_mount_data *,
struct nfs_fh *);
struct nfs_fh *,
struct nfs_subversion *);
extern struct nfs_server *nfs4_create_server(
const struct nfs_parsed_mount_data *,
struct nfs_fh *);
Expand Down Expand Up @@ -321,6 +322,7 @@ void nfs_zap_acl_cache(struct inode *inode);
extern int nfs_wait_bit_killable(void *word);

/* super.c */
extern struct file_system_type nfs_fs_type;
extern struct file_system_type nfs_xdev_fs_type;
#ifdef CONFIG_NFS_V4
extern struct file_system_type nfs4_xdev_fs_type;
Expand All @@ -329,8 +331,8 @@ extern struct file_system_type nfs4_referral_fs_type;
void nfs_initialise_sb(struct super_block *);
int nfs_set_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *);
int nfs_clone_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *);
struct dentry *nfs_fs_mount_common(struct file_system_type *, struct nfs_server *,
int, const char *, struct nfs_mount_info *);
struct dentry *nfs_fs_mount_common(struct nfs_server *, int, const char *,
struct nfs_mount_info *, struct nfs_subversion *);
struct dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *);
struct dentry * nfs_xdev_mount_common(struct file_system_type *, int,
const char *, struct nfs_mount_info *);
Expand Down
Loading

0 comments on commit ab7017a

Please sign in to comment.