dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / kernel / fs / sharefs / sharefs_vnops.c
blob91cd6728d23aec155cece4e1b41c415c7a9de707
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <sys/fs_subr.h>
29 #include <sys/errno.h>
30 #include <sys/file.h>
31 #include <sys/kmem.h>
32 #include <sys/kobj.h>
33 #include <sys/cmn_err.h>
34 #include <sys/stat.h>
35 #include <sys/systm.h>
36 #include <sys/sysmacros.h>
37 #include <sys/atomic.h>
38 #include <sys/vfs.h>
40 #include <sharefs/sharefs.h>
42 static const struct vnodeops sharefs_ops_data;
45 * sharefs_snap_create: create a large character buffer with
46 * the shares enumerated.
48 static int
49 sharefs_snap_create(shnode_t *sft)
51 sharetab_t *sht;
52 share_t *sh;
53 size_t sWritten = 0;
54 int iCount = 0;
55 char *buf;
57 rw_enter(&sharefs_lock, RW_WRITER);
58 rw_enter(&sharetab_lock, RW_READER);
60 if (sft->sharefs_snap) {
62 * Nothing has changed, so no need to grab a new copy!
64 if (sft->sharefs_generation == sharetab_generation) {
65 rw_exit(&sharetab_lock);
66 rw_exit(&sharefs_lock);
67 return (0);
70 ASSERT(sft->sharefs_size != 0);
71 kmem_free(sft->sharefs_snap, sft->sharefs_size + 1);
72 sft->sharefs_snap = NULL;
75 sft->sharefs_size = sharetab_size;
76 sft->sharefs_count = sharetab_count;
78 if (sft->sharefs_size == 0) {
79 rw_exit(&sharetab_lock);
80 rw_exit(&sharefs_lock);
81 return (0);
84 sft->sharefs_snap = kmem_zalloc(sft->sharefs_size + 1, KM_SLEEP);
86 buf = sft->sharefs_snap;
89 * Walk the Sharetab, dumping each entry.
91 for (sht = sharefs_sharetab; sht != NULL; sht = sht->s_next) {
92 int i;
94 for (i = 0; i < SHARETAB_HASHES; i++) {
95 for (sh = sht->s_buckets[i].ssh_sh;
96 sh != NULL;
97 sh = sh->sh_next) {
98 int n;
100 if ((sWritten + sh->sh_size) >
101 sft->sharefs_size) {
102 goto error_fault;
106 * Note that sh->sh_size accounts
107 * for the field seperators.
108 * We need to add one for the EOL
109 * marker. And we should note that
110 * the space is accounted for in
111 * each share by the EOS marker.
113 n = snprintf(&buf[sWritten],
114 sh->sh_size + 1,
115 "%s\t%s\t%s\t%s\t%s\n",
116 sh->sh_path,
117 sh->sh_res,
118 sh->sh_fstype,
119 sh->sh_opts,
120 sh->sh_descr);
122 if (n != sh->sh_size) {
123 goto error_fault;
126 sWritten += n;
127 iCount++;
133 * We want to record the generation number and
134 * mtime inside this snapshot.
136 gethrestime(&sharetab_snap_time);
137 sft->sharefs_snap_time = sharetab_snap_time;
138 sft->sharefs_generation = sharetab_generation;
140 ASSERT(iCount == sft->sharefs_count);
142 rw_exit(&sharetab_lock);
143 rw_exit(&sharefs_lock);
144 return (0);
146 error_fault:
148 kmem_free(sft->sharefs_snap, sft->sharefs_size + 1);
149 sft->sharefs_size = 0;
150 sft->sharefs_count = 0;
151 sft->sharefs_snap = NULL;
152 rw_exit(&sharetab_lock);
153 rw_exit(&sharefs_lock);
155 return (EFAULT);
158 /* ARGSUSED */
159 static int
160 sharefs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
161 caller_context_t *ct)
163 timestruc_t now;
164 shnode_t *sft = VTOSH(vp);
166 vap->va_type = VREG;
167 vap->va_mode = S_IRUSR | S_IRGRP | S_IROTH;
168 vap->va_nodeid = SHAREFS_INO_FILE;
169 vap->va_nlink = 1;
171 rw_enter(&sharefs_lock, RW_READER);
174 * If we get asked about a snapped vnode, then
175 * we must report the data in that vnode.
177 * Else we report what is currently in the
178 * sharetab.
180 if (sft->sharefs_real_vp) {
181 rw_enter(&sharetab_lock, RW_READER);
182 vap->va_size = sharetab_size;
183 vap->va_mtime = sharetab_mtime;
184 rw_exit(&sharetab_lock);
185 } else {
186 vap->va_size = sft->sharefs_size;
187 vap->va_mtime = sft->sharefs_snap_time;
189 rw_exit(&sharefs_lock);
191 gethrestime(&now);
192 vap->va_atime = vap->va_ctime = now;
194 vap->va_uid = 0;
195 vap->va_gid = 0;
196 vap->va_rdev = 0;
197 vap->va_blksize = DEV_BSIZE;
198 vap->va_nblocks = howmany(vap->va_size, vap->va_blksize);
199 vap->va_seq = 0;
200 vap->va_fsid = vp->v_vfsp->vfs_dev;
202 return (0);
205 /* ARGSUSED */
206 static int
207 sharefs_access(vnode_t *vp, int mode, int flags, cred_t *cr,
208 caller_context_t *ct)
210 if (mode & (VWRITE|VEXEC))
211 return (EROFS);
213 return (0);
216 /* ARGSUSED */
218 sharefs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
220 vnode_t *vp;
221 vnode_t *ovp = *vpp;
222 shnode_t *sft;
223 int error = 0;
225 if (flag & FWRITE)
226 return (EINVAL);
229 * Create a new sharefs vnode for each operation. In order to
230 * avoid locks, we create a snapshot which can not change during
231 * reads.
233 vp = gfs_file_create(sizeof (shnode_t), NULL, &sharefs_ops_data);
235 ((gfs_file_t *)vp->v_data)->gfs_ino = SHAREFS_INO_FILE;
238 * Hold the parent!
240 VFS_HOLD(ovp->v_vfsp);
242 VN_SET_VFS_TYPE_DEV(vp, ovp->v_vfsp, VREG, 0);
244 vp->v_flag |= VROOT | VNOCACHE | VNOMAP | VNOSWAP | VNOMOUNT;
246 *vpp = vp;
247 VN_RELE(ovp);
249 sft = VTOSH(vp);
252 * No need for the lock, no other thread can be accessing
253 * this data structure.
255 atomic_inc_32(&sft->sharefs_refs);
256 sft->sharefs_real_vp = 0;
259 * Since the sharetab could easily change on us whilst we
260 * are dumping an extremely huge sharetab, we make a copy
261 * of it here and use it to dump instead.
263 error = sharefs_snap_create(sft);
265 return (error);
268 /* ARGSUSED */
270 sharefs_close(vnode_t *vp, int flag, int count,
271 offset_t off, cred_t *cr, caller_context_t *ct)
273 shnode_t *sft = VTOSH(vp);
275 if (count > 1)
276 return (0);
278 rw_enter(&sharefs_lock, RW_WRITER);
279 if (vp->v_count == 1) {
280 if (sft->sharefs_snap != NULL) {
281 kmem_free(sft->sharefs_snap, sft->sharefs_size + 1);
282 sft->sharefs_size = 0;
283 sft->sharefs_snap = NULL;
284 sft->sharefs_generation = 0;
287 atomic_dec_32(&sft->sharefs_refs);
288 rw_exit(&sharefs_lock);
290 return (0);
293 /* ARGSUSED */
294 static int
295 sharefs_read(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr,
296 caller_context_t *ct)
298 shnode_t *sft = VTOSH(vp);
299 off_t off = uio->uio_offset;
300 size_t len = uio->uio_resid;
301 int error = 0;
303 rw_enter(&sharefs_lock, RW_READER);
306 * First check to see if we need to grab a new snapshot.
308 if (off == (off_t)0) {
309 rw_exit(&sharefs_lock);
310 error = sharefs_snap_create(sft);
311 if (error) {
312 return (EFAULT);
314 rw_enter(&sharefs_lock, RW_READER);
317 /* LINTED */
318 if (len <= 0 || off >= sft->sharefs_size) {
319 rw_exit(&sharefs_lock);
320 return (error);
323 if ((size_t)(off + len) > sft->sharefs_size)
324 len = sft->sharefs_size - off;
326 if (off < 0 || len > sft->sharefs_size) {
327 rw_exit(&sharefs_lock);
328 return (EFAULT);
331 if (len != 0) {
332 error = uiomove(sft->sharefs_snap + off,
333 len, UIO_READ, uio);
336 rw_exit(&sharefs_lock);
337 return (error);
340 /* ARGSUSED */
341 static void
342 sharefs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *tx)
344 gfs_file_t *fp = vp->v_data;
345 shnode_t *sft;
347 sft = (shnode_t *)gfs_file_inactive(vp);
348 if (sft) {
349 rw_enter(&sharefs_lock, RW_WRITER);
350 if (sft->sharefs_snap != NULL) {
351 kmem_free(sft->sharefs_snap, sft->sharefs_size + 1);
354 kmem_free(sft, fp->gfs_size);
355 rw_exit(&sharefs_lock);
359 vnode_t *
360 sharefs_create_root_file(vfs_t *vfsp)
362 vnode_t *vp;
363 shnode_t *sft;
365 vp = gfs_root_create_file(sizeof (shnode_t),
366 vfsp, &sharefs_ops_data, SHAREFS_INO_FILE);
368 sft = VTOSH(vp);
370 sft->sharefs_real_vp = 1;
372 return (vp);
375 static const struct vnodeops sharefs_ops_data = {
376 .vnop_name = "sharefs",
377 .vop_open = sharefs_open,
378 .vop_close = sharefs_close,
379 .vop_ioctl = fs_inval,
380 .vop_getattr = sharefs_getattr,
381 .vop_access = sharefs_access,
382 .vop_inactive = sharefs_inactive,
383 .vop_read = sharefs_read,
384 .vop_seek = fs_seek,