1a237e38eSth199096 /*
2a237e38eSth199096 * CDDL HEADER START
3a237e38eSth199096 *
4a237e38eSth199096 * The contents of this file are subject to the terms of the
5a237e38eSth199096 * Common Development and Distribution License (the "License").
6a237e38eSth199096 * You may not use this file except in compliance with the License.
7a237e38eSth199096 *
8a237e38eSth199096 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a237e38eSth199096 * or http://www.opensolaris.org/os/licensing.
10a237e38eSth199096 * See the License for the specific language governing permissions
11a237e38eSth199096 * and limitations under the License.
12a237e38eSth199096 *
13a237e38eSth199096 * When distributing Covered Code, include this CDDL HEADER in each
14a237e38eSth199096 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a237e38eSth199096 * If applicable, add the following below this CDDL HEADER, with the
16a237e38eSth199096 * fields enclosed by brackets "[]" replaced with your own identifying
17a237e38eSth199096 * information: Portions Copyright [yyyy] [name of copyright owner]
18a237e38eSth199096 *
19a237e38eSth199096 * CDDL HEADER END
20a237e38eSth199096 */
21a237e38eSth199096
22a237e38eSth199096 /*
23a237e38eSth199096 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24a237e38eSth199096 * Use is subject to license terms.
25a237e38eSth199096 */
26a237e38eSth199096
27a237e38eSth199096 #include <fs/fs_subr.h>
28a237e38eSth199096
29a237e38eSth199096 #include <sys/errno.h>
30a237e38eSth199096 #include <sys/file.h>
31a237e38eSth199096 #include <sys/kmem.h>
32a237e38eSth199096 #include <sys/kobj.h>
33a237e38eSth199096 #include <sys/cmn_err.h>
34a237e38eSth199096 #include <sys/stat.h>
35a237e38eSth199096 #include <sys/systm.h>
36a237e38eSth199096 #include <sys/sysmacros.h>
37a237e38eSth199096 #include <sys/atomic.h>
38a237e38eSth199096 #include <sys/vfs.h>
39a237e38eSth199096 #include <sys/vfs_opreg.h>
40a237e38eSth199096
41a237e38eSth199096 #include <sharefs/sharefs.h>
42a237e38eSth199096
43a237e38eSth199096 /*
44a237e38eSth199096 * sharefs_snap_create: create a large character buffer with
45a237e38eSth199096 * the shares enumerated.
46a237e38eSth199096 */
47a237e38eSth199096 static int
sharefs_snap_create(shnode_t * sft)48a237e38eSth199096 sharefs_snap_create(shnode_t *sft)
49a237e38eSth199096 {
50a237e38eSth199096 sharetab_t *sht;
51a237e38eSth199096 share_t *sh;
52a237e38eSth199096 size_t sWritten = 0;
53a237e38eSth199096 int iCount = 0;
54a237e38eSth199096 char *buf;
55a237e38eSth199096
56a237e38eSth199096 rw_enter(&sharefs_lock, RW_WRITER);
57a237e38eSth199096 rw_enter(&sharetab_lock, RW_READER);
58a237e38eSth199096
59a237e38eSth199096 if (sft->sharefs_snap) {
60a237e38eSth199096 /*
61a237e38eSth199096 * Nothing has changed, so no need to grab a new copy!
62a237e38eSth199096 */
63a237e38eSth199096 if (sft->sharefs_generation == sharetab_generation) {
64a237e38eSth199096 rw_exit(&sharetab_lock);
65a237e38eSth199096 rw_exit(&sharefs_lock);
66a237e38eSth199096 return (0);
67a237e38eSth199096 }
68a237e38eSth199096
69a237e38eSth199096 ASSERT(sft->sharefs_size != 0);
70a237e38eSth199096 kmem_free(sft->sharefs_snap, sft->sharefs_size + 1);
71a237e38eSth199096 sft->sharefs_snap = NULL;
72a237e38eSth199096 }
73a237e38eSth199096
74a237e38eSth199096 sft->sharefs_size = sharetab_size;
75a237e38eSth199096 sft->sharefs_count = sharetab_count;
76a237e38eSth199096
77a237e38eSth199096 if (sft->sharefs_size == 0) {
78a237e38eSth199096 rw_exit(&sharetab_lock);
79a237e38eSth199096 rw_exit(&sharefs_lock);
80a237e38eSth199096 return (0);
81a237e38eSth199096 }
82a237e38eSth199096
83a237e38eSth199096 sft->sharefs_snap = kmem_zalloc(sft->sharefs_size + 1, KM_SLEEP);
84a237e38eSth199096
85a237e38eSth199096 buf = sft->sharefs_snap;
86a237e38eSth199096
87a237e38eSth199096 /*
88a237e38eSth199096 * Walk the Sharetab, dumping each entry.
89a237e38eSth199096 */
90a237e38eSth199096 for (sht = sharefs_sharetab; sht != NULL; sht = sht->s_next) {
91a237e38eSth199096 int i;
92a237e38eSth199096
93a237e38eSth199096 for (i = 0; i < SHARETAB_HASHES; i++) {
94a237e38eSth199096 for (sh = sht->s_buckets[i].ssh_sh;
95a237e38eSth199096 sh != NULL;
96a237e38eSth199096 sh = sh->sh_next) {
97a237e38eSth199096 int n;
98a237e38eSth199096
99a237e38eSth199096 if ((sWritten + sh->sh_size) >
100a237e38eSth199096 sft->sharefs_size) {
101a237e38eSth199096 goto error_fault;
102a237e38eSth199096 }
103a237e38eSth199096
104a237e38eSth199096 /*
105a237e38eSth199096 * Note that sh->sh_size accounts
106a237e38eSth199096 * for the field seperators.
107a237e38eSth199096 * We need to add one for the EOL
108a237e38eSth199096 * marker. And we should note that
109a237e38eSth199096 * the space is accounted for in
110a237e38eSth199096 * each share by the EOS marker.
111a237e38eSth199096 */
112a237e38eSth199096 n = snprintf(&buf[sWritten],
113a237e38eSth199096 sh->sh_size + 1,
114a237e38eSth199096 "%s\t%s\t%s\t%s\t%s\n",
115a237e38eSth199096 sh->sh_path,
116a237e38eSth199096 sh->sh_res,
117a237e38eSth199096 sh->sh_fstype,
118a237e38eSth199096 sh->sh_opts,
119a237e38eSth199096 sh->sh_descr);
120a237e38eSth199096
121a237e38eSth199096 if (n != sh->sh_size) {
122a237e38eSth199096 goto error_fault;
123a237e38eSth199096 }
124a237e38eSth199096
125a237e38eSth199096 sWritten += n;
126a237e38eSth199096 iCount++;
127a237e38eSth199096 }
128a237e38eSth199096 }
129a237e38eSth199096 }
130a237e38eSth199096
131a237e38eSth199096 /*
132a237e38eSth199096 * We want to record the generation number and
133a237e38eSth199096 * mtime inside this snapshot.
134a237e38eSth199096 */
135a237e38eSth199096 gethrestime(&sharetab_snap_time);
136a237e38eSth199096 sft->sharefs_snap_time = sharetab_snap_time;
137a237e38eSth199096 sft->sharefs_generation = sharetab_generation;
138a237e38eSth199096
139a237e38eSth199096 ASSERT(iCount == sft->sharefs_count);
140a237e38eSth199096
141a237e38eSth199096 rw_exit(&sharetab_lock);
142a237e38eSth199096 rw_exit(&sharefs_lock);
143a237e38eSth199096 return (0);
144a237e38eSth199096
145a237e38eSth199096 error_fault:
146a237e38eSth199096
147a237e38eSth199096 kmem_free(sft->sharefs_snap, sft->sharefs_size + 1);
148a237e38eSth199096 sft->sharefs_size = 0;
149a237e38eSth199096 sft->sharefs_count = 0;
150a237e38eSth199096 sft->sharefs_snap = NULL;
151a237e38eSth199096 rw_exit(&sharetab_lock);
152a237e38eSth199096 rw_exit(&sharefs_lock);
153a237e38eSth199096
154a237e38eSth199096 return (EFAULT);
155a237e38eSth199096 }
156a237e38eSth199096
157a237e38eSth199096 /* ARGSUSED */
158a237e38eSth199096 static int
sharefs_getattr(vnode_t * vp,vattr_t * vap,int flags,cred_t * cr,caller_context_t * ct)159da6c28aaSamw sharefs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
160da6c28aaSamw caller_context_t *ct)
161a237e38eSth199096 {
162a237e38eSth199096 timestruc_t now;
163a237e38eSth199096 shnode_t *sft = VTOSH(vp);
164a237e38eSth199096
165a237e38eSth199096 vap->va_type = VREG;
166a237e38eSth199096 vap->va_mode = S_IRUSR | S_IRGRP | S_IROTH;
167a237e38eSth199096 vap->va_nodeid = SHAREFS_INO_FILE;
168a237e38eSth199096 vap->va_nlink = 1;
169a237e38eSth199096
170a237e38eSth199096 rw_enter(&sharefs_lock, RW_READER);
171a237e38eSth199096
172a237e38eSth199096 /*
173a237e38eSth199096 * If we get asked about a snapped vnode, then
174a237e38eSth199096 * we must report the data in that vnode.
175a237e38eSth199096 *
176a237e38eSth199096 * Else we report what is currently in the
177a237e38eSth199096 * sharetab.
178a237e38eSth199096 */
179a237e38eSth199096 if (sft->sharefs_real_vp) {
180a237e38eSth199096 rw_enter(&sharetab_lock, RW_READER);
181a237e38eSth199096 vap->va_size = sharetab_size;
182a237e38eSth199096 vap->va_mtime = sharetab_mtime;
183a237e38eSth199096 rw_exit(&sharetab_lock);
184a237e38eSth199096 } else {
185a237e38eSth199096 vap->va_size = sft->sharefs_size;
186a237e38eSth199096 vap->va_mtime = sft->sharefs_snap_time;
187a237e38eSth199096 }
188a237e38eSth199096 rw_exit(&sharefs_lock);
189a237e38eSth199096
190a237e38eSth199096 gethrestime(&now);
191a237e38eSth199096 vap->va_atime = vap->va_ctime = now;
192a237e38eSth199096
193a237e38eSth199096 vap->va_uid = 0;
194a237e38eSth199096 vap->va_gid = 0;
195a237e38eSth199096 vap->va_rdev = 0;
196a237e38eSth199096 vap->va_blksize = DEV_BSIZE;
197a237e38eSth199096 vap->va_nblocks = howmany(vap->va_size, vap->va_blksize);
198a237e38eSth199096 vap->va_seq = 0;
199a237e38eSth199096 vap->va_fsid = vp->v_vfsp->vfs_dev;
200a237e38eSth199096
201a237e38eSth199096 return (0);
202a237e38eSth199096 }
203a237e38eSth199096
204a237e38eSth199096 /* ARGSUSED */
205a237e38eSth199096 static int
sharefs_access(vnode_t * vp,int mode,int flags,cred_t * cr,caller_context_t * ct)206da6c28aaSamw sharefs_access(vnode_t *vp, int mode, int flags, cred_t *cr,
207da6c28aaSamw caller_context_t *ct)
208a237e38eSth199096 {
209a237e38eSth199096 if (mode & (VWRITE|VEXEC))
210a237e38eSth199096 return (EROFS);
211a237e38eSth199096
212a237e38eSth199096 return (0);
213a237e38eSth199096 }
214a237e38eSth199096
215a237e38eSth199096 /* ARGSUSED */
216a237e38eSth199096 int
sharefs_open(vnode_t ** vpp,int flag,cred_t * cr,caller_context_t * ct)217da6c28aaSamw sharefs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
218a237e38eSth199096 {
219a237e38eSth199096 vnode_t *vp;
220a237e38eSth199096 vnode_t *ovp = *vpp;
221a237e38eSth199096 shnode_t *sft;
222a237e38eSth199096 int error = 0;
223a237e38eSth199096
224a237e38eSth199096 if (flag & FWRITE)
225a237e38eSth199096 return (EINVAL);
226a237e38eSth199096
227a237e38eSth199096 /*
228a237e38eSth199096 * Create a new sharefs vnode for each operation. In order to
229a237e38eSth199096 * avoid locks, we create a snapshot which can not change during
230a237e38eSth199096 * reads.
231a237e38eSth199096 */
232a237e38eSth199096 vp = gfs_file_create(sizeof (shnode_t), NULL, sharefs_ops_data);
233a237e38eSth199096
234a237e38eSth199096 ((gfs_file_t *)vp->v_data)->gfs_ino = SHAREFS_INO_FILE;
235a237e38eSth199096
236a237e38eSth199096 /*
237a237e38eSth199096 * Hold the parent!
238a237e38eSth199096 */
239a237e38eSth199096 VFS_HOLD(ovp->v_vfsp);
240a237e38eSth199096
241a237e38eSth199096 VN_SET_VFS_TYPE_DEV(vp, ovp->v_vfsp, VREG, 0);
242a237e38eSth199096
243a237e38eSth199096 vp->v_flag |= VROOT | VNOCACHE | VNOMAP | VNOSWAP | VNOMOUNT;
244a237e38eSth199096
245a237e38eSth199096 *vpp = vp;
246a237e38eSth199096 VN_RELE(ovp);
247a237e38eSth199096
248a237e38eSth199096 sft = VTOSH(vp);
249a237e38eSth199096
250a237e38eSth199096 /*
251a237e38eSth199096 * No need for the lock, no other thread can be accessing
252a237e38eSth199096 * this data structure.
253a237e38eSth199096 */
254*1a5e258fSJosef 'Jeff' Sipek atomic_inc_32(&sft->sharefs_refs);
255a237e38eSth199096 sft->sharefs_real_vp = 0;
256a237e38eSth199096
257a237e38eSth199096 /*
258a237e38eSth199096 * Since the sharetab could easily change on us whilst we
259a237e38eSth199096 * are dumping an extremely huge sharetab, we make a copy
260a237e38eSth199096 * of it here and use it to dump instead.
261a237e38eSth199096 */
262a237e38eSth199096 error = sharefs_snap_create(sft);
263a237e38eSth199096
264a237e38eSth199096 return (error);
265a237e38eSth199096 }
266a237e38eSth199096
267a237e38eSth199096 /* ARGSUSED */
268a237e38eSth199096 int
sharefs_close(vnode_t * vp,int flag,int count,offset_t off,cred_t * cr,caller_context_t * ct)269a237e38eSth199096 sharefs_close(vnode_t *vp, int flag, int count,
270da6c28aaSamw offset_t off, cred_t *cr, caller_context_t *ct)
271a237e38eSth199096 {
272a237e38eSth199096 shnode_t *sft = VTOSH(vp);
273a237e38eSth199096
274a237e38eSth199096 if (count > 1)
275a237e38eSth199096 return (0);
276a237e38eSth199096
277a237e38eSth199096 rw_enter(&sharefs_lock, RW_WRITER);
278a237e38eSth199096 if (vp->v_count == 1) {
279a237e38eSth199096 if (sft->sharefs_snap != NULL) {
280a237e38eSth199096 kmem_free(sft->sharefs_snap, sft->sharefs_size + 1);
281a237e38eSth199096 sft->sharefs_size = 0;
282a237e38eSth199096 sft->sharefs_snap = NULL;
283a237e38eSth199096 sft->sharefs_generation = 0;
284a237e38eSth199096 }
285a237e38eSth199096 }
286*1a5e258fSJosef 'Jeff' Sipek atomic_dec_32(&sft->sharefs_refs);
287a237e38eSth199096 rw_exit(&sharefs_lock);
288a237e38eSth199096
289a237e38eSth199096 return (0);
290a237e38eSth199096 }
291a237e38eSth199096
292a237e38eSth199096 /* ARGSUSED */
293a237e38eSth199096 static int
sharefs_read(vnode_t * vp,uio_t * uio,int ioflag,cred_t * cr,caller_context_t * ct)294a237e38eSth199096 sharefs_read(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr,
295a237e38eSth199096 caller_context_t *ct)
296a237e38eSth199096 {
297a237e38eSth199096 shnode_t *sft = VTOSH(vp);
298a237e38eSth199096 off_t off = uio->uio_offset;
299a237e38eSth199096 size_t len = uio->uio_resid;
300a237e38eSth199096 int error = 0;
301a237e38eSth199096
302a237e38eSth199096 rw_enter(&sharefs_lock, RW_READER);
303a237e38eSth199096
304a237e38eSth199096 /*
305a237e38eSth199096 * First check to see if we need to grab a new snapshot.
306a237e38eSth199096 */
307a237e38eSth199096 if (off == (off_t)0) {
308a237e38eSth199096 rw_exit(&sharefs_lock);
309a237e38eSth199096 error = sharefs_snap_create(sft);
310a237e38eSth199096 if (error) {
311a237e38eSth199096 return (EFAULT);
312a237e38eSth199096 }
313a237e38eSth199096 rw_enter(&sharefs_lock, RW_READER);
314a237e38eSth199096 }
315a237e38eSth199096
316a237e38eSth199096 /* LINTED */
317a237e38eSth199096 if (len <= 0 || off >= sft->sharefs_size) {
318a237e38eSth199096 rw_exit(&sharefs_lock);
319a237e38eSth199096 return (error);
320a237e38eSth199096 }
321a237e38eSth199096
322a237e38eSth199096 if ((size_t)(off + len) > sft->sharefs_size)
323a237e38eSth199096 len = sft->sharefs_size - off;
324a237e38eSth199096
325a237e38eSth199096 if (off < 0 || len > sft->sharefs_size) {
326a237e38eSth199096 rw_exit(&sharefs_lock);
327a237e38eSth199096 return (EFAULT);
328a237e38eSth199096 }
329a237e38eSth199096
330a237e38eSth199096 if (len != 0) {
331a237e38eSth199096 error = uiomove(sft->sharefs_snap + off,
332a237e38eSth199096 len, UIO_READ, uio);
333a237e38eSth199096 }
334a237e38eSth199096
335a237e38eSth199096 rw_exit(&sharefs_lock);
336a237e38eSth199096 return (error);
337a237e38eSth199096 }
338a237e38eSth199096
339a237e38eSth199096 /* ARGSUSED */
340a237e38eSth199096 static void
sharefs_inactive(vnode_t * vp,cred_t * cr,caller_context_t * tx)341da6c28aaSamw sharefs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *tx)
342a237e38eSth199096 {
343a237e38eSth199096 gfs_file_t *fp = vp->v_data;
344a237e38eSth199096 shnode_t *sft;
345a237e38eSth199096
346a237e38eSth199096 sft = (shnode_t *)gfs_file_inactive(vp);
347a237e38eSth199096 if (sft) {
348a237e38eSth199096 rw_enter(&sharefs_lock, RW_WRITER);
349a237e38eSth199096 if (sft->sharefs_snap != NULL) {
350a237e38eSth199096 kmem_free(sft->sharefs_snap, sft->sharefs_size + 1);
351a237e38eSth199096 }
352a237e38eSth199096
353a237e38eSth199096 kmem_free(sft, fp->gfs_size);
354a237e38eSth199096 rw_exit(&sharefs_lock);
355a237e38eSth199096 }
356a237e38eSth199096 }
357a237e38eSth199096
358a237e38eSth199096 vnode_t *
sharefs_create_root_file(vfs_t * vfsp)359a237e38eSth199096 sharefs_create_root_file(vfs_t *vfsp)
360a237e38eSth199096 {
361a237e38eSth199096 vnode_t *vp;
362a237e38eSth199096 shnode_t *sft;
363a237e38eSth199096
364a237e38eSth199096 vp = gfs_root_create_file(sizeof (shnode_t),
365a237e38eSth199096 vfsp, sharefs_ops_data, SHAREFS_INO_FILE);
366a237e38eSth199096
367a237e38eSth199096 sft = VTOSH(vp);
368a237e38eSth199096
369a237e38eSth199096 sft->sharefs_real_vp = 1;
370a237e38eSth199096
371a237e38eSth199096 return (vp);
372a237e38eSth199096 }
373a237e38eSth199096
374a237e38eSth199096 const fs_operation_def_t sharefs_tops_data[] = {
375a237e38eSth199096 { VOPNAME_OPEN, { .vop_open = sharefs_open } },
376a237e38eSth199096 { VOPNAME_CLOSE, { .vop_close = sharefs_close } },
377a237e38eSth199096 { VOPNAME_IOCTL, { .error = fs_inval } },
378a237e38eSth199096 { VOPNAME_GETATTR, { .vop_getattr = sharefs_getattr } },
379a237e38eSth199096 { VOPNAME_ACCESS, { .vop_access = sharefs_access } },
380a237e38eSth199096 { VOPNAME_INACTIVE, { .vop_inactive = sharefs_inactive } },
381a237e38eSth199096 { VOPNAME_READ, { .vop_read = sharefs_read } },
382a237e38eSth199096 { VOPNAME_SEEK, { .vop_seek = fs_seek } },
383a237e38eSth199096 { NULL }
384a237e38eSth199096 };
385