Print this page
nfssrv: nfsstat reports zeroed data in zone
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/nfs/nfs_server.c
+++ new/usr/src/uts/common/fs/nfs/nfs_server.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
24 24 * Copyright (c) 2013 by Delphix. All rights reserved.
25 25 * Copyright (c) 2017 Joyent Inc
26 26 * Copyright 2019 Nexenta by DDN, Inc.
27 27 */
28 28
29 29 /*
30 30 * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
31 31 * All rights reserved.
32 32 * Use is subject to license terms.
33 33 */
34 34
35 35 /*
36 36 * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
37 37 * Copyright (c) 2013 by Delphix. All rights reserved.
38 38 * Copyright 2018 Nexenta Systems, Inc.
39 39 * Copyright (c) 2017 Joyent Inc
40 40 */
41 41
42 42 #include <sys/param.h>
43 43 #include <sys/types.h>
44 44 #include <sys/systm.h>
45 45 #include <sys/cred.h>
46 46 #include <sys/proc.h>
47 47 #include <sys/user.h>
48 48 #include <sys/buf.h>
49 49 #include <sys/vfs.h>
50 50 #include <sys/vnode.h>
51 51 #include <sys/pathname.h>
52 52 #include <sys/uio.h>
53 53 #include <sys/file.h>
54 54 #include <sys/stat.h>
55 55 #include <sys/errno.h>
56 56 #include <sys/socket.h>
57 57 #include <sys/sysmacros.h>
58 58 #include <sys/siginfo.h>
59 59 #include <sys/tiuser.h>
60 60 #include <sys/statvfs.h>
61 61 #include <sys/stream.h>
62 62 #include <sys/strsun.h>
63 63 #include <sys/strsubr.h>
64 64 #include <sys/stropts.h>
65 65 #include <sys/timod.h>
66 66 #include <sys/t_kuser.h>
67 67 #include <sys/kmem.h>
68 68 #include <sys/kstat.h>
69 69 #include <sys/dirent.h>
70 70 #include <sys/cmn_err.h>
71 71 #include <sys/debug.h>
72 72 #include <sys/unistd.h>
73 73 #include <sys/vtrace.h>
74 74 #include <sys/mode.h>
75 75 #include <sys/acl.h>
76 76 #include <sys/sdt.h>
77 77 #include <sys/debug.h>
78 78
79 79 #include <rpc/types.h>
80 80 #include <rpc/auth.h>
81 81 #include <rpc/auth_unix.h>
82 82 #include <rpc/auth_des.h>
83 83 #include <rpc/svc.h>
84 84 #include <rpc/xdr.h>
85 85 #include <rpc/rpc_rdma.h>
86 86
87 87 #include <nfs/nfs.h>
88 88 #include <nfs/export.h>
89 89 #include <nfs/nfssys.h>
90 90 #include <nfs/nfs_clnt.h>
91 91 #include <nfs/nfs_acl.h>
92 92 #include <nfs/nfs_log.h>
93 93 #include <nfs/lm.h>
94 94 #include <nfs/nfs_dispatch.h>
95 95 #include <nfs/nfs4_drc.h>
96 96
97 97 #include <sys/modctl.h>
98 98 #include <sys/cladm.h>
99 99 #include <sys/clconf.h>
100 100
101 101 #include <sys/tsol/label.h>
102 102
103 103 #define MAXHOST 32
104 104 const char *kinet_ntop6(uchar_t *, char *, size_t);
105 105
106 106 /*
107 107 * Module linkage information.
108 108 */
109 109
110 110 static struct modlmisc modlmisc = {
111 111 &mod_miscops, "NFS server module"
112 112 };
113 113
114 114 static struct modlinkage modlinkage = {
115 115 MODREV_1, (void *)&modlmisc, NULL
116 116 };
117 117
118 118 zone_key_t nfssrv_zone_key;
119 119 list_t nfssrv_globals_list;
120 120 krwlock_t nfssrv_globals_rwl;
121 121
122 122 kmem_cache_t *nfs_xuio_cache;
123 123 int nfs_loaned_buffers = 0;
124 124
125 125 int
126 126 _init(void)
127 127 {
128 128 int status;
129 129
130 130 nfs_srvinit();
131 131
132 132 status = mod_install((struct modlinkage *)&modlinkage);
133 133 if (status != 0) {
134 134 /*
135 135 * Could not load module, cleanup previous
136 136 * initialization work.
137 137 */
138 138 nfs_srvfini();
139 139
140 140 return (status);
141 141 }
142 142
143 143 /*
144 144 * Initialise some placeholders for nfssys() calls. These have
145 145 * to be declared by the nfs module, since that handles nfssys()
146 146 * calls - also used by NFS clients - but are provided by this
147 147 * nfssrv module. These also then serve as confirmation to the
148 148 * relevant code in nfs that nfssrv has been loaded, as they're
149 149 * initially NULL.
150 150 */
151 151 nfs_srv_quiesce_func = nfs_srv_quiesce_all;
152 152 nfs_srv_dss_func = rfs4_dss_setpaths;
153 153
154 154 /* setup DSS paths here; must be done before initial server startup */
155 155 rfs4_dss_paths = rfs4_dss_oldpaths = NULL;
156 156
157 157 /* initialize the copy reduction caches */
158 158
159 159 nfs_xuio_cache = kmem_cache_create("nfs_xuio_cache",
160 160 sizeof (nfs_xuio_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
161 161
162 162 return (status);
163 163 }
164 164
165 165 int
166 166 _fini()
167 167 {
168 168 return (EBUSY);
169 169 }
170 170
171 171 int
172 172 _info(struct modinfo *modinfop)
173 173 {
174 174 return (mod_info(&modlinkage, modinfop));
175 175 }
176 176
177 177 /*
178 178 * PUBLICFH_CHECK() checks if the dispatch routine supports
179 179 * RPC_PUBLICFH_OK, if the filesystem is exported public, and if the
180 180 * incoming request is using the public filehandle. The check duplicates
181 181 * the exportmatch() call done in checkexport(), and we should consider
182 182 * modifying those routines to avoid the duplication. For now, we optimize
183 183 * by calling exportmatch() only after checking that the dispatch routine
184 184 * supports RPC_PUBLICFH_OK, and if the filesystem is explicitly exported
185 185 * public (i.e., not the placeholder).
186 186 */
187 187 #define PUBLICFH_CHECK(ne, disp, exi, fsid, xfid) \
|
↓ open down ↓ |
187 lines elided |
↑ open up ↑ |
188 188 ((disp->dis_flags & RPC_PUBLICFH_OK) && \
189 189 ((exi->exi_export.ex_flags & EX_PUBLIC) || \
190 190 (exi == ne->exi_public && exportmatch(ne->exi_root, \
191 191 fsid, xfid))))
192 192
193 193 static void nfs_srv_shutdown_all(int);
194 194 static void rfs4_server_start(nfs_globals_t *, int);
195 195 static void nullfree(void);
196 196 static void rfs_dispatch(struct svc_req *, SVCXPRT *);
197 197 static void acl_dispatch(struct svc_req *, SVCXPRT *);
198 -static void common_dispatch(struct svc_req *, SVCXPRT *,
199 - rpcvers_t, rpcvers_t, char *,
200 - struct rpc_disptable *);
201 198 static int checkauth(struct exportinfo *, struct svc_req *, cred_t *, int,
202 199 bool_t, bool_t *);
203 200 static char *client_name(struct svc_req *req);
204 201 static char *client_addr(struct svc_req *req, char *buf);
205 202 extern int sec_svc_getcred(struct svc_req *, cred_t *cr, char **, int *);
206 203 extern bool_t sec_svc_inrootlist(int, caddr_t, int, caddr_t *);
207 204 static void *nfs_server_zone_init(zoneid_t);
208 205 static void nfs_server_zone_fini(zoneid_t, void *);
209 206 static void nfs_server_zone_shutdown(zoneid_t, void *);
210 207
211 208 #define NFSLOG_COPY_NETBUF(exi, xprt, nb) { \
212 209 (nb)->maxlen = (xprt)->xp_rtaddr.maxlen; \
213 210 (nb)->len = (xprt)->xp_rtaddr.len; \
214 211 (nb)->buf = kmem_alloc((nb)->len, KM_SLEEP); \
215 212 bcopy((xprt)->xp_rtaddr.buf, (nb)->buf, (nb)->len); \
216 213 }
217 214
218 215 /*
219 216 * Public Filehandle common nfs routines
220 217 */
221 218 static int MCLpath(char **);
222 219 static void URLparse(char *);
223 220
224 221 /*
225 222 * NFS callout table.
226 223 * This table is used by svc_getreq() to dispatch a request with
227 224 * a given prog/vers pair to an appropriate service provider
228 225 * dispatch routine.
229 226 *
230 227 * NOTE: ordering is relied upon below when resetting the version min/max
231 228 * for NFS_PROGRAM. Careful, if this is ever changed.
232 229 */
233 230 static SVC_CALLOUT __nfs_sc_clts[] = {
234 231 { NFS_PROGRAM, NFS_VERSMIN, NFS_VERSMAX, rfs_dispatch },
235 232 { NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX, acl_dispatch }
236 233 };
237 234
238 235 static SVC_CALLOUT_TABLE nfs_sct_clts = {
239 236 sizeof (__nfs_sc_clts) / sizeof (__nfs_sc_clts[0]), FALSE,
240 237 __nfs_sc_clts
241 238 };
242 239
243 240 static SVC_CALLOUT __nfs_sc_cots[] = {
244 241 { NFS_PROGRAM, NFS_VERSMIN, NFS_VERSMAX, rfs_dispatch },
245 242 { NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX, acl_dispatch }
246 243 };
247 244
248 245 static SVC_CALLOUT_TABLE nfs_sct_cots = {
249 246 sizeof (__nfs_sc_cots) / sizeof (__nfs_sc_cots[0]), FALSE, __nfs_sc_cots
250 247 };
251 248
252 249 static SVC_CALLOUT __nfs_sc_rdma[] = {
253 250 { NFS_PROGRAM, NFS_VERSMIN, NFS_VERSMAX, rfs_dispatch },
254 251 { NFS_ACL_PROGRAM, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX, acl_dispatch }
255 252 };
256 253
257 254 static SVC_CALLOUT_TABLE nfs_sct_rdma = {
258 255 sizeof (__nfs_sc_rdma) / sizeof (__nfs_sc_rdma[0]), FALSE, __nfs_sc_rdma
259 256 };
260 257
261 258 /*
262 259 * DSS: distributed stable storage
263 260 * lists of all DSS paths: current, and before last warmstart
264 261 */
265 262 nvlist_t *rfs4_dss_paths, *rfs4_dss_oldpaths;
266 263
267 264 int rfs4_dispatch(struct rpcdisp *, struct svc_req *, SVCXPRT *, char *);
268 265 bool_t rfs4_minorvers_mismatch(struct svc_req *, SVCXPRT *, void *);
269 266
270 267 nfs_globals_t *
271 268 nfs_srv_getzg(void)
272 269 {
273 270 nfs_globals_t *ng;
274 271
275 272 ng = zone_getspecific(nfssrv_zone_key, curzone);
276 273 return (ng);
277 274 }
278 275
279 276 /*
280 277 * Will be called at the point the server pool is being unregistered
281 278 * from the pool list. From that point onwards, the pool is waiting
282 279 * to be drained and as such the server state is stale and pertains
283 280 * to the old instantiation of the NFS server pool.
284 281 */
285 282 void
286 283 nfs_srv_offline(void)
287 284 {
288 285 nfs_globals_t *ng;
289 286
290 287 ng = nfs_srv_getzg();
291 288
292 289 mutex_enter(&ng->nfs_server_upordown_lock);
293 290 if (ng->nfs_server_upordown == NFS_SERVER_RUNNING) {
294 291 ng->nfs_server_upordown = NFS_SERVER_OFFLINE;
295 292 }
296 293 mutex_exit(&ng->nfs_server_upordown_lock);
297 294 }
298 295
299 296 /*
300 297 * Will be called at the point the server pool is being destroyed so
301 298 * all transports have been closed and no service threads are in
302 299 * existence.
303 300 *
304 301 * If we quiesce the server, we're shutting it down without destroying the
305 302 * server state. This allows it to warm start subsequently.
306 303 */
307 304 void
308 305 nfs_srv_stop_all(void)
309 306 {
310 307 int quiesce = 0;
311 308 nfs_srv_shutdown_all(quiesce);
312 309 }
313 310
314 311 /*
315 312 * This alternative shutdown routine can be requested via nfssys()
316 313 */
317 314 void
318 315 nfs_srv_quiesce_all(void)
319 316 {
320 317 int quiesce = 1;
321 318 nfs_srv_shutdown_all(quiesce);
322 319 }
323 320
324 321 static void
325 322 nfs_srv_shutdown_all(int quiesce)
326 323 {
327 324 nfs_globals_t *ng = nfs_srv_getzg();
328 325
329 326 mutex_enter(&ng->nfs_server_upordown_lock);
330 327 if (quiesce) {
331 328 if (ng->nfs_server_upordown == NFS_SERVER_RUNNING ||
332 329 ng->nfs_server_upordown == NFS_SERVER_OFFLINE) {
333 330 ng->nfs_server_upordown = NFS_SERVER_QUIESCED;
334 331 cv_signal(&ng->nfs_server_upordown_cv);
335 332
336 333 /* reset DSS state */
337 334 rfs4_dss_numnewpaths = 0;
338 335 rfs4_dss_newpaths = NULL;
339 336
340 337 cmn_err(CE_NOTE, "nfs_server: server is now quiesced; "
341 338 "NFSv4 state has been preserved");
342 339 }
343 340 } else {
344 341 if (ng->nfs_server_upordown == NFS_SERVER_OFFLINE) {
345 342 ng->nfs_server_upordown = NFS_SERVER_STOPPING;
346 343 mutex_exit(&ng->nfs_server_upordown_lock);
347 344 rfs4_state_zone_fini();
348 345 rfs4_fini_drc();
349 346 mutex_enter(&ng->nfs_server_upordown_lock);
350 347 ng->nfs_server_upordown = NFS_SERVER_STOPPED;
351 348
352 349 /* reset DSS state */
353 350 rfs4_dss_numnewpaths = 0;
354 351 rfs4_dss_newpaths = NULL;
355 352
356 353 cv_signal(&ng->nfs_server_upordown_cv);
357 354 }
358 355 }
359 356 mutex_exit(&ng->nfs_server_upordown_lock);
360 357 }
361 358
362 359 static int
363 360 nfs_srv_set_sc_versions(struct file *fp, SVC_CALLOUT_TABLE **sctpp,
364 361 rpcvers_t versmin, rpcvers_t versmax)
365 362 {
366 363 struct strioctl strioc;
367 364 struct T_info_ack tinfo;
368 365 int error, retval;
369 366
370 367 /*
371 368 * Find out what type of transport this is.
372 369 */
373 370 strioc.ic_cmd = TI_GETINFO;
374 371 strioc.ic_timout = -1;
375 372 strioc.ic_len = sizeof (tinfo);
376 373 strioc.ic_dp = (char *)&tinfo;
377 374 tinfo.PRIM_type = T_INFO_REQ;
378 375
379 376 error = strioctl(fp->f_vnode, I_STR, (intptr_t)&strioc, 0, K_TO_K,
380 377 CRED(), &retval);
381 378 if (error || retval)
382 379 return (error);
383 380
384 381 /*
385 382 * Based on our query of the transport type...
386 383 *
387 384 * Reset the min/max versions based on the caller's request
388 385 * NOTE: This assumes that NFS_PROGRAM is first in the array!!
389 386 * And the second entry is the NFS_ACL_PROGRAM.
390 387 */
391 388 switch (tinfo.SERV_type) {
392 389 case T_CLTS:
393 390 if (versmax == NFS_V4)
394 391 return (EINVAL);
395 392 __nfs_sc_clts[0].sc_versmin = versmin;
396 393 __nfs_sc_clts[0].sc_versmax = versmax;
397 394 __nfs_sc_clts[1].sc_versmin = versmin;
398 395 __nfs_sc_clts[1].sc_versmax = versmax;
399 396 *sctpp = &nfs_sct_clts;
400 397 break;
401 398 case T_COTS:
402 399 case T_COTS_ORD:
403 400 __nfs_sc_cots[0].sc_versmin = versmin;
404 401 __nfs_sc_cots[0].sc_versmax = versmax;
405 402 /* For the NFS_ACL program, check the max version */
406 403 if (versmax > NFS_ACL_VERSMAX)
407 404 versmax = NFS_ACL_VERSMAX;
408 405 __nfs_sc_cots[1].sc_versmin = versmin;
409 406 __nfs_sc_cots[1].sc_versmax = versmax;
410 407 *sctpp = &nfs_sct_cots;
411 408 break;
412 409 default:
413 410 error = EINVAL;
414 411 }
415 412
416 413 return (error);
417 414 }
418 415
419 416 /*
420 417 * NFS Server system call.
421 418 * Does all of the work of running a NFS server.
422 419 * uap->fd is the fd of an open transport provider
423 420 */
424 421 int
425 422 nfs_svc(struct nfs_svc_args *arg, model_t model)
426 423 {
427 424 nfs_globals_t *ng;
428 425 file_t *fp;
429 426 SVCMASTERXPRT *xprt;
430 427 int error;
431 428 int readsize;
432 429 char buf[KNC_STRSIZE];
433 430 size_t len;
434 431 STRUCT_HANDLE(nfs_svc_args, uap);
435 432 struct netbuf addrmask;
436 433 SVC_CALLOUT_TABLE *sctp = NULL;
437 434
438 435 #ifdef lint
439 436 model = model; /* STRUCT macros don't always refer to it */
440 437 #endif
441 438
442 439 ng = nfs_srv_getzg();
443 440 STRUCT_SET_HANDLE(uap, model, arg);
444 441
445 442 /* Check privileges in nfssys() */
446 443
447 444 if ((fp = getf(STRUCT_FGET(uap, fd))) == NULL)
448 445 return (EBADF);
449 446
450 447 /* Setup global file handle in nfs_export */
451 448 if ((error = nfs_export_get_rootfh(ng)) != 0)
452 449 return (error);
453 450
454 451 /*
455 452 * Set read buffer size to rsize
456 453 * and add room for RPC headers.
457 454 */
458 455 readsize = nfs3tsize() + (RPC_MAXDATASIZE - NFS_MAXDATA);
459 456 if (readsize < RPC_MAXDATASIZE)
460 457 readsize = RPC_MAXDATASIZE;
461 458
462 459 error = copyinstr((const char *)STRUCT_FGETP(uap, netid), buf,
463 460 KNC_STRSIZE, &len);
464 461 if (error) {
465 462 releasef(STRUCT_FGET(uap, fd));
466 463 return (error);
467 464 }
468 465
469 466 addrmask.len = STRUCT_FGET(uap, addrmask.len);
470 467 addrmask.maxlen = STRUCT_FGET(uap, addrmask.maxlen);
471 468 addrmask.buf = kmem_alloc(addrmask.maxlen, KM_SLEEP);
472 469 error = copyin(STRUCT_FGETP(uap, addrmask.buf), addrmask.buf,
473 470 addrmask.len);
474 471 if (error) {
475 472 releasef(STRUCT_FGET(uap, fd));
476 473 kmem_free(addrmask.buf, addrmask.maxlen);
477 474 return (error);
478 475 }
479 476
480 477 ng->nfs_versmin = STRUCT_FGET(uap, versmin);
481 478 ng->nfs_versmax = STRUCT_FGET(uap, versmax);
482 479
483 480 /* Double check the vers min/max ranges */
484 481 if ((ng->nfs_versmin > ng->nfs_versmax) ||
485 482 (ng->nfs_versmin < NFS_VERSMIN) ||
486 483 (ng->nfs_versmax > NFS_VERSMAX)) {
487 484 ng->nfs_versmin = NFS_VERSMIN_DEFAULT;
488 485 ng->nfs_versmax = NFS_VERSMAX_DEFAULT;
489 486 }
490 487
491 488 if (error = nfs_srv_set_sc_versions(fp, &sctp, ng->nfs_versmin,
492 489 ng->nfs_versmax)) {
493 490 releasef(STRUCT_FGET(uap, fd));
494 491 kmem_free(addrmask.buf, addrmask.maxlen);
495 492 return (error);
496 493 }
497 494
498 495 /* Initialize nfsv4 server */
499 496 if (ng->nfs_versmax == (rpcvers_t)NFS_V4)
500 497 rfs4_server_start(ng, STRUCT_FGET(uap, delegation));
501 498
502 499 /* Create a transport handle. */
503 500 error = svc_tli_kcreate(fp, readsize, buf, &addrmask, &xprt,
504 501 sctp, NULL, NFS_SVCPOOL_ID, TRUE);
505 502
506 503 if (error)
507 504 kmem_free(addrmask.buf, addrmask.maxlen);
508 505
509 506 releasef(STRUCT_FGET(uap, fd));
510 507
511 508 /* HA-NFSv4: save the cluster nodeid */
512 509 if (cluster_bootflags & CLUSTER_BOOTED)
513 510 lm_global_nlmid = clconf_get_nodeid();
514 511
515 512 return (error);
516 513 }
517 514
518 515 static void
519 516 rfs4_server_start(nfs_globals_t *ng, int nfs4_srv_delegation)
520 517 {
521 518 /*
522 519 * Determine if the server has previously been "started" and
523 520 * if not, do the per instance initialization
524 521 */
525 522 mutex_enter(&ng->nfs_server_upordown_lock);
526 523
527 524 if (ng->nfs_server_upordown != NFS_SERVER_RUNNING) {
528 525 /* Do we need to stop and wait on the previous server? */
529 526 while (ng->nfs_server_upordown == NFS_SERVER_STOPPING ||
530 527 ng->nfs_server_upordown == NFS_SERVER_OFFLINE)
531 528 cv_wait(&ng->nfs_server_upordown_cv,
532 529 &ng->nfs_server_upordown_lock);
533 530
534 531 if (ng->nfs_server_upordown != NFS_SERVER_RUNNING) {
535 532 (void) svc_pool_control(NFS_SVCPOOL_ID,
536 533 SVCPSET_UNREGISTER_PROC, (void *)&nfs_srv_offline);
537 534 (void) svc_pool_control(NFS_SVCPOOL_ID,
538 535 SVCPSET_SHUTDOWN_PROC, (void *)&nfs_srv_stop_all);
539 536
540 537 rfs4_do_server_start(ng->nfs_server_upordown,
541 538 nfs4_srv_delegation,
542 539 cluster_bootflags & CLUSTER_BOOTED);
543 540
544 541 ng->nfs_server_upordown = NFS_SERVER_RUNNING;
545 542 }
546 543 cv_signal(&ng->nfs_server_upordown_cv);
547 544 }
548 545 mutex_exit(&ng->nfs_server_upordown_lock);
549 546 }
550 547
551 548 /*
552 549 * If RDMA device available,
553 550 * start RDMA listener.
554 551 */
555 552 int
556 553 rdma_start(struct rdma_svc_args *rsa)
557 554 {
558 555 nfs_globals_t *ng;
559 556 int error;
560 557 rdma_xprt_group_t started_rdma_xprts;
561 558 rdma_stat stat;
562 559 int svc_state = 0;
563 560
564 561 /* Double check the vers min/max ranges */
565 562 if ((rsa->nfs_versmin > rsa->nfs_versmax) ||
566 563 (rsa->nfs_versmin < NFS_VERSMIN) ||
567 564 (rsa->nfs_versmax > NFS_VERSMAX)) {
568 565 rsa->nfs_versmin = NFS_VERSMIN_DEFAULT;
569 566 rsa->nfs_versmax = NFS_VERSMAX_DEFAULT;
570 567 }
571 568
572 569 ng = nfs_srv_getzg();
573 570 ng->nfs_versmin = rsa->nfs_versmin;
574 571 ng->nfs_versmax = rsa->nfs_versmax;
575 572
576 573 /* Set the versions in the callout table */
577 574 __nfs_sc_rdma[0].sc_versmin = rsa->nfs_versmin;
578 575 __nfs_sc_rdma[0].sc_versmax = rsa->nfs_versmax;
579 576 /* For the NFS_ACL program, check the max version */
580 577 __nfs_sc_rdma[1].sc_versmin = rsa->nfs_versmin;
581 578 if (rsa->nfs_versmax > NFS_ACL_VERSMAX)
582 579 __nfs_sc_rdma[1].sc_versmax = NFS_ACL_VERSMAX;
583 580 else
584 581 __nfs_sc_rdma[1].sc_versmax = rsa->nfs_versmax;
585 582
586 583 /* Initialize nfsv4 server */
587 584 if (rsa->nfs_versmax == (rpcvers_t)NFS_V4)
588 585 rfs4_server_start(ng, rsa->delegation);
589 586
590 587 started_rdma_xprts.rtg_count = 0;
591 588 started_rdma_xprts.rtg_listhead = NULL;
592 589 started_rdma_xprts.rtg_poolid = rsa->poolid;
593 590
594 591 restart:
595 592 error = svc_rdma_kcreate(rsa->netid, &nfs_sct_rdma, rsa->poolid,
596 593 &started_rdma_xprts);
597 594
598 595 svc_state = !error;
599 596
600 597 while (!error) {
601 598
602 599 /*
603 600 * wait till either interrupted by a signal on
604 601 * nfs service stop/restart or signalled by a
605 602 * rdma attach/detatch.
606 603 */
607 604
608 605 stat = rdma_kwait();
609 606
610 607 /*
611 608 * stop services if running -- either on a HCA detach event
612 609 * or if the nfs service is stopped/restarted.
613 610 */
614 611
615 612 if ((stat == RDMA_HCA_DETACH || stat == RDMA_INTR) &&
616 613 svc_state) {
617 614 rdma_stop(&started_rdma_xprts);
618 615 svc_state = 0;
619 616 }
620 617
621 618 /*
622 619 * nfs service stop/restart, break out of the
623 620 * wait loop and return;
624 621 */
625 622 if (stat == RDMA_INTR)
626 623 return (0);
627 624
628 625 /*
629 626 * restart stopped services on a HCA attach event
630 627 * (if not already running)
631 628 */
632 629
633 630 if ((stat == RDMA_HCA_ATTACH) && (svc_state == 0))
634 631 goto restart;
635 632
636 633 /*
637 634 * loop until a nfs service stop/restart
638 635 */
639 636 }
640 637
641 638 return (error);
642 639 }
643 640
644 641 /* ARGSUSED */
645 642 void
646 643 rpc_null(caddr_t *argp, caddr_t *resp, struct exportinfo *exi,
647 644 struct svc_req *req, cred_t *cr, bool_t ro)
648 645 {
649 646 }
650 647
651 648 /* ARGSUSED */
652 649 void
653 650 rpc_null_v3(caddr_t *argp, caddr_t *resp, struct exportinfo *exi,
654 651 struct svc_req *req, cred_t *cr, bool_t ro)
655 652 {
656 653 DTRACE_NFSV3_4(op__null__start, struct svc_req *, req,
657 654 cred_t *, cr, vnode_t *, NULL, struct exportinfo *, exi);
658 655 DTRACE_NFSV3_4(op__null__done, struct svc_req *, req,
659 656 cred_t *, cr, vnode_t *, NULL, struct exportinfo *, exi);
660 657 }
661 658
662 659 /* ARGSUSED */
663 660 static void
664 661 rfs_error(caddr_t *argp, caddr_t *resp, struct exportinfo *exi,
665 662 struct svc_req *req, cred_t *cr, bool_t ro)
666 663 {
667 664 /* return (EOPNOTSUPP); */
668 665 }
669 666
670 667 static void
671 668 nullfree(void)
672 669 {
673 670 }
674 671
675 672 static char *rfscallnames_v2[] = {
676 673 "RFS2_NULL",
677 674 "RFS2_GETATTR",
678 675 "RFS2_SETATTR",
679 676 "RFS2_ROOT",
680 677 "RFS2_LOOKUP",
681 678 "RFS2_READLINK",
682 679 "RFS2_READ",
683 680 "RFS2_WRITECACHE",
684 681 "RFS2_WRITE",
685 682 "RFS2_CREATE",
686 683 "RFS2_REMOVE",
687 684 "RFS2_RENAME",
688 685 "RFS2_LINK",
689 686 "RFS2_SYMLINK",
690 687 "RFS2_MKDIR",
691 688 "RFS2_RMDIR",
692 689 "RFS2_READDIR",
693 690 "RFS2_STATFS"
694 691 };
695 692
696 693 static struct rpcdisp rfsdisptab_v2[] = {
697 694 /*
698 695 * NFS VERSION 2
699 696 */
700 697
701 698 /* RFS_NULL = 0 */
702 699 {rpc_null,
703 700 xdr_void, NULL_xdrproc_t, 0,
704 701 xdr_void, NULL_xdrproc_t, 0,
705 702 nullfree, RPC_IDEMPOTENT,
706 703 0},
707 704
708 705 /* RFS_GETATTR = 1 */
709 706 {rfs_getattr,
710 707 xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t),
711 708 xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat),
712 709 nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP,
713 710 rfs_getattr_getfh},
714 711
715 712 /* RFS_SETATTR = 2 */
716 713 {rfs_setattr,
717 714 xdr_saargs, NULL_xdrproc_t, sizeof (struct nfssaargs),
718 715 xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat),
719 716 nullfree, RPC_MAPRESP,
720 717 rfs_setattr_getfh},
721 718
722 719 /* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
723 720 {rfs_error,
724 721 xdr_void, NULL_xdrproc_t, 0,
725 722 xdr_void, NULL_xdrproc_t, 0,
726 723 nullfree, RPC_IDEMPOTENT,
727 724 0},
728 725
729 726 /* RFS_LOOKUP = 4 */
730 727 {rfs_lookup,
731 728 xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs),
732 729 xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres),
733 730 nullfree, RPC_IDEMPOTENT|RPC_MAPRESP|RPC_PUBLICFH_OK,
734 731 rfs_lookup_getfh},
735 732
736 733 /* RFS_READLINK = 5 */
737 734 {rfs_readlink,
738 735 xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t),
739 736 xdr_rdlnres, NULL_xdrproc_t, sizeof (struct nfsrdlnres),
740 737 rfs_rlfree, RPC_IDEMPOTENT,
741 738 rfs_readlink_getfh},
742 739
743 740 /* RFS_READ = 6 */
744 741 {rfs_read,
745 742 xdr_readargs, NULL_xdrproc_t, sizeof (struct nfsreadargs),
746 743 xdr_rdresult, NULL_xdrproc_t, sizeof (struct nfsrdresult),
747 744 rfs_rdfree, RPC_IDEMPOTENT,
748 745 rfs_read_getfh},
749 746
750 747 /* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
751 748 {rfs_error,
752 749 xdr_void, NULL_xdrproc_t, 0,
753 750 xdr_void, NULL_xdrproc_t, 0,
754 751 nullfree, RPC_IDEMPOTENT,
755 752 0},
756 753
757 754 /* RFS_WRITE = 8 */
758 755 {rfs_write,
759 756 xdr_writeargs, NULL_xdrproc_t, sizeof (struct nfswriteargs),
760 757 xdr_attrstat, xdr_fastattrstat, sizeof (struct nfsattrstat),
761 758 nullfree, RPC_MAPRESP,
762 759 rfs_write_getfh},
763 760
764 761 /* RFS_CREATE = 9 */
765 762 {rfs_create,
766 763 xdr_creatargs, NULL_xdrproc_t, sizeof (struct nfscreatargs),
767 764 xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres),
768 765 nullfree, RPC_MAPRESP,
769 766 rfs_create_getfh},
770 767
771 768 /* RFS_REMOVE = 10 */
772 769 {rfs_remove,
773 770 xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs),
774 771 #ifdef _LITTLE_ENDIAN
775 772 xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
776 773 #else
777 774 xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
778 775 #endif
779 776 nullfree, RPC_MAPRESP,
780 777 rfs_remove_getfh},
781 778
782 779 /* RFS_RENAME = 11 */
783 780 {rfs_rename,
784 781 xdr_rnmargs, NULL_xdrproc_t, sizeof (struct nfsrnmargs),
785 782 #ifdef _LITTLE_ENDIAN
786 783 xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
787 784 #else
788 785 xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
789 786 #endif
790 787 nullfree, RPC_MAPRESP,
791 788 rfs_rename_getfh},
792 789
793 790 /* RFS_LINK = 12 */
794 791 {rfs_link,
795 792 xdr_linkargs, NULL_xdrproc_t, sizeof (struct nfslinkargs),
796 793 #ifdef _LITTLE_ENDIAN
797 794 xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
798 795 #else
799 796 xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
800 797 #endif
801 798 nullfree, RPC_MAPRESP,
802 799 rfs_link_getfh},
803 800
804 801 /* RFS_SYMLINK = 13 */
805 802 {rfs_symlink,
806 803 xdr_slargs, NULL_xdrproc_t, sizeof (struct nfsslargs),
807 804 #ifdef _LITTLE_ENDIAN
808 805 xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
809 806 #else
810 807 xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
811 808 #endif
812 809 nullfree, RPC_MAPRESP,
813 810 rfs_symlink_getfh},
814 811
815 812 /* RFS_MKDIR = 14 */
816 813 {rfs_mkdir,
817 814 xdr_creatargs, NULL_xdrproc_t, sizeof (struct nfscreatargs),
818 815 xdr_diropres, xdr_fastdiropres, sizeof (struct nfsdiropres),
819 816 nullfree, RPC_MAPRESP,
820 817 rfs_mkdir_getfh},
821 818
822 819 /* RFS_RMDIR = 15 */
823 820 {rfs_rmdir,
824 821 xdr_diropargs, NULL_xdrproc_t, sizeof (struct nfsdiropargs),
825 822 #ifdef _LITTLE_ENDIAN
826 823 xdr_enum, xdr_fastenum, sizeof (enum nfsstat),
827 824 #else
828 825 xdr_enum, NULL_xdrproc_t, sizeof (enum nfsstat),
829 826 #endif
830 827 nullfree, RPC_MAPRESP,
831 828 rfs_rmdir_getfh},
832 829
833 830 /* RFS_READDIR = 16 */
834 831 {rfs_readdir,
835 832 xdr_rddirargs, NULL_xdrproc_t, sizeof (struct nfsrddirargs),
836 833 xdr_putrddirres, NULL_xdrproc_t, sizeof (struct nfsrddirres),
837 834 rfs_rddirfree, RPC_IDEMPOTENT,
838 835 rfs_readdir_getfh},
839 836
840 837 /* RFS_STATFS = 17 */
841 838 {rfs_statfs,
842 839 xdr_fhandle, xdr_fastfhandle, sizeof (fhandle_t),
843 840 xdr_statfs, xdr_faststatfs, sizeof (struct nfsstatfs),
844 841 nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP,
845 842 rfs_statfs_getfh},
846 843 };
847 844
848 845 static char *rfscallnames_v3[] = {
849 846 "RFS3_NULL",
850 847 "RFS3_GETATTR",
851 848 "RFS3_SETATTR",
852 849 "RFS3_LOOKUP",
853 850 "RFS3_ACCESS",
854 851 "RFS3_READLINK",
855 852 "RFS3_READ",
856 853 "RFS3_WRITE",
857 854 "RFS3_CREATE",
858 855 "RFS3_MKDIR",
859 856 "RFS3_SYMLINK",
860 857 "RFS3_MKNOD",
861 858 "RFS3_REMOVE",
862 859 "RFS3_RMDIR",
863 860 "RFS3_RENAME",
864 861 "RFS3_LINK",
865 862 "RFS3_READDIR",
866 863 "RFS3_READDIRPLUS",
867 864 "RFS3_FSSTAT",
868 865 "RFS3_FSINFO",
869 866 "RFS3_PATHCONF",
870 867 "RFS3_COMMIT"
871 868 };
872 869
873 870 static struct rpcdisp rfsdisptab_v3[] = {
874 871 /*
875 872 * NFS VERSION 3
876 873 */
877 874
878 875 /* RFS_NULL = 0 */
879 876 {rpc_null_v3,
880 877 xdr_void, NULL_xdrproc_t, 0,
881 878 xdr_void, NULL_xdrproc_t, 0,
882 879 nullfree, RPC_IDEMPOTENT,
883 880 0},
884 881
885 882 /* RFS3_GETATTR = 1 */
886 883 {rfs3_getattr,
887 884 xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (GETATTR3args),
888 885 xdr_GETATTR3res, NULL_xdrproc_t, sizeof (GETATTR3res),
889 886 nullfree, (RPC_IDEMPOTENT | RPC_ALLOWANON),
890 887 rfs3_getattr_getfh},
891 888
892 889 /* RFS3_SETATTR = 2 */
893 890 {rfs3_setattr,
894 891 xdr_SETATTR3args, NULL_xdrproc_t, sizeof (SETATTR3args),
895 892 xdr_SETATTR3res, NULL_xdrproc_t, sizeof (SETATTR3res),
896 893 nullfree, 0,
897 894 rfs3_setattr_getfh},
898 895
899 896 /* RFS3_LOOKUP = 3 */
900 897 {rfs3_lookup,
901 898 xdr_diropargs3, NULL_xdrproc_t, sizeof (LOOKUP3args),
902 899 xdr_LOOKUP3res, NULL_xdrproc_t, sizeof (LOOKUP3res),
903 900 nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK),
904 901 rfs3_lookup_getfh},
905 902
906 903 /* RFS3_ACCESS = 4 */
907 904 {rfs3_access,
908 905 xdr_ACCESS3args, NULL_xdrproc_t, sizeof (ACCESS3args),
909 906 xdr_ACCESS3res, NULL_xdrproc_t, sizeof (ACCESS3res),
910 907 nullfree, RPC_IDEMPOTENT,
911 908 rfs3_access_getfh},
912 909
913 910 /* RFS3_READLINK = 5 */
914 911 {rfs3_readlink,
915 912 xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (READLINK3args),
916 913 xdr_READLINK3res, NULL_xdrproc_t, sizeof (READLINK3res),
917 914 rfs3_readlink_free, RPC_IDEMPOTENT,
918 915 rfs3_readlink_getfh},
919 916
920 917 /* RFS3_READ = 6 */
921 918 {rfs3_read,
922 919 xdr_READ3args, NULL_xdrproc_t, sizeof (READ3args),
923 920 xdr_READ3res, NULL_xdrproc_t, sizeof (READ3res),
924 921 rfs3_read_free, RPC_IDEMPOTENT,
925 922 rfs3_read_getfh},
926 923
927 924 /* RFS3_WRITE = 7 */
928 925 {rfs3_write,
929 926 xdr_WRITE3args, NULL_xdrproc_t, sizeof (WRITE3args),
930 927 xdr_WRITE3res, NULL_xdrproc_t, sizeof (WRITE3res),
931 928 nullfree, 0,
932 929 rfs3_write_getfh},
933 930
934 931 /* RFS3_CREATE = 8 */
935 932 {rfs3_create,
936 933 xdr_CREATE3args, NULL_xdrproc_t, sizeof (CREATE3args),
937 934 xdr_CREATE3res, NULL_xdrproc_t, sizeof (CREATE3res),
938 935 nullfree, 0,
939 936 rfs3_create_getfh},
940 937
941 938 /* RFS3_MKDIR = 9 */
942 939 {rfs3_mkdir,
943 940 xdr_MKDIR3args, NULL_xdrproc_t, sizeof (MKDIR3args),
944 941 xdr_MKDIR3res, NULL_xdrproc_t, sizeof (MKDIR3res),
945 942 nullfree, 0,
946 943 rfs3_mkdir_getfh},
947 944
948 945 /* RFS3_SYMLINK = 10 */
949 946 {rfs3_symlink,
950 947 xdr_SYMLINK3args, NULL_xdrproc_t, sizeof (SYMLINK3args),
951 948 xdr_SYMLINK3res, NULL_xdrproc_t, sizeof (SYMLINK3res),
952 949 nullfree, 0,
953 950 rfs3_symlink_getfh},
954 951
955 952 /* RFS3_MKNOD = 11 */
956 953 {rfs3_mknod,
957 954 xdr_MKNOD3args, NULL_xdrproc_t, sizeof (MKNOD3args),
958 955 xdr_MKNOD3res, NULL_xdrproc_t, sizeof (MKNOD3res),
959 956 nullfree, 0,
960 957 rfs3_mknod_getfh},
961 958
962 959 /* RFS3_REMOVE = 12 */
963 960 {rfs3_remove,
964 961 xdr_diropargs3, NULL_xdrproc_t, sizeof (REMOVE3args),
965 962 xdr_REMOVE3res, NULL_xdrproc_t, sizeof (REMOVE3res),
966 963 nullfree, 0,
967 964 rfs3_remove_getfh},
968 965
969 966 /* RFS3_RMDIR = 13 */
970 967 {rfs3_rmdir,
971 968 xdr_diropargs3, NULL_xdrproc_t, sizeof (RMDIR3args),
972 969 xdr_RMDIR3res, NULL_xdrproc_t, sizeof (RMDIR3res),
973 970 nullfree, 0,
974 971 rfs3_rmdir_getfh},
975 972
976 973 /* RFS3_RENAME = 14 */
977 974 {rfs3_rename,
978 975 xdr_RENAME3args, NULL_xdrproc_t, sizeof (RENAME3args),
979 976 xdr_RENAME3res, NULL_xdrproc_t, sizeof (RENAME3res),
980 977 nullfree, 0,
981 978 rfs3_rename_getfh},
982 979
983 980 /* RFS3_LINK = 15 */
984 981 {rfs3_link,
985 982 xdr_LINK3args, NULL_xdrproc_t, sizeof (LINK3args),
986 983 xdr_LINK3res, NULL_xdrproc_t, sizeof (LINK3res),
987 984 nullfree, 0,
988 985 rfs3_link_getfh},
989 986
990 987 /* RFS3_READDIR = 16 */
991 988 {rfs3_readdir,
992 989 xdr_READDIR3args, NULL_xdrproc_t, sizeof (READDIR3args),
993 990 xdr_READDIR3res, NULL_xdrproc_t, sizeof (READDIR3res),
994 991 rfs3_readdir_free, RPC_IDEMPOTENT,
995 992 rfs3_readdir_getfh},
996 993
997 994 /* RFS3_READDIRPLUS = 17 */
998 995 {rfs3_readdirplus,
999 996 xdr_READDIRPLUS3args, NULL_xdrproc_t, sizeof (READDIRPLUS3args),
1000 997 xdr_READDIRPLUS3res, NULL_xdrproc_t, sizeof (READDIRPLUS3res),
1001 998 rfs3_readdirplus_free, RPC_AVOIDWORK,
1002 999 rfs3_readdirplus_getfh},
1003 1000
1004 1001 /* RFS3_FSSTAT = 18 */
1005 1002 {rfs3_fsstat,
1006 1003 xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (FSSTAT3args),
1007 1004 xdr_FSSTAT3res, NULL_xdrproc_t, sizeof (FSSTAT3res),
1008 1005 nullfree, RPC_IDEMPOTENT,
1009 1006 rfs3_fsstat_getfh},
1010 1007
1011 1008 /* RFS3_FSINFO = 19 */
1012 1009 {rfs3_fsinfo,
1013 1010 xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (FSINFO3args),
1014 1011 xdr_FSINFO3res, NULL_xdrproc_t, sizeof (FSINFO3res),
1015 1012 nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON,
1016 1013 rfs3_fsinfo_getfh},
1017 1014
1018 1015 /* RFS3_PATHCONF = 20 */
1019 1016 {rfs3_pathconf,
1020 1017 xdr_nfs_fh3_server, NULL_xdrproc_t, sizeof (PATHCONF3args),
1021 1018 xdr_PATHCONF3res, NULL_xdrproc_t, sizeof (PATHCONF3res),
1022 1019 nullfree, RPC_IDEMPOTENT,
1023 1020 rfs3_pathconf_getfh},
1024 1021
1025 1022 /* RFS3_COMMIT = 21 */
1026 1023 {rfs3_commit,
1027 1024 xdr_COMMIT3args, NULL_xdrproc_t, sizeof (COMMIT3args),
1028 1025 xdr_COMMIT3res, NULL_xdrproc_t, sizeof (COMMIT3res),
1029 1026 nullfree, RPC_IDEMPOTENT,
1030 1027 rfs3_commit_getfh},
1031 1028 };
1032 1029
1033 1030 static char *rfscallnames_v4[] = {
1034 1031 "RFS4_NULL",
1035 1032 "RFS4_COMPOUND",
1036 1033 "RFS4_NULL",
1037 1034 "RFS4_NULL",
1038 1035 "RFS4_NULL",
1039 1036 "RFS4_NULL",
1040 1037 "RFS4_NULL",
1041 1038 "RFS4_NULL",
1042 1039 "RFS4_CREATE"
1043 1040 };
1044 1041
1045 1042 static struct rpcdisp rfsdisptab_v4[] = {
1046 1043 /*
1047 1044 * NFS VERSION 4
1048 1045 */
1049 1046
1050 1047 /* RFS_NULL = 0 */
1051 1048 {rpc_null,
1052 1049 xdr_void, NULL_xdrproc_t, 0,
1053 1050 xdr_void, NULL_xdrproc_t, 0,
1054 1051 nullfree, RPC_IDEMPOTENT, 0},
1055 1052
1056 1053 /* RFS4_compound = 1 */
1057 1054 {rfs4_compound,
1058 1055 xdr_COMPOUND4args_srv, NULL_xdrproc_t, sizeof (COMPOUND4args),
1059 1056 xdr_COMPOUND4res_srv, NULL_xdrproc_t, sizeof (COMPOUND4res),
1060 1057 rfs4_compound_free, 0, 0},
1061 1058 };
1062 1059
1063 1060 union rfs_args {
1064 1061 /*
1065 1062 * NFS VERSION 2
1066 1063 */
1067 1064
1068 1065 /* RFS_NULL = 0 */
1069 1066
1070 1067 /* RFS_GETATTR = 1 */
1071 1068 fhandle_t nfs2_getattr_args;
1072 1069
1073 1070 /* RFS_SETATTR = 2 */
1074 1071 struct nfssaargs nfs2_setattr_args;
1075 1072
1076 1073 /* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
1077 1074
1078 1075 /* RFS_LOOKUP = 4 */
1079 1076 struct nfsdiropargs nfs2_lookup_args;
1080 1077
1081 1078 /* RFS_READLINK = 5 */
1082 1079 fhandle_t nfs2_readlink_args;
1083 1080
1084 1081 /* RFS_READ = 6 */
1085 1082 struct nfsreadargs nfs2_read_args;
1086 1083
1087 1084 /* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
1088 1085
1089 1086 /* RFS_WRITE = 8 */
1090 1087 struct nfswriteargs nfs2_write_args;
1091 1088
1092 1089 /* RFS_CREATE = 9 */
1093 1090 struct nfscreatargs nfs2_create_args;
1094 1091
1095 1092 /* RFS_REMOVE = 10 */
1096 1093 struct nfsdiropargs nfs2_remove_args;
1097 1094
1098 1095 /* RFS_RENAME = 11 */
1099 1096 struct nfsrnmargs nfs2_rename_args;
1100 1097
1101 1098 /* RFS_LINK = 12 */
1102 1099 struct nfslinkargs nfs2_link_args;
1103 1100
1104 1101 /* RFS_SYMLINK = 13 */
1105 1102 struct nfsslargs nfs2_symlink_args;
1106 1103
1107 1104 /* RFS_MKDIR = 14 */
1108 1105 struct nfscreatargs nfs2_mkdir_args;
1109 1106
1110 1107 /* RFS_RMDIR = 15 */
1111 1108 struct nfsdiropargs nfs2_rmdir_args;
1112 1109
1113 1110 /* RFS_READDIR = 16 */
1114 1111 struct nfsrddirargs nfs2_readdir_args;
1115 1112
1116 1113 /* RFS_STATFS = 17 */
1117 1114 fhandle_t nfs2_statfs_args;
1118 1115
1119 1116 /*
1120 1117 * NFS VERSION 3
1121 1118 */
1122 1119
1123 1120 /* RFS_NULL = 0 */
1124 1121
1125 1122 /* RFS3_GETATTR = 1 */
1126 1123 GETATTR3args nfs3_getattr_args;
1127 1124
1128 1125 /* RFS3_SETATTR = 2 */
1129 1126 SETATTR3args nfs3_setattr_args;
1130 1127
1131 1128 /* RFS3_LOOKUP = 3 */
1132 1129 LOOKUP3args nfs3_lookup_args;
1133 1130
1134 1131 /* RFS3_ACCESS = 4 */
1135 1132 ACCESS3args nfs3_access_args;
1136 1133
1137 1134 /* RFS3_READLINK = 5 */
1138 1135 READLINK3args nfs3_readlink_args;
1139 1136
1140 1137 /* RFS3_READ = 6 */
1141 1138 READ3args nfs3_read_args;
1142 1139
1143 1140 /* RFS3_WRITE = 7 */
1144 1141 WRITE3args nfs3_write_args;
1145 1142
1146 1143 /* RFS3_CREATE = 8 */
1147 1144 CREATE3args nfs3_create_args;
1148 1145
1149 1146 /* RFS3_MKDIR = 9 */
1150 1147 MKDIR3args nfs3_mkdir_args;
1151 1148
1152 1149 /* RFS3_SYMLINK = 10 */
1153 1150 SYMLINK3args nfs3_symlink_args;
1154 1151
1155 1152 /* RFS3_MKNOD = 11 */
1156 1153 MKNOD3args nfs3_mknod_args;
1157 1154
1158 1155 /* RFS3_REMOVE = 12 */
1159 1156 REMOVE3args nfs3_remove_args;
1160 1157
1161 1158 /* RFS3_RMDIR = 13 */
1162 1159 RMDIR3args nfs3_rmdir_args;
1163 1160
1164 1161 /* RFS3_RENAME = 14 */
1165 1162 RENAME3args nfs3_rename_args;
1166 1163
1167 1164 /* RFS3_LINK = 15 */
1168 1165 LINK3args nfs3_link_args;
1169 1166
1170 1167 /* RFS3_READDIR = 16 */
1171 1168 READDIR3args nfs3_readdir_args;
1172 1169
1173 1170 /* RFS3_READDIRPLUS = 17 */
1174 1171 READDIRPLUS3args nfs3_readdirplus_args;
1175 1172
1176 1173 /* RFS3_FSSTAT = 18 */
1177 1174 FSSTAT3args nfs3_fsstat_args;
1178 1175
1179 1176 /* RFS3_FSINFO = 19 */
1180 1177 FSINFO3args nfs3_fsinfo_args;
1181 1178
1182 1179 /* RFS3_PATHCONF = 20 */
1183 1180 PATHCONF3args nfs3_pathconf_args;
1184 1181
1185 1182 /* RFS3_COMMIT = 21 */
1186 1183 COMMIT3args nfs3_commit_args;
1187 1184
1188 1185 /*
1189 1186 * NFS VERSION 4
1190 1187 */
1191 1188
1192 1189 /* RFS_NULL = 0 */
1193 1190
1194 1191 /* COMPUND = 1 */
1195 1192 COMPOUND4args nfs4_compound_args;
1196 1193 };
1197 1194
1198 1195 union rfs_res {
1199 1196 /*
1200 1197 * NFS VERSION 2
1201 1198 */
1202 1199
1203 1200 /* RFS_NULL = 0 */
1204 1201
1205 1202 /* RFS_GETATTR = 1 */
1206 1203 struct nfsattrstat nfs2_getattr_res;
1207 1204
1208 1205 /* RFS_SETATTR = 2 */
1209 1206 struct nfsattrstat nfs2_setattr_res;
1210 1207
1211 1208 /* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
1212 1209
1213 1210 /* RFS_LOOKUP = 4 */
1214 1211 struct nfsdiropres nfs2_lookup_res;
1215 1212
1216 1213 /* RFS_READLINK = 5 */
1217 1214 struct nfsrdlnres nfs2_readlink_res;
1218 1215
1219 1216 /* RFS_READ = 6 */
1220 1217 struct nfsrdresult nfs2_read_res;
1221 1218
1222 1219 /* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
1223 1220
1224 1221 /* RFS_WRITE = 8 */
1225 1222 struct nfsattrstat nfs2_write_res;
1226 1223
1227 1224 /* RFS_CREATE = 9 */
1228 1225 struct nfsdiropres nfs2_create_res;
1229 1226
1230 1227 /* RFS_REMOVE = 10 */
1231 1228 enum nfsstat nfs2_remove_res;
1232 1229
1233 1230 /* RFS_RENAME = 11 */
1234 1231 enum nfsstat nfs2_rename_res;
1235 1232
1236 1233 /* RFS_LINK = 12 */
1237 1234 enum nfsstat nfs2_link_res;
1238 1235
1239 1236 /* RFS_SYMLINK = 13 */
1240 1237 enum nfsstat nfs2_symlink_res;
1241 1238
1242 1239 /* RFS_MKDIR = 14 */
1243 1240 struct nfsdiropres nfs2_mkdir_res;
1244 1241
1245 1242 /* RFS_RMDIR = 15 */
1246 1243 enum nfsstat nfs2_rmdir_res;
1247 1244
1248 1245 /* RFS_READDIR = 16 */
1249 1246 struct nfsrddirres nfs2_readdir_res;
1250 1247
1251 1248 /* RFS_STATFS = 17 */
1252 1249 struct nfsstatfs nfs2_statfs_res;
1253 1250
1254 1251 /*
1255 1252 * NFS VERSION 3
1256 1253 */
1257 1254
1258 1255 /* RFS_NULL = 0 */
1259 1256
1260 1257 /* RFS3_GETATTR = 1 */
1261 1258 GETATTR3res nfs3_getattr_res;
1262 1259
1263 1260 /* RFS3_SETATTR = 2 */
1264 1261 SETATTR3res nfs3_setattr_res;
1265 1262
1266 1263 /* RFS3_LOOKUP = 3 */
1267 1264 LOOKUP3res nfs3_lookup_res;
1268 1265
1269 1266 /* RFS3_ACCESS = 4 */
1270 1267 ACCESS3res nfs3_access_res;
1271 1268
1272 1269 /* RFS3_READLINK = 5 */
1273 1270 READLINK3res nfs3_readlink_res;
1274 1271
1275 1272 /* RFS3_READ = 6 */
1276 1273 READ3res nfs3_read_res;
1277 1274
1278 1275 /* RFS3_WRITE = 7 */
1279 1276 WRITE3res nfs3_write_res;
1280 1277
1281 1278 /* RFS3_CREATE = 8 */
1282 1279 CREATE3res nfs3_create_res;
1283 1280
1284 1281 /* RFS3_MKDIR = 9 */
1285 1282 MKDIR3res nfs3_mkdir_res;
1286 1283
1287 1284 /* RFS3_SYMLINK = 10 */
1288 1285 SYMLINK3res nfs3_symlink_res;
1289 1286
1290 1287 /* RFS3_MKNOD = 11 */
1291 1288 MKNOD3res nfs3_mknod_res;
1292 1289
1293 1290 /* RFS3_REMOVE = 12 */
1294 1291 REMOVE3res nfs3_remove_res;
1295 1292
1296 1293 /* RFS3_RMDIR = 13 */
1297 1294 RMDIR3res nfs3_rmdir_res;
1298 1295
1299 1296 /* RFS3_RENAME = 14 */
1300 1297 RENAME3res nfs3_rename_res;
1301 1298
1302 1299 /* RFS3_LINK = 15 */
1303 1300 LINK3res nfs3_link_res;
1304 1301
1305 1302 /* RFS3_READDIR = 16 */
1306 1303 READDIR3res nfs3_readdir_res;
1307 1304
1308 1305 /* RFS3_READDIRPLUS = 17 */
1309 1306 READDIRPLUS3res nfs3_readdirplus_res;
1310 1307
1311 1308 /* RFS3_FSSTAT = 18 */
1312 1309 FSSTAT3res nfs3_fsstat_res;
1313 1310
1314 1311 /* RFS3_FSINFO = 19 */
1315 1312 FSINFO3res nfs3_fsinfo_res;
1316 1313
1317 1314 /* RFS3_PATHCONF = 20 */
1318 1315 PATHCONF3res nfs3_pathconf_res;
1319 1316
1320 1317 /* RFS3_COMMIT = 21 */
1321 1318 COMMIT3res nfs3_commit_res;
1322 1319
1323 1320 /*
1324 1321 * NFS VERSION 4
1325 1322 */
1326 1323
|
↓ open down ↓ |
1116 lines elided |
↑ open up ↑ |
1327 1324 /* RFS_NULL = 0 */
1328 1325
1329 1326 /* RFS4_COMPOUND = 1 */
1330 1327 COMPOUND4res nfs4_compound_res;
1331 1328
1332 1329 };
1333 1330
1334 1331 static struct rpc_disptable rfs_disptable[] = {
1335 1332 {sizeof (rfsdisptab_v2) / sizeof (rfsdisptab_v2[0]),
1336 1333 rfscallnames_v2,
1337 - &rfsproccnt_v2_ptr, rfsdisptab_v2},
1334 + rfsdisptab_v2},
1338 1335 {sizeof (rfsdisptab_v3) / sizeof (rfsdisptab_v3[0]),
1339 1336 rfscallnames_v3,
1340 - &rfsproccnt_v3_ptr, rfsdisptab_v3},
1337 + rfsdisptab_v3},
1341 1338 {sizeof (rfsdisptab_v4) / sizeof (rfsdisptab_v4[0]),
1342 1339 rfscallnames_v4,
1343 - &rfsproccnt_v4_ptr, rfsdisptab_v4},
1340 + rfsdisptab_v4},
1344 1341 };
1345 1342
1346 1343 /*
1347 1344 * If nfs_portmon is set, then clients are required to use privileged
1348 1345 * ports (ports < IPPORT_RESERVED) in order to get NFS services.
1349 1346 *
1350 1347 * N.B.: this attempt to carry forward the already ill-conceived notion
1351 1348 * of privileged ports for TCP/UDP is really quite ineffectual. Not only
1352 1349 * is it transport-dependent, it's laughably easy to spoof. If you're
1353 1350 * really interested in security, you must start with secure RPC instead.
1354 1351 */
1355 1352 static int nfs_portmon = 0;
1356 1353
1357 1354 #ifdef DEBUG
1358 1355 static int cred_hits = 0;
1359 1356 static int cred_misses = 0;
1360 1357 #endif
1361 1358
1362 1359 #ifdef DEBUG
1363 1360 /*
1364 1361 * Debug code to allow disabling of rfs_dispatch() use of
1365 1362 * fastxdrargs() and fastxdrres() calls for testing purposes.
1366 1363 */
1367 1364 static int rfs_no_fast_xdrargs = 0;
1368 1365 static int rfs_no_fast_xdrres = 0;
1369 1366 #endif
1370 1367
1371 1368 union acl_args {
1372 1369 /*
1373 1370 * ACL VERSION 2
1374 1371 */
1375 1372
1376 1373 /* ACL2_NULL = 0 */
1377 1374
1378 1375 /* ACL2_GETACL = 1 */
1379 1376 GETACL2args acl2_getacl_args;
1380 1377
1381 1378 /* ACL2_SETACL = 2 */
1382 1379 SETACL2args acl2_setacl_args;
1383 1380
1384 1381 /* ACL2_GETATTR = 3 */
1385 1382 GETATTR2args acl2_getattr_args;
1386 1383
1387 1384 /* ACL2_ACCESS = 4 */
1388 1385 ACCESS2args acl2_access_args;
1389 1386
1390 1387 /* ACL2_GETXATTRDIR = 5 */
1391 1388 GETXATTRDIR2args acl2_getxattrdir_args;
1392 1389
1393 1390 /*
1394 1391 * ACL VERSION 3
1395 1392 */
1396 1393
1397 1394 /* ACL3_NULL = 0 */
1398 1395
1399 1396 /* ACL3_GETACL = 1 */
1400 1397 GETACL3args acl3_getacl_args;
1401 1398
1402 1399 /* ACL3_SETACL = 2 */
1403 1400 SETACL3args acl3_setacl;
1404 1401
1405 1402 /* ACL3_GETXATTRDIR = 3 */
1406 1403 GETXATTRDIR3args acl3_getxattrdir_args;
1407 1404
1408 1405 };
1409 1406
1410 1407 union acl_res {
1411 1408 /*
1412 1409 * ACL VERSION 2
1413 1410 */
1414 1411
1415 1412 /* ACL2_NULL = 0 */
1416 1413
1417 1414 /* ACL2_GETACL = 1 */
1418 1415 GETACL2res acl2_getacl_res;
1419 1416
1420 1417 /* ACL2_SETACL = 2 */
1421 1418 SETACL2res acl2_setacl_res;
1422 1419
1423 1420 /* ACL2_GETATTR = 3 */
1424 1421 GETATTR2res acl2_getattr_res;
1425 1422
1426 1423 /* ACL2_ACCESS = 4 */
1427 1424 ACCESS2res acl2_access_res;
1428 1425
1429 1426 /* ACL2_GETXATTRDIR = 5 */
1430 1427 GETXATTRDIR2args acl2_getxattrdir_res;
1431 1428
1432 1429 /*
1433 1430 * ACL VERSION 3
1434 1431 */
1435 1432
1436 1433 /* ACL3_NULL = 0 */
1437 1434
1438 1435 /* ACL3_GETACL = 1 */
1439 1436 GETACL3res acl3_getacl_res;
1440 1437
1441 1438 /* ACL3_SETACL = 2 */
1442 1439 SETACL3res acl3_setacl_res;
1443 1440
1444 1441 /* ACL3_GETXATTRDIR = 3 */
1445 1442 GETXATTRDIR3res acl3_getxattrdir_res;
1446 1443
1447 1444 };
1448 1445
1449 1446 static bool_t
1450 1447 auth_tooweak(struct svc_req *req, char *res)
1451 1448 {
1452 1449
1453 1450 if (req->rq_vers == NFS_VERSION && req->rq_proc == RFS_LOOKUP) {
1454 1451 struct nfsdiropres *dr = (struct nfsdiropres *)res;
|
↓ open down ↓ |
101 lines elided |
↑ open up ↑ |
1455 1452 if ((enum wnfsstat)dr->dr_status == WNFSERR_CLNT_FLAVOR)
1456 1453 return (TRUE);
1457 1454 } else if (req->rq_vers == NFS_V3 && req->rq_proc == NFSPROC3_LOOKUP) {
1458 1455 LOOKUP3res *resp = (LOOKUP3res *)res;
1459 1456 if ((enum wnfsstat)resp->status == WNFSERR_CLNT_FLAVOR)
1460 1457 return (TRUE);
1461 1458 }
1462 1459 return (FALSE);
1463 1460 }
1464 1461
1465 -
1466 1462 static void
1467 1463 common_dispatch(struct svc_req *req, SVCXPRT *xprt, rpcvers_t min_vers,
1468 1464 rpcvers_t max_vers, char *pgmname, struct rpc_disptable *disptable)
1469 1465 {
1470 1466 int which;
1471 1467 rpcvers_t vers;
1472 1468 char *args;
1473 1469 union {
1474 1470 union rfs_args ra;
1475 1471 union acl_args aa;
1476 1472 } args_buf;
1477 1473 char *res;
1478 1474 union {
1479 1475 union rfs_res rr;
1480 1476 union acl_res ar;
1481 1477 } res_buf;
1482 1478 struct rpcdisp *disp = NULL;
1483 1479 int dis_flags = 0;
1484 1480 cred_t *cr;
1485 1481 int error = 0;
1486 1482 int anon_ok;
1487 1483 struct exportinfo *exi = NULL;
1488 1484 unsigned int nfslog_rec_id;
1489 1485 int dupstat;
1490 1486 struct dupreq *dr;
1491 1487 int authres;
|
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
1492 1488 bool_t publicfh_ok = FALSE;
1493 1489 enum_t auth_flavor;
1494 1490 bool_t dupcached = FALSE;
1495 1491 struct netbuf nb;
1496 1492 bool_t logging_enabled = FALSE;
1497 1493 struct exportinfo *nfslog_exi = NULL;
1498 1494 char **procnames;
1499 1495 char cbuf[INET6_ADDRSTRLEN]; /* to hold both IPv4 and IPv6 addr */
1500 1496 bool_t ro = FALSE;
1501 1497 nfs_export_t *ne = nfs_get_export();
1498 + nfs_globals_t *ng = ne->ne_globals;
1499 + kstat_named_t *svstat, *procstat;
1502 1500
1501 + ASSERT(req->rq_prog == NFS_PROGRAM || req->rq_prog == NFS_ACL_PROGRAM);
1502 +
1503 1503 vers = req->rq_vers;
1504 1504
1505 + svstat = ng->svstat[req->rq_vers];
1506 + procstat = (req->rq_prog == NFS_PROGRAM) ?
1507 + ng->rfsproccnt[vers] : ng->aclproccnt[vers];
1508 +
1505 1509 if (vers < min_vers || vers > max_vers) {
1506 1510 svcerr_progvers(req->rq_xprt, min_vers, max_vers);
1507 1511 error++;
1508 1512 cmn_err(CE_NOTE, "%s: bad version number %u", pgmname, vers);
1509 1513 goto done;
1510 1514 }
1511 1515 vers -= min_vers;
1512 1516
1513 1517 which = req->rq_proc;
1514 1518 if (which < 0 || which >= disptable[(int)vers].dis_nprocs) {
1515 1519 svcerr_noproc(req->rq_xprt);
1516 1520 error++;
1517 1521 goto done;
1518 1522 }
1519 1523
1520 - (*(disptable[(int)vers].dis_proccntp))[which].value.ui64++;
1524 + procstat[which].value.ui64++;
1521 1525
1522 1526 disp = &disptable[(int)vers].dis_table[which];
1523 1527 procnames = disptable[(int)vers].dis_procnames;
1524 1528
1525 1529 auth_flavor = req->rq_cred.oa_flavor;
1526 1530
1527 1531 /*
1528 1532 * Deserialize into the args struct.
1529 1533 */
1530 1534 args = (char *)&args_buf;
1531 1535
1532 1536 #ifdef DEBUG
1533 1537 if (rfs_no_fast_xdrargs || (auth_flavor == RPCSEC_GSS) ||
1534 1538 disp->dis_fastxdrargs == NULL_xdrproc_t ||
1535 1539 !SVC_GETARGS(xprt, disp->dis_fastxdrargs, (char *)&args))
1536 1540 #else
1537 1541 if ((auth_flavor == RPCSEC_GSS) ||
1538 1542 disp->dis_fastxdrargs == NULL_xdrproc_t ||
1539 1543 !SVC_GETARGS(xprt, disp->dis_fastxdrargs, (char *)&args))
1540 1544 #endif
1541 1545 {
1542 1546 bzero(args, disp->dis_argsz);
1543 1547 if (!SVC_GETARGS(xprt, disp->dis_xdrargs, args)) {
1544 1548 error++;
1545 1549 /*
1546 1550 * Check if we are outside our capabilities.
1547 1551 */
1548 1552 if (rfs4_minorvers_mismatch(req, xprt, (void *)args))
1549 1553 goto done;
1550 1554
1551 1555 svcerr_decode(xprt);
1552 1556 cmn_err(CE_NOTE,
1553 1557 "Failed to decode arguments for %s version %u "
1554 1558 "procedure %s client %s%s",
1555 1559 pgmname, vers + min_vers, procnames[which],
1556 1560 client_name(req), client_addr(req, cbuf));
1557 1561 goto done;
1558 1562 }
1559 1563 }
1560 1564
1561 1565 /*
1562 1566 * If Version 4 use that specific dispatch function.
1563 1567 */
1564 1568 if (req->rq_vers == 4) {
1565 1569 error += rfs4_dispatch(disp, req, xprt, args);
1566 1570 goto done;
1567 1571 }
1568 1572
1569 1573 dis_flags = disp->dis_flags;
1570 1574
1571 1575 /*
1572 1576 * Find export information and check authentication,
1573 1577 * setting the credential if everything is ok.
1574 1578 */
1575 1579 if (disp->dis_getfh != NULL) {
1576 1580 void *fh;
1577 1581 fsid_t *fsid;
1578 1582 fid_t *fid, *xfid;
1579 1583 fhandle_t *fh2;
1580 1584 nfs_fh3 *fh3;
1581 1585
1582 1586 fh = (*disp->dis_getfh)(args);
1583 1587 switch (req->rq_vers) {
1584 1588 case NFS_VERSION:
1585 1589 fh2 = (fhandle_t *)fh;
1586 1590 fsid = &fh2->fh_fsid;
1587 1591 fid = (fid_t *)&fh2->fh_len;
1588 1592 xfid = (fid_t *)&fh2->fh_xlen;
1589 1593 break;
1590 1594 case NFS_V3:
1591 1595 fh3 = (nfs_fh3 *)fh;
1592 1596 fsid = &fh3->fh3_fsid;
1593 1597 fid = FH3TOFIDP(fh3);
1594 1598 xfid = FH3TOXFIDP(fh3);
1595 1599 break;
1596 1600 }
1597 1601
1598 1602 /*
1599 1603 * Fix for bug 1038302 - corbin
1600 1604 * There is a problem here if anonymous access is
1601 1605 * disallowed. If the current request is part of the
1602 1606 * client's mount process for the requested filesystem,
1603 1607 * then it will carry root (uid 0) credentials on it, and
1604 1608 * will be denied by checkauth if that client does not
1605 1609 * have explicit root=0 permission. This will cause the
1606 1610 * client's mount operation to fail. As a work-around,
1607 1611 * we check here to see if the request is a getattr or
1608 1612 * statfs operation on the exported vnode itself, and
1609 1613 * pass a flag to checkauth with the result of this test.
1610 1614 *
1611 1615 * The filehandle refers to the mountpoint itself if
1612 1616 * the fh_data and fh_xdata portions of the filehandle
1613 1617 * are equal.
1614 1618 *
1615 1619 * Added anon_ok argument to checkauth().
1616 1620 */
1617 1621
1618 1622 if ((dis_flags & RPC_ALLOWANON) && EQFID(fid, xfid))
1619 1623 anon_ok = 1;
1620 1624 else
1621 1625 anon_ok = 0;
1622 1626
1623 1627 cr = xprt->xp_cred;
1624 1628 ASSERT(cr != NULL);
1625 1629 #ifdef DEBUG
1626 1630 {
1627 1631 if (crgetref(cr) != 1) {
1628 1632 crfree(cr);
1629 1633 cr = crget();
1630 1634 xprt->xp_cred = cr;
1631 1635 cred_misses++;
1632 1636 } else
1633 1637 cred_hits++;
1634 1638 }
1635 1639 #else
1636 1640 if (crgetref(cr) != 1) {
1637 1641 crfree(cr);
1638 1642 cr = crget();
1639 1643 xprt->xp_cred = cr;
1640 1644 }
1641 1645 #endif
1642 1646
1643 1647 exi = checkexport(fsid, xfid);
1644 1648
1645 1649 if (exi != NULL) {
1646 1650 publicfh_ok = PUBLICFH_CHECK(ne, disp, exi, fsid, xfid);
1647 1651
1648 1652 /*
1649 1653 * Don't allow non-V4 clients access
1650 1654 * to pseudo exports
1651 1655 */
1652 1656 if (PSEUDO(exi)) {
1653 1657 svcerr_weakauth(xprt);
1654 1658 error++;
1655 1659 goto done;
1656 1660 }
1657 1661
1658 1662 authres = checkauth(exi, req, cr, anon_ok, publicfh_ok,
1659 1663 &ro);
1660 1664 /*
1661 1665 * authres > 0: authentication OK - proceed
1662 1666 * authres == 0: authentication weak - return error
1663 1667 * authres < 0: authentication timeout - drop
1664 1668 */
1665 1669 if (authres <= 0) {
1666 1670 if (authres == 0) {
1667 1671 svcerr_weakauth(xprt);
1668 1672 error++;
1669 1673 }
1670 1674 goto done;
1671 1675 }
1672 1676 }
1673 1677 } else
1674 1678 cr = NULL;
1675 1679
1676 1680 if ((dis_flags & RPC_MAPRESP) && (auth_flavor != RPCSEC_GSS)) {
1677 1681 res = (char *)SVC_GETRES(xprt, disp->dis_ressz);
1678 1682 if (res == NULL)
1679 1683 res = (char *)&res_buf;
1680 1684 } else
1681 1685 res = (char *)&res_buf;
1682 1686
1683 1687 if (!(dis_flags & RPC_IDEMPOTENT)) {
1684 1688 dupstat = SVC_DUP_EXT(xprt, req, res, disp->dis_ressz, &dr,
1685 1689 &dupcached);
1686 1690
1687 1691 switch (dupstat) {
1688 1692 case DUP_ERROR:
1689 1693 svcerr_systemerr(xprt);
1690 1694 error++;
1691 1695 goto done;
1692 1696 /* NOTREACHED */
1693 1697 case DUP_INPROGRESS:
1694 1698 if (res != (char *)&res_buf)
1695 1699 SVC_FREERES(xprt);
1696 1700 error++;
1697 1701 goto done;
1698 1702 /* NOTREACHED */
1699 1703 case DUP_NEW:
1700 1704 case DUP_DROP:
1701 1705 curthread->t_flag |= T_DONTPEND;
1702 1706
1703 1707 (*disp->dis_proc)(args, res, exi, req, cr, ro);
1704 1708
1705 1709 curthread->t_flag &= ~T_DONTPEND;
1706 1710 if (curthread->t_flag & T_WOULDBLOCK) {
1707 1711 curthread->t_flag &= ~T_WOULDBLOCK;
1708 1712 SVC_DUPDONE_EXT(xprt, dr, res, NULL,
1709 1713 disp->dis_ressz, DUP_DROP);
1710 1714 if (res != (char *)&res_buf)
1711 1715 SVC_FREERES(xprt);
1712 1716 error++;
1713 1717 goto done;
1714 1718 }
1715 1719 if (dis_flags & RPC_AVOIDWORK) {
1716 1720 SVC_DUPDONE_EXT(xprt, dr, res, NULL,
1717 1721 disp->dis_ressz, DUP_DROP);
1718 1722 } else {
1719 1723 SVC_DUPDONE_EXT(xprt, dr, res,
1720 1724 disp->dis_resfree == nullfree ? NULL :
1721 1725 disp->dis_resfree,
1722 1726 disp->dis_ressz, DUP_DONE);
1723 1727 dupcached = TRUE;
1724 1728 }
1725 1729 break;
1726 1730 case DUP_DONE:
1727 1731 break;
1728 1732 }
1729 1733
1730 1734 } else {
1731 1735 curthread->t_flag |= T_DONTPEND;
1732 1736
1733 1737 (*disp->dis_proc)(args, res, exi, req, cr, ro);
1734 1738
1735 1739 curthread->t_flag &= ~T_DONTPEND;
1736 1740 if (curthread->t_flag & T_WOULDBLOCK) {
1737 1741 curthread->t_flag &= ~T_WOULDBLOCK;
1738 1742 if (res != (char *)&res_buf)
1739 1743 SVC_FREERES(xprt);
1740 1744 error++;
1741 1745 goto done;
1742 1746 }
1743 1747 }
1744 1748
1745 1749 if (auth_tooweak(req, res)) {
1746 1750 svcerr_weakauth(xprt);
1747 1751 error++;
1748 1752 goto done;
1749 1753 }
1750 1754
1751 1755 /*
1752 1756 * Check to see if logging has been enabled on the server.
1753 1757 * If so, then obtain the export info struct to be used for
1754 1758 * the later writing of the log record. This is done for
1755 1759 * the case that a lookup is done across a non-logged public
1756 1760 * file system.
1757 1761 */
1758 1762 if (nfslog_buffer_list != NULL) {
1759 1763 nfslog_exi = nfslog_get_exi(ne, exi, req, res, &nfslog_rec_id);
1760 1764 /*
1761 1765 * Is logging enabled?
1762 1766 */
1763 1767 logging_enabled = (nfslog_exi != NULL);
1764 1768
1765 1769 /*
1766 1770 * Copy the netbuf for logging purposes, before it is
1767 1771 * freed by svc_sendreply().
1768 1772 */
1769 1773 if (logging_enabled) {
1770 1774 NFSLOG_COPY_NETBUF(nfslog_exi, xprt, &nb);
1771 1775 /*
1772 1776 * If RPC_MAPRESP flag set (i.e. in V2 ops) the
1773 1777 * res gets copied directly into the mbuf and
1774 1778 * may be freed soon after the sendreply. So we
1775 1779 * must copy it here to a safe place...
1776 1780 */
1777 1781 if (res != (char *)&res_buf) {
1778 1782 bcopy(res, (char *)&res_buf, disp->dis_ressz);
1779 1783 }
1780 1784 }
1781 1785 }
1782 1786
1783 1787 /*
1784 1788 * Serialize and send results struct
1785 1789 */
1786 1790 #ifdef DEBUG
1787 1791 if (rfs_no_fast_xdrres == 0 && res != (char *)&res_buf)
1788 1792 #else
1789 1793 if (res != (char *)&res_buf)
1790 1794 #endif
1791 1795 {
1792 1796 if (!svc_sendreply(xprt, disp->dis_fastxdrres, res)) {
1793 1797 cmn_err(CE_NOTE, "%s: bad sendreply", pgmname);
1794 1798 svcerr_systemerr(xprt);
1795 1799 error++;
1796 1800 }
1797 1801 } else {
1798 1802 if (!svc_sendreply(xprt, disp->dis_xdrres, res)) {
1799 1803 cmn_err(CE_NOTE, "%s: bad sendreply", pgmname);
1800 1804 svcerr_systemerr(xprt);
1801 1805 error++;
1802 1806 }
1803 1807 }
1804 1808
1805 1809 /*
1806 1810 * Log if needed
1807 1811 */
1808 1812 if (logging_enabled) {
1809 1813 nfslog_write_record(nfslog_exi, req, args, (char *)&res_buf,
1810 1814 cr, &nb, nfslog_rec_id, NFSLOG_ONE_BUFFER);
1811 1815 exi_rele(nfslog_exi);
1812 1816 kmem_free((&nb)->buf, (&nb)->len);
1813 1817 }
1814 1818
1815 1819 /*
1816 1820 * Free results struct. With the addition of NFS V4 we can
1817 1821 * have non-idempotent procedures with functions.
1818 1822 */
1819 1823 if (disp->dis_resfree != nullfree && dupcached == FALSE) {
1820 1824 (*disp->dis_resfree)(res);
1821 1825 }
1822 1826
1823 1827 done:
1824 1828 /*
1825 1829 * Free arguments struct
1826 1830 */
1827 1831 if (disp) {
1828 1832 if (!SVC_FREEARGS(xprt, disp->dis_xdrargs, args)) {
1829 1833 cmn_err(CE_NOTE, "%s: bad freeargs", pgmname);
1830 1834 error++;
1831 1835 }
|
↓ open down ↓ |
301 lines elided |
↑ open up ↑ |
1832 1836 } else {
1833 1837 if (!SVC_FREEARGS(xprt, (xdrproc_t)0, (caddr_t)0)) {
1834 1838 cmn_err(CE_NOTE, "%s: bad freeargs", pgmname);
1835 1839 error++;
1836 1840 }
1837 1841 }
1838 1842
1839 1843 if (exi != NULL)
1840 1844 exi_rele(exi);
1841 1845
1842 - global_svstat_ptr[req->rq_vers][NFS_BADCALLS].value.ui64 += error;
1843 -
1844 - global_svstat_ptr[req->rq_vers][NFS_CALLS].value.ui64++;
1846 + svstat[NFS_BADCALLS].value.ui64 += error;
1847 + svstat[NFS_CALLS].value.ui64++;
1845 1848 }
1846 1849
1847 1850 static void
1848 1851 rfs_dispatch(struct svc_req *req, SVCXPRT *xprt)
1849 1852 {
1850 1853 common_dispatch(req, xprt, NFS_VERSMIN, NFS_VERSMAX,
1851 1854 "NFS", rfs_disptable);
1852 1855 }
1853 1856
1854 1857 static char *aclcallnames_v2[] = {
1855 1858 "ACL2_NULL",
1856 1859 "ACL2_GETACL",
1857 1860 "ACL2_SETACL",
1858 1861 "ACL2_GETATTR",
1859 1862 "ACL2_ACCESS",
1860 1863 "ACL2_GETXATTRDIR"
1861 1864 };
1862 1865
1863 1866 static struct rpcdisp acldisptab_v2[] = {
1864 1867 /*
1865 1868 * ACL VERSION 2
1866 1869 */
1867 1870
1868 1871 /* ACL2_NULL = 0 */
1869 1872 {rpc_null,
1870 1873 xdr_void, NULL_xdrproc_t, 0,
1871 1874 xdr_void, NULL_xdrproc_t, 0,
1872 1875 nullfree, RPC_IDEMPOTENT,
1873 1876 0},
1874 1877
1875 1878 /* ACL2_GETACL = 1 */
1876 1879 {acl2_getacl,
1877 1880 xdr_GETACL2args, xdr_fastGETACL2args, sizeof (GETACL2args),
1878 1881 xdr_GETACL2res, NULL_xdrproc_t, sizeof (GETACL2res),
1879 1882 acl2_getacl_free, RPC_IDEMPOTENT,
1880 1883 acl2_getacl_getfh},
1881 1884
1882 1885 /* ACL2_SETACL = 2 */
1883 1886 {acl2_setacl,
1884 1887 xdr_SETACL2args, NULL_xdrproc_t, sizeof (SETACL2args),
1885 1888 #ifdef _LITTLE_ENDIAN
1886 1889 xdr_SETACL2res, xdr_fastSETACL2res, sizeof (SETACL2res),
1887 1890 #else
1888 1891 xdr_SETACL2res, NULL_xdrproc_t, sizeof (SETACL2res),
1889 1892 #endif
1890 1893 nullfree, RPC_MAPRESP,
1891 1894 acl2_setacl_getfh},
1892 1895
1893 1896 /* ACL2_GETATTR = 3 */
1894 1897 {acl2_getattr,
1895 1898 xdr_GETATTR2args, xdr_fastGETATTR2args, sizeof (GETATTR2args),
1896 1899 #ifdef _LITTLE_ENDIAN
1897 1900 xdr_GETATTR2res, xdr_fastGETATTR2res, sizeof (GETATTR2res),
1898 1901 #else
1899 1902 xdr_GETATTR2res, NULL_xdrproc_t, sizeof (GETATTR2res),
1900 1903 #endif
1901 1904 nullfree, RPC_IDEMPOTENT|RPC_ALLOWANON|RPC_MAPRESP,
1902 1905 acl2_getattr_getfh},
1903 1906
1904 1907 /* ACL2_ACCESS = 4 */
1905 1908 {acl2_access,
1906 1909 xdr_ACCESS2args, xdr_fastACCESS2args, sizeof (ACCESS2args),
1907 1910 #ifdef _LITTLE_ENDIAN
1908 1911 xdr_ACCESS2res, xdr_fastACCESS2res, sizeof (ACCESS2res),
1909 1912 #else
1910 1913 xdr_ACCESS2res, NULL_xdrproc_t, sizeof (ACCESS2res),
1911 1914 #endif
1912 1915 nullfree, RPC_IDEMPOTENT|RPC_MAPRESP,
1913 1916 acl2_access_getfh},
1914 1917
1915 1918 /* ACL2_GETXATTRDIR = 5 */
1916 1919 {acl2_getxattrdir,
1917 1920 xdr_GETXATTRDIR2args, NULL_xdrproc_t, sizeof (GETXATTRDIR2args),
1918 1921 xdr_GETXATTRDIR2res, NULL_xdrproc_t, sizeof (GETXATTRDIR2res),
1919 1922 nullfree, RPC_IDEMPOTENT,
1920 1923 acl2_getxattrdir_getfh},
1921 1924 };
1922 1925
1923 1926 static char *aclcallnames_v3[] = {
1924 1927 "ACL3_NULL",
1925 1928 "ACL3_GETACL",
1926 1929 "ACL3_SETACL",
1927 1930 "ACL3_GETXATTRDIR"
1928 1931 };
1929 1932
1930 1933 static struct rpcdisp acldisptab_v3[] = {
1931 1934 /*
1932 1935 * ACL VERSION 3
1933 1936 */
1934 1937
1935 1938 /* ACL3_NULL = 0 */
1936 1939 {rpc_null,
1937 1940 xdr_void, NULL_xdrproc_t, 0,
1938 1941 xdr_void, NULL_xdrproc_t, 0,
1939 1942 nullfree, RPC_IDEMPOTENT,
1940 1943 0},
1941 1944
1942 1945 /* ACL3_GETACL = 1 */
1943 1946 {acl3_getacl,
1944 1947 xdr_GETACL3args, NULL_xdrproc_t, sizeof (GETACL3args),
1945 1948 xdr_GETACL3res, NULL_xdrproc_t, sizeof (GETACL3res),
1946 1949 acl3_getacl_free, RPC_IDEMPOTENT,
1947 1950 acl3_getacl_getfh},
1948 1951
1949 1952 /* ACL3_SETACL = 2 */
1950 1953 {acl3_setacl,
1951 1954 xdr_SETACL3args, NULL_xdrproc_t, sizeof (SETACL3args),
1952 1955 xdr_SETACL3res, NULL_xdrproc_t, sizeof (SETACL3res),
1953 1956 nullfree, 0,
1954 1957 acl3_setacl_getfh},
1955 1958
1956 1959 /* ACL3_GETXATTRDIR = 3 */
|
↓ open down ↓ |
102 lines elided |
↑ open up ↑ |
1957 1960 {acl3_getxattrdir,
1958 1961 xdr_GETXATTRDIR3args, NULL_xdrproc_t, sizeof (GETXATTRDIR3args),
1959 1962 xdr_GETXATTRDIR3res, NULL_xdrproc_t, sizeof (GETXATTRDIR3res),
1960 1963 nullfree, RPC_IDEMPOTENT,
1961 1964 acl3_getxattrdir_getfh},
1962 1965 };
1963 1966
1964 1967 static struct rpc_disptable acl_disptable[] = {
1965 1968 {sizeof (acldisptab_v2) / sizeof (acldisptab_v2[0]),
1966 1969 aclcallnames_v2,
1967 - &aclproccnt_v2_ptr, acldisptab_v2},
1970 + acldisptab_v2},
1968 1971 {sizeof (acldisptab_v3) / sizeof (acldisptab_v3[0]),
1969 1972 aclcallnames_v3,
1970 - &aclproccnt_v3_ptr, acldisptab_v3},
1973 + acldisptab_v3},
1971 1974 };
1972 1975
1973 1976 static void
1974 1977 acl_dispatch(struct svc_req *req, SVCXPRT *xprt)
1975 1978 {
1976 1979 common_dispatch(req, xprt, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,
1977 1980 "ACL", acl_disptable);
1978 1981 }
1979 1982
1980 1983 int
1981 1984 checkwin(int flavor, int window, struct svc_req *req)
1982 1985 {
1983 1986 struct authdes_cred *adc;
1984 1987
1985 1988 switch (flavor) {
1986 1989 case AUTH_DES:
1987 1990 adc = (struct authdes_cred *)req->rq_clntcred;
1988 1991 CTASSERT(sizeof (struct authdes_cred) <= RQCRED_SIZE);
1989 1992 if (adc->adc_fullname.window > window)
1990 1993 return (0);
1991 1994 break;
1992 1995
1993 1996 default:
1994 1997 break;
1995 1998 }
1996 1999 return (1);
1997 2000 }
1998 2001
1999 2002
2000 2003 /*
2001 2004 * checkauth() will check the access permission against the export
2002 2005 * information. Then map root uid/gid to appropriate uid/gid.
2003 2006 *
2004 2007 * This routine is used by NFS V3 and V2 code.
2005 2008 */
2006 2009 static int
2007 2010 checkauth(struct exportinfo *exi, struct svc_req *req, cred_t *cr, int anon_ok,
2008 2011 bool_t publicfh_ok, bool_t *ro)
2009 2012 {
2010 2013 int i, nfsflavor, rpcflavor, stat, access;
2011 2014 struct secinfo *secp;
2012 2015 caddr_t principal;
2013 2016 char buf[INET6_ADDRSTRLEN]; /* to hold both IPv4 and IPv6 addr */
2014 2017 int anon_res = 0;
2015 2018
2016 2019 uid_t uid;
2017 2020 gid_t gid;
2018 2021 uint_t ngids;
2019 2022 gid_t *gids;
2020 2023
2021 2024 /*
2022 2025 * Check for privileged port number
2023 2026 * N.B.: this assumes that we know the format of a netbuf.
2024 2027 */
2025 2028 if (nfs_portmon) {
2026 2029 struct sockaddr *ca;
2027 2030 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2028 2031
2029 2032 if (ca == NULL)
2030 2033 return (0);
2031 2034
2032 2035 if ((ca->sa_family == AF_INET &&
2033 2036 ntohs(((struct sockaddr_in *)ca)->sin_port) >=
2034 2037 IPPORT_RESERVED) ||
2035 2038 (ca->sa_family == AF_INET6 &&
2036 2039 ntohs(((struct sockaddr_in6 *)ca)->sin6_port) >=
2037 2040 IPPORT_RESERVED)) {
2038 2041 cmn_err(CE_NOTE,
2039 2042 "nfs_server: client %s%ssent NFS request from "
2040 2043 "unprivileged port",
2041 2044 client_name(req), client_addr(req, buf));
2042 2045 return (0);
2043 2046 }
2044 2047 }
2045 2048
2046 2049 /*
2047 2050 * return 1 on success or 0 on failure
2048 2051 */
2049 2052 stat = sec_svc_getcred(req, cr, &principal, &nfsflavor);
2050 2053
2051 2054 /*
2052 2055 * A failed AUTH_UNIX sec_svc_getcred() implies we couldn't set
2053 2056 * the credentials; below we map that to anonymous.
2054 2057 */
2055 2058 if (!stat && nfsflavor != AUTH_UNIX) {
2056 2059 cmn_err(CE_NOTE,
2057 2060 "nfs_server: couldn't get unix cred for %s",
2058 2061 client_name(req));
2059 2062 return (0);
2060 2063 }
2061 2064
2062 2065 /*
2063 2066 * Short circuit checkauth() on operations that support the
2064 2067 * public filehandle, and if the request for that operation
2065 2068 * is using the public filehandle. Note that we must call
2066 2069 * sec_svc_getcred() first so that xp_cookie is set to the
2067 2070 * right value. Normally xp_cookie is just the RPC flavor
2068 2071 * of the the request, but in the case of RPCSEC_GSS it
2069 2072 * could be a pseudo flavor.
2070 2073 */
2071 2074 if (publicfh_ok)
2072 2075 return (1);
2073 2076
2074 2077 rpcflavor = req->rq_cred.oa_flavor;
2075 2078 /*
2076 2079 * Check if the auth flavor is valid for this export
2077 2080 */
2078 2081 access = nfsauth_access(exi, req, cr, &uid, &gid, &ngids, &gids);
2079 2082 if (access & NFSAUTH_DROP)
2080 2083 return (-1); /* drop the request */
2081 2084
2082 2085 if (access & NFSAUTH_RO)
2083 2086 *ro = TRUE;
2084 2087
2085 2088 if (access & NFSAUTH_DENIED) {
2086 2089 /*
2087 2090 * If anon_ok == 1 and we got NFSAUTH_DENIED, it was
2088 2091 * probably due to the flavor not matching during
2089 2092 * the mount attempt. So map the flavor to AUTH_NONE
2090 2093 * so that the credentials get mapped to the anonymous
2091 2094 * user.
2092 2095 */
2093 2096 if (anon_ok == 1)
2094 2097 rpcflavor = AUTH_NONE;
2095 2098 else
2096 2099 return (0); /* deny access */
2097 2100
2098 2101 } else if (access & NFSAUTH_MAPNONE) {
2099 2102 /*
2100 2103 * Access was granted even though the flavor mismatched
2101 2104 * because AUTH_NONE was one of the exported flavors.
2102 2105 */
2103 2106 rpcflavor = AUTH_NONE;
2104 2107
2105 2108 } else if (access & NFSAUTH_WRONGSEC) {
2106 2109 /*
2107 2110 * NFSAUTH_WRONGSEC is used for NFSv4. If we get here,
2108 2111 * it means a client ignored the list of allowed flavors
2109 2112 * returned via the MOUNT protocol. So we just disallow it!
2110 2113 */
2111 2114 return (0);
2112 2115 }
2113 2116
2114 2117 if (rpcflavor != AUTH_SYS)
2115 2118 kmem_free(gids, ngids * sizeof (gid_t));
2116 2119
2117 2120 switch (rpcflavor) {
2118 2121 case AUTH_NONE:
2119 2122 anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2120 2123 exi->exi_export.ex_anon);
2121 2124 (void) crsetgroups(cr, 0, NULL);
2122 2125 break;
2123 2126
2124 2127 case AUTH_UNIX:
2125 2128 if (!stat || crgetuid(cr) == 0 && !(access & NFSAUTH_UIDMAP)) {
2126 2129 anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2127 2130 exi->exi_export.ex_anon);
2128 2131 (void) crsetgroups(cr, 0, NULL);
2129 2132 } else if (crgetuid(cr) == 0 && access & NFSAUTH_ROOT) {
2130 2133 /*
2131 2134 * It is root, so apply rootid to get real UID
2132 2135 * Find the secinfo structure. We should be able
2133 2136 * to find it by the time we reach here.
2134 2137 * nfsauth_access() has done the checking.
2135 2138 */
2136 2139 secp = NULL;
2137 2140 for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
2138 2141 struct secinfo *sptr;
2139 2142 sptr = &exi->exi_export.ex_secinfo[i];
2140 2143 if (sptr->s_secinfo.sc_nfsnum == nfsflavor) {
2141 2144 secp = sptr;
2142 2145 break;
2143 2146 }
2144 2147 }
2145 2148 if (secp != NULL) {
2146 2149 (void) crsetugid(cr, secp->s_rootid,
2147 2150 secp->s_rootid);
2148 2151 (void) crsetgroups(cr, 0, NULL);
2149 2152 }
2150 2153 } else if (crgetuid(cr) != uid || crgetgid(cr) != gid) {
2151 2154 if (crsetugid(cr, uid, gid) != 0)
2152 2155 anon_res = crsetugid(cr,
2153 2156 exi->exi_export.ex_anon,
2154 2157 exi->exi_export.ex_anon);
2155 2158 (void) crsetgroups(cr, 0, NULL);
2156 2159 } else if (access & NFSAUTH_GROUPS) {
2157 2160 (void) crsetgroups(cr, ngids, gids);
2158 2161 }
2159 2162
2160 2163 kmem_free(gids, ngids * sizeof (gid_t));
2161 2164
2162 2165 break;
2163 2166
2164 2167 case AUTH_DES:
2165 2168 case RPCSEC_GSS:
2166 2169 /*
2167 2170 * Find the secinfo structure. We should be able
2168 2171 * to find it by the time we reach here.
2169 2172 * nfsauth_access() has done the checking.
2170 2173 */
2171 2174 secp = NULL;
2172 2175 for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
2173 2176 if (exi->exi_export.ex_secinfo[i].s_secinfo.sc_nfsnum ==
2174 2177 nfsflavor) {
2175 2178 secp = &exi->exi_export.ex_secinfo[i];
2176 2179 break;
2177 2180 }
2178 2181 }
2179 2182
2180 2183 if (!secp) {
2181 2184 cmn_err(CE_NOTE, "nfs_server: client %s%shad "
2182 2185 "no secinfo data for flavor %d",
2183 2186 client_name(req), client_addr(req, buf),
2184 2187 nfsflavor);
2185 2188 return (0);
2186 2189 }
2187 2190
2188 2191 if (!checkwin(rpcflavor, secp->s_window, req)) {
2189 2192 cmn_err(CE_NOTE,
2190 2193 "nfs_server: client %s%sused invalid "
2191 2194 "auth window value",
2192 2195 client_name(req), client_addr(req, buf));
2193 2196 return (0);
2194 2197 }
2195 2198
2196 2199 /*
2197 2200 * Map root principals listed in the share's root= list to root,
2198 2201 * and map any others principals that were mapped to root by RPC
2199 2202 * to anon.
2200 2203 */
2201 2204 if (principal && sec_svc_inrootlist(rpcflavor, principal,
2202 2205 secp->s_rootcnt, secp->s_rootnames)) {
2203 2206 if (crgetuid(cr) == 0 && secp->s_rootid == 0)
2204 2207 return (1);
2205 2208
2206 2209
2207 2210 (void) crsetugid(cr, secp->s_rootid, secp->s_rootid);
2208 2211
2209 2212 /*
2210 2213 * NOTE: If and when kernel-land privilege tracing is
2211 2214 * added this may have to be replaced with code that
2212 2215 * retrieves root's supplementary groups (e.g., using
2213 2216 * kgss_get_group_info(). In the meantime principals
2214 2217 * mapped to uid 0 get all privileges, so setting cr's
2215 2218 * supplementary groups for them does nothing.
2216 2219 */
2217 2220 (void) crsetgroups(cr, 0, NULL);
2218 2221
2219 2222 return (1);
2220 2223 }
2221 2224
2222 2225 /*
2223 2226 * Not a root princ, or not in root list, map UID 0/nobody to
2224 2227 * the anon ID for the share. (RPC sets cr's UIDs and GIDs to
2225 2228 * UID_NOBODY and GID_NOBODY, respectively.)
2226 2229 */
2227 2230 if (crgetuid(cr) != 0 &&
2228 2231 (crgetuid(cr) != UID_NOBODY || crgetgid(cr) != GID_NOBODY))
2229 2232 return (1);
2230 2233
2231 2234 anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2232 2235 exi->exi_export.ex_anon);
2233 2236 (void) crsetgroups(cr, 0, NULL);
2234 2237 break;
2235 2238 default:
2236 2239 return (0);
2237 2240 } /* switch on rpcflavor */
2238 2241
2239 2242 /*
2240 2243 * Even if anon access is disallowed via ex_anon == -1, we allow
2241 2244 * this access if anon_ok is set. So set creds to the default
2242 2245 * "nobody" id.
2243 2246 */
2244 2247 if (anon_res != 0) {
2245 2248 if (anon_ok == 0) {
2246 2249 cmn_err(CE_NOTE,
2247 2250 "nfs_server: client %s%ssent wrong "
2248 2251 "authentication for %s",
2249 2252 client_name(req), client_addr(req, buf),
2250 2253 exi->exi_export.ex_path ?
2251 2254 exi->exi_export.ex_path : "?");
2252 2255 return (0);
2253 2256 }
2254 2257
2255 2258 if (crsetugid(cr, UID_NOBODY, GID_NOBODY) != 0)
2256 2259 return (0);
2257 2260 }
2258 2261
2259 2262 return (1);
2260 2263 }
2261 2264
2262 2265 /*
2263 2266 * returns 0 on failure, -1 on a drop, -2 on wrong security flavor,
2264 2267 * and 1 on success
2265 2268 */
2266 2269 int
2267 2270 checkauth4(struct compound_state *cs, struct svc_req *req)
2268 2271 {
2269 2272 int i, rpcflavor, access;
2270 2273 struct secinfo *secp;
2271 2274 char buf[MAXHOST + 1];
2272 2275 int anon_res = 0, nfsflavor;
2273 2276 struct exportinfo *exi;
2274 2277 cred_t *cr;
2275 2278 caddr_t principal;
2276 2279
2277 2280 uid_t uid;
2278 2281 gid_t gid;
2279 2282 uint_t ngids;
2280 2283 gid_t *gids;
2281 2284
2282 2285 exi = cs->exi;
2283 2286 cr = cs->cr;
2284 2287 principal = cs->principal;
2285 2288 nfsflavor = cs->nfsflavor;
2286 2289
2287 2290 ASSERT(cr != NULL);
2288 2291
2289 2292 rpcflavor = req->rq_cred.oa_flavor;
2290 2293 cs->access &= ~CS_ACCESS_LIMITED;
2291 2294
2292 2295 /*
2293 2296 * Check for privileged port number
2294 2297 * N.B.: this assumes that we know the format of a netbuf.
2295 2298 */
2296 2299 if (nfs_portmon) {
2297 2300 struct sockaddr *ca;
2298 2301 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2299 2302
2300 2303 if (ca == NULL)
2301 2304 return (0);
2302 2305
2303 2306 if ((ca->sa_family == AF_INET &&
2304 2307 ntohs(((struct sockaddr_in *)ca)->sin_port) >=
2305 2308 IPPORT_RESERVED) ||
2306 2309 (ca->sa_family == AF_INET6 &&
2307 2310 ntohs(((struct sockaddr_in6 *)ca)->sin6_port) >=
2308 2311 IPPORT_RESERVED)) {
2309 2312 cmn_err(CE_NOTE,
2310 2313 "nfs_server: client %s%ssent NFSv4 request from "
2311 2314 "unprivileged port",
2312 2315 client_name(req), client_addr(req, buf));
2313 2316 return (0);
2314 2317 }
2315 2318 }
2316 2319
2317 2320 /*
2318 2321 * Check the access right per auth flavor on the vnode of
2319 2322 * this export for the given request.
2320 2323 */
2321 2324 access = nfsauth4_access(cs->exi, cs->vp, req, cr, &uid, &gid, &ngids,
2322 2325 &gids);
2323 2326
2324 2327 if (access & NFSAUTH_WRONGSEC)
2325 2328 return (-2); /* no access for this security flavor */
2326 2329
2327 2330 if (access & NFSAUTH_DROP)
2328 2331 return (-1); /* drop the request */
2329 2332
2330 2333 if (access & NFSAUTH_DENIED) {
2331 2334
2332 2335 if (exi->exi_export.ex_seccnt > 0)
2333 2336 return (0); /* deny access */
2334 2337
2335 2338 } else if (access & NFSAUTH_LIMITED) {
2336 2339
2337 2340 cs->access |= CS_ACCESS_LIMITED;
2338 2341
2339 2342 } else if (access & NFSAUTH_MAPNONE) {
2340 2343 /*
2341 2344 * Access was granted even though the flavor mismatched
2342 2345 * because AUTH_NONE was one of the exported flavors.
2343 2346 */
2344 2347 rpcflavor = AUTH_NONE;
2345 2348 }
2346 2349
2347 2350 /*
2348 2351 * XXX probably need to redo some of it for nfsv4?
2349 2352 * return 1 on success or 0 on failure
2350 2353 */
2351 2354
2352 2355 if (rpcflavor != AUTH_SYS)
2353 2356 kmem_free(gids, ngids * sizeof (gid_t));
2354 2357
2355 2358 switch (rpcflavor) {
2356 2359 case AUTH_NONE:
2357 2360 anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2358 2361 exi->exi_export.ex_anon);
2359 2362 (void) crsetgroups(cr, 0, NULL);
2360 2363 break;
2361 2364
2362 2365 case AUTH_UNIX:
2363 2366 if (crgetuid(cr) == 0 && !(access & NFSAUTH_UIDMAP)) {
2364 2367 anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2365 2368 exi->exi_export.ex_anon);
2366 2369 (void) crsetgroups(cr, 0, NULL);
2367 2370 } else if (crgetuid(cr) == 0 && access & NFSAUTH_ROOT) {
2368 2371 /*
2369 2372 * It is root, so apply rootid to get real UID
2370 2373 * Find the secinfo structure. We should be able
2371 2374 * to find it by the time we reach here.
2372 2375 * nfsauth_access() has done the checking.
2373 2376 */
2374 2377 secp = NULL;
2375 2378 for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
2376 2379 struct secinfo *sptr;
2377 2380 sptr = &exi->exi_export.ex_secinfo[i];
2378 2381 if (sptr->s_secinfo.sc_nfsnum == nfsflavor) {
2379 2382 secp = &exi->exi_export.ex_secinfo[i];
2380 2383 break;
2381 2384 }
2382 2385 }
2383 2386 if (secp != NULL) {
2384 2387 (void) crsetugid(cr, secp->s_rootid,
2385 2388 secp->s_rootid);
2386 2389 (void) crsetgroups(cr, 0, NULL);
2387 2390 }
2388 2391 } else if (crgetuid(cr) != uid || crgetgid(cr) != gid) {
2389 2392 if (crsetugid(cr, uid, gid) != 0)
2390 2393 anon_res = crsetugid(cr,
2391 2394 exi->exi_export.ex_anon,
2392 2395 exi->exi_export.ex_anon);
2393 2396 (void) crsetgroups(cr, 0, NULL);
2394 2397 } if (access & NFSAUTH_GROUPS) {
2395 2398 (void) crsetgroups(cr, ngids, gids);
2396 2399 }
2397 2400
2398 2401 kmem_free(gids, ngids * sizeof (gid_t));
2399 2402
2400 2403 break;
2401 2404
2402 2405 default:
2403 2406 /*
2404 2407 * Find the secinfo structure. We should be able
2405 2408 * to find it by the time we reach here.
2406 2409 * nfsauth_access() has done the checking.
2407 2410 */
2408 2411 secp = NULL;
2409 2412 for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
2410 2413 if (exi->exi_export.ex_secinfo[i].s_secinfo.sc_nfsnum ==
2411 2414 nfsflavor) {
2412 2415 secp = &exi->exi_export.ex_secinfo[i];
2413 2416 break;
2414 2417 }
2415 2418 }
2416 2419
2417 2420 if (!secp) {
2418 2421 cmn_err(CE_NOTE, "nfs_server: client %s%shad "
2419 2422 "no secinfo data for flavor %d",
2420 2423 client_name(req), client_addr(req, buf),
2421 2424 nfsflavor);
2422 2425 return (0);
2423 2426 }
2424 2427
2425 2428 if (!checkwin(rpcflavor, secp->s_window, req)) {
2426 2429 cmn_err(CE_NOTE,
2427 2430 "nfs_server: client %s%sused invalid "
2428 2431 "auth window value",
2429 2432 client_name(req), client_addr(req, buf));
2430 2433 return (0);
2431 2434 }
2432 2435
2433 2436 /*
2434 2437 * Map root principals listed in the share's root= list to root,
2435 2438 * and map any others principals that were mapped to root by RPC
2436 2439 * to anon. If not going to anon, set to rootid (root_mapping).
2437 2440 */
2438 2441 if (principal && sec_svc_inrootlist(rpcflavor, principal,
2439 2442 secp->s_rootcnt, secp->s_rootnames)) {
2440 2443 if (crgetuid(cr) == 0 && secp->s_rootid == 0)
2441 2444 return (1);
2442 2445
2443 2446 (void) crsetugid(cr, secp->s_rootid, secp->s_rootid);
2444 2447
2445 2448 /*
2446 2449 * NOTE: If and when kernel-land privilege tracing is
2447 2450 * added this may have to be replaced with code that
2448 2451 * retrieves root's supplementary groups (e.g., using
2449 2452 * kgss_get_group_info(). In the meantime principals
2450 2453 * mapped to uid 0 get all privileges, so setting cr's
2451 2454 * supplementary groups for them does nothing.
2452 2455 */
2453 2456 (void) crsetgroups(cr, 0, NULL);
2454 2457
2455 2458 return (1);
2456 2459 }
2457 2460
2458 2461 /*
2459 2462 * Not a root princ, or not in root list, map UID 0/nobody to
2460 2463 * the anon ID for the share. (RPC sets cr's UIDs and GIDs to
2461 2464 * UID_NOBODY and GID_NOBODY, respectively.)
2462 2465 */
2463 2466 if (crgetuid(cr) != 0 &&
2464 2467 (crgetuid(cr) != UID_NOBODY || crgetgid(cr) != GID_NOBODY))
2465 2468 return (1);
2466 2469
2467 2470 anon_res = crsetugid(cr, exi->exi_export.ex_anon,
2468 2471 exi->exi_export.ex_anon);
2469 2472 (void) crsetgroups(cr, 0, NULL);
2470 2473 break;
2471 2474 } /* switch on rpcflavor */
2472 2475
2473 2476 /*
2474 2477 * Even if anon access is disallowed via ex_anon == -1, we allow
2475 2478 * this access if anon_ok is set. So set creds to the default
2476 2479 * "nobody" id.
2477 2480 */
2478 2481
2479 2482 if (anon_res != 0) {
2480 2483 cmn_err(CE_NOTE,
2481 2484 "nfs_server: client %s%ssent wrong "
2482 2485 "authentication for %s",
2483 2486 client_name(req), client_addr(req, buf),
2484 2487 exi->exi_export.ex_path ?
2485 2488 exi->exi_export.ex_path : "?");
2486 2489 return (0);
2487 2490 }
2488 2491
2489 2492 return (1);
2490 2493 }
2491 2494
2492 2495
2493 2496 static char *
2494 2497 client_name(struct svc_req *req)
2495 2498 {
2496 2499 char *hostname = NULL;
2497 2500
2498 2501 /*
2499 2502 * If it's a Unix cred then use the
2500 2503 * hostname from the credential.
2501 2504 */
2502 2505 if (req->rq_cred.oa_flavor == AUTH_UNIX) {
2503 2506 hostname = ((struct authunix_parms *)
2504 2507 req->rq_clntcred)->aup_machname;
2505 2508 }
2506 2509 if (hostname == NULL)
2507 2510 hostname = "";
2508 2511
2509 2512 return (hostname);
2510 2513 }
2511 2514
2512 2515 static char *
2513 2516 client_addr(struct svc_req *req, char *buf)
2514 2517 {
2515 2518 struct sockaddr *ca;
2516 2519 uchar_t *b;
2517 2520 char *frontspace = "";
2518 2521
2519 2522 /*
2520 2523 * We assume we are called in tandem with client_name and the
2521 2524 * format string looks like "...client %s%sblah blah..."
2522 2525 *
2523 2526 * If it's a Unix cred then client_name returned
2524 2527 * a host name, so we need insert a space between host name
2525 2528 * and IP address.
2526 2529 */
2527 2530 if (req->rq_cred.oa_flavor == AUTH_UNIX)
2528 2531 frontspace = " ";
2529 2532
2530 2533 /*
2531 2534 * Convert the caller's IP address to a dotted string
2532 2535 */
2533 2536 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2534 2537
2535 2538 if (ca->sa_family == AF_INET) {
2536 2539 b = (uchar_t *)&((struct sockaddr_in *)ca)->sin_addr;
2537 2540 (void) sprintf(buf, "%s(%d.%d.%d.%d) ", frontspace,
2538 2541 b[0] & 0xFF, b[1] & 0xFF, b[2] & 0xFF, b[3] & 0xFF);
2539 2542 } else if (ca->sa_family == AF_INET6) {
2540 2543 struct sockaddr_in6 *sin6;
2541 2544 sin6 = (struct sockaddr_in6 *)ca;
2542 2545 (void) kinet_ntop6((uchar_t *)&sin6->sin6_addr,
2543 2546 buf, INET6_ADDRSTRLEN);
2544 2547
2545 2548 } else {
2546 2549
2547 2550 /*
2548 2551 * No IP address to print. If there was a host name
2549 2552 * printed, then we print a space.
2550 2553 */
2551 2554 (void) sprintf(buf, frontspace);
2552 2555 }
2553 2556
2554 2557 return (buf);
2555 2558 }
2556 2559
2557 2560 /*
2558 2561 * NFS Server initialization routine. This routine should only be called
2559 2562 * once. It performs the following tasks:
2560 2563 * - Call sub-initialization routines (localize access to variables)
2561 2564 * - Initialize all locks
2562 2565 * - initialize the version 3 write verifier
2563 2566 */
2564 2567 void
2565 2568 nfs_srvinit(void)
2566 2569 {
2567 2570
2568 2571 /* Truly global stuff in this module (not per zone) */
2569 2572 rw_init(&nfssrv_globals_rwl, NULL, RW_DEFAULT, NULL);
2570 2573 list_create(&nfssrv_globals_list, sizeof (nfs_globals_t),
2571 2574 offsetof (nfs_globals_t, nfs_g_link));
2572 2575
2573 2576 /* The order here is important */
2574 2577 nfs_exportinit();
2575 2578 rfs_srvrinit();
2576 2579 rfs3_srvrinit();
2577 2580 rfs4_srvrinit();
2578 2581 nfsauth_init();
2579 2582
2580 2583 /*
2581 2584 * NFS server zone-specific global variables
2582 2585 * Note the zone_init is called for the GZ here.
2583 2586 */
2584 2587 zone_key_create(&nfssrv_zone_key, nfs_server_zone_init,
2585 2588 nfs_server_zone_shutdown, nfs_server_zone_fini);
2586 2589 }
2587 2590
2588 2591 /*
2589 2592 * NFS Server finalization routine. This routine is called to cleanup the
2590 2593 * initialization work previously performed if the NFS server module could
2591 2594 * not be loaded correctly.
2592 2595 */
2593 2596 void
2594 2597 nfs_srvfini(void)
2595 2598 {
2596 2599
2597 2600 /*
2598 2601 * NFS server zone-specific global variables
2599 2602 * Note the zone_fini is called for the GZ here.
2600 2603 */
2601 2604 (void) zone_key_delete(nfssrv_zone_key);
2602 2605
2603 2606 /* The order here is important (reverse of init) */
2604 2607 nfsauth_fini();
2605 2608 rfs4_srvrfini();
2606 2609 rfs3_srvrfini();
2607 2610 rfs_srvrfini();
2608 2611 nfs_exportfini();
2609 2612
2610 2613 /* Truly global stuff in this module (not per zone) */
2611 2614 list_destroy(&nfssrv_globals_list);
2612 2615 rw_destroy(&nfssrv_globals_rwl);
2613 2616 }
2614 2617
2615 2618 /*
2616 2619 * Zone init, shutdown, fini functions for the NFS server
2617 2620 *
2618 2621 * This design is careful to create the entire hierarhcy of
2619 2622 * NFS server "globals" (including those created by various
2620 2623 * per-module *_zone_init functions, etc.) so that all these
2621 2624 * objects have exactly the same lifetime.
2622 2625 *
2623 2626 * These objects are also kept on a list for two reasons:
2624 2627 * 1: It makes finding these in mdb _much_ easier.
2625 2628 * 2: It allows operating across all zone globals for
2626 2629 * functions like nfs_auth.c:exi_cache_reclaim
2627 2630 */
2628 2631 static void *
2629 2632 nfs_server_zone_init(zoneid_t zoneid)
2630 2633 {
2631 2634 nfs_globals_t *ng;
2632 2635
2633 2636 ng = kmem_zalloc(sizeof (*ng), KM_SLEEP);
2634 2637
2635 2638 ng->nfs_versmin = NFS_VERSMIN_DEFAULT;
2636 2639 ng->nfs_versmax = NFS_VERSMAX_DEFAULT;
2637 2640
2638 2641 /* Init the stuff to control start/stop */
2639 2642 ng->nfs_server_upordown = NFS_SERVER_STOPPED;
2640 2643 mutex_init(&ng->nfs_server_upordown_lock, NULL, MUTEX_DEFAULT, NULL);
2641 2644 cv_init(&ng->nfs_server_upordown_cv, NULL, CV_DEFAULT, NULL);
|
↓ open down ↓ |
661 lines elided |
↑ open up ↑ |
2642 2645 mutex_init(&ng->rdma_wait_mutex, NULL, MUTEX_DEFAULT, NULL);
2643 2646 cv_init(&ng->rdma_wait_cv, NULL, CV_DEFAULT, NULL);
2644 2647
2645 2648 ng->nfs_zoneid = zoneid;
2646 2649
2647 2650 /*
2648 2651 * Order here is important.
2649 2652 * export init must precede srv init calls.
2650 2653 */
2651 2654 nfs_export_zone_init(ng);
2655 + rfs_stat_zone_init(ng);
2652 2656 rfs_srv_zone_init(ng);
2653 2657 rfs3_srv_zone_init(ng);
2654 2658 rfs4_srv_zone_init(ng);
2655 2659 nfsauth_zone_init(ng);
2656 2660
2657 2661 rw_enter(&nfssrv_globals_rwl, RW_WRITER);
2658 2662 list_insert_tail(&nfssrv_globals_list, ng);
2659 2663 rw_exit(&nfssrv_globals_rwl);
2660 2664
2661 2665 return (ng);
2662 2666 }
2663 2667
2664 2668 /* ARGSUSED */
2665 2669 static void
2666 2670 nfs_server_zone_shutdown(zoneid_t zoneid, void *data)
2667 2671 {
2668 2672 nfs_globals_t *ng;
2669 2673
2670 2674 ng = (nfs_globals_t *)data;
2671 2675
2672 2676 /*
2673 2677 * Order is like _fini, but only
2674 2678 * some modules need this hook.
2675 2679 */
2676 2680 nfsauth_zone_shutdown(ng);
2677 2681 nfs_export_zone_shutdown(ng);
2678 2682 }
2679 2683
2680 2684 /* ARGSUSED */
2681 2685 static void
2682 2686 nfs_server_zone_fini(zoneid_t zoneid, void *data)
2683 2687 {
2684 2688 nfs_globals_t *ng;
2685 2689
2686 2690 ng = (nfs_globals_t *)data;
2687 2691
2688 2692 rw_enter(&nfssrv_globals_rwl, RW_WRITER);
2689 2693 list_remove(&nfssrv_globals_list, ng);
|
↓ open down ↓ |
28 lines elided |
↑ open up ↑ |
2690 2694 rw_exit(&nfssrv_globals_rwl);
2691 2695
2692 2696 /*
2693 2697 * Order here is important.
2694 2698 * reverse order from init
2695 2699 */
2696 2700 nfsauth_zone_fini(ng);
2697 2701 rfs4_srv_zone_fini(ng);
2698 2702 rfs3_srv_zone_fini(ng);
2699 2703 rfs_srv_zone_fini(ng);
2704 + rfs_stat_zone_fini(ng);
2700 2705 nfs_export_zone_fini(ng);
2701 2706
2702 2707 mutex_destroy(&ng->nfs_server_upordown_lock);
2703 2708 cv_destroy(&ng->nfs_server_upordown_cv);
2704 2709 mutex_destroy(&ng->rdma_wait_mutex);
2705 2710 cv_destroy(&ng->rdma_wait_cv);
2706 2711
2707 2712 kmem_free(ng, sizeof (*ng));
2708 2713 }
2709 2714
2710 2715 /*
2711 2716 * Set up an iovec array of up to cnt pointers.
2712 2717 */
2713 2718 void
2714 2719 mblk_to_iov(mblk_t *m, int cnt, struct iovec *iovp)
2715 2720 {
2716 2721 while (m != NULL && cnt-- > 0) {
2717 2722 iovp->iov_base = (caddr_t)m->b_rptr;
2718 2723 iovp->iov_len = (m->b_wptr - m->b_rptr);
2719 2724 iovp++;
2720 2725 m = m->b_cont;
2721 2726 }
2722 2727 }
2723 2728
2724 2729 /*
2725 2730 * Common code between NFS Version 2 and NFS Version 3 for the public
2726 2731 * filehandle multicomponent lookups.
2727 2732 */
2728 2733
2729 2734 /*
2730 2735 * Public filehandle evaluation of a multi-component lookup, following
2731 2736 * symbolic links, if necessary. This may result in a vnode in another
2732 2737 * filesystem, which is OK as long as the other filesystem is exported.
2733 2738 *
2734 2739 * Note that the exi will be set either to NULL or a new reference to the
2735 2740 * exportinfo struct that corresponds to the vnode of the multi-component path.
2736 2741 * It is the callers responsibility to release this reference.
2737 2742 */
2738 2743 int
2739 2744 rfs_publicfh_mclookup(char *p, vnode_t *dvp, cred_t *cr, vnode_t **vpp,
2740 2745 struct exportinfo **exi, struct sec_ol *sec)
2741 2746 {
2742 2747 int pathflag;
2743 2748 vnode_t *mc_dvp = NULL;
2744 2749 vnode_t *realvp;
2745 2750 int error;
2746 2751
2747 2752 *exi = NULL;
2748 2753
2749 2754 /*
2750 2755 * check if the given path is a url or native path. Since p is
2751 2756 * modified by MCLpath(), it may be empty after returning from
2752 2757 * there, and should be checked.
2753 2758 */
2754 2759 if ((pathflag = MCLpath(&p)) == -1)
2755 2760 return (EIO);
2756 2761
2757 2762 /*
2758 2763 * If pathflag is SECURITY_QUERY, turn the SEC_QUERY bit
2759 2764 * on in sec->sec_flags. This bit will later serve as an
2760 2765 * indication in makefh_ol() or makefh3_ol() to overload the
2761 2766 * filehandle to contain the sec modes used by the server for
2762 2767 * the path.
2763 2768 */
2764 2769 if (pathflag == SECURITY_QUERY) {
2765 2770 if ((sec->sec_index = (uint_t)(*p)) > 0) {
2766 2771 sec->sec_flags |= SEC_QUERY;
2767 2772 p++;
2768 2773 if ((pathflag = MCLpath(&p)) == -1)
2769 2774 return (EIO);
2770 2775 } else {
2771 2776 cmn_err(CE_NOTE,
2772 2777 "nfs_server: invalid security index %d, "
2773 2778 "violating WebNFS SNEGO protocol.", sec->sec_index);
2774 2779 return (EIO);
2775 2780 }
2776 2781 }
2777 2782
2778 2783 if (p[0] == '\0') {
2779 2784 error = ENOENT;
2780 2785 goto publicfh_done;
2781 2786 }
2782 2787
2783 2788 error = rfs_pathname(p, &mc_dvp, vpp, dvp, cr, pathflag);
2784 2789
2785 2790 /*
2786 2791 * If name resolves to "/" we get EINVAL since we asked for
2787 2792 * the vnode of the directory that the file is in. Try again
2788 2793 * with NULL directory vnode.
2789 2794 */
2790 2795 if (error == EINVAL) {
2791 2796 error = rfs_pathname(p, NULL, vpp, dvp, cr, pathflag);
2792 2797 if (!error) {
2793 2798 ASSERT(*vpp != NULL);
2794 2799 if ((*vpp)->v_type == VDIR) {
2795 2800 VN_HOLD(*vpp);
2796 2801 mc_dvp = *vpp;
2797 2802 } else {
2798 2803 /*
2799 2804 * This should not happen, the filesystem is
2800 2805 * in an inconsistent state. Fail the lookup
2801 2806 * at this point.
2802 2807 */
2803 2808 VN_RELE(*vpp);
2804 2809 error = EINVAL;
2805 2810 }
2806 2811 }
2807 2812 }
2808 2813
2809 2814 if (error)
2810 2815 goto publicfh_done;
2811 2816
2812 2817 if (*vpp == NULL) {
2813 2818 error = ENOENT;
2814 2819 goto publicfh_done;
2815 2820 }
2816 2821
2817 2822 ASSERT(mc_dvp != NULL);
2818 2823 ASSERT(*vpp != NULL);
2819 2824
2820 2825 if ((*vpp)->v_type == VDIR) {
2821 2826 do {
2822 2827 /*
2823 2828 * *vpp may be an AutoFS node, so we perform
2824 2829 * a VOP_ACCESS() to trigger the mount of the intended
2825 2830 * filesystem, so we can perform the lookup in the
2826 2831 * intended filesystem.
2827 2832 */
2828 2833 (void) VOP_ACCESS(*vpp, 0, 0, cr, NULL);
2829 2834
2830 2835 /*
2831 2836 * If vnode is covered, get the
2832 2837 * the topmost vnode.
2833 2838 */
2834 2839 if (vn_mountedvfs(*vpp) != NULL) {
2835 2840 error = traverse(vpp);
2836 2841 if (error) {
2837 2842 VN_RELE(*vpp);
2838 2843 goto publicfh_done;
2839 2844 }
2840 2845 }
2841 2846
2842 2847 if (VOP_REALVP(*vpp, &realvp, NULL) == 0 &&
2843 2848 realvp != *vpp) {
2844 2849 /*
2845 2850 * If realvp is different from *vpp
2846 2851 * then release our reference on *vpp, so that
2847 2852 * the export access check be performed on the
2848 2853 * real filesystem instead.
2849 2854 */
2850 2855 VN_HOLD(realvp);
2851 2856 VN_RELE(*vpp);
2852 2857 *vpp = realvp;
2853 2858 } else {
2854 2859 break;
2855 2860 }
2856 2861 /* LINTED */
2857 2862 } while (TRUE);
2858 2863
2859 2864 /*
2860 2865 * Let nfs_vptexi() figure what the real parent is.
2861 2866 */
2862 2867 VN_RELE(mc_dvp);
2863 2868 mc_dvp = NULL;
2864 2869
2865 2870 } else {
2866 2871 /*
2867 2872 * If vnode is covered, get the
2868 2873 * the topmost vnode.
2869 2874 */
2870 2875 if (vn_mountedvfs(mc_dvp) != NULL) {
2871 2876 error = traverse(&mc_dvp);
2872 2877 if (error) {
2873 2878 VN_RELE(*vpp);
2874 2879 goto publicfh_done;
2875 2880 }
2876 2881 }
2877 2882
2878 2883 if (VOP_REALVP(mc_dvp, &realvp, NULL) == 0 &&
2879 2884 realvp != mc_dvp) {
2880 2885 /*
2881 2886 * *vpp is a file, obtain realvp of the parent
2882 2887 * directory vnode.
2883 2888 */
2884 2889 VN_HOLD(realvp);
2885 2890 VN_RELE(mc_dvp);
2886 2891 mc_dvp = realvp;
2887 2892 }
2888 2893 }
2889 2894
2890 2895 /*
2891 2896 * The pathname may take us from the public filesystem to another.
2892 2897 * If that's the case then just set the exportinfo to the new export
2893 2898 * and build filehandle for it. Thanks to per-access checking there's
2894 2899 * no security issues with doing this. If the client is not allowed
2895 2900 * access to this new export then it will get an access error when it
2896 2901 * tries to use the filehandle
2897 2902 */
2898 2903 if (error = nfs_check_vpexi(mc_dvp, *vpp, kcred, exi)) {
2899 2904 VN_RELE(*vpp);
2900 2905 goto publicfh_done;
2901 2906 }
2902 2907
2903 2908 /*
2904 2909 * Not allowed access to pseudo exports.
2905 2910 */
2906 2911 if (PSEUDO(*exi)) {
2907 2912 error = ENOENT;
2908 2913 VN_RELE(*vpp);
2909 2914 goto publicfh_done;
2910 2915 }
2911 2916
2912 2917 /*
2913 2918 * Do a lookup for the index file. We know the index option doesn't
2914 2919 * allow paths through handling in the share command, so mc_dvp will
2915 2920 * be the parent for the index file vnode, if its present. Use
2916 2921 * temporary pointers to preserve and reuse the vnode pointers of the
2917 2922 * original directory in case there's no index file. Note that the
2918 2923 * index file is a native path, and should not be interpreted by
2919 2924 * the URL parser in rfs_pathname()
2920 2925 */
2921 2926 if (((*exi)->exi_export.ex_flags & EX_INDEX) &&
2922 2927 ((*vpp)->v_type == VDIR) && (pathflag == URLPATH)) {
2923 2928 vnode_t *tvp, *tmc_dvp; /* temporary vnode pointers */
2924 2929
2925 2930 tmc_dvp = mc_dvp;
2926 2931 mc_dvp = tvp = *vpp;
2927 2932
2928 2933 error = rfs_pathname((*exi)->exi_export.ex_index, NULL, vpp,
2929 2934 mc_dvp, cr, NATIVEPATH);
2930 2935
2931 2936 if (error == ENOENT) {
2932 2937 *vpp = tvp;
2933 2938 mc_dvp = tmc_dvp;
2934 2939 error = 0;
2935 2940 } else { /* ok or error other than ENOENT */
2936 2941 if (tmc_dvp)
2937 2942 VN_RELE(tmc_dvp);
2938 2943 if (error)
2939 2944 goto publicfh_done;
2940 2945
2941 2946 /*
2942 2947 * Found a valid vp for index "filename". Sanity check
2943 2948 * for odd case where a directory is provided as index
2944 2949 * option argument and leads us to another filesystem
2945 2950 */
2946 2951
2947 2952 /* Release the reference on the old exi value */
2948 2953 ASSERT(*exi != NULL);
2949 2954 exi_rele(*exi);
2950 2955 *exi = NULL;
2951 2956
2952 2957 if (error = nfs_check_vpexi(mc_dvp, *vpp, kcred, exi)) {
2953 2958 VN_RELE(*vpp);
2954 2959 goto publicfh_done;
2955 2960 }
2956 2961 /* Have a new *exi */
2957 2962 }
2958 2963 }
2959 2964
2960 2965 publicfh_done:
2961 2966 if (mc_dvp)
2962 2967 VN_RELE(mc_dvp);
2963 2968
2964 2969 return (error);
2965 2970 }
2966 2971
2967 2972 /*
2968 2973 * Evaluate a multi-component path
2969 2974 */
2970 2975 int
2971 2976 rfs_pathname(
2972 2977 char *path, /* pathname to evaluate */
2973 2978 vnode_t **dirvpp, /* ret for ptr to parent dir vnode */
2974 2979 vnode_t **compvpp, /* ret for ptr to component vnode */
2975 2980 vnode_t *startdvp, /* starting vnode */
2976 2981 cred_t *cr, /* user's credential */
2977 2982 int pathflag) /* flag to identify path, e.g. URL */
2978 2983 {
2979 2984 char namebuf[TYPICALMAXPATHLEN];
2980 2985 struct pathname pn;
2981 2986 int error;
2982 2987
2983 2988 ASSERT3U(crgetzoneid(cr), ==, curzone->zone_id);
2984 2989
2985 2990 /*
2986 2991 * If pathname starts with '/', then set startdvp to root.
2987 2992 */
2988 2993 if (*path == '/') {
2989 2994 while (*path == '/')
2990 2995 path++;
2991 2996
2992 2997 startdvp = ZONE_ROOTVP();
2993 2998 }
2994 2999
2995 3000 error = pn_get_buf(path, UIO_SYSSPACE, &pn, namebuf, sizeof (namebuf));
2996 3001 if (error == 0) {
2997 3002 /*
2998 3003 * Call the URL parser for URL paths to modify the original
2999 3004 * string to handle any '%' encoded characters that exist.
3000 3005 * Done here to avoid an extra bcopy in the lookup.
3001 3006 * We need to be careful about pathlen's. We know that
3002 3007 * rfs_pathname() is called with a non-empty path. However,
3003 3008 * it could be emptied due to the path simply being all /'s,
3004 3009 * which is valid to proceed with the lookup, or due to the
3005 3010 * URL parser finding an encoded null character at the
3006 3011 * beginning of path which should not proceed with the lookup.
3007 3012 */
3008 3013 if (pn.pn_pathlen != 0 && pathflag == URLPATH) {
3009 3014 URLparse(pn.pn_path);
3010 3015 if ((pn.pn_pathlen = strlen(pn.pn_path)) == 0)
3011 3016 return (ENOENT);
3012 3017 }
3013 3018 VN_HOLD(startdvp);
3014 3019 error = lookuppnvp(&pn, NULL, NO_FOLLOW, dirvpp, compvpp,
3015 3020 ZONE_ROOTVP(), startdvp, cr);
3016 3021 }
3017 3022 if (error == ENAMETOOLONG) {
3018 3023 /*
3019 3024 * This thread used a pathname > TYPICALMAXPATHLEN bytes long.
3020 3025 */
3021 3026 if (error = pn_get(path, UIO_SYSSPACE, &pn))
3022 3027 return (error);
3023 3028 if (pn.pn_pathlen != 0 && pathflag == URLPATH) {
3024 3029 URLparse(pn.pn_path);
3025 3030 if ((pn.pn_pathlen = strlen(pn.pn_path)) == 0) {
3026 3031 pn_free(&pn);
3027 3032 return (ENOENT);
3028 3033 }
3029 3034 }
3030 3035 VN_HOLD(startdvp);
3031 3036 error = lookuppnvp(&pn, NULL, NO_FOLLOW, dirvpp, compvpp,
3032 3037 ZONE_ROOTVP(), startdvp, cr);
3033 3038 pn_free(&pn);
3034 3039 }
3035 3040
3036 3041 return (error);
3037 3042 }
3038 3043
3039 3044 /*
3040 3045 * Adapt the multicomponent lookup path depending on the pathtype
3041 3046 */
3042 3047 static int
3043 3048 MCLpath(char **path)
3044 3049 {
3045 3050 unsigned char c = (unsigned char)**path;
3046 3051
3047 3052 /*
3048 3053 * If the MCL path is between 0x20 and 0x7E (graphic printable
3049 3054 * character of the US-ASCII coded character set), its a URL path,
3050 3055 * per RFC 1738.
3051 3056 */
3052 3057 if (c >= 0x20 && c <= 0x7E)
3053 3058 return (URLPATH);
3054 3059
3055 3060 /*
3056 3061 * If the first octet of the MCL path is not an ASCII character
3057 3062 * then it must be interpreted as a tag value that describes the
3058 3063 * format of the remaining octets of the MCL path.
3059 3064 *
3060 3065 * If the first octet of the MCL path is 0x81 it is a query
3061 3066 * for the security info.
3062 3067 */
3063 3068 switch (c) {
3064 3069 case 0x80: /* native path, i.e. MCL via mount protocol */
3065 3070 (*path)++;
3066 3071 return (NATIVEPATH);
3067 3072 case 0x81: /* security query */
3068 3073 (*path)++;
3069 3074 return (SECURITY_QUERY);
3070 3075 default:
3071 3076 return (-1);
3072 3077 }
3073 3078 }
3074 3079
3075 3080 #define fromhex(c) ((c >= '0' && c <= '9') ? (c - '0') : \
3076 3081 ((c >= 'A' && c <= 'F') ? (c - 'A' + 10) :\
3077 3082 ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : 0)))
3078 3083
3079 3084 /*
3080 3085 * The implementation of URLparse guarantees that the final string will
3081 3086 * fit in the original one. Replaces '%' occurrences followed by 2 characters
3082 3087 * with its corresponding hexadecimal character.
3083 3088 */
3084 3089 static void
3085 3090 URLparse(char *str)
3086 3091 {
3087 3092 char *p, *q;
3088 3093
3089 3094 p = q = str;
3090 3095 while (*p) {
3091 3096 *q = *p;
3092 3097 if (*p++ == '%') {
3093 3098 if (*p) {
3094 3099 *q = fromhex(*p) * 16;
3095 3100 p++;
3096 3101 if (*p) {
3097 3102 *q += fromhex(*p);
3098 3103 p++;
3099 3104 }
3100 3105 }
3101 3106 }
3102 3107 q++;
3103 3108 }
3104 3109 *q = '\0';
3105 3110 }
3106 3111
3107 3112
3108 3113 /*
3109 3114 * Get the export information for the lookup vnode, and verify its
3110 3115 * useable.
3111 3116 */
3112 3117 int
3113 3118 nfs_check_vpexi(vnode_t *mc_dvp, vnode_t *vp, cred_t *cr,
3114 3119 struct exportinfo **exi)
3115 3120 {
3116 3121 int walk;
3117 3122 int error = 0;
3118 3123
3119 3124 *exi = nfs_vptoexi(mc_dvp, vp, cr, &walk, NULL, FALSE);
3120 3125 if (*exi == NULL)
3121 3126 error = EACCES;
3122 3127 else {
3123 3128 /*
3124 3129 * If nosub is set for this export then
3125 3130 * a lookup relative to the public fh
3126 3131 * must not terminate below the
3127 3132 * exported directory.
3128 3133 */
3129 3134 if ((*exi)->exi_export.ex_flags & EX_NOSUB && walk > 0)
3130 3135 error = EACCES;
3131 3136 }
3132 3137
3133 3138 return (error);
3134 3139 }
3135 3140
3136 3141 /*
3137 3142 * Used by NFSv3 and NFSv4 server to query label of
3138 3143 * a pathname component during lookup/access ops.
3139 3144 */
3140 3145 ts_label_t *
3141 3146 nfs_getflabel(vnode_t *vp, struct exportinfo *exi)
3142 3147 {
3143 3148 zone_t *zone;
3144 3149 ts_label_t *zone_label;
3145 3150 char *path;
3146 3151
3147 3152 mutex_enter(&vp->v_lock);
3148 3153 if (vp->v_path != vn_vpath_empty) {
3149 3154 zone = zone_find_by_any_path(vp->v_path, B_FALSE);
3150 3155 mutex_exit(&vp->v_lock);
3151 3156 } else {
3152 3157 /*
3153 3158 * v_path not cached. Fall back on pathname of exported
3154 3159 * file system as we rely on pathname from which we can
3155 3160 * derive a label. The exported file system portion of
3156 3161 * path is sufficient to obtain a label.
3157 3162 */
3158 3163 path = exi->exi_export.ex_path;
3159 3164 if (path == NULL) {
3160 3165 mutex_exit(&vp->v_lock);
3161 3166 return (NULL);
3162 3167 }
3163 3168 zone = zone_find_by_any_path(path, B_FALSE);
3164 3169 mutex_exit(&vp->v_lock);
3165 3170 }
3166 3171 /*
3167 3172 * Caller has verified that the file is either
3168 3173 * exported or visible. So if the path falls in
3169 3174 * global zone, admin_low is returned; otherwise
3170 3175 * the zone's label is returned.
3171 3176 */
3172 3177 zone_label = zone->zone_slabel;
3173 3178 label_hold(zone_label);
3174 3179 zone_rele(zone);
3175 3180 return (zone_label);
3176 3181 }
3177 3182
3178 3183 /*
3179 3184 * TX NFS routine used by NFSv3 and NFSv4 to do label check
3180 3185 * on client label and server's file object lable.
3181 3186 */
3182 3187 boolean_t
3183 3188 do_rfs_label_check(bslabel_t *clabel, vnode_t *vp, int flag,
3184 3189 struct exportinfo *exi)
3185 3190 {
3186 3191 bslabel_t *slabel;
3187 3192 ts_label_t *tslabel;
3188 3193 boolean_t result;
3189 3194
3190 3195 if ((tslabel = nfs_getflabel(vp, exi)) == NULL) {
3191 3196 return (B_FALSE);
3192 3197 }
3193 3198 slabel = label2bslabel(tslabel);
3194 3199 DTRACE_PROBE4(tx__rfs__log__info__labelcheck, char *,
3195 3200 "comparing server's file label(1) with client label(2) (vp(3))",
3196 3201 bslabel_t *, slabel, bslabel_t *, clabel, vnode_t *, vp);
3197 3202
3198 3203 if (flag == EQUALITY_CHECK)
3199 3204 result = blequal(clabel, slabel);
3200 3205 else
3201 3206 result = bldominates(clabel, slabel);
3202 3207 label_rele(tslabel);
3203 3208 return (result);
3204 3209 }
3205 3210
3206 3211 /*
3207 3212 * Callback function to return the loaned buffers.
3208 3213 * Calls VOP_RETZCBUF() only after all uio_iov[]
3209 3214 * buffers are returned. nu_ref maintains the count.
3210 3215 */
3211 3216 void
3212 3217 rfs_free_xuio(void *free_arg)
3213 3218 {
3214 3219 uint_t ref;
3215 3220 nfs_xuio_t *nfsuiop = (nfs_xuio_t *)free_arg;
3216 3221
3217 3222 ref = atomic_dec_uint_nv(&nfsuiop->nu_ref);
3218 3223
3219 3224 /*
3220 3225 * Call VOP_RETZCBUF() only when all the iov buffers
3221 3226 * are sent OTW.
3222 3227 */
3223 3228 if (ref != 0)
3224 3229 return;
3225 3230
3226 3231 if (((uio_t *)nfsuiop)->uio_extflg & UIO_XUIO) {
3227 3232 (void) VOP_RETZCBUF(nfsuiop->nu_vp, (xuio_t *)free_arg, NULL,
3228 3233 NULL);
3229 3234 VN_RELE(nfsuiop->nu_vp);
3230 3235 }
3231 3236
3232 3237 kmem_cache_free(nfs_xuio_cache, free_arg);
3233 3238 }
3234 3239
3235 3240 xuio_t *
3236 3241 rfs_setup_xuio(vnode_t *vp)
3237 3242 {
3238 3243 nfs_xuio_t *nfsuiop;
3239 3244
3240 3245 nfsuiop = kmem_cache_alloc(nfs_xuio_cache, KM_SLEEP);
3241 3246
3242 3247 bzero(nfsuiop, sizeof (nfs_xuio_t));
3243 3248 nfsuiop->nu_vp = vp;
3244 3249
3245 3250 /*
3246 3251 * ref count set to 1. more may be added
3247 3252 * if multiple mblks refer to multiple iov's.
3248 3253 * This is done in uio_to_mblk().
3249 3254 */
3250 3255
3251 3256 nfsuiop->nu_ref = 1;
3252 3257
3253 3258 nfsuiop->nu_frtn.free_func = rfs_free_xuio;
3254 3259 nfsuiop->nu_frtn.free_arg = (char *)nfsuiop;
3255 3260
3256 3261 nfsuiop->nu_uio.xu_type = UIOTYPE_ZEROCOPY;
3257 3262
3258 3263 return (&nfsuiop->nu_uio);
3259 3264 }
3260 3265
3261 3266 mblk_t *
3262 3267 uio_to_mblk(uio_t *uiop)
3263 3268 {
3264 3269 struct iovec *iovp;
3265 3270 int i;
3266 3271 mblk_t *mp, *mp1;
3267 3272 nfs_xuio_t *nfsuiop = (nfs_xuio_t *)uiop;
3268 3273
3269 3274 if (uiop->uio_iovcnt == 0)
3270 3275 return (NULL);
3271 3276
3272 3277 iovp = uiop->uio_iov;
3273 3278 mp = mp1 = esballoca((uchar_t *)iovp->iov_base, iovp->iov_len,
3274 3279 BPRI_MED, &nfsuiop->nu_frtn);
3275 3280 ASSERT(mp != NULL);
3276 3281
3277 3282 mp->b_wptr += iovp->iov_len;
3278 3283 mp->b_datap->db_type = M_DATA;
3279 3284
3280 3285 for (i = 1; i < uiop->uio_iovcnt; i++) {
3281 3286 iovp = (uiop->uio_iov + i);
3282 3287
3283 3288 mp1->b_cont = esballoca(
3284 3289 (uchar_t *)iovp->iov_base, iovp->iov_len, BPRI_MED,
3285 3290 &nfsuiop->nu_frtn);
3286 3291
3287 3292 mp1 = mp1->b_cont;
3288 3293 ASSERT(mp1 != NULL);
3289 3294 mp1->b_wptr += iovp->iov_len;
3290 3295 mp1->b_datap->db_type = M_DATA;
3291 3296 }
3292 3297
3293 3298 nfsuiop->nu_ref = uiop->uio_iovcnt;
3294 3299
3295 3300 return (mp);
3296 3301 }
3297 3302
3298 3303 /*
3299 3304 * Allocate memory to hold data for a read request of len bytes.
3300 3305 *
3301 3306 * We don't allocate buffers greater than kmem_max_cached in size to avoid
3302 3307 * allocating memory from the kmem_oversized arena. If we allocate oversized
3303 3308 * buffers, we incur heavy cross-call activity when freeing these large buffers
3304 3309 * in the TCP receive path. Note that we can't set b_wptr here since the
3305 3310 * length of the data returned may differ from the length requested when
3306 3311 * reading the end of a file; we set b_wptr in rfs_rndup_mblks() once the
3307 3312 * length of the read is known.
3308 3313 */
3309 3314 mblk_t *
3310 3315 rfs_read_alloc(uint_t len, struct iovec **iov, int *iovcnt)
3311 3316 {
3312 3317 struct iovec *iovarr;
3313 3318 mblk_t *mp, **mpp = ∓
3314 3319 size_t mpsize;
3315 3320 uint_t remain = len;
3316 3321 int i, err = 0;
3317 3322
3318 3323 *iovcnt = howmany(len, kmem_max_cached);
3319 3324
3320 3325 iovarr = kmem_alloc(*iovcnt * sizeof (struct iovec), KM_SLEEP);
3321 3326 *iov = iovarr;
3322 3327
3323 3328 for (i = 0; i < *iovcnt; remain -= mpsize, i++) {
3324 3329 ASSERT(remain <= len);
3325 3330 /*
3326 3331 * We roundup the size we allocate to a multiple of
3327 3332 * BYTES_PER_XDR_UNIT (4 bytes) so that the call to
3328 3333 * xdrmblk_putmblk() never fails.
3329 3334 */
3330 3335 ASSERT(kmem_max_cached % BYTES_PER_XDR_UNIT == 0);
3331 3336 mpsize = MIN(kmem_max_cached, remain);
3332 3337 *mpp = allocb_wait(RNDUP(mpsize), BPRI_MED, STR_NOSIG, &err);
3333 3338 ASSERT(*mpp != NULL);
3334 3339 ASSERT(err == 0);
3335 3340
3336 3341 iovarr[i].iov_base = (caddr_t)(*mpp)->b_rptr;
3337 3342 iovarr[i].iov_len = mpsize;
3338 3343 mpp = &(*mpp)->b_cont;
3339 3344 }
3340 3345 return (mp);
3341 3346 }
3342 3347
3343 3348 void
3344 3349 rfs_rndup_mblks(mblk_t *mp, uint_t len, int buf_loaned)
3345 3350 {
3346 3351 int i;
3347 3352 int alloc_err = 0;
3348 3353 mblk_t *rmp;
3349 3354 uint_t mpsize, remainder;
3350 3355
3351 3356 remainder = P2NPHASE(len, BYTES_PER_XDR_UNIT);
3352 3357
3353 3358 /*
3354 3359 * Non copy-reduction case. This function assumes that blocks were
3355 3360 * allocated in multiples of BYTES_PER_XDR_UNIT bytes, which makes this
3356 3361 * padding safe without bounds checking.
3357 3362 */
3358 3363 if (!buf_loaned) {
3359 3364 /*
3360 3365 * Set the size of each mblk in the chain until we've consumed
3361 3366 * the specified length for all but the last one.
3362 3367 */
3363 3368 while ((mpsize = MBLKSIZE(mp)) < len) {
3364 3369 ASSERT(mpsize % BYTES_PER_XDR_UNIT == 0);
3365 3370 mp->b_wptr += mpsize;
3366 3371 len -= mpsize;
3367 3372 mp = mp->b_cont;
3368 3373 ASSERT(mp != NULL);
3369 3374 }
3370 3375
3371 3376 ASSERT(len + remainder <= mpsize);
3372 3377 mp->b_wptr += len;
3373 3378 for (i = 0; i < remainder; i++)
3374 3379 *mp->b_wptr++ = '\0';
3375 3380 return;
3376 3381 }
3377 3382
3378 3383 /*
3379 3384 * No remainder mblk required.
3380 3385 */
3381 3386 if (remainder == 0)
3382 3387 return;
3383 3388
3384 3389 /*
3385 3390 * Get to the last mblk in the chain.
3386 3391 */
3387 3392 while (mp->b_cont != NULL)
3388 3393 mp = mp->b_cont;
3389 3394
3390 3395 /*
3391 3396 * In case of copy-reduction mblks, the size of the mblks are fixed
3392 3397 * and are of the size of the loaned buffers. Allocate a remainder
3393 3398 * mblk and chain it to the data buffers. This is sub-optimal, but not
3394 3399 * expected to happen commonly.
3395 3400 */
3396 3401 rmp = allocb_wait(remainder, BPRI_MED, STR_NOSIG, &alloc_err);
3397 3402 ASSERT(rmp != NULL);
3398 3403 ASSERT(alloc_err == 0);
3399 3404
3400 3405 for (i = 0; i < remainder; i++)
3401 3406 *rmp->b_wptr++ = '\0';
3402 3407
3403 3408 rmp->b_datap->db_type = M_DATA;
3404 3409 mp->b_cont = rmp;
3405 3410 }
|
↓ open down ↓ |
696 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX