| 1 | /*- |
| 2 | * SPDX-License-Identifier: BSD-2-Clause |
| 3 | * |
| 4 | * Copyright (c) 2009 Rick Macklem, University of Guelph |
| 5 | * All rights reserved. |
| 6 | * |
| 7 | * Redistribution and use in source and binary forms, with or without |
| 8 | * modification, are permitted provided that the following conditions |
| 9 | * are met: |
| 10 | * 1. Redistributions of source code must retain the above copyright |
| 11 | * notice, this list of conditions and the following disclaimer. |
| 12 | * 2. Redistributions in binary form must reproduce the above copyright |
| 13 | * notice, this list of conditions and the following disclaimer in the |
| 14 | * documentation and/or other materials provided with the distribution. |
| 15 | * |
| 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 26 | * SUCH DAMAGE. |
| 27 | */ |
| 28 | |
| 29 | #ifndef _NFS_NFSRVSTATE_H_ |
| 30 | #define	_NFS_NFSRVSTATE_H_ |
| 31 | |
| 32 | #if defined(_KERNEL) || defined(KERNEL) |
| 33 | /* |
| 34 | * Definitions for NFS V4 server state handling. |
| 35 | */ |
| 36 | |
| 37 | /* |
| 38 | * List heads for nfsclient, nfsstate and nfslockfile. |
| 39 | * (Some systems seem to like to dynamically size these things, but I |
| 40 | * don't see any point in doing so for these ones.) |
| 41 | */ |
| 42 | LIST_HEAD(nfsclienthashhead, nfsclient); |
| 43 | LIST_HEAD(nfsstatehead, nfsstate); |
| 44 | LIST_HEAD(nfslockhead, nfslock); |
| 45 | LIST_HEAD(nfslockhashhead, nfslockfile); |
| 46 | LIST_HEAD(nfssessionhead, nfsdsession); |
| 47 | LIST_HEAD(nfssessionhashhead, nfsdsession); |
| 48 | TAILQ_HEAD(nfslayouthead, nfslayout); |
| 49 | SLIST_HEAD(nfsdsdirhead, nfsdsdir); |
| 50 | TAILQ_HEAD(nfsdevicehead, nfsdevice); |
| 51 | LIST_HEAD(nfsdontlisthead, nfsdontlist); |
| 52 | |
| 53 | /* |
| 54 | * List head for nfsusrgrp. |
| 55 | */ |
| 56 | TAILQ_HEAD(nfsuserhashhead, nfsusrgrp); |
| 57 | |
| 58 | #define	NFSCLIENTHASH(id)						\ |
| 59 | 	(&NFSD_VNET(nfsclienthash)[(id).lval[1] % nfsrv_clienthashsize]) |
| 60 | #define	NFSSTATEHASH(clp, id)						\ |
| 61 | 	(&((clp)->lc_stateid[(id).other[2] % nfsrv_statehashsize])) |
| 62 | #define	NFSUSERHASH(id)							\ |
| 63 | 	(&NFSD_VNET(nfsuserhash)[(id) % nfsrv_lughashsize]) |
| 64 | #define	NFSUSERNAMEHASH(p, l)						\ |
| 65 | 	(&NFSD_VNET(nfsusernamehash)[((l)>=4?(*(p)+*((p)+1)+*((p)+2)+*((p)+3)):*(p)) \ |
| 66 | 		% nfsrv_lughashsize]) |
| 67 | #define	NFSGROUPHASH(id)						\ |
| 68 | 	(&NFSD_VNET(nfsgrouphash)[(id) % nfsrv_lughashsize]) |
| 69 | #define	NFSGROUPNAMEHASH(p, l)						\ |
| 70 | 	(&NFSD_VNET(nfsgroupnamehash)[((l)>=4?(*(p)+*((p)+1)+*((p)+2)+*((p)+3)):*(p)) \ |
| 71 | 		% nfsrv_lughashsize]) |
| 72 | |
| 73 | struct nfssessionhash { |
| 74 | 	struct mtx			mtx; |
| 75 | 	struct nfssessionhashhead	list; |
| 76 | }; |
| 77 | #define	NFSSESSIONHASH(f) 						\ |
| 78 | 	(&NFSD_VNET(nfssessionhash)[nfsrv_hashsessionid(f) %		\ |
| 79 | 	 nfsrv_sessionhashsize]) |
| 80 | |
| 81 | struct nfslayouthash { |
| 82 | 	struct mtx		mtx; |
| 83 | 	struct nfslayouthead	list; |
| 84 | }; |
| 85 | #define	NFSLAYOUTHASH(f) 						\ |
| 86 | 	(&nfslayouthash[nfsrv_hashfh(f) % nfsrv_layouthashsize]) |
| 87 | |
| 88 | /* |
| 89 | * Client server structure for V4. It is doubly linked into two lists. |
| 90 | * The first is a hash table based on the clientid and the second is a |
| 91 | * list of all clients maintained in LRU order. |
| 92 | * The actual size malloc'd is large enough to accommodate the id string. |
| 93 | */ |
| 94 | struct nfsclient { |
| 95 | 	LIST_ENTRY(nfsclient) lc_hash;		/* Clientid hash list */ |
| 96 | 	struct nfsstatehead *lc_stateid;	/* Stateid hash */ |
| 97 | 	struct nfsstatehead lc_open;		/* Open owner list */ |
| 98 | 	struct nfsstatehead lc_deleg;		/* Delegations */ |
| 99 | 	struct nfsstatehead lc_olddeleg;	/* and old delegations */ |
| 100 | 	struct nfssessionhead lc_session;	/* List of NFSv4.1 sessions */ |
| 101 | 	uint64_t	lc_prevsess;		/* CreateSession cache */ |
| 102 | 	time_t		lc_expiry;		/* Expiry time (sec) */ |
| 103 | 	time_t		lc_delegtime;		/* Old deleg expiry (sec) */ |
| 104 | 	nfsquad_t	lc_clientid;		/* 64 bit clientid */ |
| 105 | 	nfsquad_t	lc_confirm;		/* 64 bit confirm value */ |
| 106 | 	nfsopbit_t	lc_mustops;		/* Must ops SP4_MACH_CRED */ |
| 107 | 	nfsopbit_t	lc_allowops;		/* Allowed ops SP4_MACH_CRED */ |
| 108 | 	u_int32_t	lc_program;		/* RPC Program # */ |
| 109 | 	u_int32_t	lc_callback;		/* Callback id */ |
| 110 | 	u_int32_t	lc_stateindex;		/* Current state index# */ |
| 111 | 	u_int32_t	lc_statemaxindex;	/* Max state index# */ |
| 112 | 	u_int32_t	lc_cbref;		/* Cnt of callbacks */ |
| 113 | 	uid_t		lc_uid;			/* User credential */ |
| 114 | 	gid_t		lc_gid; |
| 115 | 	u_int16_t	lc_idlen;		/* Client ID and len */ |
| 116 | 	u_int16_t	lc_namelen;		/* plus GSS principal and len */ |
| 117 | 	u_char		*lc_name; |
| 118 | 	struct nfssockreq lc_req;		/* Callback info */ |
| 119 | 	u_int32_t	lc_flags;		/* LCL_ flag bits */ |
| 120 | 	u_char		lc_verf[NFSX_VERF];	 /* client verifier */ |
| 121 | 	u_char		lc_id[1];		/* Malloc'd correct size */ |
| 122 | }; |
| 123 | |
| 124 | #define	CLOPS_CONFIRM		0x0001 |
| 125 | #define	CLOPS_RENEW		0x0002 |
| 126 | #define	CLOPS_RENEWOP		0x0004 |
| 127 | |
| 128 | /* |
| 129 | * Structure for NFSv4.1 Layouts. |
| 130 | * Malloc'd to correct size for the lay_xdr. |
| 131 | */ |
| 132 | struct nfslayout { |
| 133 | 	TAILQ_ENTRY(nfslayout)	lay_list; |
| 134 | 	nfsv4stateid_t		lay_stateid; |
| 135 | 	nfsquad_t		lay_clientid; |
| 136 | 	fhandle_t		lay_fh; |
| 137 | 	char			lay_deviceid[NFSX_V4DEVICEID]; |
| 138 | 	fsid_t			lay_fsid; |
| 139 | 	uint32_t		lay_layoutlen; |
| 140 | 	uint16_t		lay_mirrorcnt; |
| 141 | 	uint16_t		lay_trycnt; |
| 142 | 	uint16_t		lay_type; |
| 143 | 	uint16_t		lay_flags; |
| 144 | 	uint32_t		lay_xdr[0]; |
| 145 | }; |
| 146 | |
| 147 | /* Flags for lay_flags. */ |
| 148 | #define	NFSLAY_READ	0x0001 |
| 149 | #define	NFSLAY_RW	0x0002 |
| 150 | #define	NFSLAY_RECALL	0x0004 |
| 151 | #define	NFSLAY_RETURNED	0x0008 |
| 152 | #define	NFSLAY_CALLB	0x0010 |
| 153 | #define	NFSLAY_NOSPC	0x0020 |
| 154 | |
| 155 | /* |
| 156 | * Structure for an NFSv4.1 session. |
| 157 | * Locking rules for this structure. |
| 158 | * To add/delete one of these structures from the lists, you must lock |
| 159 | * both: NFSLOCKSTATE() and NFSLOCKSESSION(session hashhead) in that order. |
| 160 | * To traverse the lists looking for one of these, you must hold one |
| 161 | * of these two locks. |
| 162 | * The exception is if the thread holds the exclusive root sleep lock. |
| 163 | * In this case, all other nfsd threads are blocked, so locking the |
| 164 | * mutexes isn't required. |
| 165 | * When manipulating sess_refcnt, NFSLOCKSTATE() must be locked. |
| 166 | * When manipulating the fields withinsess_cbsess except nfsess_xprt, |
| 167 | * sess_cbsess.nfsess_mtx must be locked. |
| 168 | * When manipulating sess_slots and sess_cbsess.nfsess_xprt, |
| 169 | * NFSLOCKSESSION(session hashhead) must be locked. |
| 170 | */ |
| 171 | struct nfsdsession { |
| 172 | 	uint64_t		sess_refcnt;	/* Reference count. */ |
| 173 | 	LIST_ENTRY(nfsdsession)	sess_hash;	/* Hash list of sessions. */ |
| 174 | 	LIST_ENTRY(nfsdsession)	sess_list;	/* List of client sessions. */ |
| 175 | 	struct nfsslot		sess_slots[NFSV4_SLOTS]; |
| 176 | 	struct nfsclient	*sess_clp;	/* Associated clientid. */ |
| 177 | 	uint32_t		sess_crflags; |
| 178 | 	uint32_t		sess_cbprogram; |
| 179 | 	uint32_t		sess_maxreq; |
| 180 | 	uint32_t		sess_maxresp; |
| 181 | 	uint32_t		sess_maxrespcached; |
| 182 | 	uint32_t		sess_maxops; |
| 183 | 	uint32_t		sess_maxslots; |
| 184 | 	uint32_t		sess_cbmaxreq; |
| 185 | 	uint32_t		sess_cbmaxresp; |
| 186 | 	uint32_t		sess_cbmaxrespcached; |
| 187 | 	uint32_t		sess_cbmaxops; |
| 188 | 	uint8_t			sess_sessionid[NFSX_V4SESSIONID]; |
| 189 | 	struct nfsclsession	sess_cbsess;	/* Callback session. */ |
| 190 | }; |
| 191 | |
| 192 | /* |
| 193 | * Nfs state structure. I couldn't resist overloading this one, since |
| 194 | * it makes cleanup, etc. simpler. These structures are used in four ways: |
| 195 | * - open_owner structures chained off of nfsclient |
| 196 | * - open file structures chained off an open_owner structure |
| 197 | * - lock_owner structures chained off an open file structure |
| 198 | * - delegated file structures chained off of nfsclient and nfslockfile |
| 199 | * - the ls_list field is used for the chain it is in |
| 200 | * - the ls_head structure is used to chain off the sibling structure |
| 201 | * (it is a union between an nfsstate and nfslock structure head) |
| 202 | * If it is a lockowner stateid, nfslock structures hang off it. |
| 203 | * For the open file and lockowner cases, it is in the hash table in |
| 204 | * nfsclient for stateid. |
| 205 | */ |
| 206 | struct nfsstate { |
| 207 | 	LIST_ENTRY(nfsstate)	ls_hash;	/* Hash list entry */ |
| 208 | 	LIST_ENTRY(nfsstate)	ls_list;	/* List of opens/delegs */ |
| 209 | 	LIST_ENTRY(nfsstate)	ls_file;	/* Opens/Delegs for a file */ |
| 210 | 	union { |
| 211 | 		struct nfsstatehead	open; /* Opens list */ |
| 212 | 		struct nfslockhead	lock; /* Locks list */ |
| 213 | 	} ls_head; |
| 214 | 	nfsv4stateid_t		ls_stateid;	/* The state id */ |
| 215 | 	u_int32_t		ls_seq;		/* seq id */ |
| 216 | 	uid_t			ls_uid;		/* uid of locker */ |
| 217 | 	u_int32_t		ls_flags;	/* Type of lock, etc. */ |
| 218 | 	union { |
| 219 | 		struct nfsstate	*openowner;	/* Open only */ |
| 220 | 		u_int32_t	opentolockseq;	/* Lock call only */ |
| 221 | 		u_int32_t	noopens;	/* Openowner only */ |
| 222 | 		struct { |
| 223 | 			u_quad_t	filerev; /* Delegations only */ |
| 224 | 			time_t		expiry; |
| 225 | 			time_t		limit; |
| 226 | 			u_int64_t	compref; |
| 227 | 			time_t		last; |
| 228 | 		} deleg; |
| 229 | 	} ls_un; |
| 230 | 	struct nfslockfile	*ls_lfp;	/* Back pointer */ |
| 231 | 	struct nfsrvcache	*ls_op;		/* Op cache reference */ |
| 232 | 	struct nfsclient	*ls_clp;	/* Back pointer */ |
| 233 | 	u_short			ls_ownerlen;	/* Length of ls_owner */ |
| 234 | 	u_char			ls_owner[1];	/* malloc'd the correct size */ |
| 235 | }; |
| 236 | #define	ls_lock			ls_head.lock |
| 237 | #define	ls_open			ls_head.open |
| 238 | #define	ls_opentolockseq	ls_un.opentolockseq |
| 239 | #define	ls_openowner		ls_un.openowner |
| 240 | #define	ls_openstp		ls_un.openowner |
| 241 | #define	ls_noopens		ls_un.noopens |
| 242 | #define	ls_filerev		ls_un.deleg.filerev |
| 243 | #define	ls_delegtime		ls_un.deleg.expiry |
| 244 | #define	ls_delegtimelimit	ls_un.deleg.limit |
| 245 | #define	ls_compref		ls_un.deleg.compref |
| 246 | #define	ls_lastrecall		ls_un.deleg.last |
| 247 | |
| 248 | /* |
| 249 | * Nfs lock structure. |
| 250 | * This structure is chained off of the nfsstate (the lockowner) and |
| 251 | * nfslockfile (the file) structures, for the file and owner it |
| 252 | * refers to. It holds flags and a byte range. |
| 253 | * It also has back pointers to the associated lock_owner and lockfile. |
| 254 | */ |
| 255 | struct nfslock { |
| 256 | 	LIST_ENTRY(nfslock)	lo_lckowner; |
| 257 | 	LIST_ENTRY(nfslock)	lo_lckfile; |
| 258 | 	struct nfsstate		*lo_stp; |
| 259 | 	struct nfslockfile	*lo_lfp; |
| 260 | 	u_int64_t		lo_first; |
| 261 | 	u_int64_t		lo_end; |
| 262 | 	u_int32_t		lo_flags; |
| 263 | }; |
| 264 | |
| 265 | /* |
| 266 | * Structure used to return a conflicting lock. (Must be large |
| 267 | * enough for the largest lock owner we can have.) |
| 268 | */ |
| 269 | struct nfslockconflict { |
| 270 | 	nfsquad_t		cl_clientid; |
| 271 | 	u_int64_t		cl_first; |
| 272 | 	u_int64_t		cl_end; |
| 273 | 	u_int32_t		cl_flags; |
| 274 | 	u_short			cl_ownerlen; |
| 275 | 	u_char			cl_owner[NFSV4_OPAQUELIMIT]; |
| 276 | }; |
| 277 | |
| 278 | /* |
| 279 | * This structure is used to keep track of local locks that might need |
| 280 | * to be rolled back. |
| 281 | */ |
| 282 | struct nfsrollback { |
| 283 | 	LIST_ENTRY(nfsrollback)	rlck_list; |
| 284 | 	uint64_t		rlck_first; |
| 285 | 	uint64_t		rlck_end; |
| 286 | 	int			rlck_type; |
| 287 | }; |
| 288 | |
| 289 | /* |
| 290 | * This structure refers to a file for which lock(s) and/or open(s) exist. |
| 291 | * Searched via hash table on file handle or found via the back pointer from an |
| 292 | * open or lock owner. |
| 293 | */ |
| 294 | struct nfslockfile { |
| 295 | 	LIST_HEAD(, nfsstate)	lf_open;	/* Open list */ |
| 296 | 	LIST_HEAD(, nfsstate)	lf_deleg;	/* Delegation list */ |
| 297 | 	LIST_HEAD(, nfslock)	lf_lock;	/* Lock list */ |
| 298 | 	LIST_HEAD(, nfslock)	lf_locallock;	/* Local lock list */ |
| 299 | 	LIST_HEAD(, nfsrollback) lf_rollback;	/* Local lock rollback list */ |
| 300 | 	LIST_ENTRY(nfslockfile)	lf_hash;	/* Hash list entry */ |
| 301 | 	fhandle_t		lf_fh;		/* The file handle */ |
| 302 | 	struct nfsv4lock	lf_locallock_lck; /* serialize local locking */ |
| 303 | 	int			lf_usecount;	/* Ref count for locking */ |
| 304 | }; |
| 305 | |
| 306 | /* |
| 307 | * This structure is malloc'd an chained off hash lists for user/group |
| 308 | * names. |
| 309 | */ |
| 310 | struct nfsusrgrp { |
| 311 | 	TAILQ_ENTRY(nfsusrgrp)	lug_numhash;	/* Hash by id# */ |
| 312 | 	TAILQ_ENTRY(nfsusrgrp)	lug_namehash;	/* and by name */ |
| 313 | 	time_t			lug_expiry;	/* Expiry time in sec */ |
| 314 | 	union { |
| 315 | 		uid_t		un_uid;		/* id# */ |
| 316 | 		gid_t		un_gid; |
| 317 | 	} lug_un; |
| 318 | 	struct ucred		*lug_cred;	/* Cred. with groups list */ |
| 319 | 	int			lug_namelen;	/* Name length */ |
| 320 | 	u_char			lug_name[1];	/* malloc'd correct length */ |
| 321 | }; |
| 322 | #define	lug_uid		lug_un.un_uid |
| 323 | #define	lug_gid		lug_un.un_gid |
| 324 | |
| 325 | /* |
| 326 | * These structures are used for the stable storage restart stuff. |
| 327 | */ |
| 328 | /* |
| 329 | * Record at beginning of file. |
| 330 | */ |
| 331 | struct nfsf_rec { |
| 332 | 	u_int32_t	lease;			/* Lease duration */ |
| 333 | 	u_int32_t	numboots;		/* Number of boottimes */ |
| 334 | }; |
| 335 | |
| 336 | void nfsrv_cleanclient(struct nfsclient *, NFSPROC_T *, bool, SVCXPRT **); |
| 337 | void nfsrv_freedeleglist(struct nfsstatehead *); |
| 338 | |
| 339 | /* |
| 340 | * This structure is used to create the list of device info entries for |
| 341 | * a GetDeviceInfo operation and stores the DS server info. |
| 342 | * The nfsdev_addrandhost field has the fully qualified host domain name |
| 343 | * followed by the network address in XDR. |
| 344 | * It is allocated with nfsrv_dsdirsize nfsdev_dsdir[] entries. |
| 345 | */ |
| 346 | struct nfsdevice { |
| 347 | 	TAILQ_ENTRY(nfsdevice)	nfsdev_list; |
| 348 | 	vnode_t			nfsdev_dvp; |
| 349 | 	struct nfsmount		*nfsdev_nmp; |
| 350 | 	char			nfsdev_deviceid[NFSX_V4DEVICEID]; |
| 351 | 	uint16_t		nfsdev_hostnamelen; |
| 352 | 	uint16_t		nfsdev_fileaddrlen; |
| 353 | 	uint16_t		nfsdev_flexaddrlen; |
| 354 | 	uint16_t		nfsdev_mdsisset; |
| 355 | 	char			*nfsdev_fileaddr; |
| 356 | 	char			*nfsdev_flexaddr; |
| 357 | 	char			*nfsdev_host; |
| 358 | 	fsid_t			nfsdev_mdsfsid; |
| 359 | 	uint32_t		nfsdev_nextdir; |
| 360 | 	bool			nfsdev_nospc; |
| 361 | 	vnode_t			nfsdev_dsdir[0]; |
| 362 | }; |
| 363 | |
| 364 | /* |
| 365 | * This structure holds the va_size, va_filerev, va_atime, va_mtime and |
| 366 | * va_bytes for the DS file and is stored in the metadata file's extended |
| 367 | * attribute pnfsd.dsattr. |
| 368 | * opnfsdsattr was missing the va_bytes field and, as such, it was updated. |
| 369 | */ |
| 370 | struct opnfsdsattr { |
| 371 | 	uint64_t	dsa_filerev; |
| 372 | 	uint64_t	dsa_size; |
| 373 | 	struct timespec	dsa_atime; |
| 374 | 	struct timespec	dsa_mtime; |
| 375 | }; |
| 376 | |
| 377 | struct pnfsdsattr { |
| 378 | 	uint64_t	dsa_filerev; |
| 379 | 	uint64_t	dsa_size; |
| 380 | 	struct timespec	dsa_atime; |
| 381 | 	struct timespec	dsa_mtime; |
| 382 | 	uint64_t	dsa_bytes; |
| 383 | }; |
| 384 | |
| 385 | /* |
| 386 | * This structure is a list element for a list the pNFS server uses to |
| 387 | * mark that the recovery of a mirror file is in progress. |
| 388 | */ |
| 389 | struct nfsdontlist { |
| 390 | 	LIST_ENTRY(nfsdontlist)	nfsmr_list; |
| 391 | 	uint32_t		nfsmr_flags; |
| 392 | 	fhandle_t		nfsmr_fh; |
| 393 | }; |
| 394 | |
| 395 | /* nfsmr_flags bits. */ |
| 396 | #define	NFSMR_DONTLAYOUT	0x00000001 |
| 397 | |
| 398 | #endif	/* defined(_KERNEL) || defined(KERNEL) */ |
| 399 | |
| 400 | /* |
| 401 | * This structure holds the information about the DS file and is stored |
| 402 | * in the metadata file's extended attribute called pnfsd.dsfile. |
| 403 | */ |
| 404 | #define	PNFS_FILENAME_LEN	(2 * sizeof(fhandle_t)) |
| 405 | struct pnfsdsfile { |
| 406 | 	fhandle_t	dsf_fh; |
| 407 | 	uint32_t	dsf_dir; |
| 408 | 	union { |
| 409 | 		struct sockaddr_in	sin; |
| 410 | 		struct sockaddr_in6	sin6; |
| 411 | 	} dsf_nam; |
| 412 | 	char		dsf_filename[PNFS_FILENAME_LEN + 1]; |
| 413 | }; |
| 414 | #define	dsf_sin		dsf_nam.sin |
| 415 | #define	dsf_sin6	dsf_nam.sin6 |
| 416 | |
| 417 | #endif	/* _NFS_NFSRVSTATE_H_ */ |