diff options
Diffstat (limited to 'nuttx/fs/nfs')
-rw-r--r-- | nuttx/fs/nfs/Kconfig | 18 | ||||
-rw-r--r-- | nuttx/fs/nfs/nfs.h | 194 | ||||
-rw-r--r-- | nuttx/fs/nfs/nfs_mount.h | 41 | ||||
-rw-r--r-- | nuttx/fs/nfs/nfs_node.h | 6 | ||||
-rw-r--r-- | nuttx/fs/nfs/nfs_proto.h | 28 | ||||
-rw-r--r-- | nuttx/fs/nfs/nfs_socket.c | 8 | ||||
-rw-r--r-- | nuttx/fs/nfs/nfs_util.c | 103 | ||||
-rw-r--r-- | nuttx/fs/nfs/nfs_vfsops.c | 659 | ||||
-rw-r--r-- | nuttx/fs/nfs/rpc.h | 14 | ||||
-rw-r--r-- | nuttx/fs/nfs/rpc_clnt.c | 280 |
10 files changed, 370 insertions, 981 deletions
diff --git a/nuttx/fs/nfs/Kconfig b/nuttx/fs/nfs/Kconfig index 841b1ab8e..3838efffa 100644 --- a/nuttx/fs/nfs/Kconfig +++ b/nuttx/fs/nfs/Kconfig @@ -12,19 +12,13 @@ config NFS #if NFS -config NFS_TCPIP - bool "TCP/IP RPC support" +config NFS_STATISTICS + bool "NFS Stastics" default n depends on NFS ---help--- - By default, NFS uses a UDP RPC protocol. Enable this option to - build in support for a TCP/IP-based RPC. + Collect support for NFS statistics. There is no user interface to + obtain these statistics, however. So they would only be of value + if you add debug instrumentation or use a debugger. -config NFS_UNIX_AUTH - bool "NFS Unix authentication" - default n - depends on NFS - ---help--- - Build in support for Unix-style authentication. - -#endif
\ No newline at end of file +#endif diff --git a/nuttx/fs/nfs/nfs.h b/nuttx/fs/nfs/nfs.h index 0fe30f5f0..b35ef2c8d 100644 --- a/nuttx/fs/nfs/nfs.h +++ b/nuttx/fs/nfs/nfs.h @@ -54,19 +54,25 @@ * Pre-processor Definitions ****************************************************************************/ -#define NFS_TICKINTVL 5 /* Desired time for a tick (msec) */ -#define NFS_HZ (CLOCKS_PER_SEC / nfs_ticks) /* Ticks/sec */ +#if MSEC_PER_TICK <= 5 +# define NFS_TICKINTVL 5 /* Desired time for a tick (msec) */ +# define NFS_TICKS (CLOCKS_PER_SEC * NFS_TICKINTVL + 500) / 1000 +# define NFS_HZ (CLOCKS_PER_SEC / NFS_TICKS) /* Ticks/sec */ +#else +# define NFS_TICKINTVL MSEC_PER_TICK /* Smallest that we can get */ +# define NFS_TICKS 1 /* Number of system ticks */ +# define NFS_HZ CLOCKS_PER_SEC /* Ticks/sec */ +#endif + #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_MINIDEMTIMEO (5 * NFS_HZ) /* Min timeout for non-idempotent ops */ #define NFS_TIMEOUTMUL 2 /* Timeout/Delay multiplier */ #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_MAXASYNCDAEMON 20 /* Max. number async_daemons runable */ #define NFS_NPROCS 23 /* Ideally, NFS_DIRBLKSIZ should be bigger, but I've seen servers with @@ -74,85 +80,6 @@ */ #define NFS_DIRBLKSIZ 1024 /* Must be a multiple of DIRBLKSIZ */ -#define NFS_READDIRBLKSIZ 512 /* Size of read dir blocks. XXX */ - -/* Oddballs */ - -#define NFS_CMPFH(n, f, s) \ - ((n)->n_fhsize == (s) && !bcmp((void *)(n)->n_fhp, (void *)(f), (s))) -#define NFS_ISV3(i) (VFSTONFS((i)->f_inode)->nm_flag & NFSMNT_NFSV3) -#define NFS_SRVMAXDATA(n) \ - (((n)->nd_flag & ND_NFSV3) ? (((n)->nd_nam2) ? \ - NFS_MAXDGRAMDATA : NFS_MAXDATA) : NFS_V2MAXDATA) - -/* sys/malloc.h needs M_NFSDIROFF, M_NFSRVDESC and M_NFSBIGFH added. */ - -#ifndef M_NFSRVDESC -# define M_NFSRVDESC M_TEMP -#endif -#ifndef M_NFSDIROFF -# define M_NFSDIROFF M_TEMP -#endif -#ifndef M_NFSBIGFH -# define M_NFSBIGFH M_TEMP -#endif - -/*The B_INVAFTERWRITE flag should be set to whatever is required by the - * buffer cache code to say "Invalidate the block after it is written back". - */ - -#define B_INVAFTERWRITE B_INVAL - -/* Flags for nfssvc() system call. */ - -#define NFSSVC_BIOD 0x002 -#define NFSSVC_NFSD 0x004 -#define NFSSVC_ADDSOCK 0x008 -#define NFSSVC_AUTHIN 0x010 -#define NFSSVC_GOTAUTH 0x040 -#define NFSSVC_AUTHINFAIL 0x080 -#define NFSSVC_MNTD 0x100 - -/* On fast networks, the estimator will try to reduce the timeout lower than - * the latency of the server's disks, which results in too many timeouts, so - * cap the lower bound. - */ - -#define NFS_MINRTO (NFS_HZ >> 2) - -/* Keep the RTO from increasing to unreasonably large values when a server is - * not responding. - */ - -#define NFS_MAXRTO (20 * NFS_HZ) - -#define NFS_MAX_TIMER (NFS_WRITE_TIMER) -#define NFS_INITRTT (NFS_HZ << 3) - -/* Bits for "ns_flag" */ - -#define SLP_VALID 0x01 /* connection is usable */ -#define SLP_DOREC 0x02 /* receive operation required */ -#define SLP_NEEDQ 0x04 /* connection has data to queue from socket */ -#define SLP_DISCONN 0x08 /* connection is closed */ -#define SLP_GETSTREAM 0x10 /* extracting RPC from TCP connection */ -#define SLP_LASTFRAG 0x20 /* last fragment received on TCP connection */ -#define SLP_ALLFLAGS 0xff /* convenience */ - -#define SLP_INIT 0x01 /* NFS data undergoing initialization */ -#define SLP_WANTINIT 0x02 /* thread waiting on NFS initialization */ - -/* Bits for "nfsd_flag" */ - -#define NFSD_WAITING 0x01 -#define NFSD_REQINPROG 0x02 -#define NFSD_NEEDAUTH 0x04 -#define NFSD_AUTHFAIL 0x08 - -/* Bits for "nd_flag" */ - -#define ND_NFSV3 0x08 -#define NFSD_CHECKSLP 0x01 /* Increment NFS statistics */ @@ -172,111 +99,12 @@ extern uint32_t nfs_xdrneg1; #ifdef CONFIG_NFS_STATISTICS extern struct nfsstats nfsstats; #endif -extern int nfs_ticks; /**************************************************************************** * Public Types ****************************************************************************/ -#undef COMP -#ifdef COMP -/* Structures for the nfssvc(2) syscall. - * Not that anyone besides nfsd(8) should ever use it. - */ - -struct nfsd_args -{ - int sock; /* Socket to serve */ - void *name; /* Client addr for connection based sockets */ - int namelen; /* Length of name */ -}; - -struct nfsd_srvargs -{ - struct nfsd *nsd_nfsd; /* Pointer to in kernel nfsd struct */ - uid_t nsd_uid; /* Effective uid mapped to cred */ - uint32_t nsd_haddr; /* IP address of client */ - int nsd_authlen; /* Length of auth string (ret) */ - uint8_t *nsd_authstr; /* Auth string (ret) */ - int nsd_verflen; /* and the verifier */ - uint8_t *nsd_verfstr; - struct timeval nsd_timestamp; /* timestamp from verifier */ - uint32_t nsd_ttl; /* credential ttl (sec) */ -}; - -/* The set of signals the interrupt an I/O in progress for NFSMNT_INT mounts. - * What should be in this set is open to debate, but I believe that since - * I/O system calls on ufs are never interrupted by signals the set should - * be minimal. My reasoning is that many current programs that use signals - * such as SIGALRM will not expect file I/O system calls to be interrupted - * by them and break. - */ - -/* Nfs outstanding request list element */ - -struct nfsreq -{ - dq_entry_t r_chain; - struct nfsmount *r_nmp; - uint32_t r_xid; - int r_flags; /* flags on request, see below */ - int r_rexmit; /* current retrans count */ - int r_timer; /* tick counter on reply */ - int r_procnum; /* NFS procedure number */ - int r_rtt; /* RTT for rpc */ -}; - -enum nfs_rto_timers -{ - NFS_DEFAULT_TIMER, - NFS_GETATTR_TIMER, - NFS_LOOKUP_TIMER, - NFS_READ_TIMER, - NFS_WRITE_TIMER, -}; - -/* Network address hash list element */ - -union nethostaddr -{ - uint32_t had_inetaddr; - struct mbuf *had_nam; -}; - -struct nfssvc_sock -{ - // TAILQ_ENTRY(nfssvc_sock) ns_chain; /* List of all nfssvc_sock's */ - struct file *ns_fp; /* fp from the... */ - struct socket *ns_so; /* ...socket this struct wraps */ - int ns_flag; /* socket status flags */ - int ns_solock; /* lock for connected socket */ - int ns_cc; /* actual chars queued */ - int ns_reclen; /* length of first queued record */ - uint32_t ns_sref; /* # of refs to this struct */ -}; - -/* One of these structures is allocated for each nfsd. */ - -struct nfsd -{ - //TAILQ_ENTRY(nfsd) nfsd_chain; /* List of all nfsd's */ - int nfsd_flag; /* NFSD_ flags */ - struct nfssvc_sock *nfsd_slp; /* Current socket */ - struct nfsrv_descript *nfsd_nd; /* Associated nfsrv_descript */ -}; - -/* This structure is used by the server for describing each request. */ - -struct nfsrv_descript -{ - unsigned int nd_procnum; /* RPC # */ - int nd_flag; /* nd_flag */ - int nd_repstat; /* Reply status */ - uint32_t nd_retxid; /* Reply xid */ -}; -#endif - -/* Stats structure */ +/* NFS statistics structure */ struct nfsstats { diff --git a/nuttx/fs/nfs/nfs_mount.h b/nuttx/fs/nfs/nfs_mount.h index 66343f90e..d3be1a598 100644 --- a/nuttx/fs/nfs/nfs_mount.h +++ b/nuttx/fs/nfs/nfs_mount.h @@ -51,7 +51,7 @@ #include <sys/socket.h> #include "rpc.h" - + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -78,17 +78,17 @@ struct nfsmount uint8_t nm_flag; /* Flags for soft/hard... */ uint8_t nm_fhsize; /* Size of root file handle (host order) */ uint8_t nm_sotype; /* Type of socket */ - uint8_t nm_soproto; /* and protocol */ uint8_t nm_timeo; /* Init timer for NFSMNT_DUMBTIMR */ uint8_t nm_retry; /* Max retries */ 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 */ uint8_t nm_verf[NFSX_V3WRITEVERF]; /* V3 write verifier */ + 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, the reply message is in - * this union. + * that for the case of the write call message, it is the reply message that + * is in this union. */ union @@ -105,7 +105,38 @@ struct nfsmount struct rpc_call_readdir readdir; struct rpc_call_fs fs; struct rpc_reply_write write; - } nm_smallbuffer; + } nm_msgbuffer; + + /* I/O buffer (must be a aligned to 32-bit boundaries). This buffer used for all + * reply messages EXCEPT for the WRITE RPC. In that case it is used for the WRITE + * call message that contains the data to be written. This buffer must be + * dynamically sized based on the characteristics of the server and upon the + * configuration of the NuttX network. It must be sized to hold the largest + * possible WRITE call message or READ response message. + */ + + 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 + * buffer. + */ + +#define SIZEOF_nfsmount(n) (sizeof(struct nfsmount) + ((n + 3) & ~3) - sizeof(uint32_t)) + +/* Mount parameters structure. This structure is use in nfs_decode_args funtion before one + * mount structure is allocated in each NFS mount. + */ + +struct nfs_mount_parameters +{ + + uint8_t flag; /* Flags for soft/hard... */ + uint8_t timeo; /* Init timer for NFSMNT_DUMBTIMR */ + uint8_t retry; /* Max retries */ + uint16_t rsize; /* Max size of read RPC */ + uint16_t wsize; /* Max size of write RPC */ + uint16_t readdirsize; /* Size of a readdir RPC */ }; #endif diff --git a/nuttx/fs/nfs/nfs_node.h b/nuttx/fs/nfs/nfs_node.h index 02e14cbde..4ae9e162c 100644 --- a/nuttx/fs/nfs/nfs_node.h +++ b/nuttx/fs/nfs/nfs_node.h @@ -73,16 +73,10 @@ struct nfsnode 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_buflen; /* Size of I/O buffer */ struct timespec n_mtime; /* File modification time (see NOTE) */ time_t n_ctime; /* File creation time (see NOTE) */ nfsfh_t n_fhandle; /* NFS File Handle */ uint64_t n_size; /* Current size of file (see NOTE) */ - - /* I/O buffer (must be a aligned to 32-bit boundaries) */ - - uint8_t n_iobuffer[1]; /* Actual size is given by n_buflen */ }; -#define SIZEOF_nfsnode(n) (sizeof(struct nfsnode) + ((n)-1)) #endif /* __FS_NFS_NFS_NODE_H */ diff --git a/nuttx/fs/nfs/nfs_proto.h b/nuttx/fs/nfs/nfs_proto.h index 245f3e189..645b6bdf0 100644 --- a/nuttx/fs/nfs/nfs_proto.h +++ b/nuttx/fs/nfs/nfs_proto.h @@ -296,34 +296,6 @@ typedef enum NFFIFO = 7 /* Named FIFO */ } nfstype; -#if 0 -typedef struct -{ - int32_t val[2]; -} fsid_t; /* file system id type */ - -/* File identifier. - * These are unique per filesystem on a single machine. - */ - -struct fid -{ - unsigned short fid_len; /* length of data in bytes */ - unsigned short fid_reserved; /* force longword alignment */ - char fid_data[MAXFIDSZ]; /* data (variable length) */ -}; - -/* Generic file handle */ - -struct fhandle -{ - fsid_t fh_fsid; /* File system id of mount point */ - struct fid fh_fid; /* File sys specific id */ -}; - -typedef struct fhandle fhandle_t; -#endif - /* 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 * allocations for a file handle. diff --git a/nuttx/fs/nfs/nfs_socket.c b/nuttx/fs/nfs/nfs_socket.c index d429e6852..c5fe9f1e4 100644 --- a/nuttx/fs/nfs/nfs_socket.c +++ b/nuttx/fs/nfs/nfs_socket.c @@ -80,7 +80,6 @@ uint32_t nfs_true; uint32_t nfs_false; uint32_t nfs_xdrneg1; -int nfs_ticks; struct nfsstats nfsstats; /**************************************************************************** @@ -97,12 +96,6 @@ void nfs_init(void) nfs_false = txdr_unsigned(FALSE); nfs_xdrneg1 = txdr_unsigned(-1); - nfs_ticks = (CLOCKS_PER_SEC * NFS_TICKINTVL + 500) / 1000; - if (nfs_ticks < 1) - { - nfs_ticks = 1; - } - rpcclnt_init(); } @@ -131,7 +124,6 @@ int nfs_connect(struct nfsmount *nmp) rpc->rc_path = nmp->nm_path; rpc->rc_name = &nmp->nm_nam; rpc->rc_sotype = nmp->nm_sotype; - rpc->rc_soproto = nmp->nm_soproto; nmp->nm_rpcclnt = rpc; diff --git a/nuttx/fs/nfs/nfs_util.c b/nuttx/fs/nfs/nfs_util.c index 2dd7613df..643117e22 100644 --- a/nuttx/fs/nfs/nfs_util.c +++ b/nuttx/fs/nfs/nfs_util.c @@ -197,102 +197,6 @@ int nfs_checkmount(struct nfsmount *nmp) } /**************************************************************************** - * Name: nfs_fsinfo - * - * Description: - * Return information about root directory. - * - * Returned Value: - * 0 on success; positive errno value on failure - * - * Assumptions: - * The caller has exclusive access to the NFS mount structure - * - ****************************************************************************/ - -int nfs_fsinfo(FAR struct nfsmount *nmp) -{ - struct rpc_call_fs fsinfo; - struct rpc_reply_fsinfo fsp; - uint32_t pref; - uint32_t max; - int error = 0; - - memset(&fsinfo, 0, sizeof(struct rpc_call_fs)); - memset(&fsp, 0, sizeof(struct rpc_reply_fsinfo)); - - fsinfo.fs.fsroot.length = txdr_unsigned(nmp->nm_fhsize); - fsinfo.fs.fsroot.handle = nmp->nm_fh; - - /* Request FSINFO from the server */ - - nfs_statistics(NFSPROC_FSINFO); - error = nfs_request(nmp, NFSPROC_FSINFO, - (FAR const void *)&fsinfo, sizeof(struct FS3args), - (FAR void *)&fsp, sizeof(struct rpc_reply_fsinfo)); - if (error) - { - return error; - } - - /* 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) - { - nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) & ~(NFS_FABLKSIZE - 1); - } - - 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; - } - } - - 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); - if (nmp->nm_rsize == 0) - { - nmp->nm_rsize = max; - } - } - - pref = fxdr_unsigned(uint32_t, fsp.fsinfo.fs_dtpref); - if (pref < nmp->nm_readdirsize) - { - nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) & ~(NFS_DIRBLKSIZ - 1); - } - - if (max < nmp->nm_readdirsize) - { - nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1); - if (nmp->nm_readdirsize == 0) - { - nmp->nm_readdirsize = max; - } - } - - nmp->nm_flag |= NFSMNT_GOTFSINFO; - - return 0; -} - -/**************************************************************************** * Name: nfs_lookup * * Desciption: @@ -321,11 +225,6 @@ int nfs_lookup(struct nfsmount *nmp, FAR const char *filename, DEBUGASSERT(nmp && filename && fhandle); - /* Set all of the buffers to a known state */ - - memset(&request, 0, sizeof(struct rpc_call_lookup)); - memset(&response, 0, sizeof(struct rpc_reply_lookup)); - /* Get the length of the string to be sent */ namelen = strlen(filename); @@ -361,7 +260,7 @@ int nfs_lookup(struct nfsmount *nmp, FAR const char *filename, nfs_statistics(NFSPROC_LOOKUP); error = nfs_request(nmp, NFSPROC_LOOKUP, - (FAR const void *)&request, reqlen, + (FAR void *)&request, reqlen, (FAR void *)&response, sizeof(struct rpc_reply_lookup)); if (error) { diff --git a/nuttx/fs/nfs/nfs_vfsops.c b/nuttx/fs/nfs/nfs_vfsops.c index c030422ca..cd8a5ab7a 100644 --- a/nuttx/fs/nfs/nfs_vfsops.c +++ b/nuttx/fs/nfs/nfs_vfsops.c @@ -87,10 +87,7 @@ * Pre-processor Definitions ****************************************************************************/ -#define NFS_DIRHDSIZ (sizeof (struct nfs_dirent) - (MAXNAMLEN + 1)) -#define NFS_DIRENT_OVERHEAD offsetof(struct nfs_dirent, dirent) - -/* The V3 EXCLUSIVE file creation logic is not fully support. */ +/* The V3 EXCLUSIVE file creation logic is not fully supported. */ #define USE_GUARDED_CREATE 1 @@ -110,12 +107,6 @@ * Private Type Definitions ****************************************************************************/ -struct nfs_dirent -{ - uint32_t cookie[2]; - struct dirent dirent; -}; - /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -126,6 +117,7 @@ static int nfs_fileopen(FAR struct nfsmount *nmp, struct nfsnode *np, FAR const char *relpath, int oflags, mode_t mode); static int nfs_open(FAR struct file *filep, 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, size_t buflen); @@ -153,7 +145,7 @@ static int nfs_stat(struct inode *mountpt, const char *relpath, const struct mountpt_operations nfs_operations = { nfs_open, /* open */ - NULL, /* close */ + nfs_close, /* close */ nfs_read, /* read */ nfs_write, /* write */ NULL, /* seek */ @@ -220,7 +212,7 @@ static int nfs_filecreate(FAR struct nfsmount *nmp, struct nfsnode *np, /* Create the CREATE RPC call arguments */ - ptr = (FAR uint32_t *)&((FAR struct rpc_call_create *)np->n_iobuffer)->create; + ptr = (FAR uint32_t *)&((FAR struct rpc_call_create *)nmp->nm_iobuffer)->create; reqlen = 0; /* Copy the variable length, directory file handle */ @@ -285,13 +277,13 @@ static int nfs_filecreate(FAR struct nfsmount *nmp, struct nfsnode *np, *ptr++ = nfs_true; /* True: Uid value follows */ *ptr++ = 0; /* UID = 0 (nobody) */ reqlen += 2*sizeof(uint32_t); - + /* Set the group ID to one */ *ptr++ = nfs_true; /* True: Gid value follows */ *ptr++ = HTONL(1); /* GID = 1 (nogroup) */ reqlen += 2*sizeof(uint32_t); - + /* Set the size to zero */ *ptr++ = nfs_true; /* True: Size value follows */ @@ -314,7 +306,7 @@ static int nfs_filecreate(FAR struct nfsmount *nmp, struct nfsnode *np, { nfs_statistics(NFSPROC_CREATE); error = nfs_request(nmp, NFSPROC_CREATE, - (FAR void *)np->n_iobuffer, reqlen, + (FAR void *)nmp->nm_iobuffer, reqlen, (FAR void *)&resok, sizeof(struct rpc_reply_create)); } #ifdef USE_GUARDED_CREATE @@ -347,7 +339,7 @@ static int nfs_filecreate(FAR struct nfsmount *nmp, struct nfsnode *np, np->n_fhsize = (uint8_t)tmp; memcpy(&np->n_fhandle, ptr, tmp); ptr += uint32_increment(tmp); - + /* Save the attributes in the file data structure */ tmp = *ptr++; /* handle_follows */ @@ -480,11 +472,8 @@ static int nfs_fileopen(FAR struct nfsmount *nmp, struct nfsnode *np, static int nfs_open(FAR struct file *filep, FAR const char *relpath, int oflags, mode_t mode) { - struct inode *in; struct nfsmount *nmp; - struct nfsnode *np; - uint32_t buflen; - uint32_t tmp; + struct nfsnode *np = NULL; int error; /* Sanity checks */ @@ -495,54 +484,18 @@ static int nfs_open(FAR struct file *filep, FAR const char *relpath, * mountpoint private data from the inode structure */ - in = filep->f_inode; - nmp = (struct nfsmount*)in->i_private; - + nmp = (struct nfsmount*)filep->f_inode->i_private; DEBUGASSERT(nmp != NULL); - /* Determine the size of a buffer that will hold one RPC data transfer */ - - { - /* Get the maximum size of a read and a write transfer */ - - buflen = SIZEOF_rpc_call_write(nmp->nm_wsize); - tmp = SIZEOF_rpc_reply_read(nmp->nm_rsize); - - /* The buffer size will be the maximum of those two sizes */ - - if (tmp > buflen) - { - buflen = tmp; - } - - /* But don't let the buffer size exceed the MSS of the socket type */ - -#ifdef CONFIG_NFS_TCPIP - if (buflen > UIP_TCP_MSS) - { - buflen = UIP_TCP_MSS; - } -#else - if (buflen > UIP_UDP_MSS) - { - buflen = UIP_UDP_MSS; - } -#endif - } - /* Pre-allocate the file private data to describe the opened file. */ - np = (struct nfsnode *)kzalloc(SIZEOF_nfsnode(buflen)); + np = (struct nfsnode *)kzalloc(sizeof(struct nfsnode)); if (!np) { fdbg("ERROR: Failed to allocate private data\n"); return -ENOMEM; } - /* Save the allocated I/O buffer size */ - - np->n_buflen = (uint16_t)buflen; - /* Check if the mount is still healthy */ nfs_semtake(nmp); @@ -582,10 +535,10 @@ static int nfs_open(FAR struct file *filep, FAR const char *relpath, */ fdbg("ERROR: File does not exist\n"); - error = ENOENT; + error = ENOENT; goto errout_with_semaphore; } - + /* Create the file */ error = nfs_filecreate(nmp, np, relpath, mode); @@ -604,64 +557,99 @@ static int nfs_open(FAR struct file *filep, FAR const char *relpath, filep->f_priv = np; - /* Then insert the new instance into the mountpoint 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 - * (but a simple reference count could have done that). + /* 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; - np->n_flags |= (NFSNODE_OPEN | NFSNODE_MODIFIED); - nmp->nm_head = np->n_next; + nmp->nm_head = np; + np->n_flags |= (NFSNODE_OPEN | NFSNODE_MODIFIED); nfs_semgive(nmp); return OK; errout_with_semaphore: - kfree(np); + if (np) + { + kfree(np); + } nfs_semgive(nmp); return -error; } -#undef COMP -#ifdef COMP /**************************************************************************** * Name: nfs_close * + * Description: + * Close a file. + * * Returned Value: * 0 on success; a negated errno value on failure. * ****************************************************************************/ -static int nfs_close(FAR struct file *filep) done +static int nfs_close(FAR struct file *filep) { - struct nfsmount *nmp; - struct nfsnode *np; - int error = 0; - - fvdbg("Closing\n"); + FAR struct nfsmount *nmp; + FAR struct nfsnode *np; + FAR struct nfsnode *prev; + FAR struct nfsnode *curr; + int error; /* Sanity checks */ - DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); - - /* Recover our private data from the struct file instance */ + DEBUGASSERT(filep->f_inode != NULL); - np = filep->f_priv; - nmp = filep->f_inode->i_private; + /* Get the mountpoint inode reference from the file structure and the + * mountpoint private data from the inode structure + */ + nmp = (struct nfsmount*)filep->f_inode->i_private; DEBUGASSERT(nmp != NULL); - if (np->n_type == NFREG) - { - error = nfs_sync(filep); - kfree(np); - filep->f_priv = NULL; - } + /* Get exclusive access to the mount structure. */ - return -error; + nfs_semtake(nmp); + + /* Find our file structure in the list of file structures containted in the + * mount structure. + */ + + error = EINVAL; + for (prev = NULL, curr = nmp->nm_head; curr; prev = curr, curr = curr->n_next) + { + /* Check if this node is ours */ + + if (np == curr) + { + /* Yes.. remove it from the list of file structures */ + + if (prev) + { + /* Remove from mid-list */ + + prev->n_next = np->n_next; + } + else + { + /* Remove from the head of the list */ + + nmp->nm_head = np->n_next; + } + + /* Then deallocate the file structure and return success */ + + kfree(np); + error = OK; + break; + } + } + + nfs_semgive(nmp); + return error; } -#endif /**************************************************************************** * Name: nfs_read @@ -680,7 +668,6 @@ static ssize_t nfs_read(FAR struct file *filep, char *buffer, size_t buflen) ssize_t tmp; ssize_t bytesread; size_t reqlen; - struct rpc_call_read request; FAR uint32_t *ptr; int error = 0; @@ -723,7 +710,7 @@ static ssize_t nfs_read(FAR struct file *filep, char *buffer, size_t buflen) for (bytesread = 0; bytesread < buflen; ) { /* Make sure that the attempted read size does not exceed the RPC maximum */ - + readsize = buflen; if (readsize > nmp->nm_rsize) { @@ -733,14 +720,14 @@ static ssize_t nfs_read(FAR struct file *filep, char *buffer, size_t buflen) /* Make sure that the attempted read size does not exceed the IO buffer size */ tmp = SIZEOF_rpc_reply_read(readsize); - if (tmp > np->n_buflen) + if (tmp > nmp->nm_buflen) { - readsize -= (tmp - np->n_buflen); + readsize -= (tmp - nmp->nm_buflen); } /* Initialize the request */ - ptr = (FAR uint32_t*)&request.read; + ptr = (FAR uint32_t*)&nmp->nm_msgbuffer.read.read; reqlen = 0; /* Copy the variable length, file handle */ @@ -764,12 +751,12 @@ static ssize_t nfs_read(FAR struct file *filep, char *buffer, size_t buflen) reqlen += sizeof(uint32_t); /* Perform the read */ - + fvdbg("Reading %d bytes\n", readsize); nfs_statistics(NFSPROC_READ); error = nfs_request(nmp, NFSPROC_READ, - (FAR void *)&request, reqlen, - (FAR void *)np->n_iobuffer, np->n_buflen); + (FAR void *)&nmp->nm_msgbuffer.read, reqlen, + (FAR void *)nmp->nm_iobuffer, nmp->nm_buflen); if (error) { fdbg("ERROR: nfs_request failed: %d\n", error); @@ -780,7 +767,7 @@ static ssize_t nfs_read(FAR struct file *filep, char *buffer, size_t buflen) * response data. */ - ptr = (FAR uint32_t *)&((FAR struct rpc_reply_read *)np->n_iobuffer)->read; + ptr = (FAR uint32_t *)&((FAR struct rpc_reply_read *)nmp->nm_iobuffer)->read; /* Check if attributes are included in the responses */ @@ -850,7 +837,6 @@ static ssize_t nfs_write(FAR struct file *filep, const char *buffer, { struct nfsmount *nmp; struct nfsnode *np; - struct rpc_reply_write resok; ssize_t writesize; ssize_t bufsize; ssize_t byteswritten; @@ -897,7 +883,7 @@ static ssize_t nfs_write(FAR struct file *filep, const char *buffer, for (byteswritten = 0; byteswritten < buflen; ) { /* Make sure that the attempted write size does not exceed the RPC maximum */ - + writesize = buflen; if (writesize > nmp->nm_wsize) { @@ -907,9 +893,9 @@ static ssize_t nfs_write(FAR struct file *filep, const char *buffer, /* Make sure that the attempted read size does not exceed the IO buffer size */ bufsize = SIZEOF_rpc_call_write(writesize); - if (bufsize > np->n_buflen) + if (bufsize > nmp->nm_buflen) { - writesize -= (bufsize - np->n_buflen); + writesize -= (bufsize - nmp->nm_buflen); } /* Initialize the request. Here we need an offset pointer to the write @@ -917,7 +903,7 @@ static ssize_t nfs_write(FAR struct file *filep, const char *buffer, * RPC calls in that the entry RPC calls messasge lies in the I/O buffer */ - ptr = (FAR uint32_t *)&((FAR struct rpc_call_write *)np->n_iobuffer)->write; + ptr = (FAR uint32_t *)&((FAR struct rpc_call_write *)nmp->nm_iobuffer)->write; reqlen = 0; /* Copy the variable length, file handle */ @@ -952,8 +938,8 @@ static ssize_t nfs_write(FAR struct file *filep, const char *buffer, nfs_statistics(NFSPROC_WRITE); error = nfs_request(nmp, NFSPROC_WRITE, - (FAR void *)np->n_iobuffer, reqlen, - (FAR void *)&resok, sizeof(struct rpc_reply_write)); + (FAR void *)nmp->nm_iobuffer, reqlen, + (FAR void *)&nmp->nm_msgbuffer.write, sizeof(struct rpc_reply_write)); if (error) { fdbg("ERROR: nfs_request failed: %d\n", error); @@ -962,7 +948,7 @@ static ssize_t nfs_write(FAR struct file *filep, const char *buffer, /* Get a pointer to the WRITE reply data */ - ptr = (FAR uint32_t *)&resok.write; + ptr = (FAR uint32_t *)&nmp->nm_msgbuffer.write.write; /* Parse file_wcc. First, check if WCC attributes follow. */ @@ -1129,8 +1115,6 @@ errout_with_semaphore: static int nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir) { struct nfsmount *nmp; - uint32_t buffer[64]; - struct rpc_call_readdir request; struct file_handle fhandle; struct nfs_fattr obj_attributes; uint32_t tmp; @@ -1164,7 +1148,7 @@ static int nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir) * the dirent structure. */ - ptr = (FAR uint32_t*)&request.readdir; + ptr = (FAR uint32_t*)&nmp->nm_msgbuffer.readdir.readdir; reqlen = 0; /* Copy the variable length, directory file handle */ @@ -1196,8 +1180,8 @@ static int nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir) nfs_statistics(NFSPROC_READDIR); error = nfs_request(nmp, NFSPROC_READDIR, - (FAR void *)&request, reqlen, - (FAR void *)buffer, sizeof(buffer)); + (FAR void *)&nmp->nm_msgbuffer.readdir, reqlen, + (FAR void *)nmp->nm_iobuffer, nmp->nm_buflen); if (error != OK) { fdbg("ERROR: nfs_request failed: %d\n", error); @@ -1214,7 +1198,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 *)buffer)->readdir; + ptr = (uint32_t *)&((FAR struct rpc_reply_readdir *)nmp->nm_iobuffer)->readdir; /* Check if attributes follow, if 0 so Skip over the attributes */ @@ -1363,48 +1347,35 @@ errout_with_semaphore: * ****************************************************************************/ -void nfs_decode_args(struct nfsmount *nmp, struct nfs_args *argp) +void nfs_decode_args(struct nfs_mount_parameters *nprmt, struct nfs_args *argp) { - int adjsock = 0; int maxio; -#ifdef CONFIG_NFS_TCPIP - /* Re-bind if rsrvd port requested and wasn't on one */ - - adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT) - && (argp->flags & NFSMNT_RESVPORT); -#endif - - /* Also re-bind if we're switching to/from a connected UDP socket */ - - adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) != (argp->flags & NFSMNT_NOCONN)); - /* Update flags atomically. Don't change the lock bits. */ - nmp->nm_flag = - (argp->flags & ~NFSMNT_INTERNAL) | (nmp->nm_flag & NFSMNT_INTERNAL); + nprmt->flag = (argp->flags & ~NFSMNT_INTERNAL) | (nprmt->flag & NFSMNT_INTERNAL); if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { - nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; - if (nmp->nm_timeo < NFS_MINTIMEO) + nprmt->timeo = (argp->timeo * NFS_HZ + 5) / 10; + if (nprmt->timeo < NFS_MINTIMEO) { - nmp->nm_timeo = NFS_MINTIMEO; + nprmt->timeo = NFS_MINTIMEO; } - else if (nmp->nm_timeo > NFS_MAXTIMEO) + else if (nprmt->timeo > NFS_MAXTIMEO) { - nmp->nm_timeo = NFS_MAXTIMEO; + nprmt->timeo = NFS_MAXTIMEO; } } if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { - nmp->nm_retry = (argp->retrans < NFS_MAXREXMIT)? argp->retrans : NFS_MAXREXMIT; + nprmt->retry = (argp->retrans < NFS_MAXREXMIT)? argp->retrans : NFS_MAXREXMIT; } - if (!(nmp->nm_flag & NFSMNT_SOFT)) + if (!(nprmt->flag & NFSMNT_SOFT)) { - nmp->nm_retry = NFS_MAXREXMIT + 1; /* past clip limit */ + nprmt->retry = NFS_MAXREXMIT + 1; /* Past clip limit */ } if (argp->flags & NFSMNT_NFSV3) @@ -1425,88 +1396,70 @@ void nfs_decode_args(struct nfsmount *nmp, struct nfs_args *argp) if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { - int osize = nmp->nm_wsize; - nmp->nm_wsize = argp->wsize; + nprmt->wsize = argp->wsize; /* Round down to multiple of blocksize */ - nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1); - if (nmp->nm_wsize <= 0) + nprmt->wsize &= ~(NFS_FABLKSIZE - 1); + if (nprmt->wsize <= 0) { - nmp->nm_wsize = NFS_FABLKSIZE; + nprmt->wsize = NFS_FABLKSIZE; } - - adjsock |= (nmp->nm_wsize != osize); } - if (nmp->nm_wsize > maxio) + if (nprmt->wsize > maxio) { - nmp->nm_wsize = maxio; + nprmt->wsize = maxio; } - if (nmp->nm_wsize > MAXBSIZE) + if (nprmt->wsize > MAXBSIZE) { - nmp->nm_wsize = MAXBSIZE; + nprmt->wsize = MAXBSIZE; } if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { - int osize = nmp->nm_rsize; - nmp->nm_rsize = argp->rsize; + nprmt->rsize = argp->rsize; /* Round down to multiple of blocksize */ - nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1); - if (nmp->nm_rsize <= 0) + nprmt->rsize &= ~(NFS_FABLKSIZE - 1); + if (nprmt->rsize <= 0) { - nmp->nm_rsize = NFS_FABLKSIZE; + nprmt->rsize = NFS_FABLKSIZE; } - - adjsock |= (nmp->nm_rsize != osize); } - if (nmp->nm_rsize > maxio) + if (nprmt->rsize > maxio) { - nmp->nm_rsize = maxio; + nprmt->rsize = maxio; } - if (nmp->nm_rsize > MAXBSIZE) + if (nprmt->rsize > MAXBSIZE) { - nmp->nm_rsize = MAXBSIZE; + nprmt->rsize = MAXBSIZE; } if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) { - nmp->nm_readdirsize = argp->readdirsize; + nprmt->readdirsize = argp->readdirsize; /* Round down to multiple of blocksize */ - nmp->nm_readdirsize &= ~(NFS_DIRBLKSIZ - 1); - if (nmp->nm_readdirsize < NFS_DIRBLKSIZ) + nprmt->readdirsize &= ~(NFS_DIRBLKSIZ - 1); + if (nprmt->readdirsize < NFS_DIRBLKSIZ) { - nmp->nm_readdirsize = NFS_DIRBLKSIZ; + nprmt->readdirsize = NFS_DIRBLKSIZ; } } else if (argp->flags & NFSMNT_RSIZE) { - nmp->nm_readdirsize = nmp->nm_rsize; - } - - if (nmp->nm_readdirsize > maxio) - { - nmp->nm_readdirsize = maxio; + nprmt->readdirsize = nprmt->rsize; } - if (nmp->nm_so && adjsock) + if (nprmt->readdirsize > maxio) { - nfs_disconnect(nmp); - if (nmp->nm_sotype == SOCK_DGRAM) - { - while (nfs_connect(nmp)) - { - fvdbg("nfs_args: retrying connect\n"); - } - } + nprmt->readdirsize = maxio; } } @@ -1523,21 +1476,58 @@ void nfs_decode_args(struct nfsmount *nmp, struct nfs_args *argp) int mountnfs(struct nfs_args *argp, void **handle) { - FAR struct nfsmount *nmp; - struct nfsnode *np = NULL; - struct rpc_call_fs getattr; - struct rpc_reply_getattr resok; - int error = 0; + FAR struct nfsmount *nmp; + struct rpc_call_fs getattr; + struct rpc_reply_getattr resok; + struct nfs_mount_parameters nprmt; + uint32_t buflen; + uint32_t tmp; + int error = 0; + + /* Set initial values of the parameters for decode */ + + nprmt.flag = argp->flags; + nprmt.timeo = NFS_TIMEO; + nprmt.retry = NFS_RETRANS; + nprmt.wsize = NFS_WSIZE; + nprmt.rsize = NFS_RSIZE; + nprmt.readdirsize = NFS_READDIRSIZE; + + nfs_decode_args(&nprmt, argp); + + /* Determine the size of a buffer that will hold one RPC data transfer. + * First, get the maximum size of a read and a write transfer */ + + buflen = SIZEOF_rpc_call_write(nprmt.wsize); + tmp = SIZEOF_rpc_reply_read(nprmt.rsize); + + /* The buffer size will be the maximum of those two sizes */ + + if (tmp > buflen) + { + buflen = tmp; + } + + /* But don't let the buffer size exceed the MSS of the socket type */ + + if (buflen > UIP_UDP_MSS) + { + buflen = UIP_UDP_MSS; + } /* Create an instance of the mountpt state structure */ - nmp = (FAR struct nfsmount *)kzalloc(sizeof(struct nfsmount)); + nmp = (FAR struct nfsmount *)kzalloc(SIZEOF_nfsmount(buflen)); if (!nmp) { fdbg("ERROR: Failed to allocate mountpoint structure\n"); return ENOMEM; } + /* Save the allocated I/O buffer size */ + + nmp->nm_buflen = (uint16_t)buflen; + /* Initialize the allocated mountpt state structure. */ /* Initialize the semaphore that controls access. The initial count @@ -1553,27 +1543,20 @@ int mountnfs(struct nfs_args *argp, void **handle) /* Set initial values of other fields */ - nmp->nm_flag = argp->flags; - nmp->nm_timeo = NFS_TIMEO; - nmp->nm_retry = NFS_RETRANS; - nmp->nm_wsize = NFS_WSIZE; - nmp->nm_rsize = NFS_RSIZE; - nmp->nm_readdirsize = NFS_READDIRSIZE; + nmp->nm_flag = nprmt.flag; + 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); - nfs_decode_args(nmp, argp); - /* Set up the sockets and per-host congestion */ nmp->nm_sotype = argp->sotype; - nmp->nm_soproto = argp->proto; - - /* For Connection based sockets (TCP,...) defer the connect until - * the first request, in case the server is not responding. - */ if (nmp->nm_sotype == SOCK_DGRAM) { @@ -1587,33 +1570,12 @@ int mountnfs(struct nfs_args *argp, void **handle) } } - /* Create an instance of the file private data to describe the opened - * file. - */ - - np = (struct nfsnode *)kzalloc(sizeof(struct nfsnode)); - if (!np) - { - fdbg("ERROR: Failed to allocate private data\n"); - error = ENOMEM; - goto bad; - } - - np->n_type = NFDIR; - np->n_flags |= (NFSNODE_OPEN | NFSNODE_MODIFIED); - nmp->nm_head = np; nmp->nm_mounted = true; - memcpy(&nmp->nm_fh, &nmp->nm_rpcclnt->rc_fh, sizeof(nfsfh_t)); - nmp->nm_fhsize = NFSX_V3FHMAX; - memcpy(&nmp->nm_head->n_fhandle, &nmp->nm_fh, sizeof(nfsfh_t)); - nmp->nm_head->n_fhsize = nmp->nm_fhsize; nmp->nm_so = nmp->nm_rpcclnt->rc_so; + memcpy(&nmp->nm_fh, &nmp->nm_rpcclnt->rc_fh, sizeof(nfsfh_t)); /* Get the file attributes */ - memset(&getattr, 0, sizeof(struct rpc_call_fs)); - memset(&resok, 0, sizeof(struct rpc_reply_getattr)); - getattr.fs.fsroot.length = txdr_unsigned(nmp->nm_fhsize); memcpy(&getattr.fs.fsroot.handle, &nmp->nm_fh, sizeof(nfsfh_t)); @@ -1629,7 +1591,6 @@ int mountnfs(struct nfs_args *argp, void **handle) /* Save the file attributes */ memcpy(&nmp->nm_fattr, &resok.attr, sizeof(struct nfs_fattr)); - nfs_attrupdate(np, &resok.attr); /* Mounted! */ @@ -1637,16 +1598,9 @@ int mountnfs(struct nfs_args *argp, void **handle) nfs_semgive(nmp); fvdbg("Successfully mounted\n"); - return 0; + return OK; bad: - /* Free all memory that was successfully allocated */ - - if (np) - { - kfree(np); - } - if (nmp) { /* Disconnect from the server */ @@ -1718,21 +1672,32 @@ static int nfs_bind(struct inode *blkdriver, const void *data, void **handle) * ****************************************************************************/ -int nfs_unbind(void *handle, struct inode **blkdriver) +int nfs_unbind(FAR void *handle, FAR struct inode **blkdriver) { - struct nfsmount *nmp = (struct nfsmount *)handle; + FAR struct nfsmount *nmp = (FAR struct nfsmount *)handle; int error; fvdbg("Entry\n"); + DEBUGASSERT(nmp); - if (!nmp) - { - return -EINVAL; - } + /* Get exclusive access to the mount structure */ nfs_semtake(nmp); - /* Umount */ + /* Are there any open files? We can tell if there are open files by looking + * at the list of file structures in the mount structure. If this list + * not empty, then there are open files and we cannot unmount now (or a + * crash is sure to follow). + */ + + if (nmp->nm_head != NULL) + { + fdbg("ERROR; There are open files\n"); + error = EBUSY; + goto errout_with_semaphore; + } + + /* No open file... Umount the file system. */ error = rpcclnt_umount(nmp->nm_rpcclnt); if (error) @@ -1740,19 +1705,112 @@ int nfs_unbind(void *handle, struct inode **blkdriver) fdbg("ERROR: rpcclnt_umount failed: %d\n", error); } - /* Disconnect */ + /* Disconnect from the server */ nfs_disconnect(nmp); - /* And free resources */ + /* And free any allocated resources */ sem_destroy(&nmp->nm_sem); - kfree(nmp->nm_head); kfree(nmp->nm_so); kfree(nmp->nm_rpcclnt); kfree(nmp); return -error; + +errout_with_semaphore: + nfs_semgive(nmp); + return -error; +} + +/**************************************************************************** + * Name: nfs_fsinfo + * + * Description: + * Return information about root directory. + * + * Returned Value: + * 0 on success; positive errno value on failure + * + * Assumptions: + * The caller has exclusive access to the NFS mount structure + * + ****************************************************************************/ + +int nfs_fsinfo(FAR struct nfsmount *nmp) +{ + struct rpc_call_fs fsinfo; + struct rpc_reply_fsinfo fsp; + 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; + + /* 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)); + if (error) + { + return error; + } + + /* Save the root file system attributes */ + +//memcpy(&nmp->nm_fattr. &fsp.obj_attributes, sizeof(struct nfs_fattr)); + + pref = fxdr_unsigned(uint32_t, fsp.fsinfo.fs_wtpref); + if (pref < nmp->nm_wsize) + { + nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) & ~(NFS_FABLKSIZE - 1); + } + + 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; + } + } + + 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); + if (nmp->nm_rsize == 0) + { + nmp->nm_rsize = max; + } + } + + pref = fxdr_unsigned(uint32_t, fsp.fsinfo.fs_dtpref); + if (pref < nmp->nm_readdirsize) + { + nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) & ~(NFS_DIRBLKSIZ - 1); + } + + if (max < nmp->nm_readdirsize) + { + nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1); + if (nmp->nm_readdirsize == 0) + { + nmp->nm_readdirsize = max; + } + } + + return OK; } /**************************************************************************** @@ -1794,16 +1852,9 @@ static int nfs_statfs(struct inode *mountpt, struct statfs *sbp) /* Fill in the statfs info */ - memset(sbp, 0, sizeof(struct statfs)); sbp->f_type = NFS_SUPER_MAGIC; - if ((nmp->nm_flag & NFSMNT_GOTFSINFO) == 0) - { - (void)nfs_fsinfo(nmp); - } - - memset(&fsstat, 0, sizeof(struct rpc_call_fs)); - memset(&sfp, 0, sizeof(struct rpc_reply_fsstat)); + (void)nfs_fsinfo(nmp); fsstat.fs.fsroot.length = txdr_unsigned(nmp->nm_fhsize); fsstat.fs.fsroot.handle = nmp->nm_fh; @@ -1852,7 +1903,6 @@ static int nfs_remove(struct inode *mountpt, const char *relpath) struct file_handle fhandle; struct nfs_fattr fattr; char filename[NAME_MAX + 1]; - struct rpc_call_remove remove; struct rpc_reply_remove resok; FAR uint32_t *ptr; int namelen; @@ -1888,7 +1938,7 @@ static int nfs_remove(struct inode *mountpt, const char *relpath) /* Create the REMOVE RPC call arguments */ - ptr = (FAR uint32_t *)&remove.remove; + ptr = (FAR uint32_t *)&nmp->nm_msgbuffer.removef.remove; reqlen = 0; /* Copy the variable length, directory file handle */ @@ -1914,23 +1964,9 @@ static int nfs_remove(struct inode *mountpt, const char *relpath) nfs_statistics(NFSPROC_REMOVE); error = nfs_request(nmp, NFSPROC_REMOVE, - (FAR void *)&remove, reqlen, + (FAR void *)&nmp->nm_msgbuffer.removef, reqlen, (FAR void *)&resok, sizeof(struct rpc_reply_remove)); - /* Check if the file removal was successful */ - -#ifdef CONFIG_NFS_TCPIP - if (error == ENOENT) - { - /* If the first reply to the remove rpc is lost, the reply to the - * retransmitted request may be ENOENT if the file was in fact removed. - * Therefore, we cheat and return success. - */ - - error = OK; - } -#endif - errout_with_semaphore: nfs_semgive(nmp); return -error; @@ -1953,7 +1989,6 @@ static int nfs_mkdir(struct inode *mountpt, const char *relpath, mode_t mode) struct file_handle fhandle; struct nfs_fattr fattr; char dirname[NAME_MAX + 1]; - struct rpc_call_mkdir request; struct rpc_reply_mkdir resok; FAR uint32_t *ptr; uint32_t tmp; @@ -1990,7 +2025,7 @@ static int nfs_mkdir(struct inode *mountpt, const char *relpath, mode_t mode) /* Format the MKDIR call message arguments */ - ptr = (FAR uint32_t *)&request.mkdir; + ptr = (FAR uint32_t *)&nmp->nm_msgbuffer.mkdir.mkdir; reqlen = 0; /* Copy the variable length, directory file handle */ @@ -2031,13 +2066,13 @@ static int nfs_mkdir(struct inode *mountpt, const char *relpath, mode_t mode) *ptr++ = nfs_true; /* True: Uid value follows */ *ptr++ = 0; /* UID = 0 (nobody) */ reqlen += 2*sizeof(uint32_t); - + /* Set the group ID to one */ *ptr++ = nfs_true; /* True: Gid value follows */ *ptr++ = HTONL(1); /* GID = 1 (nogroup) */ reqlen += 2*sizeof(uint32_t); - + /* No size */ *ptr++ = nfs_false; /* False: No size value follows */ @@ -2053,7 +2088,7 @@ static int nfs_mkdir(struct inode *mountpt, const char *relpath, mode_t mode) nfs_statistics(NFSPROC_MKDIR); error = nfs_request(nmp, NFSPROC_MKDIR, - (FAR void *)&request, reqlen, + (FAR void *)&nmp->nm_msgbuffer.mkdir, reqlen, (FAR void *)&resok, sizeof(struct rpc_reply_mkdir)); if (error) { @@ -2082,7 +2117,6 @@ static int nfs_rmdir(struct inode *mountpt, const char *relpath) struct file_handle fhandle; struct nfs_fattr fattr; char dirname[NAME_MAX + 1]; - struct rpc_call_rmdir request; struct rpc_reply_rmdir resok; FAR uint32_t *ptr; int namelen; @@ -2118,7 +2152,7 @@ static int nfs_rmdir(struct inode *mountpt, const char *relpath) /* Set up the RMDIR call message arguments */ - ptr = (FAR uint32_t *)&request.rmdir; + ptr = (FAR uint32_t *)&nmp->nm_msgbuffer.rmdir.rmdir; reqlen = 0; /* Copy the variable length, directory file handle */ @@ -2144,22 +2178,9 @@ static int nfs_rmdir(struct inode *mountpt, const char *relpath) nfs_statistics(NFSPROC_RMDIR); error = nfs_request(nmp, NFSPROC_RMDIR, - (FAR void *)&request, reqlen, + (FAR void *)&nmp->nm_msgbuffer.rmdir, reqlen, (FAR void *)&resok, sizeof(struct rpc_reply_rmdir)); - /* Check if the removal was successful */ - -#ifdef CONFIG_NFS_TCPIP - if (error == ENOENT) - { - /* If the first reply to the remove rpc is lost, the reply to the - * retransmitted request may be ENOENT if the file was in fact removed. - * Therefore, we cheat and return success. - */ - error = 0; - } -#endif - errout_with_semaphore: nfs_semgive(nmp); return -error; @@ -2185,7 +2206,6 @@ static int nfs_rename(struct inode *mountpt, const char *oldrelpath, char from_name[NAME_MAX+1]; char to_name[NAME_MAX+1]; struct nfs_fattr fattr; - struct rpc_call_rename request; struct rpc_reply_rename resok; FAR uint32_t *ptr; int namelen; @@ -2230,7 +2250,7 @@ static int nfs_rename(struct inode *mountpt, const char *oldrelpath, /* Format the RENAME RPC arguments */ - ptr = (FAR uint32_t *)&request.rename; + ptr = (FAR uint32_t *)&nmp->nm_msgbuffer.renamef.rename; reqlen = 0; /* Copy the variable length, 'from' directory file handle */ @@ -2276,23 +2296,9 @@ static int nfs_rename(struct inode *mountpt, const char *oldrelpath, nfs_statistics(NFSPROC_RENAME); error = nfs_request(nmp, NFSPROC_RENAME, - (FAR void *)&request, reqlen, + (FAR void *)&nmp->nm_msgbuffer.renamef, reqlen, (FAR void *)&resok, sizeof(struct rpc_reply_rename)); - /* Check if the rename was successful */ - -#ifdef CONFIG_NFS_TCPIP - if (error == ENOENT) - { - /* If the first reply to the remove rpc is lost, the reply to the - * retransmitted request may be ENOENT if the file was in fact removed. - * Therefore, we cheat and return success. - */ - - error = 0; - } -#endif - errout_with_semaphore: nfs_semgive(nmp); return -error; @@ -2352,7 +2358,7 @@ static int nfs_stat(struct inode *mountpt, const char *relpath, */ tmp = fxdr_unsigned(uint32_t, obj_attributes.fa_mode); - + /* Here we exploit the fact that most mode bits are the same in NuttX * as in the NFSv3 spec. */ @@ -2423,58 +2429,3 @@ errout_with_semaphore: nfs_semgive(nmp); return -error; } - -#ifdef COMP -/**************************************************************************** - * Name: nfs_sync - * - * Description: Flush out the buffer cache - * - * Returned Value: - * 0 on success; a negated errno value on failure. - * - ****************************************************************************/ - -int nfs_sync(struct file *filep) -{ - struct inode *inode; - struct nfsmount *nmp; - struct nfsnode *np; - int error = 0; - - /* Sanity checks */ - - DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); - - /* Recover our private data from the struct file instance */ - - np = filep->f_priv; - inode = filep->f_inode; - nmp = inode->i_private; - - DEBUGASSERT(nmp != NULL); - - /* Make sure that the mount is still healthy */ - - nfs_semtake(nmp); - error = nfs_checkmount(nmp); - if (error != OK) - { - fdbg("ERROR: nfs_checkmount failed: %d\n", error); - goto errout_with_semaphore; - } - - /* Force stale buffer cache information to be flushed. */ - - /* Check if the has been modified in any way */ - - if ((np->n_flags & NFSNODE_MODIFIED) != 0) - { - //error = VOP_FSYNC(vp, cred, waitfor, p); - } - -errout_with_semaphore: - nfs_semgive(nmp); - return -error; -} -#endif diff --git a/nuttx/fs/nfs/rpc.h b/nuttx/fs/nfs/rpc.h index 82d5e46ee..5177108b7 100644 --- a/nuttx/fs/nfs/rpc.h +++ b/nuttx/fs/nfs/rpc.h @@ -277,9 +277,6 @@ struct rpc_call_header uint32_t rp_vers; /* version */ uint32_t rp_proc; /* procedure */ struct rpc_auth_info rpc_auth; -#ifdef CONFIG_NFS_UNIX_AUTH - struct auth_unix rpc_unix; -#endif struct rpc_auth_info rpc_verf; }; @@ -485,21 +482,10 @@ struct rpcclnt uint8_t rc_clntflags; /* For RPCCLNT_* flags */ uint8_t rc_sotype; /* Type of socket */ - uint8_t rc_soproto; /* and protocol */ /* These describe the current RPC call */ uint8_t rc_callflags; /* For RPCCALL_* flags */ - - /* Authentication: Can be RPCAUTH_NULL, RPCAUTH_KERBV4, RPCAUTH_UNIX - * Should be kept in XDR form - */ - - /* RPCAUTH_UNIX */ -#ifdef CONFIG_NFS_UNIX_AUTH - struct rpc_auth_info rc_oldauth; /* authentication */ - void *rc_auth; -#endif }; /**************************************************************************** diff --git a/nuttx/fs/nfs/rpc_clnt.c b/nuttx/fs/nfs/rpc_clnt.c index a749d7411..0dcb7f2b7 100644 --- a/nuttx/fs/nfs/rpc_clnt.c +++ b/nuttx/fs/nfs/rpc_clnt.c @@ -98,23 +98,6 @@ * Pre-processor Definitions ****************************************************************************/ -/* There is a congestion window for outstanding RPCs maintained per mount - * point. The cwnd size is adjusted in roughly the way that: Van Jacobson, - * Congestion avoidance and Control, In "Proceedings of SIGCOMM '88". ACM, - * August 1988. describes for TCP. The cwnd size is chopped in half on a - * retransmit timeout and incremented by 1/cwnd when each RPC reply is - * received and a full cwnd of RPCs is in progress. (The sent count and cwnd - * are scaled for integer arith.) Variants of "slow start" were tried and - * were found to be too much of a performance hit (ave. rtt 3 times larger), - * I suspect due to the large rtt that nfs RPCs have. - */ - -#define RPC_CWNDSCALE 256 -#define RPC_MAXCWND (RPC_CWNDSCALE * 32) - -#define RPC_ERRSTR_ACCEPTED_SIZE 6 -#define RPC_ERRSTR_AUTH_SIZE 6 - /* Increment RPC statistics */ #ifdef CONFIG_NFS_STATISTICS @@ -159,9 +142,6 @@ 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); -#ifdef CONFIG_NFS_TCPIP -static int rpcclnt_reconnect(FAR struct rpcclnt *rpc); -#endif 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); @@ -221,208 +201,19 @@ static int rpcclnt_receive(FAR struct rpcclnt *rpc, struct sockaddr *aname, int proc, int program, void *reply, size_t resplen) { ssize_t nbytes; -#ifdef CONFIG_NFS_TCPIP - uint32_t resplen; - int sotype; -#endif int error = 0; - int errval; -#ifdef CONFIG_NFS_TCPIP - /* Set up arguments for psock_recvfrom() */ - - sotype = rpc->rc_sotype; - - if (sotype != SOCK_DGRAM) + if (rpc->rc_so == NULL) { - tryagain: - - /* Check for fatal errors and resending request. */ - - if (rpc->rc_so == NULL) - { - error = rpcclnt_reconnect(rpc); - if (error) - { - return error; - } - - goto tryagain; - } - - while (rpc->rc_callflags & RPCCALL_MUSTRESEND) - { - rpc_statistics(rpcretries); - error = rpcclnt_send(rpc, proc, program, call, reqlen); - if (error) - { - if (error == EINTR || error == ERESTART) - { - return error; - } - - error = rpcclnt_reconnect(rpc); - if (error != OK) - { - return error; - } - - goto tryagain; - } - } - - if (sotype == SOCK_STREAM) - { - errval = 0; - do - { - socklen_t fromlen = sizeof(*rpc->rc_name) - nbytes = psock_recvfrom(rpc->rc_so, reply, resplen, - MSG_WAITALL, rpc->rc_name, - &fromlen); - if (nbytes < 0) - { - errval = errno; - fdbg("ERROR: psock_recvfrom returned %d\n", errval); - } - } - while (errval == EWOULDBLOCK); - - if (nbytes < 0) - { - error = errval; - } - else if (nbytes < resplen) - { - fdbg("ERROR: Short receive from RPC server\n"); - fvdbg(" Expected %d bytes, received %d bytes\n", - resplen, nbytes); - error = EPIPE; - } - else - { - error = 0; - } - -#warning "What is resplen? This logic is not right!" - resplen = ntohl(resplen) & ~0x80000000; - - /* This is SERIOUS! We are out of sync with the - * sender and forcing a disconnect/reconnect is all I - * can do. - */ - - else if (resplen > RPC_MAXPACKET) - { - fdbg("ERROR: Impossible length rom RPC server: %d\n", resplen); - error = EFBIG; - goto errout; - } - - errval = 0 - do - { - socklen_t fromlen = sizeof(*rpc->rc_name); - nbytes = psock_recvfrom(so, reply, sizeof(*reply), - MSG_WAITALL, rpc->rc_name, - &fromlen); - if (nbytes < 0) - { - errval = errno; - fdbg("ERROR: psock_recvfrom failed: %d\n", errval); - } - } - while (errval == EWOULDBLOCK || errval == EINTR || errval == ERESTART); - - if (nbytes < 0) - { - error = errval; - goto errout; - } - else if (nbytes < resplen) - { - fdbg("ERROR: Short receive from RPC server\n"); - fvdbg(" Expected %d bytes, received %d bytes\n", - resplen, nbytes); - error = EPIPE; - } - else - { - error = 0; - } - } - else - { - /* NB: Since uio_resid is big, MSG_WAITALL is ignored - * and psock_recvfrom() will return when it has either a - * control msg or a data msg. We have no use for - * control msg., but must grab them and then throw - * them away so we know what is going on. - */ - - errval = 0; - do - { - socklen_t fromlen = sizeof(*rpc->rc_name); - nbytes = psock_recvfrom(so, reply, sizeof(*reply), 0, - rpc->rc_name, &fromlen); - if (nbytes < 0) - { - errval = errno; - fdbg("ERROR: psock_recvfrom failed: %d\n", errval); - } - } - while (errval == EWOULDBLOCK || nbytes == 0); - - if (nbytes < 0) - { - error = errval; - goto errout; - } - else if (nbytes < resplen) - { - fdbg("ERROR: Short receive from RPC server\n"); - fvdbg(" Expected %d bytes, received %d bytes\n", - resplen, nbytes); - error = EPIPE; - } - else - { - error = 0; - } - } - - errout: - if (error != 0 && error != EINTR && error != ERESTART) - { - if (error != EPIPE) - { - fdbg("ERROR: Receive error %d from RPC server\n", error); - } - - error = rpcclnt_reconnect(rpc); - if (error == 0) - { - goto tryagain; - } - } + return EACCES; } - else -#endif - { - if (rpc->rc_so == NULL) - { - return EACCES; - } - socklen_t fromlen = sizeof(struct sockaddr); - nbytes = psock_recvfrom(rpc->rc_so, reply, resplen, 0, aname, &fromlen); - if (nbytes < 0) - { - errval = errno; - fdbg("ERROR: psock_recvfrom failed: %d\n", errval); - error = errval; - } + socklen_t fromlen = sizeof(struct sockaddr); + nbytes = psock_recvfrom(rpc->rc_so, reply, resplen, 0, aname, &fromlen); + if (nbytes < 0) + { + error = errno; + fdbg("ERROR: psock_recvfrom failed: %d\n", error); } return error; @@ -467,7 +258,7 @@ static int rpcclnt_reply(FAR struct rpcclnt *rpc, int procid, int prog, replyheader = (FAR struct rpc_reply_header *)reply; rxid = replyheader->rp_xid; - + if (replyheader->rp_direction != rpc_reply) { rpc_statistics(rpcinvalid); @@ -522,7 +313,7 @@ static void rpcclnt_fmtheader(FAR struct rpc_call_header *ch, uint32_t xid, int prog, int vers, int procid) { /* Format the call header */ - + ch->rp_xid = txdr_unsigned(xid); ch->rp_direction = rpc_call; ch->rp_rpcvers = rpc_vers; @@ -535,14 +326,6 @@ static void rpcclnt_fmtheader(FAR struct rpc_call_header *ch, ch->rpc_auth.authtype = rpc_auth_null; ch->rpc_auth.authlen = 0; -#ifdef CONFIG_NFS_UNIX_AUTH - ch->rpc_unix.stamp = txdr_unsigned(1); - ch->rpc_unix.hostname = 0; - ch->rpc_unix.uid = setuid; - ch->rpc_unix.gid = setgid; - ch->rpc_unix.gidlist = 0; -#endif - /* rpc_verf part (auth_null) */ ch->rpc_verf.authtype = rpc_auth_null; @@ -594,7 +377,6 @@ int rpcclnt_connect(struct rpcclnt *rpc) /* Create the socket */ saddr = rpc->rc_name; - memset(&sin, 0, sizeof(sin)); /* Create an instance of the socket state structure */ @@ -605,7 +387,7 @@ int rpcclnt_connect(struct rpcclnt *rpc) return ENOMEM; } - error = psock_socket(saddr->sa_family, rpc->rc_sotype, rpc->rc_soproto, so); + error = psock_socket(saddr->sa_family, rpc->rc_sotype, IPPROTO_UDP, so); if (error < 0) { errval = errno; @@ -678,8 +460,6 @@ int rpcclnt_connect(struct rpcclnt *rpc) * Get port number for MOUNTD. */ - memset(&sdata, 0, sizeof(struct rpc_call_pmap)); - memset(&rdata, 0, sizeof(struct rpc_reply_pmap)); sdata.pmap.prog = txdr_unsigned(RPCPROG_MNT); sdata.pmap.vers = txdr_unsigned(RPCMNT_VER1); sdata.pmap.proc = txdr_unsigned(IPPROTO_UDP); @@ -707,8 +487,6 @@ int rpcclnt_connect(struct rpcclnt *rpc) /* Do RPC to mountd. */ - memset(&mountd, 0, sizeof(struct rpc_call_mount)); - memset(&mdata, 0, sizeof(struct rpc_reply_mount)); strncpy(mountd.mount.rpath, rpc->rc_path, 90); mountd.mount.len = txdr_unsigned(sizeof(mountd.mount.rpath)); @@ -734,8 +512,6 @@ int rpcclnt_connect(struct rpcclnt *rpc) * NFS port in the socket. */ - memset(&sdata, 0, sizeof(struct rpc_call_pmap)); - memset(&rdata, 0, sizeof(struct rpc_reply_pmap)); sa->sin_port = htons(PMAPPORT); error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr)); @@ -776,35 +552,6 @@ bad: return error; } -/* Reconnect routine: Called when a connection is broken on a reliable - * protocol. - clean up the old socket - nfs_connect() again - set - * RPCCALL_MUSTRESEND for all outstanding requests on mount point If this - * fails the mount point is DEAD! - */ - -#ifdef CONFIG_NFS_TCPIP -int rpcclnt_reconnect(FAR struct rpcclnt *rpc) -{ - int error; - - rpcclnt_disconnect(rpc); - do - { - error = rpcclnt_connect(rpc); - if (error != OK) - { - fdbg("ERROR: rpcclnt_connect failed: %d\n", error); - if (error == EINTR || error == ERESTART) - { - return EINTR; - } - } - } - while (error != OK) - return OK; -} -#endif - void rpcclnt_disconnect(struct rpcclnt *rpc) { struct socket *so; @@ -833,8 +580,6 @@ int rpcclnt_umount(struct rpcclnt *rpc) * Get port number for MOUNTD. */ - memset(&sdata, 0, sizeof(struct rpc_call_pmap)); - memset(&rdata, 0, sizeof(struct rpc_reply_pmap)); sa->sin_port = htons(PMAPPORT); error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr)); @@ -869,9 +614,6 @@ int rpcclnt_umount(struct rpcclnt *rpc) /* Do RPC to umountd. */ - memset(&mountd, 0, sizeof(struct rpc_call_mount)); - memset(&mdata, 0, sizeof(struct rpc_reply_mount)); - strncpy(mountd.mount.rpath, rpc->rc_path, 92); mountd.mount.len = txdr_unsigned(sizeof(mountd.mount.rpath)); |