xref: /titanic_53/usr/src/uts/common/fs/sharefs/sharefs_vnops.c (revision 1a5e258f5471356ca102c7176637cdce45bac147)
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