[sheepdog] [PATCH v3 02/12] sheep: introduce NFSv3 transport

Liu Yuan namei.unix at gmail.com
Wed Jan 29 09:26:16 CET 2014


We use glibc's RPC to build NFS daemon and rpcgen for NFS marshing and
unmarshing.

Signed-off-by: Liu Yuan <namei.unix at gmail.com>
---
 configure.ac       |   12 +
 sheep/Makefile.am  |    7 +-
 sheep/nfs/nfs.c    |  125 ++++
 sheep/nfs/nfs.h    | 1134 +++++++++++++++++++++++++++++++++++
 sheep/nfs/nfsd.c   |  152 +++++
 sheep/nfs/xdr.c    | 1661 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 sheep/sheep.c      |    4 +
 sheep/sheep_priv.h |   11 +-
 8 files changed, 3104 insertions(+), 2 deletions(-)
 create mode 100644 sheep/nfs/nfs.c
 create mode 100644 sheep/nfs/nfs.h
 create mode 100644 sheep/nfs/nfsd.c
 create mode 100644 sheep/nfs/xdr.c

diff --git a/configure.ac b/configure.ac
index 949d339..a3abb7b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -250,6 +250,11 @@ AC_ARG_ENABLE([http],
 	[ enable_http="no" ],)
 AM_CONDITIONAL(BUILD_HTTP, test x$enable_http = xyes)
 
+AC_ARG_ENABLE([nfs],
+	[ --enable-nfs : enable nfs server service (default no) ],,
+	[ enable_nfs="no" ],)
+AM_CONDITIONAL(BUILD_NFS, test x$enable_nfs = xyes)
+
 CP=cp
 OS_LDL="-ldl"
 case "$host_os" in
@@ -355,6 +360,13 @@ if test "x${enable_http}" = xyes; then
 	PACKAGE_FEATURES="$PACKAGE_FEATURES http"
 fi
 
+if test "x${enable_nfs}" = xyes; then
+	AC_CHECK_HEADERS([rpc/rpc.h],,
+		AC_MSG_ERROR(rpc.h header not found))
+	AC_DEFINE_UNQUOTED(HAVE_NFS, 1, [have nfs])
+	PACKAGE_FEATURES="$PACKAGE_FEATURES nfs"
+fi
+
 # extra warnings
 EXTRA_WARNINGS=""
 
diff --git a/sheep/Makefile.am b/sheep/Makefile.am
index 5fff697..b964f5f 100644
--- a/sheep/Makefile.am
+++ b/sheep/Makefile.am
@@ -33,6 +33,11 @@ if BUILD_HTTP
 sheep_SOURCES		+= http/http.c http/kv.c http/s3.c http/swift.c \
 			   http/oalloc.c
 endif
+
+if BUILD_NFS
+sheep_SOURCES		+= nfs/nfsd.c nfs/nfs.c nfs/xdr.c
+endif
+
 if BUILD_COROSYNC
 sheep_SOURCES		+= cluster/corosync.c
 endif
@@ -53,7 +58,7 @@ sheep_LDADD	  	= ../lib/libsheepdog.a -lpthread -lm\
 sheep_DEPENDENCIES	= ../lib/libsheepdog.a
 
 
-noinst_HEADERS		= sheep_priv.h cluster.h http/http.h trace/trace.h
+noinst_HEADERS		= sheep_priv.h cluster.h http/http.h trace/trace.h nfs/nfs.h
 
 EXTRA_DIST		= 
 
diff --git a/sheep/nfs/nfs.c b/sheep/nfs/nfs.c
new file mode 100644
index 0000000..b352bac
--- /dev/null
+++ b/sheep/nfs/nfs.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2014 Taobao Inc.
+ *
+ * Liu Yuan <namei.unix at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <nfs://www.gnu.org/licenses/>.
+ */
+
+#include "sheep_priv.h"
+#include "nfs.h"
+
+void *nfs3_null(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_getattr(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_setattr(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_lookup(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_access(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_readlink(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_read(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_write(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_create(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_mkdir(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_symlink(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_mknod(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_remove(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_rmdir(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_rename(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_link(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_readdir(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_readdirplus(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_fsstat(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_fsinfo(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_pathconf(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
+
+void *nfs3_commit(struct svc_req *req, struct nfs_arg *argp)
+{
+	return NULL;
+}
diff --git a/sheep/nfs/nfs.h b/sheep/nfs/nfs.h
new file mode 100644
index 0000000..c4bc703
--- /dev/null
+++ b/sheep/nfs/nfs.h
@@ -0,0 +1,1134 @@
+#ifndef _NFS_H
+#define _NFS_H
+
+#include <rpc/rpc.h>
+
+#define NFS_PORT 2049
+#define NFS_MAXDATA 8192
+#define NFS_MAXPATHLEN 1024
+#define NFS_MAXNAMLEN 255
+#define NFS_FHSIZE 32
+#define NFS_COOKIESIZE 4
+#define NFS_FIFO_DEV -1
+#define NFSMODE_FMT 0170000
+#define NFSMODE_DIR 0040000
+#define NFSMODE_CHR 0020000
+#define NFSMODE_BLK 0060000
+#define NFSMODE_REG 0100000
+#define NFSMODE_LNK 0120000
+#define NFSMODE_SOCK 0140000
+#define NFSMODE_FIFO 0010000
+
+#define NFS3_FHSIZE 64
+#define NFS3_COOKIEVERFSIZE 8
+#define NFS3_CREATEVERFSIZE 8
+#define NFS3_WRITEVERFSIZE 8
+
+typedef u_quad_t uint64;
+
+typedef quad_t int64;
+
+typedef u_long uint32;
+
+typedef long int32;
+
+typedef char *filename3;
+
+typedef char *nfspath3;
+
+typedef uint64 fileid3;
+
+typedef uint64 cookie3;
+
+typedef char cookieverf3[NFS3_COOKIEVERFSIZE];
+
+typedef char createverf3[NFS3_CREATEVERFSIZE];
+
+typedef char writeverf3[NFS3_WRITEVERFSIZE];
+
+typedef uint32 uid3;
+
+typedef uint32 gid3;
+
+typedef uint64 size3;
+
+typedef uint64 offset3;
+
+typedef uint32 mode3;
+
+typedef uint32 count3;
+
+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 ftype3 {
+	NF3REG = 1,
+	NF3DIR = 2,
+	NF3BLK = 3,
+	NF3CHR = 4,
+	NF3LNK = 5,
+	NF3SOCK = 6,
+	NF3FIFO = 7,
+};
+typedef enum ftype3 ftype3;
+
+struct specdata3 {
+	uint32 specdata1;
+	uint32 specdata2;
+};
+typedef struct specdata3 specdata3;
+
+struct nfs_fh3 {
+	struct {
+		u_int data_len;
+		char *data_val;
+	} data;
+};
+typedef struct nfs_fh3 nfs_fh3;
+
+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;
+
+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 post_op_fh3 {
+	bool_t handle_follows;
+	union {
+		nfs_fh3 handle;
+	} post_op_fh3_u;
+};
+typedef struct post_op_fh3 post_op_fh3;
+
+enum time_how {
+	DONT_CHANGE = 0,
+	SET_TO_SERVER_TIME = 1,
+	SET_TO_CLIENT_TIME = 2,
+};
+typedef enum time_how time_how;
+
+struct set_mode3 {
+	bool_t set_it;
+	union {
+		mode3 mode;
+	} set_mode3_u;
+};
+typedef struct set_mode3 set_mode3;
+
+struct set_uid3 {
+	bool_t set_it;
+	union {
+		uid3 uid;
+	} set_uid3_u;
+};
+typedef struct set_uid3 set_uid3;
+
+struct set_gid3 {
+	bool_t set_it;
+	union {
+		gid3 gid;
+	} set_gid3_u;
+};
+typedef struct set_gid3 set_gid3;
+
+struct set_size3 {
+	bool_t set_it;
+	union {
+		size3 size;
+	} set_size3_u;
+};
+typedef struct set_size3 set_size3;
+
+struct set_atime {
+	time_how set_it;
+	union {
+		nfstime3 atime;
+	} set_atime_u;
+};
+typedef struct set_atime set_atime;
+
+struct set_mtime {
+	time_how set_it;
+	union {
+		nfstime3 mtime;
+	} set_mtime_u;
+};
+typedef struct set_mtime set_mtime;
+
+struct sattr3 {
+	set_mode3 mode;
+	set_uid3 uid;
+	set_gid3 gid;
+	set_size3 size;
+	set_atime atime;
+	set_mtime mtime;
+};
+typedef struct sattr3 sattr3;
+
+struct diropargs3 {
+	nfs_fh3 dir;
+	filename3 name;
+};
+typedef struct diropargs3 diropargs3;
+
+struct GETATTR3args {
+	nfs_fh3 object;
+};
+typedef struct GETATTR3args GETATTR3args;
+
+struct GETATTR3resok {
+	fattr3 obj_attributes;
+};
+typedef struct GETATTR3resok GETATTR3resok;
+
+struct GETATTR3res {
+	nfsstat3 status;
+	union {
+		GETATTR3resok resok;
+	} GETATTR3res_u;
+};
+typedef struct GETATTR3res GETATTR3res;
+
+struct sattrguard3 {
+	bool_t check;
+	union {
+		nfstime3 obj_ctime;
+	} sattrguard3_u;
+};
+typedef struct sattrguard3 sattrguard3;
+
+struct SETATTR3args {
+	nfs_fh3 object;
+	sattr3 new_attributes;
+	sattrguard3 guard;
+};
+typedef struct SETATTR3args SETATTR3args;
+
+struct SETATTR3resok {
+	wcc_data obj_wcc;
+};
+typedef struct SETATTR3resok SETATTR3resok;
+
+struct SETATTR3resfail {
+	wcc_data obj_wcc;
+};
+typedef struct SETATTR3resfail SETATTR3resfail;
+
+struct SETATTR3res {
+	nfsstat3 status;
+	union {
+		SETATTR3resok resok;
+		SETATTR3resfail resfail;
+	} SETATTR3res_u;
+};
+typedef struct SETATTR3res SETATTR3res;
+
+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;
+#define ACCESS3_READ 0x0001
+#define ACCESS3_LOOKUP 0x0002
+#define ACCESS3_MODIFY 0x0004
+#define ACCESS3_EXTEND 0x0008
+#define ACCESS3_DELETE 0x0010
+#define ACCESS3_EXECUTE 0x0020
+
+struct ACCESS3args {
+	nfs_fh3 object;
+	uint32 access;
+};
+typedef struct ACCESS3args ACCESS3args;
+
+struct ACCESS3resok {
+	post_op_attr obj_attributes;
+	uint32 access;
+};
+typedef struct ACCESS3resok ACCESS3resok;
+
+struct ACCESS3resfail {
+	post_op_attr obj_attributes;
+};
+typedef struct ACCESS3resfail ACCESS3resfail;
+
+struct ACCESS3res {
+	nfsstat3 status;
+	union {
+		ACCESS3resok resok;
+		ACCESS3resfail resfail;
+	} ACCESS3res_u;
+};
+typedef struct ACCESS3res ACCESS3res;
+
+struct READLINK3args {
+	nfs_fh3 symlink;
+};
+typedef struct READLINK3args READLINK3args;
+
+struct READLINK3resok {
+	post_op_attr symlink_attributes;
+	nfspath3 data;
+};
+typedef struct READLINK3resok READLINK3resok;
+
+struct READLINK3resfail {
+	post_op_attr symlink_attributes;
+};
+typedef struct READLINK3resfail READLINK3resfail;
+
+struct READLINK3res {
+	nfsstat3 status;
+	union {
+		READLINK3resok resok;
+		READLINK3resfail resfail;
+	} READLINK3res_u;
+};
+typedef struct READLINK3res READLINK3res;
+
+struct READ3args {
+	nfs_fh3 file;
+	offset3 offset;
+	count3 count;
+};
+typedef struct READ3args READ3args;
+
+struct READ3resok {
+	post_op_attr file_attributes;
+	count3 count;
+	bool_t eof;
+	struct {
+		u_int data_len;
+		char *data_val;
+	} data;
+};
+typedef struct READ3resok READ3resok;
+
+struct READ3resfail {
+	post_op_attr file_attributes;
+};
+typedef struct READ3resfail READ3resfail;
+
+struct READ3res {
+	nfsstat3 status;
+	union {
+		READ3resok resok;
+		READ3resfail resfail;
+	} READ3res_u;
+};
+typedef struct READ3res READ3res;
+
+enum stable_how {
+	UNSTABLE = 0,
+	DATA_SYNC = 1,
+	FILE_SYNC = 2,
+};
+typedef enum stable_how stable_how;
+
+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;
+
+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;
+
+enum createmode3 {
+	UNCHECKED = 0,
+	GUARDED = 1,
+	EXCLUSIVE = 2,
+};
+typedef enum createmode3 createmode3;
+
+struct createhow3 {
+	createmode3 mode;
+	union {
+		sattr3 obj_attributes;
+		createverf3 verf;
+	} createhow3_u;
+};
+typedef struct createhow3 createhow3;
+
+struct CREATE3args {
+	diropargs3 where;
+	createhow3 how;
+};
+typedef struct CREATE3args CREATE3args;
+
+struct CREATE3resok {
+	post_op_fh3 obj;
+	post_op_attr obj_attributes;
+	wcc_data dir_wcc;
+};
+typedef struct CREATE3resok CREATE3resok;
+
+struct CREATE3resfail {
+	wcc_data dir_wcc;
+};
+typedef struct CREATE3resfail CREATE3resfail;
+
+struct CREATE3res {
+	nfsstat3 status;
+	union {
+		CREATE3resok resok;
+		CREATE3resfail resfail;
+	} CREATE3res_u;
+};
+typedef struct CREATE3res CREATE3res;
+
+struct MKDIR3args {
+	diropargs3 where;
+	sattr3 attributes;
+};
+typedef struct MKDIR3args MKDIR3args;
+
+struct MKDIR3resok {
+	post_op_fh3 obj;
+	post_op_attr obj_attributes;
+	wcc_data dir_wcc;
+};
+typedef struct MKDIR3resok MKDIR3resok;
+
+struct MKDIR3resfail {
+	wcc_data dir_wcc;
+};
+typedef struct MKDIR3resfail MKDIR3resfail;
+
+struct MKDIR3res {
+	nfsstat3 status;
+	union {
+		MKDIR3resok resok;
+		MKDIR3resfail resfail;
+	} MKDIR3res_u;
+};
+typedef struct MKDIR3res MKDIR3res;
+
+struct symlinkdata3 {
+	sattr3 symlink_attributes;
+	nfspath3 symlink_data;
+};
+typedef struct symlinkdata3 symlinkdata3;
+
+struct SYMLINK3args {
+	diropargs3 where;
+	symlinkdata3 symlink;
+};
+typedef struct SYMLINK3args SYMLINK3args;
+
+struct SYMLINK3resok {
+	post_op_fh3 obj;
+	post_op_attr obj_attributes;
+	wcc_data dir_wcc;
+};
+typedef struct SYMLINK3resok SYMLINK3resok;
+
+struct SYMLINK3resfail {
+	wcc_data dir_wcc;
+};
+typedef struct SYMLINK3resfail SYMLINK3resfail;
+
+struct SYMLINK3res {
+	nfsstat3 status;
+	union {
+		SYMLINK3resok resok;
+		SYMLINK3resfail resfail;
+	} SYMLINK3res_u;
+};
+typedef struct SYMLINK3res SYMLINK3res;
+
+struct devicedata3 {
+	sattr3 dev_attributes;
+	specdata3 spec;
+};
+typedef struct devicedata3 devicedata3;
+
+struct mknoddata3 {
+	ftype3 type;
+	union {
+		devicedata3 device;
+		sattr3 pipe_attributes;
+	} mknoddata3_u;
+};
+typedef struct mknoddata3 mknoddata3;
+
+struct MKNOD3args {
+	diropargs3 where;
+	mknoddata3 what;
+};
+typedef struct MKNOD3args MKNOD3args;
+
+struct MKNOD3resok {
+	post_op_fh3 obj;
+	post_op_attr obj_attributes;
+	wcc_data dir_wcc;
+};
+typedef struct MKNOD3resok MKNOD3resok;
+
+struct MKNOD3resfail {
+	wcc_data dir_wcc;
+};
+typedef struct MKNOD3resfail MKNOD3resfail;
+
+struct MKNOD3res {
+	nfsstat3 status;
+	union {
+		MKNOD3resok resok;
+		MKNOD3resfail resfail;
+	} MKNOD3res_u;
+};
+typedef struct MKNOD3res MKNOD3res;
+
+struct REMOVE3args {
+	diropargs3 object;
+};
+typedef struct REMOVE3args REMOVE3args;
+
+struct REMOVE3resok {
+	wcc_data dir_wcc;
+};
+typedef struct REMOVE3resok REMOVE3resok;
+
+struct REMOVE3resfail {
+	wcc_data dir_wcc;
+};
+typedef struct REMOVE3resfail REMOVE3resfail;
+
+struct REMOVE3res {
+	nfsstat3 status;
+	union {
+		REMOVE3resok resok;
+		REMOVE3resfail resfail;
+	} REMOVE3res_u;
+};
+typedef struct REMOVE3res REMOVE3res;
+
+struct RMDIR3args {
+	diropargs3 object;
+};
+typedef struct RMDIR3args RMDIR3args;
+
+struct RMDIR3resok {
+	wcc_data dir_wcc;
+};
+typedef struct RMDIR3resok RMDIR3resok;
+
+struct RMDIR3resfail {
+	wcc_data dir_wcc;
+};
+typedef struct RMDIR3resfail RMDIR3resfail;
+
+struct RMDIR3res {
+	nfsstat3 status;
+	union {
+		RMDIR3resok resok;
+		RMDIR3resfail resfail;
+	} RMDIR3res_u;
+};
+typedef struct RMDIR3res RMDIR3res;
+
+struct RENAME3args {
+	diropargs3 from;
+	diropargs3 to;
+};
+typedef struct RENAME3args RENAME3args;
+
+struct RENAME3resok {
+	wcc_data fromdir_wcc;
+	wcc_data todir_wcc;
+};
+typedef struct RENAME3resok RENAME3resok;
+
+struct RENAME3resfail {
+	wcc_data fromdir_wcc;
+	wcc_data todir_wcc;
+};
+typedef struct RENAME3resfail RENAME3resfail;
+
+struct RENAME3res {
+	nfsstat3 status;
+	union {
+		RENAME3resok resok;
+		RENAME3resfail resfail;
+	} RENAME3res_u;
+};
+typedef struct RENAME3res RENAME3res;
+
+struct LINK3args {
+	nfs_fh3 file;
+	diropargs3 link;
+};
+typedef struct LINK3args LINK3args;
+
+struct LINK3resok {
+	post_op_attr file_attributes;
+	wcc_data linkdir_wcc;
+};
+typedef struct LINK3resok LINK3resok;
+
+struct LINK3resfail {
+	post_op_attr file_attributes;
+	wcc_data linkdir_wcc;
+};
+typedef struct LINK3resfail LINK3resfail;
+
+struct LINK3res {
+	nfsstat3 status;
+	union {
+		LINK3resok resok;
+		LINK3resfail resfail;
+	} LINK3res_u;
+};
+typedef struct LINK3res LINK3res;
+
+struct READDIR3args {
+	nfs_fh3 dir;
+	cookie3 cookie;
+	cookieverf3 cookieverf;
+	count3 count;
+};
+typedef struct READDIR3args READDIR3args;
+
+struct entry3 {
+	fileid3 fileid;
+	filename3 name;
+	cookie3 cookie;
+	struct entry3 *nextentry;
+};
+typedef struct entry3 entry3;
+
+struct dirlist3 {
+	entry3 *entries;
+	bool_t eof;
+};
+typedef struct dirlist3 dirlist3;
+
+struct READDIR3resok {
+	post_op_attr dir_attributes;
+	cookieverf3 cookieverf;
+	dirlist3 reply;
+};
+typedef struct READDIR3resok READDIR3resok;
+
+struct READDIR3resfail {
+	post_op_attr dir_attributes;
+};
+typedef struct READDIR3resfail READDIR3resfail;
+
+struct READDIR3res {
+	nfsstat3 status;
+	union {
+		READDIR3resok resok;
+		READDIR3resfail resfail;
+	} READDIR3res_u;
+};
+typedef struct READDIR3res READDIR3res;
+
+struct READDIRPLUS3args {
+	nfs_fh3 dir;
+	cookie3 cookie;
+	cookieverf3 cookieverf;
+	count3 dircount;
+	count3 maxcount;
+};
+typedef struct READDIRPLUS3args READDIRPLUS3args;
+
+struct entryplus3 {
+	fileid3 fileid;
+	filename3 name;
+	cookie3 cookie;
+	post_op_attr name_attributes;
+	post_op_fh3 name_handle;
+	struct entryplus3 *nextentry;
+};
+typedef struct entryplus3 entryplus3;
+
+struct dirlistplus3 {
+	entryplus3 *entries;
+	bool_t eof;
+};
+typedef struct dirlistplus3 dirlistplus3;
+
+struct READDIRPLUS3resok {
+	post_op_attr dir_attributes;
+	cookieverf3 cookieverf;
+	dirlistplus3 reply;
+};
+typedef struct READDIRPLUS3resok READDIRPLUS3resok;
+
+struct READDIRPLUS3resfail {
+	post_op_attr dir_attributes;
+};
+typedef struct READDIRPLUS3resfail READDIRPLUS3resfail;
+
+struct READDIRPLUS3res {
+	nfsstat3 status;
+	union {
+		READDIRPLUS3resok resok;
+		READDIRPLUS3resfail resfail;
+	} READDIRPLUS3res_u;
+};
+typedef struct READDIRPLUS3res READDIRPLUS3res;
+
+struct FSSTAT3args {
+	nfs_fh3 fsroot;
+};
+typedef struct FSSTAT3args FSSTAT3args;
+
+struct FSSTAT3resok {
+	post_op_attr obj_attributes;
+	size3 tbytes;
+	size3 fbytes;
+	size3 abytes;
+	size3 tfiles;
+	size3 ffiles;
+	size3 afiles;
+	uint32 invarsec;
+};
+typedef struct FSSTAT3resok FSSTAT3resok;
+
+struct FSSTAT3resfail {
+	post_op_attr obj_attributes;
+};
+typedef struct FSSTAT3resfail FSSTAT3resfail;
+
+struct FSSTAT3res {
+	nfsstat3 status;
+	union {
+		FSSTAT3resok resok;
+		FSSTAT3resfail resfail;
+	} FSSTAT3res_u;
+};
+typedef struct FSSTAT3res FSSTAT3res;
+#define FSF3_LINK 0x0001
+#define FSF3_SYMLINK 0x0002
+#define FSF3_HOMOGENEOUS 0x0008
+#define FSF3_CANSETTIME 0x0010
+
+struct FSINFO3args {
+	nfs_fh3 fsroot;
+};
+typedef struct FSINFO3args FSINFO3args;
+
+struct FSINFO3resok {
+	post_op_attr obj_attributes;
+	uint32 rtmax;
+	uint32 rtpref;
+	uint32 rtmult;
+	uint32 wtmax;
+	uint32 wtpref;
+	uint32 wtmult;
+	uint32 dtpref;
+	size3 maxfilesize;
+	nfstime3 time_delta;
+	uint32 properties;
+};
+typedef struct FSINFO3resok FSINFO3resok;
+
+struct FSINFO3resfail {
+	post_op_attr obj_attributes;
+};
+typedef struct FSINFO3resfail FSINFO3resfail;
+
+struct FSINFO3res {
+	nfsstat3 status;
+	union {
+		FSINFO3resok resok;
+		FSINFO3resfail resfail;
+	} FSINFO3res_u;
+};
+typedef struct FSINFO3res FSINFO3res;
+
+struct PATHCONF3args {
+	nfs_fh3 object;
+};
+typedef struct PATHCONF3args PATHCONF3args;
+
+struct PATHCONF3resok {
+	post_op_attr obj_attributes;
+	uint32 linkmax;
+	uint32 name_max;
+	bool_t no_trunc;
+	bool_t chown_restricted;
+	bool_t case_insensitive;
+	bool_t case_preserving;
+};
+typedef struct PATHCONF3resok PATHCONF3resok;
+
+struct PATHCONF3resfail {
+	post_op_attr obj_attributes;
+};
+typedef struct PATHCONF3resfail PATHCONF3resfail;
+
+struct PATHCONF3res {
+	nfsstat3 status;
+	union {
+		PATHCONF3resok resok;
+		PATHCONF3resfail resfail;
+	} PATHCONF3res_u;
+};
+typedef struct PATHCONF3res PATHCONF3res;
+
+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_V4 4
+#define NFS_V3 3
+#define NFS_V2 2
+
+#define NFSPROC3_NULL 0
+#define NFSPROC3_GETATTR 1
+#define NFSPROC3_SETATTR 2
+#define NFSPROC3_LOOKUP 3
+#define NFSPROC3_ACCESS 4
+#define NFSPROC3_READLINK 5
+#define NFSPROC3_READ 6
+#define NFSPROC3_WRITE 7
+#define NFSPROC3_CREATE 8
+#define NFSPROC3_MKDIR 9
+#define NFSPROC3_SYMLINK 10
+#define NFSPROC3_MKNOD 11
+#define NFSPROC3_REMOVE 12
+#define NFSPROC3_RMDIR 13
+#define NFSPROC3_RENAME 14
+#define NFSPROC3_LINK 15
+#define NFSPROC3_READDIR 16
+#define NFSPROC3_READDIRPLUS 17
+#define NFSPROC3_FSSTAT 18
+#define NFSPROC3_FSINFO 19
+#define NFSPROC3_PATHCONF 20
+#define NFSPROC3_COMMIT 21
+
+struct nfs_arg {
+	union {
+		GETATTR3args getattr;
+		SETATTR3args setattr;
+		LOOKUP3args lookup;
+		ACCESS3args access;
+		READLINK3args readlink;
+		READ3args read;
+		WRITE3args write;
+		CREATE3args create;
+		MKDIR3args mkdir;
+		SYMLINK3args symlink;
+		MKNOD3args mknod;
+		REMOVE3args remove;
+		RMDIR3args rmdir;
+		RENAME3args rename;
+		LINK3args link;
+		READDIR3args readdir;
+		READDIRPLUS3args readdirplus;
+		FSSTAT3args fsstat;
+		FSINFO3args fsinfo;
+		PATHCONF3args pathconf;
+		COMMIT3args commit;
+	};
+};
+
+extern void *nfs3_null(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_getattr(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_setattr(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_lookup(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_access(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_readlink(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_read(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_write(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_create(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_mkdir(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_symlink(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_mknod(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_remove(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_rmdir(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_rename(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_link(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_readdir(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_readdirplus(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_fsstat(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_fsinfo(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_pathconf(struct svc_req *req, struct nfs_arg *argp);
+extern void *nfs3_commit(struct svc_req *req, struct nfs_arg *argp);
+
+/* the xdr functions */
+
+extern bool_t xdr_uint64(XDR *, uint64*);
+extern bool_t xdr_int64(XDR *, int64*);
+extern bool_t xdr_uint32(XDR *, uint32*);
+extern bool_t xdr_int32(XDR *, int32*);
+extern bool_t xdr_filename3(XDR *, filename3*);
+extern bool_t xdr_nfspath3(XDR *, nfspath3*);
+extern bool_t xdr_fileid3(XDR *, fileid3*);
+extern bool_t xdr_cookie3(XDR *, cookie3*);
+extern bool_t xdr_cookieverf3(XDR *, cookieverf3);
+extern bool_t xdr_createverf3(XDR *, createverf3);
+extern bool_t xdr_writeverf3(XDR *, writeverf3);
+extern bool_t xdr_uid3(XDR *, uid3*);
+extern bool_t xdr_gid3(XDR *, gid3*);
+extern bool_t xdr_size3(XDR *, size3*);
+extern bool_t xdr_offset3(XDR *, offset3*);
+extern bool_t xdr_mode3(XDR *, mode3*);
+extern bool_t xdr_count3(XDR *, count3*);
+extern bool_t xdr_nfsstat3(XDR *, nfsstat3*);
+extern bool_t xdr_ftype3(XDR *, ftype3*);
+extern bool_t xdr_specdata3(XDR *, specdata3*);
+extern bool_t xdr_nfs_fh3(XDR *, nfs_fh3*);
+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_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_post_op_fh3(XDR *, post_op_fh3*);
+extern bool_t xdr_time_how(XDR *, time_how*);
+extern bool_t xdr_set_mode3(XDR *, set_mode3*);
+extern bool_t xdr_set_uid3(XDR *, set_uid3*);
+extern bool_t xdr_set_gid3(XDR *, set_gid3*);
+extern bool_t xdr_set_size3(XDR *, set_size3*);
+extern bool_t xdr_set_atime(XDR *, set_atime*);
+extern bool_t xdr_set_mtime(XDR *, set_mtime*);
+extern bool_t xdr_sattr3(XDR *, sattr3*);
+extern bool_t xdr_diropargs3(XDR *, diropargs3*);
+extern bool_t xdr_getattr_args(XDR *, GETATTR3args*);
+extern bool_t xdr_getattr_resok(XDR *, GETATTR3resok*);
+extern bool_t xdr_getattr_res(XDR *, GETATTR3res*);
+extern bool_t xdr_sattrguard3(XDR *, sattrguard3*);
+extern bool_t xdr_setattr_args(XDR *, SETATTR3args*);
+extern bool_t xdr_setattr_resok(XDR *, SETATTR3resok*);
+extern bool_t xdr_setattr_resfail(XDR *, SETATTR3resfail*);
+extern bool_t xdr_setattr_res(XDR *, SETATTR3res*);
+extern bool_t xdr_lookup_args(XDR *, LOOKUP3args*);
+extern bool_t xdr_lookup_resok(XDR *, LOOKUP3resok*);
+extern bool_t xdr_lookup_resfail(XDR *, LOOKUP3resfail*);
+extern bool_t xdr_lookup_res(XDR *, LOOKUP3res*);
+extern bool_t xdr_access_args(XDR *, ACCESS3args*);
+extern bool_t xdr_access_resok(XDR *, ACCESS3resok*);
+extern bool_t xdr_access_resfail(XDR *, ACCESS3resfail*);
+extern bool_t xdr_access_res(XDR *, ACCESS3res*);
+extern bool_t xdr_readlink_args(XDR *, READLINK3args*);
+extern bool_t xdr_readlink_resok(XDR *, READLINK3resok*);
+extern bool_t xdr_readlink_resfail(XDR *, READLINK3resfail*);
+extern bool_t xdr_readlink_res(XDR *, READLINK3res*);
+extern bool_t xdr_read_args(XDR *, READ3args*);
+extern bool_t xdr_read_resok(XDR *, READ3resok*);
+extern bool_t xdr_read_resfail(XDR *, READ3resfail*);
+extern bool_t xdr_read_res(XDR *, READ3res*);
+extern bool_t xdr_stable_how(XDR *, stable_how*);
+extern bool_t xdr_write_args(XDR *, WRITE3args*);
+extern bool_t xdr_write_resok(XDR *, WRITE3resok*);
+extern bool_t xdr_write_resfail(XDR *, WRITE3resfail*);
+extern bool_t xdr_write_res(XDR *, WRITE3res*);
+extern bool_t xdr_createmode3(XDR *, createmode3*);
+extern bool_t xdr_createhow3(XDR *, createhow3*);
+extern bool_t xdr_create_args(XDR *, CREATE3args*);
+extern bool_t xdr_create_resok(XDR *, CREATE3resok*);
+extern bool_t xdr_create_resfail(XDR *, CREATE3resfail*);
+extern bool_t xdr_create_res(XDR *, CREATE3res*);
+extern bool_t xdr_mkdir_args(XDR *, MKDIR3args*);
+extern bool_t xdr_mkdir_resok(XDR *, MKDIR3resok*);
+extern bool_t xdr_mkdir_resfail(XDR *, MKDIR3resfail*);
+extern bool_t xdr_mkdir_res(XDR *, MKDIR3res*);
+extern bool_t xdr_symlinkdata3(XDR *, symlinkdata3*);
+extern bool_t xdr_symlink_args(XDR *, SYMLINK3args*);
+extern bool_t xdr_symlink_resok(XDR *, SYMLINK3resok*);
+extern bool_t xdr_symlink_resfail(XDR *, SYMLINK3resfail*);
+extern bool_t xdr_symlink_res(XDR *, SYMLINK3res*);
+extern bool_t xdr_devicedata3(XDR *, devicedata3*);
+extern bool_t xdr_mknoddata3(XDR *, mknoddata3*);
+extern bool_t xdr_mknod_args(XDR *, MKNOD3args*);
+extern bool_t xdr_mknod_resok(XDR *, MKNOD3resok*);
+extern bool_t xdr_mknod_resfail(XDR *, MKNOD3resfail*);
+extern bool_t xdr_mknod_res(XDR *, MKNOD3res*);
+extern bool_t xdr_remove_args(XDR *, REMOVE3args*);
+extern bool_t xdr_remove_resok(XDR *, REMOVE3resok*);
+extern bool_t xdr_remove_resfail(XDR *, REMOVE3resfail*);
+extern bool_t xdr_remove_res(XDR *, REMOVE3res*);
+extern bool_t xdr_rmdir_args(XDR *, RMDIR3args*);
+extern bool_t xdr_rmdir_resok(XDR *, RMDIR3resok*);
+extern bool_t xdr_rmdir_resfail(XDR *, RMDIR3resfail*);
+extern bool_t xdr_rmdir_res(XDR *, RMDIR3res*);
+extern bool_t xdr_rename_args(XDR *, RENAME3args*);
+extern bool_t xdr_rename_resok(XDR *, RENAME3resok*);
+extern bool_t xdr_rename_resfail(XDR *, RENAME3resfail*);
+extern bool_t xdr_rename_res(XDR *, RENAME3res*);
+extern bool_t xdr_link_args(XDR *, LINK3args*);
+extern bool_t xdr_link_resok(XDR *, LINK3resok*);
+extern bool_t xdr_link_resfail(XDR *, LINK3resfail*);
+extern bool_t xdr_link_res(XDR *, LINK3res*);
+extern bool_t xdr_readdir_args(XDR *, READDIR3args*);
+extern bool_t xdr_entry3(XDR *, entry3*);
+extern bool_t xdr_dirlist3(XDR *, dirlist3*);
+extern bool_t xdr_readdir_resok(XDR *, READDIR3resok*);
+extern bool_t xdr_readdir_resfail(XDR *, READDIR3resfail*);
+extern bool_t xdr_readdir_res(XDR *, READDIR3res*);
+extern bool_t xdr_readdirplus_args(XDR *, READDIRPLUS3args*);
+extern bool_t xdr_entryplus3(XDR *, entryplus3*);
+extern bool_t xdr_dirlistplus3(XDR *, dirlistplus3*);
+extern bool_t xdr_readdirplus_resok(XDR *, READDIRPLUS3resok*);
+extern bool_t xdr_readdirplus_resfail(XDR *, READDIRPLUS3resfail*);
+extern bool_t xdr_readdirplus_res(XDR *, READDIRPLUS3res*);
+extern bool_t xdr_fsstat_args(XDR *, FSSTAT3args*);
+extern bool_t xdr_fsstat_resok(XDR *, FSSTAT3resok*);
+extern bool_t xdr_fsstat_resfail(XDR *, FSSTAT3resfail*);
+extern bool_t xdr_fsstat_res(XDR *, FSSTAT3res*);
+extern bool_t xdr_fsinfo_args(XDR *, FSINFO3args*);
+extern bool_t xdr_fsinfo_resok(XDR *, FSINFO3resok*);
+extern bool_t xdr_fsinfo_resfail(XDR *, FSINFO3resfail*);
+extern bool_t xdr_fsinfo_res(XDR *, FSINFO3res*);
+extern bool_t xdr_pathconf_args(XDR *, PATHCONF3args*);
+extern bool_t xdr_pathconf_resok(XDR *, PATHCONF3resok*);
+extern bool_t xdr_pathconf_resfail(XDR *, PATHCONF3resfail*);
+extern bool_t xdr_pathconf_res(XDR *, PATHCONF3res*);
+extern bool_t xdr_commit_args(XDR *, COMMIT3args*);
+extern bool_t xdr_commit_resok(XDR *, COMMIT3resok*);
+extern bool_t xdr_commit_resfail(XDR *, COMMIT3resfail*);
+extern bool_t xdr_commit_res(XDR *, COMMIT3res*);
+extern bool_t xdr_null_args(XDR *xdrs, void *);
+extern bool_t xdr_null_res(XDR *xdrs, void *);
+
+#endif /* !_NFS_H */
diff --git a/sheep/nfs/nfsd.c b/sheep/nfs/nfsd.c
new file mode 100644
index 0000000..11af50a
--- /dev/null
+++ b/sheep/nfs/nfsd.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2014 Taobao Inc.
+ *
+ * Liu Yuan <namei.unix at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <nfs://www.gnu.org/licenses/>.
+ */
+
+#include "sheep_priv.h"
+#include "nfs.h"
+#include <rpc/pmap_clnt.h>
+
+typedef void *(*svc_func)(struct svc_req *, struct nfs_arg *argp);
+
+struct svc_handler {
+	svc_func     func;    /* process the request */
+	xdrproc_t    decoder; /* XDR decode args */
+	xdrproc_t    encoder; /* XDR encode result */
+	unsigned int count;	 /* call count */
+};
+
+#define NFS_HANDLER(name)			\
+{						\
+	(svc_func)  nfs3_##name,		\
+	(xdrproc_t) xdr_##name##_args,		\
+	(xdrproc_t) xdr_##name##_res,		\
+	0,					\
+}
+
+static struct svc_handler nfs3_handlers[] = {
+	NFS_HANDLER(null),
+	NFS_HANDLER(getattr),
+	NFS_HANDLER(setattr),
+	NFS_HANDLER(lookup),
+	NFS_HANDLER(access),
+	NFS_HANDLER(readlink),
+	NFS_HANDLER(read),
+	NFS_HANDLER(write),
+	NFS_HANDLER(create),
+	NFS_HANDLER(mkdir),
+	NFS_HANDLER(symlink),
+	NFS_HANDLER(mknod),
+	NFS_HANDLER(remove),
+	NFS_HANDLER(rmdir),
+	NFS_HANDLER(rename),
+	NFS_HANDLER(link),
+	NFS_HANDLER(readdir),
+	NFS_HANDLER(readdirplus),
+	NFS_HANDLER(fsstat),
+	NFS_HANDLER(fsinfo),
+	NFS_HANDLER(pathconf),
+	NFS_HANDLER(commit),
+};
+
+static void nfs3_dispatcher(struct svc_req *reg, SVCXPRT *transp)
+{
+	struct nfs_arg arg = {};
+	int proc = reg->rq_proc;
+	void *result;
+
+	sd_debug("%d", proc);
+
+	if (!svc_getargs(transp, nfs3_handlers[proc].decoder, (caddr_t)&arg)) {
+		sd_err("svc_getargs failed");
+		svcerr_decode(transp);
+		return;
+	}
+
+	result = nfs3_handlers[proc].func(reg, &arg);
+	if (result && !svc_sendreply(transp, nfs3_handlers[proc].encoder,
+				     result)) {
+		sd_err("svc_sendreply failed");
+		svcerr_systemerr(transp);
+	}
+
+	if (!svc_freeargs(transp, nfs3_handlers[proc].decoder, (caddr_t)&arg))
+		panic("unable to free arguments");
+
+	return;
+}
+
+static int nfs_init_transport(void)
+{
+	SVCXPRT *nfs_trans = NULL;
+
+	pmap_unset(NFS_PROGRAM, NFS_V3);
+
+	nfs_trans = svcudp_create(RPC_ANYSOCK);
+	if (!nfs_trans) {
+		sd_err("svcudp_create failed");
+		return -1;
+	}
+
+	if (!svc_register(nfs_trans, NFS_PROGRAM, NFS_V3, nfs3_dispatcher,
+			  IPPROTO_UDP)) {
+		sd_err("svc_register udp, failed");
+		return -1;
+	}
+	sd_info("nfs service listen at %d, proto udp", nfs_trans->xp_port);
+
+	nfs_trans = svctcp_create(RPC_ANYSOCK, 0, 0);
+	if (!nfs_trans) {
+		sd_err("svctcp_create failed");
+		return -1;
+	}
+
+	if (!svc_register(nfs_trans, NFS_PROGRAM, NFS_V3, nfs3_dispatcher,
+			  IPPROTO_TCP)) {
+		sd_err("svc_register tcp, failed");
+		return -1;
+	}
+	sd_info("nfs service listen at %d, proto tcp", nfs_trans->xp_port);
+
+	return 0;
+}
+
+static void *nfsd(void *ignored)
+{
+	int err;
+
+	if (nfs_init_transport() < 0)
+		goto out;
+
+	/* FIXME: glibc doesn't support multi-threaded svc API */
+	svc_run();
+
+	sd_err("svc_run exited");
+out:
+	err = pthread_detach(pthread_self());
+	if (err)
+		sd_err("%s", strerror(err));
+	pthread_exit(NULL);
+}
+
+int nfs_init(const char *options)
+{
+	pthread_t t;
+	int err;
+
+	err = pthread_create(&t, NULL, nfsd, NULL);
+	if (err) {
+		sd_err("%s", strerror(err));
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/sheep/nfs/xdr.c b/sheep/nfs/xdr.c
new file mode 100644
index 0000000..15f9902
--- /dev/null
+++ b/sheep/nfs/xdr.c
@@ -0,0 +1,1661 @@
+#include "nfs.h"
+
+bool_t
+xdr_uint64(XDR *xdrs, uint64 *objp)
+{
+	if (!xdr_u_quad_t(xdrs, objp))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_int64(XDR *xdrs, int64 *objp)
+{
+	if (!xdr_quad_t(xdrs, objp))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_uint32(XDR *xdrs, uint32 *objp)
+{
+	if (!xdr_u_long(xdrs, objp))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_int32(XDR *xdrs, int32 *objp)
+{
+	if (!xdr_long(xdrs, objp))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_filename3(XDR *xdrs, filename3 *objp)
+{
+	if (!xdr_string(xdrs, objp, ~0))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_nfspath3(XDR *xdrs, nfspath3 *objp)
+{
+	if (!xdr_string(xdrs, objp, ~0))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_fileid3(XDR *xdrs, fileid3 *objp)
+{
+	if (!xdr_uint64(xdrs, objp))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_cookie3(XDR *xdrs, cookie3 *objp)
+{
+	if (!xdr_uint64(xdrs, objp))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_cookieverf3(XDR *xdrs, cookieverf3 objp)
+{
+	if (!xdr_opaque(xdrs, objp, NFS3_COOKIEVERFSIZE))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_createverf3(XDR *xdrs, createverf3 objp)
+{
+	if (!xdr_opaque(xdrs, objp, NFS3_CREATEVERFSIZE))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_writeverf3(XDR *xdrs, writeverf3 objp)
+{
+	if (!xdr_opaque(xdrs, objp, NFS3_WRITEVERFSIZE))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_uid3(XDR *xdrs, uid3 *objp)
+{
+	if (!xdr_uint32(xdrs, objp))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_gid3(XDR *xdrs, gid3 *objp)
+{
+	if (!xdr_uint32(xdrs, objp))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_size3(XDR *xdrs, size3 *objp)
+{
+	if (!xdr_uint64(xdrs, objp))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_offset3(XDR *xdrs, offset3 *objp)
+{
+	if (!xdr_uint64(xdrs, objp))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_mode3(XDR *xdrs, mode3 *objp)
+{
+	if (!xdr_uint32(xdrs, objp))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_count3(XDR *xdrs, count3 *objp)
+{
+	if (!xdr_uint32(xdrs, objp))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_nfsstat3(XDR *xdrs, nfsstat3 *objp)
+{
+	if (!xdr_enum(xdrs, (enum_t *) objp))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_ftype3(XDR *xdrs, ftype3 *objp)
+{
+	if (!xdr_enum(xdrs, (enum_t *) objp))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_specdata3(XDR *xdrs, specdata3 *objp)
+{
+	if (!xdr_uint32(xdrs, &objp->specdata1))
+		return FALSE;
+	if (!xdr_uint32(xdrs, &objp->specdata2))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_nfs_fh3(XDR *xdrs, nfs_fh3 *objp)
+{
+	if (!xdr_bytes(xdrs, (char **)&objp->data.data_val,
+		       (u_int *)&objp->data.data_len, NFS3_FHSIZE))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_nfstime3(XDR *xdrs, nfstime3 *objp)
+{
+	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)
+{
+	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)
+{
+	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_wcc_attr(XDR *xdrs, wcc_attr *objp)
+{
+	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)
+{
+	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)
+{
+	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_post_op_fh3(XDR *xdrs, post_op_fh3 *objp)
+{
+	if (!xdr_bool(xdrs, &objp->handle_follows))
+		return FALSE;
+	switch (objp->handle_follows) {
+	case TRUE:
+		if (!xdr_nfs_fh3(xdrs, &objp->post_op_fh3_u.handle))
+			return FALSE;
+		break;
+	case FALSE:
+		break;
+	default:
+		return FALSE;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_time_how(XDR *xdrs, time_how *objp)
+{
+	if (!xdr_enum(xdrs, (enum_t *) objp))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_set_mode3(XDR *xdrs, set_mode3 *objp)
+{
+	if (!xdr_bool(xdrs, &objp->set_it))
+		return FALSE;
+	switch (objp->set_it) {
+	case TRUE:
+		if (!xdr_mode3(xdrs, &objp->set_mode3_u.mode))
+			return FALSE;
+		break;
+	default:
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_set_uid3(XDR *xdrs, set_uid3 *objp)
+{
+	if (!xdr_bool(xdrs, &objp->set_it))
+		return FALSE;
+	switch (objp->set_it) {
+	case TRUE:
+		if (!xdr_uid3(xdrs, &objp->set_uid3_u.uid))
+			return FALSE;
+		break;
+	default:
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_set_gid3(XDR *xdrs, set_gid3 *objp)
+{
+	if (!xdr_bool(xdrs, &objp->set_it))
+		return FALSE;
+	switch (objp->set_it) {
+	case TRUE:
+		if (!xdr_gid3(xdrs, &objp->set_gid3_u.gid))
+			return FALSE;
+		break;
+	default:
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_set_size3(XDR *xdrs, set_size3 *objp)
+{
+	if (!xdr_bool(xdrs, &objp->set_it))
+		return FALSE;
+	switch (objp->set_it) {
+	case TRUE:
+		if (!xdr_size3(xdrs, &objp->set_size3_u.size))
+			return FALSE;
+		break;
+	default:
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_set_atime(XDR *xdrs, set_atime *objp)
+{
+	if (!xdr_time_how(xdrs, &objp->set_it))
+		return FALSE;
+	switch (objp->set_it) {
+	case SET_TO_CLIENT_TIME:
+		if (!xdr_nfstime3(xdrs, &objp->set_atime_u.atime))
+			return FALSE;
+		break;
+	default:
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_set_mtime(XDR *xdrs, set_mtime *objp)
+{
+	if (!xdr_time_how(xdrs, &objp->set_it))
+		return FALSE;
+	switch (objp->set_it) {
+	case SET_TO_CLIENT_TIME:
+		if (!xdr_nfstime3(xdrs, &objp->set_mtime_u.mtime))
+			return FALSE;
+		break;
+	default:
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_sattr3(XDR *xdrs, sattr3 *objp)
+{
+	if (!xdr_set_mode3(xdrs, &objp->mode))
+		return FALSE;
+	if (!xdr_set_uid3(xdrs, &objp->uid))
+		return FALSE;
+	if (!xdr_set_gid3(xdrs, &objp->gid))
+		return FALSE;
+	if (!xdr_set_size3(xdrs, &objp->size))
+		return FALSE;
+	if (!xdr_set_atime(xdrs, &objp->atime))
+		return FALSE;
+	if (!xdr_set_mtime(xdrs, &objp->mtime))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_diropargs3(XDR *xdrs, diropargs3 *objp)
+{
+	if (!xdr_nfs_fh3(xdrs, &objp->dir))
+		return FALSE;
+	if (!xdr_filename3(xdrs, &objp->name))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_getattr_args(XDR *xdrs, GETATTR3args *objp)
+{
+	if (!xdr_nfs_fh3(xdrs, &objp->object))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_getattr_resok(XDR *xdrs, GETATTR3resok *objp)
+{
+	if (!xdr_fattr3(xdrs, &objp->obj_attributes))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_getattr_res(XDR *xdrs, GETATTR3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_getattr_resok(xdrs, &objp->GETATTR3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_sattrguard3(XDR *xdrs, sattrguard3 *objp)
+{
+	if (!xdr_bool(xdrs, &objp->check))
+		return FALSE;
+	switch (objp->check) {
+	case TRUE:
+		if (!xdr_nfstime3(xdrs, &objp->sattrguard3_u.obj_ctime))
+			return FALSE;
+		break;
+	case FALSE:
+		break;
+	default:
+		return FALSE;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_setattr_args(XDR *xdrs, SETATTR3args *objp)
+{
+	if (!xdr_nfs_fh3(xdrs, &objp->object))
+		return FALSE;
+	if (!xdr_sattr3(xdrs, &objp->new_attributes))
+		return FALSE;
+	if (!xdr_sattrguard3(xdrs, &objp->guard))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_setattr_resok(XDR *xdrs, SETATTR3resok *objp)
+{
+	if (!xdr_wcc_data(xdrs, &objp->obj_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_setattr_resfail(XDR *xdrs, SETATTR3resfail *objp)
+{
+	if (!xdr_wcc_data(xdrs, &objp->obj_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_setattr_res(XDR *xdrs, SETATTR3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_setattr_resok(xdrs, &objp->SETATTR3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_setattr_resfail(xdrs, &objp->SETATTR3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_lookup_args(XDR *xdrs, LOOKUP3args *objp)
+{
+	if (!xdr_diropargs3(xdrs, &objp->what))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_lookup_resok(XDR *xdrs, LOOKUP3resok *objp)
+{
+	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_lookup_resfail(XDR *xdrs, LOOKUP3resfail *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->dir_attributes))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_lookup_res(XDR *xdrs, LOOKUP3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_lookup_resok(xdrs, &objp->LOOKUP3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_lookup_resfail(xdrs, &objp->LOOKUP3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_access_args(XDR *xdrs, ACCESS3args *objp)
+{
+	if (!xdr_nfs_fh3(xdrs, &objp->object))
+		return FALSE;
+	if (!xdr_uint32(xdrs, &objp->access))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_access_resok(XDR *xdrs, ACCESS3resok *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+		return FALSE;
+	if (!xdr_uint32(xdrs, &objp->access))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_access_resfail(XDR *xdrs, ACCESS3resfail *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_access_res(XDR *xdrs, ACCESS3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_access_resok(xdrs, &objp->ACCESS3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_access_resfail(xdrs, &objp->ACCESS3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_readlink_args(XDR *xdrs, READLINK3args *objp)
+{
+	if (!xdr_nfs_fh3(xdrs, &objp->symlink))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_readlink_resok(XDR *xdrs, READLINK3resok *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->symlink_attributes))
+		return FALSE;
+	if (!xdr_nfspath3(xdrs, &objp->data))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_readlink_resfail(XDR *xdrs, READLINK3resfail *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->symlink_attributes))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_readlink_res(XDR *xdrs, READLINK3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_readlink_resok(xdrs, &objp->READLINK3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_readlink_resfail(xdrs, &objp->READLINK3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_read_args(XDR *xdrs, READ3args *objp)
+{
+	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_read_resok(XDR *xdrs, READ3resok *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->file_attributes))
+		return FALSE;
+	if (!xdr_count3(xdrs, &objp->count))
+		return FALSE;
+	if (!xdr_bool(xdrs, &objp->eof))
+		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_read_resfail(XDR *xdrs, READ3resfail *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->file_attributes))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_read_res(XDR *xdrs, READ3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_read_resok(xdrs, &objp->READ3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_read_resfail(xdrs, &objp->READ3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_stable_how(XDR *xdrs, stable_how *objp)
+{
+	if (!xdr_enum(xdrs, (enum_t *) objp))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_write_args(XDR *xdrs, WRITE3args *objp)
+{
+	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_write_resok(XDR *xdrs, WRITE3resok *objp)
+{
+	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_write_resfail(XDR *xdrs, WRITE3resfail *objp)
+{
+	if (!xdr_wcc_data(xdrs, &objp->file_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_write_res(XDR *xdrs, WRITE3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_write_resok(xdrs, &objp->WRITE3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_write_resfail(xdrs, &objp->WRITE3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_createmode3(XDR *xdrs, createmode3 *objp)
+{
+	if (!xdr_enum(xdrs, (enum_t *) objp))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_createhow3(XDR *xdrs, createhow3 *objp)
+{
+	if (!xdr_createmode3(xdrs, &objp->mode))
+		return FALSE;
+	switch (objp->mode) {
+	case UNCHECKED:
+	case GUARDED:
+		if (!xdr_sattr3(xdrs, &objp->createhow3_u.obj_attributes))
+			return FALSE;
+		break;
+	case EXCLUSIVE:
+		if (!xdr_createverf3(xdrs, objp->createhow3_u.verf))
+			return FALSE;
+		break;
+	default:
+		return FALSE;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_create_args(XDR *xdrs, CREATE3args *objp)
+{
+	if (!xdr_diropargs3(xdrs, &objp->where))
+		return FALSE;
+	if (!xdr_createhow3(xdrs, &objp->how))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_create_resok(XDR *xdrs, CREATE3resok *objp)
+{
+	if (!xdr_post_op_fh3(xdrs, &objp->obj))
+		return FALSE;
+	if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+		return FALSE;
+	if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_create_resfail(XDR *xdrs, CREATE3resfail *objp)
+{
+	if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_create_res(XDR *xdrs, CREATE3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_create_resok(xdrs, &objp->CREATE3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_create_resfail(xdrs, &objp->CREATE3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_mkdir_args(XDR *xdrs, MKDIR3args *objp)
+{
+	if (!xdr_diropargs3(xdrs, &objp->where))
+		return FALSE;
+	if (!xdr_sattr3(xdrs, &objp->attributes))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_mkdir_resok(XDR *xdrs, MKDIR3resok *objp)
+{
+	if (!xdr_post_op_fh3(xdrs, &objp->obj))
+		return FALSE;
+	if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+		return FALSE;
+	if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_mkdir_resfail(XDR *xdrs, MKDIR3resfail *objp)
+{
+	if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_mkdir_res(XDR *xdrs, MKDIR3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_mkdir_resok(xdrs, &objp->MKDIR3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_mkdir_resfail(xdrs, &objp->MKDIR3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_symlinkdata3(XDR *xdrs, symlinkdata3 *objp)
+{
+	if (!xdr_sattr3(xdrs, &objp->symlink_attributes))
+		return FALSE;
+	if (!xdr_nfspath3(xdrs, &objp->symlink_data))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_symlink_args(XDR *xdrs, SYMLINK3args *objp)
+{
+	if (!xdr_diropargs3(xdrs, &objp->where))
+		return FALSE;
+	if (!xdr_symlinkdata3(xdrs, &objp->symlink))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_symlink_resok(XDR *xdrs, SYMLINK3resok *objp)
+{
+	if (!xdr_post_op_fh3(xdrs, &objp->obj))
+		return FALSE;
+	if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+		return FALSE;
+	if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_symlink_resfail(XDR *xdrs, SYMLINK3resfail *objp)
+{
+	if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_symlink_res(XDR *xdrs, SYMLINK3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_symlink_resok(xdrs, &objp->SYMLINK3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_symlink_resfail(xdrs, &objp->SYMLINK3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_devicedata3(XDR *xdrs, devicedata3 *objp)
+{
+	if (!xdr_sattr3(xdrs, &objp->dev_attributes))
+		return FALSE;
+	if (!xdr_specdata3(xdrs, &objp->spec))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_mknoddata3(XDR *xdrs, mknoddata3 *objp)
+{
+	if (!xdr_ftype3(xdrs, &objp->type))
+		return FALSE;
+	switch (objp->type) {
+	case NF3CHR:
+	case NF3BLK:
+		if (!xdr_devicedata3(xdrs, &objp->mknoddata3_u.device))
+			return FALSE;
+		break;
+	case NF3SOCK:
+	case NF3FIFO:
+		if (!xdr_sattr3(xdrs, &objp->mknoddata3_u.pipe_attributes))
+			return FALSE;
+		break;
+	default:
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_mknod_args(XDR *xdrs, MKNOD3args *objp)
+{
+	if (!xdr_diropargs3(xdrs, &objp->where))
+		return FALSE;
+	if (!xdr_mknoddata3(xdrs, &objp->what))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_mknod_resok(XDR *xdrs, MKNOD3resok *objp)
+{
+	if (!xdr_post_op_fh3(xdrs, &objp->obj))
+		return FALSE;
+	if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+		return FALSE;
+	if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_mknod_resfail(XDR *xdrs, MKNOD3resfail *objp)
+{
+	if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_mknod_res(XDR *xdrs, MKNOD3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_mknod_resok(xdrs, &objp->MKNOD3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_mknod_resfail(xdrs, &objp->MKNOD3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_remove_args(XDR *xdrs, REMOVE3args *objp)
+{
+	if (!xdr_diropargs3(xdrs, &objp->object))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_remove_resok(XDR *xdrs, REMOVE3resok *objp)
+{
+	if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_remove_resfail(XDR *xdrs, REMOVE3resfail *objp)
+{
+	if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_remove_res(XDR *xdrs, REMOVE3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_remove_resok(xdrs, &objp->REMOVE3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_remove_resfail(xdrs, &objp->REMOVE3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_rmdir_args(XDR *xdrs, RMDIR3args *objp)
+{
+	if (!xdr_diropargs3(xdrs, &objp->object))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_rmdir_resok(XDR *xdrs, RMDIR3resok *objp)
+{
+	if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_rmdir_resfail(XDR *xdrs, RMDIR3resfail *objp)
+{
+	if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_rmdir_res(XDR *xdrs, RMDIR3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_rmdir_resok(xdrs, &objp->RMDIR3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_rmdir_resfail(xdrs, &objp->RMDIR3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_rename_args(XDR *xdrs, RENAME3args *objp)
+{
+	if (!xdr_diropargs3(xdrs, &objp->from))
+		return FALSE;
+	if (!xdr_diropargs3(xdrs, &objp->to))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_rename_resok(XDR *xdrs, RENAME3resok *objp)
+{
+	if (!xdr_wcc_data(xdrs, &objp->fromdir_wcc))
+		return FALSE;
+	if (!xdr_wcc_data(xdrs, &objp->todir_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_rename_resfail(XDR *xdrs, RENAME3resfail *objp)
+{
+	if (!xdr_wcc_data(xdrs, &objp->fromdir_wcc))
+		return FALSE;
+	if (!xdr_wcc_data(xdrs, &objp->todir_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_rename_res(XDR *xdrs, RENAME3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_rename_resok(xdrs, &objp->RENAME3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_rename_resfail(xdrs, &objp->RENAME3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_link_args(XDR *xdrs, LINK3args *objp)
+{
+	if (!xdr_nfs_fh3(xdrs, &objp->file))
+		return FALSE;
+	if (!xdr_diropargs3(xdrs, &objp->link))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_link_resok(XDR *xdrs, LINK3resok *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->file_attributes))
+		return FALSE;
+	if (!xdr_wcc_data(xdrs, &objp->linkdir_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_link_resfail(XDR *xdrs, LINK3resfail *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->file_attributes))
+		return FALSE;
+	if (!xdr_wcc_data(xdrs, &objp->linkdir_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_link_res(XDR *xdrs, LINK3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_link_resok(xdrs, &objp->LINK3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_link_resfail(xdrs, &objp->LINK3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_readdir_args(XDR *xdrs, READDIR3args *objp)
+{
+	if (!xdr_nfs_fh3(xdrs, &objp->dir))
+		return FALSE;
+	if (!xdr_cookie3(xdrs, &objp->cookie))
+		return FALSE;
+	if (!xdr_cookieverf3(xdrs, objp->cookieverf))
+		return FALSE;
+	if (!xdr_count3(xdrs, &objp->count))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_entry3(XDR *xdrs, entry3 *objp)
+{
+	if (!xdr_fileid3(xdrs, &objp->fileid))
+		return FALSE;
+	if (!xdr_filename3(xdrs, &objp->name))
+		return FALSE;
+	if (!xdr_cookie3(xdrs, &objp->cookie))
+		return FALSE;
+	if (!xdr_pointer(xdrs, (char **)&objp->nextentry, sizeof(entry3),
+			 (xdrproc_t)xdr_entry3))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_dirlist3(XDR *xdrs, dirlist3 *objp)
+{
+	if (!xdr_pointer(xdrs, (char **)&objp->entries, sizeof(entry3),
+			 (xdrproc_t)xdr_entry3))
+		return FALSE;
+	if (!xdr_bool(xdrs, &objp->eof))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_readdir_resok(XDR *xdrs, READDIR3resok *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->dir_attributes))
+		return FALSE;
+	if (!xdr_cookieverf3(xdrs, objp->cookieverf))
+		return FALSE;
+	if (!xdr_dirlist3(xdrs, &objp->reply))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_readdir_resfail(XDR *xdrs, READDIR3resfail *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->dir_attributes))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_readdir_res(XDR *xdrs, READDIR3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_readdir_resok(xdrs, &objp->READDIR3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_readdir_resfail(xdrs, &objp->READDIR3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_readdirplus_args(XDR *xdrs, READDIRPLUS3args *objp)
+{
+	if (!xdr_nfs_fh3(xdrs, &objp->dir))
+		return FALSE;
+	if (!xdr_cookie3(xdrs, &objp->cookie))
+		return FALSE;
+	if (!xdr_cookieverf3(xdrs, objp->cookieverf))
+		return FALSE;
+	if (!xdr_count3(xdrs, &objp->dircount))
+		return FALSE;
+	if (!xdr_count3(xdrs, &objp->maxcount))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_entryplus3(XDR *xdrs, entryplus3 *objp)
+{
+	if (!xdr_fileid3(xdrs, &objp->fileid))
+		return FALSE;
+	if (!xdr_filename3(xdrs, &objp->name))
+		return FALSE;
+	if (!xdr_cookie3(xdrs, &objp->cookie))
+		return FALSE;
+	if (!xdr_post_op_attr(xdrs, &objp->name_attributes))
+		return FALSE;
+	if (!xdr_post_op_fh3(xdrs, &objp->name_handle))
+		return FALSE;
+	if (!xdr_pointer(xdrs, (char **)&objp->nextentry, sizeof(entryplus3),
+			 (xdrproc_t) xdr_entryplus3))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_dirlistplus3(XDR *xdrs, dirlistplus3 *objp)
+{
+	if (!xdr_pointer(xdrs, (char **)&objp->entries, sizeof(entryplus3),
+			 (xdrproc_t) xdr_entryplus3))
+		return FALSE;
+	if (!xdr_bool(xdrs, &objp->eof))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_readdirplus_resok(XDR *xdrs, READDIRPLUS3resok *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->dir_attributes))
+		return FALSE;
+	if (!xdr_cookieverf3(xdrs, objp->cookieverf))
+		return FALSE;
+	if (!xdr_dirlistplus3(xdrs, &objp->reply))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_readdirplus_resfail(XDR *xdrs, READDIRPLUS3resfail *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->dir_attributes))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_readdirplus_res(XDR *xdrs, READDIRPLUS3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_readdirplus_resok(xdrs,
+					   &objp->READDIRPLUS3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_readdirplus_resfail(xdrs,
+					     &objp->READDIRPLUS3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_fsstat_args(XDR *xdrs, FSSTAT3args *objp)
+{
+	if (!xdr_nfs_fh3(xdrs, &objp->fsroot))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_fsstat_resok(XDR *xdrs, FSSTAT3resok *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+		return FALSE;
+	if (!xdr_size3(xdrs, &objp->tbytes))
+		return FALSE;
+	if (!xdr_size3(xdrs, &objp->fbytes))
+		return FALSE;
+	if (!xdr_size3(xdrs, &objp->abytes))
+		return FALSE;
+	if (!xdr_size3(xdrs, &objp->tfiles))
+		return FALSE;
+	if (!xdr_size3(xdrs, &objp->ffiles))
+		return FALSE;
+	if (!xdr_size3(xdrs, &objp->afiles))
+		return FALSE;
+	if (!xdr_uint32(xdrs, &objp->invarsec))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_fsstat_resfail(XDR *xdrs, FSSTAT3resfail *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_fsstat_res(XDR *xdrs, FSSTAT3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_fsstat_resok(xdrs, &objp->FSSTAT3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_fsstat_resfail(xdrs, &objp->FSSTAT3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_fsinfo_args(XDR *xdrs, FSINFO3args *objp)
+{
+	if (!xdr_nfs_fh3(xdrs, &objp->fsroot))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_fsinfo_resok(XDR *xdrs, FSINFO3resok *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+		return FALSE;
+	if (!xdr_uint32(xdrs, &objp->rtmax))
+		return FALSE;
+	if (!xdr_uint32(xdrs, &objp->rtpref))
+		return FALSE;
+	if (!xdr_uint32(xdrs, &objp->rtmult))
+		return FALSE;
+	if (!xdr_uint32(xdrs, &objp->wtmax))
+		return FALSE;
+	if (!xdr_uint32(xdrs, &objp->wtpref))
+		return FALSE;
+	if (!xdr_uint32(xdrs, &objp->wtmult))
+		return FALSE;
+	if (!xdr_uint32(xdrs, &objp->dtpref))
+		return FALSE;
+	if (!xdr_size3(xdrs, &objp->maxfilesize))
+		return FALSE;
+	if (!xdr_nfstime3(xdrs, &objp->time_delta))
+		return FALSE;
+	if (!xdr_uint32(xdrs, &objp->properties))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_fsinfo_resfail(XDR *xdrs, FSINFO3resfail *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_fsinfo_res(XDR *xdrs, FSINFO3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_fsinfo_resok(xdrs, &objp->FSINFO3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_fsinfo_resfail(xdrs, &objp->FSINFO3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_pathconf_args(XDR *xdrs, PATHCONF3args *objp)
+{
+	if (!xdr_nfs_fh3(xdrs, &objp->object))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_pathconf_resok(XDR *xdrs, PATHCONF3resok *objp)
+{
+	int32_t *buf;
+
+	if (xdrs->x_op == XDR_ENCODE) {
+		if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+			return FALSE;
+		if (!xdr_uint32(xdrs, &objp->linkmax))
+			return FALSE;
+		if (!xdr_uint32(xdrs, &objp->name_max))
+			return FALSE;
+		buf = XDR_INLINE(xdrs, 4 * BYTES_PER_XDR_UNIT);
+		if (buf == NULL) {
+			if (!xdr_bool(xdrs, &objp->no_trunc))
+				return FALSE;
+			if (!xdr_bool(xdrs, &objp->chown_restricted))
+				return FALSE;
+			if (!xdr_bool(xdrs, &objp->case_insensitive))
+				return FALSE;
+			if (!xdr_bool(xdrs, &objp->case_preserving))
+				return FALSE;
+		} else {
+			IXDR_PUT_BOOL(buf, objp->no_trunc);
+			IXDR_PUT_BOOL(buf, objp->chown_restricted);
+			IXDR_PUT_BOOL(buf, objp->case_insensitive);
+			IXDR_PUT_BOOL(buf, objp->case_preserving);
+		}
+		return TRUE;
+	} else if (xdrs->x_op == XDR_DECODE) {
+		if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+			return FALSE;
+		if (!xdr_uint32(xdrs, &objp->linkmax))
+			return FALSE;
+		if (!xdr_uint32(xdrs, &objp->name_max))
+			return FALSE;
+		buf = XDR_INLINE(xdrs, 4 * BYTES_PER_XDR_UNIT);
+		if (buf == NULL) {
+			if (!xdr_bool(xdrs, &objp->no_trunc))
+				return FALSE;
+			if (!xdr_bool(xdrs, &objp->chown_restricted))
+				return FALSE;
+			if (!xdr_bool(xdrs, &objp->case_insensitive))
+				return FALSE;
+			if (!xdr_bool(xdrs, &objp->case_preserving))
+				return FALSE;
+		} else {
+			objp->no_trunc = IXDR_GET_BOOL(buf);
+			objp->chown_restricted = IXDR_GET_BOOL(buf);
+			objp->case_insensitive = IXDR_GET_BOOL(buf);
+			objp->case_preserving = IXDR_GET_BOOL(buf);
+		}
+		return TRUE;
+	}
+
+	if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+		return FALSE;
+	if (!xdr_uint32(xdrs, &objp->linkmax))
+		return FALSE;
+	if (!xdr_uint32(xdrs, &objp->name_max))
+		return FALSE;
+	if (!xdr_bool(xdrs, &objp->no_trunc))
+		return FALSE;
+	if (!xdr_bool(xdrs, &objp->chown_restricted))
+		return FALSE;
+	if (!xdr_bool(xdrs, &objp->case_insensitive))
+		return FALSE;
+	if (!xdr_bool(xdrs, &objp->case_preserving))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_pathconf_resfail(XDR *xdrs, PATHCONF3resfail *objp)
+{
+	if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_pathconf_res(XDR *xdrs, PATHCONF3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_pathconf_resok(xdrs, &objp->PATHCONF3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_pathconf_resfail(xdrs, &objp->PATHCONF3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_commit_args(XDR *xdrs, COMMIT3args *objp)
+{
+	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_commit_resok(XDR *xdrs, COMMIT3resok *objp)
+{
+	if (!xdr_wcc_data(xdrs, &objp->file_wcc))
+		return FALSE;
+	if (!xdr_writeverf3(xdrs, objp->verf))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_commit_resfail(XDR *xdrs, COMMIT3resfail *objp)
+{
+	if (!xdr_wcc_data(xdrs, &objp->file_wcc))
+		return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_commit_res(XDR *xdrs, COMMIT3res *objp)
+{
+	if (!xdr_nfsstat3(xdrs, &objp->status))
+		return FALSE;
+	switch (objp->status) {
+	case NFS3_OK:
+		if (!xdr_commit_resok(xdrs, &objp->COMMIT3res_u.resok))
+			return FALSE;
+		break;
+	default:
+		if (!xdr_commit_resfail(xdrs, &objp->COMMIT3res_u.resfail))
+			return FALSE;
+		break;
+	}
+	return TRUE;
+}
+
+bool_t xdr_null_args(XDR *xdrs, void *ignore)
+{
+	return xdr_void();
+}
+
+bool_t xdr_null_res(XDR *xdrs, void *ignore)
+{
+	return xdr_void();
+}
diff --git a/sheep/sheep.c b/sheep/sheep.c
index 7ef3746..3cf1378 100644
--- a/sheep/sheep.c
+++ b/sheep/sheep.c
@@ -911,6 +911,10 @@ int main(int argc, char **argv)
 	if (http_options && http_init(http_options) != 0)
 		exit(1);
 
+	ret = nfs_init(NULL);
+	if (ret)
+		exit(1);
+
 	if (pid_file && (create_pidfile(pid_file) != 0)) {
 		sd_err("failed to pid file '%s' - %m", pid_file);
 		exit(1);
diff --git a/sheep/sheep_priv.h b/sheep/sheep_priv.h
index e8d688b..4289861 100644
--- a/sheep/sheep_priv.h
+++ b/sheep/sheep_priv.h
@@ -152,7 +152,6 @@ struct system_info {
 #ifdef HAVE_HTTP
 	struct work_queue *http_wqueue;
 #endif
-
 	bool enable_object_cache;
 
 	uint32_t object_cache_size;
@@ -496,4 +495,14 @@ static inline int http_init(const char *options)
 }
 #endif /* END BUILD_HTTP */
 
+#ifdef HAVE_NFS
+int nfs_init(const char *options);
+#else
+static inline int nfs_init(const char *options)
+{
+	sd_notice("nfs server service is not complied");
+	return 0;
+}
+#endif
+
 #endif
-- 
1.8.1.2




More information about the sheepdog mailing list