You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/03/01 20:55:20 UTC

[incubator-nuttx] branch master updated: NFS bug fix and improvement (#412)

This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 915f094  NFS bug fix and improvement (#412)
915f094 is described below

commit 915f094a7466dcb2d4496a55bf4331aeccacb0cb
Author: Xiang Xiao <xi...@xiaomi.com>
AuthorDate: Mon Mar 2 04:53:45 2020 +0800

    NFS bug fix and improvement (#412)
    
    * fs/nfs: Remove all nfs_checkmount call.  The check just waste cpu cycle since nobody will set nm_mounted to false, and remove the unused fields(nm_mounted and n_flags) and related flags too
    * fs/nfs: Fix the definition not confirm to RFC 1813 and other minor issue(unused, typo, duplication, alignment...)
    * fs/nfs: Always represent error with negative number and remove the unused arguments from function
    * fs/nfs: Set socket receive timeout with nfs_args->timeo and fix warning:
    
    nfs/nfs.h:59:28: warning: large integer implicitly truncated to unsigned type [-Woverflow]
     #define NFS_TIMEO          (1 * NFS_HZ)   /* Default timeout = 1 second */
                                ^
    nfs/nfs_vfsops.c:1857:23: note: in expansion of macro 'NFS_TIMEO'
       nprmt.timeo       = NFS_TIMEO;
                                ^
                           ^~~~~~~~~
    
    * fs/nfs: Update the file attribute correctly in nfs_filetruncate and simplify the attrbitue conversion between NFSv3 and NuttX
    * fs/nfs: Remove the unfinished and buggy EXCLUSIVE creation mode
    * fs/nfs: Call nfs_fsinfo in nfs_bind instead of nfs_statfs since we should update the buffer size before transfer happen, and handle the attribute existence variance correctly.
    * fs/nfs: Shouldn't insert node into list again in nfs_dup and fix other typo issue
    * fs/nfs: Should skip . and .. in nfs_readdir
    * fs/nfs: Remove the unnecessary dynamic allocation and the duplicated root handle storage
---
 fs/nfs/nfs.h        |  19 +-
 fs/nfs/nfs_mount.h  |  35 +--
 fs/nfs/nfs_node.h   |  29 +-
 fs/nfs/nfs_proto.h  |  55 ++--
 fs/nfs/nfs_util.c   | 125 +++-----
 fs/nfs/nfs_vfsops.c | 800 ++++++++++++++++++++--------------------------------
 fs/nfs/rpc.h        | 103 +++----
 fs/nfs/rpc_clnt.c   | 233 ++++++---------
 fs/nfs/xdr_subs.h   |  29 --
 9 files changed, 523 insertions(+), 905 deletions(-)

diff --git a/fs/nfs/nfs.h b/fs/nfs/nfs.h
index 2001e2b..a17750c 100644
--- a/fs/nfs/nfs.h
+++ b/fs/nfs/nfs.h
@@ -54,18 +54,14 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
-#define NFS_TICKS          1              /* Number of system ticks */
-#define NFS_HZ             CLOCKS_PER_SEC /* Ticks/sec */
-#define NFS_TIMEO          (1 * NFS_HZ)   /* Default timeout = 1 second */
-#define NFS_MINTIMEO       (1 * NFS_HZ)   /* Min timeout to use */
-#define NFS_MAXTIMEO       (60 * NFS_HZ)  /* Max timeout to backoff to */
-#define NFS_TIMEOUTMUL     2              /* Timeout/Delay multiplier */
+#define NFS_TIMEO          10             /* Default timeout = 1 second */
+#define NFS_MINTIMEO       10             /* Min timeout to use */
+#define NFS_MAXTIMEO       255            /* Max timeout to backoff to */
 #define NFS_MAXREXMIT      100            /* Stop counting after this many */
 #define NFS_RETRANS        10             /* Num of retrans for soft mounts */
 #define NFS_WSIZE          8192           /* Def. write data size <= 8192 */
 #define NFS_RSIZE          8192           /* Def. read data size <= 8192 */
 #define NFS_READDIRSIZE    8192           /* Def. readdir size */
-#define NFS_NPROCS         23
 
 /* Ideally, NFS_DIRBLKSIZ should be bigger, but I've seen servers with
  * broken NFS/ethernet drivers that won't work with anything bigger (Linux..)
@@ -85,9 +81,6 @@
  *  Public Data
  ****************************************************************************/
 
-extern uint32_t nfs_true;
-extern uint32_t nfs_false;
-extern uint32_t nfs_xdrneg1;
 #ifdef CONFIG_NFS_STATISTICS
 extern struct nfsstats nfsstats;
 #endif
@@ -115,11 +108,7 @@ extern "C" {
 #define EXTERN extern
 #endif
 
-EXTERN void nfs_semtake(FAR struct nfsmount *nmp);
-EXTERN void nfs_semgive(FAR struct nfsmount *nmp);
-EXTERN int  nfs_checkmount(FAR struct nfsmount *nmp);
-EXTERN int  nfs_fsinfo(FAR struct nfsmount *nmp);
-EXTERN int nfs_request(struct nfsmount *nmp, int procnum,
+EXTERN int nfs_request(FAR struct nfsmount *nmp, int procnum,
                 FAR void *request, size_t reqlen,
                 FAR void *response, size_t resplen);
 EXTERN int  nfs_lookup(FAR struct nfsmount *nmp, FAR const char *filename,
diff --git a/fs/nfs/nfs_mount.h b/fs/nfs/nfs_mount.h
index bb43f44..4bab615 100644
--- a/fs/nfs/nfs_mount.h
+++ b/fs/nfs/nfs_mount.h
@@ -67,23 +67,18 @@
 
 struct nfsmount
 {
-  struct nfsnode  *nm_head;                   /* A list of all files opened on this mountpoint */
-  sem_t            nm_sem;                    /* Used to assure thread-safe access */
-  nfsfh_t          nm_fh;                     /* File handle of root dir */
-  char             nm_path[90];               /* server's path of the directory being mounted */
-  struct nfs_fattr nm_fattr;                  /* nfs file attribute cache */
-  struct rpcclnt  *nm_rpcclnt;                /* RPC state */
-  struct socket   *nm_so;                     /* RPC socket */
-  struct sockaddr  nm_nam;                    /* Addr of server */
-  bool             nm_mounted;                /* true: The file system is ready */
-  uint8_t          nm_fhsize;                 /* Size of root file handle (host order) */
-  uint8_t          nm_sotype;                 /* Type of socket */
-  uint8_t          nm_retry;                  /* Max retries */
-  uint16_t         nm_timeo;                  /* Timeout value (in system clock ticks) */
-  uint16_t         nm_rsize;                  /* Max size of read RPC */
-  uint16_t         nm_wsize;                  /* Max size of write RPC */
-  uint16_t         nm_readdirsize;            /* Size of a readdir RPC */
-  uint16_t         nm_buflen;                 /* Size of I/O buffer */
+  FAR struct nfsnode       *nm_head;          /* A list of all files opened on this mountpoint */
+  sem_t                     nm_sem;           /* Used to assure thread-safe access */
+  nfsfh_t                  *nm_fh;            /* File handle of root dir */
+  char                      nm_path[90];      /* server's path of the directory being mounted */
+  struct nfs_fattr          nm_fattr;         /* nfs file attribute cache */
+  FAR struct rpcclnt       *nm_rpcclnt;       /* RPC state */
+  struct sockaddr           nm_nam;           /* Addr of server */
+  uint8_t                   nm_fhsize;        /* Size of root file handle (host order) */
+  uint16_t                  nm_rsize;         /* Max size of read RPC */
+  uint16_t                  nm_wsize;         /* Max size of write RPC */
+  uint16_t                  nm_readdirsize;   /* Size of a readdir RPC */
+  uint16_t                  nm_buflen;        /* Size of I/O buffer */
 
   /* Set aside memory on the stack to hold the largest call message.  NOTE
    * that for the case of the write call message, it is the reply message that
@@ -104,7 +99,7 @@ struct nfsmount
     struct rpc_call_readdir readdir;
     struct rpc_call_fs      fsstat;
     struct rpc_call_setattr setattr;
-    struct rpc_call_fs      fs;
+    struct rpc_call_fs      fsinfo;
     struct rpc_reply_write  write;
   } nm_msgbuffer;
 
@@ -116,10 +111,10 @@ struct nfsmount
    * possible WRITE call message or READ response message.
    */
 
-  uint32_t         nm_iobuffer[1];            /* Actual size is given by nm_buflen */
+  uint32_t                  nm_iobuffer[1];   /* Actual size is given by nm_buflen */
 };
 
-/* The size of the nfsmount structure will debug on the size of the allocated I/O
+/* The size of the nfsmount structure will depend on the size of the allocated I/O
  * buffer.
  */
 
diff --git a/fs/nfs/nfs_node.h b/fs/nfs/nfs_node.h
index cb5925f..cedd884 100644
--- a/fs/nfs/nfs_node.h
+++ b/fs/nfs/nfs_node.h
@@ -51,15 +51,6 @@
 #include "nfs_proto.h"
 
 /****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-/* Flags for struct nfsnode n_flag */
-
-#define NFSNODE_OPEN           (1 << 0) /* File is still open */
-#define NFSNODE_MODIFIED       (1 << 1) /* Might have a modified buffer */
-
-/****************************************************************************
  * Public Types
  ****************************************************************************/
 
@@ -69,16 +60,16 @@
 
 struct nfsnode
 {
-  struct nfsnode    *n_next;        /* Retained in a singly linked list. */
-  uint8_t            n_crefs;       /* Reference count (for nfs_dup) */
-  uint8_t            n_type;        /* File type */
-  uint8_t            n_fhsize;      /* Size in bytes of the file handle */
-  uint8_t            n_flags;       /* Node flags */
-  uint16_t           n_mode;        /* File mode for fstat() */
-  time_t             n_mtime;       /* File modification time */
-  time_t             n_ctime;       /* File creation time */
-  nfsfh_t            n_fhandle;     /* NFS File Handle */
-  uint64_t           n_size;        /* Current size of file */
+  FAR struct nfsnode *n_next;       /* Retained in a singly linked list. */
+  uint8_t             n_crefs;      /* Reference count (for nfs_dup) */
+  uint8_t             n_type;       /* File type */
+  uint8_t             n_fhsize;     /* Size in bytes of the file handle */
+  uint16_t            n_mode;       /* File mode for fstat() */
+  time_t              n_atime;      /* File access time */
+  time_t              n_mtime;      /* File modification time */
+  time_t              n_ctime;      /* File creation time */
+  nfsfh_t             n_fhandle;    /* NFS File Handle */
+  uint64_t            n_size;       /* Current size of file */
 };
 
 #endif /* __FS_NFS_NFS_NODE_H */
diff --git a/fs/nfs/nfs_proto.h b/fs/nfs/nfs_proto.h
index 185dc6e..7b63d00 100644
--- a/fs/nfs/nfs_proto.h
+++ b/fs/nfs/nfs_proto.h
@@ -118,13 +118,13 @@
 
 /* Specific to NFS Version 3 */
 
-#define NFSX_V3FH               (sizeof (fhandle_t))  /* size this server uses */
+#define NFSX_V3FH               (sizeof(struct fhandle))  /* size this server uses */
 #define NFSX_V3FHMAX            64    /* max. allowed by protocol */
 #define NFSX_V3FATTR            84
 #define NFSX_V3SATTR            60    /* max. all fields filled in */
 #define NFSX_V3SRVSATTR         (sizeof (struct nfsv3_sattr))
 #define NFSX_V3POSTOPATTR       (NFSX_V3FATTR + NFSX_UNSIGNED)
-#define NFSX_V3WCCDATA          (NFSX_V3POSTOPATTR + 8 * NFSX_UNSIGNED)
+#define NFSX_V3WCCDATA          (NFSX_V3POSTOPATTR + 7 * NFSX_UNSIGNED)
 #define NFSX_V3COOKIEVERF       8
 #define NFSX_V3WRITEVERF        8
 #define NFSX_V3CREATEVERF       8
@@ -185,13 +185,6 @@
 #define NFSV3FSINFO_HOMOGENEOUS  0x08
 #define NFSV3FSINFO_CANSETTIME   0x10
 
-/* Conversion macros */
-
-#define vtonfsv3_mode(m)         txdr_unsigned((m) & 07777)
-#define nfstov_mode(a)           (fxdr_unsigned(u_int16_t, (a))&07777)
-#define vtonfsv3_type(a)         txdr_unsigned(nfsv3_type[((int32_t)(a))])
-#define nfsv3tov_type(a)         nv3tov_type[fxdr_unsigned(uint32_t,(a))&0x7]
-
 /* Mode bit values */
 
 #define NFSMODE_IXOTH            (1 << 0)      /* Execute permission for others on a file */
@@ -230,7 +223,7 @@ typedef enum
 } nfstype;
 
 /* File Handle variable is up to 64 bytes for version 3. This structures a
- * ariable sized and are provided only for setting aside maximum memory
+ * variable sized and are provided only for setting aside maximum memory
  * allocations for a file handle.
  */
 
@@ -305,7 +298,7 @@ struct nfsv3_sattr
   uint32_t           sa_gidfollows;    /* TRUE: Mode value follows */
   uint32_t           sa_gid;           /* Mode value */
   uint32_t           sa_sizefollows;   /* TRUE: Size value follows */
-  uint32_t           sa_size;          /* Size value */
+  nfsuint64          sa_size;          /* Size value */
   uint32_t           sa_atimetype;     /* Don't change, use server timer, or use client time  */
   nfstime3           sa_atime;         /* Client time */
   uint32_t           sa_mtimetype;     /* Don't change, use server timer, or use client time  */
@@ -314,6 +307,7 @@ struct nfsv3_sattr
 
 struct nfs_statfs
 {
+  uint32_t           obj_attributes_follow;
   struct nfs_fattr   obj_attributes;
   nfsuint64          sf_tbytes;
   nfsuint64          sf_fbytes;
@@ -324,16 +318,10 @@ struct nfs_statfs
   uint32_t           sf_invarsec;
 };
 
-struct post_attr
-{
-  uint32_t           obj_attributesfalse;
-  struct nfs_fattr   attributes;
-};
-
 struct nfsv3_fsinfo
 {
-//struct post_attr   obj_attributes;
-  uint32_t           obj_attributesfalse;
+  uint32_t           obj_attributes_follow;
+  struct nfs_fattr   obj_attributes;
   uint32_t           fs_rtmax;
   uint32_t           fs_rtpref;
   uint32_t           fs_rtmult;
@@ -393,6 +381,18 @@ struct CREATE3resok
   struct wcc_data    dir_wcc;
 };
 
+struct SETATTR3args
+{
+  struct file_handle     fhandle;              /* Variable length */
+  struct nfsv3_sattr     new_attributes;       /* Variable length */
+  uint32_t               guard;                /* Guard value */
+};
+
+struct SETATTR3resok
+{
+  struct wcc_data         wcc_data;
+};
+
 /* The actual size of the lookup argument is variable.  These structures are, therefore,
  * only useful in setting aside maximum memory usage for the LOOKUP arguments.
  */
@@ -409,18 +409,6 @@ struct LOOKUP3args
   struct LOOKUP3filename name;                 /* Variable length  */
 };
 
-struct SETATTR3args
-{
-  struct file_handle     fhandle;              /* Variable length */
-  struct nfsv3_sattr     new_attributes;       /* Variable length */
-  uint32_t               guard;                /* Guard value */
-};
-
-struct SETATTR3resok
-{
-  struct wcc_data         wcc_data;
-};
-
 /* Actual size of LOOKUP3args */
 
 #define SIZEOF_LOOKUP3filename(b) (sizeof(uint32_t) + (((b)+3) & ~3))
@@ -464,6 +452,7 @@ struct nfs_wrhdr_s
   uint64_t           offset;
   uint32_t           count;
   uint32_t           stable;
+  uint32_t           length;
 };
 
 struct WRITE3args
@@ -528,10 +517,6 @@ struct RMDIR3resok
   struct wcc_data    dir_wcc;
 };
 
-/* The actual size of the lookup argument is variable.  This structures is, therefore,
- * only useful in setting aside maximum memory usage for the LOOKUP arguments.
- */
-
 struct READDIR3args
 {
   struct file_handle dir;                      /* Variable length */
diff --git a/fs/nfs/nfs_util.c b/fs/nfs/nfs_util.c
index 594f6f2..abfa796 100644
--- a/fs/nfs/nfs_util.c
+++ b/fs/nfs/nfs_util.c
@@ -42,18 +42,14 @@
 #include <sys/time.h>
 
 #include <stdint.h>
-#include <queue.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <time.h>
 #include <string.h>
 #include <assert.h>
 #include <errno.h>
-#include <assert.h>
 #include <debug.h>
 
-#include <nuttx/fs/dirent.h>
-
 #include "rpc.h"
 #include "nfs.h"
 #include "nfs_proto.h"
@@ -105,7 +101,7 @@ static inline int nfs_pathsegment(FAR const char **path, FAR char *buffer,
       else if (nbytes >= NAME_MAX)
         {
           ferr("ERROR: File name segment is too long: %d\n", *path);
-          return EFBIG;
+          return -EFBIG;
         }
       else
         {
@@ -122,77 +118,25 @@ static inline int nfs_pathsegment(FAR const char **path, FAR char *buffer,
  ****************************************************************************/
 
 /****************************************************************************
- * Name: nfs_semtake
- ****************************************************************************/
-
-void nfs_semtake(struct nfsmount *nmp)
-{
-  nxsem_wait_uninterruptible(&nmp->nm_sem);
-}
-
-/****************************************************************************
- * Name: nfs_semgive
- ****************************************************************************/
-
-void nfs_semgive(struct nfsmount *nmp)
-{
-  nxsem_post(&nmp->nm_sem);
-}
-
-/****************************************************************************
- * Name: nfs_checkmount
- *
- * Description: Check if the mountpoint is still valid.
- *
- *   The caller should hold the mountpoint semaphore
- *
- ****************************************************************************/
-
-int nfs_checkmount(struct nfsmount *nmp)
-{
-  struct nfsnode *file;
-
-  /* If the nm_mounted flag is false, then we have already handled the loss
-   * of the mount.
-   */
-
-  DEBUGASSERT(nmp);
-  if (!nmp->nm_mounted)
-    {
-      /* Make sure that this is flagged in every opened file */
-
-      for (file = nmp->nm_head; file; file = file->n_next)
-        {
-          file->n_flags &= ~NFSNODE_OPEN;
-        }
-
-      return -ENODEV;
-    }
-
-  return 0;
-}
-
-/****************************************************************************
  * Name: nfs_request
  *
  * Description:
- *   Perform the NFS request. On successful receipt, it verifies the NFS level of the
- *   returned values.
+ *   Perform the NFS request. On successful receipt, it verifies the NFS level
+ *   of the returned values.
  *
  * Returned Value:
- *   Zero on success; a positive errno value on failure.
+ *   Zero on success; a negative errno value on failure.
  *
  ****************************************************************************/
 
-int nfs_request(struct nfsmount *nmp, int procnum,
+int nfs_request(FAR struct nfsmount *nmp, int procnum,
                 FAR void *request, size_t reqlen,
                 FAR void *response, size_t resplen)
 {
-  struct rpcclnt *clnt = nmp->nm_rpcclnt;
+  FAR struct rpcclnt *clnt = nmp->nm_rpcclnt;
   struct nfs_reply_header replyh;
   int error;
 
-tryagain:
   error = rpcclnt_request(clnt, procnum, NFS_PROG, NFS_VER3,
                           request, reqlen, response, resplen);
   if (error != 0)
@@ -207,29 +151,23 @@ tryagain:
     {
       if (fxdr_unsigned(uint32_t, replyh.nfs_status) > 32)
         {
-          error = EOPNOTSUPP;
+          error = -EOPNOTSUPP;
         }
       else
         {
           /* NFS_ERRORS are the same as NuttX errno values */
 
-          error = fxdr_unsigned(uint32_t, replyh.nfs_status);
+          error = -fxdr_unsigned(uint32_t, replyh.nfs_status);
         }
 
       return error;
     }
 
-  if (replyh.rpc_verfi.authtype != 0)
+  if (replyh.rh.rpc_verfi.authtype != 0)
     {
-      error = fxdr_unsigned(int, replyh.rpc_verfi.authtype);
-
-      if (error == EAGAIN)
-        {
-          error = 0;
-          goto tryagain;
-        }
-
-      ferr("ERROR: NFS error %d from server\n", error);
+      error = -EOPNOTSUPP;
+      ferr("ERROR: NFS authtype %d from server\n",
+           fxdr_unsigned(int, replyh.rpc_verfi.authtype));
       return error;
     }
 
@@ -251,7 +189,7 @@ tryagain:
  *
  ****************************************************************************/
 
-int nfs_lookup(struct nfsmount *nmp, FAR const char *filename,
+int nfs_lookup(FAR struct nfsmount *nmp, FAR const char *filename,
                FAR struct file_handle *fhandle,
                FAR struct nfs_fattr *obj_attributes,
                FAR struct nfs_fattr *dir_attributes)
@@ -270,7 +208,7 @@ int nfs_lookup(struct nfsmount *nmp, FAR const char *filename,
   if (namelen > NAME_MAX)
     {
       ferr("ERROR: Length of the string is too long: %d\n", namelen);
-      return E2BIG;
+      return -E2BIG;
     }
 
   /* Initialize the request */
@@ -284,7 +222,7 @@ int nfs_lookup(struct nfsmount *nmp, FAR const char *filename,
   reqlen += sizeof(uint32_t);
 
   memcpy(ptr, &fhandle->handle, fhandle->length);
-  reqlen += fhandle->length;
+  reqlen += uint32_alignup(fhandle->length);
   ptr    += uint32_increment(fhandle->length);
 
   /* Copy the variable-length file name */
@@ -322,7 +260,7 @@ int nfs_lookup(struct nfsmount *nmp, FAR const char *filename,
   if (value > NFSX_V3FHMAX)
     {
       ferr("ERROR: Bad file handle length: %d\n", value);
-      return EIO;
+      return -EIO;
     }
 
   /* Return the file handle */
@@ -367,11 +305,11 @@ int nfs_lookup(struct nfsmount *nmp, FAR const char *filename,
  *   return the handle of the directory entry of the requested object.
  *
  * Returned Value:
- *   Zero on success; a positive errno value on failure.
+ *   Zero on success; a negative errno value on failure.
  *
  ****************************************************************************/
 
-int nfs_findnode(struct nfsmount *nmp, FAR const char *relpath,
+int nfs_findnode(FAR struct nfsmount *nmp, FAR const char *relpath,
                  FAR struct file_handle *fhandle,
                  FAR struct nfs_fattr *obj_attributes,
                  FAR struct nfs_fattr *dir_attributes)
@@ -385,13 +323,13 @@ int nfs_findnode(struct nfsmount *nmp, FAR const char *relpath,
   /* Start with the file handle of the root directory.  */
 
   fhandle->length = nmp->nm_fhsize;
-  memcpy(&fhandle->handle, &nmp->nm_fh, nmp->nm_fhsize);
+  memcpy(&fhandle->handle, nmp->nm_fh, nmp->nm_fhsize);
 
   /* If no path was provided, then the root directory must be exactly what
    * the caller is looking for.
    */
 
-  if (*path == '\0' || strlen(path) == 0)
+  if (*path == '\0')
     {
       /* Return the root directory attributes */
 
@@ -461,8 +399,8 @@ int nfs_findnode(struct nfsmount *nmp, FAR const char *relpath,
           /* Ooops.. we found something else */
 
           ferr("ERROR: Intermediate segment \"%s\" of \'%s\" is not a directory\n",
-               buffer, path);
-          return ENOTDIR;
+               buffer, relpath);
+          return -ENOTDIR;
         }
     }
 }
@@ -476,11 +414,11 @@ int nfs_findnode(struct nfsmount *nmp, FAR const char *relpath,
  *   object.
  *
  * Returned Value:
- *   Zero on success; a positive errno value on failure.
+ *   Zero on success; a negative errno value on failure.
  *
  ****************************************************************************/
 
-int nfs_finddir(struct nfsmount *nmp, FAR const char *relpath,
+int nfs_finddir(FAR struct nfsmount *nmp, FAR const char *relpath,
                 FAR struct file_handle *fhandle,
                 FAR struct nfs_fattr *attributes, FAR char *filename)
 {
@@ -491,17 +429,15 @@ int nfs_finddir(struct nfsmount *nmp, FAR const char *relpath,
 
   /* Verify that a path was provided */
 
-  if (*path == '\0' || strlen(path) == 0)
+  if (*path == '\0')
     {
-      /* Return the root directory attributes */
-
-      return ENOENT;
+      return -ENOENT;
     }
 
   /* Start with the file handle of the root directory.  */
 
   fhandle->length = nmp->nm_fhsize;
-  memcpy(&fhandle->handle, &nmp->nm_fh, nmp->nm_fhsize);
+  memcpy(&fhandle->handle, nmp->nm_fh, nmp->nm_fhsize);
   memcpy(attributes, &nmp->nm_fattr, sizeof(struct nfs_fattr));
 
   /* Loop until the directory entry containing the path is found. */
@@ -552,8 +488,8 @@ int nfs_finddir(struct nfsmount *nmp, FAR const char *relpath,
           /* Ooops.. we found something else */
 
           ferr("ERROR: Intermediate segment \"%s\" of \'%s\" is not a directory\n",
-               filename, path);
-          return ENOTDIR;
+               filename, relpath);
+          return -ENOTDIR;
         }
     }
 }
@@ -579,6 +515,9 @@ void nfs_attrupdate(FAR struct nfsnode *np, FAR struct nfs_fattr *attributes)
   np->n_mode   = fxdr_unsigned(uint16_t, attributes->fa_mode);
   np->n_size   = fxdr_hyper(&attributes->fa_size);
 
+  fxdr_nfsv3time(&attributes->fa_atime, &ts);
+  np->n_atime  = ts.tv_sec;
+
   fxdr_nfsv3time(&attributes->fa_mtime, &ts);
   np->n_mtime  = ts.tv_sec;
 
diff --git a/fs/nfs/nfs_vfsops.c b/fs/nfs/nfs_vfsops.c
index f9c55d4..59670c4 100644
--- a/fs/nfs/nfs_vfsops.c
+++ b/fs/nfs/nfs_vfsops.c
@@ -55,7 +55,6 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <stdlib.h>
-#include <queue.h>
 #include <string.h>
 #include <fcntl.h>
 #include <time.h>
@@ -86,10 +85,6 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
-/* The V3 EXCLUSIVE file creation logic is not fully supported. */
-
-#define USE_GUARDED_CREATE    1
-
 /* include/nuttx/fs/dirent.h has its own version of these lengths.  They must
  * match the NFS versions.
  */
@@ -103,37 +98,20 @@
 #endif
 
 /****************************************************************************
- * Private Types
+ * Private Data
  ****************************************************************************/
 
-/* Use to pass file information to nfs_stat_common() */
-
-struct nfs_statinfo_s
-{
-  uint16_t ns_mode;    /* File access mode */
-  uint8_t  ns_type;    /* File type */
-  uint64_t ns_size;    /* File size */
-  time_t   ns_atime;   /* Time of last access */
-  time_t   ns_mtime;   /* Time of last modification */
-  time_t   ns_ctime;   /* Time of last status change */
-};
-
-/****************************************************************************
- * Public Data
- ****************************************************************************/
-
-uint32_t nfs_true;
-uint32_t nfs_false;
-uint32_t nfs_xdrneg1;
-
-#ifdef CONFIG_NFS_STATISTICS
-struct nfsstats nfsstats;
-#endif
+static uint32_t nfs_true;
+static uint32_t nfs_false;
+static uint32_t nfs_xdrneg1;
 
 /****************************************************************************
  * Private Function Prototypes
  ****************************************************************************/
 
+static void    nfs_semtake(FAR struct nfsmount *nmp);
+static void    nfs_semgive(FAR struct nfsmount *nmp);
+
 static int     nfs_filecreate(FAR struct nfsmount *nmp,
                    FAR struct nfsnode *np, FAR const char *relpath,
                    mode_t mode);
@@ -143,24 +121,25 @@ static int     nfs_fileopen(FAR struct nfsmount *nmp,
                    FAR struct nfsnode *np, FAR const char *relpath,
                    int oflags, mode_t mode);
 
-static int     nfs_open(FAR struct file *filep, const char *relpath,
+static int     nfs_open(FAR struct file *filep, FAR const char *relpath,
                    int oflags, mode_t mode);
 static int     nfs_close(FAR struct file *filep);
-static ssize_t nfs_read(FAR struct file *filep, char *buffer, size_t buflen);
-static ssize_t nfs_write(FAR struct file *filep, const char *buffer,
+static ssize_t nfs_read(FAR struct file *filep, FAR char *buffer, size_t buflen);
+static ssize_t nfs_write(FAR struct file *filep, FAR const char *buffer,
                    size_t buflen);
 static int     nfs_dup(FAR const struct file *oldp, FAR struct file *newp);
+static int     nfs_fsinfo(FAR struct nfsmount *nmp);
 static int     nfs_fstat(FAR const struct file *filep, FAR struct stat *buf);
 static int     nfs_truncate(FAR struct file *filep, off_t length);
-static int     nfs_opendir(struct inode *mountpt, const char *relpath,
-                   struct fs_dirent_s *dir);
-static int     nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir);
+static int     nfs_opendir(FAR struct inode *mountpt, FAR const char *relpath,
+                   FAR struct fs_dirent_s *dir);
+static int     nfs_readdir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir);
 static int     nfs_rewinddir(FAR struct inode *mountpt,
                    FAR struct fs_dirent_s *dir);
 static void    nfs_decode_args(FAR struct nfs_mount_parameters *nprmt,
                    FAR struct nfs_args *argp);
-static int     nfs_bind(FAR struct inode *blkdriver, const void *data,
-                   void **handle);
+static int     nfs_bind(FAR struct inode *blkdriver, FAR const void *data,
+                   FAR void **handle);
 static int     nfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
                    unsigned int flags);
 static int     nfs_statfs(FAR struct inode *mountpt,
@@ -173,15 +152,18 @@ static int     nfs_rmdir(FAR struct inode *mountpt,
                    FAR const char *relpath);
 static int     nfs_rename(FAR struct inode *mountpt,
                    FAR const char *oldrelpath, FAR const char *newrelpath);
-static void    nfs_stat_common(FAR struct nfs_statinfo_s *info,
-                   FAR struct stat *buf);
-static int     nfs_stat(struct inode *mountpt, FAR const char *relpath,
+static mode_t  nfs_stat_mode(unsigned int mode, unsigned int type);
+static int     nfs_stat(FAR struct inode *mountpt, FAR const char *relpath,
                    FAR struct stat *buf);
 
 /****************************************************************************
  * Public Data
  ****************************************************************************/
 
+#ifdef CONFIG_NFS_STATISTICS
+struct nfsstats nfsstats;
+#endif
+
 /* nfs vfs operations. */
 
 const struct mountpt_operations nfs_operations =
@@ -215,9 +197,27 @@ const struct mountpt_operations nfs_operations =
 };
 
 /****************************************************************************
- * Public Functions
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nfs_semtake
  ****************************************************************************/
 
+static void nfs_semtake(FAR struct nfsmount *nmp)
+{
+  nxsem_wait_uninterruptible(&nmp->nm_sem);
+}
+
+/****************************************************************************
+ * Name: nfs_semgive
+ ****************************************************************************/
+
+static void nfs_semgive(FAR struct nfsmount *nmp)
+{
+  nxsem_post(&nmp->nm_sem);
+}
+
 /****************************************************************************
  * Name: nfs_filecreate
  *
@@ -226,7 +226,7 @@ const struct mountpt_operations nfs_operations =
  *   the user asks to create a file.
  *
  * Returned Value:
- *   0 on success; a positive errno value on failure.
+ *   0 on success; a negative errno value on failure.
  *
  ****************************************************************************/
 
@@ -262,7 +262,7 @@ static int nfs_filecreate(FAR struct nfsmount *nmp, FAR struct nfsnode *np,
   reqlen += sizeof(uint32_t);
 
   memcpy(ptr, &fhandle.handle, fhandle.length);
-  reqlen += (int)fhandle.length;
+  reqlen += uint32_alignup(fhandle.length);
   ptr    += uint32_increment(fhandle.length);
 
   /* Copy the variable-length file name */
@@ -278,84 +278,54 @@ static int nfs_filecreate(FAR struct nfsmount *nmp, FAR struct nfsnode *np,
 
   /* Set the creation mode */
 
-  if ((mode & O_CREAT) != 0)
-    {
-#ifdef USE_GUARDED_CREATE
-      *ptr++  = HTONL(NFSV3CREATE_GUARDED);
-#else
-      *ptr++  = HTONL(NFSV3CREATE_EXCLUSIVE);
-#endif
-    }
-  else
-    {
-      *ptr++  = HTONL(NFSV3CREATE_UNCHECKED);
-    }
-
+  *ptr++  = HTONL(NFSV3CREATE_GUARDED);
   reqlen += sizeof(uint32_t);
 
-  /* Mode information is not provided if EXCLUSIVE creation is used.
-   * in this case, we must call SETATTR after successfully creating
-   * the file.
+  /* Set the mode.  NOTE: Here we depend on the fact that the NuttX and NFS
+   * bit settings are the same (at least for the bits of interest).
    */
 
-#ifndef USE_GUARDED_CREATE
-  if ((mode & O_CREAT) == 0)
-#endif
-    {
-      /* Set the mode.  NOTE: Here we depend on the fact that the NuttX and NFS
-       * bit settings are the same (at least for the bits of interest).
-       */
-
-      *ptr++  = nfs_true; /* True: mode value follows */
-      reqlen += sizeof(uint32_t);
+  *ptr++  = nfs_true; /* True: mode value follows */
+  reqlen += sizeof(uint32_t);
 
-      tmp = mode & (NFSMODE_IWOTH | NFSMODE_IROTH | NFSMODE_IWGRP |
-                    NFSMODE_IRGRP | NFSMODE_IWUSR | NFSMODE_IRUSR);
-      *ptr++  = txdr_unsigned(tmp);
-      reqlen += sizeof(uint32_t);
+  tmp = mode & (NFSMODE_IXOTH | NFSMODE_IWOTH | NFSMODE_IROTH |
+                NFSMODE_IXGRP | NFSMODE_IWGRP | NFSMODE_IRGRP |
+                NFSMODE_IXUSR | NFSMODE_IWUSR | NFSMODE_IRUSR |
+                NFSMODE_SAVETEXT | NFSMODE_ISGID | NFSMODE_ISUID);
+  *ptr++  = txdr_unsigned(tmp);
+  reqlen += sizeof(uint32_t);
 
-      /* Set the user ID to zero */
+  /* Set the user ID to zero */
 
-      *ptr++  = nfs_true;             /* True: Uid value follows */
-      *ptr++  = 0;                    /* UID = 0 (nobody) */
-      reqlen += 2*sizeof(uint32_t);
+  *ptr++  = nfs_true;             /* True: Uid value follows */
+  *ptr++  = 0;                    /* UID = 0 (nobody) */
+  reqlen += 2*sizeof(uint32_t);
 
-      /* Set the group ID to one */
+  /* Set the group ID to one */
 
-      *ptr++  = nfs_true;            /* True: Gid value follows */
-      *ptr++  = HTONL(1);            /* GID = 1 (nogroup) */
-      reqlen += 2*sizeof(uint32_t);
+  *ptr++  = nfs_true;            /* True: Gid value follows */
+  *ptr++  = HTONL(1);            /* GID = 1 (nogroup) */
+  reqlen += 2*sizeof(uint32_t);
 
-      /* Set the size to zero */
+  /* Set the size to zero */
 
-      *ptr++  = nfs_true;            /* True: Size value follows */
-      *ptr++  = 0;                   /* Size = 0 */
-      *ptr++  = 0;
-      reqlen += 3*sizeof(uint32_t);
+  *ptr++  = nfs_true;            /* True: Size value follows */
+  *ptr++  = 0;                   /* Size = 0 */
+  *ptr++  = 0;
+  reqlen += 3*sizeof(uint32_t);
 
-      /* Don't change times */
+  /* Don't change times */
 
-      *ptr++  = HTONL(NFSV3SATTRTIME_DONTCHANGE); /* Don't change atime */
-      *ptr++  = HTONL(NFSV3SATTRTIME_DONTCHANGE); /* Don't change mtime */
-      reqlen += 2*sizeof(uint32_t);
-    }
+  *ptr++  = HTONL(NFSV3SATTRTIME_DONTCHANGE); /* Don't change atime */
+  *ptr++  = HTONL(NFSV3SATTRTIME_DONTCHANGE); /* Don't change mtime */
+  reqlen += 2*sizeof(uint32_t);
 
-  /* Send the NFS request.  Note there is special logic here to handle version 3
-   * exclusive open semantics.
-   */
+  /* Send the NFS request. */
 
-  do
-    {
-      nfs_statistics(NFSPROC_CREATE);
-      error = nfs_request(nmp, NFSPROC_CREATE,
-                          (FAR void *)&nmp->nm_msgbuffer.create, reqlen,
-                          (FAR void *)nmp->nm_iobuffer, nmp->nm_buflen);
-    }
-#ifdef USE_GUARDED_CREATE
-  while (0);
-#else
-  while (((mode & O_CREAT) != 0) && error == EOPNOTSUPP);
-#endif
+  nfs_statistics(NFSPROC_CREATE);
+  error = nfs_request(nmp, NFSPROC_CREATE,
+                      (FAR void *)&nmp->nm_msgbuffer.create, reqlen,
+                      (FAR void *)nmp->nm_iobuffer, nmp->nm_buflen);
 
   /* Check for success */
 
@@ -372,7 +342,7 @@ static int nfs_filecreate(FAR struct nfsmount *nmp, FAR struct nfsnode *np,
       if (!tmp)
         {
           ferr("ERROR: no file handle follows\n");
-          return EINVAL;
+          return -EINVAL;
         }
 
       tmp = *ptr++;
@@ -385,7 +355,7 @@ static int nfs_filecreate(FAR struct nfsmount *nmp, FAR struct nfsnode *np,
 
       /* Save the attributes in the file data structure */
 
-      tmp = *ptr;  /* handle_follows */
+      tmp = *ptr;  /* attributes_follows */
       if (!tmp)
         {
           fwarn("WARNING: no file attributes\n");
@@ -404,14 +374,13 @@ static int nfs_filecreate(FAR struct nfsmount *nmp, FAR struct nfsnode *np,
 }
 
 /****************************************************************************
- * Name: nfs_fileopen
+ * Name: nfs_filetruncate
  *
  * Description:
- *   Truncate an open file to zero length.  This is part of the file open
- *   logic.
+ *   Truncate an open file to length.  This is part of the file open logic.
  *
  * Returned Value:
- *   0 on success; a positive errno value on failure.
+ *   0 on success; a negative errno value on failure.
  *
  ****************************************************************************/
 
@@ -435,7 +404,7 @@ static int nfs_filetruncate(FAR struct nfsmount *nmp,
   reqlen += sizeof(uint32_t);
 
   memcpy(ptr, &np->n_fhandle, np->n_fhsize);
-  reqlen += (int)np->n_fhsize;
+  reqlen += uint32_alignup(np->n_fhsize);
   ptr    += uint32_increment(np->n_fhsize);
 
   /* Copy the variable-length attributes */
@@ -444,8 +413,8 @@ static int nfs_filetruncate(FAR struct nfsmount *nmp,
   *ptr++  = nfs_false;                        /* Don't change uid */
   *ptr++  = nfs_false;                        /* Don't change gid */
   *ptr++  = nfs_true;                         /* Use the following size */
-  *ptr++  = length;                           /* Truncate to the specified length */
   *ptr++  = 0;
+  *ptr++  = txdr_unsigned(length);            /* Truncate to the specified length */
   *ptr++  = HTONL(NFSV3SATTRTIME_TOSERVER);   /* Use the server's time */
   *ptr++  = HTONL(NFSV3SATTRTIME_TOSERVER);   /* Use the server's time */
   *ptr++  = nfs_false;                        /* No guard value */
@@ -463,9 +432,29 @@ static int nfs_filetruncate(FAR struct nfsmount *nmp,
       return error;
     }
 
-  /* Indicate that the file now has zero length */
+  /* Get a pointer to the SETATTR reply data */
+
+  ptr = (FAR uint32_t *)&((FAR struct rpc_reply_setattr *)
+    nmp->nm_iobuffer)->setattr;
+
+  /* Parse file_wcc.  First, check if WCC attributes follow. */
+
+  if (*ptr++ != 0)
+    {
+      /* Yes.. WCC attributes follow.  But we just skip over them. */
+
+      ptr += uint32_increment(sizeof(struct wcc_attr));
+    }
+
+  /* Check if normal file attributes follow */
+
+  if (*ptr++ != 0)
+    {
+      /* Yes.. Update the cached file status in the file structure. */
+
+      nfs_attrupdate(np, (FAR struct nfs_fattr *)ptr);
+    }
 
-  np->n_size = 0;
   return OK;
 }
 
@@ -477,7 +466,7 @@ static int nfs_filetruncate(FAR struct nfsmount *nmp,
  *   an existing file.
  *
  * Returned Value:
- *   0 on success; a positive errno value on failure.
+ *   0 on success; a negative errno value on failure.
  *
  ****************************************************************************/
 
@@ -506,7 +495,7 @@ static int nfs_fileopen(FAR struct nfsmount *nmp, FAR struct nfsnode *np,
       /* Exit with EISDIR if we attempt to open a directory */
 
       ferr("ERROR: Path is a directory\n");
-      return EISDIR;
+      return -EISDIR;
     }
 
   /* Check if the caller has sufficient privileges to open the file */
@@ -522,7 +511,7 @@ static int nfs_fileopen(FAR struct nfsmount *nmp, FAR struct nfsnode *np,
       if ((tmp & (NFSMODE_IWOTH | NFSMODE_IWGRP | NFSMODE_IWUSR)) == 0)
         {
           ferr("ERROR: File is read-only: %08x\n", tmp);
-          return EACCES;
+          return -EACCES;
         }
     }
 
@@ -533,7 +522,7 @@ static int nfs_fileopen(FAR struct nfsmount *nmp, FAR struct nfsnode *np,
       /* Already exists -- can't create it exclusively */
 
       ferr("ERROR: File exists\n");
-      return EEXIST;
+      return -EEXIST;
     }
 
   /* Initialize the file private data.
@@ -581,8 +570,8 @@ static int nfs_fileopen(FAR struct nfsmount *nmp, FAR struct nfsnode *np,
 static int nfs_open(FAR struct file *filep, FAR const char *relpath,
                     int oflags, mode_t mode)
 {
-  struct nfsmount *nmp;
-  struct nfsnode *np;
+  FAR struct nfsmount *nmp;
+  FAR struct nfsnode *np;
   int error;
 
   /* Sanity checks */
@@ -598,22 +587,14 @@ static int nfs_open(FAR struct file *filep, FAR const char *relpath,
 
   /* Pre-allocate the file private data to describe the opened file. */
 
-  np = (struct nfsnode *)kmm_zalloc(sizeof(struct nfsnode));
+  np = (FAR struct nfsnode *)kmm_zalloc(sizeof(struct nfsnode));
   if (!np)
     {
       ferr("ERROR: Failed to allocate private data\n");
       return -ENOMEM;
     }
 
-  /* Check if the mount is still healthy */
-
   nfs_semtake(nmp);
-  error = nfs_checkmount(nmp);
-  if (error != OK)
-    {
-      ferr("ERROR: nfs_checkmount failed: %d\n", error);
-      goto errout_with_semaphore;
-    }
 
   /* Try to open an existing file at that path */
 
@@ -626,9 +607,9 @@ static int nfs_open(FAR struct file *filep, FAR const char *relpath,
        * file.
        */
 
-      if (error != ENOENT)
+      if (error != -ENOENT)
         {
-          ferr("ERROR: nfs_findnode failed: %d\n", error);
+          ferr("ERROR: nfs_fileopen failed: %d\n", error);
           goto errout_with_semaphore;
         }
 
@@ -644,7 +625,6 @@ static int nfs_open(FAR struct file *filep, FAR const char *relpath,
            */
 
           ferr("ERROR: File does not exist\n");
-           error = ENOENT;
           goto errout_with_semaphore;
         }
 
@@ -669,7 +649,7 @@ static int nfs_open(FAR struct file *filep, FAR const char *relpath,
   filep->f_priv = np;
 
   /* Then insert the new instance at the head of the list in the mountpoint
-   * tructure. It needs to be there (1) to handle error conditions that effect
+   * structure. It needs to be there (1) to handle error conditions that effect
    * all files, and (2) to inform the umount logic that we are busy.  We
    * cannot unmount the file system if this list is not empty!
    */
@@ -677,7 +657,6 @@ static int nfs_open(FAR struct file *filep, FAR const char *relpath,
   np->n_next   = nmp->nm_head;
   nmp->nm_head = np;
 
-  np->n_flags |= (NFSNODE_OPEN | NFSNODE_MODIFIED);
   nfs_semgive(nmp);
   return OK;
 
@@ -688,7 +667,7 @@ errout_with_semaphore:
     }
 
   nfs_semgive(nmp);
-  return -error;
+  return error;
 }
 
 /****************************************************************************
@@ -794,7 +773,7 @@ static int nfs_close(FAR struct file *filep)
  *
  ****************************************************************************/
 
-static ssize_t nfs_read(FAR struct file *filep, char *buffer, size_t buflen)
+static ssize_t nfs_read(FAR struct file *filep, FAR char *buffer, size_t buflen)
 {
   FAR struct nfsmount       *nmp;
   FAR struct nfsnode        *np;
@@ -818,15 +797,7 @@ static ssize_t nfs_read(FAR struct file *filep, char *buffer, size_t buflen)
 
   DEBUGASSERT(nmp != NULL);
 
-  /* Make sure that the mount is still healthy */
-
   nfs_semtake(nmp);
-  error = nfs_checkmount(nmp);
-  if (error != OK)
-    {
-      ferr("ERROR: nfs_checkmount failed: %d\n", error);
-      goto errout_with_semaphore;
-    }
 
   /* Get the number of bytes left in the file and truncate read count so that
    * it does not exceed the number of bytes left in the file.
@@ -870,8 +841,8 @@ static ssize_t nfs_read(FAR struct file *filep, char *buffer, size_t buflen)
       reqlen += sizeof(uint32_t);
 
       memcpy(ptr, &np->n_fhandle, np->n_fhsize);
-      reqlen += (int)np->n_fhsize;
-      ptr    += uint32_increment((int)np->n_fhsize);
+      reqlen += uint32_alignup(np->n_fhsize);
+      ptr    += uint32_increment(np->n_fhsize);
 
       /* Copy the file offset */
 
@@ -906,10 +877,11 @@ static ssize_t nfs_read(FAR struct file *filep, char *buffer, size_t buflen)
       /* Check if attributes are included in the responses */
 
       tmp = *ptr++;
-      if (*ptr != 0)
+      if (tmp != 0)
         {
-          /* Yes... just skip over the attributes for now */
+          /* Yes.. Update the cached file status in the file structure. */
 
+          nfs_attrupdate(np, (FAR struct nfs_fattr *)ptr);
           ptr += uint32_increment(sizeof(struct nfs_fattr));
         }
 
@@ -954,7 +926,7 @@ static ssize_t nfs_read(FAR struct file *filep, char *buffer, size_t buflen)
 
 errout_with_semaphore:
   nfs_semgive(nmp);
-  return -error;
+  return error;
 }
 
 /****************************************************************************
@@ -966,11 +938,11 @@ errout_with_semaphore:
  *
  ****************************************************************************/
 
-static ssize_t nfs_write(FAR struct file *filep, const char *buffer,
+static ssize_t nfs_write(FAR struct file *filep, FAR const char *buffer,
                          size_t buflen)
 {
-  struct nfsmount       *nmp;
-  struct nfsnode        *np;
+  FAR struct nfsmount   *nmp;
+  FAR struct nfsnode    *np;
   ssize_t                writesize;
   ssize_t                bufsize;
   ssize_t                byteswritten;
@@ -994,34 +966,25 @@ static ssize_t nfs_write(FAR struct file *filep, const char *buffer,
 
   DEBUGASSERT(nmp != NULL);
 
-  /* Make sure that the mount is still healthy */
-
   nfs_semtake(nmp);
-  error = nfs_checkmount(nmp);
-  if (error != OK)
-    {
-      ferr("ERROR: nfs_checkmount failed: %d\n", error);
-      goto errout_with_semaphore;
-    }
 
   /* Check if the file size would exceed the range of off_t */
 
   if (np->n_size + buflen < np->n_size)
     {
-      error = EFBIG;
+      error = -EFBIG;
       goto errout_with_semaphore;
     }
 
   /* Now loop until we send the entire user buffer */
 
-  writesize = 0;
   for (byteswritten = 0; byteswritten < buflen; )
     {
       /* Make sure that the attempted write size does not exceed the RPC
        * maximum.
        */
 
-      writesize = buflen;
+      writesize = buflen - byteswritten;
       if (writesize > nmp->nm_wsize)
         {
           writesize = nmp->nm_wsize;
@@ -1052,8 +1015,8 @@ static ssize_t nfs_write(FAR struct file *filep, const char *buffer,
       reqlen += sizeof(uint32_t);
 
       memcpy(ptr, &np->n_fhandle, np->n_fhsize);
-      reqlen += (int)np->n_fhsize;
-      ptr    += uint32_increment((int)np->n_fhsize);
+      reqlen += uint32_alignup(np->n_fhsize);
+      ptr    += uint32_increment(np->n_fhsize);
 
       /* Copy the file offset */
 
@@ -1063,13 +1026,13 @@ static ssize_t nfs_write(FAR struct file *filep, const char *buffer,
 
       /* Copy the count and stable values */
 
-      *ptr++  = txdr_unsigned(buflen);
+      *ptr++  = txdr_unsigned(writesize);
       *ptr++  = txdr_unsigned(committed);
       reqlen += 2*sizeof(uint32_t);
 
       /* Copy a chunk of the user data into the I/O buffer */
 
-      *ptr++  = txdr_unsigned(buflen);
+      *ptr++  = txdr_unsigned(writesize);
       reqlen += sizeof(uint32_t);
       memcpy(ptr, buffer, writesize);
       reqlen += uint32_alignup(writesize);
@@ -1119,7 +1082,7 @@ static ssize_t nfs_write(FAR struct file *filep, const char *buffer,
 
       if (tmp < 1 || tmp > writesize)
         {
-          error = EIO;
+          error = -EIO;
           goto errout_with_semaphore;
         }
 
@@ -1146,11 +1109,11 @@ static ssize_t nfs_write(FAR struct file *filep, const char *buffer,
     }
 
   nfs_semgive(nmp);
-  return writesize;
+  return byteswritten;
 
 errout_with_semaphore:
   nfs_semgive(nmp);
-  return -error;
+  return error;
 }
 
 /****************************************************************************
@@ -1163,9 +1126,8 @@ errout_with_semaphore:
 
 static int nfs_dup(FAR const struct file *oldp, FAR struct file *newp)
 {
-  struct nfsmount *nmp;
+  FAR struct nfsmount *nmp;
   FAR struct nfsnode *np;
-  int error;
 
   finfo("Dup %p->%p\n", oldp, newp);
 
@@ -1180,16 +1142,7 @@ static int nfs_dup(FAR const struct file *oldp, FAR struct file *newp)
 
   DEBUGASSERT(nmp != NULL);
 
-  /* Check if the mount is still healthy */
-
   nfs_semtake(nmp);
-  error = nfs_checkmount(nmp);
-  if (error != OK)
-    {
-      ferr("ERROR: nfs_checkmount failed: %d\n", error);
-      nfs_semgive(nmp);
-      return -error;
-    }
 
   /* Increment the reference count on the NFS node structure */
 
@@ -1200,15 +1153,6 @@ static int nfs_dup(FAR const struct file *oldp, FAR struct file *newp)
 
   newp->f_priv = np;
 
-  /* Then insert the new instance at the head of the list in the mountpoint
-   * tructure. It needs to be there (1) to handle error conditions that effect
-   * all files, and (2) to inform the umount logic that we are busy.  We
-   * cannot unmount the file system if this list is not empty!
-   */
-
-  np->n_next   = nmp->nm_head;
-  nmp->nm_head = np;
-
   nfs_semgive(nmp);
   return OK;
 }
@@ -1226,10 +1170,6 @@ static int nfs_fstat(FAR const struct file *filep, FAR struct stat *buf)
 {
   FAR struct nfsmount *nmp;
   FAR struct nfsnode *np;
-  struct nfs_statinfo_s info;
-  struct timespec ts;
-  int error;
-  int ret;
 
   finfo("Buf %p\n", buf);
   DEBUGASSERT(filep != NULL && buf != NULL);
@@ -1242,49 +1182,25 @@ static int nfs_fstat(FAR const struct file *filep, FAR struct stat *buf)
   nmp = (FAR struct nfsmount *)filep->f_inode->i_private;
   DEBUGASSERT(nmp != NULL);
 
-  /* Make sure that the mount is still healthy */
+  memset(buf, 0, sizeof(*buf));
 
   nfs_semtake(nmp);
-  error = nfs_checkmount(nmp);
-  if (error != OK)
-    {
-      ferr("ERROR: nfs_checkmount failed: %d\n", error);
-      goto errout_with_semaphore;
-    }
 
   /* Extract the file mode, file type, and file size from the nfsnode
    * structure.
    */
 
-  info.ns_mode  = np->n_mode;
-  info.ns_type  = np->n_type;
-  info.ns_size  = (off_t)np->n_size;
+  buf->st_mode  = nfs_stat_mode(np->n_mode, np->n_type);
+  buf->st_size  = (off_t)np->n_size;
 
   /* Extract time values as type time_t in units of seconds. */
 
-  info.ns_mtime = np->n_mtime;
-  info.ns_ctime = np->n_ctime;
-
-  /* Use the current time for the time of last access. */
-
-  ret = clock_gettime(CLOCK_REALTIME, &ts);
-  if (ret < 0)
-    {
-      error = -get_errno();
-      ferr("ERROR: clock_gettime failed: %d\n", error);
-      goto errout_with_semaphore;
-    }
-
-  info.ns_atime = ts.tv_sec;
-
-  /* Then update the stat buffer with this information */
-
-  nfs_stat_common(&info, buf);
-  ret = OK;
+  buf->st_atime = np->n_atime;
+  buf->st_mtime = np->n_mtime;
+  buf->st_ctime = np->n_ctime;
 
-errout_with_semaphore:
   nfs_semgive(nmp);
-  return -error;
+  return OK;
 }
 
 /****************************************************************************
@@ -1298,8 +1214,8 @@ errout_with_semaphore:
 
 static int nfs_truncate(FAR struct file *filep, off_t length)
 {
-  struct nfsmount *nmp;
-  struct nfsnode *np;
+  FAR struct nfsmount *nmp;
+  FAR struct nfsnode *np;
   int error;
 
   finfo("Truncate to %ld bytes\n", (long)length);
@@ -1312,23 +1228,14 @@ static int nfs_truncate(FAR struct file *filep, off_t length)
 
   DEBUGASSERT(nmp != NULL);
 
-  /* Make sure that the mount is still healthy */
-
   nfs_semtake(nmp);
-  error = nfs_checkmount(nmp);
-  if (error != OK)
-    {
-      ferr("ERROR: nfs_checkmount failed: %d\n", error);
-      goto errout_with_semaphore;
-    }
 
   /* Then perform the SETATTR RPC to set the new file size */
 
   error = nfs_filetruncate(nmp, np, length);
 
-errout_with_semaphore:
   nfs_semgive(nmp);
-  return -error;
+  return error;
 }
 
 /****************************************************************************
@@ -1342,11 +1249,11 @@ errout_with_semaphore:
  *
  ****************************************************************************/
 
-static int nfs_opendir(struct inode *mountpt, const char *relpath,
-                       struct fs_dirent_s *dir)
+static int nfs_opendir(FAR struct inode *mountpt, FAR const char *relpath,
+                       FAR struct fs_dirent_s *dir)
 {
-  struct nfsmount *nmp;
-  struct file_handle fhandle;
+  FAR struct nfsmount *nmp;
+  FAR struct file_handle fhandle;
   struct nfs_fattr obj_attributes;
   uint32_t objtype;
   int error;
@@ -1365,15 +1272,7 @@ static int nfs_opendir(struct inode *mountpt, const char *relpath,
 
   memset(&dir->u.nfs, 0, sizeof(struct nfsdir_s));
 
-  /* Make sure that the mount is still healthy */
-
   nfs_semtake(nmp);
-  error = nfs_checkmount(nmp);
-  if (error != OK)
-    {
-      ferr("ERROR: nfs_checkmount failed: %d\n", error);
-      goto errout_with_semaphore;
-    }
 
   /* Find the NFS node associate with the path */
 
@@ -1390,7 +1289,7 @@ static int nfs_opendir(struct inode *mountpt, const char *relpath,
   if (objtype != NFDIR)
     {
       ferr("ERROR:  Not a directory, type=%d\n", objtype);
-      error = ENOTDIR;
+      error = -ENOTDIR;
       goto errout_with_semaphore;
     }
 
@@ -1401,12 +1300,12 @@ static int nfs_opendir(struct inode *mountpt, const char *relpath,
   dir->u.nfs.nfs_fhsize = (uint8_t)fhandle.length;
   DEBUGASSERT(fhandle.length <= DIRENT_NFS_MAXHANDLE);
 
-  memcpy(dir->u.nfs.nfs_fhandle, &fhandle.handle, DIRENT_NFS_MAXHANDLE);
+  memcpy(dir->u.nfs.nfs_fhandle, &fhandle.handle, fhandle.length);
   error = OK;
 
 errout_with_semaphore:
   nfs_semgive(nmp);
-  return -error;
+  return error;
 }
 
 /****************************************************************************
@@ -1419,15 +1318,15 @@ errout_with_semaphore:
  *
  ****************************************************************************/
 
-static int nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir)
+static int nfs_readdir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir)
 {
-  struct nfsmount *nmp;
+  FAR struct nfsmount *nmp;
   struct file_handle fhandle;
   struct nfs_fattr obj_attributes;
   uint32_t readsize;
   uint32_t tmp;
-  uint32_t *ptr;
-  uint8_t *name;
+  FAR uint32_t *ptr;
+  FAR uint8_t *name;
   unsigned int length;
   int reqlen;
   int error = 0;
@@ -1442,16 +1341,9 @@ static int nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir)
 
   nmp = mountpt->i_private;
 
-  /* Make sure that the mount is still healthy */
-
   nfs_semtake(nmp);
-  error = nfs_checkmount(nmp);
-  if (error != OK)
-    {
-      ferr("ERROR: nfs_checkmount failed: %d\n", error);
-      goto errout_with_semaphore;
-    }
 
+read_dir:
   /* Request a block directory entries, copying directory information from
    * the dirent structure.
    */
@@ -1465,8 +1357,8 @@ static int nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir)
   reqlen += sizeof(uint32_t);
 
   memcpy(ptr, dir->u.nfs.nfs_fhandle, dir->u.nfs.nfs_fhsize);
-  reqlen += (int)dir->u.nfs.nfs_fhsize;
-  ptr    += uint32_increment((int)dir->u.nfs.nfs_fhsize);
+  reqlen += uint32_alignup(dir->u.nfs.nfs_fhsize);
+  ptr    += uint32_increment(dir->u.nfs.nfs_fhsize);
 
   /* Cookie and cookie verifier */
 
@@ -1513,7 +1405,7 @@ static int nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir)
    * 4) Values follows indication    - 4 bytes
    */
 
-  ptr = (uint32_t *)&((FAR struct rpc_reply_readdir *)nmp->nm_iobuffer)->readdir;
+  ptr = (FAR uint32_t *)&((FAR struct rpc_reply_readdir *)nmp->nm_iobuffer)->readdir;
 
   /* Check if attributes follow, if 0 so Skip over the attributes */
 
@@ -1530,6 +1422,7 @@ static int nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir)
   memcpy(dir->u.nfs.nfs_verifier, ptr, DIRENT_NFS_VERFLEN);
   ptr += uint32_increment(DIRENT_NFS_VERFLEN);
 
+next_entry:
   /* Check if values follow.  If no values follow, then the EOF indication
    * will appear next.
    */
@@ -1545,7 +1438,8 @@ static int nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir)
       if (tmp != 0)
         {
           finfo("End of directory\n");
-          error = ENOENT;
+          error = -ENOENT;
+          goto errout_with_semaphore;
         }
 
       /* What would it mean if there were not data and we not at the end of
@@ -1555,10 +1449,8 @@ static int nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir)
        else
         {
           finfo("No data but not end of directory???\n");
-          error = EAGAIN;
+          goto read_dir;
         }
-
-      goto errout_with_semaphore;
     }
 
   /* If we are not at the end of the directory listing, then a set of entries
@@ -1592,8 +1484,6 @@ static int nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir)
   dir->u.nfs.nfs_cookie[0] = *ptr++;
   dir->u.nfs.nfs_cookie[1] = *ptr++;
 
-  ptr++; /* Just skip over the nextentry for now */
-
   /* Return the name of the node to the caller */
 
   if (length > NAME_MAX)
@@ -1605,12 +1495,18 @@ static int nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir)
   dir->fd_dir.d_name[length] = '\0';
   finfo("name: \"%s\"\n", dir->fd_dir.d_name);
 
+  if (strcmp(dir->fd_dir.d_name, ".") == 0 ||
+      strcmp(dir->fd_dir.d_name, "..") == 0)
+    {
+      goto next_entry; /* Skip . and .. */
+    }
+
   /* Get the file attributes associated with this name and return
    * the file type.
    */
 
   fhandle.length = (uint32_t)dir->u.nfs.nfs_fhsize;
-  memcpy(&fhandle.handle, dir->u.nfs.nfs_fhandle, DIRENT_NFS_MAXHANDLE);
+  memcpy(&fhandle.handle, dir->u.nfs.nfs_fhandle, fhandle.length);
 
   error = nfs_lookup(nmp, dir->fd_dir.d_name, &fhandle, &obj_attributes, NULL);
   if (error != OK)
@@ -1626,8 +1522,14 @@ static int nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir)
     {
     default:
     case NFNON:        /* Unknown type */
+      break;
+
     case NFSOCK:       /* Socket */
+      dir->fd_dir.d_type = DTYPE_SOCK;
+      break;
+
     case NFLNK:        /* Symbolic link */
+      dir->fd_dir.d_type = DTYPE_LINK;
       break;
 
     case NFREG:        /* Regular file */
@@ -1643,6 +1545,9 @@ static int nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir)
       break;
 
     case NFFIFO:       /* Named FIFO */
+      dir->fd_dir.d_type = DTYPE_FIFO;
+      break;
+
     case NFCHR:        /* Character special device file */
       dir->fd_dir.d_type = DTYPE_CHR;
       break;
@@ -1652,7 +1557,7 @@ static int nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir)
 
 errout_with_semaphore:
   nfs_semgive(nmp);
-  return -error;
+  return error;
 }
 
 /****************************************************************************
@@ -1702,17 +1607,18 @@ static void nfs_decode_args(FAR struct nfs_mount_parameters *nprmt,
 
   if ((argp->flags & NFSMNT_TIMEO) != 0 && argp->timeo > 0)
     {
-      uint32_t tmp = ((uint32_t)argp->timeo * NFS_HZ + 5) / 10;
-      if (tmp < NFS_MINTIMEO)
+      if (argp->timeo < NFS_MINTIMEO)
         {
-          tmp = NFS_MINTIMEO;
+          nprmt->timeo = NFS_MINTIMEO;
         }
-      else if (tmp > NFS_MAXTIMEO)
+      else if (argp->timeo > NFS_MAXTIMEO)
         {
-          tmp = NFS_MAXTIMEO;
+          nprmt->timeo = NFS_MAXTIMEO;
+        }
+      else
+        {
+          nprmt->timeo = argp->timeo;
         }
-
-      nprmt->timeo = tmp;
     }
 
   /* Get the selected retransmission count */
@@ -1840,9 +1746,7 @@ static int nfs_bind(FAR struct inode *blkdriver, FAR const void *data,
 {
   FAR struct nfs_args        *argp = (FAR struct nfs_args *)data;
   FAR struct nfsmount        *nmp;
-  struct rpcclnt             *rpc;
-  struct rpc_call_fs          getattr;
-  struct rpc_reply_getattr    resok;
+  FAR struct rpcclnt         *rpc;
   struct nfs_mount_parameters nprmt;
   uint32_t                    buflen;
   uint32_t                    tmp;
@@ -1895,7 +1799,7 @@ static int nfs_bind(FAR struct inode *blkdriver, FAR const void *data,
   if (!nmp)
     {
       ferr("ERROR: Failed to allocate mountpoint structure\n");
-      return ENOMEM;
+      return -ENOMEM;
     }
 
   /* Save the allocated I/O buffer size */
@@ -1921,31 +1825,26 @@ static int nfs_bind(FAR struct inode *blkdriver, FAR const void *data,
 
   /* Set initial values of other fields */
 
-  nmp->nm_timeo       = nprmt.timeo;
-  nmp->nm_retry       = nprmt.retry;
   nmp->nm_wsize       = nprmt.wsize;
   nmp->nm_rsize       = nprmt.rsize;
   nmp->nm_readdirsize = nprmt.readdirsize;
-  nmp->nm_fhsize      = NFSX_V3FHMAX;
 
   strncpy(nmp->nm_path, argp->path, 90);
   memcpy(&nmp->nm_nam, &argp->addr, argp->addrlen);
 
   /* Set up the sockets and per-host congestion */
 
-  nmp->nm_sotype  = argp->sotype;
-
-  if (nmp->nm_sotype == SOCK_DGRAM)
+  if (argp->sotype == SOCK_DGRAM)
     {
       /* Connection-less... connect now */
 
       /* Create an instance of the rpc state structure */
 
-      rpc = (struct rpcclnt *)kmm_zalloc(sizeof(struct rpcclnt));
+      rpc = (FAR struct rpcclnt *)kmm_zalloc(sizeof(struct rpcclnt));
       if (!rpc)
         {
           ferr("ERROR: Failed to allocate rpc structure\n");
-          return ENOMEM;
+          return -ENOMEM;
         }
 
       finfo("Connecting\n");
@@ -1954,8 +1853,9 @@ static int nfs_bind(FAR struct inode *blkdriver, FAR const void *data,
 
       rpc->rc_path       = nmp->nm_path;
       rpc->rc_name       = &nmp->nm_nam;
-      rpc->rc_sotype     = nmp->nm_sotype;
-      rpc->rc_retry      = nmp->nm_retry;
+      rpc->rc_sotype     = argp->sotype;
+      rpc->rc_timeo      = nprmt.timeo;
+      rpc->rc_retry      = nprmt.retry;
 
       nmp->nm_rpcclnt    = rpc;
 
@@ -1967,29 +1867,18 @@ static int nfs_bind(FAR struct inode *blkdriver, FAR const void *data,
         }
     }
 
-  nmp->nm_mounted        = true;
-  nmp->nm_so             = nmp->nm_rpcclnt->rc_so;
   nmp->nm_fhsize         = nmp->nm_rpcclnt->rc_fhsize;
-  memcpy(&nmp->nm_fh, &nmp->nm_rpcclnt->rc_fh, sizeof(nfsfh_t));
-
-  /* Get the file attributes */
+  nmp->nm_fh             = &nmp->nm_rpcclnt->rc_fh;
 
-  getattr.fs.fsroot.length = txdr_unsigned(nmp->nm_fhsize);
-  memcpy(&getattr.fs.fsroot.handle, &nmp->nm_fh, sizeof(nfsfh_t));
+  /* Get the file sytem info */
 
-  error = nfs_request(nmp, NFSPROC_GETATTR,
-                      (FAR void *)&getattr, sizeof(struct FS3args),
-                      (FAR void *)&resok, sizeof(struct rpc_reply_getattr));
+  error = nfs_fsinfo(nmp);
   if (error)
     {
-      ferr("ERROR: nfs_request failed: %d\n", error);
+      ferr("ERROR: nfs_fsinfo failed: %d\n", error);
       goto bad;
     }
 
-  /* Save the file attributes */
-
-  memcpy(&nmp->nm_fattr, &resok.attr, sizeof(struct nfs_fattr));
-
   /* Mounted! */
 
   *handle = (FAR void *)nmp;
@@ -2003,21 +1892,15 @@ bad:
     {
       /* Disconnect from the server */
 
-      rpcclnt_disconnect(nmp->nm_rpcclnt);
-
-      /* Free connection-related resources */
-
-      nxsem_destroy(&nmp->nm_sem);
-      if (nmp->nm_so)
-        {
-          kmm_free(nmp->nm_so);
-        }
-
       if (nmp->nm_rpcclnt)
         {
+          rpcclnt_disconnect(nmp->nm_rpcclnt);
           kmm_free(nmp->nm_rpcclnt);
         }
 
+      /* Free connection-related resources */
+
+      nxsem_destroy(&nmp->nm_sem);
       kmm_free(nmp);
     }
 
@@ -2062,7 +1945,7 @@ static int nfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
        * no open file references.
        */
 
-      error = (flags != 0) ? ENOSYS : EBUSY;
+      error = (flags != 0) ? -ENOSYS : -EBUSY;
       goto errout_with_semaphore;
     }
 
@@ -2081,15 +1964,14 @@ static int nfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
   /* And free any allocated resources */
 
   nxsem_destroy(&nmp->nm_sem);
-  kmm_free(nmp->nm_so);
   kmm_free(nmp->nm_rpcclnt);
   kmm_free(nmp);
 
-  return -error;
+  return error;
 
 errout_with_semaphore:
   nfs_semgive(nmp);
-  return -error;
+  return error;
 }
 
 /****************************************************************************
@@ -2099,30 +1981,32 @@ errout_with_semaphore:
  *   Return information about root directory.
  *
  * Returned Value:
- *   0 on success; positive errno value on failure
+ *   0 on success; negative errno value on failure
  *
  * Assumptions:
  *   The caller has exclusive access to the NFS mount structure
  *
  ****************************************************************************/
 
-int nfs_fsinfo(FAR struct nfsmount *nmp)
+static int nfs_fsinfo(FAR struct nfsmount *nmp)
 {
-  struct rpc_call_fs fsinfo;
-  struct rpc_reply_fsinfo fsp;
+  FAR struct rpc_call_fs *fsinfo;
+  FAR struct rpc_reply_getattr *attr;
+  FAR uint32_t *ptr;
   uint32_t pref;
   uint32_t max;
   int error = 0;
 
-  fsinfo.fs.fsroot.length = txdr_unsigned(nmp->nm_fhsize);
-  fsinfo.fs.fsroot.handle = nmp->nm_fh;
+  fsinfo = &nmp->nm_msgbuffer.fsinfo;
+  fsinfo->fs.fsroot.length = txdr_unsigned(nmp->nm_fhsize);
+  memcpy(&fsinfo->fs.fsroot.handle, nmp->nm_fh, nmp->nm_fhsize);
 
   /* Request FSINFO from the server */
 
   nfs_statistics(NFSPROC_FSINFO);
   error = nfs_request(nmp, NFSPROC_FSINFO,
-                      (FAR void *)&fsinfo, sizeof(struct FS3args),
-                      (FAR void *)&fsp, sizeof(struct rpc_reply_fsinfo));
+                      (FAR void *)fsinfo, sizeof(struct FS3args),
+                      (FAR void *)nmp->nm_iobuffer, nmp->nm_buflen);
   if (error)
     {
       return error;
@@ -2130,33 +2014,21 @@ int nfs_fsinfo(FAR struct nfsmount *nmp)
 
   /* Save the root file system attributes */
 
-#if 0
-  memcpy(&nmp->nm_fattr. &fsp.obj_attributes, sizeof(struct nfs_fattr));
-#endif
-
-  pref = fxdr_unsigned(uint32_t, fsp.fsinfo.fs_wtpref);
-  if (pref < nmp->nm_wsize)
+  ptr = (FAR uint32_t *)&((FAR struct rpc_reply_fsinfo *)nmp->nm_iobuffer)->fsinfo;
+  if (*ptr++ != 0)
     {
-      nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) & ~(NFS_FABLKSIZE - 1);
+      memcpy(&nmp->nm_fattr, ptr, sizeof(struct nfs_fattr));
+      ptr += uint32_increment(sizeof(struct nfs_fattr));
     }
 
-  max = fxdr_unsigned(uint32_t, fsp.fsinfo.fs_wtmax);
-  if (max < nmp->nm_wsize)
-    {
-      nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
-      if (nmp->nm_wsize == 0)
-        {
-          nmp->nm_wsize = max;
-        }
-    }
+  max  = fxdr_unsigned(uint32_t, *ptr++);
+  pref = fxdr_unsigned(uint32_t, *ptr++);
+  ptr += 1; /* Skip fs_rtmult */
 
-  pref = fxdr_unsigned(uint32_t, fsp.fsinfo.fs_rtpref);
   if (pref < nmp->nm_rsize)
     {
       nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) & ~(NFS_FABLKSIZE - 1);
     }
-
-  max = fxdr_unsigned(uint32_t, fsp.fsinfo.fs_rtmax);
   if (max < nmp->nm_rsize)
     {
       nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
@@ -2166,19 +2038,44 @@ int nfs_fsinfo(FAR struct nfsmount *nmp)
         }
     }
 
-  pref = fxdr_unsigned(uint32_t, fsp.fsinfo.fs_dtpref);
+  max  = fxdr_unsigned(uint32_t, *ptr++);
+  pref = fxdr_unsigned(uint32_t, *ptr++);
+  ptr += 1; /* Skip fs_wtmult */
+
+  if (pref < nmp->nm_wsize)
+    {
+      nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) & ~(NFS_FABLKSIZE - 1);
+    }
+  if (max < nmp->nm_wsize)
+    {
+      nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
+      if (nmp->nm_wsize == 0)
+        {
+          nmp->nm_wsize = max;
+        }
+    }
+
+  pref = fxdr_unsigned(uint32_t, *ptr++);
   if (pref < nmp->nm_readdirsize)
     {
       nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) & ~(NFS_DIRBLKSIZ - 1);
     }
 
-  if (max < nmp->nm_readdirsize)
+  /* Get the file attributes if needed */
+
+  if (nmp->nm_fattr.fa_type == 0)
     {
-      nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1);
-      if (nmp->nm_readdirsize == 0)
+      nfs_statistics(NFSPROC_GETATTR);
+      error = nfs_request(nmp, NFSPROC_GETATTR,
+                          (FAR void *)fsinfo, sizeof(struct FS3args),
+                          (FAR void *)nmp->nm_iobuffer, nmp->nm_buflen);
+      if (error)
         {
-          nmp->nm_readdirsize = max;
+          return error;
         }
+
+      attr = (FAR struct rpc_reply_getattr *)nmp->nm_iobuffer;
+      memcpy(&nmp->nm_fattr, &attr->attr, sizeof(struct nfs_fattr));
     }
 
   return OK;
@@ -2211,25 +2108,15 @@ static int nfs_statfs(FAR struct inode *mountpt, FAR struct statfs *sbp)
 
   nmp = (FAR struct nfsmount *)mountpt->i_private;
 
-  /* Check if the mount is still healthy */
-
   nfs_semtake(nmp);
-  error = nfs_checkmount(nmp);
-  if (error != OK)
-    {
-      ferr("ERROR: nfs_checkmount failed: %d\n", error);
-      goto errout_with_semaphore;
-    }
 
   /* Fill in the statfs info */
 
   sbp->f_type = NFS_SUPER_MAGIC;
 
-  nfs_fsinfo(nmp);
-
   fsstat = &nmp->nm_msgbuffer.fsstat;
   fsstat->fs.fsroot.length = txdr_unsigned(nmp->nm_fhsize);
-  memcpy(&fsstat->fs.fsroot.handle, &nmp->nm_fh, sizeof(nfsfh_t));
+  memcpy(&fsstat->fs.fsroot.handle, nmp->nm_fh, nmp->nm_fhsize);
 
   nfs_statistics(NFSPROC_FSSTAT);
   error = nfs_request(nmp, NFSPROC_FSSTAT,
@@ -2256,7 +2143,7 @@ static int nfs_statfs(FAR struct inode *mountpt, FAR struct statfs *sbp)
 
 errout_with_semaphore:
   nfs_semgive(nmp);
-  return -error;
+  return error;
 }
 
 /****************************************************************************
@@ -2270,7 +2157,7 @@ errout_with_semaphore:
  *
  ****************************************************************************/
 
-static int nfs_remove(struct inode *mountpt, const char *relpath)
+static int nfs_remove(FAR struct inode *mountpt, FAR const char *relpath)
 {
   FAR struct nfsmount    *nmp;
   struct file_handle      fhandle;
@@ -2289,15 +2176,7 @@ static int nfs_remove(struct inode *mountpt, const char *relpath)
 
   nmp = (FAR struct nfsmount *)mountpt->i_private;
 
-  /* Check if the mount is still healthy */
-
   nfs_semtake(nmp);
-  error = nfs_checkmount(nmp);
-  if (error != OK)
-    {
-      ferr("ERROR: nfs_checkmount failed: %d\n", error);
-      goto errout_with_semaphore;
-    }
 
   /* Find the NFS node of the directory containing the file to be deleted */
 
@@ -2319,7 +2198,7 @@ static int nfs_remove(struct inode *mountpt, const char *relpath)
   reqlen += sizeof(uint32_t);
 
   memcpy(ptr, &fhandle.handle, fhandle.length);
-  reqlen += (int)fhandle.length;
+  reqlen += uint32_alignup(fhandle.length);
   ptr    += uint32_increment(fhandle.length);
 
   /* Copy the variable-length file name */
@@ -2341,7 +2220,7 @@ static int nfs_remove(struct inode *mountpt, const char *relpath)
 
 errout_with_semaphore:
   nfs_semgive(nmp);
-  return -error;
+  return error;
 }
 
 /****************************************************************************
@@ -2355,9 +2234,9 @@ errout_with_semaphore:
  *
  ****************************************************************************/
 
-static int nfs_mkdir(struct inode *mountpt, const char *relpath, mode_t mode)
+static int nfs_mkdir(FAR struct inode *mountpt, FAR const char *relpath, mode_t mode)
 {
-  struct nfsmount       *nmp;
+  FAR struct nfsmount   *nmp;
   struct file_handle     fhandle;
   struct nfs_fattr       fattr;
   char                   dirname[NAME_MAX + 1];
@@ -2375,15 +2254,7 @@ static int nfs_mkdir(struct inode *mountpt, const char *relpath, mode_t mode)
 
   nmp = (FAR struct nfsmount *) mountpt->i_private;
 
-  /* Check if the mount is still healthy */
-
   nfs_semtake(nmp);
-  error = nfs_checkmount(nmp);
-  if (error != OK)
-    {
-      ferr("ERROR: nfs_checkmount: %d\n", error);
-      goto errout_with_semaphore;
-    }
 
   /* Find the NFS node of the directory containing the directory to be created */
 
@@ -2391,7 +2262,7 @@ static int nfs_mkdir(struct inode *mountpt, const char *relpath, mode_t mode)
   if (error != OK)
     {
       ferr("ERROR: nfs_finddir returned: %d\n", error);
-      return error;
+      goto errout_with_semaphore;
     }
 
   /* Format the MKDIR call message arguments */
@@ -2406,7 +2277,7 @@ static int nfs_mkdir(struct inode *mountpt, const char *relpath, mode_t mode)
 
   memcpy(ptr, &fhandle.handle, fhandle.length);
   ptr    += uint32_increment(fhandle.length);
-  reqlen += (int)fhandle.length;
+  reqlen += uint32_alignup(fhandle.length);
 
   /* Copy the variable-length directory name */
 
@@ -2428,7 +2299,8 @@ static int nfs_mkdir(struct inode *mountpt, const char *relpath, mode_t mode)
 
   tmp = mode & (NFSMODE_IXOTH | NFSMODE_IWOTH | NFSMODE_IROTH |
                 NFSMODE_IXGRP | NFSMODE_IWGRP | NFSMODE_IRGRP |
-                NFSMODE_IXUSR | NFSMODE_IWUSR | NFSMODE_IRUSR);
+                NFSMODE_IXUSR | NFSMODE_IWUSR | NFSMODE_IRUSR |
+                NFSMODE_SAVETEXT | NFSMODE_ISGID | NFSMODE_ISUID);
   *ptr++  = txdr_unsigned(tmp);
   reqlen += sizeof(uint32_t);
 
@@ -2468,7 +2340,7 @@ static int nfs_mkdir(struct inode *mountpt, const char *relpath, mode_t mode)
 
 errout_with_semaphore:
   nfs_semgive(nmp);
-  return -error;
+  return error;
 }
 
 /****************************************************************************
@@ -2482,9 +2354,9 @@ errout_with_semaphore:
  *
  ****************************************************************************/
 
-static int nfs_rmdir(struct inode *mountpt, const char *relpath)
+static int nfs_rmdir(FAR struct inode *mountpt, FAR const char *relpath)
 {
-  struct nfsmount       *nmp;
+  FAR struct nfsmount   *nmp;
   struct file_handle     fhandle;
   struct nfs_fattr       fattr;
   char                   dirname[NAME_MAX + 1];
@@ -2499,17 +2371,9 @@ static int nfs_rmdir(struct inode *mountpt, const char *relpath)
 
   /* Get the mountpoint private data from the inode structure */
 
-  nmp = (struct nfsmount *)mountpt->i_private;
-
-  /* Check if the mount is still healthy */
+  nmp = (FAR struct nfsmount *)mountpt->i_private;
 
   nfs_semtake(nmp);
-  error = nfs_checkmount(nmp);
-  if (error != OK)
-    {
-      ferr("ERROR: nfs_checkmount failed: %d\n", error);
-      goto errout_with_semaphore;
-    }
 
   /* Find the NFS node of the directory containing the directory to be removed */
 
@@ -2517,7 +2381,7 @@ static int nfs_rmdir(struct inode *mountpt, const char *relpath)
   if (error != OK)
     {
       ferr("ERROR: nfs_finddir returned: %d\n", error);
-      return error;
+      goto errout_with_semaphore;
     }
 
   /* Set up the RMDIR call message arguments */
@@ -2531,7 +2395,7 @@ static int nfs_rmdir(struct inode *mountpt, const char *relpath)
   reqlen += sizeof(uint32_t);
 
   memcpy(ptr, &fhandle.handle, fhandle.length);
-  reqlen += (int)fhandle.length;
+  reqlen += uint32_alignup(fhandle.length);
   ptr    += uint32_increment(fhandle.length);
 
   /* Copy the variable-length directory name */
@@ -2553,7 +2417,7 @@ static int nfs_rmdir(struct inode *mountpt, const char *relpath)
 
 errout_with_semaphore:
   nfs_semgive(nmp);
-  return -error;
+  return error;
 }
 
 /****************************************************************************
@@ -2567,10 +2431,10 @@ errout_with_semaphore:
  *
  ****************************************************************************/
 
-static int nfs_rename(struct inode *mountpt, const char *oldrelpath,
-                      const char *newrelpath)
+static int nfs_rename(FAR struct inode *mountpt, FAR const char *oldrelpath,
+                      FAR const char *newrelpath)
 {
-  struct nfsmount        *nmp;
+  FAR struct nfsmount    *nmp;
   struct file_handle      from_handle;
   struct file_handle      to_handle;
   char                    from_name[NAME_MAX + 1];
@@ -2587,17 +2451,9 @@ static int nfs_rename(struct inode *mountpt, const char *oldrelpath,
 
   /* Get the mountpoint private data from the inode structure */
 
-  nmp = (struct nfsmount *)mountpt->i_private;
-
-  /* Check if the mount is still healthy */
+  nmp = (FAR struct nfsmount *)mountpt->i_private;
 
   nfs_semtake(nmp);
-  error = nfs_checkmount(nmp);
-  if (error != OK)
-    {
-      ferr("ERROR: nfs_checkmount returned: %d\n", error);
-      goto errout_with_semaphore;
-    }
 
   /* Find the NFS node of the directory containing the 'from' object */
 
@@ -2605,16 +2461,16 @@ static int nfs_rename(struct inode *mountpt, const char *oldrelpath,
   if (error != OK)
     {
       ferr("ERROR: nfs_finddir returned: %d\n", error);
-      return error;
+      goto errout_with_semaphore;
     }
 
-  /* Find the NFS node of the directory containing the 'from' object */
+  /* Find the NFS node of the directory containing the 'to' object */
 
   error = nfs_finddir(nmp, newrelpath, &to_handle, &fattr, to_name);
   if (error != OK)
     {
       ferr("ERROR: nfs_finddir returned: %d\n", error);
-      return error;
+      goto errout_with_semaphore;
     }
 
   /* Format the RENAME RPC arguments */
@@ -2628,7 +2484,7 @@ static int nfs_rename(struct inode *mountpt, const char *oldrelpath,
   reqlen += sizeof(uint32_t);
 
   memcpy(ptr, &from_handle.handle, from_handle.length);
-  reqlen += (int)from_handle.length;
+  reqlen += uint32_alignup(from_handle.length);
   ptr    += uint32_increment(from_handle.length);
 
   /* Copy the variable-length 'from' object name */
@@ -2649,7 +2505,7 @@ static int nfs_rename(struct inode *mountpt, const char *oldrelpath,
 
   memcpy(ptr, &to_handle.handle, to_handle.length);
   ptr    += uint32_increment(to_handle.length);
-  reqlen += (int)to_handle.length;
+  reqlen += uint32_alignup(to_handle.length);
 
   /* Copy the variable-length 'to' object name */
 
@@ -2670,49 +2526,34 @@ static int nfs_rename(struct inode *mountpt, const char *oldrelpath,
 
 errout_with_semaphore:
   nfs_semgive(nmp);
-  return -error;
+  return error;
 }
 
 /****************************************************************************
- * Name: nfs_stat_common
+ * Name: nfs_stat_mode
  *
  * Description:
- *   Return information about the file system object described by 'info'
+ *   Convert NFSv3's type and mode to NuttX's mode
  *
  * Returned Value:
- *   None
+ *   Return NuttX's mode
  *
  ****************************************************************************/
 
-static void nfs_stat_common(FAR struct nfs_statinfo_s *info,
-                            FAR struct stat *buf)
+static mode_t nfs_stat_mode(unsigned int mode, unsigned int type)
 {
-  mode_t mode;
-
-  /* Here we exploit the fact that most mode bits are the same in NuttX
+  /* Here we exploit the fact all mode bits are the same in NuttX
    * as in the NFSv3 spec.
    */
 
-  mode = info->ns_mode &
-           (NFSMODE_IXOTH | NFSMODE_IWOTH | NFSMODE_IROTH |
-            NFSMODE_IXGRP | NFSMODE_IWGRP | NFSMODE_IRGRP |
-            NFSMODE_IXUSR | NFSMODE_IWUSR | NFSMODE_IRUSR);
-
-  /* Handle the cases that are not the same */
-
-  if ((info->ns_mode & NFSMODE_ISGID) != 0)
-    {
-      mode |= S_ISGID;
-    }
-
-  if ((info->ns_mode & NFSMODE_ISUID) != 0)
-    {
-      mode |= S_ISUID;
-    }
+  mode &= (NFSMODE_IXOTH | NFSMODE_IWOTH | NFSMODE_IROTH |
+           NFSMODE_IXGRP | NFSMODE_IWGRP | NFSMODE_IRGRP |
+           NFSMODE_IXUSR | NFSMODE_IWUSR | NFSMODE_IRUSR |
+           NFSMODE_SAVETEXT | NFSMODE_ISGID | NFSMODE_ISUID);
 
   /* Now OR in the file type */
 
-  switch (info->ns_type)
+  switch (type)
     {
     default:
     case NFNON:   /* Unknown type */
@@ -2743,17 +2584,11 @@ static void nfs_stat_common(FAR struct nfs_statinfo_s *info,
       break;
 
     case NFFIFO:  /* Named pipe */
-      mode |= S_IFMT;
+      mode |= S_IFIFO;
       break;
     }
 
-  buf->st_mode    = mode;
-  buf->st_size    = (off_t)info->ns_size;
-  buf->st_blksize = 0;
-  buf->st_blocks  = 0;
-  buf->st_mtime   = info->ns_mtime;
-  buf->st_atime   = info->ns_atime;
-  buf->st_ctime   = info->ns_ctime;
+  return mode;
 }
 
 /****************************************************************************
@@ -2767,13 +2602,12 @@ static void nfs_stat_common(FAR struct nfs_statinfo_s *info,
  *
  ****************************************************************************/
 
-static int nfs_stat(struct inode *mountpt, const char *relpath,
-                    struct stat *buf)
+static int nfs_stat(FAR struct inode *mountpt, FAR const char *relpath,
+                    FAR struct stat *buf)
 {
-  struct nfsmount *nmp;
+  FAR struct nfsmount *nmp;
   struct file_handle fhandle;
-  struct nfs_fattr obj_attributes;
-  struct nfs_statinfo_s info;
+  struct nfs_fattr attributes;
   struct timespec ts;
   int error;
 
@@ -2786,19 +2620,13 @@ static int nfs_stat(struct inode *mountpt, const char *relpath,
   nmp = (FAR struct nfsmount *)mountpt->i_private;
   DEBUGASSERT(nmp && buf);
 
-  /* Check if the mount is still healthy */
+  memset(buf, 0, sizeof(*buf));
 
   nfs_semtake(nmp);
-  error = nfs_checkmount(nmp);
-  if (error != OK)
-    {
-      ferr("ERROR: nfs_checkmount failed: %d\n", error);
-      goto errout_with_semaphore;
-    }
 
   /* Get the file handle attributes of the requested node */
 
-  error = nfs_findnode(nmp, relpath, &fhandle, &obj_attributes, NULL);
+  error = nfs_findnode(nmp, relpath, &fhandle, &attributes, NULL);
   if (error != OK)
     {
       ferr("ERROR: nfs_findnode failed: %d\n", error);
@@ -2807,26 +2635,22 @@ static int nfs_stat(struct inode *mountpt, const char *relpath,
 
   /* Extract the file mode, file type, and file size. */
 
-  info.ns_mode  = fxdr_unsigned(uint16_t, obj_attributes.fa_mode);
-  info.ns_type  = fxdr_unsigned(uint8_t, obj_attributes.fa_type);
-  info.ns_size  = fxdr_hyper(&obj_attributes.fa_size);
+  buf->st_mode  = nfs_stat_mode(fxdr_unsigned(uint16_t, attributes.fa_mode),
+                                fxdr_unsigned(uint8_t, attributes.fa_type));
+  buf->st_size  = fxdr_hyper(&attributes.fa_size);
 
   /* Extract time values as type time_t in units of seconds */
 
-  fxdr_nfsv3time(&obj_attributes.fa_mtime, &ts);
-  info.ns_mtime = ts.tv_sec;
-
-  fxdr_nfsv3time(&obj_attributes.fa_atime, &ts);
-  info.ns_atime = ts.tv_sec;
+  fxdr_nfsv3time(&attributes.fa_mtime, &ts);
+  buf->st_mtime = ts.tv_sec;
 
-  fxdr_nfsv3time(&obj_attributes.fa_ctime, &ts);
-  info.ns_ctime = ts.tv_sec;
+  fxdr_nfsv3time(&attributes.fa_atime, &ts);
+  buf->st_atime = ts.tv_sec;
 
-  /* Then update the stat buffer with this information */
-
-  nfs_stat_common(&info, buf);
+  fxdr_nfsv3time(&attributes.fa_ctime, &ts);
+  buf->st_ctime = ts.tv_sec;
 
 errout_with_semaphore:
   nfs_semgive(nmp);
-  return -error;
+  return error;
 }
diff --git a/fs/nfs/rpc.h b/fs/nfs/rpc.h
index d392474..1139338 100644
--- a/fs/nfs/rpc.h
+++ b/fs/nfs/rpc.h
@@ -75,6 +75,8 @@
  ****************************************************************************/
 
 #include <sys/types.h>
+#include <nuttx/net/net.h>
+
 #include "nfs_proto.h"
 
 /****************************************************************************
@@ -161,25 +163,13 @@
  * Public Types
  ****************************************************************************/
 
-/* Global RPC statistics */
-
-#ifdef CONFIG_NFS_STATISTICS
-struct rpcstats
-{
-  int rpcretries;
-  int rpcrequests;
-  int rpctimeouts;
-  int rpcinvalid;
-};
-#endif
-
 /* PMAP headers */
 
 struct call_args_pmap
 {
   uint32_t prog;
   uint32_t vers;
-  uint32_t proc;
+  uint32_t prot;
   uint32_t port;
 };
 
@@ -218,7 +208,7 @@ struct call_result_mount
   uint32_t status;
   struct file_handle fhandle;
   uint32_t authlen;
-  uint32_t autolist[AUTH_MAX];
+  uint32_t authlist[AUTH_MAX];
 };
 
 /* Generic RPC call headers */
@@ -231,11 +221,11 @@ struct rpc_auth_info
 
 struct auth_unix
 {
-  int32_t stamp;
-  uint8_t hostname;           /* null */
-  int32_t uid;
-  int32_t gid;
-  int32_t gidlist;            /* null */
+  uint32_t stamp;
+  uint32_t hostname;          /* null */
+  uint32_t uid;
+  uint32_t gid;
+  uint32_t gidlist;           /* null */
 };
 
 struct rpc_call_header
@@ -349,11 +339,7 @@ struct rpc_reply_header
 
 struct nfs_reply_header
 {
-  uint32_t rp_xid;            /* Request transaction id */
-  uint32_t rp_direction;      /* Call direction (1) */
-  uint32_t type;
-  struct rpc_auth_info rpc_verfi;
-  uint32_t status;
+  struct rpc_reply_header rh;
   uint32_t nfs_status;
 };
 
@@ -376,115 +362,100 @@ struct rpc_reply_umount
 
 struct rpc_reply_create
 {
-  struct rpc_reply_header rh;
-  uint32_t status;
+  struct nfs_reply_header rh;
   struct CREATE3resok create;
 };
 
 struct rpc_reply_lookup
 {
-  struct rpc_reply_header rh;
-  uint32_t status;
+  struct nfs_reply_header rh;
   struct LOOKUP3resok lookup;
 };
 
 struct rpc_reply_write
 {
-  struct rpc_reply_header rh;
-  uint32_t status;
+  struct nfs_reply_header rh;
   struct WRITE3resok write;      /* Variable length */
 };
 
 struct rpc_reply_read
 {
-  struct rpc_reply_header rh;
-  uint32_t status;
+  struct nfs_reply_header rh;
   struct READ3resok read;        /* Variable length */
 };
 
 #define SIZEOF_rpc_reply_read(n) \
-  (sizeof(struct rpc_reply_header) + sizeof(uint32_t) + \
-   SIZEOF_READ3resok(n))
+  (sizeof(struct nfs_reply_header) + SIZEOF_READ3resok(n))
 
 struct rpc_reply_remove
 {
-  struct rpc_reply_header rh;
-  uint32_t status;
+  struct nfs_reply_header rh;
   struct REMOVE3resok remove;
 };
 
 struct rpc_reply_rename
 {
-  struct rpc_reply_header rh;
-  uint32_t status;
+  struct nfs_reply_header rh;
   struct RENAME3resok rename;
 };
 
 struct rpc_reply_mkdir
 {
-  struct rpc_reply_header rh;
-  uint32_t status;
+  struct nfs_reply_header rh;
   struct MKDIR3resok mkdir;
 };
 
 struct rpc_reply_rmdir
 {
-  struct rpc_reply_header rh;
-  uint32_t status;
+  struct nfs_reply_header rh;
   struct RMDIR3resok rmdir;
 };
 
 struct rpc_reply_readdir
 {
-  struct rpc_reply_header rh;
-  uint32_t status;
+  struct nfs_reply_header rh;
   struct READDIR3resok readdir;
 };
 
 #define SIZEOF_rpc_reply_readdir(n) \
-  (sizeof(struct rpc_reply_header) + sizeof(uint32_t) + \
-   SIZEOF_READDIR3resok(n))
+  (sizeof(struct nfs_reply_header) + SIZEOF_READDIR3resok(n))
 
 struct rpc_reply_fsinfo
 {
-  struct rpc_reply_header rh;
-  uint32_t status;
+  struct nfs_reply_header rh;
   struct nfsv3_fsinfo fsinfo;
 };
 
 struct rpc_reply_fsstat
 {
-  struct rpc_reply_header rh;
-  uint32_t status;
+  struct nfs_reply_header rh;
   struct nfs_statfs fsstat;
 };
 
 struct rpc_reply_getattr
 {
-  struct rpc_reply_header rh;
-  uint32_t status;
+  struct nfs_reply_header rh;
   struct nfs_fattr attr;
 };
 
 struct rpc_reply_setattr
 {
-  struct rpc_reply_header rh;
-  uint32_t status;
+  struct nfs_reply_header rh;
   struct SETATTR3resok setattr;
 };
 
-struct  rpcclnt
+struct rpcclnt
 {
-  nfsfh_t  rc_fh;             /* File handle of the root directory */
-  uint8_t  rc_fhsize;         /* File size of the root directory */
-  char    *rc_path;           /* Server's path of the mounted directory */
+  nfsfh_t   rc_fh;            /* File handle of the root directory */
+  uint8_t   rc_fhsize;        /* File size of the root directory */
+  FAR char *rc_path;          /* Server's path of the mounted directory */
 
-  struct  sockaddr *rc_name;
-  struct  socket *rc_so;      /* RPC socket */
+  FAR struct sockaddr *rc_name;
+  struct socket rc_so;        /* RPC socket */
 
-  bool     rc_timeout;        /* Receipt of reply timed out */
-  uint8_t  rc_sotype;         /* Type of socket */
-  uint8_t  rc_retry;          /* Max retries */
+  uint8_t   rc_sotype;        /* Type of socket */
+  uint8_t   rc_timeo;         /* Timeout value (in deciseconds) */
+  uint8_t   rc_retry;         /* Max retries */
 };
 
 /****************************************************************************
@@ -493,12 +464,10 @@ struct  rpcclnt
 
 void rpcclnt_init(void);
 int  rpcclnt_connect(FAR struct rpcclnt *rpc);
-int  rpcclnt_reconnect(FAR struct rpcclnt *rpc);
 void rpcclnt_disconnect(FAR struct rpcclnt *rpc);
 int  rpcclnt_umount(FAR struct rpcclnt *rpc);
-void rpcclnt_safedisconnect(FAR struct rpcclnt *rpc);
-int  rpcclnt_request(FAR struct rpcclnt *rpc, int procnum, int prog, int version,
-                     FAR void *request, size_t reqlen,
+int  rpcclnt_request(FAR struct rpcclnt *rpc, int procnum, int prog,
+                     int version, FAR void *request, size_t reqlen,
                      FAR void *response, size_t resplen);
 
 #endif /* __FS_NFS_RPC_H */
diff --git a/fs/nfs/rpc_clnt.c b/fs/nfs/rpc_clnt.c
index 180c234..aa40e46 100644
--- a/fs/nfs/rpc_clnt.c
+++ b/fs/nfs/rpc_clnt.c
@@ -89,7 +89,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <debug.h>
-#include <nuttx/kmalloc.h>
 
 #include "xdr_subs.h"
 #include "nfs_proto.h"
@@ -108,6 +107,22 @@
 #endif
 
 /****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* Global RPC statistics */
+
+#ifdef CONFIG_NFS_STATISTICS
+struct rpcstats
+{
+  int rpcretries;
+  int rpcrequests;
+  int rpctimeouts;
+  int rpcinvalid;
+};
+#endif
+
+/****************************************************************************
  * Private Data
  ****************************************************************************/
 
@@ -116,11 +131,6 @@
 static uint32_t rpc_reply;
 static uint32_t rpc_call;
 static uint32_t rpc_vers;
-static uint32_t rpc_msgdenied;
-static uint32_t rpc_mismatch;
-static uint32_t rpc_auth_unix;
-static uint32_t rpc_msgaccepted;
-static uint32_t rpc_autherr;
 static uint32_t rpc_auth_null;
 
 /* Global statics for all client instances.  Cleared by NuttX on boot-up. */
@@ -133,12 +143,12 @@ static struct rpcstats rpcstats;
  * Private Function Prototypes
  ****************************************************************************/
 
-static int rpcclnt_send(FAR struct rpcclnt *rpc, int procid, int prog,
+static int rpcclnt_send(FAR struct rpcclnt *rpc,
                         FAR void *call, int reqlen);
-static int rpcclnt_receive(FAR struct rpcclnt *rpc, struct sockaddr *aname,
-                           int proc, int program, void *reply, size_t resplen);
-static int rpcclnt_reply(FAR struct rpcclnt *rpc, int procid, int prog,
-                         void *reply, size_t resplen);
+static int rpcclnt_receive(FAR struct rpcclnt *rpc,
+                           FAR void *reply, size_t resplen);
+static int rpcclnt_reply(FAR struct rpcclnt *rpc,
+                         FAR void *reply, size_t resplen);
 static uint32_t rpcclnt_newxid(void);
 static void rpcclnt_fmtheader(FAR struct rpc_call_header *ch,
                               uint32_t xid, int procid, int prog, int vers);
@@ -154,11 +164,11 @@ static void rpcclnt_fmtheader(FAR struct rpc_call_header *ch,
  *   This is the nfs send routine.
  *
  * Returned Value:
- *   Returns zero on success or a (positive) errno value on failure.
+ *   Returns zero on success or a (negative) errno value on failure.
  *
  ****************************************************************************/
 
-static int rpcclnt_send(FAR struct rpcclnt *rpc, int procid, int prog,
+static int rpcclnt_send(FAR struct rpcclnt *rpc,
                         FAR void *call, int reqlen)
 {
   ssize_t nbytes;
@@ -170,13 +180,13 @@ static int rpcclnt_send(FAR struct rpcclnt *rpc, int procid, int prog,
    * On failure, it returns a negated errno value.
    */
 
-  nbytes = psock_send(rpc->rc_so, call, reqlen, 0);
+  nbytes = psock_send(&rpc->rc_so, call, reqlen, 0);
 
   if (nbytes < 0)
     {
       /* psock_sendto failed */
 
-      ret = (int)-nbytes;
+      ret = nbytes;
       ferr("ERROR: psock_sendto failed: %d\n", ret);
     }
 
@@ -187,24 +197,21 @@ static int rpcclnt_send(FAR struct rpcclnt *rpc, int procid, int prog,
  * Name: rpcclnt_receive
  *
  * Description:
- *   Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all done
- *   by psock_recvfrom().
+ *   Receive a Sun RPC Request/Reply.
  *
  ****************************************************************************/
 
-static int rpcclnt_receive(FAR struct rpcclnt *rpc, FAR struct sockaddr *aname,
-                           int proc, int program, FAR void *reply,
-                           size_t resplen)
+static int rpcclnt_receive(FAR struct rpcclnt *rpc,
+                           FAR void *reply, size_t resplen)
 {
   ssize_t nbytes;
   int error = 0;
 
-  socklen_t fromlen = sizeof(struct sockaddr);
-  nbytes = psock_recvfrom(rpc->rc_so, reply, resplen, 0, aname, &fromlen);
+  nbytes = psock_recv(&rpc->rc_so, reply, resplen, 0);
   if (nbytes < 0)
     {
-      error = (int)-nbytes;
-      ferr("ERROR: psock_recvfrom failed: %d\n", error);
+      error = nbytes;
+      ferr("ERROR: psock_recv failed: %d\n", error);
     }
 
   return error;
@@ -218,26 +225,17 @@ static int rpcclnt_receive(FAR struct rpcclnt *rpc, FAR struct sockaddr *aname,
  *
  ****************************************************************************/
 
-static int rpcclnt_reply(FAR struct rpcclnt *rpc, int procid, int prog,
+static int rpcclnt_reply(FAR struct rpcclnt *rpc,
                          FAR void *reply, size_t resplen)
 {
   int error;
 
   /* Get the next RPC reply from the socket */
 
-  error = rpcclnt_receive(rpc, rpc->rc_name, procid, prog, reply, resplen);
+  error = rpcclnt_receive(rpc, reply, resplen);
   if (error != 0)
     {
       ferr("ERROR: rpcclnt_receive returned: %d\n", error);
-
-      /* If we failed because of a timeout, then try sending the CALL
-       * message again.
-       */
-
-      if (error == EAGAIN || error == ETIMEDOUT)
-        {
-          rpc->rc_timeout = true;
-        }
     }
 
   /* Get the xid and check that it is an RPC replysvr */
@@ -251,7 +249,7 @@ static int rpcclnt_reply(FAR struct rpcclnt *rpc, int procid, int prog,
         {
           ferr("ERROR: Different RPC REPLY returned\n");
           rpc_statistics(rpcinvalid);
-          error = EPROTO;
+          error = -EPROTO;
         }
     }
 
@@ -271,9 +269,9 @@ static uint32_t rpcclnt_newxid(void)
   static uint32_t rpcclnt_xid = 0;
   static uint32_t rpcclnt_xid_touched = 0;
 
-  srand(time(NULL));
   if ((rpcclnt_xid == 0) && (rpcclnt_xid_touched == 0))
     {
+      srand(time(NULL));
       rpcclnt_xid = rand();
       rpcclnt_xid_touched = 1;
     }
@@ -342,11 +340,6 @@ void rpcclnt_init(void)
   rpc_reply = txdr_unsigned(RPC_REPLY);
   rpc_vers = txdr_unsigned(RPC_VER2);
   rpc_call = txdr_unsigned(RPC_CALL);
-  rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
-  rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
-  rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
-  rpc_autherr = txdr_unsigned(RPC_AUTHERR);
-  rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
   rpc_auth_null = txdr_unsigned(RPCAUTH_NULL);
 
   finfo("RPC initialized\n");
@@ -361,13 +354,12 @@ void rpcclnt_init(void)
  *
  ****************************************************************************/
 
-int rpcclnt_connect(struct rpcclnt *rpc)
+int rpcclnt_connect(FAR struct rpcclnt *rpc)
 {
-  struct socket *so;
   int error;
-  struct sockaddr *saddr;
+  FAR struct sockaddr *saddr;
   struct sockaddr_in sin;
-  struct sockaddr_in *sa;
+  FAR struct sockaddr_in *sa;
 
   union
   {
@@ -383,7 +375,6 @@ int rpcclnt_connect(struct rpcclnt *rpc)
 
   struct timeval tv;
   uint16_t tport;
-  int errval;
 
   finfo("Connecting\n");
 
@@ -391,38 +382,25 @@ int rpcclnt_connect(struct rpcclnt *rpc)
 
   saddr = rpc->rc_name;
 
-  /* Create an instance of the socket state structure */
-
-  so = (struct socket *)kmm_zalloc(sizeof(struct socket));
-  if (!so)
-    {
-      ferr("ERROR: Failed to allocate socket structure\n");
-      return ENOMEM;
-    }
-
-  error = psock_socket(saddr->sa_family, rpc->rc_sotype, IPPROTO_UDP, so);
+  error = psock_socket(saddr->sa_family, rpc->rc_sotype, IPPROTO_UDP, &rpc->rc_so);
   if (error < 0)
     {
-      errval = -error;
-      ferr("ERROR: psock_socket failed: %d", errval);
-      return errval;
+      ferr("ERROR: psock_socket failed: %d", error);
+      return error;
     }
 
-  rpc->rc_so = so;
-
   /* Always set receive timeout to detect server crash and reconnect.
    * Otherwise, we can get stuck in psock_receive forever.
    */
 
-  tv.tv_sec  = 1;
-  tv.tv_usec = 0;
+  tv.tv_sec  = rpc->rc_timeo / 10;
+  tv.tv_usec = (rpc->rc_timeo % 10) * 100000;
 
-  error = psock_setsockopt(rpc->rc_so, SOL_SOCKET, SO_RCVTIMEO,
-                          (const void *)&tv, sizeof(tv));
+  error = psock_setsockopt(&rpc->rc_so, SOL_SOCKET, SO_RCVTIMEO,
+                          (FAR const void *)&tv, sizeof(tv));
   if (error < 0)
     {
-      errval = -error;
-      ferr("ERROR: psock_setsockopt failed: %d\n", errval);
+      ferr("ERROR: psock_setsockopt failed: %d\n", error);
       goto bad;
     }
 
@@ -435,24 +413,22 @@ int rpcclnt_connect(struct rpcclnt *rpc)
   sin.sin_addr.s_addr = INADDR_ANY;
   tport               = 1024;
 
-  errval = 0;
   do
     {
       tport--;
       sin.sin_port = htons(tport);
 
-      error = psock_bind(rpc->rc_so, (struct sockaddr *)&sin, sizeof(sin));
+      error = psock_bind(&rpc->rc_so, (struct sockaddr *)&sin, sizeof(sin));
       if (error < 0)
         {
-          errval = -error;
-          ferr("ERROR: psock_bind failed: %d\n", errval);
+          ferr("ERROR: psock_bind failed: %d\n", error);
         }
     }
-  while (errval == EADDRINUSE && tport > 1024 / 2);
+  while (error == -EADDRINUSE && tport > 1024 / 2);
 
   if (error)
     {
-      ferr("ERROR: psock_bind failed: %d\n", errval);
+      ferr("ERROR: psock_bind failed: %d\n", error);
       goto bad;
     }
 
@@ -461,11 +437,10 @@ int rpcclnt_connect(struct rpcclnt *rpc)
    * the NFS_PORT.
    */
 
-  error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
+  error = psock_connect(&rpc->rc_so, saddr, sizeof(*saddr));
   if (error < 0)
     {
-      errval = -error;
-      ferr("ERROR: psock_connect to PMAP port failed: %d", errval);
+      ferr("ERROR: psock_connect to PMAP port failed: %d", error);
       goto bad;
     }
 
@@ -475,7 +450,7 @@ int rpcclnt_connect(struct rpcclnt *rpc)
 
   request.sdata.pmap.prog = txdr_unsigned(RPCPROG_MNT);
   request.sdata.pmap.vers = txdr_unsigned(RPCMNT_VER3);
-  request.sdata.pmap.proc = txdr_unsigned(IPPROTO_UDP);
+  request.sdata.pmap.prot = txdr_unsigned(IPPROTO_UDP);
   request.sdata.pmap.port = 0;
 
   error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
@@ -490,11 +465,10 @@ int rpcclnt_connect(struct rpcclnt *rpc)
   sa = (FAR struct sockaddr_in *)saddr;
   sa->sin_port = htons(fxdr_unsigned(uint32_t, response.rdata.pmap.port));
 
-  error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
+  error = psock_connect(&rpc->rc_so, saddr, sizeof(*saddr));
   if (error < 0)
     {
-      errval = -error;
-      ferr("ERROR: psock_connect MOUNTD port failed: %d\n", errval);
+      ferr("ERROR: psock_connect MOUNTD port failed: %d\n", error);
       goto bad;
     }
 
@@ -530,17 +504,16 @@ int rpcclnt_connect(struct rpcclnt *rpc)
 
   sa->sin_port = htons(PMAPPORT);
 
-  error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
+  error = psock_connect(&rpc->rc_so, saddr, sizeof(*saddr));
   if (error < 0)
     {
-      errval = -error;
-      ferr("ERROR: psock_connect PMAP port failed: %d\n", errval);
+      ferr("ERROR: psock_connect PMAP port failed: %d\n", error);
       goto bad;
     }
 
   request.sdata.pmap.prog = txdr_unsigned(NFS_PROG);
   request.sdata.pmap.vers = txdr_unsigned(NFS_VER3);
-  request.sdata.pmap.proc = txdr_unsigned(IPPROTO_UDP);
+  request.sdata.pmap.prot = txdr_unsigned(IPPROTO_UDP);
   request.sdata.pmap.port = 0;
 
   error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
@@ -556,10 +529,9 @@ int rpcclnt_connect(struct rpcclnt *rpc)
 
   sa->sin_port = htons(fxdr_unsigned(uint32_t, response.rdata.pmap.port));
 
-  error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
+  error = psock_connect(&rpc->rc_so, saddr, sizeof(*saddr));
   if (error < 0)
     {
-      error = -error;
       ferr("ERROR: psock_connect NFS port returns %d\n", error);
       goto bad;
     }
@@ -579,12 +551,9 @@ bad:
  *
  ****************************************************************************/
 
-void rpcclnt_disconnect(struct rpcclnt *rpc)
+void rpcclnt_disconnect(FAR struct rpcclnt *rpc)
 {
-  if (rpc->rc_so != NULL)
-    {
-      psock_close(rpc->rc_so);
-    }
+  psock_close(&rpc->rc_so);
 }
 
 /****************************************************************************
@@ -595,10 +564,10 @@ void rpcclnt_disconnect(struct rpcclnt *rpc)
  *
  ****************************************************************************/
 
-int rpcclnt_umount(struct rpcclnt *rpc)
+int rpcclnt_umount(FAR struct rpcclnt *rpc)
 {
-  struct sockaddr *saddr;
-  struct sockaddr_in *sa;
+  FAR struct sockaddr *saddr;
+  FAR struct sockaddr_in *sa;
 
   union
   {
@@ -613,7 +582,6 @@ int rpcclnt_umount(struct rpcclnt *rpc)
   } response;
 
   int error;
-  int ret;
 
   saddr = rpc->rc_name;
   sa = (FAR struct sockaddr_in *)saddr;
@@ -624,10 +592,9 @@ int rpcclnt_umount(struct rpcclnt *rpc)
 
   sa->sin_port = htons(PMAPPORT);
 
-  ret = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
-  if (ret < 0)
+  error = psock_connect(&rpc->rc_so, saddr, sizeof(*saddr));
+  if (error < 0)
     {
-      error = -ret;
       ferr("ERROR: psock_connect failed [port=%d]: %d\n",
             ntohs(sa->sin_port), error);
       goto bad;
@@ -635,7 +602,7 @@ int rpcclnt_umount(struct rpcclnt *rpc)
 
   request.sdata.pmap.prog = txdr_unsigned(RPCPROG_MNT);
   request.sdata.pmap.vers = txdr_unsigned(RPCMNT_VER3);
-  request.sdata.pmap.proc = txdr_unsigned(IPPROTO_UDP);
+  request.sdata.pmap.prot = txdr_unsigned(IPPROTO_UDP);
   request.sdata.pmap.port = 0;
 
   error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
@@ -651,10 +618,9 @@ int rpcclnt_umount(struct rpcclnt *rpc)
 
   sa->sin_port = htons(fxdr_unsigned(uint32_t, response.rdata.pmap.port));
 
-  ret = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
-  if (ret < 0)
+  error = psock_connect(&rpc->rc_so, saddr, sizeof(*saddr));
+  if (error < 0)
     {
-      error = -ret;
       ferr("ERROR: psock_connect failed [port=%d]: %d\n",
             ntohs(sa->sin_port), error);
       goto bad;
@@ -693,7 +659,7 @@ bad:
  *   certain errors.
  *
  *   On successful receipt, it verifies the RPC level of the returned values.
- *   (There may still be be NFS layer errors that will be deted by calling
+ *   (There may still be be NFS layer errors that will be detected by calling
  *   logic).
  *
  ****************************************************************************/
@@ -702,10 +668,10 @@ int rpcclnt_request(FAR struct rpcclnt *rpc, int procnum, int prog,
                     int version, FAR void *request, size_t reqlen,
                     FAR void *response, size_t resplen)
 {
-  struct rpc_reply_header *replymsg;
+  FAR struct rpc_reply_header *replymsg;
   uint32_t tmp;
   uint32_t xid;
-  int retries;
+  int retries = 0;
   int error = 0;
 
   /* Get a new (non-zero) xid */
@@ -728,17 +694,15 @@ int rpcclnt_request(FAR struct rpcclnt *rpc, int procnum, int prog,
    * timeouts.
    */
 
-  retries = 0;
-  do
+  for (; ; )
     {
       /* Do the client side RPC. */
 
       rpc_statistics(rpcrequests);
-      rpc->rc_timeout = false;
 
       /* Send the RPC CALL message */
 
-      error = rpcclnt_send(rpc, procnum, prog, request, reqlen);
+      error = rpcclnt_send(rpc, request, reqlen);
       if (error != OK)
         {
           finfo("ERROR rpcclnt_send failed: %d\n", error);
@@ -748,16 +712,29 @@ int rpcclnt_request(FAR struct rpcclnt *rpc, int procnum, int prog,
 
       else
         {
-          error = rpcclnt_reply(rpc, procnum, prog, response, resplen);
+          error = rpcclnt_reply(rpc, response, resplen);
           if (error != OK)
             {
               finfo("ERROR rpcclnt_reply failed: %d\n", error);
             }
         }
 
-      retries++;
+      /* If we failed because of a timeout, then try sending the CALL
+       * message again.
+       */
+
+      if (error != -EAGAIN && error != -ETIMEDOUT)
+        {
+          break;
+        }
+
+      rpc_statistics(rpctimeouts);
+      if (++retries >= rpc->rc_retry)
+        {
+          break;
+        }
+      rpc_statistics(rpcretries);
     }
-  while (rpc->rc_timeout && retries <= rpc->rc_retry);
 
   if (error != OK)
     {
@@ -770,26 +747,9 @@ int rpcclnt_request(FAR struct rpcclnt *rpc, int procnum, int prog,
   replymsg = (FAR struct rpc_reply_header *)response;
 
   tmp = fxdr_unsigned(uint32_t, replymsg->type);
-  if (tmp == RPC_MSGDENIED)
+  if (tmp != RPC_MSGACCEPTED)
     {
-      tmp = fxdr_unsigned(uint32_t, replymsg->status);
-      switch (tmp)
-        {
-        case RPC_MISMATCH:
-          ferr("ERROR: RPC_MSGDENIED: RPC_MISMATCH error\n");
-          return EOPNOTSUPP;
-
-        case RPC_AUTHERR:
-          ferr("ERROR: RPC_MSGDENIED: RPC_AUTHERR error\n");
-          return EACCES;
-
-        default:
-          return EOPNOTSUPP;
-        }
-    }
-  else if (tmp != RPC_MSGACCEPTED)
-    {
-      return EOPNOTSUPP;
+      return -EOPNOTSUPP;
     }
 
   tmp = fxdr_unsigned(uint32_t, replymsg->status);
@@ -797,15 +757,10 @@ int rpcclnt_request(FAR struct rpcclnt *rpc, int procnum, int prog,
     {
       finfo("RPC_SUCCESS\n");
     }
-  else if (tmp == RPC_PROGMISMATCH)
-    {
-      ferr("ERROR: RPC_MSGACCEPTED: RPC_PROGMISMATCH error\n");
-      return EOPNOTSUPP;
-    }
-  else if (tmp > 5)
+  else
     {
       ferr("ERROR: Unsupported RPC type: %d\n", tmp);
-      return EOPNOTSUPP;
+      return -EOPNOTSUPP;
     }
 
   return OK;
diff --git a/fs/nfs/xdr_subs.h b/fs/nfs/xdr_subs.h
index f3f3c58..a1117a1 100644
--- a/fs/nfs/xdr_subs.h
+++ b/fs/nfs/xdr_subs.h
@@ -68,47 +68,18 @@
 #define fxdr_unsigned(t, v)  ((t)ntohl(v))
 #define txdr_unsigned(v)     (htonl(v))
 
-#define fxdr_nfsv2time(f, t) \
-{ \
-  (t)->tv_sec = ntohl(((struct nfsv2_time *)(f))->nfsv2_sec); \
-  if (((struct nfsv2_time *)(f))->nfsv2_usec != 0xffffffff) \
-    (t)->tv_nsec = 1000 * ntohl(((struct nfsv2_time *)(f))->nfsv2_usec); \
-  else \
-    (t)->tv_nsec = 0; \
-}
-
-#define txdr_nfsv2time(f, t) \
-{ \
-  ((struct nfsv2_time *)(t))->nfsv2_sec = htonl((f)->tv_sec); \
-  if ((f)->tv_nsec != -1) \
-    ((struct nfsv2_time *)(t))->nfsv2_usec = htonl((f)->tv_nsec / 1000); \
-  else \
-    ((struct nfsv2_time *)(t))->nfsv2_usec = 0xffffffff; \
-}
-
 #define fxdr_nfsv3time(f, t) \
 { \
   (t)->tv_sec = ntohl(((struct nfsv3_time *)(f))->nfsv3_sec); \
   (t)->tv_nsec = ntohl(((struct nfsv3_time *)(f))->nfsv3_nsec); \
 }
 
-#define fxdr_nfsv3time2(f, t) { \
-  (t)->nfsv3_sec = ntohl(((struct nfsv3_time *)(f))->nfsv3_sec); \
-  (t)->nfsv3_nsec = ntohl(((struct nfsv3_time *)(f))->nfsv3_nsec); \
-}
-
 #define txdr_nfsv3time(f, t) \
 { \
   ((struct nfsv3_time *)(t))->nfsv3_sec = htonl((f)->tv_sec); \
   ((struct nfsv3_time *)(t))->nfsv3_nsec = htonl((f)->tv_nsec); \
 }
 
-#define txdr_nfsv3time2(f, t) \
-{ \
-  ((struct nfsv3_time *)(t))->nfsv3_sec = htonl((f)->nfsv3_sec); \
-  ((struct nfsv3_time *)(t))->nfsv3_nsec = htonl((f)->nfsv3_nsec); \
-}
-
 #define fxdr_hyper(f) \
   ((((uint64_t)ntohl(((uint32_t *)(f))[0])) << 32) |  \
    (uint64_t)(ntohl(((uint32_t *)(f))[1])))