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