+ int8_t free; /* next unused slot */
+ int8_t mru; /* head of MRU list */
+ int8_t next[NFSNUMCOOKIES]; /* MRU list links */
+ struct {
+ uint64_t key; /* cookie */
+ uint64_t lbn; /* lbn of buffer */
+ } cookies[NFSNUMCOOKIES]; /* MRU list entries */
+};
+
+/*
+ * NFS vnode attribute structure
+ */
+#define NFSTIME_ACCESS 0 /* time of last access */
+#define NFSTIME_MODIFY 1 /* time of last modification */
+#define NFSTIME_CHANGE 2 /* time file changed */
+#define NFSTIME_CREATE 3 /* time file created */
+#define NFSTIME_BACKUP 4 /* time of last backup */
+#define NFSTIME_COUNT 5
+
+#define NFS_COMPARE_MTIME(TVP, NVAP, CMP) \
+ (((TVP)->tv_sec == (NVAP)->nva_timesec[NFSTIME_MODIFY]) ? \
+ ((TVP)->tv_nsec CMP (NVAP)->nva_timensec[NFSTIME_MODIFY]) : \
+ ((TVP)->tv_sec CMP (NVAP)->nva_timesec[NFSTIME_MODIFY]))
+#define NFS_COPY_TIME(TVP, NVAP, WHICH) \
+ do { \
+ (TVP)->tv_sec = (NVAP)->nva_timesec[NFSTIME_##WHICH]; \
+ (TVP)->tv_nsec = (NVAP)->nva_timensec[NFSTIME_##WHICH]; \
+ } while (0)
+
+struct nfs_vattr {
+ enum vtype nva_type; /* vnode type (for create) */
+ uint32_t nva_mode; /* file's access mode (and type) */
+ uid_t nva_uid; /* owner user id */
+ gid_t nva_gid; /* owner group id */
+ guid_t nva_uuuid; /* owner user UUID */
+ guid_t nva_guuid; /* owner group UUID */
+ kauth_acl_t nva_acl; /* access control list */
+ nfs_specdata nva_rawdev; /* device the special file represents */
+ uint32_t nva_flags; /* file flags (see below) */
+ uint32_t nva_maxlink; /* maximum # of links (v4) */
+ uint64_t nva_nlink; /* number of references to file */
+ uint64_t nva_fileid; /* file id */
+ nfs_fsid nva_fsid; /* file system id */
+ uint64_t nva_size; /* file size in bytes */
+ uint64_t nva_bytes; /* bytes of disk space held by file */
+ uint64_t nva_change; /* change attribute */
+ int64_t nva_timesec[NFSTIME_COUNT];
+ int32_t nva_timensec[NFSTIME_COUNT];
+ uint32_t nva_bitmap[NFS_ATTR_BITMAP_LEN]; /* attributes that are valid */
+};
+
+/* nva_flags */
+#define NFS_FFLAG_ARCHIVED 0x0001
+#define NFS_FFLAG_HIDDEN 0x0002
+#define NFS_FFLAG_HAS_NAMED_ATTRS 0x0004 /* file has named attributes */
+#define NFS_FFLAG_TRIGGER 0x0008 /* node is a trigger/mirror mount point */
+#define NFS_FFLAG_TRIGGER_REFERRAL 0x0010 /* trigger is a referral */
+#define NFS_FFLAG_IS_ATTR 0x8000 /* file is a named attribute file/directory */
+
+/* flags for nfs_getattr() */
+#define NGA_CACHED 0x0001 /* use cached attributes (if still valid) */
+#define NGA_UNCACHED 0x0002 /* fetch new attributes */
+#define NGA_ACL 0x0004 /* fetch ACL */
+#define NGA_MONITOR 0x0008 /* vnode monitor attr update poll */
+#define NGA_SOFT 0x0010 /* use cached attributes if ETIMEOUT */
+
+/* macros for initting/cleaning up nfs_vattr structures */
+#define NVATTR_INIT(NVAP) \
+ do { \
+ NFS_CLEAR_ATTRIBUTES((NVAP)->nva_bitmap); \
+ (NVAP)->nva_flags = 0; \
+ (NVAP)->nva_acl = NULL; \
+ } while (0)
+#define NVATTR_CLEANUP(NVAP) \
+ do { \
+ NFS_CLEAR_ATTRIBUTES((NVAP)->nva_bitmap); \
+ if ((NVAP)->nva_acl) { \
+ kauth_acl_free((NVAP)->nva_acl); \
+ (NVAP)->nva_acl = NULL; \
+ } \
+ } while (0)
+
+/*
+ * macros for detecting node changes
+ *
+ * These macros help us determine if a file has been changed on the server and
+ * thus whether or not we need to invalidate any cached data.
+ *
+ * For NFSv2/v3, the modification time is used.
+ * For NFSv4, the change attribute is used.
+ */
+#define NFS_CHANGED(VERS, NP, NVAP) \
+ (((VERS) >= NFS_VER4) ? \
+ ((NP)->n_change != (NVAP)->nva_change) : \
+ NFS_COMPARE_MTIME(&(NP)->n_mtime, (NVAP), !=))
+#define NFS_CHANGED_NC(VERS, NP, NVAP) \
+ (((VERS) >= NFS_VER4) ? \
+ ((NP)->n_ncchange != (NVAP)->nva_change) : \
+ NFS_COMPARE_MTIME(&(NP)->n_ncmtime, (NVAP), !=))
+#define NFS_CHANGED_UPDATE(VERS, NP, NVAP) \
+ do { \
+ if ((VERS) >= NFS_VER4) \
+ (NP)->n_change = (NVAP)->nva_change; \
+ else \
+ NFS_COPY_TIME(&(NP)->n_mtime, (NVAP), MODIFY); \
+ } while (0)
+#define NFS_CHANGED_UPDATE_NC(VERS, NP, NVAP) \
+ do { \
+ if ((VERS) >= NFS_VER4) \
+ (NP)->n_ncchange = (NVAP)->nva_change; \
+ else \
+ NFS_COPY_TIME(&(NP)->n_ncmtime, (NVAP), MODIFY); \
+ } while (0)
+
+
+extern lck_grp_t *nfs_open_grp;
+extern uint32_t nfs_open_owner_seqnum, nfs_lock_owner_seqnum;
+
+/*
+ * NFSv4 open owner structure - one per cred per mount
+ */
+struct nfs_open_owner {
+ TAILQ_ENTRY(nfs_open_owner) noo_link; /* List of open owners (on mount) */
+ lck_mtx_t noo_lock; /* owner mutex */
+ struct nfsmount * noo_mount; /* NFS mount */
+ uint32_t noo_refcnt; /* # outstanding references */
+ uint32_t noo_flags; /* see below */
+ kauth_cred_t noo_cred; /* credentials of open owner */
+ uint32_t noo_name; /* unique name used otw */
+ uint32_t noo_seqid; /* client-side sequence ID */
+ TAILQ_HEAD(,nfs_open_file) noo_opens; /* list of open files */
+};
+/* noo_flags */
+#define NFS_OPEN_OWNER_LINK 0x1 /* linked into mount's open owner list */
+#define NFS_OPEN_OWNER_BUSY 0x2 /* open state-modifying operation in progress */
+#define NFS_OPEN_OWNER_WANT 0x4 /* someone else wants to mark busy */
+
+/*
+ * NFS open file structure - one per open owner per nfsnode
+ */
+struct nfs_open_file {
+ lck_mtx_t nof_lock; /* open file mutex */
+ TAILQ_ENTRY(nfs_open_file) nof_link; /* list of open files */
+ TAILQ_ENTRY(nfs_open_file) nof_oolink; /* list of open owner's open files */
+ struct nfs_open_owner * nof_owner; /* open owner */
+ nfsnode_t nof_np; /* nfsnode this open is for */
+ nfs_stateid nof_stateid; /* open stateid */
+ thread_t nof_creator; /* thread that created file */
+ uint32_t nof_opencnt; /* open file count */
+ uint16_t nof_flags; /* see below */
+ uint8_t nof_access:4; /* access mode for this open */
+ uint8_t nof_deny:4; /* deny mode for this open */
+ uint8_t nof_mmap_access:4; /* mmap open access mode */
+ uint8_t nof_mmap_deny:4; /* mmap open deny mode */
+ /* counts of access/deny mode open combinations */
+ uint32_t nof_r; /* read opens (deny none) */
+ uint32_t nof_w; /* write opens (deny none) */
+ uint32_t nof_rw; /* read/write opens (deny none) */
+ uint32_t nof_r_dw; /* read deny-write opens */
+ /* the rest of the counts have a max of 2 (1 for open + 1 for mmap) */
+ uint32_t nof_w_dw:2; /* write deny-write opens (max 2) */
+ uint32_t nof_rw_dw:2; /* read/write deny-write opens (max 2) */
+ uint32_t nof_r_drw:2; /* read deny-read/write opens (max 2) */
+ uint32_t nof_w_drw:2; /* write deny-read/write opens (max 2) */
+ uint32_t nof_rw_drw:2; /* read/write deny-read/write opens (max 2) */
+ /* counts of DELEGATED access/deny mode open combinations */
+ uint32_t nof_d_w_dw:2; /* write deny-write opens (max 2) */
+ uint32_t nof_d_rw_dw:2; /* read/write deny-write opens (max 2) */
+ uint32_t nof_d_r_drw:2; /* read deny-read/write opens (max 2) */
+ uint32_t nof_d_w_drw:2; /* write deny-read/write opens (max 2) */
+ uint32_t nof_d_rw_drw:2; /* read/write deny-read/write opens (max 2) */
+ uint32_t nof_d_r; /* read opens (deny none) */
+ uint32_t nof_d_w; /* write opens (deny none) */
+ uint32_t nof_d_rw; /* read/write opens (deny none) */
+ uint32_t nof_d_r_dw; /* read deny-write opens */