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

[PATCH] A basic NFSv4 client for 2.5.x

Further cleanups

Separate the static and dynamic filesystem data retrieval calls as per the
NFSv3 spec. This also simplifies things for NFSv4, since many of the
attributes in the fsinfo+fstat combined call are not mandatory to
implement.
parent e078deae
...@@ -240,7 +240,13 @@ int nfs_sb_init(struct super_block *sb) ...@@ -240,7 +240,13 @@ int nfs_sb_init(struct super_block *sb)
{ {
struct nfs_server *server; struct nfs_server *server;
struct inode *root_inode = NULL; struct inode *root_inode = NULL;
struct nfs_fsinfo fsinfo; struct nfs_fattr fattr;
struct nfs_fsinfo fsinfo = {
.fattr = &fattr,
};
struct nfs_pathconf pathinfo = {
.fattr = &fattr,
};
/* We probably want something more informative here */ /* 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)); snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
...@@ -265,31 +271,27 @@ int nfs_sb_init(struct super_block *sb) ...@@ -265,31 +271,27 @@ int nfs_sb_init(struct super_block *sb)
sb->s_root->d_op = &nfs_dentry_operations; sb->s_root->d_op = &nfs_dentry_operations;
/* Get some general file system info */ /* Get some general file system info */
if (server->rpc_ops->statfs(server, &server->fh, &fsinfo) >= 0) { if (server->rpc_ops->fsinfo(server, &server->fh, &fsinfo) < 0) {
if (server->namelen == 0)
server->namelen = fsinfo.namelen;
} else {
printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n"); printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n");
goto out_no_root; goto out_no_root;
} }
if (server->namelen == 0 &&
server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
server->namelen = pathinfo.max_namelen;
/* Work out a lot of parameters */ /* Work out a lot of parameters */
if (server->rsize == 0) if (server->rsize == 0)
server->rsize = nfs_block_size(fsinfo.rtpref, NULL); server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
if (server->wsize == 0) if (server->wsize == 0)
server->wsize = nfs_block_size(fsinfo.wtpref, NULL); server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
/* NFSv3: we don't have bsize, but rather rtmult and wtmult... */ if (sb->s_blocksize == 0) {
if (!fsinfo.bsize) if (fsinfo.wtmult == 0) {
fsinfo.bsize = (fsinfo.rtmult>fsinfo.wtmult) ? fsinfo.rtmult : fsinfo.wtmult; sb->s_blocksize = 512;
/* Also make sure we don't go below rsize/wsize since sb->s_blocksize_bits = 9;
* RPC calls are expensive */ } else
if (fsinfo.bsize < server->rsize) sb->s_blocksize = nfs_block_bits(fsinfo.wtmult,
fsinfo.bsize = server->rsize; &sb->s_blocksize_bits);
if (fsinfo.bsize < server->wsize) }
fsinfo.bsize = server->wsize;
if (sb->s_blocksize == 0)
sb->s_blocksize = nfs_block_bits(fsinfo.bsize, &sb->s_blocksize_bits);
if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax) if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax)
server->rsize = nfs_block_size(fsinfo.rtmax, NULL); server->rsize = nfs_block_size(fsinfo.rtmax, NULL);
if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax) if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax)
...@@ -472,29 +474,30 @@ nfs_statfs(struct super_block *sb, struct statfs *buf) ...@@ -472,29 +474,30 @@ nfs_statfs(struct super_block *sb, struct statfs *buf)
struct nfs_server *server = NFS_SB(sb); struct nfs_server *server = NFS_SB(sb);
unsigned char blockbits; unsigned char blockbits;
unsigned long blockres; unsigned long blockres;
struct nfs_fsinfo res; struct nfs_fh *rootfh = NFS_FH(sb->s_root->d_inode);
struct nfs_fattr fattr;
struct nfs_fsstat res = {
.fattr = &fattr,
};
int error; int error;
lock_kernel(); lock_kernel();
error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root->d_inode), &res); error = server->rpc_ops->statfs(server, rootfh, &res);
buf->f_type = NFS_SUPER_MAGIC; buf->f_type = NFS_SUPER_MAGIC;
if (error < 0) if (error < 0)
goto out_err; goto out_err;
if (res.bsize == 0) buf->f_bsize = sb->s_blocksize;
res.bsize = sb->s_blocksize; blockbits = sb->s_blocksize_bits;
buf->f_bsize = nfs_block_bits(res.bsize, &blockbits);
blockres = (1 << blockbits) - 1; blockres = (1 << blockbits) - 1;
buf->f_blocks = (res.tbytes + blockres) >> blockbits; buf->f_blocks = (res.tbytes + blockres) >> blockbits;
buf->f_bfree = (res.fbytes + blockres) >> blockbits; buf->f_bfree = (res.fbytes + blockres) >> blockbits;
buf->f_bavail = (res.abytes + blockres) >> blockbits; buf->f_bavail = (res.abytes + blockres) >> blockbits;
buf->f_files = res.tfiles; buf->f_files = res.tfiles;
buf->f_ffree = res.afiles; buf->f_ffree = res.afiles;
if (res.namelen == 0 || res.namelen > server->namelen)
res.namelen = server->namelen;
buf->f_namelen = res.namelen;
buf->f_namelen = server->namelen;
out: out:
unlock_kernel(); unlock_kernel();
......
...@@ -596,37 +596,18 @@ nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res) ...@@ -596,37 +596,18 @@ nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
* Decode STATFS reply * Decode STATFS reply
*/ */
static int static int
nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res) nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs2_fsstat *res)
{ {
int status; int status;
u32 xfer_size;
if ((status = ntohl(*p++))) if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
/* For NFSv2, we more or less have to guess the preferred res->tsize = ntohl(*p++);
* read/write/readdir sizes from the single 'transfer size'
* value.
*/
xfer_size = ntohl(*p++); /* tsize */
res->rtmax = 8 * 1024;
res->rtpref = xfer_size;
res->rtmult = xfer_size;
res->wtmax = 8 * 1024;
res->wtpref = xfer_size;
res->wtmult = xfer_size;
res->dtpref = PAGE_CACHE_SIZE;
res->maxfilesize = 0x7FFFFFFF; /* just a guess */
res->bsize = ntohl(*p++); res->bsize = ntohl(*p++);
res->blocks = ntohl(*p++);
res->tbytes = ntohl(*p++) * res->bsize; res->bfree = ntohl(*p++);
res->fbytes = ntohl(*p++) * res->bsize; res->bavail = ntohl(*p++);
res->abytes = ntohl(*p++) * res->bsize;
res->tfiles = 0;
res->ffiles = 0;
res->afiles = 0;
res->namelen = 0;
return 0; return 0;
} }
......
...@@ -639,24 +639,42 @@ nfs3_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr, ...@@ -639,24 +639,42 @@ nfs3_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
return status; return status;
} }
/*
* This is a combo call of fsstat and fsinfo
*/
static int static int
nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info) struct nfs_fsstat *stat)
{ {
int status; int status;
dprintk("NFS call fsstat\n"); dprintk("NFS call fsstat\n");
memset((char *)info, 0, sizeof(*info)); stat->fattr->valid = 0;
status = rpc_call(server->client, NFS3PROC_FSSTAT, fhandle, info, 0); status = rpc_call(server->client, NFS3PROC_FSSTAT, fhandle, stat, 0);
if (status < 0) dprintk("NFS reply statfs: %d\n", status);
goto error; return status;
}
static int
nfs3_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info)
{
int status;
dprintk("NFS call fsinfo\n");
info->fattr->valid = 0;
status = rpc_call(server->client, NFS3PROC_FSINFO, fhandle, info, 0); status = rpc_call(server->client, NFS3PROC_FSINFO, fhandle, info, 0);
dprintk("NFS reply fsinfo: %d\n", status);
return status;
}
error: static int
dprintk("NFS reply statfs: %d\n", status); nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_pathconf *info)
{
int status;
dprintk("NFS call pathconf\n");
info->fattr->valid = 0;
status = rpc_call(server->client, NFS3PROC_PATHCONF, fhandle, info, 0);
dprintk("NFS reply pathconf: %d\n", status);
return status; return status;
} }
...@@ -824,6 +842,8 @@ struct nfs_rpc_ops nfs_v3_clientops = { ...@@ -824,6 +842,8 @@ struct nfs_rpc_ops nfs_v3_clientops = {
.readdir = nfs3_proc_readdir, .readdir = nfs3_proc_readdir,
.mknod = nfs3_proc_mknod, .mknod = nfs3_proc_mknod,
.statfs = nfs3_proc_statfs, .statfs = nfs3_proc_statfs,
.fsinfo = nfs3_proc_fsinfo,
.pathconf = nfs3_proc_pathconf,
.decode_dirent = nfs3_decode_dirent, .decode_dirent = nfs3_decode_dirent,
.read_setup = nfs3_proc_read_setup, .read_setup = nfs3_proc_read_setup,
.write_setup = nfs3_proc_write_setup, .write_setup = nfs3_proc_write_setup,
......
...@@ -912,14 +912,13 @@ nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res) ...@@ -912,14 +912,13 @@ nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
* Decode FSSTAT reply * Decode FSSTAT reply
*/ */
static int static int
nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res) nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsstat *res)
{ {
struct nfs_fattr dummy;
int status; int status;
status = ntohl(*p++); status = ntohl(*p++);
p = xdr_decode_post_op_attr(p, &dummy); p = xdr_decode_post_op_attr(p, res->fattr);
if (status != 0) if (status != 0)
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
...@@ -940,12 +939,11 @@ nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res) ...@@ -940,12 +939,11 @@ nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
static int static int
nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res) nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
{ {
struct nfs_fattr dummy;
int status; int status;
status = ntohl(*p++); status = ntohl(*p++);
p = xdr_decode_post_op_attr(p, &dummy); p = xdr_decode_post_op_attr(p, res->fattr);
if (status != 0) if (status != 0)
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
...@@ -959,6 +957,7 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res) ...@@ -959,6 +957,7 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
p = xdr_decode_hyper(p, &res->maxfilesize); p = xdr_decode_hyper(p, &res->maxfilesize);
/* ignore time_delta and properties */ /* ignore time_delta and properties */
res->lease_time = 0;
return 0; return 0;
} }
...@@ -966,18 +965,17 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res) ...@@ -966,18 +965,17 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
* Decode PATHCONF reply * Decode PATHCONF reply
*/ */
static int static int
nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res) nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_pathconf *res)
{ {
struct nfs_fattr dummy;
int status; int status;
status = ntohl(*p++); status = ntohl(*p++);
p = xdr_decode_post_op_attr(p, &dummy); p = xdr_decode_post_op_attr(p, res->fattr);
if (status != 0) if (status != 0)
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
res->linkmax = ntohl(*p++); res->max_link = ntohl(*p++);
res->namelen = ntohl(*p++); res->max_namelen = ntohl(*p++);
/* ignore remaining fields */ /* ignore remaining fields */
return 0; return 0;
......
...@@ -460,17 +460,62 @@ nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, ...@@ -460,17 +460,62 @@ nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
static int static int
nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info) struct nfs_fsstat *stat)
{ {
struct nfs2_fsstat fsinfo;
int status; int status;
dprintk("NFS call statfs\n"); dprintk("NFS call statfs\n");
memset((char *)info, 0, sizeof(*info)); stat->fattr->valid = 0;
status = rpc_call(server->client, NFSPROC_STATFS, fhandle, info, 0); status = rpc_call(server->client, NFSPROC_STATFS, fhandle, &fsinfo, 0);
dprintk("NFS reply statfs: %d\n", status); dprintk("NFS reply statfs: %d\n", status);
if (status)
goto out;
stat->tbytes = (u64)fsinfo.blocks * fsinfo.bsize;
stat->fbytes = (u64)fsinfo.bfree * fsinfo.bsize;
stat->abytes = (u64)fsinfo.bavail * fsinfo.bsize;
stat->tfiles = 0;
stat->ffiles = 0;
stat->afiles = 0;
out:
return status;
}
static int
nfs_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info)
{
struct nfs2_fsstat fsinfo;
int status;
dprintk("NFS call fsinfo\n");
info->fattr->valid = 0;
status = rpc_call(server->client, NFSPROC_STATFS, fhandle, &info, 0);
dprintk("NFS reply fsinfo: %d\n", status);
if (status)
goto out;
info->rtmax = NFS_MAXDATA;
info->rtpref = fsinfo.tsize;
info->rtmult = fsinfo.bsize;
info->wtmax = NFS_MAXDATA;
info->wtpref = fsinfo.tsize;
info->wtmult = fsinfo.bsize;
info->dtpref = fsinfo.tsize;
info->maxfilesize = 0x7FFFFFFF;
info->lease_time = 0;
out:
return status; return status;
} }
static int
nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_pathconf *info)
{
info->max_link = 0;
info->max_namelen = NFS2_MAXNAMLEN;
return 0;
}
extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int); extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
static void static void
...@@ -590,6 +635,8 @@ struct nfs_rpc_ops nfs_v2_clientops = { ...@@ -590,6 +635,8 @@ struct nfs_rpc_ops nfs_v2_clientops = {
.readdir = nfs_proc_readdir, .readdir = nfs_proc_readdir,
.mknod = nfs_proc_mknod, .mknod = nfs_proc_mknod,
.statfs = nfs_proc_statfs, .statfs = nfs_proc_statfs,
.fsinfo = nfs_proc_fsinfo,
.pathconf = nfs_proc_pathconf,
.decode_dirent = nfs_decode_dirent, .decode_dirent = nfs_decode_dirent,
.read_setup = nfs_proc_read_setup, .read_setup = nfs_proc_read_setup,
.write_setup = nfs_proc_write_setup, .write_setup = nfs_proc_write_setup,
......
...@@ -50,6 +50,7 @@ struct nfs_fattr { ...@@ -50,6 +50,7 @@ struct nfs_fattr {
* Info on the file system * Info on the file system
*/ */
struct nfs_fsinfo { struct nfs_fsinfo {
struct nfs_fattr *fattr; /* Post-op attributes */
__u32 rtmax; /* max. read transfer size */ __u32 rtmax; /* max. read transfer size */
__u32 rtpref; /* pref. read transfer size */ __u32 rtpref; /* pref. read transfer size */
__u32 rtmult; /* reads should be multiple of this */ __u32 rtmult; /* reads should be multiple of this */
...@@ -58,16 +59,31 @@ struct nfs_fsinfo { ...@@ -58,16 +59,31 @@ struct nfs_fsinfo {
__u32 wtmult; /* writes should be multiple of this */ __u32 wtmult; /* writes should be multiple of this */
__u32 dtpref; /* pref. readdir transfer size */ __u32 dtpref; /* pref. readdir transfer size */
__u64 maxfilesize; __u64 maxfilesize;
__u64 bsize; /* block size */ __u32 lease_time; /* in seconds */
};
struct nfs_fsstat {
struct nfs_fattr *fattr; /* Post-op attributes */
__u64 tbytes; /* total size in bytes */ __u64 tbytes; /* total size in bytes */
__u64 fbytes; /* # of free bytes */ __u64 fbytes; /* # of free bytes */
__u64 abytes; /* # of bytes available to user */ __u64 abytes; /* # of bytes available to user */
__u64 tfiles; /* # of files */ __u64 tfiles; /* # of files */
__u64 ffiles; /* # of free files */ __u64 ffiles; /* # of free files */
__u64 afiles; /* # of files available to user */ __u64 afiles; /* # of files available to user */
__u32 linkmax;/* max # of hard links */ };
__u32 namelen;/* max name length */
__u32 lease_time; /* in seconds */ struct nfs2_fsstat {
__u32 tsize; /* Server transfer size */
__u32 bsize; /* Filesystem block size */
__u32 blocks; /* No. of "bsize" blocks on filesystem */
__u32 bfree; /* No. of free "bsize" blocks */
__u32 bavail; /* No. of available "bsize" blocks */
};
struct nfs_pathconf {
struct nfs_fattr *fattr; /* Post-op attributes */
__u32 max_link; /* max # of hard links */
__u32 max_namelen; /* max name length */
}; };
/* /*
...@@ -391,7 +407,11 @@ struct nfs_rpc_ops { ...@@ -391,7 +407,11 @@ struct nfs_rpc_ops {
int (*mknod) (struct inode *, struct qstr *, struct iattr *, int (*mknod) (struct inode *, struct qstr *, struct iattr *,
dev_t, struct nfs_fh *, struct nfs_fattr *); dev_t, struct nfs_fh *, struct nfs_fattr *);
int (*statfs) (struct nfs_server *, struct nfs_fh *, int (*statfs) (struct nfs_server *, struct nfs_fh *,
struct nfs_fsstat *);
int (*fsinfo) (struct nfs_server *, struct nfs_fh *,
struct nfs_fsinfo *); struct nfs_fsinfo *);
int (*pathconf) (struct nfs_server *, struct nfs_fh *,
struct nfs_pathconf *);
u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus); u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus);
void (*read_setup) (struct nfs_read_data *, unsigned int count); void (*read_setup) (struct nfs_read_data *, unsigned int count);
void (*write_setup) (struct nfs_write_data *, unsigned int count, int how); void (*write_setup) (struct nfs_write_data *, unsigned int count, int how);
......
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