+/*
+ * The nfsbuf is the nfs equivalent to a struct buf.
+ */
+struct nfsbuf {
+ LIST_ENTRY(nfsbuf) nb_hash; /* hash chain */
+ LIST_ENTRY(nfsbuf) nb_vnbufs; /* vnode's nfsbuf chain */
+ TAILQ_ENTRY(nfsbuf) nb_free; /* free list position if not active. */
+ volatile long nb_flags; /* NB_* flags. */
+ volatile long nb_lflags; /* NBL_* flags. */
+ volatile long nb_refs; /* outstanding references. */
+ long nb_bufsize; /* buffer size */
+ daddr64_t nb_lblkno; /* logical block number. */
+ time_t nb_timestamp; /* buffer timestamp */
+ int nb_error; /* errno value. */
+ u_int32_t nb_valid; /* valid pages in buf */
+ u_int32_t nb_dirty; /* dirty pages in buf */
+ int nb_validoff; /* offset in buffer of valid region. */
+ int nb_validend; /* offset of end of valid region. */
+ int nb_dirtyoff; /* offset in buffer of dirty region. */
+ int nb_dirtyend; /* offset of end of dirty region. */
+ caddr_t nb_data; /* mapped buffer */
+ vnode_t nb_vp; /* device vnode */
+ proc_t nb_proc; /* associated proc; NULL if kernel. */
+ struct ucred * nb_rcred; /* read credentials reference */
+ struct ucred * nb_wcred; /* write credentials reference */
+ void * nb_pagelist; /* upl */
+};
+
+#define NFS_MAXBSIZE (32 * PAGE_SIZE) /* valid/dirty page masks limit buffer size */
+
+/*
+ * These flags are kept in b_lflags...
+ * nfs_buf_mutex must be held before examining/updating
+ */
+#define NBL_BUSY 0x00000001 /* I/O in progress. */
+#define NBL_WANTED 0x00000002 /* Process wants this buffer. */
+
+/*
+ * These flags are kept in nb_flags and they're (purposefully)
+ * very similar to the B_* flags for struct buf.
+ * nfs_buf_mutex is not needed to examine/update these.
+ */
+#define NB_NEEDCOMMIT 0x00000002 /* Append-write in progress. */
+#define NB_ASYNC 0x00000004 /* Start I/O, do not wait. */
+#define NB_CACHE 0x00000020 /* Bread found us in the cache. */
+#define NB_STABLE 0x00000040 /* write FILESYNC not UNSTABLE. */
+#define NB_DELWRI 0x00000080 /* Delay I/O until buffer reused. */
+#define NB_DONE 0x00000200 /* I/O completed. */
+#define NB_EINTR 0x00000400 /* I/O was interrupted */
+#define NB_ERROR 0x00000800 /* I/O error occurred. */
+#define NB_WASDIRTY 0x00001000 /* page was found dirty in the VM cache */
+#define NB_INVAL 0x00002000 /* Does not contain valid info. */
+#define NB_NOCACHE 0x00008000 /* Do not cache block after use. */
+#define NB_READ 0x00100000 /* Read buffer. */
+#define NB_PAGELIST 0x00400000 /* Buffer describes pagelist I/O. */
+#define NB_WRITE 0x00000000 /* Write buffer (pseudo flag). */
+#define NB_WRITEINPROG 0x01000000 /* Write in progress. */
+#define NB_META 0x40000000 /* buffer contains meta-data. */
+#define NB_IOD 0x80000000 /* buffer being handled by nfsiod. */
+
+/* Flags for operation type in nfs_buf_get() */
+#define NBLK_READ 0x00000001 /* buffer for read */
+#define NBLK_WRITE 0x00000002 /* buffer for write */
+#define NBLK_META 0x00000004 /* buffer for metadata */
+#define NBLK_OPMASK 0x00000007 /* operation mask */
+/* modifiers for above flags... */
+#define NBLK_NOWAIT 0x40000000 /* don't wait on busy buffer */
+#define NBLK_ONLYVALID 0x80000000 /* only return cached buffer */
+
+/* These flags are used for nfsbuf iterating */
+#define NBI_ITER 0x01 /* iteration in progress */
+#define NBI_ITERWANT 0x02 /* waiting to iterate */
+#define NBI_CLEAN 0x04 /* requesting clean buffers */
+#define NBI_DIRTY 0x08 /* requesting dirty buffers */
+#define NBI_NOWAIT 0x10 /* don't block on NBI_ITER */
+
+/* Flags for nfs_buf_acquire */
+#define NBAC_NOWAIT 0x01 /* Don't wait if buffer is busy */
+#define NBAC_REMOVE 0x02 /* Remove from free list once buffer is acquired */
+
+/* some convenience macros... */
+#define NBOFF(BP) ((off_t)(BP)->nb_lblkno * (off_t)(BP)->nb_bufsize)
+#define NBPGVALID(BP,P) (((BP)->nb_valid >> (P)) & 0x1)
+#define NBPGDIRTY(BP,P) (((BP)->nb_dirty >> (P)) & 0x1)
+#define NBPGVALID_SET(BP,P) ((BP)->nb_valid |= (1 << (P)))
+#define NBPGDIRTY_SET(BP,P) ((BP)->nb_dirty |= (1 << (P)))
+
+#define NBUFSTAMPVALID(BP) ((BP)->nb_timestamp != ~0)
+#define NBUFSTAMPINVALIDATE(BP) ((BP)->nb_timestamp = ~0)
+
+#define NFS_BUF_MAP(BP) \
+ do { \
+ if (!(BP)->nb_data && nfs_buf_map(BP)) \
+ panic("nfs_buf_map failed"); \
+ } while (0)
+
+LIST_HEAD(nfsbuflists, nfsbuf);
+TAILQ_HEAD(nfsbuffreehead, nfsbuf);
+
+#define NFSNOLIST ((struct nfsbuf *)0xdeadbeef)
+
+extern lck_mtx_t *nfs_buf_mutex;
+extern int nfsbufcnt, nfsbufmin, nfsbufmax, nfsbufmetacnt, nfsbufmetamax;
+extern int nfsbuffreecnt, nfsbuffreemetacnt, nfsbufdelwricnt, nfsneedbuffer;
+extern int nfs_nbdwrite;
+extern struct nfsbuffreehead nfsbuffree, nfsbufdelwri;
+extern time_t nfsbuffreeuptimestamp;
+
+#define NFSBUFCNTCHK(locked) \
+ do { \
+ if (!locked) lck_mtx_lock(nfs_buf_mutex); \
+ if ( (nfsbufcnt < 0) || \
+ (nfsbufcnt > nfsbufmax) || \
+ (nfsbufmetacnt < 0) || \
+ (nfsbufmetacnt > nfsbufmetamax) || \
+ (nfsbufmetacnt > nfsbufcnt) || \
+ (nfsbuffreecnt < 0) || \
+ (nfsbuffreecnt > nfsbufmax) || \
+ (nfsbuffreecnt > nfsbufcnt) || \
+ (nfsbuffreemetacnt < 0) || \
+ (nfsbuffreemetacnt > nfsbufmax) || \
+ (nfsbuffreemetacnt > nfsbufcnt) || \
+ (nfsbuffreemetacnt > nfsbufmetamax) || \
+ (nfsbuffreemetacnt > nfsbufmetacnt) || \
+ (nfsbufdelwricnt < 0) || \
+ (nfsbufdelwricnt > nfsbufmax) || \
+ (nfsbufdelwricnt > nfsbufcnt) || \
+ (nfs_nbdwrite < 0) || \
+ (nfs_nbdwrite > nfsbufcnt) || \
+ 0) \
+ panic("nfsbuf count error: max %d meta %d cnt %d meta %d free %d meta %d delwr %d bdw %d\n", \
+ nfsbufmax, nfsbufmetamax, nfsbufcnt, nfsbufmetacnt, nfsbuffreecnt, nfsbuffreemetacnt, \
+ nfsbufdelwricnt, nfs_nbdwrite); \
+ if (!locked) lck_mtx_unlock(nfs_buf_mutex); \
+ } while (0)
+
+struct nfs_vattr {
+ enum vtype nva_type; /* vnode type (for create) */
+ u_short nva_mode; /* files access mode and type */
+ dev_t nva_rdev; /* device the special file represents */
+ uid_t nva_uid; /* owner user id */
+ gid_t nva_gid; /* owner group id */
+ uint32_t nva_fsid; /* file system id (dev for now) */
+ uint64_t nva_nlink; /* number of references to file */
+ uint64_t nva_fileid; /* file id */
+ uint64_t nva_size; /* file size in bytes */
+ uint64_t nva_bytes; /* bytes of disk space held by file */
+ uint32_t nva_blocksize; /* blocksize preferred for i/o */
+ struct timespec nva_atime; /* time of last access */
+ struct timespec nva_mtime; /* time of last modification */
+ struct timespec nva_ctime; /* time file changed */
+};
+