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 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #pragma ident   "%Z%%M% %I%     %E% SMI"
  27 
  28 #include <sys/param.h>
  29 #include <sys/types.h>
  30 #include <sys/systm.h>
  31 #include <sys/cred.h>
  32 #include <sys/proc.h>
  33 #include <sys/user.h>
  34 #include <sys/vfs.h>
  35 #include <sys/vfs_opreg.h>
  36 #include <sys/vnode.h>
  37 #include <sys/pathname.h>
  38 #include <sys/uio.h>
  39 #include <sys/tiuser.h>
  40 #include <sys/sysmacros.h>
  41 #include <sys/kmem.h>
  42 #include <sys/mount.h>
  43 #include <sys/ioctl.h>
  44 #include <sys/statvfs.h>
  45 #include <sys/stat.h>
  46 #include <sys/errno.h>
  47 #include <sys/debug.h>
  48 #include <sys/cmn_err.h>
  49 #include <sys/utsname.h>
  50 #include <sys/bootconf.h>
  51 #include <sys/reboot.h>
  52 #include <sys/modctl.h>
  53 #include <rpc/types.h>
  54 
  55 #include <sys/fs/cachefs_fs.h>
  56 #include <sys/fs/cachefs_log.h>
  57 #include <sys/mkdev.h>
  58 #include <sys/dnlc.h>
  59 #include <sys/policy.h>
  60 #include "fs/fs_subr.h"
  61 
  62 extern kmutex_t cachefs_kmem_lock;
  63 kmutex_t cachefs_kstat_key_lock;
  64 
  65 /* forward declarations */
  66 static int cachefs_remount(struct vfs *, struct mounta *);
  67 static void cachefs_delete_cachep(cachefscache_t *);
  68 
  69 #define CFS_MAPSIZE     256
  70 
  71 kmutex_t cachefs_cachelock;                     /* Cache list mutex */
  72 cachefscache_t *cachefs_cachelist = NULL;               /* Cache struct list */
  73 
  74 int cachefs_mount_retries = 3;
  75 kmutex_t cachefs_minor_lock;            /* Lock for minor device map */
  76 major_t cachefs_major = 0;
  77 minor_t cachefs_minor = 0;
  78 cachefs_kstat_key_t *cachefs_kstat_key = NULL;
  79 int cachefs_kstat_key_n = 0;
  80 static uint32_t cachefs_nfsv4_warnmsg = FALSE;
  81 
  82 /*
  83  * cachefs vfs operations.
  84  */
  85 static  int cachefs_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *);
  86 static  int cachefs_unmount(vfs_t *, int, cred_t *);
  87 static  int cachefs_root(vfs_t *, vnode_t **);
  88 static  int cachefs_statvfs(register vfs_t *, struct statvfs64 *);
  89 static  int cachefs_sync(vfs_t *, short, cred_t *);
  90 
  91 /*
  92  * Initialize the vfs structure
  93  */
  94 int cachefsfstyp;
  95 int cnodesize = 0;
  96 
  97 int
  98 cachefs_init_vfsops(int fstype)
  99 {
 100         static const fs_operation_def_t cachefs_vfsops_template[] = {
 101                 VFSNAME_MOUNT,          { .vfs_mount = cachefs_mount },
 102                 VFSNAME_UNMOUNT,        { .vfs_unmount = cachefs_unmount },
 103                 VFSNAME_ROOT,           { .vfs_root = cachefs_root },
 104                 VFSNAME_STATVFS,        { .vfs_statvfs = cachefs_statvfs },
 105                 VFSNAME_SYNC,           { .vfs_sync = cachefs_sync },
 106                 NULL,                   NULL
 107         };
 108         int error;
 109 
 110         error = vfs_setfsops(fstype, cachefs_vfsops_template, NULL);
 111         if (error != 0)
 112                 return (error);
 113 
 114         cachefsfstyp = fstype;
 115 
 116         return (0);
 117 }
 118 
 119 dev_t
 120 cachefs_mkmntdev(void)
 121 {
 122         dev_t cachefs_dev;
 123 
 124         mutex_enter(&cachefs_minor_lock);
 125         do {
 126                 cachefs_minor = (cachefs_minor + 1) & MAXMIN32;
 127                 cachefs_dev = makedevice(cachefs_major, cachefs_minor);
 128         } while (vfs_devismounted(cachefs_dev));
 129         mutex_exit(&cachefs_minor_lock);
 130 
 131         return (cachefs_dev);
 132 }
 133 
 134 /*
 135  * vfs operations
 136  */
 137 static int
 138 cachefs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
 139 {
 140         char *data = uap->dataptr;
 141         STRUCT_DECL(cachefs_mountargs, map);
 142         struct cachefsoptions   *cfs_options;
 143         char                    *backfs, *cacheid, *cachedir;
 144         vnode_t *cachedirvp = NULL;
 145         vnode_t *backrootvp = NULL;
 146         cachefscache_t *cachep = NULL;
 147         fscache_t *fscp = NULL;
 148         cnode_t *cp;
 149         struct fid *cookiep = NULL;
 150         struct vattr *attrp = NULL;
 151         dev_t cachefs_dev;                      /* devid for this mount */
 152         int error = 0;
 153         int retries = cachefs_mount_retries;
 154         ino64_t fsid;
 155         cfs_cid_t cid;
 156         char *backmntpt;
 157         ino64_t backfileno;
 158         struct vfs *backvfsp;
 159         size_t strl;
 160         char tmpstr[MAXPATHLEN];
 161         vnode_t *tmpdirvp = NULL;
 162         ulong_t maxfilesizebits;
 163         uint32_t valid_fid;
 164 
 165 #ifdef CFSDEBUG
 166         CFS_DEBUG(CFSDEBUG_VFSOP)
 167                 printf("cachefs_mount: ENTER cachefs_mntargs %p\n", data);
 168 #endif
 169 
 170         /*
 171          * Make sure we have sufficient privileges.
 172          */
 173         if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
 174                 goto out;
 175 
 176         /*
 177          * make sure we're mounting on a directory
 178          */
 179         if (mvp->v_type != VDIR) {
 180                 error = ENOTDIR;
 181                 goto out;
 182         }
 183 
 184         /*
 185          * Determine the zone we're being mounted into, and make sure it's the
 186          * global zone.
 187          */
 188         if (getzoneid() == GLOBAL_ZONEID) {
 189                 zone_t *mntzone;
 190 
 191                 mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
 192                 ASSERT(mntzone != NULL);
 193                 zone_rele(mntzone);
 194                 if (mntzone != curproc->p_zone) {
 195                         error = EBUSY;
 196                         goto out;
 197                 }
 198         } else {
 199                 error = EPERM;
 200                 goto out;
 201         }
 202 
 203         if (uap->flags & MS_REMOUNT) {
 204                 error = cachefs_remount(vfsp, uap);
 205                 goto out;
 206         }
 207 
 208         /*
 209          * Assign a unique device id to the mount
 210          */
 211         cachefs_dev = cachefs_mkmntdev();
 212 #ifdef _LP64
 213         /*
 214          * It's not a good idea to make fsid bigger since that'll
 215          * have adverse effects on nfs filehandles.  For now assume that
 216          * cachefs be used on devices that fit into dev32_t's.
 217          */
 218         if (cachefs_dev == NODEV) {
 219                 error = EOVERFLOW;
 220                 goto out;
 221         }
 222 #endif
 223 
 224         /*
 225          * Copy in the arguments
 226          */
 227         STRUCT_INIT(map, get_udatamodel());
 228         error = copyin(data, STRUCT_BUF(map),
 229                         SIZEOF_STRUCT(cachefs_mountargs, DATAMODEL_NATIVE));
 230         if (error) {
 231                 goto out;
 232         }
 233 
 234         cfs_options = (struct cachefsoptions *)STRUCT_FADDR(map, cfs_options);
 235         cacheid = (char *)STRUCT_FGETP(map, cfs_cacheid);
 236         if ((cfs_options->opt_flags &
 237             (CFS_WRITE_AROUND|CFS_NONSHARED|CFS_BACKFS_NFSV4)) == 0) {
 238                 error = EINVAL;
 239                 goto out;
 240         }
 241         if ((cfs_options->opt_popsize % MAXBSIZE) != 0) {
 242                 error = EINVAL;
 243                 goto out;
 244         }
 245         /*
 246          * Get the cache directory vp
 247          */
 248         /*LINTED 32-bit pointer casting okay*/
 249         cachedir = (char *)STRUCT_FGETP(map, cfs_cachedir);
 250         error = lookupname(cachedir, UIO_USERSPACE, FOLLOW,
 251                         NULLVPP, &cachedirvp);
 252         if (error)
 253                 goto out;
 254 
 255         /*
 256          * Make sure the thing we just looked up is a directory
 257          */
 258         if (cachedirvp->v_type != VDIR) {
 259                 cmn_err(CE_WARN, "cachefs_mount: cachedir not a directory\n");
 260                 error = EINVAL;
 261                 goto out;
 262         }
 263 
 264         /*
 265          * Make sure the cache doesn't live in cachefs!
 266          */
 267         if (vn_matchops(cachedirvp, cachefs_getvnodeops())) {
 268                 cmn_err(CE_WARN, "cachefs_mount: cachedir in cachefs!\n");
 269                 error = EINVAL;
 270                 goto out;
 271         }
 272 
 273         /* if the backfs is mounted */
 274         /*LINTED 32-bit pointer casting okay*/
 275         if ((backfs = STRUCT_FGETP(map, cfs_backfs)) != NULL) {
 276                 /*
 277                  * Get the back file system root vp
 278                  */
 279                 error = lookupname(backfs, UIO_USERSPACE, FOLLOW,
 280                         NULLVPP, &backrootvp);
 281                 if (error)
 282                         goto out;
 283 
 284                 /*
 285                  * Make sure the thing we just looked up is a directory
 286                  * and a root of a file system
 287                  */
 288                 if (backrootvp->v_type != VDIR ||
 289                     !(backrootvp->v_flag & VROOT)) {
 290                         cmn_err(CE_WARN,
 291                             "cachefs_mount: backpath not a directory\n");
 292                         error = EINVAL;
 293                         goto out;
 294                 }
 295 
 296                 /*
 297                  * Get the fid and attributes for the root of the
 298                  * backfilesystem, except if NFSv4 is in use,
 299                  * in which case we get the attributes only (the
 300                  * (VOP_FID() operation called by cachefs_get_cookie()
 301                  * is not supported in NFSv4).
 302                  */
 303                 cookiep = cachefs_kmem_alloc(sizeof (struct fid), KM_SLEEP);
 304                 attrp = cachefs_kmem_alloc(sizeof (struct vattr), KM_SLEEP);
 305 
 306                 if ((cfs_options->opt_flags & CFS_BACKFS_NFSV4)) {
 307                         valid_fid = FALSE;
 308                 } else {
 309                         valid_fid = TRUE;
 310                 }
 311                 error = cachefs_getcookie(backrootvp, cookiep, attrp, cr,
 312                                                 valid_fid);
 313 
 314                 if (error)
 315                         goto out;
 316 
 317                 backmntpt = backfs;
 318                 backfileno = attrp->va_nodeid;
 319                 backvfsp = backrootvp->v_vfsp;
 320         } else {
 321                 backmntpt = NULL;
 322                 backfileno = 0;
 323                 backvfsp = NULL;
 324         }
 325 
 326 again:
 327 
 328         /*
 329          * In SVR4 it's not acceptable to stack up mounts
 330          * unless MS_OVERLAY specified.
 331          */
 332         mutex_enter(&mvp->v_lock);
 333         if (((uap->flags & MS_OVERLAY) == 0) &&
 334             ((mvp->v_count != 1) || (mvp->v_flag & VROOT))) {
 335                 mutex_exit(&mvp->v_lock);
 336                 error = EBUSY;
 337                 goto out;
 338         }
 339         mutex_exit(&mvp->v_lock);
 340 
 341         /*
 342          * Lock out other mounts and unmounts until we safely have
 343          * a mounted fscache object.
 344          */
 345         mutex_enter(&cachefs_cachelock);
 346 
 347         /*
 348          * Find the cache structure
 349          */
 350         for (cachep = cachefs_cachelist; cachep != NULL;
 351                 cachep = cachep->c_next) {
 352                 if (cachep->c_dirvp == cachedirvp)
 353                         break;
 354         }
 355 
 356         /* if the cache object does not exist, then create it */
 357         if (cachep == NULL) {
 358                 cachep = cachefs_cache_create();
 359                 error = cachefs_cache_activate_ro(cachep, cachedirvp);
 360                 if (error) {
 361                         cachefs_cache_destroy(cachep);
 362                         cachep = NULL;
 363                         goto out;
 364                 }
 365                 if ((cfs_options->opt_flags & CFS_NOFILL) == 0)
 366                         cachefs_cache_activate_rw(cachep);
 367                 else
 368                         cfs_options->opt_flags &= ~CFS_NOFILL;
 369 
 370                 cachep->c_next = cachefs_cachelist;
 371                 cachefs_cachelist = cachep;
 372         } else if (cfs_options->opt_flags & CFS_NOFILL) {
 373                 cmn_err(CE_WARN,
 374                     "CacheFS: attempt to convert nonempty cache "
 375                     "to NOFILL mode");
 376                 error = EINVAL;
 377                 goto out;
 378         }
 379 
 380         /* get the fscache id for this name */
 381         error = fscache_name_to_fsid(cachep, cacheid, &fsid);
 382         if (error) {
 383                 fsid = 0;
 384         }
 385 
 386         /* find the fscache object for this mount point or create it */
 387         mutex_enter(&cachep->c_fslistlock);
 388         fscp = fscache_list_find(cachep, fsid);
 389         if (fscp == NULL) {
 390                 fscp = fscache_create(cachep);
 391                 error = fscache_activate(fscp, fsid, cacheid,
 392                         cfs_options, backfileno);
 393                 if (error) {
 394                         fscache_destroy(fscp);
 395                         fscp = NULL;
 396                         mutex_exit(&cachep->c_fslistlock);
 397                         if ((error == ENOSPC) && (retries-- > 0)) {
 398                                 mutex_exit(&cachefs_cachelock);
 399                                 delay(6 * hz);
 400                                 goto again;
 401                         }
 402                         goto out;
 403                 }
 404                 fscache_list_add(cachep, fscp);
 405         } else {
 406                 /* compare the options to make sure they are compatible */
 407                 error = fscache_compare_options(fscp, cfs_options);
 408                 if (error) {
 409                         cmn_err(CE_WARN,
 410                                 "CacheFS: mount failed, options do not match.");
 411                         fscp = NULL;
 412                         mutex_exit(&cachep->c_fslistlock);
 413                         goto out;
 414                 }
 415 
 416                 /* copy options into the fscache */
 417                 mutex_enter(&fscp->fs_fslock);
 418                 fscp->fs_info.fi_mntflags = cfs_options->opt_flags;
 419                 fscp->fs_info.fi_popsize = cfs_options->opt_popsize;
 420                 fscp->fs_info.fi_fgsize = cfs_options->opt_fgsize;
 421                 fscp->fs_flags |= CFS_FS_DIRTYINFO;
 422                 mutex_exit(&fscp->fs_fslock);
 423         }
 424         fscache_hold(fscp);
 425 
 426         error = 0;
 427         if (fscp->fs_fscdirvp) {
 428                 error = VOP_LOOKUP(fscp->fs_fscdirvp, CACHEFS_DLOG_FILE,
 429                     &tmpdirvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
 430 
 431                 /*
 432                  * If a log file exists and the cache is being mounted without
 433                  * the snr (aka disconnectable) option, return an error.
 434                  */
 435                 if ((error == 0) &&
 436                     !(cfs_options->opt_flags & CFS_DISCONNECTABLE)) {
 437                         mutex_exit(&cachep->c_fslistlock);
 438                         cmn_err(CE_WARN, "cachefs: log exists and "
 439                             "disconnectable option not specified\n");
 440                         error = EINVAL;
 441                         goto out;
 442                 }
 443         }
 444 
 445         /*
 446          * Acquire the name of the mount point
 447          */
 448         if (fscp->fs_mntpt == NULL) {
 449                 /*
 450                  * the string length returned by copystr includes the
 451                  * terminating NULL character, unless a NULL string is
 452                  * passed in, then the string length is unchanged.
 453                  */
 454                 strl = 0;
 455                 tmpstr[0] = '\0';
 456                 (void) copyinstr(uap->dir, tmpstr, MAXPATHLEN, &strl);
 457                 if (strl > 1) {
 458                         fscp->fs_mntpt = kmem_alloc(strl, KM_SLEEP);
 459                         (void) strncpy(fscp->fs_mntpt, tmpstr, strl);
 460                 }
 461                 /*
 462                  * else fscp->fs_mntpt is unchanged(still NULL) try again
 463                  * next time
 464                  */
 465         }
 466 
 467         /*
 468          * Acquire the name of the server
 469          */
 470         if (fscp->fs_hostname == NULL) {
 471                 strl = 0;
 472                 tmpstr[0] = '\0';
 473                 /*LINTED 32-bit pointer casting okay*/
 474                 (void) copyinstr((char *)STRUCT_FGETP(map, cfs_hostname),
 475                                 tmpstr, MAXPATHLEN, &strl);
 476                 if (strl > 1) {
 477                         fscp->fs_hostname = kmem_alloc(strl, KM_SLEEP);
 478                         (void) strncpy(fscp->fs_hostname, tmpstr, strl);
 479                 }
 480                 /*
 481                  * else fscp->fs_hostname remains unchanged (is still NULL)
 482                  */
 483         }
 484 
 485         /*
 486          * Acquire name of the back filesystem
 487          */
 488         if (fscp->fs_backfsname == NULL) {
 489                 strl = 0;
 490                 tmpstr[0] = '\0';
 491                 /*LINTED 32-bit pointer casting okay*/
 492                 (void) copyinstr((char *)STRUCT_FGETP(map, cfs_backfsname),
 493                                 tmpstr, MAXPATHLEN, &strl);
 494                 if (strl > 1) {
 495                         fscp->fs_backfsname = kmem_alloc(strl, KM_SLEEP);
 496                         (void) strncpy(fscp->fs_backfsname, tmpstr, strl);
 497                 }
 498                 /*
 499                  * else fscp->fs_backfsname remains unchanged (is still NULL)
 500                  */
 501         }
 502 
 503         backfileno = fscp->fs_info.fi_root;
 504         mutex_exit(&cachep->c_fslistlock);
 505 
 506         /* see if fscache object is already mounted, it not, make it so */
 507         error = fscache_mounted(fscp, vfsp, backvfsp);
 508         if (error) {
 509                 /* fs cache was already mounted */
 510                 error = EBUSY;
 511                 goto out;
 512         }
 513 
 514         cachefs_kstat_mount(fscp, uap->dir, backmntpt, cachedir, cacheid);
 515 
 516         /* set nfs style time out parameters */
 517         fscache_acset(fscp, STRUCT_FGET(map, cfs_acregmin),
 518             STRUCT_FGET(map, cfs_acregmax),
 519             STRUCT_FGET(map, cfs_acdirmin), STRUCT_FGET(map, cfs_acdirmax));
 520 
 521         vfsp->vfs_dev = cachefs_dev;
 522         vfsp->vfs_data = (caddr_t)fscp;
 523         vfs_make_fsid(&vfsp->vfs_fsid, cachefs_dev, cachefsfstyp);
 524         vfsp->vfs_fstype = cachefsfstyp;
 525         if (backvfsp)
 526                 vfsp->vfs_bsize = backvfsp->vfs_bsize;
 527         else
 528                 vfsp->vfs_bsize = MAXBSIZE;  /* XXX */
 529 
 530         /* make a cnode for the root of the file system */
 531         cid.cid_flags = 0;
 532         cid.cid_fileno = backfileno;
 533         error = cachefs_cnode_make(&cid, fscp, (valid_fid ? cookiep : NULL),
 534                                 attrp, backrootvp, cr, CN_ROOT, &cp);
 535 
 536         if (error) {
 537                 cmn_err(CE_WARN, "cachefs_mount: can't create root cnode\n");
 538                 goto out;
 539         }
 540 
 541         /* stick the root cnode in the fscache object */
 542         mutex_enter(&fscp->fs_fslock);
 543         fscp->fs_rootvp = CTOV(cp);
 544         fscp->fs_rootvp->v_flag |= VROOT;
 545         fscp->fs_rootvp->v_type |= cp->c_attr.va_type;
 546         ASSERT(fscp->fs_rootvp->v_type == VDIR);
 547 
 548         /*
 549          * Get the maxfilesize bits of the back file system.
 550          */
 551 
 552         error = VOP_PATHCONF(backrootvp, _PC_FILESIZEBITS, &maxfilesizebits,
 553                     kcred, NULL);
 554 
 555         if (error) {
 556                 cmn_err(CE_WARN,
 557         "cachefs_mount: Can't get the FILESIZEBITS of the back root vnode \n");
 558                 goto out;
 559         }
 560 
 561         fscp->fs_offmax = (1LL << (maxfilesizebits - 1)) - 1;
 562         mutex_exit(&fscp->fs_fslock);
 563 
 564         /* remove the unmount file if it is there */
 565         (void) VOP_REMOVE(fscp->fs_fscdirvp, CACHEFS_UNMNT_FILE, kcred, NULL,
 566             0);
 567 
 568         /* wake up the cache worker if ANY packed pending work */
 569         mutex_enter(&cachep->c_contentslock);
 570         if (cachep->c_flags & CACHE_PACKED_PENDING)
 571                 cv_signal(&cachep->c_cwcv);
 572         mutex_exit(&cachep->c_contentslock);
 573 
 574         /*
 575          * Warn that caching is disabled with NFSv4 first time around.
 576          */
 577         if (!cachefs_nfsv4_warnmsg && CFS_ISFS_BACKFS_NFSV4(fscp)) {
 578                 cmn_err(CE_WARN,
 579                         "Cachefs has detected a mount with NFSv4: caching will"
 580                         " be disabled for this and other NFSv4 mounts\n");
 581                 cachefs_nfsv4_warnmsg = TRUE;
 582         }
 583 
 584 out:
 585         /*
 586          * make a log entry, if appropriate
 587          */
 588 
 589         if ((cachep != NULL) &&
 590             CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_MOUNT))
 591                 cachefs_log_mount(cachep, error, vfsp, fscp,
 592                     uap->dir, UIO_USERSPACE,
 593                     (STRUCT_BUF(map) != NULL) ? cacheid : NULL);
 594 
 595         /*
 596          * Cleanup our mess
 597          */
 598         if (cookiep != NULL)
 599                 cachefs_kmem_free(cookiep, sizeof (struct fid));
 600         if (cachedirvp != NULL)
 601                 VN_RELE(cachedirvp);
 602         if (backrootvp != NULL)
 603                 VN_RELE(backrootvp);
 604         if (fscp)
 605                 fscache_rele(fscp);
 606         if (attrp)
 607                 cachefs_kmem_free(attrp, sizeof (struct vattr));
 608 
 609         if (error) {
 610                 if (cachep) {
 611                         int xx;
 612 
 613                         /* lock the cachep's fslist */
 614                         mutex_enter(&cachep->c_fslistlock);
 615 
 616                         /*
 617                          * gc isn't necessary for list_mounted(), but
 618                          * we want to do it anyway.
 619                          */
 620 
 621                         fscache_list_gc(cachep);
 622                         xx = fscache_list_mounted(cachep);
 623 
 624                         mutex_exit(&cachep->c_fslistlock);
 625 
 626                         /* if no more references to this cachep, punt it. */
 627                         if (xx == 0)
 628                                 cachefs_delete_cachep(cachep);
 629                         mutex_exit(&cachefs_cachelock);
 630                 }
 631         } else {
 632                 mutex_exit(&cachefs_cachelock);
 633         }
 634 
 635 #ifdef CFSDEBUG
 636         CFS_DEBUG(CFSDEBUG_VFSOP)
 637                 printf("cachefs_mount: EXIT\n");
 638 #endif
 639         return (error);
 640 }
 641 
 642 void
 643 cachefs_kstat_mount(struct fscache *fscp,
 644     char *umountpoint, char *ubackfs, char *ucachedir, char *cacheid)
 645 {
 646         cachefscache_t *cachep = fscp->fs_cache;
 647         cachefs_kstat_key_t *key;
 648         char *mountpoint = NULL, *backfs = NULL, *cachedir = NULL;
 649         size_t len;
 650         kstat_t *ksp;
 651         int i, rc;
 652 
 653         mountpoint = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
 654         if (copyinstr(umountpoint, mountpoint, MAXPATHLEN, &len) != 0)
 655                 goto out;
 656 
 657         cachedir = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
 658         if (copyinstr(ucachedir, cachedir, MAXPATHLEN, &len) != 0)
 659                 goto out;
 660 
 661         backfs = cachefs_kmem_alloc(MAXPATHLEN, KM_SLEEP);
 662         if (backfs) {
 663                 if (copyinstr(ubackfs, backfs, MAXPATHLEN, &len) != 0)
 664                         goto out;
 665         } else {
 666                 (void) strcpy(backfs, "no back file system");
 667         }
 668 
 669         ASSERT(strlen(mountpoint) < MAXPATHLEN);
 670         ASSERT(strlen(backfs) < MAXPATHLEN);
 671         ASSERT(strlen(cachedir) < MAXPATHLEN);
 672 
 673         /* protect cachefs_kstat_key */
 674         mutex_enter(&cachefs_kstat_key_lock);
 675         /*
 676          * XXXX If already there, why not go straight to it?
 677          * We know that fscp->fs_kstat_id == i + 1
 678          */
 679         i = fscp->fs_kstat_id - 1;
 680         if ((i >= 0) && (i < cachefs_kstat_key_n))
 681                 rc = 1;
 682         else
 683                 rc = i = 0;
 684         for (; i < cachefs_kstat_key_n; i++) {
 685                 key = cachefs_kstat_key + i;
 686                 if (strcmp((char *)(uintptr_t)key->ks_mountpoint,
 687                     mountpoint) == 0 &&
 688                     strcmp((char *)(uintptr_t)key->ks_cachedir,
 689                     cachedir) == 0 &&
 690                     strcmp((char *)(uintptr_t)key->ks_cacheid, cacheid) == 0)
 691                         break;
 692                 if (rc) {       /* direct key did not work - check all */
 693                         i = -1; /* will increment to zero in loop */
 694                         rc = 0;
 695                 }
 696         }
 697 
 698         if (i >= cachefs_kstat_key_n) {
 699                 key = cachefs_kmem_alloc((cachefs_kstat_key_n + 1) *
 700                     sizeof (cachefs_kstat_key_t), KM_SLEEP);
 701                 if (cachefs_kstat_key != NULL) {
 702                         bcopy(cachefs_kstat_key, key,
 703                             cachefs_kstat_key_n * sizeof (*key));
 704                         cachefs_kmem_free(cachefs_kstat_key,
 705                             cachefs_kstat_key_n * sizeof (*key));
 706                 }
 707                 cachefs_kstat_key = key;
 708                 key = cachefs_kstat_key + cachefs_kstat_key_n;
 709                 ++cachefs_kstat_key_n;
 710                 rc = key->ks_id = cachefs_kstat_key_n; /* offset + 1 */
 711 
 712                 key->ks_mountpoint = (uint64_t)(uintptr_t)
 713                     cachefs_strdup(mountpoint);
 714                 key->ks_backfs = (uint64_t)(uintptr_t)cachefs_strdup(backfs);
 715                 key->ks_cachedir = (uint64_t)(uintptr_t)
 716                     cachefs_strdup(cachedir);
 717                 key->ks_cacheid = (uint64_t)(uintptr_t)cachefs_strdup(cacheid);
 718         } else
 719                 rc = key->ks_id;
 720 
 721         mutex_enter(&fscp->fs_fslock); /* protect fscp */
 722 
 723         fscp->fs_kstat_id = rc;
 724 
 725         mutex_exit(&fscp->fs_fslock); /* finished with fscp */
 726         /* finished cachefs_kstat_key */
 727         mutex_exit(&cachefs_kstat_key_lock);
 728 
 729         key->ks_vfsp = (uint64_t)(uintptr_t)fscp->fs_cfsvfsp;
 730         key->ks_mounted = 1;
 731 
 732         /*
 733          * we must not be holding any mutex that is a ks_lock field
 734          * for one of the kstats when we invoke kstat_create,
 735          * kstat_install, and friends.
 736          */
 737         ASSERT(MUTEX_NOT_HELD(&cachefs_kstat_key_lock));
 738         /* really should be EVERY cachep's c_log_mutex */
 739         ASSERT(MUTEX_NOT_HELD(&cachep->c_log_mutex));
 740 
 741         /* cachefs.#.log */
 742         ksp = kstat_create("cachefs", fscp->fs_kstat_id, "log",
 743             "misc", KSTAT_TYPE_RAW, 1,
 744             KSTAT_FLAG_WRITABLE | KSTAT_FLAG_VIRTUAL);
 745         if (ksp != NULL) {
 746                 ksp->ks_data = cachep->c_log_ctl;
 747                 ksp->ks_data_size = sizeof (cachefs_log_control_t);
 748                 ksp->ks_lock = &cachep->c_log_mutex;
 749                 ksp->ks_snapshot = cachefs_log_kstat_snapshot;
 750                 kstat_install(ksp);
 751         }
 752         /* cachefs.#.stats */
 753         ksp = kstat_create("cachefs", fscp->fs_kstat_id, "stats",
 754             "misc", KSTAT_TYPE_RAW, 1,
 755             KSTAT_FLAG_WRITABLE | KSTAT_FLAG_VIRTUAL);
 756         if (ksp != NULL) {
 757                 ksp->ks_data = fscp;
 758                 ksp->ks_data_size = sizeof (cachefs_stats_t);
 759                 ksp->ks_snapshot = cachefs_stats_kstat_snapshot;
 760                 kstat_install(ksp);
 761         }
 762 
 763 out:
 764         if (mountpoint != NULL)
 765                 cachefs_kmem_free(mountpoint, MAXPATHLEN);
 766         if (backfs != NULL)
 767                 cachefs_kmem_free(backfs, MAXPATHLEN);
 768         if (cachedir != NULL)
 769                 cachefs_kmem_free(cachedir, MAXPATHLEN);
 770 }
 771 
 772 void
 773 cachefs_kstat_umount(int ksid)
 774 {
 775         cachefs_kstat_key_t *k = cachefs_kstat_key + (ksid - 1);
 776 
 777         ASSERT(k->ks_id == ksid);
 778 
 779         k->ks_mounted = 0;
 780 
 781         kstat_delete_byname("cachefs", ksid, "stats");
 782         kstat_delete_byname("cachefs", ksid, "log");
 783 }
 784 
 785 int
 786 cachefs_kstat_key_update(kstat_t *ksp, int rw)
 787 {
 788         cachefs_kstat_key_t *key = *((cachefs_kstat_key_t **)ksp->ks_data);
 789         cachefs_kstat_key_t *k;
 790         int i;
 791 
 792         if (rw == KSTAT_WRITE)
 793                 return (EIO);
 794         if (key == NULL)
 795                 return (EIO);
 796 
 797         ksp->ks_data_size = cachefs_kstat_key_n * sizeof (*key);
 798         for (i = 0; i < cachefs_kstat_key_n; i++) {
 799                 k = key + i;
 800 
 801                 ksp->ks_data_size +=
 802                     strlen((char *)(uintptr_t)k->ks_mountpoint) + 1;
 803                 ksp->ks_data_size +=
 804                     strlen((char *)(uintptr_t)k->ks_backfs) + 1;
 805                 ksp->ks_data_size +=
 806                     strlen((char *)(uintptr_t)k->ks_cachedir) + 1;
 807                 ksp->ks_data_size +=
 808                     strlen((char *)(uintptr_t)k->ks_cacheid) + 1;
 809         }
 810 
 811         ksp->ks_ndata = cachefs_kstat_key_n;
 812 
 813         return (0);
 814 }
 815 
 816 int
 817 cachefs_kstat_key_snapshot(kstat_t *ksp, void *buf, int rw)
 818 {
 819         cachefs_kstat_key_t *key = *((cachefs_kstat_key_t **)ksp->ks_data);
 820         cachefs_kstat_key_t *k;
 821         caddr_t s;
 822         int i;
 823 
 824         if (rw == KSTAT_WRITE)
 825                 return (EIO);
 826 
 827         if (key == NULL)
 828                 return (0); /* paranoid */
 829 
 830         bcopy(key, buf, cachefs_kstat_key_n * sizeof (*key));
 831         key = buf;
 832         s = (caddr_t)(key + cachefs_kstat_key_n);
 833 
 834         for (i = 0; i < cachefs_kstat_key_n; i++) {
 835                 k = key + i;
 836 
 837                 (void) strcpy(s, (char *)(uintptr_t)k->ks_mountpoint);
 838                 k->ks_mountpoint = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
 839                 s += strlen(s) + 1;
 840                 (void) strcpy(s, (char *)(uintptr_t)k->ks_backfs);
 841                 k->ks_backfs = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
 842                 s += strlen(s) + 1;
 843                 (void) strcpy(s, (char *)(uintptr_t)k->ks_cachedir);
 844                 k->ks_cachedir = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
 845                 s += strlen(s) + 1;
 846                 (void) strcpy(s, (char *)(uintptr_t)k->ks_cacheid);
 847                 k->ks_cacheid = (uint64_t)(uintptr_t)(s - (uintptr_t)buf);
 848                 s += strlen(s) + 1;
 849         }
 850 
 851         return (0);
 852 }
 853 
 854 extern void  cachefs_inactivate();
 855 
 856 static int
 857 cachefs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
 858 {
 859         fscache_t *fscp = VFS_TO_FSCACHE(vfsp);
 860         struct cachefscache *cachep = fscp->fs_cache;
 861         int error;
 862         int xx;
 863         vnode_t *nmvp;
 864         struct vattr attr;
 865 
 866 #ifdef CFSDEBUG
 867         CFS_DEBUG(CFSDEBUG_VFSOP)
 868                 printf("cachefs_unmount: ENTER fscp %p\n", fscp);
 869 #endif
 870 
 871         if ((error = secpolicy_fs_unmount(cr, vfsp)) != 0)
 872                 goto out;
 873 
 874         /*
 875          * forced unmount is not supported by this file system
 876          * and thus, ENOTSUP, is being returned.
 877          */
 878         if (flag & MS_FORCE) {
 879                 error = ENOTSUP;
 880                 goto out;
 881         }
 882         /* if a log file exists don't allow the unmount */
 883         if (fscp->fs_dlogfile) {
 884                 error = EBUSY;
 885                 goto out;
 886         }
 887 
 888         /*
 889          * wait for the cache-wide async queue to drain.  Someone
 890          * here may be trying to sync our fscache...
 891          */
 892         while (cachefs_async_halt(&fscp->fs_cache->c_workq, 0) == EBUSY) {
 893 #ifdef CFSDEBUG
 894                 CFS_DEBUG(CFSDEBUG_VFSOP)
 895                         printf("unmount: waiting for cache async queue...\n");
 896 #endif
 897         }
 898 
 899         error = cachefs_async_halt(&fscp->fs_workq, 1);
 900         if (error) {
 901 #ifdef CFSDEBUG
 902                 CFS_DEBUG(CFSDEBUG_VFSOP)
 903                         printf("cachefs_unmount: "
 904                             "cachefs_async_halt error %d\n", error);
 905 #endif
 906                 goto out;
 907         }
 908 
 909         /*
 910          * No active cnodes on this cache && rootvp refcnt == 1
 911          */
 912         mutex_enter(&fscp->fs_fslock);
 913         xx = fscp->fs_cnodecnt - fscp->fs_idlecnt;
 914         ASSERT(xx >= 1);
 915         if (xx > 1 || fscp->fs_rootvp->v_count != 1) {
 916                 mutex_exit(&fscp->fs_fslock);
 917 #ifdef CFSDEBUG
 918                 CFS_DEBUG(CFSDEBUG_VFSOP)
 919                         printf("cachefs_unmount: busy (cnodes active %d, idle "
 920                                 "%d)\n", fscp->fs_cnodecnt, fscp->fs_idlecnt);
 921 #endif
 922                 error = EBUSY;
 923                 goto out;
 924         }
 925         mutex_exit(&fscp->fs_fslock);
 926 
 927         /* get rid of anything on the idle list */
 928         ASSERT(fscp->fs_idleclean == 0);
 929         cachefs_cnode_idleclean(fscp, 1);
 930         if (fscp->fs_cnodecnt > 1) {
 931 #ifdef CFSDEBUG
 932                 CFS_DEBUG(CFSDEBUG_VFSOP)
 933                         printf("cachefs_unmount: busy (cnode count %d)\n",
 934                                 fscp->fs_cnodecnt);
 935 #endif
 936                 error = EBUSY;
 937                 goto out;
 938         }
 939 
 940         fscache_hold(fscp);
 941 
 942         /* get rid of the root cnode */
 943         if (cachefs_cnode_inactive(fscp->fs_rootvp, cr) == EBUSY) {
 944                 fscache_rele(fscp);
 945 #ifdef CFSDEBUG
 946                 CFS_DEBUG(CFSDEBUG_VFSOP)
 947                         printf("cachefs_unmount: busy (inactive failed)\n");
 948 #endif
 949                 error = EBUSY;
 950                 goto out;
 951         }
 952 
 953         /* create the file indicating not mounted */
 954         attr.va_mode = S_IFREG | 0666;
 955         attr.va_uid = 0;
 956         attr.va_gid = 0;
 957         attr.va_type = VREG;
 958         attr.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
 959         if (fscp->fs_fscdirvp != NULL)
 960                 xx = VOP_CREATE(fscp->fs_fscdirvp, CACHEFS_UNMNT_FILE, &attr,
 961                     NONEXCL, 0600, &nmvp, kcred, 0, NULL, NULL);
 962         else
 963                 xx = ENOENT; /* for unmounting when NOCACHE */
 964         if (xx == 0) {
 965                 VN_RELE(nmvp);
 966         } else {
 967                 printf("could not create %s %d\n", CACHEFS_UNMNT_FILE, xx);
 968         }
 969 
 970         ASSERT(fscp->fs_cnodecnt == 0);
 971 
 972         /* sync the file system just in case */
 973         fscache_sync(fscp);
 974 
 975         /* lock out other unmounts and mount */
 976         mutex_enter(&cachefs_cachelock);
 977 
 978         /* mark the file system as not mounted */
 979         mutex_enter(&fscp->fs_fslock);
 980         fscp->fs_flags &= ~CFS_FS_MOUNTED;
 981         fscp->fs_rootvp = NULL;
 982         if (fscp->fs_kstat_id > 0)
 983                 cachefs_kstat_umount(fscp->fs_kstat_id);
 984         fscp->fs_kstat_id = 0;
 985 
 986         /* drop the inum translation table */
 987         if (fscp->fs_inum_size > 0) {
 988                 cachefs_kmem_free(fscp->fs_inum_trans,
 989                     fscp->fs_inum_size * sizeof (cachefs_inum_trans_t));
 990                 fscp->fs_inum_size = 0;
 991                 fscp->fs_inum_trans = NULL;
 992                 fscp->fs_flags &= ~CFS_FS_HASHPRINT;
 993         }
 994         mutex_exit(&fscp->fs_fslock);
 995 
 996         fscache_rele(fscp);
 997 
 998         /* get rid of any unused fscache objects */
 999         mutex_enter(&cachep->c_fslistlock);
1000         fscache_list_gc(cachep);
1001         mutex_exit(&cachep->c_fslistlock);
1002 
1003         /* get the number of mounts on this cache */
1004         mutex_enter(&cachep->c_fslistlock);
1005         xx = fscache_list_mounted(cachep);
1006         mutex_exit(&cachep->c_fslistlock);
1007 
1008         if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_UMOUNT))
1009                 cachefs_log_umount(cachep, 0, vfsp);
1010 
1011         /* if no mounts left, deactivate the cache */
1012         if (xx == 0)
1013                 cachefs_delete_cachep(cachep);
1014 
1015         mutex_exit(&cachefs_cachelock);
1016 
1017 out:
1018         if (error) {
1019                 if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_UMOUNT))
1020                         cachefs_log_umount(cachep, error, vfsp);
1021         }
1022 #ifdef CFSDEBUG
1023         CFS_DEBUG(CFSDEBUG_VFSOP)
1024                 printf("cachefs_unmount: EXIT\n");
1025 #endif
1026         return (error);
1027 }
1028 
1029 /*
1030  * remove the cache from the list of caches
1031  */
1032 
1033 static void
1034 cachefs_delete_cachep(cachefscache_t *cachep)
1035 {
1036         struct cachefscache **cachepp;
1037         int found = 0;
1038 
1039         ASSERT(MUTEX_HELD(&cachefs_cachelock));
1040 
1041         for (cachepp = &cachefs_cachelist;
1042             *cachepp != NULL;
1043             cachepp = &(*cachepp)->c_next) {
1044                 if (*cachepp == cachep) {
1045                         *cachepp = cachep->c_next;
1046                         found++;
1047                         break;
1048                 }
1049         }
1050         ASSERT(found);
1051 
1052         /* shut down the cache */
1053         cachefs_cache_destroy(cachep);
1054 }
1055 
1056 static int
1057 cachefs_root(vfs_t *vfsp, vnode_t **vpp)
1058 {
1059         /*LINTED alignment okay*/
1060         struct fscache *fscp = (struct fscache *)vfsp->vfs_data;
1061 
1062         ASSERT(fscp != NULL);
1063         ASSERT(fscp->fs_rootvp != NULL);
1064 
1065         if (getzoneid() != GLOBAL_ZONEID)
1066                 return (EPERM);
1067         *vpp = fscp->fs_rootvp;
1068         VN_HOLD(*vpp);
1069         return (0);
1070 }
1071 
1072 /*
1073  * Get file system statistics.
1074  */
1075 static int
1076 cachefs_statvfs(register vfs_t *vfsp, struct statvfs64 *sbp)
1077 {
1078         struct fscache *fscp = VFS_TO_FSCACHE(vfsp);
1079         struct cache_label *lp = &fscp->fs_cache->c_label;
1080         struct cache_usage *up = &fscp->fs_cache->c_usage;
1081         int error;
1082 
1083         if (getzoneid() != GLOBAL_ZONEID)
1084                 return (EPERM);
1085         error = cachefs_cd_access(fscp, 0, 0);
1086         if (error)
1087                 return (error);
1088 
1089         if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
1090                 /*
1091                  * When connected return backfs stats
1092                  */
1093                 error = VFS_STATVFS(fscp->fs_backvfsp, sbp);
1094         } else {
1095                 /*
1096                  * Otherwise, just return the frontfs stats
1097                  */
1098                 ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1099                 error = VFS_STATVFS(fscp->fs_fscdirvp->v_vfsp, sbp);
1100                 if (!error) {
1101                         dev32_t d32;
1102 
1103                         sbp->f_frsize = MAXBSIZE;
1104                         sbp->f_blocks = lp->cl_maxblks;
1105                         sbp->f_bfree = sbp->f_bavail =
1106                             lp->cl_maxblks - up->cu_blksused;
1107                         sbp->f_files = lp->cl_maxinodes;
1108                         sbp->f_ffree = sbp->f_favail =
1109                             lp->cl_maxinodes - up->cu_filesused;
1110                         (void) cmpldev(&d32, vfsp->vfs_dev);
1111                         sbp->f_fsid = d32;
1112                 }
1113         }
1114         cachefs_cd_release(fscp);
1115         if (error)
1116                 return (error);
1117 
1118         /*
1119          * Make sure fstype is CFS.
1120          */
1121         (void) strcpy(sbp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name);
1122         bzero(sbp->f_fstr, sizeof (sbp->f_fstr));
1123 
1124         return (0);
1125 }
1126 
1127 /*
1128  * queue a request to sync the given fscache
1129  */
1130 static void
1131 queue_sync(struct cachefscache *cachep, cred_t *cr)
1132 {
1133         struct cachefs_req *rp;
1134 
1135         rp = kmem_cache_alloc(cachefs_req_cache, KM_SLEEP);
1136         rp->cfs_cmd = CFS_CACHE_SYNC;
1137         rp->cfs_cr = cr;
1138         rp->cfs_req_u.cu_fs_sync.cf_cachep = cachep;
1139         crhold(rp->cfs_cr);
1140         cachefs_addqueue(rp, &cachep->c_workq);
1141 }
1142 
1143 /*ARGSUSED*/
1144 static int
1145 cachefs_sync(vfs_t *vfsp, short flag, cred_t *cr)
1146 {
1147         struct fscache *fscp;
1148         struct cachefscache *cachep;
1149 
1150         if (getzoneid() != GLOBAL_ZONEID)
1151                 return (EPERM);
1152         if (!(flag & SYNC_ATTR)) {
1153                 /*
1154                  * queue an async request to do the sync.
1155                  * We always sync an entire cache (as opposed to an
1156                  * individual fscache) so that we have an opportunity
1157                  * to set the clean flag.
1158                  */
1159                 if (vfsp) {
1160                         /*LINTED alignment okay*/
1161                         fscp = (struct fscache *)vfsp->vfs_data;
1162                         queue_sync(fscp->fs_cache, cr);
1163                 } else {
1164                         mutex_enter(&cachefs_cachelock);
1165                         for (cachep = cachefs_cachelist; cachep != NULL;
1166                             cachep = cachep->c_next) {
1167                                 queue_sync(cachep, cr);
1168                         }
1169                         mutex_exit(&cachefs_cachelock);
1170                 }
1171         }
1172         return (0);
1173 }
1174 
1175 static int
1176 cachefs_remount(struct vfs *vfsp, struct mounta *uap)
1177 {
1178         fscache_t *fscp = VFS_TO_FSCACHE(vfsp);
1179         cachefscache_t *cachep = fscp->fs_cache;
1180         int error = 0;
1181         STRUCT_DECL(cachefs_mountargs, map);
1182         struct cachefsoptions   *cfs_options;
1183         char                    *backfs, *cacheid, *cachedir;
1184         struct vnode *cachedirvp = NULL;
1185         ino64_t fsid;
1186         vnode_t *backrootvp = NULL;
1187         struct vnode *tmpdirvp = NULL;
1188 
1189         STRUCT_INIT(map, get_udatamodel());
1190         error = copyin(uap->dataptr, STRUCT_BUF(map),
1191                         SIZEOF_STRUCT(cachefs_mountargs, DATAMODEL_NATIVE));
1192         if (error)
1193                 goto out;
1194 
1195         /*
1196          * get cache directory vp
1197          */
1198         cachedir = (char *)STRUCT_FGETP(map, cfs_cachedir);
1199         error = lookupname(cachedir, UIO_USERSPACE, FOLLOW,
1200             NULLVPP, &cachedirvp);
1201         if (error)
1202                 goto out;
1203         if (cachedirvp->v_type != VDIR) {
1204                 error = EINVAL;
1205                 goto out;
1206         }
1207 
1208         error = 0;
1209         if (cachedirvp) {
1210                 error = VOP_LOOKUP(cachedirvp, CACHEFS_DLOG_FILE,
1211                     &tmpdirvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
1212         }
1213         cfs_options = (struct cachefsoptions *)STRUCT_FADDR(map, cfs_options);
1214         cacheid = (char *)STRUCT_FGETP(map, cfs_cacheid);
1215 /* XXX not quite right */
1216 #if 0
1217         /*
1218          * If a log file exists and the cache is being mounted without
1219          * the snr (aka disconnectable) option, return an error.
1220          */
1221         if ((error == 0) &&
1222             !(cfs_options->opt_flags & CFS_DISCONNECTABLE)) {
1223                 cmn_err(CE_WARN,
1224                     "cachefs_mount: log exists and disconnectable"
1225                     "option not specified\n");
1226                 error = EINVAL;
1227                 goto out;
1228         }
1229 #endif
1230         error = 0;
1231 
1232         /*
1233          * If the user is using NFSv4 and there are other options
1234          * specified, make sure we ignore the other options.
1235          */
1236         if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
1237                 cfs_options->opt_flags = CFS_BACKFS_NFSV4;
1238         }
1239 
1240         /* XXX need mount options "nocache" and "nofill" */
1241 
1242         /* if nocache is being turned off */
1243         if (cachep->c_flags & CACHE_NOCACHE) {
1244                 error = cachefs_cache_activate_ro(cachep, cachedirvp);
1245                 if (error)
1246                         goto out;
1247                 cachefs_cache_activate_rw(cachep);
1248 
1249                 /* get the fsid for the fscache */
1250                 error = fscache_name_to_fsid(cachep, cacheid, &fsid);
1251                 if (error)
1252                         fsid = 0;
1253 
1254                 /* activate the fscache */
1255                 mutex_enter(&cachep->c_fslistlock);
1256                 error = fscache_enable(fscp, fsid, cacheid,
1257                         cfs_options, fscp->fs_info.fi_root);
1258                 mutex_exit(&cachep->c_fslistlock);
1259                 if (error) {
1260                         cmn_err(CE_WARN, "cachefs: cannot remount %s\n",
1261                                 cacheid);
1262                         goto out;
1263                 }
1264 
1265                 /* enable the cache */
1266                 cachefs_enable_caching(fscp);
1267                 fscache_activate_rw(fscp);
1268         }
1269 
1270         /* else if nofill is being turn off */
1271         else if (cachep->c_flags & CACHE_NOFILL) {
1272                 ASSERT(cachep->c_flags & CACHE_NOFILL);
1273                 cachefs_cache_activate_rw(cachep);
1274 
1275                 /* enable the cache */
1276                 cachefs_enable_caching(fscp);
1277                 fscache_activate_rw(fscp);
1278         }
1279 
1280         fscache_acset(fscp, STRUCT_FGET(map, cfs_acregmin),
1281             STRUCT_FGET(map, cfs_acregmax),
1282             STRUCT_FGET(map, cfs_acdirmin), STRUCT_FGET(map, cfs_acdirmax));
1283 
1284         /* if the backfs is mounted now or we have a new backfs */
1285         backfs = (char *)STRUCT_FGETP(map, cfs_backfs);
1286         if (backfs && (cfs_options->opt_flags & CFS_SLIDE)) {
1287                 /* get the back file system root vp */
1288                 error = lookupname(backfs, UIO_USERSPACE, FOLLOW,
1289                         NULLVPP, &backrootvp);
1290                 if (error)
1291                         goto out;
1292 
1293                 /*
1294                  * Make sure the thing we just looked up is a directory
1295                  * and a root of a file system
1296                  */
1297                 if (backrootvp->v_type != VDIR ||
1298                     !(backrootvp->v_flag & VROOT)) {
1299                         cmn_err(CE_WARN,
1300                             "cachefs_mount: backpath not a directory\n");
1301                         error = EINVAL;
1302                         goto out;
1303                 }
1304 
1305                 /*
1306                  * XXX
1307                  * Kind of dangerous to just set this but we do
1308                  * not have locks around usage of fs_backvfsp.
1309                  * Hope for the best for now.
1310                  * Probably should also spin through vnodes and fix them up.
1311                  * Krishna - fixed c_backvp to reflect the change.
1312                  */
1313                 fscp->fs_backvfsp = backrootvp->v_vfsp;
1314                 ((cnode_t *)(fscp->fs_rootvp->v_data))->c_backvp = backrootvp;
1315 
1316                 /*
1317                  * Now the root cnode structure is an owner of
1318                  * the opened back root vnode structure; we must
1319                  * clear the pointer to back root vnode here as
1320                  * we don't need it since now, and the root cnode
1321                  * structure will control the vnode
1322                  */
1323                 backrootvp = (vnode_t *)NULL;
1324         }
1325 
1326         if (fscp->fs_kstat_id > 0)
1327                 cachefs_kstat_umount(fscp->fs_kstat_id);
1328         fscp->fs_kstat_id = 0;
1329         cachefs_kstat_mount(fscp, uap->dir, backfs, cachedir, cacheid);
1330 
1331         if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_MOUNT))
1332                 cachefs_log_mount(cachep, error, vfsp, fscp,
1333                     uap->dir, UIO_USERSPACE,
1334                     (STRUCT_BUF(map) != NULL) ? cacheid : NULL);
1335 
1336 out:
1337         if (cachedirvp)
1338                 VN_RELE(cachedirvp);
1339         if (backrootvp)
1340                 VN_RELE(backrootvp);
1341         return (error);
1342 }