]> git.hungrycats.org Git - linux/commitdiff
[PATCH] A basic NFSv4 client for 2.5.x
authorTrond Myklebust <trond.myklebust@fys.uio.no>
Tue, 15 Oct 2002 12:30:42 +0000 (05:30 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Tue, 15 Oct 2002 12:30:42 +0000 (05:30 -0700)
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.

fs/nfs/inode.c
fs/nfs/nfs2xdr.c
fs/nfs/nfs3proc.c
fs/nfs/nfs3xdr.c
fs/nfs/proc.c
include/linux/nfs_xdr.h

index f6cfe092fb132755d07dffa3af0ff6feef195f1a..940173f909b85ad3d653f45f2a9fbb0abddffb53 100644 (file)
@@ -240,7 +240,13 @@ int nfs_sb_init(struct super_block *sb)
 {
        struct nfs_server       *server;
        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 */
        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)
        sb->s_root->d_op = &nfs_dentry_operations;
 
        /* Get some general file system info */
-        if (server->rpc_ops->statfs(server, &server->fh, &fsinfo) >= 0) {
-               if (server->namelen == 0)
-                       server->namelen = fsinfo.namelen;
-       } else {
+        if (server->rpc_ops->fsinfo(server, &server->fh, &fsinfo) < 0) {
                printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n");
                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 */
        if (server->rsize == 0)
                server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
        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)
-               fsinfo.bsize = (fsinfo.rtmult>fsinfo.wtmult) ? fsinfo.rtmult : fsinfo.wtmult;
-       /* Also make sure we don't go below rsize/wsize since
-        * RPC calls are expensive */
-       if (fsinfo.bsize < server->rsize)
-               fsinfo.bsize = server->rsize;
-       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 (sb->s_blocksize == 0) {
+               if (fsinfo.wtmult == 0) {
+                       sb->s_blocksize = 512;
+                       sb->s_blocksize_bits = 9;
+               } else
+                       sb->s_blocksize = nfs_block_bits(fsinfo.wtmult,
+                                                        &sb->s_blocksize_bits);
+       }
+
        if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax)
                server->rsize = nfs_block_size(fsinfo.rtmax, NULL);
        if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax)
@@ -472,29 +474,30 @@ nfs_statfs(struct super_block *sb, struct statfs *buf)
        struct nfs_server *server = NFS_SB(sb);
        unsigned char blockbits;
        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;
 
        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;
        if (error < 0)
                goto out_err;
 
-       if (res.bsize == 0)
-               res.bsize = sb->s_blocksize;
-       buf->f_bsize = nfs_block_bits(res.bsize, &blockbits);
+       buf->f_bsize = sb->s_blocksize;
+       blockbits = sb->s_blocksize_bits;
        blockres = (1 << blockbits) - 1;
        buf->f_blocks = (res.tbytes + blockres) >> blockbits;
        buf->f_bfree = (res.fbytes + blockres) >> blockbits;
        buf->f_bavail = (res.abytes + blockres) >> blockbits;
        buf->f_files = res.tfiles;
        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:
        unlock_kernel();
 
index 8dc92b8b3a1caa7d3e7d131374ea6769a1e95eda..8e652afdfea481705a81b1b78f75fd247e89330c 100644 (file)
@@ -596,37 +596,18 @@ nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
  * Decode STATFS reply
  */
 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;
-       u32     xfer_size;
 
        if ((status = ntohl(*p++)))
                return -nfs_stat_to_errno(status);
 
-       /* For NFSv2, we more or less have to guess the preferred
-        * 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->tsize  = ntohl(*p++);
        res->bsize  = ntohl(*p++);
-
-       res->tbytes = ntohl(*p++) * res->bsize;
-       res->fbytes = ntohl(*p++) * res->bsize;
-       res->abytes = ntohl(*p++) * res->bsize;
-       res->tfiles = 0;
-       res->ffiles = 0;
-       res->afiles = 0;
-       res->namelen = 0;
-
+       res->blocks = ntohl(*p++);
+       res->bfree  = ntohl(*p++);
+       res->bavail = ntohl(*p++);
        return 0;
 }
 
index 1ddb51374cbac0cc188d831ff3a4419fc5ac0067..790c27ead44f79f99a457601708cc883a4609bda 100644 (file)
@@ -639,24 +639,42 @@ nfs3_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
        return status;
 }
 
-/*
- * This is a combo call of fsstat and fsinfo
- */
 static int
 nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
-                struct nfs_fsinfo *info)
+                struct nfs_fsstat *stat)
 {
        int     status;
 
        dprintk("NFS call  fsstat\n");
-       memset((char *)info, 0, sizeof(*info));
-       status = rpc_call(server->client, NFS3PROC_FSSTAT, fhandle, info, 0);
-       if (status < 0)
-               goto error;
+       stat->fattr->valid = 0;
+       status = rpc_call(server->client, NFS3PROC_FSSTAT, fhandle, stat, 0);
+       dprintk("NFS reply statfs: %d\n", status);
+       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);
+       dprintk("NFS reply fsinfo: %d\n", status);
+       return status;
+}
 
-error:
-       dprintk("NFS reply statfs: %d\n", status);
+static int
+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;
 }
 
@@ -824,6 +842,8 @@ struct nfs_rpc_ops  nfs_v3_clientops = {
        .readdir        = nfs3_proc_readdir,
        .mknod          = nfs3_proc_mknod,
        .statfs         = nfs3_proc_statfs,
+       .fsinfo         = nfs3_proc_fsinfo,
+       .pathconf       = nfs3_proc_pathconf,
        .decode_dirent  = nfs3_decode_dirent,
        .read_setup     = nfs3_proc_read_setup,
        .write_setup    = nfs3_proc_write_setup,
index b0c77b19fff9db06993fb814b62af0e1e3649545..2a813fb65365ef6a4652ec2b927dac6d41701973 100644 (file)
@@ -912,14 +912,13 @@ nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
  * Decode FSSTAT reply
  */
 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;
 
        status = ntohl(*p++);
 
-       p = xdr_decode_post_op_attr(p, &dummy);
+       p = xdr_decode_post_op_attr(p, res->fattr);
        if (status != 0)
                return -nfs_stat_to_errno(status);
 
@@ -940,12 +939,11 @@ nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
 static int
 nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
 {
-       struct nfs_fattr dummy;
        int             status;
 
        status = ntohl(*p++);
 
-       p = xdr_decode_post_op_attr(p, &dummy);
+       p = xdr_decode_post_op_attr(p, res->fattr);
        if (status != 0)
                return -nfs_stat_to_errno(status);
 
@@ -959,6 +957,7 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
        p = xdr_decode_hyper(p, &res->maxfilesize);
 
        /* ignore time_delta and properties */
+       res->lease_time = 0;
        return 0;
 }
 
@@ -966,18 +965,17 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
  * Decode PATHCONF reply
  */
 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;
 
        status = ntohl(*p++);
 
-       p = xdr_decode_post_op_attr(p, &dummy);
+       p = xdr_decode_post_op_attr(p, res->fattr);
        if (status != 0)
                return -nfs_stat_to_errno(status);
-       res->linkmax = ntohl(*p++);
-       res->namelen = ntohl(*p++);
+       res->max_link = ntohl(*p++);
+       res->max_namelen = ntohl(*p++);
 
        /* ignore remaining fields */
        return 0;
index 2ad13ec4cd275a2470c82e4b20adca0f20adc60d..a5a1c373444d4a1dcbca2612c17f36971b0020d8 100644 (file)
@@ -460,17 +460,62 @@ nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
 
 static int
 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;
 
        dprintk("NFS call  statfs\n");
-       memset((char *)info, 0, sizeof(*info));
-       status = rpc_call(server->client, NFSPROC_STATFS, fhandle, info, 0);
+       stat->fattr->valid = 0;
+       status = rpc_call(server->client, NFSPROC_STATFS, fhandle, &fsinfo, 0);
        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;
 }
 
+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);
 
 static void
@@ -590,6 +635,8 @@ struct nfs_rpc_ops  nfs_v2_clientops = {
        .readdir        = nfs_proc_readdir,
        .mknod          = nfs_proc_mknod,
        .statfs         = nfs_proc_statfs,
+       .fsinfo         = nfs_proc_fsinfo,
+       .pathconf       = nfs_proc_pathconf,
        .decode_dirent  = nfs_decode_dirent,
        .read_setup     = nfs_proc_read_setup,
        .write_setup    = nfs_proc_write_setup,
index b71b1b217c704119155fdeee1c4ef76f8630d104..e542fe6982c5bb42418ff497ff7a0c66339dc397 100644 (file)
@@ -50,6 +50,7 @@ struct nfs_fattr {
  * Info on the file system
  */
 struct nfs_fsinfo {
+       struct nfs_fattr        *fattr; /* Post-op attributes */
        __u32                   rtmax;  /* max.  read transfer size */
        __u32                   rtpref; /* pref. read transfer size */
        __u32                   rtmult; /* reads should be multiple of this */
@@ -58,16 +59,31 @@ struct nfs_fsinfo {
        __u32                   wtmult; /* writes should be multiple of this */
        __u32                   dtpref; /* pref. readdir transfer size */
        __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                   fbytes; /* # of free bytes */
        __u64                   abytes; /* # of bytes available to user */
        __u64                   tfiles; /* # of files */
        __u64                   ffiles; /* # of free files */
        __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 {
        int     (*mknod)   (struct inode *, struct qstr *, struct iattr *,
                            dev_t, struct nfs_fh *, struct nfs_fattr *);
        int     (*statfs)  (struct nfs_server *, struct nfs_fh *,
+                           struct nfs_fsstat *);
+       int     (*fsinfo)  (struct nfs_server *, struct nfs_fh *,
                            struct nfs_fsinfo *);
+       int     (*pathconf) (struct nfs_server *, struct nfs_fh *,
+                            struct nfs_pathconf *);
        u32 *   (*decode_dirent)(u32 *, struct nfs_entry *, int plus);
        void    (*read_setup)   (struct nfs_read_data *, unsigned int count);
        void    (*write_setup)  (struct nfs_write_data *, unsigned int count, int how);