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 };