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]
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>
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>
45 #include <sys/ctfs_impl.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
= {
88 static vfsdef_t vfw
= {
92 VSW_HASPROTO
|VSW_ZMOUNT
,
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
109 return (mod_install(&modlinkage
));
113 _info(struct modinfo
*modinfop
)
115 return (mod_info(&modlinkage
, modinfop
));
122 * As unloading filesystem modules isn't completely safe, we
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
140 ctfs_init(int fstype
, char *name
)
144 ctfs_fstype
= fstype
;
145 if (error
= vfs_setfsops(fstype
, &ctfs_vfsops
)) {
146 cmn_err(CE_WARN
, "ctfs_init: bad fstype");
150 if ((ctfs_major
= getudev()) == (major_t
)-1) {
151 cmn_err(CE_WARN
, "ctfs_init: can't get unique device number");
159 * ctfs_mount - the VFS_MOUNT entry point
162 ctfs_mount(vfs_t
*vfsp
, vnode_t
*mvp
, struct mounta
*uap
, cred_t
*cr
)
166 gfs_dirent_t
*dirent
;
169 if (secpolicy_fs_mount(cr
, mvp
, vfsp
) != 0)
172 if (mvp
->v_type
!= VDIR
)
175 if ((uap
->flags
& MS_OVERLAY
) == 0 &&
176 (mvp
->v_count
> 1 || (mvp
->v_flag
& VROOT
)))
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
;
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
;
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
;
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
));
221 * ctfs_unmount - the VFS_UNMOUNT entry point
224 ctfs_unmount(vfs_t
*vfsp
, int flag
, struct cred
*cr
)
228 if (secpolicy_fs_unmount(cr
, vfsp
) != 0)
232 * Supporting forced unmounts would be nice to do at some
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)
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
);
261 kmem_free(data
, sizeof (ctfs_vfs_t
));
267 * ctfs_root - the VFS_ROOT entry point
270 ctfs_root(vfs_t
*vfsp
, vnode_t
**vpp
)
274 vp
= ((ctfs_vfs_t
*)vfsp
->vfs_data
)->ctvfs_root
;
282 * ctfs_statvfs - the VFS_STATVFS entry point
285 ctfs_statvfs(vfs_t
*vfsp
, statvfs64_t
*sp
)
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
]);
296 sp
->f_favail
= sp
->f_ffree
= INT_MAX
- total
;
297 (void) cmpldev(&d32
, vfsp
->vfs_dev
);
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
));
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.
322 ctfs_common_getattr(vnode_t
*vp
, vattr_t
*vap
)
327 vap
->va_blksize
= DEV_BSIZE
;
328 vap
->va_nblocks
= howmany(vap
->va_size
, vap
->va_blksize
);
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
343 ctfs_open(vnode_t
**vpp
, int flag
, cred_t
*cr
, caller_context_t
*ct
)
345 if ((flag
& (FWRITE
)) != 0)
352 * ctfs_close - common fop_close entry point
354 * For all ctfs vnode types which have no close-time clean-up to do.
364 caller_context_t
*ct
)
370 * ctfs_access_dir - common fop_access entry point for directories
379 caller_context_t
*ct
)
388 * ctfs_access_dir - common fop_access entry point for read-only files
392 ctfs_access_readonly(
397 caller_context_t
*ct
)
399 if (mode
& (VWRITE
| VEXEC
))
406 * ctfs_access_dir - common fop_access entry point for read-write files
410 ctfs_access_readwrite(
415 caller_context_t
*ct
)
424 * ctfs_root_getattr - fop_getattr entry point
433 caller_context_t
*ct
)
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
);
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
,
464 .vop_inactive
= gfs_vop_inactive
,