Commit e078deae authored by Trond Myklebust's avatar Trond Myklebust Committed by Linus Torvalds

[PATCH] A basic NFSv4 client for 2.5.x

Clean up nfs_fill_super().

Separate the parsing of the nfs_mount_data struct and the
initialization + sanity checking of the resulting super_block.
The latter is now performed in the new function nfs_sb_init().
parent 431121f4
......@@ -234,131 +234,28 @@ nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh)
}
/*
* The way this works is that the mount process passes a structure
* in the data argument which contains the server's IP address
* and the root file handle obtained from the server's mount
* daemon. We stash these away in the private superblock fields.
* Do NFS version-independent mount processing, and sanity checking
*/
int nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent)
int nfs_sb_init(struct super_block *sb)
{
struct nfs_server *server;
struct rpc_xprt *xprt = NULL;
struct rpc_clnt *clnt = NULL;
struct inode *root_inode = NULL;
rpc_authflavor_t authflavor;
struct rpc_timeout timeparms;
struct nfs_fsinfo fsinfo;
int tcp, version, maxlen;
/* We probably want something more informative here */
snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
server = NFS_SB(sb);
sb->s_magic = NFS_SUPER_MAGIC;
sb->s_op = &nfs_sops;
sb->s_blocksize_bits = 0;
sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
server = NFS_SB(sb);
server->rsize = nfs_block_size(data->rsize, NULL);
server->wsize = nfs_block_size(data->wsize, NULL);
server->flags = data->flags & NFS_MOUNT_FLAGMASK;
if (data->flags & NFS_MOUNT_NOAC) {
data->acregmin = data->acregmax = 0;
data->acdirmin = data->acdirmax = 0;
sb->s_flags |= MS_SYNCHRONOUS;
}
server->acregmin = data->acregmin*HZ;
server->acregmax = data->acregmax*HZ;
server->acdirmin = data->acdirmin*HZ;
server->acdirmax = data->acdirmax*HZ;
server->namelen = data->namlen;
server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
if (!server->hostname)
goto out_unlock;
strcpy(server->hostname, data->hostname);
INIT_LIST_HEAD(&server->lru_read);
INIT_LIST_HEAD(&server->lru_dirty);
INIT_LIST_HEAD(&server->lru_commit);
INIT_LIST_HEAD(&server->lru_busy);
nfsv3_try_again:
server->caps = 0;
/* Check NFS protocol revision and initialize RPC op vector
* and file handle pool. */
if (data->flags & NFS_MOUNT_VER3) {
#ifdef CONFIG_NFS_V3
server->rpc_ops = &nfs_v3_clientops;
version = 3;
server->caps |= NFS_CAP_READDIRPLUS;
if (data->version < 4) {
printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n");
goto out_unlock;
}
#else
printk(KERN_NOTICE "NFS: NFSv3 not supported.\n");
goto out_unlock;
#endif
} else {
server->rpc_ops = &nfs_v2_clientops;
version = 2;
}
/* Which protocol do we use? */
tcp = (data->flags & NFS_MOUNT_TCP);
/* Initialize timeout values */
timeparms.to_initval = data->timeo * HZ / 10;
timeparms.to_retries = data->retrans;
timeparms.to_maxval = tcp? RPC_MAX_TCP_TIMEOUT : RPC_MAX_UDP_TIMEOUT;
timeparms.to_exponential = 1;
if (!timeparms.to_initval)
timeparms.to_initval = (tcp ? 600 : 11) * HZ / 10;
if (!timeparms.to_retries)
timeparms.to_retries = 5;
/* Now create transport and client */
xprt = xprt_create_proto(tcp? IPPROTO_TCP : IPPROTO_UDP,
&server->addr, &timeparms);
if (xprt == NULL)
goto out_no_xprt;
/* Choose authentication flavor */
authflavor = RPC_AUTH_UNIX;
if (data->flags & NFS_MOUNT_SECURE)
authflavor = RPC_AUTH_DES;
else if (data->flags & NFS_MOUNT_KERBEROS)
authflavor = RPC_AUTH_KRB;
clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
version, authflavor);
if (clnt == NULL)
goto out_no_client;
clnt->cl_intr = (data->flags & NFS_MOUNT_INTR)? 1 : 0;
clnt->cl_softrtry = (data->flags & NFS_MOUNT_SOFT)? 1 : 0;
clnt->cl_droppriv = (data->flags & NFS_MOUNT_BROKEN_SUID) ? 1 : 0;
clnt->cl_chatty = 1;
server->client = clnt;
/* Fire up rpciod if not yet running */
if (rpciod_up() != 0)
goto out_no_iod;
/*
* Keep the super block locked while we try to get
* the root fh attributes.
*/
/* Did getting the root inode fail? */
if (!(root_inode = nfs_get_root(sb, &server->fh))
&& (data->flags & NFS_MOUNT_VER3)) {
data->flags &= ~NFS_MOUNT_VER3;
rpciod_down();
rpc_shutdown_client(server->client);
goto nfsv3_try_again;
}
root_inode = nfs_get_root(sb, &server->fh);
if (!root_inode)
goto out_no_root;
sb->s_root = d_alloc_root(root_inode);
......@@ -377,9 +274,9 @@ int nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int sile
}
/* Work out a lot of parameters */
if (data->rsize == 0)
if (server->rsize == 0)
server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
if (data->wsize == 0)
if (server->wsize == 0)
server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
/* NFSv3: we don't have bsize, but rather rtmult and wtmult... */
if (!fsinfo.bsize)
......@@ -391,12 +288,12 @@ int nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int sile
if (fsinfo.bsize < server->wsize)
fsinfo.bsize = server->wsize;
if (data->bsize == 0)
if (sb->s_blocksize == 0)
sb->s_blocksize = nfs_block_bits(fsinfo.bsize, &sb->s_blocksize_bits);
if (server->rsize > fsinfo.rtmax)
server->rsize = fsinfo.rtmax;
if (server->wsize > fsinfo.wtmax)
server->wsize = fsinfo.wtmax;
if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax)
server->rsize = nfs_block_size(fsinfo.rtmax, NULL);
if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax)
server->wsize = nfs_block_size(fsinfo.wtmax, NULL);
server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
if (server->rpages > NFS_READ_MAXIOV) {
......@@ -416,10 +313,11 @@ int nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int sile
if (server->dtsize > server->rsize)
server->dtsize = server->rsize;
maxlen = (version == 2) ? NFS2_MAXNAMLEN : NFS3_MAXNAMLEN;
if (server->namelen == 0 || server->namelen > maxlen)
server->namelen = maxlen;
if (server->flags & NFS_MOUNT_NOAC) {
server->acregmin = server->acregmax = 0;
server->acdirmin = server->acdirmax = 0;
sb->s_flags |= MS_SYNCHRONOUS;
}
sb->s_maxbytes = fsinfo.maxfilesize;
if (sb->s_maxbytes > MAX_LFS_FILESIZE)
......@@ -432,44 +330,140 @@ int nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int sile
}
/* We're airborne Set socket buffersize */
rpc_setbufsize(clnt, server->wsize + 100, server->rsize + 100);
/* Check whether to start the lockd process */
if (!(server->flags & NFS_MOUNT_NONLM))
lockd_up();
rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
return 0;
/* Yargs. It didn't work out. */
failure_kill_reqlist:
failure_kill_reqlist:
nfs_reqlist_exit(server);
out_free_all:
if (root_inode)
iput(root_inode);
nfs_reqlist_free(server);
return -EINVAL;
out_no_root:
printk("nfs_read_super: get root inode failed\n");
iput(root_inode);
rpciod_down();
goto out_shutdown;
goto out_free_all;
}
out_no_iod:
printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
out_shutdown:
rpc_shutdown_client(server->client);
goto out_free_host;
/*
* The way this works is that the mount process passes a structure
* in the data argument which contains the server's IP address
* and the root file handle obtained from the server's mount
* daemon. We stash these away in the private superblock fields.
*/
int nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent)
{
struct nfs_server *server;
struct rpc_xprt *xprt = NULL;
struct rpc_clnt *clnt = NULL;
struct rpc_timeout timeparms;
int tcp, err = -EIO;
out_no_client:
printk(KERN_WARNING "NFS: cannot create RPC client.\n");
xprt_destroy(xprt);
goto out_free_host;
server = NFS_SB(sb);
sb->s_blocksize_bits = 0;
sb->s_blocksize = 0;
if (data->bsize)
sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
if (data->rsize)
server->rsize = nfs_block_size(data->rsize, NULL);
if (data->wsize)
server->wsize = nfs_block_size(data->wsize, NULL);
server->flags = data->flags & NFS_MOUNT_FLAGMASK;
out_no_xprt:
printk(KERN_WARNING "NFS: cannot create RPC transport.\n");
server->acregmin = data->acregmin*HZ;
server->acregmax = data->acregmax*HZ;
server->acdirmin = data->acdirmin*HZ;
server->acdirmax = data->acdirmax*HZ;
out_free_host:
nfs_reqlist_free(server);
kfree(server->hostname);
out_unlock:
goto out_fail;
server->namelen = data->namlen;
server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
if (!server->hostname)
goto out_fail;
strcpy(server->hostname, data->hostname);
/* Check NFS protocol revision and initialize RPC op vector
* and file handle pool. */
if (server->flags & NFS_MOUNT_VER3) {
#ifdef CONFIG_NFS_V3
server->rpc_ops = &nfs_v3_clientops;
server->caps |= NFS_CAP_READDIRPLUS;
if (data->version < 4) {
printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n");
goto out_fail;
}
#else
printk(KERN_NOTICE "NFS: NFSv3 not supported.\n");
goto out_fail;
#endif
} else {
server->rpc_ops = &nfs_v2_clientops;
}
/* Which protocol do we use? */
tcp = (data->flags & NFS_MOUNT_TCP);
/* Initialize timeout values */
timeparms.to_initval = data->timeo * HZ / 10;
timeparms.to_retries = data->retrans;
timeparms.to_maxval = tcp? RPC_MAX_TCP_TIMEOUT : RPC_MAX_UDP_TIMEOUT;
timeparms.to_exponential = 1;
if (!timeparms.to_initval)
timeparms.to_initval = (tcp ? 600 : 11) * HZ / 10;
if (!timeparms.to_retries)
timeparms.to_retries = 5;
/* Now create transport and client */
xprt = xprt_create_proto(tcp? IPPROTO_TCP : IPPROTO_UDP,
&server->addr, &timeparms);
if (xprt == NULL) {
printk(KERN_WARNING "NFS: cannot create RPC transport.\n");
goto out_fail;
}
clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
server->rpc_ops->version, RPC_AUTH_UNIX);
if (clnt == NULL) {
printk(KERN_WARNING "NFS: cannot create RPC client.\n");
xprt_destroy(xprt);
goto out_fail;
}
clnt->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0;
clnt->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0;
clnt->cl_droppriv = (server->flags & NFS_MOUNT_BROKEN_SUID) ? 1 : 0;
clnt->cl_chatty = 1;
server->client = clnt;
/* Fire up rpciod if not yet running */
if (rpciod_up() != 0) {
printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
goto out_shutdown;
}
err = nfs_sb_init(sb);
if (err != 0)
goto out_noinit;
if (server->flags & NFS_MOUNT_VER3) {
if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
server->namelen = NFS3_MAXNAMLEN;
} else {
if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
server->namelen = NFS2_MAXNAMLEN;
}
/* Check whether to start the lockd process */
if (!(server->flags & NFS_MOUNT_NONLM))
lockd_up();
return 0;
out_noinit:
rpciod_down();
out_shutdown:
rpc_shutdown_client(server->client);
out_fail:
return -EINVAL;
if (server->hostname)
kfree(server->hostname);
return err;
}
static int
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment