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 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <fs/fs_subr.h>
29 #include <sys/errno.h>
33 #include <sys/cmn_err.h>
35 #include <sys/systm.h>
36 #include <sys/sysmacros.h>
37 #include <sys/atomic.h>
39 #include <sys/vfs_opreg.h>
41 #include <sharefs/sharefs.h>
44 * sharefs_snap_create: create a large character buffer with
45 * the shares enumerated.
48 sharefs_snap_create(shnode_t
*sft
)
56 rw_enter(&sharefs_lock
, RW_WRITER
);
57 rw_enter(&sharetab_lock
, RW_READER
);
59 if (sft
->sharefs_snap
) {
61 * Nothing has changed, so no need to grab a new copy!
63 if (sft
->sharefs_generation
== sharetab_generation
) {
64 rw_exit(&sharetab_lock
);
65 rw_exit(&sharefs_lock
);
69 ASSERT(sft
->sharefs_size
!= 0);
70 kmem_free(sft
->sharefs_snap
, sft
->sharefs_size
+ 1);
71 sft
->sharefs_snap
= NULL
;
74 sft
->sharefs_size
= sharetab_size
;
75 sft
->sharefs_count
= sharetab_count
;
77 if (sft
->sharefs_size
== 0) {
78 rw_exit(&sharetab_lock
);
79 rw_exit(&sharefs_lock
);
83 sft
->sharefs_snap
= kmem_zalloc(sft
->sharefs_size
+ 1, KM_SLEEP
);
85 buf
= sft
->sharefs_snap
;
88 * Walk the Sharetab, dumping each entry.
90 for (sht
= sharefs_sharetab
; sht
!= NULL
; sht
= sht
->s_next
) {
93 for (i
= 0; i
< SHARETAB_HASHES
; i
++) {
94 for (sh
= sht
->s_buckets
[i
].ssh_sh
;
99 if ((sWritten
+ sh
->sh_size
) >
105 * Note that sh->sh_size accounts
106 * for the field seperators.
107 * We need to add one for the EOL
108 * marker. And we should note that
109 * the space is accounted for in
110 * each share by the EOS marker.
112 n
= snprintf(&buf
[sWritten
],
114 "%s\t%s\t%s\t%s\t%s\n",
121 if (n
!= sh
->sh_size
) {
132 * We want to record the generation number and
133 * mtime inside this snapshot.
135 gethrestime(&sharetab_snap_time
);
136 sft
->sharefs_snap_time
= sharetab_snap_time
;
137 sft
->sharefs_generation
= sharetab_generation
;
139 ASSERT(iCount
== sft
->sharefs_count
);
141 rw_exit(&sharetab_lock
);
142 rw_exit(&sharefs_lock
);
147 kmem_free(sft
->sharefs_snap
, sft
->sharefs_size
+ 1);
148 sft
->sharefs_size
= 0;
149 sft
->sharefs_count
= 0;
150 sft
->sharefs_snap
= NULL
;
151 rw_exit(&sharetab_lock
);
152 rw_exit(&sharefs_lock
);
159 sharefs_getattr(vnode_t
*vp
, vattr_t
*vap
, int flags
, cred_t
*cr
,
160 caller_context_t
*ct
)
163 shnode_t
*sft
= VTOSH(vp
);
166 vap
->va_mode
= S_IRUSR
| S_IRGRP
| S_IROTH
;
167 vap
->va_nodeid
= SHAREFS_INO_FILE
;
170 rw_enter(&sharefs_lock
, RW_READER
);
173 * If we get asked about a snapped vnode, then
174 * we must report the data in that vnode.
176 * Else we report what is currently in the
179 if (sft
->sharefs_real_vp
) {
180 rw_enter(&sharetab_lock
, RW_READER
);
181 vap
->va_size
= sharetab_size
;
182 vap
->va_mtime
= sharetab_mtime
;
183 rw_exit(&sharetab_lock
);
185 vap
->va_size
= sft
->sharefs_size
;
186 vap
->va_mtime
= sft
->sharefs_snap_time
;
188 rw_exit(&sharefs_lock
);
191 vap
->va_atime
= vap
->va_ctime
= now
;
196 vap
->va_blksize
= DEV_BSIZE
;
197 vap
->va_nblocks
= howmany(vap
->va_size
, vap
->va_blksize
);
199 vap
->va_fsid
= vp
->v_vfsp
->vfs_dev
;
206 sharefs_access(vnode_t
*vp
, int mode
, int flags
, cred_t
*cr
,
207 caller_context_t
*ct
)
209 if (mode
& (VWRITE
|VEXEC
))
217 sharefs_open(vnode_t
**vpp
, int flag
, cred_t
*cr
, caller_context_t
*ct
)
228 * Create a new sharefs vnode for each operation. In order to
229 * avoid locks, we create a snapshot which can not change during
232 vp
= gfs_file_create(sizeof (shnode_t
), NULL
, sharefs_ops_data
);
234 ((gfs_file_t
*)vp
->v_data
)->gfs_ino
= SHAREFS_INO_FILE
;
239 VFS_HOLD(ovp
->v_vfsp
);
241 VN_SET_VFS_TYPE_DEV(vp
, ovp
->v_vfsp
, VREG
, 0);
243 vp
->v_flag
|= VROOT
| VNOCACHE
| VNOMAP
| VNOSWAP
| VNOMOUNT
;
251 * No need for the lock, no other thread can be accessing
252 * this data structure.
254 atomic_inc_32(&sft
->sharefs_refs
);
255 sft
->sharefs_real_vp
= 0;
258 * Since the sharetab could easily change on us whilst we
259 * are dumping an extremely huge sharetab, we make a copy
260 * of it here and use it to dump instead.
262 error
= sharefs_snap_create(sft
);
269 sharefs_close(vnode_t
*vp
, int flag
, int count
,
270 offset_t off
, cred_t
*cr
, caller_context_t
*ct
)
272 shnode_t
*sft
= VTOSH(vp
);
277 rw_enter(&sharefs_lock
, RW_WRITER
);
278 if (vp
->v_count
== 1) {
279 if (sft
->sharefs_snap
!= NULL
) {
280 kmem_free(sft
->sharefs_snap
, sft
->sharefs_size
+ 1);
281 sft
->sharefs_size
= 0;
282 sft
->sharefs_snap
= NULL
;
283 sft
->sharefs_generation
= 0;
286 atomic_dec_32(&sft
->sharefs_refs
);
287 rw_exit(&sharefs_lock
);
294 sharefs_read(vnode_t
*vp
, uio_t
*uio
, int ioflag
, cred_t
*cr
,
295 caller_context_t
*ct
)
297 shnode_t
*sft
= VTOSH(vp
);
298 off_t off
= uio
->uio_offset
;
299 size_t len
= uio
->uio_resid
;
302 rw_enter(&sharefs_lock
, RW_READER
);
305 * First check to see if we need to grab a new snapshot.
307 if (off
== (off_t
)0) {
308 rw_exit(&sharefs_lock
);
309 error
= sharefs_snap_create(sft
);
313 rw_enter(&sharefs_lock
, RW_READER
);
317 if (len
<= 0 || off
>= sft
->sharefs_size
) {
318 rw_exit(&sharefs_lock
);
322 if ((size_t)(off
+ len
) > sft
->sharefs_size
)
323 len
= sft
->sharefs_size
- off
;
325 if (off
< 0 || len
> sft
->sharefs_size
) {
326 rw_exit(&sharefs_lock
);
331 error
= uiomove(sft
->sharefs_snap
+ off
,
335 rw_exit(&sharefs_lock
);
341 sharefs_inactive(vnode_t
*vp
, cred_t
*cr
, caller_context_t
*tx
)
343 gfs_file_t
*fp
= vp
->v_data
;
346 sft
= (shnode_t
*)gfs_file_inactive(vp
);
348 rw_enter(&sharefs_lock
, RW_WRITER
);
349 if (sft
->sharefs_snap
!= NULL
) {
350 kmem_free(sft
->sharefs_snap
, sft
->sharefs_size
+ 1);
353 kmem_free(sft
, fp
->gfs_size
);
354 rw_exit(&sharefs_lock
);
359 sharefs_create_root_file(vfs_t
*vfsp
)
364 vp
= gfs_root_create_file(sizeof (shnode_t
),
365 vfsp
, sharefs_ops_data
, SHAREFS_INO_FILE
);
369 sft
->sharefs_real_vp
= 1;
374 const fs_operation_def_t sharefs_tops_data
[] = {
375 { VOPNAME_OPEN
, { .vop_open
= sharefs_open
} },
376 { VOPNAME_CLOSE
, { .vop_close
= sharefs_close
} },
377 { VOPNAME_IOCTL
, { .error
= fs_inval
} },
378 { VOPNAME_GETATTR
, { .vop_getattr
= sharefs_getattr
} },
379 { VOPNAME_ACCESS
, { .vop_access
= sharefs_access
} },
380 { VOPNAME_INACTIVE
, { .vop_inactive
= sharefs_inactive
} },
381 { VOPNAME_READ
, { .vop_read
= sharefs_read
} },
382 { VOPNAME_SEEK
, { .vop_seek
= fs_seek
} },