4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
24 * Copyright (c) 2013 by Delphix. All rights reserved.
25 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
26 * Copyright (c) 2017 Joyent Inc
30 * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
31 * All rights reserved.
32 * Use is subject to license terms.
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/systm.h>
43 #include <sys/vnode.h>
44 #include <sys/pathname.h>
48 #include <sys/errno.h>
49 #include <sys/socket.h>
50 #include <sys/sysmacros.h>
51 #include <sys/siginfo.h>
52 #include <sys/tiuser.h>
53 #include <sys/statvfs.h>
54 #include <sys/stream.h>
55 #include <sys/strsun.h>
56 #include <sys/strsubr.h>
57 #include <sys/stropts.h>
58 #include <sys/timod.h>
59 #include <sys/t_kuser.h>
61 #include <sys/kstat.h>
62 #include <sys/dirent.h>
63 #include <sys/cmn_err.h>
64 #include <sys/debug.h>
65 #include <sys/unistd.h>
66 #include <sys/vtrace.h>
70 #include <sys/debug.h>
72 #include <rpc/types.h>
74 #include <rpc/auth_unix.h>
75 #include <rpc/auth_des.h>
78 #include <rpc/rpc_rdma.h>
81 #include <nfs/export.h>
82 #include <nfs/nfssys.h>
83 #include <nfs/nfs_clnt.h>
84 #include <nfs/nfs_acl.h>
85 #include <nfs/nfs_log.h>
86 #include <nfs/nfs_cmd.h>
88 #include <nfs/nfs_dispatch.h>
89 #include <nfs/nfs4_drc.h>
91 #include <sys/modctl.h>
94 const char *kinet_ntop6(uchar_t
*, char *, size_t);
97 * Module linkage information.
100 static struct modlmisc modlmisc
= {
101 &mod_miscops
, "NFS server module"
104 static struct modlinkage modlinkage
= {
105 MODREV_1
, (void *)&modlmisc
, NULL
108 kmem_cache_t
*nfs_xuio_cache
;
109 int nfs_loaned_buffers
= 0;
116 if ((status
= nfs_srvinit()) != 0) {
117 cmn_err(CE_WARN
, "_init: nfs_srvinit failed");
121 status
= mod_install((struct modlinkage
*)&modlinkage
);
124 * Could not load module, cleanup previous
125 * initialization work.
133 * Initialise some placeholders for nfssys() calls. These have
134 * to be declared by the nfs module, since that handles nfssys()
135 * calls - also used by NFS clients - but are provided by this
136 * nfssrv module. These also then serve as confirmation to the
137 * relevant code in nfs that nfssrv has been loaded, as they're
140 nfs_srv_quiesce_func
= nfs_srv_quiesce_all
;
141 nfs_srv_dss_func
= rfs4_dss_setpaths
;
143 /* setup DSS paths here; must be done before initial server startup */
144 rfs4_dss_paths
= rfs4_dss_oldpaths
= NULL
;
146 /* initialize the copy reduction caches */
148 nfs_xuio_cache
= kmem_cache_create("nfs_xuio_cache",
149 sizeof (nfs_xuio_t
), 0, NULL
, NULL
, NULL
, NULL
, NULL
, 0);
161 _info(struct modinfo
*modinfop
)
163 return (mod_info(&modlinkage
, modinfop
));
167 * PUBLICFH_CHECK() checks if the dispatch routine supports
168 * RPC_PUBLICFH_OK, if the filesystem is exported public, and if the
169 * incoming request is using the public filehandle. The check duplicates
170 * the exportmatch() call done in checkexport(), and we should consider
171 * modifying those routines to avoid the duplication. For now, we optimize
172 * by calling exportmatch() only after checking that the dispatch routine
173 * supports RPC_PUBLICFH_OK, and if the filesystem is explicitly exported
174 * public (i.e., not the placeholder).
176 #define PUBLICFH_CHECK(disp, exi, fsid, xfid) \
177 ((disp->dis_flags & RPC_PUBLICFH_OK) && \
178 ((exi->exi_export.ex_flags & EX_PUBLIC) || \
179 (exi == exi_public && exportmatch(exi_root, \
182 static void nfs_srv_shutdown_all(int);
183 static void rfs4_server_start(int);
184 static void nullfree(void);
185 static void rfs_dispatch(struct svc_req
*, SVCXPRT
*);
186 static void acl_dispatch(struct svc_req
*, SVCXPRT
*);
187 static void common_dispatch(struct svc_req
*, SVCXPRT
*,
188 rpcvers_t
, rpcvers_t
, char *,
189 struct rpc_disptable
*);
190 static void hanfsv4_failover(void);
191 static int checkauth(struct exportinfo
*, struct svc_req
*, cred_t
*, int,
193 static char *client_name(struct svc_req
*req
);
194 static char *client_addr(struct svc_req
*req
, char *buf
);
195 extern int sec_svc_getcred(struct svc_req
*, cred_t
*cr
, char **, int *);
196 extern bool_t
sec_svc_inrootlist(int, caddr_t
, int, caddr_t
*);
198 #define NFSLOG_COPY_NETBUF(exi, xprt, nb) { \
199 (nb)->maxlen = (xprt)->xp_rtaddr.maxlen; \
200 (nb)->len = (xprt)->xp_rtaddr.len; \
201 (nb)->buf = kmem_alloc((nb)->len, KM_SLEEP); \
202 bcopy((xprt)->xp_rtaddr.buf, (nb)->buf, (nb)->len); \
206 * Public Filehandle common nfs routines
208 static int MCLpath(char **);
209 static void URLparse(char *);
213 * This table is used by svc_getreq() to dispatch a request with
214 * a given prog/vers pair to an appropriate service provider
217 * NOTE: ordering is relied upon below when resetting the version min/max
218 * for NFS_PROGRAM. Careful, if this is ever changed.
220 static SVC_CALLOUT __nfs_sc_clts
[] = {
221 { NFS_PROGRAM
, NFS_VERSMIN
, NFS_VERSMAX
, rfs_dispatch
},
222 { NFS_ACL_PROGRAM
, NFS_ACL_VERSMIN
, NFS_ACL_VERSMAX
, acl_dispatch
}
225 static SVC_CALLOUT_TABLE nfs_sct_clts
= {
226 sizeof (__nfs_sc_clts
) / sizeof (__nfs_sc_clts
[0]), FALSE
,
230 static SVC_CALLOUT __nfs_sc_cots
[] = {
231 { NFS_PROGRAM
, NFS_VERSMIN
, NFS_VERSMAX
, rfs_dispatch
},
232 { NFS_ACL_PROGRAM
, NFS_ACL_VERSMIN
, NFS_ACL_VERSMAX
, acl_dispatch
}
235 static SVC_CALLOUT_TABLE nfs_sct_cots
= {
236 sizeof (__nfs_sc_cots
) / sizeof (__nfs_sc_cots
[0]), FALSE
, __nfs_sc_cots
239 static SVC_CALLOUT __nfs_sc_rdma
[] = {
240 { NFS_PROGRAM
, NFS_VERSMIN
, NFS_VERSMAX
, rfs_dispatch
},
241 { NFS_ACL_PROGRAM
, NFS_ACL_VERSMIN
, NFS_ACL_VERSMAX
, acl_dispatch
}
244 static SVC_CALLOUT_TABLE nfs_sct_rdma
= {
245 sizeof (__nfs_sc_rdma
) / sizeof (__nfs_sc_rdma
[0]), FALSE
, __nfs_sc_rdma
247 rpcvers_t nfs_versmin
= NFS_VERSMIN_DEFAULT
;
248 rpcvers_t nfs_versmax
= NFS_VERSMAX_DEFAULT
;
251 * Used to track the state of the server so that initialization
252 * can be done properly.
255 NFS_SERVER_STOPPED
, /* server state destroyed */
256 NFS_SERVER_STOPPING
, /* server state being destroyed */
258 NFS_SERVER_QUIESCED
, /* server state preserved */
259 NFS_SERVER_OFFLINE
/* server pool offline */
260 } nfs_server_running_t
;
262 static nfs_server_running_t nfs_server_upordown
;
263 static kmutex_t nfs_server_upordown_lock
;
264 static kcondvar_t nfs_server_upordown_cv
;
267 * DSS: distributed stable storage
268 * lists of all DSS paths: current, and before last warmstart
270 nvlist_t
*rfs4_dss_paths
, *rfs4_dss_oldpaths
;
272 int rfs4_dispatch(struct rpcdisp
*, struct svc_req
*, SVCXPRT
*, char *);
273 bool_t
rfs4_minorvers_mismatch(struct svc_req
*, SVCXPRT
*, void *);
276 * RDMA wait variables.
278 static kcondvar_t rdma_wait_cv
;
279 static kmutex_t rdma_wait_mutex
;
282 * Will be called at the point the server pool is being unregistered
283 * from the pool list. From that point onwards, the pool is waiting
284 * to be drained and as such the server state is stale and pertains
285 * to the old instantiation of the NFS server pool.
288 nfs_srv_offline(void)
290 mutex_enter(&nfs_server_upordown_lock
);
291 if (nfs_server_upordown
== NFS_SERVER_RUNNING
) {
292 nfs_server_upordown
= NFS_SERVER_OFFLINE
;
294 mutex_exit(&nfs_server_upordown_lock
);
298 * Will be called at the point the server pool is being destroyed so
299 * all transports have been closed and no service threads are in
302 * If we quiesce the server, we're shutting it down without destroying the
303 * server state. This allows it to warm start subsequently.
306 nfs_srv_stop_all(void)
309 nfs_srv_shutdown_all(quiesce
);
313 * This alternative shutdown routine can be requested via nfssys()
316 nfs_srv_quiesce_all(void)
319 nfs_srv_shutdown_all(quiesce
);
323 nfs_srv_shutdown_all(int quiesce
) {
324 mutex_enter(&nfs_server_upordown_lock
);
326 if (nfs_server_upordown
== NFS_SERVER_RUNNING
||
327 nfs_server_upordown
== NFS_SERVER_OFFLINE
) {
328 nfs_server_upordown
= NFS_SERVER_QUIESCED
;
329 cv_signal(&nfs_server_upordown_cv
);
331 /* reset DSS state, for subsequent warm restart */
332 rfs4_dss_numnewpaths
= 0;
333 rfs4_dss_newpaths
= NULL
;
335 cmn_err(CE_NOTE
, "nfs_server: server is now quiesced; "
336 "NFSv4 state has been preserved");
339 if (nfs_server_upordown
== NFS_SERVER_OFFLINE
) {
340 nfs_server_upordown
= NFS_SERVER_STOPPING
;
341 mutex_exit(&nfs_server_upordown_lock
);
343 rfs4_fini_drc(nfs4_drc
);
344 mutex_enter(&nfs_server_upordown_lock
);
345 nfs_server_upordown
= NFS_SERVER_STOPPED
;
346 cv_signal(&nfs_server_upordown_cv
);
349 mutex_exit(&nfs_server_upordown_lock
);
353 nfs_srv_set_sc_versions(struct file
*fp
, SVC_CALLOUT_TABLE
**sctpp
,
354 rpcvers_t versmin
, rpcvers_t versmax
)
356 struct strioctl strioc
;
357 struct T_info_ack tinfo
;
361 * Find out what type of transport this is.
363 strioc
.ic_cmd
= TI_GETINFO
;
364 strioc
.ic_timout
= -1;
365 strioc
.ic_len
= sizeof (tinfo
);
366 strioc
.ic_dp
= (char *)&tinfo
;
367 tinfo
.PRIM_type
= T_INFO_REQ
;
369 error
= strioctl(fp
->f_vnode
, I_STR
, (intptr_t)&strioc
, 0, K_TO_K
,
375 * Based on our query of the transport type...
377 * Reset the min/max versions based on the caller's request
378 * NOTE: This assumes that NFS_PROGRAM is first in the array!!
379 * And the second entry is the NFS_ACL_PROGRAM.
381 switch (tinfo
.SERV_type
) {
383 if (versmax
== NFS_V4
)
385 __nfs_sc_clts
[0].sc_versmin
= versmin
;
386 __nfs_sc_clts
[0].sc_versmax
= versmax
;
387 __nfs_sc_clts
[1].sc_versmin
= versmin
;
388 __nfs_sc_clts
[1].sc_versmax
= versmax
;
389 *sctpp
= &nfs_sct_clts
;
393 __nfs_sc_cots
[0].sc_versmin
= versmin
;
394 __nfs_sc_cots
[0].sc_versmax
= versmax
;
395 /* For the NFS_ACL program, check the max version */
396 if (versmax
> NFS_ACL_VERSMAX
)
397 versmax
= NFS_ACL_VERSMAX
;
398 __nfs_sc_cots
[1].sc_versmin
= versmin
;
399 __nfs_sc_cots
[1].sc_versmax
= versmax
;
400 *sctpp
= &nfs_sct_cots
;
410 * NFS Server system call.
411 * Does all of the work of running a NFS server.
412 * uap->fd is the fd of an open transport provider
415 nfs_svc(struct nfs_svc_args
*arg
, model_t model
)
421 char buf
[KNC_STRSIZE
];
423 STRUCT_HANDLE(nfs_svc_args
, uap
);
424 struct netbuf addrmask
;
425 SVC_CALLOUT_TABLE
*sctp
= NULL
;
428 STRUCT_SET_HANDLE(uap
, model
, arg
);
430 /* Check privileges in nfssys() */
432 if ((fp
= getf(STRUCT_FGET(uap
, fd
))) == NULL
)
436 * Set read buffer size to rsize
437 * and add room for RPC headers.
439 readsize
= nfs3tsize() + (RPC_MAXDATASIZE
- NFS_MAXDATA
);
440 if (readsize
< RPC_MAXDATASIZE
)
441 readsize
= RPC_MAXDATASIZE
;
443 error
= copyinstr((const char *)STRUCT_FGETP(uap
, netid
), buf
,
446 releasef(STRUCT_FGET(uap
, fd
));
450 addrmask
.len
= STRUCT_FGET(uap
, addrmask
.len
);
451 addrmask
.maxlen
= STRUCT_FGET(uap
, addrmask
.maxlen
);
452 addrmask
.buf
= kmem_alloc(addrmask
.maxlen
, KM_SLEEP
);
453 error
= copyin(STRUCT_FGETP(uap
, addrmask
.buf
), addrmask
.buf
,
456 releasef(STRUCT_FGET(uap
, fd
));
457 kmem_free(addrmask
.buf
, addrmask
.maxlen
);
461 nfs_versmin
= STRUCT_FGET(uap
, versmin
);
462 nfs_versmax
= STRUCT_FGET(uap
, versmax
);
464 /* Double check the vers min/max ranges */
465 if ((nfs_versmin
> nfs_versmax
) ||
466 (nfs_versmin
< NFS_VERSMIN
) ||
467 (nfs_versmax
> NFS_VERSMAX
)) {
468 nfs_versmin
= NFS_VERSMIN_DEFAULT
;
469 nfs_versmax
= NFS_VERSMAX_DEFAULT
;
473 nfs_srv_set_sc_versions(fp
, &sctp
, nfs_versmin
, nfs_versmax
)) {
474 releasef(STRUCT_FGET(uap
, fd
));
475 kmem_free(addrmask
.buf
, addrmask
.maxlen
);
479 /* Initialize nfsv4 server */
480 if (nfs_versmax
== (rpcvers_t
)NFS_V4
)
481 rfs4_server_start(STRUCT_FGET(uap
, delegation
));
483 /* Create a transport handle. */
484 error
= svc_tli_kcreate(fp
, readsize
, buf
, &addrmask
, &xprt
,
485 sctp
, NULL
, NFS_SVCPOOL_ID
, TRUE
);
488 kmem_free(addrmask
.buf
, addrmask
.maxlen
);
490 releasef(STRUCT_FGET(uap
, fd
));
496 rfs4_server_start(int nfs4_srv_delegation
)
499 * Determine if the server has previously been "started" and
500 * if not, do the per instance initialization
502 mutex_enter(&nfs_server_upordown_lock
);
504 if (nfs_server_upordown
!= NFS_SERVER_RUNNING
) {
505 /* Do we need to stop and wait on the previous server? */
506 while (nfs_server_upordown
== NFS_SERVER_STOPPING
||
507 nfs_server_upordown
== NFS_SERVER_OFFLINE
)
508 cv_wait(&nfs_server_upordown_cv
,
509 &nfs_server_upordown_lock
);
511 if (nfs_server_upordown
!= NFS_SERVER_RUNNING
) {
512 (void) svc_pool_control(NFS_SVCPOOL_ID
,
513 SVCPSET_UNREGISTER_PROC
, (void *)&nfs_srv_offline
);
514 (void) svc_pool_control(NFS_SVCPOOL_ID
,
515 SVCPSET_SHUTDOWN_PROC
, (void *)&nfs_srv_stop_all
);
517 /* is this an nfsd warm start? */
518 if (nfs_server_upordown
== NFS_SERVER_QUIESCED
) {
519 cmn_err(CE_NOTE
, "nfs_server: "
520 "server was previously quiesced; "
521 "existing NFSv4 state will be re-used");
525 nfs4_drc
= rfs4_init_drc(nfs4_drc_max
,
530 * Check to see if delegation is to be
531 * enabled at the server
533 if (nfs4_srv_delegation
!= FALSE
)
534 rfs4_set_deleg_policy(SRV_NORMAL_DELEGATE
);
536 nfs_server_upordown
= NFS_SERVER_RUNNING
;
538 cv_signal(&nfs_server_upordown_cv
);
540 mutex_exit(&nfs_server_upordown_lock
);
544 * If RDMA device available,
545 * start RDMA listener.
548 rdma_start(struct rdma_svc_args
*rsa
)
551 rdma_xprt_group_t started_rdma_xprts
;
555 /* Double check the vers min/max ranges */
556 if ((rsa
->nfs_versmin
> rsa
->nfs_versmax
) ||
557 (rsa
->nfs_versmin
< NFS_VERSMIN
) ||
558 (rsa
->nfs_versmax
> NFS_VERSMAX
)) {
559 rsa
->nfs_versmin
= NFS_VERSMIN_DEFAULT
;
560 rsa
->nfs_versmax
= NFS_VERSMAX_DEFAULT
;
562 nfs_versmin
= rsa
->nfs_versmin
;
563 nfs_versmax
= rsa
->nfs_versmax
;
565 /* Set the versions in the callout table */
566 __nfs_sc_rdma
[0].sc_versmin
= rsa
->nfs_versmin
;
567 __nfs_sc_rdma
[0].sc_versmax
= rsa
->nfs_versmax
;
568 /* For the NFS_ACL program, check the max version */
569 __nfs_sc_rdma
[1].sc_versmin
= rsa
->nfs_versmin
;
570 if (rsa
->nfs_versmax
> NFS_ACL_VERSMAX
)
571 __nfs_sc_rdma
[1].sc_versmax
= NFS_ACL_VERSMAX
;
573 __nfs_sc_rdma
[1].sc_versmax
= rsa
->nfs_versmax
;
575 /* Initialize nfsv4 server */
576 if (rsa
->nfs_versmax
== (rpcvers_t
)NFS_V4
)
577 rfs4_server_start(rsa
->delegation
);
579 started_rdma_xprts
.rtg_count
= 0;
580 started_rdma_xprts
.rtg_listhead
= NULL
;
581 started_rdma_xprts
.rtg_poolid
= rsa
->poolid
;
584 error
= svc_rdma_kcreate(rsa
->netid
, &nfs_sct_rdma
, rsa
->poolid
,
585 &started_rdma_xprts
);
592 * wait till either interrupted by a signal on
593 * nfs service stop/restart or signalled by a
594 * rdma plugin attach/detatch.
600 * stop services if running -- either on a HCA detach event
601 * or if the nfs service is stopped/restarted.
604 if ((stat
== RDMA_HCA_DETACH
|| stat
== RDMA_INTR
) &&
606 rdma_stop(&started_rdma_xprts
);
611 * nfs service stop/restart, break out of the
612 * wait loop and return;
614 if (stat
== RDMA_INTR
)
618 * restart stopped services on a HCA attach event
619 * (if not already running)
622 if ((stat
== RDMA_HCA_ATTACH
) && (svc_state
== 0))
626 * loop until a nfs service stop/restart
635 rpc_null(caddr_t
*argp
, caddr_t
*resp
, struct exportinfo
*exi
,
636 struct svc_req
*req
, cred_t
*cr
, bool_t ro
)
642 rpc_null_v3(caddr_t
*argp
, caddr_t
*resp
, struct exportinfo
*exi
,
643 struct svc_req
*req
, cred_t
*cr
, bool_t ro
)
645 DTRACE_NFSV3_3(op__null__start
, struct svc_req
*, req
,
646 cred_t
*, cr
, vnode_t
*, NULL
);
647 DTRACE_NFSV3_3(op__null__done
, struct svc_req
*, req
,
648 cred_t
*, cr
, vnode_t
*, NULL
);
653 rfs_error(caddr_t
*argp
, caddr_t
*resp
, struct exportinfo
*exi
,
654 struct svc_req
*req
, cred_t
*cr
, bool_t ro
)
656 /* return (EOPNOTSUPP); */
664 static char *rfscallnames_v2
[] = {
685 static struct rpcdisp rfsdisptab_v2
[] = {
692 xdr_void
, NULL_xdrproc_t
, 0,
693 xdr_void
, NULL_xdrproc_t
, 0,
694 nullfree
, RPC_IDEMPOTENT
,
697 /* RFS_GETATTR = 1 */
699 xdr_fhandle
, xdr_fastfhandle
, sizeof (fhandle_t
),
700 xdr_attrstat
, xdr_fastattrstat
, sizeof (struct nfsattrstat
),
701 nullfree
, RPC_IDEMPOTENT
|RPC_ALLOWANON
|RPC_MAPRESP
,
704 /* RFS_SETATTR = 2 */
706 xdr_saargs
, NULL_xdrproc_t
, sizeof (struct nfssaargs
),
707 xdr_attrstat
, xdr_fastattrstat
, sizeof (struct nfsattrstat
),
708 nullfree
, RPC_MAPRESP
,
711 /* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
713 xdr_void
, NULL_xdrproc_t
, 0,
714 xdr_void
, NULL_xdrproc_t
, 0,
715 nullfree
, RPC_IDEMPOTENT
,
720 xdr_diropargs
, NULL_xdrproc_t
, sizeof (struct nfsdiropargs
),
721 xdr_diropres
, xdr_fastdiropres
, sizeof (struct nfsdiropres
),
722 nullfree
, RPC_IDEMPOTENT
|RPC_MAPRESP
|RPC_PUBLICFH_OK
,
725 /* RFS_READLINK = 5 */
727 xdr_fhandle
, xdr_fastfhandle
, sizeof (fhandle_t
),
728 xdr_rdlnres
, NULL_xdrproc_t
, sizeof (struct nfsrdlnres
),
729 rfs_rlfree
, RPC_IDEMPOTENT
,
734 xdr_readargs
, NULL_xdrproc_t
, sizeof (struct nfsreadargs
),
735 xdr_rdresult
, NULL_xdrproc_t
, sizeof (struct nfsrdresult
),
736 rfs_rdfree
, RPC_IDEMPOTENT
,
739 /* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
741 xdr_void
, NULL_xdrproc_t
, 0,
742 xdr_void
, NULL_xdrproc_t
, 0,
743 nullfree
, RPC_IDEMPOTENT
,
748 xdr_writeargs
, NULL_xdrproc_t
, sizeof (struct nfswriteargs
),
749 xdr_attrstat
, xdr_fastattrstat
, sizeof (struct nfsattrstat
),
750 nullfree
, RPC_MAPRESP
,
755 xdr_creatargs
, NULL_xdrproc_t
, sizeof (struct nfscreatargs
),
756 xdr_diropres
, xdr_fastdiropres
, sizeof (struct nfsdiropres
),
757 nullfree
, RPC_MAPRESP
,
760 /* RFS_REMOVE = 10 */
762 xdr_diropargs
, NULL_xdrproc_t
, sizeof (struct nfsdiropargs
),
763 #ifdef _LITTLE_ENDIAN
764 xdr_enum
, xdr_fastenum
, sizeof (enum nfsstat
),
766 xdr_enum
, NULL_xdrproc_t
, sizeof (enum nfsstat
),
768 nullfree
, RPC_MAPRESP
,
771 /* RFS_RENAME = 11 */
773 xdr_rnmargs
, NULL_xdrproc_t
, sizeof (struct nfsrnmargs
),
774 #ifdef _LITTLE_ENDIAN
775 xdr_enum
, xdr_fastenum
, sizeof (enum nfsstat
),
777 xdr_enum
, NULL_xdrproc_t
, sizeof (enum nfsstat
),
779 nullfree
, RPC_MAPRESP
,
784 xdr_linkargs
, NULL_xdrproc_t
, sizeof (struct nfslinkargs
),
785 #ifdef _LITTLE_ENDIAN
786 xdr_enum
, xdr_fastenum
, sizeof (enum nfsstat
),
788 xdr_enum
, NULL_xdrproc_t
, sizeof (enum nfsstat
),
790 nullfree
, RPC_MAPRESP
,
793 /* RFS_SYMLINK = 13 */
795 xdr_slargs
, NULL_xdrproc_t
, sizeof (struct nfsslargs
),
796 #ifdef _LITTLE_ENDIAN
797 xdr_enum
, xdr_fastenum
, sizeof (enum nfsstat
),
799 xdr_enum
, NULL_xdrproc_t
, sizeof (enum nfsstat
),
801 nullfree
, RPC_MAPRESP
,
806 xdr_creatargs
, NULL_xdrproc_t
, sizeof (struct nfscreatargs
),
807 xdr_diropres
, xdr_fastdiropres
, sizeof (struct nfsdiropres
),
808 nullfree
, RPC_MAPRESP
,
813 xdr_diropargs
, NULL_xdrproc_t
, sizeof (struct nfsdiropargs
),
814 #ifdef _LITTLE_ENDIAN
815 xdr_enum
, xdr_fastenum
, sizeof (enum nfsstat
),
817 xdr_enum
, NULL_xdrproc_t
, sizeof (enum nfsstat
),
819 nullfree
, RPC_MAPRESP
,
822 /* RFS_READDIR = 16 */
824 xdr_rddirargs
, NULL_xdrproc_t
, sizeof (struct nfsrddirargs
),
825 xdr_putrddirres
, NULL_xdrproc_t
, sizeof (struct nfsrddirres
),
826 rfs_rddirfree
, RPC_IDEMPOTENT
,
829 /* RFS_STATFS = 17 */
831 xdr_fhandle
, xdr_fastfhandle
, sizeof (fhandle_t
),
832 xdr_statfs
, xdr_faststatfs
, sizeof (struct nfsstatfs
),
833 nullfree
, RPC_IDEMPOTENT
|RPC_ALLOWANON
|RPC_MAPRESP
,
837 static char *rfscallnames_v3
[] = {
862 static struct rpcdisp rfsdisptab_v3
[] = {
869 xdr_void
, NULL_xdrproc_t
, 0,
870 xdr_void
, NULL_xdrproc_t
, 0,
871 nullfree
, RPC_IDEMPOTENT
,
874 /* RFS3_GETATTR = 1 */
876 xdr_nfs_fh3_server
, NULL_xdrproc_t
, sizeof (GETATTR3args
),
877 xdr_GETATTR3res
, NULL_xdrproc_t
, sizeof (GETATTR3res
),
878 nullfree
, (RPC_IDEMPOTENT
| RPC_ALLOWANON
),
881 /* RFS3_SETATTR = 2 */
883 xdr_SETATTR3args
, NULL_xdrproc_t
, sizeof (SETATTR3args
),
884 xdr_SETATTR3res
, NULL_xdrproc_t
, sizeof (SETATTR3res
),
888 /* RFS3_LOOKUP = 3 */
890 xdr_diropargs3
, NULL_xdrproc_t
, sizeof (LOOKUP3args
),
891 xdr_LOOKUP3res
, NULL_xdrproc_t
, sizeof (LOOKUP3res
),
892 nullfree
, (RPC_IDEMPOTENT
| RPC_PUBLICFH_OK
),
895 /* RFS3_ACCESS = 4 */
897 xdr_ACCESS3args
, NULL_xdrproc_t
, sizeof (ACCESS3args
),
898 xdr_ACCESS3res
, NULL_xdrproc_t
, sizeof (ACCESS3res
),
899 nullfree
, RPC_IDEMPOTENT
,
902 /* RFS3_READLINK = 5 */
904 xdr_nfs_fh3_server
, NULL_xdrproc_t
, sizeof (READLINK3args
),
905 xdr_READLINK3res
, NULL_xdrproc_t
, sizeof (READLINK3res
),
906 rfs3_readlink_free
, RPC_IDEMPOTENT
,
907 rfs3_readlink_getfh
},
911 xdr_READ3args
, NULL_xdrproc_t
, sizeof (READ3args
),
912 xdr_READ3res
, NULL_xdrproc_t
, sizeof (READ3res
),
913 rfs3_read_free
, RPC_IDEMPOTENT
,
918 xdr_WRITE3args
, NULL_xdrproc_t
, sizeof (WRITE3args
),
919 xdr_WRITE3res
, NULL_xdrproc_t
, sizeof (WRITE3res
),
923 /* RFS3_CREATE = 8 */
925 xdr_CREATE3args
, NULL_xdrproc_t
, sizeof (CREATE3args
),
926 xdr_CREATE3res
, NULL_xdrproc_t
, sizeof (CREATE3res
),
932 xdr_MKDIR3args
, NULL_xdrproc_t
, sizeof (MKDIR3args
),
933 xdr_MKDIR3res
, NULL_xdrproc_t
, sizeof (MKDIR3res
),
937 /* RFS3_SYMLINK = 10 */
939 xdr_SYMLINK3args
, NULL_xdrproc_t
, sizeof (SYMLINK3args
),
940 xdr_SYMLINK3res
, NULL_xdrproc_t
, sizeof (SYMLINK3res
),
944 /* RFS3_MKNOD = 11 */
946 xdr_MKNOD3args
, NULL_xdrproc_t
, sizeof (MKNOD3args
),
947 xdr_MKNOD3res
, NULL_xdrproc_t
, sizeof (MKNOD3res
),
951 /* RFS3_REMOVE = 12 */
953 xdr_diropargs3
, NULL_xdrproc_t
, sizeof (REMOVE3args
),
954 xdr_REMOVE3res
, NULL_xdrproc_t
, sizeof (REMOVE3res
),
958 /* RFS3_RMDIR = 13 */
960 xdr_diropargs3
, NULL_xdrproc_t
, sizeof (RMDIR3args
),
961 xdr_RMDIR3res
, NULL_xdrproc_t
, sizeof (RMDIR3res
),
965 /* RFS3_RENAME = 14 */
967 xdr_RENAME3args
, NULL_xdrproc_t
, sizeof (RENAME3args
),
968 xdr_RENAME3res
, NULL_xdrproc_t
, sizeof (RENAME3res
),
974 xdr_LINK3args
, NULL_xdrproc_t
, sizeof (LINK3args
),
975 xdr_LINK3res
, NULL_xdrproc_t
, sizeof (LINK3res
),
979 /* RFS3_READDIR = 16 */
981 xdr_READDIR3args
, NULL_xdrproc_t
, sizeof (READDIR3args
),
982 xdr_READDIR3res
, NULL_xdrproc_t
, sizeof (READDIR3res
),
983 rfs3_readdir_free
, RPC_IDEMPOTENT
,
986 /* RFS3_READDIRPLUS = 17 */
988 xdr_READDIRPLUS3args
, NULL_xdrproc_t
, sizeof (READDIRPLUS3args
),
989 xdr_READDIRPLUS3res
, NULL_xdrproc_t
, sizeof (READDIRPLUS3res
),
990 rfs3_readdirplus_free
, RPC_AVOIDWORK
,
991 rfs3_readdirplus_getfh
},
993 /* RFS3_FSSTAT = 18 */
995 xdr_nfs_fh3_server
, NULL_xdrproc_t
, sizeof (FSSTAT3args
),
996 xdr_FSSTAT3res
, NULL_xdrproc_t
, sizeof (FSSTAT3res
),
997 nullfree
, RPC_IDEMPOTENT
,
1000 /* RFS3_FSINFO = 19 */
1002 xdr_nfs_fh3_server
, NULL_xdrproc_t
, sizeof (FSINFO3args
),
1003 xdr_FSINFO3res
, NULL_xdrproc_t
, sizeof (FSINFO3res
),
1004 nullfree
, RPC_IDEMPOTENT
|RPC_ALLOWANON
,
1007 /* RFS3_PATHCONF = 20 */
1009 xdr_nfs_fh3_server
, NULL_xdrproc_t
, sizeof (PATHCONF3args
),
1010 xdr_PATHCONF3res
, NULL_xdrproc_t
, sizeof (PATHCONF3res
),
1011 nullfree
, RPC_IDEMPOTENT
,
1012 rfs3_pathconf_getfh
},
1014 /* RFS3_COMMIT = 21 */
1016 xdr_COMMIT3args
, NULL_xdrproc_t
, sizeof (COMMIT3args
),
1017 xdr_COMMIT3res
, NULL_xdrproc_t
, sizeof (COMMIT3res
),
1018 nullfree
, RPC_IDEMPOTENT
,
1022 static char *rfscallnames_v4
[] = {
1034 static struct rpcdisp rfsdisptab_v4
[] = {
1041 xdr_void
, NULL_xdrproc_t
, 0,
1042 xdr_void
, NULL_xdrproc_t
, 0,
1043 nullfree
, RPC_IDEMPOTENT
, 0},
1045 /* RFS4_compound = 1 */
1047 xdr_COMPOUND4args_srv
, NULL_xdrproc_t
, sizeof (COMPOUND4args
),
1048 xdr_COMPOUND4res_srv
, NULL_xdrproc_t
, sizeof (COMPOUND4res
),
1049 rfs4_compound_free
, 0, 0},
1059 /* RFS_GETATTR = 1 */
1060 fhandle_t nfs2_getattr_args
;
1062 /* RFS_SETATTR = 2 */
1063 struct nfssaargs nfs2_setattr_args
;
1065 /* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
1067 /* RFS_LOOKUP = 4 */
1068 struct nfsdiropargs nfs2_lookup_args
;
1070 /* RFS_READLINK = 5 */
1071 fhandle_t nfs2_readlink_args
;
1074 struct nfsreadargs nfs2_read_args
;
1076 /* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
1079 struct nfswriteargs nfs2_write_args
;
1081 /* RFS_CREATE = 9 */
1082 struct nfscreatargs nfs2_create_args
;
1084 /* RFS_REMOVE = 10 */
1085 struct nfsdiropargs nfs2_remove_args
;
1087 /* RFS_RENAME = 11 */
1088 struct nfsrnmargs nfs2_rename_args
;
1091 struct nfslinkargs nfs2_link_args
;
1093 /* RFS_SYMLINK = 13 */
1094 struct nfsslargs nfs2_symlink_args
;
1096 /* RFS_MKDIR = 14 */
1097 struct nfscreatargs nfs2_mkdir_args
;
1099 /* RFS_RMDIR = 15 */
1100 struct nfsdiropargs nfs2_rmdir_args
;
1102 /* RFS_READDIR = 16 */
1103 struct nfsrddirargs nfs2_readdir_args
;
1105 /* RFS_STATFS = 17 */
1106 fhandle_t nfs2_statfs_args
;
1114 /* RFS3_GETATTR = 1 */
1115 GETATTR3args nfs3_getattr_args
;
1117 /* RFS3_SETATTR = 2 */
1118 SETATTR3args nfs3_setattr_args
;
1120 /* RFS3_LOOKUP = 3 */
1121 LOOKUP3args nfs3_lookup_args
;
1123 /* RFS3_ACCESS = 4 */
1124 ACCESS3args nfs3_access_args
;
1126 /* RFS3_READLINK = 5 */
1127 READLINK3args nfs3_readlink_args
;
1130 READ3args nfs3_read_args
;
1132 /* RFS3_WRITE = 7 */
1133 WRITE3args nfs3_write_args
;
1135 /* RFS3_CREATE = 8 */
1136 CREATE3args nfs3_create_args
;
1138 /* RFS3_MKDIR = 9 */
1139 MKDIR3args nfs3_mkdir_args
;
1141 /* RFS3_SYMLINK = 10 */
1142 SYMLINK3args nfs3_symlink_args
;
1144 /* RFS3_MKNOD = 11 */
1145 MKNOD3args nfs3_mknod_args
;
1147 /* RFS3_REMOVE = 12 */
1148 REMOVE3args nfs3_remove_args
;
1150 /* RFS3_RMDIR = 13 */
1151 RMDIR3args nfs3_rmdir_args
;
1153 /* RFS3_RENAME = 14 */
1154 RENAME3args nfs3_rename_args
;
1156 /* RFS3_LINK = 15 */
1157 LINK3args nfs3_link_args
;
1159 /* RFS3_READDIR = 16 */
1160 READDIR3args nfs3_readdir_args
;
1162 /* RFS3_READDIRPLUS = 17 */
1163 READDIRPLUS3args nfs3_readdirplus_args
;
1165 /* RFS3_FSSTAT = 18 */
1166 FSSTAT3args nfs3_fsstat_args
;
1168 /* RFS3_FSINFO = 19 */
1169 FSINFO3args nfs3_fsinfo_args
;
1171 /* RFS3_PATHCONF = 20 */
1172 PATHCONF3args nfs3_pathconf_args
;
1174 /* RFS3_COMMIT = 21 */
1175 COMMIT3args nfs3_commit_args
;
1184 COMPOUND4args nfs4_compound_args
;
1194 /* RFS_GETATTR = 1 */
1195 struct nfsattrstat nfs2_getattr_res
;
1197 /* RFS_SETATTR = 2 */
1198 struct nfsattrstat nfs2_setattr_res
;
1200 /* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
1202 /* RFS_LOOKUP = 4 */
1203 struct nfsdiropres nfs2_lookup_res
;
1205 /* RFS_READLINK = 5 */
1206 struct nfsrdlnres nfs2_readlink_res
;
1209 struct nfsrdresult nfs2_read_res
;
1211 /* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
1214 struct nfsattrstat nfs2_write_res
;
1216 /* RFS_CREATE = 9 */
1217 struct nfsdiropres nfs2_create_res
;
1219 /* RFS_REMOVE = 10 */
1220 enum nfsstat nfs2_remove_res
;
1222 /* RFS_RENAME = 11 */
1223 enum nfsstat nfs2_rename_res
;
1226 enum nfsstat nfs2_link_res
;
1228 /* RFS_SYMLINK = 13 */
1229 enum nfsstat nfs2_symlink_res
;
1231 /* RFS_MKDIR = 14 */
1232 struct nfsdiropres nfs2_mkdir_res
;
1234 /* RFS_RMDIR = 15 */
1235 enum nfsstat nfs2_rmdir_res
;
1237 /* RFS_READDIR = 16 */
1238 struct nfsrddirres nfs2_readdir_res
;
1240 /* RFS_STATFS = 17 */
1241 struct nfsstatfs nfs2_statfs_res
;
1249 /* RFS3_GETATTR = 1 */
1250 GETATTR3res nfs3_getattr_res
;
1252 /* RFS3_SETATTR = 2 */
1253 SETATTR3res nfs3_setattr_res
;
1255 /* RFS3_LOOKUP = 3 */
1256 LOOKUP3res nfs3_lookup_res
;
1258 /* RFS3_ACCESS = 4 */
1259 ACCESS3res nfs3_access_res
;
1261 /* RFS3_READLINK = 5 */
1262 READLINK3res nfs3_readlink_res
;
1265 READ3res nfs3_read_res
;
1267 /* RFS3_WRITE = 7 */
1268 WRITE3res nfs3_write_res
;
1270 /* RFS3_CREATE = 8 */
1271 CREATE3res nfs3_create_res
;
1273 /* RFS3_MKDIR = 9 */
1274 MKDIR3res nfs3_mkdir_res
;
1276 /* RFS3_SYMLINK = 10 */
1277 SYMLINK3res nfs3_symlink_res
;
1279 /* RFS3_MKNOD = 11 */
1280 MKNOD3res nfs3_mknod_res
;
1282 /* RFS3_REMOVE = 12 */
1283 REMOVE3res nfs3_remove_res
;
1285 /* RFS3_RMDIR = 13 */
1286 RMDIR3res nfs3_rmdir_res
;
1288 /* RFS3_RENAME = 14 */
1289 RENAME3res nfs3_rename_res
;
1291 /* RFS3_LINK = 15 */
1292 LINK3res nfs3_link_res
;
1294 /* RFS3_READDIR = 16 */
1295 READDIR3res nfs3_readdir_res
;
1297 /* RFS3_READDIRPLUS = 17 */
1298 READDIRPLUS3res nfs3_readdirplus_res
;
1300 /* RFS3_FSSTAT = 18 */
1301 FSSTAT3res nfs3_fsstat_res
;
1303 /* RFS3_FSINFO = 19 */
1304 FSINFO3res nfs3_fsinfo_res
;
1306 /* RFS3_PATHCONF = 20 */
1307 PATHCONF3res nfs3_pathconf_res
;
1309 /* RFS3_COMMIT = 21 */
1310 COMMIT3res nfs3_commit_res
;
1318 /* RFS4_COMPOUND = 1 */
1319 COMPOUND4res nfs4_compound_res
;
1323 static struct rpc_disptable rfs_disptable
[] = {
1324 {sizeof (rfsdisptab_v2
) / sizeof (rfsdisptab_v2
[0]),
1326 &rfsproccnt_v2_ptr
, rfsdisptab_v2
},
1327 {sizeof (rfsdisptab_v3
) / sizeof (rfsdisptab_v3
[0]),
1329 &rfsproccnt_v3_ptr
, rfsdisptab_v3
},
1330 {sizeof (rfsdisptab_v4
) / sizeof (rfsdisptab_v4
[0]),
1332 &rfsproccnt_v4_ptr
, rfsdisptab_v4
},
1336 * If nfs_portmon is set, then clients are required to use privileged
1337 * ports (ports < IPPORT_RESERVED) in order to get NFS services.
1339 * N.B.: this attempt to carry forward the already ill-conceived notion
1340 * of privileged ports for TCP/UDP is really quite ineffectual. Not only
1341 * is it transport-dependent, it's laughably easy to spoof. If you're
1342 * really interested in security, you must start with secure RPC instead.
1344 static int nfs_portmon
= 0;
1347 static int cred_hits
= 0;
1348 static int cred_misses
= 0;
1354 * Debug code to allow disabling of rfs_dispatch() use of
1355 * fastxdrargs() and fastxdrres() calls for testing purposes.
1357 static int rfs_no_fast_xdrargs
= 0;
1358 static int rfs_no_fast_xdrres
= 0;
1368 /* ACL2_GETACL = 1 */
1369 GETACL2args acl2_getacl_args
;
1371 /* ACL2_SETACL = 2 */
1372 SETACL2args acl2_setacl_args
;
1374 /* ACL2_GETATTR = 3 */
1375 GETATTR2args acl2_getattr_args
;
1377 /* ACL2_ACCESS = 4 */
1378 ACCESS2args acl2_access_args
;
1380 /* ACL2_GETXATTRDIR = 5 */
1381 GETXATTRDIR2args acl2_getxattrdir_args
;
1389 /* ACL3_GETACL = 1 */
1390 GETACL3args acl3_getacl_args
;
1392 /* ACL3_SETACL = 2 */
1393 SETACL3args acl3_setacl
;
1395 /* ACL3_GETXATTRDIR = 3 */
1396 GETXATTRDIR3args acl3_getxattrdir_args
;
1407 /* ACL2_GETACL = 1 */
1408 GETACL2res acl2_getacl_res
;
1410 /* ACL2_SETACL = 2 */
1411 SETACL2res acl2_setacl_res
;
1413 /* ACL2_GETATTR = 3 */
1414 GETATTR2res acl2_getattr_res
;
1416 /* ACL2_ACCESS = 4 */
1417 ACCESS2res acl2_access_res
;
1419 /* ACL2_GETXATTRDIR = 5 */
1420 GETXATTRDIR2args acl2_getxattrdir_res
;
1428 /* ACL3_GETACL = 1 */
1429 GETACL3res acl3_getacl_res
;
1431 /* ACL3_SETACL = 2 */
1432 SETACL3res acl3_setacl_res
;
1434 /* ACL3_GETXATTRDIR = 3 */
1435 GETXATTRDIR3res acl3_getxattrdir_res
;
1440 auth_tooweak(struct svc_req
*req
, char *res
)
1443 if (req
->rq_vers
== NFS_VERSION
&& req
->rq_proc
== RFS_LOOKUP
) {
1444 struct nfsdiropres
*dr
= (struct nfsdiropres
*)res
;
1445 if ((enum wnfsstat
)dr
->dr_status
== WNFSERR_CLNT_FLAVOR
)
1447 } else if (req
->rq_vers
== NFS_V3
&& req
->rq_proc
== NFSPROC3_LOOKUP
) {
1448 LOOKUP3res
*resp
= (LOOKUP3res
*)res
;
1449 if ((enum wnfsstat
)resp
->status
== WNFSERR_CLNT_FLAVOR
)
1457 common_dispatch(struct svc_req
*req
, SVCXPRT
*xprt
, rpcvers_t min_vers
,
1458 rpcvers_t max_vers
, char *pgmname
,
1459 struct rpc_disptable
*disptable
)
1473 struct rpcdisp
*disp
= NULL
;
1478 struct exportinfo
*exi
= NULL
;
1479 unsigned int nfslog_rec_id
;
1483 bool_t publicfh_ok
= FALSE
;
1485 bool_t dupcached
= FALSE
;
1487 bool_t logging_enabled
= FALSE
;
1488 struct exportinfo
*nfslog_exi
= NULL
;
1490 char cbuf
[INET6_ADDRSTRLEN
]; /* to hold both IPv4 and IPv6 addr */
1493 vers
= req
->rq_vers
;
1495 if (vers
< min_vers
|| vers
> max_vers
) {
1496 svcerr_progvers(req
->rq_xprt
, min_vers
, max_vers
);
1498 cmn_err(CE_NOTE
, "%s: bad version number %u", pgmname
, vers
);
1503 which
= req
->rq_proc
;
1504 if (which
< 0 || which
>= disptable
[(int)vers
].dis_nprocs
) {
1505 svcerr_noproc(req
->rq_xprt
);
1510 (*(disptable
[(int)vers
].dis_proccntp
))[which
].value
.ui64
++;
1512 disp
= &disptable
[(int)vers
].dis_table
[which
];
1513 procnames
= disptable
[(int)vers
].dis_procnames
;
1515 auth_flavor
= req
->rq_cred
.oa_flavor
;
1518 * Deserialize into the args struct.
1520 args
= (char *)&args_buf
;
1523 if (rfs_no_fast_xdrargs
|| (auth_flavor
== RPCSEC_GSS
) ||
1524 disp
->dis_fastxdrargs
== NULL_xdrproc_t
||
1525 !SVC_GETARGS(xprt
, disp
->dis_fastxdrargs
, (char *)&args
))
1527 if ((auth_flavor
== RPCSEC_GSS
) ||
1528 disp
->dis_fastxdrargs
== NULL_xdrproc_t
||
1529 !SVC_GETARGS(xprt
, disp
->dis_fastxdrargs
, (char *)&args
))
1532 bzero(args
, disp
->dis_argsz
);
1533 if (!SVC_GETARGS(xprt
, disp
->dis_xdrargs
, args
)) {
1536 * Check if we are outside our capabilities.
1538 if (rfs4_minorvers_mismatch(req
, xprt
, (void *)args
))
1541 svcerr_decode(xprt
);
1543 "Failed to decode arguments for %s version %u "
1544 "procedure %s client %s%s",
1545 pgmname
, vers
+ min_vers
, procnames
[which
],
1546 client_name(req
), client_addr(req
, cbuf
));
1552 * If Version 4 use that specific dispatch function.
1554 if (req
->rq_vers
== 4) {
1555 error
+= rfs4_dispatch(disp
, req
, xprt
, args
);
1559 dis_flags
= disp
->dis_flags
;
1562 * Find export information and check authentication,
1563 * setting the credential if everything is ok.
1565 if (disp
->dis_getfh
!= NULL
) {
1572 fh
= (*disp
->dis_getfh
)(args
);
1573 switch (req
->rq_vers
) {
1575 fh2
= (fhandle_t
*)fh
;
1576 fsid
= &fh2
->fh_fsid
;
1577 fid
= (fid_t
*)&fh2
->fh_len
;
1578 xfid
= (fid_t
*)&fh2
->fh_xlen
;
1581 fh3
= (nfs_fh3
*)fh
;
1582 fsid
= &fh3
->fh3_fsid
;
1583 fid
= FH3TOFIDP(fh3
);
1584 xfid
= FH3TOXFIDP(fh3
);
1589 * Fix for bug 1038302 - corbin
1590 * There is a problem here if anonymous access is
1591 * disallowed. If the current request is part of the
1592 * client's mount process for the requested filesystem,
1593 * then it will carry root (uid 0) credentials on it, and
1594 * will be denied by checkauth if that client does not
1595 * have explicit root=0 permission. This will cause the
1596 * client's mount operation to fail. As a work-around,
1597 * we check here to see if the request is a getattr or
1598 * statfs operation on the exported vnode itself, and
1599 * pass a flag to checkauth with the result of this test.
1601 * The filehandle refers to the mountpoint itself if
1602 * the fh_data and fh_xdata portions of the filehandle
1605 * Added anon_ok argument to checkauth().
1608 if ((dis_flags
& RPC_ALLOWANON
) && EQFID(fid
, xfid
))
1616 if (crgetref(cr
) != 1) {
1624 if (crgetref(cr
) != 1) {
1631 exi
= checkexport(fsid
, xfid
);
1634 publicfh_ok
= PUBLICFH_CHECK(disp
, exi
, fsid
, xfid
);
1637 * Don't allow non-V4 clients access
1641 svcerr_weakauth(xprt
);
1646 authres
= checkauth(exi
, req
, cr
, anon_ok
, publicfh_ok
,
1649 * authres > 0: authentication OK - proceed
1650 * authres == 0: authentication weak - return error
1651 * authres < 0: authentication timeout - drop
1655 svcerr_weakauth(xprt
);
1664 if ((dis_flags
& RPC_MAPRESP
) && (auth_flavor
!= RPCSEC_GSS
)) {
1665 res
= (char *)SVC_GETRES(xprt
, disp
->dis_ressz
);
1667 res
= (char *)&res_buf
;
1669 res
= (char *)&res_buf
;
1671 if (!(dis_flags
& RPC_IDEMPOTENT
)) {
1672 dupstat
= SVC_DUP_EXT(xprt
, req
, res
, disp
->dis_ressz
, &dr
,
1677 svcerr_systemerr(xprt
);
1681 case DUP_INPROGRESS
:
1682 if (res
!= (char *)&res_buf
)
1689 curthread
->t_flag
|= T_DONTPEND
;
1691 (*disp
->dis_proc
)(args
, res
, exi
, req
, cr
, ro
);
1693 curthread
->t_flag
&= ~T_DONTPEND
;
1694 if (curthread
->t_flag
& T_WOULDBLOCK
) {
1695 curthread
->t_flag
&= ~T_WOULDBLOCK
;
1696 SVC_DUPDONE_EXT(xprt
, dr
, res
, NULL
,
1697 disp
->dis_ressz
, DUP_DROP
);
1698 if (res
!= (char *)&res_buf
)
1703 if (dis_flags
& RPC_AVOIDWORK
) {
1704 SVC_DUPDONE_EXT(xprt
, dr
, res
, NULL
,
1705 disp
->dis_ressz
, DUP_DROP
);
1707 SVC_DUPDONE_EXT(xprt
, dr
, res
,
1708 disp
->dis_resfree
== nullfree
? NULL
:
1710 disp
->dis_ressz
, DUP_DONE
);
1719 curthread
->t_flag
|= T_DONTPEND
;
1721 (*disp
->dis_proc
)(args
, res
, exi
, req
, cr
, ro
);
1723 curthread
->t_flag
&= ~T_DONTPEND
;
1724 if (curthread
->t_flag
& T_WOULDBLOCK
) {
1725 curthread
->t_flag
&= ~T_WOULDBLOCK
;
1726 if (res
!= (char *)&res_buf
)
1733 if (auth_tooweak(req
, res
)) {
1734 svcerr_weakauth(xprt
);
1740 * Check to see if logging has been enabled on the server.
1741 * If so, then obtain the export info struct to be used for
1742 * the later writing of the log record. This is done for
1743 * the case that a lookup is done across a non-logged public
1746 if (nfslog_buffer_list
!= NULL
) {
1747 nfslog_exi
= nfslog_get_exi(exi
, req
, res
, &nfslog_rec_id
);
1749 * Is logging enabled?
1751 logging_enabled
= (nfslog_exi
!= NULL
);
1754 * Copy the netbuf for logging purposes, before it is
1755 * freed by svc_sendreply().
1757 if (logging_enabled
) {
1758 NFSLOG_COPY_NETBUF(nfslog_exi
, xprt
, &nb
);
1760 * If RPC_MAPRESP flag set (i.e. in V2 ops) the
1761 * res gets copied directly into the mbuf and
1762 * may be freed soon after the sendreply. So we
1763 * must copy it here to a safe place...
1765 if (res
!= (char *)&res_buf
) {
1766 bcopy(res
, (char *)&res_buf
, disp
->dis_ressz
);
1772 * Serialize and send results struct
1775 if (rfs_no_fast_xdrres
== 0 && res
!= (char *)&res_buf
)
1777 if (res
!= (char *)&res_buf
)
1780 if (!svc_sendreply(xprt
, disp
->dis_fastxdrres
, res
)) {
1781 cmn_err(CE_NOTE
, "%s: bad sendreply", pgmname
);
1782 svcerr_systemerr(xprt
);
1786 if (!svc_sendreply(xprt
, disp
->dis_xdrres
, res
)) {
1787 cmn_err(CE_NOTE
, "%s: bad sendreply", pgmname
);
1788 svcerr_systemerr(xprt
);
1796 if (logging_enabled
) {
1797 nfslog_write_record(nfslog_exi
, req
, args
, (char *)&res_buf
,
1798 cr
, &nb
, nfslog_rec_id
, NFSLOG_ONE_BUFFER
);
1799 exi_rele(nfslog_exi
);
1800 kmem_free((&nb
)->buf
, (&nb
)->len
);
1804 * Free results struct. With the addition of NFS V4 we can
1805 * have non-idempotent procedures with functions.
1807 if (disp
->dis_resfree
!= nullfree
&& dupcached
== FALSE
) {
1808 (*disp
->dis_resfree
)(res
);
1813 * Free arguments struct
1816 if (!SVC_FREEARGS(xprt
, disp
->dis_xdrargs
, args
)) {
1817 cmn_err(CE_NOTE
, "%s: bad freeargs", pgmname
);
1821 if (!SVC_FREEARGS(xprt
, (xdrproc_t
)0, (caddr_t
)0)) {
1822 cmn_err(CE_NOTE
, "%s: bad freeargs", pgmname
);
1830 global_svstat_ptr
[req
->rq_vers
][NFS_BADCALLS
].value
.ui64
+= error
;
1832 global_svstat_ptr
[req
->rq_vers
][NFS_CALLS
].value
.ui64
++;
1836 rfs_dispatch(struct svc_req
*req
, SVCXPRT
*xprt
)
1838 common_dispatch(req
, xprt
, NFS_VERSMIN
, NFS_VERSMAX
,
1839 "NFS", rfs_disptable
);
1842 static char *aclcallnames_v2
[] = {
1851 static struct rpcdisp acldisptab_v2
[] = {
1858 xdr_void
, NULL_xdrproc_t
, 0,
1859 xdr_void
, NULL_xdrproc_t
, 0,
1860 nullfree
, RPC_IDEMPOTENT
,
1863 /* ACL2_GETACL = 1 */
1865 xdr_GETACL2args
, xdr_fastGETACL2args
, sizeof (GETACL2args
),
1866 xdr_GETACL2res
, NULL_xdrproc_t
, sizeof (GETACL2res
),
1867 acl2_getacl_free
, RPC_IDEMPOTENT
,
1870 /* ACL2_SETACL = 2 */
1872 xdr_SETACL2args
, NULL_xdrproc_t
, sizeof (SETACL2args
),
1873 #ifdef _LITTLE_ENDIAN
1874 xdr_SETACL2res
, xdr_fastSETACL2res
, sizeof (SETACL2res
),
1876 xdr_SETACL2res
, NULL_xdrproc_t
, sizeof (SETACL2res
),
1878 nullfree
, RPC_MAPRESP
,
1881 /* ACL2_GETATTR = 3 */
1883 xdr_GETATTR2args
, xdr_fastGETATTR2args
, sizeof (GETATTR2args
),
1884 #ifdef _LITTLE_ENDIAN
1885 xdr_GETATTR2res
, xdr_fastGETATTR2res
, sizeof (GETATTR2res
),
1887 xdr_GETATTR2res
, NULL_xdrproc_t
, sizeof (GETATTR2res
),
1889 nullfree
, RPC_IDEMPOTENT
|RPC_ALLOWANON
|RPC_MAPRESP
,
1890 acl2_getattr_getfh
},
1892 /* ACL2_ACCESS = 4 */
1894 xdr_ACCESS2args
, xdr_fastACCESS2args
, sizeof (ACCESS2args
),
1895 #ifdef _LITTLE_ENDIAN
1896 xdr_ACCESS2res
, xdr_fastACCESS2res
, sizeof (ACCESS2res
),
1898 xdr_ACCESS2res
, NULL_xdrproc_t
, sizeof (ACCESS2res
),
1900 nullfree
, RPC_IDEMPOTENT
|RPC_MAPRESP
,
1903 /* ACL2_GETXATTRDIR = 5 */
1905 xdr_GETXATTRDIR2args
, NULL_xdrproc_t
, sizeof (GETXATTRDIR2args
),
1906 xdr_GETXATTRDIR2res
, NULL_xdrproc_t
, sizeof (GETXATTRDIR2res
),
1907 nullfree
, RPC_IDEMPOTENT
,
1908 acl2_getxattrdir_getfh
},
1911 static char *aclcallnames_v3
[] = {
1918 static struct rpcdisp acldisptab_v3
[] = {
1925 xdr_void
, NULL_xdrproc_t
, 0,
1926 xdr_void
, NULL_xdrproc_t
, 0,
1927 nullfree
, RPC_IDEMPOTENT
,
1930 /* ACL3_GETACL = 1 */
1932 xdr_GETACL3args
, NULL_xdrproc_t
, sizeof (GETACL3args
),
1933 xdr_GETACL3res
, NULL_xdrproc_t
, sizeof (GETACL3res
),
1934 acl3_getacl_free
, RPC_IDEMPOTENT
,
1937 /* ACL3_SETACL = 2 */
1939 xdr_SETACL3args
, NULL_xdrproc_t
, sizeof (SETACL3args
),
1940 xdr_SETACL3res
, NULL_xdrproc_t
, sizeof (SETACL3res
),
1944 /* ACL3_GETXATTRDIR = 3 */
1946 xdr_GETXATTRDIR3args
, NULL_xdrproc_t
, sizeof (GETXATTRDIR3args
),
1947 xdr_GETXATTRDIR3res
, NULL_xdrproc_t
, sizeof (GETXATTRDIR3res
),
1948 nullfree
, RPC_IDEMPOTENT
,
1949 acl3_getxattrdir_getfh
},
1952 static struct rpc_disptable acl_disptable
[] = {
1953 {sizeof (acldisptab_v2
) / sizeof (acldisptab_v2
[0]),
1955 &aclproccnt_v2_ptr
, acldisptab_v2
},
1956 {sizeof (acldisptab_v3
) / sizeof (acldisptab_v3
[0]),
1958 &aclproccnt_v3_ptr
, acldisptab_v3
},
1962 acl_dispatch(struct svc_req
*req
, SVCXPRT
*xprt
)
1964 common_dispatch(req
, xprt
, NFS_ACL_VERSMIN
, NFS_ACL_VERSMAX
,
1965 "ACL", acl_disptable
);
1969 checkwin(int flavor
, int window
, struct svc_req
*req
)
1971 struct authdes_cred
*adc
;
1975 adc
= (struct authdes_cred
*)req
->rq_clntcred
;
1976 CTASSERT(sizeof (struct authdes_cred
) <= RQCRED_SIZE
);
1977 if (adc
->adc_fullname
.window
> window
)
1989 * checkauth() will check the access permission against the export
1990 * information. Then map root uid/gid to appropriate uid/gid.
1992 * This routine is used by NFS V3 and V2 code.
1995 checkauth(struct exportinfo
*exi
, struct svc_req
*req
, cred_t
*cr
, int anon_ok
,
1996 bool_t publicfh_ok
, bool_t
*ro
)
1998 int i
, nfsflavor
, rpcflavor
, stat
, access
;
1999 struct secinfo
*secp
;
2001 char buf
[INET6_ADDRSTRLEN
]; /* to hold both IPv4 and IPv6 addr */
2010 * Check for privileged port number
2011 * N.B.: this assumes that we know the format of a netbuf.
2014 struct sockaddr
*ca
;
2015 ca
= (struct sockaddr
*)svc_getrpccaller(req
->rq_xprt
)->buf
;
2020 if ((ca
->sa_family
== AF_INET
&&
2021 ntohs(((struct sockaddr_in
*)ca
)->sin_port
) >=
2023 (ca
->sa_family
== AF_INET6
&&
2024 ntohs(((struct sockaddr_in6
*)ca
)->sin6_port
) >=
2027 "nfs_server: client %s%ssent NFS request from "
2028 "unprivileged port",
2029 client_name(req
), client_addr(req
, buf
));
2035 * return 1 on success or 0 on failure
2037 stat
= sec_svc_getcred(req
, cr
, &principal
, &nfsflavor
);
2040 * A failed AUTH_UNIX sec_svc_getcred() implies we couldn't set
2041 * the credentials; below we map that to anonymous.
2043 if (!stat
&& nfsflavor
!= AUTH_UNIX
) {
2045 "nfs_server: couldn't get unix cred for %s",
2051 * Short circuit checkauth() on operations that support the
2052 * public filehandle, and if the request for that operation
2053 * is using the public filehandle. Note that we must call
2054 * sec_svc_getcred() first so that xp_cookie is set to the
2055 * right value. Normally xp_cookie is just the RPC flavor
2056 * of the the request, but in the case of RPCSEC_GSS it
2057 * could be a pseudo flavor.
2062 rpcflavor
= req
->rq_cred
.oa_flavor
;
2064 * Check if the auth flavor is valid for this export
2066 access
= nfsauth_access(exi
, req
, cr
, &uid
, &gid
, &ngids
, &gids
);
2067 if (access
& NFSAUTH_DROP
)
2068 return (-1); /* drop the request */
2070 if (access
& NFSAUTH_RO
)
2073 if (access
& NFSAUTH_DENIED
) {
2075 * If anon_ok == 1 and we got NFSAUTH_DENIED, it was
2076 * probably due to the flavor not matching during
2077 * the mount attempt. So map the flavor to AUTH_NONE
2078 * so that the credentials get mapped to the anonymous
2082 rpcflavor
= AUTH_NONE
;
2084 return (0); /* deny access */
2086 } else if (access
& NFSAUTH_MAPNONE
) {
2088 * Access was granted even though the flavor mismatched
2089 * because AUTH_NONE was one of the exported flavors.
2091 rpcflavor
= AUTH_NONE
;
2093 } else if (access
& NFSAUTH_WRONGSEC
) {
2095 * NFSAUTH_WRONGSEC is used for NFSv4. If we get here,
2096 * it means a client ignored the list of allowed flavors
2097 * returned via the MOUNT protocol. So we just disallow it!
2102 if (rpcflavor
!= AUTH_SYS
)
2103 kmem_free(gids
, ngids
* sizeof (gid_t
));
2105 switch (rpcflavor
) {
2107 anon_res
= crsetugid(cr
, exi
->exi_export
.ex_anon
,
2108 exi
->exi_export
.ex_anon
);
2109 (void) crsetgroups(cr
, 0, NULL
);
2113 if (!stat
|| crgetuid(cr
) == 0 && !(access
& NFSAUTH_UIDMAP
)) {
2114 anon_res
= crsetugid(cr
, exi
->exi_export
.ex_anon
,
2115 exi
->exi_export
.ex_anon
);
2116 (void) crsetgroups(cr
, 0, NULL
);
2117 } else if (crgetuid(cr
) == 0 && access
& NFSAUTH_ROOT
) {
2119 * It is root, so apply rootid to get real UID
2120 * Find the secinfo structure. We should be able
2121 * to find it by the time we reach here.
2122 * nfsauth_access() has done the checking.
2125 for (i
= 0; i
< exi
->exi_export
.ex_seccnt
; i
++) {
2126 struct secinfo
*sptr
;
2127 sptr
= &exi
->exi_export
.ex_secinfo
[i
];
2128 if (sptr
->s_secinfo
.sc_nfsnum
== nfsflavor
) {
2134 (void) crsetugid(cr
, secp
->s_rootid
,
2136 (void) crsetgroups(cr
, 0, NULL
);
2138 } else if (crgetuid(cr
) != uid
|| crgetgid(cr
) != gid
) {
2139 if (crsetugid(cr
, uid
, gid
) != 0)
2140 anon_res
= crsetugid(cr
,
2141 exi
->exi_export
.ex_anon
,
2142 exi
->exi_export
.ex_anon
);
2143 (void) crsetgroups(cr
, 0, NULL
);
2144 } else if (access
& NFSAUTH_GROUPS
) {
2145 (void) crsetgroups(cr
, ngids
, gids
);
2148 kmem_free(gids
, ngids
* sizeof (gid_t
));
2155 * Find the secinfo structure. We should be able
2156 * to find it by the time we reach here.
2157 * nfsauth_access() has done the checking.
2160 for (i
= 0; i
< exi
->exi_export
.ex_seccnt
; i
++) {
2161 if (exi
->exi_export
.ex_secinfo
[i
].s_secinfo
.sc_nfsnum
==
2163 secp
= &exi
->exi_export
.ex_secinfo
[i
];
2169 cmn_err(CE_NOTE
, "nfs_server: client %s%shad "
2170 "no secinfo data for flavor %d",
2171 client_name(req
), client_addr(req
, buf
),
2176 if (!checkwin(rpcflavor
, secp
->s_window
, req
)) {
2178 "nfs_server: client %s%sused invalid "
2179 "auth window value",
2180 client_name(req
), client_addr(req
, buf
));
2185 * Map root principals listed in the share's root= list to root,
2186 * and map any others principals that were mapped to root by RPC
2189 if (principal
&& sec_svc_inrootlist(rpcflavor
, principal
,
2190 secp
->s_rootcnt
, secp
->s_rootnames
)) {
2191 if (crgetuid(cr
) == 0 && secp
->s_rootid
== 0)
2195 (void) crsetugid(cr
, secp
->s_rootid
, secp
->s_rootid
);
2198 * NOTE: If and when kernel-land privilege tracing is
2199 * added this may have to be replaced with code that
2200 * retrieves root's supplementary groups (e.g., using
2201 * kgss_get_group_info(). In the meantime principals
2202 * mapped to uid 0 get all privileges, so setting cr's
2203 * supplementary groups for them does nothing.
2205 (void) crsetgroups(cr
, 0, NULL
);
2211 * Not a root princ, or not in root list, map UID 0/nobody to
2212 * the anon ID for the share. (RPC sets cr's UIDs and GIDs to
2213 * UID_NOBODY and GID_NOBODY, respectively.)
2215 if (crgetuid(cr
) != 0 &&
2216 (crgetuid(cr
) != UID_NOBODY
|| crgetgid(cr
) != GID_NOBODY
))
2219 anon_res
= crsetugid(cr
, exi
->exi_export
.ex_anon
,
2220 exi
->exi_export
.ex_anon
);
2221 (void) crsetgroups(cr
, 0, NULL
);
2225 } /* switch on rpcflavor */
2228 * Even if anon access is disallowed via ex_anon == -1, we allow
2229 * this access if anon_ok is set. So set creds to the default
2232 if (anon_res
!= 0) {
2235 "nfs_server: client %s%ssent wrong "
2236 "authentication for %s",
2237 client_name(req
), client_addr(req
, buf
),
2238 exi
->exi_export
.ex_path
?
2239 exi
->exi_export
.ex_path
: "?");
2243 if (crsetugid(cr
, UID_NOBODY
, GID_NOBODY
) != 0)
2251 * returns 0 on failure, -1 on a drop, -2 on wrong security flavor,
2255 checkauth4(struct compound_state
*cs
, struct svc_req
*req
)
2257 int i
, rpcflavor
, access
;
2258 struct secinfo
*secp
;
2259 char buf
[MAXHOST
+ 1];
2260 int anon_res
= 0, nfsflavor
;
2261 struct exportinfo
*exi
;
2272 principal
= cs
->principal
;
2273 nfsflavor
= cs
->nfsflavor
;
2277 rpcflavor
= req
->rq_cred
.oa_flavor
;
2278 cs
->access
&= ~CS_ACCESS_LIMITED
;
2281 * Check for privileged port number
2282 * N.B.: this assumes that we know the format of a netbuf.
2285 struct sockaddr
*ca
;
2286 ca
= (struct sockaddr
*)svc_getrpccaller(req
->rq_xprt
)->buf
;
2291 if ((ca
->sa_family
== AF_INET
&&
2292 ntohs(((struct sockaddr_in
*)ca
)->sin_port
) >=
2294 (ca
->sa_family
== AF_INET6
&&
2295 ntohs(((struct sockaddr_in6
*)ca
)->sin6_port
) >=
2298 "nfs_server: client %s%ssent NFSv4 request from "
2299 "unprivileged port",
2300 client_name(req
), client_addr(req
, buf
));
2306 * Check the access right per auth flavor on the vnode of
2307 * this export for the given request.
2309 access
= nfsauth4_access(cs
->exi
, cs
->vp
, req
, cr
, &uid
, &gid
, &ngids
,
2312 if (access
& NFSAUTH_WRONGSEC
)
2313 return (-2); /* no access for this security flavor */
2315 if (access
& NFSAUTH_DROP
)
2316 return (-1); /* drop the request */
2318 if (access
& NFSAUTH_DENIED
) {
2320 if (exi
->exi_export
.ex_seccnt
> 0)
2321 return (0); /* deny access */
2323 } else if (access
& NFSAUTH_LIMITED
) {
2325 cs
->access
|= CS_ACCESS_LIMITED
;
2327 } else if (access
& NFSAUTH_MAPNONE
) {
2329 * Access was granted even though the flavor mismatched
2330 * because AUTH_NONE was one of the exported flavors.
2332 rpcflavor
= AUTH_NONE
;
2336 * XXX probably need to redo some of it for nfsv4?
2337 * return 1 on success or 0 on failure
2340 if (rpcflavor
!= AUTH_SYS
)
2341 kmem_free(gids
, ngids
* sizeof (gid_t
));
2343 switch (rpcflavor
) {
2345 anon_res
= crsetugid(cr
, exi
->exi_export
.ex_anon
,
2346 exi
->exi_export
.ex_anon
);
2347 (void) crsetgroups(cr
, 0, NULL
);
2351 if (crgetuid(cr
) == 0 && !(access
& NFSAUTH_UIDMAP
)) {
2352 anon_res
= crsetugid(cr
, exi
->exi_export
.ex_anon
,
2353 exi
->exi_export
.ex_anon
);
2354 (void) crsetgroups(cr
, 0, NULL
);
2355 } else if (crgetuid(cr
) == 0 && access
& NFSAUTH_ROOT
) {
2357 * It is root, so apply rootid to get real UID
2358 * Find the secinfo structure. We should be able
2359 * to find it by the time we reach here.
2360 * nfsauth_access() has done the checking.
2363 for (i
= 0; i
< exi
->exi_export
.ex_seccnt
; i
++) {
2364 struct secinfo
*sptr
;
2365 sptr
= &exi
->exi_export
.ex_secinfo
[i
];
2366 if (sptr
->s_secinfo
.sc_nfsnum
== nfsflavor
) {
2367 secp
= &exi
->exi_export
.ex_secinfo
[i
];
2372 (void) crsetugid(cr
, secp
->s_rootid
,
2374 (void) crsetgroups(cr
, 0, NULL
);
2376 } else if (crgetuid(cr
) != uid
|| crgetgid(cr
) != gid
) {
2377 if (crsetugid(cr
, uid
, gid
) != 0)
2378 anon_res
= crsetugid(cr
,
2379 exi
->exi_export
.ex_anon
,
2380 exi
->exi_export
.ex_anon
);
2381 (void) crsetgroups(cr
, 0, NULL
);
2382 } if (access
& NFSAUTH_GROUPS
) {
2383 (void) crsetgroups(cr
, ngids
, gids
);
2386 kmem_free(gids
, ngids
* sizeof (gid_t
));
2392 * Find the secinfo structure. We should be able
2393 * to find it by the time we reach here.
2394 * nfsauth_access() has done the checking.
2397 for (i
= 0; i
< exi
->exi_export
.ex_seccnt
; i
++) {
2398 if (exi
->exi_export
.ex_secinfo
[i
].s_secinfo
.sc_nfsnum
==
2400 secp
= &exi
->exi_export
.ex_secinfo
[i
];
2406 cmn_err(CE_NOTE
, "nfs_server: client %s%shad "
2407 "no secinfo data for flavor %d",
2408 client_name(req
), client_addr(req
, buf
),
2413 if (!checkwin(rpcflavor
, secp
->s_window
, req
)) {
2415 "nfs_server: client %s%sused invalid "
2416 "auth window value",
2417 client_name(req
), client_addr(req
, buf
));
2422 * Map root principals listed in the share's root= list to root,
2423 * and map any others principals that were mapped to root by RPC
2424 * to anon. If not going to anon, set to rootid (root_mapping).
2426 if (principal
&& sec_svc_inrootlist(rpcflavor
, principal
,
2427 secp
->s_rootcnt
, secp
->s_rootnames
)) {
2428 if (crgetuid(cr
) == 0 && secp
->s_rootid
== 0)
2431 (void) crsetugid(cr
, secp
->s_rootid
, secp
->s_rootid
);
2434 * NOTE: If and when kernel-land privilege tracing is
2435 * added this may have to be replaced with code that
2436 * retrieves root's supplementary groups (e.g., using
2437 * kgss_get_group_info(). In the meantime principals
2438 * mapped to uid 0 get all privileges, so setting cr's
2439 * supplementary groups for them does nothing.
2441 (void) crsetgroups(cr
, 0, NULL
);
2447 * Not a root princ, or not in root list, map UID 0/nobody to
2448 * the anon ID for the share. (RPC sets cr's UIDs and GIDs to
2449 * UID_NOBODY and GID_NOBODY, respectively.)
2451 if (crgetuid(cr
) != 0 &&
2452 (crgetuid(cr
) != UID_NOBODY
|| crgetgid(cr
) != GID_NOBODY
))
2455 anon_res
= crsetugid(cr
, exi
->exi_export
.ex_anon
,
2456 exi
->exi_export
.ex_anon
);
2457 (void) crsetgroups(cr
, 0, NULL
);
2459 } /* switch on rpcflavor */
2462 * Even if anon access is disallowed via ex_anon == -1, we allow
2463 * this access if anon_ok is set. So set creds to the default
2467 if (anon_res
!= 0) {
2469 "nfs_server: client %s%ssent wrong "
2470 "authentication for %s",
2471 client_name(req
), client_addr(req
, buf
),
2472 exi
->exi_export
.ex_path
?
2473 exi
->exi_export
.ex_path
: "?");
2482 client_name(struct svc_req
*req
)
2484 char *hostname
= NULL
;
2487 * If it's a Unix cred then use the
2488 * hostname from the credential.
2490 if (req
->rq_cred
.oa_flavor
== AUTH_UNIX
) {
2491 hostname
= ((struct authunix_parms
*)
2492 req
->rq_clntcred
)->aup_machname
;
2494 if (hostname
== NULL
)
2501 client_addr(struct svc_req
*req
, char *buf
)
2503 struct sockaddr
*ca
;
2505 char *frontspace
= "";
2508 * We assume we are called in tandem with client_name and the
2509 * format string looks like "...client %s%sblah blah..."
2511 * If it's a Unix cred then client_name returned
2512 * a host name, so we need insert a space between host name
2515 if (req
->rq_cred
.oa_flavor
== AUTH_UNIX
)
2519 * Convert the caller's IP address to a dotted string
2521 ca
= (struct sockaddr
*)svc_getrpccaller(req
->rq_xprt
)->buf
;
2523 if (ca
->sa_family
== AF_INET
) {
2524 b
= (uchar_t
*)&((struct sockaddr_in
*)ca
)->sin_addr
;
2525 (void) sprintf(buf
, "%s(%d.%d.%d.%d) ", frontspace
,
2526 b
[0] & 0xFF, b
[1] & 0xFF, b
[2] & 0xFF, b
[3] & 0xFF);
2527 } else if (ca
->sa_family
== AF_INET6
) {
2528 struct sockaddr_in6
*sin6
;
2529 sin6
= (struct sockaddr_in6
*)ca
;
2530 (void) kinet_ntop6((uchar_t
*)&sin6
->sin6_addr
,
2531 buf
, INET6_ADDRSTRLEN
);
2536 * No IP address to print. If there was a host name
2537 * printed, then we print a space.
2539 (void) sprintf(buf
, frontspace
);
2546 * NFS Server initialization routine. This routine should only be called
2547 * once. It performs the following tasks:
2548 * - Call sub-initialization routines (localize access to variables)
2549 * - Initialize all locks
2550 * - initialize the version 3 write verifier
2557 error
= nfs_exportinit();
2560 error
= rfs4_srvrinit();
2569 /* Init the stuff to control start/stop */
2570 nfs_server_upordown
= NFS_SERVER_STOPPED
;
2571 mutex_init(&nfs_server_upordown_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
2572 cv_init(&nfs_server_upordown_cv
, NULL
, CV_DEFAULT
, NULL
);
2573 mutex_init(&rdma_wait_mutex
, NULL
, MUTEX_DEFAULT
, NULL
);
2574 cv_init(&rdma_wait_cv
, NULL
, CV_DEFAULT
, NULL
);
2580 * NFS Server finalization routine. This routine is called to cleanup the
2581 * initialization work previously performed if the NFS server module could
2582 * not be loaded correctly.
2592 mutex_destroy(&nfs_server_upordown_lock
);
2593 cv_destroy(&nfs_server_upordown_cv
);
2594 mutex_destroy(&rdma_wait_mutex
);
2595 cv_destroy(&rdma_wait_cv
);
2599 * Set up an iovec array of up to cnt pointers.
2603 mblk_to_iov(mblk_t
*m
, int cnt
, struct iovec
*iovp
)
2605 while (m
!= NULL
&& cnt
-- > 0) {
2606 iovp
->iov_base
= (caddr_t
)m
->b_rptr
;
2607 iovp
->iov_len
= (m
->b_wptr
- m
->b_rptr
);
2614 * Common code between NFS Version 2 and NFS Version 3 for the public
2615 * filehandle multicomponent lookups.
2619 * Public filehandle evaluation of a multi-component lookup, following
2620 * symbolic links, if necessary. This may result in a vnode in another
2621 * filesystem, which is OK as long as the other filesystem is exported.
2623 * Note that the exi will be set either to NULL or a new reference to the
2624 * exportinfo struct that corresponds to the vnode of the multi-component path.
2625 * It is the callers responsibility to release this reference.
2628 rfs_publicfh_mclookup(char *p
, vnode_t
*dvp
, cred_t
*cr
, vnode_t
**vpp
,
2629 struct exportinfo
**exi
, struct sec_ol
*sec
)
2632 vnode_t
*mc_dvp
= NULL
;
2639 * check if the given path is a url or native path. Since p is
2640 * modified by MCLpath(), it may be empty after returning from
2641 * there, and should be checked.
2643 if ((pathflag
= MCLpath(&p
)) == -1)
2647 * If pathflag is SECURITY_QUERY, turn the SEC_QUERY bit
2648 * on in sec->sec_flags. This bit will later serve as an
2649 * indication in makefh_ol() or makefh3_ol() to overload the
2650 * filehandle to contain the sec modes used by the server for
2653 if (pathflag
== SECURITY_QUERY
) {
2654 if ((sec
->sec_index
= (uint_t
)(*p
)) > 0) {
2655 sec
->sec_flags
|= SEC_QUERY
;
2657 if ((pathflag
= MCLpath(&p
)) == -1)
2661 "nfs_server: invalid security index %d, "
2662 "violating WebNFS SNEGO protocol.", sec
->sec_index
);
2672 error
= rfs_pathname(p
, &mc_dvp
, vpp
, dvp
, cr
, pathflag
);
2675 * If name resolves to "/" we get EINVAL since we asked for
2676 * the vnode of the directory that the file is in. Try again
2677 * with NULL directory vnode.
2679 if (error
== EINVAL
) {
2680 error
= rfs_pathname(p
, NULL
, vpp
, dvp
, cr
, pathflag
);
2682 ASSERT(*vpp
!= NULL
);
2683 if ((*vpp
)->v_type
== VDIR
) {
2688 * This should not happen, the filesystem is
2689 * in an inconsistent state. Fail the lookup
2706 ASSERT(mc_dvp
!= NULL
);
2707 ASSERT(*vpp
!= NULL
);
2709 if ((*vpp
)->v_type
== VDIR
) {
2712 * *vpp may be an AutoFS node, so we perform
2713 * a fop_access() to trigger the mount of the intended
2714 * filesystem, so we can perform the lookup in the
2715 * intended filesystem.
2717 (void) fop_access(*vpp
, 0, 0, cr
, NULL
);
2720 * If vnode is covered, get the
2721 * the topmost vnode.
2723 if (vn_mountedvfs(*vpp
) != NULL
) {
2724 error
= traverse(vpp
);
2731 if (fop_realvp(*vpp
, &realvp
, NULL
) == 0 &&
2734 * If realvp is different from *vpp
2735 * then release our reference on *vpp, so that
2736 * the export access check be performed on the
2737 * real filesystem instead.
2749 * Let nfs_vptexi() figure what the real parent is.
2756 * If vnode is covered, get the
2757 * the topmost vnode.
2759 if (vn_mountedvfs(mc_dvp
) != NULL
) {
2760 error
= traverse(&mc_dvp
);
2767 if (fop_realvp(mc_dvp
, &realvp
, NULL
) == 0 &&
2770 * *vpp is a file, obtain realvp of the parent
2780 * The pathname may take us from the public filesystem to another.
2781 * If that's the case then just set the exportinfo to the new export
2782 * and build filehandle for it. Thanks to per-access checking there's
2783 * no security issues with doing this. If the client is not allowed
2784 * access to this new export then it will get an access error when it
2785 * tries to use the filehandle
2787 if (error
= nfs_check_vpexi(mc_dvp
, *vpp
, kcred
, exi
)) {
2793 * Not allowed access to pseudo exports.
2802 * Do a lookup for the index file. We know the index option doesn't
2803 * allow paths through handling in the share command, so mc_dvp will
2804 * be the parent for the index file vnode, if its present. Use
2805 * temporary pointers to preserve and reuse the vnode pointers of the
2806 * original directory in case there's no index file. Note that the
2807 * index file is a native path, and should not be interpreted by
2808 * the URL parser in rfs_pathname()
2810 if (((*exi
)->exi_export
.ex_flags
& EX_INDEX
) &&
2811 ((*vpp
)->v_type
== VDIR
) && (pathflag
== URLPATH
)) {
2812 vnode_t
*tvp
, *tmc_dvp
; /* temporary vnode pointers */
2815 mc_dvp
= tvp
= *vpp
;
2817 error
= rfs_pathname((*exi
)->exi_export
.ex_index
, NULL
, vpp
,
2818 mc_dvp
, cr
, NATIVEPATH
);
2820 if (error
== ENOENT
) {
2824 } else { /* ok or error other than ENOENT */
2831 * Found a valid vp for index "filename". Sanity check
2832 * for odd case where a directory is provided as index
2833 * option argument and leads us to another filesystem
2836 /* Release the reference on the old exi value */
2837 ASSERT(*exi
!= NULL
);
2840 if (error
= nfs_check_vpexi(mc_dvp
, *vpp
, kcred
, exi
)) {
2855 * Evaluate a multi-component path
2859 char *path
, /* pathname to evaluate */
2860 vnode_t
**dirvpp
, /* ret for ptr to parent dir vnode */
2861 vnode_t
**compvpp
, /* ret for ptr to component vnode */
2862 vnode_t
*startdvp
, /* starting vnode */
2863 cred_t
*cr
, /* user's credential */
2864 int pathflag
) /* flag to identify path, e.g. URL */
2866 char namebuf
[TYPICALMAXPATHLEN
];
2871 * If pathname starts with '/', then set startdvp to root.
2874 while (*path
== '/')
2880 error
= pn_get_buf(path
, UIO_SYSSPACE
, &pn
, namebuf
, sizeof (namebuf
));
2883 * Call the URL parser for URL paths to modify the original
2884 * string to handle any '%' encoded characters that exist.
2885 * Done here to avoid an extra bcopy in the lookup.
2886 * We need to be careful about pathlen's. We know that
2887 * rfs_pathname() is called with a non-empty path. However,
2888 * it could be emptied due to the path simply being all /'s,
2889 * which is valid to proceed with the lookup, or due to the
2890 * URL parser finding an encoded null character at the
2891 * beginning of path which should not proceed with the lookup.
2893 if (pn
.pn_pathlen
!= 0 && pathflag
== URLPATH
) {
2894 URLparse(pn
.pn_path
);
2895 if ((pn
.pn_pathlen
= strlen(pn
.pn_path
)) == 0)
2899 error
= lookuppnvp(&pn
, NULL
, NO_FOLLOW
, dirvpp
, compvpp
,
2900 rootdir
, startdvp
, cr
);
2902 if (error
== ENAMETOOLONG
) {
2904 * This thread used a pathname > TYPICALMAXPATHLEN bytes long.
2906 if (error
= pn_get(path
, UIO_SYSSPACE
, &pn
))
2908 if (pn
.pn_pathlen
!= 0 && pathflag
== URLPATH
) {
2909 URLparse(pn
.pn_path
);
2910 if ((pn
.pn_pathlen
= strlen(pn
.pn_path
)) == 0) {
2916 error
= lookuppnvp(&pn
, NULL
, NO_FOLLOW
, dirvpp
, compvpp
,
2917 rootdir
, startdvp
, cr
);
2925 * Adapt the multicomponent lookup path depending on the pathtype
2928 MCLpath(char **path
)
2930 unsigned char c
= (unsigned char)**path
;
2933 * If the MCL path is between 0x20 and 0x7E (graphic printable
2934 * character of the US-ASCII coded character set), its a URL path,
2937 if (c
>= 0x20 && c
<= 0x7E)
2941 * If the first octet of the MCL path is not an ASCII character
2942 * then it must be interpreted as a tag value that describes the
2943 * format of the remaining octets of the MCL path.
2945 * If the first octet of the MCL path is 0x81 it is a query
2946 * for the security info.
2949 case 0x80: /* native path, i.e. MCL via mount protocol */
2951 return (NATIVEPATH
);
2952 case 0x81: /* security query */
2954 return (SECURITY_QUERY
);
2960 #define fromhex(c) ((c >= '0' && c <= '9') ? (c - '0') : \
2961 ((c >= 'A' && c <= 'F') ? (c - 'A' + 10) :\
2962 ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : 0)))
2965 * The implementation of URLparse guarantees that the final string will
2966 * fit in the original one. Replaces '%' occurrences followed by 2 characters
2967 * with its corresponding hexadecimal character.
2979 *q
= fromhex(*p
) * 16;
2994 * Get the export information for the lookup vnode, and verify its
2998 nfs_check_vpexi(vnode_t
*mc_dvp
, vnode_t
*vp
, cred_t
*cr
,
2999 struct exportinfo
**exi
)
3004 *exi
= nfs_vptoexi(mc_dvp
, vp
, cr
, &walk
, NULL
, FALSE
);
3009 * If nosub is set for this export then
3010 * a lookup relative to the public fh
3011 * must not terminate below the
3012 * exported directory.
3014 if ((*exi
)->exi_export
.ex_flags
& EX_NOSUB
&& walk
> 0)
3022 * Do the main work of handling HA-NFSv4 Resource Group failover on
3024 * We need to detect whether any RG admin paths have been added or removed,
3025 * and adjust resources accordingly.
3026 * Currently we're using a very inefficient algorithm, ~ 2 * O(n**2). In
3027 * order to scale, the list and array of paths need to be held in more
3028 * suitable data structures.
3031 hanfsv4_failover(void)
3033 int i
, start_grace
, numadded_paths
= 0;
3034 char **added_paths
= NULL
;
3035 rfs4_dss_path_t
*dss_path
;
3038 * Note: currently, rfs4_dss_pathlist cannot be NULL, since
3039 * it will always include an entry for NFS4_DSS_VAR_DIR. If we
3040 * make the latter dynamically specified too, the following will
3041 * need to be adjusted.
3045 * First, look for removed paths: RGs that have been failed-over
3046 * away from this node.
3047 * Walk the "currently-serving" rfs4_dss_pathlist and, for each
3048 * path, check if it is on the "passed-in" rfs4_dss_newpaths array
3049 * from nfsd. If not, that RG path has been removed.
3051 * Note that nfsd has sorted rfs4_dss_newpaths for us, and removed
3054 dss_path
= rfs4_dss_pathlist
;
3057 char *path
= dss_path
->path
;
3059 /* used only for non-HA so may not be removed */
3060 if (strcmp(path
, NFS4_DSS_VAR_DIR
) == 0) {
3061 dss_path
= dss_path
->next
;
3065 for (i
= 0; i
< rfs4_dss_numnewpaths
; i
++) {
3067 char *newpath
= rfs4_dss_newpaths
[i
];
3070 * Since nfsd has sorted rfs4_dss_newpaths for us,
3071 * once the return from strcmp is negative we know
3072 * we've passed the point where "path" should be,
3073 * and can stop searching: "path" has been removed.
3075 cmpret
= strcmp(path
, newpath
);
3085 unsigned index
= dss_path
->index
;
3086 rfs4_servinst_t
*sip
= dss_path
->sip
;
3087 rfs4_dss_path_t
*path_next
= dss_path
->next
;
3090 * This path has been removed.
3091 * We must clear out the servinst reference to
3092 * it, since it's now owned by another
3093 * node: we should not attempt to touch it.
3095 ASSERT(dss_path
== sip
->dss_paths
[index
]);
3096 sip
->dss_paths
[index
] = NULL
;
3098 /* remove from "currently-serving" list, and destroy */
3101 kmem_free(dss_path
->path
, strlen(dss_path
->path
) + 1);
3102 kmem_free(dss_path
, sizeof (rfs4_dss_path_t
));
3104 dss_path
= path_next
;
3106 /* path was found; not removed */
3107 dss_path
= dss_path
->next
;
3109 } while (dss_path
!= rfs4_dss_pathlist
);
3112 * Now, look for added paths: RGs that have been failed-over
3114 * Walk the "passed-in" rfs4_dss_newpaths array from nfsd and,
3115 * for each path, check if it is on the "currently-serving"
3116 * rfs4_dss_pathlist. If not, that RG path has been added.
3118 * Note: we don't do duplicate detection here; nfsd does that for us.
3120 * Note: numadded_paths <= rfs4_dss_numnewpaths, which gives us
3121 * an upper bound for the size needed for added_paths[numadded_paths].
3124 /* probably more space than we need, but guaranteed to be enough */
3125 if (rfs4_dss_numnewpaths
> 0) {
3126 size_t sz
= rfs4_dss_numnewpaths
* sizeof (char *);
3127 added_paths
= kmem_zalloc(sz
, KM_SLEEP
);
3130 /* walk the "passed-in" rfs4_dss_newpaths array from nfsd */
3131 for (i
= 0; i
< rfs4_dss_numnewpaths
; i
++) {
3133 char *newpath
= rfs4_dss_newpaths
[i
];
3135 dss_path
= rfs4_dss_pathlist
;
3137 char *path
= dss_path
->path
;
3139 /* used only for non-HA */
3140 if (strcmp(path
, NFS4_DSS_VAR_DIR
) == 0) {
3141 dss_path
= dss_path
->next
;
3145 if (strncmp(path
, newpath
, strlen(path
)) == 0) {
3150 dss_path
= dss_path
->next
;
3151 } while (dss_path
!= rfs4_dss_pathlist
);
3154 added_paths
[numadded_paths
] = newpath
;
3159 /* did we find any added paths? */
3160 if (numadded_paths
> 0) {
3161 /* create a new server instance, and start its grace period */
3163 rfs4_servinst_create(start_grace
, numadded_paths
, added_paths
);
3165 /* read in the stable storage state from these paths */
3166 rfs4_dss_readstate(numadded_paths
, added_paths
);
3169 * Multiple failovers during a grace period will cause
3170 * clients of the same resource group to be partitioned
3171 * into different server instances, with different
3172 * grace periods. Since clients of the same resource
3173 * group must be subject to the same grace period,
3174 * we need to reset all currently active grace periods.
3176 rfs4_grace_reset_all();
3179 if (rfs4_dss_numnewpaths
> 0)
3180 kmem_free(added_paths
, rfs4_dss_numnewpaths
* sizeof (char *));
3184 * Callback function to return the loaned buffers.
3185 * Calls fop_retzcbuf() only after all uio_iov[]
3186 * buffers are returned. nu_ref maintains the count.
3189 rfs_free_xuio(void *free_arg
)
3192 nfs_xuio_t
*nfsuiop
= (nfs_xuio_t
*)free_arg
;
3194 ref
= atomic_dec_uint_nv(&nfsuiop
->nu_ref
);
3197 * Call fop_retzcbuf() only when all the iov buffers
3203 if (((uio_t
*)nfsuiop
)->uio_extflg
& UIO_XUIO
) {
3204 (void) fop_retzcbuf(nfsuiop
->nu_vp
, (xuio_t
*)free_arg
, NULL
,
3206 VN_RELE(nfsuiop
->nu_vp
);
3209 kmem_cache_free(nfs_xuio_cache
, free_arg
);
3213 rfs_setup_xuio(vnode_t
*vp
)
3215 nfs_xuio_t
*nfsuiop
;
3217 nfsuiop
= kmem_cache_alloc(nfs_xuio_cache
, KM_SLEEP
);
3219 bzero(nfsuiop
, sizeof (nfs_xuio_t
));
3220 nfsuiop
->nu_vp
= vp
;
3223 * ref count set to 1. more may be added
3224 * if multiple mblks refer to multiple iov's.
3225 * This is done in uio_to_mblk().
3228 nfsuiop
->nu_ref
= 1;
3230 nfsuiop
->nu_frtn
.free_func
= rfs_free_xuio
;
3231 nfsuiop
->nu_frtn
.free_arg
= (char *)nfsuiop
;
3233 nfsuiop
->nu_uio
.xu_type
= UIOTYPE_ZEROCOPY
;
3235 return (&nfsuiop
->nu_uio
);
3239 uio_to_mblk(uio_t
*uiop
)
3244 nfs_xuio_t
*nfsuiop
= (nfs_xuio_t
*)uiop
;
3246 if (uiop
->uio_iovcnt
== 0)
3249 iovp
= uiop
->uio_iov
;
3250 mp
= mp1
= esballoca((uchar_t
*)iovp
->iov_base
, iovp
->iov_len
,
3251 BPRI_MED
, &nfsuiop
->nu_frtn
);
3254 mp
->b_wptr
+= iovp
->iov_len
;
3255 mp
->b_datap
->db_type
= M_DATA
;
3257 for (i
= 1; i
< uiop
->uio_iovcnt
; i
++) {
3258 iovp
= (uiop
->uio_iov
+ i
);
3260 mp1
->b_cont
= esballoca(
3261 (uchar_t
*)iovp
->iov_base
, iovp
->iov_len
, BPRI_MED
,
3265 ASSERT(mp1
!= NULL
);
3266 mp1
->b_wptr
+= iovp
->iov_len
;
3267 mp1
->b_datap
->db_type
= M_DATA
;
3270 nfsuiop
->nu_ref
= uiop
->uio_iovcnt
;
3276 * Allocate memory to hold data for a read request of len bytes.
3278 * We don't allocate buffers greater than kmem_max_cached in size to avoid
3279 * allocating memory from the kmem_oversized arena. If we allocate oversized
3280 * buffers, we incur heavy cross-call activity when freeing these large buffers
3281 * in the TCP receive path. Note that we can't set b_wptr here since the
3282 * length of the data returned may differ from the length requested when
3283 * reading the end of a file; we set b_wptr in rfs_rndup_mblks() once the
3284 * length of the read is known.
3287 rfs_read_alloc(uint_t len
, struct iovec
**iov
, int *iovcnt
)
3289 struct iovec
*iovarr
;
3290 mblk_t
*mp
, **mpp
= &mp
;
3292 uint_t remain
= len
;
3295 *iovcnt
= howmany(len
, kmem_max_cached
);
3297 iovarr
= kmem_alloc(*iovcnt
* sizeof (struct iovec
), KM_SLEEP
);
3300 for (i
= 0; i
< *iovcnt
; remain
-= mpsize
, i
++) {
3301 ASSERT(remain
<= len
);
3303 * We roundup the size we allocate to a multiple of
3304 * BYTES_PER_XDR_UNIT (4 bytes) so that the call to
3305 * xdrmblk_putmblk() never fails.
3307 ASSERT(kmem_max_cached
% BYTES_PER_XDR_UNIT
== 0);
3308 mpsize
= MIN(kmem_max_cached
, remain
);
3309 *mpp
= allocb_wait(RNDUP(mpsize
), BPRI_MED
, STR_NOSIG
, &err
);
3310 ASSERT(*mpp
!= NULL
);
3313 iovarr
[i
].iov_base
= (caddr_t
)(*mpp
)->b_rptr
;
3314 iovarr
[i
].iov_len
= mpsize
;
3315 mpp
= &(*mpp
)->b_cont
;
3321 rfs_rndup_mblks(mblk_t
*mp
, uint_t len
, int buf_loaned
)
3326 uint_t mpsize
, remainder
;
3328 remainder
= P2NPHASE(len
, BYTES_PER_XDR_UNIT
);
3331 * Non copy-reduction case. This function assumes that blocks were
3332 * allocated in multiples of BYTES_PER_XDR_UNIT bytes, which makes this
3333 * padding safe without bounds checking.
3337 * Set the size of each mblk in the chain until we've consumed
3338 * the specified length for all but the last one.
3340 while ((mpsize
= MBLKSIZE(mp
)) < len
) {
3341 ASSERT(mpsize
% BYTES_PER_XDR_UNIT
== 0);
3342 mp
->b_wptr
+= mpsize
;
3348 ASSERT(len
+ remainder
<= mpsize
);
3350 for (i
= 0; i
< remainder
; i
++)
3351 *mp
->b_wptr
++ = '\0';
3356 * No remainder mblk required.
3362 * Get to the last mblk in the chain.
3364 while (mp
->b_cont
!= NULL
)
3368 * In case of copy-reduction mblks, the size of the mblks are fixed
3369 * and are of the size of the loaned buffers. Allocate a remainder
3370 * mblk and chain it to the data buffers. This is sub-optimal, but not
3371 * expected to happen commonly.
3373 rmp
= allocb_wait(remainder
, BPRI_MED
, STR_NOSIG
, &alloc_err
);
3374 ASSERT(rmp
!= NULL
);
3375 ASSERT(alloc_err
== 0);
3377 for (i
= 0; i
< remainder
; i
++)
3378 *rmp
->b_wptr
++ = '\0';
3380 rmp
->b_datap
->db_type
= M_DATA
;