4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/types.h>
27 #include <sys/types32.h>
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <rpc/types.h>
32 #include <sys/siginfo.h>
33 #include <sys/proc.h> /* for exit() declaration */
35 #include <sys/pathname.h>
36 #include <sys/debug.h>
37 #include <sys/vtrace.h>
38 #include <sys/cmn_err.h>
39 #include <sys/atomic.h>
40 #include <sys/policy.h>
42 #include <sharefs/sharefs.h>
45 * A macro to avoid cut-and-paste errors on getting a string field
48 #define SHARETAB_COPYIN(field) \
49 if (copyinstr(STRUCT_FGETP(u_sh, sh_##field), \
51 bufsz + 1, /* Add one for extra NUL */ \
57 * Need to remove 1 because copyinstr() counts the NUL. \
60 sh->sh_##field = kmem_alloc(len + 1, KM_SLEEP); \
61 bcopy(buf, sh->sh_##field, len); \
62 sh->sh_##field[len] = '\0'; \
63 shl.shl_##field = (int)len; \
64 sh->sh_size += shl.shl_##field; /* Debug counting */
66 #define SHARETAB_DELETE_FIELD(field) \
67 if (sh->sh_##field) { \
68 kmem_free(sh->sh_##field, \
69 shl ? shl->shl_##field + 1 : \
70 strlen(sh->sh_##field) + 1); \
73 sharetab_t
*sharefs_sharetab
= NULL
; /* The incore sharetab. */
75 uint_t sharetab_count
;
77 krwlock_t sharetab_lock
; /* lock to protect the cached sharetab */
79 krwlock_t sharefs_lock
; /* lock to protect the vnode ops */
81 timestruc_t sharetab_mtime
;
82 timestruc_t sharetab_snap_time
;
84 uint_t sharetab_generation
; /* Only increments and wraps! */
87 * Take care of cleaning up a share.
88 * If passed in a length array, use it to determine how much
89 * space to clean up. Else, figure that out.
92 sharefree(share_t
*sh
, sharefs_lens_t
*shl
)
97 SHARETAB_DELETE_FIELD(path
);
98 SHARETAB_DELETE_FIELD(res
);
99 SHARETAB_DELETE_FIELD(fstype
);
100 SHARETAB_DELETE_FIELD(opts
);
101 SHARETAB_DELETE_FIELD(descr
);
103 kmem_free(sh
, sizeof (share_t
));
107 * If there is no error, then this function is responsible for
108 * cleaning up the memory associated with the share argument.
111 sharefs_remove(share_t
*sh
, sharefs_lens_t
*shl
)
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) {
129 * There does not exist a fstype in memory which
130 * matches the share passed in.
133 rw_exit(&sharetab_lock
);
137 iPath
= shl
? shl
->shl_path
: strlen(sh
->sh_path
);
138 iHash
= pkp_tab_hash(sh
->sh_path
, strlen(sh
->sh_path
));
141 * Now walk down the hash table and find the entry to free!
143 for (p
= NULL
, s
= sht
->s_buckets
[iHash
].ssh_sh
;
144 s
!= NULL
; s
= s
->sh_next
) {
146 * We need exact matches.
148 if (strcmp(sh
->sh_path
, s
->sh_path
) == 0 &&
149 strlen(s
->sh_path
) == iPath
) {
151 p
->sh_next
= s
->sh_next
;
153 sht
->s_buckets
[iHash
].ssh_sh
= s
->sh_next
;
156 ASSERT(sht
->s_buckets
[iHash
].ssh_count
!= 0);
157 atomic_dec_32(&sht
->s_buckets
[iHash
].ssh_count
);
158 atomic_dec_32(&sht
->s_count
);
159 atomic_dec_32(&sharetab_count
);
161 ASSERT(sharetab_size
>= s
->sh_size
);
162 sharetab_size
-= s
->sh_size
;
164 gethrestime(&sharetab_mtime
);
165 atomic_inc_32(&sharetab_generation
);
173 rw_exit(&sharetab_lock
);
183 * We need to free the share for the caller.
191 * The caller must have allocated memory for us to use.
194 sharefs_add(share_t
*sh
, sharefs_lens_t
*shl
)
207 * We need to find the hash buckets for the fstype.
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) {
217 * Did not exist, so allocate one and add it to the
221 sht
= kmem_zalloc(sizeof (*sht
), KM_SLEEP
);
222 n
= strlen(sh
->sh_fstype
);
223 sht
->s_fstype
= kmem_zalloc(n
+ 1, KM_SLEEP
);
224 (void) strncpy(sht
->s_fstype
, sh
->sh_fstype
, n
);
226 sht
->s_next
= sharefs_sharetab
;
227 sharefs_sharetab
= sht
;
231 * Now we need to find where we have to add the entry.
233 iHash
= pkp_tab_hash(sh
->sh_path
, strlen(sh
->sh_path
));
235 iPath
= shl
? shl
->shl_path
: strlen(sh
->sh_path
);
238 sh
->sh_size
= shl
->shl_path
+ shl
->shl_res
+
239 shl
->shl_fstype
+ shl
->shl_opts
+ shl
->shl_descr
;
241 sh
->sh_size
= strlen(sh
->sh_path
) +
242 strlen(sh
->sh_res
) + strlen(sh
->sh_fstype
) +
243 strlen(sh
->sh_opts
) + strlen(sh
->sh_descr
);
247 * We need to account for field seperators and
253 * Now walk down the hash table and add the new entry!
255 for (p
= NULL
, s
= sht
->s_buckets
[iHash
].ssh_sh
;
256 s
!= NULL
; s
= s
->sh_next
) {
258 * We need exact matches.
260 * We found a matching path. Either we have a
261 * duplicate path in a share command or we are
262 * being asked to replace an existing entry.
264 if (strcmp(sh
->sh_path
, s
->sh_path
) == 0 &&
265 strlen(s
->sh_path
) == iPath
) {
269 sht
->s_buckets
[iHash
].ssh_sh
= sh
;
272 sh
->sh_next
= s
->sh_next
;
274 ASSERT(sharetab_size
>= s
->sh_size
);
275 sharetab_size
-= s
->sh_size
;
276 sharetab_size
+= sh
->sh_size
;
279 * Get rid of the old node.
283 gethrestime(&sharetab_mtime
);
284 atomic_inc_32(&sharetab_generation
);
286 ASSERT(sht
->s_buckets
[iHash
].ssh_count
!= 0);
287 rw_exit(&sharetab_lock
);
296 * Okay, we have gone through the entire hash chain and not
297 * found a match. We just need to add this node.
299 sh
->sh_next
= sht
->s_buckets
[iHash
].ssh_sh
;
300 sht
->s_buckets
[iHash
].ssh_sh
= sh
;
301 atomic_inc_32(&sht
->s_buckets
[iHash
].ssh_count
);
302 atomic_inc_32(&sht
->s_count
);
303 atomic_inc_32(&sharetab_count
);
304 sharetab_size
+= sh
->sh_size
;
306 gethrestime(&sharetab_mtime
);
307 atomic_inc_32(&sharetab_generation
);
309 rw_exit(&sharetab_lock
);
315 sharefs_sharetab_init(void)
317 rw_init(&sharetab_lock
, NULL
, RW_DEFAULT
, NULL
);
318 rw_init(&sharefs_lock
, NULL
, RW_DEFAULT
, NULL
);
322 sharetab_generation
= 1;
324 gethrestime(&sharetab_mtime
);
325 gethrestime(&sharetab_snap_time
);
329 sharefs_impl(enum sharefs_sys_op opcode
, share_t
*sh_in
, uint32_t iMaxLen
)
342 STRUCT_DECL(share
, u_sh
);
347 * Before we do anything, lets make sure we have
348 * a sharetab in memory if we need one.
350 rw_enter(&sharetab_lock
, RW_READER
);
352 case (SHAREFS_REMOVE
) :
353 case (SHAREFS_REPLACE
) :
354 if (!sharefs_sharetab
) {
355 rw_exit(&sharetab_lock
);
356 return (set_errno(ENOENT
));
363 rw_exit(&sharetab_lock
);
365 model
= get_udatamodel();
368 * Initialize the data pointers.
370 STRUCT_INIT(u_sh
, model
);
371 if (copyin(sh_in
, STRUCT_BUF(u_sh
), STRUCT_SIZE(u_sh
))) {
372 return (set_errno(EFAULT
));
378 sh
= kmem_zalloc(sizeof (share_t
), KM_SLEEP
);
381 * Get some storage for copying in the strings.
383 buf
= kmem_zalloc(bufsz
+ 1, KM_SLEEP
);
384 bzero(&shl
, sizeof (sharefs_lens_t
));
387 * Only grab these two until we know what we want.
389 SHARETAB_COPYIN(path
);
390 SHARETAB_COPYIN(fstype
);
394 case (SHAREFS_REPLACE
) :
395 SHARETAB_COPYIN(res
);
396 SHARETAB_COPYIN(opts
);
397 SHARETAB_COPYIN(descr
);
399 error
= sharefs_add(sh
, &shl
);
402 case (SHAREFS_REMOVE
) :
404 error
= sharefs_remove(sh
, &shl
);
415 * If there is no error, then we have stashed the structure
416 * away in the sharetab hash table or have deleted it.
418 * Either way, the only reason to blow away the data is if
419 * there was an error.
426 kmem_free(buf
, bufsz
+ 1);
429 return ((error
!= 0) ? set_errno(error
) : 0);
433 sharefs(enum sharefs_sys_op opcode
, share_t
*sh_in
, uint32_t iMaxLen
)
435 if (secpolicy_sys_config(CRED(), B_FALSE
) != 0)
436 return (set_errno(EPERM
));
438 return (sharefs_impl(opcode
, sh_in
, iMaxLen
));