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 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 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/vfs_opreg.h> 32 #include <sys/gfs.h> 33 #include <sys/vnode.h> 34 #include <sys/systm.h> 35 #include <sys/cmn_err.h> 36 #include <sys/errno.h> 37 #include <sys/sysmacros.h> 38 #include <sys/policy.h> 39 #include <sys/mount.h> 40 #include <sys/pathname.h> 41 #include <sys/dirent.h> 42 #include <fs/fs_subr.h> 43 #include <sys/contract.h> 44 #include <sys/contract_impl.h> 45 #include <sys/ctfs.h> 46 #include <sys/ctfs_impl.h> 47 #include <sys/uio.h> 48 #include <sys/file.h> 49 #include <sys/atomic.h> 50 #include <sys/sunddi.h> 51 52 /* 53 * ctfs, the contract filesystem. 54 * 55 * Exposes the construct subsystem to userland. The structure of the 56 * filesytem is a public interface, but the behavior of the files is 57 * private and unstable. Contract consumers are expected to use 58 * libcontract(3lib) to operate on ctfs file descriptors. 59 * 60 * We're trying something a little different here. Rather than make 61 * each vnode op itself call into a vector of file type operations, we 62 * actually use different vnode types (gasp!), the implementations of 63 * which may call into routines providing common functionality. This 64 * design should hopefully make it easier to factor and maintain the 65 * code. For the most part, there is a separate file for each vnode 66 * type's implementation. The exceptions to this are the ctl/stat 67 * nodes, which are very similar, and the three event endpoint types. 68 * 69 * This file contains common routines used by some or all of the vnode 70 * types, the filesystem's module linkage and VFS operations, and the 71 * implementation of the root vnode. 72 */ 73 74 /* 75 * Ops vectors for all the vnode types; they have to be defined 76 * somewhere. See gfs_make_opsvec for thoughts on how this could be 77 * done differently. 78 */ 79 vnodeops_t *ctfs_ops_root; 80 vnodeops_t *ctfs_ops_adir; 81 vnodeops_t *ctfs_ops_sym; 82 vnodeops_t *ctfs_ops_tdir; 83 vnodeops_t *ctfs_ops_tmpl; 84 vnodeops_t *ctfs_ops_cdir; 85 vnodeops_t *ctfs_ops_ctl; 86 vnodeops_t *ctfs_ops_stat; 87 vnodeops_t *ctfs_ops_event; 88 vnodeops_t *ctfs_ops_bundle; 89 vnodeops_t *ctfs_ops_latest; 90 91 static const fs_operation_def_t ctfs_vfstops[]; 92 static gfs_opsvec_t ctfs_opsvec[]; 93 94 static int ctfs_init(int, char *); 95 96 static ino64_t ctfs_root_do_inode(vnode_t *, int); 97 98 99 /* 100 * File system module linkage 101 */ 102 static mntopts_t ctfs_mntopts = { 103 0, 104 NULL 105 }; 106 107 static vfsdef_t vfw = { 108 VFSDEF_VERSION, 109 "ctfs", 110 ctfs_init, 111 VSW_HASPROTO|VSW_ZMOUNT, 112 &ctfs_mntopts, 113 }; 114 115 extern struct mod_ops mod_fsops; 116 117 static struct modlfs modlfs = { 118 &mod_fsops, "contract filesystem", &vfw 119 }; 120 121 static struct modlinkage modlinkage = { 122 MODREV_1, (void *)&modlfs, NULL 123 }; 124 125 int 126 _init(void) 127 { 128 return (mod_install(&modlinkage)); 129 } 130 131 int 132 _info(struct modinfo *modinfop) 133 { 134 return (mod_info(&modlinkage, modinfop)); 135 } 136 137 int 138 _fini(void) 139 { 140 /* 141 * As unloading filesystem modules isn't completely safe, we 142 * don't allow it. 143 */ 144 return (EBUSY); 145 } 146 147 static int ctfs_fstype; 148 static major_t ctfs_major; 149 static minor_t ctfs_minor = 0; 150 151 /* 152 * The ops vector vector. 153 */ 154 static const fs_operation_def_t ctfs_tops_root[]; 155 extern const fs_operation_def_t ctfs_tops_tmpl[]; 156 extern const fs_operation_def_t ctfs_tops_ctl[]; 157 extern const fs_operation_def_t ctfs_tops_adir[]; 158 extern const fs_operation_def_t ctfs_tops_cdir[]; 159 extern const fs_operation_def_t ctfs_tops_tdir[]; 160 extern const fs_operation_def_t ctfs_tops_latest[]; 161 extern const fs_operation_def_t ctfs_tops_stat[]; 162 extern const fs_operation_def_t ctfs_tops_sym[]; 163 extern const fs_operation_def_t ctfs_tops_event[]; 164 extern const fs_operation_def_t ctfs_tops_bundle[]; 165 static gfs_opsvec_t ctfs_opsvec[] = { 166 { "ctfs root directory", ctfs_tops_root, &ctfs_ops_root }, 167 { "ctfs all directory", ctfs_tops_adir, &ctfs_ops_adir }, 168 { "ctfs all symlink", ctfs_tops_sym, &ctfs_ops_sym }, 169 { "ctfs template directory", ctfs_tops_tdir, &ctfs_ops_tdir }, 170 { "ctfs template file", ctfs_tops_tmpl, &ctfs_ops_tmpl }, 171 { "ctfs contract directory", ctfs_tops_cdir, &ctfs_ops_cdir }, 172 { "ctfs ctl file", ctfs_tops_ctl, &ctfs_ops_ctl }, 173 { "ctfs status file", ctfs_tops_stat, &ctfs_ops_stat }, 174 { "ctfs events file", ctfs_tops_event, &ctfs_ops_event }, 175 { "ctfs bundle file", ctfs_tops_bundle, &ctfs_ops_bundle }, 176 { "ctfs latest file", ctfs_tops_latest, &ctfs_ops_latest }, 177 { NULL } 178 }; 179 180 181 /* 182 * ctfs_init - the vfsdef_t init entry point 183 * 184 * Sets the VFS ops, builds all the vnode ops, and allocates a device 185 * number. 186 */ 187 /* ARGSUSED */ 188 static int 189 ctfs_init(int fstype, char *name) 190 { 191 vfsops_t *vfsops; 192 int error; 193 194 ctfs_fstype = fstype; 195 if (error = vfs_setfsops(fstype, ctfs_vfstops, &vfsops)) { 196 cmn_err(CE_WARN, "ctfs_init: bad vfs ops template"); 197 return (error); 198 } 199 200 if (error = gfs_make_opsvec(ctfs_opsvec)) { 201 (void) vfs_freevfsops(vfsops); 202 return (error); 203 } 204 205 if ((ctfs_major = getudev()) == (major_t)-1) { 206 cmn_err(CE_WARN, "ctfs_init: can't get unique device number"); 207 ctfs_major = 0; 208 } 209 210 return (0); 211 } 212 213 /* 214 * ctfs_mount - the VFS_MOUNT entry point 215 */ 216 static int 217 ctfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 218 { 219 ctfs_vfs_t *data; 220 dev_t dev; 221 gfs_dirent_t *dirent; 222 int i; 223 224 if (secpolicy_fs_mount(cr, mvp, vfsp) != 0) 225 return (EPERM); 226 227 if (mvp->v_type != VDIR) 228 return (ENOTDIR); 229 230 if ((uap->flags & MS_OVERLAY) == 0 && 231 (mvp->v_count > 1 || (mvp->v_flag & VROOT))) 232 return (EBUSY); 233 234 data = kmem_alloc(sizeof (ctfs_vfs_t), KM_SLEEP); 235 236 /* 237 * Initialize vfs fields not initialized by VFS_INIT/domount 238 */ 239 vfsp->vfs_bsize = DEV_BSIZE; 240 vfsp->vfs_fstype = ctfs_fstype; 241 do { 242 dev = makedevice(ctfs_major, 243 atomic_inc_32_nv(&ctfs_minor) & L_MAXMIN32); 244 } while (vfs_devismounted(dev)); 245 vfs_make_fsid(&vfsp->vfs_fsid, dev, ctfs_fstype); 246 vfsp->vfs_data = data; 247 vfsp->vfs_dev = dev; 248 249 /* 250 * Dynamically create gfs_dirent_t array for the root directory. 251 */ 252 dirent = kmem_zalloc((ct_ntypes + 2) * sizeof (gfs_dirent_t), KM_SLEEP); 253 for (i = 0; i < ct_ntypes; i++) { 254 dirent[i].gfse_name = (char *)ct_types[i]->ct_type_name; 255 dirent[i].gfse_ctor = ctfs_create_tdirnode; 256 dirent[i].gfse_flags = GFS_CACHE_VNODE; 257 } 258 dirent[i].gfse_name = "all"; 259 dirent[i].gfse_ctor = ctfs_create_adirnode; 260 dirent[i].gfse_flags = GFS_CACHE_VNODE; 261 dirent[i+1].gfse_name = NULL; 262 263 /* 264 * Create root vnode 265 */ 266 data->ctvfs_root = gfs_root_create(sizeof (ctfs_rootnode_t), 267 vfsp, ctfs_ops_root, CTFS_INO_ROOT, dirent, ctfs_root_do_inode, 268 CTFS_NAME_MAX, NULL, NULL); 269 270 kmem_free(dirent, (ct_ntypes + 2) * sizeof (gfs_dirent_t)); 271 272 return (0); 273 } 274 275 /* 276 * ctfs_unmount - the VFS_UNMOUNT entry point 277 */ 278 static int 279 ctfs_unmount(vfs_t *vfsp, int flag, struct cred *cr) 280 { 281 ctfs_vfs_t *data; 282 283 if (secpolicy_fs_unmount(cr, vfsp) != 0) 284 return (EPERM); 285 286 /* 287 * Supporting forced unmounts would be nice to do at some 288 * point. 289 */ 290 if (flag & MS_FORCE) 291 return (ENOTSUP); 292 293 /* 294 * We should never have a reference count less than 2: one for 295 * the caller, one for the root vnode. 296 */ 297 ASSERT(vfsp->vfs_count >= 2); 298 299 /* 300 * If we have any active vnodes, they will (transitively) have 301 * holds on the root vnode. 302 */ 303 data = vfsp->vfs_data; 304 if (data->ctvfs_root->v_count > 1) 305 return (EBUSY); 306 307 /* 308 * Release the last hold on the root vnode. It will, in turn, 309 * release its hold on us. 310 */ 311 VN_RELE(data->ctvfs_root); 312 313 /* 314 * Disappear. 315 */ 316 kmem_free(data, sizeof (ctfs_vfs_t)); 317 318 return (0); 319 } 320 321 /* 322 * ctfs_root - the VFS_ROOT entry point 323 */ 324 static int 325 ctfs_root(vfs_t *vfsp, vnode_t **vpp) 326 { 327 vnode_t *vp; 328 329 vp = ((ctfs_vfs_t *)vfsp->vfs_data)->ctvfs_root; 330 VN_HOLD(vp); 331 *vpp = vp; 332 333 return (0); 334 } 335 336 /* 337 * ctfs_statvfs - the VFS_STATVFS entry point 338 */ 339 static int 340 ctfs_statvfs(vfs_t *vfsp, statvfs64_t *sp) 341 { 342 dev32_t d32; 343 int total, i; 344 345 bzero(sp, sizeof (*sp)); 346 sp->f_bsize = DEV_BSIZE; 347 sp->f_frsize = DEV_BSIZE; 348 for (i = 0, total = 0; i < ct_ntypes; i++) 349 total += contract_type_count(ct_types[i]); 350 sp->f_files = total; 351 sp->f_favail = sp->f_ffree = INT_MAX - total; 352 (void) cmpldev(&d32, vfsp->vfs_dev); 353 sp->f_fsid = d32; 354 (void) strlcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name, 355 sizeof (sp->f_basetype)); 356 sp->f_flag = vf_to_stf(vfsp->vfs_flag); 357 sp->f_namemax = CTFS_NAME_MAX; 358 (void) strlcpy(sp->f_fstr, "contract", sizeof (sp->f_fstr)); 359 360 return (0); 361 } 362 363 static const fs_operation_def_t ctfs_vfstops[] = { 364 { VFSNAME_MOUNT, { .vfs_mount = ctfs_mount } }, 365 { VFSNAME_UNMOUNT, { .vfs_unmount = ctfs_unmount } }, 366 { VFSNAME_ROOT, { .vfs_root = ctfs_root } }, 367 { VFSNAME_STATVFS, { .vfs_statvfs = ctfs_statvfs } }, 368 { NULL, NULL } 369 }; 370 371 /* 372 * ctfs_common_getattr 373 * 374 * Implements functionality common to all ctfs VOP_GETATTR entry 375 * points. It assumes vap->va_size is set. 376 */ 377 void 378 ctfs_common_getattr(vnode_t *vp, vattr_t *vap) 379 { 380 vap->va_uid = 0; 381 vap->va_gid = 0; 382 vap->va_rdev = 0; 383 vap->va_blksize = DEV_BSIZE; 384 vap->va_nblocks = howmany(vap->va_size, vap->va_blksize); 385 vap->va_seq = 0; 386 vap->va_fsid = vp->v_vfsp->vfs_dev; 387 vap->va_nodeid = gfs_file_inode(vp); 388 } 389 390 /* 391 * ctfs_open - common VOP_OPEN entry point 392 * 393 * Used by all ctfs directories; just verifies we are using large-file 394 * aware interfaces and we aren't trying to open the directories 395 * writable. 396 */ 397 /* ARGSUSED */ 398 int 399 ctfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) 400 { 401 if ((flag & (FOFFMAX | FWRITE)) != FOFFMAX) 402 return (EINVAL); 403 404 return (0); 405 } 406 407 /* 408 * ctfs_close - common VOP_CLOSE entry point 409 * 410 * For all ctfs vnode types which have no close-time clean-up to do. 411 */ 412 /* ARGSUSED */ 413 int 414 ctfs_close( 415 vnode_t *vp, 416 int flag, 417 int count, 418 offset_t offset, 419 cred_t *cr, 420 caller_context_t *ct) 421 { 422 return (0); 423 } 424 425 /* 426 * ctfs_access_dir - common VOP_ACCESS entry point for directories 427 */ 428 /* ARGSUSED */ 429 int 430 ctfs_access_dir( 431 vnode_t *vp, 432 int mode, 433 int flags, 434 cred_t *cr, 435 caller_context_t *ct) 436 { 437 if (mode & VWRITE) 438 return (EACCES); 439 440 return (0); 441 } 442 443 /* 444 * ctfs_access_dir - common VOP_ACCESS entry point for read-only files 445 */ 446 /* ARGSUSED */ 447 int 448 ctfs_access_readonly( 449 vnode_t *vp, 450 int mode, 451 int flags, 452 cred_t *cr, 453 caller_context_t *ct) 454 { 455 if (mode & (VWRITE | VEXEC)) 456 return (EACCES); 457 458 return (0); 459 } 460 461 /* 462 * ctfs_access_dir - common VOP_ACCESS entry point for read-write files 463 */ 464 /* ARGSUSED */ 465 int 466 ctfs_access_readwrite( 467 vnode_t *vp, 468 int mode, 469 int flags, 470 cred_t *cr, 471 caller_context_t *ct) 472 { 473 if (mode & VEXEC) 474 return (EACCES); 475 476 return (0); 477 } 478 479 /* 480 * ctfs_root_getattr - VOP_GETATTR entry point 481 */ 482 /* ARGSUSED */ 483 static int 484 ctfs_root_getattr( 485 vnode_t *vp, 486 vattr_t *vap, 487 int flags, 488 cred_t *cr, 489 caller_context_t *ct) 490 { 491 vap->va_type = VDIR; 492 vap->va_mode = 0555; 493 vap->va_nlink = 2 + ct_ntypes + 1; 494 vap->va_size = vap->va_nlink; 495 vap->va_atime.tv_sec = vp->v_vfsp->vfs_mtime; 496 vap->va_atime.tv_nsec = 0; 497 vap->va_mtime = vap->va_ctime = vap->va_atime; 498 ctfs_common_getattr(vp, vap); 499 500 return (0); 501 } 502 503 /* ARGSUSED */ 504 static ino64_t 505 ctfs_root_do_inode(vnode_t *vp, int index) 506 { 507 return (CTFS_INO_TYPE_DIR(index)); 508 } 509 510 static const fs_operation_def_t ctfs_tops_root[] = { 511 { VOPNAME_OPEN, { .vop_open = ctfs_open } }, 512 { VOPNAME_CLOSE, { .vop_close = ctfs_close } }, 513 { VOPNAME_IOCTL, { .error = fs_inval } }, 514 { VOPNAME_GETATTR, { .vop_getattr = ctfs_root_getattr } }, 515 { VOPNAME_ACCESS, { .vop_access = ctfs_access_dir } }, 516 { VOPNAME_READDIR, { .vop_readdir = gfs_vop_readdir } }, 517 { VOPNAME_LOOKUP, { .vop_lookup = gfs_vop_lookup } }, 518 { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 519 { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } }, 520 { NULL, NULL } 521 };