From e88d1ff1f09ba0ea6999ab2e5e2d55dc88434646 Mon Sep 17 00:00:00 2001 From: patacongo Date: Sat, 12 May 2012 00:11:24 +0000 Subject: NFS update git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4724 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/fs/nfs/nfs_mount.h | 1 + nuttx/fs/nfs/nfs_socket.c | 6 +- nuttx/fs/nfs/nfs_vfsops.c | 19 +++- nuttx/fs/nfs/rpc.h | 57 ++++++++--- nuttx/fs/nfs/rpc_clnt.c | 222 ++++++++++++++++++++++++++++++++----------- nuttx/include/nuttx/fs/nfs.h | 1 + 6 files changed, 237 insertions(+), 69 deletions(-) diff --git a/nuttx/fs/nfs/nfs_mount.h b/nuttx/fs/nfs/nfs_mount.h index 26b3eb2f9..cd3980f79 100644 --- a/nuttx/fs/nfs/nfs_mount.h +++ b/nuttx/fs/nfs/nfs_mount.h @@ -75,6 +75,7 @@ struct nfsmount sem_t nm_sem; /* Used to assume thread-safe access */ int nm_numgrps; /* Max. size of groupslist */ nfsfh_t nm_fh; /* File handle of root dir */ + char *nm_path; /* server's path of the directory being mount */ int nm_fhsize; /* Size of root file handle */ struct rpcclnt *nm_rpcclnt; /* rpc state */ struct socket *nm_so; /* Rpc socket */ diff --git a/nuttx/fs/nfs/nfs_socket.c b/nuttx/fs/nfs/nfs_socket.c index fc658a481..c1508171d 100644 --- a/nuttx/fs/nfs/nfs_socket.c +++ b/nuttx/fs/nfs/nfs_socket.c @@ -144,7 +144,7 @@ int nfs_connect(struct nfsmount *nmp) //rpc->rc_flag |= RPCCLNT_REDIRECT; /* Make this a mount option. */ rpc->rc_authtype = RPCAUTH_NULL; /* for now */ - //rpc->rc_servername = nmp->nm_mountp->mnt_stat.f_mntfromname; + rpc->rc_path = nmp->nm_path; rpc->rc_name = &nmp->nm_nam; rpc->rc_sotype = nmp->nm_sotype; @@ -191,7 +191,9 @@ tryagain: memset(&reply, 0, sizeof(reply)); - if ((error = rpcclnt_request(clnt, procnum, &reply, datain)) != 0) + error = rpcclnt_request(clnt, procnum, nmp->nm_rpcclnt->rc_prog->prog_id, + nmp->nm_rpcclnt->rc_prog->prog_version, &reply, datain); + if (error != 0) { goto out; } diff --git a/nuttx/fs/nfs/nfs_vfsops.c b/nuttx/fs/nfs/nfs_vfsops.c index bfdc2e955..879c21ed2 100644 --- a/nuttx/fs/nfs/nfs_vfsops.c +++ b/nuttx/fs/nfs/nfs_vfsops.c @@ -995,7 +995,7 @@ int mountnfs(struct nfs_args *argp, void **handle) { struct nfsmount *nmp; struct nfsnode *np; - int error; + int error = 0; /* Create an instance of the mountpt state structure */ @@ -1031,6 +1031,7 @@ int mountnfs(struct nfs_args *argp, void **handle) //strncpy(&mp->mnt_stat.f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN); //memmove(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); //bcopy(pth, nmp->nm_mntonname, 90); + nmp->nm_path = argp->path; //memmove(argp, &mp->mnt_stat.mount_info.nfs_args, sizeof(*argp)); nmp->nm_nam = argp->addr; nfs_decode_args(nmp, argp); @@ -1064,6 +1065,7 @@ int mountnfs(struct nfs_args *argp, void **handle) /* Mounted! */ nmp->nm_mounted = true; + nmp->nm_fh = nmp->nm_rpcclnt->rc_fh; nmp->nm_so = nmp->nm_rpcclnt->rc_so; *handle = (void*)nmp; nfs_semgive(nmp); @@ -1130,7 +1132,8 @@ static int nfs_bind(struct inode *blkdriver, const void *data, void **handle) int nfs_unbind(void *handle, struct inode **blkdriver) { - struct nfsmount *nmp = (struct nfsmount *) handle ; + struct nfsmount *nmp = (struct nfsmount *)handle; + int error; fvdbg("Entry\n"); @@ -1140,6 +1143,14 @@ int nfs_unbind(void *handle, struct inode **blkdriver) } nfs_semtake(nmp); + + error = rpcclnt_umount(nmp->nm_rpcclnt); + if (error) + { + dbg("Umounting fails %d\n", error); + goto bad; + } + nfs_disconnect(nmp); sem_destroy(&nmp->nm_sem); kfree(nmp->nm_head); @@ -1148,6 +1159,10 @@ int nfs_unbind(void *handle, struct inode **blkdriver) kfree(nmp); return 0; + +bad: + nfs_disconnect(nmp); + return(error); } /**************************************************************************** diff --git a/nuttx/fs/nfs/rpc.h b/nuttx/fs/nfs/rpc.h index fe93a6e4d..f6b8d6674 100644 --- a/nuttx/fs/nfs/rpc.h +++ b/nuttx/fs/nfs/rpc.h @@ -10,7 +10,7 @@ * copyright (c) 2003 * the regents of the university of michigan * all rights reserved - * + * * permission is granted to use, copy, create derivative works and redistribute * this software and such derivative works for any purpose, so long as the name * of the university of michigan is not used in any advertising or publicity @@ -18,7 +18,7 @@ * written prior authorization. if the above copyright notice or any other * identification of the university of michigan is included in any copy of any * portion of this software, then the disclaimer below must also be included. - * + * * this software is provided as is, without representation from the university * of michigan as to its fitness for any purpose, and without warranty by the * university of michigan of any kind, either express or implied, including @@ -84,7 +84,7 @@ #define RPCCLNT_SOFT 0x001 /* soft mount (hard is details) */ #define RPCCLNT_INT 0x002 /* allow interrupts on hard mounts */ #define RPCCLNT_NOCONN 0x004 /* dont connect the socket (udp) */ -#define RPCCLNT_DUMBTIMR 0x010 +#define RPCCLNT_DUMBTIMR 0x010 /* XXX should be replaced with real locks */ @@ -93,10 +93,42 @@ #define RPCCLNT_RCVLOCK 0x400 #define RPCCLNT_WANTRCV 0x800 +/* RPC definitions for the portmapper. */ + +#define PMAPPORT 111 +#define PMAPPROG 100000 +#define PMAPVERS 2 +#define PMAPPROC_NULL 0 +#define MAPPROC_SET 1 +#define PMAPPROC_UNSET 2 +#define PMAPPROC_GETPORT 3 +#define PMAPPROC_DUMP 4 +#define PMAPPROC_CALLIT 5 + /**************************************************************************** * Public Types ****************************************************************************/ +struct call_args_pmap +{ + uint32_t prog; + uint32_t vers; + uint32_t proc; + uint32_t port; +}; + + struct call_result_pmap +{ + uint16_t port; + unsigned char *extradata; +}; + + struct call_result_mount +{ + uint16_t problem; + nfsfh_t fhandle; +}; + struct rpc_program { uint32_t prog_id; @@ -107,9 +139,7 @@ struct rpc_program struct rpctask { dq_entry_t r_chain; - struct rpcclnt *r_rpcclnt; - uint32_t r_xid; int r_flags; /* flags on request, see below */ int r_retry; /* max retransmission count */ @@ -146,7 +176,9 @@ struct rpc_call uint32_t rp_proc; /* procedure */ unsigned char *data; struct rpc_auth_info rpc_auth; - struct auth_unix rpc_unix; +#ifdef CONFIG_NFS_UNIX_AUTH + struct auth_unix rpc_unix; +#endif struct rpc_auth_info rpc_verf; }; @@ -154,6 +186,7 @@ struct rpc_reply { uint32_t rp_xid; /* request transaction id */ int32_t rp_direction; /* call direction (1) */ + struct { uint32_t type; @@ -173,7 +206,7 @@ struct rpc_reply uint32_t high; } mismatch_info; } stat; - + struct rpc_auth_info rpc_verfi; }; @@ -191,8 +224,10 @@ struct rpcclnt int rc_wsize; /* Max size of the request data */ int rc_rsize; /* Max size of the response data */ + nfsfh_t rc_fh; /* File handle of root dir */ + char *rc_path; /* server's path of the directory being mount */ - struct sockaddr *rc_name; + struct sockaddr *rc_name; struct socket *rc_so; /* Rpc socket */ uint8_t rc_sotype; /* Type of socket */ @@ -234,14 +269,12 @@ struct rpcclnt ****************************************************************************/ void rpcclnt_init(void); -//void rpcclnt_uninit(void); - -//int rpcclnt_setup(struct rpcclnt *, struct rpc_program *, struct sockaddr *, int, int, struct rpc_auth_info *, int, int, int); int rpcclnt_connect(struct rpcclnt *); int rpcclnt_reconnect(struct rpctask *); void rpcclnt_disconnect(struct rpcclnt *); +int rpcclnt_umount(struct rpcclnt *); void rpcclnt_safedisconnect(struct rpcclnt *); -int rpcclnt_request(struct rpcclnt *, int, struct rpc_reply *, void *); +int rpcclnt_request(struct rpcclnt *, int, int, int, struct rpc_reply *, void *); int rpcclnt_cancelreqs(struct rpcclnt *); diff --git a/nuttx/fs/nfs/rpc_clnt.c b/nuttx/fs/nfs/rpc_clnt.c index 0e72ff5b0..ab0a381b9 100644 --- a/nuttx/fs/nfs/rpc_clnt.c +++ b/nuttx/fs/nfs/rpc_clnt.c @@ -102,7 +102,7 @@ * Pre-processor Definitions ****************************************************************************/ -#define RPC_RETURN(X) do { dbg("returning %d", X); return X; }while(0) +#define RPC_RETURN(X) do { nvdbg("returning %d\n", X); return X; } while(0) /* Estimate rto for an nfs rpc sent via. an unreliable datagram. Use the mean * and mean deviation of rtt for the appropriate type of rpc for the frequent @@ -223,7 +223,8 @@ static int rpcclnt_sigintr(struct rpcclnt *, struct rpctask *, cthread_t *); static void rpcclnt_softterm(struct rpctask *task); static uint32_t rpcclnt_proct(struct rpcclnt *, uint32_t); -static int rpcclnt_buildheader(struct rpcclnt *, int, void *, struct rpc_call *); +static int rpcclnt_buildheader(struct rpcclnt *, int, int, int, void *, + struct rpc_call *); /**************************************************************************** * Private Functions @@ -294,7 +295,7 @@ rpcclnt_send(struct socket *so, struct sockaddr *nam, struct rpc_call *call, } error = psock_sendto(so, call, sizeof(*call), flags, sendnam, sizeof(*sendnam)); - if (error != 0) + if (error < 0) { if (rep != NULL) { @@ -317,16 +318,13 @@ rpcclnt_send(struct socket *so, struct sockaddr *nam, struct rpc_call *call, ndbg("rpc service send error %d\n", error); } - /* Handle any recoverable (soft) socket errors here. */ + RPC_RETURN(error); - if (error != EINTR && error != ERESTART && - error != EWOULDBLOCK && error != EPIPE) - { - error = 0; - } } - - RPC_RETURN(error); + else + { + RPC_RETURN(0); + } } /* Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all @@ -538,25 +536,20 @@ static int rpcclnt_receive(struct rpctask *rep, struct sockaddr *aname, RPC_RETURN(EACCES); } - do + socklen_t fromlen = sizeof(*aname); + rcvflg = 0; + error = psock_recvfrom(so, reply, sizeof(*reply), rcvflg, + aname, &fromlen); + nvdbg("psock_recvfrom returns %d\n", error); + if (error > 0) { - socklen_t fromlen = sizeof(*aname); - rcvflg = 0; - error = psock_recvfrom(so, reply, sizeof(*reply), rcvflg, - aname, &fromlen); - dbg("psock_recvfrom returns %d", error); - if (error == EWOULDBLOCK && (rep->r_flags & TASK_SOFTTERM)) - { - dbg("wouldblock && softerm -> EINTR"); - RPC_RETURN(EINTR); - } + RPC_RETURN(0); } - while (error == EWOULDBLOCK); #ifdef CONFIG_NFS_TCPIP } #endif - RPC_RETURN(error); + RPC_RETURN(ENONET); } /* Implement receipt of reply on a socket. We must search through the list of @@ -573,10 +566,11 @@ rpcclnt_reply(struct rpctask *myrep, struct rpc_call *call, //Here we need to m int32_t t1; uint32_t rxid; int error; + int count; /* Loop around until we get our own reply */ - for (;;) + for (count = 0; count < 9; count++) { /* Lock against other receivers so that I don't get stuck in * sbwait() after someone else has received my reply for me. @@ -594,7 +588,6 @@ rpcclnt_reply(struct rpctask *myrep, struct rpc_call *call, //Here we need to m /* Get the next Rpc reply off the socket */ error = rpcclnt_receive(myrep, rpc->rc_name, reply, call); - #ifdef CONFIG_NFS_TCPIP rpcclnt_rcvunlock(&rpc->rc_flag); #endif @@ -612,7 +605,7 @@ rpcclnt_reply(struct rpctask *myrep, struct rpc_call *call, //Here we need to m RPC_RETURN(0); } - ndbg("ingoring routing error on connectionless protocol."); + ndbg("ignoring routing error on connectionless protocol."); continue; } RPC_RETURN(error); @@ -698,8 +691,9 @@ rpcclnt_reply(struct rpctask *myrep, struct rpc_call *call, //Here we need to m if (rep == 0) { + ndbg("rpc reply not matched\n"); rpcstats.rpcunexpected++; - dbg("rpc reply not matched\n"); + RPC_RETURN(ENOMSG); } else if (rep == myrep) { @@ -711,6 +705,8 @@ rpcclnt_reply(struct rpctask *myrep, struct rpc_call *call, //Here we need to m RPC_RETURN(0); } } + + RPC_RETURN(ENONET); } #ifdef CONFIG_NFS_TCPIP @@ -923,7 +919,7 @@ void rpcclnt_init(void) //rpcclnt_timer(NULL, callmgs); - nvdbg("rpc initialed"); + nvdbg("rpc initialized"); return; } @@ -946,6 +942,11 @@ int rpcclnt_connect(struct rpcclnt *rpc) int error; struct sockaddr *saddr; struct sockaddr_in sin; + struct sockaddr_in *sa; + struct call_args_pmap sdata; + struct call_result_pmap *rdata; + struct call_result_mount *mdata; + struct rpc_reply reply; struct timeval tv; uint16_t tport; @@ -999,6 +1000,20 @@ int rpcclnt_connect(struct rpcclnt *rpc) goto bad; } + /* 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; + + error = psock_setsockopt(rpc->rc_so, SOL_SOCKET, SO_RCVTIMEO, + (const void *)&tv, sizeof(tv)); + if (error != 0) + { + goto bad; + } + /* Protocols that do not require connections may be optionally left * unconnected for servers that reply from a port other than * NFS_PORT. @@ -1011,31 +1026,74 @@ int rpcclnt_connect(struct rpcclnt *rpc) goto bad; } else - { #endif + { error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr)); if (error) { - dbg("psock_connect returns %d", error); + ndbg("psock_connect to ppmap port returns %d", error); goto bad; } -#ifdef CONFIG_NFS_TCPIP - } -#endif - /* Always set receive timeout to detect server crash and reconnect. - * Otherwise, we can get stuck in psock_receive forever. - */ + /* Do the RPC to get a dynamic bounding with the server using ppmap */ + /* Get port number for MOUNTD. */ - tv.tv_sec = 1; - tv.tv_usec = 0; + sdata.prog = txdr_unsigned(RPCPROG_MNT); + sdata.vers = txdr_unsigned(RPCMNT_VER1); + sdata.proc = txdr_unsigned(IPPROTO_UDP); + sdata.port = 0; - if ((error = - psock_setsockopt(rpc->rc_so, SOL_SOCKET, SO_RCVTIMEO, (const void *)&tv, - sizeof(tv)))) - { - goto bad; + memset(&reply, 0, sizeof(reply)); + + error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS, + &reply, &sdata); + if (error != 0) + { + goto bad; + } + + rdata = (struct call_result_pmap *)reply.stat.where; + + sa = (FAR struct sockaddr_in *)saddr; + sa->sin_port = rdata->port; + + error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr)); + if (error) + { + ndbg("psock_connect NFS port returns %d\n", error); + goto bad; + } + + /* Do RPC to mountd. */ + + memset(&reply, 0, sizeof(reply)); + + error = rpcclnt_request(rpc, RPCMNT_MOUNT, RPCPROG_MNT, RPCMNT_VER1, + &reply, &rpc->rc_path); + if (error != 0) + { + goto bad; + } + + mdata = (struct call_result_mount *)reply.stat.where; + rpc->rc_fh = mdata->fhandle; + + if (mdata->problem) + { + ndbg("error mounting with the server %d\n", error); + goto bad; + } + + /* NFS port in the socket*/ + + sa->sin_port = htons(NFS_PORT); + error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr)); + if (error) + { + ndbg("psock_connect NFS port returns %d\n", error); + goto bad; + } } /* Initialize other non-zero congestion variables */ @@ -1104,6 +1162,65 @@ void rpcclnt_disconnect(struct rpcclnt *rpc) } } +int rpcclnt_umount(struct rpcclnt *rpc) +{ + struct sockaddr *saddr; + struct sockaddr_in *sa; + struct rpc_reply reply; + struct call_args_pmap sdata; + struct call_result_pmap *rdata; + int error; + + saddr = rpc->rc_name; + + /* Do the RPC to get a dynamic bounding with the server using ppmap*/ + /* Get port number for MOUNTD. */ + + sdata.prog = txdr_unsigned(RPCPROG_MNT); + sdata.vers = txdr_unsigned(RPCMNT_VER1); + sdata.proc = txdr_unsigned(IPPROTO_UDP); + sdata.port = 0; + + memset(&reply, 0, sizeof(reply)); + + error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS, + &reply, &sdata); + if (error != 0) + { + goto bad; + } + + rdata = (struct call_result_pmap *)reply.stat.where; + + sa = (FAR struct sockaddr_in *)saddr; + sa->sin_port = rdata->port; + + error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr)); + + if (error) + { + ndbg("psock_connect umount port returns %d\n", error); + goto bad; + } + + /* Do RPC to umountd. */ + + memset(&reply, 0, sizeof(reply)); + + error = rpcclnt_request(rpc, RPCMNT_UMOUNT, RPCPROG_MNT, RPCMNT_VER1, + &reply, &rpc->rc_path); + if (error != 0) + { + goto bad; + } + + RPC_RETURN(0); + +bad: + rpcclnt_disconnect(rpc); + RPC_RETURN(error); +} + #ifdef CONFIG_NFS_TCPIP void rpcclnt_safedisconnect(struct rpcclnt *rpc) { @@ -1127,13 +1244,13 @@ void rpcclnt_safedisconnect(struct rpcclnt *rpc) * are invalid unless reply->type == RPC_MSGACCEPTED */ -int rpcclnt_request(struct rpcclnt *rpc, int procnum, struct rpc_reply *reply, void *datain) +int rpcclnt_request(struct rpcclnt *rpc, int procnum, int prog, int version, + struct rpc_reply *reply, void *datain) { struct rpc_call *callhost; struct rpc_reply *replysvr; struct rpctask *task; int error = 0; - int xid = 0; /* Create an instance of the call state structure */ @@ -1162,7 +1279,7 @@ int rpcclnt_request(struct rpcclnt *rpc, int procnum, struct rpc_reply *reply, v return -ENOMEM; } - error = rpcclnt_buildheader(rpc, procnum, datain, callhost); + error = rpcclnt_buildheader(rpc, procnum, prog, version, datain, callhost); if (error) { ndbg("building call header error"); @@ -1208,7 +1325,7 @@ int rpcclnt_request(struct rpcclnt *rpc, int procnum, struct rpc_reply *reply, v * now. */ - if (rpc->rc_so && (rpc->rc_sotype != SOCK_DGRAM || + if (rpc->rc_so && (rpc->rc_sotype == SOCK_DGRAM || (rpc->rc_flag & RPCCLNT_DUMBTIMR) || rpc->rc_sent < rpc->rc_cwnd)) { @@ -1218,7 +1335,6 @@ int rpcclnt_request(struct rpcclnt *rpc, int procnum, struct rpc_reply *reply, v error = rpcclnt_sndlock(&rpc->rc_flag, task); } #endif - if (error == 0) { error = rpcclnt_send(rpc->rc_so, rpc->rc_name, callhost, task); @@ -1248,6 +1364,7 @@ int rpcclnt_request(struct rpcclnt *rpc, int procnum, struct rpc_reply *reply, v { error = rpcclnt_reply(task, callhost, replysvr); } + nvdbg("out for reply %d\n", error); /* RPC done, unlink the request. */ @@ -1311,7 +1428,6 @@ int rpcclnt_request(struct rpcclnt *rpc, int procnum, struct rpc_reply *reply, v if (reply->stat.status == RPC_SUCCESS) { nvdbg("RPC_SUCCESS"); - reply->stat.where = replysvr->stat.where; } else if (reply->stat.status == RPC_PROGMISMATCH) @@ -1475,7 +1591,7 @@ void rpcclnt_timer(void *arg, struct rpc_call *call) /* Build the RPC header and fill in the authorization info. */ -int rpcclnt_buildheader(struct rpcclnt *rpc, int procid, +int rpcclnt_buildheader(struct rpcclnt *rpc, int procid, int prog, int vers, void *datain, struct rpc_call *call) { #ifdef CONFIG_NFS_UNIX_AUTH @@ -1507,8 +1623,8 @@ int rpcclnt_buildheader(struct rpcclnt *rpc, int procid, call->rp_xid = txdr_unsigned(rpcclnt_xid); call->rp_direction = rpc_call; call->rp_rpcvers = rpc_vers; - call->rp_prog = txdr_unsigned(rpc->rc_prog->prog_id); - call->rp_vers = txdr_unsigned(rpc->rc_prog->prog_version); + call->rp_prog = txdr_unsigned(prog); + call->rp_vers = txdr_unsigned(vers); call->rp_proc = txdr_unsigned(procid); call->data = datain; diff --git a/nuttx/include/nuttx/fs/nfs.h b/nuttx/include/nuttx/fs/nfs.h index 423c212e6..431c1d130 100644 --- a/nuttx/include/nuttx/fs/nfs.h +++ b/nuttx/include/nuttx/fs/nfs.h @@ -127,6 +127,7 @@ struct nfs_args int readahead; /* # of blocks to readahead */ int leaseterm; /* Term (sec) of lease */ int deadthresh; /* Retrans threshold */ + char *path; /* server's path of the directory being mount */ int acregmin; /* cache attrs for reg files min time */ int acregmax; /* cache attrs for reg files max time */ int acdirmin; /* cache attrs for dirs min time */ -- cgit v1.2.3