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