Print this page
11083 support NFS server in zone
Portions contributed by: Dan Kruchinin <dan.kruchinin@nexenta.com>
Portions contributed by: Stepan Zastupov <stepan.zastupov@gmail.com>
Portions contributed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Portions contributed by: Mike Zeller <mike@mikezeller.net>
Portions contributed by: Dan McDonald <danmcd@joyent.com>
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>
Portions contributed by: Vitaliy Gusev <gusev.vitaliy@gmail.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Jason King <jbk@joyent.com>
Reviewed by: C Fraire <cfraire@me.com>
Change-Id: I22f289d357503f9b48a0bc2482cc4328a6d43d16
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/nfs/nfs_export.c
+++ new/usr/src/uts/common/fs/nfs/nfs_export.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 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
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 /*
23 - * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24 23 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
25 24 */
26 25
27 26 /*
28 - * Copyright 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T.
27 + * Copyright 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T.
29 28 * All rights reserved.
30 29 */
31 30
31 +/*
32 + * Copyright 2018 Nexenta Systems, Inc.
33 + */
32 34
33 35 #include <sys/types.h>
34 36 #include <sys/param.h>
35 37 #include <sys/time.h>
36 38 #include <sys/vfs.h>
37 39 #include <sys/vnode.h>
38 40 #include <sys/socket.h>
39 41 #include <sys/errno.h>
40 42 #include <sys/uio.h>
41 43 #include <sys/proc.h>
42 44 #include <sys/user.h>
43 45 #include <sys/file.h>
44 46 #include <sys/tiuser.h>
45 47 #include <sys/kmem.h>
46 48 #include <sys/pathname.h>
47 49 #include <sys/debug.h>
48 50 #include <sys/vtrace.h>
49 51 #include <sys/cmn_err.h>
50 52 #include <sys/acl.h>
51 53 #include <sys/utsname.h>
52 54 #include <sys/sdt.h>
53 55 #include <netinet/in.h>
54 56 #include <sys/avl.h>
55 57
56 58 #include <rpc/types.h>
57 59 #include <rpc/auth.h>
|
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
58 60 #include <rpc/svc.h>
59 61
60 62 #include <nfs/nfs.h>
61 63 #include <nfs/export.h>
62 64 #include <nfs/nfssys.h>
63 65 #include <nfs/nfs_clnt.h>
64 66 #include <nfs/nfs_acl.h>
65 67 #include <nfs/nfs_log.h>
66 68 #include <nfs/lm.h>
67 69 #include <sys/sunddi.h>
68 -#include <sys/pkp_hash.h>
69 70
70 -treenode_t *ns_root;
71 +/*
72 + * exi_id support
73 + *
74 + * exi_id_next The next exi_id available.
75 + * exi_id_overflow The exi_id_next already overflowed, so we should
76 + * thoroughly check for duplicates.
77 + * exi_id_tree AVL tree indexed by exi_id.
78 + * nfs_exi_id_lock Lock to protect the export ID list
79 + *
80 + * All exi_id_next, exi_id_overflow, and exi_id_tree are protected by
81 + * nfs_exi_id_lock.
82 + */
83 +static int exi_id_next;
84 +static bool_t exi_id_overflow;
85 +avl_tree_t exi_id_tree;
86 +kmutex_t nfs_exi_id_lock;
71 87
72 -struct exportinfo *exptable_path_hash[PKP_HASH_SIZE];
73 -struct exportinfo *exptable[EXPTABLESIZE];
74 -
75 -static int unexport(exportinfo_t *);
88 +static int unexport(nfs_export_t *, exportinfo_t *);
76 89 static void exportfree(exportinfo_t *);
77 90 static int loadindex(exportdata_t *);
78 91
79 92 extern void nfsauth_cache_free(exportinfo_t *);
80 93 extern int sec_svc_loadrootnames(int, int, caddr_t **, model_t);
81 94 extern void sec_svc_freerootnames(int, int, caddr_t *);
82 95
83 -static int build_seclist_nodups(exportdata_t *, secinfo_t *, int);
84 -static void srv_secinfo_add(secinfo_t **, int *, secinfo_t *, int, int);
85 -static void srv_secinfo_remove(secinfo_t **, int *, secinfo_t *, int);
86 -static void srv_secinfo_treeclimb(exportinfo_t *, secinfo_t *, int, bool_t);
96 +static int build_seclist_nodups(exportdata_t *, secinfo_t *, int);
97 +static void srv_secinfo_add(secinfo_t **, int *, secinfo_t *, int, int);
98 +static void srv_secinfo_remove(secinfo_t **, int *, secinfo_t *, int);
99 +static void srv_secinfo_treeclimb(nfs_export_t *, exportinfo_t *,
100 + secinfo_t *, int, bool_t);
87 101
88 102 #ifdef VOLATILE_FH_TEST
89 103 static struct ex_vol_rename *find_volrnm_fh(exportinfo_t *, nfs_fh4 *);
90 104 static uint32_t find_volrnm_fh_id(exportinfo_t *, nfs_fh4 *);
91 -static void free_volrnm_list(exportinfo_t *);
105 +static void free_volrnm_list(exportinfo_t *);
92 106 #endif /* VOLATILE_FH_TEST */
93 107
94 -/*
95 - * exported_lock Read/Write lock that protects the exportinfo list.
96 - * This lock must be held when searching or modifiying
97 - * the exportinfo list.
98 - */
99 -krwlock_t exported_lock;
100 -
101 -/*
102 - * "public" and default (root) location for public filehandle
103 - */
104 -struct exportinfo *exi_public, *exi_root;
105 -
106 -fid_t exi_rootfid; /* for checking the default public file handle */
107 -
108 108 fhandle_t nullfh2; /* for comparing V2 filehandles */
109 109
110 110 /*
111 111 * macro for static dtrace probes to trace server namespace ref count mods.
112 112 */
113 113 #define SECREF_TRACE(seclist, tag, flav, aftcnt) \
114 114 DTRACE_PROBE4(nfss__i__nmspc__secref, struct secinfo *, (seclist), \
115 115 char *, (tag), int, (int)(flav), int, (int)(aftcnt))
116 116
117 117
118 118 #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1))
119 119
120 +extern nfs_export_t *
121 +nfs_get_export(void)
122 +{
123 + nfs_globals_t *ng = nfs_srv_getzg();
124 + nfs_export_t *ne = ng->nfs_export;
125 + ASSERT(ne != NULL);
126 + return (ne);
127 +}
128 +
120 129 static uint8_t
121 130 xor_hash(uint8_t *data, int len)
122 131 {
123 132 uint8_t h = 0;
124 133
125 134 while (len--)
126 135 h ^= *data++;
127 136
128 137 return (h);
129 138 }
130 139
131 140 /*
132 141 * File handle hash function, XOR over all bytes in fsid and fid.
133 142 */
134 143 static unsigned
135 144 nfs_fhhash(fsid_t *fsid, fid_t *fid)
136 145 {
137 146 int len;
138 147 uint8_t h;
139 148
140 149 h = xor_hash((uint8_t *)fsid, sizeof (fsid_t));
141 150
142 151 /*
143 152 * Sanity check the length before using it
144 153 * blindly in case the client trashed it.
145 154 */
146 155 len = fid->fid_len > NFS_FH4MAXDATA ? 0 : fid->fid_len;
147 156 h ^= xor_hash((uint8_t *)fid->fid_data, len);
148 157
149 158 return ((unsigned)h);
150 159 }
151 160
152 161 /*
153 162 * Free the memory allocated within a secinfo entry.
154 163 */
155 164 void
156 165 srv_secinfo_entry_free(struct secinfo *secp)
157 166 {
158 167 if (secp->s_rootcnt > 0 && secp->s_rootnames != NULL) {
159 168 sec_svc_freerootnames(secp->s_secinfo.sc_rpcnum,
160 169 secp->s_rootcnt, secp->s_rootnames);
161 170 secp->s_rootcnt = 0;
162 171 }
163 172
164 173 if ((secp->s_secinfo.sc_rpcnum == RPCSEC_GSS) &&
165 174 (secp->s_secinfo.sc_gss_mech_type)) {
166 175 kmem_free(secp->s_secinfo.sc_gss_mech_type->elements,
167 176 secp->s_secinfo.sc_gss_mech_type->length);
168 177 kmem_free(secp->s_secinfo.sc_gss_mech_type,
169 178 sizeof (rpc_gss_OID_desc));
170 179 secp->s_secinfo.sc_gss_mech_type = NULL;
171 180 }
172 181 }
173 182
174 183 /*
175 184 * Free a list of secinfo allocated in the exportdata structure.
176 185 */
177 186 void
178 187 srv_secinfo_list_free(struct secinfo *secinfo, int cnt)
179 188 {
180 189 int i;
181 190
182 191 if (cnt == 0)
183 192 return;
184 193
185 194 for (i = 0; i < cnt; i++)
186 195 srv_secinfo_entry_free(&secinfo[i]);
187 196
188 197 kmem_free(secinfo, cnt * sizeof (struct secinfo));
189 198 }
190 199
191 200 /*
192 201 * Allocate and copy a secinfo data from "from" to "to".
193 202 *
194 203 * This routine is used by srv_secinfo_add() to add a new flavor to an
195 204 * ancestor's export node. The rootnames are not copied because the
196 205 * allowable rootname access only applies to the explicit exported node,
197 206 * not its ancestor's.
198 207 *
199 208 * "to" should have already been allocated and zeroed before calling
200 209 * this routine.
201 210 *
202 211 * This routine is used under the protection of exported_lock (RW_WRITER).
203 212 */
204 213 void
205 214 srv_secinfo_copy(struct secinfo *from, struct secinfo *to)
206 215 {
207 216 to->s_secinfo.sc_nfsnum = from->s_secinfo.sc_nfsnum;
208 217 to->s_secinfo.sc_rpcnum = from->s_secinfo.sc_rpcnum;
209 218
210 219 if (from->s_secinfo.sc_rpcnum == RPCSEC_GSS) {
211 220 to->s_secinfo.sc_service = from->s_secinfo.sc_service;
212 221 bcopy(from->s_secinfo.sc_name, to->s_secinfo.sc_name,
213 222 strlen(from->s_secinfo.sc_name));
214 223 bcopy(from->s_secinfo.sc_gss_mech, to->s_secinfo.sc_gss_mech,
215 224 strlen(from->s_secinfo.sc_gss_mech));
216 225
217 226 /* copy mechanism oid */
218 227 to->s_secinfo.sc_gss_mech_type =
219 228 kmem_alloc(sizeof (rpc_gss_OID_desc), KM_SLEEP);
220 229 to->s_secinfo.sc_gss_mech_type->length =
221 230 from->s_secinfo.sc_gss_mech_type->length;
222 231 to->s_secinfo.sc_gss_mech_type->elements =
223 232 kmem_alloc(from->s_secinfo.sc_gss_mech_type->length,
224 233 KM_SLEEP);
225 234 bcopy(from->s_secinfo.sc_gss_mech_type->elements,
226 235 to->s_secinfo.sc_gss_mech_type->elements,
227 236 from->s_secinfo.sc_gss_mech_type->length);
228 237 }
229 238
230 239 to->s_refcnt = from->s_refcnt;
231 240 to->s_window = from->s_window;
232 241 /* no need to copy the mode bits - s_flags */
233 242 }
234 243
235 244 /*
236 245 * Create a secinfo array without duplicates. The condensed
237 246 * flavor list is used to propagate flavor ref counts to an
238 247 * export's ancestor pseudonodes.
239 248 */
240 249 static int
241 250 build_seclist_nodups(exportdata_t *exd, secinfo_t *nodups, int exponly)
242 251 {
243 252 int ccnt, c;
244 253 int ncnt, n;
245 254 struct secinfo *cursec;
246 255
247 256 ncnt = 0;
248 257 ccnt = exd->ex_seccnt;
249 258 cursec = exd->ex_secinfo;
250 259
251 260 for (c = 0; c < ccnt; c++) {
252 261
253 262 if (exponly && ! SEC_REF_EXPORTED(&cursec[c]))
254 263 continue;
255 264
256 265 for (n = 0; n < ncnt; n++) {
257 266 if (nodups[n].s_secinfo.sc_nfsnum ==
258 267 cursec[c].s_secinfo.sc_nfsnum)
259 268 break;
260 269 }
261 270
262 271 /*
263 272 * The structure copy below also copys ptrs embedded
264 273 * within struct secinfo. The ptrs are copied but
265 274 * they are never freed from the nodups array. If
266 275 * an ancestor's secinfo array doesn't contain one
267 276 * of the nodups flavors, then the entry is properly
268 277 * copied into the ancestor's secinfo array.
269 278 * (see srv_secinfo_copy)
270 279 */
271 280 if (n == ncnt) {
272 281 nodups[n] = cursec[c];
273 282 ncnt++;
274 283 }
275 284 }
276 285 return (ncnt);
277 286 }
278 287
279 288 /*
280 289 * Add the new security flavors from newdata to the current list, pcursec.
281 290 * Upon return, *pcursec has the newly merged secinfo list.
282 291 *
283 292 * There should be at least 1 secinfo entry in newsec.
284 293 *
285 294 * This routine is used under the protection of exported_lock (RW_WRITER).
286 295 */
287 296 static void
288 297 srv_secinfo_add(secinfo_t **pcursec, int *pcurcnt, secinfo_t *newsec,
289 298 int newcnt, int is_pseudo)
290 299 {
291 300 int ccnt, c; /* sec count in current data - curdata */
292 301 int n; /* index for newsec - newsecinfo */
293 302 int tcnt; /* total sec count after merge */
294 303 int mcnt; /* total sec count after merge */
295 304 struct secinfo *msec; /* merged secinfo list */
296 305 struct secinfo *cursec;
297 306
298 307 cursec = *pcursec;
299 308 ccnt = *pcurcnt;
300 309
301 310 ASSERT(newcnt > 0);
302 311 tcnt = ccnt + newcnt;
303 312
304 313 for (n = 0; n < newcnt; n++) {
305 314 for (c = 0; c < ccnt; c++) {
306 315 if (newsec[n].s_secinfo.sc_nfsnum ==
307 316 cursec[c].s_secinfo.sc_nfsnum) {
308 317 cursec[c].s_refcnt += newsec[n].s_refcnt;
309 318 SECREF_TRACE(cursec, "add_ref",
310 319 cursec[c].s_secinfo.sc_nfsnum,
311 320 cursec[c].s_refcnt);
312 321 tcnt--;
313 322 break;
314 323 }
315 324 }
316 325 }
317 326
318 327 if (tcnt == ccnt)
319 328 return; /* no change; no new flavors */
320 329
321 330 msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
322 331
323 332 /* move current secinfo list data to the new list */
324 333 for (c = 0; c < ccnt; c++)
325 334 msec[c] = cursec[c];
326 335
327 336 /* Add the flavor that's not in the current data */
328 337 mcnt = ccnt;
329 338 for (n = 0; n < newcnt; n++) {
330 339 for (c = 0; c < ccnt; c++) {
331 340 if (newsec[n].s_secinfo.sc_nfsnum ==
332 341 cursec[c].s_secinfo.sc_nfsnum)
333 342 break;
334 343 }
335 344
336 345 /* This is the one. Add it. */
337 346 if (c == ccnt) {
338 347 srv_secinfo_copy(&newsec[n], &msec[mcnt]);
339 348
340 349 if (is_pseudo)
341 350 msec[mcnt].s_flags = M_RO;
342 351
343 352 SECREF_TRACE(msec, "new_ref",
344 353 msec[mcnt].s_secinfo.sc_nfsnum,
345 354 msec[mcnt].s_refcnt);
346 355 mcnt++;
347 356 }
348 357 }
349 358
350 359 ASSERT(mcnt == tcnt);
351 360
352 361 /*
353 362 * Done. Update curdata. Free the old secinfo list in
354 363 * curdata and return the new sec array info
355 364 */
356 365 if (ccnt > 0)
357 366 kmem_free(cursec, ccnt * sizeof (struct secinfo));
358 367 *pcurcnt = tcnt;
359 368 *pcursec = msec;
360 369 }
361 370
362 371 /*
363 372 * For NFS V4.
364 373 * Remove the security data of the unexported node from its ancestors.
365 374 * Assume there is at least one flavor entry in the current sec list
366 375 * (pcursec).
367 376 *
368 377 * This routine is used under the protection of exported_lock (RW_WRITER).
369 378 *
370 379 * Every element of remsec is an explicitly exported flavor. If
371 380 * srv_secinfo_remove() is called fom an exportfs error path, then
372 381 * the flavor list was derived from the user's share cmdline,
373 382 * and all flavors are explicit. If it was called from the unshare path,
374 383 * build_seclist_nodups() was called with the exponly flag.
375 384 */
376 385 static void
377 386 srv_secinfo_remove(secinfo_t **pcursec, int *pcurcnt, secinfo_t *remsec,
378 387 int remcnt)
379 388 {
380 389 int ccnt, c; /* sec count in current data - cursec */
381 390 int r; /* sec count in removal data - remsec */
382 391 int tcnt, mcnt; /* total sec count after removing */
383 392 struct secinfo *msec; /* final secinfo list after removing */
384 393 struct secinfo *cursec;
385 394
386 395 cursec = *pcursec;
387 396 ccnt = *pcurcnt;
388 397 tcnt = ccnt;
389 398
390 399 for (r = 0; r < remcnt; r++) {
391 400 /*
392 401 * At unshare/reshare time, only explicitly shared flavor ref
393 402 * counts are decremented and propagated to ancestors.
394 403 * Implicit flavor refs came from shared descendants, and
395 404 * they must be kept.
396 405 */
397 406 if (! SEC_REF_EXPORTED(&remsec[r]))
398 407 continue;
399 408
400 409 for (c = 0; c < ccnt; c++) {
401 410 if (remsec[r].s_secinfo.sc_nfsnum ==
402 411 cursec[c].s_secinfo.sc_nfsnum) {
403 412
404 413 /*
405 414 * Decrement secinfo reference count by 1.
406 415 * If this entry is invalid after decrementing
407 416 * the count (i.e. count < 1), this entry will
408 417 * be removed.
409 418 */
410 419 cursec[c].s_refcnt--;
411 420
412 421 SECREF_TRACE(cursec, "del_ref",
413 422 cursec[c].s_secinfo.sc_nfsnum,
414 423 cursec[c].s_refcnt);
415 424
416 425 ASSERT(cursec[c].s_refcnt >= 0);
417 426
418 427 if (SEC_REF_INVALID(&cursec[c]))
419 428 tcnt--;
420 429 break;
421 430 }
422 431 }
423 432 }
424 433
425 434 ASSERT(tcnt >= 0);
426 435 if (tcnt == ccnt)
427 436 return; /* no change; no flavors to remove */
428 437
429 438 if (tcnt == 0) {
430 439 srv_secinfo_list_free(cursec, ccnt);
431 440 *pcurcnt = 0;
432 441 *pcursec = NULL;
433 442 return;
434 443 }
435 444
436 445 msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
437 446
438 447 /* walk thru the given secinfo list to remove the flavors */
439 448 mcnt = 0;
440 449 for (c = 0; c < ccnt; c++) {
441 450 if (SEC_REF_INVALID(&cursec[c])) {
442 451 srv_secinfo_entry_free(&cursec[c]);
443 452 } else {
444 453 msec[mcnt] = cursec[c];
445 454 mcnt++;
446 455 }
447 456 }
448 457
449 458 ASSERT(mcnt == tcnt);
450 459 /*
451 460 * Done. Update curdata.
452 461 * Free the existing secinfo list in curdata. All pointers
453 462 * within the list have either been moved to msec or freed
454 463 * if it's invalid.
455 464 */
456 465 kmem_free(*pcursec, ccnt * sizeof (struct secinfo));
457 466 *pcursec = msec;
458 467 *pcurcnt = tcnt;
459 468 }
460 469
461 470
462 471 /*
463 472 * For the reshare case, sec flavor accounting happens in 3 steps:
464 473 * 1) propagate addition of new flavor refs up the ancestor tree
465 474 * 2) transfer flavor refs of descendants to new/reshared exportdata
466 475 * 3) propagate removal of old flavor refs up the ancestor tree
467 476 *
468 477 * srv_secinfo_exp2exp() implements step 2 of a reshare. At this point,
469 478 * the new flavor list has already been propagated up through the
470 479 * ancestor tree via srv_secinfo_treeclimb().
471 480 *
472 481 * If there is more than 1 export reference to an old flavor (i.e. some
473 482 * of its children shared with this flavor), this flavor information
474 483 * needs to be transferred to the new exportdata struct. A flavor in
475 484 * the old exportdata has descendant refs when its s_refcnt > 1 or it
476 485 * is implicitly shared (M_SEC4_EXPORTED not set in s_flags).
477 486 *
478 487 * SEC_REF_EXPORTED() is only true when M_SEC4_EXPORTED is set
479 488 * SEC_REF_SELF() is only true when both M_SEC4_EXPORTED is set and s_refcnt==1
480 489 *
481 490 * Transferring descendant flavor refcnts happens in 2 passes:
482 491 * a) flavors used before (oldsecinfo) and after (curdata->ex_secinfo) reshare
483 492 * b) flavors used before but not after reshare
484 493 *
485 494 * This routine is used under the protection of exported_lock (RW_WRITER).
486 495 */
487 496 void
488 497 srv_secinfo_exp2exp(exportdata_t *curdata, secinfo_t *oldsecinfo, int ocnt)
489 498 {
490 499 int ccnt, c; /* sec count in current data - curdata */
491 500 int o; /* sec count in old data - oldsecinfo */
492 501 int tcnt, mcnt; /* total sec count after the transfer */
493 502 struct secinfo *msec; /* merged secinfo list */
494 503
495 504 ccnt = curdata->ex_seccnt;
496 505
497 506 ASSERT(ocnt > 0);
498 507 ASSERT(!(curdata->ex_flags & EX_PSEUDO));
499 508
500 509 /*
501 510 * If the oldsecinfo has flavors with more than 1 reference count
502 511 * and the flavor is specified in the reshare, transfer the flavor
503 512 * refs to the new seclist (curdata.ex_secinfo).
504 513 */
505 514 tcnt = ccnt + ocnt;
506 515
507 516 for (o = 0; o < ocnt; o++) {
508 517
509 518 if (SEC_REF_SELF(&oldsecinfo[o])) {
510 519 tcnt--;
511 520 continue;
512 521 }
513 522
514 523 for (c = 0; c < ccnt; c++) {
515 524 if (oldsecinfo[o].s_secinfo.sc_nfsnum ==
516 525 curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) {
517 526
518 527 /*
519 528 * add old reference to the current
520 529 * secinfo count
521 530 */
522 531 curdata->ex_secinfo[c].s_refcnt +=
523 532 oldsecinfo[o].s_refcnt;
524 533
525 534 /*
526 535 * Delete the old export flavor
527 536 * reference. The initial reference
528 537 * was created during srv_secinfo_add,
529 538 * and the count is decremented below
530 539 * to account for the initial reference.
531 540 */
532 541 if (SEC_REF_EXPORTED(&oldsecinfo[o]))
533 542 curdata->ex_secinfo[c].s_refcnt--;
534 543
535 544 SECREF_TRACE(curdata->ex_path,
536 545 "reshare_xfer_common_child_refs",
537 546 curdata->ex_secinfo[c].s_secinfo.sc_nfsnum,
538 547 curdata->ex_secinfo[c].s_refcnt);
539 548
540 549 ASSERT(curdata->ex_secinfo[c].s_refcnt >= 0);
541 550
542 551 tcnt--;
543 552 break;
544 553 }
545 554 }
546 555 }
547 556
548 557 if (tcnt == ccnt)
549 558 return; /* no more transfer to do */
550 559
551 560 /*
552 561 * oldsecinfo has flavors referenced by its children that are not
553 562 * in the current (new) export flavor list. Add these flavors.
554 563 */
555 564 msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
556 565
557 566 /* move current secinfo list data to the new list */
558 567 for (c = 0; c < ccnt; c++)
559 568 msec[c] = curdata->ex_secinfo[c];
560 569
561 570 /*
562 571 * Add the flavor that's not in the new export, but still
563 572 * referenced by its children.
564 573 */
565 574 mcnt = ccnt;
566 575 for (o = 0; o < ocnt; o++) {
567 576 if (! SEC_REF_SELF(&oldsecinfo[o])) {
568 577 for (c = 0; c < ccnt; c++) {
569 578 if (oldsecinfo[o].s_secinfo.sc_nfsnum ==
570 579 curdata->ex_secinfo[c].s_secinfo.sc_nfsnum)
571 580 break;
572 581 }
573 582
574 583 /*
575 584 * This is the one. Add it. Decrement the ref count
576 585 * by 1 if the flavor is an explicitly shared flavor
577 586 * for the oldsecinfo export node.
578 587 */
579 588 if (c == ccnt) {
580 589 srv_secinfo_copy(&oldsecinfo[o], &msec[mcnt]);
581 590 if (SEC_REF_EXPORTED(&oldsecinfo[o]))
582 591 msec[mcnt].s_refcnt--;
583 592
584 593 SECREF_TRACE(curdata,
585 594 "reshare_xfer_implicit_child_refs",
586 595 msec[mcnt].s_secinfo.sc_nfsnum,
587 596 msec[mcnt].s_refcnt);
588 597
589 598 ASSERT(msec[mcnt].s_refcnt >= 0);
590 599 mcnt++;
591 600 }
592 601 }
593 602 }
594 603
595 604 ASSERT(mcnt == tcnt);
596 605 /*
597 606 * Done. Update curdata, free the existing secinfo list in
598 607 * curdata and set the new value.
599 608 */
600 609 if (ccnt > 0)
601 610 kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo));
602 611 curdata->ex_seccnt = tcnt;
603 612 curdata->ex_secinfo = msec;
604 613 }
605 614
606 615 /*
607 616 * When unsharing an old export node and the old node becomes a pseudo node,
608 617 * if there is more than 1 export reference to an old flavor (i.e. some of
609 618 * its children shared with this flavor), this flavor information needs to
610 619 * be transferred to the new shared node.
611 620 *
612 621 * This routine is used under the protection of exported_lock (RW_WRITER).
613 622 */
614 623 void
615 624 srv_secinfo_exp2pseu(exportdata_t *curdata, exportdata_t *olddata)
616 625 {
617 626 int ocnt, o; /* sec count in transfer data - trandata */
618 627 int tcnt, mcnt; /* total sec count after transfer */
619 628 struct secinfo *msec; /* merged secinfo list */
620 629
621 630 ASSERT(curdata->ex_flags & EX_PSEUDO);
622 631 ASSERT(curdata->ex_seccnt == 0);
623 632
624 633 ocnt = olddata->ex_seccnt;
625 634
626 635 /*
627 636 * If the olddata has flavors with more than 1 reference count,
628 637 * transfer the information to the curdata.
629 638 */
630 639 tcnt = ocnt;
631 640
632 641 for (o = 0; o < ocnt; o++) {
633 642 if (SEC_REF_SELF(&olddata->ex_secinfo[o]))
634 643 tcnt--;
635 644 }
636 645
637 646 if (tcnt == 0)
638 647 return; /* no transfer to do */
639 648
640 649 msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
641 650
642 651 mcnt = 0;
643 652 for (o = 0; o < ocnt; o++) {
644 653 if (! SEC_REF_SELF(&olddata->ex_secinfo[o])) {
645 654
646 655 /*
647 656 * Decrement the reference count by 1 if the flavor is
648 657 * an explicitly shared flavor for the olddata export
649 658 * node.
650 659 */
651 660 srv_secinfo_copy(&olddata->ex_secinfo[o], &msec[mcnt]);
652 661 msec[mcnt].s_flags = M_RO;
653 662 if (SEC_REF_EXPORTED(&olddata->ex_secinfo[o]))
654 663 msec[mcnt].s_refcnt--;
655 664
656 665 SECREF_TRACE(curdata, "unshare_morph_pseudo",
657 666 msec[mcnt].s_secinfo.sc_nfsnum,
658 667 msec[mcnt].s_refcnt);
659 668
660 669 ASSERT(msec[mcnt].s_refcnt >= 0);
661 670 mcnt++;
662 671 }
663 672 }
664 673
665 674 ASSERT(mcnt == tcnt);
666 675 /*
667 676 * Done. Update curdata.
668 677 * Free up the existing secinfo list in curdata and
669 678 * set the new value.
670 679 */
671 680 curdata->ex_seccnt = tcnt;
672 681 curdata->ex_secinfo = msec;
673 682 }
674 683
675 684 /*
676 685 * Find for given treenode the exportinfo which has its
677 686 * exp_visible linked on its exi_visible list.
678 687 *
679 688 * Note: We could add new pointer either to treenode or
680 689 * to exp_visible, which will point there directly.
681 690 * This would buy some speed for some memory.
682 691 */
683 692 exportinfo_t *
684 693 vis2exi(treenode_t *tnode)
685 694 {
|
↓ open down ↓ |
556 lines elided |
↑ open up ↑ |
686 695 exportinfo_t *exi_ret = NULL;
687 696
688 697 for (;;) {
689 698 tnode = tnode->tree_parent;
690 699 if (TREE_ROOT(tnode)) {
691 700 exi_ret = tnode->tree_exi;
692 701 break;
693 702 }
694 703 }
695 704
696 - ASSERT(exi_ret); /* Every visible should have its home exportinfo */
705 + /* Every visible should have its home exportinfo */
706 + ASSERT(exi_ret != NULL);
697 707 return (exi_ret);
698 708 }
699 709
700 710 /*
701 711 * For NFS V4.
702 712 * Add or remove the newly exported or unexported security flavors of the
703 713 * given exportinfo from its ancestors upto the system root.
704 714 */
705 -void
706 -srv_secinfo_treeclimb(exportinfo_t *exip, secinfo_t *sec, int seccnt,
707 - bool_t isadd)
715 +static void
716 +srv_secinfo_treeclimb(nfs_export_t *ne, exportinfo_t *exip, secinfo_t *sec,
717 + int seccnt, bool_t isadd)
708 718 {
709 - treenode_t *tnode = exip->exi_tree;
719 + treenode_t *tnode;
710 720
711 - ASSERT(RW_WRITE_HELD(&exported_lock));
712 - ASSERT(tnode != NULL);
721 + ASSERT(RW_WRITE_HELD(&ne->exported_lock));
713 722
723 + /*
724 + * exi_tree can be null for the zone root
725 + * which means we're already at the "top"
726 + * and there's nothing more to "climb".
727 + */
728 + tnode = exip->exi_tree;
729 + if (tnode == NULL) {
730 + /* Should only happen for... */
731 + ASSERT(exip == ne->exi_root);
732 + return;
733 + }
734 +
714 735 if (seccnt == 0)
715 736 return;
716 737
717 738 /*
718 739 * If flavors are being added and the new export root isn't
719 740 * also VROOT, its implicitly allowed flavors are inherited from
720 741 * its pseudonode.
721 742 * Note - for VROOT exports the implicitly allowed flavors were
722 743 * transferred from the PSEUDO export in exportfs()
723 744 */
724 745 if (isadd && !(exip->exi_vp->v_flag & VROOT) &&
746 + !VN_CMP(exip->exi_vp, EXI_TO_ZONEROOTVP(exip)) &&
725 747 tnode->tree_vis->vis_seccnt > 0) {
726 748 srv_secinfo_add(&exip->exi_export.ex_secinfo,
727 749 &exip->exi_export.ex_seccnt, tnode->tree_vis->vis_secinfo,
728 750 tnode->tree_vis->vis_seccnt, FALSE);
729 751 }
730 752
731 753 /*
732 754 * Move to parent node and propagate sec flavor
733 755 * to exportinfo and to visible structures.
734 756 */
735 757 tnode = tnode->tree_parent;
736 758
737 759 while (tnode != NULL) {
738 760
739 761 /* If there is exportinfo, update it */
740 762 if (tnode->tree_exi != NULL) {
741 763 secinfo_t **pxsec =
742 764 &tnode->tree_exi->exi_export.ex_secinfo;
743 765 int *pxcnt = &tnode->tree_exi->exi_export.ex_seccnt;
744 766 int is_pseudo = PSEUDO(tnode->tree_exi);
745 767 if (isadd)
746 768 srv_secinfo_add(pxsec, pxcnt, sec, seccnt,
747 769 is_pseudo);
748 770 else
749 771 srv_secinfo_remove(pxsec, pxcnt, sec, seccnt);
750 772 }
751 773
752 774 /* Update every visible - only root node has no visible */
753 775 if (tnode->tree_vis != NULL) {
754 776 secinfo_t **pxsec = &tnode->tree_vis->vis_secinfo;
755 777 int *pxcnt = &tnode->tree_vis->vis_seccnt;
756 778 if (isadd)
757 779 srv_secinfo_add(pxsec, pxcnt, sec, seccnt,
758 780 FALSE);
759 781 else
760 782 srv_secinfo_remove(pxsec, pxcnt, sec, seccnt);
761 783 }
762 784 tnode = tnode->tree_parent;
763 785 }
764 786 }
765 787
766 788 /* hash_name is a text substitution for either fid_hash or path_hash */
767 789 #define exp_hash_unlink(exi, hash_name) \
768 790 if (*(exi)->hash_name.bckt == (exi)) \
769 791 *(exi)->hash_name.bckt = (exi)->hash_name.next; \
770 792 if ((exi)->hash_name.prev) \
771 793 (exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \
772 794 if ((exi)->hash_name.next) \
773 795 (exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \
774 796 (exi)->hash_name.bckt = NULL;
|
↓ open down ↓ |
40 lines elided |
↑ open up ↑ |
775 797
776 798 #define exp_hash_link(exi, hash_name, bucket) \
777 799 (exi)->hash_name.bckt = (bucket); \
778 800 (exi)->hash_name.prev = NULL; \
779 801 (exi)->hash_name.next = *(bucket); \
780 802 if ((exi)->hash_name.next) \
781 803 (exi)->hash_name.next->hash_name.prev = (exi); \
782 804 *(bucket) = (exi);
783 805
784 806 void
785 -export_link(exportinfo_t *exi)
807 +export_link(nfs_export_t *ne, exportinfo_t *exi)
786 808 {
787 809 exportinfo_t **bckt;
788 810
789 - bckt = &exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
811 + ASSERT(RW_WRITE_HELD(&ne->exported_lock));
812 +
813 + bckt = &ne->exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
790 814 exp_hash_link(exi, fid_hash, bckt);
791 815
792 - bckt = &exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
816 + bckt = &ne->exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
793 817 strlen(exi->exi_export.ex_path))];
794 818 exp_hash_link(exi, path_hash, bckt);
819 + exi->exi_ne = ne;
795 820 }
796 821
797 822 /*
798 - * Initialization routine for export routines. Should only be called once.
823 + * Helper functions for exi_id handling
799 824 */
825 +static int
826 +exi_id_compar(const void *v1, const void *v2)
827 +{
828 + const struct exportinfo *e1 = v1;
829 + const struct exportinfo *e2 = v2;
830 +
831 + if (e1->exi_id < e2->exi_id)
832 + return (-1);
833 + if (e1->exi_id > e2->exi_id)
834 + return (1);
835 +
836 + return (0);
837 +}
838 +
800 839 int
801 -nfs_exportinit(void)
840 +exi_id_get_next()
802 841 {
803 - int error;
842 + struct exportinfo e;
843 + int ret = exi_id_next;
844 +
845 + ASSERT(MUTEX_HELD(&nfs_exi_id_lock));
846 +
847 + do {
848 + exi_id_next++;
849 + if (exi_id_next == 0)
850 + exi_id_overflow = TRUE;
851 +
852 + if (!exi_id_overflow)
853 + break;
854 +
855 + if (exi_id_next == ret)
856 + cmn_err(CE_PANIC, "exi_id exhausted");
857 +
858 + e.exi_id = exi_id_next;
859 + } while (avl_find(&exi_id_tree, &e, NULL) != NULL);
860 +
861 + return (ret);
862 +}
863 +
864 +/*
865 + * Get the root file handle for this zone.
866 + * Called when nfs_svc() starts
867 + */
868 +int
869 +nfs_export_get_rootfh(nfs_globals_t *g)
870 +{
871 + nfs_export_t *ne = g->nfs_export;
872 + int err;
873 +
874 + ne->exi_rootfid.fid_len = MAXFIDSZ;
875 + err = vop_fid_pseudo(ne->exi_root->exi_vp, &ne->exi_rootfid);
876 + if (err != 0) {
877 + ne->exi_rootfid.fid_len = 0;
878 + return (err);
879 + }
880 +
881 + /* Setup the fhandle template exi_fh */
882 + ne->exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
883 + ne->exi_root->exi_fh.fh_xlen = ne->exi_rootfid.fid_len;
884 + bcopy(ne->exi_rootfid.fid_data, ne->exi_root->exi_fh.fh_xdata,
885 + ne->exi_rootfid.fid_len);
886 + ne->exi_root->exi_fh.fh_len = sizeof (ne->exi_root->exi_fh.fh_data);
887 +
888 + return (0);
889 +}
890 +
891 +void
892 +nfs_export_zone_init(nfs_globals_t *ng)
893 +{
804 894 int i;
895 + nfs_export_t *ne;
896 + zone_t *zone;
805 897
806 - rw_init(&exported_lock, NULL, RW_DEFAULT, NULL);
898 + ne = kmem_zalloc(sizeof (*ne), KM_SLEEP);
807 899
900 + rw_init(&ne->exported_lock, NULL, RW_DEFAULT, NULL);
901 +
902 + ne->ne_globals = ng; /* "up" pointer */
903 +
808 904 /*
809 905 * Allocate the place holder for the public file handle, which
810 906 * is all zeroes. It is initially set to the root filesystem.
811 907 */
812 - exi_root = kmem_zalloc(sizeof (*exi_root), KM_SLEEP);
813 - exi_public = exi_root;
908 + ne->exi_root = kmem_zalloc(sizeof (*ne->exi_root), KM_SLEEP);
909 + ne->exi_public = ne->exi_root;
814 910
815 - exi_root->exi_export.ex_flags = EX_PUBLIC;
816 - exi_root->exi_export.ex_pathlen = 1; /* length of "/" */
817 - exi_root->exi_export.ex_path =
818 - kmem_alloc(exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
819 - exi_root->exi_export.ex_path[0] = '/';
820 - exi_root->exi_export.ex_path[1] = '\0';
911 + ne->exi_root->exi_export.ex_flags = EX_PUBLIC;
912 + ne->exi_root->exi_export.ex_pathlen = 1; /* length of "/" */
913 + ne->exi_root->exi_export.ex_path =
914 + kmem_alloc(ne->exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
915 + ne->exi_root->exi_export.ex_path[0] = '/';
916 + ne->exi_root->exi_export.ex_path[1] = '\0';
821 917
822 - exi_root->exi_count = 1;
823 - mutex_init(&exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
918 + ne->exi_root->exi_count = 1;
919 + mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
824 920
825 - exi_root->exi_vp = rootdir;
826 - exi_rootfid.fid_len = MAXFIDSZ;
827 - error = vop_fid_pseudo(exi_root->exi_vp, &exi_rootfid);
828 - if (error) {
829 - mutex_destroy(&exi_root->exi_lock);
830 - kmem_free(exi_root, sizeof (*exi_root));
831 - return (error);
832 - }
921 + /*
922 + * Because we cannot:
923 + * ASSERT(curzone->zone_id == ng->nfs_zoneid);
924 + * We grab the zone pointer explicitly (like netstacks do) and
925 + * set the rootvp here.
926 + *
927 + * Subsequent exportinfo_t's that get export_link()ed to "ne" also
928 + * will backpoint to "ne" such that exi->exi_ne->exi_root->exi_vp
929 + * will get the zone's rootvp for a given exportinfo_t.
930 + */
931 + zone = zone_find_by_id_nolock(ng->nfs_zoneid);
932 + ne->exi_root->exi_vp = zone->zone_rootvp;
933 + ne->exi_root->exi_zoneid = ng->nfs_zoneid;
833 934
834 935 /*
835 - * Initialize auth cache and auth cache lock
936 + * Fill in ne->exi_rootfid later, in nfs_export_get_rootfid
937 + * because we can't correctly return errors here.
836 938 */
939 +
940 + /* Initialize auth cache and auth cache lock */
837 941 for (i = 0; i < AUTH_TABLESIZE; i++) {
838 - exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
942 + ne->exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
839 943 KM_SLEEP);
840 - avl_create(exi_root->exi_cache[i], nfsauth_cache_clnt_compar,
841 - sizeof (struct auth_cache_clnt),
944 + avl_create(ne->exi_root->exi_cache[i],
945 + nfsauth_cache_clnt_compar, sizeof (struct auth_cache_clnt),
842 946 offsetof(struct auth_cache_clnt, authc_link));
843 947 }
844 - rw_init(&exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
948 + rw_init(&ne->exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
845 949
846 - /* setup the fhandle template */
847 - exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
848 - exi_root->exi_fh.fh_xlen = exi_rootfid.fid_len;
849 - bcopy(exi_rootfid.fid_data, exi_root->exi_fh.fh_xdata,
850 - exi_rootfid.fid_len);
851 - exi_root->exi_fh.fh_len = sizeof (exi_root->exi_fh.fh_data);
950 + /* setup exi_fh later, in nfs_export_get_rootfid */
852 951
853 - /*
854 - * Publish the exportinfo in the hash table
855 - */
856 - export_link(exi_root);
952 + rw_enter(&ne->exported_lock, RW_WRITER);
857 953
858 - nfslog_init();
859 - ns_root = NULL;
954 + /* Publish the exportinfo in the hash table */
955 + export_link(ne, ne->exi_root);
860 956
861 - return (0);
957 + /* Initialize exi_id and exi_kstats */
958 + mutex_enter(&nfs_exi_id_lock);
959 + ne->exi_root->exi_id = exi_id_get_next();
960 + avl_add(&exi_id_tree, ne->exi_root);
961 + mutex_exit(&nfs_exi_id_lock);
962 +
963 + rw_exit(&ne->exported_lock);
964 + ne->ns_root = NULL;
965 +
966 + ng->nfs_export = ne;
862 967 }
863 968
864 969 /*
865 - * Finalization routine for export routines. Called to cleanup previously
866 - * initialization work when the NFS server module could not be loaded correctly.
970 + * During zone shutdown, remove exports
867 971 */
868 972 void
869 -nfs_exportfini(void)
973 +nfs_export_zone_shutdown(nfs_globals_t *ng)
870 974 {
975 + nfs_export_t *ne = ng->nfs_export;
976 + struct exportinfo *exi, *nexi;
977 + int i, errors;
978 +
979 + rw_enter(&ne->exported_lock, RW_READER);
980 +
981 + errors = 0;
982 + for (i = 0; i < EXPTABLESIZE; i++) {
983 +
984 + exi = ne->exptable[i];
985 + if (exi != NULL)
986 + exi_hold(exi);
987 +
988 + while (exi != NULL) {
989 +
990 + /*
991 + * Get and hold next export before
992 + * dropping the rwlock and unexport
993 + */
994 + nexi = exi->fid_hash.next;
995 + if (nexi != NULL)
996 + exi_hold(nexi);
997 +
998 + rw_exit(&ne->exported_lock);
999 +
1000 + /*
1001 + * Skip ne->exi_root which gets special
1002 + * create/destroy handling.
1003 + */
1004 + if (exi != ne->exi_root &&
1005 + unexport(ne, exi) != 0)
1006 + errors++;
1007 + exi_rele(exi);
1008 +
1009 + rw_enter(&ne->exported_lock, RW_READER);
1010 + exi = nexi;
1011 + }
1012 + }
1013 + if (errors > 0) {
1014 + cmn_err(CE_NOTE, "NFS: failed un-exports in zone %d",
1015 + (int)ng->nfs_zoneid);
1016 + }
1017 +
1018 + rw_exit(&ne->exported_lock);
1019 +}
1020 +
1021 +void
1022 +nfs_export_zone_fini(nfs_globals_t *ng)
1023 +{
871 1024 int i;
1025 + nfs_export_t *ne = ng->nfs_export;
1026 + struct exportinfo *exi;
872 1027
1028 + ng->nfs_export = NULL;
1029 +
1030 + rw_enter(&ne->exported_lock, RW_WRITER);
1031 +
1032 + mutex_enter(&nfs_exi_id_lock);
1033 + avl_remove(&exi_id_tree, ne->exi_root);
1034 + mutex_exit(&nfs_exi_id_lock);
1035 +
1036 + export_unlink(ne, ne->exi_root);
1037 +
1038 + rw_exit(&ne->exported_lock);
1039 +
1040 + /* Deallocate the place holder for the public file handle */
1041 + srv_secinfo_list_free(ne->exi_root->exi_export.ex_secinfo,
1042 + ne->exi_root->exi_export.ex_seccnt);
1043 + mutex_destroy(&ne->exi_root->exi_lock);
1044 +
1045 + rw_destroy(&ne->exi_root->exi_cache_lock);
1046 + for (i = 0; i < AUTH_TABLESIZE; i++) {
1047 + avl_destroy(ne->exi_root->exi_cache[i]);
1048 + kmem_free(ne->exi_root->exi_cache[i], sizeof (avl_tree_t));
1049 + }
1050 +
1051 + kmem_free(ne->exi_root->exi_export.ex_path,
1052 + ne->exi_root->exi_export.ex_pathlen + 1);
1053 + kmem_free(ne->exi_root, sizeof (*ne->exi_root));
1054 +
873 1055 /*
874 - * Deallocate the place holder for the public file handle.
1056 + * The shutdown hook should have left the exi_id_tree
1057 + * with nothing belonging to this zone.
875 1058 */
876 - srv_secinfo_list_free(exi_root->exi_export.ex_secinfo,
877 - exi_root->exi_export.ex_seccnt);
878 - mutex_destroy(&exi_root->exi_lock);
879 - rw_destroy(&exi_root->exi_cache_lock);
880 - for (i = 0; i < AUTH_TABLESIZE; i++) {
881 - avl_destroy(exi_root->exi_cache[i]);
882 - kmem_free(exi_root->exi_cache[i], sizeof (avl_tree_t));
1059 + mutex_enter(&nfs_exi_id_lock);
1060 + i = 0;
1061 + exi = avl_first(&exi_id_tree);
1062 + while (exi != NULL) {
1063 + if (exi->exi_zoneid == ng->nfs_zoneid)
1064 + i++;
1065 + exi = AVL_NEXT(&exi_id_tree, exi);
883 1066 }
884 - kmem_free(exi_root, sizeof (*exi_root));
1067 + mutex_exit(&nfs_exi_id_lock);
1068 + if (i > 0) {
1069 + cmn_err(CE_NOTE,
1070 + "NFS: zone %d has %d export IDs left after shutdown",
1071 + (int)ng->nfs_zoneid, i);
1072 + }
1073 + rw_destroy(&ne->exported_lock);
1074 + kmem_free(ne, sizeof (*ne));
1075 +}
885 1076
886 - rw_destroy(&exported_lock);
1077 +/*
1078 + * Initialization routine for export routines.
1079 + * Should only be called once.
1080 + */
1081 +void
1082 +nfs_exportinit(void)
1083 +{
1084 + mutex_init(&nfs_exi_id_lock, NULL, MUTEX_DEFAULT, NULL);
1085 +
1086 + /* exi_id handling initialization */
1087 + exi_id_next = 0;
1088 + exi_id_overflow = FALSE;
1089 + avl_create(&exi_id_tree, exi_id_compar, sizeof (struct exportinfo),
1090 + offsetof(struct exportinfo, exi_id_link));
1091 +
1092 + nfslog_init();
887 1093 }
888 1094
889 1095 /*
1096 + * Finalization routine for export routines.
1097 + */
1098 +void
1099 +nfs_exportfini(void)
1100 +{
1101 + avl_destroy(&exi_id_tree);
1102 + mutex_destroy(&nfs_exi_id_lock);
1103 +}
1104 +
1105 +/*
890 1106 * Check if 2 gss mechanism identifiers are the same.
891 1107 *
892 1108 * return FALSE if not the same.
893 1109 * return TRUE if the same.
894 1110 */
895 1111 static bool_t
896 1112 nfs_mech_equal(rpc_gss_OID mech1, rpc_gss_OID mech2)
897 1113 {
898 1114 if ((mech1->length == 0) && (mech2->length == 0))
899 1115 return (TRUE);
900 1116
901 1117 if (mech1->length != mech2->length)
902 1118 return (FALSE);
903 1119
904 1120 return (bcmp(mech1->elements, mech2->elements, mech1->length) == 0);
905 1121 }
906 1122
907 1123 /*
908 1124 * This routine is used by rpc to map rpc security number
909 1125 * to nfs specific security flavor number.
910 1126 *
911 1127 * The gss callback prototype is
912 1128 * callback(struct svc_req *, gss_cred_id_t *, gss_ctx_id_t *,
913 1129 * rpc_gss_lock_t *, void **),
914 1130 * since nfs does not use the gss_cred_id_t/gss_ctx_id_t arguments
|
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
915 1131 * we cast them to void.
916 1132 */
917 1133 /*ARGSUSED*/
918 1134 bool_t
919 1135 rfs_gsscallback(struct svc_req *req, gss_cred_id_t deleg, void *gss_context,
920 1136 rpc_gss_lock_t *lock, void **cookie)
921 1137 {
922 1138 int i, j;
923 1139 rpc_gss_rawcred_t *raw_cred;
924 1140 struct exportinfo *exi;
1141 + nfs_export_t *ne = nfs_get_export();
925 1142
926 1143 /*
927 1144 * We don't deal with delegated credentials.
928 1145 */
929 1146 if (deleg != GSS_C_NO_CREDENTIAL)
930 1147 return (FALSE);
931 1148
932 1149 raw_cred = lock->raw_cred;
933 1150 *cookie = NULL;
934 1151
935 - rw_enter(&exported_lock, RW_READER);
1152 + rw_enter(&ne->exported_lock, RW_READER);
1153 +
936 1154 for (i = 0; i < EXPTABLESIZE; i++) {
937 - exi = exptable[i];
1155 + exi = ne->exptable[i];
938 1156 while (exi) {
939 1157 if (exi->exi_export.ex_seccnt > 0) {
940 1158 struct secinfo *secp;
941 1159 seconfig_t *se;
942 1160 int seccnt;
943 1161
944 1162 secp = exi->exi_export.ex_secinfo;
945 1163 seccnt = exi->exi_export.ex_seccnt;
946 1164 for (j = 0; j < seccnt; j++) {
947 1165 /*
948 1166 * If there is a map of the triplet
949 1167 * (mechanism, service, qop) between
950 1168 * raw_cred and the exported flavor,
951 1169 * get the psudo flavor number.
952 1170 * Also qop should not be NULL, it
953 1171 * should be "default" or something
954 1172 * else.
955 1173 */
956 1174 se = &secp[j].s_secinfo;
957 1175 if ((se->sc_rpcnum == RPCSEC_GSS) &&
958 1176
959 1177 (nfs_mech_equal(
960 1178 se->sc_gss_mech_type,
961 1179 raw_cred->mechanism)) &&
962 1180
963 1181 (se->sc_service ==
964 1182 raw_cred->service) &&
965 1183 (raw_cred->qop == se->sc_qop)) {
966 1184
|
↓ open down ↓ |
19 lines elided |
↑ open up ↑ |
967 1185 *cookie = (void *)(uintptr_t)
968 1186 se->sc_nfsnum;
969 1187 goto done;
970 1188 }
971 1189 }
972 1190 }
973 1191 exi = exi->fid_hash.next;
974 1192 }
975 1193 }
976 1194 done:
977 - rw_exit(&exported_lock);
1195 + rw_exit(&ne->exported_lock);
978 1196
979 1197 /*
980 1198 * If no nfs pseudo number mapping can be found in the export
981 1199 * table, assign the nfsflavor to NFS_FLAVOR_NOMAP. In V4, we may
982 1200 * recover the flavor mismatch from NFS layer (NFS4ERR_WRONGSEC).
983 1201 *
984 1202 * For example:
985 1203 * server first shares with krb5i;
986 1204 * client mounts with krb5i;
987 1205 * server re-shares with krb5p;
988 1206 * client tries with krb5i, but no mapping can be found;
989 1207 * rpcsec_gss module calls this routine to do the mapping,
990 1208 * if this routine fails, request is rejected from
991 1209 * the rpc layer.
992 1210 * What we need is to let the nfs layer rejects the request.
993 1211 * For V4, we can reject with NFS4ERR_WRONGSEC and the client
994 1212 * may recover from it by getting the new flavor via SECINFO.
995 1213 *
996 1214 * nfs pseudo number for RPCSEC_GSS mapping (see nfssec.conf)
997 1215 * is owned by IANA (see RFC 2623).
998 1216 *
999 1217 * XXX NFS_FLAVOR_NOMAP is defined in Solaris to work around
1000 1218 * the implementation issue. This number should not overlap with
1001 1219 * any new IANA defined pseudo flavor numbers.
1002 1220 */
1003 1221 if (*cookie == NULL)
1004 1222 *cookie = (void *)NFS_FLAVOR_NOMAP;
1005 1223
1006 1224 lock->locked = TRUE;
1007 1225
1008 1226 return (TRUE);
1009 1227 }
1010 1228
1011 1229
1012 1230 /*
1013 1231 * Exportfs system call; credentials should be checked before
1014 1232 * calling this function.
1015 1233 */
1016 1234 int
1017 1235 exportfs(struct exportfs_args *args, model_t model, cred_t *cr)
1018 1236 {
1019 1237 vnode_t *vp;
1020 1238 vnode_t *dvp;
1021 1239 struct exportdata *kex;
1022 1240 struct exportinfo *exi = NULL;
1023 1241 struct exportinfo *ex, *ex1, *ex2;
1024 1242 fid_t fid;
1025 1243 fsid_t fsid;
1026 1244 int error;
1027 1245 size_t allocsize;
1028 1246 struct secinfo *sp;
1029 1247 struct secinfo *exs;
1030 1248 rpc_gss_callback_t cb;
1031 1249 char *pathbuf;
1032 1250 char *log_buffer;
1033 1251 char *tagbuf;
|
↓ open down ↓ |
46 lines elided |
↑ open up ↑ |
1034 1252 int callback;
1035 1253 int allocd_seccnt;
1036 1254 STRUCT_HANDLE(exportfs_args, uap);
1037 1255 STRUCT_DECL(exportdata, uexi);
1038 1256 struct secinfo newsec[MAX_FLAVORS];
1039 1257 int newcnt;
1040 1258 struct secinfo oldsec[MAX_FLAVORS];
1041 1259 int oldcnt;
1042 1260 int i;
1043 1261 struct pathname lookpn;
1262 + nfs_export_t *ne = nfs_get_export();
1044 1263
1045 1264 STRUCT_SET_HANDLE(uap, model, args);
1046 1265
1047 1266 /* Read in pathname from userspace */
1048 1267 if (error = pn_get(STRUCT_FGETP(uap, dname), UIO_USERSPACE, &lookpn))
1049 1268 return (error);
1050 1269
1051 1270 /* Walk the export list looking for that pathname */
1052 - rw_enter(&exported_lock, RW_READER);
1271 + rw_enter(&ne->exported_lock, RW_READER);
1053 1272 DTRACE_PROBE(nfss__i__exported_lock1_start);
1054 - for (ex1 = exptable_path_hash[pkp_tab_hash(lookpn.pn_path,
1273 + for (ex1 = ne->exptable_path_hash[pkp_tab_hash(lookpn.pn_path,
1055 1274 strlen(lookpn.pn_path))]; ex1; ex1 = ex1->path_hash.next) {
1056 - if (ex1 != exi_root && 0 ==
1275 + if (ex1 != ne->exi_root && 0 ==
1057 1276 strcmp(ex1->exi_export.ex_path, lookpn.pn_path)) {
1058 1277 exi_hold(ex1);
1059 1278 break;
1060 1279 }
1061 1280 }
1062 1281 DTRACE_PROBE(nfss__i__exported_lock1_stop);
1063 - rw_exit(&exported_lock);
1282 + rw_exit(&ne->exported_lock);
1064 1283
1065 1284 /* Is this an unshare? */
1066 1285 if (STRUCT_FGETP(uap, uex) == NULL) {
1067 1286 pn_free(&lookpn);
1068 1287 if (ex1 == NULL)
1069 1288 return (EINVAL);
1070 - error = unexport(ex1);
1289 + error = unexport(ne, ex1);
1071 1290 exi_rele(ex1);
1072 1291 return (error);
1073 1292 }
1074 1293
1075 1294 /* It is a share or a re-share */
1076 1295 error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1077 1296 FOLLOW, &dvp, &vp);
1078 1297 if (error == EINVAL) {
1079 1298 /*
1080 1299 * if fname resolves to / we get EINVAL error
1081 1300 * since we wanted the parent vnode. Try again
1082 1301 * with NULL dvp.
1083 1302 */
1084 1303 error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1085 1304 FOLLOW, NULL, &vp);
1086 1305 dvp = NULL;
1087 1306 }
1088 1307 if (!error && vp == NULL) {
1089 1308 /* Last component of fname not found */
1090 1309 if (dvp != NULL)
1091 1310 VN_RELE(dvp);
1092 1311 error = ENOENT;
1093 1312 }
1094 1313 if (error) {
1095 1314 pn_free(&lookpn);
1096 1315 if (ex1)
1097 1316 exi_rele(ex1);
1098 1317 return (error);
1099 1318 }
1100 1319
1101 1320 /*
1102 1321 * 'vp' may be an AUTOFS node, so we perform a
1103 1322 * VOP_ACCESS() to trigger the mount of the
1104 1323 * intended filesystem, so we can share the intended
1105 1324 * filesystem instead of the AUTOFS filesystem.
1106 1325 */
1107 1326 (void) VOP_ACCESS(vp, 0, 0, cr, NULL);
1108 1327
1109 1328 /*
1110 1329 * We're interested in the top most filesystem.
1111 1330 * This is specially important when uap->dname is a trigger
1112 1331 * AUTOFS node, since we're really interested in sharing the
1113 1332 * filesystem AUTOFS mounted as result of the VOP_ACCESS()
1114 1333 * call not the AUTOFS node itself.
1115 1334 */
1116 1335 if (vn_mountedvfs(vp) != NULL) {
1117 1336 if (error = traverse(&vp)) {
1118 1337 VN_RELE(vp);
1119 1338 if (dvp != NULL)
1120 1339 VN_RELE(dvp);
1121 1340 pn_free(&lookpn);
1122 1341 if (ex1)
1123 1342 exi_rele(ex1);
1124 1343 return (error);
1125 1344 }
1126 1345 }
1127 1346
1128 1347 /* Do not allow sharing another vnode for already shared path */
1129 1348 if (ex1 && !PSEUDO(ex1) && !VN_CMP(ex1->exi_vp, vp)) {
1130 1349 VN_RELE(vp);
1131 1350 if (dvp != NULL)
1132 1351 VN_RELE(dvp);
1133 1352 pn_free(&lookpn);
1134 1353 exi_rele(ex1);
1135 1354 return (EEXIST);
1136 1355 }
1137 1356 if (ex1)
1138 1357 exi_rele(ex1);
1139 1358
1140 1359 /*
1141 1360 * Get the vfs id
1142 1361 */
1143 1362 bzero(&fid, sizeof (fid));
1144 1363 fid.fid_len = MAXFIDSZ;
1145 1364 error = VOP_FID(vp, &fid, NULL);
1146 1365 fsid = vp->v_vfsp->vfs_fsid;
1147 1366
1148 1367 if (error) {
1149 1368 VN_RELE(vp);
1150 1369 if (dvp != NULL)
1151 1370 VN_RELE(dvp);
1152 1371 /*
1153 1372 * If VOP_FID returns ENOSPC then the fid supplied
1154 1373 * is too small. For now we simply return EREMOTE.
1155 1374 */
|
↓ open down ↓ |
75 lines elided |
↑ open up ↑ |
1156 1375 if (error == ENOSPC)
1157 1376 error = EREMOTE;
1158 1377 pn_free(&lookpn);
1159 1378 return (error);
1160 1379 }
1161 1380
1162 1381 /*
1163 1382 * Do not allow re-sharing a shared vnode under a different path
1164 1383 * PSEUDO export has ex_path fabricated, e.g. "/tmp (pseudo)", skip it.
1165 1384 */
1166 - rw_enter(&exported_lock, RW_READER);
1385 + rw_enter(&ne->exported_lock, RW_READER);
1167 1386 DTRACE_PROBE(nfss__i__exported_lock2_start);
1168 - for (ex2 = exptable[exptablehash(&fsid, &fid)]; ex2;
1387 + for (ex2 = ne->exptable[exptablehash(&fsid, &fid)]; ex2;
1169 1388 ex2 = ex2->fid_hash.next) {
1170 - if (ex2 != exi_root && !PSEUDO(ex2) &&
1389 + if (ex2 != ne->exi_root && !PSEUDO(ex2) &&
1171 1390 VN_CMP(ex2->exi_vp, vp) &&
1172 1391 strcmp(ex2->exi_export.ex_path, lookpn.pn_path) != 0) {
1173 1392 DTRACE_PROBE(nfss__i__exported_lock2_stop);
1174 - rw_exit(&exported_lock);
1393 + rw_exit(&ne->exported_lock);
1175 1394 VN_RELE(vp);
1176 1395 if (dvp != NULL)
1177 1396 VN_RELE(dvp);
1178 1397 pn_free(&lookpn);
1179 1398 return (EEXIST);
1180 1399 }
1181 1400 }
1182 1401 DTRACE_PROBE(nfss__i__exported_lock2_stop);
1183 - rw_exit(&exported_lock);
1402 + rw_exit(&ne->exported_lock);
1184 1403 pn_free(&lookpn);
1185 1404
1186 1405 exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
1187 1406 exi->exi_fsid = fsid;
1188 1407 exi->exi_fid = fid;
1189 1408 exi->exi_vp = vp;
1190 1409 exi->exi_count = 1;
1410 + exi->exi_zoneid = crgetzoneid(cr);
1411 + ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
1191 1412 exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
1192 1413 VSW_VOLATILEDEV) ? 1 : 0;
1193 1414 mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
1194 1415 exi->exi_dvp = dvp;
1195 1416
1196 1417 /*
1197 1418 * Initialize auth cache and auth cache lock
1198 1419 */
1199 1420 for (i = 0; i < AUTH_TABLESIZE; i++) {
1200 1421 exi->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
1201 1422 avl_create(exi->exi_cache[i], nfsauth_cache_clnt_compar,
1202 1423 sizeof (struct auth_cache_clnt),
1203 1424 offsetof(struct auth_cache_clnt, authc_link));
1204 1425 }
1205 1426 rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
1206 1427
1207 1428 /*
1208 1429 * Build up the template fhandle
1209 1430 */
1210 1431 exi->exi_fh.fh_fsid = fsid;
1211 1432 if (exi->exi_fid.fid_len > sizeof (exi->exi_fh.fh_xdata)) {
1212 1433 error = EREMOTE;
1213 1434 goto out1;
1214 1435 }
1215 1436 exi->exi_fh.fh_xlen = exi->exi_fid.fid_len;
1216 1437 bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata,
1217 1438 exi->exi_fid.fid_len);
1218 1439
1219 1440 exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data);
1220 1441
1221 1442 kex = &exi->exi_export;
1222 1443
1223 1444 /*
1224 1445 * Load in everything, and do sanity checking
1225 1446 */
1226 1447 STRUCT_INIT(uexi, model);
1227 1448 if (copyin(STRUCT_FGETP(uap, uex), STRUCT_BUF(uexi),
1228 1449 STRUCT_SIZE(uexi))) {
1229 1450 error = EFAULT;
1230 1451 goto out1;
1231 1452 }
1232 1453
1233 1454 kex->ex_version = STRUCT_FGET(uexi, ex_version);
1234 1455 if (kex->ex_version != EX_CURRENT_VERSION) {
1235 1456 error = EINVAL;
1236 1457 cmn_err(CE_WARN,
1237 1458 "NFS: exportfs requires export struct version 2 - got %d\n",
1238 1459 kex->ex_version);
1239 1460 goto out1;
1240 1461 }
1241 1462
1242 1463 /*
1243 1464 * Must have at least one security entry
1244 1465 */
1245 1466 kex->ex_seccnt = STRUCT_FGET(uexi, ex_seccnt);
1246 1467 if (kex->ex_seccnt < 1) {
1247 1468 error = EINVAL;
1248 1469 goto out1;
1249 1470 }
1250 1471
1251 1472 kex->ex_path = STRUCT_FGETP(uexi, ex_path);
1252 1473 kex->ex_pathlen = STRUCT_FGET(uexi, ex_pathlen);
1253 1474 kex->ex_flags = STRUCT_FGET(uexi, ex_flags);
1254 1475 kex->ex_anon = STRUCT_FGET(uexi, ex_anon);
1255 1476 kex->ex_secinfo = STRUCT_FGETP(uexi, ex_secinfo);
1256 1477 kex->ex_index = STRUCT_FGETP(uexi, ex_index);
1257 1478 kex->ex_log_buffer = STRUCT_FGETP(uexi, ex_log_buffer);
1258 1479 kex->ex_log_bufferlen = STRUCT_FGET(uexi, ex_log_bufferlen);
1259 1480 kex->ex_tag = STRUCT_FGETP(uexi, ex_tag);
1260 1481 kex->ex_taglen = STRUCT_FGET(uexi, ex_taglen);
1261 1482
1262 1483 /*
1263 1484 * Copy the exported pathname into
1264 1485 * an appropriately sized buffer.
1265 1486 */
1266 1487 pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1267 1488 if (copyinstr(kex->ex_path, pathbuf, MAXPATHLEN, &kex->ex_pathlen)) {
1268 1489 kmem_free(pathbuf, MAXPATHLEN);
1269 1490 error = EFAULT;
1270 1491 goto out1;
1271 1492 }
1272 1493 kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP);
1273 1494 bcopy(pathbuf, kex->ex_path, kex->ex_pathlen);
1274 1495 kex->ex_path[kex->ex_pathlen] = '\0';
1275 1496 kmem_free(pathbuf, MAXPATHLEN);
1276 1497
1277 1498 /*
1278 1499 * Get the path to the logging buffer and the tag
1279 1500 */
1280 1501 if (kex->ex_flags & EX_LOG) {
1281 1502 log_buffer = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1282 1503 if (copyinstr(kex->ex_log_buffer, log_buffer, MAXPATHLEN,
1283 1504 &kex->ex_log_bufferlen)) {
1284 1505 kmem_free(log_buffer, MAXPATHLEN);
1285 1506 error = EFAULT;
1286 1507 goto out2;
1287 1508 }
1288 1509 kex->ex_log_buffer =
1289 1510 kmem_alloc(kex->ex_log_bufferlen + 1, KM_SLEEP);
1290 1511 bcopy(log_buffer, kex->ex_log_buffer, kex->ex_log_bufferlen);
1291 1512 kex->ex_log_buffer[kex->ex_log_bufferlen] = '\0';
1292 1513 kmem_free(log_buffer, MAXPATHLEN);
1293 1514
1294 1515 tagbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1295 1516 if (copyinstr(kex->ex_tag, tagbuf, MAXPATHLEN,
1296 1517 &kex->ex_taglen)) {
1297 1518 kmem_free(tagbuf, MAXPATHLEN);
1298 1519 error = EFAULT;
1299 1520 goto out3;
1300 1521 }
1301 1522 kex->ex_tag = kmem_alloc(kex->ex_taglen + 1, KM_SLEEP);
1302 1523 bcopy(tagbuf, kex->ex_tag, kex->ex_taglen);
1303 1524 kex->ex_tag[kex->ex_taglen] = '\0';
1304 1525 kmem_free(tagbuf, MAXPATHLEN);
1305 1526 }
1306 1527
1307 1528 /*
1308 1529 * Load the security information for each flavor
1309 1530 */
1310 1531 allocsize = kex->ex_seccnt * SIZEOF_STRUCT(secinfo, model);
1311 1532 sp = kmem_zalloc(allocsize, KM_SLEEP);
1312 1533 if (copyin(kex->ex_secinfo, sp, allocsize)) {
1313 1534 kmem_free(sp, allocsize);
1314 1535 error = EFAULT;
1315 1536 goto out4;
1316 1537 }
1317 1538
1318 1539 /*
1319 1540 * All of these nested structures need to be converted to
1320 1541 * the kernel native format.
1321 1542 */
1322 1543 if (model != DATAMODEL_NATIVE) {
1323 1544 size_t allocsize2;
1324 1545 struct secinfo *sp2;
1325 1546
1326 1547 allocsize2 = kex->ex_seccnt * sizeof (struct secinfo);
1327 1548 sp2 = kmem_zalloc(allocsize2, KM_SLEEP);
1328 1549
1329 1550 for (i = 0; i < kex->ex_seccnt; i++) {
1330 1551 STRUCT_HANDLE(secinfo, usi);
1331 1552
1332 1553 STRUCT_SET_HANDLE(usi, model,
1333 1554 (struct secinfo *)((caddr_t)sp +
1334 1555 (i * SIZEOF_STRUCT(secinfo, model))));
1335 1556 bcopy(STRUCT_FGET(usi, s_secinfo.sc_name),
1336 1557 sp2[i].s_secinfo.sc_name, MAX_NAME_LEN);
1337 1558 sp2[i].s_secinfo.sc_nfsnum =
1338 1559 STRUCT_FGET(usi, s_secinfo.sc_nfsnum);
1339 1560 sp2[i].s_secinfo.sc_rpcnum =
1340 1561 STRUCT_FGET(usi, s_secinfo.sc_rpcnum);
1341 1562 bcopy(STRUCT_FGET(usi, s_secinfo.sc_gss_mech),
1342 1563 sp2[i].s_secinfo.sc_gss_mech, MAX_NAME_LEN);
1343 1564 sp2[i].s_secinfo.sc_gss_mech_type =
1344 1565 STRUCT_FGETP(usi, s_secinfo.sc_gss_mech_type);
1345 1566 sp2[i].s_secinfo.sc_qop =
1346 1567 STRUCT_FGET(usi, s_secinfo.sc_qop);
1347 1568 sp2[i].s_secinfo.sc_service =
1348 1569 STRUCT_FGET(usi, s_secinfo.sc_service);
1349 1570
1350 1571 sp2[i].s_flags = STRUCT_FGET(usi, s_flags);
1351 1572 sp2[i].s_window = STRUCT_FGET(usi, s_window);
1352 1573 sp2[i].s_rootid = STRUCT_FGET(usi, s_rootid);
1353 1574 sp2[i].s_rootcnt = STRUCT_FGET(usi, s_rootcnt);
1354 1575 sp2[i].s_rootnames = STRUCT_FGETP(usi, s_rootnames);
1355 1576 }
1356 1577 kmem_free(sp, allocsize);
1357 1578 sp = sp2;
1358 1579 allocsize = allocsize2;
1359 1580 }
1360 1581
1361 1582 kex->ex_secinfo = sp;
1362 1583
1363 1584 /*
1364 1585 * And now copy rootnames for each individual secinfo.
1365 1586 */
1366 1587 callback = 0;
1367 1588 allocd_seccnt = 0;
1368 1589 while (allocd_seccnt < kex->ex_seccnt) {
1369 1590
1370 1591 exs = &sp[allocd_seccnt];
1371 1592 if (exs->s_rootcnt > 0) {
1372 1593 if (!sec_svc_loadrootnames(exs->s_secinfo.sc_rpcnum,
1373 1594 exs->s_rootcnt, &exs->s_rootnames, model)) {
1374 1595 error = EFAULT;
1375 1596 goto out5;
1376 1597 }
1377 1598 }
1378 1599
1379 1600 if (exs->s_secinfo.sc_rpcnum == RPCSEC_GSS) {
1380 1601 rpc_gss_OID mech_tmp;
1381 1602 STRUCT_DECL(rpc_gss_OID_s, umech_tmp);
1382 1603 caddr_t elements_tmp;
1383 1604
1384 1605 /* Copyin mechanism type */
1385 1606 STRUCT_INIT(umech_tmp, model);
1386 1607 mech_tmp = kmem_alloc(sizeof (*mech_tmp), KM_SLEEP);
1387 1608 if (copyin(exs->s_secinfo.sc_gss_mech_type,
1388 1609 STRUCT_BUF(umech_tmp), STRUCT_SIZE(umech_tmp))) {
1389 1610 kmem_free(mech_tmp, sizeof (*mech_tmp));
1390 1611 error = EFAULT;
1391 1612 goto out5;
1392 1613 }
1393 1614 mech_tmp->length = STRUCT_FGET(umech_tmp, length);
1394 1615 mech_tmp->elements = STRUCT_FGETP(umech_tmp, elements);
1395 1616
1396 1617 elements_tmp = kmem_alloc(mech_tmp->length, KM_SLEEP);
1397 1618 if (copyin(mech_tmp->elements, elements_tmp,
1398 1619 mech_tmp->length)) {
1399 1620 kmem_free(elements_tmp, mech_tmp->length);
1400 1621 kmem_free(mech_tmp, sizeof (*mech_tmp));
1401 1622 error = EFAULT;
1402 1623 goto out5;
1403 1624 }
1404 1625 mech_tmp->elements = elements_tmp;
1405 1626 exs->s_secinfo.sc_gss_mech_type = mech_tmp;
1406 1627 allocd_seccnt++;
1407 1628
1408 1629 callback = 1;
1409 1630 } else
1410 1631 allocd_seccnt++;
1411 1632 }
1412 1633
1413 1634 /*
1414 1635 * Init the secinfo reference count and mark these flavors
1415 1636 * explicitly exported flavors.
1416 1637 */
1417 1638 for (i = 0; i < kex->ex_seccnt; i++) {
1418 1639 kex->ex_secinfo[i].s_flags |= M_4SEC_EXPORTED;
1419 1640 kex->ex_secinfo[i].s_refcnt = 1;
1420 1641 }
1421 1642
1422 1643 /*
1423 1644 * Set up rpcsec_gss callback routine entry if any.
1424 1645 */
1425 1646 if (callback) {
1426 1647 cb.callback = rfs_gsscallback;
1427 1648 cb.program = NFS_ACL_PROGRAM;
1428 1649 for (cb.version = NFS_ACL_VERSMIN;
1429 1650 cb.version <= NFS_ACL_VERSMAX; cb.version++) {
1430 1651 (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK,
1431 1652 (void *)&cb);
1432 1653 }
1433 1654
1434 1655 cb.program = NFS_PROGRAM;
1435 1656 for (cb.version = NFS_VERSMIN;
1436 1657 cb.version <= NFS_VERSMAX; cb.version++) {
1437 1658 (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK,
1438 1659 (void *)&cb);
1439 1660 }
1440 1661 }
1441 1662
1442 1663 /*
1443 1664 * Check the index flag. Do this here to avoid holding the
1444 1665 * lock while dealing with the index option (as we do with
1445 1666 * the public option).
1446 1667 */
1447 1668 if (kex->ex_flags & EX_INDEX) {
1448 1669 if (!kex->ex_index) { /* sanity check */
1449 1670 error = EINVAL;
1450 1671 goto out5;
1451 1672 }
1452 1673 if (error = loadindex(kex))
1453 1674 goto out5;
|
↓ open down ↓ |
253 lines elided |
↑ open up ↑ |
1454 1675 }
1455 1676
1456 1677 if (kex->ex_flags & EX_LOG) {
1457 1678 if (error = nfslog_setup(exi))
1458 1679 goto out6;
1459 1680 }
1460 1681
1461 1682 /*
1462 1683 * Insert the new entry at the front of the export list
1463 1684 */
1464 - rw_enter(&exported_lock, RW_WRITER);
1685 + rw_enter(&ne->exported_lock, RW_WRITER);
1465 1686 DTRACE_PROBE(nfss__i__exported_lock3_start);
1466 1687
1467 - export_link(exi);
1688 + export_link(ne, exi);
1468 1689
1469 1690 /*
1470 1691 * Check the rest of the list for an old entry for the fs.
1471 1692 * If one is found then unlink it, wait until this is the
1472 1693 * only reference and then free it.
1473 1694 */
1474 1695 for (ex = exi->fid_hash.next; ex != NULL; ex = ex->fid_hash.next) {
1475 - if (ex != exi_root && VN_CMP(ex->exi_vp, vp)) {
1476 - export_unlink(ex);
1696 + if (ex != ne->exi_root && VN_CMP(ex->exi_vp, vp)) {
1697 + mutex_enter(&nfs_exi_id_lock);
1698 + avl_remove(&exi_id_tree, ex);
1699 + mutex_exit(&nfs_exi_id_lock);
1700 + export_unlink(ne, ex);
1477 1701 break;
1478 1702 }
1479 1703 }
1480 1704
1481 1705 /*
1482 1706 * If the public filehandle is pointing at the
1483 1707 * old entry, then point it back at the root.
1484 1708 */
1485 - if (ex != NULL && ex == exi_public)
1486 - exi_public = exi_root;
1709 + if (ex != NULL && ex == ne->exi_public)
1710 + ne->exi_public = ne->exi_root;
1487 1711
1488 1712 /*
1489 1713 * If the public flag is on, make the global exi_public
1490 1714 * point to this entry and turn off the public bit so that
1491 1715 * we can distinguish it from the place holder export.
1492 1716 */
1493 1717 if (kex->ex_flags & EX_PUBLIC) {
1494 - exi_public = exi;
1718 + ne->exi_public = exi;
1495 1719 kex->ex_flags &= ~EX_PUBLIC;
1496 1720 }
1497 1721
1498 1722 #ifdef VOLATILE_FH_TEST
1499 1723 /*
1500 1724 * Set up the volatile_id value if volatile on share.
1501 1725 * The list of volatile renamed filehandles is always destroyed,
1502 1726 * if the fs was reshared.
1503 1727 */
1504 1728 if (kex->ex_flags & EX_VOLFH)
1505 1729 exi->exi_volatile_id = gethrestime_sec();
1506 1730
1507 1731 mutex_init(&exi->exi_vol_rename_lock, NULL, MUTEX_DEFAULT, NULL);
1508 1732 #endif /* VOLATILE_FH_TEST */
1509 1733
1510 1734 /*
1511 1735 * If this is a new export, then climb up
1512 1736 * the tree and check if any pseudo exports
1513 1737 * need to be created to provide a path for
1514 1738 * NFS v4 clients.
1515 1739 */
|
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
1516 1740 if (ex == NULL) {
1517 1741 error = treeclimb_export(exi);
1518 1742 if (error)
1519 1743 goto out7;
1520 1744 } else {
1521 1745 /* If it's a re-export update namespace tree */
1522 1746 exi->exi_tree = ex->exi_tree;
1523 1747 exi->exi_tree->tree_exi = exi;
1524 1748
1525 1749 /* Update the change timestamp */
1526 - tree_update_change(exi->exi_tree, NULL);
1750 + tree_update_change(ne, exi->exi_tree, NULL);
1527 1751 }
1528 1752
1529 1753 /*
1530 1754 * build a unique flavor list from the flavors specified
1531 1755 * in the share cmd. unique means that each flavor only
1532 1756 * appears once in the secinfo list -- no duplicates allowed.
1533 1757 */
1534 1758 newcnt = build_seclist_nodups(&exi->exi_export, newsec, FALSE);
1535 1759
1536 - srv_secinfo_treeclimb(exi, newsec, newcnt, TRUE);
1760 + srv_secinfo_treeclimb(ne, exi, newsec, newcnt, TRUE);
1537 1761
1538 1762 /*
1539 1763 * If re-sharing an old export entry, update the secinfo data
1540 1764 * depending on if the old entry is a pseudo node or not.
1541 1765 */
1542 1766 if (ex != NULL) {
1543 1767 oldcnt = build_seclist_nodups(&ex->exi_export, oldsec, FALSE);
1544 1768 if (PSEUDO(ex)) {
1545 1769 /*
1546 1770 * The dir being shared is a pseudo export root (which
1547 1771 * will be transformed into a real export root). The
1548 1772 * flavor(s) of the new share were propagated to the
1549 1773 * ancestors by srv_secinfo_treeclimb() above. Now
1550 1774 * transfer the implicit flavor refs from the old
|
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
1551 1775 * pseudo exprot root to the new (real) export root.
1552 1776 */
1553 1777 srv_secinfo_add(&exi->exi_export.ex_secinfo,
1554 1778 &exi->exi_export.ex_seccnt, oldsec, oldcnt, TRUE);
1555 1779 } else {
1556 1780 /*
1557 1781 * First transfer implicit flavor refs to new export.
1558 1782 * Remove old flavor refs last.
1559 1783 */
1560 1784 srv_secinfo_exp2exp(&exi->exi_export, oldsec, oldcnt);
1561 - srv_secinfo_treeclimb(ex, oldsec, oldcnt, FALSE);
1785 + srv_secinfo_treeclimb(ne, ex, oldsec, oldcnt, FALSE);
1562 1786 }
1563 1787 }
1564 1788
1565 1789 /*
1566 1790 * If it's a re-export and the old entry has a pseudonode list,
1567 1791 * transfer it to the new export.
1568 1792 */
1569 1793 if (ex != NULL && (ex->exi_visible != NULL)) {
1570 1794 exi->exi_visible = ex->exi_visible;
1571 1795 ex->exi_visible = NULL;
1572 1796 }
1573 1797
1798 + /*
1799 + * Initialize exi_id and exi_kstats
1800 + */
1801 + if (ex != NULL) {
1802 + exi->exi_id = ex->exi_id;
1803 + } else {
1804 + mutex_enter(&nfs_exi_id_lock);
1805 + exi->exi_id = exi_id_get_next();
1806 + mutex_exit(&nfs_exi_id_lock);
1807 + }
1808 + mutex_enter(&nfs_exi_id_lock);
1809 + avl_add(&exi_id_tree, exi);
1810 + mutex_exit(&nfs_exi_id_lock);
1811 +
1574 1812 DTRACE_PROBE(nfss__i__exported_lock3_stop);
1575 - rw_exit(&exported_lock);
1813 + rw_exit(&ne->exported_lock);
1576 1814
1577 - if (exi_public == exi || kex->ex_flags & EX_LOG) {
1815 + if (ne->exi_public == exi || kex->ex_flags & EX_LOG) {
1578 1816 /*
1579 1817 * Log share operation to this buffer only.
1580 1818 */
1581 1819 nfslog_share_record(exi, cr);
1582 1820 }
1583 1821
1584 1822 if (ex != NULL)
1585 1823 exi_rele(ex);
1586 1824
1587 1825 return (0);
1588 1826
1589 1827 out7:
1590 1828 /* Unlink the new export in exptable. */
1591 - export_unlink(exi);
1829 + export_unlink(ne, exi);
1592 1830 DTRACE_PROBE(nfss__i__exported_lock3_stop);
1593 - rw_exit(&exported_lock);
1831 + rw_exit(&ne->exported_lock);
1594 1832 out6:
1595 1833 if (kex->ex_flags & EX_INDEX)
1596 1834 kmem_free(kex->ex_index, strlen(kex->ex_index) + 1);
1597 1835 out5:
1598 1836 /* free partially completed allocation */
1599 1837 while (--allocd_seccnt >= 0) {
1600 1838 exs = &kex->ex_secinfo[allocd_seccnt];
1601 1839 srv_secinfo_entry_free(exs);
1602 1840 }
1603 1841
1604 1842 if (kex->ex_secinfo) {
1605 1843 kmem_free(kex->ex_secinfo,
1606 1844 kex->ex_seccnt * sizeof (struct secinfo));
1607 1845 }
1608 1846
1609 1847 out4:
1610 1848 if ((kex->ex_flags & EX_LOG) && kex->ex_tag != NULL)
1611 1849 kmem_free(kex->ex_tag, kex->ex_taglen + 1);
1612 1850 out3:
1613 1851 if ((kex->ex_flags & EX_LOG) && kex->ex_log_buffer != NULL)
1614 1852 kmem_free(kex->ex_log_buffer, kex->ex_log_bufferlen + 1);
1615 1853 out2:
1616 1854 kmem_free(kex->ex_path, kex->ex_pathlen + 1);
1617 1855 out1:
1618 1856 VN_RELE(vp);
1619 1857 if (dvp != NULL)
1620 1858 VN_RELE(dvp);
1621 1859 mutex_destroy(&exi->exi_lock);
1622 1860 rw_destroy(&exi->exi_cache_lock);
1623 1861 for (i = 0; i < AUTH_TABLESIZE; i++) {
1624 1862 avl_destroy(exi->exi_cache[i]);
1625 1863 kmem_free(exi->exi_cache[i], sizeof (avl_tree_t));
1626 1864 }
|
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
1627 1865
1628 1866 kmem_free(exi, sizeof (*exi));
1629 1867
1630 1868 return (error);
1631 1869 }
1632 1870
1633 1871 /*
1634 1872 * Remove the exportinfo from the export list
1635 1873 */
1636 1874 void
1637 -export_unlink(struct exportinfo *exi)
1875 +export_unlink(nfs_export_t *ne, struct exportinfo *exi)
1638 1876 {
1639 - ASSERT(RW_WRITE_HELD(&exported_lock));
1877 + ASSERT(RW_WRITE_HELD(&ne->exported_lock));
1640 1878
1641 1879 exp_hash_unlink(exi, fid_hash);
1642 1880 exp_hash_unlink(exi, path_hash);
1881 + ASSERT3P(exi->exi_ne, ==, ne);
1882 + exi->exi_ne = NULL;
1643 1883 }
1644 1884
1645 1885 /*
1646 1886 * Unexport an exported filesystem
1647 1887 */
1648 1888 static int
1649 -unexport(struct exportinfo *exi)
1889 +unexport(nfs_export_t *ne, struct exportinfo *exi)
1650 1890 {
1651 1891 struct secinfo cursec[MAX_FLAVORS];
1652 1892 int curcnt;
1653 1893
1654 - rw_enter(&exported_lock, RW_WRITER);
1894 + rw_enter(&ne->exported_lock, RW_WRITER);
1655 1895
1656 1896 /* Check if exi is still linked in the export table */
1657 1897 if (!EXP_LINKED(exi) || PSEUDO(exi)) {
1658 - rw_exit(&exported_lock);
1898 + rw_exit(&ne->exported_lock);
1659 1899 return (EINVAL);
1660 1900 }
1661 1901
1662 - export_unlink(exi);
1902 + mutex_enter(&nfs_exi_id_lock);
1903 + avl_remove(&exi_id_tree, exi);
1904 + mutex_exit(&nfs_exi_id_lock);
1905 + export_unlink(ne, exi);
1663 1906
1664 1907 /*
1665 1908 * Remove security flavors before treeclimb_unexport() is called
1666 1909 * because srv_secinfo_treeclimb needs the namespace tree
1667 1910 */
1668 1911 curcnt = build_seclist_nodups(&exi->exi_export, cursec, TRUE);
1912 + srv_secinfo_treeclimb(ne, exi, cursec, curcnt, FALSE);
1669 1913
1670 - srv_secinfo_treeclimb(exi, cursec, curcnt, FALSE);
1671 -
1672 1914 /*
1673 1915 * If there's a visible list, then need to leave
1674 1916 * a pseudo export here to retain the visible list
1675 1917 * for paths to exports below.
1676 1918 */
1677 1919 if (exi->exi_visible != NULL) {
1678 1920 struct exportinfo *newexi;
1679 1921
1680 - newexi = pseudo_exportfs(exi->exi_vp, &exi->exi_fid,
1922 + newexi = pseudo_exportfs(ne, exi->exi_vp, &exi->exi_fid,
1681 1923 exi->exi_visible, &exi->exi_export);
1682 1924 exi->exi_visible = NULL;
1683 1925
1684 1926 /* interconnect the existing treenode with the new exportinfo */
1685 1927 newexi->exi_tree = exi->exi_tree;
1686 1928 newexi->exi_tree->tree_exi = newexi;
1687 1929
1688 1930 /* Update the change timestamp */
1689 - tree_update_change(exi->exi_tree, NULL);
1931 + tree_update_change(ne, exi->exi_tree, NULL);
1690 1932 } else {
1691 - treeclimb_unexport(exi);
1933 + treeclimb_unexport(ne, exi);
1692 1934 }
1693 1935
1694 - rw_exit(&exported_lock);
1936 + rw_exit(&ne->exported_lock);
1695 1937
1696 1938 /*
1697 1939 * Need to call into the NFSv4 server and release all data
1698 1940 * held on this particular export. This is important since
1699 1941 * the v4 server may be holding file locks or vnodes under
1700 1942 * this export.
1701 1943 */
1702 - rfs4_clean_state_exi(exi);
1944 + rfs4_clean_state_exi(ne, exi);
1703 1945
1704 1946 /*
1705 1947 * Notify the lock manager that the filesystem is being
1706 1948 * unexported.
1707 1949 */
1708 1950 lm_unexport(exi);
1709 1951
1710 1952 /*
1711 1953 * If this was a public export, restore
1712 1954 * the public filehandle to the root.
1713 1955 */
1714 - if (exi == exi_public) {
1715 - exi_public = exi_root;
1716 1956
1717 - nfslog_share_record(exi_public, CRED());
1957 + /*
1958 + * XXX KEBE ASKS --> Should CRED() instead be
1959 + * exi->exi_zone->zone_kcred?
1960 + */
1961 + if (exi == ne->exi_public) {
1962 + ne->exi_public = ne->exi_root;
1963 +
1964 + nfslog_share_record(ne->exi_public, CRED());
1718 1965 }
1719 1966
1720 - if (exi->exi_export.ex_flags & EX_LOG) {
1967 + if (exi->exi_export.ex_flags & EX_LOG)
1721 1968 nfslog_unshare_record(exi, CRED());
1722 - }
1723 1969
1724 1970 exi_rele(exi);
1725 1971 return (0);
1726 1972 }
1727 1973
1728 1974 /*
1729 1975 * Get file handle system call.
1730 1976 * Takes file name and returns a file handle for it.
1731 1977 * Credentials must be verified before calling.
1732 1978 */
1733 1979 int
1734 1980 nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
1735 1981 {
1736 1982 nfs_fh3 fh;
1737 1983 char buf[NFS3_MAXFHSIZE];
1738 1984 char *logptr, logbuf[NFS3_MAXFHSIZE];
1739 1985 int l = NFS3_MAXFHSIZE;
1740 1986 vnode_t *vp;
1741 1987 vnode_t *dvp;
1742 1988 struct exportinfo *exi;
1743 1989 int error;
1744 1990 int vers;
1745 1991 STRUCT_HANDLE(nfs_getfh_args, uap);
1746 1992
1747 1993 #ifdef lint
1748 1994 model = model; /* STRUCT macros don't always use it */
1749 1995 #endif
1750 1996
1751 1997 STRUCT_SET_HANDLE(uap, model, args);
1752 1998
1753 1999 error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE,
1754 2000 FOLLOW, &dvp, &vp);
1755 2001 if (error == EINVAL) {
1756 2002 /*
1757 2003 * if fname resolves to / we get EINVAL error
1758 2004 * since we wanted the parent vnode. Try again
1759 2005 * with NULL dvp.
1760 2006 */
1761 2007 error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE,
1762 2008 FOLLOW, NULL, &vp);
1763 2009 dvp = NULL;
1764 2010 }
1765 2011 if (!error && vp == NULL) {
1766 2012 /*
1767 2013 * Last component of fname not found
1768 2014 */
1769 2015 if (dvp != NULL) {
1770 2016 VN_RELE(dvp);
1771 2017 }
1772 2018 error = ENOENT;
1773 2019 }
1774 2020 if (error)
1775 2021 return (error);
1776 2022
1777 2023 /*
1778 2024 * 'vp' may be an AUTOFS node, so we perform a
1779 2025 * VOP_ACCESS() to trigger the mount of the
1780 2026 * intended filesystem, so we can share the intended
1781 2027 * filesystem instead of the AUTOFS filesystem.
1782 2028 */
1783 2029 (void) VOP_ACCESS(vp, 0, 0, cr, NULL);
1784 2030
1785 2031 /*
1786 2032 * We're interested in the top most filesystem.
1787 2033 * This is specially important when uap->dname is a trigger
1788 2034 * AUTOFS node, since we're really interested in sharing the
1789 2035 * filesystem AUTOFS mounted as result of the VOP_ACCESS()
1790 2036 * call not the AUTOFS node itself.
1791 2037 */
1792 2038 if (vn_mountedvfs(vp) != NULL) {
1793 2039 if (error = traverse(&vp)) {
1794 2040 VN_RELE(vp);
1795 2041 if (dvp != NULL)
1796 2042 VN_RELE(dvp);
1797 2043 return (error);
1798 2044 }
1799 2045 }
1800 2046
1801 2047 vers = STRUCT_FGET(uap, vers);
1802 2048 exi = nfs_vptoexi(dvp, vp, cr, NULL, &error, FALSE);
1803 2049 if (!error) {
1804 2050 if (vers == NFS_VERSION) {
1805 2051 error = makefh((fhandle_t *)buf, vp, exi);
1806 2052 l = NFS_FHSIZE;
1807 2053 logptr = buf;
1808 2054 } else if (vers == NFS_V3) {
1809 2055 int i, sz, pad;
1810 2056
1811 2057 error = makefh3(&fh, vp, exi);
1812 2058 l = RNDUP(fh.fh3_length);
1813 2059 if (!error && (l > sizeof (fhandle3_t)))
1814 2060 error = EREMOTE;
1815 2061 logptr = logbuf;
1816 2062 if (!error) {
1817 2063 i = 0;
1818 2064 sz = sizeof (fsid_t);
1819 2065 bcopy(&fh.fh3_fsid, &buf[i], sz);
1820 2066 i += sz;
1821 2067
1822 2068 /*
1823 2069 * For backwards compatibility, the
1824 2070 * fid length may be less than
1825 2071 * NFS_FHMAXDATA, but it was always
1826 2072 * encoded as NFS_FHMAXDATA bytes.
1827 2073 */
1828 2074
1829 2075 sz = sizeof (ushort_t);
1830 2076 bcopy(&fh.fh3_len, &buf[i], sz);
1831 2077 i += sz;
1832 2078 bcopy(fh.fh3_data, &buf[i], fh.fh3_len);
1833 2079 i += fh.fh3_len;
1834 2080 pad = (NFS_FHMAXDATA - fh.fh3_len);
1835 2081 if (pad > 0) {
1836 2082 bzero(&buf[i], pad);
1837 2083 i += pad;
1838 2084 l += pad;
1839 2085 }
1840 2086
1841 2087 sz = sizeof (ushort_t);
1842 2088 bcopy(&fh.fh3_xlen, &buf[i], sz);
1843 2089 i += sz;
1844 2090 bcopy(fh.fh3_xdata, &buf[i], fh.fh3_xlen);
1845 2091 i += fh.fh3_xlen;
1846 2092 pad = (NFS_FHMAXDATA - fh.fh3_xlen);
1847 2093 if (pad > 0) {
1848 2094 bzero(&buf[i], pad);
1849 2095 i += pad;
1850 2096 l += pad;
1851 2097 }
1852 2098 }
1853 2099 /*
1854 2100 * If we need to do NFS logging, the filehandle
1855 2101 * must be downsized to 32 bytes.
1856 2102 */
1857 2103 if (!error && exi->exi_export.ex_flags & EX_LOG) {
1858 2104 i = 0;
1859 2105 sz = sizeof (fsid_t);
1860 2106 bcopy(&fh.fh3_fsid, &logbuf[i], sz);
1861 2107 i += sz;
1862 2108 sz = sizeof (ushort_t);
1863 2109 bcopy(&fh.fh3_len, &logbuf[i], sz);
1864 2110 i += sz;
1865 2111 sz = NFS_FHMAXDATA;
1866 2112 bcopy(fh.fh3_data, &logbuf[i], sz);
1867 2113 i += sz;
1868 2114 sz = sizeof (ushort_t);
1869 2115 bcopy(&fh.fh3_xlen, &logbuf[i], sz);
1870 2116 i += sz;
1871 2117 sz = NFS_FHMAXDATA;
1872 2118 bcopy(fh.fh3_xdata, &logbuf[i], sz);
1873 2119 i += sz;
1874 2120 }
1875 2121 }
1876 2122 if (!error && exi->exi_export.ex_flags & EX_LOG) {
1877 2123 nfslog_getfh(exi, (fhandle_t *)logptr,
1878 2124 STRUCT_FGETP(uap, fname), UIO_USERSPACE, cr);
1879 2125 }
1880 2126 exi_rele(exi);
1881 2127 if (!error) {
1882 2128 if (copyout(&l, STRUCT_FGETP(uap, lenp), sizeof (int)))
1883 2129 error = EFAULT;
1884 2130 if (copyout(buf, STRUCT_FGETP(uap, fhp), l))
1885 2131 error = EFAULT;
1886 2132 }
1887 2133 }
1888 2134 VN_RELE(vp);
1889 2135 if (dvp != NULL) {
1890 2136 VN_RELE(dvp);
1891 2137 }
1892 2138 return (error);
1893 2139 }
1894 2140
1895 2141 /*
1896 2142 * Strategy: if vp is in the export list, then
1897 2143 * return the associated file handle. Otherwise, ".."
1898 2144 * once up the vp and try again, until the root of the
1899 2145 * filesystem is reached.
1900 2146 */
1901 2147 struct exportinfo *
1902 2148 nfs_vptoexi(vnode_t *dvp, vnode_t *vp, cred_t *cr, int *walk,
1903 2149 int *err, bool_t v4srv)
1904 2150 {
1905 2151 fid_t fid;
1906 2152 int error;
1907 2153 struct exportinfo *exi;
1908 2154
1909 2155 ASSERT(vp);
1910 2156 VN_HOLD(vp);
1911 2157 if (dvp != NULL) {
1912 2158 VN_HOLD(dvp);
1913 2159 }
1914 2160 if (walk != NULL)
1915 2161 *walk = 0;
1916 2162
1917 2163 for (;;) {
1918 2164 bzero(&fid, sizeof (fid));
1919 2165 fid.fid_len = MAXFIDSZ;
1920 2166 error = vop_fid_pseudo(vp, &fid);
1921 2167 if (error) {
1922 2168 /*
1923 2169 * If vop_fid_pseudo returns ENOSPC then the fid
1924 2170 * supplied is too small. For now we simply
1925 2171 * return EREMOTE.
1926 2172 */
1927 2173 if (error == ENOSPC)
1928 2174 error = EREMOTE;
1929 2175 break;
1930 2176 }
1931 2177
1932 2178 if (v4srv)
1933 2179 exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
1934 2180 else
1935 2181 exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid);
1936 2182
1937 2183 if (exi != NULL) {
1938 2184 /*
|
↓ open down ↓ |
206 lines elided |
↑ open up ↑ |
1939 2185 * Found the export info
1940 2186 */
1941 2187 break;
1942 2188 }
1943 2189
1944 2190 /*
1945 2191 * We have just failed finding a matching export.
1946 2192 * If we're at the root of this filesystem, then
1947 2193 * it's time to stop (with failure).
1948 2194 */
1949 - if (vp->v_flag & VROOT) {
2195 + ASSERT3P(vp->v_vfsp->vfs_zone, ==, curzone);
2196 + if ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp)) {
1950 2197 error = EINVAL;
1951 2198 break;
1952 2199 }
1953 2200
1954 2201 if (walk != NULL)
1955 2202 (*walk)++;
1956 2203
1957 2204 /*
1958 2205 * Now, do a ".." up vp. If dvp is supplied, use it,
1959 2206 * otherwise, look it up.
1960 2207 */
1961 2208 if (dvp == NULL) {
1962 2209 error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr,
1963 2210 NULL, NULL, NULL);
1964 2211 if (error)
1965 2212 break;
1966 2213 }
1967 2214 VN_RELE(vp);
1968 2215 vp = dvp;
1969 2216 dvp = NULL;
1970 2217 }
1971 2218 VN_RELE(vp);
1972 2219 if (dvp != NULL) {
1973 2220 VN_RELE(dvp);
1974 2221 }
1975 2222 if (error != 0) {
1976 2223 if (err != NULL)
1977 2224 *err = error;
1978 2225 return (NULL);
1979 2226 }
1980 2227 return (exi);
1981 2228 }
1982 2229
1983 2230 int
1984 2231 chk_clnt_sec(exportinfo_t *exi, struct svc_req *req)
1985 2232 {
1986 2233 int i, nfsflavor;
1987 2234 struct secinfo *sp;
1988 2235
1989 2236 /*
1990 2237 * Get the nfs flavor number from xprt.
1991 2238 */
1992 2239 nfsflavor = (int)(uintptr_t)req->rq_xprt->xp_cookie;
1993 2240
1994 2241 sp = exi->exi_export.ex_secinfo;
1995 2242 for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
1996 2243 if ((nfsflavor == sp[i].s_secinfo.sc_nfsnum) &&
1997 2244 SEC_REF_EXPORTED(sp + i))
1998 2245 return (TRUE);
1999 2246 }
2000 2247 return (FALSE);
2001 2248 }
2002 2249
2003 2250 /*
2004 2251 * Make an fhandle from a vnode
2005 2252 */
2006 2253 int
2007 2254 makefh(fhandle_t *fh, vnode_t *vp, exportinfo_t *exi)
2008 2255 {
2009 2256 int error;
2010 2257
2011 2258 *fh = exi->exi_fh; /* struct copy */
2012 2259
2013 2260 error = VOP_FID(vp, (fid_t *)&fh->fh_len, NULL);
2014 2261 if (error) {
2015 2262 /*
2016 2263 * Should be something other than EREMOTE
2017 2264 */
2018 2265 return (EREMOTE);
2019 2266 }
2020 2267 return (0);
2021 2268 }
2022 2269
2023 2270 /*
2024 2271 * This routine makes an overloaded V2 fhandle which contains
2025 2272 * sec modes.
2026 2273 *
2027 2274 * Note that the first four octets contain the length octet,
2028 2275 * the status octet, and two padded octets to make them XDR
2029 2276 * four-octet aligned.
2030 2277 *
2031 2278 * 1 2 3 4 32
2032 2279 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+
2033 2280 * | l | s | | | sec_1 |...| sec_n |...| |
2034 2281 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+
2035 2282 *
2036 2283 * where
2037 2284 *
2038 2285 * the status octet s indicates whether there are more security
2039 2286 * flavors (1 means yes, 0 means no) that require the client to
2040 2287 * perform another 0x81 LOOKUP to get them,
2041 2288 *
2042 2289 * the length octet l is the length describing the number of
2043 2290 * valid octets that follow. (l = 4 * n, where n is the number
2044 2291 * of security flavors sent in the current overloaded filehandle.)
2045 2292 *
2046 2293 * sec_index should always be in the inclusive range: [1 - ex_seccnt],
2047 2294 * and it tells server where to start within the secinfo array.
2048 2295 * Usually it will always be 1; however, if more flavors are used
2049 2296 * for the public export than can be encoded in the overloaded FH
2050 2297 * (7 for NFS2), subsequent SNEGO MCLs will have a larger index
2051 2298 * so the server will pick up where it left off from the previous
2052 2299 * MCL reply.
2053 2300 *
2054 2301 * With NFS4 support, implicitly allowed flavors are also in
2055 2302 * the secinfo array; however, they should not be returned in
2056 2303 * SNEGO MCL replies.
2057 2304 */
2058 2305 int
2059 2306 makefh_ol(fhandle_t *fh, exportinfo_t *exi, uint_t sec_index)
2060 2307 {
2061 2308 secinfo_t sec[MAX_FLAVORS];
2062 2309 int totalcnt, i, *ipt, cnt, seccnt, secidx, fh_max_cnt;
2063 2310 char *c;
2064 2311
2065 2312 if (fh == NULL || exi == NULL || sec_index < 1)
2066 2313 return (EREMOTE);
2067 2314
2068 2315 /*
2069 2316 * WebNFS clients need to know the unique set of explicitly
2070 2317 * shared flavors in used for the public export. When
2071 2318 * "TRUE" is passed to build_seclist_nodups(), only explicitly
2072 2319 * shared flavors are included in the list.
2073 2320 */
2074 2321 seccnt = build_seclist_nodups(&exi->exi_export, sec, TRUE);
2075 2322 if (sec_index > seccnt)
2076 2323 return (EREMOTE);
2077 2324
2078 2325 fh_max_cnt = (NFS_FHSIZE / sizeof (int)) - 1;
2079 2326 totalcnt = seccnt - sec_index + 1;
2080 2327 cnt = totalcnt > fh_max_cnt ? fh_max_cnt : totalcnt;
2081 2328
2082 2329 c = (char *)fh;
2083 2330 /*
2084 2331 * Encode the length octet representing the number of
2085 2332 * security flavors (in bytes) in this overloaded fh.
2086 2333 */
2087 2334 *c = cnt * sizeof (int);
2088 2335
2089 2336 /*
2090 2337 * Encode the status octet that indicates whether there
2091 2338 * are more security flavors the client needs to get.
2092 2339 */
2093 2340 *(c + 1) = totalcnt > fh_max_cnt;
2094 2341
2095 2342 /*
2096 2343 * put security flavors in the overloaded fh
2097 2344 */
2098 2345 ipt = (int *)(c + sizeof (int32_t));
2099 2346 secidx = sec_index - 1;
2100 2347 for (i = 0; i < cnt; i++) {
2101 2348 ipt[i] = htonl(sec[i + secidx].s_secinfo.sc_nfsnum);
2102 2349 }
2103 2350 return (0);
2104 2351 }
2105 2352
2106 2353 /*
2107 2354 * Make an nfs_fh3 from a vnode
2108 2355 */
2109 2356 int
2110 2357 makefh3(nfs_fh3 *fh, vnode_t *vp, struct exportinfo *exi)
2111 2358 {
2112 2359 int error;
2113 2360 fid_t fid;
2114 2361
2115 2362 bzero(&fid, sizeof (fid));
2116 2363 fid.fid_len = sizeof (fh->fh3_data);
2117 2364 error = VOP_FID(vp, &fid, NULL);
2118 2365 if (error)
2119 2366 return (EREMOTE);
2120 2367
2121 2368 bzero(fh, sizeof (nfs_fh3));
2122 2369 fh->fh3_fsid = exi->exi_fsid;
2123 2370 fh->fh3_len = fid.fid_len;
2124 2371 bcopy(fid.fid_data, fh->fh3_data, fh->fh3_len);
2125 2372
2126 2373 fh->fh3_xlen = exi->exi_fid.fid_len;
2127 2374 ASSERT(fh->fh3_xlen <= sizeof (fh->fh3_xdata));
2128 2375 bcopy(exi->exi_fid.fid_data, fh->fh3_xdata, fh->fh3_xlen);
2129 2376
2130 2377 fh->fh3_length = sizeof (fh->fh3_fsid)
2131 2378 + sizeof (fh->fh3_len) + fh->fh3_len
2132 2379 + sizeof (fh->fh3_xlen) + fh->fh3_xlen;
2133 2380 fh->fh3_flags = 0;
2134 2381
2135 2382 return (0);
2136 2383 }
2137 2384
2138 2385 /*
2139 2386 * This routine makes an overloaded V3 fhandle which contains
2140 2387 * sec modes.
2141 2388 *
2142 2389 * 1 4
2143 2390 * +--+--+--+--+
2144 2391 * | len |
2145 2392 * +--+--+--+--+
2146 2393 * up to 64
2147 2394 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+
2148 2395 * |s | | | | sec_1 | sec_2 | ... | sec_n |
2149 2396 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+
2150 2397 *
2151 2398 * len = 4 * (n+1), where n is the number of security flavors
2152 2399 * sent in the current overloaded filehandle.
2153 2400 *
2154 2401 * the status octet s indicates whether there are more security
2155 2402 * mechanisms (1 means yes, 0 means no) that require the client
2156 2403 * to perform another 0x81 LOOKUP to get them.
2157 2404 *
2158 2405 * Three octets are padded after the status octet.
2159 2406 */
2160 2407 int
2161 2408 makefh3_ol(nfs_fh3 *fh, struct exportinfo *exi, uint_t sec_index)
2162 2409 {
2163 2410 secinfo_t sec[MAX_FLAVORS];
2164 2411 int totalcnt, cnt, *ipt, i, seccnt, fh_max_cnt, secidx;
2165 2412 char *c;
2166 2413
2167 2414 if (fh == NULL || exi == NULL || sec_index < 1)
2168 2415 return (EREMOTE);
2169 2416
2170 2417 /*
2171 2418 * WebNFS clients need to know the unique set of explicitly
2172 2419 * shared flavors in used for the public export. When
2173 2420 * "TRUE" is passed to build_seclist_nodups(), only explicitly
2174 2421 * shared flavors are included in the list.
2175 2422 */
2176 2423 seccnt = build_seclist_nodups(&exi->exi_export, sec, TRUE);
2177 2424
2178 2425 if (sec_index > seccnt)
2179 2426 return (EREMOTE);
2180 2427
2181 2428 fh_max_cnt = (NFS3_FHSIZE / sizeof (int)) - 1;
2182 2429 totalcnt = seccnt - sec_index + 1;
2183 2430 cnt = totalcnt > fh_max_cnt ? fh_max_cnt : totalcnt;
2184 2431
2185 2432 /*
2186 2433 * Place the length in fh3_length representing the number
2187 2434 * of security flavors (in bytes) in this overloaded fh.
2188 2435 */
2189 2436 fh->fh3_flags = FH_WEBNFS;
2190 2437 fh->fh3_length = (cnt+1) * sizeof (int32_t);
2191 2438
2192 2439 c = (char *)&fh->fh3_u.nfs_fh3_i.fh3_i;
2193 2440 /*
2194 2441 * Encode the status octet that indicates whether there
2195 2442 * are more security flavors the client needs to get.
2196 2443 */
2197 2444 *c = totalcnt > fh_max_cnt;
2198 2445
2199 2446 /*
2200 2447 * put security flavors in the overloaded fh
2201 2448 */
2202 2449 secidx = sec_index - 1;
2203 2450 ipt = (int *)(c + sizeof (int32_t));
2204 2451 for (i = 0; i < cnt; i++) {
2205 2452 ipt[i] = htonl(sec[i + secidx].s_secinfo.sc_nfsnum);
2206 2453 }
2207 2454 return (0);
2208 2455 }
2209 2456
2210 2457 /*
2211 2458 * Make an nfs_fh4 from a vnode
2212 2459 */
2213 2460 int
2214 2461 makefh4(nfs_fh4 *fh, vnode_t *vp, struct exportinfo *exi)
2215 2462 {
2216 2463 int error;
2217 2464 nfs_fh4_fmt_t *fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val;
2218 2465 fid_t fid;
2219 2466
2220 2467 bzero(&fid, sizeof (fid));
2221 2468 fid.fid_len = MAXFIDSZ;
2222 2469 /*
2223 2470 * vop_fid_pseudo() is used to set up NFSv4 namespace, so
2224 2471 * use vop_fid_pseudo() here to get the fid instead of VOP_FID.
2225 2472 */
2226 2473 error = vop_fid_pseudo(vp, &fid);
2227 2474 if (error)
2228 2475 return (error);
2229 2476
2230 2477 fh->nfs_fh4_len = NFS_FH4_LEN;
2231 2478
2232 2479 fh_fmtp->fh4_i.fhx_fsid = exi->exi_fh.fh_fsid;
2233 2480 fh_fmtp->fh4_i.fhx_xlen = exi->exi_fh.fh_xlen;
2234 2481
2235 2482 bzero(fh_fmtp->fh4_i.fhx_data, sizeof (fh_fmtp->fh4_i.fhx_data));
2236 2483 bzero(fh_fmtp->fh4_i.fhx_xdata, sizeof (fh_fmtp->fh4_i.fhx_xdata));
2237 2484 ASSERT(exi->exi_fh.fh_xlen <= sizeof (fh_fmtp->fh4_i.fhx_xdata));
2238 2485 bcopy(exi->exi_fh.fh_xdata, fh_fmtp->fh4_i.fhx_xdata,
2239 2486 exi->exi_fh.fh_xlen);
2240 2487
2241 2488 fh_fmtp->fh4_len = fid.fid_len;
2242 2489 ASSERT(fid.fid_len <= sizeof (fh_fmtp->fh4_data));
2243 2490 bcopy(fid.fid_data, fh_fmtp->fh4_data, fid.fid_len);
2244 2491 fh_fmtp->fh4_flag = 0;
2245 2492
2246 2493 #ifdef VOLATILE_FH_TEST
2247 2494 /*
2248 2495 * XXX (temporary?)
2249 2496 * Use the rnode volatile_id value to add volatility to the fh.
2250 2497 *
2251 2498 * For testing purposes there are currently two scenarios, based
2252 2499 * on whether the filesystem was shared with "volatile_fh"
2253 2500 * or "expire_on_rename". In the first case, use the value of
2254 2501 * export struct share_time as the volatile_id. In the second
2255 2502 * case use the vnode volatile_id value (which is set to the
2256 2503 * time in which the file was renamed).
2257 2504 *
2258 2505 * Note that the above are temporary constructs for testing only
2259 2506 * XXX
2260 2507 */
2261 2508 if (exi->exi_export.ex_flags & EX_VOLRNM) {
2262 2509 fh_fmtp->fh4_volatile_id = find_volrnm_fh_id(exi, fh);
2263 2510 } else if (exi->exi_export.ex_flags & EX_VOLFH) {
2264 2511 fh_fmtp->fh4_volatile_id = exi->exi_volatile_id;
2265 2512 } else {
2266 2513 fh_fmtp->fh4_volatile_id = 0;
2267 2514 }
2268 2515 #endif /* VOLATILE_FH_TEST */
2269 2516
2270 2517 return (0);
2271 2518 }
2272 2519
2273 2520 /*
2274 2521 * Convert an fhandle into a vnode.
2275 2522 * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode.
2276 2523 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2277 2524 * are done with it.
2278 2525 */
2279 2526 vnode_t *
2280 2527 nfs_fhtovp(fhandle_t *fh, struct exportinfo *exi)
2281 2528 {
2282 2529 vfs_t *vfsp;
2283 2530 vnode_t *vp;
2284 2531 int error;
2285 2532 fid_t *fidp;
2286 2533
2287 2534 TRACE_0(TR_FAC_NFS, TR_FHTOVP_START,
2288 2535 "fhtovp_start");
2289 2536
2290 2537 if (exi == NULL) {
2291 2538 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2292 2539 "fhtovp_end:(%S)", "exi NULL");
2293 2540 return (NULL); /* not exported */
2294 2541 }
2295 2542
2296 2543 ASSERT(exi->exi_vp != NULL);
2297 2544
2298 2545 if (PUBLIC_FH2(fh)) {
2299 2546 if (exi->exi_export.ex_flags & EX_PUBLIC) {
2300 2547 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2301 2548 "fhtovp_end:(%S)", "root not exported");
2302 2549 return (NULL);
2303 2550 }
2304 2551 vp = exi->exi_vp;
2305 2552 VN_HOLD(vp);
2306 2553 return (vp);
2307 2554 }
2308 2555
2309 2556 vfsp = exi->exi_vp->v_vfsp;
2310 2557 ASSERT(vfsp != NULL);
2311 2558 fidp = (fid_t *)&fh->fh_len;
2312 2559
2313 2560 error = VFS_VGET(vfsp, &vp, fidp);
2314 2561 if (error || vp == NULL) {
2315 2562 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2316 2563 "fhtovp_end:(%S)", "VFS_GET failed or vp NULL");
2317 2564 return (NULL);
2318 2565 }
2319 2566 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2320 2567 "fhtovp_end:(%S)", "end");
2321 2568 return (vp);
2322 2569 }
2323 2570
2324 2571 /*
2325 2572 * Convert an nfs_fh3 into a vnode.
2326 2573 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2327 2574 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2328 2575 * are done with it.
2329 2576 */
2330 2577 vnode_t *
2331 2578 nfs3_fhtovp(nfs_fh3 *fh, struct exportinfo *exi)
2332 2579 {
2333 2580 vfs_t *vfsp;
2334 2581 vnode_t *vp;
2335 2582 int error;
2336 2583 fid_t *fidp;
2337 2584
2338 2585 if (exi == NULL)
2339 2586 return (NULL); /* not exported */
2340 2587
2341 2588 ASSERT(exi->exi_vp != NULL);
2342 2589
2343 2590 if (PUBLIC_FH3(fh)) {
2344 2591 if (exi->exi_export.ex_flags & EX_PUBLIC)
2345 2592 return (NULL);
2346 2593 vp = exi->exi_vp;
2347 2594 VN_HOLD(vp);
2348 2595 return (vp);
2349 2596 }
2350 2597
2351 2598 if (fh->fh3_length < NFS3_OLDFHSIZE ||
2352 2599 fh->fh3_length > NFS3_MAXFHSIZE)
2353 2600 return (NULL);
2354 2601
2355 2602 vfsp = exi->exi_vp->v_vfsp;
2356 2603 ASSERT(vfsp != NULL);
2357 2604 fidp = FH3TOFIDP(fh);
2358 2605
2359 2606 error = VFS_VGET(vfsp, &vp, fidp);
2360 2607 if (error || vp == NULL)
2361 2608 return (NULL);
2362 2609
2363 2610 return (vp);
2364 2611 }
2365 2612
2366 2613 /*
2367 2614 * Convert an nfs_fh4 into a vnode.
2368 2615 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2369 2616 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2370 2617 * are done with it.
2371 2618 */
2372 2619 vnode_t *
2373 2620 nfs4_fhtovp(nfs_fh4 *fh, struct exportinfo *exi, nfsstat4 *statp)
2374 2621 {
2375 2622 vfs_t *vfsp;
2376 2623 vnode_t *vp = NULL;
2377 2624 int error;
2378 2625 fid_t *fidp;
2379 2626 nfs_fh4_fmt_t *fh_fmtp;
2380 2627 #ifdef VOLATILE_FH_TEST
2381 2628 uint32_t volatile_id = 0;
2382 2629 #endif /* VOLATILE_FH_TEST */
2383 2630
2384 2631 if (exi == NULL) {
2385 2632 *statp = NFS4ERR_STALE;
2386 2633 return (NULL); /* not exported */
2387 2634 }
2388 2635 ASSERT(exi->exi_vp != NULL);
2389 2636
2390 2637 /* caller should have checked this */
2391 2638 ASSERT(fh->nfs_fh4_len >= NFS_FH4_LEN);
2392 2639
2393 2640 fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val;
2394 2641 vfsp = exi->exi_vp->v_vfsp;
2395 2642 ASSERT(vfsp != NULL);
2396 2643 fidp = (fid_t *)&fh_fmtp->fh4_len;
2397 2644
2398 2645 #ifdef VOLATILE_FH_TEST
2399 2646 /* XXX check if volatile - should be changed later */
2400 2647 if (exi->exi_export.ex_flags & (EX_VOLRNM | EX_VOLFH)) {
2401 2648 /*
2402 2649 * Filesystem is shared with volatile filehandles
2403 2650 */
2404 2651 if (exi->exi_export.ex_flags & EX_VOLRNM)
2405 2652 volatile_id = find_volrnm_fh_id(exi, fh);
2406 2653 else
2407 2654 volatile_id = exi->exi_volatile_id;
2408 2655
2409 2656 if (fh_fmtp->fh4_volatile_id != volatile_id) {
2410 2657 *statp = NFS4ERR_FHEXPIRED;
2411 2658 return (NULL);
2412 2659 }
2413 2660 }
2414 2661 /*
2415 2662 * XXX even if test_volatile_fh false, the fh may contain a
2416 2663 * volatile id if obtained when the test was set.
2417 2664 */
2418 2665 fh_fmtp->fh4_volatile_id = (uchar_t)0;
2419 2666 #endif /* VOLATILE_FH_TEST */
2420 2667
2421 2668 error = VFS_VGET(vfsp, &vp, fidp);
2422 2669 /*
2423 2670 * If we can not get vp from VFS_VGET, perhaps this is
2424 2671 * an nfs v2/v3/v4 node in an nfsv4 pseudo filesystem.
2425 2672 * Check it out.
2426 2673 */
2427 2674 if (error && PSEUDO(exi))
2428 2675 error = nfs4_vget_pseudo(exi, &vp, fidp);
2429 2676
2430 2677 if (error || vp == NULL) {
2431 2678 *statp = NFS4ERR_STALE;
2432 2679 return (NULL);
2433 2680 }
2434 2681 /* XXX - disgusting hack */
2435 2682 if (vp->v_type == VNON && vp->v_flag & V_XATTRDIR)
2436 2683 vp->v_type = VDIR;
2437 2684 *statp = NFS4_OK;
2438 2685 return (vp);
|
↓ open down ↓ |
479 lines elided |
↑ open up ↑ |
2439 2686 }
2440 2687
2441 2688 /*
2442 2689 * Find the export structure associated with the given filesystem.
2443 2690 * If found, then increment the ref count (exi_count).
2444 2691 */
2445 2692 struct exportinfo *
2446 2693 checkexport(fsid_t *fsid, fid_t *fid)
2447 2694 {
2448 2695 struct exportinfo *exi;
2696 + nfs_export_t *ne = nfs_get_export();
2449 2697
2450 - rw_enter(&exported_lock, RW_READER);
2451 - for (exi = exptable[exptablehash(fsid, fid)];
2698 + rw_enter(&ne->exported_lock, RW_READER);
2699 + for (exi = ne->exptable[exptablehash(fsid, fid)];
2452 2700 exi != NULL;
2453 2701 exi = exi->fid_hash.next) {
2454 2702 if (exportmatch(exi, fsid, fid)) {
2455 2703 /*
2456 2704 * If this is the place holder for the
2457 2705 * public file handle, then return the
2458 2706 * real export entry for the public file
2459 2707 * handle.
2460 2708 */
2461 2709 if (exi->exi_export.ex_flags & EX_PUBLIC) {
2462 - exi = exi_public;
2710 + exi = ne->exi_public;
2463 2711 }
2464 2712
2465 2713 exi_hold(exi);
2466 - rw_exit(&exported_lock);
2714 + rw_exit(&ne->exported_lock);
2467 2715 return (exi);
2468 2716 }
2469 2717 }
2470 - rw_exit(&exported_lock);
2718 + rw_exit(&ne->exported_lock);
2471 2719 return (NULL);
2472 2720 }
2473 2721
2474 2722
2475 2723 /*
2476 2724 * "old school" version of checkexport() for NFS4. NFS4
2477 2725 * rfs4_compound holds exported_lock for duration of compound
2478 2726 * processing. This version doesn't manipulate exi_count
2479 2727 * since NFS4 breaks fundamental assumptions in the exi_count
2480 2728 * design.
2481 2729 */
2482 2730 struct exportinfo *
2483 2731 checkexport4(fsid_t *fsid, fid_t *fid, vnode_t *vp)
2484 2732 {
2485 2733 struct exportinfo *exi;
2734 + nfs_export_t *ne = nfs_get_export();
2486 2735
2487 - ASSERT(RW_LOCK_HELD(&exported_lock));
2736 + ASSERT(RW_LOCK_HELD(&ne->exported_lock));
2488 2737
2489 - for (exi = exptable[exptablehash(fsid, fid)];
2738 + for (exi = ne->exptable[exptablehash(fsid, fid)];
2490 2739 exi != NULL;
2491 2740 exi = exi->fid_hash.next) {
2492 2741 if (exportmatch(exi, fsid, fid)) {
2493 2742 /*
2494 2743 * If this is the place holder for the
2495 2744 * public file handle, then return the
2496 2745 * real export entry for the public file
2497 2746 * handle.
2498 2747 */
2499 2748 if (exi->exi_export.ex_flags & EX_PUBLIC) {
2500 - exi = exi_public;
2749 + exi = ne->exi_public;
2501 2750 }
2502 2751
2503 2752 /*
2504 2753 * If vp is given, check if vp is the
2505 2754 * same vnode as the exported node.
2506 2755 *
2507 2756 * Since VOP_FID of a lofs node returns the
2508 2757 * fid of its real node (ufs), the exported
2509 2758 * node for lofs and (pseudo) ufs may have
2510 2759 * the same fsid and fid.
2511 2760 */
2512 2761 if (vp == NULL || vp == exi->exi_vp)
2513 2762 return (exi);
2514 2763 }
2515 2764 }
2516 2765
2517 2766 return (NULL);
2518 2767 }
2519 2768
2520 2769 /*
2521 2770 * Free an entire export list node
2522 2771 */
2523 2772 void
2524 2773 exportfree(struct exportinfo *exi)
2525 2774 {
2526 2775 struct exportdata *ex;
2527 2776 struct charset_cache *cache;
2528 2777 int i;
2529 2778
2530 2779 ex = &exi->exi_export;
2531 2780
2532 2781 ASSERT(exi->exi_vp != NULL && !(exi->exi_export.ex_flags & EX_PUBLIC));
2533 2782 VN_RELE(exi->exi_vp);
2534 2783 if (exi->exi_dvp != NULL)
2535 2784 VN_RELE(exi->exi_dvp);
2536 2785
2537 2786 if (ex->ex_flags & EX_INDEX)
2538 2787 kmem_free(ex->ex_index, strlen(ex->ex_index) + 1);
2539 2788
2540 2789 kmem_free(ex->ex_path, ex->ex_pathlen + 1);
2541 2790 nfsauth_cache_free(exi);
2542 2791
2543 2792 /*
2544 2793 * if there is a character set mapping cached, clean it up.
2545 2794 */
2546 2795 for (cache = exi->exi_charset; cache != NULL;
2547 2796 cache = exi->exi_charset) {
2548 2797 if (cache->inbound != (kiconv_t)-1)
2549 2798 (void) kiconv_close(cache->inbound);
2550 2799 if (cache->outbound != (kiconv_t)-1)
2551 2800 (void) kiconv_close(cache->outbound);
2552 2801 exi->exi_charset = cache->next;
2553 2802 kmem_free(cache, sizeof (struct charset_cache));
2554 2803 }
2555 2804
2556 2805 if (exi->exi_logbuffer != NULL)
2557 2806 nfslog_disable(exi);
2558 2807
2559 2808 if (ex->ex_flags & EX_LOG) {
2560 2809 kmem_free(ex->ex_log_buffer, ex->ex_log_bufferlen + 1);
2561 2810 kmem_free(ex->ex_tag, ex->ex_taglen + 1);
2562 2811 }
2563 2812
2564 2813 if (exi->exi_visible)
2565 2814 free_visible(exi->exi_visible);
2566 2815
2567 2816 srv_secinfo_list_free(ex->ex_secinfo, ex->ex_seccnt);
2568 2817
2569 2818 #ifdef VOLATILE_FH_TEST
2570 2819 free_volrnm_list(exi);
2571 2820 mutex_destroy(&exi->exi_vol_rename_lock);
2572 2821 #endif /* VOLATILE_FH_TEST */
2573 2822
2574 2823 mutex_destroy(&exi->exi_lock);
2575 2824 rw_destroy(&exi->exi_cache_lock);
2576 2825 /*
2577 2826 * All nodes in the exi_cache AVL trees were removed and freed in the
2578 2827 * nfsauth_cache_free() call above. We will just destroy and free the
2579 2828 * empty AVL trees here.
2580 2829 */
2581 2830 for (i = 0; i < AUTH_TABLESIZE; i++) {
2582 2831 avl_destroy(exi->exi_cache[i]);
2583 2832 kmem_free(exi->exi_cache[i], sizeof (avl_tree_t));
2584 2833 }
2585 2834
2586 2835 kmem_free(exi, sizeof (*exi));
2587 2836 }
2588 2837
2589 2838 /*
2590 2839 * load the index file from user space into kernel space.
2591 2840 */
2592 2841 static int
2593 2842 loadindex(struct exportdata *kex)
2594 2843 {
2595 2844 int error;
2596 2845 char index[MAXNAMELEN+1];
2597 2846 size_t len;
2598 2847
2599 2848 /*
2600 2849 * copyinstr copies the complete string including the NULL and
2601 2850 * returns the len with the NULL byte included in the calculation
2602 2851 * as long as the max length is not exceeded.
2603 2852 */
2604 2853 if (error = copyinstr(kex->ex_index, index, sizeof (index), &len))
2605 2854 return (error);
2606 2855
2607 2856 kex->ex_index = kmem_alloc(len, KM_SLEEP);
2608 2857 bcopy(index, kex->ex_index, len);
2609 2858
2610 2859 return (0);
2611 2860 }
2612 2861
2613 2862 void
2614 2863 exi_hold(struct exportinfo *exi)
2615 2864 {
2616 2865 mutex_enter(&exi->exi_lock);
2617 2866 exi->exi_count++;
2618 2867 mutex_exit(&exi->exi_lock);
2619 2868 }
2620 2869
2621 2870 /*
2622 2871 * When a thread completes using exi, it should call exi_rele().
2623 2872 * exi_rele() decrements exi_count. It releases exi if exi_count == 0, i.e.
2624 2873 * if this is the last user of exi and exi is not on exportinfo list anymore
2625 2874 */
2626 2875 void
2627 2876 exi_rele(struct exportinfo *exi)
2628 2877 {
2629 2878 mutex_enter(&exi->exi_lock);
2630 2879 exi->exi_count--;
2631 2880 if (exi->exi_count == 0) {
2632 2881 mutex_exit(&exi->exi_lock);
2633 2882 exportfree(exi);
2634 2883 } else
2635 2884 mutex_exit(&exi->exi_lock);
2636 2885 }
2637 2886
2638 2887 #ifdef VOLATILE_FH_TEST
2639 2888 /*
2640 2889 * Test for volatile fh's - add file handle to list and set its volatile id
2641 2890 * to time it was renamed. If EX_VOLFH is also on and the fs is reshared,
2642 2891 * the vol_rename queue is purged.
2643 2892 *
2644 2893 * XXX This code is for unit testing purposes only... To correctly use it, it
2645 2894 * needs to tie a rename list to the export struct and (more
2646 2895 * important), protect access to the exi rename list using a write lock.
2647 2896 */
2648 2897
2649 2898 /*
2650 2899 * get the fh vol record if it's in the volatile on rename list. Don't check
2651 2900 * volatile_id in the file handle - compare only the file handles.
2652 2901 */
2653 2902 static struct ex_vol_rename *
2654 2903 find_volrnm_fh(struct exportinfo *exi, nfs_fh4 *fh4p)
2655 2904 {
2656 2905 struct ex_vol_rename *p = NULL;
2657 2906 fhandle4_t *fhp;
2658 2907
2659 2908 /* XXX shouldn't we assert &exported_lock held? */
2660 2909 ASSERT(MUTEX_HELD(&exi->exi_vol_rename_lock));
2661 2910
2662 2911 if (fh4p->nfs_fh4_len != NFS_FH4_LEN) {
2663 2912 return (NULL);
2664 2913 }
2665 2914 fhp = &((nfs_fh4_fmt_t *)fh4p->nfs_fh4_val)->fh4_i;
2666 2915 for (p = exi->exi_vol_rename; p != NULL; p = p->vrn_next) {
2667 2916 if (bcmp(fhp, &p->vrn_fh_fmt.fh4_i,
2668 2917 sizeof (fhandle4_t)) == 0)
2669 2918 break;
2670 2919 }
2671 2920 return (p);
2672 2921 }
2673 2922
2674 2923 /*
2675 2924 * get the volatile id for the fh (if there is - else return 0). Ignore the
2676 2925 * volatile_id in the file handle - compare only the file handles.
2677 2926 */
2678 2927 static uint32_t
2679 2928 find_volrnm_fh_id(struct exportinfo *exi, nfs_fh4 *fh4p)
2680 2929 {
2681 2930 struct ex_vol_rename *p;
2682 2931 uint32_t volatile_id;
2683 2932
2684 2933 mutex_enter(&exi->exi_vol_rename_lock);
2685 2934 p = find_volrnm_fh(exi, fh4p);
2686 2935 volatile_id = (p ? p->vrn_fh_fmt.fh4_volatile_id :
2687 2936 exi->exi_volatile_id);
2688 2937 mutex_exit(&exi->exi_vol_rename_lock);
2689 2938 return (volatile_id);
2690 2939 }
2691 2940
2692 2941 /*
2693 2942 * Free the volatile on rename list - will be called if a filesystem is
2694 2943 * unshared or reshared without EX_VOLRNM
2695 2944 */
2696 2945 static void
2697 2946 free_volrnm_list(struct exportinfo *exi)
2698 2947 {
2699 2948 struct ex_vol_rename *p, *pnext;
2700 2949
2701 2950 /* no need to hold mutex lock - this one is called from exportfree */
2702 2951 for (p = exi->exi_vol_rename; p != NULL; p = pnext) {
2703 2952 pnext = p->vrn_next;
2704 2953 kmem_free(p, sizeof (*p));
2705 2954 }
2706 2955 exi->exi_vol_rename = NULL;
2707 2956 }
2708 2957
2709 2958 /*
2710 2959 * Add a file handle to the volatile on rename list.
2711 2960 */
2712 2961 void
2713 2962 add_volrnm_fh(struct exportinfo *exi, vnode_t *vp)
2714 2963 {
2715 2964 struct ex_vol_rename *p;
2716 2965 char fhbuf[NFS4_FHSIZE];
2717 2966 nfs_fh4 fh4;
2718 2967 int error;
2719 2968
2720 2969 fh4.nfs_fh4_val = fhbuf;
2721 2970 error = makefh4(&fh4, vp, exi);
2722 2971 if ((error) || (fh4.nfs_fh4_len != sizeof (p->vrn_fh_fmt))) {
2723 2972 return;
2724 2973 }
2725 2974
2726 2975 mutex_enter(&exi->exi_vol_rename_lock);
2727 2976
2728 2977 p = find_volrnm_fh(exi, &fh4);
2729 2978
2730 2979 if (p == NULL) {
2731 2980 p = kmem_alloc(sizeof (*p), KM_SLEEP);
2732 2981 bcopy(fh4.nfs_fh4_val, &p->vrn_fh_fmt, sizeof (p->vrn_fh_fmt));
2733 2982 p->vrn_next = exi->exi_vol_rename;
2734 2983 exi->exi_vol_rename = p;
2735 2984 }
2736 2985
2737 2986 p->vrn_fh_fmt.fh4_volatile_id = gethrestime_sec();
2738 2987 mutex_exit(&exi->exi_vol_rename_lock);
2739 2988 }
2740 2989
2741 2990 #endif /* VOLATILE_FH_TEST */
|
↓ open down ↓ |
231 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX