Print this page
11083 support NFS server in zone
Portions contributed by: Dan Kruchinin <dan.kruchinin@nexenta.com>
Portions contributed by: Stepan Zastupov <stepan.zastupov@gmail.com>
Portions contributed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Portions contributed by: Mike Zeller <mike@mikezeller.net>
Portions contributed by: Dan McDonald <danmcd@joyent.com>
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>
Portions contributed by: Vitaliy Gusev <gusev.vitaliy@gmail.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Jason King <jbk@joyent.com>
Reviewed by: C Fraire <cfraire@me.com>
Change-Id: I22f289d357503f9b48a0bc2482cc4328a6d43d16
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/sharefs/sharetab.c
+++ new/usr/src/uts/common/fs/sharefs/sharetab.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
|
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
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 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 +/*
27 + * Copyright 2018 Nexenta Systems, Inc.
28 + * Copyright 2020 Joyent, Inc.
29 + */
30 +
26 31 #include <sys/types.h>
27 32 #include <sys/types32.h>
28 33 #include <sys/param.h>
29 34 #include <sys/systm.h>
30 35 #include <rpc/types.h>
31 36 #include <sys/vfs.h>
32 37 #include <sys/siginfo.h>
33 38 #include <sys/proc.h> /* for exit() declaration */
34 39 #include <sys/kmem.h>
35 40 #include <sys/pathname.h>
36 41 #include <sys/debug.h>
37 42 #include <sys/vtrace.h>
38 43 #include <sys/cmn_err.h>
39 44 #include <sys/atomic.h>
|
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
40 45 #include <sys/policy.h>
41 46
42 47 #include <sharefs/sharefs.h>
43 48
44 49 /*
45 50 * A macro to avoid cut-and-paste errors on getting a string field
46 51 * from user-land.
47 52 */
48 53 #define SHARETAB_COPYIN(field) \
49 54 if (copyinstr(STRUCT_FGETP(u_sh, sh_##field), \
50 - buf, \
51 - bufsz + 1, /* Add one for extra NUL */ \
52 - &len)) { \
55 + buf, \
56 + bufsz + 1, /* Add one for extra NUL */ \
57 + &len)) { \
53 58 error = EFAULT; \
54 59 goto cleanup; \
55 60 } \
56 - /* \
57 - * Need to remove 1 because copyinstr() counts the NUL. \
58 - */ \
61 + /* Need to remove 1 because copyinstr() counts the NUL */ \
59 62 len--; \
60 63 sh->sh_##field = kmem_alloc(len + 1, KM_SLEEP); \
61 64 bcopy(buf, sh->sh_##field, len); \
62 65 sh->sh_##field[len] = '\0'; \
63 66 shl.shl_##field = (int)len; \
64 67 sh->sh_size += shl.shl_##field; /* Debug counting */
65 68
66 69 #define SHARETAB_DELETE_FIELD(field) \
67 - if (sh->sh_##field) { \
70 + if (sh->sh_##field != NULL) { \
68 71 kmem_free(sh->sh_##field, \
69 - shl ? shl->shl_##field + 1 : \
70 - strlen(sh->sh_##field) + 1); \
72 + shl ? shl->shl_##field + 1 : \
73 + strlen(sh->sh_##field) + 1); \
71 74 }
72 75
73 -sharetab_t *sharefs_sharetab = NULL; /* The incore sharetab. */
74 -size_t sharetab_size;
75 -uint_t sharetab_count;
76 +static zone_key_t sharetab_zone_key;
76 77
77 -krwlock_t sharetab_lock; /* lock to protect the cached sharetab */
78 -
79 -krwlock_t sharefs_lock; /* lock to protect the vnode ops */
80 -
81 -timestruc_t sharetab_mtime;
82 -timestruc_t sharetab_snap_time;
83 -
84 -uint_t sharetab_generation; /* Only increments and wraps! */
85 -
86 78 /*
87 79 * Take care of cleaning up a share.
88 80 * If passed in a length array, use it to determine how much
89 81 * space to clean up. Else, figure that out.
90 82 */
91 83 static void
92 84 sharefree(share_t *sh, sharefs_lens_t *shl)
93 85 {
94 - if (!sh)
86 + if (sh == NULL)
95 87 return;
96 88
97 89 SHARETAB_DELETE_FIELD(path);
98 90 SHARETAB_DELETE_FIELD(res);
99 91 SHARETAB_DELETE_FIELD(fstype);
100 92 SHARETAB_DELETE_FIELD(opts);
101 93 SHARETAB_DELETE_FIELD(descr);
102 94
103 - kmem_free(sh, sizeof (share_t));
95 + kmem_free(sh, sizeof (*sh));
104 96 }
105 97
106 98 /*
107 99 * If there is no error, then this function is responsible for
108 100 * cleaning up the memory associated with the share argument.
109 101 */
110 102 static int
111 -sharefs_remove(share_t *sh, sharefs_lens_t *shl)
103 +sharefs_remove(sharetab_globals_t *sg, share_t *sh, sharefs_lens_t *shl)
112 104 {
113 105 int iHash;
114 106 sharetab_t *sht;
115 107 share_t *s, *p;
116 108 int iPath;
117 109
118 110 if (!sh)
119 111 return (ENOENT);
120 112
121 - rw_enter(&sharetab_lock, RW_WRITER);
122 - for (sht = sharefs_sharetab; sht != NULL; sht = sht->s_next) {
123 - if (strcmp(sh->sh_fstype, sht->s_fstype) == 0) {
113 + rw_enter(&sg->sharetab_lock, RW_WRITER);
114 + for (sht = sg->sharefs_sharetab; sht != NULL; sht = sht->s_next) {
115 + if (strcmp(sh->sh_fstype, sht->s_fstype) == 0)
124 116 break;
125 - }
126 117 }
127 118
128 119 /*
129 120 * There does not exist a fstype in memory which
130 121 * matches the share passed in.
131 122 */
132 - if (!sht) {
133 - rw_exit(&sharetab_lock);
123 + if (sht == NULL) {
124 + rw_exit(&sg->sharetab_lock);
134 125 return (ENOENT);
135 126 }
136 127
137 - iPath = shl ? shl->shl_path : strlen(sh->sh_path);
128 + iPath = shl != NULL ? shl->shl_path : strlen(sh->sh_path);
138 129 iHash = pkp_tab_hash(sh->sh_path, strlen(sh->sh_path));
139 130
140 131 /*
141 132 * Now walk down the hash table and find the entry to free!
142 133 */
143 134 for (p = NULL, s = sht->s_buckets[iHash].ssh_sh;
144 135 s != NULL; s = s->sh_next) {
145 136 /*
146 137 * We need exact matches.
147 138 */
148 139 if (strcmp(sh->sh_path, s->sh_path) == 0 &&
149 140 strlen(s->sh_path) == iPath) {
150 - if (p) {
141 + if (p != NULL)
151 142 p->sh_next = s->sh_next;
152 - } else {
143 + else
153 144 sht->s_buckets[iHash].ssh_sh = s->sh_next;
154 - }
155 145
156 146 ASSERT(sht->s_buckets[iHash].ssh_count != 0);
157 147 atomic_dec_32(&sht->s_buckets[iHash].ssh_count);
158 148 atomic_dec_32(&sht->s_count);
159 - atomic_dec_32(&sharetab_count);
149 + atomic_dec_32(&sg->sharetab_count);
160 150
161 - ASSERT(sharetab_size >= s->sh_size);
162 - sharetab_size -= s->sh_size;
151 + ASSERT(sg->sharetab_size >= s->sh_size);
152 + sg->sharetab_size -= s->sh_size;
163 153
164 - gethrestime(&sharetab_mtime);
165 - atomic_inc_32(&sharetab_generation);
154 + gethrestime(&sg->sharetab_mtime);
155 + atomic_inc_32(&sg->sharetab_generation);
166 156
167 157 break;
168 158 }
169 159
170 160 p = s;
171 161 }
172 162
173 - rw_exit(&sharetab_lock);
163 + rw_exit(&sg->sharetab_lock);
174 164
175 - if (!s) {
165 + if (s == NULL)
176 166 return (ENOENT);
177 - }
178 167
179 168 s->sh_next = NULL;
180 169 sharefree(s, NULL);
181 170
182 - /*
183 - * We need to free the share for the caller.
184 - */
171 + /* We need to free the share for the caller */
185 172 sharefree(sh, shl);
186 173
187 174 return (0);
188 175 }
189 176
190 177 /*
191 178 * The caller must have allocated memory for us to use.
192 179 */
193 180 static int
194 -sharefs_add(share_t *sh, sharefs_lens_t *shl)
181 +sharefs_add(sharetab_globals_t *sg, share_t *sh, sharefs_lens_t *shl)
195 182 {
196 183 int iHash;
197 184 sharetab_t *sht;
198 185 share_t *s, *p;
199 186 int iPath;
200 187 int n;
201 188
202 - if (!sh) {
189 + if (sh == NULL)
203 190 return (ENOENT);
204 - }
205 191
206 - /*
207 - * We need to find the hash buckets for the fstype.
208 - */
209 - rw_enter(&sharetab_lock, RW_WRITER);
210 - for (sht = sharefs_sharetab; sht != NULL; sht = sht->s_next) {
211 - if (strcmp(sh->sh_fstype, sht->s_fstype) == 0) {
192 + /* We need to find the hash buckets for the fstype */
193 + rw_enter(&sg->sharetab_lock, RW_WRITER);
194 + for (sht = sg->sharefs_sharetab; sht != NULL; sht = sht->s_next) {
195 + if (strcmp(sh->sh_fstype, sht->s_fstype) == 0)
212 196 break;
213 - }
214 197 }
215 198
216 - /*
217 - * Did not exist, so allocate one and add it to the
218 - * sharetab.
219 - */
220 - if (!sht) {
199 + /* Did not exist, so allocate one and add it to the sharetab */
200 + if (sht == NULL) {
221 201 sht = kmem_zalloc(sizeof (*sht), KM_SLEEP);
222 202 n = strlen(sh->sh_fstype);
223 203 sht->s_fstype = kmem_zalloc(n + 1, KM_SLEEP);
224 204 (void) strncpy(sht->s_fstype, sh->sh_fstype, n);
225 205
226 - sht->s_next = sharefs_sharetab;
227 - sharefs_sharetab = sht;
206 + sht->s_next = sg->sharefs_sharetab;
207 + sg->sharefs_sharetab = sht;
228 208 }
229 209
230 - /*
231 - * Now we need to find where we have to add the entry.
232 - */
210 + /* Now we need to find where we have to add the entry */
211 + iPath = shl != NULL ? shl->shl_path : strlen(sh->sh_path);
233 212 iHash = pkp_tab_hash(sh->sh_path, strlen(sh->sh_path));
234 213
235 - iPath = shl ? shl->shl_path : strlen(sh->sh_path);
236 -
237 214 if (shl) {
238 215 sh->sh_size = shl->shl_path + shl->shl_res +
239 216 shl->shl_fstype + shl->shl_opts + shl->shl_descr;
240 217 } else {
241 218 sh->sh_size = strlen(sh->sh_path) +
242 219 strlen(sh->sh_res) + strlen(sh->sh_fstype) +
243 220 strlen(sh->sh_opts) + strlen(sh->sh_descr);
244 221 }
245 222
246 - /*
247 - * We need to account for field seperators and
248 - * the EOL.
249 - */
223 + /* We need to account for field separators and the EOL */
250 224 sh->sh_size += 5;
251 225
252 - /*
253 - * Now walk down the hash table and add the new entry!
254 - */
226 + /* Now walk down the hash table and add the new entry */
255 227 for (p = NULL, s = sht->s_buckets[iHash].ssh_sh;
256 228 s != NULL; s = s->sh_next) {
257 229 /*
258 230 * We need exact matches.
259 231 *
260 232 * We found a matching path. Either we have a
261 233 * duplicate path in a share command or we are
262 234 * being asked to replace an existing entry.
263 235 */
264 236 if (strcmp(sh->sh_path, s->sh_path) == 0 &&
265 237 strlen(s->sh_path) == iPath) {
266 - if (p) {
238 + if (p != NULL)
267 239 p->sh_next = sh;
268 - } else {
240 + else
269 241 sht->s_buckets[iHash].ssh_sh = sh;
270 - }
271 242
272 243 sh->sh_next = s->sh_next;
273 244
274 - ASSERT(sharetab_size >= s->sh_size);
275 - sharetab_size -= s->sh_size;
276 - sharetab_size += sh->sh_size;
245 + ASSERT(sg->sharetab_size >= s->sh_size);
246 + sg->sharetab_size -= s->sh_size;
247 + sg->sharetab_size += sh->sh_size;
277 248
278 - /*
279 - * Get rid of the old node.
280 - */
249 + /* Get rid of the old node */
281 250 sharefree(s, NULL);
282 251
283 - gethrestime(&sharetab_mtime);
284 - atomic_inc_32(&sharetab_generation);
252 + gethrestime(&sg->sharetab_mtime);
253 + atomic_inc_32(&sg->sharetab_generation);
285 254
286 255 ASSERT(sht->s_buckets[iHash].ssh_count != 0);
287 - rw_exit(&sharetab_lock);
256 + rw_exit(&sg->sharetab_lock);
288 257
289 258 return (0);
290 259 }
291 260
292 261 p = s;
293 262 }
294 263
295 264 /*
296 265 * Okay, we have gone through the entire hash chain and not
297 266 * found a match. We just need to add this node.
298 267 */
299 268 sh->sh_next = sht->s_buckets[iHash].ssh_sh;
300 269 sht->s_buckets[iHash].ssh_sh = sh;
301 270 atomic_inc_32(&sht->s_buckets[iHash].ssh_count);
302 271 atomic_inc_32(&sht->s_count);
303 - atomic_inc_32(&sharetab_count);
304 - sharetab_size += sh->sh_size;
272 + atomic_inc_32(&sg->sharetab_count);
273 + sg->sharetab_size += sh->sh_size;
305 274
306 - gethrestime(&sharetab_mtime);
307 - atomic_inc_32(&sharetab_generation);
275 + gethrestime(&sg->sharetab_mtime);
276 + atomic_inc_32(&sg->sharetab_generation);
308 277
309 - rw_exit(&sharetab_lock);
278 + rw_exit(&sg->sharetab_lock);
310 279
311 280 return (0);
312 281 }
313 282
283 +/* ARGSUSED */
284 +static void *
285 +sharetab_zone_init(zoneid_t zoneid)
286 +{
287 + sharetab_globals_t *sg;
288 +
289 + sg = kmem_zalloc(sizeof (*sg), KM_SLEEP);
290 +
291 + rw_init(&sg->sharetab_lock, NULL, RW_DEFAULT, NULL);
292 + rw_init(&sg->sharefs_lock, NULL, RW_DEFAULT, NULL);
293 +
294 + sg->sharetab_size = 0;
295 + sg->sharetab_count = 0;
296 + sg->sharetab_generation = 1;
297 +
298 + gethrestime(&sg->sharetab_mtime);
299 + gethrestime(&sg->sharetab_snap_time);
300 +
301 + return (sg);
302 +}
303 +
304 +/* ARGSUSED */
305 +static void
306 +sharetab_zone_fini(zoneid_t zoneid, void *data)
307 +{
308 + sharetab_globals_t *sg = data;
309 +
310 + rw_destroy(&sg->sharefs_lock);
311 + rw_destroy(&sg->sharetab_lock);
312 +
313 + /* ALL of the allocated things must be cleaned before we free sg. */
314 + while (sg->sharefs_sharetab != NULL) {
315 + int i;
316 + sharetab_t *freeing = sg->sharefs_sharetab;
317 +
318 + sg->sharefs_sharetab = freeing->s_next;
319 + kmem_free(freeing->s_fstype, strlen(freeing->s_fstype) + 1);
320 + for (i = 0; i < PKP_HASH_SIZE; i++) {
321 + sharefs_hash_head_t *bucket;
322 +
323 + bucket = &(freeing->s_buckets[i]);
324 + while (bucket->ssh_sh != NULL) {
325 + share_t *share = bucket->ssh_sh;
326 +
327 + bucket->ssh_sh = share->sh_next;
328 + sharefree(share, NULL);
329 + }
330 + }
331 + kmem_free(freeing, sizeof (*freeing));
332 + }
333 +
334 + kmem_free(sg, sizeof (*sg));
335 +}
336 +
314 337 void
315 338 sharefs_sharetab_init(void)
316 339 {
317 - rw_init(&sharetab_lock, NULL, RW_DEFAULT, NULL);
318 - rw_init(&sharefs_lock, NULL, RW_DEFAULT, NULL);
340 + zone_key_create(&sharetab_zone_key, sharetab_zone_init,
341 + NULL, sharetab_zone_fini);
342 +}
319 343
320 - sharetab_size = 0;
321 - sharetab_count = 0;
322 - sharetab_generation = 1;
323 -
324 - gethrestime(&sharetab_mtime);
325 - gethrestime(&sharetab_snap_time);
344 +sharetab_globals_t *
345 +sharetab_get_globals(zone_t *zone)
346 +{
347 + return (zone_getspecific(sharetab_zone_key, zone));
326 348 }
327 349
328 350 int
329 351 sharefs_impl(enum sharefs_sys_op opcode, share_t *sh_in, uint32_t iMaxLen)
330 352 {
331 353 int error = 0;
332 354 size_t len;
333 355 size_t bufsz;
334 356 share_t *sh;
335 -
336 357 sharefs_lens_t shl;
337 -
338 358 model_t model;
339 -
340 359 char *buf = NULL;
360 + sharetab_globals_t *sg = sharetab_get_globals(curzone);
341 361
342 362 STRUCT_DECL(share, u_sh);
343 363
344 364 bufsz = iMaxLen;
345 365
346 366 /*
347 367 * Before we do anything, lets make sure we have
348 368 * a sharetab in memory if we need one.
349 369 */
350 - rw_enter(&sharetab_lock, RW_READER);
370 + rw_enter(&sg->sharetab_lock, RW_READER);
351 371 switch (opcode) {
352 - case (SHAREFS_REMOVE) :
353 - case (SHAREFS_REPLACE) :
354 - if (!sharefs_sharetab) {
355 - rw_exit(&sharetab_lock);
372 + case SHAREFS_REMOVE:
373 + case SHAREFS_REPLACE:
374 + if (!sg->sharefs_sharetab) {
375 + rw_exit(&sg->sharetab_lock);
356 376 return (set_errno(ENOENT));
357 377 }
358 378 break;
359 - case (SHAREFS_ADD) :
360 - default :
379 + case SHAREFS_ADD:
380 + default:
361 381 break;
362 382 }
363 - rw_exit(&sharetab_lock);
383 + rw_exit(&sg->sharetab_lock);
364 384
365 385 model = get_udatamodel();
366 386
367 387 /*
368 388 * Initialize the data pointers.
369 389 */
370 390 STRUCT_INIT(u_sh, model);
371 - if (copyin(sh_in, STRUCT_BUF(u_sh), STRUCT_SIZE(u_sh))) {
391 + if (copyin(sh_in, STRUCT_BUF(u_sh), STRUCT_SIZE(u_sh)))
372 392 return (set_errno(EFAULT));
373 - }
374 393
375 - /*
376 - * Get the share.
377 - */
394 + /* Get the share */
378 395 sh = kmem_zalloc(sizeof (share_t), KM_SLEEP);
379 396
380 - /*
381 - * Get some storage for copying in the strings.
382 - */
397 + /* Get some storage for copying in the strings */
383 398 buf = kmem_zalloc(bufsz + 1, KM_SLEEP);
384 399 bzero(&shl, sizeof (sharefs_lens_t));
385 400
386 - /*
387 - * Only grab these two until we know what we want.
388 - */
401 + /* Only grab these two until we know what we want */
389 402 SHARETAB_COPYIN(path);
390 403 SHARETAB_COPYIN(fstype);
391 404
392 405 switch (opcode) {
393 - case (SHAREFS_ADD) :
394 - case (SHAREFS_REPLACE) :
406 + case SHAREFS_ADD:
407 + case SHAREFS_REPLACE:
395 408 SHARETAB_COPYIN(res);
396 409 SHARETAB_COPYIN(opts);
397 410 SHARETAB_COPYIN(descr);
398 -
399 - error = sharefs_add(sh, &shl);
411 + error = sharefs_add(sg, sh, &shl);
400 412 break;
401 -
402 - case (SHAREFS_REMOVE) :
403 -
404 - error = sharefs_remove(sh, &shl);
413 + case SHAREFS_REMOVE:
414 + error = sharefs_remove(sg, sh, &shl);
405 415 break;
406 -
407 416 default:
408 417 error = EINVAL;
409 418 break;
410 419 }
411 420
412 421 cleanup:
413 -
414 422 /*
415 423 * If there is no error, then we have stashed the structure
416 424 * away in the sharetab hash table or have deleted it.
417 425 *
418 426 * Either way, the only reason to blow away the data is if
419 427 * there was an error.
420 428 */
421 - if (error != 0) {
429 + if (error != 0)
422 430 sharefree(sh, &shl);
423 - }
424 431
425 - if (buf) {
432 + if (buf != NULL)
426 433 kmem_free(buf, bufsz + 1);
427 - }
428 434
429 - return ((error != 0) ? set_errno(error) : 0);
435 + return (error != 0 ? set_errno(error) : 0);
430 436 }
431 437
432 438 int
433 439 sharefs(enum sharefs_sys_op opcode, share_t *sh_in, uint32_t iMaxLen)
434 440 {
435 - if (secpolicy_sys_config(CRED(), B_FALSE) != 0)
436 - return (set_errno(EPERM));
441 + /*
442 + * If we're in the global zone PRIV_SYS_CONFIG gives us the
443 + * privileges needed to act on sharetab. However if we're in
444 + * a non-global zone PRIV_SYS_CONFIG is not allowed. To work
445 + * around this issue PRIV_SYS_NFS is used in this case.
446 + *
447 + * TODO: This basically overloads the definition/use of
448 + * PRIV_SYS_NFS to work around the limitation of PRIV_SYS_CONFIG
449 + * in a zone. Solaris 11 solved this by implementing a PRIV_SYS_SHARE
450 + * we should do the same and replace the use of PRIV_SYS_NFS here and
451 + * in zfs_secpolicy_share.
452 + */
453 + if (INGLOBALZONE(curproc)) {
454 + if (secpolicy_sys_config(CRED(), B_FALSE) != 0)
455 + return (set_errno(EPERM));
456 + } else {
457 + /* behave like zfs_secpolicy_share() */
458 + if (secpolicy_nfs(CRED()) != 0)
459 + return (set_errno(EPERM));
437 460
461 + }
438 462 return (sharefs_impl(opcode, sh_in, iMaxLen));
439 463 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX