drop net-snmp dep
[unleashed.git] / kernel / fs / ctfs / ctfs_root.c
blob3ffc4c4486f6fbd70c069b41a9c555dfce735e98
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
22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/modctl.h>
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/time.h>
29 #include <sys/cred.h>
30 #include <sys/vfs.h>
31 #include <sys/gfs.h>
32 #include <sys/vnode.h>
33 #include <sys/systm.h>
34 #include <sys/cmn_err.h>
35 #include <sys/errno.h>
36 #include <sys/sysmacros.h>
37 #include <sys/policy.h>
38 #include <sys/mount.h>
39 #include <sys/pathname.h>
40 #include <sys/dirent.h>
41 #include <sys/fs_subr.h>
42 #include <sys/contract.h>
43 #include <sys/contract_impl.h>
44 #include <sys/ctfs.h>
45 #include <sys/ctfs_impl.h>
46 #include <sys/uio.h>
47 #include <sys/file.h>
48 #include <sys/atomic.h>
49 #include <sys/sunddi.h>
52 * ctfs, the contract filesystem.
54 * Exposes the construct subsystem to userland. The structure of the
55 * filesystem is a public interface, but the behavior of the files is
56 * private and unstable. Contract consumers are expected to use
57 * libcontract(3lib) to operate on ctfs file descriptors.
59 * We're trying something a little different here. Rather than make
60 * each vnode op itself call into a vector of file type operations, we
61 * actually use different vnode types (gasp!), the implementations of
62 * which may call into routines providing common functionality. This
63 * design should hopefully make it easier to factor and maintain the
64 * code. For the most part, there is a separate file for each vnode
65 * type's implementation. The exceptions to this are the ctl/stat
66 * nodes, which are very similar, and the three event endpoint types.
68 * This file contains common routines used by some or all of the vnode
69 * types, the filesystem's module linkage and VFS operations, and the
70 * implementation of the root vnode.
73 static const struct vfsops ctfs_vfsops;
75 static int ctfs_init(int, char *);
77 static ino64_t ctfs_root_do_inode(vnode_t *, int);
81 * File system module linkage
83 static mntopts_t ctfs_mntopts = {
85 NULL
88 static vfsdef_t vfw = {
89 VFSDEF_VERSION,
90 "ctfs",
91 ctfs_init,
92 VSW_HASPROTO|VSW_ZMOUNT,
93 &ctfs_mntopts,
96 extern struct mod_ops mod_fsops;
98 static struct modlfs modlfs = {
99 &mod_fsops, "contract filesystem", &vfw
102 static struct modlinkage modlinkage = {
103 MODREV_1, (void *)&modlfs, NULL
107 _init(void)
109 return (mod_install(&modlinkage));
113 _info(struct modinfo *modinfop)
115 return (mod_info(&modlinkage, modinfop));
119 _fini(void)
122 * As unloading filesystem modules isn't completely safe, we
123 * don't allow it.
125 return (EBUSY);
128 static int ctfs_fstype;
129 static major_t ctfs_major;
130 static minor_t ctfs_minor = 0;
133 * ctfs_init - the vfsdef_t init entry point
135 * Sets the VFS ops, builds all the vnode ops, and allocates a device
136 * number.
138 /* ARGSUSED */
139 static int
140 ctfs_init(int fstype, char *name)
142 int error;
144 ctfs_fstype = fstype;
145 if (error = vfs_setfsops(fstype, &ctfs_vfsops)) {
146 cmn_err(CE_WARN, "ctfs_init: bad fstype");
147 return (error);
150 if ((ctfs_major = getudev()) == (major_t)-1) {
151 cmn_err(CE_WARN, "ctfs_init: can't get unique device number");
152 ctfs_major = 0;
155 return (0);
159 * ctfs_mount - the VFS_MOUNT entry point
161 static int
162 ctfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
164 ctfs_vfs_t *data;
165 dev_t dev;
166 gfs_dirent_t *dirent;
167 int i;
169 if (secpolicy_fs_mount(cr, mvp, vfsp) != 0)
170 return (EPERM);
172 if (mvp->v_type != VDIR)
173 return (ENOTDIR);
175 if ((uap->flags & MS_OVERLAY) == 0 &&
176 (mvp->v_count > 1 || (mvp->v_flag & VROOT)))
177 return (EBUSY);
179 data = kmem_alloc(sizeof (ctfs_vfs_t), KM_SLEEP);
182 * Initialize vfs fields not initialized by VFS_INIT/domount
184 vfsp->vfs_bsize = DEV_BSIZE;
185 vfsp->vfs_fstype = ctfs_fstype;
186 do {
187 dev = makedevice(ctfs_major,
188 atomic_inc_32_nv(&ctfs_minor) & L_MAXMIN32);
189 } while (vfs_devismounted(dev));
190 vfs_make_fsid(&vfsp->vfs_fsid, dev, ctfs_fstype);
191 vfsp->vfs_data = data;
192 vfsp->vfs_dev = dev;
195 * Dynamically create gfs_dirent_t array for the root directory.
197 dirent = kmem_zalloc((ct_ntypes + 2) * sizeof (gfs_dirent_t), KM_SLEEP);
198 for (i = 0; i < ct_ntypes; i++) {
199 dirent[i].gfse_name = (char *)ct_types[i]->ct_type_name;
200 dirent[i].gfse_ctor = ctfs_create_tdirnode;
201 dirent[i].gfse_flags = GFS_CACHE_VNODE;
203 dirent[i].gfse_name = "all";
204 dirent[i].gfse_ctor = ctfs_create_adirnode;
205 dirent[i].gfse_flags = GFS_CACHE_VNODE;
206 dirent[i+1].gfse_name = NULL;
209 * Create root vnode
211 data->ctvfs_root = gfs_root_create(sizeof (ctfs_rootnode_t),
212 vfsp, &ctfs_ops_root, CTFS_INO_ROOT, dirent, ctfs_root_do_inode,
213 CTFS_NAME_MAX, NULL, NULL);
215 kmem_free(dirent, (ct_ntypes + 2) * sizeof (gfs_dirent_t));
217 return (0);
221 * ctfs_unmount - the VFS_UNMOUNT entry point
223 static int
224 ctfs_unmount(vfs_t *vfsp, int flag, struct cred *cr)
226 ctfs_vfs_t *data;
228 if (secpolicy_fs_unmount(cr, vfsp) != 0)
229 return (EPERM);
232 * Supporting forced unmounts would be nice to do at some
233 * point.
235 if (flag & MS_FORCE)
236 return (ENOTSUP);
239 * We should never have a reference count less than 2: one for
240 * the caller, one for the root vnode.
242 ASSERT(vfsp->vfs_count >= 2);
245 * If we have any active vnodes, they will (transitively) have
246 * holds on the root vnode.
248 data = vfsp->vfs_data;
249 if (data->ctvfs_root->v_count > 1)
250 return (EBUSY);
253 * Release the last hold on the root vnode. It will, in turn,
254 * release its hold on us.
256 VN_RELE(data->ctvfs_root);
259 * Disappear.
261 kmem_free(data, sizeof (ctfs_vfs_t));
263 return (0);
267 * ctfs_root - the VFS_ROOT entry point
269 static int
270 ctfs_root(vfs_t *vfsp, vnode_t **vpp)
272 vnode_t *vp;
274 vp = ((ctfs_vfs_t *)vfsp->vfs_data)->ctvfs_root;
275 VN_HOLD(vp);
276 *vpp = vp;
278 return (0);
282 * ctfs_statvfs - the VFS_STATVFS entry point
284 static int
285 ctfs_statvfs(vfs_t *vfsp, statvfs64_t *sp)
287 dev32_t d32;
288 int total, i;
290 bzero(sp, sizeof (*sp));
291 sp->f_bsize = DEV_BSIZE;
292 sp->f_frsize = DEV_BSIZE;
293 for (i = 0, total = 0; i < ct_ntypes; i++)
294 total += contract_type_count(ct_types[i]);
295 sp->f_files = total;
296 sp->f_favail = sp->f_ffree = INT_MAX - total;
297 (void) cmpldev(&d32, vfsp->vfs_dev);
298 sp->f_fsid = d32;
299 (void) strlcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name,
300 sizeof (sp->f_basetype));
301 sp->f_flag = vf_to_stf(vfsp->vfs_flag);
302 sp->f_namemax = CTFS_NAME_MAX;
303 (void) strlcpy(sp->f_fstr, "contract", sizeof (sp->f_fstr));
305 return (0);
308 static const struct vfsops ctfs_vfsops = {
309 .vfs_mount = ctfs_mount,
310 .vfs_unmount = ctfs_unmount,
311 .vfs_root = ctfs_root,
312 .vfs_statvfs = ctfs_statvfs,
316 * ctfs_common_getattr
318 * Implements functionality common to all ctfs fop_getattr entry
319 * points. It assumes vap->va_size is set.
321 void
322 ctfs_common_getattr(vnode_t *vp, vattr_t *vap)
324 vap->va_uid = 0;
325 vap->va_gid = 0;
326 vap->va_rdev = 0;
327 vap->va_blksize = DEV_BSIZE;
328 vap->va_nblocks = howmany(vap->va_size, vap->va_blksize);
329 vap->va_seq = 0;
330 vap->va_fsid = vp->v_vfsp->vfs_dev;
331 vap->va_nodeid = gfs_file_inode(vp);
335 * ctfs_open - common fop_open entry point
337 * Used by all ctfs directories; just verifies we are using large-file
338 * aware interfaces and we aren't trying to open the directories
339 * writable.
341 /* ARGSUSED */
343 ctfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
345 if ((flag & (FOFFMAX | FWRITE)) != FOFFMAX)
346 return (EINVAL);
348 return (0);
352 * ctfs_close - common fop_close entry point
354 * For all ctfs vnode types which have no close-time clean-up to do.
356 /* ARGSUSED */
358 ctfs_close(
359 vnode_t *vp,
360 int flag,
361 int count,
362 offset_t offset,
363 cred_t *cr,
364 caller_context_t *ct)
366 return (0);
370 * ctfs_access_dir - common fop_access entry point for directories
372 /* ARGSUSED */
374 ctfs_access_dir(
375 vnode_t *vp,
376 int mode,
377 int flags,
378 cred_t *cr,
379 caller_context_t *ct)
381 if (mode & VWRITE)
382 return (EACCES);
384 return (0);
388 * ctfs_access_dir - common fop_access entry point for read-only files
390 /* ARGSUSED */
392 ctfs_access_readonly(
393 vnode_t *vp,
394 int mode,
395 int flags,
396 cred_t *cr,
397 caller_context_t *ct)
399 if (mode & (VWRITE | VEXEC))
400 return (EACCES);
402 return (0);
406 * ctfs_access_dir - common fop_access entry point for read-write files
408 /* ARGSUSED */
410 ctfs_access_readwrite(
411 vnode_t *vp,
412 int mode,
413 int flags,
414 cred_t *cr,
415 caller_context_t *ct)
417 if (mode & VEXEC)
418 return (EACCES);
420 return (0);
424 * ctfs_root_getattr - fop_getattr entry point
426 /* ARGSUSED */
427 static int
428 ctfs_root_getattr(
429 vnode_t *vp,
430 vattr_t *vap,
431 int flags,
432 cred_t *cr,
433 caller_context_t *ct)
435 vap->va_type = VDIR;
436 vap->va_mode = 0555;
437 vap->va_nlink = 2 + ct_ntypes + 1;
438 vap->va_size = vap->va_nlink;
439 vap->va_atime.tv_sec = vp->v_vfsp->vfs_mtime;
440 vap->va_atime.tv_nsec = 0;
441 vap->va_mtime = vap->va_ctime = vap->va_atime;
442 ctfs_common_getattr(vp, vap);
444 return (0);
447 /* ARGSUSED */
448 static ino64_t
449 ctfs_root_do_inode(vnode_t *vp, int index)
451 return (CTFS_INO_TYPE_DIR(index));
454 const struct vnodeops ctfs_ops_root = {
455 .vnop_name = "ctfs root directory",
456 .vop_open = ctfs_open,
457 .vop_close = ctfs_close,
458 .vop_ioctl = fs_inval,
459 .vop_getattr = ctfs_root_getattr,
460 .vop_access = ctfs_access_dir,
461 .vop_readdir = gfs_vop_readdir,
462 .vop_lookup = gfs_vop_lookup,
463 .vop_seek = fs_seek,
464 .vop_inactive = gfs_vop_inactive,