diff options
Diffstat (limited to 'usr/src')
21 files changed, 10518 insertions, 745 deletions
diff --git a/usr/src/head/rpcsvc/nfs4_prot.x b/usr/src/head/rpcsvc/nfs4_prot.x index 24460cca7b..2618150477 100644 --- a/usr/src/head/rpcsvc/nfs4_prot.x +++ b/usr/src/head/rpcsvc/nfs4_prot.x @@ -1,12 +1,12 @@ /* - * This file was machine generated for [RFC7530]. + * This file was machine generated for [RFC7862]. * - * Last updated Tue Mar 10 11:51:21 PDT 2015. + * Last updated Sun Mar 13 10:58:40 PDT 2016 */ /* - * Copyright (c) 2015 IETF Trust and the persons identified - * as authors of the code. All rights reserved. + * Copyright (c) 2016 IETF Trust and the persons identified + * as the authors. All rights reserved. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -41,23 +41,30 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ /* - * This code was derived from RFC 7531. + * This code was derived from RFC 7863. */ /* - * nfs4_prot.x - * + * nfsv42.x */ +%#ifndef _AUTH_SYS_DEFINE_FOR_NFSv42 +%#define _AUTH_SYS_DEFINE_FOR_NFSv42 +%#include <rpc/auth_sys.h> +%typedef struct authsys_parms authsys_parms; +%#endif /* _AUTH_SYS_DEFINE_FOR_NFSv42 */ + /* * Basic typedefs for RFC 1832 data type definitions */ + /* - * typedef int int32_t; - * typedef unsigned int uint32_t; + * typedef int int32_t; + * typedef unsigned int uint32_t; * typedef hyper int64_t; * typedef unsigned hyper uint64_t; */ @@ -69,101 +76,164 @@ const NFS4_FHSIZE = 128; const NFS4_VERIFIER_SIZE = 8; const NFS4_OTHER_SIZE = 12; const NFS4_OPAQUE_LIMIT = 1024; +const NFS4_SESSIONID_SIZE = 16; const NFS4_INT64_MAX = 0x7fffffffffffffff; const NFS4_UINT64_MAX = 0xffffffffffffffff; const NFS4_INT32_MAX = 0x7fffffff; const NFS4_UINT32_MAX = 0xffffffff; +const NFS4_MAXFILELEN = 0xffffffffffffffff; +const NFS4_MAXFILEOFF = 0xfffffffffffffffe; + /* * File types */ enum nfs_ftype4 { - NF4REG = 1, /* Regular File */ - NF4DIR = 2, /* Directory */ - NF4BLK = 3, /* Special File - block device */ - NF4CHR = 4, /* Special File - character device */ - NF4LNK = 5, /* Symbolic Link */ - NF4SOCK = 6, /* Special File - socket */ - NF4FIFO = 7, /* Special File - fifo */ - NF4ATTRDIR - = 8, /* Attribute Directory */ - NF4NAMEDATTR - = 9 /* Named Attribute */ + NF4REG = 1, /* Regular File */ + NF4DIR = 2, /* Directory */ + NF4BLK = 3, /* Special File -- block device */ + NF4CHR = 4, /* Special File -- character device */ + NF4LNK = 5, /* Symbolic Link */ + NF4SOCK = 6, /* Special File -- socket */ + NF4FIFO = 7, /* Special File -- fifo */ + NF4ATTRDIR = 8, /* Attribute Directory */ + NF4NAMEDATTR = 9 /* Named Attribute */ }; /* * Error status */ enum nfsstat4 { - NFS4_OK = 0, /* everything is okay */ - NFS4ERR_PERM = 1, /* caller not privileged */ - NFS4ERR_NOENT = 2, /* no such file/directory */ - NFS4ERR_IO = 5, /* hard I/O error */ - NFS4ERR_NXIO = 6, /* no such device */ - NFS4ERR_ACCESS = 13, /* access denied */ - NFS4ERR_EXIST = 17, /* file already exists */ - NFS4ERR_XDEV = 18, /* different file systems */ - /* Unused/reserved 19 */ - NFS4ERR_NOTDIR = 20, /* should be a directory */ - NFS4ERR_ISDIR = 21, /* should not be directory */ - NFS4ERR_INVAL = 22, /* invalid argument */ - NFS4ERR_FBIG = 27, /* file exceeds server max */ - NFS4ERR_NOSPC = 28, /* no space on file system */ - NFS4ERR_ROFS = 30, /* read-only file system */ - NFS4ERR_MLINK = 31, /* too many hard links */ - NFS4ERR_NAMETOOLONG = 63, /* name exceeds server max */ - NFS4ERR_NOTEMPTY = 66, /* directory not empty */ - NFS4ERR_DQUOT = 69, /* hard quota limit reached */ - NFS4ERR_STALE = 70, /* file no longer exists */ - NFS4ERR_BADHANDLE = 10001,/* Illegal filehandle */ - NFS4ERR_BAD_COOKIE = 10003,/* READDIR cookie is stale */ - NFS4ERR_NOTSUPP = 10004,/* operation not supported */ - NFS4ERR_TOOSMALL = 10005,/* response limit exceeded */ - NFS4ERR_SERVERFAULT = 10006,/* undefined server error */ - NFS4ERR_BADTYPE = 10007,/* type invalid for CREATE */ - NFS4ERR_DELAY = 10008,/* file "busy" - retry */ - NFS4ERR_SAME = 10009,/* nverify says attrs same */ - NFS4ERR_DENIED = 10010,/* lock unavailable */ - NFS4ERR_EXPIRED = 10011,/* lock lease expired */ - NFS4ERR_LOCKED = 10012,/* I/O failed due to lock */ - NFS4ERR_GRACE = 10013,/* in grace period */ - NFS4ERR_FHEXPIRED = 10014,/* filehandle expired */ - NFS4ERR_SHARE_DENIED = 10015,/* share reserve denied */ - NFS4ERR_WRONGSEC = 10016,/* wrong security flavor */ - NFS4ERR_CLID_INUSE = 10017,/* clientid in use */ - NFS4ERR_RESOURCE = 10018,/* resource exhaustion */ - NFS4ERR_MOVED = 10019,/* file system relocated */ - NFS4ERR_NOFILEHANDLE = 10020,/* current FH is not set */ - NFS4ERR_MINOR_VERS_MISMATCH = 10021,/* minor vers not supp */ - NFS4ERR_STALE_CLIENTID = 10022,/* server has rebooted */ - NFS4ERR_STALE_STATEID = 10023,/* server has rebooted */ - NFS4ERR_OLD_STATEID = 10024,/* state is out of sync */ - NFS4ERR_BAD_STATEID = 10025,/* incorrect stateid */ - NFS4ERR_BAD_SEQID = 10026,/* request is out of seq. */ - NFS4ERR_NOT_SAME = 10027,/* verify - attrs not same */ - NFS4ERR_LOCK_RANGE = 10028,/* lock range not supported */ - NFS4ERR_SYMLINK = 10029,/* should be file/directory */ - NFS4ERR_RESTOREFH = 10030,/* no saved filehandle */ - NFS4ERR_LEASE_MOVED = 10031,/* some file system moved */ - NFS4ERR_ATTRNOTSUPP = 10032,/* recommended attr not sup */ - NFS4ERR_NO_GRACE = 10033,/* reclaim outside of grace */ - NFS4ERR_RECLAIM_BAD = 10034,/* reclaim error at server */ - NFS4ERR_RECLAIM_CONFLICT = 10035,/* conflict on reclaim */ - NFS4ERR_BADXDR = 10036,/* XDR decode failed */ - NFS4ERR_LOCKS_HELD = 10037,/* file locks held at CLOSE */ - NFS4ERR_OPENMODE = 10038,/* conflict in OPEN and I/O */ - NFS4ERR_BADOWNER = 10039,/* owner translation bad */ - NFS4ERR_BADCHAR = 10040,/* UTF-8 char not supported */ - NFS4ERR_BADNAME = 10041,/* name not supported */ - NFS4ERR_BAD_RANGE = 10042,/* lock range not supported */ - NFS4ERR_LOCK_NOTSUPP = 10043,/* no atomic up/downgrade */ - NFS4ERR_OP_ILLEGAL = 10044,/* undefined operation */ - NFS4ERR_DEADLOCK = 10045,/* file locking deadlock */ - NFS4ERR_FILE_OPEN = 10046,/* open file blocks op. */ - NFS4ERR_ADMIN_REVOKED = 10047,/* lock-owner state revoked */ - NFS4ERR_CB_PATH_DOWN = 10048 /* callback path down */ + NFS4_OK = 0, /* everything is okay */ + NFS4ERR_PERM = 1, /* caller not privileged */ + NFS4ERR_NOENT = 2, /* no such file/directory */ + NFS4ERR_IO = 5, /* hard I/O error */ + NFS4ERR_NXIO = 6, /* no such device */ + NFS4ERR_ACCESS = 13, /* access denied */ + NFS4ERR_EXIST = 17, /* file already exists */ + NFS4ERR_XDEV = 18, /* different file systems */ + +/* + * Please do not allocate value 19; it was used in NFSv3, + * and we do not want a value in NFSv3 to have a different + * meaning in NFSv4.x. + */ + + NFS4ERR_NOTDIR = 20, /* should be a directory */ + NFS4ERR_ISDIR = 21, /* should not be a directory */ + NFS4ERR_INVAL = 22, /* invalid argument */ + NFS4ERR_FBIG = 27, /* file exceeds server max */ + NFS4ERR_NOSPC = 28, /* no space on file system */ + NFS4ERR_ROFS = 30, /* read-only file system */ + NFS4ERR_MLINK = 31, /* too many hard links */ + NFS4ERR_NAMETOOLONG = 63, /* name exceeds server max */ + NFS4ERR_NOTEMPTY = 66, /* directory not empty */ + NFS4ERR_DQUOT = 69, /* hard quota limit reached */ + NFS4ERR_STALE = 70, /* file no longer exists */ + NFS4ERR_BADHANDLE = 10001, /* illegal filehandle */ + NFS4ERR_BAD_COOKIE = 10003, /* READDIR cookie is stale */ + NFS4ERR_NOTSUPP = 10004, /* operation not supported */ + NFS4ERR_TOOSMALL = 10005, /* response limit exceeded */ + NFS4ERR_SERVERFAULT = 10006, /* undefined server error */ + NFS4ERR_BADTYPE = 10007, /* type invalid for CREATE */ + NFS4ERR_DELAY = 10008, /* file "busy" -- retry */ + NFS4ERR_SAME = 10009, /* nverify says attrs same */ + NFS4ERR_DENIED = 10010, /* lock unavailable */ + NFS4ERR_EXPIRED = 10011, /* lock lease expired */ + NFS4ERR_LOCKED = 10012, /* I/O failed due to lock */ + NFS4ERR_GRACE = 10013, /* in grace period */ + NFS4ERR_FHEXPIRED = 10014, /* filehandle expired */ + NFS4ERR_SHARE_DENIED = 10015, /* share reserve denied */ + NFS4ERR_WRONGSEC = 10016, /* wrong security flavor */ + NFS4ERR_CLID_INUSE = 10017, /* client ID in use */ + + /* NFS4ERR_RESOURCE is not a valid error in NFSv4.1. */ + NFS4ERR_RESOURCE = 10018, /* resource exhaustion */ + + NFS4ERR_MOVED = 10019, /* file system relocated */ + NFS4ERR_NOFILEHANDLE = 10020, /* current FH is not set */ + NFS4ERR_MINOR_VERS_MISMATCH= 10021, /* minor vers not supp */ + NFS4ERR_STALE_CLIENTID = 10022, /* server has rebooted */ + NFS4ERR_STALE_STATEID = 10023, /* server has rebooted */ + NFS4ERR_OLD_STATEID = 10024, /* state is out of sync */ + NFS4ERR_BAD_STATEID = 10025, /* incorrect stateid */ + NFS4ERR_BAD_SEQID = 10026, /* request is out of seq. */ + NFS4ERR_NOT_SAME = 10027, /* verify -- attrs not same */ + NFS4ERR_LOCK_RANGE = 10028, /* overlapping lock range */ + NFS4ERR_SYMLINK = 10029, /* should be file/directory */ + NFS4ERR_RESTOREFH = 10030, /* no saved filehandle */ + NFS4ERR_LEASE_MOVED = 10031, /* some file system moved */ + NFS4ERR_ATTRNOTSUPP = 10032, /* recommended attr not supp */ + NFS4ERR_NO_GRACE = 10033, /* reclaim outside of grace */ + NFS4ERR_RECLAIM_BAD = 10034, /* reclaim error at server */ + NFS4ERR_RECLAIM_CONFLICT= 10035, /* conflict on reclaim */ + NFS4ERR_BADXDR = 10036, /* XDR decode failed */ + NFS4ERR_LOCKS_HELD = 10037, /* file locks held at CLOSE */ + NFS4ERR_OPENMODE = 10038, /* conflict in OPEN and I/O */ + NFS4ERR_BADOWNER = 10039, /* owner translation bad */ + NFS4ERR_BADCHAR = 10040, /* UTF-8 char not supported */ + NFS4ERR_BADNAME = 10041, /* name not supported */ + NFS4ERR_BAD_RANGE = 10042, /* lock range not supported */ + NFS4ERR_LOCK_NOTSUPP = 10043, /* no atomic up/downgrade */ + NFS4ERR_OP_ILLEGAL = 10044, /* undefined operation */ + NFS4ERR_DEADLOCK = 10045, /* file-locking deadlock */ + NFS4ERR_FILE_OPEN = 10046, /* open file blocks op */ + NFS4ERR_ADMIN_REVOKED = 10047, /* lock-owner state revoked */ + NFS4ERR_CB_PATH_DOWN = 10048, /* callback path down */ + + /* NFSv4.1 errors start here. */ + + NFS4ERR_BADIOMODE = 10049, + NFS4ERR_BADLAYOUT = 10050, + NFS4ERR_BAD_SESSION_DIGEST = 10051, + NFS4ERR_BADSESSION = 10052, + NFS4ERR_BADSLOT = 10053, + NFS4ERR_COMPLETE_ALREADY = 10054, + NFS4ERR_CONN_NOT_BOUND_TO_SESSION = 10055, + NFS4ERR_DELEG_ALREADY_WANTED = 10056, + NFS4ERR_BACK_CHAN_BUSY = 10057, /* backchan reqs outstanding */ + NFS4ERR_LAYOUTTRYLATER = 10058, + NFS4ERR_LAYOUTUNAVAILABLE = 10059, + NFS4ERR_NOMATCHING_LAYOUT = 10060, + NFS4ERR_RECALLCONFLICT = 10061, + NFS4ERR_UNKNOWN_LAYOUTTYPE = 10062, + NFS4ERR_SEQ_MISORDERED = 10063, /* unexpected seq. ID in req */ + NFS4ERR_SEQUENCE_POS = 10064, /* [CB_]SEQ. op not 1st op */ + NFS4ERR_REQ_TOO_BIG = 10065, /* request too big */ + NFS4ERR_REP_TOO_BIG = 10066, /* reply too big */ + NFS4ERR_REP_TOO_BIG_TO_CACHE =10067, /* rep. not all cached */ + NFS4ERR_RETRY_UNCACHED_REP =10068, /* retry + rep. uncached */ + NFS4ERR_UNSAFE_COMPOUND =10069, /* retry/recovery too hard */ + NFS4ERR_TOO_MANY_OPS = 10070, /* too many ops in [CB_]COMP */ + NFS4ERR_OP_NOT_IN_SESSION =10071, /* op needs [CB_]SEQ. op */ + NFS4ERR_HASH_ALG_UNSUPP = 10072, /* hash alg. not supp */ + /* Error 10073 is unused. */ + NFS4ERR_CLIENTID_BUSY = 10074, /* client ID has state */ + NFS4ERR_PNFS_IO_HOLE = 10075, /* IO to _SPARSE file hole */ + NFS4ERR_SEQ_FALSE_RETRY= 10076, /* retry != original req */ + NFS4ERR_BAD_HIGH_SLOT = 10077, /* req has bad highest_slot */ + NFS4ERR_DEADSESSION = 10078, /* new req sent to dead sess */ + NFS4ERR_ENCR_ALG_UNSUPP= 10079, /* encr alg. not supp */ + NFS4ERR_PNFS_NO_LAYOUT = 10080, /* I/O without a layout */ + NFS4ERR_NOT_ONLY_OP = 10081, /* addl ops not allowed */ + NFS4ERR_WRONG_CRED = 10082, /* op done by wrong cred */ + NFS4ERR_WRONG_TYPE = 10083, /* op on wrong type object */ + NFS4ERR_DIRDELEG_UNAVAIL=10084, /* delegation not avail. */ + NFS4ERR_REJECT_DELEG = 10085, /* cb rejected delegation */ + NFS4ERR_RETURNCONFLICT = 10086, /* layout get before return */ + NFS4ERR_DELEG_REVOKED = 10087, /* deleg./layout revoked */ + + /* NFSv4.2 errors start here. */ + + NFS4ERR_PARTNER_NOTSUPP= 10088, /* s2s not supported */ + NFS4ERR_PARTNER_NO_AUTH= 10089, /* s2s not authorized */ + NFS4ERR_UNION_NOTSUPP = 10090, /* arm of union not supp */ + NFS4ERR_OFFLOAD_DENIED = 10091, /* dest not allowing copy */ + NFS4ERR_WRONG_LFS = 10092, /* LFS not supported */ + NFS4ERR_BADLABEL = 10093, /* incorrect label */ + NFS4ERR_OFFLOAD_NO_REQS= 10094 /* dest not meeting reqs */ }; /* @@ -178,11 +248,13 @@ typedef uint64_t length4; typedef uint32_t mode4; typedef uint64_t nfs_cookie4; typedef opaque nfs_fh4<NFS4_FHSIZE>; -typedef uint32_t nfs_lease4; typedef uint64_t offset4; typedef uint32_t qop4; typedef opaque sec_oid4<>; +typedef uint32_t sequenceid4; typedef uint32_t seqid4; +typedef opaque sessionid4[NFS4_SESSIONID_SIZE]; +typedef uint32_t slotid4; typedef opaque utf8string<>; typedef utf8string utf8str_cis; typedef utf8string utf8str_cs; @@ -191,9 +263,9 @@ typedef utf8str_cs component4; typedef opaque linktext4<>; typedef utf8string ascii_REQUIRED4; typedef component4 pathname4<>; -typedef uint64_t nfs_lockid4; typedef opaque verifier4[NFS4_VERIFIER_SIZE]; - +typedef string secret4<>; +typedef uint32_t policy4; /* * Timeval @@ -216,22 +288,30 @@ union settime4 switch (time_how4 set_it) { }; +typedef uint32_t nfs_lease4; + /* * File attribute definitions */ /* - * FSID structure for major/minor + * File System ID (FSID) structure for major/minor */ struct fsid4 { uint64_t major; uint64_t minor; }; - /* - * File system locations attribute for relocation/migration + * File system locations attribute + * for relocation/migration and + * related attributes */ +struct change_policy4 { + uint64_t cp_major; + uint64_t cp_minor; +}; + struct fs_location4 { utf8str_cis server<>; pathname4 rootpath; @@ -242,14 +322,13 @@ struct fs_locations4 { fs_location4 locations<>; }; - /* - * Various Access Control Entry definitions + * Various Access Control Entry (ACE) definitions */ /* - * Mask that indicates which Access Control Entries - * are supported. Values for the fattr4_aclsupport attribute. + * Mask that indicates which ACEs are supported. + * Values for the fattr4_aclsupport attribute. */ const ACL4_SUPPORT_ALLOW_ACL = 0x00000001; const ACL4_SUPPORT_DENY_ACL = 0x00000002; @@ -261,7 +340,7 @@ typedef uint32_t acetype4; /* - * acetype4 values; others can be added as needed. + * acetype4 values. Others can be added as needed. */ const ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000; const ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001; @@ -273,7 +352,7 @@ const ACE4_SYSTEM_ALARM_ACE_TYPE = 0x00000003; /* * ACE flag */ -typedef uint32_t aceflag4; +typedef uint32_t aceflag4; /* @@ -286,6 +365,7 @@ const ACE4_INHERIT_ONLY_ACE = 0x00000008; const ACE4_SUCCESSFUL_ACCESS_ACE_FLAG = 0x00000010; const ACE4_FAILED_ACCESS_ACE_FLAG = 0x00000020; const ACE4_IDENTIFIER_GROUP = 0x00000040; +const ACE4_INHERITED_ACE = 0x00000080; @@ -310,6 +390,8 @@ const ACE4_EXECUTE = 0x00000020; const ACE4_DELETE_CHILD = 0x00000040; const ACE4_READ_ATTRIBUTES = 0x00000080; const ACE4_WRITE_ATTRIBUTES = 0x00000100; +const ACE4_WRITE_RETENTION = 0x00000200; +const ACE4_WRITE_RETENTION_HOLD = 0x00000400; const ACE4_DELETE = 0x00010000; const ACE4_READ_ACL = 0x00020000; @@ -319,7 +401,7 @@ const ACE4_SYNCHRONIZE = 0x00100000; /* - * ACE4_GENERIC_READ - defined as a combination of + * ACE4_GENERIC_READ -- defined as a combination of * ACE4_READ_ACL | * ACE4_READ_DATA | * ACE4_READ_ATTRIBUTES | @@ -329,7 +411,7 @@ const ACE4_SYNCHRONIZE = 0x00100000; const ACE4_GENERIC_READ = 0x00120081; /* - * ACE4_GENERIC_WRITE - defined as a combination of + * ACE4_GENERIC_WRITE -- defined as a combination of * ACE4_READ_ACL | * ACE4_WRITE_DATA | * ACE4_WRITE_ATTRIBUTES | @@ -341,28 +423,52 @@ const ACE4_GENERIC_WRITE = 0x00160106; /* - * ACE4_GENERIC_EXECUTE - defined as a combination of - * ACE4_READ_ACL - * ACE4_READ_ATTRIBUTES - * ACE4_EXECUTE + * ACE4_GENERIC_EXECUTE -- defined as a combination of + * ACE4_READ_ACL | + * ACE4_READ_ATTRIBUTES | + * ACE4_EXECUTE | * ACE4_SYNCHRONIZE */ const ACE4_GENERIC_EXECUTE = 0x001200A0; /* - * Access Control Entry definition + * ACE definition */ struct nfsace4 { - acetype4 type; - aceflag4 flag; - acemask4 access_mask; - utf8str_mixed who; + acetype4 type; + aceflag4 flag; + acemask4 access_mask; + utf8str_mixed who; }; /* - * Field definitions for the fattr4_mode attribute + * Access Control List (ACL) flag + */ + +typedef uint32_t aclflag4; + +/* + * ACL flag values + */ +const ACL4_AUTO_INHERIT = 0x00000001; +const ACL4_PROTECTED = 0x00000002; +const ACL4_DEFAULTED = 0x00000004; + + +/* + * Version 4.1 ACL definition + */ +struct nfsacl41 { + aclflag4 na41_flag; + nfsace4 na41_aces<>; +}; + + +/* + * Field definitions for the fattr4_mode + * and fattr4_mode_set_masked attributes */ const MODE4_SUID = 0x800; /* set user id on execution */ const MODE4_SGID = 0x400; /* set group id on execution */ @@ -379,15 +485,27 @@ const MODE4_XOTH = 0x001; /* execute permission: other */ /* + * Masked mode for the mode_set_masked attribute + */ +struct mode_masked4 { + mode4 mm_value_to_set; /* Values of bits + to set or reset + in mode */ + + mode4 mm_mask_bits; /* Mask of bits to + set or reset + in mode */ +}; + +/* * Special data/attribute associated with - * file types NF4BLK and NF4CHR. + * file types NF4BLK and NF4CHR */ struct specdata4 { - uint32_t specdata1; /* major device number */ - uint32_t specdata2; /* minor device number */ + uint32_t specdata1; /* Major device number */ + uint32_t specdata2; /* Minor device number */ }; - /* * Values for fattr4_fh_expire_type */ @@ -398,68 +516,366 @@ const FH4_VOL_MIGRATION = 0x00000004; const FH4_VOL_RENAME = 0x00000008; -typedef bitmap4 fattr4_supported_attrs; -typedef nfs_ftype4 fattr4_type; -typedef uint32_t fattr4_fh_expire_type; -typedef changeid4 fattr4_change; -typedef uint64_t fattr4_size; -typedef bool fattr4_link_support; -typedef bool fattr4_symlink_support; -typedef bool fattr4_named_attr; -typedef fsid4 fattr4_fsid; -typedef bool fattr4_unique_handles; -typedef nfs_lease4 fattr4_lease_time; -typedef nfsstat4 fattr4_rdattr_error; - -typedef nfsace4 fattr4_acl<>; -typedef uint32_t fattr4_aclsupport; -typedef bool fattr4_archive; -typedef bool fattr4_cansettime; -typedef bool fattr4_case_insensitive; -typedef bool fattr4_case_preserving; -typedef bool fattr4_chown_restricted; -typedef uint64_t fattr4_fileid; -typedef uint64_t fattr4_files_avail; -typedef nfs_fh4 fattr4_filehandle; -typedef uint64_t fattr4_files_free; -typedef uint64_t fattr4_files_total; -typedef fs_locations4 fattr4_fs_locations; -typedef bool fattr4_hidden; -typedef bool fattr4_homogeneous; -typedef uint64_t fattr4_maxfilesize; -typedef uint32_t fattr4_maxlink; -typedef uint32_t fattr4_maxname; -typedef uint64_t fattr4_maxread; -typedef uint64_t fattr4_maxwrite; -typedef ascii_REQUIRED4 fattr4_mimetype; -typedef mode4 fattr4_mode; -typedef uint64_t fattr4_mounted_on_fileid; -typedef bool fattr4_no_trunc; -typedef uint32_t fattr4_numlinks; -typedef utf8str_mixed fattr4_owner; -typedef utf8str_mixed fattr4_owner_group; -typedef uint64_t fattr4_quota_avail_hard; -typedef uint64_t fattr4_quota_avail_soft; -typedef uint64_t fattr4_quota_used; -typedef specdata4 fattr4_rawdev; -typedef uint64_t fattr4_space_avail; -typedef uint64_t fattr4_space_free; -typedef uint64_t fattr4_space_total; -typedef uint64_t fattr4_space_used; -typedef bool fattr4_system; -typedef nfstime4 fattr4_time_access; -typedef settime4 fattr4_time_access_set; -typedef nfstime4 fattr4_time_backup; -typedef nfstime4 fattr4_time_create; -typedef nfstime4 fattr4_time_delta; -typedef nfstime4 fattr4_time_metadata; -typedef nfstime4 fattr4_time_modify; -typedef settime4 fattr4_time_modify_set; - - -/* - * Mandatory attributes +struct netaddr4 { + /* See struct rpcb in RFC 1833. */ + string na_r_netid<>; /* Network id */ + string na_r_addr<>; /* Universal address */ +}; + + +/* + * Data structures new to NFSv4.1 + */ + +struct nfs_impl_id4 { + utf8str_cis nii_domain; + utf8str_cs nii_name; + nfstime4 nii_date; +}; + + +/* + * Stateid + */ +struct stateid4 { + uint32_t seqid; + opaque other[NFS4_OTHER_SIZE]; +}; + +enum layouttype4 { + LAYOUT4_NFSV4_1_FILES = 0x1, + LAYOUT4_OSD2_OBJECTS = 0x2, + LAYOUT4_BLOCK_VOLUME = 0x3 +}; + +struct layout_content4 { + layouttype4 loc_type; + opaque loc_body<>; +}; + + +%/* +% * LAYOUT4_OSD2_OBJECTS loc_body description +% * is in a separate .x file. +% */ +% +%/* +% * LAYOUT4_BLOCK_VOLUME loc_body description +% * is in a separate .x file. +% */ + +struct layouthint4 { + layouttype4 loh_type; + opaque loh_body<>; +}; + +enum layoutiomode4 { + LAYOUTIOMODE4_READ = 1, + LAYOUTIOMODE4_RW = 2, + LAYOUTIOMODE4_ANY = 3 +}; + +struct layout4 { + offset4 lo_offset; + length4 lo_length; + layoutiomode4 lo_iomode; + layout_content4 lo_content; +}; + +const NFS4_DEVICEID4_SIZE = 16; + +typedef opaque deviceid4[NFS4_DEVICEID4_SIZE]; + +struct device_addr4 { + layouttype4 da_layout_type; + opaque da_addr_body<>; +}; + + +struct layoutupdate4 { + layouttype4 lou_type; + opaque lou_body<>; +}; + +% +/* Constants used for LAYOUTRETURN and CB_LAYOUTRECALL */ +const LAYOUT4_RET_REC_FILE = 1; +const LAYOUT4_RET_REC_FSID = 2; +const LAYOUT4_RET_REC_ALL = 3; +% +enum layoutreturn_type4 { + LAYOUTRETURN4_FILE = LAYOUT4_RET_REC_FILE, + LAYOUTRETURN4_FSID = LAYOUT4_RET_REC_FSID, + LAYOUTRETURN4_ALL = LAYOUT4_RET_REC_ALL +}; + +struct layoutreturn_file4 { + offset4 lrf_offset; + length4 lrf_length; + stateid4 lrf_stateid; +% /* layouttype4 specific data */ + opaque lrf_body<>; +}; + +union layoutreturn4 switch (layoutreturn_type4 lr_returntype) { + case LAYOUTRETURN4_FILE: + layoutreturn_file4 lr_layout; + default: + void; +}; +% + +enum fs4_status_type { + STATUS4_FIXED = 1, + STATUS4_UPDATED = 2, + STATUS4_VERSIONED = 3, + STATUS4_WRITABLE = 4, + STATUS4_REFERRAL = 5 +}; + +struct fs4_status { + bool fss_absent; + fs4_status_type fss_type; + utf8str_cs fss_source; + utf8str_cs fss_current; + int32_t fss_age; + nfstime4 fss_version; +}; + + +const TH4_READ_SIZE = 0; +const TH4_WRITE_SIZE = 1; +const TH4_READ_IOSIZE = 2; +const TH4_WRITE_IOSIZE = 3; + +typedef length4 threshold4_read_size; +typedef length4 threshold4_write_size; +typedef length4 threshold4_read_iosize; +typedef length4 threshold4_write_iosize; + +struct threshold_item4 { + layouttype4 thi_layout_type; + bitmap4 thi_hintset; + opaque thi_hintlist<>; +}; + +struct mdsthreshold4 { + threshold_item4 mth_hints<>; +}; + +const RET4_DURATION_INFINITE = 0xffffffffffffffff; +struct retention_get4 { + uint64_t rg_duration; + nfstime4 rg_begin_time<1>; +}; + +struct retention_set4 { + bool rs_enable; + uint64_t rs_duration<1>; +}; + +const FSCHARSET_CAP4_CONTAINS_NON_UTF8 = 0x1; +const FSCHARSET_CAP4_ALLOWS_ONLY_UTF8 = 0x2; + +typedef uint32_t fs_charset_cap4; + + +/* + * Data structures new to NFSv4.2 */ + +enum netloc_type4 { + NL4_NAME = 1, + NL4_URL = 2, + NL4_NETADDR = 3 +}; +union netloc4 switch (netloc_type4 nl_type) { + case NL4_NAME: utf8str_cis nl_name; + case NL4_URL: utf8str_cis nl_url; + case NL4_NETADDR: netaddr4 nl_addr; +}; + +enum change_attr_type4 { + NFS4_CHANGE_TYPE_IS_MONOTONIC_INCR = 0, + NFS4_CHANGE_TYPE_IS_VERSION_COUNTER = 1, + NFS4_CHANGE_TYPE_IS_VERSION_COUNTER_NOPNFS = 2, + NFS4_CHANGE_TYPE_IS_TIME_METADATA = 3, + NFS4_CHANGE_TYPE_IS_UNDEFINED = 4 +}; + +struct labelformat_spec4 { + policy4 lfs_lfs; + policy4 lfs_pi; +}; + +struct sec_label4 { + labelformat_spec4 slai_lfs; + opaque slai_data<>; +}; + + +struct copy_from_auth_priv { + secret4 cfap_shared_secret; + netloc4 cfap_destination; + /* The NFSv4 user name that the user principal maps to */ + utf8str_mixed cfap_username; +}; + +struct copy_to_auth_priv { + /* Equal to cfap_shared_secret */ + secret4 ctap_shared_secret; + netloc4 ctap_source<>; + /* The NFSv4 user name that the user principal maps to */ + utf8str_mixed ctap_username; +}; + +struct copy_confirm_auth_priv { + /* Equal to GSS_GetMIC() of cfap_shared_secret */ + opaque ccap_shared_secret_mic<>; + /* The NFSv4 user name that the user principal maps to */ + utf8str_mixed ccap_username; +}; + + +struct app_data_block4 { + offset4 adb_offset; + length4 adb_block_size; + length4 adb_block_count; + length4 adb_reloff_blocknum; + count4 adb_block_num; + length4 adb_reloff_pattern; + opaque adb_pattern<>; +}; + + +struct data4 { + offset4 d_offset; + opaque d_data<>; +}; + +struct data_info4 { + offset4 di_offset; + length4 di_length; +}; + + +enum data_content4 { + NFS4_CONTENT_DATA = 0, + NFS4_CONTENT_HOLE = 1 +}; + + + +enum stable_how4 { + UNSTABLE4 = 0, + DATA_SYNC4 = 1, + FILE_SYNC4 = 2 +}; + + + +struct write_response4 { + stateid4 wr_callback_id<1>; + length4 wr_count; + stable_how4 wr_committed; + verifier4 wr_writeverf; +}; + + +/* + * NFSv4.1 attributes + */ +typedef bitmap4 fattr4_supported_attrs; +typedef nfs_ftype4 fattr4_type; +typedef uint32_t fattr4_fh_expire_type; +typedef changeid4 fattr4_change; +typedef uint64_t fattr4_size; +typedef bool fattr4_link_support; +typedef bool fattr4_symlink_support; +typedef bool fattr4_named_attr; +typedef fsid4 fattr4_fsid; +typedef bool fattr4_unique_handles; +typedef nfs_lease4 fattr4_lease_time; +typedef nfsstat4 fattr4_rdattr_error; +typedef nfsace4 fattr4_acl<>; +typedef uint32_t fattr4_aclsupport; +typedef bool fattr4_archive; +typedef bool fattr4_cansettime; +typedef bool fattr4_case_insensitive; +typedef bool fattr4_case_preserving; +typedef bool fattr4_chown_restricted; +typedef uint64_t fattr4_fileid; +typedef uint64_t fattr4_files_avail; +typedef nfs_fh4 fattr4_filehandle; +typedef uint64_t fattr4_files_free; +typedef uint64_t fattr4_files_total; +typedef fs_locations4 fattr4_fs_locations; +typedef bool fattr4_hidden; +typedef bool fattr4_homogeneous; +typedef uint64_t fattr4_maxfilesize; +typedef uint32_t fattr4_maxlink; +typedef uint32_t fattr4_maxname; +typedef uint64_t fattr4_maxread; +typedef uint64_t fattr4_maxwrite; +typedef ascii_REQUIRED4 fattr4_mimetype; +typedef mode4 fattr4_mode; +typedef mode_masked4 fattr4_mode_set_masked; +typedef uint64_t fattr4_mounted_on_fileid; +typedef bool fattr4_no_trunc; +typedef uint32_t fattr4_numlinks; +typedef utf8str_mixed fattr4_owner; +typedef utf8str_mixed fattr4_owner_group; +typedef uint64_t fattr4_quota_avail_hard; +typedef uint64_t fattr4_quota_avail_soft; +typedef uint64_t fattr4_quota_used; +typedef specdata4 fattr4_rawdev; +typedef uint64_t fattr4_space_avail; +typedef length4 fattr4_space_free; +typedef uint64_t fattr4_space_total; +typedef uint64_t fattr4_space_used; +typedef bool fattr4_system; +typedef nfstime4 fattr4_time_access; +typedef settime4 fattr4_time_access_set; +typedef nfstime4 fattr4_time_backup; +typedef nfstime4 fattr4_time_create; +typedef nfstime4 fattr4_time_delta; +typedef nfstime4 fattr4_time_metadata; +typedef nfstime4 fattr4_time_modify; +typedef settime4 fattr4_time_modify_set; +/* + * Attributes new to NFSv4.1 + */ +typedef bitmap4 fattr4_suppattr_exclcreat; +typedef nfstime4 fattr4_dir_notif_delay; +typedef nfstime4 fattr4_dirent_notif_delay; +typedef layouttype4 fattr4_fs_layout_types<>; +typedef fs4_status fattr4_fs_status; +typedef fs_charset_cap4 fattr4_fs_charset_cap; +typedef uint32_t fattr4_layout_alignment; +typedef uint32_t fattr4_layout_blksize; +typedef layouthint4 fattr4_layout_hint; +typedef layouttype4 fattr4_layout_types<>; +typedef mdsthreshold4 fattr4_mdsthreshold; +typedef retention_get4 fattr4_retention_get; +typedef retention_set4 fattr4_retention_set; +typedef retention_get4 fattr4_retentevt_get; +typedef retention_set4 fattr4_retentevt_set; +typedef uint64_t fattr4_retention_hold; +typedef nfsacl41 fattr4_dacl; +typedef nfsacl41 fattr4_sacl; +typedef change_policy4 fattr4_change_policy; +/* + * Attributes new to NFSv4.2 + */ +typedef uint64_t fattr4_space_freed; +typedef change_attr_type4 + fattr4_change_attr_type; +typedef sec_label4 fattr4_sec_label; +typedef uint32_t fattr4_clone_blksize; + +%/* +% * REQUIRED attributes +% */ const FATTR4_SUPPORTED_ATTRS = 0; const FATTR4_TYPE = 1; const FATTR4_FH_EXPIRE_TYPE = 2; @@ -474,9 +890,14 @@ const FATTR4_LEASE_TIME = 10; const FATTR4_RDATTR_ERROR = 11; const FATTR4_FILEHANDLE = 19; -/* - * Recommended attributes - */ +%/* +% * New to NFSv4.1 +% */ +const FATTR4_SUPPATTR_EXCLCREAT = 75; + +%/* +% * RECOMMENDED attributes +% */ const FATTR4_ACL = 12; const FATTR4_ACLSUPPORT = 13; const FATTR4_ARCHIVE = 14; @@ -521,6 +942,38 @@ const FATTR4_TIME_MODIFY = 53; const FATTR4_TIME_MODIFY_SET = 54; const FATTR4_MOUNTED_ON_FILEID = 55; +%/* +% * New to NFSv4.1 +% */ +const FATTR4_DIR_NOTIF_DELAY = 56; +const FATTR4_DIRENT_NOTIF_DELAY = 57; +const FATTR4_DACL = 58; +const FATTR4_SACL = 59; +const FATTR4_CHANGE_POLICY = 60; +const FATTR4_FS_STATUS = 61; +const FATTR4_FS_LAYOUT_TYPES = 62; +const FATTR4_LAYOUT_HINT = 63; +const FATTR4_LAYOUT_TYPES = 64; +const FATTR4_LAYOUT_BLKSIZE = 65; +const FATTR4_LAYOUT_ALIGNMENT = 66; +const FATTR4_FS_LOCATIONS_INFO = 67; +const FATTR4_MDSTHRESHOLD = 68; +const FATTR4_RETENTION_GET = 69; +const FATTR4_RETENTION_SET = 70; +const FATTR4_RETENTEVT_GET = 71; +const FATTR4_RETENTEVT_SET = 72; +const FATTR4_RETENTION_HOLD = 73; +const FATTR4_MODE_SET_MASKED = 74; +const FATTR4_FS_CHARSET_CAP = 76; + +%/* +% * New to NFSv4.2 +% */ +const FATTR4_CLONE_BLKSIZE = 77; +const FATTR4_SPACE_FREED = 78; +const FATTR4_CHANGE_ATTR_TYPE = 79; +const FATTR4_SEC_LABEL = 80; + /* * File attribute container */ @@ -529,7 +982,6 @@ struct fattr4 { attrlist4 attr_vals; }; - /* * Change info for the client */ @@ -539,66 +991,336 @@ struct change_info4 { changeid4 after; }; - -struct clientaddr4 { - /* see struct rpcb in RFC 1833 */ - string r_netid<>; /* network id */ - string r_addr<>; /* universal address */ -}; - +typedef netaddr4 clientaddr4; /* * Callback program info as provided by the client */ struct cb_client4 { - unsigned int cb_program; - clientaddr4 cb_location; + uint32_t cb_program; + netaddr4 cb_location; }; - /* - * Stateid + * NFSv4.0 long-hand client ID */ -struct stateid4 { - uint32_t seqid; - opaque other[NFS4_OTHER_SIZE]; +struct nfs_client_id4 { + verifier4 verifier; + opaque id<NFS4_OPAQUE_LIMIT>; }; /* - * Client ID + * NFSv4.1 client owner (aka long-hand client ID) */ -struct nfs_client_id4 { - verifier4 verifier; - opaque id<NFS4_OPAQUE_LIMIT>; +struct client_owner4 { + verifier4 co_verifier; + opaque co_ownerid<NFS4_OPAQUE_LIMIT>; }; -struct open_owner4 { - clientid4 clientid; - opaque owner<NFS4_OPAQUE_LIMIT>; +/* + * NFSv4.1 server owner + */ +struct server_owner4 { + uint64_t so_minor_id; + opaque so_major_id<NFS4_OPAQUE_LIMIT>; }; -struct lock_owner4 { +struct state_owner4 { clientid4 clientid; opaque owner<NFS4_OPAQUE_LIMIT>; }; +typedef state_owner4 open_owner4; +typedef state_owner4 lock_owner4; + enum nfs_lock_type4 { READ_LT = 1, WRITE_LT = 2, - READW_LT = 3, /* blocking read */ - WRITEW_LT = 4 /* blocking write */ + READW_LT = 3, /* Blocking read */ + WRITEW_LT = 4 /* Blocking write */ +}; + + +% +%/* Input for computing subkeys */ +enum ssv_subkey4 { + SSV4_SUBKEY_MIC_I2T = 1, + SSV4_SUBKEY_MIC_T2I = 2, + SSV4_SUBKEY_SEAL_I2T = 3, + SSV4_SUBKEY_SEAL_T2I = 4 +}; +% + +% +%/* Input for computing smt_hmac */ +struct ssv_mic_plain_tkn4 { + uint32_t smpt_ssv_seq; + opaque smpt_orig_plain<>; +}; +% + +% +%/* +% * Secret State Verifier Generic Security Service (SSV GSS) +% * PerMsgToken token +% */ +struct ssv_mic_tkn4 { + uint32_t smt_ssv_seq; + opaque smt_hmac<>; +}; +% + +% +%/* Input for computing ssct_encr_data and ssct_hmac */ +struct ssv_seal_plain_tkn4 { + opaque sspt_confounder<>; + uint32_t sspt_ssv_seq; + opaque sspt_orig_plain<>; + opaque sspt_pad<>; +}; +% + +% +%/* SSV GSS SealedMessage token */ +struct ssv_seal_cipher_tkn4 { + uint32_t ssct_ssv_seq; + opaque ssct_iv<>; + opaque ssct_encr_data<>; + opaque ssct_hmac<>; +}; +% + +/* + * Defines an individual server replica + */ +struct fs_locations_server4 { + int32_t fls_currency; + opaque fls_info<>; + utf8str_cis fls_server; +}; + +/* + * Byte indices of items within + * fls_info: flag fields, class numbers, + * bytes indicating ranks and orders + */ +const FSLI4BX_GFLAGS = 0; +const FSLI4BX_TFLAGS = 1; + +const FSLI4BX_CLSIMUL = 2; +const FSLI4BX_CLHANDLE = 3; +const FSLI4BX_CLFILEID = 4; +const FSLI4BX_CLWRITEVER = 5; +const FSLI4BX_CLCHANGE = 6; +const FSLI4BX_CLREADDIR = 7; + +const FSLI4BX_READRANK = 8; +const FSLI4BX_WRITERANK = 9; +const FSLI4BX_READORDER = 10; +const FSLI4BX_WRITEORDER = 11; + +/* + * Bits defined within the general flag byte + */ +const FSLI4GF_WRITABLE = 0x01; +const FSLI4GF_CUR_REQ = 0x02; +const FSLI4GF_ABSENT = 0x04; +const FSLI4GF_GOING = 0x08; +const FSLI4GF_SPLIT = 0x10; + +/* + * Bits defined within the transport flag byte + */ +const FSLI4TF_RDMA = 0x01; + +/* + * Defines a set of replicas sharing + * a common value of the root path + * within the corresponding + * single-server namespaces + */ +struct fs_locations_item4 { + fs_locations_server4 fli_entries<>; + pathname4 fli_rootpath; +}; + +/* + * Defines the overall structure of + * the fs_locations_info attribute + */ +struct fs_locations_info4 { + uint32_t fli_flags; + int32_t fli_valid_for; + pathname4 fli_fs_root; + fs_locations_item4 fli_items<>; }; +/* + * Flag bits in fli_flags + */ +const FSLI4IF_VAR_SUB = 0x00000001; + +typedef fs_locations_info4 fattr4_fs_locations_info; + +const NFL4_UFLG_MASK = 0x0000003F; +const NFL4_UFLG_DENSE = 0x00000001; +const NFL4_UFLG_COMMIT_THRU_MDS = 0x00000002; +const NFL42_UFLG_IO_ADVISE_THRU_MDS = 0x00000004; +const NFL4_UFLG_STRIPE_UNIT_SIZE_MASK = 0xFFFFFFC0; + +typedef uint32_t nfl_util4; + +% + +enum filelayout_hint_care4 { + NFLH4_CARE_DENSE = NFL4_UFLG_DENSE, -const ACCESS4_READ = 0x00000001; -const ACCESS4_LOOKUP = 0x00000002; -const ACCESS4_MODIFY = 0x00000004; -const ACCESS4_EXTEND = 0x00000008; -const ACCESS4_DELETE = 0x00000010; -const ACCESS4_EXECUTE = 0x00000020; + NFLH4_CARE_COMMIT_THRU_MDS + = NFL4_UFLG_COMMIT_THRU_MDS, + + NFL42_CARE_IO_ADVISE_THRU_MDS + = NFL42_UFLG_IO_ADVISE_THRU_MDS, + + NFLH4_CARE_STRIPE_UNIT_SIZE + = 0x00000040, + + NFLH4_CARE_STRIPE_COUNT = 0x00000080 +}; +% +%/* +% * Encoded in the loh_body field of data type layouthint4: +% */ +% +struct nfsv4_1_file_layouthint4 { + uint32_t nflh_care; + nfl_util4 nflh_util; + count4 nflh_stripe_count; +}; + +% + +% +typedef netaddr4 multipath_list4<>; +% +%/* +% * Encoded in the da_addr_body field of data type device_addr4: +% */ +struct nfsv4_1_file_layout_ds_addr4 { + uint32_t nflda_stripe_indices<>; + multipath_list4 nflda_multipath_ds_list<>; +}; + +% + +% +%/* +% * Encoded in the loc_body field of data type layout_content4: +% */ +struct nfsv4_1_file_layout4 { + deviceid4 nfl_deviceid; + nfl_util4 nfl_util; + uint32_t nfl_first_stripe_index; + offset4 nfl_pattern_offset; + nfs_fh4 nfl_fh_list<>; +}; + +% + + +/* + * Operation arrays (the opnum first) + */ + +enum nfs_opnum4 { + OP_ACCESS = 3, + OP_CLOSE = 4, + OP_COMMIT = 5, + OP_CREATE = 6, + OP_DELEGPURGE = 7, + OP_DELEGRETURN = 8, + OP_GETATTR = 9, + OP_GETFH = 10, + OP_LINK = 11, + OP_LOCK = 12, + OP_LOCKT = 13, + OP_LOCKU = 14, + OP_LOOKUP = 15, + OP_LOOKUPP = 16, + OP_NVERIFY = 17, + OP_OPEN = 18, + OP_OPENATTR = 19, + OP_OPEN_CONFIRM = 20, /* Mandatory not-to-implement */ + OP_OPEN_DOWNGRADE = 21, + OP_PUTFH = 22, + OP_PUTPUBFH = 23, + OP_PUTROOTFH = 24, + OP_READ = 25, + OP_READDIR = 26, + OP_READLINK = 27, + OP_REMOVE = 28, + OP_RENAME = 29, + OP_RENEW = 30, /* Mandatory not-to-implement */ + OP_RESTOREFH = 31, + OP_SAVEFH = 32, + OP_SECINFO = 33, + OP_SETATTR = 34, + OP_SETCLIENTID = 35, /* Mandatory not-to-implement */ + OP_SETCLIENTID_CONFIRM = 36, /* Mandatory not-to-implement */ + OP_VERIFY = 37, + OP_WRITE = 38, + OP_RELEASE_LOCKOWNER = 39, /* Mandatory not-to-implement */ +% +%/* New operations for NFSv4.1 */ +% + OP_BACKCHANNEL_CTL = 40, + OP_BIND_CONN_TO_SESSION = 41, + OP_EXCHANGE_ID = 42, + OP_CREATE_SESSION = 43, + OP_DESTROY_SESSION = 44, + OP_FREE_STATEID = 45, + OP_GET_DIR_DELEGATION = 46, + OP_GETDEVICEINFO = 47, + OP_GETDEVICELIST = 48, + OP_LAYOUTCOMMIT = 49, + OP_LAYOUTGET = 50, + OP_LAYOUTRETURN = 51, + OP_SECINFO_NO_NAME = 52, + OP_SEQUENCE = 53, + OP_SET_SSV = 54, + OP_TEST_STATEID = 55, + OP_WANT_DELEGATION = 56, + OP_DESTROY_CLIENTID = 57, + OP_RECLAIM_COMPLETE = 58, +% +%/* New operations for NFSv4.2 */ +% + OP_ALLOCATE = 59, + OP_COPY = 60, + OP_COPY_NOTIFY = 61, + OP_DEALLOCATE = 62, + OP_IO_ADVISE = 63, + OP_LAYOUTERROR = 64, + OP_LAYOUTSTATS = 65, + OP_OFFLOAD_CANCEL = 66, + OP_OFFLOAD_STATUS = 67, + OP_READ_PLUS = 68, + OP_SEEK = 69, + OP_WRITE_SAME = 70, + OP_CLONE = 71, + OP_ILLEGAL = 10044 +}; + + + +const ACCESS4_READ = 0x00000001; +const ACCESS4_LOOKUP = 0x00000002; +const ACCESS4_MODIFY = 0x00000004; +const ACCESS4_EXTEND = 0x00000008; +const ACCESS4_DELETE = 0x00000010; +const ACCESS4_EXECUTE = 0x00000020; struct ACCESS4args { /* CURRENT_FH: object */ @@ -612,11 +1334,24 @@ struct ACCESS4resok { union ACCESS4res switch (nfsstat4 status) { case NFS4_OK: - ACCESS4resok resok4; + ACCESS4resok resok4; default: void; }; +struct CLONE4args { + /* SAVED_FH: source file */ + /* CURRENT_FH: destination file */ + stateid4 cl_src_stateid; + stateid4 cl_dst_stateid; + offset4 cl_src_offset; + offset4 cl_dst_offset; + length4 cl_count; +}; + +struct CLONE4res { + nfsstat4 cl_status; +}; struct CLOSE4args { /* CURRENT_FH: object */ seqid4 seqid; @@ -658,7 +1393,7 @@ union createtype4 switch (nfs_ftype4 type) { case NF4DIR: void; default: - void; /* server should return NFS4ERR_BADTYPE */ + void; /* Server should return NFS4ERR_BADTYPE. */ }; struct CREATE4args { @@ -670,11 +1405,12 @@ struct CREATE4args { struct CREATE4resok { change_info4 cinfo; - bitmap4 attrset; /* attributes set */ + bitmap4 attrset; /* Attributes set */ }; union CREATE4res switch (nfsstat4 status) { case NFS4_OK: + /* New CURRENTFH: created object */ CREATE4resok resok4; default: void; @@ -689,7 +1425,7 @@ struct DELEGPURGE4res { }; struct DELEGRETURN4args { - /* CURRENT_FH: delegated file */ + /* CURRENT_FH: delegated object */ stateid4 deleg_stateid; }; @@ -698,7 +1434,7 @@ struct DELEGRETURN4res { }; struct GETATTR4args { - /* CURRENT_FH: directory or file */ + /* CURRENT_FH: object */ bitmap4 attr_request; }; @@ -742,7 +1478,8 @@ union LINK4res switch (nfsstat4 status) { }; /* - * For LOCK, transition from open_owner to new lock_owner + * For LOCK, transition from open_stateid and lock_owner + * to a lock stateid. */ struct open_to_lock_owner4 { seqid4 open_seqid; @@ -752,7 +1489,8 @@ struct open_to_lock_owner4 { }; /* - * For LOCK, existing lock_owner continues to request file locks + * For LOCK, existing lock stateid continues to request new + * file lock for the same lock_owner and open_stateid. */ struct exist_lock_owner4 { stateid4 lock_stateid; @@ -837,12 +1575,12 @@ struct LOOKUP4args { }; struct LOOKUP4res { - /* CURRENT_FH: object */ + /* New CURRENT_FH: object */ nfsstat4 status; }; struct LOOKUPP4res { - /* CURRENT_FH: directory */ + /* New CURRENT_FH: parent directory */ nfsstat4 status; }; @@ -855,21 +1593,25 @@ struct NVERIFY4res { nfsstat4 status; }; -const OPEN4_SHARE_ACCESS_READ = 0x00000001; -const OPEN4_SHARE_ACCESS_WRITE = 0x00000002; -const OPEN4_SHARE_ACCESS_BOTH = 0x00000003; - -const OPEN4_SHARE_DENY_NONE = 0x00000000; -const OPEN4_SHARE_DENY_READ = 0x00000001; -const OPEN4_SHARE_DENY_WRITE = 0x00000002; -const OPEN4_SHARE_DENY_BOTH = 0x00000003; /* * Various definitions for OPEN */ enum createmode4 { UNCHECKED4 = 0, GUARDED4 = 1, - EXCLUSIVE4 = 2 + /* Deprecated in NFSv4.1 */ + EXCLUSIVE4 = 2, + /* + * New to NFSv4.1. If session is persistent, + * GUARDED4 MUST be used. Otherwise, use + * EXCLUSIVE4_1 instead of EXCLUSIVE4. + */ + EXCLUSIVE4_1 = 3 +}; + +struct creatverfattr { + verifier4 cva_verf; + fattr4 cva_attrs; }; union createhow4 switch (createmode4 mode) { @@ -878,6 +1620,8 @@ union createhow4 switch (createmode4 mode) { fattr4 createattrs; case EXCLUSIVE4: verifier4 createverf; + case EXCLUSIVE4_1: + creatverfattr ch_createboth; }; enum opentype4 { @@ -896,7 +1640,7 @@ union openflag4 switch (opentype4 opentype) { enum limit_by4 { NFS_LIMIT_SIZE = 1, NFS_LIMIT_BLOCKS = 2 - /* others as needed */ + /* Others as needed */ }; struct nfs_modified_limit4 { @@ -905,25 +1649,80 @@ struct nfs_modified_limit4 { }; union nfs_space_limit4 switch (limit_by4 limitby) { - /* limit specified as file size */ + /* Limit specified as file size */ case NFS_LIMIT_SIZE: uint64_t filesize; - /* limit specified by number of blocks */ + /* Limit specified by number of blocks */ case NFS_LIMIT_BLOCKS: nfs_modified_limit4 mod_blocks; -} ; +}; + +/* + * Share Access and Deny constants for open argument + */ +const OPEN4_SHARE_ACCESS_READ = 0x00000001; +const OPEN4_SHARE_ACCESS_WRITE = 0x00000002; +const OPEN4_SHARE_ACCESS_BOTH = 0x00000003; + +const OPEN4_SHARE_DENY_NONE = 0x00000000; +const OPEN4_SHARE_DENY_READ = 0x00000001; +const OPEN4_SHARE_DENY_WRITE = 0x00000002; +const OPEN4_SHARE_DENY_BOTH = 0x00000003; + + +/* New flags for share_access field of OPEN4args */ +const OPEN4_SHARE_ACCESS_WANT_DELEG_MASK = 0xFF00; +const OPEN4_SHARE_ACCESS_WANT_NO_PREFERENCE = 0x0000; +const OPEN4_SHARE_ACCESS_WANT_READ_DELEG = 0x0100; +const OPEN4_SHARE_ACCESS_WANT_WRITE_DELEG = 0x0200; +const OPEN4_SHARE_ACCESS_WANT_ANY_DELEG = 0x0300; +const OPEN4_SHARE_ACCESS_WANT_NO_DELEG = 0x0400; +const OPEN4_SHARE_ACCESS_WANT_CANCEL = 0x0500; + +const + OPEN4_SHARE_ACCESS_WANT_SIGNAL_DELEG_WHEN_RESRC_AVAIL + = 0x10000; + +const + OPEN4_SHARE_ACCESS_WANT_PUSH_DELEG_WHEN_UNCONTENDED + = 0x20000; enum open_delegation_type4 { OPEN_DELEGATE_NONE = 0, OPEN_DELEGATE_READ = 1, - OPEN_DELEGATE_WRITE = 2 + OPEN_DELEGATE_WRITE = 2, + OPEN_DELEGATE_NONE_EXT = 3 /* New to NFSv4.1 */ }; enum open_claim_type4 { + /* + * Not a reclaim + */ CLAIM_NULL = 0, + CLAIM_PREVIOUS = 1, CLAIM_DELEGATE_CUR = 2, - CLAIM_DELEGATE_PREV = 3 + CLAIM_DELEGATE_PREV = 3, + + /* + * Not a reclaim + * + * Like CLAIM_NULL, but object identified + * by the current filehandle + */ + CLAIM_FH = 4, /* New to NFSv4.1 */ + + /* + * Like CLAIM_DELEGATE_CUR, but object identified + * by current filehandle + */ + CLAIM_DELEG_CUR_FH = 5, /* New to NFSv4.1 */ + + /* + * Like CLAIM_DELEGATE_PREV, but object identified + * by current filehandle + */ + CLAIM_DELEG_PREV_FH = 6 /* New to NFSv4.1 */ }; struct open_claim_delegate_cur4 { @@ -964,12 +1763,41 @@ union open_claim4 switch (open_claim_type4 claim) { * of the client. File is specified by name. */ case CLAIM_DELEGATE_PREV: - /* CURRENT_FH: directory */ + /* CURRENT_FH: directory */ component4 file_delegate_prev; + + /* + * Like CLAIM_NULL. No special rights + * to file. Ordinary OPEN of the + * specified file by current filehandle. + */ + case CLAIM_FH: /* New to NFSv4.1 */ + /* CURRENT_FH: regular file to open */ + void; + + /* + * Like CLAIM_DELEGATE_PREV. Right to file based on a + * delegation granted to a previous boot + * instance of the client. File is identified + * by filehandle. + */ + case CLAIM_DELEG_PREV_FH: /* New to NFSv4.1 */ + /* CURRENT_FH: file being opened */ + void; + + /* + * Like CLAIM_DELEGATE_CUR. Right to file based on + * a delegation granted by the server. + * File is identified by filehandle. + */ + case CLAIM_DELEG_CUR_FH: /* New to NFSv4.1 */ + /* CURRENT_FH: file being opened */ + stateid4 oc_delegate_stateid; + }; /* - * OPEN: Open a file, potentially receiving an open delegation + * OPEN: Open a file, potentially receiving an open delegation. */ struct OPEN4args { seqid4 seqid; @@ -984,11 +1812,11 @@ struct open_read_delegation4 { stateid4 stateid; /* Stateid for delegation */ bool recall; /* Pre-recalled flag for delegations obtained - by reclaim (CLAIM_PREVIOUS). */ + by reclaim (CLAIM_PREVIOUS) */ nfsace4 permissions; /* Defines users who don't need an ACCESS call to - open for read. */ + open for read */ }; struct open_write_delegation4 { @@ -996,52 +1824,85 @@ struct open_write_delegation4 { bool recall; /* Pre-recalled flag for delegations obtained by reclaim - (CLAIM_PREVIOUS). */ + (CLAIM_PREVIOUS) */ nfs_space_limit4 space_limit; /* Defines condition that the client must check to determine whether the file needs to be flushed - to the server on close. */ + to the server on close */ nfsace4 permissions; /* Defines users who don't need an ACCESS call as part of a delegated - open. */ + open */ +}; + + +enum why_no_delegation4 { /* New to NFSv4.1 */ + WND4_NOT_WANTED = 0, + WND4_CONTENTION = 1, + WND4_RESOURCE = 2, + WND4_NOT_SUPP_FTYPE = 3, + WND4_WRITE_DELEG_NOT_SUPP_FTYPE = 4, + WND4_NOT_SUPP_UPGRADE = 5, + WND4_NOT_SUPP_DOWNGRADE = 6, + WND4_CANCELLED = 7, + WND4_IS_DIR = 8 +}; + +union open_none_delegation4 /* New to NFSv4.1 */ + switch (why_no_delegation4 ond_why) { + case WND4_CONTENTION: + bool ond_server_will_push_deleg; + case WND4_RESOURCE: + bool ond_server_will_signal_avail; + default: + void; }; union open_delegation4 -switch (open_delegation_type4 delegation_type) { - case OPEN_DELEGATE_NONE: - void; - case OPEN_DELEGATE_READ: - open_read_delegation4 read; - case OPEN_DELEGATE_WRITE: - open_write_delegation4 write; + switch (open_delegation_type4 delegation_type) { + case OPEN_DELEGATE_NONE: + void; + case OPEN_DELEGATE_READ: + open_read_delegation4 read; + case OPEN_DELEGATE_WRITE: + open_write_delegation4 write; + case OPEN_DELEGATE_NONE_EXT: /* New to NFSv4.1 */ + open_none_delegation4 od_whynone; }; /* * Result flags */ -/* Client must confirm open */ +/* Client must confirm open. */ const OPEN4_RESULT_CONFIRM = 0x00000002; -/* Type of file locking behavior at the server */ +/* Type of file-locking behavior at the server */ const OPEN4_RESULT_LOCKTYPE_POSIX = 0x00000004; +/* Server will preserve file if removed while open. */ +const OPEN4_RESULT_PRESERVE_UNLINKED = 0x00000008; + +/* + * Server may use CB_NOTIFY_LOCK on locks + * derived from this open. + */ +const OPEN4_RESULT_MAY_NOTIFY_LOCK = 0x00000020; struct OPEN4resok { - stateid4 stateid; /* Stateid for open */ - change_info4 cinfo; /* Directory change info */ - uint32_t rflags; /* Result flags */ - bitmap4 attrset; /* attribute set for create */ - open_delegation4 delegation; /* Info on any open + stateid4 stateid; /* Stateid for open */ + change_info4 cinfo; /* Directory change info */ + uint32_t rflags; /* Result flags */ + bitmap4 attrset; /* Attribute set for create */ + open_delegation4 delegation; /* Info on any open delegation */ }; union OPEN4res switch (nfsstat4 status) { case NFS4_OK: - /* CURRENT_FH: opened file */ + /* New CURRENT_FH: opened file */ OPEN4resok resok4; default: void; @@ -1053,10 +1914,15 @@ struct OPENATTR4args { }; struct OPENATTR4res { - /* CURRENT_FH: named attr directory */ + /* + * If status is NFS4_OK, + * New CURRENT_FH: named attribute + * directory + */ nfsstat4 status; }; +/* Obsolete in NFSv4.1 */ struct OPEN_CONFIRM4args { /* CURRENT_FH: opened file */ stateid4 open_stateid; @@ -1098,17 +1964,26 @@ struct PUTFH4args { }; struct PUTFH4res { - /* CURRENT_FH: */ + /* + * If status is NFS4_OK, + * New CURRENT_FH: argument to PUTFH + */ nfsstat4 status; }; struct PUTPUBFH4res { - /* CURRENT_FH: public fh */ + /* + * If status is NFS4_OK, + * New CURRENT_FH: public fh + */ nfsstat4 status; }; struct PUTROOTFH4res { - /* CURRENT_FH: root fh */ + /* + * If status is NFS4_OK, + * New CURRENT_FH: root fh + */ nfsstat4 status; }; @@ -1212,6 +2087,7 @@ union RENAME4res switch (nfsstat4 status) { void; }; +/* Obsolete in NFSv4.1 */ struct RENEW4args { clientid4 clientid; }; @@ -1221,12 +2097,18 @@ struct RENEW4res { }; struct RESTOREFH4res { - /* CURRENT_FH: value of saved fh */ + /* + * If status is NFS4_OK, + * New CURRENT_FH: value of saved fh + */ nfsstat4 status; }; struct SAVEFH4res { - /* SAVED_FH: value of current fh */ + /* + * If status is NFS4_OK, + * New SAVED_FH: value of current fh + */ nfsstat4 status; }; @@ -1250,7 +2132,7 @@ struct rpcsec_gss_info { rpc_gss_svc_t service; }; -/* RPCSEC_GSS has a value of '6'. See RFC 2203 */ +/* RPCSEC_GSS has a value of "6". See RFC 2203. */ union secinfo4 switch (uint32_t flavor) { case RPCSEC_GSS: rpcsec_gss_info flavor_info; @@ -1262,6 +2144,7 @@ typedef secinfo4 SECINFO4resok<>; union SECINFO4res switch (nfsstat4 status) { case NFS4_OK: + /* CURRENTFH: consumed */ SECINFO4resok resok4; default: void; @@ -1278,6 +2161,7 @@ struct SETATTR4res { bitmap4 attrsset; }; +/* Obsolete in NFSv4.1 */ struct SETCLIENTID4args { nfs_client_id4 client; cb_client4 callback; @@ -1298,6 +2182,7 @@ union SETCLIENTID4res switch (nfsstat4 status) { void; }; +/* Obsolete in NFSv4.1 */ struct SETCLIENTID_CONFIRM4args { clientid4 clientid; verifier4 setclientid_confirm; @@ -1316,12 +2201,6 @@ struct VERIFY4res { nfsstat4 status; }; -enum stable_how4 { - UNSTABLE4 = 0, - DATA_SYNC4 = 1, - FILE_SYNC4 = 2 -}; - struct WRITE4args { /* CURRENT_FH: file */ stateid4 stateid; @@ -1343,6 +2222,7 @@ union WRITE4res switch (nfsstat4 status) { void; }; +/* Obsolete in NFSv4.1 */ struct RELEASE_LOCKOWNER4args { lock_owner4 lock_owner; }; @@ -1355,153 +2235,1037 @@ struct ILLEGAL4res { nfsstat4 status; }; +typedef opaque gsshandle4_t<>; + +struct gss_cb_handles4 { + rpc_gss_svc_t gcbp_service; /* RFC 2203 */ + gsshandle4_t gcbp_handle_from_server; + gsshandle4_t gcbp_handle_from_client; +}; + +union callback_sec_parms4 switch (uint32_t cb_secflavor) { + case AUTH_NONE: + void; + case AUTH_SYS: + authsys_parms cbsp_sys_cred; /* RFC 5531 */ + case RPCSEC_GSS: + gss_cb_handles4 cbsp_gss_handles; +}; + +struct BACKCHANNEL_CTL4args { + uint32_t bca_cb_program; + callback_sec_parms4 bca_sec_parms<>; +}; + +struct BACKCHANNEL_CTL4res { + nfsstat4 bcr_status; +}; + +enum channel_dir_from_client4 { + CDFC4_FORE = 0x1, + CDFC4_BACK = 0x2, + CDFC4_FORE_OR_BOTH = 0x3, + CDFC4_BACK_OR_BOTH = 0x7 +}; + +struct BIND_CONN_TO_SESSION4args { + sessionid4 bctsa_sessid; + + channel_dir_from_client4 + bctsa_dir; + + bool bctsa_use_conn_in_rdma_mode; +}; + +enum channel_dir_from_server4 { + CDFS4_FORE = 0x1, + CDFS4_BACK = 0x2, + CDFS4_BOTH = 0x3 +}; + +struct BIND_CONN_TO_SESSION4resok { + sessionid4 bctsr_sessid; + + channel_dir_from_server4 + bctsr_dir; + + bool bctsr_use_conn_in_rdma_mode; +}; + +union BIND_CONN_TO_SESSION4res + switch (nfsstat4 bctsr_status) { + case NFS4_OK: + BIND_CONN_TO_SESSION4resok bctsr_resok4; + default: + void; +}; + +const EXCHGID4_FLAG_SUPP_MOVED_REFER = 0x00000001; +const EXCHGID4_FLAG_SUPP_MOVED_MIGR = 0x00000002; +const EXCHGID4_FLAG_SUPP_FENCE_OPS = 0x00000004; + +const EXCHGID4_FLAG_BIND_PRINC_STATEID = 0x00000100; + +const EXCHGID4_FLAG_USE_NON_PNFS = 0x00010000; +const EXCHGID4_FLAG_USE_PNFS_MDS = 0x00020000; +const EXCHGID4_FLAG_USE_PNFS_DS = 0x00040000; + +const EXCHGID4_FLAG_MASK_PNFS = 0x00070000; + +const EXCHGID4_FLAG_UPD_CONFIRMED_REC_A = 0x40000000; +const EXCHGID4_FLAG_CONFIRMED_R = 0x80000000; + +struct state_protect_ops4 { + bitmap4 spo_must_enforce; + bitmap4 spo_must_allow; +}; + +struct ssv_sp_parms4 { + state_protect_ops4 ssp_ops; + sec_oid4 ssp_hash_algs<>; + sec_oid4 ssp_encr_algs<>; + uint32_t ssp_window; + uint32_t ssp_num_gss_handles; +}; + +enum state_protect_how4 { + SP4_NONE = 0, + SP4_MACH_CRED = 1, + SP4_SSV = 2 +}; + +union state_protect4_a switch (state_protect_how4 spa_how) { + case SP4_NONE: + void; + case SP4_MACH_CRED: + state_protect_ops4 spa_mach_ops; + case SP4_SSV: + ssv_sp_parms4 spa_ssv_parms; +}; + +struct EXCHANGE_ID4args { + client_owner4 eia_clientowner; + uint32_t eia_flags; + state_protect4_a eia_state_protect; + nfs_impl_id4 eia_client_impl_id<1>; +}; + +struct ssv_prot_info4 { + state_protect_ops4 spi_ops; + uint32_t spi_hash_alg; + uint32_t spi_encr_alg; + uint32_t spi_ssv_len; + uint32_t spi_window; + gsshandle4_t spi_handles<>; +}; + +union state_protect4_r switch (state_protect_how4 spr_how) { + case SP4_NONE: + void; + case SP4_MACH_CRED: + state_protect_ops4 spr_mach_ops; + case SP4_SSV: + ssv_prot_info4 spr_ssv_info; +}; + +struct EXCHANGE_ID4resok { + clientid4 eir_clientid; + sequenceid4 eir_sequenceid; + uint32_t eir_flags; + state_protect4_r eir_state_protect; + server_owner4 eir_server_owner; + opaque eir_server_scope<NFS4_OPAQUE_LIMIT>; + nfs_impl_id4 eir_server_impl_id<1>; +}; + +union EXCHANGE_ID4res switch (nfsstat4 eir_status) { + case NFS4_OK: + EXCHANGE_ID4resok eir_resok4; + + default: + void; +}; + +struct channel_attrs4 { + count4 ca_headerpadsize; + count4 ca_maxrequestsize; + count4 ca_maxresponsesize; + count4 ca_maxresponsesize_cached; + count4 ca_maxoperations; + count4 ca_maxrequests; + uint32_t ca_rdma_ird<1>; +}; + +const CREATE_SESSION4_FLAG_PERSIST = 0x00000001; +const CREATE_SESSION4_FLAG_CONN_BACK_CHAN = 0x00000002; +const CREATE_SESSION4_FLAG_CONN_RDMA = 0x00000004; + +struct CREATE_SESSION4args { + clientid4 csa_clientid; + sequenceid4 csa_sequence; + + uint32_t csa_flags; + + channel_attrs4 csa_fore_chan_attrs; + channel_attrs4 csa_back_chan_attrs; + + uint32_t csa_cb_program; + callback_sec_parms4 csa_sec_parms<>; +}; + +struct CREATE_SESSION4resok { + sessionid4 csr_sessionid; + sequenceid4 csr_sequence; + + uint32_t csr_flags; + + channel_attrs4 csr_fore_chan_attrs; + channel_attrs4 csr_back_chan_attrs; +}; + +union CREATE_SESSION4res switch (nfsstat4 csr_status) { + case NFS4_OK: + CREATE_SESSION4resok csr_resok4; + default: + void; +}; + +struct DESTROY_SESSION4args { + sessionid4 dsa_sessionid; +}; + +struct DESTROY_SESSION4res { + nfsstat4 dsr_status; +}; + +struct FREE_STATEID4args { + stateid4 fsa_stateid; +}; + +struct FREE_STATEID4res { + nfsstat4 fsr_status; +}; + + +typedef nfstime4 attr_notice4; + +struct GET_DIR_DELEGATION4args { + /* CURRENT_FH: delegated directory */ + bool gdda_signal_deleg_avail; + bitmap4 gdda_notification_types; + attr_notice4 gdda_child_attr_delay; + attr_notice4 gdda_dir_attr_delay; + bitmap4 gdda_child_attributes; + bitmap4 gdda_dir_attributes; +}; +struct GET_DIR_DELEGATION4resok { + verifier4 gddr_cookieverf; + /* Stateid for get_dir_delegation */ + stateid4 gddr_stateid; + /* Which notifications can the server support? */ + bitmap4 gddr_notification; + bitmap4 gddr_child_attributes; + bitmap4 gddr_dir_attributes; +}; + +enum gddrnf4_status { + GDD4_OK = 0, + GDD4_UNAVAIL = 1 +}; + +union GET_DIR_DELEGATION4res_non_fatal + switch (gddrnf4_status gddrnf_status) { + case GDD4_OK: + GET_DIR_DELEGATION4resok gddrnf_resok4; + case GDD4_UNAVAIL: + bool gddrnf_will_signal_deleg_avail; +}; + +union GET_DIR_DELEGATION4res + switch (nfsstat4 gddr_status) { + case NFS4_OK: + GET_DIR_DELEGATION4res_non_fatal gddr_res_non_fatal4; + default: + void; +}; + +struct GETDEVICEINFO4args { + deviceid4 gdia_device_id; + layouttype4 gdia_layout_type; + count4 gdia_maxcount; + bitmap4 gdia_notify_types; +}; + +struct GETDEVICEINFO4resok { + device_addr4 gdir_device_addr; + bitmap4 gdir_notification; +}; + +union GETDEVICEINFO4res switch (nfsstat4 gdir_status) { + case NFS4_OK: + GETDEVICEINFO4resok gdir_resok4; + case NFS4ERR_TOOSMALL: + count4 gdir_mincount; + default: + void; +}; + +struct GETDEVICELIST4args { + /* CURRENT_FH: object belonging to the file system */ + layouttype4 gdla_layout_type; + + /* Number of device IDs to return */ + count4 gdla_maxdevices; + + nfs_cookie4 gdla_cookie; + verifier4 gdla_cookieverf; +}; + +struct GETDEVICELIST4resok { + nfs_cookie4 gdlr_cookie; + verifier4 gdlr_cookieverf; + deviceid4 gdlr_deviceid_list<>; + bool gdlr_eof; +}; + +union GETDEVICELIST4res switch (nfsstat4 gdlr_status) { + case NFS4_OK: + GETDEVICELIST4resok gdlr_resok4; + default: + void; +}; + +union newtime4 switch (bool nt_timechanged) { + case TRUE: + nfstime4 nt_time; + case FALSE: + void; +}; + +union newoffset4 switch (bool no_newoffset) { + case TRUE: + offset4 no_offset; + case FALSE: + void; +}; + +struct LAYOUTCOMMIT4args { + /* CURRENT_FH: file */ + offset4 loca_offset; + length4 loca_length; + bool loca_reclaim; + stateid4 loca_stateid; + newoffset4 loca_last_write_offset; + newtime4 loca_time_modify; + layoutupdate4 loca_layoutupdate; +}; +union newsize4 switch (bool ns_sizechanged) { + case TRUE: + length4 ns_size; + case FALSE: + void; +}; + +struct LAYOUTCOMMIT4resok { + newsize4 locr_newsize; +}; + +union LAYOUTCOMMIT4res switch (nfsstat4 locr_status) { + case NFS4_OK: + LAYOUTCOMMIT4resok locr_resok4; + default: + void; +}; + +struct LAYOUTGET4args { + /* CURRENT_FH: file */ + bool loga_signal_layout_avail; + layouttype4 loga_layout_type; + layoutiomode4 loga_iomode; + offset4 loga_offset; + length4 loga_length; + length4 loga_minlength; + stateid4 loga_stateid; + count4 loga_maxcount; +}; +struct LAYOUTGET4resok { + bool logr_return_on_close; + stateid4 logr_stateid; + layout4 logr_layout<>; +}; + +union LAYOUTGET4res switch (nfsstat4 logr_status) { + case NFS4_OK: + LAYOUTGET4resok logr_resok4; + case NFS4ERR_LAYOUTTRYLATER: + bool logr_will_signal_layout_avail; + default: + void; +}; + + +struct LAYOUTRETURN4args { + /* CURRENT_FH: file */ + bool lora_reclaim; + layouttype4 lora_layout_type; + layoutiomode4 lora_iomode; + layoutreturn4 lora_layoutreturn; +}; + + +union layoutreturn_stateid switch (bool lrs_present) { + case TRUE: + stateid4 lrs_stateid; + case FALSE: + void; +}; + +union LAYOUTRETURN4res switch (nfsstat4 lorr_status) { + case NFS4_OK: + layoutreturn_stateid lorr_stateid; + default: + void; +}; + +enum secinfo_style4 { + SECINFO_STYLE4_CURRENT_FH = 0, + SECINFO_STYLE4_PARENT = 1 +}; + +/* CURRENT_FH: object or child directory */ +typedef secinfo_style4 SECINFO_NO_NAME4args; + +/* CURRENTFH: consumed if status is NFS4_OK */ +typedef SECINFO4res SECINFO_NO_NAME4res; + +struct SEQUENCE4args { + sessionid4 sa_sessionid; + sequenceid4 sa_sequenceid; + slotid4 sa_slotid; + slotid4 sa_highest_slotid; + bool sa_cachethis; +}; + +const SEQ4_STATUS_CB_PATH_DOWN = 0x00000001; +const SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRING = 0x00000002; +const SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRED = 0x00000004; +const SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED = 0x00000008; +const SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED = 0x00000010; +const SEQ4_STATUS_ADMIN_STATE_REVOKED = 0x00000020; +const SEQ4_STATUS_RECALLABLE_STATE_REVOKED = 0x00000040; +const SEQ4_STATUS_LEASE_MOVED = 0x00000080; +const SEQ4_STATUS_RESTART_RECLAIM_NEEDED = 0x00000100; +const SEQ4_STATUS_CB_PATH_DOWN_SESSION = 0x00000200; +const SEQ4_STATUS_BACKCHANNEL_FAULT = 0x00000400; +const SEQ4_STATUS_DEVID_CHANGED = 0x00000800; +const SEQ4_STATUS_DEVID_DELETED = 0x00001000; + +struct SEQUENCE4resok { + sessionid4 sr_sessionid; + sequenceid4 sr_sequenceid; + slotid4 sr_slotid; + slotid4 sr_highest_slotid; + slotid4 sr_target_highest_slotid; + uint32_t sr_status_flags; +}; + +union SEQUENCE4res switch (nfsstat4 sr_status) { + case NFS4_OK: + SEQUENCE4resok sr_resok4; + default: + void; +}; + +struct ssa_digest_input4 { + SEQUENCE4args sdi_seqargs; +}; + +struct SET_SSV4args { + opaque ssa_ssv<>; + opaque ssa_digest<>; +}; + +struct ssr_digest_input4 { + SEQUENCE4res sdi_seqres; +}; + +struct SET_SSV4resok { + opaque ssr_digest<>; +}; + +union SET_SSV4res switch (nfsstat4 ssr_status) { + case NFS4_OK: + SET_SSV4resok ssr_resok4; + default: + void; +}; + +struct TEST_STATEID4args { + stateid4 ts_stateids<>; +}; + +struct TEST_STATEID4resok { + nfsstat4 tsr_status_codes<>; +}; + +union TEST_STATEID4res switch (nfsstat4 tsr_status) { + case NFS4_OK: + TEST_STATEID4resok tsr_resok4; + default: + void; +}; + +union deleg_claim4 switch (open_claim_type4 dc_claim) { /* - * Operation arrays + * No special rights to object. Ordinary delegation + * request of the specified object. Object identified + * by filehandle. */ + case CLAIM_FH: /* New to NFSv4.1 */ + /* CURRENT_FH: object being delegated */ + void; -enum nfs_opnum4 { - OP_ACCESS = 3, - OP_CLOSE = 4, - OP_COMMIT = 5, - OP_CREATE = 6, - OP_DELEGPURGE = 7, - OP_DELEGRETURN = 8, - OP_GETATTR = 9, - OP_GETFH = 10, - OP_LINK = 11, - OP_LOCK = 12, - OP_LOCKT = 13, - OP_LOCKU = 14, - OP_LOOKUP = 15, - OP_LOOKUPP = 16, - OP_NVERIFY = 17, - OP_OPEN = 18, - OP_OPENATTR = 19, - OP_OPEN_CONFIRM = 20, - OP_OPEN_DOWNGRADE = 21, - OP_PUTFH = 22, - OP_PUTPUBFH = 23, - OP_PUTROOTFH = 24, - OP_READ = 25, - OP_READDIR = 26, - OP_READLINK = 27, - OP_REMOVE = 28, - OP_RENAME = 29, - OP_RENEW = 30, - OP_RESTOREFH = 31, - OP_SAVEFH = 32, - OP_SECINFO = 33, - OP_SETATTR = 34, - OP_SETCLIENTID = 35, - OP_SETCLIENTID_CONFIRM = 36, - OP_VERIFY = 37, - OP_WRITE = 38, - OP_RELEASE_LOCKOWNER = 39, - OP_ILLEGAL = 10044 +/* + * Right to file based on a delegation granted + * to a previous boot instance of the client. + * File is specified by filehandle. + */ + case CLAIM_DELEG_PREV_FH: /* New to NFSv4.1 */ + /* CURRENT_FH: object being delegated */ + void; + +/* + * Right to the file established by an open previous + * to server reboot. File identified by filehandle. + * Used during server reclaim grace period. + */ + case CLAIM_PREVIOUS: + /* CURRENT_FH: object being reclaimed */ + open_delegation_type4 dc_delegate_type; +}; + +struct WANT_DELEGATION4args { + uint32_t wda_want; + deleg_claim4 wda_claim; +}; + +union WANT_DELEGATION4res switch (nfsstat4 wdr_status) { + case NFS4_OK: + open_delegation4 wdr_resok4; + default: + void; +}; + +struct DESTROY_CLIENTID4args { + clientid4 dca_clientid; +}; + +struct DESTROY_CLIENTID4res { + nfsstat4 dcr_status; +}; + +struct RECLAIM_COMPLETE4args { + /* + * If rca_one_fs TRUE, + * + * CURRENT_FH: object in + * file system for which the + * reclaim is complete. + */ + bool rca_one_fs; +}; + +struct RECLAIM_COMPLETE4res { + nfsstat4 rcr_status; +}; + +struct COPY4args { + /* SAVED_FH: source file */ + /* CURRENT_FH: destination file */ + stateid4 ca_src_stateid; + stateid4 ca_dst_stateid; + offset4 ca_src_offset; + offset4 ca_dst_offset; + length4 ca_count; + bool ca_consecutive; + bool ca_synchronous; + netloc4 ca_source_server<>; +}; + + +struct copy_requirements4 { + bool cr_consecutive; + bool cr_synchronous; +}; + +struct COPY4resok { + write_response4 cr_response; + copy_requirements4 cr_requirements; +}; + +union COPY4res switch (nfsstat4 cr_status) { + case NFS4_OK: + COPY4resok cr_resok4; + case NFS4ERR_OFFLOAD_NO_REQS: + copy_requirements4 cr_requirements; + default: + void; +}; + +struct COPY_NOTIFY4args { + /* CURRENT_FH: source file */ + stateid4 cna_src_stateid; + netloc4 cna_destination_server; +}; + +struct COPY_NOTIFY4resok { + nfstime4 cnr_lease_time; + stateid4 cnr_stateid; + netloc4 cnr_source_server<>; +}; + +union COPY_NOTIFY4res switch (nfsstat4 cnr_status) { + case NFS4_OK: + COPY_NOTIFY4resok resok4; + default: + void; +}; + +struct OFFLOAD_CANCEL4args { + /* CURRENT_FH: file to cancel */ + stateid4 oca_stateid; +}; + +struct OFFLOAD_CANCEL4res { + nfsstat4 ocr_status; +}; + + +struct OFFLOAD_STATUS4args { + /* CURRENT_FH: destination file */ + stateid4 osa_stateid; +}; + +struct OFFLOAD_STATUS4resok { + length4 osr_count; + nfsstat4 osr_complete<1>; +}; + +union OFFLOAD_STATUS4res switch (nfsstat4 osr_status) { + case NFS4_OK: + OFFLOAD_STATUS4resok osr_resok4; + default: + void; +}; + +struct ALLOCATE4args { + /* CURRENT_FH: file */ + stateid4 aa_stateid; + offset4 aa_offset; + length4 aa_length; +}; +struct ALLOCATE4res { + nfsstat4 ar_status; +}; + +struct DEALLOCATE4args { + /* CURRENT_FH: file */ + stateid4 da_stateid; + offset4 da_offset; + length4 da_length; +}; + + +struct DEALLOCATE4res { + nfsstat4 dr_status; +}; +enum IO_ADVISE_type4 { + IO_ADVISE4_NORMAL = 0, + IO_ADVISE4_SEQUENTIAL = 1, + IO_ADVISE4_SEQUENTIAL_BACKWARDS = 2, + IO_ADVISE4_RANDOM = 3, + IO_ADVISE4_WILLNEED = 4, + IO_ADVISE4_WILLNEED_OPPORTUNISTIC = 5, + IO_ADVISE4_DONTNEED = 6, + IO_ADVISE4_NOREUSE = 7, + IO_ADVISE4_READ = 8, + IO_ADVISE4_WRITE = 9, + IO_ADVISE4_INIT_PROXIMITY = 10 +}; + +struct IO_ADVISE4args { + /* CURRENT_FH: file */ + stateid4 iaa_stateid; + offset4 iaa_offset; + length4 iaa_count; + bitmap4 iaa_hints; +}; + +struct IO_ADVISE4resok { + bitmap4 ior_hints; +}; + +union IO_ADVISE4res switch (nfsstat4 ior_status) { + case NFS4_OK: + IO_ADVISE4resok resok4; + default: + void; }; + +struct device_error4 { + deviceid4 de_deviceid; + nfsstat4 de_status; + nfs_opnum4 de_opnum; +}; + + +struct LAYOUTERROR4args { + /* CURRENT_FH: file */ + offset4 lea_offset; + length4 lea_length; + stateid4 lea_stateid; + device_error4 lea_errors<>; +}; + +struct LAYOUTERROR4res { + nfsstat4 ler_status; +}; + +struct io_info4 { + uint64_t ii_count; + uint64_t ii_bytes; +}; + +struct LAYOUTSTATS4args { + /* CURRENT_FH: file */ + offset4 lsa_offset; + length4 lsa_length; + stateid4 lsa_stateid; + io_info4 lsa_read; + io_info4 lsa_write; + deviceid4 lsa_deviceid; + layoutupdate4 lsa_layoutupdate; +}; + +struct LAYOUTSTATS4res { + nfsstat4 lsr_status; +}; + +struct READ_PLUS4args { + /* CURRENT_FH: file */ + stateid4 rpa_stateid; + offset4 rpa_offset; + count4 rpa_count; +}; +union read_plus_content switch (data_content4 rpc_content) { + case NFS4_CONTENT_DATA: + data4 rpc_data; + case NFS4_CONTENT_HOLE: + data_info4 rpc_hole; + default: + void; +}; + +/* + * Allow a return of an array of contents. + */ +struct read_plus_res4 { + bool rpr_eof; + read_plus_content rpr_contents<>; +}; + +union READ_PLUS4res switch (nfsstat4 rp_status) { + case NFS4_OK: + read_plus_res4 rp_resok4; + default: + void; +}; + +struct SEEK4args { + /* CURRENT_FH: file */ + stateid4 sa_stateid; + offset4 sa_offset; + data_content4 sa_what; +}; +struct seek_res4 { + bool sr_eof; + offset4 sr_offset; +}; +union SEEK4res switch (nfsstat4 sa_status) { + case NFS4_OK: + seek_res4 resok4; + default: + void; +}; + +struct WRITE_SAME4args { + /* CURRENT_FH: file */ + stateid4 wsa_stateid; + stable_how4 wsa_stable; + app_data_block4 wsa_adb; +}; + + +union WRITE_SAME4res switch (nfsstat4 wsr_status) { + case NFS4_OK: + write_response4 resok4; + default: + void; +}; + + +/* + * Operation arrays (the rest) + */ + union nfs_argop4 switch (nfs_opnum4 argop) { - case OP_ACCESS: ACCESS4args opaccess; - case OP_CLOSE: CLOSE4args opclose; - case OP_COMMIT: COMMIT4args opcommit; - case OP_CREATE: CREATE4args opcreate; - case OP_DELEGPURGE: DELEGPURGE4args opdelegpurge; - case OP_DELEGRETURN: DELEGRETURN4args opdelegreturn; - case OP_GETATTR: GETATTR4args opgetattr; - case OP_GETFH: void; - case OP_LINK: LINK4args oplink; - case OP_LOCK: LOCK4args oplock; - case OP_LOCKT: LOCKT4args oplockt; - case OP_LOCKU: LOCKU4args oplocku; - case OP_LOOKUP: LOOKUP4args oplookup; - case OP_LOOKUPP: void; - case OP_NVERIFY: NVERIFY4args opnverify; - case OP_OPEN: OPEN4args opopen; - case OP_OPENATTR: OPENATTR4args opopenattr; - case OP_OPEN_CONFIRM: OPEN_CONFIRM4args opopen_confirm; - case OP_OPEN_DOWNGRADE: - OPEN_DOWNGRADE4args opopen_downgrade; - case OP_PUTFH: PUTFH4args opputfh; - case OP_PUTPUBFH: void; - case OP_PUTROOTFH: void; - case OP_READ: READ4args opread; - case OP_READDIR: READDIR4args opreaddir; - case OP_READLINK: void; - case OP_REMOVE: REMOVE4args opremove; - case OP_RENAME: RENAME4args oprename; - case OP_RENEW: RENEW4args oprenew; - case OP_RESTOREFH: void; - case OP_SAVEFH: void; - case OP_SECINFO: SECINFO4args opsecinfo; - case OP_SETATTR: SETATTR4args opsetattr; - case OP_SETCLIENTID: SETCLIENTID4args opsetclientid; - case OP_SETCLIENTID_CONFIRM: SETCLIENTID_CONFIRM4args - opsetclientid_confirm; - case OP_VERIFY: VERIFY4args opverify; - case OP_WRITE: WRITE4args opwrite; + case OP_ACCESS: ACCESS4args opaccess; + case OP_CLOSE: CLOSE4args opclose; + case OP_COMMIT: COMMIT4args opcommit; + case OP_CREATE: CREATE4args opcreate; + case OP_DELEGPURGE: DELEGPURGE4args opdelegpurge; + case OP_DELEGRETURN: DELEGRETURN4args opdelegreturn; + case OP_GETATTR: GETATTR4args opgetattr; + case OP_GETFH: void; + case OP_LINK: LINK4args oplink; + case OP_LOCK: LOCK4args oplock; + case OP_LOCKT: LOCKT4args oplockt; + case OP_LOCKU: LOCKU4args oplocku; + case OP_LOOKUP: LOOKUP4args oplookup; + case OP_LOOKUPP: void; + case OP_NVERIFY: NVERIFY4args opnverify; + case OP_OPEN: OPEN4args opopen; + case OP_OPENATTR: OPENATTR4args opopenattr; + + /* Not for NFSv4.1 */ + case OP_OPEN_CONFIRM: OPEN_CONFIRM4args opopen_confirm; + + case OP_OPEN_DOWNGRADE: OPEN_DOWNGRADE4args opopen_downgrade; + + case OP_PUTFH: PUTFH4args opputfh; + case OP_PUTPUBFH: void; + case OP_PUTROOTFH: void; + case OP_READ: READ4args opread; + case OP_READDIR: READDIR4args opreaddir; + case OP_READLINK: void; + case OP_REMOVE: REMOVE4args opremove; + case OP_RENAME: RENAME4args oprename; + + /* Not for NFSv4.1 */ + case OP_RENEW: RENEW4args oprenew; + + case OP_RESTOREFH: void; + case OP_SAVEFH: void; + case OP_SECINFO: SECINFO4args opsecinfo; + case OP_SETATTR: SETATTR4args opsetattr; + + /* Not for NFSv4.1 */ + case OP_SETCLIENTID: SETCLIENTID4args opsetclientid; + + /* Not for NFSv4.1 */ + case OP_SETCLIENTID_CONFIRM: + SETCLIENTID_CONFIRM4args + opsetclientid_confirm; + + case OP_VERIFY: VERIFY4args opverify; + case OP_WRITE: WRITE4args opwrite; + + /* Not for NFSv4.1 */ case OP_RELEASE_LOCKOWNER: - RELEASE_LOCKOWNER4args - oprelease_lockowner; - case OP_ILLEGAL: void; + RELEASE_LOCKOWNER4args + oprelease_lockowner; + + /* Operations new to NFSv4.1 */ + case OP_BACKCHANNEL_CTL: + BACKCHANNEL_CTL4args opbackchannel_ctl; + + case OP_BIND_CONN_TO_SESSION: + BIND_CONN_TO_SESSION4args + opbind_conn_to_session; + + case OP_EXCHANGE_ID: EXCHANGE_ID4args opexchange_id; + + case OP_CREATE_SESSION: CREATE_SESSION4args opcreate_session; + + case OP_DESTROY_SESSION: + DESTROY_SESSION4args opdestroy_session; + + case OP_FREE_STATEID: FREE_STATEID4args opfree_stateid; + + case OP_GET_DIR_DELEGATION: + GET_DIR_DELEGATION4args + opget_dir_delegation; + + case OP_GETDEVICEINFO: GETDEVICEINFO4args opgetdeviceinfo; + case OP_GETDEVICELIST: GETDEVICELIST4args opgetdevicelist; + case OP_LAYOUTCOMMIT: LAYOUTCOMMIT4args oplayoutcommit; + case OP_LAYOUTGET: LAYOUTGET4args oplayoutget; + case OP_LAYOUTRETURN: LAYOUTRETURN4args oplayoutreturn; + + case OP_SECINFO_NO_NAME: + SECINFO_NO_NAME4args opsecinfo_no_name; + + case OP_SEQUENCE: SEQUENCE4args opsequence; + case OP_SET_SSV: SET_SSV4args opset_ssv; + case OP_TEST_STATEID: TEST_STATEID4args optest_stateid; + + case OP_WANT_DELEGATION: + WANT_DELEGATION4args opwant_delegation; + + case OP_DESTROY_CLIENTID: + DESTROY_CLIENTID4args + opdestroy_clientid; + + case OP_RECLAIM_COMPLETE: + RECLAIM_COMPLETE4args + opreclaim_complete; + + /* Operations new to NFSv4.2 */ + case OP_ALLOCATE: ALLOCATE4args opallocate; + case OP_COPY: COPY4args opcopy; + case OP_COPY_NOTIFY: COPY_NOTIFY4args opoffload_notify; + case OP_DEALLOCATE: DEALLOCATE4args opdeallocate; + case OP_IO_ADVISE: IO_ADVISE4args opio_advise; + case OP_LAYOUTERROR: LAYOUTERROR4args oplayouterror; + case OP_LAYOUTSTATS: LAYOUTSTATS4args oplayoutstats; + case OP_OFFLOAD_CANCEL: OFFLOAD_CANCEL4args opoffload_cancel; + case OP_OFFLOAD_STATUS: OFFLOAD_STATUS4args opoffload_status; + case OP_READ_PLUS: READ_PLUS4args opread_plus; + case OP_SEEK: SEEK4args opseek; + case OP_WRITE_SAME: WRITE_SAME4args opwrite_same; + case OP_CLONE: CLONE4args opclone; + + /* Operations not new to NFSv4.1 */ + case OP_ILLEGAL: void; }; union nfs_resop4 switch (nfs_opnum4 resop) { - case OP_ACCESS: ACCESS4res opaccess; - case OP_CLOSE: CLOSE4res opclose; - case OP_COMMIT: COMMIT4res opcommit; - case OP_CREATE: CREATE4res opcreate; - case OP_DELEGPURGE: DELEGPURGE4res opdelegpurge; - case OP_DELEGRETURN: DELEGRETURN4res opdelegreturn; - case OP_GETATTR: GETATTR4res opgetattr; - case OP_GETFH: GETFH4res opgetfh; - case OP_LINK: LINK4res oplink; - case OP_LOCK: LOCK4res oplock; - case OP_LOCKT: LOCKT4res oplockt; - case OP_LOCKU: LOCKU4res oplocku; - case OP_LOOKUP: LOOKUP4res oplookup; - case OP_LOOKUPP: LOOKUPP4res oplookupp; - case OP_NVERIFY: NVERIFY4res opnverify; - case OP_OPEN: OPEN4res opopen; - case OP_OPENATTR: OPENATTR4res opopenattr; - case OP_OPEN_CONFIRM: OPEN_CONFIRM4res opopen_confirm; - case OP_OPEN_DOWNGRADE: - OPEN_DOWNGRADE4res - opopen_downgrade; - case OP_PUTFH: PUTFH4res opputfh; - case OP_PUTPUBFH: PUTPUBFH4res opputpubfh; - case OP_PUTROOTFH: PUTROOTFH4res opputrootfh; - case OP_READ: READ4res opread; - case OP_READDIR: READDIR4res opreaddir; - case OP_READLINK: READLINK4res opreadlink; - case OP_REMOVE: REMOVE4res opremove; - case OP_RENAME: RENAME4res oprename; - case OP_RENEW: RENEW4res oprenew; - case OP_RESTOREFH: RESTOREFH4res oprestorefh; - case OP_SAVEFH: SAVEFH4res opsavefh; - case OP_SECINFO: SECINFO4res opsecinfo; - case OP_SETATTR: SETATTR4res opsetattr; - case OP_SETCLIENTID: SETCLIENTID4res opsetclientid; + case OP_ACCESS: ACCESS4res opaccess; + case OP_CLOSE: CLOSE4res opclose; + case OP_COMMIT: COMMIT4res opcommit; + case OP_CREATE: CREATE4res opcreate; + case OP_DELEGPURGE: DELEGPURGE4res opdelegpurge; + case OP_DELEGRETURN: DELEGRETURN4res opdelegreturn; + case OP_GETATTR: GETATTR4res opgetattr; + case OP_GETFH: GETFH4res opgetfh; + case OP_LINK: LINK4res oplink; + case OP_LOCK: LOCK4res oplock; + case OP_LOCKT: LOCKT4res oplockt; + case OP_LOCKU: LOCKU4res oplocku; + case OP_LOOKUP: LOOKUP4res oplookup; + case OP_LOOKUPP: LOOKUPP4res oplookupp; + case OP_NVERIFY: NVERIFY4res opnverify; + case OP_OPEN: OPEN4res opopen; + case OP_OPENATTR: OPENATTR4res opopenattr; + /* Not for NFSv4.1 */ + case OP_OPEN_CONFIRM: OPEN_CONFIRM4res opopen_confirm; + + case OP_OPEN_DOWNGRADE: OPEN_DOWNGRADE4res opopen_downgrade; + + case OP_PUTFH: PUTFH4res opputfh; + case OP_PUTPUBFH: PUTPUBFH4res opputpubfh; + case OP_PUTROOTFH: PUTROOTFH4res opputrootfh; + case OP_READ: READ4res opread; + case OP_READDIR: READDIR4res opreaddir; + case OP_READLINK: READLINK4res opreadlink; + case OP_REMOVE: REMOVE4res opremove; + case OP_RENAME: RENAME4res oprename; + /* Not for NFSv4.1 */ + case OP_RENEW: RENEW4res oprenew; + case OP_RESTOREFH: RESTOREFH4res oprestorefh; + case OP_SAVEFH: SAVEFH4res opsavefh; + case OP_SECINFO: SECINFO4res opsecinfo; + case OP_SETATTR: SETATTR4res opsetattr; + /* Not for NFSv4.1 */ + case OP_SETCLIENTID: SETCLIENTID4res opsetclientid; + + /* Not for NFSv4.1 */ case OP_SETCLIENTID_CONFIRM: - SETCLIENTID_CONFIRM4res - opsetclientid_confirm; - case OP_VERIFY: VERIFY4res opverify; - case OP_WRITE: WRITE4res opwrite; + SETCLIENTID_CONFIRM4res + opsetclientid_confirm; + case OP_VERIFY: VERIFY4res opverify; + case OP_WRITE: WRITE4res opwrite; + + /* Not for NFSv4.1 */ case OP_RELEASE_LOCKOWNER: - RELEASE_LOCKOWNER4res - oprelease_lockowner; - case OP_ILLEGAL: ILLEGAL4res opillegal; + RELEASE_LOCKOWNER4res + oprelease_lockowner; + + /* Operations new to NFSv4.1 */ + case OP_BACKCHANNEL_CTL: + BACKCHANNEL_CTL4res opbackchannel_ctl; + + case OP_BIND_CONN_TO_SESSION: + BIND_CONN_TO_SESSION4res + opbind_conn_to_session; + + case OP_EXCHANGE_ID: EXCHANGE_ID4res opexchange_id; + + case OP_CREATE_SESSION: CREATE_SESSION4res opcreate_session; + + case OP_DESTROY_SESSION: + DESTROY_SESSION4res opdestroy_session; + + case OP_FREE_STATEID: FREE_STATEID4res opfree_stateid; + + case OP_GET_DIR_DELEGATION: + GET_DIR_DELEGATION4res + opget_dir_delegation; + + case OP_GETDEVICEINFO: GETDEVICEINFO4res opgetdeviceinfo; + case OP_GETDEVICELIST: GETDEVICELIST4res opgetdevicelist; + case OP_LAYOUTCOMMIT: LAYOUTCOMMIT4res oplayoutcommit; + case OP_LAYOUTGET: LAYOUTGET4res oplayoutget; + case OP_LAYOUTRETURN: LAYOUTRETURN4res oplayoutreturn; + + case OP_SECINFO_NO_NAME: + SECINFO_NO_NAME4res opsecinfo_no_name; + + case OP_SEQUENCE: SEQUENCE4res opsequence; + case OP_SET_SSV: SET_SSV4res opset_ssv; + case OP_TEST_STATEID: TEST_STATEID4res optest_stateid; + + case OP_WANT_DELEGATION: + WANT_DELEGATION4res opwant_delegation; + + case OP_DESTROY_CLIENTID: + DESTROY_CLIENTID4res + opdestroy_clientid; + + case OP_RECLAIM_COMPLETE: + RECLAIM_COMPLETE4res + opreclaim_complete; + + /* Operations new to NFSv4.2 */ + case OP_ALLOCATE: ALLOCATE4res opallocate; + case OP_COPY: COPY4res opcopy; + case OP_COPY_NOTIFY: COPY_NOTIFY4res opcopy_notify; + case OP_DEALLOCATE: DEALLOCATE4res opdeallocate; + case OP_IO_ADVISE: IO_ADVISE4res opio_advise; + case OP_LAYOUTERROR: LAYOUTERROR4res oplayouterror; + case OP_LAYOUTSTATS: LAYOUTSTATS4res oplayoutstats; + case OP_OFFLOAD_CANCEL: OFFLOAD_CANCEL4res opoffload_cancel; + case OP_OFFLOAD_STATUS: OFFLOAD_STATUS4res opoffload_status; + case OP_READ_PLUS: READ_PLUS4res opread_plus; + case OP_SEEK: SEEK4res opseek; + case OP_WRITE_SAME: WRITE_SAME4res opwrite_same; + case OP_CLONE: CLONE4res opclone; + + /* Operations not new to NFSv4.1 */ + case OP_ILLEGAL: ILLEGAL4res opillegal; }; struct COMPOUND4args { - utf8str_cs tag; - uint32_t minorversion; - nfs_argop4 argarray<>; + utf8str_cs tag; + uint32_t minorversion; + nfs_argop4 argarray<>; }; struct COMPOUND4res { - nfsstat4 status; - utf8str_cs tag; - nfs_resop4 resarray<>; + nfsstat4 status; + utf8str_cs tag; + nfs_resop4 resarray<>; }; @@ -1511,10 +3275,10 @@ struct COMPOUND4res { program NFS4_PROGRAM { version NFS_V4 { void - NFSPROC4_NULL(void) = 0; + NFSPROC4_NULL(void) = 0; COMPOUND4res - NFSPROC4_COMPOUND(COMPOUND4args) = 1; + NFSPROC4_COMPOUND(COMPOUND4args) = 1; } = 4; } = 100003; @@ -1556,24 +3320,361 @@ struct CB_ILLEGAL4res { }; /* - * Various definitions for CB_COMPOUND + * NFSv4.1 callback arguments and results */ -enum nfs_cb_opnum4 { - OP_CB_GETATTR = 3, - OP_CB_RECALL = 4, - OP_CB_ILLEGAL = 10044 + +enum layoutrecall_type4 { + LAYOUTRECALL4_FILE = LAYOUT4_RET_REC_FILE, + LAYOUTRECALL4_FSID = LAYOUT4_RET_REC_FSID, + LAYOUTRECALL4_ALL = LAYOUT4_RET_REC_ALL }; -union nfs_cb_argop4 switch (unsigned argop) { - case OP_CB_GETATTR: CB_GETATTR4args opcbgetattr; - case OP_CB_RECALL: CB_RECALL4args opcbrecall; - case OP_CB_ILLEGAL: void; +struct layoutrecall_file4 { + nfs_fh4 lor_fh; + offset4 lor_offset; + length4 lor_length; + stateid4 lor_stateid; }; -union nfs_cb_resop4 switch (unsigned resop) { - case OP_CB_GETATTR: CB_GETATTR4res opcbgetattr; - case OP_CB_RECALL: CB_RECALL4res opcbrecall; - case OP_CB_ILLEGAL: CB_ILLEGAL4res opcbillegal; +union layoutrecall4 switch (layoutrecall_type4 lor_recalltype) { + case LAYOUTRECALL4_FILE: + layoutrecall_file4 lor_layout; + case LAYOUTRECALL4_FSID: + fsid4 lor_fsid; + case LAYOUTRECALL4_ALL: + void; +}; + +struct CB_LAYOUTRECALL4args { + layouttype4 clora_type; + layoutiomode4 clora_iomode; + bool clora_changed; + layoutrecall4 clora_recall; +}; +struct CB_LAYOUTRECALL4res { + nfsstat4 clorr_status; +}; + +/* + * Directory notification types + */ +enum notify_type4 { + NOTIFY4_CHANGE_CHILD_ATTRS = 0, + NOTIFY4_CHANGE_DIR_ATTRS = 1, + NOTIFY4_REMOVE_ENTRY = 2, + NOTIFY4_ADD_ENTRY = 3, + NOTIFY4_RENAME_ENTRY = 4, + NOTIFY4_CHANGE_COOKIE_VERIFIER = 5 +}; + +/* Changed entry information */ +struct notify_entry4 { + component4 ne_file; + fattr4 ne_attrs; +}; + +/* Previous entry information */ +struct prev_entry4 { + notify_entry4 pe_prev_entry; + /* What READDIR returned for this entry */ + nfs_cookie4 pe_prev_entry_cookie; +}; + +struct notify_remove4 { + notify_entry4 nrm_old_entry; + nfs_cookie4 nrm_old_entry_cookie; +}; + +struct notify_add4 { + /* + * During a rename, contains + * the object that was deleted. + */ + notify_remove4 nad_old_entry<1>; + notify_entry4 nad_new_entry; + /* What READDIR would have returned for this entry */ + nfs_cookie4 nad_new_entry_cookie<1>; + prev_entry4 nad_prev_entry<1>; + bool nad_last_entry; +}; + +struct notify_attr4 { + notify_entry4 na_changed_entry; +}; + +struct notify_rename4 { + notify_remove4 nrn_old_entry; + notify_add4 nrn_new_entry; +}; + +struct notify_verifier4 { + verifier4 nv_old_cookieverf; + verifier4 nv_new_cookieverf; +}; + +/* + * Objects of type notify_<>4 and + * notify_device_<>4 are encoded in this. + */ +typedef opaque notifylist4<>; + +struct notify4 { + /* Composed from notify_type4 or notify_deviceid_type4 */ + bitmap4 notify_mask; + notifylist4 notify_vals; +}; + +struct CB_NOTIFY4args { + stateid4 cna_stateid; + nfs_fh4 cna_fh; + notify4 cna_changes<>; +}; + +struct CB_NOTIFY4res { + nfsstat4 cnr_status; +}; + +struct CB_PUSH_DELEG4args { + nfs_fh4 cpda_fh; + open_delegation4 cpda_delegation; + +}; + +struct CB_PUSH_DELEG4res { + nfsstat4 cpdr_status; +}; + +const RCA4_TYPE_MASK_RDATA_DLG = 0; +const RCA4_TYPE_MASK_WDATA_DLG = 1; +const RCA4_TYPE_MASK_DIR_DLG = 2; +const RCA4_TYPE_MASK_FILE_LAYOUT = 3; +const RCA4_TYPE_MASK_BLK_LAYOUT = 4; +const RCA4_TYPE_MASK_OBJ_LAYOUT_MIN = 8; +const RCA4_TYPE_MASK_OBJ_LAYOUT_MAX = 9; +const RCA4_TYPE_MASK_OTHER_LAYOUT_MIN = 12; +const RCA4_TYPE_MASK_OTHER_LAYOUT_MAX = 15; + +struct CB_RECALL_ANY4args { + uint32_t craa_objects_to_keep; + bitmap4 craa_type_mask; +}; + +struct CB_RECALL_ANY4res { + nfsstat4 crar_status; +}; + +typedef CB_RECALL_ANY4args CB_RECALLABLE_OBJ_AVAIL4args; + +struct CB_RECALLABLE_OBJ_AVAIL4res { + nfsstat4 croa_status; +}; + +struct CB_RECALL_SLOT4args { + slotid4 rsa_target_highest_slotid; +}; + +struct CB_RECALL_SLOT4res { + nfsstat4 rsr_status; +}; + +struct referring_call4 { + sequenceid4 rc_sequenceid; + slotid4 rc_slotid; +}; + +struct referring_call_list4 { + sessionid4 rcl_sessionid; + referring_call4 rcl_referring_calls<>; +}; + +struct CB_SEQUENCE4args { + sessionid4 csa_sessionid; + sequenceid4 csa_sequenceid; + slotid4 csa_slotid; + slotid4 csa_highest_slotid; + bool csa_cachethis; + referring_call_list4 csa_referring_call_lists<>; +}; + +struct CB_SEQUENCE4resok { + sessionid4 csr_sessionid; + sequenceid4 csr_sequenceid; + slotid4 csr_slotid; + slotid4 csr_highest_slotid; + slotid4 csr_target_highest_slotid; +}; + +union CB_SEQUENCE4res switch (nfsstat4 csr_status) { + case NFS4_OK: + CB_SEQUENCE4resok csr_resok4; + default: + void; +}; + +struct CB_WANTS_CANCELLED4args { + bool cwca_contended_wants_cancelled; + bool cwca_resourced_wants_cancelled; +}; + +struct CB_WANTS_CANCELLED4res { + nfsstat4 cwcr_status; +}; + +struct CB_NOTIFY_LOCK4args { + nfs_fh4 cnla_fh; + lock_owner4 cnla_lock_owner; +}; + +struct CB_NOTIFY_LOCK4res { + nfsstat4 cnlr_status; +}; + +/* + * Device notification types + */ +enum notify_deviceid_type4 { + NOTIFY_DEVICEID4_CHANGE = 1, + NOTIFY_DEVICEID4_DELETE = 2 +}; + +/* For NOTIFY4_DEVICEID4_DELETE */ +struct notify_deviceid_delete4 { + layouttype4 ndd_layouttype; + deviceid4 ndd_deviceid; +}; + +/* For NOTIFY4_DEVICEID4_CHANGE */ +struct notify_deviceid_change4 { + layouttype4 ndc_layouttype; + deviceid4 ndc_deviceid; + bool ndc_immediate; +}; + +struct CB_NOTIFY_DEVICEID4args { + notify4 cnda_changes<>; +}; + +struct CB_NOTIFY_DEVICEID4res { + nfsstat4 cndr_status; +}; + +union offload_info4 switch (nfsstat4 coa_status) { + case NFS4_OK: + write_response4 coa_resok4; + default: + length4 coa_bytes_copied; +}; +struct CB_OFFLOAD4args { + nfs_fh4 coa_fh; + stateid4 coa_stateid; + offload_info4 coa_offload_info; +}; +struct CB_OFFLOAD4res { + nfsstat4 cor_status; +}; +/* + * Various definitions for CB_COMPOUND + */ +% +enum nfs_cb_opnum4 { + OP_CB_GETATTR = 3, + OP_CB_RECALL = 4, +%/* Callback operations new to NFSv4.1 */ + OP_CB_LAYOUTRECALL = 5, + OP_CB_NOTIFY = 6, + OP_CB_PUSH_DELEG = 7, + OP_CB_RECALL_ANY = 8, + OP_CB_RECALLABLE_OBJ_AVAIL = 9, + OP_CB_RECALL_SLOT = 10, + OP_CB_SEQUENCE = 11, + OP_CB_WANTS_CANCELLED = 12, + OP_CB_NOTIFY_LOCK = 13, + OP_CB_NOTIFY_DEVICEID = 14, +%/* Callback operations new to NFSv4.2 */ + OP_CB_OFFLOAD = 15, + + OP_CB_ILLEGAL = 10044 +}; + +union nfs_cb_argop4 switch (nfs_cb_opnum4 argop) { + case OP_CB_GETATTR: + CB_GETATTR4args opcbgetattr; + + /* New NFSv4.1 operations */ + case OP_CB_RECALL: + CB_RECALL4args opcbrecall; + case OP_CB_LAYOUTRECALL: + CB_LAYOUTRECALL4args opcblayoutrecall; + case OP_CB_NOTIFY: + CB_NOTIFY4args opcbnotify; + case OP_CB_PUSH_DELEG: + CB_PUSH_DELEG4args opcbpush_deleg; + case OP_CB_RECALL_ANY: + CB_RECALL_ANY4args opcbrecall_any; + case OP_CB_RECALLABLE_OBJ_AVAIL: + CB_RECALLABLE_OBJ_AVAIL4args opcbrecallable_obj_avail; + case OP_CB_RECALL_SLOT: + CB_RECALL_SLOT4args opcbrecall_slot; + case OP_CB_SEQUENCE: + CB_SEQUENCE4args opcbsequence; + case OP_CB_WANTS_CANCELLED: + CB_WANTS_CANCELLED4args opcbwants_cancelled; + case OP_CB_NOTIFY_LOCK: + CB_NOTIFY_LOCK4args opcbnotify_lock; + case OP_CB_NOTIFY_DEVICEID: + CB_NOTIFY_DEVICEID4args opcbnotify_deviceid; + + /* New NFSv4.2 operations */ + case OP_CB_OFFLOAD: + CB_OFFLOAD4args opcboffload; + + case OP_CB_ILLEGAL: void; +}; + +union nfs_cb_resop4 switch (nfs_cb_opnum4 resop) { + case OP_CB_GETATTR: CB_GETATTR4res opcbgetattr; + case OP_CB_RECALL: CB_RECALL4res opcbrecall; + + /* New NFSv4.1 operations */ + case OP_CB_LAYOUTRECALL: + CB_LAYOUTRECALL4res + opcblayoutrecall; + + case OP_CB_NOTIFY: CB_NOTIFY4res opcbnotify; + + case OP_CB_PUSH_DELEG: CB_PUSH_DELEG4res + opcbpush_deleg; + + case OP_CB_RECALL_ANY: CB_RECALL_ANY4res + opcbrecall_any; + + case OP_CB_RECALLABLE_OBJ_AVAIL: + CB_RECALLABLE_OBJ_AVAIL4res + opcbrecallable_obj_avail; + + case OP_CB_RECALL_SLOT: + CB_RECALL_SLOT4res + opcbrecall_slot; + + case OP_CB_SEQUENCE: CB_SEQUENCE4res opcbsequence; + + case OP_CB_WANTS_CANCELLED: + CB_WANTS_CANCELLED4res + opcbwants_cancelled; + + case OP_CB_NOTIFY_LOCK: + CB_NOTIFY_LOCK4res + opcbnotify_lock; + + case OP_CB_NOTIFY_DEVICEID: + CB_NOTIFY_DEVICEID4res + opcbnotify_deviceid; + + /* New NFSv4.2 operations */ + case OP_CB_OFFLOAD: CB_OFFLOAD4res opcboffload; + + /* Not new operation */ + case OP_CB_ILLEGAL: CB_ILLEGAL4res opcbillegal; }; @@ -1585,7 +3686,7 @@ struct CB_COMPOUND4args { }; struct CB_COMPOUND4res { - nfsstat4 status; + nfsstat4 status; utf8str_cs tag; nfs_cb_resop4 resarray<>; }; @@ -1595,7 +3696,8 @@ struct CB_COMPOUND4res { /* * Program number is in the transient range, since the client * will assign the exact transient program number and provide - * that to the server via the SETCLIENTID operation. + * that to the server via the CREATE_SESSION or + * BACKCHANNEL_CTL operations. */ program NFS4_CALLBACK { version NFS_CB { diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index 7dfbae4a68..b250ad08d9 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -1136,14 +1136,16 @@ NFS_OBJS += nfs_client.o nfs_common.o nfs_dump.o \ nfs4_acache.o nfs4_common.o nfs4_client_state.o \ nfs4_callback.o nfs4_recovery.o nfs4_client_secinfo.o \ nfs4_client_debug.o nfs_stats.o \ - nfs4_acl.o nfs4_stub_vnops.o nfs_cmd.o + nfs4_acl.o nfs4_stub_vnops.o nfs_cmd.o \ + nfs4x_xdr.o NFSSRV_OBJS += nfs_server.o nfs_srv.o nfs3_srv.o \ nfs_acl_srv.o nfs_auth.o nfs_auth_xdr.o \ nfs_export.o nfs_log.o nfs_log_xdr.o \ nfs4_srv.o nfs4_state.o nfs4_srv_attr.o \ nfs4_srv_ns.o nfs4_db.o nfs4_srv_deleg.o \ - nfs4_deleg_ops.o nfs4_srv_readdir.o nfs4_dispatch.o + nfs4_deleg_ops.o nfs4_srv_readdir.o nfs4_dispatch.o \ + nfs4x_srv.o nfs4x_state.o nfs4x_dispatch.o SMBSRV_SHARED_OBJS += \ smb_cfg_util.o \ diff --git a/usr/src/uts/common/fs/nfs/nfs4_attr.c b/usr/src/uts/common/fs/nfs/nfs4_attr.c index c32a9526ec..820b804312 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_attr.c +++ b/usr/src/uts/common/fs/nfs/nfs4_attr.c @@ -772,6 +772,9 @@ struct nfs4_ntov_map nfs4_ntov_map[] = { xdr_u_longlong_t, NULL, "fattr4_mounted_on_fileid" }, + { FATTR4_SUPPATTR_EXCLCREAT_MASK_LOCAL, 0, FALSE, FALSE, + FATTR4_MOUNTED_ON_FILEID + 1, 0, xdr_bitmap4, + NULL, "fattr4_suppattr_exclcreat" }, }; uint_t nfs4_ntov_map_size = sizeof (nfs4_ntov_map) / diff --git a/usr/src/uts/common/fs/nfs/nfs4_dispatch.c b/usr/src/uts/common/fs/nfs/nfs4_dispatch.c index 1fdfd0f601..0988dea0ef 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_dispatch.c +++ b/usr/src/uts/common/fs/nfs/nfs4_dispatch.c @@ -26,6 +26,7 @@ /* * Copyright 2018 Nexenta Systems, Inc. + * Copyright 2020 RackTop Systems, Inc. */ #include <sys/systm.h> @@ -40,7 +41,7 @@ #include <nfs/nfs_dispatch.h> #include <nfs/nfs4_drc.h> -#define NFS4_MAX_MINOR_VERSION 0 +#define NFS4_MAX_MINOR_VERSION 2 /* * The default size of the duplicate request cache @@ -372,43 +373,28 @@ rfs4_find_dr(struct svc_req *req, rfs4_drc_t *drc, rfs4_dupreq_t **dup) * */ int -rfs4_dispatch(struct rpcdisp *disp, struct svc_req *req, SVCXPRT *xprt, - char *ap) +rfs40_dispatch(struct svc_req *req, SVCXPRT *xprt, char *ap) { COMPOUND4res res_buf; COMPOUND4res *rbp; COMPOUND4args *cap; - cred_t *cr = NULL; int error = 0; int dis_flags = 0; int dr_stat = NFS4_NOT_DUP; rfs4_dupreq_t *drp = NULL; int rv; + struct compound_state cs; nfs4_srv_t *nsrv4 = nfs4_get_srv(); rfs4_drc_t *nfs4_drc = nsrv4->nfs4_drc; - ASSERT(disp); - - /* - * Short circuit the RPC_NULL proc. - */ - if (disp->dis_proc == rpc_null) { - DTRACE_NFSV4_1(null__start, struct svc_req *, req); - if (!svc_sendreply(xprt, xdr_void, NULL)) { - DTRACE_NFSV4_1(null__done, struct svc_req *, req); - svcerr_systemerr(xprt); - return (1); - } - DTRACE_NFSV4_1(null__done, struct svc_req *, req); - return (0); - } - /* Only NFSv4 Compounds from this point onward */ rbp = &res_buf; cap = (COMPOUND4args *)ap; + rfs4_init_compound_state(&cs); + /* * Figure out the disposition of the whole COMPOUND * and record it's IDEMPOTENTCY. @@ -445,9 +431,11 @@ rfs4_dispatch(struct rpcdisp *disp, struct svc_req *req, SVCXPRT *xprt, case NFS4_DUP_NEW: curthread->t_flag |= T_DONTPEND; /* NON-IDEMPOTENT proc call */ - rfs4_compound(cap, rbp, NULL, req, cr, &rv); + rfs4_compound(cap, rbp, &cs, req, &rv); curthread->t_flag &= ~T_DONTPEND; + rfs4_fini_compound_state(&cs); + if (rv) /* short ckt sendreply on error */ return (rv); @@ -478,9 +466,11 @@ rfs4_dispatch(struct rpcdisp *disp, struct svc_req *req, SVCXPRT *xprt, } else { curthread->t_flag |= T_DONTPEND; /* IDEMPOTENT proc call */ - rfs4_compound(cap, rbp, NULL, req, cr, &rv); + rfs4_compound(cap, rbp, &cs, req, &rv); curthread->t_flag &= ~T_DONTPEND; + rfs4_fini_compound_state(&cs); + if (rv) /* short ckt sendreply on error */ return (rv); @@ -528,19 +518,11 @@ rfs4_dispatch(struct rpcdisp *disp, struct svc_req *req, SVCXPRT *xprt, return (error); } -bool_t -rfs4_minorvers_mismatch(struct svc_req *req, SVCXPRT *xprt, void *args) +static int +rfs4_send_minor_mismatch(SVCXPRT *xprt, COMPOUND4args *argsp) { - COMPOUND4args *argsp; COMPOUND4res res_buf, *resp; - - if (req->rq_vers != 4) - return (FALSE); - - argsp = (COMPOUND4args *)args; - - if (argsp->minorversion <= NFS4_MAX_MINOR_VERSION) - return (FALSE); + int err = 0; resp = &res_buf; @@ -563,8 +545,26 @@ rfs4_minorvers_mismatch(struct svc_req *req, SVCXPRT *xprt, void *args) DTRACE_PROBE2(nfss__e__minorvers_mismatch, SVCXPRT *, xprt, char *, resp); svcerr_systemerr(xprt); + err = 1; } rfs4_compound_free(resp); + return (err); +} + +bool_t +rfs4_minorvers_mismatch(struct svc_req *req, SVCXPRT *xprt, void *args) +{ + COMPOUND4args *argsp; + + if (req->rq_vers != 4) + return (FALSE); + + argsp = (COMPOUND4args *)args; + + if (argsp->minorversion <= NFS4_MAX_MINOR_VERSION) + return (FALSE); + + (void) rfs4_send_minor_mismatch(xprt, argsp); return (TRUE); } @@ -619,3 +619,37 @@ rfs4_resource_err(struct svc_req *req, COMPOUND4args *argsp) UTF8STRING_FREE(rbp->tag); kmem_free(rbp->array, rbp->array_len * sizeof (nfs_resop4)); } + +/* ARGSUSED */ +int +rfs4_dispatch(struct rpcdisp *disp, struct svc_req *req, + SVCXPRT *xprt, char *ap) +{ + COMPOUND4args *cmp; + int error = 0; + + /* + * Handle the NULL Proc here + */ + if (req->rq_proc == RFS_NULL) { + return (!svc_sendreply(xprt, xdr_void, NULL)); + } + + cmp = (COMPOUND4args *)ap; + ASSERT(cmp != NULL); + + switch (cmp->minorversion) { + case 1: + case 2: + error = rfs4x_dispatch(req, xprt, ap); + break; + + case 0: + error = rfs40_dispatch(req, xprt, ap); + break; + + default: + error = rfs4_send_minor_mismatch(xprt, cmp); + } + return (error); +} diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv.c b/usr/src/uts/common/fs/nfs/nfs4_srv.c index 757964eb84..acaf6a8f8b 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_srv.c +++ b/usr/src/uts/common/fs/nfs/nfs4_srv.c @@ -32,6 +32,7 @@ * Copyright (c) 2012, 2016 by Delphix. All rights reserved. * Copyright 2019 Nexenta Systems, Inc. * Copyright 2019 Nexenta by DDN, Inc. + * Copyright 2020 RackTop Systems, Inc. */ #include <sys/param.h> @@ -185,6 +186,8 @@ static void rfs4_op_getfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *, static void rfs4_op_getfh_free(nfs_resop4 *); static void rfs4_op_illegal(nfs_argop4 *, nfs_resop4 *, struct svc_req *, struct compound_state *); +static void rfs4_op_notsup(nfs_argop4 *, nfs_resop4 *, struct svc_req *, + struct compound_state *); static void rfs4_op_link(nfs_argop4 *, nfs_resop4 *, struct svc_req *, struct compound_state *); static void rfs4_op_lock(nfs_argop4 *, nfs_resop4 *, struct svc_req *, @@ -247,12 +250,36 @@ static void rfs4_op_secinfo(nfs_argop4 *, nfs_resop4 *, struct svc_req *, struct compound_state *); static void rfs4_op_secinfo_free(nfs_resop4 *); +void rfs4x_op_exchange_id(nfs_argop4 *argop, nfs_resop4 *resop, + struct svc_req *req, struct compound_state *cs); +void rfs4x_exchange_id_free(nfs_resop4 *); + +void rfs4x_op_create_session(nfs_argop4 *argop, nfs_resop4 *resop, + struct svc_req *req, struct compound_state *cs); + +void rfs4x_op_destroy_session(nfs_argop4 *argop, nfs_resop4 *resop, + struct svc_req *req, compound_state_t *cs); + +void rfs4x_op_sequence(nfs_argop4 *argop, nfs_resop4 *resop, + struct svc_req *req, struct compound_state *cs); + +void rfs4x_op_reclaim_complete(nfs_argop4 *argop, nfs_resop4 *resop, + struct svc_req *req, compound_state_t *cs); + +void rfs4x_op_destroy_clientid(nfs_argop4 *argop, nfs_resop4 *resop, + struct svc_req *req, compound_state_t *cs); + +void rfs4x_op_bind_conn_to_session(nfs_argop4 *argop, nfs_resop4 *resop, + struct svc_req *req, compound_state_t *cs); + +void rfs4x_op_secinfo_noname(nfs_argop4 *argop, nfs_resop4 *resop, + struct svc_req *req, compound_state_t *cs); + static nfsstat4 check_open_access(uint32_t, struct compound_state *, struct svc_req *); nfsstat4 rfs4_client_sysid(rfs4_client_t *, sysid_t *); void rfs4_ss_clid(nfs4_srv_t *, rfs4_client_t *); - /* * translation table for attrs */ @@ -410,6 +437,67 @@ static struct rfsv4disp rfsv4disptab[] = { /* OP_RELEASE_LOCKOWNER = 39 */ {rfs4_op_release_lockowner, nullfree, 0}, + + /* + * NFSv4.1 operations + */ + + /* OP_BACKCHANNEL_CTL = 40 */ + {rfs4_op_notsup, nullfree, 0}, + + /* OP_BIND_CONN_TO_SESSION = 41 */ + {rfs4x_op_bind_conn_to_session, nullfree, 0}, + + /* OP_EXCHANGE_ID = 42 */ + {rfs4x_op_exchange_id, rfs4x_exchange_id_free, 0}, + + /* OP_CREATE_SESSION = 43 */ + {rfs4x_op_create_session, nullfree, 0}, + + /* OP_DESTROY_SESSION = 44 */ + {rfs4x_op_destroy_session, nullfree, 0}, + + /* OP_FREE_STATEID = 45 */ + {rfs4_op_notsup, nullfree, 0}, + + /* OP_GET_DIR_DELEGATION = 46 */ + {rfs4_op_notsup, nullfree, 0}, + + /* OP_GETDEVICEINFO = 47 */ + {rfs4_op_notsup, nullfree, 0}, + + /* OP_GETDEVICELIST = 48 */ + {rfs4_op_notsup, nullfree, 0}, + + /* OP_LAYOUTCOMMIT = 49 */ + {rfs4_op_notsup, nullfree, 0}, + + /* OP_LAYOUTGET = 50 */ + {rfs4_op_notsup, nullfree, 0}, + + /* OP_LAYOUTRETURN = 51 */ + {rfs4_op_notsup, nullfree, 0}, + + /* OP_SECINFO_NO_NAME = 52 */ + {rfs4x_op_secinfo_noname, rfs4_op_secinfo_free, 0}, + + /* OP_SEQUENCE = 53 */ + {rfs4x_op_sequence, nullfree, 0}, + + /* OP_SET_SSV = 54 */ + {rfs4_op_notsup, nullfree, 0}, + + /* OP_TEST_STATEID = 55 */ + {rfs4_op_notsup, nullfree, 0}, + + /* OP_WANT_DELEGATION = 56 */ + {rfs4_op_notsup, nullfree, 0}, + + /* OP_DESTROY_CLIENTID = 57 */ + {rfs4x_op_destroy_clientid, nullfree, 0}, + + /* OP_RECLAIM_COMPLETE = 58 */ + {rfs4x_op_reclaim_complete, nullfree, 0}, }; static uint_t rfsv4disp_cnt = sizeof (rfsv4disptab) / sizeof (rfsv4disptab[0]); @@ -463,8 +551,29 @@ static char *rfs4_op_string[] = { "rfs4_op_verify", "rfs4_op_write", "rfs4_op_release_lockowner", + /* NFSv4.1 */ + "backchannel_ctl", + "bind_conn_to_session", + "exchange_id", + "create_session", + "destroy_session", + "free_stateid", + "get_dir_delegation", + "getdeviceinfo", + "getdevicelist", + "layoutcommit", + "layoutget", + "layoutreturn", + "secinfo_no_name", + "sequence", + "set_ssv", + "test_stateid", + "want_delegation", + "destroy_clientid", + "reclaim_complete", "rfs4_op_illegal" }; + #endif void rfs4_ss_chkclid(nfs4_srv_t *, rfs4_client_t *); @@ -662,6 +771,31 @@ rfs4_init_compound_state(struct compound_state *cs) cs->fh.nfs_fh4_val = cs->fhbuf; } +/* Do cleanup of the compound_state */ +void +rfs4_fini_compound_state(struct compound_state *cs) +{ + if (cs->vp) { + VN_RELE(cs->vp); + } + if (cs->saved_vp) { + VN_RELE(cs->saved_vp); + } + if (cs->cr) { + crfree(cs->cr); + } + if (cs->saved_fh.nfs_fh4_val) { + kmem_free(cs->saved_fh.nfs_fh4_val, NFS4_FHSIZE); + } + + if (cs->basecr) { + crfree(cs->basecr); + } + if (cs->sp) { + rfs4x_session_rele(cs->sp); + } +} + void rfs4_grace_start(rfs4_servinst_t *sip) { @@ -697,6 +831,8 @@ rfs4_servinst_in_grace(rfs4_servinst_t *sip) rw_enter(&sip->rwlock, RW_READER); grace_expiry = sip->start_time + sip->grace_period; + if (sip->nreclaim == 0) + grace_expiry = 0; rw_exit(&sip->rwlock); return (((time_t)TICK_TO_SEC(ddi_get_lbolt())) < grace_expiry); @@ -796,6 +932,7 @@ rfs4_servinst_create(nfs4_srv_t *nsrv4, int start_grace, sip = kmem_alloc(sizeof (rfs4_servinst_t), KM_SLEEP); rw_init(&sip->rwlock, NULL, RW_DEFAULT, NULL); + sip->nreclaim = 0; sip->start_time = (time_t)0; sip->grace_period = (time_t)0; sip->next = NULL; @@ -948,7 +1085,7 @@ in_flavor_list(int nfsnum, int *flavor_list, int count) * export structure associated with the component. */ /* ARGSUSED */ -static nfsstat4 +nfsstat4 do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp) { int error, different_export = 0; @@ -1274,9 +1411,14 @@ rfs4_op_secinfo(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, goto out; } - *cs->statusp = resp->status = do_rfs4_op_secinfo(cs, name, resp); + if (resp->status == NFS4_OK && rfs4_has_session(cs)) { + /* See rfc 5661 section 2.6.3.1.1.8 and 18.29.3 */ + VN_RELE(cs->vp); + cs->vp = NULL; + } + if (name != nm) kmem_free(name, MAXPATHLEN + 1); kmem_free(nm, len); @@ -2521,6 +2663,14 @@ rfs4_op_illegal(nfs_argop4 *argop, nfs_resop4 *resop, *cs->statusp = resp->status = NFS4ERR_OP_ILLEGAL; } +/* ARGSUSED */ +static void +rfs4_op_notsup(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, + struct compound_state *cs) +{ + *cs->statusp = *((nfsstat4 *)&(resop)->nfs_resop4_u) = NFS4ERR_NOTSUPP; +} + /* * link: args: SAVED_FH: file, CURRENT_FH: target directory * res: status. If success - CURRENT_FH unchanged, return change_info @@ -3257,7 +3407,7 @@ rfs4_op_read(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, } if ((stat = rfs4_check_stateid(FREAD, vp, &args->stateid, FALSE, - deleg, TRUE, &ct)) != NFS4_OK) { + deleg, TRUE, &ct, cs)) != NFS4_OK) { *cs->statusp = resp->status = stat; goto out; } @@ -5198,6 +5348,7 @@ do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs, */ goto done; } + if ((sarg.vap->va_mask == 0) && (! (fattrp->attrmask & FATTR4_ACL_MASK))) { /* @@ -5233,7 +5384,7 @@ do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs, if (sarg.vap->va_mask & AT_SIZE) { trunc = (sarg.vap->va_size == 0); status = rfs4_check_stateid(FWRITE, cs->vp, stateid, - trunc, &cs->deleg, sarg.vap->va_mask & AT_SIZE, &ct); + trunc, &cs->deleg, sarg.vap->va_mask & AT_SIZE, &ct, cs); if (status != NFS4_OK) goto done; } else { @@ -5622,7 +5773,7 @@ rfs4_op_write(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, cr = cs->cr; if ((stat = rfs4_check_stateid(FWRITE, vp, &args->stateid, FALSE, - deleg, TRUE, &ct)) != NFS4_OK) { + deleg, TRUE, &ct, cs)) != NFS4_OK) { *cs->statusp = resp->status = stat; goto out; } @@ -5790,18 +5941,31 @@ out: /* XXX put in a header file */ extern int sec_svc_getcred(struct svc_req *, cred_t *, caddr_t *, int *); +static inline int +rfs4_opnum_in_range(const compound_state_t *cs, int opnum) +{ + if (opnum < FIRST_NFS4_OP || opnum > LAST_NFS4_OP) + return (0); + else if (cs->minorversion == 0 && opnum > LAST_NFS40_OP) + return (0); + else if (cs->minorversion == 1 && opnum > LAST_NFS41_OP) + return (0); + else if (cs->minorversion == 2 && opnum > LAST_NFS42_OP) + return (0); + return (1); +} + void -rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi, - struct svc_req *req, cred_t *cr, int *rv) +rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, compound_state_t *cs, + struct svc_req *req, int *rv) { uint_t i; - struct compound_state cs; + cred_t *cr; nfs4_srv_t *nsrv4; nfs_export_t *ne = nfs_get_export(); if (rv != NULL) *rv = 0; - rfs4_init_compound_state(&cs); /* * Form a reply tag by copying over the request tag. */ @@ -5815,53 +5979,41 @@ rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi, resp->tag.utf8string_val = NULL; } - cs.statusp = &resp->status; - cs.req = req; + cs->statusp = &resp->status; + cs->req = req; + cs->minorversion = args->minorversion; resp->array = NULL; resp->array_len = 0; - /* - * XXX for now, minorversion should be zero - */ - if (args->minorversion != NFS4_MINORVERSION) { - DTRACE_NFSV4_2(compound__start, struct compound_state *, - &cs, COMPOUND4args *, args); - resp->status = NFS4ERR_MINOR_VERS_MISMATCH; - DTRACE_NFSV4_2(compound__done, struct compound_state *, - &cs, COMPOUND4res *, resp); - return; - } - if (args->array_len == 0) { resp->status = NFS4_OK; return; } - ASSERT(exi == NULL); - ASSERT(cr == NULL); - cr = crget(); ASSERT(cr != NULL); - if (sec_svc_getcred(req, cr, &cs.principal, &cs.nfsflavor) == 0) { + if (sec_svc_getcred(req, cr, &cs->principal, &cs->nfsflavor) == 0) { DTRACE_NFSV4_2(compound__start, struct compound_state *, - &cs, COMPOUND4args *, args); + cs, COMPOUND4args *, args); crfree(cr); DTRACE_NFSV4_2(compound__done, struct compound_state *, - &cs, COMPOUND4res *, resp); + cs, COMPOUND4res *, resp); svcerr_badcred(req->rq_xprt); if (rv != NULL) *rv = 1; return; } + resp->array_len = args->array_len; resp->array = kmem_zalloc(args->array_len * sizeof (nfs_resop4), KM_SLEEP); - cs.basecr = cr; + cs->op_len = args->array_len; + cs->basecr = cr; nsrv4 = nfs4_get_srv(); - DTRACE_NFSV4_2(compound__start, struct compound_state *, &cs, + DTRACE_NFSV4_2(compound__start, struct compound_state *, cs, COMPOUND4args *, args); /* @@ -5890,7 +6042,7 @@ rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi, nsrv4->seen_first_compound = 1; } - for (i = 0; i < args->array_len && cs.cont; i++) { + for (i = 0; i < args->array_len && cs->cont; i++) { nfs_argop4 *argop; nfs_resop4 *resop; uint_t op; @@ -5901,7 +6053,8 @@ rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi, resop->resop = argop->argop; op = (uint_t)resop->resop; - if (op < rfsv4disp_cnt) { + cs->op_pos = i; + if (op < rfsv4disp_cnt && rfs4_opnum_in_range(cs, op)) { /* * Count the individual ops here; NULL and COMPOUND * are counted in common_dispatch() @@ -5910,11 +6063,11 @@ rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi, NFS4_DEBUG(rfs4_debug > 1, (CE_NOTE, "Executing %s", rfs4_op_string[op])); - (*rfsv4disptab[op].dis_proc)(argop, resop, req, &cs); + (*rfsv4disptab[op].dis_proc)(argop, resop, req, cs); NFS4_DEBUG(rfs4_debug > 1, (CE_NOTE, "%s returned %d", - rfs4_op_string[op], *cs.statusp)); - if (*cs.statusp != NFS4_OK) - cs.cont = FALSE; + rfs4_op_string[op], *cs->statusp)); + if (*cs->statusp != NFS4_OK) + cs->cont = FALSE; } else { /* * This is effectively dead code since XDR code @@ -5925,15 +6078,15 @@ rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi, op = OP_ILLEGAL; stat[OP_ILLEGAL_IDX].value.ui64++; - rfs4_op_illegal(argop, resop, req, &cs); - cs.cont = FALSE; + rfs4_op_illegal(argop, resop, req, cs); + cs->cont = FALSE; } /* * If not at last op, and if we are to stop, then * compact the results array. */ - if ((i + 1) < args->array_len && !cs.cont) { + if ((i + 1) < args->array_len && !cs->cont) { nfs_resop4 *new_res = kmem_alloc( (i+1) * sizeof (nfs_resop4), KM_SLEEP); bcopy(resp->array, @@ -5948,27 +6101,9 @@ rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi, rw_exit(&ne->exported_lock); - /* - * clear exportinfo and vnode fields from compound_state before dtrace - * probe, to avoid tracing residual values for path and share path. - */ - if (cs.vp) - VN_RELE(cs.vp); - if (cs.saved_vp) - VN_RELE(cs.saved_vp); - cs.exi = cs.saved_exi = NULL; - cs.vp = cs.saved_vp = NULL; - - DTRACE_NFSV4_2(compound__done, struct compound_state *, &cs, + DTRACE_NFSV4_2(compound__done, struct compound_state *, cs, COMPOUND4res *, resp); - if (cs.saved_fh.nfs_fh4_val) - kmem_free(cs.saved_fh.nfs_fh4_val, NFS4_FHSIZE); - - if (cs.basecr) - crfree(cs.basecr); - if (cs.cr) - crfree(cs.cr); /* * done with this compound request, free the label */ @@ -6094,7 +6229,7 @@ static void lock_print(char *str, int operation, struct flock64 *flk) /*ARGSUSED*/ static bool_t -creds_ok(cred_set_t cr_set, struct svc_req *req, struct compound_state *cs) +creds_ok(cred_set_t *cr_set, struct svc_req *req, struct compound_state *cs) { return (TRUE); } @@ -6360,6 +6495,21 @@ check_open_access(uint32_t access, struct compound_state *cs, return (NFS4_OK); } +static void +rfs4_verifier_to_mtime(verifier4 v, timestruc_t *mtime) +{ + timespec32_t *time = (timespec32_t *)&v; + + /* + * Ensure no time overflows. Assumes underlying + * filesystem supports at least 32 bits. + * Truncate nsec to usec resolution to allow valid + * compares even if the underlying filesystem truncates. + */ + mtime->tv_sec = time->tv_sec % TIME32_MAX; + mtime->tv_nsec = (time->tv_nsec / 1000) * 1000; +} + static nfsstat4 rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs, change_info4 *cinfo, bitmap4 *attrset, clientid4 clientid) @@ -6373,7 +6523,6 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs, vnode_t *vp; vattr_t bva, ava, iva, cva, *vap; vnode_t *dvp; - timespec32_t *mtime; char *nm = NULL; uint_t buflen; bool_t created; @@ -6386,6 +6535,9 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs, bslabel_t *clabel; struct sockaddr *ca; char *name = NULL; + fattr4 *fattr = NULL; + + ASSERT(*attrset == 0); sarg.sbp = &sb; sarg.is_referral = B_FALSE; @@ -6411,11 +6563,17 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs, } } + if ((args->mode == EXCLUSIVE4 || args->mode == EXCLUSIVE4_1) && + dvp->v_flag & V_XATTRDIR) { + /* prohibit EXCL create of named attributes */ + return (NFS4ERR_INVAL); + } + /* * Get the last component of path name in nm. cs will reference * the including directory on success. */ - component = &args->open_claim4_u.file; + component = &args->claim.open_claim4_u.file; status = utf8_dir_verify(component); if (status != NFS4_OK) return (status); @@ -6448,12 +6606,17 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs, case GUARDED4: /*FALLTHROUGH*/ case UNCHECKED4: + case EXCLUSIVE4_1: nfs4_ntov_table_init(&ntov); ntov_table_init = TRUE; - *attrset = 0; + if (args->mode == EXCLUSIVE4_1) + fattr = &args->createhow4_u.ch_createboth.cva_attrs; + else + fattr = &args->createhow4_u.createattrs; + status = do_rfs4_set_attrs(attrset, - &args->createhow4_u.createattrs, + fattr, cs, &sarg, &ntov, NFS4ATTR_SETIT); if (status == NFS4_OK && (sarg.vap->va_mask & AT_TYPE) && @@ -6494,28 +6657,24 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs, } setsize = TRUE; } + if (args->mode == EXCLUSIVE4_1) { + rfs4_verifier_to_mtime( + args->createhow4_u.ch_createboth.cva_verf, + &vap->va_mtime); + /* attrset will be set later */ + fattr->attrmask |= FATTR4_TIME_MODIFY_MASK; + vap->va_mask |= AT_MTIME; + } break; case EXCLUSIVE4: - /* prohibit EXCL create of named attributes */ - if (dvp->v_flag & V_XATTRDIR) { - kmem_free(nm, buflen); - *attrset = 0; - return (NFS4ERR_INVAL); - } - cva.va_mask = AT_TYPE | AT_MTIME | AT_MODE; cva.va_type = VREG; - /* - * Ensure no time overflows. Assumes underlying - * filesystem supports at least 32 bits. - * Truncate nsec to usec resolution to allow valid - * compares even if the underlying filesystem truncates. - */ - mtime = (timespec32_t *)&args->createhow4_u.createverf; - cva.va_mtime.tv_sec = mtime->tv_sec % TIME32_MAX; - cva.va_mtime.tv_nsec = (mtime->tv_nsec / 1000) * 1000; cva.va_mode = (mode_t)0; + + rfs4_verifier_to_mtime(args->createhow4_u.createverf, + &cva.va_mtime); + vap = &cva; /* @@ -6551,7 +6710,7 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs, trunc = (setsize && !created); if (args->mode != EXCLUSIVE4) { - bitmap4 createmask = args->createhow4_u.createattrs.attrmask; + bitmap4 createmask = fattr->attrmask; /* * True verification that object was created with correct @@ -6993,6 +7152,16 @@ rfs4_do_open(struct compound_state *cs, struct svc_req *req, /*ARGSUSED*/ static void +rfs4_do_openfh(struct compound_state *cs, struct svc_req *req, OPEN4args *args, + rfs4_openowner_t *oo, OPEN4res *resp) +{ + /* cs->vp and cs->fh have been updated by putfh. */ + rfs4_do_open(cs, req, oo, DELEG_ANY, + (args->share_access & 0xff), args->share_deny, resp, 0); +} + +/*ARGSUSED*/ +static void rfs4_do_opennull(struct compound_state *cs, struct svc_req *req, OPEN4args *args, rfs4_openowner_t *oo, OPEN4res *resp) { @@ -7000,7 +7169,7 @@ rfs4_do_opennull(struct compound_state *cs, struct svc_req *req, bitmap4 *attrset = &resp->attrset; if (args->opentype == OPEN4_NOCREATE) - resp->status = rfs4_lookupfile(&args->open_claim4_u.file, + resp->status = rfs4_lookupfile(&args->claim.open_claim4_u.file, req, cs, args->share_access, cinfo); else { /* inhibit delegation grants during exclusive create */ @@ -7087,7 +7256,7 @@ rfs4_do_openprev(struct compound_state *cs, struct svc_req *req, cinfo->atomic = FALSE; rfs4_do_open(cs, req, oo, - NFS4_DELEG4TYPE2REQTYPE(args->open_claim4_u.delegate_type), + NFS4_DELEG4TYPE2REQTYPE(args->claim.open_claim4_u.delegate_type), args->share_access, args->share_deny, resp, 0); } @@ -7098,7 +7267,7 @@ rfs4_do_opendelcur(struct compound_state *cs, struct svc_req *req, int error; nfsstat4 status; stateid4 stateid = - args->open_claim4_u.delegate_cur_info.delegate_stateid; + args->claim.open_claim4_u.delegate_cur_info.delegate_stateid; rfs4_deleg_state_t *dsp; /* @@ -7168,7 +7337,8 @@ rfs4_do_opendelprev(struct compound_state *cs, struct svc_req *req, nfsace4 *ace; /* Note we ignore oflags */ - resp->status = rfs4_lookupfile(&args->open_claim4_u.file_delegate_prev, + resp->status = rfs4_lookupfile( + &args->claim.open_claim4_u.file_delegate_prev, req, cs, args->share_access, &resp->cinfo); if (resp->status != NFS4_OK) { @@ -7298,10 +7468,14 @@ rfs4_check_seqid(seqid4 seqid, nfs_resop4 *lastop, static rfs4_chkseq_t -rfs4_check_open_seqid(seqid4 seqid, rfs4_openowner_t *op, nfs_resop4 *resop) +rfs4_check_open_seqid(seqid4 seqid, rfs4_openowner_t *op, nfs_resop4 *resop, + const compound_state_t *cs) { rfs4_chkseq_t rc; + if (rfs4_has_session(cs)) + return (NFS4_CHKSEQ_OKAY); + rfs4_dbe_lock(op->ro_dbe); rc = rfs4_check_seqid(op->ro_open_seqid, &op->ro_reply, seqid, resop, TRUE); @@ -7347,7 +7521,7 @@ rfs4_op_open(nfs_argop4 *argop, nfs_resop4 *resop, OPEN4args *args = &argop->nfs_argop4_u.opopen; OPEN4res *resp = &resop->nfs_resop4_u.opopen; open_owner4 *owner = &args->owner; - open_claim_type4 claim = args->claim; + open_claim_type4 claim = args->claim.claim; rfs4_client_t *cp; rfs4_openowner_t *oo; bool_t create; @@ -7362,6 +7536,10 @@ rfs4_op_open(nfs_argop4 *argop, nfs_resop4 *resop, goto end; } + /* rfc5661 section 18.16.3 */ + if (rfs4_has_session(cs)) + owner->clientid = cs->client->rc_clientid; + /* * Need to check clientid and lease expiration first based on * error ordering and incrementing sequence id. @@ -7394,6 +7572,13 @@ retry: goto end; } + /* + * OPEN_CONFIRM must not be implemented in v4.1 + */ + if (rfs4_has_session(cs)) { + oo->ro_need_confirm = FALSE; + } + /* Hold off access to the sequence space while the open is done */ rfs4_sw_enter(&oo->ro_sw); @@ -7402,7 +7587,7 @@ retry: * the sequence id. */ if (!create && !oo->ro_postpone_confirm) { - switch (rfs4_check_open_seqid(args->seqid, oo, resop)) { + switch (rfs4_check_open_seqid(args->seqid, oo, resop, cs)) { case NFS4_CHKSEQ_BAD: if ((args->seqid > oo->ro_open_seqid) && oo->ro_need_confirm) { @@ -7434,7 +7619,8 @@ retry: } /* Grace only applies to regular-type OPENs */ if (rfs4_clnt_in_grace(cp) && - (claim == CLAIM_NULL || claim == CLAIM_DELEGATE_CUR)) { + (claim == CLAIM_NULL || claim == CLAIM_DELEGATE_CUR || + claim == CLAIM_FH)) { *cs->statusp = resp->status = NFS4ERR_GRACE; goto out; } @@ -7512,6 +7698,9 @@ retry: case CLAIM_DELEGATE_PREV: rfs4_do_opendelprev(cs, req, args, oo, resp); break; + case CLAIM_FH: + rfs4_do_openfh(cs, req, args, oo, resp); + break; default: resp->status = NFS4ERR_INVAL; break; @@ -7636,6 +7825,8 @@ rfs4_op_open_confirm(nfs_argop4 *argop, nfs_resop4 *resop, DTRACE_NFSV4_2(op__open__confirm__start, struct compound_state *, cs, OPEN_CONFIRM4args *, args); + ASSERT(!rfs4_has_session(cs)); + if (cs->vp == NULL) { *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; goto out; @@ -7663,10 +7854,10 @@ rfs4_op_open_confirm(nfs_argop4 *argop, nfs_resop4 *resop, /* hold off other access to open_owner while we tinker */ rfs4_sw_enter(&sp->rs_owner->ro_sw); - switch (rfs4_check_stateid_seqid(sp, &args->open_stateid)) { + switch (rfs4_check_stateid_seqid(sp, &args->open_stateid, cs)) { case NFS4_CHECK_STATEID_OKAY: if (rfs4_check_open_seqid(args->seqid, sp->rs_owner, - resop) != 0) { + resop, cs) != 0) { *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; break; } @@ -7692,7 +7883,7 @@ rfs4_op_open_confirm(nfs_argop4 *argop, nfs_resop4 *resop, break; case NFS4_CHECK_STATEID_REPLAY: switch (rfs4_check_open_seqid(args->seqid, sp->rs_owner, - resop)) { + resop, cs)) { case NFS4_CHKSEQ_OKAY: /* * This is replayed stateid; if seqid matches @@ -7714,7 +7905,7 @@ rfs4_op_open_confirm(nfs_argop4 *argop, nfs_resop4 *resop, break; case NFS4_CHECK_STATEID_UNCONFIRMED: if (rfs4_check_open_seqid(args->seqid, sp->rs_owner, - resop) != NFS4_CHKSEQ_OKAY) { + resop, cs) != NFS4_CHKSEQ_OKAY) { *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; break; } @@ -7783,10 +7974,10 @@ rfs4_op_open_downgrade(nfs_argop4 *argop, nfs_resop4 *resop, /* hold off other access to open_owner while we tinker */ rfs4_sw_enter(&sp->rs_owner->ro_sw); - switch (rfs4_check_stateid_seqid(sp, &args->open_stateid)) { + switch (rfs4_check_stateid_seqid(sp, &args->open_stateid, cs)) { case NFS4_CHECK_STATEID_OKAY: if (rfs4_check_open_seqid(args->seqid, sp->rs_owner, - resop) != NFS4_CHKSEQ_OKAY) { + resop, cs) != NFS4_CHKSEQ_OKAY) { *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; goto end; } @@ -7807,9 +7998,11 @@ rfs4_op_open_downgrade(nfs_argop4 *argop, nfs_resop4 *resop, *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; goto end; case NFS4_CHECK_STATEID_REPLAY: + ASSERT(!rfs4_has_session(cs)); + /* Check the sequence id for the open owner */ switch (rfs4_check_open_seqid(args->seqid, sp->rs_owner, - resop)) { + resop, cs)) { case NFS4_CHKSEQ_OKAY: /* * This is replayed stateid; if seqid matches @@ -8098,7 +8291,7 @@ retry: */ if (cp_confirmed) { /* If creds don't match then client identifier is inuse */ - if (!creds_ok(cp_confirmed->rc_cr_set, req, cs)) { + if (!creds_ok(&cp_confirmed->rc_cr_set, req, cs)) { rfs4_cbinfo_t *cbp; /* * Some one else has established this client @@ -8260,7 +8453,7 @@ rfs4_op_setclientid_confirm(nfs_argop4 *argop, nfs_resop4 *resop, goto out; } - if (!creds_ok(cp, req, cs)) { + if (!creds_ok(&cp->rc_cr_set, req, cs)) { *cs->statusp = res->status = NFS4ERR_CLID_INUSE; rfs4_client_rele(cp); goto out; @@ -8352,10 +8545,10 @@ rfs4_op_close(nfs_argop4 *argop, nfs_resop4 *resop, /* hold off other access to open_owner while we tinker */ rfs4_sw_enter(&sp->rs_owner->ro_sw); - switch (rfs4_check_stateid_seqid(sp, &args->open_stateid)) { + switch (rfs4_check_stateid_seqid(sp, &args->open_stateid, cs)) { case NFS4_CHECK_STATEID_OKAY: if (rfs4_check_open_seqid(args->seqid, sp->rs_owner, - resop) != NFS4_CHKSEQ_OKAY) { + resop, cs) != NFS4_CHKSEQ_OKAY) { *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; goto end; } @@ -8376,9 +8569,11 @@ rfs4_op_close(nfs_argop4 *argop, nfs_resop4 *resop, *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; goto end; case NFS4_CHECK_STATEID_REPLAY: + ASSERT(!rfs4_has_session(cs)); + /* Check the sequence id for the open owner */ switch (rfs4_check_open_seqid(args->seqid, sp->rs_owner, - resop)) { + resop, cs)) { case NFS4_CHKSEQ_OKAY: /* * This is replayed stateid; if seqid matches @@ -8911,7 +9106,7 @@ rfs4_op_lock(nfs_argop4 *argop, nfs_resop4 *resop, /* hold off other access to open_owner while we tinker */ rfs4_sw_enter(&sp->rs_owner->ro_sw); - switch (rc = rfs4_check_stateid_seqid(sp, stateid)) { + switch (rc = rfs4_check_stateid_seqid(sp, stateid, cs)) { case NFS4_CHECK_STATEID_OLD: *cs->statusp = resp->status = NFS4ERR_OLD_STATEID; goto end; @@ -8928,7 +9123,12 @@ rfs4_op_lock(nfs_argop4 *argop, nfs_resop4 *resop, *cs->statusp = resp->status = NFS4ERR_OLD_STATEID; goto end; case NFS4_CHECK_STATEID_OKAY: + if (rfs4_has_session(cs)) + break; + /* FALLTHROUGH */ case NFS4_CHECK_STATEID_REPLAY: + ASSERT(!rfs4_has_session(cs)); + switch (rfs4_check_olo_seqid(olo->open_seqid, sp->rs_owner, resop)) { case NFS4_CHKSEQ_OKAY: @@ -8995,7 +9195,7 @@ rfs4_op_lock(nfs_argop4 *argop, nfs_resop4 *resop, * not appropriate. The client should be using the * existing lock_owner branch. */ - if (dup_lock == FALSE && create == FALSE) { + if (!rfs4_has_session(cs) && !dup_lock && !create) { if (lsp->rls_lock_completed == TRUE) { *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; @@ -9087,12 +9287,15 @@ rfs4_op_lock(nfs_argop4 *argop, nfs_resop4 *resop, rfs4_sw_enter(&lsp->rls_sw); ls_sw_held = TRUE; - switch (rfs4_check_lo_stateid_seqid(lsp, stateid)) { + switch (rfs4_check_lo_stateid_seqid(lsp, stateid, cs)) { /* * The stateid looks like it was okay (expected to be * the next one) */ case NFS4_CHECK_STATEID_OKAY: + if (rfs4_has_session(cs)) + break; + /* * The sequence id is now checked. Determine * if this is a replay or if it is in the @@ -9152,6 +9355,8 @@ rfs4_op_lock(nfs_argop4 *argop, nfs_resop4 *resop, *cs->statusp = resp->status = NFS4ERR_OLD_STATEID; goto end; case NFS4_CHECK_STATEID_REPLAY: + ASSERT(!rfs4_has_session(cs)); + switch (rfs4_check_lock_seqid( args->locker.locker4_u.lock_owner.lock_seqid, lsp, resop)) { @@ -9317,8 +9522,11 @@ rfs4_op_locku(nfs_argop4 *argop, nfs_resop4 *resop, /* hold off other access to lsp while we tinker */ rfs4_sw_enter(&lsp->rls_sw); - switch (rfs4_check_lo_stateid_seqid(lsp, stateid)) { + switch (rfs4_check_lo_stateid_seqid(lsp, stateid, cs)) { case NFS4_CHECK_STATEID_OKAY: + if (rfs4_has_session(cs)) + break; + if (rfs4_check_lock_seqid(args->seqid, lsp, resop) != NFS4_CHKSEQ_OKAY) { *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; @@ -9338,6 +9546,8 @@ rfs4_op_locku(nfs_argop4 *argop, nfs_resop4 *resop, *cs->statusp = resp->status = NFS4ERR_OLD_STATEID; goto end; case NFS4_CHECK_STATEID_REPLAY: + ASSERT(!rfs4_has_session(cs)); + switch (rfs4_check_lock_seqid(args->seqid, lsp, resop)) { case NFS4_CHKSEQ_OKAY: /* diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c b/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c index a9ee217a8b..a558c48466 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c +++ b/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c @@ -26,6 +26,7 @@ /* * Copyright 2018 Nexenta Systems, Inc. + * Copyright 2020 RackTop Systems, Inc. */ #include <sys/systm.h> @@ -126,6 +127,24 @@ static int rfs4_fattr4_time_modify_set(); /* * Initialize the supported attributes */ +bitmap4 supported_attrs[3]; + +static void +init_supported_attrs() +{ + bitmap4 supported = rfs4_supported_attrs; + + supported_attrs[0] = supported_attrs[1] = supported_attrs[2] = + rfs4_supported_attrs; + + /* restrict to nfsv4.0 */ + supported_attrs[0] &= ~(FATTR4_SUPPATTR_EXCLCREAT_MASK_LOCAL | + FATTR4_SEC_LABEL_MASK_LOCAL); + + /* restrict to nfsv4.1 */ + supported_attrs[1] &= ~FATTR4_SEC_LABEL_MASK_LOCAL; +} + void rfs4_attr_init() { @@ -143,6 +162,7 @@ rfs4_attr_init() cs.vp = rootvp; cs.fh.nfs_fh4_val = NULL; cs.cr = kcred; + cs.minorversion = 2; /* * Get all the supported attributes @@ -169,6 +189,8 @@ rfs4_attr_init() rfs4_supported_attrs |= nfs4_ntov_map[i].fbit; } } + + init_supported_attrs(); } /* @@ -219,6 +241,7 @@ rfs4_fattr4_supported_attrs(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, union nfs4_attr_u *na) { int error = 0; + bitmap4 supported = supported_attrs[sarg->cs->minorversion]; switch (cmd) { case NFS4ATTR_SUPPORTED: @@ -226,7 +249,7 @@ rfs4_fattr4_supported_attrs(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, error = EINVAL; break; /* this attr is supported */ case NFS4ATTR_GETIT: - na->supported_attrs = rfs4_supported_attrs; + na->supported_attrs = supported; break; case NFS4ATTR_SETIT: /* @@ -238,7 +261,7 @@ rfs4_fattr4_supported_attrs(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, /* * Compare the input bitmap to the server's bitmap */ - if (na->supported_attrs != rfs4_supported_attrs) { + if (na->supported_attrs != supported) { error = -1; /* no match */ } break; @@ -2814,6 +2837,40 @@ rfs4_fattr4_time_modify_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, return (error); } +/* ARGSUSED */ +static int +rfs4_fattr4_suppattr_exclcreat(nfs4_attr_cmd_t cmd, + struct nfs4_svgetit_arg *sarg, union nfs4_attr_u *na) +{ + int error = 0; + + /* Not supported for nfs4.0 */ + if (sarg->cs->minorversion == 0) + return (ENOTSUP); + + switch (cmd) { + case NFS4ATTR_SUPPORTED: + if (sarg->op == NFS4ATTR_SETIT) + error = EINVAL; + break; /* this attr is supported */ + case NFS4ATTR_GETIT: + na->supp_exclcreat = RFS4_SUPPATTR_EXCLCREAT; + break; + case NFS4ATTR_SETIT: + /* + * read-only attr + */ + error = EINVAL; + break; + case NFS4ATTR_VERIT: + if (na->supp_exclcreat != RFS4_SUPPATTR_EXCLCREAT) + error = -1; /* no match */ + break; + case NFS4ATTR_FREEIT: + break; + } + return (error); +} static void rfs4_ntov_init(void) @@ -2875,4 +2932,5 @@ rfs4_ntov_init(void) nfs4_ntov_map[53].sv_getit = rfs4_fattr4_time_modify; nfs4_ntov_map[54].sv_getit = rfs4_fattr4_time_modify_set; nfs4_ntov_map[55].sv_getit = rfs4_fattr4_mounted_on_fileid; + nfs4_ntov_map[56].sv_getit = rfs4_fattr4_suppattr_exclcreat; } diff --git a/usr/src/uts/common/fs/nfs/nfs4_state.c b/usr/src/uts/common/fs/nfs/nfs4_state.c index b95dd6fb02..582813bf93 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_state.c +++ b/usr/src/uts/common/fs/nfs/nfs4_state.c @@ -26,6 +26,7 @@ /* * Copyright 2018 Nexenta Systems, Inc. * Copyright 2019 Nexenta by DDN, Inc. + * Copyright 2020 RackTop Systems, Inc. */ #include <sys/systm.h> @@ -595,6 +596,31 @@ rfs4_ss_getstate(vnode_t *dvp, rfs4_ss_pn_t *ss_pn) #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) /* + * Check whether list @head already contains the @client + * This protects against counting the same client twice. + */ +static bool_t +rfs4_ss_has_client(rfs4_oldstate_t *head, nfs_client_id4 *client) +{ + rfs4_oldstate_t *p; + + for (p = head->next; p != head; p = p->next) { + nfs_client_id4 *m = &p->cl_id4; + + if (m->id_len != client->id_len) + continue; + + if (bcmp(m->id_val, client->id_val, client->id_len) == 0) + continue; + + /* client ids match */ + return (TRUE); + } + + return (FALSE); +} + +/* * Add entries from statedir to supplied oldstate list. * Optionally, move all entries from statedir -> destdir. */ @@ -610,6 +636,7 @@ rfs4_ss_oldstate(rfs4_oldstate_t *oldstate, char *statedir, char *destdir) struct uio uio; struct dirent64 *dep; offset_t dirchunk_offset = 0; + unsigned int nclients = 0; /* * open the state directory @@ -670,6 +697,11 @@ rfs4_ss_oldstate(rfs4_oldstate_t *oldstate, char *statedir, char *destdir) } else { cl_ss->ss_pn = ss_pn; } + + if (!rfs4_ss_has_client(oldstate, + &cl_ss->cl_id4)) + nclients++; + insque(cl_ss, oldstate); } else { rfs4_ss_pnfree(ss_pn); @@ -682,6 +714,12 @@ out: VN_RELE(dvp); if (dirt) kmem_free((caddr_t)dirt, RFS4_SS_DIRSIZE); + + if (nclients > 0) { + nfs4_srv_t *nsrv4 = nfs4_get_srv(); + + atomic_add_32(&(nsrv4->nfs4_cur_servinst->nreclaim), nclients); + } } static void @@ -1181,6 +1219,9 @@ rfs4_state_g_init() /* CSTYLED */ rfs4_delegstID_mem_cache = nfs4_init_mem_cache("DelegStateID_entry_cache", 2, sizeof (rfs4_deleg_state_t), 7); + /* CSTYLED */ + (void) nfs4_init_mem_cache("Session_entry_cache", 1, sizeof (rfs4_session_t), 8); + rfs4_client_clrst = rfs4_clear_client_state; } @@ -1480,6 +1521,8 @@ rfs4_state_zone_init(nfs4_srv_t *nsrv4) deleg_state_compare, deleg_state_mkkey, FALSE); + rfs4x_state_init_locked(nsrv4); + mutex_exit(&nsrv4->state_lock); /* @@ -1516,6 +1559,8 @@ rfs4_state_zone_fini() return; } + rfs4x_state_fini(nsrv4); + /* destroy server instances and current instance ptr */ rfs4_servinst_destroy_all(nsrv4); @@ -1720,6 +1765,8 @@ rfs4_client_destroy(rfs4_entry_t u_entry) cv_destroy(cp->rc_cbinfo.cb_cv_nullcaller); list_destroy(&cp->rc_openownerlist); + list_destroy(&cp->rc_sessions); + /* free callback info */ rfs4_cbinfo_free(&cp->rc_cbinfo); @@ -1738,6 +1785,8 @@ rfs4_client_destroy(rfs4_entry_t u_entry) if (cp->rc_sysidt != LM_NOSYSID) lm_free_sysidt(cp->rc_sysidt); + + rfs4_free_cred_set(&cp->rc_cr_set); } static bool_t @@ -1786,6 +1835,7 @@ rfs4_client_create(rfs4_entry_t u_entry, void *arg) /* We need the client to ack us */ cp->rc_need_confirm = TRUE; cp->rc_cp_confirmed = NULL; + cp->rc_destroying = FALSE; /* TRUE all the time until the callback path actually fails */ cp->rc_cbinfo.cb_notified_of_cb_path_down = TRUE; @@ -1793,13 +1843,16 @@ rfs4_client_create(rfs4_entry_t u_entry, void *arg) /* Initialize the access time to now */ cp->rc_last_access = gethrestime_sec(); - cp->rc_cr_set = NULL; + bzero(&cp->rc_cr_set, sizeof (cred_set_t)); cp->rc_sysidt = LM_NOSYSID; list_create(&cp->rc_openownerlist, sizeof (rfs4_openowner_t), offsetof(rfs4_openowner_t, ro_node)); + list_create(&cp->rc_sessions, sizeof (rfs4_session_t), + offsetof(rfs4_session_t, sn_node)); + /* set up the callback control structure */ cp->rc_cbinfo.cb_state = CB_UNINIT; mutex_init(cp->rc_cbinfo.cb_lock, NULL, MUTEX_DEFAULT, NULL); @@ -1815,6 +1868,12 @@ rfs4_client_create(rfs4_entry_t u_entry, void *arg) rfs4_servinst_assign(nsrv4, cp, nsrv4->nfs4_cur_servinst); rfs4_dbe_rele(cp->rc_dbe); + /* + * NFSv4.1: See rfc5661, Section 18.36.4, eir_sequenceid + */ + cp->rc_contrived.xi_sid = 1; + cp->rc_contrived.cs_status = NFS4ERR_SEQ_MISORDERED; + return (TRUE); } @@ -2202,7 +2261,6 @@ rfs4_openowner_create(rfs4_entry_t u_entry, void *arg) oo->ro_open_seqid = seqid; bzero(&oo->ro_reply, sizeof (nfs_resop4)); oo->ro_client = cp; - oo->ro_cr_set = NULL; list_create(&oo->ro_statelist, sizeof (rfs4_state_t), offsetof(rfs4_state_t, rs_node)); @@ -3337,6 +3395,7 @@ rfs4_client_close(rfs4_client_t *cp) rfs4_dbe_unlock(cp->rc_dbe); rfs4_client_state_remove(cp); + rfs4x_client_session_remove(cp); /* Release the client */ rfs4_client_rele(cp); @@ -3461,19 +3520,26 @@ rfs4_get_state(stateid4 *stateid, rfs4_state_t **spp, } int -rfs4_check_stateid_seqid(rfs4_state_t *sp, stateid4 *stateid) +rfs4_check_stateid_seqid(rfs4_state_t *sp, stateid4 *stateid, + const compound_state_t *cs) { stateid_t *id = (stateid_t *)stateid; + bool_t has_session = rfs4_has_session(cs); if (rfs4_lease_expired(sp->rs_owner->ro_client)) return (NFS4_CHECK_STATEID_EXPIRED); + if (has_session && id->bits.chgseq == 0) + return (NFS4_CHECK_STATEID_OKAY); + /* Stateid is some time in the future - that's bad */ if (sp->rs_stateid.bits.chgseq < id->bits.chgseq) return (NFS4_CHECK_STATEID_BAD); - if (sp->rs_stateid.bits.chgseq == id->bits.chgseq + 1) + if (!has_session && + sp->rs_stateid.bits.chgseq == id->bits.chgseq + 1) { return (NFS4_CHECK_STATEID_REPLAY); + } /* Stateid is some time in the past - that's old */ if (sp->rs_stateid.bits.chgseq > id->bits.chgseq) @@ -3490,19 +3556,26 @@ rfs4_check_stateid_seqid(rfs4_state_t *sp, stateid4 *stateid) } int -rfs4_check_lo_stateid_seqid(rfs4_lo_state_t *lsp, stateid4 *stateid) +rfs4_check_lo_stateid_seqid(rfs4_lo_state_t *lsp, stateid4 *stateid, + const compound_state_t *cs) { stateid_t *id = (stateid_t *)stateid; + bool_t has_session = rfs4_has_session(cs); if (rfs4_lease_expired(lsp->rls_state->rs_owner->ro_client)) return (NFS4_CHECK_STATEID_EXPIRED); + if (has_session && id->bits.chgseq == 0) + return (NFS4_CHECK_STATEID_OKAY); + /* Stateid is some time in the future - that's bad */ if (lsp->rls_lockid.bits.chgseq < id->bits.chgseq) return (NFS4_CHECK_STATEID_BAD); - if (lsp->rls_lockid.bits.chgseq == id->bits.chgseq + 1) + if (!has_session && + lsp->rls_lockid.bits.chgseq == id->bits.chgseq + 1) { return (NFS4_CHECK_STATEID_REPLAY); + } /* Stateid is some time in the past - that's old */ if (lsp->rls_lockid.bits.chgseq > id->bits.chgseq) @@ -3663,6 +3736,24 @@ out: return (stat); } +static nfsstat4 +check_state_seqid(stateid_t *st, stateid_t *in, bool_t has_session) +{ + /* rfc56661, section 8.2.2, "seqid to zero" */ + if (has_session && in->bits.chgseq == 0) + return (NFS4_OK); + + /* Seqid in the future? - that's bad */ + if (st->bits.chgseq < in->bits.chgseq) + return (NFS4ERR_BAD_STATEID); + + /* Seqid in the past? - that's old */ + if (st->bits.chgseq > in->bits.chgseq) + return (NFS4ERR_OLD_STATEID); + + return (NFS4_OK); +} + /* * Given the I/O mode (FREAD or FWRITE), the vnode, the stateid and whether * the file is being truncated, return NFS4_OK if allowed or appropriate @@ -3681,7 +3772,7 @@ out: nfsstat4 rfs4_check_stateid(int mode, vnode_t *vp, stateid4 *stateid, bool_t trunc, bool_t *deleg, - bool_t do_access, caller_context_t *ct) + bool_t do_access, caller_context_t *ct, compound_state_t *cs) { rfs4_file_t *fp; bool_t create = FALSE; @@ -3690,6 +3781,7 @@ rfs4_check_stateid(int mode, vnode_t *vp, rfs4_lo_state_t *lsp; stateid_t *id = (stateid_t *)stateid; nfsstat4 stat = NFS4_OK; + bool_t use_ss = rfs4_has_session(cs); if (ct != NULL) { ct->cc_sysid = 0; @@ -3702,6 +3794,7 @@ rfs4_check_stateid(int mode, vnode_t *vp, fp = rfs4_findfile(vp, NULL, &create); if (fp == NULL) return (NFS4_OK); + if (fp->rf_dinfo.rd_dtype == OPEN_DELEGATE_NONE) { rfs4_file_rele(fp); return (NFS4_OK); @@ -3718,6 +3811,7 @@ rfs4_check_stateid(int mode, vnode_t *vp, stat = rfs4_get_all_state(stateid, &sp, &dsp, &lsp); if (stat != NFS4_OK) return (stat); + if (lsp != NULL) { /* Is associated server instance in its grace period? */ if (rfs4_clnt_in_grace(lsp->rls_locker->rl_client)) { @@ -3726,31 +3820,24 @@ rfs4_check_stateid(int mode, vnode_t *vp, rfs4_state_rele_nounlock(sp); return (NFS4ERR_GRACE); } - if (id->bits.type == LOCKID) { - /* Seqid in the future? - that's bad */ - if (lsp->rls_lockid.bits.chgseq < - id->bits.chgseq) { - rfs4_lo_state_rele(lsp, FALSE); - if (sp != NULL) - rfs4_state_rele_nounlock(sp); - return (NFS4ERR_BAD_STATEID); - } - /* Seqid in the past? - that's old */ - if (lsp->rls_lockid.bits.chgseq > - id->bits.chgseq) { - rfs4_lo_state_rele(lsp, FALSE); - if (sp != NULL) - rfs4_state_rele_nounlock(sp); - return (NFS4ERR_OLD_STATEID); - } - /* Ensure specified filehandle matches */ - if (lsp->rls_state->rs_finfo->rf_vp != vp) { - rfs4_lo_state_rele(lsp, FALSE); - if (sp != NULL) - rfs4_state_rele_nounlock(sp); - return (NFS4ERR_BAD_STATEID); - } + + ASSERT(id->bits.type == LOCKID); + stat = check_state_seqid(&lsp->rls_lockid, id, use_ss); + if (stat) { + rfs4_lo_state_rele(lsp, FALSE); + if (sp) + rfs4_state_rele_nounlock(sp); + return (stat); + } + + /* Ensure specified filehandle matches */ + if (lsp->rls_state->rs_finfo->rf_vp != vp) { + rfs4_lo_state_rele(lsp, FALSE); + if (sp != NULL) + rfs4_state_rele_nounlock(sp); + return (NFS4ERR_BAD_STATEID); } + if (ct != NULL) { ct->cc_sysid = lsp->rls_locker->rl_client->rc_sysidt; @@ -3766,18 +3853,13 @@ rfs4_check_stateid(int mode, vnode_t *vp, rfs4_state_rele_nounlock(sp); return (NFS4ERR_GRACE); } + /* Skip if is here via the LOCKID */ if (id->bits.type == OPENID) { - /* Seqid in the future? - that's bad */ - if (sp->rs_stateid.bits.chgseq < - id->bits.chgseq) { + stat = check_state_seqid(&sp->rs_stateid, id, + use_ss); + if (stat) { rfs4_state_rele_nounlock(sp); - return (NFS4ERR_BAD_STATEID); - } - /* Seqid in the past - that's old */ - if (sp->rs_stateid.bits.chgseq > - id->bits.chgseq) { - rfs4_state_rele_nounlock(sp); - return (NFS4ERR_OLD_STATEID); + return (stat); } } /* Ensure specified filehandle matches */ @@ -3842,9 +3924,11 @@ rfs4_check_stateid(int mode, vnode_t *vp, rfs4_deleg_state_rele(dsp); return (NFS4ERR_GRACE); } - if (dsp->rds_delegid.bits.chgseq != id->bits.chgseq) { + + stat = check_state_seqid(&dsp->rds_delegid, id, use_ss); + if (stat) { rfs4_deleg_state_rele(dsp); - return (NFS4ERR_BAD_STATEID); + return (stat); } /* Ensure specified filehandle matches */ diff --git a/usr/src/uts/common/fs/nfs/nfs4_xdr.c b/usr/src/uts/common/fs/nfs/nfs4_xdr.c index 36b19fe657..1879482a14 100644 --- a/usr/src/uts/common/fs/nfs/nfs4_xdr.c +++ b/usr/src/uts/common/fs/nfs/nfs4_xdr.c @@ -21,6 +21,7 @@ /* * Copyright 2016 Nexenta Systems, Inc. All rights reserved. + * Copyright 2020 RackTop Systems, Inc. */ /* @@ -65,6 +66,7 @@ bool_t xdr_bitmap4(XDR *xdrs, bitmap4 *objp) { int32_t len, size; + uint32_t bmval2 = 0; if (xdrs->x_op == XDR_FREE) return (TRUE); @@ -75,7 +77,15 @@ xdr_bitmap4(XDR *xdrs, bitmap4 *objp) * uint64_t and ignore all of the rest. */ if (xdrs->x_op == XDR_ENCODE) { - len = 2; + bitmap4 obj = *objp; + + objp = &obj; + if (*objp & FATTR4_SUPPATTR_EXCLCREAT_MASK_LOCAL) { + bmval2 |= 1ULL << (FATTR4_SUPPATTR_EXCLCREAT - 64); + *objp &= ~FATTR4_SUPPATTR_EXCLCREAT_MASK_LOCAL; + } + + len = bmval2 ? 3 : 2; if (!XDR_PUTINT32(xdrs, &len)) return (FALSE); @@ -83,15 +93,19 @@ xdr_bitmap4(XDR *xdrs, bitmap4 *objp) #if defined(_LITTLE_ENDIAN) if (XDR_PUTINT32(xdrs, (int32_t *)((char *)objp + BYTES_PER_XDR_UNIT)) == TRUE) { - return (XDR_PUTINT32(xdrs, (int32_t *)objp)); + if (!XDR_PUTINT32(xdrs, (int32_t *)objp)) + return (FALSE); } #elif defined(_BIG_ENDIAN) if (XDR_PUTINT32(xdrs, (int32_t *)objp) == TRUE) { - return (XDR_PUTINT32(xdrs, (int32_t *)((char *)objp + - BYTES_PER_XDR_UNIT))); + if (!XDR_PUTINT32(xdrs, (int32_t *)((char *)objp + + BYTES_PER_XDR_UNIT))) + return (FALSE); } #endif - return (FALSE); + if (len == 3 && !XDR_PUTINT32(xdrs, (int32_t *)&bmval2)) + return (FALSE); + return (TRUE); } if (!XDR_GETINT32(xdrs, &len)) @@ -100,19 +114,28 @@ xdr_bitmap4(XDR *xdrs, bitmap4 *objp) /* * Common fast DECODE cases */ - if (len == 2) { + if (len == 2 || len == 3) { #if defined(_LITTLE_ENDIAN) if (XDR_GETINT32(xdrs, (int32_t *)((char *)objp + BYTES_PER_XDR_UNIT)) == TRUE) { - return (XDR_GETINT32(xdrs, (int32_t *)objp)); + if (!XDR_GETINT32(xdrs, (int32_t *)objp)) + return (FALSE); } #elif defined(_BIG_ENDIAN) if (XDR_GETINT32(xdrs, (int32_t *)objp) == TRUE) { - return (XDR_GETINT32(xdrs, (int32_t *)((char *)objp + - BYTES_PER_XDR_UNIT))); + if (!XDR_GETINT32(xdrs, (int32_t *)((char *)objp + + BYTES_PER_XDR_UNIT))) + return (FALSE); } #endif - return (FALSE); + if (len == 3) { + if (!XDR_GETINT32(xdrs, (int32_t *)&bmval2)) + return (FALSE); + if (bmval2 & (1ULL << (FATTR4_SUPPATTR_EXCLCREAT - 64))) + *objp |= FATTR4_SUPPATTR_EXCLCREAT_MASK_LOCAL; + } + + return (TRUE); } *objp = 0; @@ -134,6 +157,12 @@ xdr_bitmap4(XDR *xdrs, bitmap4 *objp) return (FALSE); if (--len == 0) return (TRUE); + + if (!XDR_GETINT32(xdrs, (int32_t *)&bmval2)) + return (FALSE); + if (bmval2 & (1ULL << (FATTR4_SUPPATTR_EXCLCREAT - 64))) + *objp |= FATTR4_SUPPATTR_EXCLCREAT_MASK_LOCAL; + if (!XDR_GETINT32(xdrs, (int32_t *)((char *)objp + BYTES_PER_XDR_UNIT))) return (FALSE); #else @@ -661,7 +690,7 @@ xdr_fs_location4(XDR *xdrs, fs_location4 *objp) } /* Called by xdr_array */ -static bool_t +bool_t xdr_nfsace4(XDR *xdrs, nfsace4 *objp) { if (xdrs->x_op != XDR_FREE) { @@ -755,6 +784,33 @@ xdr_nfstime4(XDR *xdrs, nfstime4 *objp) return (xdr_u_int(xdrs, &objp->nseconds)); } +bool_t +xdr_fattr4_sec_label(XDR *xdrs, fattr4_sec_label *objp) +{ + uint_t dummy = 0; + + if (xdrs->x_op == XDR_FREE) { + /* + * Optimized free case + */ + if (objp->slai_val != NULL) + kmem_free(objp->slai_val, objp->slai_len); + return (TRUE); + } + + /* + * For now use a 0 here to indicate the null translation; in + * the future we place a call to translation code here. + */ + if (!xdr_u_int(xdrs, &dummy)) /* lfs */ + return (FALSE); + + if (!xdr_u_int(xdrs, &dummy)) /* pi */ + return (FALSE); + + return (xdr_bytes(xdrs, (char **)&objp->slai_val, + (uint_t *)&objp->slai_len, NFS4_OPAQUE_LIMIT)); +} /* * structured used for calls into xdr_ga_fattr_res() as a means @@ -2510,7 +2566,7 @@ xdr_settime4(XDR *xdrs, settime4 *objp) return (xdr_u_int(xdrs, &objp->time.nseconds)); } -static bool_t +bool_t xdr_fattr4(XDR *xdrs, fattr4 *objp) { if (xdrs->x_op != XDR_FREE) { @@ -2882,12 +2938,29 @@ xdr_LOCKU4args(XDR *xdrs, LOCKU4args *objp) } static bool_t +xdr_share_access(XDR *xdrs, uint32_t *share_access, uint32_t *deleg_want) +{ + uint32_t w; + + if (xdrs->x_op == XDR_DECODE) { + if (!xdr_u_int(xdrs, &w)) + return (FALSE); + + *share_access = w & OPEN4_SHARE_ACCESS_MASK; + *deleg_want = w & OPEN4_SHARE_WANT_MASK; + } + + return (TRUE); +} + +static bool_t xdr_OPEN4args(XDR *xdrs, OPEN4args *objp) { if (xdrs->x_op != XDR_FREE) { if (!xdr_u_int(xdrs, &objp->seqid)) return (FALSE); - if (!xdr_u_int(xdrs, &objp->share_access)) + if (!xdr_share_access(xdrs, &objp->share_access, + &objp->deleg_want)) return (FALSE); if (!xdr_u_int(xdrs, &objp->share_deny)) return (FALSE); @@ -2922,47 +2995,21 @@ xdr_OPEN4args(XDR *xdrs, OPEN4args *objp) createverf)) return (FALSE); break; + case EXCLUSIVE4_1: + if (!xdr_creatverfattr(xdrs, + &objp->createhow4_u.ch_createboth)) + return (FALSE); + break; default: return (FALSE); } } /* xdr_open_claim4 */ - if (!xdr_int(xdrs, (int *)&objp->claim)) - return (FALSE); - - switch (objp->claim) { - case CLAIM_NULL: - return (xdr_bytes(xdrs, (char **)&objp->open_claim4_u. - file.utf8string_val, - (uint_t *)&objp->open_claim4_u.file. - utf8string_len, - NFS4_MAX_UTF8STRING)); - case CLAIM_PREVIOUS: - return (xdr_int(xdrs, - (int *)&objp->open_claim4_u.delegate_type)); - case CLAIM_DELEGATE_CUR: - if (!xdr_u_int(xdrs, (uint_t *)&objp->open_claim4_u. - delegate_cur_info.delegate_stateid.seqid)) - return (FALSE); - if (!xdr_opaque(xdrs, objp->open_claim4_u. - delegate_cur_info.delegate_stateid.other, - NFS4_OTHER_SIZE)) - return (FALSE); - return (xdr_bytes(xdrs, (char **)&objp->open_claim4_u. - delegate_cur_info.file.utf8string_val, - (uint_t *)&objp->open_claim4_u. - delegate_cur_info.file.utf8string_len, - NFS4_MAX_UTF8STRING)); - case CLAIM_DELEGATE_PREV: - return (xdr_bytes(xdrs, (char **)&objp->open_claim4_u. - file_delegate_prev.utf8string_val, - (uint_t *)&objp->open_claim4_u. - file_delegate_prev.utf8string_len, - NFS4_MAX_UTF8STRING)); - default: + if (!xdr_open_claim4(xdrs, &objp->claim)) return (FALSE); - } + + return (TRUE); } /* @@ -2984,35 +3031,8 @@ xdr_OPEN4args(XDR *xdrs, OPEN4args *objp) } } - switch (objp->claim) { - case CLAIM_NULL: - if (objp->open_claim4_u.file.utf8string_val != NULL) - kmem_free(objp->open_claim4_u.file.utf8string_val, - objp->open_claim4_u.file.utf8string_len); - return (TRUE); - case CLAIM_PREVIOUS: - return (TRUE); - case CLAIM_DELEGATE_CUR: - if (objp->open_claim4_u.delegate_cur_info.file.utf8string_val != - NULL) { - kmem_free(objp->open_claim4_u.delegate_cur_info.file. - utf8string_val, - objp->open_claim4_u.delegate_cur_info.file. - utf8string_len); - } - return (TRUE); - case CLAIM_DELEGATE_PREV: - if (objp->open_claim4_u.file_delegate_prev.utf8string_val != - NULL) { - kmem_free(objp->open_claim4_u.file_delegate_prev. - utf8string_val, - objp->open_claim4_u.file_delegate_prev. - utf8string_len); - } - return (TRUE); - default: - return (TRUE); - } + (void) xdr_open_claim4(xdrs, &objp->claim); + return (TRUE); } static bool_t @@ -3284,7 +3304,7 @@ xdr_OPEN_DOWNGRADE4args(XDR *xdrs, OPEN_DOWNGRADE4args *objp) return (FALSE); if (!xdr_u_int(xdrs, &objp->seqid)) return (FALSE); - if (!xdr_u_int(xdrs, &objp->share_access)) + if (!xdr_share_access(xdrs, &objp->share_access, &objp->deleg_want)) return (FALSE); return (xdr_u_int(xdrs, &objp->share_deny)); } @@ -3792,6 +3812,18 @@ xdr_secinfo4(XDR *xdrs, secinfo4 *objp) return (TRUE); } +bool_t +xdr_SECINFO4res(XDR *xdrs, SECINFO4res *objp) +{ + if (!xdr_int(xdrs, (int32_t *)&objp->status)) + return (FALSE); + if (objp->status != NFS4_OK) + return (TRUE); + return (xdr_array(xdrs, (char **)&objp->SECINFO4resok_val, + (uint_t *)&objp->SECINFO4resok_len, ~0, sizeof (secinfo4), + (xdrproc_t)xdr_secinfo4)); +} + static bool_t xdr_SETCLIENTID4args(XDR *xdrs, SETCLIENTID4args *objp) { @@ -3948,6 +3980,13 @@ xdr_snfs_argop4_free(XDR *xdrs, nfs_argop4 **arrayp, int len) return (TRUE); for (i = 0; i < len; i++) { + /* Freeing for nfs4.x */ + if (array[i].argop >= OP_BACKCHANNEL_CTL && + array[i].argop != OP_ILLEGAL) { + xdr_nfs4x_argop4(xdrs, &array[i]); + continue; + } + /* * These should be ordered by frequency of use */ @@ -4309,6 +4348,10 @@ xdr_snfs_argop4(XDR *xdrs, nfs_argop4 *objp) return (xdr_decode_nfs_fh4(xdrs, &objp->nfs_argop4_u.opputfh.object)); default: + if (objp->argop >= OP_BACKCHANNEL_CTL && + objp->argop != OP_ILLEGAL) + return (xdr_nfs4x_argop4(xdrs, objp)); + return (xdr_nfs_argop4(xdrs, objp)); } } @@ -4775,6 +4818,10 @@ xdr_snfs_resop4(XDR *xdrs, nfs_resop4 *objp) return (xdr_encode_nfs_fh4(xdrs, &objp->nfs_resop4_u.opgetfh.object)); default: + if (objp->resop >= OP_BACKCHANNEL_CTL && + objp->resop != OP_ILLEGAL) + return (xdr_nfs4x_resop4(xdrs, objp)); + return (xdr_nfs_resop4(xdrs, objp)); } } @@ -5176,32 +5223,6 @@ xdr_cnfs_cb_argop4(XDR *xdrs, nfs_cb_argop4 *objp) return (FALSE); } -static bool_t -xdr_nfs_cb_resop4(XDR *xdrs, nfs_cb_resop4 *objp) -{ - if (!xdr_u_int(xdrs, &objp->resop)) - return (FALSE); - switch (objp->resop) { - case OP_CB_GETATTR: - if (!xdr_int(xdrs, - (int32_t *)&objp->nfs_cb_resop4_u.opcbgetattr. - status)) - return (FALSE); - if (objp->nfs_cb_resop4_u.opcbgetattr.status != NFS4_OK) - return (TRUE); - return (xdr_fattr4(xdrs, - &objp->nfs_cb_resop4_u.opcbgetattr. - obj_attributes)); - case OP_CB_RECALL: - return (xdr_int(xdrs, - (int32_t *)&objp->nfs_cb_resop4_u.opcbrecall.status)); - case OP_CB_ILLEGAL: - return (xdr_int(xdrs, - (int32_t *)&objp->nfs_cb_resop4_u.opcbillegal.status)); - } - return (FALSE); -} - /* * The NFS client side callback, RPC server */ diff --git a/usr/src/uts/common/fs/nfs/nfs4x_dispatch.c b/usr/src/uts/common/fs/nfs/nfs4x_dispatch.c new file mode 100644 index 0000000000..49ae2d6ad4 --- /dev/null +++ b/usr/src/uts/common/fs/nfs/nfs4x_dispatch.c @@ -0,0 +1,177 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2017 RackTop Systems. + */ + +#include <sys/systm.h> +#include <sys/sdt.h> +#include <rpc/types.h> +#include <rpc/auth.h> +#include <rpc/auth_unix.h> +#include <rpc/auth_des.h> +#include <rpc/svc.h> +#include <rpc/xdr.h> +#include <nfs/nfs4.h> +#include <nfs/nfs_dispatch.h> +#include <sys/cmn_err.h> +#include <sys/modctl.h> + +static void +rfs4_err_resp(COMPOUND4args *args, COMPOUND4res *resp, nfsstat4 err) +{ + size_t sz; + + resp->array_len = 1; + sz = resp->array_len * sizeof (nfs_resop4); + resp->array = kmem_zalloc(sz, KM_SLEEP); + + resp->array[0].resop = args->array[0].argop; + resp->status = resp->array[0].nfs_resop4_u.opillegal.status = err; +} + +/* + * The function checks if given compound operation is allowed + * to be the very fist operation in compound array. + */ +static bool_t +valid_first_compound_op(nfs_opnum4 op) +{ + if (op == OP_BIND_CONN_TO_SESSION || + op == OP_SEQUENCE || + op == OP_EXCHANGE_ID || + op == OP_CREATE_SESSION || + op == OP_DESTROY_SESSION || + op == OP_DESTROY_CLIENTID || + op == OP_ILLEGAL) + return (TRUE); + + return (FALSE); +} + +/* + * The function verifies arguments passed to mds_op_compound. + * If agrguments are valid, NFS4_OK is returned, otherwise + * function returns correspoinding NFS4 error code. + */ +static nfsstat4 +verify_compound_args(COMPOUND4args *args) +{ + if (args->array_len == 0) + return (NFS4_OK); + + if (!valid_first_compound_op(args->array[0].argop)) + return (NFS4ERR_OP_NOT_IN_SESSION); + + if (args->array_len > 1 && args->array[0].argop != OP_SEQUENCE) { + /* + * Compound is outside the session. There must be + * only one operation in request. + */ + return (NFS4ERR_NOT_ONLY_OP); + } + + return (NFS4_OK); +} + +static void +rfs4x_dispatch_done(compound_state_t *cs) +{ + if (cs->slot) + rfs4x_sequence_done(cs->cmpresp, cs); + else { + rfs4_compound_free(cs->cmpresp); + } + cs->cs_flags |= RFS4_DISPATCH_DONE; +} + +static bool_t +xdr_compound_wrapper(XDR *xdrs, compound_state_t *cs) +{ + COMPOUND4res *resp = cs->cmpresp; + bool_t res = FALSE; + bool_t isreal = (xdrs->x_handy != 0); /* real data encoding ? */ + + if (!(cs->cs_flags & RFS4_DISPATCH_DONE)) { + res = xdr_COMPOUND4res_srv(xdrs, resp); + if (isreal) + rfs4x_dispatch_done(cs); + } + + return (res); +} + +int +rfs4x_dispatch(struct svc_req *req, SVCXPRT *xprt, char *ap) +{ + struct compound_state cs; + COMPOUND4res res_buf; + COMPOUND4res *rbp; + COMPOUND4args *cap; + int rpcerr = 0; + nfsstat4 error; + + bzero(&res_buf, sizeof (COMPOUND4res)); + rbp = &res_buf; + cap = (COMPOUND4args *)ap; + rfs4_init_compound_state(&cs); + + cs.statusp = &error; + cs.cmpresp = rbp; + + error = verify_compound_args(cap); + if (error != NFS4_OK) { /* NFS4_OK is 0 */ + rfs4_err_resp(cap, rbp, error); + goto out_send; + } + + error = rfs4x_sequence_prep(cap, rbp, &cs); + if (error != NFS4_OK) { + if (error != nfserr_replay_cache) + rfs4_err_resp(cap, rbp, error); + goto out_send; + } + + /* Regular processing */ + curthread->t_flag |= T_DONTPEND; + rfs4_compound(cap, rbp, &cs, req, &rpcerr); + curthread->t_flag &= ~T_DONTPEND; + + /* + * On RPC error, short sendreply + */ + if (rpcerr) { + goto out_free; + } + + if (curthread->t_flag & T_WOULDBLOCK) { + curthread->t_flag &= ~T_WOULDBLOCK; + error = 1; + goto out_free; + } + +out_send: + if (!svc_sendreply(xprt, xdr_compound_wrapper, (char *)&cs)) { + DTRACE_PROBE2(sendfail, SVCXPRT *, xprt, + compound_state_t *, &cs); + svcerr_systemerr(xprt); + rpcerr = 1; + } + +out_free: + if (!(cs.cs_flags & RFS4_DISPATCH_DONE)) { + rfs4x_dispatch_done(&cs); + } + + rfs4_fini_compound_state(&cs); + return ((error != NFS4_OK || rpcerr) ? 1 : 0); +} diff --git a/usr/src/uts/common/fs/nfs/nfs4x_srv.c b/usr/src/uts/common/fs/nfs/nfs4x_srv.c new file mode 100644 index 0000000000..854a8e1abe --- /dev/null +++ b/usr/src/uts/common/fs/nfs/nfs4x_srv.c @@ -0,0 +1,1250 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 RackTop Systems. + */ + +#include <rpc/types.h> +#include <rpc/auth.h> +#include <rpc/rpcsec_gss.h> +#include <sys/sdt.h> +#include <sys/disp.h> +#include <nfs/nfs.h> +#include <nfs/nfs4.h> +#include <sys/systeminfo.h> + +/* Helpers */ + +/* Principal handling routines */ +/* returns 0 if no match; or 1 for a match */ +int +rfs4_cmp_cred_set(cred_set_t *p, struct compound_state *cs) +{ + int rc = 0; + rpc_gss_principal_t recp; /* cached clnt princ */ + rpc_gss_principal_t ibrp; /* inbound req princ */ + + + if (p->cp_cr == NULL) + return (rc); /* nothing to compare with */ + + if (p->cp_aflavor != cs->req->rq_cred.oa_flavor) + return (rc); + + if (p->cp_secmod != cs->nfsflavor) + return (rc); + + if (crcmp(p->cp_cr, cs->basecr)) + return (rc); + + switch (p->cp_aflavor) { + case AUTH_DES: + rc = (strcmp(p->cp_princ, cs->principal) == 0); + break; + + case RPCSEC_GSS: + recp = (rpc_gss_principal_t)p->cp_princ; + ibrp = (rpc_gss_principal_t)cs->principal; + + if (recp->len != ibrp->len) + break; + rc = (bcmp(recp->name, ibrp->name, ibrp->len) == 0); + break; + + case AUTH_SYS: + case AUTH_NONE: + default: + rc = 1; + break; + } + return (rc); +} + +static rpc_gss_principal_t +rfs4_dup_princ(rpc_gss_principal_t ppl) +{ + rpc_gss_principal_t pdup; + int len; + + if (ppl == NULL) + return (NULL); + + len = sizeof (int) + ppl->len; + pdup = (rpc_gss_principal_t)kmem_alloc(len, KM_SLEEP); + bcopy(ppl, pdup, len); + return (pdup); +} + +void +rfs4_set_cred_set(cred_set_t *p, struct compound_state *cs) +{ + ASSERT(p->cp_cr == NULL); + + p->cp_cr = crdup(cs->basecr); + p->cp_aflavor = cs->req->rq_cred.oa_flavor; + p->cp_secmod = cs->nfsflavor; /* secmod != flavor for RPCSEC_GSS */ + + /* + * Set principal as per security flavor + */ + switch (p->cp_aflavor) { + case AUTH_DES: + p->cp_princ = strdup(cs->principal); + break; + + case RPCSEC_GSS: + p->cp_princ = + (caddr_t)rfs4_dup_princ((rpc_gss_principal_t)cs->principal); + break; + + case AUTH_SYS: + case AUTH_NONE: + default: + break; + } +} + +void +rfs4_free_cred_set(cred_set_t *p) +{ + rpc_gss_principal_t ppl; + + if (p->cp_cr == NULL) + return; + + switch (p->cp_aflavor) { + case AUTH_DES: + kmem_free(p->cp_princ, strlen(p->cp_princ) + 1); + break; + + case RPCSEC_GSS: + ppl = (rpc_gss_principal_t)p->cp_princ; + kmem_free(ppl, ppl->len + sizeof (int)); + break; + } + + crfree(p->cp_cr); + p->cp_cr = NULL; +} + +/* principal end */ + +bool_t +nfs_clid4_cmp(nfs_client_id4 *s1, nfs_client_id4 *s2) +{ + if (s1->verifier != s2->verifier) + return (FALSE); + if (s1->id_len != s2->id_len) + return (FALSE); + if (bcmp(s1->id_val, s2->id_val, s2->id_len)) + return (FALSE); + return (TRUE); +} + +/* + * Rudimentary server implementation (XXX - for now) + */ +void +rfs4x_get_server_impl_id(EXCHANGE_ID4resok *resp) +{ + char *sol_impl = "illumos NFSv4.1 Server Implementation"; + char *sol_idom = "nfsv41.ietf.org"; + void *p; + uint_t len = 0; + nfs_impl_id4 *nip; + + resp->eir_server_impl_id.eir_server_impl_id_len = 1; + nip = kmem_zalloc(sizeof (nfs_impl_id4), KM_SLEEP); + resp->eir_server_impl_id.eir_server_impl_id_val = nip; + + /* Domain */ + nip->nii_domain.utf8string_len = len = strlen(sol_idom); + p = kmem_zalloc(len * sizeof (char), KM_SLEEP); + nip->nii_domain.utf8string_val = p; + bcopy(sol_idom, p, len); + + /* Implementation */ + nip->nii_name.utf8string_len = len = strlen(sol_impl); + p = kmem_zalloc(len * sizeof (char), KM_SLEEP); + nip->nii_name.utf8string_val = p; + bcopy(sol_impl, p, len); + + /* Time is zero for now */ +} + +/* + * Compute the "use bits", i.e. the flags specifying the permissible + * regular, MDS, and data server ops for the returned clientid. + * + * The minorversion1 specification allows a server implementor two + * alternatives: allow PNFS_MDS and PNFS_DS on the same clientid, or + * force the client to create separate clientids to distinguish + * MDS versus DS operations. + * + * Our design distinguishes operations based upon filehandle, and thus + * there is no reason to force the client to create separate clientids. + * Thus, we give the client as much as possible, while keeping the result + * within the allowed combinations as specified in the specification. + * + * Our constraints are: use a subset of the client's request, unless + * the client requested nothing, in which case we may return any + * legal combination; and, the combination of NON_PNFS and PNFS_MDS + * may not both be set in the results. These constraints are reflected + * in the ASSERT()s at the end. + */ + +static uint32_t +compute_use_pnfs_flags(uint32_t request) +{ + uint32_t rc; + + /* Start with the client's initial request */ + rc = request & EXCHGID4_FLAG_MASK_PNFS; + + /* If the client requested nothing, return the most permissive. */ + if (rc == 0) { + rc = EXCHGID4_FLAG_USE_NON_PNFS; + goto done; + } + + /* Don't permit the illegal combination of MDS and NON_PNFS */ + if ((rc & + (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS)) == + (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS)) + rc &= ~EXCHGID4_FLAG_USE_PNFS_MDS; +done: + ASSERT(((request & EXCHGID4_FLAG_MASK_PNFS) == 0) || + ((rc & ~(request & EXCHGID4_FLAG_MASK_PNFS)) == 0)); + ASSERT((rc & (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS)) + != (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS)); + ASSERT(rc != 0); + + return (rc); +} + +static void +rfs4x_set_trunkinfo(EXCHANGE_ID4resok *rok) +{ + const char *nodename = uts_nodename(); + unsigned int nd_len = strlen(nodename); + unsigned int hw_len = strlen(hw_serial); + unsigned id_len = nd_len + 1 + hw_len; + char *s = kmem_alloc(id_len, KM_SLEEP); + server_owner4 *so = &rok->eir_server_owner; + struct eir_server_scope *ss = &rok->eir_server_scope; + + (void) memcpy(s, nodename, nd_len); + s[nd_len] = ' '; + (void) memcpy(s + nd_len + 1, hw_serial, hw_len); + + so->so_major_id.so_major_id_len = id_len; + so->so_major_id.so_major_id_val = s; + + ss->eir_server_scope_len = id_len; + ss->eir_server_scope_val = kmem_alloc(id_len, KM_SLEEP); + (void) memcpy(ss->eir_server_scope_val, s, id_len); + + rok->eir_server_owner.so_minor_id = 0; +} + +static bool_t +client_has_state_locked(rfs4_client_t *cp) +{ + if (list_head(&cp->rc_sessions) != NULL || + list_head(&cp->rc_openownerlist) != NULL) + return (TRUE); + else + return (FALSE); +} + +/* OPERATIONS */ + +/* EXCHANGE_ID */ +void +rfs4x_op_exchange_id(nfs_argop4 *argop, nfs_resop4 *resop, + struct svc_req *req, compound_state_t *cs) +{ + EXCHANGE_ID4args *args = &argop->nfs_argop4_u.opexchange_id; + EXCHANGE_ID4res *resp = &resop->nfs_resop4_u.opexchange_id; + EXCHANGE_ID4resok *rok = &resp->EXCHANGE_ID4res_u.eir_resok4; + rfs4_client_t *cp, *conf; + bool_t update, create; + client_owner4 *cop; + nfs_client_id4 cid; /* cip */ + nfsstat4 status = NFS4_OK; + nfs4_srv_t *nsrv4; + + DTRACE_NFSV4_2(op__exchange__id__start, + struct compound_state *, cs, + EXCHANGE_ID4args *, args); + + /* + * EXCHANGE_ID's may be preceded by SEQUENCE + * + * Check that eia_flags only has "valid" spec bits + * and that no 'eir_flag' ONLY bits are specified. + */ + if (args->eia_flags & ~EXID4_FLAG_MASK) { + status = NFS4ERR_INVAL; + goto err; + } + + update = (args->eia_flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A); + cop = &args->eia_clientowner; + conf = NULL; + + cid.verifier = cop->co_verifier; + cid.id_len = cop->co_ownerid.co_ownerid_len; + cid.id_val = cop->co_ownerid.co_ownerid_val; + cid.cl_addr = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; + + /* + * Refer to Section 18.35.4 + */ +again: + create = TRUE; + cp = rfs4_findclient(&cid, &create, conf); + ASSERT(cp != NULL); + + if (conf) { + rfs4_dbe_lock(cp->rc_dbe); + if (cp->rc_cp_confirmed == NULL) + cp->rc_cp_confirmed = conf; + else + rfs4_client_rele(conf); + rfs4_dbe_unlock(cp->rc_dbe); + conf = NULL; + } + + if (create) { + /* Record just created */ + if (!update) { + /* case 1 - utok */ + rfs4_set_cred_set(&cp->rc_cr_set, cs); + + rok->eir_clientid = cp->rc_clientid; + rok->eir_sequenceid = cp->rc_contrived.xi_sid; + goto out; + } else { + /* no record and trying to update */ + status = NFS4ERR_NOENT; + goto err_out; + } + } + + /* Record exists */ + + /* expired clients should be ignored and released */ + if (rfs4_lease_expired(cp)) { + rfs4_client_close(cp); + update = FALSE; + goto again; + } + + if (cp->rc_need_confirm) { + /* UNCONFIRMED */ + if (!update) { + /* case 4 - utok */ + rfs4_client_close(cp); + + ASSERT(!update); + goto again; + } else { + /* case 7 - utok */ + status = NFS4ERR_NOENT; + goto err_out; + } + } + + /* record exists and confirmed */ + if (!update) { + if (!rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) { + /* case 3 */ + /* lease is checked above */ + rfs4_dbe_lock(cp->rc_dbe); + if (!client_has_state_locked(cp)) { + rfs4_dbe_unlock(cp->rc_dbe); + + rfs4_client_close(cp); + ASSERT(!update); + goto again; + } + rfs4_dbe_unlock(cp->rc_dbe); + + /* + * clid_in_use. old_client_ret has unexpired + * lease with state. + */ + status = NFS4ERR_CLID_INUSE; + goto err_out; + } else if (cp->rc_nfs_client.verifier != cid.verifier) { + /* case 5: Client Restart */ + /* + * Skip confirmed client record to allow confirmed + * and unconfirmed state at the same time. The number + * of states can collapse to one once the server + * receives an applicable CREATE_SESSION or EXCHANGE_ID. + */ + ASSERT(conf == NULL); + conf = cp; + ASSERT(!update); + goto again; + + } else if (nfs_clid4_cmp(&cp->rc_nfs_client, &cid)) { + /* case 2 - utok */ + rok->eir_clientid = cp->rc_clientid; + rok->eir_sequenceid = cp->rc_contrived.xi_sid; + /* trickle down to "out" */ + + } else { + /* something is really wacky in srv state */ + status = NFS4ERR_SERVERFAULT; + goto err_out; + } + + } else { /* UPDATE */ + if (cp->rc_nfs_client.verifier != cid.verifier) { + /* 18.35.4 case 8 */ + status = NFS4ERR_NOT_SAME; + goto err_out; + } + if (!rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) { + /* 18.35.4 case 9 */ + status = NFS4ERR_PERM; + goto err_out; + } + + /* case 6 - utok */ + rok->eir_clientid = cp->rc_clientid; + rok->eir_sequenceid = cp->rc_contrived.xi_sid; + /* trickle down to "out" */ + } +out: + rok->eir_flags = 0; + if (resp->eir_status == NFS4_OK && !cp->rc_need_confirm) + rok->eir_flags |= EXCHGID4_FLAG_CONFIRMED_R; + + /* + * State Protection Mojo + */ + cp->rc_state_prot.sp_type = args->eia_state_protect.spa_how; + switch (cp->rc_state_prot.sp_type) { + case SP4_NONE: + break; + + case SP4_MACH_CRED: + /* XXX - Some of Karen's secret sauce here... */ + break; + + case SP4_SSV: + /* XXX - ... and here */ +#define ssv_args eia_state_protect.state_protect4_a_u.spa_ssv_parms + if (args->ssv_args.ssp_ops.spo_must_allow & OP_EXCHANGE_ID) { + /* + * if the client ID was created specifying SP4_SSV + * state protection and EXCHANGE_ID as the one of + * the operations in spo_must_allow, then server MUST + * authorize EXCHANGE_IDs with the SSV principal in + * addition to the principal that created the client + * ID. + */ + /* EMPTY */; + } + break; + } + + /* + * Referrals supports + */ + if (args->eia_flags & EXCHGID4_FLAG_SUPP_MOVED_REFER) { + rok->eir_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; + } + + /* + * Migration/Replication not (yet) supported + */ + if (args->eia_flags & EXCHGID4_FLAG_SUPP_MOVED_MIGR) + rok->eir_flags &= ~EXCHGID4_FLAG_SUPP_MOVED_MIGR; + + /* + * TODO: Add the appropriate "use_pnfs" flags. + */ + rok->eir_flags |= compute_use_pnfs_flags(args->eia_flags); + + /* force no state protection for now */ + rok->eir_state_protect.spr_how = SP4_NONE; + + /* Implementation specific mojo */ + if (args->eia_client_impl_id.eia_client_impl_id_len != 0) { + /* EMPTY */; + } + + nsrv4 = nfs4_get_srv(); + + /* XXX - jw - best guess */ + rfs4_ss_clid(nsrv4, cp); + + /* Server's implementation */ + rfs4x_get_server_impl_id(rok); + + /* compute trunking capabilities */ + bzero(&rok->eir_server_scope, sizeof (rok->eir_server_scope)); + bzero(&rok->eir_server_owner, sizeof (server_owner4)); + + /* Add trunk handling */ + rfs4x_set_trunkinfo(rok); + + /* + * XXX - jw - best guess + * Check to see if client can perform reclaims + */ + rfs4_ss_chkclid(nsrv4, cp); + +err_out: + rfs4_client_rele(cp); +err: + *cs->statusp = resp->eir_status = status; + + DTRACE_NFSV4_2(op__exchange__id__done, + struct compound_state *, cs, + EXCHANGE_ID4res *, resp); +} + +void +rfs4x_exchange_id_free(nfs_resop4 *resop) +{ + EXCHANGE_ID4res *resp = &resop->nfs_resop4_u.opexchange_id; + EXCHANGE_ID4resok *rok = &resp->EXCHANGE_ID4res_u.eir_resok4; + struct server_owner4 *sop = &rok->eir_server_owner; + nfs_impl_id4 *nip; + int len = 0; + + /* Server Owner: major */ + if ((len = sop->so_major_id.so_major_id_len) != 0) + kmem_free(sop->so_major_id.so_major_id_val, len); + + if ((nip = rok->eir_server_impl_id.eir_server_impl_id_val) != NULL) { + /* Immplementation */ + len = nip->nii_name.utf8string_len; + kmem_free(nip->nii_name.utf8string_val, len * sizeof (char)); + + /* Domain */ + len = nip->nii_domain.utf8string_len; + kmem_free(nip->nii_domain.utf8string_val, len * sizeof (char)); + + /* Server Impl */ + kmem_free(nip, sizeof (nfs_impl_id4)); + } +} + +void +rfs4x_op_create_session(nfs_argop4 *argop, nfs_resop4 *resop, + struct svc_req *req, compound_state_t *cs) +{ + CREATE_SESSION4args *args = &argop->nfs_argop4_u.opcreate_session; + CREATE_SESSION4res *resp = &resop->nfs_resop4_u.opcreate_session; + CREATE_SESSION4resok *rok = &resp->CREATE_SESSION4res_u.csr_resok4; + CREATE_SESSION4resok *crp; + rfs4_client_t *cp; + rfs4_session_t *sp; + session41_create_t sca; + sequenceid4 stseq; + sequenceid4 agseq; + nfsstat4 status = NFS4_OK; + + DTRACE_NFSV4_2(op__create__session__start, + struct compound_state *, cs, + CREATE_SESSION4args*, args); + + /* + * A CREATE_SESSION request can be prefixed by OP_SEQUENCE. + * In this case, the newly created session has no relation + * to the sessid used for the OP_SEQUENCE. + */ + + /* + * Find the clientid + */ + cp = rfs4_findclient_by_id(args->csa_clientid, TRUE); + if (cp == NULL) { + status = NFS4ERR_STALE_CLIENTID; + goto out; + } + + /* + * Make sure the lease is still valid. + */ + if (rfs4_lease_expired(cp)) { + rfs4_client_close(cp); + status = NFS4ERR_STALE_CLIENTID; + goto out; + } + + /* + * Sequenceid processing (handling replay's, etc) + */ + agseq = args->csa_sequence; + stseq = cp->rc_contrived.xi_sid; + if (stseq == agseq + 1) { + /* + * If the previous sequenceid, then must be a replay of a + * previous CREATE_SESSION; return the cached result. + */ + crp = (CREATE_SESSION4resok *)&cp->rc_contrived.cs_res; + status = cp->rc_contrived.cs_status; + rok->csr_sequence = agseq; + bcopy(crp->csr_sessionid, rok->csr_sessionid, + sizeof (sessionid4)); + rok->csr_flags = crp->csr_flags; + rok->csr_fore_chan_attrs = crp->csr_fore_chan_attrs; + rok->csr_back_chan_attrs = crp->csr_back_chan_attrs; + + rfs4_update_lease(cp); + rfs4_client_rele(cp); + goto out; + } + + if (stseq != agseq) { + /* + * No way to differentiate MISORD_NEWREQ vs. MISORD_REPLAY, + * so anything else, we simply treat as SEQ_MISORDERED. + */ + status = NFS4ERR_SEQ_MISORDERED; + rfs4_client_rele(cp); + goto out; + } + + /* + * Clientid confirmation + */ + if (cp->rc_need_confirm) { + if (rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) { + cp->rc_need_confirm = FALSE; + if (cp->rc_cp_confirmed != NULL) { + rfs4_client_close(cp->rc_cp_confirmed); + cp->rc_cp_confirmed = NULL; + } + } else { + status = NFS4ERR_CLID_INUSE; + rfs4_client_rele(cp); + goto out; + } + } + + /* + * Session creation + */ + sca.cs_error = 0; + sca.cs_req = req; + sca.cs_client = cp; + sca.cs_aotw = *args; + sp = rfs4x_createsession(&sca); + + if (sca.cs_error) { + status = sca.cs_error; + rfs4_client_rele(cp); + if (sp != NULL) + rfs4x_session_rele(sp); + goto out; + } + + if (sp == NULL) { + status = NFS4ERR_SERVERFAULT; + rfs4_client_rele(cp); + goto out; + } + + /* + * Need to store the result in the rfs4_client_t's contrived + * result slot and then respond from there. This way, when the + * csa_sequence == contrived.cc_sid, we can return the latest + * cached result. (see replay: above) + */ + crp = (CREATE_SESSION4resok *)&cp->rc_contrived.cs_res; + cp->rc_contrived.cs_status = NFS4_OK; + rok->csr_sequence = crp->csr_sequence = cp->rc_contrived.xi_sid; + bcopy(sp->sn_sessid, rok->csr_sessionid, sizeof (sessionid4)); + bcopy(sp->sn_sessid, crp->csr_sessionid, sizeof (sessionid4)); + rok->csr_flags = crp->csr_flags = sp->sn_csflags; + + cp->rc_contrived.xi_sid++; + + /* + * XXX: struct assignment of channel4_attrs is broken because + * ca_rdma_ird is specified as a single element array. A struct + * assignment will copy the ca_rdma_ird array ptr to multiple args/ + * res structs, and the ptr will be free'd multiple times. + * Without RDMA, ca_rdma_ird is a zero element array so its ptr + * is NULL (which is why this doesn't cause problems right now). + * + * Struct assignment is convenient, and it would be best to enable + * it by creating an in-kernel channel4_attrs struct which didn't + * contain the single element array, but just contained the inbound + * receive queue depth. Let the XDR encode/decode funcs convert + * from the in-kernel form to the OTW form. + */ + rok->csr_fore_chan_attrs = + crp->csr_fore_chan_attrs = sp->sn_fore->cn_attrs; + rok->csr_back_chan_attrs = crp->csr_back_chan_attrs = + args->csa_back_chan_attrs; + + rfs4_update_lease(cp); + + /* + * References from the session to the client are + * accounted for while session is being created. + */ + rfs4_client_rele(cp); + rfs4x_session_rele(sp); +out: + *cs->statusp = resp->csr_status = status; + + DTRACE_NFSV4_2(op__create__session__done, + struct compound_state *, cs, + CREATE_SESSION4res *, resp); +} + +/* ARGSUSED */ +void +rfs4x_op_destroy_session(nfs_argop4 *argop, nfs_resop4 *resop, + struct svc_req *req, compound_state_t *cs) +{ + DESTROY_SESSION4args *args = &argop->nfs_argop4_u.opdestroy_session; + DESTROY_SESSION4res *resp = &resop->nfs_resop4_u.opdestroy_session; + rfs4_session_t *sp; + rfs4_client_t *cp; + nfsstat4 status = NFS4_OK; + int addref = 0; /* additional reference */ + + DTRACE_NFSV4_2(op__destroy__session__start, + struct compound_state *, cs, + DESTROY_SESSION4args *, args); + + /* section 18.37.3 rfc5661 */ + if (rfs4_has_session(cs)) { + /* compound with a sequence */ + if (bcmp(args->dsa_sessionid, cs->sp->sn_sessid, + sizeof (sessionid4)) == 0) { + /* + * Same session. + * must be the final operation in the COMPOUND request + */ + if ((cs->op_pos + 1) != cs->op_len) { + status = NFS4ERR_NOT_ONLY_OP; + goto out; + } + addref++; + } else { + /* Not the same session */ + /* + * TODO: need to verify that both sessions share + * the connection + */ + DTRACE_PROBE(nfss41__i__destroy_encap_session); + + } + } + + sp = rfs4x_findsession_by_id(args->dsa_sessionid); + if (sp == NULL) { + status = NFS4ERR_BADSESSION; + goto out; + } + /* + * verify cred that was used to create the session matches and is in + * concordance w/the state protection type used. + */ + cp = sp->sn_clnt; + switch (cp->rc_state_prot.sp_type) { + case SP4_MACH_CRED: + cmn_err(CE_NOTE, "op_destroy_session: SP4_MACH_CRED"); + if (!rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) { + status = NFS4ERR_PERM; + rfs4x_session_rele(sp); + goto out; + } + break; + + case SP4_SSV: + /* + * XXX - Need some of Karen's secret ssv sauce + * here. For now, just allow the destroy. + */ + cmn_err(CE_NOTE, "op_destroy_session: SP4_SSV"); + break; + + case SP4_NONE: + break; + + default: + break; + } + + status = rfs4x_destroysession(sp, 2 + addref); + rfs4x_session_rele(sp); +out: + *cs->statusp = resp->dsr_status = status; + + DTRACE_NFSV4_2(op__destroy__session__done, + struct compound_state *, cs, + DESTROY_SESSION4res *, resp); +} + +/* + * The thread will traverse the entire list pinging the connections + * that need it and refreshing any stale/dead connections. + */ +static void +ping_cb_null_thr(rfs4_session_t *sp) +{ + /* TODO: Need implementation */ + cmn_err(CE_NOTE, "nfs4x: ping_cb_null thread"); + rfs4x_session_rele(sp); + thread_exit(); +} + +/* + * Find session and validate sequence args. + * If this function successfully completes the compound state + * will contain a session pointer. + */ +static nfsstat4 +rfs4x_find_session(SEQUENCE4args *sargs, struct compound_state *cs) +{ + rfs4_session_t *sp; + slotid4 slot; + + ASSERT(sargs != NULL); + + if ((sp = rfs4x_findsession_by_id(sargs->sa_sessionid)) == NULL) + return (NFS4ERR_BADSESSION); + + slot = sargs->sa_slotid; + if (slot < 0 || slot >= sp->sn_fore->cn_attrs.ca_maxrequests) { + rfs4x_session_rele(sp); + return (NFS4ERR_BADSLOT); + } + cs->sp = sp; + cs->cachethis = sargs->sa_cachethis; + + return (NFS4_OK); +} + +/* called under held lock */ +static nfsstat4 +check_slot_seqid(rfs4_slot_t *slot, sequenceid4 seqid) +{ + nfsstat4 status = NFS4ERR_SEQ_MISORDERED; + + if (slot->se_flags & RFS4_SLOT_INUSE) { + /* + * There are three cases: + * 1. Duplicated requests for currently performing + * duplicated request. + * 2. New request for currently performing duplicated + * request. + * 3. Request with bad seqid for non finished performing + * request (due to a little window between 'prep' + * stage and actual renew se_seqid). + * In all cases tell a client to retry request later. + */ + if (slot->se_seqid == seqid || slot->se_seqid + 1 == seqid) { + status = NFS4ERR_DELAY; + } + } else { + if (seqid == slot->se_seqid + 1) + status = NFS4_OK; + else if (seqid == slot->se_seqid) + status = nfserr_replay_cache; + } + return (status); +} + +/* + * Prep stage for SEQUENCE operation. + * + * Main purpose to call this: + * - check on cached replay + * - Set cs.sp and cs.slot + */ +int +rfs4x_sequence_prep(COMPOUND4args *args, COMPOUND4res *resp, + compound_state_t *cs) +{ + SEQUENCE4args *sargs; + nfsstat4 status; + rfs4_slot_t *slot; + + if (args->array_len == 0 || args->array[0].argop != OP_SEQUENCE) + return (NFS4_OK); + + sargs = &args->array[0].nfs_argop4_u.opsequence; + + status = rfs4x_find_session(sargs, cs); + if (status != NFS4_OK) + return (status); + + /* have reference to session */ + slot = &cs->sp->sn_slots[sargs->sa_slotid]; + + mutex_enter(&slot->se_lock); + status = check_slot_seqid(slot, sargs->sa_sequenceid); + if (status == nfserr_replay_cache) { + if (slot->se_flags & RFS4_SLOT_CACHED) { + slot->se_flags |= RFS4_SLOT_INUSE; + cs->slot = slot; + *resp = slot->se_buf; + } else { + status = NFS4ERR_SEQ_MISORDERED; + } + } else if (status == NFS4_OK) { + slot->se_flags |= RFS4_SLOT_INUSE; + cs->slot = slot; + } + mutex_exit(&slot->se_lock); + + return (status); +} + +/* + * Do cleanup things + * 1. cache reply + * 2. release slot + */ +void +rfs4x_sequence_done(COMPOUND4res *resp, compound_state_t *cs) +{ + rfs4_slot_t *slot = cs->slot; + rfs4_session_t *sp = cs->sp; + int add = 0; + + ASSERT(slot != NULL); + ASSERT(sp != NULL); + + mutex_enter(&slot->se_lock); + slot->se_flags &= ~RFS4_SLOT_INUSE; + + if (*cs->statusp != nfserr_replay_cache) { + if (slot->se_flags & RFS4_SLOT_CACHED) { + rfs4_compound_free(&slot->se_buf); + slot->se_flags &= ~RFS4_SLOT_CACHED; + add = -1; + } + + if (*cs->statusp == NFS4_OK && cs->cachethis) { + slot->se_flags |= RFS4_SLOT_CACHED; + slot->se_buf = *resp; /* cache a reply */ + add += 1; + } else { + rfs4_compound_free(resp); + } + } + mutex_exit(&slot->se_lock); + + if (add != 0) + atomic_add_32(&sp->sn_rcached, add); +} + +/* + * Process the SEQUENCE operation. The session pointer has already been + * cached in the compound state, so we just dereference + */ +/*ARGSUSED*/ +void +rfs4x_op_sequence(nfs_argop4 *argop, nfs_resop4 *resop, + struct svc_req *req, compound_state_t *cs) +{ + SEQUENCE4args *args = &argop->nfs_argop4_u.opsequence; + SEQUENCE4res *resp = &resop->nfs_resop4_u.opsequence; + SEQUENCE4resok *rok = &resp->SEQUENCE4res_u.sr_resok4; + rfs4_session_t *sp = cs->sp; + rfs4_slot_t *slot = cs->slot; + nfsstat4 status = NFS4_OK; + uint32_t cbstat = 0x0; + + DTRACE_NFSV4_2(op__sequence__start, + struct compound_state *, cs, + SEQUENCE4args *, args); + + ASSERT(sp != NULL && slot != NULL); + + if (cs->op_pos != 0) { + status = NFS4ERR_SEQUENCE_POS; + goto out; + } + + if (rfs4_lease_expired(sp->sn_clnt)) { + status = NFS4ERR_BADSESSION; + goto out; + } + + /* + * If the back channel has been established... + * . if the channel has _not_ been marked as failed _AND_ + * there are connections that have pings outstanding, + * we go ahead and fire the thread to traverse all of + * the session's conns, issuing CB_NULL's to those that + * need a ping. + * . if the channel is _not_ OK (ie. failed), then notify + * client that there is currently a problem with the CB + * path. + */ + rfs4_dbe_lock(sp->sn_dbe); + if (SN_CB_CHAN_EST(sp)) { + if (SN_CB_CHAN_OK(sp)) { + if (sp->sn_bc.pngcnt > 0 && !sp->sn_bc.pnginprog) { + kthread_t *t; + + rfs4x_session_hold(sp); + t = thread_create(NULL, 0, ping_cb_null_thr, + sp, 0, &p0, TS_RUN, minclsyspri); + if (!t) + rfs4x_session_rele(sp); + } + } else { + cbstat |= SEQ4_STATUS_CB_PATH_DOWN; + } + } + cs->client = sp->sn_clnt; + + DTRACE_PROBE1(compound_clid, clientid4, cs->client->rc_clientid); + + ASSERT(args->sa_sequenceid == slot->se_seqid + 1); + + /* + * New request. + */ + mutex_enter(&slot->se_lock); + slot->se_seqid = args->sa_sequenceid; + mutex_exit(&slot->se_lock); + + /* + * Update access time and lease + */ + cs->slotno = args->sa_slotid; + sp->sn_laccess = nfs_sys_uptime(); + rfs4_update_lease(cs->client); + + /* + * Let's keep it simple for now + */ + bcopy(sp->sn_sessid, rok->sr_sessionid, sizeof (sessionid4)); + rok->sr_sequenceid = slot->se_seqid; + rok->sr_slotid = args->sa_slotid; + rok->sr_highest_slotid = + sp->sn_fore->cn_attrs.ca_maxrequests - 1; + rok->sr_target_highest_slotid = + sp->sn_fore->cn_attrs.ca_maxrequests - 1; + rok->sr_status_flags |= cbstat; + rfs4_dbe_unlock(sp->sn_dbe); +out: + *cs->statusp = resp->sr_status = status; + DTRACE_NFSV4_2(op__sequence__done, + struct compound_state *, cs, + SEQUENCE4res *, resp); +} + +/* ARGSUSED */ +void +rfs4x_op_reclaim_complete(nfs_argop4 *argop, nfs_resop4 *resop, + struct svc_req *req, compound_state_t *cs) +{ + RECLAIM_COMPLETE4args *args = &argop->nfs_argop4_u.opreclaim_complete; + RECLAIM_COMPLETE4res *resp = &resop->nfs_resop4_u.opreclaim_complete; + rfs4_client_t *cp; + nfsstat4 status = NFS4_OK; + + DTRACE_NFSV4_2(op__reclaim__complete__start, + struct compound_state *, cs, + RECLAIM_COMPLETE4args *, args); + + cp = cs->client; + rfs4_dbe_lock(cp->rc_dbe); + if (args->rca_one_fs) { + /* do what? we don't track this */ + goto out; + } + + if (cp->rc_reclaim_completed) { + status = NFS4ERR_COMPLETE_ALREADY; + goto out; + } + + if (cp->rc_can_reclaim) { + ASSERT(rfs4_servinst(cp)->nreclaim > 0); + atomic_add_32(&(rfs4_servinst(cp))->nreclaim, -1); + } + + cp->rc_reclaim_completed = 1; +out: + rfs4_dbe_unlock(cp->rc_dbe); + + *cs->statusp = resp->rcr_status = status; + DTRACE_NFSV4_2(op__reclaim__complete__done, + struct compound_state *, cs, + RECLAIM_COMPLETE4res *, resp); +} + +/* ARGSUSED */ +void +rfs4x_op_destroy_clientid(nfs_argop4 *argop, nfs_resop4 *resop, + struct svc_req *req, compound_state_t *cs) +{ + DESTROY_CLIENTID4args *args = &argop->nfs_argop4_u.opdestroy_clientid; + DESTROY_CLIENTID4res *resp = &resop->nfs_resop4_u.opdestroy_clientid; + rfs4_client_t *cp; + nfsstat4 status = NFS4_OK; + + DTRACE_NFSV4_2(op__destroy__clientid__start, + struct compound_state *, cs, + DESTROY_CLIENTID4args *, args); + + cp = rfs4_findclient_by_id(args->dca_clientid, TRUE); + if (cp == NULL) { + status = NFS4ERR_STALE_CLIENTID; + goto end; + } + + rfs4_dbe_lock(cp->rc_dbe); + if (client_has_state_locked(cp)) + status = NFS4ERR_CLIENTID_BUSY; + else + cp->rc_destroying = TRUE; + rfs4_dbe_unlock(cp->rc_dbe); + + if (status == NFS4_OK) + rfs4_client_close(cp); + else + rfs4_client_rele(cp); +end: + *cs->statusp = resp->dcr_status = status; + + DTRACE_NFSV4_2(op__destroy__clientid__done, + struct compound_state *, cs, + DESTROY_CLIENTID4res *, resp); +} + +/*ARGSUSED*/ +void +rfs4x_op_bind_conn_to_session(nfs_argop4 *argop, nfs_resop4 *resop, + struct svc_req *req, compound_state_t *cs) +{ + BIND_CONN_TO_SESSION4args *args = + &argop->nfs_argop4_u.opbind_conn_to_session; + BIND_CONN_TO_SESSION4res *resp = + &resop->nfs_resop4_u.opbind_conn_to_session; + BIND_CONN_TO_SESSION4resok *rok = + &resp->BIND_CONN_TO_SESSION4res_u.bctsr_resok4; + rfs4_session_t *sp; + nfsstat4 status = NFS4_OK; + + DTRACE_NFSV4_2(op__bind__conn__to__session__start, + struct compound_state *, cs, + BIND_CONN_TO_SESSION4args *, args); + + if (cs->op_pos != 0) { + status = NFS4ERR_NOT_ONLY_OP; + goto end; + } + + sp = rfs4x_findsession_by_id(args->bctsa_sessid); + if (sp == NULL) { + status = NFS4ERR_BADSESSION; + goto end; + } + + rfs4_update_lease(sp->sn_clnt); /* no need lock protection */ + + rfs4_dbe_lock(sp->sn_dbe); + sp->sn_laccess = nfs_sys_uptime(); + rfs4_dbe_unlock(sp->sn_dbe); + + rok->bctsr_use_conn_in_rdma_mode = FALSE; + + switch (args->bctsa_dir) { + case CDFC4_FORE: + case CDFC4_FORE_OR_BOTH: + /* always map to Fore */ + rok->bctsr_dir = CDFS4_FORE; + break; + + case CDFC4_BACK: + case CDFC4_BACK_OR_BOTH: + /* TODO: always map to Back */ + rok->bctsr_dir = CDFS4_FORE; + break; + default: + break; + } + + bcopy(sp->sn_sessid, rok->bctsr_sessid, sizeof (sessionid4)); + rfs4x_session_rele(sp); +end: + *cs->statusp = resp->bctsr_status = status; + + DTRACE_NFSV4_2(op__bind__conn__to__session__done, + struct compound_state *, cs, + BIND_CONN_TO_SESSION4res *, resp); +} + +/* ARGSUSED */ +void +rfs4x_op_secinfo_noname(nfs_argop4 *argop, nfs_resop4 *resop, + struct svc_req *req, compound_state_t *cs) +{ + SECINFO_NO_NAME4res *resp = &resop->nfs_resop4_u.opsecinfo_no_name; + nfsstat4 status; + bool_t dotdot; + + DTRACE_NFSV4_1(op__secinfo__no__name__start, + struct compound_state *, cs); + + if (cs->vp == NULL) { + status = NFS4ERR_NOFILEHANDLE; + goto out; + } + + if (cs->vp->v_type != VDIR) { + status = NFS4ERR_NOTDIR; + goto out; + } + + dotdot = + (argop->nfs_argop4_u.opsecinfo_no_name == SECINFO_STYLE4_PARENT); + + status = do_rfs4_op_secinfo(cs, dotdot ? ".." : ".", resp); + + /* Cleanup FH as described at 18.45.3 and 2.6.3.1.1.8 */ + if (status == NFS4_OK) { + VN_RELE(cs->vp); + cs->vp = NULL; + } +out: + *cs->statusp = resp->status = status; + + DTRACE_NFSV4_2(op__secinfo__no__name__done, + struct compound_state *, cs, + SECINFO_NO_NAME4res *, resp); +} diff --git a/usr/src/uts/common/fs/nfs/nfs4x_state.c b/usr/src/uts/common/fs/nfs/nfs4x_state.c new file mode 100644 index 0000000000..aba02734fc --- /dev/null +++ b/usr/src/uts/common/fs/nfs/nfs4x_state.c @@ -0,0 +1,576 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 RackTop Systems. + */ + +#include <sys/sdt.h> +#include <sys/atomic.h> +#include <nfs/nfs4.h> + +#ifdef DEBUG +#define RFS4_TABSIZE 17 +#else +#define RFS4_TABSIZE 2047 +#endif + +#define RFS4_MAXTABSZ 1024*1024 + +slotid4 rfs4_max_slots = MAXSLOTS; /* fore channel */ +slotid4 rfs4_back_max_slots = MAXSLOTS_BACK; /* back channel */ + +typedef union { + /* Both members have the same size */ + struct { + uint32_t pad0; + uint32_t pad1; + uint32_t start_time; /* NFS server start time */ + uint32_t s_id; /* unique session index */ + } impl_id; + sessionid4 id4; +} rfs4_sid; + +/* + * -------------------------------------------------------- + * MDS - NFSv4.1 Sessions + * -------------------------------------------------------- + */ +static uint32_t +sessid_hash(void *key) +{ + rfs4_sid *idp = key; + + return (idp->impl_id.s_id); +} + +static bool_t +sessid_compare(rfs4_entry_t entry, void *key) +{ + rfs4_session_t *sp = (rfs4_session_t *)entry; + sessionid4 *idp = (sessionid4 *)key; + + return (bcmp(idp, &sp->sn_sessid, sizeof (sessionid4)) == 0); +} + +static void * +sessid_mkkey(rfs4_entry_t entry) +{ + rfs4_session_t *sp = (rfs4_session_t *)entry; + + return (&sp->sn_sessid); +} + +/* ARGSUSED */ +static bool_t +cmp_false(rfs4_entry_t entry, void *key) +{ + return (FALSE); +} + +/* ARGSUSED */ +static void * +mkkey_null(rfs4_entry_t entry) +{ + return (NULL); +} + +void +rfs4x_session_rele(rfs4_session_t *sp) +{ + rfs4_dbe_rele(sp->sn_dbe); +} + +void +rfs4x_session_hold(rfs4_session_t *sp) +{ + rfs4_dbe_hold(sp->sn_dbe); +} + +rfs4_session_t * +rfs4x_findsession_by_id(sessionid4 sessid) +{ + rfs4_session_t *sp; + bool_t create = FALSE; + nfs4_srv_t *nsrv4 = nfs4_get_srv(); + + rw_enter(&nsrv4->findsession_lock, RW_READER); + sp = (rfs4_session_t *)rfs4_dbsearch(nsrv4->rfs4_session_idx, + sessid, &create, NULL, RFS4_DBS_VALID); + rw_exit(&nsrv4->findsession_lock); + + return (sp); +} + +/* + * A clientid can have multiple sessions associated with it. Hence, + * performing a raw 'mds_findsession' (even for a create) might + * yield a list of sessions associated with the clientid in question. + * Call rfs4_dbseach() function with key that cannot be found + * and create an association between the session table and both + * primary (sessionid) index and secondary (clientid) index for the + * newly created session. + */ + +rfs4_session_t * +rfs4x_createsession(session41_create_t *ap) +{ + static volatile uint32_t session_id_counter; + + rfs4_session_t *sp = NULL; + bool_t create = TRUE; + rfs4_sid key = {0, 0, 0, 0}; + nfs4_srv_t *nsrv4 = nfs4_get_srv(); + + /* + * Use unique counter for s_id and s_id to ensure that + * created entry will have the same index in dbi_buckets[] + */ + ap->cs_id = key.impl_id.s_id = atomic_inc_32_nv(&session_id_counter); + + rw_enter(&nsrv4->findsession_lock, RW_WRITER); + if ((sp = (rfs4_session_t *)rfs4_dbsearch(nsrv4->rfs4_session_idx, + &key, &create, (void *)ap, RFS4_DBS_VALID)) == NULL) { + DTRACE_PROBE1(mds__srv__createsession__fail, + session41_create_t *, ap); + } + rw_exit(&nsrv4->findsession_lock); + return (sp); +} + +/* return success of operation */ +static bool_t +client_insert_session(rfs4_client_t *cp, rfs4_session_t *sp) +{ + bool_t res = TRUE; + + rfs4_dbe_lock(cp->rc_dbe); + if (cp->rc_destroying) + res = FALSE; + else + list_insert_tail(&cp->rc_sessions, sp); + rfs4_dbe_unlock(cp->rc_dbe); + + return (res); +} + +static void +client_remove_session(rfs4_client_t *cp, rfs4_session_t *sp) +{ + rfs4_dbe_lock(cp->rc_dbe); + if (list_link_active(&sp->sn_node)) + list_remove(&cp->rc_sessions, sp); + rfs4_dbe_unlock(cp->rc_dbe); +} + +/* + * Invalidate the session in the DB (so it can't be found anymore) + */ +nfsstat4 +rfs4x_destroysession(rfs4_session_t *sp, unsigned useref) +{ + nfsstat4 status = NFS4_OK; + + /* + * RFC 7862 Section 14.1.3: + * In hindsight, the NFSv4.1 specification should have + * mandated that DESTROY_SESSION either abort or complete + * all outstanding operations. + */ + rfs4_dbe_lock(sp->sn_dbe); + if (rfs4_dbe_refcnt(sp->sn_dbe) > useref) + status = NFS4ERR_DELAY; + else + rfs4_dbe_invalidate(sp->sn_dbe); + rfs4_dbe_unlock(sp->sn_dbe); + + if (status == NFS4_OK) + client_remove_session(sp->sn_clnt, sp); + + return (status); +} + +/* Invalidate all client's sessions */ +void +rfs4x_client_session_remove(rfs4_client_t *cp) +{ + rfs4_session_t *sp; + + /* + * Client is forcibly closing so invalidate all sessions + * without checking the refcount. + */ + rfs4_dbe_lock(cp->rc_dbe); + while ((sp = list_head(&cp->rc_sessions)) != NULL) { + list_remove(&cp->rc_sessions, sp); + + rfs4_dbe_lock(sp->sn_dbe); + rfs4_dbe_invalidate(sp->sn_dbe); + rfs4_dbe_unlock(sp->sn_dbe); + + } + rfs4_dbe_unlock(cp->rc_dbe); +} + +nfsstat4 +sess_chan_limits(sess_channel_t *scp) +{ + if (scp->cn_attrs.ca_maxrequests > rfs4_max_slots) { + scp->cn_attrs.ca_maxrequests = rfs4_max_slots; + } + + if (scp->cn_back_attrs.ca_maxrequests > rfs4_back_max_slots) + scp->cn_back_attrs.ca_maxrequests = rfs4_back_max_slots; + + + if (scp->cn_attrs.ca_maxoperations > NFS4_COMPOUND_LIMIT) + scp->cn_attrs.ca_maxoperations = NFS4_COMPOUND_LIMIT; + + /* + * Lower limit should be set to smallest sane COMPOUND. Even + * though a singleton SEQUENCE op is the very smallest COMPOUND, + * it's also quite boring. For all practical purposes, the lower + * limit for creating a sess is limited to: + * + * [SEQUENCE + PUTROOTFH + GETFH] + * + * XXX - can't limit READ's to a specific threshold, otherwise + * we artificially limit the clients to perform reads of + * AT LEAST that granularity, which is WRONG !!! Same goes + * for READDIR's and GETATTR's. + */ + if (scp->cn_attrs.ca_maxresponsesize < (sizeof (SEQUENCE4res) + + sizeof (PUTROOTFH4res) + sizeof (GETFH4res))) + return (NFS4ERR_TOOSMALL); + return (NFS4_OK); +} + +/* + * NFSv4.1 Slot replay cache + */ +static void +rfs41_cleanup_slot(rfs4_slot_t *se) +{ + rfs4_compound_free((COMPOUND4res *)&se->se_buf); +} + +static rfs4_slot_t * +slots_alloc(size_t n) +{ + rfs4_slot_t *p; + int i; + + p = kmem_zalloc(sizeof (rfs4_slot_t) * n, KM_SLEEP); + for (i = 0; i < n; i++) { + mutex_init(&p[i].se_lock, NULL, MUTEX_DEFAULT, NULL); + } + + return (p); +} + +static void +slots_free(rfs4_slot_t *slots, size_t n) +{ + int i; + + for (i = 0; i < n; i++) { + rfs4_slot_t *slot = &slots[i]; + + mutex_destroy(&slot->se_lock); + + if (slot->se_flags & RFS4_SLOT_CACHED) { + rfs41_cleanup_slot(slot); + } + } + kmem_free(slots, sizeof (rfs4_slot_t) * n); +} + +/* Additional functions */ + +/* check csa_flags for OP_CREATE_SESSION */ +bool_t +nfs4x_csa_flags_valid(uint32_t flags) +{ + if (flags & ~CREATE_SESSION4_FLAG_MASK) + return (FALSE); + + return (TRUE); +} + +sess_channel_t * +rfs41_create_session_channel(channel_dir_from_server4 dir) +{ + sess_channel_t *cp; + sess_bcsd_t *bp; + + cp = (sess_channel_t *)kmem_zalloc(sizeof (sess_channel_t), KM_SLEEP); + rw_init(&cp->cn_lock, NULL, RW_DEFAULT, NULL); + + switch (dir) { + case CDFS4_FORE: + break; + + case CDFS4_BOTH: + case CDFS4_BACK: + /* BackChan Specific Data */ + bp = (sess_bcsd_t *)kmem_zalloc(sizeof (sess_bcsd_t), KM_SLEEP); + rw_init(&bp->bsd_rwlock, NULL, RW_DEFAULT, NULL); + cp->cn_csd = (sess_bcsd_t *)bp; + break; + } + return (cp); +} + +void +rfs41_destroy_session_channel(rfs4_session_t *sp) +{ + sess_channel_t *cp; + sess_bcsd_t *bp; + + if (sp->sn_back != NULL) { + /* only one channel for both direction for now */ + ASSERT(sp->sn_fore == sp->sn_back); + + cp = sp->sn_back; + bp = (sess_bcsd_t *)cp->cn_csd; + rw_destroy(&bp->bsd_rwlock); + kmem_free(bp, sizeof (sess_bcsd_t)); + } else { + cp = sp->sn_fore; + } + + rw_destroy(&cp->cn_lock); + kmem_free(cp, sizeof (sess_channel_t)); + + sp->sn_back = NULL; + sp->sn_fore = NULL; +} + +static bool_t +rfs4_session_create(rfs4_entry_t u_entry, void *arg) +{ + rfs4_session_t *sp = (rfs4_session_t *)u_entry; + session41_create_t *ap = (session41_create_t *)arg; + sess_channel_t *ocp = NULL; + rfs4_sid *sidp; + bool_t bdrpc = FALSE; + channel_dir_from_server4 dir; + nfsstat4 sle; + nfs4_srv_t *nsrv4 = nfs4_get_srv(); + + ASSERT(sp != NULL); + if (sp == NULL) + return (FALSE); + + /* + * Back pointer/ref to parent data struct (rfs4_client_t) + */ + sp->sn_clnt = (rfs4_client_t *)ap->cs_client; + rfs4_dbe_hold(sp->sn_clnt->rc_dbe); + + /* + * Handcrafting the session id + */ + sidp = (rfs4_sid *)&sp->sn_sessid; + sidp->impl_id.pad0 = 0x00000000; + sidp->impl_id.pad1 = 0xFFFFFFFF; + sidp->impl_id.start_time = nsrv4->rfs4_start_time; + sidp->impl_id.s_id = ap->cs_id; + + /* + * Process csa_flags; note that CREATE_SESSION4_FLAG_CONN_BACK_CHAN + * is processed below since it affects direction and setup of the + * backchannel accordingly. + */ + if (!nfs4x_csa_flags_valid(ap->cs_aotw.csa_flags)) { + ap->cs_error = NFS4ERR_INVAL; + goto err; + } + + sp->sn_csflags = 0; + if (ap->cs_aotw.csa_flags & CREATE_SESSION4_FLAG_PERSIST) + /* XXX - Worry about persistence later */ + sp->sn_csflags &= ~CREATE_SESSION4_FLAG_PERSIST; + + if (ap->cs_aotw.csa_flags & CREATE_SESSION4_FLAG_CONN_RDMA) + /* XXX - No RDMA for now */ + sp->sn_csflags &= ~CREATE_SESSION4_FLAG_CONN_RDMA; + + /* + * Initialize some overall sessions values + */ + sp->sn_bc.progno = ap->cs_aotw.csa_cb_program; + sp->sn_laccess = nfs_sys_uptime(); + sp->sn_flags = 0; + sp->sn_rcached = 0; + + /* + * Check if client has specified that the FORE channel should + * also be used for call back traffic (ie. bidir RPC). If so, + * let's try to accomodate the request. + */ + DTRACE_PROBE1(csa__flags, uint32_t, ap->cs_aotw.csa_flags); + + /* + * Session's channel flags depending on bdrpc + * TODO: Add backchannel handling, i.e. when bdrpc is TRUE + */ + dir = bdrpc ? (CDFS4_FORE | CDFS4_BACK) : CDFS4_FORE; + ocp = rfs41_create_session_channel(dir); + ocp->cn_dir = dir; + sp->sn_fore = ocp; + + /* + * Check if channel attrs will be flexible enough for future + * purposes. Channel attribute enforcement is done as part of + * COMPOUND processing. + */ + ocp->cn_attrs = ap->cs_aotw.csa_fore_chan_attrs; + ocp->cn_back_attrs = ap->cs_aotw.csa_back_chan_attrs; + if (sle = sess_chan_limits(ocp)) { + ap->cs_error = sle; + goto err_free_chan; + } + + /* will fail if client is going to destroy */ + if (!client_insert_session(sp->sn_clnt, sp)) { + ap->cs_error = NFS4ERR_DELAY; + goto err_free_chan; + } + + /* + * No need for locks/synchronization at this time, + * since we're barely creating the session. + */ + if (bdrpc) { + /* Need to be implemented */ + VERIFY(0); + } else { + /* + * If not doing bdrpc, then we expect the client to perform + * an explicit BIND_CONN_TO_SESSION if it wants callback + * traffic. Subsequently, the cb channel should be set up + * at that point along with its corresponding slot (see + * rfs41_bc_setup). + */ + sp->sn_csflags &= ~CREATE_SESSION4_FLAG_CONN_BACK_CHAN; + sp->sn_back = NULL; + + /* + * XXX 08/15/2008 (rick) - if the channel is not bidir when + * created in CREATE_SESSION, then we should save off + * the ap->cs_aotw.csa_back_chan_attrs in case later + * a bc2s is called to create the back channel. + */ + } + + /* + * Now we allocate space for the slrc, initializing each slot's + * sequenceid and slotid to zero and a (pre)cached result of + * NFS4ERR_SEQ_MISORDERED. Note that we zero out the entries + * by virtue of the z-alloc. + */ + sp->sn_slots = slots_alloc(ocp->cn_attrs.ca_maxrequests); + + return (TRUE); + +err_free_chan: + rfs41_destroy_session_channel(sp); +err: + rfs4_dbe_rele(sp->sn_clnt->rc_dbe); + return (FALSE); +} + +static void +rfs4_session_destroy(rfs4_entry_t u_entry) +{ + rfs4_session_t *sp = (rfs4_session_t *)u_entry; + sess_bcsd_t *bsdp; + + if (SN_CB_CHAN_EST(sp) && (bsdp = sp->sn_back->cn_csd) != NULL) { + slots_free(bsdp->bsd_slots, + sp->sn_back->cn_back_attrs.ca_maxrequests); + bsdp->bsd_slots = NULL; + } + + /* + * Nuke slot replay cache for this session + */ + if (sp->sn_slots) { + slots_free(sp->sn_slots, sp->sn_fore->cn_attrs.ca_maxrequests); + sp->sn_slots = NULL; + } + + /* + * XXX - A session can have multiple BC clnt handles that need + * to be discarded. rfs4_session_inval calls CLNT_DESTROY + * which will remove the CB client handle from the global + * list (cb_clnt_list) now. This will have to change once + * we manage the BC clnt handles per session. + */ + + /* + * Remove the fore and back channels. + */ + rfs41_destroy_session_channel(sp); + + client_remove_session(sp->sn_clnt, sp); + + rfs4_client_rele(sp->sn_clnt); +} + +static bool_t +rfs4_session_expiry(rfs4_entry_t u_entry) +{ + rfs4_session_t *sp = (rfs4_session_t *)u_entry; + + if (sp == NULL || rfs4_dbe_is_invalid(sp->sn_dbe)) + return (TRUE); + + if (rfs4_lease_expired(sp->sn_clnt)) + return (TRUE); + + return (FALSE); +} + +void +rfs4x_state_init_locked(nfs4_srv_t *nsrv4) +{ + rw_init(&nsrv4->findsession_lock, NULL, RW_DEFAULT, NULL); + + nsrv4->rfs4_session_tab = rfs4_table_create(nsrv4->nfs4_server_state, + "Session", 5 * rfs4_lease_time, 1, rfs4_session_create, + rfs4_session_destroy, rfs4_session_expiry, sizeof (rfs4_session_t), + RFS4_TABSIZE, RFS4_MAXTABSZ/8, 100); + + nsrv4->rfs4_session_idx = rfs4_index_create(nsrv4->rfs4_session_tab, + "session_idx", sessid_hash, sessid_compare, sessid_mkkey, TRUE); +} + +void +rfs4x_state_fini(nfs4_srv_t *nsrv4) +{ + /* All tables will be destroyed by caller */ + rw_destroy(&nsrv4->findsession_lock); +} diff --git a/usr/src/uts/common/fs/nfs/nfs4x_xdr.c b/usr/src/uts/common/fs/nfs/nfs4x_xdr.c new file mode 100644 index 0000000000..7b4bce31f8 --- /dev/null +++ b/usr/src/uts/common/fs/nfs/nfs4x_xdr.c @@ -0,0 +1,2935 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * Copyright 2017 RackTop Systems. + */ + +/* + * This file contains the xdr for datatypes and operations that are + * specific to NFSv4 minor version 1 (i.e., datatypes that + * were either introduced or changed by the NFSv4.1 specification). + */ + +/* + * INSTRUCTIONS for updating to a new NFSv4.1: + * + * **DO NOT** simply replace this file with code rpcgen creates + * and then remove non-NFS41 code. The file now contains the hand + * coded xdr for the NFS4.1 attributes. If you run rpcgen, + * manually integrate parts related to the draft diffs. + */ +#include <sys/statvfs.h> +#include <sys/sysmacros.h> +#include <sys/sdt.h> +#include <nfs/nfs4.h> +#include <nfs/nfs4_attr.h> + +#ifndef _KERNEL +#include <stdlib.h> +#endif /* !_KERNEL */ + +/* modified version */ +bool_t +xdr_verifier4(XDR *xdrs, verifier4 *objp) +{ + if (!xdr_u_longlong_t(xdrs, (u_longlong_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_sequenceid4(XDR *xdrs, sequenceid4 *objp) +{ + if (!xdr_uint32_t(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_sessionid4(XDR *xdrs, sessionid4 objp) +{ + if (!xdr_opaque(xdrs, objp, NFS4_SESSIONID_SIZE)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_slotid4(XDR *xdrs, slotid4 *objp) +{ + + if (!xdr_uint32_t(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_change_policy4(XDR *xdrs, change_policy4 *objp) +{ + if (!xdr_uint64_t(xdrs, &objp->cp_major)) + return (FALSE); + if (!xdr_uint64_t(xdrs, &objp->cp_minor)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_aclflag4(XDR *xdrs, aclflag4 *objp) +{ + if (!xdr_uint32_t(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_nfsacl41(XDR *xdrs, nfsacl41 *objp) +{ + if (!xdr_aclflag4(xdrs, &objp->na41_flag)) + return (FALSE); + if (!xdr_array(xdrs, (char **)&objp->na41_aces.na41_aces_val, + (uint_t *)&objp->na41_aces.na41_aces_len, ~0, sizeof (nfsace4), + (xdrproc_t)xdr_nfsace4)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_mode_masked4(XDR *xdrs, mode_masked4 *objp) +{ + if (!xdr_mode4(xdrs, &objp->mm_value_to_set)) + return (FALSE); + if (!xdr_mode4(xdrs, &objp->mm_mask_bits)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_nfs_impl_id4(XDR *xdrs, nfs_impl_id4 *objp) +{ + if (!xdr_utf8str_cis(xdrs, &objp->nii_domain)) + return (FALSE); + if (!xdr_utf8str_cs(xdrs, &objp->nii_name)) + return (FALSE); + if (!xdr_nfstime4(xdrs, &objp->nii_date)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_layouttype4(XDR *xdrs, layouttype4 *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_layout_content4(XDR *xdrs, layout_content4 *objp) +{ + if (!xdr_layouttype4(xdrs, &objp->loc_type)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->loc_body.loc_body_val, + (uint_t *)&objp->loc_body.loc_body_len, ~0)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_layoutiomode4(XDR *xdrs, layoutiomode4 *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + + +bool_t +xdr_layout4(XDR *xdrs, layout4 *objp) +{ + if (!xdr_offset4(xdrs, &objp->lo_offset)) + return (FALSE); + if (!xdr_length4(xdrs, &objp->lo_length)) + return (FALSE); + if (!xdr_layoutiomode4(xdrs, &objp->lo_iomode)) + return (FALSE); + if (!xdr_layout_content4(xdrs, &objp->lo_content)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_deviceid4(XDR *xdrs, deviceid4 objp) +{ + if (!xdr_opaque(xdrs, objp, NFS4_DEVICEID4_SIZE)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_device_addr4(XDR *xdrs, device_addr4 *objp) +{ + if (!xdr_layouttype4(xdrs, &objp->da_layout_type)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->da_addr_body.da_addr_body_val, + (uint_t *)&objp->da_addr_body.da_addr_body_len, ~0)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_layoutupdate4(XDR *xdrs, layoutupdate4 *objp) +{ + if (!xdr_layouttype4(xdrs, &objp->lou_type)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->lou_body.lou_body_val, + (uint_t *)&objp->lou_body.lou_body_len, ~0)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_layoutreturn_type4(XDR *xdrs, layoutreturn_type4 *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} +/* layouttype4 specific data */ + +bool_t +xdr_layoutreturn_file4(XDR *xdrs, layoutreturn_file4 *objp) +{ + if (!xdr_offset4(xdrs, &objp->lrf_offset)) + return (FALSE); + if (!xdr_length4(xdrs, &objp->lrf_length)) + return (FALSE); + if (!xdr_stateid4(xdrs, &objp->lrf_stateid)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->lrf_body.lrf_body_val, + (uint_t *)&objp->lrf_body.lrf_body_len, ~0)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_layoutreturn4(XDR *xdrs, layoutreturn4 *objp) +{ + if (!xdr_layoutreturn_type4(xdrs, &objp->lr_returntype)) + return (FALSE); + switch (objp->lr_returntype) { + case LAYOUTRETURN4_FILE: + if (!xdr_layoutreturn_file4(xdrs, + &objp->layoutreturn4_u.lr_layout)) + return (FALSE); + break; + } + return (TRUE); +} + + +bool_t +xdr_fs4_status_type(XDR *xdrs, fs4_status_type *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fs4_status(XDR *xdrs, fs4_status *objp) +{ + if (!xdr_bool(xdrs, &objp->fss_absent)) + return (FALSE); + if (!xdr_fs4_status_type(xdrs, &objp->fss_type)) + return (FALSE); + if (!xdr_utf8str_cs(xdrs, &objp->fss_source)) + return (FALSE); + if (!xdr_utf8str_cs(xdrs, &objp->fss_current)) + return (FALSE); + if (!xdr_int32_t(xdrs, &objp->fss_age)) + return (FALSE); + if (!xdr_nfstime4(xdrs, &objp->fss_version)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_threshold4_read_size(XDR *xdrs, threshold4_read_size *objp) +{ + + if (!xdr_length4(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_threshold4_write_size(XDR *xdrs, threshold4_write_size *objp) +{ + if (!xdr_length4(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_threshold4_read_iosize(XDR *xdrs, threshold4_read_iosize *objp) +{ + if (!xdr_length4(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_threshold4_write_iosize(XDR *xdrs, threshold4_write_iosize *objp) +{ + if (!xdr_length4(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_threshold_item4(XDR *xdrs, threshold_item4 *objp) +{ + if (!xdr_layouttype4(xdrs, &objp->thi_layout_type)) + return (FALSE); + if (!xdr_bitmap4(xdrs, &objp->thi_hintset)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->thi_hintlist.thi_hintlist_val, + (uint_t *)&objp->thi_hintlist.thi_hintlist_len, ~0)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_mdsthreshold4(XDR *xdrs, mdsthreshold4 *objp) +{ + if (!xdr_array(xdrs, (char **)&objp->mth_hints.mth_hints_val, + (uint_t *)&objp->mth_hints.mth_hints_len, ~0, + sizeof (threshold_item4), (xdrproc_t)xdr_threshold_item4)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_retention_get4(XDR *xdrs, retention_get4 *objp) +{ + if (!xdr_uint64_t(xdrs, &objp->rg_duration)) + return (FALSE); + if (!xdr_array(xdrs, (char **)&objp->rg_begin_time.rg_begin_time_val, + (uint_t *)&objp->rg_begin_time.rg_begin_time_len, 1, + sizeof (nfstime4), (xdrproc_t)xdr_nfstime4)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_retention_set4(XDR *xdrs, retention_set4 *objp) +{ + if (!xdr_bool(xdrs, &objp->rs_enable)) + return (FALSE); + if (!xdr_array(xdrs, (char **)&objp->rs_duration.rs_duration_val, + (uint_t *)&objp->rs_duration.rs_duration_len, 1, sizeof (uint64_t), + (xdrproc_t)xdr_uint64_t)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fs_charset_cap4(XDR *xdrs, fs_charset_cap4 *objp) +{ + + if (!xdr_uint32_t(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fattr4_mode_set_masked(XDR *xdrs, fattr4_mode_set_masked *objp) +{ + if (!xdr_mode_masked4(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fattr4_dir_notif_delay(XDR *xdrs, fattr4_dir_notif_delay *objp) +{ + + if (!xdr_nfstime4(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fattr4_dirent_notif_delay(XDR *xdrs, fattr4_dirent_notif_delay *objp) +{ + if (!xdr_nfstime4(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fattr4_fs_layout_types(XDR *xdrs, fattr4_fs_layout_types *objp) +{ + if (!xdr_array(xdrs, (char **)&objp->fattr4_fs_layout_types_val, + (uint_t *)&objp->fattr4_fs_layout_types_len, ~0, + sizeof (layouttype4), (xdrproc_t)xdr_layouttype4)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fattr4_fs_status(XDR *xdrs, fattr4_fs_status *objp) +{ + if (!xdr_fs4_status(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fattr4_fs_charset_cap4(XDR *xdrs, fattr4_fs_charset_cap *objp) +{ + if (!xdr_fs_charset_cap4(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fattr4_retention_get(XDR *xdrs, fattr4_retention_get *objp) +{ + if (!xdr_retention_get4(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fattr4_retention_set(XDR *xdrs, fattr4_retention_set *objp) +{ + if (!xdr_retention_set4(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fattr4_retentevt_get(XDR *xdrs, fattr4_retentevt_get *objp) +{ + if (!xdr_retention_get4(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fattr4_retentevt_set(XDR *xdrs, fattr4_retentevt_set *objp) +{ + if (!xdr_retention_set4(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fattr4_retention_hold(XDR *xdrs, fattr4_retention_hold *objp) +{ + if (!xdr_uint64_t(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fattr4_dacl(XDR *xdrs, fattr4_dacl *objp) +{ + if (!xdr_nfsacl41(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fattr4_sacl(XDR *xdrs, fattr4_sacl *objp) +{ + if (!xdr_nfsacl41(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_client_owner4(XDR *xdrs, client_owner4 *objp) +{ + if (!xdr_verifier4(xdrs, (verifier4 *)&objp->co_verifier)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->co_ownerid.co_ownerid_val, + (uint_t *)&objp->co_ownerid.co_ownerid_len, NFS4_OPAQUE_LIMIT)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_server_owner4(XDR *xdrs, server_owner4 *objp) +{ + if (!xdr_uint64_t(xdrs, &objp->so_minor_id)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->so_major_id.so_major_id_val, + (uint_t *)&objp->so_major_id.so_major_id_len, NFS4_OPAQUE_LIMIT)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_state_owner4(XDR *xdrs, state_owner4 *objp) +{ + if (!xdr_clientid4(xdrs, &objp->clientid)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->owner.owner_val, + (uint_t *)&objp->owner.owner_len, NFS4_OPAQUE_LIMIT)) + return (FALSE); + return (TRUE); +} + +/* Input for computing subkeys */ + +bool_t +xdr_ssv_subkey4(XDR *xdrs, ssv_subkey4 *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + + +/* Input for computing smt_hmac */ + +bool_t +xdr_ssv_mic_plain_tkn4(XDR *xdrs, ssv_mic_plain_tkn4 *objp) +{ + if (!xdr_uint32_t(xdrs, &objp->smpt_ssv_seq)) + return (FALSE); + if (!xdr_bytes(xdrs, + (char **)&objp->smpt_orig_plain.smpt_orig_plain_val, + (uint_t *)&objp->smpt_orig_plain.smpt_orig_plain_len, ~0)) + return (FALSE); + return (TRUE); +} + + +/* SSV GSS PerMsgToken token */ + +bool_t +xdr_ssv_mic_tkn4(XDR *xdrs, ssv_mic_tkn4 *objp) +{ + if (!xdr_uint32_t(xdrs, &objp->smt_ssv_seq)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->smt_hmac.smt_hmac_val, + (uint_t *)&objp->smt_hmac.smt_hmac_len, ~0)) + return (FALSE); + return (TRUE); +} + + +/* Input for computing ssct_encr_data and ssct_hmac */ + +bool_t +xdr_ssv_seal_plain_tkn4(XDR *xdrs, ssv_seal_plain_tkn4 *objp) +{ + if (!xdr_bytes(xdrs, + (char **)&objp->sspt_confounder.sspt_confounder_val, + (uint_t *)&objp->sspt_confounder.sspt_confounder_len, ~0)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->sspt_ssv_seq)) + return (FALSE); + if (!xdr_bytes(xdrs, + (char **)&objp->sspt_orig_plain.sspt_orig_plain_val, + (uint_t *)&objp->sspt_orig_plain.sspt_orig_plain_len, ~0)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->sspt_pad.sspt_pad_val, + (uint_t *)&objp->sspt_pad.sspt_pad_len, ~0)) + return (FALSE); + return (TRUE); +} + + +/* SSV GSS SealedMessage token */ + +bool_t +xdr_ssv_seal_cipher_tkn4(XDR *xdrs, ssv_seal_cipher_tkn4 *objp) +{ + if (!xdr_uint32_t(xdrs, &objp->ssct_ssv_seq)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->ssct_iv.ssct_iv_val, + (uint_t *)&objp->ssct_iv.ssct_iv_len, ~0)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->ssct_encr_data.ssct_encr_data_val, + (uint_t *)&objp->ssct_encr_data.ssct_encr_data_len, ~0)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->ssct_hmac.ssct_hmac_val, + (uint_t *)&objp->ssct_hmac.ssct_hmac_len, ~0)) + return (FALSE); + return (TRUE); +} + + +bool_t +xdr_fs_locations_server4(XDR *xdrs, fs_locations_server4 *objp) +{ + if (!xdr_int32_t(xdrs, &objp->fls_currency)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->fls_info.fls_info_val, + (uint_t *)&objp->fls_info.fls_info_len, ~0)) + return (FALSE); + if (!xdr_utf8str_cis(xdrs, &objp->fls_server)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fs_locations_item4(XDR *xdrs, fs_locations_item4 *objp) +{ + if (!xdr_array(xdrs, (char **)&objp->fli_entries.fli_entries_val, + (uint_t *)&objp->fli_entries.fli_entries_len, ~0, + sizeof (fs_locations_server4), (xdrproc_t)xdr_fs_locations_server4)) + return (FALSE); + if (!xdr_pathname4(xdrs, &objp->fli_rootpath)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fs_locations_info4(XDR *xdrs, fs_locations_info4 *objp) +{ + if (!xdr_uint32_t(xdrs, &objp->fli_flags)) + return (FALSE); + if (!xdr_int32_t(xdrs, &objp->fli_valid_for)) + return (FALSE); + if (!xdr_pathname4(xdrs, &objp->fli_fs_root)) + return (FALSE); + if (!xdr_array(xdrs, (char **)&objp->fli_items.fli_items_val, + (uint_t *)&objp->fli_items.fli_items_len, ~0, + sizeof (fs_locations_item4), (xdrproc_t)xdr_fs_locations_item4)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fattr4_fs_locations_info(XDR *xdrs, fattr4_fs_locations_info *objp) +{ + if (!xdr_fs_locations_info4(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_nfl_util4(XDR *xdrs, nfl_util4 *objp) +{ + if (!xdr_uint32_t(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_filelayout_hint_care4(XDR *xdrs, filelayout_hint_care4 *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + + +bool_t +xdr_multipath_list4(XDR *xdrs, multipath_list4 *objp) +{ + if (!xdr_array(xdrs, (char **)&objp->multipath_list4_val, + (uint_t *)&objp->multipath_list4_len, ~0, + sizeof (netaddr4), (xdrproc_t)xdr_netaddr4)) + return (FALSE); + return (TRUE); +} + +/* Encoded in the da_addr_body field of type device_addr4: */ + +bool_t +xdr_nfsv4_1_file_layout_ds_addr4(XDR *xdrs, nfsv4_1_file_layout_ds_addr4 *objp) +{ + if (!xdr_array(xdrs, + (char **)&objp->nflda_stripe_indices.nflda_stripe_indices_val, + (uint_t *)&objp->nflda_stripe_indices.nflda_stripe_indices_len, ~0, + sizeof (uint32_t), (xdrproc_t)xdr_uint32_t)) + return (FALSE); + if (!xdr_array(xdrs, + (char **)&objp->nflda_multipath_ds_list.nflda_multipath_ds_list_val, + (uint_t *)&objp->nflda_multipath_ds_list. + nflda_multipath_ds_list_len, ~0, sizeof (multipath_list4), + (xdrproc_t)xdr_multipath_list4)) + return (FALSE); + return (TRUE); +} + + +/* Encoded in the loc_body field of type layout_content4: */ + +bool_t +xdr_nfsv4_1_file_layout4(XDR *xdrs, nfsv4_1_file_layout4 *objp) +{ + if (!xdr_deviceid4(xdrs, objp->nfl_deviceid)) + return (FALSE); + if (!xdr_nfl_util4(xdrs, &objp->nfl_util)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->nfl_first_stripe_index)) + return (FALSE); + if (!xdr_offset4(xdrs, &objp->nfl_pattern_offset)) + return (FALSE); + if (!xdr_array(xdrs, (char **)&objp->nfl_fh_list.nfl_fh_list_val, + (uint_t *)&objp->nfl_fh_list.nfl_fh_list_len, ~0, + sizeof (nfs_fh4), (xdrproc_t)xdr_nfs_fh4)) + return (FALSE); + return (TRUE); +} + +/* + * Encoded in the lou_body field of type layoutupdate4: + * Nothing. lou_body is a zero length array of octets. + */ + + +bool_t +xdr_creatverfattr(XDR *xdrs, creatverfattr *objp) +{ + if (!xdr_verifier4(xdrs, (verifier4 *)&objp->cva_verf)) + return (FALSE); + if (!xdr_fattr4(xdrs, &objp->cva_attrs)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_open_claim_delegate_cur4(XDR *xdrs, open_claim_delegate_cur4 *objp) +{ + if (!xdr_stateid4(xdrs, &objp->delegate_stateid)) + return (FALSE); + if (!xdr_component4(xdrs, &objp->file)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_open_claim4(XDR *xdrs, open_claim4 *objp) +{ + if (!xdr_open_claim_type4(xdrs, &objp->claim)) + return (FALSE); + switch (objp->claim) { + case CLAIM_NULL: + if (!xdr_component4(xdrs, &objp->open_claim4_u.file)) + return (FALSE); + break; + case CLAIM_PREVIOUS: + if (!xdr_open_delegation_type4(xdrs, + &objp->open_claim4_u.delegate_type)) + return (FALSE); + break; + case CLAIM_DELEGATE_CUR: + if (!xdr_open_claim_delegate_cur4(xdrs, + &objp->open_claim4_u.delegate_cur_info)) + return (FALSE); + break; + case CLAIM_DELEGATE_PREV: + if (!xdr_component4(xdrs, + &objp->open_claim4_u.file_delegate_prev)) + return (FALSE); + break; + case CLAIM_FH: + break; + case CLAIM_DELEG_PREV_FH: + break; + case CLAIM_DELEG_CUR_FH: + if (!xdr_stateid4(xdrs, + &objp->open_claim4_u.oc_delegate_stateid)) + return (FALSE); + break; + default: + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_why_no_delegation4(XDR *xdrs, why_no_delegation4 *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_open_none_delegation4(XDR *xdrs, open_none_delegation4 *objp) +{ + if (!xdr_why_no_delegation4(xdrs, &objp->ond_why)) + return (FALSE); + switch (objp->ond_why) { + case WND4_CONTENTION: + if (!xdr_bool(xdrs, + &objp->open_none_delegation4_u.ond_server_will_push_deleg)) + return (FALSE); + break; + case WND4_RESOURCE: + if (!xdr_bool(xdrs, &objp->open_none_delegation4_u. + ond_server_will_signal_avail)) + return (FALSE); + break; + } + return (TRUE); +} + +bool_t +xdr_open_delegation4(XDR *xdrs, open_delegation4 *objp) +{ + if (!xdr_open_delegation_type4(xdrs, &objp->delegation_type)) + return (FALSE); + switch (objp->delegation_type) { + case OPEN_DELEGATE_NONE: + break; + case OPEN_DELEGATE_READ: + if (!xdr_open_read_delegation4(xdrs, + &objp->open_delegation4_u.read)) + return (FALSE); + break; + case OPEN_DELEGATE_WRITE: + if (!xdr_open_write_delegation4(xdrs, + &objp->open_delegation4_u.write)) + return (FALSE); + break; + case OPEN_DELEGATE_NONE_EXT: + if (!xdr_open_none_delegation4(xdrs, + &objp->open_delegation4_u.od_whynone)) + return (FALSE); + break; + default: + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_gsshandle4_t(XDR *xdrs, gsshandle4_t *objp) +{ + if (!xdr_bytes(xdrs, (char **)&objp->gsshandle4_t_val, + (uint_t *)&objp->gsshandle4_t_len, ~0)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_gss_cb_handles4(XDR *xdrs, gss_cb_handles4 *objp) +{ + if (!xdr_rpc_gss_svc_t(xdrs, &objp->gcbp_service)) + return (FALSE); + if (!xdr_gsshandle4_t(xdrs, &objp->gcbp_handle_from_server)) + return (FALSE); + if (!xdr_gsshandle4_t(xdrs, &objp->gcbp_handle_from_client)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_callback_sec_parms4(XDR *xdrs, callback_sec_parms4 *objp) +{ + if (!xdr_uint32_t(xdrs, &objp->cb_secflavor)) + return (FALSE); + switch (objp->cb_secflavor) { + case AUTH_NONE: + break; + case AUTH_SYS: + if (!xdr_authsys_parms(xdrs, + &objp->callback_sec_parms4_u.cbsp_sys_cred)) + return (FALSE); + break; + case RPCSEC_GSS: + if (!xdr_gss_cb_handles4(xdrs, + &objp->callback_sec_parms4_u.cbsp_gss_handles)) + return (FALSE); + break; + default: + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_BACKCHANNEL_CTL4args(XDR *xdrs, BACKCHANNEL_CTL4args *objp) +{ + if (!xdr_uint32_t(xdrs, &objp->bca_cb_program)) + return (FALSE); + if (!xdr_array(xdrs, (char **)&objp->bca_sec_parms.bca_sec_parms_val, + (uint_t *)&objp->bca_sec_parms.bca_sec_parms_len, ~0, + sizeof (callback_sec_parms4), (xdrproc_t)xdr_callback_sec_parms4)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_BACKCHANNEL_CTL4res(XDR *xdrs, BACKCHANNEL_CTL4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->bcr_status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_channel_dir_from_client4(XDR *xdrs, channel_dir_from_client4 *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_BIND_CONN_TO_SESSION4args(XDR *xdrs, BIND_CONN_TO_SESSION4args *objp) +{ + if (!xdr_sessionid4(xdrs, objp->bctsa_sessid)) + return (FALSE); + if (!xdr_channel_dir_from_client4(xdrs, &objp->bctsa_dir)) + return (FALSE); + if (!xdr_bool(xdrs, &objp->bctsa_use_conn_in_rdma_mode)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_channel_dir_from_server4(XDR *xdrs, channel_dir_from_server4 *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_BIND_CONN_TO_SESSION4resok(XDR *xdrs, BIND_CONN_TO_SESSION4resok *objp) +{ + if (!xdr_sessionid4(xdrs, objp->bctsr_sessid)) + return (FALSE); + if (!xdr_channel_dir_from_server4(xdrs, &objp->bctsr_dir)) + return (FALSE); + if (!xdr_bool(xdrs, &objp->bctsr_use_conn_in_rdma_mode)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_BIND_CONN_TO_SESSION4res(XDR *xdrs, BIND_CONN_TO_SESSION4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->bctsr_status)) + return (FALSE); + switch (objp->bctsr_status) { + case NFS4_OK: + if (!xdr_BIND_CONN_TO_SESSION4resok(xdrs, + &objp->BIND_CONN_TO_SESSION4res_u.bctsr_resok4)) + return (FALSE); + break; + } + return (TRUE); +} + +bool_t +xdr_state_protect_ops4(XDR *xdrs, state_protect_ops4 *objp) +{ + if (!xdr_bitmap4(xdrs, &objp->spo_must_enforce)) + return (FALSE); + if (!xdr_bitmap4(xdrs, &objp->spo_must_allow)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_ssv_sp_parms4(XDR *xdrs, ssv_sp_parms4 *objp) +{ + if (!xdr_state_protect_ops4(xdrs, &objp->ssp_ops)) + return (FALSE); + if (!xdr_array(xdrs, (char **)&objp->ssp_hash_algs.ssp_hash_algs_val, + (uint_t *)&objp->ssp_hash_algs.ssp_hash_algs_len, ~0, + sizeof (sec_oid4), (xdrproc_t)xdr_sec_oid4)) + return (FALSE); + if (!xdr_array(xdrs, (char **)&objp->ssp_encr_algs.ssp_encr_algs_val, + (uint_t *)&objp->ssp_encr_algs.ssp_encr_algs_len, ~0, + sizeof (sec_oid4), (xdrproc_t)xdr_sec_oid4)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->ssp_window)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->ssp_num_gss_handles)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_state_protect_how4(XDR *xdrs, state_protect_how4 *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_state_protect4_a(XDR *xdrs, state_protect4_a *objp) +{ + if (!xdr_state_protect_how4(xdrs, &objp->spa_how)) + return (FALSE); + switch (objp->spa_how) { + case SP4_NONE: + break; + case SP4_MACH_CRED: + if (!xdr_state_protect_ops4(xdrs, + &objp->state_protect4_a_u.spa_mach_ops)) + return (FALSE); + break; + case SP4_SSV: + if (!xdr_ssv_sp_parms4(xdrs, + &objp->state_protect4_a_u.spa_ssv_parms)) + return (FALSE); + break; + default: + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_EXCHANGE_ID4args(XDR *xdrs, EXCHANGE_ID4args *objp) +{ + if (!xdr_client_owner4(xdrs, &objp->eia_clientowner)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->eia_flags)) + return (FALSE); + if (!xdr_state_protect4_a(xdrs, &objp->eia_state_protect)) + return (FALSE); + if (!xdr_array(xdrs, + (char **)&objp->eia_client_impl_id.eia_client_impl_id_val, + (uint_t *)&objp->eia_client_impl_id.eia_client_impl_id_len, 1, + sizeof (nfs_impl_id4), (xdrproc_t)xdr_nfs_impl_id4)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_ssv_prot_info4(XDR *xdrs, ssv_prot_info4 *objp) +{ + if (!xdr_state_protect_ops4(xdrs, &objp->spi_ops)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->spi_hash_alg)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->spi_encr_alg)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->spi_ssv_len)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->spi_window)) + return (FALSE); + if (!xdr_array(xdrs, (char **)&objp->spi_handles.spi_handles_val, + (uint_t *)&objp->spi_handles.spi_handles_len, ~0, + sizeof (gsshandle4_t), (xdrproc_t)xdr_gsshandle4_t)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_state_protect4_r(XDR *xdrs, state_protect4_r *objp) +{ + if (!xdr_state_protect_how4(xdrs, &objp->spr_how)) + return (FALSE); + switch (objp->spr_how) { + case SP4_NONE: + break; + case SP4_MACH_CRED: + if (!xdr_state_protect_ops4(xdrs, + &objp->state_protect4_r_u.spr_mach_ops)) + return (FALSE); + break; + case SP4_SSV: + if (!xdr_ssv_prot_info4(xdrs, + &objp->state_protect4_r_u.spr_ssv_info)) + return (FALSE); + break; + default: + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_EXCHANGE_ID4resok(XDR *xdrs, EXCHANGE_ID4resok *objp) +{ + if (!xdr_clientid4(xdrs, &objp->eir_clientid)) + return (FALSE); + if (!xdr_sequenceid4(xdrs, &objp->eir_sequenceid)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->eir_flags)) + return (FALSE); + if (!xdr_state_protect4_r(xdrs, &objp->eir_state_protect)) + return (FALSE); + if (!xdr_server_owner4(xdrs, &objp->eir_server_owner)) + return (FALSE); + if (!xdr_bytes(xdrs, + (char **)&objp->eir_server_scope.eir_server_scope_val, + (uint_t *)&objp->eir_server_scope.eir_server_scope_len, + NFS4_OPAQUE_LIMIT)) + return (FALSE); + if (!xdr_array(xdrs, + (char **)&objp->eir_server_impl_id.eir_server_impl_id_val, + (uint_t *)&objp->eir_server_impl_id.eir_server_impl_id_len, 1, + sizeof (nfs_impl_id4), (xdrproc_t)xdr_nfs_impl_id4)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_EXCHANGE_ID4res(XDR *xdrs, EXCHANGE_ID4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->eir_status)) + return (FALSE); + switch (objp->eir_status) { + case NFS4_OK: + if (!xdr_EXCHANGE_ID4resok(xdrs, + &objp->EXCHANGE_ID4res_u.eir_resok4)) + return (FALSE); + break; + } + return (TRUE); +} + +bool_t +xdr_channel_attrs4(XDR *xdrs, channel_attrs4 *objp) +{ + if (!xdr_count4(xdrs, &objp->ca_headerpadsize)) + return (FALSE); + if (!xdr_count4(xdrs, &objp->ca_maxrequestsize)) + return (FALSE); + if (!xdr_count4(xdrs, &objp->ca_maxresponsesize)) + return (FALSE); + if (!xdr_count4(xdrs, &objp->ca_maxresponsesize_cached)) + return (FALSE); + if (!xdr_count4(xdrs, &objp->ca_maxoperations)) + return (FALSE); + if (!xdr_count4(xdrs, &objp->ca_maxrequests)) + return (FALSE); + if (!xdr_array(xdrs, (char **)&objp->ca_rdma_ird.ca_rdma_ird_val, + (uint_t *)&objp->ca_rdma_ird.ca_rdma_ird_len, 1, + sizeof (uint32_t), (xdrproc_t)xdr_uint32_t)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CREATE_SESSION4args(XDR *xdrs, CREATE_SESSION4args *objp) +{ + + if (!xdr_clientid4(xdrs, &objp->csa_clientid)) + return (FALSE); + if (!xdr_sequenceid4(xdrs, &objp->csa_sequence)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->csa_flags)) + return (FALSE); + if (!xdr_channel_attrs4(xdrs, &objp->csa_fore_chan_attrs)) + return (FALSE); + if (!xdr_channel_attrs4(xdrs, &objp->csa_back_chan_attrs)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->csa_cb_program)) + return (FALSE); + if (!xdr_array(xdrs, (char **)&objp->csa_sec_parms.csa_sec_parms_val, + (uint_t *)&objp->csa_sec_parms.csa_sec_parms_len, ~0, + sizeof (callback_sec_parms4), (xdrproc_t)xdr_callback_sec_parms4)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CREATE_SESSION4resok(XDR *xdrs, CREATE_SESSION4resok *objp) +{ + if (!xdr_sessionid4(xdrs, objp->csr_sessionid)) + return (FALSE); + if (!xdr_sequenceid4(xdrs, &objp->csr_sequence)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->csr_flags)) + return (FALSE); + if (!xdr_channel_attrs4(xdrs, &objp->csr_fore_chan_attrs)) + return (FALSE); + if (!xdr_channel_attrs4(xdrs, &objp->csr_back_chan_attrs)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CREATE_SESSION4res(XDR *xdrs, CREATE_SESSION4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->csr_status)) + return (FALSE); + switch (objp->csr_status) { + case NFS4_OK: + if (!xdr_CREATE_SESSION4resok(xdrs, + &objp->CREATE_SESSION4res_u.csr_resok4)) + return (FALSE); + break; + } + return (TRUE); +} + +bool_t +xdr_DESTROY_SESSION4args(XDR *xdrs, DESTROY_SESSION4args *objp) +{ + if (!xdr_sessionid4(xdrs, objp->dsa_sessionid)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_DESTROY_SESSION4res(XDR *xdrs, DESTROY_SESSION4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->dsr_status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_FREE_STATEID4args(XDR *xdrs, FREE_STATEID4args *objp) +{ + if (!xdr_stateid4(xdrs, &objp->fsa_stateid)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_FREE_STATEID4res(XDR *xdrs, FREE_STATEID4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->fsr_status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_attr_notice4(XDR *xdrs, attr_notice4 *objp) +{ + if (!xdr_nfstime4(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_GET_DIR_DELEGATION4args(XDR *xdrs, GET_DIR_DELEGATION4args *objp) +{ + if (!xdr_bool(xdrs, &objp->gdda_signal_deleg_avail)) + return (FALSE); + if (!xdr_bitmap4(xdrs, &objp->gdda_notification_types)) + return (FALSE); + if (!xdr_attr_notice4(xdrs, &objp->gdda_child_attr_delay)) + return (FALSE); + if (!xdr_attr_notice4(xdrs, &objp->gdda_dir_attr_delay)) + return (FALSE); + if (!xdr_bitmap4(xdrs, &objp->gdda_child_attributes)) + return (FALSE); + if (!xdr_bitmap4(xdrs, &objp->gdda_dir_attributes)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_GET_DIR_DELEGATION4resok(XDR *xdrs, GET_DIR_DELEGATION4resok *objp) +{ + if (!xdr_verifier4(xdrs, (verifier4 *)&objp->gddr_cookieverf)) + return (FALSE); + if (!xdr_stateid4(xdrs, &objp->gddr_stateid)) + return (FALSE); + if (!xdr_bitmap4(xdrs, &objp->gddr_notification)) + return (FALSE); + if (!xdr_bitmap4(xdrs, &objp->gddr_child_attributes)) + return (FALSE); + if (!xdr_bitmap4(xdrs, &objp->gddr_dir_attributes)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_gddrnf4_status(XDR *xdrs, gddrnf4_status *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_GET_DIR_DELEGATION4res_non_fatal(XDR *xdrs, + GET_DIR_DELEGATION4res_non_fatal *objp) +{ + if (!xdr_gddrnf4_status(xdrs, &objp->gddrnf_status)) + return (FALSE); + switch (objp->gddrnf_status) { + case GDD4_OK: + if (!xdr_GET_DIR_DELEGATION4resok(xdrs, + &objp->GET_DIR_DELEGATION4res_non_fatal_u.gddrnf_resok4)) + return (FALSE); + break; + case GDD4_UNAVAIL: + if (!xdr_bool(xdrs, &objp->GET_DIR_DELEGATION4res_non_fatal_u. + gddrnf_will_signal_deleg_avail)) + return (FALSE); + break; + default: + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_GET_DIR_DELEGATION4res(XDR *xdrs, GET_DIR_DELEGATION4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->gddr_status)) + return (FALSE); + switch (objp->gddr_status) { + case NFS4_OK: + if (!xdr_GET_DIR_DELEGATION4res_non_fatal(xdrs, + &objp->GET_DIR_DELEGATION4res_u.gddr_res_non_fatal4)) + return (FALSE); + break; + } + return (TRUE); +} + +/* + * Special xdr function to encode single word bitmaps for + * notification bitmaps which only need a single word. + */ +bool_t +xdr_bitmap4_notify(XDR *xdrs, bitmap4 *objp) +{ + int32_t len = 1; + + ASSERT(xdrs->x_op == XDR_ENCODE); + if (!XDR_PUTINT32(xdrs, &len)) + return (FALSE); +#if defined(_BIG_ENDIAN) + return (XDR_PUTINT32(xdrs, (int32_t *)objp)); +#elif defined(_LITTLE_ENDIAN) + return (XDR_PUTINT32(xdrs, (int32_t *)objp+1)); +#endif +} + +bool_t +xdr_GETDEVICEINFO4args(XDR *xdrs, GETDEVICEINFO4args *objp) +{ + if (!xdr_deviceid4(xdrs, objp->gdia_device_id)) + return (FALSE); + if (!xdr_layouttype4(xdrs, &objp->gdia_layout_type)) + return (FALSE); + if (!xdr_count4(xdrs, &objp->gdia_maxcount)) + return (FALSE); + if (xdrs->x_op == XDR_ENCODE) { + if (!xdr_bitmap4_notify(xdrs, &objp->gdia_notify_types)) + return (FALSE); + } else + if (!xdr_bitmap4(xdrs, &objp->gdia_notify_types)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_GETDEVICEINFO4resok(XDR *xdrs, GETDEVICEINFO4resok *objp) +{ + if (!xdr_device_addr4(xdrs, &objp->gdir_device_addr)) + return (FALSE); + if (xdrs->x_op == XDR_ENCODE) { + if (!xdr_bitmap4_notify(xdrs, &objp->gdir_notification)) + return (FALSE); + } else + if (!xdr_bitmap4(xdrs, &objp->gdir_notification)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_GETDEVICEINFO4res(XDR *xdrs, GETDEVICEINFO4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->gdir_status)) + return (FALSE); + switch (objp->gdir_status) { + case NFS4_OK: + if (!xdr_GETDEVICEINFO4resok(xdrs, + &objp->GETDEVICEINFO4res_u.gdir_resok4)) + return (FALSE); + break; + case NFS4ERR_TOOSMALL: + if (!xdr_count4(xdrs, &objp->GETDEVICEINFO4res_u.gdir_mincount)) + return (FALSE); + break; + } + return (TRUE); +} + +bool_t +xdr_GETDEVICELIST4args(XDR *xdrs, GETDEVICELIST4args *objp) +{ + if (!xdr_layouttype4(xdrs, &objp->gdla_layout_type)) + return (FALSE); + if (!xdr_count4(xdrs, &objp->gdla_maxdevices)) + return (FALSE); + if (!xdr_nfs_cookie4(xdrs, &objp->gdla_cookie)) + return (FALSE); + if (!xdr_verifier4(xdrs, (verifier4 *)&objp->gdla_cookieverf)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_GETDEVICELIST4resok(XDR *xdrs, GETDEVICELIST4resok *objp) +{ + if (!xdr_nfs_cookie4(xdrs, &objp->gdlr_cookie)) + return (FALSE); + if (!xdr_verifier4(xdrs, (verifier4 *)&objp->gdlr_cookieverf)) + return (FALSE); + if (!xdr_array(xdrs, + (char **)&objp->gdlr_deviceid_list.gdlr_deviceid_list_val, + (uint_t *)&objp->gdlr_deviceid_list.gdlr_deviceid_list_len, + ~0, sizeof (deviceid4), (xdrproc_t)xdr_deviceid4)) + return (FALSE); + if (!xdr_bool(xdrs, &objp->gdlr_eof)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_GETDEVICELIST4res(XDR *xdrs, GETDEVICELIST4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->gdlr_status)) + return (FALSE); + switch (objp->gdlr_status) { + case NFS4_OK: + if (!xdr_GETDEVICELIST4resok(xdrs, + &objp->GETDEVICELIST4res_u.gdlr_resok4)) + return (FALSE); + break; + default: + break; + } + return (TRUE); +} + +bool_t +xdr_newtime4(XDR *xdrs, newtime4 *objp) +{ + if (!xdr_bool(xdrs, &objp->nt_timechanged)) + return (FALSE); + switch (objp->nt_timechanged) { + case TRUE: + if (!xdr_nfstime4(xdrs, &objp->newtime4_u.nt_time)) + return (FALSE); + break; + case FALSE: + break; + default: + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_newoffset4(XDR *xdrs, newoffset4 *objp) +{ + if (!xdr_bool(xdrs, &objp->no_newoffset)) + return (FALSE); + switch (objp->no_newoffset) { + case TRUE: + if (!xdr_offset4(xdrs, &objp->newoffset4_u.no_offset)) + return (FALSE); + break; + case FALSE: + break; + default: + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_LAYOUTCOMMIT4args(XDR *xdrs, LAYOUTCOMMIT4args *objp) +{ + if (!xdr_offset4(xdrs, &objp->loca_offset)) + return (FALSE); + if (!xdr_length4(xdrs, &objp->loca_length)) + return (FALSE); + if (!xdr_bool(xdrs, &objp->loca_reclaim)) + return (FALSE); + if (!xdr_stateid4(xdrs, &objp->loca_stateid)) + return (FALSE); + if (!xdr_newoffset4(xdrs, &objp->loca_last_write_offset)) + return (FALSE); + if (!xdr_newtime4(xdrs, &objp->loca_time_modify)) + return (FALSE); + if (!xdr_layoutupdate4(xdrs, &objp->loca_layoutupdate)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_newsize4(XDR *xdrs, newsize4 *objp) +{ + if (!xdr_bool(xdrs, &objp->ns_sizechanged)) + return (FALSE); + switch (objp->ns_sizechanged) { + case TRUE: + if (!xdr_length4(xdrs, &objp->newsize4_u.ns_size)) + return (FALSE); + break; + case FALSE: + break; + default: + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_LAYOUTCOMMIT4resok(XDR *xdrs, LAYOUTCOMMIT4resok *objp) +{ + if (!xdr_newsize4(xdrs, &objp->locr_newsize)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_LAYOUTCOMMIT4res(XDR *xdrs, LAYOUTCOMMIT4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->locr_status)) + return (FALSE); + switch (objp->locr_status) { + case NFS4_OK: + if (!xdr_LAYOUTCOMMIT4resok(xdrs, + &objp->LAYOUTCOMMIT4res_u.locr_resok4)) + return (FALSE); + break; + } + return (TRUE); +} + +bool_t +xdr_LAYOUTGET4args(XDR *xdrs, LAYOUTGET4args *objp) +{ + if (!xdr_bool(xdrs, &objp->loga_signal_layout_avail)) + return (FALSE); + if (!xdr_layouttype4(xdrs, &objp->loga_layout_type)) + return (FALSE); + if (!xdr_layoutiomode4(xdrs, &objp->loga_iomode)) + return (FALSE); + if (!xdr_offset4(xdrs, &objp->loga_offset)) + return (FALSE); + if (!xdr_length4(xdrs, &objp->loga_length)) + return (FALSE); + if (!xdr_length4(xdrs, &objp->loga_minlength)) + return (FALSE); + if (!xdr_stateid4(xdrs, &objp->loga_stateid)) + return (FALSE); + if (!xdr_count4(xdrs, &objp->loga_maxcount)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_LAYOUTGET4resok(XDR *xdrs, LAYOUTGET4resok *objp) +{ + if (!xdr_bool(xdrs, &objp->logr_return_on_close)) + return (FALSE); + if (!xdr_stateid4(xdrs, &objp->logr_stateid)) + return (FALSE); + if (!xdr_array(xdrs, (char **)&objp->logr_layout.logr_layout_val, + (uint_t *)&objp->logr_layout.logr_layout_len, ~0, + sizeof (layout4), (xdrproc_t)xdr_layout4)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_LAYOUTGET4res(XDR *xdrs, LAYOUTGET4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->logr_status)) + return (FALSE); + switch (objp->logr_status) { + case NFS4_OK: + if (!xdr_LAYOUTGET4resok(xdrs, + &objp->LAYOUTGET4res_u.logr_resok4)) + return (FALSE); + break; + case NFS4ERR_LAYOUTTRYLATER: + if (!xdr_bool(xdrs, + &objp->LAYOUTGET4res_u.logr_will_signal_layout_avail)) + return (FALSE); + break; + } + return (TRUE); +} + +bool_t +xdr_LAYOUTRETURN4args(XDR *xdrs, LAYOUTRETURN4args *objp) +{ + if (!xdr_bool(xdrs, &objp->lora_reclaim)) + return (FALSE); + if (!xdr_layouttype4(xdrs, &objp->lora_layout_type)) + return (FALSE); + if (!xdr_layoutiomode4(xdrs, &objp->lora_iomode)) + return (FALSE); + if (!xdr_layoutreturn4(xdrs, &objp->lora_layoutreturn)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_layoutreturn_stateid(XDR *xdrs, layoutreturn_stateid *objp) +{ + if (!xdr_bool(xdrs, &objp->lrs_present)) + return (FALSE); + switch (objp->lrs_present) { + case TRUE: + if (!xdr_stateid4(xdrs, + &objp->layoutreturn_stateid_u.lrs_stateid)) + return (FALSE); + break; + case FALSE: + break; + default: + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_LAYOUTRETURN4res(XDR *xdrs, LAYOUTRETURN4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->lorr_status)) + return (FALSE); + switch (objp->lorr_status) { + case NFS4_OK: + if (!xdr_layoutreturn_stateid(xdrs, + &objp->LAYOUTRETURN4res_u.lorr_stateid)) + return (FALSE); + break; + } + return (TRUE); +} + +bool_t +xdr_secinfo_style4(XDR *xdrs, secinfo_style4 *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_SECINFO_NO_NAME4args(XDR *xdrs, SECINFO_NO_NAME4args *objp) +{ + if (!xdr_secinfo_style4(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_SECINFO_NO_NAME4res(XDR *xdrs, SECINFO_NO_NAME4res *objp) +{ + if (!xdr_SECINFO4res(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_SEQUENCE4args(XDR *xdrs, SEQUENCE4args *objp) +{ + if (!xdr_sessionid4(xdrs, objp->sa_sessionid)) + return (FALSE); + if (!xdr_sequenceid4(xdrs, &objp->sa_sequenceid)) + return (FALSE); + if (!xdr_slotid4(xdrs, &objp->sa_slotid)) + return (FALSE); + if (!xdr_slotid4(xdrs, &objp->sa_highest_slotid)) + return (FALSE); + if (!xdr_bool(xdrs, &objp->sa_cachethis)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_SEQUENCE4resok(XDR *xdrs, SEQUENCE4resok *objp) +{ + if (!xdr_sessionid4(xdrs, objp->sr_sessionid)) + return (FALSE); + if (!xdr_sequenceid4(xdrs, &objp->sr_sequenceid)) + return (FALSE); + if (!xdr_slotid4(xdrs, &objp->sr_slotid)) + return (FALSE); + if (!xdr_slotid4(xdrs, &objp->sr_highest_slotid)) + return (FALSE); + if (!xdr_slotid4(xdrs, &objp->sr_target_highest_slotid)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->sr_status_flags)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_SEQUENCE4res(XDR *xdrs, SEQUENCE4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->sr_status)) + return (FALSE); + switch (objp->sr_status) { + case NFS4_OK: + if (!xdr_SEQUENCE4resok(xdrs, &objp->SEQUENCE4res_u.sr_resok4)) + return (FALSE); + break; + } + return (TRUE); +} + +bool_t +xdr_ssa_digest_input4(XDR *xdrs, ssa_digest_input4 *objp) +{ + if (!xdr_SEQUENCE4args(xdrs, &objp->sdi_seqargs)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_SET_SSV4args(XDR *xdrs, SET_SSV4args *objp) +{ + if (!xdr_bytes(xdrs, (char **)&objp->ssa_ssv.ssa_ssv_val, + (uint_t *)&objp->ssa_ssv.ssa_ssv_len, ~0)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->ssa_digest.ssa_digest_val, + (uint_t *)&objp->ssa_digest.ssa_digest_len, ~0)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_ssr_digest_input4(XDR *xdrs, ssr_digest_input4 *objp) +{ + if (!xdr_SEQUENCE4res(xdrs, &objp->sdi_seqres)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_SET_SSV4resok(XDR *xdrs, SET_SSV4resok *objp) +{ + if (!xdr_bytes(xdrs, (char **)&objp->ssr_digest.ssr_digest_val, + (uint_t *)&objp->ssr_digest.ssr_digest_len, ~0)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_SET_SSV4res(XDR *xdrs, SET_SSV4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->ssr_status)) + return (FALSE); + switch (objp->ssr_status) { + case NFS4_OK: + if (!xdr_SET_SSV4resok(xdrs, &objp->SET_SSV4res_u.ssr_resok4)) + return (FALSE); + break; + } + return (TRUE); +} + +bool_t +xdr_TEST_STATEID4args(XDR *xdrs, TEST_STATEID4args *objp) +{ + if (!xdr_array(xdrs, (char **)&objp->ts_stateids.ts_stateids_val, + (uint_t *)&objp->ts_stateids.ts_stateids_len, ~0, + sizeof (stateid4), (xdrproc_t)xdr_stateid4)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_TEST_STATEID4resok(XDR *xdrs, TEST_STATEID4resok *objp) +{ + if (!xdr_array(xdrs, + (char **)&objp->tsr_status_codes.tsr_status_codes_val, + (uint_t *)&objp->tsr_status_codes.tsr_status_codes_len, ~0, + sizeof (nfsstat4), (xdrproc_t)xdr_nfsstat4)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_TEST_STATEID4res(XDR *xdrs, TEST_STATEID4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->tsr_status)) + return (FALSE); + switch (objp->tsr_status) { + case NFS4_OK: + if (!xdr_TEST_STATEID4resok(xdrs, + &objp->TEST_STATEID4res_u.tsr_resok4)) + return (FALSE); + break; + } + return (TRUE); +} + +bool_t +xdr_deleg_claim4(XDR *xdrs, deleg_claim4 *objp) +{ + if (!xdr_open_claim_type4(xdrs, &objp->dc_claim)) + return (FALSE); + switch (objp->dc_claim) { + case CLAIM_FH: + break; + case CLAIM_DELEG_PREV_FH: + break; + case CLAIM_PREVIOUS: + if (!xdr_open_delegation_type4(xdrs, + &objp->deleg_claim4_u.dc_delegate_type)) + return (FALSE); + break; + default: + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_WANT_DELEGATION4args(XDR *xdrs, WANT_DELEGATION4args *objp) +{ + if (!xdr_uint32_t(xdrs, &objp->wda_want)) + return (FALSE); + if (!xdr_deleg_claim4(xdrs, &objp->wda_claim)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_WANT_DELEGATION4res(XDR *xdrs, WANT_DELEGATION4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->wdr_status)) + return (FALSE); + switch (objp->wdr_status) { + case NFS4_OK: + if (!xdr_open_delegation4(xdrs, + &objp->WANT_DELEGATION4res_u.wdr_resok4)) + return (FALSE); + break; + } + return (TRUE); +} + +bool_t +xdr_DESTROY_CLIENTID4args(XDR *xdrs, DESTROY_CLIENTID4args *objp) +{ + if (!xdr_clientid4(xdrs, &objp->dca_clientid)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_DESTROY_CLIENTID4res(XDR *xdrs, DESTROY_CLIENTID4res *objp) +{ + + if (!xdr_nfsstat4(xdrs, &objp->dcr_status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_RECLAIM_COMPLETE4args(XDR *xdrs, RECLAIM_COMPLETE4args *objp) +{ + if (!xdr_bool(xdrs, &objp->rca_one_fs)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_RECLAIM_COMPLETE4res(XDR *xdrs, RECLAIM_COMPLETE4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->rcr_status)) + return (FALSE); + return (TRUE); +} + +/* new operations for NFSv4.1 */ + +bool_t +xdr_nfs4x_argop4(XDR *xdrs, nfs_argop4 *objp) +{ + /* nfs_opnum4 has already been xdr'd */ + switch (objp->argop) { + case OP_BACKCHANNEL_CTL: + if (!xdr_BACKCHANNEL_CTL4args(xdrs, + &objp->nfs_argop4_u.opbackchannel_ctl)) + return (FALSE); + break; + case OP_BIND_CONN_TO_SESSION: + if (!xdr_BIND_CONN_TO_SESSION4args(xdrs, + &objp->nfs_argop4_u.opbind_conn_to_session)) + return (FALSE); + break; + case OP_EXCHANGE_ID: + if (!xdr_EXCHANGE_ID4args(xdrs, + &objp->nfs_argop4_u.opexchange_id)) + return (FALSE); + break; + case OP_CREATE_SESSION: + if (!xdr_CREATE_SESSION4args(xdrs, + &objp->nfs_argop4_u.opcreate_session)) + return (FALSE); + break; + case OP_DESTROY_SESSION: + if (!xdr_DESTROY_SESSION4args(xdrs, + &objp->nfs_argop4_u.opdestroy_session)) + return (FALSE); + break; + case OP_FREE_STATEID: + if (!xdr_FREE_STATEID4args(xdrs, + &objp->nfs_argop4_u.opfree_stateid)) + return (FALSE); + break; + case OP_GET_DIR_DELEGATION: + if (!xdr_GET_DIR_DELEGATION4args(xdrs, + &objp->nfs_argop4_u.opget_dir_delegation)) + return (FALSE); + break; + case OP_GETDEVICEINFO: + if (!xdr_GETDEVICEINFO4args(xdrs, + &objp->nfs_argop4_u.opgetdeviceinfo)) + return (FALSE); + break; + case OP_GETDEVICELIST: + if (!xdr_GETDEVICELIST4args(xdrs, + &objp->nfs_argop4_u.opgetdevicelist)) + return (FALSE); + break; + case OP_LAYOUTCOMMIT: + if (!xdr_LAYOUTCOMMIT4args(xdrs, + &objp->nfs_argop4_u.oplayoutcommit)) + return (FALSE); + break; + case OP_LAYOUTGET: + if (!xdr_LAYOUTGET4args(xdrs, + &objp->nfs_argop4_u.oplayoutget)) + return (FALSE); + break; + case OP_LAYOUTRETURN: + if (!xdr_LAYOUTRETURN4args(xdrs, + &objp->nfs_argop4_u.oplayoutreturn)) + return (FALSE); + break; + case OP_SECINFO_NO_NAME: + if (!xdr_SECINFO_NO_NAME4args(xdrs, + &objp->nfs_argop4_u.opsecinfo_no_name)) + return (FALSE); + break; + case OP_SEQUENCE: + if (!xdr_SEQUENCE4args(xdrs, + &objp->nfs_argop4_u.opsequence)) + return (FALSE); + break; + case OP_SET_SSV: + if (!xdr_SET_SSV4args(xdrs, + &objp->nfs_argop4_u.opset_ssv)) + return (FALSE); + break; + case OP_TEST_STATEID: + if (!xdr_TEST_STATEID4args(xdrs, + &objp->nfs_argop4_u.optest_stateid)) + return (FALSE); + break; + case OP_WANT_DELEGATION: + if (!xdr_WANT_DELEGATION4args(xdrs, + &objp->nfs_argop4_u.opwant_delegation)) + return (FALSE); + break; + case OP_DESTROY_CLIENTID: + if (!xdr_DESTROY_CLIENTID4args(xdrs, + &objp->nfs_argop4_u.opdestroy_clientid)) + return (FALSE); + break; + case OP_RECLAIM_COMPLETE: + if (!xdr_RECLAIM_COMPLETE4args(xdrs, + &objp->nfs_argop4_u.opreclaim_complete)) + return (FALSE); + break; + default: + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_nfs4x_resop4(XDR *xdrs, nfs_resop4 *objp) +{ + /* nfs_opnum4 has already been xdr's */ + switch (objp->resop) { + case OP_BACKCHANNEL_CTL: + if (!xdr_BACKCHANNEL_CTL4res(xdrs, + &objp->nfs_resop4_u.opbackchannel_ctl)) + return (FALSE); + break; + case OP_BIND_CONN_TO_SESSION: + if (!xdr_BIND_CONN_TO_SESSION4res(xdrs, + &objp->nfs_resop4_u.opbind_conn_to_session)) + return (FALSE); + break; + case OP_EXCHANGE_ID: + if (!xdr_EXCHANGE_ID4res(xdrs, + &objp->nfs_resop4_u.opexchange_id)) + return (FALSE); + break; + case OP_CREATE_SESSION: + if (!xdr_CREATE_SESSION4res(xdrs, + &objp->nfs_resop4_u.opcreate_session)) + return (FALSE); + break; + case OP_DESTROY_SESSION: + if (!xdr_DESTROY_SESSION4res(xdrs, + &objp->nfs_resop4_u.opdestroy_session)) + return (FALSE); + break; + case OP_FREE_STATEID: + if (!xdr_FREE_STATEID4res(xdrs, + &objp->nfs_resop4_u.opfree_stateid)) + return (FALSE); + break; + case OP_GET_DIR_DELEGATION: + if (!xdr_GET_DIR_DELEGATION4res(xdrs, + &objp->nfs_resop4_u.opget_dir_delegation)) + return (FALSE); + break; + case OP_GETDEVICEINFO: + if (!xdr_GETDEVICEINFO4res(xdrs, + &objp->nfs_resop4_u.opgetdeviceinfo)) + return (FALSE); + break; + case OP_GETDEVICELIST: + if (!xdr_GETDEVICELIST4res(xdrs, + &objp->nfs_resop4_u.opgetdevicelist)) + return (FALSE); + break; + case OP_LAYOUTCOMMIT: + if (!xdr_LAYOUTCOMMIT4res(xdrs, + &objp->nfs_resop4_u.oplayoutcommit)) + return (FALSE); + break; + case OP_LAYOUTGET: + if (!xdr_LAYOUTGET4res(xdrs, + &objp->nfs_resop4_u.oplayoutget)) + return (FALSE); + break; + case OP_LAYOUTRETURN: + if (!xdr_LAYOUTRETURN4res(xdrs, + &objp->nfs_resop4_u.oplayoutreturn)) + return (FALSE); + break; + case OP_SECINFO_NO_NAME: + if (!xdr_SECINFO_NO_NAME4res(xdrs, + &objp->nfs_resop4_u.opsecinfo_no_name)) + return (FALSE); + break; + case OP_SEQUENCE: + if (!xdr_SEQUENCE4res(xdrs, + &objp->nfs_resop4_u.opsequence)) + return (FALSE); + break; + case OP_SET_SSV: + if (!xdr_SET_SSV4res(xdrs, + &objp->nfs_resop4_u.opset_ssv)) + return (FALSE); + break; + case OP_TEST_STATEID: + if (!xdr_TEST_STATEID4res(xdrs, + &objp->nfs_resop4_u.optest_stateid)) + return (FALSE); + break; + case OP_WANT_DELEGATION: + if (!xdr_WANT_DELEGATION4res(xdrs, + &objp->nfs_resop4_u.opwant_delegation)) + return (FALSE); + break; + case OP_DESTROY_CLIENTID: + if (!xdr_DESTROY_CLIENTID4res(xdrs, + &objp->nfs_resop4_u.opdestroy_clientid)) + return (FALSE); + break; + case OP_RECLAIM_COMPLETE: + if (!xdr_RECLAIM_COMPLETE4res(xdrs, + &objp->nfs_resop4_u.opreclaim_complete)) + return (FALSE); + break; + default: + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_layoutrecall_type4(XDR *xdrs, layoutrecall_type4 *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_layoutrecall_file4(XDR *xdrs, layoutrecall_file4 *objp) +{ + switch (xdrs->x_op) { + case XDR_ENCODE: + /* TODO: encode nfs4x_fh */ + return (FALSE); + + case XDR_DECODE: + if (!xdr_bytes(xdrs, (char **)&objp->lor_fh.nfs_fh4_val, + (uint_t *)&objp->lor_fh.nfs_fh4_len, NFS4_FHSIZE)) + return (FALSE); + break; + + case XDR_FREE: + if (objp->lor_fh.nfs_fh4_val != NULL) { + if (!xdr_bytes(xdrs, + (char **)&objp->lor_fh.nfs_fh4_val, + (uint_t *)&objp->lor_fh.nfs_fh4_len, + NFS4_FHSIZE)) + return (FALSE); + } + break; + } + + if (!xdr_offset4(xdrs, &objp->lor_offset)) + return (FALSE); + if (!xdr_length4(xdrs, &objp->lor_length)) + return (FALSE); + if (!xdr_stateid4(xdrs, &objp->lor_stateid)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_layoutrecall4(XDR *xdrs, layoutrecall4 *objp) +{ + if (!xdr_layoutrecall_type4(xdrs, &objp->lor_recalltype)) + return (FALSE); + switch (objp->lor_recalltype) { + case LAYOUTRECALL4_FILE: + if (!xdr_layoutrecall_file4(xdrs, + &objp->layoutrecall4_u.lor_layout)) + return (FALSE); + break; + case LAYOUTRECALL4_FSID: + if (!xdr_fsid4(xdrs, &objp->layoutrecall4_u.lor_fsid)) + return (FALSE); + break; + case LAYOUTRECALL4_ALL: + break; + default: + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_CB_LAYOUTRECALL4args(XDR *xdrs, CB_LAYOUTRECALL4args *objp) +{ + if (!xdr_layouttype4(xdrs, &objp->clora_type)) + return (FALSE); + if (!xdr_layoutiomode4(xdrs, &objp->clora_iomode)) + return (FALSE); + if (!xdr_bool(xdrs, &objp->clora_changed)) + return (FALSE); + if (!xdr_layoutrecall4(xdrs, &objp->clora_recall)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_LAYOUTRECALL4res(XDR *xdrs, CB_LAYOUTRECALL4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->clorr_status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_notify_type4(XDR *xdrs, notify_type4 *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_notify_entry4(XDR *xdrs, notify_entry4 *objp) +{ + if (!xdr_component4(xdrs, &objp->ne_file)) + return (FALSE); + if (!xdr_fattr4(xdrs, &objp->ne_attrs)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_prev_entry4(XDR *xdrs, prev_entry4 *objp) +{ + if (!xdr_notify_entry4(xdrs, &objp->pe_prev_entry)) + return (FALSE); + if (!xdr_nfs_cookie4(xdrs, &objp->pe_prev_entry_cookie)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_notify_remove4(XDR *xdrs, notify_remove4 *objp) +{ + + if (!xdr_notify_entry4(xdrs, &objp->nrm_old_entry)) + return (FALSE); + if (!xdr_nfs_cookie4(xdrs, &objp->nrm_old_entry_cookie)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_notify_add4(XDR *xdrs, notify_add4 *objp) +{ + if (!xdr_array(xdrs, (char **)&objp->nad_old_entry.nad_old_entry_val, + (uint_t *)&objp->nad_old_entry.nad_old_entry_len, 1, + sizeof (notify_remove4), (xdrproc_t)xdr_notify_remove4)) + return (FALSE); + if (!xdr_notify_entry4(xdrs, &objp->nad_new_entry)) + return (FALSE); + if (!xdr_array(xdrs, + (char **)&objp->nad_new_entry_cookie.nad_new_entry_cookie_val, + (uint_t *)&objp->nad_new_entry_cookie.nad_new_entry_cookie_len, 1, + sizeof (nfs_cookie4), (xdrproc_t)xdr_nfs_cookie4)) + return (FALSE); + if (!xdr_array(xdrs, (char **)&objp->nad_prev_entry.nad_prev_entry_val, + (uint_t *)&objp->nad_prev_entry.nad_prev_entry_len, 1, + sizeof (prev_entry4), (xdrproc_t)xdr_prev_entry4)) + return (FALSE); + if (!xdr_bool(xdrs, &objp->nad_last_entry)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_notify_attr4(XDR *xdrs, notify_attr4 *objp) +{ + if (!xdr_notify_entry4(xdrs, &objp->na_changed_entry)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_notify_rename4(XDR *xdrs, notify_rename4 *objp) +{ + if (!xdr_notify_remove4(xdrs, &objp->nrn_old_entry)) + return (FALSE); + if (!xdr_notify_add4(xdrs, &objp->nrn_new_entry)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_notify_verifier4(XDR *xdrs, notify_verifier4 *objp) +{ + if (!xdr_verifier4(xdrs, (verifier4 *)&objp->nv_old_cookieverf)) + return (FALSE); + if (!xdr_verifier4(xdrs, (verifier4 *)&objp->nv_new_cookieverf)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_notifylist4(XDR *xdrs, notifylist4 *objp) +{ + if (!xdr_bytes(xdrs, (char **)&objp->notifylist4_val, + (uint_t *)&objp->notifylist4_len, ~0)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_notify4(XDR *xdrs, notify4 *objp) +{ + if (xdrs->x_op == XDR_ENCODE) { + if (!xdr_bitmap4_notify(xdrs, &objp->notify_mask)) + return (FALSE); + } else + if (!xdr_bitmap4(xdrs, &objp->notify_mask)) + return (FALSE); + if (!xdr_notifylist4(xdrs, &objp->notify_vals)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_NOTIFY4args(XDR *xdrs, CB_NOTIFY4args *objp) +{ + if (!xdr_stateid4(xdrs, &objp->cna_stateid)) + return (FALSE); + if (!xdr_nfs_fh4(xdrs, &objp->cna_fh)) + return (FALSE); + if (!xdr_array(xdrs, (char **)&objp->cna_changes.cna_changes_val, + (uint_t *)&objp->cna_changes.cna_changes_len, ~0, + sizeof (notify4), (xdrproc_t)xdr_notify4)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_NOTIFY4res(XDR *xdrs, CB_NOTIFY4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->cnr_status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_PUSH_DELEG4args(XDR *xdrs, CB_PUSH_DELEG4args *objp) +{ + if (!xdr_nfs_fh4(xdrs, &objp->cpda_fh)) + return (FALSE); + if (!xdr_open_delegation4(xdrs, &objp->cpda_delegation)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_PUSH_DELEG4res(XDR *xdrs, CB_PUSH_DELEG4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->cpdr_status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_RECALL_ANY4args(XDR *xdrs, CB_RECALL_ANY4args *objp) +{ + if (!xdr_uint32_t(xdrs, &objp->craa_objects_to_keep)) + return (FALSE); + if (!xdr_bitmap4(xdrs, &objp->craa_type_mask)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_RECALL_ANY4res(XDR *xdrs, CB_RECALL_ANY4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->crar_status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_RECALLABLE_OBJ_AVAIL4args(XDR *xdrs, CB_RECALLABLE_OBJ_AVAIL4args *objp) +{ + if (!xdr_CB_RECALL_ANY4args(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_RECALLABLE_OBJ_AVAIL4res(XDR *xdrs, CB_RECALLABLE_OBJ_AVAIL4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->croa_status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_RECALL_SLOT4args(XDR *xdrs, CB_RECALL_SLOT4args *objp) +{ + if (!xdr_slotid4(xdrs, &objp->rsa_target_highest_slotid)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_RECALL_SLOT4res(XDR *xdrs, CB_RECALL_SLOT4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->rsr_status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_referring_call4(XDR *xdrs, referring_call4 *objp) +{ + if (!xdr_sequenceid4(xdrs, &objp->rc_sequenceid)) + return (FALSE); + if (!xdr_slotid4(xdrs, &objp->rc_slotid)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_referring_call_list4(XDR *xdrs, referring_call_list4 *objp) +{ + if (!xdr_sessionid4(xdrs, objp->rcl_sessionid)) + return (FALSE); + if (!xdr_array(xdrs, (char **)&objp->rcl_referring_calls. + rcl_referring_calls_val, + (uint_t *)&objp->rcl_referring_calls.rcl_referring_calls_len, ~0, + sizeof (referring_call4), (xdrproc_t)xdr_referring_call4)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_SEQUENCE4args(XDR *xdrs, CB_SEQUENCE4args *objp) +{ + if (!xdr_sessionid4(xdrs, objp->csa_sessionid)) + return (FALSE); + if (!xdr_sequenceid4(xdrs, &objp->csa_sequenceid)) + return (FALSE); + if (!xdr_slotid4(xdrs, &objp->csa_slotid)) + return (FALSE); + if (!xdr_slotid4(xdrs, &objp->csa_highest_slotid)) + return (FALSE); + if (!xdr_bool(xdrs, &objp->csa_cachethis)) + return (FALSE); + if (!xdr_array(xdrs, (char **)&objp->csa_referring_call_lists. + csa_referring_call_lists_val, + (uint_t *)&objp->csa_referring_call_lists. + csa_referring_call_lists_len, ~0, sizeof (referring_call_list4), + (xdrproc_t)xdr_referring_call_list4)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_SEQUENCE4resok(XDR *xdrs, CB_SEQUENCE4resok *objp) +{ + if (!xdr_sessionid4(xdrs, objp->csr_sessionid)) + return (FALSE); + if (!xdr_sequenceid4(xdrs, &objp->csr_sequenceid)) + return (FALSE); + if (!xdr_slotid4(xdrs, &objp->csr_slotid)) + return (FALSE); + if (!xdr_slotid4(xdrs, &objp->csr_highest_slotid)) + return (FALSE); + if (!xdr_slotid4(xdrs, &objp->csr_target_highest_slotid)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_SEQUENCE4res(XDR *xdrs, CB_SEQUENCE4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->csr_status)) + return (FALSE); + switch (objp->csr_status) { + case NFS4_OK: + if (!xdr_CB_SEQUENCE4resok(xdrs, + &objp->CB_SEQUENCE4res_u.csr_resok4)) + return (FALSE); + break; + } + return (TRUE); +} + +bool_t +xdr_CB_WANTS_CANCELLED4args(XDR *xdrs, CB_WANTS_CANCELLED4args *objp) +{ + if (!xdr_bool(xdrs, &objp->cwca_contended_wants_cancelled)) + return (FALSE); + if (!xdr_bool(xdrs, &objp->cwca_resourced_wants_cancelled)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_WANTS_CANCELLED4res(XDR *xdrs, CB_WANTS_CANCELLED4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->cwcr_status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_NOTIFY_LOCK4args(XDR *xdrs, CB_NOTIFY_LOCK4args *objp) +{ + if (!xdr_nfs_fh4(xdrs, &objp->cnla_fh)) + return (FALSE); + if (!xdr_lock_owner4(xdrs, &objp->cnla_lock_owner)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_NOTIFY_LOCK4res(XDR *xdrs, CB_NOTIFY_LOCK4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->cnlr_status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_notify_deviceid_type4(XDR *xdrs, notify_deviceid_type4 *objp) +{ + + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_notify_deviceid_delete4(XDR *xdrs, notify_deviceid_delete4 *objp) +{ + if (!xdr_layouttype4(xdrs, &objp->ndd_layouttype)) + return (FALSE); + if (!xdr_deviceid4(xdrs, objp->ndd_deviceid)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_notify_deviceid_change4(XDR *xdrs, notify_deviceid_change4 *objp) +{ + + if (!xdr_layouttype4(xdrs, &objp->ndc_layouttype)) + return (FALSE); + if (!xdr_deviceid4(xdrs, objp->ndc_deviceid)) + return (FALSE); + if (!xdr_bool(xdrs, &objp->ndc_immediate)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_NOTIFY_DEVICEID4args(XDR *xdrs, CB_NOTIFY_DEVICEID4args *objp) +{ + if (!xdr_array(xdrs, (char **)&objp->cnda_changes.cnda_changes_val, + (uint_t *)&objp->cnda_changes.cnda_changes_len, ~0, + sizeof (notify4), (xdrproc_t)xdr_notify4)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_NOTIFY_DEVICEID4res(XDR *xdrs, CB_NOTIFY_DEVICEID4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->cndr_status)) + return (FALSE); + return (TRUE); +} + +/* Callback operations new to NFSv4.1 */ + +bool_t +xdr_nfs_cb_argop4(XDR *xdrs, nfs_cb_argop4 *objp) +{ + /* argop has already been xdr'd */ + switch (objp->argop) { + case OP_CB_LAYOUTRECALL: + if (!xdr_CB_LAYOUTRECALL4args(xdrs, + &objp->nfs_cb_argop4_u.opcblayoutrecall)) + return (FALSE); + break; + case OP_CB_NOTIFY: + if (!xdr_CB_NOTIFY4args(xdrs, + &objp->nfs_cb_argop4_u.opcbnotify)) + return (FALSE); + break; + case OP_CB_PUSH_DELEG: + if (!xdr_CB_PUSH_DELEG4args(xdrs, + &objp->nfs_cb_argop4_u.opcbpush_deleg)) + return (FALSE); + break; + case OP_CB_RECALL_ANY: + if (!xdr_CB_RECALL_ANY4args(xdrs, + &objp->nfs_cb_argop4_u.opcbrecall_any)) + return (FALSE); + break; + case OP_CB_RECALLABLE_OBJ_AVAIL: + if (!xdr_CB_RECALLABLE_OBJ_AVAIL4args(xdrs, + &objp->nfs_cb_argop4_u.opcbrecallable_obj_avail)) + return (FALSE); + break; + case OP_CB_RECALL_SLOT: + if (!xdr_CB_RECALL_SLOT4args(xdrs, + &objp->nfs_cb_argop4_u.opcbrecall_slot)) + return (FALSE); + break; + case OP_CB_SEQUENCE: + if (!xdr_CB_SEQUENCE4args(xdrs, + &objp->nfs_cb_argop4_u.opcbsequence)) + return (FALSE); + break; + case OP_CB_WANTS_CANCELLED: + if (!xdr_CB_WANTS_CANCELLED4args(xdrs, + &objp->nfs_cb_argop4_u.opcbwants_cancelled)) + return (FALSE); + break; + case OP_CB_NOTIFY_LOCK: + if (!xdr_CB_NOTIFY_LOCK4args(xdrs, + &objp->nfs_cb_argop4_u.opcbnotify_lock)) + return (FALSE); + break; + case OP_CB_NOTIFY_DEVICEID: + if (!xdr_CB_NOTIFY_DEVICEID4args(xdrs, + &objp->nfs_cb_argop4_u.opcbnotify_deviceid)) + return (FALSE); + break; + default: + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_CB_GETATTR4res(XDR *xdrs, CB_GETATTR4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->status)) + return (FALSE); + + switch (objp->status) { + case NFS4_OK: + if (!xdr_fattr4(xdrs, &objp->obj_attributes)) + return (FALSE); + break; + } + return (TRUE); +} + +bool_t +xdr_CB_RECALL4res(XDR *xdrs, CB_RECALL4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_CB_ILLEGAL4res(XDR *xdrs, CB_ILLEGAL4res *objp) +{ + if (!xdr_nfsstat4(xdrs, &objp->status)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_nfs_cb_resop4(XDR *xdrs, nfs_cb_resop4 *objp) +{ + if (!xdr_u_int(xdrs, &objp->resop)) + return (FALSE); + + switch (objp->resop) { + case OP_CB_GETATTR: + if (!xdr_CB_GETATTR4res(xdrs, + &objp->nfs_cb_resop4_u.opcbgetattr)) + return (FALSE); + break; + case OP_CB_RECALL: + if (!xdr_CB_RECALL4res(xdrs, + &objp->nfs_cb_resop4_u.opcbrecall)) + return (FALSE); + break; + case OP_CB_LAYOUTRECALL: + if (!xdr_CB_LAYOUTRECALL4res(xdrs, + &objp->nfs_cb_resop4_u.opcblayoutrecall)) + return (FALSE); + break; + case OP_CB_NOTIFY: + if (!xdr_CB_NOTIFY4res(xdrs, + &objp->nfs_cb_resop4_u.opcbnotify)) + return (FALSE); + break; + case OP_CB_PUSH_DELEG: + if (!xdr_CB_PUSH_DELEG4res(xdrs, + &objp->nfs_cb_resop4_u.opcbpush_deleg)) + return (FALSE); + break; + case OP_CB_RECALL_ANY: + if (!xdr_CB_RECALL_ANY4res(xdrs, + &objp->nfs_cb_resop4_u.opcbrecall_any)) + return (FALSE); + break; + case OP_CB_RECALLABLE_OBJ_AVAIL: + if (!xdr_CB_RECALLABLE_OBJ_AVAIL4res(xdrs, + &objp->nfs_cb_resop4_u.opcbrecallable_obj_avail)) + return (FALSE); + break; + case OP_CB_RECALL_SLOT: + if (!xdr_CB_RECALL_SLOT4res(xdrs, + &objp->nfs_cb_resop4_u.opcbrecall_slot)) + return (FALSE); + break; + case OP_CB_SEQUENCE: + if (!xdr_CB_SEQUENCE4res(xdrs, + &objp->nfs_cb_resop4_u.opcbsequence)) + return (FALSE); + break; + case OP_CB_WANTS_CANCELLED: + if (!xdr_CB_WANTS_CANCELLED4res(xdrs, + &objp->nfs_cb_resop4_u.opcbwants_cancelled)) + return (FALSE); + break; + case OP_CB_NOTIFY_LOCK: + if (!xdr_CB_NOTIFY_LOCK4res(xdrs, + &objp->nfs_cb_resop4_u.opcbnotify_lock)) + return (FALSE); + break; + case OP_CB_NOTIFY_DEVICEID: + if (!xdr_CB_NOTIFY_DEVICEID4res(xdrs, + &objp->nfs_cb_resop4_u.opcbnotify_deviceid)) + return (FALSE); + break; + case OP_CB_ILLEGAL: + if (!xdr_CB_ILLEGAL4res(xdrs, + &objp->nfs_cb_resop4_u.opcbillegal)) + return (FALSE); + break; + default: + return (FALSE); + } + return (TRUE); +} + +/* + * Additional common NFSv4 XDR + */ + +bool_t +xdr_clientid4(XDR *xdrs, clientid4 *objp) +{ + if (!xdr_uint64_t(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_component4(XDR *xdrs, component4 *objp) +{ + if (!xdr_utf8string(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_count4(XDR *xdrs, count4 *objp) +{ + if (!xdr_uint32_t(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_fsid4(XDR *xdrs, fsid4 *objp) +{ + if (!xdr_uint64_t(xdrs, &objp->major)) + return (FALSE); + if (!xdr_uint64_t(xdrs, &objp->minor)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_length4(XDR *xdrs, length4 *objp) +{ + if (!xdr_uint64_t(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_limit_by4(XDR *xdrs, limit_by4 *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_lock_owner4(XDR *xdrs, lock_owner4 *objp) +{ + if (!xdr_clientid4(xdrs, &objp->clientid)) + return (FALSE); + if (!xdr_bytes(xdrs, (char **)&objp->owner_val, + (uint_t *)&objp->owner_len, NFS4_OPAQUE_LIMIT)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_mode4(XDR *xdrs, mode4 *objp) +{ + if (!xdr_uint32_t(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_netaddr4(XDR *xdrs, netaddr4 *objp) +{ + if (!xdr_string(xdrs, &objp->na_r_netid, ~0)) + return (FALSE); + if (!xdr_string(xdrs, &objp->na_r_addr, ~0)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_nfs_cookie4(XDR *xdrs, nfs_cookie4 *objp) +{ + if (!xdr_uint64_t(xdrs, objp)) + return (FALSE); + return (TRUE); +} + + +bool_t +xdr_nfs_modified_limit4(XDR *xdrs, nfs_modified_limit4 *objp) +{ + if (!xdr_uint32_t(xdrs, &objp->num_blocks)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->bytes_per_block)) + return (FALSE); + return (TRUE); +} + + +bool_t +xdr_nfs_space_limit4(XDR *xdrs, nfs_space_limit4 *objp) +{ + if (!xdr_limit_by4(xdrs, &objp->limitby)) + return (FALSE); + switch (objp->limitby) { + case NFS_LIMIT_SIZE: + if (!xdr_uint64_t(xdrs, &objp->nfs_space_limit4_u.filesize)) + return (FALSE); + break; + case NFS_LIMIT_BLOCKS: + if (!xdr_nfs_modified_limit4(xdrs, + &objp->nfs_space_limit4_u.mod_blocks)) + return (FALSE); + break; + default: + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_nfsstat4(XDR *xdrs, nfsstat4 *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_offset4(XDR *xdrs, offset4 *objp) +{ + if (!xdr_uint64_t(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_open_claim_type4(XDR *xdrs, open_claim_type4 *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_open_delegation_type4(XDR *xdrs, open_delegation_type4 *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_open_read_delegation4(XDR *xdrs, open_read_delegation4 *objp) +{ + if (!xdr_stateid4(xdrs, &objp->stateid)) + return (FALSE); + if (!xdr_bool(xdrs, &objp->recall)) + return (FALSE); + if (!xdr_nfsace4(xdrs, &objp->permissions)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_open_write_delegation4(XDR *xdrs, open_write_delegation4 *objp) +{ + if (!xdr_stateid4(xdrs, &objp->stateid)) + return (FALSE); + if (!xdr_bool(xdrs, &objp->recall)) + return (FALSE); + if (!xdr_nfs_space_limit4(xdrs, &objp->space_limit)) + return (FALSE); + if (!xdr_nfsace4(xdrs, &objp->permissions)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_pathname4(XDR *xdrs, pathname4 *objp) +{ + if (!xdr_array(xdrs, (char **)&objp->pathname4_val, + (uint_t *)&objp->pathname4_len, ~0, sizeof (component4), + (xdrproc_t)xdr_component4)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_sec_oid4(XDR *xdrs, sec_oid4 *objp) +{ + if (!xdr_bytes(xdrs, (char **)&objp->sec_oid4_val, + (uint_t *)&objp->sec_oid4_len, ~0)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_rpc_gss_svc_t(XDR *xdrs, rpc_gss_svc_t *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_stateid4(XDR *xdrs, stateid4 *objp) +{ + if (!xdr_uint32_t(xdrs, &objp->seqid)) + return (FALSE); + if (!xdr_opaque(xdrs, objp->other, 12)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_utf8str_cis(XDR *xdrs, utf8str_cis *objp) +{ + if (!xdr_utf8string(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_utf8str_cs(XDR *xdrs, utf8str_cs *objp) +{ + if (!xdr_utf8string(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +/* End of additional common NFSv4 XDR */ diff --git a/usr/src/uts/common/fs/nfs/nfs_server.c b/usr/src/uts/common/fs/nfs/nfs_server.c index b916f727d9..0071fe50c8 100644 --- a/usr/src/uts/common/fs/nfs/nfs_server.c +++ b/usr/src/uts/common/fs/nfs/nfs_server.c @@ -261,7 +261,6 @@ static SVC_CALLOUT_TABLE nfs_sct_rdma = { */ nvlist_t *rfs4_dss_paths, *rfs4_dss_oldpaths; -int rfs4_dispatch(struct rpcdisp *, struct svc_req *, SVCXPRT *, char *); bool_t rfs4_minorvers_mismatch(struct svc_req *, SVCXPRT *, void *); /* @@ -1056,13 +1055,13 @@ static struct rpcdisp rfsdisptab_v4[] = { */ /* RFS_NULL = 0 */ - {rpc_null, + {NULL, xdr_void, NULL_xdrproc_t, 0, xdr_void, NULL_xdrproc_t, 0, nullfree, RPC_IDEMPOTENT, 0}, /* RFS4_compound = 1 */ - {rfs4_compound, + {NULL, xdr_COMPOUND4args_srv, NULL_xdrproc_t, sizeof (COMPOUND4args), xdr_COMPOUND4res_srv, NULL_xdrproc_t, sizeof (COMPOUND4res), rfs4_compound_free, 0, 0}, diff --git a/usr/src/uts/common/fs/nfs/nfs_stats.c b/usr/src/uts/common/fs/nfs/nfs_stats.c index 97f820d756..6dc19f67d3 100644 --- a/usr/src/uts/common/fs/nfs/nfs_stats.c +++ b/usr/src/uts/common/fs/nfs/nfs_stats.c @@ -21,6 +21,8 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2020 RackTop Systems, Inc. */ #include <sys/types.h> @@ -417,6 +419,25 @@ static const kstat_named_t rfsproccnt_v4_tmpl[] = { { "verify", KSTAT_DATA_UINT64 }, { "write", KSTAT_DATA_UINT64 }, { "release_lockowner", KSTAT_DATA_UINT64 }, + { "backchannel_ctl", KSTAT_DATA_UINT64 }, + { "bind_conn_to_session", KSTAT_DATA_UINT64 }, + { "exchange_id", KSTAT_DATA_UINT64 }, + { "create_session", KSTAT_DATA_UINT64 }, + { "destroy_session", KSTAT_DATA_UINT64 }, + { "free_stateid", KSTAT_DATA_UINT64 }, + { "get_dir_delegation", KSTAT_DATA_UINT64 }, + { "getdeviceinfo", KSTAT_DATA_UINT64 }, + { "getdevicelist", KSTAT_DATA_UINT64 }, + { "layoutcommit", KSTAT_DATA_UINT64 }, + { "layoutget", KSTAT_DATA_UINT64 }, + { "layoutreturn", KSTAT_DATA_UINT64 }, + { "secinfo_no_name", KSTAT_DATA_UINT64 }, + { "sequence", KSTAT_DATA_UINT64 }, + { "set_ssv", KSTAT_DATA_UINT64 }, + { "test_stateid", KSTAT_DATA_UINT64 }, + { "want_delegation", KSTAT_DATA_UINT64 }, + { "destroy_clientid", KSTAT_DATA_UINT64 }, + { "reclaim_complete", KSTAT_DATA_UINT64 }, { "illegal", KSTAT_DATA_UINT64 }, }; diff --git a/usr/src/uts/common/fs/nfs/nfs_subr.c b/usr/src/uts/common/fs/nfs/nfs_subr.c index 68cd0df081..ee622988ab 100644 --- a/usr/src/uts/common/fs/nfs/nfs_subr.c +++ b/usr/src/uts/common/fs/nfs/nfs_subr.c @@ -5277,3 +5277,13 @@ do_xattr_exists_check(vnode_t *vp, ulong_t *valp, cred_t *cr) kmem_free(dbuf, dlen); return (0); } + +/* + * NFS specific function that returns time since + * system boot in seconds. + */ +time_t +nfs_sys_uptime(void) +{ + return (TICK_TO_SEC(ddi_get_lbolt())); +} diff --git a/usr/src/uts/common/nfs/Makefile b/usr/src/uts/common/nfs/Makefile index a40eaa9939..5d9d326368 100644 --- a/usr/src/uts/common/nfs/Makefile +++ b/usr/src/uts/common/nfs/Makefile @@ -33,7 +33,7 @@ HDRS= export.h lm.h \ nfs_clnt.h nfs_log.h nfs_sec.h nfs4.h \ nfs4_attr.h nfs4_clnt.h rnode.h rnode4.h \ nfs4_kprot.h nfs4_db_impl.h nfs4_idmap_impl.h \ - nfsid_map.h auth.h nfs_cmd.h + nfsid_map.h auth.h nfs_cmd.h nfs4x.h ROOTDIRS= $(ROOT)/usr/include/nfs diff --git a/usr/src/uts/common/nfs/nfs.h b/usr/src/uts/common/nfs/nfs.h index 6f76fc93ea..ace44d9dc6 100644 --- a/usr/src/uts/common/nfs/nfs.h +++ b/usr/src/uts/common/nfs/nfs.h @@ -2400,6 +2400,8 @@ extern mblk_t *rfs_read_alloc(uint_t, struct iovec **, int *); extern void rfs_rndup_mblks(mblk_t *, uint_t, int); extern void rfs_free_xuio(void *); +extern time_t nfs_sys_uptime(void); + #endif /* _KERNEL */ #ifdef __cplusplus diff --git a/usr/src/uts/common/nfs/nfs4.h b/usr/src/uts/common/nfs/nfs4.h index 48e6194d8a..f98f0ef77d 100644 --- a/usr/src/uts/common/nfs/nfs4.h +++ b/usr/src/uts/common/nfs/nfs4.h @@ -47,6 +47,7 @@ #include <nfs/nfs4_attr.h> #include <sys/acl.h> #include <sys/list.h> +#include <nfs/nfs4x.h> #ifdef __cplusplus extern "C" { @@ -76,6 +77,12 @@ typedef struct nfs4_fhandle { #define NFS4_MINORVERSION 0 #define CB4_MINORVERSION 0 +#define FIRST_NFS4_OP OP_ACCESS +#define LAST_NFS40_OP OP_RELEASE_LOCKOWNER +#define LAST_NFS41_OP OP_RECLAIM_COMPLETE +#define LAST_NFS42_OP OP_RECLAIM_COMPLETE +#define LAST_NFS4_OP LAST_NFS42_OP + /* * Set the fattr4_change variable using a time struct. Note that change * is 64 bits, but timestruc_t is 128 bits in a 64-bit kernel. @@ -238,14 +245,6 @@ typedef union { */ typedef enum {OPENID, LOCKID, DELEGID} stateid_type_t; - -/* - * Set of RPC credentials used for a particular operation. - * Used for operations like SETCLIENTID_CONFIRM where the - * credentials needs to match those used at SETCLIENTID. - */ -typedef void *cred_set_t; /* For now XXX */ - /* * "wait" struct for use in the open open and lock owner state * structures to provide serialization between server threads that are @@ -364,6 +363,7 @@ typedef struct rfs4_servinst { krwlock_t oldstate_lock; time_t start_time; time_t grace_period; + uint_t nreclaim; /* number reclaim clients */ rfs4_oldstate_t *oldstate; struct rfs4_dss_path **dss_paths; struct rfs4_servinst *next; @@ -513,6 +513,7 @@ typedef struct rfs4_client { unsigned rc_can_reclaim:1; unsigned rc_ss_remove:1; unsigned rc_forced_expire:1; + unsigned rc_reclaim_completed:1; uint_t rc_deleg_revoked; struct rfs4_client *rc_cp_confirmed; time_t rc_last_access; @@ -523,6 +524,12 @@ typedef struct rfs4_client { rfs4_ss_pn_t *rc_ss_pn; struct sockaddr_storage rc_addr; rfs4_servinst_t *rc_server_instance; + + /* nfsv4.1 */ + rfs41_csr_t rc_contrived; + rfs41_sprot_t rc_state_prot; + list_t rc_sessions; + unsigned rc_destroying:1; /* flag: going to destroy */ } rfs4_client_t; /* @@ -550,7 +557,6 @@ typedef struct rfs4_clntip { * state2confirm - what stateid4 should be used on the OPEN_CONFIRM * open_seqid - what is the next open_seqid expected for this openowner * oo_sw - used to serialize access to the open seqid/reply handling - * cr_set - credential used for the OPEN * statelist - root of state struct list associated with this openowner * node - node for client struct list of openowners * reply_fh - open replay processing needs the filehandle so that it is @@ -566,7 +572,6 @@ typedef struct rfs4_openowner { unsigned ro_postpone_confirm:1; seqid4 ro_open_seqid; rfs4_state_wait_t ro_sw; - cred_set_t ro_cr_set; list_t ro_statelist; list_node_t ro_node; nfs_fh4 ro_reply_fh; @@ -854,6 +859,11 @@ typedef struct nfs4_srv { rfs4_index_t *rfs4_deleg_idx; rfs4_index_t *rfs4_deleg_state_idx; + /* nfs4.x */ + krwlock_t findsession_lock; + rfs4_table_t *rfs4_session_tab; + rfs4_index_t *rfs4_session_idx; + /* client stable storage */ int rfs4_ss_enabled; } nfs4_srv_t; @@ -874,11 +884,10 @@ typedef struct rfs4_db_mem_cache { kmem_cache_t *r_db_mem_cache; } rfs4_db_mem_cache_t; -#define RFS4_DB_MEM_CACHE_NUM 8 +#define RFS4_DB_MEM_CACHE_NUM 9 extern rfs4_db_mem_cache_t rfs4_db_mem_cache_table[RFS4_DB_MEM_CACHE_NUM]; - extern srv_deleg_policy_t nfs4_get_deleg_policy(); extern void rfs4_servinst_create(nfs4_srv_t *, int, int, char **); @@ -963,12 +972,16 @@ extern nfsstat4 rfs4_get_deleg_state(stateid4 *, rfs4_deleg_state_t **); extern nfsstat4 rfs4_get_lo_state(stateid4 *, rfs4_lo_state_t **, bool_t); +struct compound_state; extern nfsstat4 rfs4_check_stateid(int, vnode_t *, stateid4 *, bool_t, bool_t *, bool_t, - caller_context_t *); -extern int rfs4_check_stateid_seqid(rfs4_state_t *, stateid4 *); + caller_context_t *, + struct compound_state *); +extern int rfs4_check_stateid_seqid(rfs4_state_t *, stateid4 *, + const struct compound_state *); extern int rfs4_check_lo_stateid_seqid(rfs4_lo_state_t *, - stateid4 *); + stateid4 *, + const struct compound_state *); /* return values for rfs4_check_stateid_seqid() */ #define NFS4_CHECK_STATEID_OKAY 1 @@ -1210,8 +1223,29 @@ struct compound_state { /* saved_vp != NULL */ struct svc_req *req; char fhbuf[NFS4_FHSIZE]; + + /* NFSv4.1 */ + uint8_t minorversion; /* NFS4 minor version */ + rfs4_session_t *sp; /* OP_SEQUENCE set it */ + slotid4 slotno; + rfs4_slot_t *slot; + rfs4_client_t *client; + uint16_t op_pos; + uint16_t op_len; /* number operations in compound req */ +#define RFS4_DISPATCH_DONE (1 << 0) + uint8_t cs_flags; + bool_t cachethis; + COMPOUND4res *cmpresp; }; +typedef struct compound_state compound_state_t; + +static inline bool_t +rfs4_has_session(const compound_state_t *cs) +{ + return (cs->slot != NULL); +} + /* * Conversion commands for nfsv4 server attr checking */ @@ -1237,6 +1271,7 @@ struct nfs4_svgetit_arg { /* (if rdattr_err) */ bool_t is_referral; /* because sometimes we tell lies */ bool_t mntdfid_set; + fattr4_mounted_on_fileid mounted_on_fileid; /* readdir op can always return */ @@ -1479,13 +1514,25 @@ extern stateid4 clnt_special1; #define CLNT_ISSPECIAL(id) (stateid4_cmp(id, &clnt_special0) || \ stateid4_cmp(id, &clnt_special1)) +/* State's functions */ +extern void rfs4_ss_clid(nfs4_srv_t *nsrv4, rfs4_client_t *); +extern void rfs4_ss_chkclid(nfs4_srv_t *nsrv4, rfs4_client_t *); + +/* Declarations for nfs4.x */ +nfsstat4 do_rfs4_op_secinfo(struct compound_state *, char *, SECINFO4res *); + /* * The NFS Version 4 service procedures. */ extern void rfs4_do_server_start(int, int, int); extern void rfs4_compound(COMPOUND4args *, COMPOUND4res *, - struct exportinfo *, struct svc_req *, cred_t *, int *); + compound_state_t *, struct svc_req *, int *); +extern void rfs4_init_compound_state(struct compound_state *); +extern void rfs4_fini_compound_state(struct compound_state *); + +struct rpcdisp; +extern int rfs4_dispatch(struct rpcdisp *, struct svc_req *, SVCXPRT *, char *); extern void rfs4_compound_free(COMPOUND4res *); extern void rfs4_compound_flagproc(COMPOUND4args *, int *); diff --git a/usr/src/uts/common/nfs/nfs4_attr.h b/usr/src/uts/common/nfs/nfs4_attr.h index 026a155abc..2b6b88ee41 100644 --- a/usr/src/uts/common/nfs/nfs4_attr.h +++ b/usr/src/uts/common/nfs/nfs4_attr.h @@ -94,6 +94,12 @@ extern "C" { #define FATTR4_TIME_MODIFY_SET_MASK (1ULL << (FATTR4_WORD1 + 22)) #define FATTR4_MOUNTED_ON_FILEID_MASK (1ULL << (FATTR4_WORD1 + 23)) +/* nfsv4.1 */ + +/* Overload to fit to 64-bits bitmap4 */ +#define FATTR4_SUPPATTR_EXCLCREAT_MASK_LOCAL (1ULL << (FATTR4_WORD1 + 24)) +#define FATTR4_SEC_LABEL_MASK_LOCAL (1ULL << (FATTR4_WORD1 + 25)) + /* * Common bitmap4 of file attributes to be gathered */ @@ -299,12 +305,20 @@ extern "C" { FATTR4_MOUNTED_ON_FILEID_MASK \ ) +/* nfsv4.1 */ +#define RFS4_SUPPATTR_EXCLCREAT ( \ + FATTR4_SIZE_MASK | \ + FATTR4_MODE_MASK | \ + FATTR4_ACL_MASK | \ + FATTR4_OWNER_MASK | \ + FATTR4_OWNER_GROUP_MASK | \ + FATTR4_TIME_ACCESS_SET_MASK) #define FATTR4_FSID_EQ(a, b) \ ((a)->major == (b)->major && (a)->minor == (b)->minor) #define NFS4_MAXNUM_BITWORDS 2 -#define NFS4_MAXNUM_ATTRS 56 +#define NFS4_MAXNUM_ATTRS 57 union nfs4_attr_u { fattr4_supported_attrs supported_attrs; @@ -363,6 +377,7 @@ union nfs4_attr_u { fattr4_time_modify time_modify; fattr4_time_modify_set time_modify_set; fattr4_mounted_on_fileid mounted_on_fileid; + fattr4_suppattr_exclcreat supp_exclcreat; }; /* diff --git a/usr/src/uts/common/nfs/nfs4_kprot.h b/usr/src/uts/common/nfs/nfs4_kprot.h index e3acc9b901..8311b0de3b 100644 --- a/usr/src/uts/common/nfs/nfs4_kprot.h +++ b/usr/src/uts/common/nfs/nfs4_kprot.h @@ -21,6 +21,7 @@ /* * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2020 RackTop Systems, Inc. */ /* @@ -33,7 +34,7 @@ /* * Kernel specific version. - * NFS Version 4 protocol definitions. From nfs4_prot.x rev 1.119. + * NFS Version 4 protocol definitions. From nfs4_prot.x RFC 5662 */ #ifdef __cplusplus @@ -46,6 +47,9 @@ extern "C" { #endif #include <sys/stream.h> +#include <rpc/auth_sys.h> +typedef struct authsys_parms authsys_parms; + #define NFS4_FHSIZE 128 #define NFS4_VERIFIER_SIZE 8 #define NFS4_OTHER_SIZE 12 @@ -61,6 +65,8 @@ extern "C" { #define NFS4_FATTR4_LIMIT 1048576 #define NFS4_DATA_LIMIT 134217728 +#define NFS4_SESSIONID_SIZE 16 + enum nfs_ftype4 { NF4REG = 1, NF4DIR = 2, @@ -140,7 +146,48 @@ enum nfsstat4 { NFS4ERR_DEADLOCK = 10045, NFS4ERR_FILE_OPEN = 10046, NFS4ERR_ADMIN_REVOKED = 10047, - NFS4ERR_CB_PATH_DOWN = 10048 + NFS4ERR_CB_PATH_DOWN = 10048, + NFS4ERR_BADIOMODE = 10049, /* nfsv4.1 */ + NFS4ERR_BADLAYOUT = 10050, + NFS4ERR_BAD_SESSION_DIGEST = 10051, + NFS4ERR_BADSESSION = 10052, + NFS4ERR_BADSLOT = 10053, + NFS4ERR_COMPLETE_ALREADY = 10054, + NFS4ERR_CONN_NOT_BOUND_TO_SESSION = 10055, + NFS4ERR_DELEG_ALREADY_WANTED = 10056, + NFS4ERR_BACK_CHAN_BUSY = 10057, + NFS4ERR_LAYOUTTRYLATER = 10058, + NFS4ERR_LAYOUTUNAVAILABLE = 10059, + NFS4ERR_NOMATCHING_LAYOUT = 10060, + NFS4ERR_RECALLCONFLICT = 10061, + NFS4ERR_UNKNOWN_LAYOUTTYPE = 10062, + NFS4ERR_SEQ_MISORDERED = 10063, + NFS4ERR_SEQUENCE_POS = 10064, + NFS4ERR_REQ_TOO_BIG = 10065, + NFS4ERR_REP_TOO_BIG = 10066, + NFS4ERR_REP_TOO_BIG_TO_CACHE = 10067, + NFS4ERR_RETRY_UNCACHED_REP = 10068, + NFS4ERR_UNSAFE_COMPOUND = 10069, + NFS4ERR_TOO_MANY_OPS = 10070, + NFS4ERR_OP_NOT_IN_SESSION = 10071, + NFS4ERR_HASH_ALG_UNSUPP = 10072, + NFS4ERR_CLIENTID_BUSY = 10074, + NFS4ERR_PNFS_IO_HOLE = 10075, + NFS4ERR_SEQ_FALSE_RETRY = 10076, + NFS4ERR_BAD_HIGH_SLOT = 10077, + NFS4ERR_DEADSESSION = 10078, + NFS4ERR_ENCR_ALG_UNSUPP = 10079, + NFS4ERR_PNFS_NO_LAYOUT = 10080, + NFS4ERR_NOT_ONLY_OP = 10081, + NFS4ERR_WRONG_CRED = 10082, + NFS4ERR_WRONG_TYPE = 10083, + NFS4ERR_DIRDELEG_UNAVAIL = 10084, + NFS4ERR_REJECT_DELEG = 10085, + NFS4ERR_RETURNCONFLICT = 10086, + NFS4ERR_DELEG_REVOKED = 10087, + + /* for internal use */ + NFS4ERR_REPLAY_CACHE = 30000 }; typedef enum nfsstat4 nfsstat4; @@ -149,6 +196,11 @@ typedef enum nfsstat4 nfsstat4; */ typedef uint64_t bitmap4; +typedef struct { + uint_t attrlist4_len; + char *attrlist4_val; +} attrlist4; + typedef uint64_t offset4; typedef uint32_t count4; @@ -161,6 +213,12 @@ typedef uint32_t nfs_lease4; typedef uint32_t seqid4; +typedef uint32_t sequenceid4; + +typedef char sessionid4[NFS4_SESSIONID_SIZE]; + +typedef uint32_t slotid4; + typedef struct { uint_t utf8string_len; char *utf8string_val; @@ -168,13 +226,17 @@ typedef struct { typedef utf8string component4; +typedef utf8string utf8str_cis; + +typedef utf8string utf8str_cs; + +typedef utf8string utf8str_mixed; + typedef struct { uint_t pathname4_len; component4 *pathname4_val; } pathname4; -typedef uint64_t nfs_lockid4; - typedef uint64_t nfs_cookie4; typedef struct { @@ -226,6 +288,12 @@ struct fsid4 { }; typedef struct fsid4 fsid4; +struct change_policy4 { + uint64_t cp_major; + uint64_t cp_minor; +}; +typedef struct change_policy4 change_policy4; + struct fs_location4 { uint_t server_len; utf8string *server_val; @@ -268,6 +336,8 @@ typedef uint32_t aceflag4; #define ACE4_SUCCESSFUL_ACCESS_ACE_FLAG 0x00000010 #define ACE4_FAILED_ACCESS_ACE_FLAG 0x00000020 #define ACE4_IDENTIFIER_GROUP 0x00000040 +#define ACE4_INHERITED_ACE 0x00000080 + /* * This defines all valid flag bits, as defined by RFC 7530. If * any additional flag bits are deemed part of the NFSv4 spec, @@ -295,6 +365,8 @@ typedef uint32_t acemask4; #define ACE4_DELETE_CHILD 0x00000040 #define ACE4_READ_ATTRIBUTES 0x00000080 #define ACE4_WRITE_ATTRIBUTES 0x00000100 +#define ACE4_WRITE_RETENTION 0x00000200 +#define ACE4_WRITE_RETENTION_HOLD 0x00000400 #define ACE4_DELETE 0x00010000 #define ACE4_READ_ACL 0x00020000 #define ACE4_WRITE_ACL 0x00040000 @@ -341,6 +413,21 @@ struct nfsace4 { utf8string who; }; typedef struct nfsace4 nfsace4; + +typedef uint32_t aclflag4; /* 4.1 */ +#define ACL4_AUTO_INHERIT 0x00000001 +#define ACL4_PROTECTED 0x00000002 +#define ACL4_DEFAULTED 0x00000004 + +struct nfsacl41 { /* 4.1 */ + aclflag4 na41_flag; + struct { + u_int na41_aces_len; + nfsace4 *na41_aces_val; + } na41_aces; +}; +typedef struct nfsacl41 nfsacl41; + #define MODE4_SUID 0x800 #define MODE4_SGID 0x400 #define MODE4_SVTX 0x200 @@ -354,6 +441,12 @@ typedef struct nfsace4 nfsace4; #define MODE4_WOTH 0x002 #define MODE4_XOTH 0x001 +struct mode_masked4 { /* 4.1 */ + mode4 mm_value_to_set; + mode4 mm_mask_bits; +}; +typedef struct mode_masked4 mode_masked4; + /* * ACL conversion helpers */ @@ -401,6 +494,206 @@ typedef struct specdata4 specdata4; #define FH4_VOL_MIGRATION 0x00000004 #define FH4_VOL_RENAME 0x00000008 +/* + * nfsv4.1 + */ +struct netaddr4 { + char *na_r_netid; + char *na_r_addr; +}; +typedef struct netaddr4 netaddr4; + +struct nfs_impl_id4 { + utf8str_cis nii_domain; + utf8str_cs nii_name; + nfstime4 nii_date; +}; +typedef struct nfs_impl_id4 nfs_impl_id4; + +struct stateid4 { + uint32_t seqid; + char other[NFS4_OTHER_SIZE]; +}; +typedef struct stateid4 stateid4; + +enum layouttype4 { + LAYOUT4_NFSV4_1_FILES = 0x1, + LAYOUT4_OSD2_OBJECTS = 0x2, + LAYOUT4_BLOCK_VOLUME = 0x3 +}; +typedef enum layouttype4 layouttype4; + +struct layout_content4 { + layouttype4 loc_type; + struct { + u_int loc_body_len; + char *loc_body_val; + } loc_body; +}; +typedef struct layout_content4 layout_content4; + +/* + * LAYOUT4_OSD2_OBJECTS loc_body description + * is in a separate .x file + */ + +/* + * LAYOUT4_BLOCK_VOLUME loc_body description + * is in a separate .x file + */ + +struct layouthint4 { + layouttype4 loh_type; + struct { + u_int loh_body_len; + char *loh_body_val; + } loh_body; +}; +typedef struct layouthint4 layouthint4; + +enum layoutiomode4 { + LAYOUTIOMODE4_READ = 1, + LAYOUTIOMODE4_RW = 2, + LAYOUTIOMODE4_ANY = 3 +}; +typedef enum layoutiomode4 layoutiomode4; + +struct layout4 { + offset4 lo_offset; + length4 lo_length; + layoutiomode4 lo_iomode; + layout_content4 lo_content; +}; +typedef struct layout4 layout4; +#define NFS4_DEVICEID4_SIZE 16 + +typedef char deviceid4[NFS4_DEVICEID4_SIZE]; + +struct device_addr4 { + layouttype4 da_layout_type; + struct { + u_int da_addr_body_len; + char *da_addr_body_val; + } da_addr_body; +}; +typedef struct device_addr4 device_addr4; + +struct layoutupdate4 { + layouttype4 lou_type; + struct { + u_int lou_body_len; + char *lou_body_val; + } lou_body; +}; +typedef struct layoutupdate4 layoutupdate4; + +#define LAYOUT4_RET_REC_FILE 1 +#define LAYOUT4_RET_REC_FSID 2 +#define LAYOUT4_RET_REC_ALL 3 + +enum layoutreturn_type4 { + LAYOUTRETURN4_FILE = LAYOUT4_RET_REC_FILE, + LAYOUTRETURN4_FSID = LAYOUT4_RET_REC_FSID, + LAYOUTRETURN4_ALL = LAYOUT4_RET_REC_ALL +}; +typedef enum layoutreturn_type4 layoutreturn_type4; + +/* layouttype4 specific data */ + +struct layoutreturn_file4 { + offset4 lrf_offset; + length4 lrf_length; + stateid4 lrf_stateid; + struct { + u_int lrf_body_len; + char *lrf_body_val; + } lrf_body; +}; +typedef struct layoutreturn_file4 layoutreturn_file4; + +struct layoutreturn4 { + layoutreturn_type4 lr_returntype; + union { + layoutreturn_file4 lr_layout; + } layoutreturn4_u; +}; +typedef struct layoutreturn4 layoutreturn4; + +enum fs4_status_type { + STATUS4_FIXED = 1, + STATUS4_UPDATED = 2, + STATUS4_VERSIONED = 3, + STATUS4_WRITABLE = 4, + STATUS4_REFERRAL = 5 +}; +typedef enum fs4_status_type fs4_status_type; + +struct fs4_status { + bool_t fss_absent; + fs4_status_type fss_type; + utf8str_cs fss_source; + utf8str_cs fss_current; + int32_t fss_age; + nfstime4 fss_version; +}; +typedef struct fs4_status fs4_status; + +#define TH4_READ_SIZE 0 +#define TH4_WRITE_SIZE 1 +#define TH4_READ_IOSIZE 2 +#define TH4_WRITE_IOSIZE 3 + +typedef length4 threshold4_read_size; + +typedef length4 threshold4_write_size; + +typedef length4 threshold4_read_iosize; + +typedef length4 threshold4_write_iosize; + +struct threshold_item4 { + layouttype4 thi_layout_type; + bitmap4 thi_hintset; + struct { + u_int thi_hintlist_len; + char *thi_hintlist_val; + } thi_hintlist; +}; +typedef struct threshold_item4 threshold_item4; + +struct mdsthreshold4 { + struct { + u_int mth_hints_len; + threshold_item4 *mth_hints_val; + } mth_hints; +}; +typedef struct mdsthreshold4 mdsthreshold4; +#define RET4_DURATION_INFINITE 0xffffffffffffffff + +struct retention_get4 { + uint64_t rg_duration; + struct { + u_int rg_begin_time_len; + nfstime4 *rg_begin_time_val; + } rg_begin_time; +}; +typedef struct retention_get4 retention_get4; + +struct retention_set4 { + bool_t rs_enable; + struct { + u_int rs_duration_len; + uint64_t *rs_duration_val; + } rs_duration; +}; +typedef struct retention_set4 retention_set4; +#define FSCHARSET_CAP4_CONTAINS_NON_UTF8 0x1 +#define FSCHARSET_CAP4_ALLOWS_ONLY_UTF8 0x2 + +typedef uint32_t fs_charset_cap4; + +/* nfsv4.1 end */ + typedef bitmap4 fattr4_supported_attrs; typedef nfs_ftype4 fattr4_type; @@ -472,6 +765,8 @@ typedef ascii_REQUIRED4 fattr4_mimetype; typedef mode4 fattr4_mode; +typedef mode_masked4 fattr4_mode_set_masked; + typedef uint64_t fattr4_mounted_on_fileid; typedef bool_t fattr4_no_trunc; @@ -515,6 +810,57 @@ typedef nfstime4 fattr4_time_metadata; typedef nfstime4 fattr4_time_modify; typedef settime4 fattr4_time_modify_set; + +/* nfsv4.1 */ +typedef bitmap4 fattr4_suppattr_exclcreat; + +typedef nfstime4 fattr4_dir_notif_delay; + +typedef nfstime4 fattr4_dirent_notif_delay; + +typedef struct { + u_int fattr4_fs_layout_types_len; + layouttype4 *fattr4_fs_layout_types_val; +} fattr4_fs_layout_types; + +typedef fs4_status fattr4_fs_status; + +typedef fs_charset_cap4 fattr4_fs_charset_cap; + +typedef uint32_t fattr4_layout_alignment; + +typedef uint32_t fattr4_layout_blksize; + +typedef layouthint4 fattr4_layout_hint; + +typedef struct { + u_int fattr4_layout_types_len; + layouttype4 *fattr4_layout_types_val; +} fattr4_layout_types; + +typedef mdsthreshold4 fattr4_mdsthreshold; + +typedef retention_get4 fattr4_retention_get; + +typedef retention_set4 fattr4_retention_set; + +typedef retention_get4 fattr4_retentevt_get; + +typedef retention_set4 fattr4_retentevt_set; + +typedef uint64_t fattr4_retention_hold; + +typedef nfsacl41 fattr4_dacl; + +typedef nfsacl41 fattr4_sacl; + +typedef change_policy4 fattr4_change_policy; + +/* nfsv4.1 end */ + +/* + * REQUIRED Attributes + */ #define FATTR4_SUPPORTED_ATTRS 0 #define FATTR4_TYPE 1 #define FATTR4_FH_EXPIRE_TYPE 2 @@ -528,6 +874,12 @@ typedef settime4 fattr4_time_modify_set; #define FATTR4_LEASE_TIME 10 #define FATTR4_RDATTR_ERROR 11 #define FATTR4_FILEHANDLE 19 +/* new to NFSV4.1 */ +#define FATTR4_SUPPATTR_EXCLCREAT 75 + +/* + * RECOMMENDED Attributes + */ #define FATTR4_ACL 12 #define FATTR4_ACLSUPPORT 13 #define FATTR4_ARCHIVE 14 @@ -572,6 +924,32 @@ typedef settime4 fattr4_time_modify_set; #define FATTR4_TIME_MODIFY_SET 54 #define FATTR4_MOUNTED_ON_FILEID 55 +/* new to NFSV4.1 */ +#define FATTR4_DIR_NOTIF_DELAY 56 +#define FATTR4_DIRENT_NOTIF_DELAY 57 +#define FATTR4_DACL 58 +#define FATTR4_SACL 59 +#define FATTR4_CHANGE_POLICY 60 +#define FATTR4_FS_STATUS 61 +#define FATTR4_FS_LAYOUT_TYPES 62 +#define FATTR4_LAYOUT_HINT 63 +#define FATTR4_LAYOUT_TYPES 64 +#define FATTR4_LAYOUT_BLKSIZE 65 +#define FATTR4_LAYOUT_ALIGNMENT 66 +#define FATTR4_FS_LOCATIONS_INFO 67 +#define FATTR4_MDSTHRESHOLD 68 +#define FATTR4_RETENTION_GET 69 +#define FATTR4_RETENTION_SET 70 +#define FATTR4_RETENTEVT_GET 71 +#define FATTR4_RETENTEVT_SET 72 +#define FATTR4_RETENTION_HOLD 73 +#define FATTR4_MODE_SET_MASKED 74 +#define FATTR4_SUPPATTR_EXCLCREAT 75 +#define FATTR4_FS_CHARSET_CAP 76 + +/* new to NFSv4.2 */ +#define FATTR4_SEC_LABEL 80 + struct fattr4 { bitmap4 attrmask; char *attrlist4; @@ -598,12 +976,6 @@ struct cb_client4 { }; typedef struct cb_client4 cb_client4; -struct stateid4 { - uint32_t seqid; - char other[NFS4_OTHER_SIZE]; -}; -typedef struct stateid4 stateid4; - struct nfs_client_id4 { verifier4 verifier; uint_t id_len; @@ -612,6 +984,33 @@ struct nfs_client_id4 { }; typedef struct nfs_client_id4 nfs_client_id4; +struct client_owner4 { + verifier4 co_verifier; + struct { + u_int co_ownerid_len; + char *co_ownerid_val; + } co_ownerid; +}; +typedef struct client_owner4 client_owner4; + +struct server_owner4 { + uint64_t so_minor_id; + struct { + u_int so_major_id_len; + char *so_major_id_val; + } so_major_id; +}; +typedef struct server_owner4 server_owner4; + +struct state_owner4 { + clientid4 clientid; + struct { + uint_t owner_len; + char *owner_val; + } owner; +}; +typedef struct state_owner4 state_owner4; + struct open_owner4 { clientid4 clientid; uint_t owner_len; @@ -633,6 +1032,207 @@ enum nfs_lock_type4 { WRITEW_LT = 4 }; typedef enum nfs_lock_type4 nfs_lock_type4; + +/* + * nfsv4.1 + */ + +/* Input for computing subkeys */ + +enum ssv_subkey4 { + SSV4_SUBKEY_MIC_I2T = 1, + SSV4_SUBKEY_MIC_T2I = 2, + SSV4_SUBKEY_SEAL_I2T = 3, + SSV4_SUBKEY_SEAL_T2I = 4 +}; +typedef enum ssv_subkey4 ssv_subkey4; + +/* Input for computing smt_hmac */ + +struct ssv_mic_plain_tkn4 { + uint32_t smpt_ssv_seq; + struct { + u_int smpt_orig_plain_len; + char *smpt_orig_plain_val; + } smpt_orig_plain; +}; +typedef struct ssv_mic_plain_tkn4 ssv_mic_plain_tkn4; + +/* SSV GSS PerMsgToken token */ + +struct ssv_mic_tkn4 { + uint32_t smt_ssv_seq; + struct { + u_int smt_hmac_len; + char *smt_hmac_val; + } smt_hmac; +}; +typedef struct ssv_mic_tkn4 ssv_mic_tkn4; + +/* Input for computing ssct_encr_data and ssct_hmac */ + +struct ssv_seal_plain_tkn4 { + struct { + u_int sspt_confounder_len; + char *sspt_confounder_val; + } sspt_confounder; + uint32_t sspt_ssv_seq; + struct { + u_int sspt_orig_plain_len; + char *sspt_orig_plain_val; + } sspt_orig_plain; + struct { + u_int sspt_pad_len; + char *sspt_pad_val; + } sspt_pad; +}; +typedef struct ssv_seal_plain_tkn4 ssv_seal_plain_tkn4; + +/* SSV GSS SealedMessage token */ + +struct ssv_seal_cipher_tkn4 { + uint32_t ssct_ssv_seq; + struct { + u_int ssct_iv_len; + char *ssct_iv_val; + } ssct_iv; + struct { + u_int ssct_encr_data_len; + char *ssct_encr_data_val; + } ssct_encr_data; + struct { + u_int ssct_hmac_len; + char *ssct_hmac_val; + } ssct_hmac; +}; +typedef struct ssv_seal_cipher_tkn4 ssv_seal_cipher_tkn4; + +struct fs_locations_server4 { + int32_t fls_currency; + struct { + u_int fls_info_len; + char *fls_info_val; + } fls_info; + utf8str_cis fls_server; +}; +typedef struct fs_locations_server4 fs_locations_server4; +#define FSLI4BX_GFLAGS 0 +#define FSLI4BX_TFLAGS 1 +#define FSLI4BX_CLSIMUL 2 +#define FSLI4BX_CLHANDLE 3 +#define FSLI4BX_CLFILEID 4 +#define FSLI4BX_CLWRITEVER 5 +#define FSLI4BX_CLCHANGE 6 +#define FSLI4BX_CLREADDIR 7 +#define FSLI4BX_READRANK 8 +#define FSLI4BX_WRITERANK 9 +#define FSLI4BX_READORDER 10 +#define FSLI4BX_WRITEORDER 11 +#define FSLI4GF_WRITABLE 0x01 +#define FSLI4GF_CUR_REQ 0x02 +#define FSLI4GF_ABSENT 0x04 +#define FSLI4GF_GOING 0x08 +#define FSLI4GF_SPLIT 0x10 +#define FSLI4TF_RDMA 0x01 + +struct fs_locations_item4 { + struct { + u_int fli_entries_len; + fs_locations_server4 *fli_entries_val; + } fli_entries; + pathname4 fli_rootpath; +}; +typedef struct fs_locations_item4 fs_locations_item4; + +struct fs_locations_info4 { + uint32_t fli_flags; + int32_t fli_valid_for; + pathname4 fli_fs_root; + struct { + u_int fli_items_len; + fs_locations_item4 *fli_items_val; + } fli_items; +}; +typedef struct fs_locations_info4 fs_locations_info4; +#define FSLI4IF_VAR_SUB 0x00000001 + +typedef fs_locations_info4 fattr4_fs_locations_info; +#define NFL4_UFLG_MASK 0x0000003F +#define NFL4_UFLG_DENSE 0x00000001 +#define NFL4_UFLG_COMMIT_THRU_MDS 0x00000002 +#define NFL4_UFLG_STRIPE_UNIT_SIZE_MASK 0xFFFFFFC0 + +typedef uint32_t nfl_util4; + +enum filelayout_hint_care4 { + NFLH4_CARE_DENSE = NFL4_UFLG_DENSE, + NFLH4_CARE_COMMIT_THRU_MDS = NFL4_UFLG_COMMIT_THRU_MDS, + NFLH4_CARE_STRIPE_UNIT_SIZE = 0x00000040, + NFLH4_CARE_STRIPE_COUNT = 0x00000080 +}; +typedef enum filelayout_hint_care4 filelayout_hint_care4; + +/* Encoded in the loh_body field of data type layouthint4: */ + +struct nfsv4_1_file_layouthint4 { + uint32_t nflh_care; + nfl_util4 nflh_util; + count4 nflh_stripe_count; +}; +typedef struct nfsv4_1_file_layouthint4 nfsv4_1_file_layouthint4; + +typedef struct { + u_int multipath_list4_len; + netaddr4 *multipath_list4_val; +} multipath_list4; + +/* + * Encoded in the da_addr_body field of + * data type device_addr4: + */ + +struct nfsv4_1_file_layout_ds_addr4 { + struct { + u_int nflda_stripe_indices_len; + uint32_t *nflda_stripe_indices_val; + } nflda_stripe_indices; + struct { + u_int nflda_multipath_ds_list_len; + multipath_list4 *nflda_multipath_ds_list_val; + } nflda_multipath_ds_list; +}; +typedef struct nfsv4_1_file_layout_ds_addr4 nfsv4_1_file_layout_ds_addr4; + +/* + * Encoded in the loc_body field of + * data type layout_content4: + */ + +struct nfsv4_1_file_layout4 { + deviceid4 nfl_deviceid; + nfl_util4 nfl_util; + uint32_t nfl_first_stripe_index; + offset4 nfl_pattern_offset; + struct { + u_int nfl_fh_list_len; + nfs_fh4 *nfl_fh_list_val; + } nfl_fh_list; +}; +typedef struct nfsv4_1_file_layout4 nfsv4_1_file_layout4; + +/* + * Encoded in the lou_body field of data type layoutupdate4: + * Nothing. lou_body is a zero length array of bytes. + */ + +/* + * Encoded in the lrf_body field of + * data type layoutreturn_file4: + * Nothing. lrf_body is a zero length array of bytes. + */ + +/* nfsv4.1 end */ + #define ACCESS4_READ 0x00000001 #define ACCESS4_LOOKUP 0x00000002 #define ACCESS4_MODIFY 0x00000004 @@ -892,16 +1492,41 @@ typedef struct NVERIFY4res NVERIFY4res; enum createmode4 { UNCHECKED4 = 0, GUARDED4 = 1, - EXCLUSIVE4 = 2 + EXCLUSIVE4 = 2, + EXCLUSIVE4_1 = 3 }; typedef enum createmode4 createmode4; +struct creatverfattr { + verifier4 cva_verf; + fattr4 cva_attrs; +}; +typedef struct creatverfattr creatverfattr; + +struct createhow4 { + createmode4 mode; + union { + fattr4 createattrs; + verifier4 createverf; + creatverfattr ch_createboth; + } createhow4_u; +}; +typedef struct createhow4 createhow4; + enum opentype4 { OPEN4_NOCREATE = 0, OPEN4_CREATE = 1 }; typedef enum opentype4 opentype4; +struct openflag4 { + opentype4 opentype; + union { + createhow4 how; + } openflag4_u; +}; +typedef struct openflag4 openflag4; + enum limit_by4 { NFS_LIMIT_SIZE = 1, NFS_LIMIT_BLOCKS = 2 @@ -922,6 +1547,8 @@ struct nfs_space_limit4 { } nfs_space_limit4_u; }; typedef struct nfs_space_limit4 nfs_space_limit4; + +#define OPEN4_SHARE_ACCESS_MASK 0x00FF #define OPEN4_SHARE_ACCESS_READ 0x00000001 #define OPEN4_SHARE_ACCESS_WRITE 0x00000002 #define OPEN4_SHARE_ACCESS_BOTH 0x00000003 @@ -929,11 +1556,24 @@ typedef struct nfs_space_limit4 nfs_space_limit4; #define OPEN4_SHARE_DENY_READ 0x00000001 #define OPEN4_SHARE_DENY_WRITE 0x00000002 #define OPEN4_SHARE_DENY_BOTH 0x00000003 +/* nfsv4.1 */ +#define OPEN4_SHARE_WANT_MASK 0xFF00 +#define OPEN4_SHARE_WANT_NO_PREFERENCE 0x0000 +#define OPEN4_SHARE_WANT_READ_DELEG 0x0100 +#define OPEN4_SHARE_WANT_WRITE_DELEG 0x0200 +#define OPEN4_SHARE_WANT_ANY_DELEG 0x0300 +#define OPEN4_SHARE_WANT_NO_DELEG 0x0400 +#define OPEN4_SHARE_WANT_CANCEL 0x0500 + +#define OPEN4_SHARE_WHEN_MASK 0xF0000 +#define OPEN4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL 0x10000 +#define OPEN4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED 0x20000 enum open_delegation_type4 { OPEN_DELEGATE_NONE = 0, OPEN_DELEGATE_READ = 1, - OPEN_DELEGATE_WRITE = 2 + OPEN_DELEGATE_WRITE = 2, + OPEN_DELEGATE_NONE_EXT = 3 }; typedef enum open_delegation_type4 open_delegation_type4; @@ -941,7 +1581,10 @@ enum open_claim_type4 { CLAIM_NULL = 0, CLAIM_PREVIOUS = 1, CLAIM_DELEGATE_CUR = 2, - CLAIM_DELEGATE_PREV = 3 + CLAIM_DELEGATE_PREV = 3, + CLAIM_FH = 4, + CLAIM_DELEG_CUR_FH = 5, + CLAIM_DELEG_PREV_FH = 6 }; typedef enum open_claim_type4 open_claim_type4; @@ -957,9 +1600,22 @@ struct copen_claim_delegate_cur4 { }; typedef struct copen_claim_delegate_cur4 copen_claim_delegate_cur4; +struct open_claim4 { + open_claim_type4 claim; + union { + component4 file; + open_delegation_type4 delegate_type; + open_claim_delegate_cur4 delegate_cur_info; + component4 file_delegate_prev; + stateid4 oc_delegate_stateid; + } open_claim4_u; +}; +typedef struct open_claim4 open_claim4; + struct OPEN4args { seqid4 seqid; uint32_t share_access; + uint32_t deleg_want; /* nfsv4.1 */ uint32_t share_deny; open_owner4 owner; opentype4 opentype; @@ -967,14 +1623,9 @@ struct OPEN4args { union { fattr4 createattrs; verifier4 createverf; + creatverfattr ch_createboth; /* for nfsv4.1 */ } createhow4_u; - open_claim_type4 claim; - union { - component4 file; - open_delegation_type4 delegate_type; - open_claim_delegate_cur4 delegate_cur_info; - component4 file_delegate_prev; - } open_claim4_u; + open_claim4 claim; }; typedef struct OPEN4args OPEN4args; @@ -1014,16 +1665,44 @@ struct open_write_delegation4 { }; typedef struct open_write_delegation4 open_write_delegation4; +/* nfsv4.1 */ +enum why_no_delegation4 { + WND4_NOT_WANTED = 0, + WND4_CONTENTION = 1, + WND4_RESOURCE = 2, + WND4_NOT_SUPP_FTYPE = 3, + WND4_WRITE_DELEG_NOT_SUPP_FTYPE = 4, + WND4_NOT_SUPP_UPGRADE = 5, + WND4_NOT_SUPP_DOWNGRADE = 6, + WND4_CANCELLED = 7, + WND4_IS_DIR = 8 +}; +typedef enum why_no_delegation4 why_no_delegation4; + +struct open_none_delegation4 { + why_no_delegation4 ond_why; + union { + bool_t ond_server_will_push_deleg; + bool_t ond_server_will_signal_avail; + } open_none_delegation4_u; +}; +typedef struct open_none_delegation4 open_none_delegation4; + +/* nfsv4.1 end */ + struct open_delegation4 { open_delegation_type4 delegation_type; union { open_read_delegation4 read; open_write_delegation4 write; + open_none_delegation4 od_whynone; /* nfsv4.1 */ } open_delegation4_u; }; typedef struct open_delegation4 open_delegation4; #define OPEN4_RESULT_CONFIRM 0x00000002 #define OPEN4_RESULT_LOCKTYPE_POSIX 0x00000004 +#define OPEN4_RESULT_PRESERVE_UNLINKED 0x00000008 /* nfsv4.1 */ +#define OPEN4_RESULT_MAY_NOTIFY_LOCK 0x00000020 /* nfsv4.1 */ struct OPEN4res { nfsstat4 status; @@ -1061,6 +1740,7 @@ struct OPEN_DOWNGRADE4args { stateid4 open_stateid; seqid4 seqid; uint32_t share_access; + uint32_t deleg_want; /* nfsv4.1 */ uint32_t share_deny; }; typedef struct OPEN_DOWNGRADE4args OPEN_DOWNGRADE4args; @@ -1365,6 +2045,616 @@ struct ILLEGAL4res { }; typedef struct ILLEGAL4res ILLEGAL4res; +/* + * New operations for nfsv4.1 + */ +typedef struct { + u_int gsshandle4_t_len; + char *gsshandle4_t_val; +} gsshandle4_t; + +struct gss_cb_handles4 { + rpc_gss_svc_t gcbp_service; + gsshandle4_t gcbp_handle_from_server; + gsshandle4_t gcbp_handle_from_client; +}; +typedef struct gss_cb_handles4 gss_cb_handles4; + +struct callback_sec_parms4 { + uint32_t cb_secflavor; + union { + authsys_parms cbsp_sys_cred; + gss_cb_handles4 cbsp_gss_handles; + } callback_sec_parms4_u; +}; +typedef struct callback_sec_parms4 callback_sec_parms4; + +struct BACKCHANNEL_CTL4args { + uint32_t bca_cb_program; + struct { + u_int bca_sec_parms_len; + callback_sec_parms4 *bca_sec_parms_val; + } bca_sec_parms; +}; +typedef struct BACKCHANNEL_CTL4args BACKCHANNEL_CTL4args; + +struct BACKCHANNEL_CTL4res { + nfsstat4 bcr_status; +}; +typedef struct BACKCHANNEL_CTL4res BACKCHANNEL_CTL4res; + +enum channel_dir_from_client4 { + CDFC4_FORE = 0x1, + CDFC4_BACK = 0x2, + CDFC4_FORE_OR_BOTH = 0x3, + CDFC4_BACK_OR_BOTH = 0x7 +}; +typedef enum channel_dir_from_client4 channel_dir_from_client4; + +struct BIND_CONN_TO_SESSION4args { + sessionid4 bctsa_sessid; + channel_dir_from_client4 bctsa_dir; + bool_t bctsa_use_conn_in_rdma_mode; +}; +typedef struct BIND_CONN_TO_SESSION4args BIND_CONN_TO_SESSION4args; + +enum channel_dir_from_server4 { + CDFS4_FORE = 0x1, + CDFS4_BACK = 0x2, + CDFS4_BOTH = 0x3 +}; +typedef enum channel_dir_from_server4 channel_dir_from_server4; + +struct BIND_CONN_TO_SESSION4resok { + sessionid4 bctsr_sessid; + channel_dir_from_server4 bctsr_dir; + bool_t bctsr_use_conn_in_rdma_mode; +}; +typedef struct BIND_CONN_TO_SESSION4resok BIND_CONN_TO_SESSION4resok; + +struct BIND_CONN_TO_SESSION4res { + nfsstat4 bctsr_status; + union { + BIND_CONN_TO_SESSION4resok bctsr_resok4; + } BIND_CONN_TO_SESSION4res_u; +}; +typedef struct BIND_CONN_TO_SESSION4res BIND_CONN_TO_SESSION4res; + +#define EXCHGID4_FLAG_SUPP_MOVED_REFER 0x00000001 +#define EXCHGID4_FLAG_SUPP_MOVED_MIGR 0x00000002 +#define EXCHGID4_FLAG_BIND_PRINC_STATEID 0x00000100 + +#define EXCHGID4_FLAG_USE_NON_PNFS 0x00010000 +#define EXCHGID4_FLAG_USE_PNFS_MDS 0x00020000 +#define EXCHGID4_FLAG_USE_PNFS_DS 0x00040000 +#define EXCHGID4_FLAG_MASK_PNFS 0x00070000 + +#define EXCHGID4_FLAG_UPD_CONFIRMED_REC_A 0x40000000 +#define EXCHGID4_FLAG_CONFIRMED_R 0x80000000 + +#define EXID4_FLAG_MASK 0x40070103 + +struct state_protect_ops4 { + bitmap4 spo_must_enforce; + bitmap4 spo_must_allow; +}; +typedef struct state_protect_ops4 state_protect_ops4; + +struct ssv_sp_parms4 { + state_protect_ops4 ssp_ops; + struct { + u_int ssp_hash_algs_len; + sec_oid4 *ssp_hash_algs_val; + } ssp_hash_algs; + struct { + u_int ssp_encr_algs_len; + sec_oid4 *ssp_encr_algs_val; + } ssp_encr_algs; + uint32_t ssp_window; + uint32_t ssp_num_gss_handles; +}; +typedef struct ssv_sp_parms4 ssv_sp_parms4; + +enum state_protect_how4 { + SP4_NONE = 0, + SP4_MACH_CRED = 1, + SP4_SSV = 2 +}; +typedef enum state_protect_how4 state_protect_how4; + +struct state_protect4_a { + state_protect_how4 spa_how; + union { + state_protect_ops4 spa_mach_ops; + ssv_sp_parms4 spa_ssv_parms; + } state_protect4_a_u; +}; +typedef struct state_protect4_a state_protect4_a; + +struct EXCHANGE_ID4args { + client_owner4 eia_clientowner; + uint32_t eia_flags; + state_protect4_a eia_state_protect; + struct { + u_int eia_client_impl_id_len; + nfs_impl_id4 *eia_client_impl_id_val; + } eia_client_impl_id; +}; +typedef struct EXCHANGE_ID4args EXCHANGE_ID4args; + +struct ssv_prot_info4 { + state_protect_ops4 spi_ops; + uint32_t spi_hash_alg; + uint32_t spi_encr_alg; + uint32_t spi_ssv_len; + uint32_t spi_window; + struct { + u_int spi_handles_len; + gsshandle4_t *spi_handles_val; + } spi_handles; +}; +typedef struct ssv_prot_info4 ssv_prot_info4; + +struct state_protect4_r { + state_protect_how4 spr_how; + union { + state_protect_ops4 spr_mach_ops; + ssv_prot_info4 spr_ssv_info; + } state_protect4_r_u; +}; +typedef struct state_protect4_r state_protect4_r; + +struct EXCHANGE_ID4resok { + clientid4 eir_clientid; + sequenceid4 eir_sequenceid; + uint32_t eir_flags; + state_protect4_r eir_state_protect; + server_owner4 eir_server_owner; + struct eir_server_scope { + u_int eir_server_scope_len; + char *eir_server_scope_val; + } eir_server_scope; + struct { + u_int eir_server_impl_id_len; + nfs_impl_id4 *eir_server_impl_id_val; + } eir_server_impl_id; +}; +typedef struct EXCHANGE_ID4resok EXCHANGE_ID4resok; + +struct EXCHANGE_ID4res { + nfsstat4 eir_status; + union { + EXCHANGE_ID4resok eir_resok4; + } EXCHANGE_ID4res_u; +}; +typedef struct EXCHANGE_ID4res EXCHANGE_ID4res; + +struct channel_attrs4 { + count4 ca_headerpadsize; + count4 ca_maxrequestsize; + count4 ca_maxresponsesize; + count4 ca_maxresponsesize_cached; + count4 ca_maxoperations; + count4 ca_maxrequests; + struct { + u_int ca_rdma_ird_len; + uint32_t *ca_rdma_ird_val; + } ca_rdma_ird; +}; +typedef struct channel_attrs4 channel_attrs4; + +#define CREATE_SESSION4_FLAG_PERSIST 0x00000001 +#define CREATE_SESSION4_FLAG_CONN_BACK_CHAN 0x00000002 +#define CREATE_SESSION4_FLAG_CONN_RDMA 0x00000004 + +#define CREATE_SESSION4_FLAG_MASK 0x07 + +struct CREATE_SESSION4args { + clientid4 csa_clientid; + sequenceid4 csa_sequence; + uint32_t csa_flags; + channel_attrs4 csa_fore_chan_attrs; + channel_attrs4 csa_back_chan_attrs; + uint32_t csa_cb_program; + struct { + u_int csa_sec_parms_len; + callback_sec_parms4 *csa_sec_parms_val; + } csa_sec_parms; +}; +typedef struct CREATE_SESSION4args CREATE_SESSION4args; + +struct CREATE_SESSION4resok { + sessionid4 csr_sessionid; + sequenceid4 csr_sequence; + uint32_t csr_flags; + channel_attrs4 csr_fore_chan_attrs; + channel_attrs4 csr_back_chan_attrs; +}; +typedef struct CREATE_SESSION4resok CREATE_SESSION4resok; + +struct CREATE_SESSION4res { + nfsstat4 csr_status; + union { + CREATE_SESSION4resok csr_resok4; + } CREATE_SESSION4res_u; +}; +typedef struct CREATE_SESSION4res CREATE_SESSION4res; + +struct DESTROY_SESSION4args { + sessionid4 dsa_sessionid; +}; +typedef struct DESTROY_SESSION4args DESTROY_SESSION4args; + +struct DESTROY_SESSION4res { + nfsstat4 dsr_status; +}; +typedef struct DESTROY_SESSION4res DESTROY_SESSION4res; + +struct FREE_STATEID4args { + stateid4 fsa_stateid; +}; +typedef struct FREE_STATEID4args FREE_STATEID4args; + +struct FREE_STATEID4res { + nfsstat4 fsr_status; +}; +typedef struct FREE_STATEID4res FREE_STATEID4res; + +typedef nfstime4 attr_notice4; + +struct GET_DIR_DELEGATION4args { + bool_t gdda_signal_deleg_avail; + bitmap4 gdda_notification_types; + attr_notice4 gdda_child_attr_delay; + attr_notice4 gdda_dir_attr_delay; + bitmap4 gdda_child_attributes; + bitmap4 gdda_dir_attributes; +}; +typedef struct GET_DIR_DELEGATION4args GET_DIR_DELEGATION4args; + +struct GET_DIR_DELEGATION4resok { + verifier4 gddr_cookieverf; + stateid4 gddr_stateid; + bitmap4 gddr_notification; + bitmap4 gddr_child_attributes; + bitmap4 gddr_dir_attributes; +}; +typedef struct GET_DIR_DELEGATION4resok GET_DIR_DELEGATION4resok; + +enum gddrnf4_status { + GDD4_OK = 0, + GDD4_UNAVAIL = 1 +}; +typedef enum gddrnf4_status gddrnf4_status; + +struct GET_DIR_DELEGATION4res_non_fatal { + gddrnf4_status gddrnf_status; + union { + GET_DIR_DELEGATION4resok gddrnf_resok4; + bool_t gddrnf_will_signal_deleg_avail; + } GET_DIR_DELEGATION4res_non_fatal_u; +}; +typedef struct GET_DIR_DELEGATION4res_non_fatal + GET_DIR_DELEGATION4res_non_fatal; + +struct GET_DIR_DELEGATION4res { + nfsstat4 gddr_status; + union { + GET_DIR_DELEGATION4res_non_fatal gddr_res_non_fatal4; + } GET_DIR_DELEGATION4res_u; +}; +typedef struct GET_DIR_DELEGATION4res GET_DIR_DELEGATION4res; + +struct GETDEVICEINFO4args { + deviceid4 gdia_device_id; + layouttype4 gdia_layout_type; + count4 gdia_maxcount; + bitmap4 gdia_notify_types; +}; +typedef struct GETDEVICEINFO4args GETDEVICEINFO4args; + +struct GETDEVICEINFO4resok { + device_addr4 gdir_device_addr; + bitmap4 gdir_notification; +}; +typedef struct GETDEVICEINFO4resok GETDEVICEINFO4resok; + +struct GETDEVICEINFO4res { + nfsstat4 gdir_status; + union { + GETDEVICEINFO4resok gdir_resok4; + count4 gdir_mincount; + } GETDEVICEINFO4res_u; +}; +typedef struct GETDEVICEINFO4res GETDEVICEINFO4res; + +struct GETDEVICELIST4args { + layouttype4 gdla_layout_type; + count4 gdla_maxdevices; + nfs_cookie4 gdla_cookie; + verifier4 gdla_cookieverf; +}; +typedef struct GETDEVICELIST4args GETDEVICELIST4args; + +struct GETDEVICELIST4resok { + nfs_cookie4 gdlr_cookie; + verifier4 gdlr_cookieverf; + struct { + u_int gdlr_deviceid_list_len; + deviceid4 *gdlr_deviceid_list_val; + } gdlr_deviceid_list; + bool_t gdlr_eof; +}; +typedef struct GETDEVICELIST4resok GETDEVICELIST4resok; + +struct GETDEVICELIST4res { + nfsstat4 gdlr_status; + union { + GETDEVICELIST4resok gdlr_resok4; + } GETDEVICELIST4res_u; +}; +typedef struct GETDEVICELIST4res GETDEVICELIST4res; + +struct newtime4 { + bool_t nt_timechanged; + union { + nfstime4 nt_time; + } newtime4_u; +}; +typedef struct newtime4 newtime4; + +struct newoffset4 { + bool_t no_newoffset; + union { + offset4 no_offset; + } newoffset4_u; +}; +typedef struct newoffset4 newoffset4; + +struct LAYOUTCOMMIT4args { + offset4 loca_offset; + length4 loca_length; + bool_t loca_reclaim; + stateid4 loca_stateid; + newoffset4 loca_last_write_offset; + newtime4 loca_time_modify; + layoutupdate4 loca_layoutupdate; +}; +typedef struct LAYOUTCOMMIT4args LAYOUTCOMMIT4args; + +struct newsize4 { + bool_t ns_sizechanged; + union { + length4 ns_size; + } newsize4_u; +}; +typedef struct newsize4 newsize4; + +struct LAYOUTCOMMIT4resok { + newsize4 locr_newsize; +}; +typedef struct LAYOUTCOMMIT4resok LAYOUTCOMMIT4resok; + +struct LAYOUTCOMMIT4res { + nfsstat4 locr_status; + union { + LAYOUTCOMMIT4resok locr_resok4; + } LAYOUTCOMMIT4res_u; +}; +typedef struct LAYOUTCOMMIT4res LAYOUTCOMMIT4res; + +struct LAYOUTGET4args { + bool_t loga_signal_layout_avail; + layouttype4 loga_layout_type; + layoutiomode4 loga_iomode; + offset4 loga_offset; + length4 loga_length; + length4 loga_minlength; + stateid4 loga_stateid; + count4 loga_maxcount; +}; +typedef struct LAYOUTGET4args LAYOUTGET4args; + +struct LAYOUTGET4resok { + bool_t logr_return_on_close; + stateid4 logr_stateid; + struct { + u_int logr_layout_len; + layout4 *logr_layout_val; + } logr_layout; +}; +typedef struct LAYOUTGET4resok LAYOUTGET4resok; + +struct LAYOUTGET4res { + nfsstat4 logr_status; + union { + LAYOUTGET4resok logr_resok4; + bool_t logr_will_signal_layout_avail; + } LAYOUTGET4res_u; +}; +typedef struct LAYOUTGET4res LAYOUTGET4res; + +struct LAYOUTRETURN4args { + bool_t lora_reclaim; + layouttype4 lora_layout_type; + layoutiomode4 lora_iomode; + layoutreturn4 lora_layoutreturn; +}; +typedef struct LAYOUTRETURN4args LAYOUTRETURN4args; + +struct layoutreturn_stateid { + bool_t lrs_present; + union { + stateid4 lrs_stateid; + } layoutreturn_stateid_u; +}; +typedef struct layoutreturn_stateid layoutreturn_stateid; + +struct LAYOUTRETURN4res { + nfsstat4 lorr_status; + union { + layoutreturn_stateid lorr_stateid; + } LAYOUTRETURN4res_u; +}; +typedef struct LAYOUTRETURN4res LAYOUTRETURN4res; + +enum secinfo_style4 { + SECINFO_STYLE4_CURRENT_FH = 0, + SECINFO_STYLE4_PARENT = 1 +}; +typedef enum secinfo_style4 secinfo_style4; + +typedef secinfo_style4 SECINFO_NO_NAME4args; + +typedef SECINFO4res SECINFO_NO_NAME4res; + +struct SEQUENCE4args { + sessionid4 sa_sessionid; + sequenceid4 sa_sequenceid; + slotid4 sa_slotid; + slotid4 sa_highest_slotid; + bool_t sa_cachethis; +}; +typedef struct SEQUENCE4args SEQUENCE4args; +#define SEQ4_STATUS_CB_PATH_DOWN 0x00000001 +#define SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRING 0x00000002 +#define SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRED 0x00000004 +#define SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED 0x00000008 +#define SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED 0x00000010 +#define SEQ4_STATUS_ADMIN_STATE_REVOKED 0x00000020 +#define SEQ4_STATUS_RECALLABLE_STATE_REVOKED 0x00000040 +#define SEQ4_STATUS_LEASE_MOVED 0x00000080 +#define SEQ4_STATUS_RESTART_RECLAIM_NEEDED 0x00000100 +#define SEQ4_STATUS_CB_PATH_DOWN_SESSION 0x00000200 +#define SEQ4_STATUS_BACKCHANNEL_FAULT 0x00000400 +#define SEQ4_STATUS_DEVID_CHANGED 0x00000800 +#define SEQ4_STATUS_DEVID_DELETED 0x00001000 +#define SEQ4_HIGH_BIT SEQ4_STATUS_DEVID_DELETED /* highest defined flag */ + +struct SEQUENCE4resok { + sessionid4 sr_sessionid; + sequenceid4 sr_sequenceid; + slotid4 sr_slotid; + slotid4 sr_highest_slotid; + slotid4 sr_target_highest_slotid; + uint32_t sr_status_flags; +}; +typedef struct SEQUENCE4resok SEQUENCE4resok; + +struct SEQUENCE4res { + nfsstat4 sr_status; + union { + SEQUENCE4resok sr_resok4; + } SEQUENCE4res_u; +}; +typedef struct SEQUENCE4res SEQUENCE4res; + +struct ssa_digest_input4 { + SEQUENCE4args sdi_seqargs; +}; +typedef struct ssa_digest_input4 ssa_digest_input4; + +struct SET_SSV4args { + struct { + u_int ssa_ssv_len; + char *ssa_ssv_val; + } ssa_ssv; + struct { + u_int ssa_digest_len; + char *ssa_digest_val; + } ssa_digest; +}; +typedef struct SET_SSV4args SET_SSV4args; + +struct ssr_digest_input4 { + SEQUENCE4res sdi_seqres; +}; +typedef struct ssr_digest_input4 ssr_digest_input4; + +struct SET_SSV4resok { + struct { + u_int ssr_digest_len; + char *ssr_digest_val; + } ssr_digest; +}; +typedef struct SET_SSV4resok SET_SSV4resok; + +struct SET_SSV4res { + nfsstat4 ssr_status; + union { + SET_SSV4resok ssr_resok4; + } SET_SSV4res_u; +}; +typedef struct SET_SSV4res SET_SSV4res; + +struct TEST_STATEID4args { + struct { + u_int ts_stateids_len; + stateid4 *ts_stateids_val; + } ts_stateids; +}; +typedef struct TEST_STATEID4args TEST_STATEID4args; + +struct TEST_STATEID4resok { + struct { + u_int tsr_status_codes_len; + nfsstat4 *tsr_status_codes_val; + } tsr_status_codes; +}; +typedef struct TEST_STATEID4resok TEST_STATEID4resok; + +struct TEST_STATEID4res { + nfsstat4 tsr_status; + union { + TEST_STATEID4resok tsr_resok4; + } TEST_STATEID4res_u; +}; +typedef struct TEST_STATEID4res TEST_STATEID4res; + +struct deleg_claim4 { + open_claim_type4 dc_claim; + union { + open_delegation_type4 dc_delegate_type; + } deleg_claim4_u; +}; +typedef struct deleg_claim4 deleg_claim4; + +struct WANT_DELEGATION4args { + uint32_t wda_want; + deleg_claim4 wda_claim; +}; +typedef struct WANT_DELEGATION4args WANT_DELEGATION4args; + +struct WANT_DELEGATION4res { + nfsstat4 wdr_status; + union { + open_delegation4 wdr_resok4; + } WANT_DELEGATION4res_u; +}; +typedef struct WANT_DELEGATION4res WANT_DELEGATION4res; + +struct DESTROY_CLIENTID4args { + clientid4 dca_clientid; +}; +typedef struct DESTROY_CLIENTID4args DESTROY_CLIENTID4args; + +struct DESTROY_CLIENTID4res { + nfsstat4 dcr_status; +}; +typedef struct DESTROY_CLIENTID4res DESTROY_CLIENTID4res; + +struct RECLAIM_COMPLETE4args { + bool_t rca_one_fs; +}; +typedef struct RECLAIM_COMPLETE4args RECLAIM_COMPLETE4args; + +struct RECLAIM_COMPLETE4res { + nfsstat4 rcr_status; +}; +typedef struct RECLAIM_COMPLETE4res RECLAIM_COMPLETE4res; + +/* new operations for NFSv4.1 end */ + enum nfs_opnum4 { OP_ACCESS = 3, OP_CLOSE = 4, @@ -1403,6 +2693,28 @@ enum nfs_opnum4 { OP_VERIFY = 37, OP_WRITE = 38, OP_RELEASE_LOCKOWNER = 39, + + /* nfsv4.1 */ + OP_BACKCHANNEL_CTL = 40, + OP_BIND_CONN_TO_SESSION = 41, + OP_EXCHANGE_ID = 42, + OP_CREATE_SESSION = 43, + OP_DESTROY_SESSION = 44, + OP_FREE_STATEID = 45, + OP_GET_DIR_DELEGATION = 46, + OP_GETDEVICEINFO = 47, + OP_GETDEVICELIST = 48, + OP_LAYOUTCOMMIT = 49, + OP_LAYOUTGET = 50, + OP_LAYOUTRETURN = 51, + OP_SECINFO_NO_NAME = 52, + OP_SEQUENCE = 53, + OP_SET_SSV = 54, + OP_TEST_STATEID = 55, + OP_WANT_DELEGATION = 56, + OP_DESTROY_CLIENTID = 57, + OP_RECLAIM_COMPLETE = 58, + OP_ILLEGAL = 10044, /* * These are internal client pseudo ops that *MUST* never go over the wire @@ -1461,6 +2773,25 @@ struct nfs_argop4 { VERIFY4args opverify; WRITE4args opwrite; RELEASE_LOCKOWNER4args oprelease_lockowner; + BACKCHANNEL_CTL4args opbackchannel_ctl; /* nfsv4.1 */ + BIND_CONN_TO_SESSION4args opbind_conn_to_session; + EXCHANGE_ID4args opexchange_id; + CREATE_SESSION4args opcreate_session; + DESTROY_SESSION4args opdestroy_session; + FREE_STATEID4args opfree_stateid; + GET_DIR_DELEGATION4args opget_dir_delegation; + GETDEVICEINFO4args opgetdeviceinfo; + GETDEVICELIST4args opgetdevicelist; + LAYOUTCOMMIT4args oplayoutcommit; + LAYOUTGET4args oplayoutget; + LAYOUTRETURN4args oplayoutreturn; + SECINFO_NO_NAME4args opsecinfo_no_name; + SEQUENCE4args opsequence; + SET_SSV4args opset_ssv; + TEST_STATEID4args optest_stateid; + WANT_DELEGATION4args opwant_delegation; + DESTROY_CLIENTID4args opdestroy_clientid; + RECLAIM_COMPLETE4args opreclaim_complete; } nfs_argop4_u; }; typedef struct nfs_argop4 nfs_argop4; @@ -1506,6 +2837,25 @@ struct nfs_resop4 { VERIFY4res opverify; WRITE4res opwrite; RELEASE_LOCKOWNER4res oprelease_lockowner; + BACKCHANNEL_CTL4res opbackchannel_ctl; /* nfsv4.1 */ + BIND_CONN_TO_SESSION4res opbind_conn_to_session; + EXCHANGE_ID4res opexchange_id; + CREATE_SESSION4res opcreate_session; + DESTROY_SESSION4res opdestroy_session; + FREE_STATEID4res opfree_stateid; + GET_DIR_DELEGATION4res opget_dir_delegation; + GETDEVICEINFO4res opgetdeviceinfo; + GETDEVICELIST4res opgetdevicelist; + LAYOUTCOMMIT4res oplayoutcommit; + LAYOUTGET4res oplayoutget; + LAYOUTRETURN4res oplayoutreturn; + SECINFO_NO_NAME4res opsecinfo_no_name; + SEQUENCE4res opsequence; + SET_SSV4res opset_ssv; + TEST_STATEID4res optest_stateid; + WANT_DELEGATION4res opwant_delegation; + DESTROY_CLIENTID4res opdestroy_clientid; + RECLAIM_COMPLETE4res opreclaim_complete; ILLEGAL4res opillegal; } nfs_resop4_u; }; @@ -1585,9 +2935,297 @@ struct CB_ILLEGAL4res { }; typedef struct CB_ILLEGAL4res CB_ILLEGAL4res; +/* + * New to nfsv4.1 + */ +enum layoutrecall_type4 { + LAYOUTRECALL4_FILE = LAYOUT4_RET_REC_FILE, + LAYOUTRECALL4_FSID = LAYOUT4_RET_REC_FSID, + LAYOUTRECALL4_ALL = LAYOUT4_RET_REC_ALL +}; +typedef enum layoutrecall_type4 layoutrecall_type4; + +struct layoutrecall_file4 { + nfs_fh4 lor_fh; + offset4 lor_offset; + length4 lor_length; + stateid4 lor_stateid; +}; +typedef struct layoutrecall_file4 layoutrecall_file4; + +struct layoutrecall4 { + layoutrecall_type4 lor_recalltype; + union { + layoutrecall_file4 lor_layout; + fsid4 lor_fsid; + } layoutrecall4_u; +}; +typedef struct layoutrecall4 layoutrecall4; + +struct CB_LAYOUTRECALL4args { + layouttype4 clora_type; + layoutiomode4 clora_iomode; + bool_t clora_changed; + layoutrecall4 clora_recall; +}; +typedef struct CB_LAYOUTRECALL4args CB_LAYOUTRECALL4args; + +struct CB_LAYOUTRECALL4res { + nfsstat4 clorr_status; +}; +typedef struct CB_LAYOUTRECALL4res CB_LAYOUTRECALL4res; + +enum notify_type4 { + NOTIFY4_CHANGE_CHILD_ATTRS = 0, + NOTIFY4_CHANGE_DIR_ATTRS = 1, + NOTIFY4_REMOVE_ENTRY = 2, + NOTIFY4_ADD_ENTRY = 3, + NOTIFY4_RENAME_ENTRY = 4, + NOTIFY4_CHANGE_COOKIE_VERIFIER = 5 +}; +typedef enum notify_type4 notify_type4; + +struct notify_entry4 { + component4 ne_file; + fattr4 ne_attrs; +}; +typedef struct notify_entry4 notify_entry4; + +struct prev_entry4 { + notify_entry4 pe_prev_entry; + nfs_cookie4 pe_prev_entry_cookie; +}; +typedef struct prev_entry4 prev_entry4; + +struct notify_remove4 { + notify_entry4 nrm_old_entry; + nfs_cookie4 nrm_old_entry_cookie; +}; +typedef struct notify_remove4 notify_remove4; + +struct notify_add4 { + struct { + u_int nad_old_entry_len; + notify_remove4 *nad_old_entry_val; + } nad_old_entry; + notify_entry4 nad_new_entry; + struct { + u_int nad_new_entry_cookie_len; + nfs_cookie4 *nad_new_entry_cookie_val; +} nad_new_entry_cookie; + struct { + u_int nad_prev_entry_len; + prev_entry4 *nad_prev_entry_val; + } nad_prev_entry; + bool_t nad_last_entry; +}; +typedef struct notify_add4 notify_add4; + +struct notify_attr4 { + notify_entry4 na_changed_entry; +}; +typedef struct notify_attr4 notify_attr4; + +struct notify_rename4 { + notify_remove4 nrn_old_entry; + notify_add4 nrn_new_entry; +}; +typedef struct notify_rename4 notify_rename4; + +struct notify_verifier4 { + verifier4 nv_old_cookieverf; + verifier4 nv_new_cookieverf; +}; +typedef struct notify_verifier4 notify_verifier4; + +typedef struct { + u_int notifylist4_len; + char *notifylist4_val; +} notifylist4; + +struct notify4 { + bitmap4 notify_mask; + notifylist4 notify_vals; +}; +typedef struct notify4 notify4; + +struct CB_NOTIFY4args { + stateid4 cna_stateid; + nfs_fh4 cna_fh; + struct { + u_int cna_changes_len; + notify4 *cna_changes_val; + } cna_changes; +}; +typedef struct CB_NOTIFY4args CB_NOTIFY4args; + +struct CB_NOTIFY4res { + nfsstat4 cnr_status; +}; +typedef struct CB_NOTIFY4res CB_NOTIFY4res; + +struct CB_PUSH_DELEG4args { + nfs_fh4 cpda_fh; + open_delegation4 cpda_delegation; +}; +typedef struct CB_PUSH_DELEG4args CB_PUSH_DELEG4args; + +struct CB_PUSH_DELEG4res { + nfsstat4 cpdr_status; +}; +typedef struct CB_PUSH_DELEG4res CB_PUSH_DELEG4res; +#define RCA4_TYPE_MASK_RDATA_DLG 0 +#define RCA4_TYPE_MASK_WDATA_DLG 1 +#define RCA4_TYPE_MASK_DIR_DLG 2 +#define RCA4_TYPE_MASK_FILE_LAYOUT 3 +#define RCA4_TYPE_MASK_BLK_LAYOUT 4 +#define RCA4_TYPE_MASK_OBJ_LAYOUT_MIN 8 +#define RCA4_TYPE_MASK_OBJ_LAYOUT_MAX 9 +#define RCA4_TYPE_MASK_OTHER_LAYOUT_MIN 12 +#define RCA4_TYPE_MASK_OTHER_LAYOUT_MAX 15 + +struct CB_RECALL_ANY4args { + uint32_t craa_objects_to_keep; + bitmap4 craa_type_mask; +}; +typedef struct CB_RECALL_ANY4args CB_RECALL_ANY4args; + +struct CB_RECALL_ANY4res { + nfsstat4 crar_status; +}; +typedef struct CB_RECALL_ANY4res CB_RECALL_ANY4res; + +typedef CB_RECALL_ANY4args CB_RECALLABLE_OBJ_AVAIL4args; + +struct CB_RECALLABLE_OBJ_AVAIL4res { + nfsstat4 croa_status; +}; +typedef struct CB_RECALLABLE_OBJ_AVAIL4res CB_RECALLABLE_OBJ_AVAIL4res; + +struct CB_RECALL_SLOT4args { + slotid4 rsa_target_highest_slotid; +}; +typedef struct CB_RECALL_SLOT4args CB_RECALL_SLOT4args; + +struct CB_RECALL_SLOT4res { + nfsstat4 rsr_status; +}; +typedef struct CB_RECALL_SLOT4res CB_RECALL_SLOT4res; + +struct referring_call4 { + sequenceid4 rc_sequenceid; + slotid4 rc_slotid; +}; +typedef struct referring_call4 referring_call4; + +struct referring_call_list4 { + sessionid4 rcl_sessionid; + struct { + u_int rcl_referring_calls_len; + referring_call4 *rcl_referring_calls_val; + } rcl_referring_calls; +}; +typedef struct referring_call_list4 referring_call_list4; + +struct CB_SEQUENCE4args { + sessionid4 csa_sessionid; + sequenceid4 csa_sequenceid; + slotid4 csa_slotid; + slotid4 csa_highest_slotid; + bool_t csa_cachethis; + struct { + u_int csa_referring_call_lists_len; + referring_call_list4 *csa_referring_call_lists_val; + } csa_referring_call_lists; +}; +typedef struct CB_SEQUENCE4args CB_SEQUENCE4args; + +struct CB_SEQUENCE4resok { + sessionid4 csr_sessionid; + sequenceid4 csr_sequenceid; + slotid4 csr_slotid; + slotid4 csr_highest_slotid; + slotid4 csr_target_highest_slotid; +}; +typedef struct CB_SEQUENCE4resok CB_SEQUENCE4resok; + +struct CB_SEQUENCE4res { + nfsstat4 csr_status; + union { + CB_SEQUENCE4resok csr_resok4; + } CB_SEQUENCE4res_u; +}; +typedef struct CB_SEQUENCE4res CB_SEQUENCE4res; + +struct CB_WANTS_CANCELLED4args { + bool_t cwca_contended_wants_cancelled; + bool_t cwca_resourced_wants_cancelled; +}; +typedef struct CB_WANTS_CANCELLED4args CB_WANTS_CANCELLED4args; + +struct CB_WANTS_CANCELLED4res { + nfsstat4 cwcr_status; +}; +typedef struct CB_WANTS_CANCELLED4res CB_WANTS_CANCELLED4res; + +struct CB_NOTIFY_LOCK4args { + nfs_fh4 cnla_fh; + lock_owner4 cnla_lock_owner; +}; +typedef struct CB_NOTIFY_LOCK4args CB_NOTIFY_LOCK4args; + +struct CB_NOTIFY_LOCK4res { + nfsstat4 cnlr_status; +}; +typedef struct CB_NOTIFY_LOCK4res CB_NOTIFY_LOCK4res; + +enum notify_deviceid_type4 { + NOTIFY_DEVICEID4_CHANGE = 1, + NOTIFY_DEVICEID4_DELETE = 2 +}; +typedef enum notify_deviceid_type4 notify_deviceid_type4; + +struct notify_deviceid_delete4 { + layouttype4 ndd_layouttype; + deviceid4 ndd_deviceid; +}; +typedef struct notify_deviceid_delete4 notify_deviceid_delete4; + +struct notify_deviceid_change4 { + layouttype4 ndc_layouttype; + deviceid4 ndc_deviceid; + bool_t ndc_immediate; +}; +typedef struct notify_deviceid_change4 notify_deviceid_change4; + +struct CB_NOTIFY_DEVICEID4args { + struct { + u_int cnda_changes_len; + notify4 *cnda_changes_val; + } cnda_changes; +}; +typedef struct CB_NOTIFY_DEVICEID4args CB_NOTIFY_DEVICEID4args; + +struct CB_NOTIFY_DEVICEID4res { + nfsstat4 cndr_status; +}; +typedef struct CB_NOTIFY_DEVICEID4res CB_NOTIFY_DEVICEID4res; + +/* Callback operations new to NFSv4.1 */ + enum nfs_cb_opnum4 { OP_CB_GETATTR = 3, OP_CB_RECALL = 4, + OP_CB_LAYOUTRECALL = 5, + OP_CB_NOTIFY = 6, + OP_CB_PUSH_DELEG = 7, + OP_CB_RECALL_ANY = 8, + OP_CB_RECALLABLE_OBJ_AVAIL = 9, + OP_CB_RECALL_SLOT = 10, + OP_CB_SEQUENCE = 11, + OP_CB_WANTS_CANCELLED = 12, + OP_CB_NOTIFY_LOCK = 13, + OP_CB_NOTIFY_DEVICEID = 14, OP_CB_ILLEGAL = 10044 }; typedef enum nfs_cb_opnum4 nfs_cb_opnum4; @@ -1597,6 +3235,16 @@ struct nfs_cb_argop4 { union { CB_GETATTR4args opcbgetattr; CB_RECALL4args opcbrecall; + CB_LAYOUTRECALL4args opcblayoutrecall; + CB_NOTIFY4args opcbnotify; + CB_PUSH_DELEG4args opcbpush_deleg; + CB_RECALL_ANY4args opcbrecall_any; + CB_RECALLABLE_OBJ_AVAIL4args opcbrecallable_obj_avail; + CB_RECALL_SLOT4args opcbrecall_slot; + CB_SEQUENCE4args opcbsequence; + CB_WANTS_CANCELLED4args opcbwants_cancelled; + CB_NOTIFY_LOCK4args opcbnotify_lock; + CB_NOTIFY_DEVICEID4args opcbnotify_deviceid; } nfs_cb_argop4_u; }; typedef struct nfs_cb_argop4 nfs_cb_argop4; @@ -1606,6 +3254,16 @@ struct nfs_cb_resop4 { union { CB_GETATTR4res opcbgetattr; CB_RECALL4res opcbrecall; + CB_LAYOUTRECALL4res opcblayoutrecall; + CB_NOTIFY4res opcbnotify; + CB_PUSH_DELEG4res opcbpush_deleg; + CB_RECALL_ANY4res opcbrecall_any; + CB_RECALLABLE_OBJ_AVAIL4res opcbrecallable_obj_avail; + CB_RECALL_SLOT4res opcbrecall_slot; + CB_SEQUENCE4res opcbsequence; + CB_WANTS_CANCELLED4res opcbwants_cancelled; + CB_NOTIFY_LOCK4res opcbnotify_lock; + CB_NOTIFY_DEVICEID4res opcbnotify_deviceid; CB_ILLEGAL4res opcbillegal; } nfs_cb_resop4_u; }; @@ -1655,6 +3313,380 @@ extern bool_t xdr_CB_COMPOUND4args_clnt(XDR *, CB_COMPOUND4args *); extern bool_t xdr_CB_COMPOUND4args_srv(XDR *, CB_COMPOUND4args *); extern bool_t xdr_CB_COMPOUND4res(XDR *, CB_COMPOUND4res *); +/* New XDR to nfsv4.1 */ +extern bool_t xdr_nfs_ftype4(XDR *, nfs_ftype4*); +extern bool_t xdr_nfsstat4(XDR *, nfsstat4*); +extern bool_t xdr_attrlist4(XDR *, attrlist4*); +extern bool_t xdr_bitmap4(XDR *, bitmap4*); +extern bool_t xdr_changeid4(XDR *, changeid4*); +extern bool_t xdr_clientid4(XDR *, clientid4*); +extern bool_t xdr_count4(XDR *, count4*); +extern bool_t xdr_length4(XDR *, length4*); +extern bool_t xdr_mode4(XDR *, mode4*); +extern bool_t xdr_nfs_cookie4(XDR *, nfs_cookie4*); +extern bool_t xdr_nfs_fh4(XDR *, nfs_fh4*); +extern bool_t xdr_offset4(XDR *, offset4*); +extern bool_t xdr_qop4(XDR *, qop4*); +extern bool_t xdr_sec_oid4(XDR *, sec_oid4*); +extern bool_t xdr_sequenceid4(XDR *, sequenceid4*); +extern bool_t xdr_seqid4(XDR *, seqid4*); +extern bool_t xdr_sessionid4(XDR *, sessionid4); +extern bool_t xdr_slotid4(XDR *, slotid4*); +extern bool_t xdr_utf8string(XDR *, utf8string*); +extern bool_t xdr_utf8str_cis(XDR *, utf8str_cis*); +extern bool_t xdr_utf8str_cs(XDR *, utf8str_cs*); +extern bool_t xdr_utf8str_mixed(XDR *, utf8str_mixed*); +extern bool_t xdr_component4(XDR *, component4*); +extern bool_t xdr_linktext4(XDR *, linktext4*); +extern bool_t xdr_pathname4(XDR *, pathname4*); +extern bool_t xdr_verifier4(XDR *, verifier4*); +extern bool_t xdr_nfstime4(XDR *, nfstime4*); +extern bool_t xdr_time_how4(XDR *, time_how4*); +extern bool_t xdr_settime4(XDR *, settime4*); +extern bool_t xdr_nfs_lease4(XDR *, nfs_lease4*); +extern bool_t xdr_fsid4(XDR *, fsid4*); +extern bool_t xdr_change_policy4(XDR *, change_policy4*); +extern bool_t xdr_fs_locations4(XDR *, fs_locations4*); +extern bool_t xdr_acetype4(XDR *, acetype4*); +extern bool_t xdr_aceflag4(XDR *, aceflag4*); +extern bool_t xdr_acemask4(XDR *, acemask4*); +extern bool_t xdr_nfsace4(XDR *, nfsace4*); +extern bool_t xdr_aclflag4(XDR *, aclflag4*); +extern bool_t xdr_nfsacl41(XDR *, nfsacl41*); +extern bool_t xdr_mode_masked4(XDR *, mode_masked4*); +extern bool_t xdr_specdata4(XDR *, specdata4*); +extern bool_t xdr_netaddr4(XDR *, netaddr4*); +extern bool_t xdr_nfs_impl_id4(XDR *, nfs_impl_id4*); +extern bool_t xdr_stateid4(XDR *, stateid4*); +extern bool_t xdr_layouttype4(XDR *, layouttype4*); +extern bool_t xdr_layout_content4(XDR *, layout_content4*); +extern bool_t xdr_layouthint4(XDR *, layouthint4*); +extern bool_t xdr_layoutiomode4(XDR *, layoutiomode4*); +extern bool_t xdr_layout4(XDR *, layout4*); +extern bool_t xdr_deviceid4(XDR *, deviceid4); +extern bool_t xdr_device_addr4(XDR *, device_addr4*); +extern bool_t xdr_layoutupdate4(XDR *, layoutupdate4*); +extern bool_t xdr_layoutreturn_type4(XDR *, layoutreturn_type4*); +extern bool_t xdr_layoutreturn_file4(XDR *, layoutreturn_file4*); +extern bool_t xdr_layoutreturn4(XDR *, layoutreturn4*); +extern bool_t xdr_fs4_status_type(XDR *, fs4_status_type*); +extern bool_t xdr_fs4_status(XDR *, fs4_status*); +extern bool_t xdr_threshold4_read_size(XDR *, threshold4_read_size*); +extern bool_t xdr_threshold4_write_size(XDR *, threshold4_write_size*); +extern bool_t xdr_threshold4_read_iosize(XDR *, threshold4_read_iosize*); +extern bool_t xdr_threshold4_write_iosize(XDR *, threshold4_write_iosize*); +extern bool_t xdr_threshold_item4(XDR *, threshold_item4*); +extern bool_t xdr_mdsthreshold4(XDR *, mdsthreshold4*); +extern bool_t xdr_retention_get4(XDR *, retention_get4*); +extern bool_t xdr_retention_set4(XDR *, retention_set4*); +extern bool_t xdr_fs_charset_cap4(XDR *, fs_charset_cap4*); +extern bool_t xdr_fattr4_supported_attrs(XDR *, fattr4_supported_attrs*); +extern bool_t xdr_fattr4_type(XDR *, fattr4_type*); +extern bool_t xdr_fattr4_fh_expire_type(XDR *, fattr4_fh_expire_type*); +extern bool_t xdr_fattr4_change(XDR *, fattr4_change*); +extern bool_t xdr_fattr4_size(XDR *, fattr4_size*); +extern bool_t xdr_fattr4_link_support(XDR *, fattr4_link_support*); +extern bool_t xdr_fattr4_symlink_support(XDR *, fattr4_symlink_support*); +extern bool_t xdr_fattr4_named_attr(XDR *, fattr4_named_attr*); +extern bool_t xdr_fattr4_fsid(XDR *, fattr4_fsid*); +extern bool_t xdr_fattr4_unique_handles(XDR *, fattr4_unique_handles*); +extern bool_t xdr_fattr4_lease_time(XDR *, fattr4_lease_time*); +extern bool_t xdr_fattr4_rdattr_error(XDR *, fattr4_rdattr_error*); +extern bool_t xdr_fattr4_acl(XDR *, fattr4_acl*); +extern bool_t xdr_fattr4_aclsupport(XDR *, fattr4_aclsupport*); +extern bool_t xdr_fattr4_archive(XDR *, fattr4_archive*); +extern bool_t xdr_fattr4_cansettime(XDR *, fattr4_cansettime*); +extern bool_t xdr_fattr4_case_insensitive(XDR *, fattr4_case_insensitive*); +extern bool_t xdr_fattr4_case_preserving(XDR *, fattr4_case_preserving*); +extern bool_t xdr_fattr4_chown_restricted(XDR *, fattr4_chown_restricted*); +extern bool_t xdr_fattr4_fileid(XDR *, fattr4_fileid*); +extern bool_t xdr_fattr4_files_avail(XDR *, fattr4_files_avail*); +extern bool_t xdr_fattr4_filehandle(XDR *, fattr4_filehandle*); +extern bool_t xdr_fattr4_files_free(XDR *, fattr4_files_free*); +extern bool_t xdr_fattr4_files_total(XDR *, fattr4_files_total*); +extern bool_t xdr_fattr4_fs_locations(XDR *, fattr4_fs_locations*); +extern bool_t xdr_fattr4_hidden(XDR *, fattr4_hidden*); +extern bool_t xdr_fattr4_homogeneous(XDR *, fattr4_homogeneous*); +extern bool_t xdr_fattr4_maxfilesize(XDR *, fattr4_maxfilesize*); +extern bool_t xdr_fattr4_maxlink(XDR *, fattr4_maxlink*); +extern bool_t xdr_fattr4_maxname(XDR *, fattr4_maxname*); +extern bool_t xdr_fattr4_maxread(XDR *, fattr4_maxread*); +extern bool_t xdr_fattr4_maxwrite(XDR *, fattr4_maxwrite*); +extern bool_t xdr_fattr4_mimetype(XDR *, fattr4_mimetype*); +extern bool_t xdr_fattr4_mode(XDR *, fattr4_mode*); +extern bool_t xdr_fattr4_mode_set_masked(XDR *, fattr4_mode_set_masked*); +extern bool_t xdr_fattr4_mounted_on_fileid(XDR *, fattr4_mounted_on_fileid*); +extern bool_t xdr_fattr4_no_trunc(XDR *, fattr4_no_trunc*); +extern bool_t xdr_fattr4_numlinks(XDR *, fattr4_numlinks*); +extern bool_t xdr_fattr4_owner(XDR *, fattr4_owner*); +extern bool_t xdr_fattr4_owner_group(XDR *, fattr4_owner_group*); +extern bool_t xdr_fattr4_quota_avail_hard(XDR *, fattr4_quota_avail_hard*); +extern bool_t xdr_fattr4_quota_avail_soft(XDR *, fattr4_quota_avail_soft*); +extern bool_t xdr_fattr4_quota_used(XDR *, fattr4_quota_used*); +extern bool_t xdr_fattr4_rawdev(XDR *, fattr4_rawdev*); +extern bool_t xdr_fattr4_space_avail(XDR *, fattr4_space_avail*); +extern bool_t xdr_fattr4_space_free(XDR *, fattr4_space_free*); +extern bool_t xdr_fattr4_space_total(XDR *, fattr4_space_total*); +extern bool_t xdr_fattr4_space_used(XDR *, fattr4_space_used*); +extern bool_t xdr_fattr4_system(XDR *, fattr4_system*); +extern bool_t xdr_fattr4_time_access(XDR *, fattr4_time_access*); +extern bool_t xdr_fattr4_time_access_set(XDR *, fattr4_time_access_set*); +extern bool_t xdr_fattr4_time_backup(XDR *, fattr4_time_backup*); +extern bool_t xdr_fattr4_time_create(XDR *, fattr4_time_create*); +extern bool_t xdr_fattr4_time_delta(XDR *, fattr4_time_delta*); +extern bool_t xdr_fattr4_time_metadata(XDR *, fattr4_time_metadata*); +extern bool_t xdr_fattr4_time_modify(XDR *, fattr4_time_modify*); +extern bool_t xdr_fattr4_time_modify_set(XDR *, fattr4_time_modify_set*); +extern bool_t xdr_fattr4_suppattr_exclcreat(XDR *, fattr4_suppattr_exclcreat*); +extern bool_t xdr_fattr4_dir_notif_delay(XDR *, fattr4_dir_notif_delay*); +extern bool_t xdr_fattr4_dirent_notif_delay(XDR *, fattr4_dirent_notif_delay*); +extern bool_t xdr_fattr4_fs_layout_types(XDR *, fattr4_fs_layout_types*); +extern bool_t xdr_fattr4_fs_status(XDR *, fattr4_fs_status*); +extern bool_t xdr_fattr4_fs_charset_cap(XDR *, fattr4_fs_charset_cap*); +extern bool_t xdr_fattr4_layout_alignment(XDR *, fattr4_layout_alignment*); +extern bool_t xdr_fattr4_layout_blksize(XDR *, fattr4_layout_blksize*); +extern bool_t xdr_fattr4_layout_hint(XDR *, fattr4_layout_hint*); +extern bool_t xdr_fattr4_layout_types(XDR *, fattr4_layout_types*); +extern bool_t xdr_fattr4_mdsthreshold(XDR *, fattr4_mdsthreshold*); +extern bool_t xdr_fattr4_retention_get(XDR *, fattr4_retention_get*); +extern bool_t xdr_fattr4_retention_set(XDR *, fattr4_retention_set*); +extern bool_t xdr_fattr4_retentevt_get(XDR *, fattr4_retentevt_get*); +extern bool_t xdr_fattr4_retentevt_set(XDR *, fattr4_retentevt_set*); +extern bool_t xdr_fattr4_retention_hold(XDR *, fattr4_retention_hold*); +extern bool_t xdr_fattr4_dacl(XDR *, fattr4_dacl*); +extern bool_t xdr_fattr4_sacl(XDR *, fattr4_sacl*); +extern bool_t xdr_fattr4_change_policy(XDR *, fattr4_change_policy*); +extern bool_t xdr_fattr4(XDR *, fattr4*); +extern bool_t xdr_change_info4(XDR *, change_info4*); +extern bool_t xdr_clientaddr4(XDR *, clientaddr4*); +extern bool_t xdr_cb_client4(XDR *, cb_client4*); +extern bool_t xdr_nfs_client_id4(XDR *, nfs_client_id4*); +extern bool_t xdr_client_owner4(XDR *, client_owner4*); +extern bool_t xdr_server_owner4(XDR *, server_owner4*); +extern bool_t xdr_state_owner4(XDR *, state_owner4*); +extern bool_t xdr_open_owner4(XDR *, open_owner4*); +extern bool_t xdr_lock_owner4(XDR *, lock_owner4*); +extern bool_t xdr_nfs_lock_type4(XDR *, nfs_lock_type4*); +extern bool_t xdr_ssv_subkey4(XDR *, ssv_subkey4*); +extern bool_t xdr_ssv_mic_plain_tkn4(XDR *, ssv_mic_plain_tkn4*); +extern bool_t xdr_ssv_mic_tkn4(XDR *, ssv_mic_tkn4*); +extern bool_t xdr_ssv_seal_plain_tkn4(XDR *, ssv_seal_plain_tkn4*); +extern bool_t xdr_ssv_seal_cipher_tkn4(XDR *, ssv_seal_cipher_tkn4*); +extern bool_t xdr_fs_locations_server4(XDR *, fs_locations_server4*); +extern bool_t xdr_fs_locations_item4(XDR *, fs_locations_item4*); +extern bool_t xdr_fs_locations_info4(XDR *, fs_locations_info4*); +extern bool_t xdr_fattr4_fs_locations_info(XDR *, fattr4_fs_locations_info*); +extern bool_t xdr_nfl_util4(XDR *, nfl_util4*); +extern bool_t xdr_filelayout_hint_care4(XDR *, filelayout_hint_care4*); +extern bool_t xdr_nfsv4_1_file_layouthint4(XDR *, nfsv4_1_file_layouthint4*); +extern bool_t xdr_multipath_list4(XDR *, multipath_list4*); +extern bool_t xdr_nfsv4_1_file_layout_ds_addr4(XDR *, + nfsv4_1_file_layout_ds_addr4*); +extern bool_t xdr_nfsv4_1_file_layout4(XDR *, nfsv4_1_file_layout4*); +extern bool_t xdr_ACCESS4args(XDR *, ACCESS4args*); +extern bool_t xdr_COMMIT4args(XDR *, COMMIT4args*); +extern bool_t xdr_COMMIT4res(XDR *, COMMIT4res*); +extern bool_t xdr_DELEGPURGE4args(XDR *, DELEGPURGE4args*); +extern bool_t xdr_DELEGPURGE4res(XDR *, DELEGPURGE4res*); +extern bool_t xdr_DELEGRETURN4args(XDR *, DELEGRETURN4args*); +extern bool_t xdr_DELEGRETURN4res(XDR *, DELEGRETURN4res*); +extern bool_t xdr_GETATTR4args(XDR *, GETATTR4args*); +extern bool_t xdr_GETATTR4res(XDR *, GETATTR4res*); +extern bool_t xdr_GETFH4res(XDR *, GETFH4res*); +extern bool_t xdr_open_to_lock_owner4(XDR *, open_to_lock_owner4*); +extern bool_t xdr_exist_lock_owner4(XDR *, exist_lock_owner4*); +extern bool_t xdr_locker4(XDR *, locker4*); +extern bool_t xdr_LOCK4denied(XDR *, LOCK4denied*); +extern bool_t xdr_LOOKUP4args(XDR *, LOOKUP4args*); +extern bool_t xdr_LOOKUP4res(XDR *, LOOKUP4res*); +extern bool_t xdr_LOOKUPP4res(XDR *, LOOKUPP4res*); +extern bool_t xdr_NVERIFY4args(XDR *, NVERIFY4args*); +extern bool_t xdr_NVERIFY4res(XDR *, NVERIFY4res*); +extern bool_t xdr_createmode4(XDR *, createmode4*); +extern bool_t xdr_creatverfattr(XDR *, creatverfattr*); +extern bool_t xdr_createhow4(XDR *, createhow4*); +extern bool_t xdr_opentype4(XDR *, opentype4*); +extern bool_t xdr_openflag4(XDR *, openflag4*); +extern bool_t xdr_limit_by4(XDR *, limit_by4*); +extern bool_t xdr_nfs_modified_limit4(XDR *, nfs_modified_limit4*); +extern bool_t xdr_nfs_space_limit4(XDR *, nfs_space_limit4*); +extern bool_t xdr_open_delegation_type4(XDR *, open_delegation_type4*); +extern bool_t xdr_open_claim_type4(XDR *, open_claim_type4*); +extern bool_t xdr_open_claim_delegate_cur4(XDR *, open_claim_delegate_cur4*); +extern bool_t xdr_open_claim4(XDR *, open_claim4*); +extern bool_t xdr_open_read_delegation4(XDR *, open_read_delegation4*); +extern bool_t xdr_open_write_delegation4(XDR *, open_write_delegation4*); +extern bool_t xdr_why_no_delegation4(XDR *, why_no_delegation4*); +extern bool_t xdr_open_none_delegation4(XDR *, open_none_delegation4*); +extern bool_t xdr_open_delegation4(XDR *, open_delegation4*); +extern bool_t xdr_PUTFH4args(XDR *, PUTFH4args*); +extern bool_t xdr_PUTFH4res(XDR *, PUTFH4res*); +extern bool_t xdr_PUTPUBFH4res(XDR *, PUTPUBFH4res*); +extern bool_t xdr_PUTROOTFH4res(XDR *, PUTROOTFH4res*); +extern bool_t xdr_RENEW4args(XDR *, RENEW4args*); +extern bool_t xdr_RENEW4res(XDR *, RENEW4res*); +extern bool_t xdr_RESTOREFH4res(XDR *, RESTOREFH4res*); +extern bool_t xdr_SAVEFH4res(XDR *, SAVEFH4res*); +extern bool_t xdr_SECINFO4args(XDR *, SECINFO4args*); +extern bool_t xdr_rpc_gss_svc_t(XDR *, rpc_gss_svc_t *); +extern bool_t xdr_rpcsec_gss_info(XDR *, rpcsec_gss_info*); +extern bool_t xdr_SECINFO4res(XDR *, SECINFO4res*); +extern bool_t xdr_SETATTR4args(XDR *, SETATTR4args*); +extern bool_t xdr_SETATTR4res(XDR *, SETATTR4res*); +extern bool_t xdr_SETCLIENTID_CONFIRM4args(XDR *, SETCLIENTID_CONFIRM4args*); +extern bool_t xdr_SETCLIENTID_CONFIRM4res(XDR *, SETCLIENTID_CONFIRM4res*); +extern bool_t xdr_VERIFY4args(XDR *, VERIFY4args*); +extern bool_t xdr_VERIFY4res(XDR *, VERIFY4res*); +extern bool_t xdr_stable_how4(XDR *, stable_how4*); +extern bool_t xdr_RELEASE_LOCKOWNER4args(XDR *, RELEASE_LOCKOWNER4args*); +extern bool_t xdr_RELEASE_LOCKOWNER4res(XDR *, RELEASE_LOCKOWNER4res*); +extern bool_t xdr_ILLEGAL4res(XDR *, ILLEGAL4res*); +extern bool_t xdr_gsshandle4_t(XDR *, gsshandle4_t *); +extern bool_t xdr_gss_cb_handles4(XDR *, gss_cb_handles4*); +extern bool_t xdr_callback_sec_parms4(XDR *, callback_sec_parms4*); +extern bool_t xdr_BACKCHANNEL_CTL4args(XDR *, BACKCHANNEL_CTL4args*); +extern bool_t xdr_BACKCHANNEL_CTL4res(XDR *, BACKCHANNEL_CTL4res*); +extern bool_t xdr_channel_dir_from_client4(XDR *, channel_dir_from_client4*); +extern bool_t xdr_BIND_CONN_TO_SESSION4args(XDR *, BIND_CONN_TO_SESSION4args*); +extern bool_t xdr_channel_dir_from_server4(XDR *, channel_dir_from_server4*); +extern bool_t xdr_BIND_CONN_TO_SESSION4resok(XDR *, + BIND_CONN_TO_SESSION4resok*); +extern bool_t xdr_BIND_CONN_TO_SESSION4res(XDR *, BIND_CONN_TO_SESSION4res*); +extern bool_t xdr_state_protect_ops4(XDR *, state_protect_ops4*); +extern bool_t xdr_ssv_sp_parms4(XDR *, ssv_sp_parms4*); +extern bool_t xdr_state_protect_how4(XDR *, state_protect_how4*); +extern bool_t xdr_state_protect4_a(XDR *, state_protect4_a*); +extern bool_t xdr_EXCHANGE_ID4args(XDR *, EXCHANGE_ID4args*); +extern bool_t xdr_ssv_prot_info4(XDR *, ssv_prot_info4*); +extern bool_t xdr_state_protect4_r(XDR *, state_protect4_r*); +extern bool_t xdr_EXCHANGE_ID4resok(XDR *, EXCHANGE_ID4resok*); +extern bool_t xdr_EXCHANGE_ID4res(XDR *, EXCHANGE_ID4res*); +extern bool_t xdr_channel_attrs4(XDR *, channel_attrs4*); +extern bool_t xdr_CREATE_SESSION4args(XDR *, CREATE_SESSION4args*); +extern bool_t xdr_CREATE_SESSION4resok(XDR *, CREATE_SESSION4resok*); +extern bool_t xdr_CREATE_SESSION4res(XDR *, CREATE_SESSION4res*); +extern bool_t xdr_DESTROY_SESSION4args(XDR *, DESTROY_SESSION4args*); +extern bool_t xdr_DESTROY_SESSION4res(XDR *, DESTROY_SESSION4res*); +extern bool_t xdr_FREE_STATEID4args(XDR *, FREE_STATEID4args*); +extern bool_t xdr_FREE_STATEID4res(XDR *, FREE_STATEID4res*); +extern bool_t xdr_attr_notice4(XDR *, attr_notice4*); +extern bool_t xdr_GET_DIR_DELEGATION4args(XDR *, GET_DIR_DELEGATION4args*); +extern bool_t xdr_GET_DIR_DELEGATION4resok(XDR *, GET_DIR_DELEGATION4resok*); +extern bool_t xdr_gddrnf4_status(XDR *, gddrnf4_status*); +extern bool_t xdr_GET_DIR_DELEGATION4res_non_fatal(XDR *, + GET_DIR_DELEGATION4res_non_fatal*); +extern bool_t xdr_GET_DIR_DELEGATION4res(XDR *, GET_DIR_DELEGATION4res*); +extern bool_t xdr_GETDEVICEINFO4args(XDR *, GETDEVICEINFO4args*); +extern bool_t xdr_GETDEVICEINFO4resok(XDR *, GETDEVICEINFO4resok*); +extern bool_t xdr_GETDEVICEINFO4res(XDR *, GETDEVICEINFO4res*); +extern bool_t xdr_GETDEVICELIST4args(XDR *, GETDEVICELIST4args*); +extern bool_t xdr_GETDEVICELIST4resok(XDR *, GETDEVICELIST4resok*); +extern bool_t xdr_GETDEVICELIST4res(XDR *, GETDEVICELIST4res*); +extern bool_t xdr_newtime4(XDR *, newtime4*); +extern bool_t xdr_newoffset4(XDR *, newoffset4*); +extern bool_t xdr_LAYOUTCOMMIT4args(XDR *, LAYOUTCOMMIT4args*); +extern bool_t xdr_newsize4(XDR *, newsize4*); +extern bool_t xdr_LAYOUTCOMMIT4resok(XDR *, LAYOUTCOMMIT4resok*); +extern bool_t xdr_LAYOUTCOMMIT4res(XDR *, LAYOUTCOMMIT4res*); +extern bool_t xdr_LAYOUTGET4args(XDR *, LAYOUTGET4args*); +extern bool_t xdr_LAYOUTGET4resok(XDR *, LAYOUTGET4resok*); +extern bool_t xdr_LAYOUTGET4res(XDR *, LAYOUTGET4res*); +extern bool_t xdr_LAYOUTRETURN4args(XDR *, LAYOUTRETURN4args*); +extern bool_t xdr_layoutreturn_stateid(XDR *, layoutreturn_stateid*); +extern bool_t xdr_LAYOUTRETURN4res(XDR *, LAYOUTRETURN4res*); +extern bool_t xdr_secinfo_style4(XDR *, secinfo_style4*); +extern bool_t xdr_SECINFO_NO_NAME4args(XDR *, SECINFO_NO_NAME4args*); +extern bool_t xdr_SECINFO_NO_NAME4res(XDR *, SECINFO_NO_NAME4res*); +extern bool_t xdr_SEQUENCE4args(XDR *, SEQUENCE4args*); +extern bool_t xdr_SEQUENCE4resok(XDR *, SEQUENCE4resok*); +extern bool_t xdr_SEQUENCE4res(XDR *, SEQUENCE4res*); +extern bool_t xdr_ssa_digest_input4(XDR *, ssa_digest_input4*); +extern bool_t xdr_SET_SSV4args(XDR *, SET_SSV4args*); +extern bool_t xdr_ssr_digest_input4(XDR *, ssr_digest_input4*); +extern bool_t xdr_SET_SSV4resok(XDR *, SET_SSV4resok*); +extern bool_t xdr_SET_SSV4res(XDR *, SET_SSV4res*); +extern bool_t xdr_TEST_STATEID4args(XDR *, TEST_STATEID4args*); +extern bool_t xdr_TEST_STATEID4resok(XDR *, TEST_STATEID4resok*); +extern bool_t xdr_TEST_STATEID4res(XDR *, TEST_STATEID4res*); +extern bool_t xdr_deleg_claim4(XDR *, deleg_claim4*); +extern bool_t xdr_WANT_DELEGATION4args(XDR *, WANT_DELEGATION4args*); +extern bool_t xdr_WANT_DELEGATION4res(XDR *, WANT_DELEGATION4res*); +extern bool_t xdr_DESTROY_CLIENTID4args(XDR *, DESTROY_CLIENTID4args*); +extern bool_t xdr_DESTROY_CLIENTID4res(XDR *, DESTROY_CLIENTID4res*); +extern bool_t xdr_RECLAIM_COMPLETE4args(XDR *, RECLAIM_COMPLETE4args*); +extern bool_t xdr_RECLAIM_COMPLETE4res(XDR *, RECLAIM_COMPLETE4res*); +extern bool_t xdr_nfs_opnum4(XDR *, nfs_opnum4*); +extern bool_t xdr_COMPOUND4args(XDR *, COMPOUND4args*); +extern bool_t xdr_COMPOUND4res(XDR *, COMPOUND4res*); +extern bool_t xdr_CB_GETATTR4args(XDR *, CB_GETATTR4args*); +extern bool_t xdr_CB_GETATTR4res(XDR *, CB_GETATTR4res*); +extern bool_t xdr_CB_RECALL4args(XDR *, CB_RECALL4args*); +extern bool_t xdr_CB_RECALL4res(XDR *, CB_RECALL4res*); +extern bool_t xdr_CB_ILLEGAL4res(XDR *, CB_ILLEGAL4res*); +extern bool_t xdr_layoutrecall_type4(XDR *, layoutrecall_type4*); +extern bool_t xdr_layoutrecall_file4(XDR *, layoutrecall_file4*); +extern bool_t xdr_layoutrecall4(XDR *, layoutrecall4*); +extern bool_t xdr_CB_LAYOUTRECALL4args(XDR *, CB_LAYOUTRECALL4args*); +extern bool_t xdr_CB_LAYOUTRECALL4res(XDR *, CB_LAYOUTRECALL4res*); +extern bool_t xdr_notify_type4(XDR *, notify_type4*); +extern bool_t xdr_notify_entry4(XDR *, notify_entry4*); +extern bool_t xdr_prev_entry4(XDR *, prev_entry4*); +extern bool_t xdr_notify_remove4(XDR *, notify_remove4*); +extern bool_t xdr_notify_add4(XDR *, notify_add4*); +extern bool_t xdr_notify_attr4(XDR *, notify_attr4*); +extern bool_t xdr_notify_rename4(XDR *, notify_rename4*); +extern bool_t xdr_notify_verifier4(XDR *, notify_verifier4*); +extern bool_t xdr_notifylist4(XDR *, notifylist4*); +extern bool_t xdr_notify4(XDR *, notify4*); +extern bool_t xdr_CB_NOTIFY4args(XDR *, CB_NOTIFY4args*); +extern bool_t xdr_CB_NOTIFY4res(XDR *, CB_NOTIFY4res*); +extern bool_t xdr_CB_PUSH_DELEG4args(XDR *, CB_PUSH_DELEG4args*); +extern bool_t xdr_CB_PUSH_DELEG4res(XDR *, CB_PUSH_DELEG4res*); +extern bool_t xdr_CB_RECALL_ANY4args(XDR *, CB_RECALL_ANY4args*); +extern bool_t xdr_CB_RECALL_ANY4res(XDR *, CB_RECALL_ANY4res*); +extern bool_t xdr_CB_RECALLABLE_OBJ_AVAIL4args(XDR *, + CB_RECALLABLE_OBJ_AVAIL4args*); +extern bool_t xdr_CB_RECALLABLE_OBJ_AVAIL4res(XDR *, + CB_RECALLABLE_OBJ_AVAIL4res*); +extern bool_t xdr_CB_RECALL_SLOT4args(XDR *, CB_RECALL_SLOT4args*); +extern bool_t xdr_CB_RECALL_SLOT4res(XDR *, CB_RECALL_SLOT4res*); +extern bool_t xdr_referring_call4(XDR *, referring_call4*); +extern bool_t xdr_referring_call_list4(XDR *, referring_call_list4*); +extern bool_t xdr_CB_SEQUENCE4args(XDR *, CB_SEQUENCE4args*); +extern bool_t xdr_CB_SEQUENCE4resok(XDR *, CB_SEQUENCE4resok*); +extern bool_t xdr_CB_SEQUENCE4res(XDR *, CB_SEQUENCE4res*); +extern bool_t xdr_CB_WANTS_CANCELLED4args(XDR *, CB_WANTS_CANCELLED4args*); +extern bool_t xdr_CB_WANTS_CANCELLED4res(XDR *, CB_WANTS_CANCELLED4res*); +extern bool_t xdr_CB_NOTIFY_LOCK4args(XDR *, CB_NOTIFY_LOCK4args*); +extern bool_t xdr_CB_NOTIFY_LOCK4res(XDR *, CB_NOTIFY_LOCK4res*); +extern bool_t xdr_notify_deviceid_type4(XDR *, notify_deviceid_type4*); +extern bool_t xdr_notify_deviceid_delete4(XDR *, notify_deviceid_delete4*); +extern bool_t xdr_notify_deviceid_change4(XDR *, notify_deviceid_change4*); +extern bool_t xdr_CB_NOTIFY_DEVICEID4args(XDR *, CB_NOTIFY_DEVICEID4args*); +extern bool_t xdr_CB_NOTIFY_DEVICEID4res(XDR *, CB_NOTIFY_DEVICEID4res*); +extern bool_t xdr_nfs_cb_opnum4(XDR *, nfs_cb_opnum4*); +extern bool_t xdr_nfs_cb_argop4(XDR *, nfs_cb_argop4*); +extern bool_t xdr_nfs_cb_resop4(XDR *, nfs_cb_resop4*); +extern bool_t xdr_CB_COMPOUND4args(XDR *, CB_COMPOUND4args*); +extern bool_t xdr_CB_COMPOUND4res(XDR *, CB_COMPOUND4res*); +/* nfsv4.1 end */ + +/* nfsv4.2 */ +struct sec_label4 { + uint_t slai_len; + char *slai_val; +}; + +typedef struct sec_label4 sec_label4; +typedef sec_label4 fattr4_sec_label; + +extern bool_t xdr_fattr4_sec_label(XDR *xdrs, fattr4_sec_label *objp); +/* nfsv4.2 end */ + +/* NFSv4.x xdr */ +extern bool_t xdr_nfs4x_argop4(XDR *xdrs, nfs_argop4 *objp); +extern bool_t xdr_nfs4x_resop4(XDR *xdrs, nfs_resop4 *objp); + /* * xdr for referrrals upcall */ diff --git a/usr/src/uts/common/nfs/nfs4x.h b/usr/src/uts/common/nfs/nfs4x.h new file mode 100644 index 0000000000..9606d14f2c --- /dev/null +++ b/usr/src/uts/common/nfs/nfs4x.h @@ -0,0 +1,195 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2017 RackTop Systems. + */ + +#ifndef _NFS4X_SRV_H +#define _NFS4X_SRV_H + +#ifdef _KERNEL + +#include <sys/cred.h> +#include <nfs/nfs4_kprot.h> + +/* + * NFSv4.1: slot support (reply cache) + */ + +#define RFS4_SLOT_INUSE (1 << 0) +#define RFS4_SLOT_CACHED (1 << 1) + +/* Slot entry structure */ +typedef struct rfs4_slot { + uint32_t se_flags; + sequenceid4 se_seqid; + COMPOUND4res se_buf; /* Buf for slot and replays */ + kmutex_t se_lock; +} rfs4_slot_t; + +/* + * NFSv4.1 Sessions + */ + +typedef struct rfs41_csr { /* contrived create_session result */ + sequenceid4 xi_sid; /* seqid response to EXCHG_ID */ + nfsstat4 cs_status; + CREATE_SESSION4resok cs_res; /* cached results if NFS4_OK */ +} rfs41_csr_t; + +/* + * Sessions Callback Infrastructure + * + * Locking: + * + * . cn_lock protects all fields in sess_channel_t, but since + * fore/back and dir don't change often, we serialize only + * the occasional update. + * + * cn_lock: cn_lock + * bsd_rwlock: cn_lock -> bsd_rwlock + */ + +#define MAX_CH_CACHE 10 +typedef struct { /* Back Chan Specific Data */ + rfs4_slot_t *bsd_slots; /* opaque token for slot tab */ + nfsstat4 bsd_stat; + krwlock_t bsd_rwlock; /* protect slot tab info */ + uint64_t bsd_idx; /* Index of next spare CLNT */ + uint64_t bsd_cur; /* Most recent added CLNT */ + int bsd_ch_free; + CLIENT *bsd_clnt[MAX_CH_CACHE]; +} sess_bcsd_t; + +typedef struct { + channel_dir_from_server4 cn_dir; /* Chan Direction */ + channel_attrs4 cn_attrs; /* chan Attrs */ + channel_attrs4 cn_back_attrs; /* back channel Attrs */ + sess_bcsd_t *cn_csd; /* Chan Specific Data */ + krwlock_t cn_lock; +} sess_channel_t; + +/* + * Maximum number of concurrent COMPOUND requests per session + */ +#define MAXSLOTS 256 +#define MAXSLOTS_BACK 4 + +typedef struct { + state_protect_how4 sp_type; +} rfs41_sprot_t; + +/* + * NFSv4.1 Sessions (cont'd) + * + * rfs4_session_t rfs4_client_t + * +-------------+ +--------------------+ + * | sn_sessid | | clientid | + * | sn_clnt * -|---------->| : | + * | sn_fore | +--------------------+ + * | sn_back | + * | sn_slots * -|---------> +--------------------------------+ + * +-------------+ | (slot_ent_t) | + * | +----------------------------+| + * | | status, slot, seqid, resp *||------><Res> + * | +----------------------------+| + * | | status, slot, seqid, resp *|| + * | +----------------------------+| + * | | status, slot, seqid, resp *|| + * | +----------------------------+| + * | . | + * | : | + * +--------------------------------+ + * stok_t + */ +struct rfs4_client; +struct rfs4_dbe; + +typedef struct { + nfsstat4 cs_error; + struct rfs4_client *cs_client; + struct svc_req *cs_req; + uint32_t cs_id; + CREATE_SESSION4args cs_aotw; +} session41_create_t; + +/* + * sn_seq4 - sequence result bit accounting info (session scope) + * CB_PATH_DOWN_SESSION, CB_GSS_CONTEXT_EXPIRING, + * CB_GSS_CONTEXT_EXPIRED, BACKCHANNEL_FAULT + */ +typedef struct rfs4_session { + struct rfs4_dbe *sn_dbe; + sessionid4 sn_sessid; /* session id */ + struct rfs4_client *sn_clnt; /* back ptr to client state */ + sess_channel_t *sn_fore; /* fore chan for this session */ + sess_channel_t *sn_back; /* back chan for this session */ + rfs4_slot_t *sn_slots; /* slot replay cache */ + time_t sn_laccess; /* struct was last accessed */ + int sn_csflags; /* create_session only flags */ + uint32_t sn_flags; /* SEQ4 status bits */ + list_node_t sn_node; /* link node to rfs4_client */ + struct { + uint32_t pngcnt; /* conn pings outstanding */ + uint32_t progno; /* cb_program number */ + uint32_t failed:1; /* TRUE if no cb path avail */ + uint32_t pnginprog:1; + } sn_bc; + uint32_t sn_rcached; /* cached replies, for stat */ +} rfs4_session_t; + +#define SN_CB_CHAN_EST(x) ((x)->sn_back != NULL) +#define SN_CB_CHAN_OK(x) ((x)->sn_bc.failed == 0) + +/* error code for internal use */ +#define nfserr_replay_cache NFS4ERR_REPLAY_CACHE + +/* Session end */ + +/* + * Set of RPC credentials used for a particular operation. + * Used for operations like SETCLIENTID_CONFIRM where the + * credentials needs to match those used at SETCLIENTID. + * For EXCHANGE_ID (NFSv4.1+) + */ + +typedef struct { + cred_t *cp_cr; + int cp_aflavor; + int cp_secmod; + caddr_t cp_princ; +} cred_set_t; + +/* NFSv4.1 Functions */ +extern int rfs4x_dispatch(struct svc_req *, SVCXPRT *, char *); + +void rfs4_free_cred_set(cred_set_t *); +void rfs4x_session_rele(rfs4_session_t *); +rfs4_session_t *rfs4x_createsession(session41_create_t *); +nfsstat4 rfs4x_destroysession(rfs4_session_t *, unsigned useref); +void rfs4x_client_session_remove(struct rfs4_client *); +rfs4_session_t *rfs4x_findsession_by_id(sessionid4); +void rfs4x_session_hold(rfs4_session_t *); +void rfs4x_session_rele(rfs4_session_t *); + +/* Some init/fini helpers */ +struct rfs4_srv; +struct compound_state; +void rfs4x_state_init_locked(struct nfs4_srv *); +void rfs4x_state_fini(struct nfs4_srv *); +int rfs4x_sequence_prep(COMPOUND4args *, COMPOUND4res *, + struct compound_state *); +void rfs4x_sequence_done(COMPOUND4res *, struct compound_state *); + +#endif /* _KERNEL */ + +#endif /* _NFS4_SRV_H */ |
