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
This commit is contained in:
Xiang Xiao 2020-03-02 04:53:45 +08:00 committed by Gregory Nutt
parent 350adb236f
commit 915f094a74
9 changed files with 524 additions and 906 deletions

View file

@ -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,

View file

@ -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.
*/

View file

@ -50,15 +50,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 */

View file

@ -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 */

View file

@ -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
{
@ -121,78 +117,26 @@ static inline int nfs_pathsegment(FAR const char **path, FAR char *buffer,
* Public Functions
****************************************************************************/
/****************************************************************************
* 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;

File diff suppressed because it is too large Load diff

View file

@ -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 */

View file

@ -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"
@ -107,6 +106,22 @@
# define rpc_statistics(n)
#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;

View file

@ -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])))