net: NFS: Add NFSv3 support
PATCH 1/1 net: NFS: Add NFSv3 support
This patch enables NFSv3 support.
If NFSv2 is available use it as usual.
If NFSv2 is not available, but NFSv3 is available, use NFSv3.
If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.
Tested on iMX6 sabrelite with 4 Linux NFS servers:
* NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
* NFSv2 + NFSv3 server: use NFSv3 protocol
* NFSv3 + NFSv4 server: use NFSv3 protocol
* NFSv3 server: use NFSv3 protocol
--- net/nfs.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++++----------- net/nfs.h | 15 +++- 2 files changed, 246 insertions(+), 50 deletions(-)
net/nfs.c +232 -49
@@ -22,6 +22,10 @@* possible, maximum 16 steps). There is no clearing of ".."'s inside the * path, so please DON'T DO THAT. thx. */ +/* NOTE 4: NFSv3 support added by Guillaume GARDET. +* NFSv2 is still used by default. But if server does not support NFSv2, then +* NFSv3 is used, if available on NFS server. */ +#include <common.h> #include <command.h> #include <net.h>
@@ -47,8 +51,11 @@ static int nfs_offset = -1;static int nfs_len;static ulong nfs_timeout =NFS_TIMEOUT ; -static char dirfh[NFS_FHSIZE ];/* file handle of directory */ -static char filefh[NFS_FHSIZE ];/* file handle of kernel image */ +static char dirfh[NFS_FHSIZE ];/* NFSv2 / NFSv3 file handle of directory */ +static char filefh[NFS_FHSIZE ];/* NFSv2 file handle */ + +static char filefh3[NFS3_FHSIZE ];/* NFSv3 file handle */ +static int filefh3_length;/* (variable) length of filefh3 */ static enum net_loop_state nfs_download_state;static struct in_addr nfs_server_ip;
@@ -70,6 +77,10 @@ static char *nfs_filename;static char *nfs_path;static char nfs_path_buff[2048 ]; +#define NFSV2_FLAG 1 +#define NFSV3_FLAG 1 << 1 +static char supported_nfs_versions =NFSV2_FLAG |NFSV3_FLAG ; +static inline int store_block (uchar *src,unsigned offset,unsigned len) {ulong newsize = offset + len;
@@ -188,7 +199,18 @@ static void rpc_req(int rpc_prog, int rpc_proc, uint32_t *data, int datalen) pkt.u.call.type =htonl (MSG_CALL ); pkt.u.call.rpcvers =htonl (2 );/* use RPC version 2 */ pkt.u.call.prog =htonl (rpc_prog); - pkt.u.call.vers =htonl (2 );/* portmapper is version 2 */ +switch (rpc_prog) { +case PROG_NFS : +if (supported_nfs_versions &NFSV2_FLAG ) + pkt.u.call.vers =htonl (2 );/* NFS v2 */ +else /* NFSV3_FLAG */ + pkt.u.call.vers =htonl (3 );/* NFS v3 */ +break ; +case PROG_PORTMAP : +case PROG_MOUNT : +default : + pkt.u.call.vers =htonl (2 );/* portmapper is version 2 */ + } pkt.u.call.proc =htonl (rpc_proc); p = (uint32_t *)&(pkt.u.call.data);
@@ -224,7 +246,6 @@ static void rpc_lookup_req(int prog, int ver) data[5 ] =htonl (ver); data[6 ] =htonl (17 );/* IP_UDP */ data[7 ] =0 ; -rpc_req (PROG_PORTMAP ,PORTMAP_GETPORT , data,8 ); }
@@ -291,8 +312,14 @@ static void nfs_readlink_req(void) p = &(data[0 ]); p = (uint32_t *)rpc_add_credentials ((long *)p); -memcpy (p, filefh,NFS_FHSIZE ); - p += (NFS_FHSIZE /4 ); +if (supported_nfs_versions &NFSV2_FLAG ) { +memcpy (p, filefh,NFS_FHSIZE ); + p += (NFS_FHSIZE /4 ); + }else {/* NFSV3_FLAG */ + *p++ =htonl (filefh3_length); +memcpy (p, filefh3, filefh3_length); + p += (filefh3_length /4 ); + } len = (uint32_t *)p - (uint32_t *)&(data[0 ]);
@@ -314,17 +341,32 @@ static void nfs_lookup_req(char *fname) p = &(data[0 ]); p = (uint32_t *)rpc_add_credentials ((long *)p); -memcpy (p, dirfh,NFS_FHSIZE ); - p += (NFS_FHSIZE /4 ); - *p++ =htonl (fnamelen); -if (fnamelen &3 ) - *(p + fnamelen /4 ) =0 ; -memcpy (p, fname, fnamelen); - p += (fnamelen +3 ) /4 ; - - len = (uint32_t *)p - (uint32_t *)&(data[0 ]); - -rpc_req (PROG_NFS ,NFS_LOOKUP , data, len); +if (supported_nfs_versions &NFSV2_FLAG ) { +memcpy (p, dirfh,NFS_FHSIZE ); + p += (NFS_FHSIZE /4 ); + *p++ =htonl (fnamelen); +if (fnamelen &3 ) + *(p + fnamelen /4 ) =0 ; +memcpy (p, fname, fnamelen); + p += (fnamelen +3 ) /4 ; + + len = (uint32_t *)p - (uint32_t *)&(data[0 ]); + +rpc_req (PROG_NFS ,NFS_LOOKUP , data, len); + }else {/* NFSV3_FLAG */ + *p++ =htonl (NFS_FHSIZE );/* Dir handle length */ +memcpy (p, dirfh,NFS_FHSIZE ); + p += (NFS_FHSIZE /4 ); + *p++ =htonl (fnamelen); +if (fnamelen &3 ) + *(p + fnamelen /4 ) =0 ; +memcpy (p, fname, fnamelen); + p += (fnamelen +3 ) /4 ; + + len = (uint32_t *)p - (uint32_t *)&(data[0 ]); + +rpc_req (PROG_NFS ,NFS3PROC_LOOKUP , data, len); + } }/**************************************************************************
@@ -339,11 +381,21 @@ static void nfs_read_req(int offset, int readlen) p = &(data[0 ]); p = (uint32_t *)rpc_add_credentials ((long *)p); -memcpy (p, filefh,NFS_FHSIZE ); - p += (NFS_FHSIZE /4 ); - *p++ =htonl (offset); - *p++ =htonl (readlen); - *p++ =0 ; +if (supported_nfs_versions &NFSV2_FLAG ) { +memcpy (p, filefh,NFS_FHSIZE ); + p += (NFS_FHSIZE /4 ); + *p++ =htonl (offset); + *p++ =htonl (readlen); + *p++ =0 ; + }else {/* NFSV3_FLAG */ + *p++ =htonl (filefh3_length); +memcpy (p, filefh3, filefh3_length); + p += (filefh3_length /4 ); + *p++ =htonl (0 );/* offset is 64-bit long, so fill with 0 */ + *p++ =htonl (offset); + *p++ =htonl (readlen); + *p++ =0 ; + } len = (uint32_t *)p - (uint32_t *)&(data[0 ]);
@@ -359,10 +411,16 @@ static void nfs_send(void)switch (nfs_state) {case STATE_PRCLOOKUP_PROG_MOUNT_REQ : -rpc_lookup_req (PROG_MOUNT ,1 ); +if (supported_nfs_versions &NFSV2_FLAG ) +rpc_lookup_req (PROG_MOUNT ,1 ); +else /* NFSV3_FLAG */ +rpc_lookup_req (PROG_MOUNT ,3 );break ;case STATE_PRCLOOKUP_PROG_NFS_REQ : -rpc_lookup_req (PROG_NFS ,2 ); +if (supported_nfs_versions &NFSV2_FLAG ) +rpc_lookup_req (PROG_NFS ,2 ); +else /* NFSV3_FLAG */ +rpc_lookup_req (PROG_NFS ,3 );break ;case STATE_MOUNT_REQ :nfs_mount_req (nfs_path);
@@ -436,6 +494,7 @@ static int nfs_mount_reply(uchar *pkt, unsigned len)return -1 ; fs_mounted =1 ; +/* NFSv2 and NFSv3 use same structure */ memcpy (dirfh, rpc_pkt.u.reply.data +1 ,NFS_FHSIZE );return 0 ;
@@ -481,24 +540,51 @@ static int nfs_lookup_reply(uchar *pkt, unsigned len)if (rpc_pkt.u.reply.rstatus || rpc_pkt.u.reply.verifier || rpc_pkt.u.reply.astatus || - rpc_pkt.u.reply.data[0 ]){ -switch (ntohl (rpc_pkt.u.reply.astatus)){ -case 0 :/* Not an error */ + rpc_pkt.u.reply.data[0 ]) { +switch (ntohl (rpc_pkt.u.reply.astatus)) { +case NFS_RPC_SUCCESS :/* Not an error */ break ; -case 2 :/* Remote can't support NFS version */ -printf ("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n" , -2 , -ntohl (rpc_pkt.u.reply.data[0 ]), -ntohl (rpc_pkt.u.reply.data[1 ])); +case NFS_RPC_PROG_MISMATCH : +/* Remote can't support requested NFS version */ +switch (ntohl (rpc_pkt.u.reply.data[0 ])) { +/* Minimal supported NFS version */ +case 3 : +debug ("*** Waring: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n" , + (supported_nfs_versions &NFSV2_FLAG ) ?2 :3 , +ntohl (rpc_pkt.u.reply.data[0 ]), +ntohl (rpc_pkt.u.reply.data[1 ])); +debug ("Will retry with NFSv3\n" ); +/* Clear NFSV2_FLAG from supported versions */ + supported_nfs_versions = supported_nfs_versions & ~NFSV2_FLAG ; +return -NFS_RPC_PROG_MISMATCH ; +case 4 : +default : +printf ("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n" , + (supported_nfs_versions &NFSV2_FLAG ) ?2 :3 , +ntohl (rpc_pkt.u.reply.data[0 ]), +ntohl (rpc_pkt.u.reply.data[1 ])); + }break ; +case NFS_RPC_PROG_UNAVAIL : +case NFS_RPC_PROC_UNAVAIL : +case NFS_RPC_GARBAGE_ARGS : +case NFS_RPC_SYSTEM_ERR :default :/* Unknown error on 'accept state' flag */ -printf ("*** ERROR: accept state error (%d)\n" ,ntohl (rpc_pkt.u.reply.astatus)); +printf ("*** ERROR: accept state error (%d)\n" , +ntohl (rpc_pkt.u.reply.astatus));break ; }return -1 ; } -memcpy (filefh, rpc_pkt.u.reply.data +1 ,NFS_FHSIZE ); +if (supported_nfs_versions &NFSV2_FLAG ) { +memcpy (filefh, rpc_pkt.u.reply.data +1 ,NFS_FHSIZE ); + }else {/* NFSV3_FLAG */ + filefh3_length =ntohl (rpc_pkt.u.reply.data[1 ]); +if (filefh3_length >NFS3_FHSIZE ) + filefh3_length =NFS3_FHSIZE ; +memcpy (filefh3, rpc_pkt.u.reply.data +2 , filefh3_length); + }return 0 ; }
@@ -523,18 +609,68 @@ static int nfs_readlink_reply(uchar *pkt, unsigned len) rpc_pkt.u.reply.data[0])return -1 ; - rlen =ntohl (rpc_pkt.u.reply.data[1 ]);/* new path length */ +if (supported_nfs_versions &NFSV2_FLAG ) { -if (*((char *)&(rpc_pkt.u.reply.data[2 ])) !='/' ) { -int pathlen; -strcat (nfs_path,"/" ); - pathlen =strlen (nfs_path); -memcpy (nfs_path + pathlen, (uchar *)&(rpc_pkt.u.reply.data[2 ]), - rlen); - nfs_path[pathlen + rlen] =0 ; - }else { -memcpy (nfs_path, (uchar *)&(rpc_pkt.u.reply.data[2 ]), rlen); - nfs_path[rlen] =0 ; + rlen =ntohl (rpc_pkt.u.reply.data[1 ]);/* new path length */ + +if (*((char *)&(rpc_pkt.u.reply.data[2 ])) !='/' ) { +int pathlen; +strcat (nfs_path,"/" ); + pathlen =strlen (nfs_path); +memcpy (nfs_path + pathlen, + (uchar *)&(rpc_pkt.u.reply.data[2 ]), + rlen); + nfs_path[pathlen + rlen] =0 ; + }else { +memcpy (nfs_path, + (uchar *)&(rpc_pkt.u.reply.data[2 ]), + rlen); + nfs_path[rlen] =0 ; + } + }else {/* NFSV3_FLAG */ +int nfsv3_data_offset =0 ; +if (ntohl (rpc_pkt.u.reply.data[1 ]) !=0 ) { +/* 'attributes_follow' flag is TRUE, +* so we have attributes on 21 bytes */ +/* Skip unused values : +type; 32 bits value, +mode; 32 bits value, +nlink; 32 bits value, +uid; 32 bits value, +gid; 32 bits value, +size; 64 bits value, +used; 64 bits value, +rdev; 64 bits value, +fsid; 64 bits value, +fileid; 64 bits value, +atime; 64 bits value, +mtime; 64 bits value, +ctime; 64 bits value, +*/ + nfsv3_data_offset =22 ; + }else { +/* 'attributes_follow' flag is FALSE, +* so we don't have any attributes */ + nfsv3_data_offset =1 ; + } + +/* new path length */ + rlen =ntohl (rpc_pkt.u.reply.data[1 +nfsv3_data_offset]); + +if (*((char *)&(rpc_pkt.u.reply.data[2 +nfsv3_data_offset])) !='/' ) { +int pathlen; +strcat (nfs_path,"/" ); + pathlen =strlen (nfs_path); +memcpy (nfs_path + pathlen, + (uchar *)&(rpc_pkt.u.reply.data[2 +nfsv3_data_offset]), + rlen); + nfs_path[pathlen + rlen] =0 ; + }else { +memcpy (nfs_path, + (uchar *)&(rpc_pkt.u.reply.data[2 +nfsv3_data_offset]), + rlen); + nfs_path[rlen] =0 ; + } }return 0 ; }
@@ -543,6 +679,7 @@ static int nfs_read_reply(uchar *pkt, unsigned len) {struct rpc_t rpc_pkt;int rlen; +uchar *data_ptr;debug ("%s\n" , __func__);
@@ -570,10 +707,47 @@ static int nfs_read_reply(uchar *pkt, unsigned len)if (!(nfs_offset % ((NFS_READ_SIZE /2 ) *10 )))putc ('#' ); - rlen =ntohl (rpc_pkt.u.reply.data[18 ]); -if (store_block ((uchar *)pkt +sizeof (rpc_pkt.u.reply), - nfs_offset, rlen)) -return -9999 ; +if (supported_nfs_versions &NFSV2_FLAG ) { + rlen =ntohl (rpc_pkt.u.reply.data[18 ]); + data_ptr = (uchar *)&(rpc_pkt.u.reply.data[19 ]); + }else {/* NFSV3_FLAG */ +if (ntohl (rpc_pkt.u.reply.data[1 ]) !=0 ) { +/* 'attributes_follow' is TRUE, +* so we have attributes on 21 bytes */ +/* Skip unused values : +type; 32 bits value, +mode; 32 bits value, +nlink; 32 bits value, +uid; 32 bits value, +gid; 32 bits value, +size; 64 bits value, +used; 64 bits value, +rdev; 64 bits value, +fsid; 64 bits value, +fileid; 64 bits value, +atime; 64 bits value, +mtime; 64 bits value, +ctime; 64 bits value, +*/ + rlen =ntohl (rpc_pkt.u.reply.data[23 ]);/* count value */ +/* Skip unused values : +EOF: 32 bits value, +data_size: 32 bits value, +*/ + data_ptr = (uchar *)&(rpc_pkt.u.reply.data[26 ]); + }else { +/* attributes_follow is FALSE, so we don't have any attributes */ + rlen =ntohl (rpc_pkt.u.reply.data[2 ]);/* count value */ +/* Skip unused values : +EOF: 32 bits value, +data_size: 32 bits value, +*/ + data_ptr = (uchar *)&(rpc_pkt.u.reply.data[5 ]); + } + } + +if (store_block (data_ptr, nfs_offset, rlen)) +return -9999 ;return rlen; }
@@ -657,6 +831,13 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip,puts ("*** ERROR: File lookup fail\n" ); nfs_state =STATE_UMOUNT_REQ ;nfs_send (); + }else if (reply == -NFS_RPC_PROG_MISMATCH && supported_nfs_versions !=0 ) { +/* umount */ + nfs_state =STATE_UMOUNT_REQ ; +nfs_send (); +/* And retry with another supported version */ + nfs_state =STATE_PRCLOOKUP_PROG_MOUNT_REQ ; +nfs_send (); }else { nfs_state =STATE_READ_REQ ; nfs_offset =0 ;
@@ -696,6 +877,8 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip, }else {if (!rlen) nfs_download_state =NETLOOP_SUCCESS ; +if (rlen <0 ) +printf ("NFS READ error (%d)\n" , rlen); nfs_state =STATE_UMOUNT_REQ ;nfs_send (); }
net/nfs.h +14 -1
@@ -25,7 +25,10 @@#define NFS_READLINK 5#define NFS_READ 6 +#define NFS3PROC_LOOKUP 3 +#define NFS_FHSIZE 32 +#define NFS3_FHSIZE 64#define NFSERR_PERM 1#define NFSERR_NOENT 2
@@ -46,6 +49,16 @@#define NFS_MAXLINKDEPTH 16 +/* Values for Accept State flag on RPC answers (See: rfc1831) */ +enum rpc_accept_stat { +NFS_RPC_SUCCESS =0 ,/* RPC executed successfully */ +NFS_RPC_PROG_UNAVAIL =1 ,/* remote hasn't exported program */ +NFS_RPC_PROG_MISMATCH =2 ,/* remote can't support version # */ +NFS_RPC_PROC_UNAVAIL =3 ,/* program can't support procedure */ +NFS_RPC_GARBAGE_ARGS =4 ,/* procedure can't decode params */ +NFS_RPC_SYSTEM_ERR =5 /* errors like memory allocation failure */ +}; + struct rpc_t { union { uint8_t data[2048];
@@ -65,7 +78,7 @@ struct rpc_t {uint32_t verifier;uint32_t v2;uint32_t astatus; -uint32_t data[19 ]; +uint32_t data[NFS_READ_SIZE ]; } reply; } u; };
Signature · 1 line
1.8.4.5
PATCH 1/1 net: NFS: Add NFSv3 support
Please note that, this patch applies on top of this one:
NFS: Add error message when U-Boot NFS version (V2) is not supported by NFS server
https://patchwork.ozlabs.org/patch/630898/
It would be nice if people could test it on other boards and with other NFS servers.
Guillaume
Le 20/06/2016 21:27, Guillaume GARDET a ?crit :
Quoted 469 lines
This patch enables NFSv3 support.
If NFSv2 is available use it as usual.
If NFSv2 is not available, but NFSv3 is available, use NFSv3.
If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.Tested on iMX6 sabrelite with 4 Linux NFS servers:
* NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
* NFSv2 + NFSv3 server: use NFSv3 protocol
* NFSv3 + NFSv4 server: use NFSv3 protocol
* NFSv3 server: use NFSv3 protocolSigned-off-by Guillaume GARDET <[email protected]>Cc Tom Rini <[email protected]>Cc joe.hershberger at ni.com--- net/nfs.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++++----------- net/nfs.h | 15 +++- 2 files changed, 246 insertions(+), 50 deletions(-)net/nfs.c +232
-49@@ -22,6 +22,10 @@* possible, maximum 16 steps). There is no clearing of ".."'s inside the * path, so please DON'T DO THAT. thx. */ +/* NOTE 4: NFSv3 support added by Guillaume GARDET. +* NFSv2 is still used by default. But if server does not support NFSv2, then +* NFSv3 is used, if available on NFS server. */ +#include <common.h> #include <command.h> #include <net.h> @@ -47,8 +51,11 @@ static int nfs_offset = -1;static int nfs_len;static ulong nfs_timeout =NFS_TIMEOUT ; -static char dirfh[NFS_FHSIZE ];/* file handle of directory */ -static char filefh[NFS_FHSIZE ];/* file handle of kernel image */ +static char dirfh[NFS_FHSIZE ];/* NFSv2 / NFSv3 file handle of directory */ +static char filefh[NFS_FHSIZE ];/* NFSv2 file handle */ + +static char filefh3[NFS3_FHSIZE ];/* NFSv3 file handle */ +static int filefh3_length;/* (variable) length of filefh3 */ static enum net_loop_state nfs_download_state;static struct in_addr nfs_server_ip;@@ -70,6 +77,10 @@ static char *nfs_filename;static char *nfs_path;static char nfs_path_buff[2048 ]; +#define NFSV2_FLAG 1 +#define NFSV3_FLAG 1 << 1 +static char supported_nfs_versions =NFSV2_FLAG |NFSV3_FLAG ; +static inline int store_block (uchar *src,unsigned offset,unsigned len) {ulong newsize = offset + len;@@ -188,7 +199,18 @@ static void rpc_req(int rpc_prog, int rpc_proc, uint32_t *data, int datalen) pkt.u.call.type =htonl (MSG_CALL ); pkt.u.call.rpcvers =htonl (2 );/* use RPC version 2 */ pkt.u.call.prog =htonl (rpc_prog); - pkt.u.call.vers =htonl (2 );/* portmapper is version 2 */ +switch (rpc_prog) { +case PROG_NFS : +if (supported_nfs_versions &NFSV2_FLAG ) + pkt.u.call.vers =htonl (2 );/* NFS v2 */ +else /* NFSV3_FLAG */ + pkt.u.call.vers =htonl (3 );/* NFS v3 */ +break ; +case PROG_PORTMAP : +case PROG_MOUNT : +default : + pkt.u.call.vers =htonl (2 );/* portmapper is version 2 */ + } pkt.u.call.proc =htonl (rpc_proc); p = (uint32_t *)&(pkt.u.call.data);@@ -224,7 +246,6 @@ static void rpc_lookup_req(int prog, int ver) data[5 ] =htonl (ver); data[6 ] =htonl (17 );/* IP_UDP */ data[7 ] =0 ; -rpc_req (PROG_PORTMAP ,PORTMAP_GETPORT , data,8 ); }@@ -291,8 +312,14 @@ static void nfs_readlink_req(void) p = &(data[0 ]); p = (uint32_t *)rpc_add_credentials ((long *)p); -memcpy (p, filefh,NFS_FHSIZE ); - p += (NFS_FHSIZE /4 ); +if (supported_nfs_versions &NFSV2_FLAG ) { +memcpy (p, filefh,NFS_FHSIZE ); + p += (NFS_FHSIZE /4 ); + }else {/* NFSV3_FLAG */ + *p++ =htonl (filefh3_length); +memcpy (p, filefh3, filefh3_length); + p += (filefh3_length /4 ); + } len = (uint32_t *)p - (uint32_t *)&(data[0 ]);@@ -314,17 +341,32 @@ static void nfs_lookup_req(char *fname) p = &(data[0 ]); p = (uint32_t *)rpc_add_credentials ((long *)p); -memcpy (p, dirfh,NFS_FHSIZE ); - p += (NFS_FHSIZE /4 ); - *p++ =htonl (fnamelen); -if (fnamelen &3 ) - *(p + fnamelen /4 ) =0 ; -memcpy (p, fname, fnamelen); - p += (fnamelen +3 ) /4 ; - - len = (uint32_t *)p - (uint32_t *)&(data[0 ]); - -rpc_req (PROG_NFS ,NFS_LOOKUP , data, len); +if (supported_nfs_versions &NFSV2_FLAG ) { +memcpy (p, dirfh,NFS_FHSIZE ); + p += (NFS_FHSIZE /4 ); + *p++ =htonl (fnamelen); +if (fnamelen &3 ) + *(p + fnamelen /4 ) =0 ; +memcpy (p, fname, fnamelen); + p += (fnamelen +3 ) /4 ; + + len = (uint32_t *)p - (uint32_t *)&(data[0 ]); + +rpc_req (PROG_NFS ,NFS_LOOKUP , data, len); + }else {/* NFSV3_FLAG */ + *p++ =htonl (NFS_FHSIZE );/* Dir handle length */ +memcpy (p, dirfh,NFS_FHSIZE ); + p += (NFS_FHSIZE /4 ); + *p++ =htonl (fnamelen); +if (fnamelen &3 ) + *(p + fnamelen /4 ) =0 ; +memcpy (p, fname, fnamelen); + p += (fnamelen +3 ) /4 ; + + len = (uint32_t *)p - (uint32_t *)&(data[0 ]); + +rpc_req (PROG_NFS ,NFS3PROC_LOOKUP , data, len); + } }/************************************************************************** @@ -339,11 +381,21 @@ static void nfs_read_req(int offset, int readlen) p = &(data[0 ]); p = (uint32_t *)rpc_add_credentials ((long *)p); -memcpy (p, filefh,NFS_FHSIZE ); - p += (NFS_FHSIZE /4 ); - *p++ =htonl (offset); - *p++ =htonl (readlen); - *p++ =0 ; +if (supported_nfs_versions &NFSV2_FLAG ) { +memcpy (p, filefh,NFS_FHSIZE ); + p += (NFS_FHSIZE /4 ); + *p++ =htonl (offset); + *p++ =htonl (readlen); + *p++ =0 ; + }else {/* NFSV3_FLAG */ + *p++ =htonl (filefh3_length); +memcpy (p, filefh3, filefh3_length); + p += (filefh3_length /4 ); + *p++ =htonl (0 );/* offset is 64-bit long, so fill with 0 */ + *p++ =htonl (offset); + *p++ =htonl (readlen); + *p++ =0 ; + } len = (uint32_t *)p - (uint32_t *)&(data[0 ]);@@ -359,10 +411,16 @@ static void nfs_send(void)switch (nfs_state) {case STATE_PRCLOOKUP_PROG_MOUNT_REQ : -rpc_lookup_req (PROG_MOUNT ,1 ); +if (supported_nfs_versions &NFSV2_FLAG ) +rpc_lookup_req (PROG_MOUNT ,1 ); +else /* NFSV3_FLAG */ +rpc_lookup_req (PROG_MOUNT ,3 );break ;case STATE_PRCLOOKUP_PROG_NFS_REQ : -rpc_lookup_req (PROG_NFS ,2 ); +if (supported_nfs_versions &NFSV2_FLAG ) +rpc_lookup_req (PROG_NFS ,2 ); +else /* NFSV3_FLAG */ +rpc_lookup_req (PROG_NFS ,3 );break ;case STATE_MOUNT_REQ :nfs_mount_req (nfs_path);@@ -436,6 +494,7 @@ static int nfs_mount_reply(uchar *pkt, unsigned len)return -1 ; fs_mounted =1 ; +/* NFSv2 and NFSv3 use same structure */ memcpy (dirfh, rpc_pkt.u.reply.data +1 ,NFS_FHSIZE );return 0 ;@@ -481,24 +540,51 @@ static int nfs_lookup_reply(uchar *pkt, unsigned len)if (rpc_pkt.u.reply.rstatus || rpc_pkt.u.reply.verifier || rpc_pkt.u.reply.astatus || - rpc_pkt.u.reply.data[0 ]){ -switch (ntohl (rpc_pkt.u.reply.astatus)){ -case 0 :/* Not an error */ + rpc_pkt.u.reply.data[0 ]) { +switch (ntohl (rpc_pkt.u.reply.astatus)) { +case NFS_RPC_SUCCESS :/* Not an error */ break ; -case 2 :/* Remote can't support NFS version */ -printf ("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n" , -2 , -ntohl (rpc_pkt.u.reply.data[0 ]), -ntohl (rpc_pkt.u.reply.data[1 ])); +case NFS_RPC_PROG_MISMATCH : +/* Remote can't support requested NFS version */ +switch (ntohl (rpc_pkt.u.reply.data[0 ])) { +/* Minimal supported NFS version */ +case 3 : +debug ("*** Waring: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n" , + (supported_nfs_versions &NFSV2_FLAG ) ?2 :3 , +ntohl (rpc_pkt.u.reply.data[0 ]), +ntohl (rpc_pkt.u.reply.data[1 ])); +debug ("Will retry with NFSv3\n" ); +/* Clear NFSV2_FLAG from supported versions */ + supported_nfs_versions = supported_nfs_versions & ~NFSV2_FLAG ; +return -NFS_RPC_PROG_MISMATCH ; +case 4 : +default : +printf ("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n" , + (supported_nfs_versions &NFSV2_FLAG ) ?2 :3 , +ntohl (rpc_pkt.u.reply.data[0 ]), +ntohl (rpc_pkt.u.reply.data[1 ])); + }break ; +case NFS_RPC_PROG_UNAVAIL : +case NFS_RPC_PROC_UNAVAIL : +case NFS_RPC_GARBAGE_ARGS : +case NFS_RPC_SYSTEM_ERR :default :/* Unknown error on 'accept state' flag */ -printf ("*** ERROR: accept state error (%d)\n" ,ntohl (rpc_pkt.u.reply.astatus)); +printf ("*** ERROR: accept state error (%d)\n" , +ntohl (rpc_pkt.u.reply.astatus));break ; }return -1 ; } -memcpy (filefh, rpc_pkt.u.reply.data +1 ,NFS_FHSIZE ); +if (supported_nfs_versions &NFSV2_FLAG ) { +memcpy (filefh, rpc_pkt.u.reply.data +1 ,NFS_FHSIZE ); + }else {/* NFSV3_FLAG */ + filefh3_length =ntohl (rpc_pkt.u.reply.data[1 ]); +if (filefh3_length >NFS3_FHSIZE ) + filefh3_length =NFS3_FHSIZE ; +memcpy (filefh3, rpc_pkt.u.reply.data +2 , filefh3_length); + }return 0 ; }@@ -523,18 +609,68 @@ static int nfs_readlink_reply(uchar *pkt, unsigned len) rpc_pkt.u.reply.data[0])return -1 ; - rlen =ntohl (rpc_pkt.u.reply.data[1 ]);/* new path length */ +if (supported_nfs_versions &NFSV2_FLAG ) { -if (*((char *)&(rpc_pkt.u.reply.data[2 ])) !='/' ) { -int pathlen; -strcat (nfs_path,"/" ); - pathlen =strlen (nfs_path); -memcpy (nfs_path + pathlen, (uchar *)&(rpc_pkt.u.reply.data[2 ]), - rlen); - nfs_path[pathlen + rlen] =0 ; - }else { -memcpy (nfs_path, (uchar *)&(rpc_pkt.u.reply.data[2 ]), rlen); - nfs_path[rlen] =0 ; + rlen =ntohl (rpc_pkt.u.reply.data[1 ]);/* new path length */ + +if (*((char *)&(rpc_pkt.u.reply.data[2 ])) !='/' ) { +int pathlen; +strcat (nfs_path,"/" ); + pathlen =strlen (nfs_path); +memcpy (nfs_path + pathlen, + (uchar *)&(rpc_pkt.u.reply.data[2 ]), + rlen); + nfs_path[pathlen + rlen] =0 ; + }else { +memcpy (nfs_path, + (uchar *)&(rpc_pkt.u.reply.data[2 ]), + rlen); + nfs_path[rlen] =0 ; + } + }else {/* NFSV3_FLAG */ +int nfsv3_data_offset =0 ; +if (ntohl (rpc_pkt.u.reply.data[1 ]) !=0 ) { +/* 'attributes_follow' flag is TRUE, +* so we have attributes on 21 bytes */ +/* Skip unused values : +type; 32 bits value, +mode; 32 bits value, +nlink; 32 bits value, +uid; 32 bits value, +gid; 32 bits value, +size; 64 bits value, +used; 64 bits value, +rdev; 64 bits value, +fsid; 64 bits value, +fileid; 64 bits value, +atime; 64 bits value, +mtime; 64 bits value, +ctime; 64 bits value, +*/ + nfsv3_data_offset =22 ; + }else { +/* 'attributes_follow' flag is FALSE, +* so we don't have any attributes */ + nfsv3_data_offset =1 ; + } + +/* new path length */ + rlen =ntohl (rpc_pkt.u.reply.data[1 +nfsv3_data_offset]); + +if (*((char *)&(rpc_pkt.u.reply.data[2 +nfsv3_data_offset])) !='/' ) { +int pathlen; +strcat (nfs_path,"/" ); + pathlen =strlen (nfs_path); +memcpy (nfs_path + pathlen, + (uchar *)&(rpc_pkt.u.reply.data[2 +nfsv3_data_offset]), + rlen); + nfs_path[pathlen + rlen] =0 ; + }else { +memcpy (nfs_path, + (uchar *)&(rpc_pkt.u.reply.data[2 +nfsv3_data_offset]), + rlen); + nfs_path[rlen] =0 ; + } }return 0 ; }@@ -543,6 +679,7 @@ static int nfs_read_reply(uchar *pkt, unsigned len) {struct rpc_t rpc_pkt;int rlen; +uchar *data_ptr;debug ("%s\n" , __func__);@@ -570,10 +707,47 @@ static int nfs_read_reply(uchar *pkt, unsigned len)if (!(nfs_offset % ((NFS_READ_SIZE /2 ) *10 )))putc ('#' ); - rlen =ntohl (rpc_pkt.u.reply.data[18 ]); -if (store_block ((uchar *)pkt +sizeof (rpc_pkt.u.reply), - nfs_offset, rlen)) -return -9999 ; +if (supported_nfs_versions &NFSV2_FLAG ) { + rlen =ntohl (rpc_pkt.u.reply.data[18 ]); + data_ptr = (uchar *)&(rpc_pkt.u.reply.data[19 ]); + }else {/* NFSV3_FLAG */ +if (ntohl (rpc_pkt.u.reply.data[1 ]) !=0 ) { +/* 'attributes_follow' is TRUE, +* so we have attributes on 21 bytes */ +/* Skip unused values : +type; 32 bits value, +mode; 32 bits value, +nlink; 32 bits value, +uid; 32 bits value, +gid; 32 bits value, +size; 64 bits value, +used; 64 bits value, +rdev; 64 bits value, +fsid; 64 bits value, +fileid; 64 bits value, +atime; 64 bits value, +mtime; 64 bits value, +ctime; 64 bits value, +*/ + rlen =ntohl (rpc_pkt.u.reply.data[23 ]);/* count value */ +/* Skip unused values : +EOF: 32 bits value, +data_size: 32 bits value, +*/ + data_ptr = (uchar *)&(rpc_pkt.u.reply.data[26 ]); + }else { +/* attributes_follow is FALSE, so we don't have any attributes */ + rlen =ntohl (rpc_pkt.u.reply.data[2 ]);/* count value */ +/* Skip unused values : +EOF: 32 bits value, +data_size: 32 bits value, +*/ + data_ptr = (uchar *)&(rpc_pkt.u.reply.data[5 ]); + } + } + +if (store_block (data_ptr, nfs_offset, rlen)) +return -9999 ;return rlen; }@@ -657,6 +831,13 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip,puts ("*** ERROR: File lookup fail\n" ); nfs_state =STATE_UMOUNT_REQ ;nfs_send (); + }else if (reply == -NFS_RPC_PROG_MISMATCH && supported_nfs_versions !=0 ) { +/* umount */ + nfs_state =STATE_UMOUNT_REQ ; +nfs_send (); +/* And retry with another supported version */ + nfs_state =STATE_PRCLOOKUP_PROG_MOUNT_REQ ; +nfs_send (); }else { nfs_state =STATE_READ_REQ ; nfs_offset =0 ;@@ -696,6 +877,8 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip, }else {if (!rlen) nfs_download_state =NETLOOP_SUCCESS ; +if (rlen <0 ) +printf ("NFS READ error (%d)\n" , rlen); nfs_state =STATE_UMOUNT_REQ ;nfs_send (); }net/nfs.h +14
-1@@ -25,7 +25,10 @@#define NFS_READLINK 5#define NFS_READ 6 +#define NFS3PROC_LOOKUP 3 +#define NFS_FHSIZE 32 +#define NFS3_FHSIZE 64#define NFSERR_PERM 1#define NFSERR_NOENT 2@@ -46,6 +49,16 @@#define NFS_MAXLINKDEPTH 16 +/* Values for Accept State flag on RPC answers (See: rfc1831) */ +enum rpc_accept_stat { +NFS_RPC_SUCCESS =0 ,/* RPC executed successfully */ +NFS_RPC_PROG_UNAVAIL =1 ,/* remote hasn't exported program */ +NFS_RPC_PROG_MISMATCH =2 ,/* remote can't support version # */ +NFS_RPC_PROC_UNAVAIL =3 ,/* program can't support procedure */ +NFS_RPC_GARBAGE_ARGS =4 ,/* procedure can't decode params */ +NFS_RPC_SYSTEM_ERR =5 /* errors like memory allocation failure */ +}; + struct rpc_t { union { uint8_t data[2048];@@ -65,7 +78,7 @@ struct rpc_t {uint32_t verifier;uint32_t v2;uint32_t astatus; -uint32_t data[19 ]; +uint32_t data[NFS_READ_SIZE ]; } reply; } u; };
PATCH 1/1 net: NFS: Add NFSv3 support
Quoted 4 lines · Guillaume Gardet
Please note that, this patch applies on top of this one:
NFS: Add error message when U-Boot NFS version (V2) is not supported by
NFS serverhttps://patchwork.ozlabs.org/patch/630898/
Please make sure to run your patches through scripts/checkpatch.pl.
Thanks,
-Joe
PATCH 1/1 net: NFS: Add NFSv3 support
Hi,
Le 20/06/2016 23:43, Joe Hershberger a ?crit :
Quoted 7 lines
Quoted 4 lines · Guillaume Gardet
Please note that, this patch applies on top of this one:
NFS: Add error message when U-Boot NFS version (V2) is not supported by
NFS serverhttps://patchwork.ozlabs.org/patch/630898/Please make sure to run your patches through
scripts/checkpatch.pl.
I did for the NFSv3 patch. There are only a few lines longer than 80 char, but not very easy to wrap.
For the previous patch, do you want a V2? You told me that you will take care to fix it manually.
If you don't want to include the previous patch for 2016.07 release, then you can drop it, and I can rebase this patch. Just tell me.
Guillaume
Quoted 4 lines
Thanks,
-Joe
PATCH v2 1/1 net: NFS: Add NFSv3 support
In reply to Guillaume GARDETThis patch enables NFSv3 support.
If NFSv2 is available use it as usual.
If NFSv2 is not available, but NFSv3 is available, use NFSv3.
If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.
Tested on iMX6 sabrelite with 4 Linux NFS servers:
* NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
* NFSv2 + NFSv3 server: use NFSv3 protocol
* NFSv3 + NFSv4 server: use NFSv3 protocol
* NFSv3 server: use NFSv3 protocol
---
Changes in V2:
* rebase on latest GIT
* shorten some long lines
* no functionnal changes
net/nfs.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++++++----------- net/nfs.h | 15 +++- 2 files changed, 242 insertions(+), 47 deletions(-)
net/nfs.c +228 -46
@@ -22,6 +22,10 @@* possible, maximum 16 steps). There is no clearing of ".."'s inside the * path, so please DON'T DO THAT. thx. */ +/* NOTE 4: NFSv3 support added by Guillaume GARDET, 2016-June-20. +* NFSv2 is still used by default. But if server does not support NFSv2, then +* NFSv3 is used, if available on NFS server. */ +#include <common.h> #include <command.h> #include <net.h>
@@ -47,8 +51,11 @@ static int nfs_offset = -1;static int nfs_len;static ulong nfs_timeout =NFS_TIMEOUT ; -static char dirfh[NFS_FHSIZE ];/* file handle of directory */ -static char filefh[NFS_FHSIZE ];/* file handle of kernel image */ +static char dirfh[NFS_FHSIZE ];/* NFSv2 / NFSv3 file handle of directory */ +static char filefh[NFS_FHSIZE ];/* NFSv2 file handle */ + +static char filefh3[NFS3_FHSIZE ];/* NFSv3 file handle */ +static int filefh3_length;/* (variable) length of filefh3 */ static enum net_loop_state nfs_download_state;static struct in_addr nfs_server_ip;
@@ -70,6 +77,10 @@ static char *nfs_filename;static char *nfs_path;static char nfs_path_buff[2048 ]; +#define NFSV2_FLAG 1 +#define NFSV3_FLAG 1 << 1 +static char supported_nfs_versions =NFSV2_FLAG |NFSV3_FLAG ; +static inline int store_block (uchar *src,unsigned offset,unsigned len) {ulong newsize = offset + len;
@@ -188,7 +199,18 @@ static void rpc_req(int rpc_prog, int rpc_proc, uint32_t *data, int datalen) pkt.u.call.type =htonl (MSG_CALL ); pkt.u.call.rpcvers =htonl (2 );/* use RPC version 2 */ pkt.u.call.prog =htonl (rpc_prog); - pkt.u.call.vers =htonl (2 );/* portmapper is version 2 */ +switch (rpc_prog) { +case PROG_NFS : +if (supported_nfs_versions &NFSV2_FLAG ) + pkt.u.call.vers =htonl (2 );/* NFS v2 */ +else /* NFSV3_FLAG */ + pkt.u.call.vers =htonl (3 );/* NFS v3 */ +break ; +case PROG_PORTMAP : +case PROG_MOUNT : +default : + pkt.u.call.vers =htonl (2 );/* portmapper is version 2 */ + } pkt.u.call.proc =htonl (rpc_proc); p = (uint32_t *)&(pkt.u.call.data);
@@ -224,7 +246,6 @@ static void rpc_lookup_req(int prog, int ver) data[5 ] =htonl (ver); data[6 ] =htonl (17 );/* IP_UDP */ data[7 ] =0 ; -rpc_req (PROG_PORTMAP ,PORTMAP_GETPORT , data,8 ); }
@@ -291,8 +312,14 @@ static void nfs_readlink_req(void) p = &(data[0 ]); p = (uint32_t *)rpc_add_credentials ((long *)p); -memcpy (p, filefh,NFS_FHSIZE ); - p += (NFS_FHSIZE /4 ); +if (supported_nfs_versions &NFSV2_FLAG ) { +memcpy (p, filefh,NFS_FHSIZE ); + p += (NFS_FHSIZE /4 ); + }else {/* NFSV3_FLAG */ + *p++ =htonl (filefh3_length); +memcpy (p, filefh3, filefh3_length); + p += (filefh3_length /4 ); + } len = (uint32_t *)p - (uint32_t *)&(data[0 ]);
@@ -314,17 +341,32 @@ static void nfs_lookup_req(char *fname) p = &(data[0 ]); p = (uint32_t *)rpc_add_credentials ((long *)p); -memcpy (p, dirfh,NFS_FHSIZE ); - p += (NFS_FHSIZE /4 ); - *p++ =htonl (fnamelen); -if (fnamelen &3 ) - *(p + fnamelen /4 ) =0 ; -memcpy (p, fname, fnamelen); - p += (fnamelen +3 ) /4 ; - - len = (uint32_t *)p - (uint32_t *)&(data[0 ]); - -rpc_req (PROG_NFS ,NFS_LOOKUP , data, len); +if (supported_nfs_versions &NFSV2_FLAG ) { +memcpy (p, dirfh,NFS_FHSIZE ); + p += (NFS_FHSIZE /4 ); + *p++ =htonl (fnamelen); +if (fnamelen &3 ) + *(p + fnamelen /4 ) =0 ; +memcpy (p, fname, fnamelen); + p += (fnamelen +3 ) /4 ; + + len = (uint32_t *)p - (uint32_t *)&(data[0 ]); + +rpc_req (PROG_NFS ,NFS_LOOKUP , data, len); + }else {/* NFSV3_FLAG */ + *p++ =htonl (NFS_FHSIZE );/* Dir handle length */ +memcpy (p, dirfh,NFS_FHSIZE ); + p += (NFS_FHSIZE /4 ); + *p++ =htonl (fnamelen); +if (fnamelen &3 ) + *(p + fnamelen /4 ) =0 ; +memcpy (p, fname, fnamelen); + p += (fnamelen +3 ) /4 ; + + len = (uint32_t *)p - (uint32_t *)&(data[0 ]); + +rpc_req (PROG_NFS ,NFS3PROC_LOOKUP , data, len); + } }/**************************************************************************
@@ -339,11 +381,21 @@ static void nfs_read_req(int offset, int readlen) p = &(data[0 ]); p = (uint32_t *)rpc_add_credentials ((long *)p); -memcpy (p, filefh,NFS_FHSIZE ); - p += (NFS_FHSIZE /4 ); - *p++ =htonl (offset); - *p++ =htonl (readlen); - *p++ =0 ; +if (supported_nfs_versions &NFSV2_FLAG ) { +memcpy (p, filefh,NFS_FHSIZE ); + p += (NFS_FHSIZE /4 ); + *p++ =htonl (offset); + *p++ =htonl (readlen); + *p++ =0 ; + }else {/* NFSV3_FLAG */ + *p++ =htonl (filefh3_length); +memcpy (p, filefh3, filefh3_length); + p += (filefh3_length /4 ); + *p++ =htonl (0 );/* offset is 64-bit long, so fill with 0 */ + *p++ =htonl (offset); + *p++ =htonl (readlen); + *p++ =0 ; + } len = (uint32_t *)p - (uint32_t *)&(data[0 ]);
@@ -359,10 +411,16 @@ static void nfs_send(void)switch (nfs_state) {case STATE_PRCLOOKUP_PROG_MOUNT_REQ : -rpc_lookup_req (PROG_MOUNT ,1 ); +if (supported_nfs_versions &NFSV2_FLAG ) +rpc_lookup_req (PROG_MOUNT ,1 ); +else /* NFSV3_FLAG */ +rpc_lookup_req (PROG_MOUNT ,3 );break ;case STATE_PRCLOOKUP_PROG_NFS_REQ : -rpc_lookup_req (PROG_NFS ,2 ); +if (supported_nfs_versions &NFSV2_FLAG ) +rpc_lookup_req (PROG_NFS ,2 ); +else /* NFSV3_FLAG */ +rpc_lookup_req (PROG_NFS ,3 );break ;case STATE_MOUNT_REQ :nfs_mount_req (nfs_path);
@@ -436,6 +494,7 @@ static int nfs_mount_reply(uchar *pkt, unsigned len)return -1 ; fs_mounted =1 ; +/* NFSv2 and NFSv3 use same structure */ memcpy (dirfh, rpc_pkt.u.reply.data +1 ,NFS_FHSIZE );return 0 ;
@@ -483,14 +542,33 @@ static int nfs_lookup_reply(uchar *pkt, unsigned len) rpc_pkt.u.reply.astatus || rpc_pkt.u.reply.data[0]) {switch (ntohl (rpc_pkt.u.reply.astatus)) { -case 0 :/* Not an error */ +case NFS_RPC_SUCCESS :/* Not an error */ break ; -case 2 :/* Remote can't support NFS version */ -printf ("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n" , -2 , -ntohl (rpc_pkt.u.reply.data[0 ]), -ntohl (rpc_pkt.u.reply.data[1 ])); +case NFS_RPC_PROG_MISMATCH : +/* Remote can't support NFS version */ +switch (ntohl (rpc_pkt.u.reply.data[0 ])) { +/* Minimal supported NFS version */ +case 3 : +debug ("*** Waring: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n" , + (supported_nfs_versions &NFSV2_FLAG ) ?2 :3 , +ntohl (rpc_pkt.u.reply.data[0 ]), +ntohl (rpc_pkt.u.reply.data[1 ])); +debug ("Will retry with NFSv3\n" ); +/* Clear NFSV2_FLAG from supported versions */ + supported_nfs_versions &= ~NFSV2_FLAG ; +return -NFS_RPC_PROG_MISMATCH ; +case 4 : +default : +printf ("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n" , + (supported_nfs_versions &NFSV2_FLAG ) ?2 :3 , +ntohl (rpc_pkt.u.reply.data[0 ]), +ntohl (rpc_pkt.u.reply.data[1 ])); + }break ; +case NFS_RPC_PROG_UNAVAIL : +case NFS_RPC_PROC_UNAVAIL : +case NFS_RPC_GARBAGE_ARGS : +case NFS_RPC_SYSTEM_ERR :default :/* Unknown error on 'accept state' flag */ printf ("*** ERROR: accept state error (%d)\n" ,ntohl (rpc_pkt.u.reply.astatus));
@@ -499,7 +577,14 @@ static int nfs_lookup_reply(uchar *pkt, unsigned len)return -1 ; } -memcpy (filefh, rpc_pkt.u.reply.data +1 ,NFS_FHSIZE ); +if (supported_nfs_versions &NFSV2_FLAG ) { +memcpy (filefh, rpc_pkt.u.reply.data +1 ,NFS_FHSIZE ); + }else {/* NFSV3_FLAG */ + filefh3_length =ntohl (rpc_pkt.u.reply.data[1 ]); +if (filefh3_length >NFS3_FHSIZE ) + filefh3_length =NFS3_FHSIZE ; +memcpy (filefh3, rpc_pkt.u.reply.data +2 , filefh3_length); + }return 0 ; }
@@ -524,18 +609,68 @@ static int nfs_readlink_reply(uchar *pkt, unsigned len) rpc_pkt.u.reply.data[0])return -1 ; - rlen =ntohl (rpc_pkt.u.reply.data[1 ]);/* new path length */ +if (supported_nfs_versions &NFSV2_FLAG ) { -if (*((char *)&(rpc_pkt.u.reply.data[2 ])) !='/' ) { -int pathlen; -strcat (nfs_path,"/" ); - pathlen =strlen (nfs_path); -memcpy (nfs_path + pathlen, (uchar *)&(rpc_pkt.u.reply.data[2 ]), - rlen); - nfs_path[pathlen + rlen] =0 ; - }else { -memcpy (nfs_path, (uchar *)&(rpc_pkt.u.reply.data[2 ]), rlen); - nfs_path[rlen] =0 ; + rlen =ntohl (rpc_pkt.u.reply.data[1 ]);/* new path length */ + +if (*((char *)&(rpc_pkt.u.reply.data[2 ])) !='/' ) { +int pathlen; +strcat (nfs_path,"/" ); + pathlen =strlen (nfs_path); +memcpy (nfs_path + pathlen, + (uchar *)&(rpc_pkt.u.reply.data[2 ]), + rlen); + nfs_path[pathlen + rlen] =0 ; + }else { +memcpy (nfs_path, + (uchar *)&(rpc_pkt.u.reply.data[2 ]), + rlen); + nfs_path[rlen] =0 ; + } + }else {/* NFSV3_FLAG */ +int nfsv3_data_offset =0 ; +if (ntohl (rpc_pkt.u.reply.data[1 ]) !=0 ) { +/* 'attributes_follow' flag is TRUE, +* so we have attributes on 21 bytes */ +/* Skip unused values : +type; 32 bits value, +mode; 32 bits value, +nlink; 32 bits value, +uid; 32 bits value, +gid; 32 bits value, +size; 64 bits value, +used; 64 bits value, +rdev; 64 bits value, +fsid; 64 bits value, +fileid; 64 bits value, +atime; 64 bits value, +mtime; 64 bits value, +ctime; 64 bits value, +*/ + nfsv3_data_offset =22 ; + }else { +/* 'attributes_follow' flag is FALSE, +* so we don't have any attributes */ + nfsv3_data_offset =1 ; + } + +/* new path length */ + rlen =ntohl (rpc_pkt.u.reply.data[1 +nfsv3_data_offset]); + +if (*((char *)&(rpc_pkt.u.reply.data[2 +nfsv3_data_offset])) !='/' ) { +int pathlen; +strcat (nfs_path,"/" ); + pathlen =strlen (nfs_path); +memcpy (nfs_path + pathlen, + (uchar *)&(rpc_pkt.u.reply.data[2 +nfsv3_data_offset]), + rlen); + nfs_path[pathlen + rlen] =0 ; + }else { +memcpy (nfs_path, + (uchar *)&(rpc_pkt.u.reply.data[2 +nfsv3_data_offset]), + rlen); + nfs_path[rlen] =0 ; + } }return 0 ; }
@@ -544,6 +679,7 @@ static int nfs_read_reply(uchar *pkt, unsigned len) {struct rpc_t rpc_pkt;int rlen; +uchar *data_ptr;debug ("%s\n" , __func__);
@@ -571,10 +707,47 @@ static int nfs_read_reply(uchar *pkt, unsigned len)if (!(nfs_offset % ((NFS_READ_SIZE /2 ) *10 )))putc ('#' ); - rlen =ntohl (rpc_pkt.u.reply.data[18 ]); -if (store_block ((uchar *)pkt +sizeof (rpc_pkt.u.reply), - nfs_offset, rlen)) -return -9999 ; +if (supported_nfs_versions &NFSV2_FLAG ) { + rlen =ntohl (rpc_pkt.u.reply.data[18 ]); + data_ptr = (uchar *)&(rpc_pkt.u.reply.data[19 ]); + }else {/* NFSV3_FLAG */ +if (ntohl (rpc_pkt.u.reply.data[1 ]) !=0 ) { +/* 'attributes_follow' is TRUE, +* so we have attributes on 21 bytes */ +/* Skip unused values : +type; 32 bits value, +mode; 32 bits value, +nlink; 32 bits value, +uid; 32 bits value, +gid; 32 bits value, +size; 64 bits value, +used; 64 bits value, +rdev; 64 bits value, +fsid; 64 bits value, +fileid; 64 bits value, +atime; 64 bits value, +mtime; 64 bits value, +ctime; 64 bits value, +*/ + rlen =ntohl (rpc_pkt.u.reply.data[23 ]);/* count value */ +/* Skip unused values : +EOF: 32 bits value, +data_size: 32 bits value, +*/ + data_ptr = (uchar *)&(rpc_pkt.u.reply.data[26 ]); + }else { +/* attributes_follow is FALSE, so we don't have any attributes */ + rlen =ntohl (rpc_pkt.u.reply.data[2 ]);/* count value */ +/* Skip unused values : +EOF: 32 bits value, +data_size: 32 bits value, +*/ + data_ptr = (uchar *)&(rpc_pkt.u.reply.data[5 ]); + } + } + +if (store_block (data_ptr, nfs_offset, rlen)) +return -9999 ;return rlen; }
@@ -658,6 +831,13 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip,puts ("*** ERROR: File lookup fail\n" ); nfs_state =STATE_UMOUNT_REQ ;nfs_send (); + }else if (reply == -NFS_RPC_PROG_MISMATCH && supported_nfs_versions !=0 ) { +/* umount */ + nfs_state =STATE_UMOUNT_REQ ; +nfs_send (); +/* And retry with another supported version */ + nfs_state =STATE_PRCLOOKUP_PROG_MOUNT_REQ ; +nfs_send (); }else { nfs_state =STATE_READ_REQ ; nfs_offset =0 ;
@@ -697,6 +877,8 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip, }else {if (!rlen) nfs_download_state =NETLOOP_SUCCESS ; +if (rlen <0 ) +printf ("NFS READ error (%d)\n" , rlen); nfs_state =STATE_UMOUNT_REQ ;nfs_send (); }
net/nfs.h +14 -1
@@ -25,7 +25,10 @@#define NFS_READLINK 5#define NFS_READ 6 +#define NFS3PROC_LOOKUP 3 +#define NFS_FHSIZE 32 +#define NFS3_FHSIZE 64#define NFSERR_PERM 1#define NFSERR_NOENT 2
@@ -46,6 +49,16 @@#define NFS_MAXLINKDEPTH 16 +/* Values for Accept State flag on RPC answers (See: rfc1831) */ +enum rpc_accept_stat { +NFS_RPC_SUCCESS =0 ,/* RPC executed successfully */ +NFS_RPC_PROG_UNAVAIL =1 ,/* remote hasn't exported program */ +NFS_RPC_PROG_MISMATCH =2 ,/* remote can't support version # */ +NFS_RPC_PROC_UNAVAIL =3 ,/* program can't support procedure */ +NFS_RPC_GARBAGE_ARGS =4 ,/* procedure can't decode params */ +NFS_RPC_SYSTEM_ERR =5 /* errors like memory allocation failure */ +}; + struct rpc_t { union { uint8_t data[2048];
@@ -65,7 +78,7 @@ struct rpc_t {uint32_t verifier;uint32_t v2;uint32_t astatus; -uint32_t data[19 ]; +uint32_t data[NFS_READ_SIZE ]; } reply; } u; };
Signature · 1 line
1.8.4.5
PATCH v2 1/1 net: NFS: Add NFSv3 support
Quoted 10 lines · Guillaume GARDET
This patch enables NFSv3 support.
If NFSv2 is available use it as usual.
If NFSv2 is not available, but NFSv3 is available, use NFSv3.
If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.Tested on iMX6 sabrelite with 4 Linux NFS servers:
* NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
* NFSv2 + NFSv3 server: use NFSv3 protocol
* NFSv3 + NFSv4 server: use NFSv3 protocol
* NFSv3 server: use NFSv3 protocol
So, why do we have v2+v3+v4 -> v2 and not v2+v3+v4 -> v3, when we do v2+v3 -> v3 and v3+v4 -> v3 ? We should be consistent in preferring either v2 over v3 or v3 over v2. Thanks!
Signature · 8 lines
Tom -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160623/51f14073/attachment.sig>
PATCH v2 1/1 net: NFS: Add NFSv3 support
Le 23/06/2016 21:08, Tom Rini a ?crit :
Quoted 7 lines · Guillaume GARDET
Quoted 6 lines
This patch enables NFSv3 support.
If NFSv2 is available use it as usual.
If NFSv2 is not available, but NFSv3 is available, use NFSv3.
If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.
Quoted 9 lines
Quoted 5 lines
Tested on iMX6 sabrelite with 4 Linux NFS servers:
* NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
* NFSv2 + NFSv3 server: use NFSv3 protocol
* NFSv3 + NFSv4 server: use NFSv3 protocol
* NFSv3 server: use NFSv3 protocolSo, why do we have v2+v3+v4 -> v2 and not v2+v3+v4 -> v3, when we do v2+v3 -> v3 and v3+v4 -> v3 ? We should be consistent in preferring either v2 over v3 or v3 over v2. Thanks!
Sorry, it is a typo error. Please read: "NFSv2 + NFSv3 server: use NFSv2 protocol".
As long as NFSv2 is available, we use it. Otherwise, we use v3 if available. As explained above.
Guillaume
PATCH v2 1/1 net: NFS: Add NFSv3 support
Quoted 20 lines · Guillaume Gardet
Le 23/06/2016 21:08, Tom Rini a ?crit :
Quoted 7 lines · Guillaume GARDET
Quoted 6 lines
This patch enables NFSv3 support.
If NFSv2 is available use it as usual.
If NFSv2 is not available, but NFSv3 is available, use NFSv3.
If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.Quoted 9 lines
Quoted 5 lines
Tested on iMX6 sabrelite with 4 Linux NFS servers:
* NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
* NFSv2 + NFSv3 server: use NFSv3 protocol
* NFSv3 + NFSv4 server: use NFSv3 protocol
* NFSv3 server: use NFSv3 protocolSo, why do we have v2+v3+v4 -> v2 and not v2+v3+v4 -> v3, when we do v2+v3 -> v3 and v3+v4 -> v3 ? We should be consistent in preferring either v2 over v3 or v3 over v2. Thanks!
Quoted 4 lines
Sorry, it is a typo error. Please read: "NFSv2 + NFSv3 server: use NFSv2 protocol".
As long as NFSv2 is available, we use it. Otherwise, we use v3 if available. As explained above.
OK, that makes sense, thanks! Joe, I assume you can just fix that in the commit message when you pick this up.
Signature · 8 lines
Tom -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160624/aae1f621/attachment.sig>
PATCH v2 1/1 net: NFS: Add NFSv3 support
Quoted 22 lines · Tom Rini
Quoted 20 lines · Guillaume Gardet
Le 23/06/2016 21:08, Tom Rini a ?crit :
Quoted 16 lines · Guillaume GARDET
Quoted 11 lines
This patch enables NFSv3 support.
If NFSv2 is available use it as usual.
If NFSv2 is not available, but NFSv3 is available, use NFSv3.
If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.Tested on iMX6 sabrelite with 4 Linux NFS servers:
* NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
* NFSv2 + NFSv3 server: use NFSv3 protocol
* NFSv3 + NFSv4 server: use NFSv3 protocol
* NFSv3 server: use NFSv3 protocolSo, why do we have v2+v3+v4 -> v2 and not v2+v3+v4 -> v3, when we do v2+v3 -> v3 and v3+v4 -> v3 ? We should be consistent in preferring either v2 over v3 or v3 over v2. Thanks!
Quoted 7 lines
Quoted 4 lines
Sorry, it is a typo error. Please read: "NFSv2 + NFSv3 server: use NFSv2 protocol".
As long as NFSv2 is available, we use it. Otherwise, we use v3 if available. As explained above.
OK, that makes sense, thanks! Joe, I assume you can just fix that in the commit message when you pick this up.
Yup, no problem.
PATCH v2 1/1 net: NFS: Add NFSv3 support
Le 25/06/2016 ? 21:26, Joe Hershberger a ?crit :
Quoted 20 lines · Tom Rini
Quoted 19 lines · Guillaume Gardet
Quoted 18 lines
Le 23/06/2016 21:08, Tom Rini a ?crit :
Quoted 16 lines · Guillaume GARDET
Quoted 11 lines
This patch enables NFSv3 support.
If NFSv2 is available use it as usual.
If NFSv2 is not available, but NFSv3 is available, use NFSv3.
If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.Tested on iMX6 sabrelite with 4 Linux NFS servers:
* NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
* NFSv2 + NFSv3 server: use NFSv3 protocol
* NFSv3 + NFSv4 server: use NFSv3 protocol
* NFSv3 server: use NFSv3 protocolSo, why do we have v2+v3+v4 -> v2 and not v2+v3+v4 -> v3, when we do v2+v3 -> v3 and v3+v4 -> v3 ? We should be consistent in preferring either v2 over v3 or v3 over v2. Thanks!
Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
Sorry, it is a typo error. Please read: "NFSv2 + NFSv3 server: use NFSv2 protocol".
As long as NFSv2 is available, we use it. Otherwise, we use v3 if available. As explained above.
OK, that makes sense, thanks! Joe, I assume you can just fix that in the commit message when you pick this up.
Yup, no problem.
Just a friendly reminder for this patch. :)
Guillaume
PATCH v3 1/1 net: NFS: Add NFSv3 support
This patch enables NFSv3 support.
If NFSv2 is available use it as usual.
If NFSv2 is not available, but NFSv3 is available, use NFSv3.
If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.
Tested on iMX6 sabrelite with 4 Linux NFS servers:
* NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
* NFSv2 + NFSv3 server: use NFSv2 protocol
* NFSv3 + NFSv4 server: use NFSv3 protocol
* NFSv3 server: use NFSv3 protocol
---
Changes in V3:
* rebase on latest GIT
* Fix typo in commit mesage
Changes in V2:
* rebase on latest GIT
* shorten some long lines
* no functionnal changes
net/nfs.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++++++----------- net/nfs.h | 15 +++- 2 files changed, 242 insertions(+), 47 deletions(-)
net/nfs.c +228 -46
@@ -22,6 +22,10 @@* possible, maximum 16 steps). There is no clearing of ".."'s inside the * path, so please DON'T DO THAT. thx. */ +/* NOTE 4: NFSv3 support added by Guillaume GARDET, 2016-June-20. +* NFSv2 is still used by default. But if server does not support NFSv2, then +* NFSv3 is used, if available on NFS server. */ +#include <common.h> #include <command.h> #include <net.h>
@@ -47,8 +51,11 @@ static int nfs_offset = -1;static int nfs_len;static ulong nfs_timeout =NFS_TIMEOUT ; -static char dirfh[NFS_FHSIZE ];/* file handle of directory */ -static char filefh[NFS_FHSIZE ];/* file handle of kernel image */ +static char dirfh[NFS_FHSIZE ];/* NFSv2 / NFSv3 file handle of directory */ +static char filefh[NFS_FHSIZE ];/* NFSv2 file handle */ + +static char filefh3[NFS3_FHSIZE ];/* NFSv3 file handle */ +static int filefh3_length;/* (variable) length of filefh3 */ static enum net_loop_state nfs_download_state;static struct in_addr nfs_server_ip;
@@ -70,6 +77,10 @@ static char *nfs_filename;static char *nfs_path;static char nfs_path_buff[2048 ]; +#define NFSV2_FLAG 1 +#define NFSV3_FLAG 1 << 1 +static char supported_nfs_versions =NFSV2_FLAG |NFSV3_FLAG ; +static inline int store_block (uchar *src,unsigned offset,unsigned len) {ulong newsize = offset + len;
@@ -188,7 +199,18 @@ static void rpc_req(int rpc_prog, int rpc_proc, uint32_t *data, int datalen) pkt.u.call.type =htonl (MSG_CALL ); pkt.u.call.rpcvers =htonl (2 );/* use RPC version 2 */ pkt.u.call.prog =htonl (rpc_prog); - pkt.u.call.vers =htonl (2 );/* portmapper is version 2 */ +switch (rpc_prog) { +case PROG_NFS : +if (supported_nfs_versions &NFSV2_FLAG ) + pkt.u.call.vers =htonl (2 );/* NFS v2 */ +else /* NFSV3_FLAG */ + pkt.u.call.vers =htonl (3 );/* NFS v3 */ +break ; +case PROG_PORTMAP : +case PROG_MOUNT : +default : + pkt.u.call.vers =htonl (2 );/* portmapper is version 2 */ + } pkt.u.call.proc =htonl (rpc_proc); p = (uint32_t *)&(pkt.u.call.data);
@@ -224,7 +246,6 @@ static void rpc_lookup_req(int prog, int ver) data[5 ] =htonl (ver); data[6 ] =htonl (17 );/* IP_UDP */ data[7 ] =0 ; -rpc_req (PROG_PORTMAP ,PORTMAP_GETPORT , data,8 ); }
@@ -291,8 +312,14 @@ static void nfs_readlink_req(void) p = &(data[0 ]); p =rpc_add_credentials (p); -memcpy (p, filefh,NFS_FHSIZE ); - p += (NFS_FHSIZE /4 ); +if (supported_nfs_versions &NFSV2_FLAG ) { +memcpy (p, filefh,NFS_FHSIZE ); + p += (NFS_FHSIZE /4 ); + }else {/* NFSV3_FLAG */ + *p++ =htonl (filefh3_length); +memcpy (p, filefh3, filefh3_length); + p += (filefh3_length /4 ); + } len = (uint32_t *)p - (uint32_t *)&(data[0 ]);
@@ -314,17 +341,32 @@ static void nfs_lookup_req(char *fname) p = &(data[0 ]); p =rpc_add_credentials (p); -memcpy (p, dirfh,NFS_FHSIZE ); - p += (NFS_FHSIZE /4 ); - *p++ =htonl (fnamelen); -if (fnamelen &3 ) - *(p + fnamelen /4 ) =0 ; -memcpy (p, fname, fnamelen); - p += (fnamelen +3 ) /4 ; - - len = (uint32_t *)p - (uint32_t *)&(data[0 ]); - -rpc_req (PROG_NFS ,NFS_LOOKUP , data, len); +if (supported_nfs_versions &NFSV2_FLAG ) { +memcpy (p, dirfh,NFS_FHSIZE ); + p += (NFS_FHSIZE /4 ); + *p++ =htonl (fnamelen); +if (fnamelen &3 ) + *(p + fnamelen /4 ) =0 ; +memcpy (p, fname, fnamelen); + p += (fnamelen +3 ) /4 ; + + len = (uint32_t *)p - (uint32_t *)&(data[0 ]); + +rpc_req (PROG_NFS ,NFS_LOOKUP , data, len); + }else {/* NFSV3_FLAG */ + *p++ =htonl (NFS_FHSIZE );/* Dir handle length */ +memcpy (p, dirfh,NFS_FHSIZE ); + p += (NFS_FHSIZE /4 ); + *p++ =htonl (fnamelen); +if (fnamelen &3 ) + *(p + fnamelen /4 ) =0 ; +memcpy (p, fname, fnamelen); + p += (fnamelen +3 ) /4 ; + + len = (uint32_t *)p - (uint32_t *)&(data[0 ]); + +rpc_req (PROG_NFS ,NFS3PROC_LOOKUP , data, len); + } }/**************************************************************************
@@ -339,11 +381,21 @@ static void nfs_read_req(int offset, int readlen) p = &(data[0 ]); p =rpc_add_credentials (p); -memcpy (p, filefh,NFS_FHSIZE ); - p += (NFS_FHSIZE /4 ); - *p++ =htonl (offset); - *p++ =htonl (readlen); - *p++ =0 ; +if (supported_nfs_versions &NFSV2_FLAG ) { +memcpy (p, filefh,NFS_FHSIZE ); + p += (NFS_FHSIZE /4 ); + *p++ =htonl (offset); + *p++ =htonl (readlen); + *p++ =0 ; + }else {/* NFSV3_FLAG */ + *p++ =htonl (filefh3_length); +memcpy (p, filefh3, filefh3_length); + p += (filefh3_length /4 ); + *p++ =htonl (0 );/* offset is 64-bit long, so fill with 0 */ + *p++ =htonl (offset); + *p++ =htonl (readlen); + *p++ =0 ; + } len = (uint32_t *)p - (uint32_t *)&(data[0 ]);
@@ -359,10 +411,16 @@ static void nfs_send(void)switch (nfs_state) {case STATE_PRCLOOKUP_PROG_MOUNT_REQ : -rpc_lookup_req (PROG_MOUNT ,1 ); +if (supported_nfs_versions &NFSV2_FLAG ) +rpc_lookup_req (PROG_MOUNT ,1 ); +else /* NFSV3_FLAG */ +rpc_lookup_req (PROG_MOUNT ,3 );break ;case STATE_PRCLOOKUP_PROG_NFS_REQ : -rpc_lookup_req (PROG_NFS ,2 ); +if (supported_nfs_versions &NFSV2_FLAG ) +rpc_lookup_req (PROG_NFS ,2 ); +else /* NFSV3_FLAG */ +rpc_lookup_req (PROG_NFS ,3 );break ;case STATE_MOUNT_REQ :nfs_mount_req (nfs_path);
@@ -436,6 +494,7 @@ static int nfs_mount_reply(uchar *pkt, unsigned len)return -1 ; fs_mounted =1 ; +/* NFSv2 and NFSv3 use same structure */ memcpy (dirfh, rpc_pkt.u.reply.data +1 ,NFS_FHSIZE );return 0 ;
@@ -483,14 +542,33 @@ static int nfs_lookup_reply(uchar *pkt, unsigned len) rpc_pkt.u.reply.astatus || rpc_pkt.u.reply.data[0]) {switch (ntohl (rpc_pkt.u.reply.astatus)) { -case 0 :/* Not an error */ +case NFS_RPC_SUCCESS :/* Not an error */ break ; -case 2 :/* Remote can't support NFS version */ -printf ("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n" , -2 , -ntohl (rpc_pkt.u.reply.data[0 ]), -ntohl (rpc_pkt.u.reply.data[1 ])); +case NFS_RPC_PROG_MISMATCH : +/* Remote can't support NFS version */ +switch (ntohl (rpc_pkt.u.reply.data[0 ])) { +/* Minimal supported NFS version */ +case 3 : +debug ("*** Waring: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n" , + (supported_nfs_versions &NFSV2_FLAG ) ?2 :3 , +ntohl (rpc_pkt.u.reply.data[0 ]), +ntohl (rpc_pkt.u.reply.data[1 ])); +debug ("Will retry with NFSv3\n" ); +/* Clear NFSV2_FLAG from supported versions */ + supported_nfs_versions &= ~NFSV2_FLAG ; +return -NFS_RPC_PROG_MISMATCH ; +case 4 : +default : +printf ("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n" , + (supported_nfs_versions &NFSV2_FLAG ) ?2 :3 , +ntohl (rpc_pkt.u.reply.data[0 ]), +ntohl (rpc_pkt.u.reply.data[1 ])); + }break ; +case NFS_RPC_PROG_UNAVAIL : +case NFS_RPC_PROC_UNAVAIL : +case NFS_RPC_GARBAGE_ARGS : +case NFS_RPC_SYSTEM_ERR :default :/* Unknown error on 'accept state' flag */ printf ("*** ERROR: accept state error (%d)\n" ,ntohl (rpc_pkt.u.reply.astatus));
@@ -499,7 +577,14 @@ static int nfs_lookup_reply(uchar *pkt, unsigned len)return -1 ; } -memcpy (filefh, rpc_pkt.u.reply.data +1 ,NFS_FHSIZE ); +if (supported_nfs_versions &NFSV2_FLAG ) { +memcpy (filefh, rpc_pkt.u.reply.data +1 ,NFS_FHSIZE ); + }else {/* NFSV3_FLAG */ + filefh3_length =ntohl (rpc_pkt.u.reply.data[1 ]); +if (filefh3_length >NFS3_FHSIZE ) + filefh3_length =NFS3_FHSIZE ; +memcpy (filefh3, rpc_pkt.u.reply.data +2 , filefh3_length); + }return 0 ; }
@@ -524,18 +609,68 @@ static int nfs_readlink_reply(uchar *pkt, unsigned len) rpc_pkt.u.reply.data[0])return -1 ; - rlen =ntohl (rpc_pkt.u.reply.data[1 ]);/* new path length */ +if (supported_nfs_versions &NFSV2_FLAG ) { -if (*((char *)&(rpc_pkt.u.reply.data[2 ])) !='/' ) { -int pathlen; -strcat (nfs_path,"/" ); - pathlen =strlen (nfs_path); -memcpy (nfs_path + pathlen, (uchar *)&(rpc_pkt.u.reply.data[2 ]), - rlen); - nfs_path[pathlen + rlen] =0 ; - }else { -memcpy (nfs_path, (uchar *)&(rpc_pkt.u.reply.data[2 ]), rlen); - nfs_path[rlen] =0 ; + rlen =ntohl (rpc_pkt.u.reply.data[1 ]);/* new path length */ + +if (*((char *)&(rpc_pkt.u.reply.data[2 ])) !='/' ) { +int pathlen; +strcat (nfs_path,"/" ); + pathlen =strlen (nfs_path); +memcpy (nfs_path + pathlen, + (uchar *)&(rpc_pkt.u.reply.data[2 ]), + rlen); + nfs_path[pathlen + rlen] =0 ; + }else { +memcpy (nfs_path, + (uchar *)&(rpc_pkt.u.reply.data[2 ]), + rlen); + nfs_path[rlen] =0 ; + } + }else {/* NFSV3_FLAG */ +int nfsv3_data_offset =0 ; +if (ntohl (rpc_pkt.u.reply.data[1 ]) !=0 ) { +/* 'attributes_follow' flag is TRUE, +* so we have attributes on 21 bytes */ +/* Skip unused values : +type; 32 bits value, +mode; 32 bits value, +nlink; 32 bits value, +uid; 32 bits value, +gid; 32 bits value, +size; 64 bits value, +used; 64 bits value, +rdev; 64 bits value, +fsid; 64 bits value, +fileid; 64 bits value, +atime; 64 bits value, +mtime; 64 bits value, +ctime; 64 bits value, +*/ + nfsv3_data_offset =22 ; + }else { +/* 'attributes_follow' flag is FALSE, +* so we don't have any attributes */ + nfsv3_data_offset =1 ; + } + +/* new path length */ + rlen =ntohl (rpc_pkt.u.reply.data[1 +nfsv3_data_offset]); + +if (*((char *)&(rpc_pkt.u.reply.data[2 +nfsv3_data_offset])) !='/' ) { +int pathlen; +strcat (nfs_path,"/" ); + pathlen =strlen (nfs_path); +memcpy (nfs_path + pathlen, + (uchar *)&(rpc_pkt.u.reply.data[2 +nfsv3_data_offset]), + rlen); + nfs_path[pathlen + rlen] =0 ; + }else { +memcpy (nfs_path, + (uchar *)&(rpc_pkt.u.reply.data[2 +nfsv3_data_offset]), + rlen); + nfs_path[rlen] =0 ; + } }return 0 ; }
@@ -544,6 +679,7 @@ static int nfs_read_reply(uchar *pkt, unsigned len) {struct rpc_t rpc_pkt;int rlen; +uchar *data_ptr;debug ("%s\n" , __func__);
@@ -571,10 +707,47 @@ static int nfs_read_reply(uchar *pkt, unsigned len)if (!(nfs_offset % ((NFS_READ_SIZE /2 ) *10 )))putc ('#' ); - rlen =ntohl (rpc_pkt.u.reply.data[18 ]); -if (store_block ((uchar *)pkt +sizeof (rpc_pkt.u.reply), - nfs_offset, rlen)) -return -9999 ; +if (supported_nfs_versions &NFSV2_FLAG ) { + rlen =ntohl (rpc_pkt.u.reply.data[18 ]); + data_ptr = (uchar *)&(rpc_pkt.u.reply.data[19 ]); + }else {/* NFSV3_FLAG */ +if (ntohl (rpc_pkt.u.reply.data[1 ]) !=0 ) { +/* 'attributes_follow' is TRUE, +* so we have attributes on 21 bytes */ +/* Skip unused values : +type; 32 bits value, +mode; 32 bits value, +nlink; 32 bits value, +uid; 32 bits value, +gid; 32 bits value, +size; 64 bits value, +used; 64 bits value, +rdev; 64 bits value, +fsid; 64 bits value, +fileid; 64 bits value, +atime; 64 bits value, +mtime; 64 bits value, +ctime; 64 bits value, +*/ + rlen =ntohl (rpc_pkt.u.reply.data[23 ]);/* count value */ +/* Skip unused values : +EOF: 32 bits value, +data_size: 32 bits value, +*/ + data_ptr = (uchar *)&(rpc_pkt.u.reply.data[26 ]); + }else { +/* attributes_follow is FALSE, so we don't have any attributes */ + rlen =ntohl (rpc_pkt.u.reply.data[2 ]);/* count value */ +/* Skip unused values : +EOF: 32 bits value, +data_size: 32 bits value, +*/ + data_ptr = (uchar *)&(rpc_pkt.u.reply.data[5 ]); + } + } + +if (store_block (data_ptr, nfs_offset, rlen)) +return -9999 ;return rlen; }
@@ -658,6 +831,13 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip,puts ("*** ERROR: File lookup fail\n" ); nfs_state =STATE_UMOUNT_REQ ;nfs_send (); + }else if (reply == -NFS_RPC_PROG_MISMATCH && supported_nfs_versions !=0 ) { +/* umount */ + nfs_state =STATE_UMOUNT_REQ ; +nfs_send (); +/* And retry with another supported version */ + nfs_state =STATE_PRCLOOKUP_PROG_MOUNT_REQ ; +nfs_send (); }else { nfs_state =STATE_READ_REQ ; nfs_offset =0 ;
@@ -697,6 +877,8 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip, }else {if (!rlen) nfs_download_state =NETLOOP_SUCCESS ; +if (rlen <0 ) +printf ("NFS READ error (%d)\n" , rlen); nfs_state =STATE_UMOUNT_REQ ;nfs_send (); }
net/nfs.h +14 -1
@@ -25,7 +25,10 @@#define NFS_READLINK 5#define NFS_READ 6 +#define NFS3PROC_LOOKUP 3 +#define NFS_FHSIZE 32 +#define NFS3_FHSIZE 64#define NFSERR_PERM 1#define NFSERR_NOENT 2
@@ -46,6 +49,16 @@#define NFS_MAXLINKDEPTH 16 +/* Values for Accept State flag on RPC answers (See: rfc1831) */ +enum rpc_accept_stat { +NFS_RPC_SUCCESS =0 ,/* RPC executed successfully */ +NFS_RPC_PROG_UNAVAIL =1 ,/* remote hasn't exported program */ +NFS_RPC_PROG_MISMATCH =2 ,/* remote can't support version # */ +NFS_RPC_PROC_UNAVAIL =3 ,/* program can't support procedure */ +NFS_RPC_GARBAGE_ARGS =4 ,/* procedure can't decode params */ +NFS_RPC_SYSTEM_ERR =5 /* errors like memory allocation failure */ +}; + struct rpc_t { union { uint8_t data[2048];
@@ -65,7 +78,7 @@ struct rpc_t {uint32_t verifier;uint32_t v2;uint32_t astatus; -uint32_t data[19 ]; +uint32_t data[NFS_READ_SIZE ]; } reply; } u; };
Signature · 1 line
1.8.4.5
PATCH v3 1/1 net: NFS: Add NFSv3 support
Quoted 11 lines · Guillaume GARDET
This patch enables NFSv3 support.
If NFSv2 is available use it as usual.
If NFSv2 is not available, but NFSv3 is available, use NFSv3.
If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.Tested on iMX6 sabrelite with 4 Linux NFS servers:
* NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
* NFSv2 + NFSv3 server: use NFSv2 protocol
* NFSv3 + NFSv4 server: use NFSv3 protocol
* NFSv3 server: use NFSv3 protocol
Quoted 3 lines
Signed-off-by Guillaume GARDET <[email protected]>Cc Tom Rini <[email protected]>Cc joe.hershberger at ni.com
Sorry for the delay...