--- /dev/null
+
+all: nfsclient nfsio
+
+clean:
+ rm -f *.o
+ rm -f nfsclient
+
+nfsio: nfsio.o mount_xdr.o mount_client.o nfs_xdr.o nfs_client.o
+ gcc -o $@ nfsio.o mount_client.o mount_xdr.o nfs_client.o nfs_xdr.o -lpthread
+
+nfsclient: nfsclient.o mount_xdr.o mount_client.o nfs_xdr.o nfs_client.o
+ gcc -o $@ nfsclient.o mount_client.o mount_xdr.o nfs_client.o nfs_xdr.o
+
+nfsio.o: nfsio.c
+ gcc -g -c nfsio.c -o $@
+
+nfsclient.o: nfsclient.c
+ gcc -g -c nfsclient.c -o $@
+
+mount_xdr.o: mount_xdr.c
+ gcc -g -c mount_xdr.c -o $@
+
+mount_client.o: mount_client.c
+ gcc -g -c mount_client.c -o $@
+
+mount.h: mount.x
+ @echo Generating $@
+ rpcgen -h mount.x > mount.h
+
+mount_xdr.c: mount.x mount.h
+ @echo Generating $@
+ rpcgen -c mount.x > mount_xdr.c
+
+mount_client.c: mount.x mount.h
+ @echo Generating $@
+ rpcgen -l mount.x > mount_client.c
+
+nfs_xdr.o: nfs_xdr.c
+ gcc -g -c nfs_xdr.c -o $@
+
+nfs_client.o: nfs_client.c
+ gcc -g -c nfs_client.c -o $@
+
+nfs.h: nfs.x
+ @echo Generating $@
+ rpcgen -h nfs.x > nfs.h
+
+nfs_xdr.c: nfs.x nfs.h
+ @echo Generating $@
+ rpcgen -c nfs.x > nfs_xdr.c
+
+nfs_client.c: nfs.x nfs.h
+ @echo Generating $@
+ rpcgen -l nfs.x > nfs_client.c
+
+
--- /dev/null
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#ifndef _MOUNT_H_RPCGEN
+#define _MOUNT_H_RPCGEN
+
+#include <rpc/rpc.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MNTPATHLEN 1024
+#define MNTNAMLEN 255
+#define FHSIZE3 64
+
+typedef struct {
+ u_int fhandle3_len;
+ char *fhandle3_val;
+} fhandle3;
+
+typedef char *dirpath;
+
+typedef char *name;
+
+enum mountstat3 {
+ MNT3_OK = 0,
+ MNT3ERR_PERM = 1,
+ MNT3ERR_NOENT = 2,
+ MNT3ERR_IO = 5,
+ MNT3ERR_ACCES = 13,
+ MNT3ERR_NOTDIR = 20,
+ MNT3ERR_INVAL = 22,
+ MNT3ERR_NAMETOOLONG = 63,
+ MNT3ERR_NOTSUPP = 10004,
+ MNT3ERR_SERVERFAULT = 10006,
+};
+typedef enum mountstat3 mountstat3;
+
+typedef struct mountbody *mountlist;
+
+struct mountbody {
+ name ml_hostname;
+ dirpath ml_directory;
+ mountlist ml_next;
+};
+typedef struct mountbody mountbody;
+
+typedef struct groupnode *groups;
+
+struct groupnode {
+ name gr_name;
+ groups gr_next;
+};
+typedef struct groupnode groupnode;
+
+typedef struct exportnode *exports;
+
+struct exportnode {
+ dirpath ex_dir;
+ groups ex_groups;
+ exports ex_next;
+};
+typedef struct exportnode exportnode;
+
+struct mountres3_ok {
+ fhandle3 fhandle;
+ struct {
+ u_int auth_flavors_len;
+ int *auth_flavors_val;
+ } auth_flavors;
+};
+typedef struct mountres3_ok mountres3_ok;
+
+struct mountres3 {
+ mountstat3 fhs_status;
+ union {
+ mountres3_ok mountinfo;
+ } mountres3_u;
+};
+typedef struct mountres3 mountres3;
+
+#define MOUNT_PROGRAM 100005
+#define MOUNT_V3 3
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define MOUNTPROC3_NULL 0
+extern void * mountproc3_null_3(void *, CLIENT *);
+extern void * mountproc3_null_3_svc(void *, struct svc_req *);
+#define MOUNTPROC3_MNT 1
+extern mountres3 * mountproc3_mnt_3(dirpath *, CLIENT *);
+extern mountres3 * mountproc3_mnt_3_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC3_DUMP 2
+extern mountlist * mountproc3_dump_3(void *, CLIENT *);
+extern mountlist * mountproc3_dump_3_svc(void *, struct svc_req *);
+#define MOUNTPROC3_UMNT 3
+extern void * mountproc3_umnt_3(dirpath *, CLIENT *);
+extern void * mountproc3_umnt_3_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC3_UMNTALL 4
+extern void * mountproc3_umntall_3(void *, CLIENT *);
+extern void * mountproc3_umntall_3_svc(void *, struct svc_req *);
+#define MOUNTPROC3_EXPORT 5
+extern exports * mountproc3_export_3(void *, CLIENT *);
+extern exports * mountproc3_export_3_svc(void *, struct svc_req *);
+extern int mount_program_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#else /* K&R C */
+#define MOUNTPROC3_NULL 0
+extern void * mountproc3_null_3();
+extern void * mountproc3_null_3_svc();
+#define MOUNTPROC3_MNT 1
+extern mountres3 * mountproc3_mnt_3();
+extern mountres3 * mountproc3_mnt_3_svc();
+#define MOUNTPROC3_DUMP 2
+extern mountlist * mountproc3_dump_3();
+extern mountlist * mountproc3_dump_3_svc();
+#define MOUNTPROC3_UMNT 3
+extern void * mountproc3_umnt_3();
+extern void * mountproc3_umnt_3_svc();
+#define MOUNTPROC3_UMNTALL 4
+extern void * mountproc3_umntall_3();
+extern void * mountproc3_umntall_3_svc();
+#define MOUNTPROC3_EXPORT 5
+extern exports * mountproc3_export_3();
+extern exports * mountproc3_export_3_svc();
+extern int mount_program_3_freeresult ();
+#endif /* K&R C */
+
+/* the xdr functions */
+
+#if defined(__STDC__) || defined(__cplusplus)
+extern bool_t xdr_fhandle3 (XDR *, fhandle3*);
+extern bool_t xdr_dirpath (XDR *, dirpath*);
+extern bool_t xdr_name (XDR *, name*);
+extern bool_t xdr_mountstat3 (XDR *, mountstat3*);
+extern bool_t xdr_mountlist (XDR *, mountlist*);
+extern bool_t xdr_mountbody (XDR *, mountbody*);
+extern bool_t xdr_groups (XDR *, groups*);
+extern bool_t xdr_groupnode (XDR *, groupnode*);
+extern bool_t xdr_exports (XDR *, exports*);
+extern bool_t xdr_exportnode (XDR *, exportnode*);
+extern bool_t xdr_mountres3_ok (XDR *, mountres3_ok*);
+extern bool_t xdr_mountres3 (XDR *, mountres3*);
+
+#else /* K&R C */
+extern bool_t xdr_fhandle3 ();
+extern bool_t xdr_dirpath ();
+extern bool_t xdr_name ();
+extern bool_t xdr_mountstat3 ();
+extern bool_t xdr_mountlist ();
+extern bool_t xdr_mountbody ();
+extern bool_t xdr_groups ();
+extern bool_t xdr_groupnode ();
+extern bool_t xdr_exports ();
+extern bool_t xdr_exportnode ();
+extern bool_t xdr_mountres3_ok ();
+extern bool_t xdr_mountres3 ();
+
+#endif /* K&R C */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_MOUNT_H_RPCGEN */
--- /dev/null
+/* copied from RFC1813 */
+
+const MNTPATHLEN = 1024; /* Maximum bytes in a path name */
+const MNTNAMLEN = 255; /* Maximum bytes in a name */
+const FHSIZE3 = 64; /* Maximum bytes in a V3 file handle */
+
+
+typedef opaque fhandle3<FHSIZE3>;
+typedef string dirpath<MNTPATHLEN>;
+typedef string name<MNTNAMLEN>;
+
+enum mountstat3 {
+ MNT3_OK = 0, /* no error */
+ MNT3ERR_PERM = 1, /* Not owner */
+ MNT3ERR_NOENT = 2, /* No such file or directory */
+ MNT3ERR_IO = 5, /* I/O error */
+ MNT3ERR_ACCES = 13, /* Permission denied */
+ MNT3ERR_NOTDIR = 20, /* Not a directory */
+ MNT3ERR_INVAL = 22, /* Invalid argument */
+ MNT3ERR_NAMETOOLONG = 63, /* Filename too long */
+ MNT3ERR_NOTSUPP = 10004, /* Operation not supported */
+ MNT3ERR_SERVERFAULT = 10006 /* A failure on the server */
+};
+
+
+typedef struct mountbody *mountlist;
+
+struct mountbody {
+ name ml_hostname;
+ dirpath ml_directory;
+ mountlist ml_next;
+};
+
+typedef struct groupnode *groups;
+
+struct groupnode {
+ name gr_name;
+ groups gr_next;
+};
+
+
+typedef struct exportnode *exports;
+
+struct exportnode {
+ dirpath ex_dir;
+ groups ex_groups;
+ exports ex_next;
+};
+
+struct mountres3_ok {
+ fhandle3 fhandle;
+ int auth_flavors<>;
+};
+
+union mountres3 switch (mountstat3 fhs_status) {
+ case MNT3_OK:
+ mountres3_ok mountinfo;
+ default:
+ void;
+};
+
+program MOUNT_PROGRAM {
+ version MOUNT_V3 {
+ void MOUNTPROC3_NULL(void) = 0;
+ mountres3 MOUNTPROC3_MNT(dirpath) = 1;
+ mountlist MOUNTPROC3_DUMP(void) = 2;
+ void MOUNTPROC3_UMNT(dirpath) = 3;
+ void MOUNTPROC3_UMNTALL(void) = 4;
+ exports MOUNTPROC3_EXPORT(void) = 5;
+ } = 3;
+} = 100005;
--- /dev/null
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include <memory.h> /* for memset */
+#include "mount.h"
+
+/* Default timeout can be changed using clnt_control() */
+static struct timeval TIMEOUT = { 25, 0 };
+
+void *
+mountproc3_null_3(void *argp, CLIENT *clnt)
+{
+ static char clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call (clnt, MOUNTPROC3_NULL,
+ (xdrproc_t) xdr_void, (caddr_t) argp,
+ (xdrproc_t) xdr_void, (caddr_t) &clnt_res,
+ TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return ((void *)&clnt_res);
+}
+
+mountres3 *
+mountproc3_mnt_3(dirpath *argp, CLIENT *clnt)
+{
+ static mountres3 clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call (clnt, MOUNTPROC3_MNT,
+ (xdrproc_t) xdr_dirpath, (caddr_t) argp,
+ (xdrproc_t) xdr_mountres3, (caddr_t) &clnt_res,
+ TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&clnt_res);
+}
+
+mountlist *
+mountproc3_dump_3(void *argp, CLIENT *clnt)
+{
+ static mountlist clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call (clnt, MOUNTPROC3_DUMP,
+ (xdrproc_t) xdr_void, (caddr_t) argp,
+ (xdrproc_t) xdr_mountlist, (caddr_t) &clnt_res,
+ TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&clnt_res);
+}
+
+void *
+mountproc3_umnt_3(dirpath *argp, CLIENT *clnt)
+{
+ static char clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call (clnt, MOUNTPROC3_UMNT,
+ (xdrproc_t) xdr_dirpath, (caddr_t) argp,
+ (xdrproc_t) xdr_void, (caddr_t) &clnt_res,
+ TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return ((void *)&clnt_res);
+}
+
+void *
+mountproc3_umntall_3(void *argp, CLIENT *clnt)
+{
+ static char clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call (clnt, MOUNTPROC3_UMNTALL,
+ (xdrproc_t) xdr_void, (caddr_t) argp,
+ (xdrproc_t) xdr_void, (caddr_t) &clnt_res,
+ TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return ((void *)&clnt_res);
+}
+
+exports *
+mountproc3_export_3(void *argp, CLIENT *clnt)
+{
+ static exports clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call (clnt, MOUNTPROC3_EXPORT,
+ (xdrproc_t) xdr_void, (caddr_t) argp,
+ (xdrproc_t) xdr_exports, (caddr_t) &clnt_res,
+ TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&clnt_res);
+}
--- /dev/null
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include "mount.h"
+
+bool_t
+xdr_fhandle3 (XDR *xdrs, fhandle3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_dirpath (XDR *xdrs, dirpath *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, objp, MNTPATHLEN))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_name (XDR *xdrs, name *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, objp, MNTNAMLEN))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_mountstat3 (XDR *xdrs, mountstat3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_enum (xdrs, (enum_t *) objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_mountlist (XDR *xdrs, mountlist *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_pointer (xdrs, (char **)objp, sizeof (struct mountbody), (xdrproc_t) xdr_mountbody))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_mountbody (XDR *xdrs, mountbody *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_name (xdrs, &objp->ml_hostname))
+ return FALSE;
+ if (!xdr_dirpath (xdrs, &objp->ml_directory))
+ return FALSE;
+ if (!xdr_mountlist (xdrs, &objp->ml_next))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_groups (XDR *xdrs, groups *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_pointer (xdrs, (char **)objp, sizeof (struct groupnode), (xdrproc_t) xdr_groupnode))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_groupnode (XDR *xdrs, groupnode *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_name (xdrs, &objp->gr_name))
+ return FALSE;
+ if (!xdr_groups (xdrs, &objp->gr_next))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_exports (XDR *xdrs, exports *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_pointer (xdrs, (char **)objp, sizeof (struct exportnode), (xdrproc_t) xdr_exportnode))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_exportnode (XDR *xdrs, exportnode *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_dirpath (xdrs, &objp->ex_dir))
+ return FALSE;
+ if (!xdr_groups (xdrs, &objp->ex_groups))
+ return FALSE;
+ if (!xdr_exports (xdrs, &objp->ex_next))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_fhandle3 (xdrs, &objp->fhandle))
+ return FALSE;
+ if (!xdr_array (xdrs, (char **)&objp->auth_flavors.auth_flavors_val, (u_int *) &objp->auth_flavors.auth_flavors_len, ~0,
+ sizeof (int), (xdrproc_t) xdr_int))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_mountres3 (XDR *xdrs, mountres3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_mountstat3 (xdrs, &objp->fhs_status))
+ return FALSE;
+ switch (objp->fhs_status) {
+ case MNT3_OK:
+ if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
--- /dev/null
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#ifndef _NFS_H_RPCGEN
+#define _NFS_H_RPCGEN
+
+#include <rpc/rpc.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NFS3_FHSIZE 64
+#define NFS3_WRITEVERFSIZE 8
+
+struct nfs_fh3 {
+ struct {
+ u_int data_len;
+ char *data_val;
+ } data;
+};
+typedef struct nfs_fh3 nfs_fh3;
+
+typedef char *filename3;
+
+struct diropargs3 {
+ nfs_fh3 dir;
+ filename3 name;
+};
+typedef struct diropargs3 diropargs3;
+
+enum ftype3 {
+ NF3REG = 1,
+ NF3DIR = 2,
+ NF3BLK = 3,
+ NF3CHR = 4,
+ NF3LNK = 5,
+ NF3SOCK = 6,
+ NF3FIFO = 7,
+};
+typedef enum ftype3 ftype3;
+
+typedef u_long uint32;
+
+typedef long int32;
+
+typedef uint32 mode3;
+
+typedef uint32 uid3;
+
+typedef uint32 gid3;
+
+typedef u_quad_t uint64;
+
+typedef uint64 size3;
+
+typedef uint64 fileid3;
+
+struct specdata3 {
+ uint32 specdata1;
+ uint32 specdata2;
+};
+typedef struct specdata3 specdata3;
+
+struct nfstime3 {
+ uint32 seconds;
+ uint32 nseconds;
+};
+typedef struct nfstime3 nfstime3;
+
+struct fattr3 {
+ ftype3 type;
+ mode3 mode;
+ uint32 nlink;
+ uid3 uid;
+ gid3 gid;
+ size3 size;
+ size3 used;
+ specdata3 rdev;
+ uint64 fsid;
+ fileid3 fileid;
+ nfstime3 atime;
+ nfstime3 mtime;
+ nfstime3 ctime;
+};
+typedef struct fattr3 fattr3;
+
+struct post_op_attr {
+ bool_t attributes_follow;
+ union {
+ fattr3 attributes;
+ } post_op_attr_u;
+};
+typedef struct post_op_attr post_op_attr;
+
+enum nfsstat3 {
+ NFS3_OK = 0,
+ NFS3ERR_PERM = 1,
+ NFS3ERR_NOENT = 2,
+ NFS3ERR_IO = 5,
+ NFS3ERR_NXIO = 6,
+ NFS3ERR_ACCES = 13,
+ NFS3ERR_EXIST = 17,
+ NFS3ERR_XDEV = 18,
+ NFS3ERR_NODEV = 19,
+ NFS3ERR_NOTDIR = 20,
+ NFS3ERR_ISDIR = 21,
+ NFS3ERR_INVAL = 22,
+ NFS3ERR_FBIG = 27,
+ NFS3ERR_NOSPC = 28,
+ NFS3ERR_ROFS = 30,
+ NFS3ERR_MLINK = 31,
+ NFS3ERR_NAMETOOLONG = 63,
+ NFS3ERR_NOTEMPTY = 66,
+ NFS3ERR_DQUOT = 69,
+ NFS3ERR_STALE = 70,
+ NFS3ERR_REMOTE = 71,
+ NFS3ERR_BADHANDLE = 10001,
+ NFS3ERR_NOT_SYNC = 10002,
+ NFS3ERR_BAD_COOKIE = 10003,
+ NFS3ERR_NOTSUPP = 10004,
+ NFS3ERR_TOOSMALL = 10005,
+ NFS3ERR_SERVERFAULT = 10006,
+ NFS3ERR_BADTYPE = 10007,
+ NFS3ERR_JUKEBOX = 10008,
+};
+typedef enum nfsstat3 nfsstat3;
+
+enum stable_how {
+ UNSTABLE = 0,
+ DATA_SYNC = 1,
+ FILE_SYNC = 2,
+};
+typedef enum stable_how stable_how;
+
+typedef uint64 offset3;
+
+typedef uint32 count3;
+
+struct wcc_attr {
+ size3 size;
+ nfstime3 mtime;
+ nfstime3 ctime;
+};
+typedef struct wcc_attr wcc_attr;
+
+struct pre_op_attr {
+ bool_t attributes_follow;
+ union {
+ wcc_attr attributes;
+ } pre_op_attr_u;
+};
+typedef struct pre_op_attr pre_op_attr;
+
+struct wcc_data {
+ pre_op_attr before;
+ post_op_attr after;
+};
+typedef struct wcc_data wcc_data;
+
+struct WRITE3args {
+ nfs_fh3 file;
+ offset3 offset;
+ count3 count;
+ stable_how stable;
+ struct {
+ u_int data_len;
+ char *data_val;
+ } data;
+};
+typedef struct WRITE3args WRITE3args;
+
+typedef char writeverf3[NFS3_WRITEVERFSIZE];
+
+struct WRITE3resok {
+ wcc_data file_wcc;
+ count3 count;
+ stable_how committed;
+ writeverf3 verf;
+};
+typedef struct WRITE3resok WRITE3resok;
+
+struct WRITE3resfail {
+ wcc_data file_wcc;
+};
+typedef struct WRITE3resfail WRITE3resfail;
+
+struct WRITE3res {
+ nfsstat3 status;
+ union {
+ WRITE3resok resok;
+ WRITE3resfail resfail;
+ } WRITE3res_u;
+};
+typedef struct WRITE3res WRITE3res;
+
+struct LOOKUP3args {
+ diropargs3 what;
+};
+typedef struct LOOKUP3args LOOKUP3args;
+
+struct LOOKUP3resok {
+ nfs_fh3 object;
+ post_op_attr obj_attributes;
+ post_op_attr dir_attributes;
+};
+typedef struct LOOKUP3resok LOOKUP3resok;
+
+struct LOOKUP3resfail {
+ post_op_attr dir_attributes;
+};
+typedef struct LOOKUP3resfail LOOKUP3resfail;
+
+struct LOOKUP3res {
+ nfsstat3 status;
+ union {
+ LOOKUP3resok resok;
+ LOOKUP3resfail resfail;
+ } LOOKUP3res_u;
+};
+typedef struct LOOKUP3res LOOKUP3res;
+
+struct COMMIT3args {
+ nfs_fh3 file;
+ offset3 offset;
+ count3 count;
+};
+typedef struct COMMIT3args COMMIT3args;
+
+struct COMMIT3resok {
+ wcc_data file_wcc;
+ writeverf3 verf;
+};
+typedef struct COMMIT3resok COMMIT3resok;
+
+struct COMMIT3resfail {
+ wcc_data file_wcc;
+};
+typedef struct COMMIT3resfail COMMIT3resfail;
+
+struct COMMIT3res {
+ nfsstat3 status;
+ union {
+ COMMIT3resok resok;
+ COMMIT3resfail resfail;
+ } COMMIT3res_u;
+};
+typedef struct COMMIT3res COMMIT3res;
+
+#define NFS_PROGRAM 100003
+#define NFS_V3 3
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define NFSPROC3_NULL 0
+extern void * nfsproc3_null_3(void *, CLIENT *);
+extern void * nfsproc3_null_3_svc(void *, struct svc_req *);
+#define NFSPROC3_LOOKUP 3
+extern LOOKUP3res * nfsproc3_lookup_3(LOOKUP3args *, CLIENT *);
+extern LOOKUP3res * nfsproc3_lookup_3_svc(LOOKUP3args *, struct svc_req *);
+#define NFSPROC3_WRITE 7
+extern WRITE3res * nfsproc3_write_3(WRITE3args *, CLIENT *);
+extern WRITE3res * nfsproc3_write_3_svc(WRITE3args *, struct svc_req *);
+#define NFSPROC3_COMMIT 21
+extern COMMIT3res * nfsproc3_commit_3(COMMIT3args *, CLIENT *);
+extern COMMIT3res * nfsproc3_commit_3_svc(COMMIT3args *, struct svc_req *);
+extern int nfs_program_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#else /* K&R C */
+#define NFSPROC3_NULL 0
+extern void * nfsproc3_null_3();
+extern void * nfsproc3_null_3_svc();
+#define NFSPROC3_LOOKUP 3
+extern LOOKUP3res * nfsproc3_lookup_3();
+extern LOOKUP3res * nfsproc3_lookup_3_svc();
+#define NFSPROC3_WRITE 7
+extern WRITE3res * nfsproc3_write_3();
+extern WRITE3res * nfsproc3_write_3_svc();
+#define NFSPROC3_COMMIT 21
+extern COMMIT3res * nfsproc3_commit_3();
+extern COMMIT3res * nfsproc3_commit_3_svc();
+extern int nfs_program_3_freeresult ();
+#endif /* K&R C */
+
+/* the xdr functions */
+
+#if defined(__STDC__) || defined(__cplusplus)
+extern bool_t xdr_nfs_fh3 (XDR *, nfs_fh3*);
+extern bool_t xdr_filename3 (XDR *, filename3*);
+extern bool_t xdr_diropargs3 (XDR *, diropargs3*);
+extern bool_t xdr_ftype3 (XDR *, ftype3*);
+extern bool_t xdr_uint32 (XDR *, uint32*);
+extern bool_t xdr_int32 (XDR *, int32*);
+extern bool_t xdr_mode3 (XDR *, mode3*);
+extern bool_t xdr_uid3 (XDR *, uid3*);
+extern bool_t xdr_gid3 (XDR *, gid3*);
+extern bool_t xdr_uint64 (XDR *, uint64*);
+extern bool_t xdr_size3 (XDR *, size3*);
+extern bool_t xdr_fileid3 (XDR *, fileid3*);
+extern bool_t xdr_specdata3 (XDR *, specdata3*);
+extern bool_t xdr_nfstime3 (XDR *, nfstime3*);
+extern bool_t xdr_fattr3 (XDR *, fattr3*);
+extern bool_t xdr_post_op_attr (XDR *, post_op_attr*);
+extern bool_t xdr_nfsstat3 (XDR *, nfsstat3*);
+extern bool_t xdr_stable_how (XDR *, stable_how*);
+extern bool_t xdr_offset3 (XDR *, offset3*);
+extern bool_t xdr_count3 (XDR *, count3*);
+extern bool_t xdr_wcc_attr (XDR *, wcc_attr*);
+extern bool_t xdr_pre_op_attr (XDR *, pre_op_attr*);
+extern bool_t xdr_wcc_data (XDR *, wcc_data*);
+extern bool_t xdr_WRITE3args (XDR *, WRITE3args*);
+extern bool_t xdr_writeverf3 (XDR *, writeverf3);
+extern bool_t xdr_WRITE3resok (XDR *, WRITE3resok*);
+extern bool_t xdr_WRITE3resfail (XDR *, WRITE3resfail*);
+extern bool_t xdr_WRITE3res (XDR *, WRITE3res*);
+extern bool_t xdr_LOOKUP3args (XDR *, LOOKUP3args*);
+extern bool_t xdr_LOOKUP3resok (XDR *, LOOKUP3resok*);
+extern bool_t xdr_LOOKUP3resfail (XDR *, LOOKUP3resfail*);
+extern bool_t xdr_LOOKUP3res (XDR *, LOOKUP3res*);
+extern bool_t xdr_COMMIT3args (XDR *, COMMIT3args*);
+extern bool_t xdr_COMMIT3resok (XDR *, COMMIT3resok*);
+extern bool_t xdr_COMMIT3resfail (XDR *, COMMIT3resfail*);
+extern bool_t xdr_COMMIT3res (XDR *, COMMIT3res*);
+
+#else /* K&R C */
+extern bool_t xdr_nfs_fh3 ();
+extern bool_t xdr_filename3 ();
+extern bool_t xdr_diropargs3 ();
+extern bool_t xdr_ftype3 ();
+extern bool_t xdr_uint32 ();
+extern bool_t xdr_int32 ();
+extern bool_t xdr_mode3 ();
+extern bool_t xdr_uid3 ();
+extern bool_t xdr_gid3 ();
+extern bool_t xdr_uint64 ();
+extern bool_t xdr_size3 ();
+extern bool_t xdr_fileid3 ();
+extern bool_t xdr_specdata3 ();
+extern bool_t xdr_nfstime3 ();
+extern bool_t xdr_fattr3 ();
+extern bool_t xdr_post_op_attr ();
+extern bool_t xdr_nfsstat3 ();
+extern bool_t xdr_stable_how ();
+extern bool_t xdr_offset3 ();
+extern bool_t xdr_count3 ();
+extern bool_t xdr_wcc_attr ();
+extern bool_t xdr_pre_op_attr ();
+extern bool_t xdr_wcc_data ();
+extern bool_t xdr_WRITE3args ();
+extern bool_t xdr_writeverf3 ();
+extern bool_t xdr_WRITE3resok ();
+extern bool_t xdr_WRITE3resfail ();
+extern bool_t xdr_WRITE3res ();
+extern bool_t xdr_LOOKUP3args ();
+extern bool_t xdr_LOOKUP3resok ();
+extern bool_t xdr_LOOKUP3resfail ();
+extern bool_t xdr_LOOKUP3res ();
+extern bool_t xdr_COMMIT3args ();
+extern bool_t xdr_COMMIT3resok ();
+extern bool_t xdr_COMMIT3resfail ();
+extern bool_t xdr_COMMIT3res ();
+
+#endif /* K&R C */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_NFS_H_RPCGEN */
--- /dev/null
+/* from rfc 1813 */
+
+const NFS3_FHSIZE = 64; /* Maximum bytes in a V3 file handle */
+const NFS3_WRITEVERFSIZE = 8;
+
+struct nfs_fh3 {
+ opaque data<NFS3_FHSIZE>;
+};
+
+typedef string filename3<>;
+
+struct diropargs3 {
+ nfs_fh3 dir;
+ filename3 name;
+};
+
+enum ftype3 {
+ NF3REG = 1,
+ NF3DIR = 2,
+ NF3BLK = 3,
+ NF3CHR = 4,
+ NF3LNK = 5,
+ NF3SOCK = 6,
+ NF3FIFO = 7
+};
+
+typedef unsigned long uint32;
+
+typedef long int32;
+
+typedef uint32 mode3;
+
+typedef uint32 uid3;
+
+typedef uint32 gid3;
+
+typedef unsigned hyper uint64;
+
+typedef uint64 size3;
+
+typedef uint64 fileid3;
+
+struct specdata3 {
+ uint32 specdata1;
+ uint32 specdata2;
+};
+
+struct nfstime3 {
+ uint32 seconds;
+ uint32 nseconds;
+};
+
+struct fattr3 {
+ ftype3 type;
+ mode3 mode;
+ uint32 nlink;
+ uid3 uid;
+ gid3 gid;
+ size3 size;
+ size3 used;
+ specdata3 rdev;
+ uint64 fsid;
+ fileid3 fileid;
+ nfstime3 atime;
+ nfstime3 mtime;
+ nfstime3 ctime;
+};
+
+union post_op_attr switch (bool attributes_follow) {
+ case TRUE:
+ fattr3 attributes;
+ case FALSE:
+ void;
+};
+
+
+enum nfsstat3 {
+ NFS3_OK = 0,
+ NFS3ERR_PERM = 1,
+ NFS3ERR_NOENT = 2,
+ NFS3ERR_IO = 5,
+ NFS3ERR_NXIO = 6,
+ NFS3ERR_ACCES = 13,
+ NFS3ERR_EXIST = 17,
+ NFS3ERR_XDEV = 18,
+ NFS3ERR_NODEV = 19,
+ NFS3ERR_NOTDIR = 20,
+ NFS3ERR_ISDIR = 21,
+ NFS3ERR_INVAL = 22,
+ NFS3ERR_FBIG = 27,
+ NFS3ERR_NOSPC = 28,
+ NFS3ERR_ROFS = 30,
+ NFS3ERR_MLINK = 31,
+ NFS3ERR_NAMETOOLONG = 63,
+ NFS3ERR_NOTEMPTY = 66,
+ NFS3ERR_DQUOT = 69,
+ NFS3ERR_STALE = 70,
+ NFS3ERR_REMOTE = 71,
+ NFS3ERR_BADHANDLE = 10001,
+ NFS3ERR_NOT_SYNC = 10002,
+ NFS3ERR_BAD_COOKIE = 10003,
+ NFS3ERR_NOTSUPP = 10004,
+ NFS3ERR_TOOSMALL = 10005,
+ NFS3ERR_SERVERFAULT = 10006,
+ NFS3ERR_BADTYPE = 10007,
+ NFS3ERR_JUKEBOX = 10008
+};
+
+enum stable_how {
+ UNSTABLE = 0,
+ DATA_SYNC = 1,
+ FILE_SYNC = 2
+};
+
+typedef uint64 offset3;
+
+typedef uint32 count3;
+
+struct wcc_attr {
+ size3 size;
+ nfstime3 mtime;
+ nfstime3 ctime;
+};
+
+union pre_op_attr switch (bool attributes_follow) {
+ case TRUE:
+ wcc_attr attributes;
+ case FALSE:
+ void;
+};
+
+struct wcc_data {
+ pre_op_attr before;
+ post_op_attr after;
+};
+
+struct WRITE3args {
+ nfs_fh3 file;
+ offset3 offset;
+ count3 count;
+ stable_how stable;
+ opaque data<>;
+};
+
+typedef opaque writeverf3[NFS3_WRITEVERFSIZE];
+
+struct WRITE3resok {
+ wcc_data file_wcc;
+ count3 count;
+ stable_how committed;
+ writeverf3 verf;
+};
+
+struct WRITE3resfail {
+ wcc_data file_wcc;
+};
+
+union WRITE3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ WRITE3resok resok;
+ default:
+ WRITE3resfail resfail;
+};
+
+struct LOOKUP3args {
+ diropargs3 what;
+};
+
+struct LOOKUP3resok {
+ nfs_fh3 object;
+ post_op_attr obj_attributes;
+ post_op_attr dir_attributes;
+};
+
+struct LOOKUP3resfail {
+ post_op_attr dir_attributes;
+};
+
+
+
+union LOOKUP3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ LOOKUP3resok resok;
+ default:
+ LOOKUP3resfail resfail;
+};
+
+struct COMMIT3args {
+ nfs_fh3 file;
+ offset3 offset;
+ count3 count;
+};
+
+struct COMMIT3resok {
+ wcc_data file_wcc;
+ writeverf3 verf;
+};
+
+struct COMMIT3resfail {
+ wcc_data file_wcc;
+};
+
+union COMMIT3res switch (nfsstat3 status) {
+ case NFS3_OK:
+ COMMIT3resok resok;
+ default:
+ COMMIT3resfail resfail;
+};
+
+
+program NFS_PROGRAM {
+ version NFS_V3 {
+ void NFSPROC3_NULL(void) = 0;
+/* GETATTR3res NFSPROC3_GETATTR(GETATTR3args) = 1;*/
+/* SETATTR3res NFSPROC3_SETATTR(SETATTR3args) = 2;*/
+ LOOKUP3res NFSPROC3_LOOKUP(LOOKUP3args) = 3;
+/* ACCESS3res NFSPROC3_ACCESS(ACCESS3args) = 4;*/
+/* READLINK3res NFSPROC3_READLINK(READLINK3args) = 5;*/
+/* READ3res NFSPROC3_READ(READ3args) = 6;*/
+ WRITE3res NFSPROC3_WRITE(WRITE3args) = 7;
+/* CREATE3res NFSPROC3_CREATE(CREATE3args) = 8;*/
+/* MKDIR3res NFSPROC3_MKDIR(MKDIR3args) = 9;*/
+/* SYMLINK3res NFSPROC3_SYMLINK(SYMLINK3args) = 10;*/
+/* MKNOD3res NFSPROC3_MKNOD(MKNOD3args) = 11;*/
+/* REMOVE3res NFSPROC3_REMOVE(REMOVE3args) = 12;*/
+/* RMDIR3res NFSPROC3_RMDIR(RMDIR3args) = 13;*/
+/* RENAME3res NFSPROC3_RENAME(RENAME3args) = 14;*/
+/* LINK3res NFSPROC3_LINK(LINK3args) = 15;*/
+/* READDIR3res NFSPROC3_READDIR(READDIR3args) = 16;*/
+/* READDIRPLUS3res NFSPROC3_READDIRPLUS(READDIRPLUS3args) = 17;*/
+/* FSSTAT3res NFSPROC3_FSSTAT(FSSTAT3args) = 18;*/
+/* FSINFO3res NFSPROC3_FSINFO(FSINFO3args) = 19;*/
+/* PATHCONF3res NFSPROC3_PATHCONF(PATHCONF3args) = 20;*/
+ COMMIT3res NFSPROC3_COMMIT(COMMIT3args) = 21;
+ } = 3;
+} = 100003;
--- /dev/null
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include <memory.h> /* for memset */
+#include "nfs.h"
+
+/* Default timeout can be changed using clnt_control() */
+static struct timeval TIMEOUT = { 25, 0 };
+
+void *
+nfsproc3_null_3(void *argp, CLIENT *clnt)
+{
+ static char clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call (clnt, NFSPROC3_NULL,
+ (xdrproc_t) xdr_void, (caddr_t) argp,
+ (xdrproc_t) xdr_void, (caddr_t) &clnt_res,
+ TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return ((void *)&clnt_res);
+}
+
+LOOKUP3res *
+nfsproc3_lookup_3(LOOKUP3args *argp, CLIENT *clnt)
+{
+ static LOOKUP3res clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call (clnt, NFSPROC3_LOOKUP,
+ (xdrproc_t) xdr_LOOKUP3args, (caddr_t) argp,
+ (xdrproc_t) xdr_LOOKUP3res, (caddr_t) &clnt_res,
+ TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&clnt_res);
+}
+
+WRITE3res *
+nfsproc3_write_3(WRITE3args *argp, CLIENT *clnt)
+{
+ static WRITE3res clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call (clnt, NFSPROC3_WRITE,
+ (xdrproc_t) xdr_WRITE3args, (caddr_t) argp,
+ (xdrproc_t) xdr_WRITE3res, (caddr_t) &clnt_res,
+ TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&clnt_res);
+}
+
+COMMIT3res *
+nfsproc3_commit_3(COMMIT3args *argp, CLIENT *clnt)
+{
+ static COMMIT3res clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call (clnt, NFSPROC3_COMMIT,
+ (xdrproc_t) xdr_COMMIT3args, (caddr_t) argp,
+ (xdrproc_t) xdr_COMMIT3res, (caddr_t) &clnt_res,
+ TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&clnt_res);
+}
--- /dev/null
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include "nfs.h"
+
+bool_t
+xdr_nfs_fh3 (XDR *xdrs, nfs_fh3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, NFS3_FHSIZE))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_filename3 (XDR *xdrs, filename3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_string (xdrs, objp, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_diropargs3 (XDR *xdrs, diropargs3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_nfs_fh3 (xdrs, &objp->dir))
+ return FALSE;
+ if (!xdr_filename3 (xdrs, &objp->name))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_ftype3 (XDR *xdrs, ftype3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_enum (xdrs, (enum_t *) objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_uint32 (XDR *xdrs, uint32 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_u_long (xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_int32 (XDR *xdrs, int32 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_long (xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_mode3 (XDR *xdrs, mode3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_uint32 (xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_uid3 (XDR *xdrs, uid3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_uint32 (xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_gid3 (XDR *xdrs, gid3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_uint32 (xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_uint64 (XDR *xdrs, uint64 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_u_quad_t (xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_size3 (XDR *xdrs, size3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_uint64 (xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_fileid3 (XDR *xdrs, fileid3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_uint64 (xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_specdata3 (XDR *xdrs, specdata3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_uint32 (xdrs, &objp->specdata1))
+ return FALSE;
+ if (!xdr_uint32 (xdrs, &objp->specdata2))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_nfstime3 (XDR *xdrs, nfstime3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_uint32 (xdrs, &objp->seconds))
+ return FALSE;
+ if (!xdr_uint32 (xdrs, &objp->nseconds))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_fattr3 (XDR *xdrs, fattr3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_ftype3 (xdrs, &objp->type))
+ return FALSE;
+ if (!xdr_mode3 (xdrs, &objp->mode))
+ return FALSE;
+ if (!xdr_uint32 (xdrs, &objp->nlink))
+ return FALSE;
+ if (!xdr_uid3 (xdrs, &objp->uid))
+ return FALSE;
+ if (!xdr_gid3 (xdrs, &objp->gid))
+ return FALSE;
+ if (!xdr_size3 (xdrs, &objp->size))
+ return FALSE;
+ if (!xdr_size3 (xdrs, &objp->used))
+ return FALSE;
+ if (!xdr_specdata3 (xdrs, &objp->rdev))
+ return FALSE;
+ if (!xdr_uint64 (xdrs, &objp->fsid))
+ return FALSE;
+ if (!xdr_fileid3 (xdrs, &objp->fileid))
+ return FALSE;
+ if (!xdr_nfstime3 (xdrs, &objp->atime))
+ return FALSE;
+ if (!xdr_nfstime3 (xdrs, &objp->mtime))
+ return FALSE;
+ if (!xdr_nfstime3 (xdrs, &objp->ctime))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_post_op_attr (XDR *xdrs, post_op_attr *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_bool (xdrs, &objp->attributes_follow))
+ return FALSE;
+ switch (objp->attributes_follow) {
+ case TRUE:
+ if (!xdr_fattr3 (xdrs, &objp->post_op_attr_u.attributes))
+ return FALSE;
+ break;
+ case FALSE:
+ break;
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool_t
+xdr_nfsstat3 (XDR *xdrs, nfsstat3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_enum (xdrs, (enum_t *) objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_stable_how (XDR *xdrs, stable_how *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_enum (xdrs, (enum_t *) objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_offset3 (XDR *xdrs, offset3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_uint64 (xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_count3 (XDR *xdrs, count3 *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_uint32 (xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_wcc_attr (XDR *xdrs, wcc_attr *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_size3 (xdrs, &objp->size))
+ return FALSE;
+ if (!xdr_nfstime3 (xdrs, &objp->mtime))
+ return FALSE;
+ if (!xdr_nfstime3 (xdrs, &objp->ctime))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_pre_op_attr (XDR *xdrs, pre_op_attr *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_bool (xdrs, &objp->attributes_follow))
+ return FALSE;
+ switch (objp->attributes_follow) {
+ case TRUE:
+ if (!xdr_wcc_attr (xdrs, &objp->pre_op_attr_u.attributes))
+ return FALSE;
+ break;
+ case FALSE:
+ break;
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool_t
+xdr_wcc_data (XDR *xdrs, wcc_data *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_pre_op_attr (xdrs, &objp->before))
+ return FALSE;
+ if (!xdr_post_op_attr (xdrs, &objp->after))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_WRITE3args (XDR *xdrs, WRITE3args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_nfs_fh3 (xdrs, &objp->file))
+ return FALSE;
+ if (!xdr_offset3 (xdrs, &objp->offset))
+ return FALSE;
+ if (!xdr_count3 (xdrs, &objp->count))
+ return FALSE;
+ if (!xdr_stable_how (xdrs, &objp->stable))
+ return FALSE;
+ if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_writeverf3 (XDR *xdrs, writeverf3 objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_opaque (xdrs, objp, NFS3_WRITEVERFSIZE))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_WRITE3resok (XDR *xdrs, WRITE3resok *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_wcc_data (xdrs, &objp->file_wcc))
+ return FALSE;
+ if (!xdr_count3 (xdrs, &objp->count))
+ return FALSE;
+ if (!xdr_stable_how (xdrs, &objp->committed))
+ return FALSE;
+ if (!xdr_writeverf3 (xdrs, objp->verf))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_WRITE3resfail (XDR *xdrs, WRITE3resfail *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_wcc_data (xdrs, &objp->file_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_WRITE3res (XDR *xdrs, WRITE3res *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_nfsstat3 (xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_WRITE3resok (xdrs, &objp->WRITE3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_WRITE3resfail (xdrs, &objp->WRITE3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t
+xdr_LOOKUP3args (XDR *xdrs, LOOKUP3args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_diropargs3 (xdrs, &objp->what))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_LOOKUP3resok (XDR *xdrs, LOOKUP3resok *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_nfs_fh3 (xdrs, &objp->object))
+ return FALSE;
+ if (!xdr_post_op_attr (xdrs, &objp->obj_attributes))
+ return FALSE;
+ if (!xdr_post_op_attr (xdrs, &objp->dir_attributes))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_LOOKUP3resfail (XDR *xdrs, LOOKUP3resfail *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_post_op_attr (xdrs, &objp->dir_attributes))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_LOOKUP3res (XDR *xdrs, LOOKUP3res *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_nfsstat3 (xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_LOOKUP3resok (xdrs, &objp->LOOKUP3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_LOOKUP3resfail (xdrs, &objp->LOOKUP3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t
+xdr_COMMIT3args (XDR *xdrs, COMMIT3args *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_nfs_fh3 (xdrs, &objp->file))
+ return FALSE;
+ if (!xdr_offset3 (xdrs, &objp->offset))
+ return FALSE;
+ if (!xdr_count3 (xdrs, &objp->count))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_COMMIT3resok (XDR *xdrs, COMMIT3resok *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_wcc_data (xdrs, &objp->file_wcc))
+ return FALSE;
+ if (!xdr_writeverf3 (xdrs, objp->verf))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_COMMIT3resfail (XDR *xdrs, COMMIT3resfail *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_wcc_data (xdrs, &objp->file_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_COMMIT3res (XDR *xdrs, COMMIT3res *objp)
+{
+ register int32_t *buf;
+
+ if (!xdr_nfsstat3 (xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_COMMIT3resok (xdrs, &objp->COMMIT3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_COMMIT3resfail (xdrs, &objp->COMMIT3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
--- /dev/null
+/*
+ simple nfsclient
+
+ Copyright (C) Ronnie Sahlberg 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <stdio.h>
+#include "mount.h"
+#include "nfs.h"
+
+static fhandle3 *
+get_mount_fh(const char *client, char *mntdir)
+{
+ CLIENT *clnt;
+ dirpath mountdir=mntdir;
+ mountres3 *mountres;
+ fhandle3 *mfh;
+ int i;
+
+ clnt = clnt_create(client, MOUNT_PROGRAM, MOUNT_V3, "tcp");
+ if (clnt == NULL) {
+ printf("ERROR: failed to connect to MOUNT daemon on %s\n", client);
+ exit(10);
+ }
+
+ mountres=mountproc3_mnt_3(&mountdir, clnt);
+ if (mountres == NULL) {
+ printf("ERROR: failed to call the MNT procedure\n");
+ exit(10);
+ }
+ if (mountres->fhs_status != MNT3_OK) {
+ printf("ERROR: Server returned error %d when trying to MNT\n",mountres->fhs_status);
+ exit(10);
+ }
+
+ mfh = malloc(sizeof(fhandle3));
+ mfh->fhandle3_len = mountres->mountres3_u.mountinfo.fhandle.fhandle3_len;
+ mfh->fhandle3_val = malloc(mountres->mountres3_u.mountinfo.fhandle.fhandle3_len);
+ memcpy(mfh->fhandle3_val,
+ mountres->mountres3_u.mountinfo.fhandle.fhandle3_val,
+ mountres->mountres3_u.mountinfo.fhandle.fhandle3_len);
+
+ clnt_destroy(clnt);
+
+ printf("mount filehandle : %d ", mfh->fhandle3_len);
+ for (i=0;i<mfh->fhandle3_len;i++) {
+ printf("%02x", mfh->fhandle3_val[i]);
+ }
+ printf("\n");
+
+ return mfh;
+}
+
+
+static nfs_fh3 *
+lookup_fh(CLIENT *clnt, nfs_fh3 *dir, char *name)
+{
+ nfs_fh3 *fh;
+ LOOKUP3args l3args;
+ LOOKUP3res *l3res;
+ int i;
+
+ l3args.what.dir.data.data_len = dir->data.data_len;
+ l3args.what.dir.data.data_val = dir->data.data_val;
+ l3args.what.name = name;
+ l3res = nfsproc3_lookup_3(&l3args, clnt);
+ if (l3res == NULL) {
+ printf("Failed to lookup file %s\n", "x.dat");
+ exit(10);
+ }
+ if (l3res->status != NFS3_OK) {
+ printf("lookup returned error %d\n", l3res->status);
+ exit(10);
+ }
+
+ fh = malloc(sizeof(nfs_fh3));
+ fh->data.data_len = l3res->LOOKUP3res_u.resok.object.data.data_len;
+ fh->data.data_val = malloc(fh->data.data_len);
+ memcpy(fh->data.data_val,
+ l3res->LOOKUP3res_u.resok.object.data.data_val,
+ fh->data.data_len);
+
+ printf("file filehandle : %d ", fh->data.data_len);
+ for (i=0;i<fh->data.data_len;i++) {
+ printf("%02x", fh->data.data_val[i]);
+ }
+ printf("\n");
+
+ return fh;
+}
+
+/* return number of bytes weitten or -1 if there was an error */
+static int
+write_data(CLIENT *clnt, nfs_fh3 *fh, offset3 offset, char *buffer,
+ count3 count, enum stable_how stable)
+{
+ WRITE3args w3args;
+ WRITE3res *w3res;
+
+ w3args.file = *fh;
+ w3args.offset = offset;
+ w3args.count = count;
+ w3args.stable = stable;
+ w3args.data.data_len = count;
+ w3args.data.data_val = buffer;
+ w3res = nfsproc3_write_3(&w3args, clnt);
+ if (w3res == NULL) {
+ return -1;
+ }
+ if (w3res->status != NFS3_OK) {
+ return -1;
+ }
+ return w3res->WRITE3res_u.resok.count;
+}
+
+
+static void
+commit_data(CLIENT *clnt, nfs_fh3 *fh)
+{
+ COMMIT3args c3args;
+ COMMIT3res *c3res;
+
+ c3args.file = *fh;
+ c3args.offset = 0;
+ c3args.count = 0;
+
+ c3res = nfsproc3_commit_3(&c3args, clnt);
+}
+
+int main(int argc, const char *argv[])
+{
+ CLIENT *clnt;
+ fhandle3 *mfh;
+ nfs_fh3 *fh;
+ char buffer[512];
+
+ /* get the filehandle for the mountpoint */
+ mfh = get_mount_fh("9.155.61.98", "/gpfs1/data");
+
+ /* connect to NFS */
+ clnt = clnt_create("9.155.61.98", NFS_PROGRAM, NFS_V3, "tcp");
+ if (clnt == NULL) {
+ printf("ERROR: failed to connect to NFS daemon on %s\n", "9.155.61.98");
+ exit(10);
+ }
+
+
+ /* get the file filehandle */
+ fh = lookup_fh(clnt, (nfs_fh3 *)mfh, "x.dat");
+
+
+ if (write_data(clnt, fh, 1024, buffer, sizeof(buffer), UNSTABLE) == -1) {
+ printf("failed to write data\n");
+ exit(10);
+ }
+ commit_data(clnt, fh);
+
+ return 0;
+}
--- /dev/null
+/*
+ simulate IO and thread pattern in ntap sio test
+
+ Copyright (C) Andrew Tridgell <tridge@samba.org> 2007
+
+ Released under the GNU GPL version 2 or later
+*/
+
+#define _GNU_SOURCE
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE64_SOURCE
+#define _LARGE_FILES
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <getopt.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <dirent.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include "mount.h"
+#include "nfs.h"
+
+static size_t block_size = 8192;
+static off_t file_size = 1024*1024*(1024LL);
+static unsigned num_threads = 1;
+static const char *fname;
+static volatile unsigned *io_count;
+static volatile int run_finished;
+static unsigned runtime = 20;
+static bool sync_io;
+static int flush_blocks;
+
+/* filehandle for the mount */
+static fhandle3 *mfh;
+
+
+static fhandle3 *
+get_mount_fh(const char *client, char *mntdir)
+{
+ CLIENT *clnt;
+ dirpath mountdir=mntdir;
+ mountres3 *mountres;
+ fhandle3 *mfh;
+ int i;
+
+ clnt = clnt_create(client, MOUNT_PROGRAM, MOUNT_V3, "tcp");
+ if (clnt == NULL) {
+ printf("ERROR: failed to connect to MOUNT daemon on %s\n", client);
+ exit(10);
+ }
+
+ mountres=mountproc3_mnt_3(&mountdir, clnt);
+ if (mountres == NULL) {
+ printf("ERROR: failed to call the MNT procedure\n");
+ exit(10);
+ }
+ if (mountres->fhs_status != MNT3_OK) {
+ printf("ERROR: Server returned error %d when trying to MNT\n",mountres->fhs_status);
+ exit(10);
+ }
+
+ mfh = malloc(sizeof(fhandle3));
+ mfh->fhandle3_len = mountres->mountres3_u.mountinfo.fhandle.fhandle3_len;
+ mfh->fhandle3_val = malloc(mountres->mountres3_u.mountinfo.fhandle.fhandle3_len);
+ memcpy(mfh->fhandle3_val,
+ mountres->mountres3_u.mountinfo.fhandle.fhandle3_val,
+ mountres->mountres3_u.mountinfo.fhandle.fhandle3_len);
+
+ clnt_destroy(clnt);
+
+ printf("mount filehandle : %d ", mfh->fhandle3_len);
+ for (i=0;i<mfh->fhandle3_len;i++) {
+ printf("%02x", mfh->fhandle3_val[i]);
+ }
+ printf("\n");
+
+ return mfh;
+}
+
+static nfs_fh3 *
+lookup_fh(CLIENT *clnt, nfs_fh3 *dir, char *name)
+{
+ nfs_fh3 *fh;
+ LOOKUP3args l3args;
+ LOOKUP3res *l3res;
+ int i;
+
+ l3args.what.dir.data.data_len = dir->data.data_len;
+ l3args.what.dir.data.data_val = dir->data.data_val;
+ l3args.what.name = name;
+ l3res = nfsproc3_lookup_3(&l3args, clnt);
+ if (l3res == NULL) {
+ printf("Failed to lookup file %s\n", name);
+ exit(10);
+ }
+ if (l3res->status != NFS3_OK) {
+ printf("lookup returned error %d\n", l3res->status);
+ exit(10);
+ }
+
+ fh = malloc(sizeof(nfs_fh3));
+ fh->data.data_len = l3res->LOOKUP3res_u.resok.object.data.data_len;
+ fh->data.data_val = malloc(fh->data.data_len);
+ memcpy(fh->data.data_val,
+ l3res->LOOKUP3res_u.resok.object.data.data_val,
+ fh->data.data_len);
+
+ printf("file filehandle : %d ", fh->data.data_len);
+ for (i=0;i<fh->data.data_len;i++) {
+ printf("%02x", fh->data.data_val[i]);
+ }
+ printf("\n");
+
+ return fh;
+}
+
+/* return number of bytes written or -1 if there was an error */
+static int
+write_data(CLIENT *clnt, nfs_fh3 *fh, offset3 offset, char *buffer,
+ count3 count, enum stable_how stable)
+{
+ WRITE3args w3args;
+ WRITE3res *w3res;
+
+ w3args.file = *fh;
+ w3args.offset = offset;
+ w3args.count = count;
+ w3args.stable = stable;
+ w3args.data.data_len = count;
+ w3args.data.data_val = buffer;
+ w3res = nfsproc3_write_3(&w3args, clnt);
+ if (w3res == NULL) {
+ return -1;
+ }
+ if (w3res->status != NFS3_OK) {
+ return -1;
+ }
+ return w3res->WRITE3res_u.resok.count;
+}
+
+static void
+commit_data(CLIENT *clnt, nfs_fh3 *fh)
+{
+ COMMIT3args c3args;
+ COMMIT3res *c3res;
+
+ c3args.file = *fh;
+ c3args.offset = 0;
+ c3args.count = 0;
+
+ c3res = nfsproc3_commit_3(&c3args, clnt);
+}
+
+static void run_child(int id)
+{
+ unsigned num_blocks = file_size / block_size;
+ char *buf;
+ CLIENT *clnt;
+ nfs_fh3 *fh;
+ enum stable_how stable = UNSTABLE;
+
+ if (sync_io) {
+ stable = FILE_SYNC;
+ }
+
+ /* connect to NFS */
+ clnt = clnt_create("9.155.61.98", NFS_PROGRAM, NFS_V3, "tcp");
+ if (clnt == NULL) {
+ printf("ERROR: failed to connect to NFS daemon on %s\n", "9.155.61.98");
+ exit(10);
+ }
+
+
+ /* get the file filehandle */
+ fh = lookup_fh(clnt, (nfs_fh3 *)mfh, fname);
+
+ buf = malloc(block_size);
+ memset(buf, 1, block_size);
+
+ srandom(id ^ random());
+
+ while (!run_finished) {
+ unsigned offset = random() % num_blocks;
+ if (write_data(clnt, fh, offset*(off_t)block_size, buf, block_size, stable) != block_size) {
+ printf("write_data failed!\n");
+ exit(1);
+ }
+ io_count[id]++;
+ if (flush_blocks && io_count[id] % flush_blocks == 0) {
+ commit_data(clnt, fh);
+ }
+ }
+
+ return;
+}
+
+/*
+ create a thread with initial function fn(private)
+*/
+static pthread_t thread_start(void (*fn)(int), int id)
+{
+ pthread_t thread_id;
+ pthread_attr_t thread_attr;
+ int rc;
+ typedef void *(*thread_fn_t)(void *);
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, 0);
+ rc = pthread_create(&thread_id, &thread_attr, (thread_fn_t)fn, (void *)id);
+ pthread_attr_destroy(&thread_attr);
+
+ if (rc != 0) {
+ fprintf(stderr,"Thread create failed for id %d\n", id);
+ exit(1);
+ }
+
+ return thread_id;
+}
+
+/* wait for a thread to exit */
+static int thread_join(pthread_t id)
+{
+ return pthread_join(id, NULL);
+}
+
+static void run_test(void)
+{
+ int i;
+ pthread_t *tids;
+ time_t started = 0;
+ unsigned warmup_count=0;
+ unsigned total;
+
+ /* get the filehandle for the mountpoint */
+ mfh = get_mount_fh("9.155.61.98", "/gpfs1/data");
+
+ tids = calloc(num_threads, sizeof(pthread_t));
+ io_count = calloc(num_threads, sizeof(unsigned));
+
+
+ for (i=0;i<num_threads;i++) {
+ tids[i] = thread_start(run_child, i);
+ }
+
+ while (1) {
+ int in_warmup=0;
+ time_t t = time(NULL);
+ total = 0;
+
+ sleep(1);
+ if (started == 0) {
+ in_warmup = 1;
+ started = t;
+ }
+ for (i=0;i<num_threads;i++) {
+ unsigned count = io_count[i];
+ printf("%6u ", count);
+ if (count == 0) {
+ started = 0;
+ }
+ total += count;
+ }
+ printf(" total: %6u ", total);
+ if (started != 0 && started != t) {
+ printf(" %3u seconds %.0f kbytes/s\n",
+ (unsigned)(t - started),
+ block_size*(total-warmup_count)/(1024.0*(t-started)));
+ } else {
+ printf("warmup\n");
+ }
+ if (started != 0) {
+ if (in_warmup) {
+ printf("Starting run\n");
+ warmup_count = total;
+ }
+ if (time(NULL) - started >= runtime) {
+ break;
+ }
+ }
+ }
+
+ run_finished = 1;
+ printf("Run finished - cleaning up\n");
+ for (i=0;i<num_threads;i++) {
+ thread_join(tids[i]);
+ printf("finished thread %d\n", i);
+ }
+
+ printf("Throughput %.0f kbytes/s\n",
+ block_size*(total-warmup_count)/(1024.0*runtime));
+}
+
+static void usage(void)
+{
+ printf("Usage: threadio <options> <filename>\n");
+ printf("Options:\n");
+ printf(" -b <size> block size\n");
+ printf(" -f <size> file size\n");
+ printf(" -n <number> number of threads\n");
+ printf(" -t <time> runtime in seconds\n");
+ printf(" -F <numios> fsync every numios blocks per thread\n");
+ printf(" -S use FILE_SYNC for writes\n");
+}
+
+
+int main(int argc, char * const argv[])
+{
+ int opt;
+
+ setlinebuf(stdout);
+
+ while ((opt = getopt(argc, argv, "b:f:n:t:1F:SD")) != -1) {
+ switch (opt) {
+ case 'b':
+ block_size = strtoul(optarg, NULL, 0);
+ break;
+ case 'f':
+ file_size = strtoull(optarg, NULL, 0);
+ break;
+ case 'n':
+ num_threads = strtoul(optarg, NULL, 0);
+ break;
+ case 't':
+ runtime = strtoul(optarg, NULL, 0);
+ break;
+ case 'S':
+ sync_io = true;
+ break;
+ case 'F':
+ flush_blocks = strtoul(optarg, NULL, 0);
+ break;
+ default:
+ printf("Invalid option '%c'\n", opt);
+ usage();
+ exit(1);
+ }
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ if (argc < 1) {
+ usage();
+ exit(1);
+ }
+
+ fname = argv[0];
+
+ srandom(time(NULL));
+
+ run_test();
+ return 0;
+}
--- /dev/null
+/*
+ simulate IO and thread pattern in ntap sio test
+
+ Copyright (C) Andrew Tridgell <tridge@samba.org> 2007
+
+ Released under the GNU GPL version 2 or later
+*/
+
+#define _GNU_SOURCE
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE64_SOURCE
+#define _LARGE_FILES
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <getopt.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <dirent.h>
+#include <pthread.h>
+#include <stdbool.h>
+
+static size_t block_size = 8192;
+static off_t file_size = 1024*1024*(1024LL);
+static unsigned num_threads = 1;
+static const char *fname;
+static volatile unsigned *io_count;
+static volatile int run_finished;
+static unsigned runtime = 20;
+static bool sync_io;
+static bool direct_io;
+static int flush_blocks;
+static bool one_fd;
+
+static int shared_fd;
+
+static int open_file(void)
+{
+ unsigned flags = O_RDWR|O_CREAT|O_LARGEFILE;
+ int fd;
+
+ if (sync_io) flags |= O_SYNC;
+ if (direct_io) flags |= O_DIRECT;
+ fd = open(fname, flags, 0644);
+ if (fd == -1) {
+ perror(fname);
+ exit(1);
+ }
+ return fd;
+}
+
+static void run_child(int id)
+{
+ unsigned num_blocks = file_size / block_size;
+ char *buf;
+ int fd;
+
+ if (!one_fd) {
+ fd = open_file();
+ } else {
+ fd = shared_fd;
+ }
+
+ buf = malloc(block_size);
+ memset(buf, 1, block_size);
+
+ srandom(id ^ random());
+
+ while (!run_finished) {
+ unsigned offset = random() % num_blocks;
+ if (pwrite(fd, buf, block_size, offset*(off_t)block_size) != block_size) {
+ perror("pwrite");
+ printf("pwrite failed!\n");
+ exit(1);
+ }
+ io_count[id]++;
+ if (flush_blocks && io_count[id] % flush_blocks == 0) {
+ fsync(fd);
+ }
+ }
+
+ close(fd);
+ return;
+}
+
+/*
+ create a thread with initial function fn(private)
+*/
+static pthread_t thread_start(void (*fn)(int), int id)
+{
+ pthread_t thread_id;
+ pthread_attr_t thread_attr;
+ int rc;
+ typedef void *(*thread_fn_t)(void *);
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, 0);
+ rc = pthread_create(&thread_id, &thread_attr, (thread_fn_t)fn, (void *)id);
+ pthread_attr_destroy(&thread_attr);
+
+ if (rc != 0) {
+ fprintf(stderr,"Thread create failed for id %d\n", id);
+ exit(1);
+ }
+
+ return thread_id;
+}
+
+/* wait for a thread to exit */
+static int thread_join(pthread_t id)
+{
+ return pthread_join(id, NULL);
+}
+
+
+static void run_test(void)
+{
+ int i;
+ pthread_t *tids;
+ time_t started = 0;
+ unsigned warmup_count=0;
+ unsigned total;
+
+ tids = calloc(num_threads, sizeof(pthread_t));
+ io_count = calloc(num_threads, sizeof(unsigned));
+
+ if (one_fd) {
+ shared_fd = open_file();
+ }
+
+
+ for (i=0;i<num_threads;i++) {
+ tids[i] = thread_start(run_child, i);
+ }
+
+ while (1) {
+ int in_warmup=0;
+ time_t t = time(NULL);
+ total = 0;
+
+ sleep(1);
+ if (started == 0) {
+ in_warmup = 1;
+ started = t;
+ }
+ for (i=0;i<num_threads;i++) {
+ unsigned count = io_count[i];
+ printf("%6u ", count);
+ if (count == 0) {
+ started = 0;
+ }
+ total += count;
+ }
+ printf(" total: %6u ", total);
+ if (started != 0 && started != t) {
+ printf(" %3u seconds %.0f kbytes/s\n",
+ (unsigned)(t - started),
+ block_size*(total-warmup_count)/(1024.0*(t-started)));
+ } else {
+ printf("warmup\n");
+ }
+ if (started != 0) {
+ if (in_warmup) {
+ printf("Starting run\n");
+ warmup_count = total;
+ }
+ if (time(NULL) - started >= runtime) {
+ break;
+ }
+ }
+ }
+
+ run_finished = 1;
+ printf("Run finished - cleaning up\n");
+ for (i=0;i<num_threads;i++) {
+ thread_join(tids[i]);
+ printf("finished thread %d\n", i);
+ }
+
+ printf("Throughput %.0f kbytes/s\n",
+ block_size*(total-warmup_count)/(1024.0*runtime));
+}
+
+static void usage(void)
+{
+ printf("Usage: threadio <options> <filename>\n");
+ printf("Options:\n");
+ printf(" -b <size> block size\n");
+ printf(" -f <size> file size\n");
+ printf(" -n <number> number of threads\n");
+ printf(" -t <time> runtime in seconds\n");
+ printf(" -F <numios> fsync every numios blocks per thread\n");
+ printf(" -S use O_SYNC on open\n");
+ printf(" -D use O_DIRECT on open\n");
+ printf(" -1 use one file descriptor for all threads\n");
+}
+
+
+int main(int argc, char * const argv[])
+{
+ int opt;
+
+ setlinebuf(stdout);
+
+ while ((opt = getopt(argc, argv, "b:f:n:t:1F:SD")) != -1) {
+ switch (opt) {
+ case 'b':
+ block_size = strtoul(optarg, NULL, 0);
+ break;
+ case 'f':
+ file_size = strtoull(optarg, NULL, 0);
+ break;
+ case 'n':
+ num_threads = strtoul(optarg, NULL, 0);
+ break;
+ case 't':
+ runtime = strtoul(optarg, NULL, 0);
+ break;
+ case 'S':
+ sync_io = true;
+ break;
+ case 'D':
+ direct_io = true;
+ break;
+ case 'F':
+ flush_blocks = strtoul(optarg, NULL, 0);
+ break;
+ case '1':
+ one_fd = true;
+ break;
+ default:
+ printf("Invalid option '%c'\n", opt);
+ usage();
+ exit(1);
+ }
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ if (argc < 1) {
+ usage();
+ exit(1);
+ }
+
+ fname = argv[0];
+
+ srandom(time(NULL));
+
+ run_test();
+ return 0;
+}
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <scsi/sg.h>
+
+#define SCSI_TIMEOUT 5000 /* ms */
+
+
+static struct timeval tp1,tp2;
+static size_t num_blocks = 1;
+static int do_sync = 0;
+static int do_random = 0;
+
+static void start_timer()
+{
+ gettimeofday(&tp1,NULL);
+}
+
+static double end_timer()
+{
+ gettimeofday(&tp2,NULL);
+ return((tp2.tv_sec - tp1.tv_sec) +
+ (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
+}
+
+const char *sensetable[16]={
+ "no sense",
+ "recovered error",
+ "not ready",
+ "medium error",
+ "hardware error",
+ "illegal request",
+ "unit attention",
+ "data protect",
+ "blank check",
+ "vendor specific",
+ "copy aborted",
+ "aboreted command",
+ "unknown",
+ "unknown",
+ "unknown",
+ "unknown"
+};
+
+void print_sense_data(unsigned char *sense, int sense_len)
+{
+ int i;
+ unsigned char asc, ascq;
+
+ printf("Device returned sense information\n");
+ if(sense[0]==0x70){
+ printf("filemark:%d eom:%d ili:%d sense-key:0x%02x (%s)\n",
+ !!(sense[2]&0x80),
+ !!(sense[2]&0x40),
+ !!(sense[2]&0x20),
+ sense[2]&0x0f,
+ sensetable[sense[2]&0x0f]);
+ printf("command specific info: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ sense[8],sense[9],sense[10],sense[11]);
+
+ asc=sense[12];
+ printf("additional sense code:0x%02x\n", asc);
+
+ ascq=sense[13];
+ printf("additional sense code qualifier:0x%02x\n", ascq);
+
+ printf("field replacable unit code:0x%02x\n", sense[14]);
+
+ if((asc==0x20)&&(ascq==0x00))
+ printf("INVALID COMMAND OPERATION CODE\n");
+ }
+
+ printf("Sense data:\n");
+ for(i=0;i<sense_len;i++){
+ printf("0x%02x ", sense[i]);
+ if((i%8)==7)printf("\n");
+ }
+ printf("\n");
+}
+
+int open_scsi_device(const char *dev)
+{
+ int fd, vers;
+
+ if((fd=open(dev, O_RDWR))<0){
+ printf("ERROR could not open device %s\n", dev);
+ return -1;
+ }
+ if ((ioctl(fd, SG_GET_VERSION_NUM, &vers) < 0) || (vers < 30000)) {
+ printf("/dev is not an sg device, or old sg driver\n");
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+int scsi_io(int fd, unsigned char *cdb, unsigned char cdb_size, int xfer_dir, unsigned char *data, unsigned int *data_size, unsigned char *sense, unsigned int *sense_len)
+{
+ sg_io_hdr_t io_hdr;
+
+ memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
+ io_hdr.interface_id = 'S';
+
+ /* CDB */
+ io_hdr.cmdp = cdb;
+ io_hdr.cmd_len = cdb_size;
+
+ /* Where to store the sense_data, if there was an error */
+ io_hdr.sbp = sense;
+ io_hdr.mx_sb_len = *sense_len;
+ *sense_len=0;
+
+ /* Transfer direction, either in or out. Linux does not yet
+ support bidirectional SCSI transfers ?
+ */
+ io_hdr.dxfer_direction = xfer_dir;
+
+ /* Where to store the DATA IN/OUT from the device and how big the
+ buffer is
+ */
+ io_hdr.dxferp = data;
+ io_hdr.dxfer_len = *data_size;
+
+ /* SCSI timeout in ms */
+ io_hdr.timeout = SCSI_TIMEOUT;
+
+
+ if(ioctl(fd, SG_IO, &io_hdr) < 0){
+ perror("SG_IO ioctl failed");
+ return -1;
+ }
+
+ /* now for the error processing */
+ if((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK){
+ if(io_hdr.sb_len_wr > 0){
+ *sense_len=io_hdr.sb_len_wr;
+ return 0;
+ }
+ }
+ if(io_hdr.masked_status){
+ printf("status=0x%x\n", io_hdr.status);
+ printf("masked_status=0x%x\n", io_hdr.masked_status);
+ return -2;
+ }
+ if(io_hdr.host_status){
+ printf("host_status=0x%x\n", io_hdr.host_status);
+ return -3;
+ }
+ if(io_hdr.driver_status){
+ printf("driver_status=0x%x\n", io_hdr.driver_status);
+ return -4;
+ }
+
+ return 0;
+}
+
+unsigned long read_uint32(unsigned char *data)
+{
+ unsigned long val;
+
+ val = data[0];
+ val <<= 8;
+ val |= data[1];
+ val <<= 8;
+ val |= data[2];
+ val <<= 8;
+ val |= data[3];
+
+ return val;
+}
+
+struct scsi_inquiry_data {
+ int peripheral_qualifier;
+#define SCSI_DEV_TYPE_SBC 0x00
+ int peripheral_device_type;
+ int removable;
+};
+
+struct scsi_inquiry_data *scsi_inquiry(int fd)
+{
+ unsigned char cdb[]={0x12,0,0,0,0,0};
+
+ unsigned int data_size=96;
+ unsigned char data[data_size];
+
+ unsigned int sense_len=32;
+ unsigned char sense[sense_len];
+
+ int res, alen, i;
+
+ static struct scsi_inquiry_data inq;
+
+ cdb[3]=(data_size>>8)&0xff;
+ cdb[4]=data_size&0xff;
+
+
+ res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, data, &data_size, sense, &sense_len);
+ if(res){
+ printf("SCSI_IO failed\n");
+ return NULL;
+ }
+ if(sense_len){
+ print_sense_data(sense, sense_len);
+ return NULL;
+ }
+
+ /* Peripheral Qualifier */
+ inq.peripheral_qualifier = data[0]&0xe0;
+
+ /* Peripheral Device Type */
+ inq.peripheral_device_type = data[0]&0x1f;
+
+
+ /* RMB */
+ inq.removable = data[1]&0x80;
+
+ return &inq;
+}
+
+
+struct scsi_capacity_data {
+ unsigned long blocks;
+ unsigned long blocksize;
+};
+
+struct scsi_capacity_data *scsi_read_capacity10(int fd)
+{
+ unsigned char cdb[]={0x25,0,0,0,0,0,0,0,0,0};
+
+ unsigned int data_size=96;
+ unsigned char data[data_size];
+
+ unsigned int sense_len=32;
+ unsigned char sense[sense_len];
+
+ int res, alen, i;
+ static struct scsi_capacity_data capacity;
+
+ res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, data, &data_size, sense, &sense_len);
+ if(res){
+ printf("SCSI_IO failed\n");
+ return NULL;
+ }
+ if(sense_len){
+ print_sense_data(sense, sense_len);
+ return NULL;
+ }
+
+ capacity.blocks = read_uint32(&data[0]);
+ capacity.blocksize = read_uint32(&data[4]);
+
+ return &capacity;
+}
+
+#define READ_FUA 0x04
+#define REAF_FUA_NV 0x02
+/* If READ_FUA is not set the device may return data from cache
+ if it is set the device must read the data from medium
+*/
+unsigned char *scsi_read10(int fd, unsigned long lba, unsigned short len, unsigned char fua)
+{
+ unsigned char cdb[]={0x28,0,0,0,0,0,0,0,0,0};
+
+ unsigned int data_size=len*512;
+
+ unsigned int sense_len=32;
+ unsigned char sense[sense_len];
+ int res, alen, i;
+ char *buf;
+
+ buf = malloc(len * 512);
+ if (!buf) {
+ printf("Malloc of %d failed\n", len * 512);
+ exit(1);
+ }
+ /* allow device to return data from cache or force a read from the medium ?*/
+ cdb[1] = fua;
+
+
+ /* lba */
+ cdb[2] = (lba>>24)&0xff;
+ cdb[3] = (lba>>16)&0xff;
+ cdb[4] = (lba>> 8)&0xff;
+ cdb[5] = (lba )&0xff;
+
+ /* number of blocks */
+ cdb[7] = (len>>8)&0xff;
+ cdb[8] = (len )&0xff;
+
+ res=scsi_io(fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, buf, &data_size, sense, &sense_len);
+ if(res){
+ printf("SCSI_IO failed\n");
+ return NULL;
+ }
+ if(sense_len){
+ print_sense_data(sense, sense_len);
+ return NULL;
+ }
+
+ return buf;
+}
+
+static void read_disk(int fd, struct scsi_capacity_data *capacity)
+{
+ static double total, thisrun;
+ unsigned char *buf;
+ unsigned long offset = 0;
+
+ total = 0;
+ while (1) {
+ if (do_random) {
+ offset = random() % (capacity->blocks - num_blocks);
+ } else {
+ offset += num_blocks;
+ }
+ buf = scsi_read10(fd, offset, num_blocks, do_sync);
+ if (buf == NULL) {
+ printf("read failure\n");
+ exit(0);
+ }
+ free(buf);
+
+ total += num_blocks*512;
+ thisrun += num_blocks*512;
+ if (end_timer() >= 1.0) {
+ printf("%d MB %g MB/sec\n",
+ (int)(total/1.0e6),
+ (thisrun*1.0e-6)/end_timer());
+ start_timer();
+ thisrun = 0;
+ }
+ }
+}
+
+
+static void usage(void)
+{
+ printf("\n" \
+"readfiles - reads from a list of files, showing read throughput\n" \
+"\n" \
+"Usage: readfiles [options] <files>\n" \
+"\n" \
+"Options:\n" \
+" -B size number of 512-byte blocks per i/o\n" \
+" -S force device to bypass any read cache\n" \
+" -R random read\n" \
+"");
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ extern char *optarg;
+ extern int optind;
+ int c;
+ int fd;
+ struct scsi_inquiry_data *inq_data;
+ struct scsi_capacity_data *capacity;
+
+
+ while ((c = getopt(argc, argv, "B:h:SR")) != -1) {
+ switch (c) {
+ case 'B':
+ num_blocks = strtol(optarg, NULL, 0);
+ break;
+ case 'S':
+ do_sync = READ_FUA;
+ break;
+ case 'R':
+ do_random = 1;
+ break;
+ case 'h':
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0) {
+ usage();
+ exit(1);
+ }
+
+ /* open the scsi device */
+ fd = open_scsi_device(argv[0]);
+ if (fd == -1) {
+ perror(argv[0]);
+ exit(10);
+ }
+
+ /* read inq data and make sure it is a DISK device so that we will
+ use the correct scsi protocol later
+ */
+ inq_data = scsi_inquiry(fd);
+ if (inq_data == NULL) {
+ printf("Failed to read INQ data from device\n");
+ exit(10);
+ }
+ if (inq_data->peripheral_device_type != SCSI_DEV_TYPE_SBC) {
+ printf("Not a SCSI disk\n");
+ exit(10);
+ }
+
+ /* get size of the device in number of 512 byte blocks */
+ capacity = scsi_read_capacity10(fd);
+ if (capacity == NULL) {
+ printf("Failed to read capacity from device\n");
+ exit(10);
+ }
+
+
+ srandom(time(NULL));
+ start_timer();
+
+ read_disk(fd, capacity);
+
+ return 0;
+}
+