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 #pragma ident   "%Z%%M% %I%     %E% SMI"
  26 
  27 #include <sys/param.h>
  28 #include <sys/types.h>
  29 #include <sys/systm.h>
  30 #include <sys/cred.h>
  31 #include <sys/proc.h>
  32 #include <sys/user.h>
  33 #include <sys/time.h>
  34 #include <sys/vnode.h>
  35 #include <sys/vfs.h>
  36 #include <sys/file.h>
  37 #include <sys/filio.h>
  38 #include <sys/uio.h>
  39 #include <sys/buf.h>
  40 #include <sys/mman.h>
  41 #include <sys/tiuser.h>
  42 #include <sys/pathname.h>
  43 #include <sys/dirent.h>
  44 #include <sys/conf.h>
  45 #include <sys/debug.h>
  46 #include <sys/vmsystm.h>
  47 #include <sys/fcntl.h>
  48 #include <sys/flock.h>
  49 #include <sys/fbuf.h>
  50 #include <sys/swap.h>
  51 #include <sys/errno.h>
  52 #include <sys/sysmacros.h>
  53 #include <sys/disp.h>
  54 #include <sys/kmem.h>
  55 #include <sys/cmn_err.h>
  56 #include <sys/vtrace.h>
  57 #include <sys/mount.h>
  58 #include <sys/dnlc.h>
  59 #include <sys/stat.h>
  60 #include <rpc/types.h>
  61 
  62 #include <vm/hat.h>
  63 #include <vm/as.h>
  64 #include <vm/page.h>
  65 #include <vm/pvn.h>
  66 #include <vm/seg.h>
  67 #include <vm/seg_map.h>
  68 #include <vm/seg_vn.h>
  69 #include <vm/rm.h>
  70 #include <sys/fs/cachefs_fs.h>
  71 #include <sys/fs/cachefs_dlog.h>
  72 #include <sys/fs/cachefs_ioctl.h>
  73 #include <sys/fs/cachefs_dir.h>
  74 #include <sys/fs/cachefs_dlog.h>
  75 #include "fs/fs_subr.h"
  76 
  77 void cachefs_addhash(struct cnode *);
  78 
  79 
  80 /*
  81  * Local functions
  82  */
  83 static void sync_metadata(cnode_t *);
  84 static void drop_backvp(cnode_t *);
  85 static void allow_pendrm(cnode_t *cp);
  86 static int cachefs_unpack_common(vnode_t *vp);
  87 static int cachefs_unpackall_list(cachefscache_t *cachep,
  88     enum cachefs_rl_type type);
  89 static void cachefs_modified_fix(fscache_t *fscp);
  90 static void cachefs_iosetneedattrs(fscache_t *fscp, cfs_cid_t *cidp);
  91 
  92 #if (defined(_SYSCALL32_IMPL) || defined(_LP64))
  93 
  94 #define CACHEFS_DECL(type, handle)                                      \
  95         type    handle
  96 
  97 #define CACHEFS_TMPPTR_SET(in_addr, tmp_addr, tmp_ptr, type)            \
  98         tmp_ptr = (type *)(tmp_addr)
  99 
 100 #define CACHEFS_FID_COPYOUT(in_fidp, out_fidp)                          \
 101         CACHEFS_FID_COPY((fid_t *)(in_fidp), (cfs_fid_t *)(out_fidp))
 102 
 103 #define CACHEFS_FID_COPYIN(in_fidp, out_fidp)                           \
 104         CACHEFS_FID_COPY((cfs_fid_t *)(in_fidp), (fid_t *)(out_fidp))
 105 
 106 #define CACHEFS_VATTR_COPYOUT(in_vattrp, out_vattrp, error)             \
 107         if (!error) {                                                   \
 108                 CACHEFS_VATTR_TO_CFS_VATTR_COPY((vattr_t *)(in_vattrp), \
 109                         (cfs_vattr_t *)(out_vattrp), error);            \
 110         }
 111 
 112 #define CACHEFS_VATTR_COPYIN(in_vattrp, out_vattrp)                     \
 113         CACHEFS_CFS_VATTR_TO_VATTR_COPY((cfs_vattr_t *)(in_vattrp),     \
 114                         (vattr_t *)(out_vattrp))
 115 
 116 #else /* not _SYSCALL32_IMPL || _LP64 */
 117 
 118 #define CACHEFS_DECL(type, handle)
 119 
 120 #define CACHEFS_TMPPTR_SET(in_addr, tmp_addr, tmp_ptr, type)            \
 121         tmp_ptr = (type *)(in_addr)
 122 
 123 #define CACHEFS_FID_COPYOUT(in_fidp, out_fidp)
 124 
 125 #define CACHEFS_FID_COPYIN(in_fidp, out_fidp)
 126 
 127 #define CACHEFS_VATTR_COPYOUT(in_vattrp, out_vattrp, error)
 128 
 129 #define CACHEFS_VATTR_COPYIN(in_vattrp, out_vattrp)
 130 
 131 #endif  /* _SYSCALL32_IMPL || _LP64 */
 132 
 133 /*
 134  * Conjure up a credential from the partial credential stored in
 135  * a file.  This is bogus and cachefs should really be fixed, but
 136  * this maintains maximum compatibility.
 137  * dl_cred *cr points to a basic credential followed directly by a buffer that
 138  * takes a number of groups.
 139  */
 140 
 141 static cred_t *
 142 conj_cred(dl_cred_t *cr)
 143 {
 144         cred_t *newcr = crget();
 145 
 146         (void) crsetresuid(newcr, cr->cr_ruid, cr->cr_uid, cr->cr_suid);
 147         (void) crsetresgid(newcr, cr->cr_rgid, cr->cr_gid, cr->cr_sgid);
 148 
 149         (void) crsetgroups(newcr, MIN(NGROUPS_MAX_DEFAULT, cr->cr_ngroups),
 150                 cr->cr_groups);
 151 
 152         return (newcr);
 153 }
 154 /*
 155  * Pack a file in the cache
 156  *      dvp is the directory the file resides in.
 157  *      name is the name of the file.
 158  *      Returns 0 or an error if could not perform the operation.
 159  */
 160 int
 161 cachefs_pack(struct vnode *dvp, char *name, cred_t *cr)
 162 {
 163         fscache_t *fscp = C_TO_FSCACHE(VTOC(dvp));
 164         int error = 0;
 165         int connected = 0;
 166         vnode_t *vp;
 167 
 168         /*
 169          * Return if NFSv4 is the backfs (no caching).
 170          */
 171         if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
 172                 goto out;
 173         }
 174 
 175         for (;;) {
 176                 /* get access to the file system */
 177                 error = cachefs_cd_access(fscp, connected, 0);
 178                 if (error)
 179                         break;
 180 
 181                 /* lookup the file name */
 182                 error = cachefs_lookup_common(dvp, name, &vp, NULL, 0, NULL,
 183                     cr);
 184                 if (error == 0) {
 185                         error = cachefs_pack_common(vp, cr);
 186                         VN_RELE(vp);
 187                 }
 188                 if (CFS_TIMEOUT(fscp, error)) {
 189                         if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
 190                                 cachefs_cd_release(fscp);
 191                                 cachefs_cd_timedout(fscp);
 192                                 connected = 0;
 193                                 continue;
 194                         } else {
 195                                 cachefs_cd_release(fscp);
 196                                 connected = 1;
 197                                 continue;
 198                         }
 199                 }
 200                 cachefs_cd_release(fscp);
 201                 break;
 202         }
 203 
 204 out:
 205         return (error);
 206 }
 207 /*
 208  * Packs the file belonging to the passed in vnode.
 209  */
 210 int
 211 cachefs_pack_common(vnode_t *vp, cred_t *cr)
 212 {
 213         cnode_t *cp = VTOC(vp);
 214         fscache_t *fscp = C_TO_FSCACHE(cp);
 215         int error = 0;
 216         offset_t off;
 217         caddr_t buf;
 218         int buflen;
 219         rl_entry_t rl_ent;
 220         u_offset_t cnode_size;
 221 
 222         rw_enter(&cp->c_rwlock, RW_WRITER);
 223         mutex_enter(&cp->c_statelock);
 224 
 225         /* done if cannot write to cache */
 226         if ((cp->c_filegrp->fg_flags & CFS_FG_WRITE) == 0) {
 227                 error = EROFS;
 228                 goto out;
 229         }
 230 
 231         /* done if not usable */
 232         if (cp->c_flags & (CN_STALE | CN_DESTROY)) {
 233                 error = ESTALE;
 234                 goto out;
 235         }
 236 
 237         /* make sure up to date */
 238         error = CFSOP_CHECK_COBJECT(fscp, cp, C_BACK_CHECK, cr);
 239         if (error)
 240                 goto out;
 241 
 242         /* make it cachable */
 243         cp->c_flags &= ~CN_NOCACHE;
 244 
 245         /* get a metadata slot if we do not have one yet */
 246         if (cp->c_flags & CN_ALLOC_PENDING) {
 247                 if (cp->c_filegrp->fg_flags & CFS_FG_ALLOC_ATTR) {
 248                         (void) filegrp_allocattr(cp->c_filegrp);
 249                 }
 250                 error = filegrp_create_metadata(cp->c_filegrp,
 251                     &cp->c_metadata, &cp->c_id);
 252                 if (error)
 253                         goto out;
 254                 cp->c_flags &= ~CN_ALLOC_PENDING;
 255                 cp->c_flags |= CN_UPDATED;
 256         }
 257 
 258         /* cache the ACL if necessary */
 259         if (((fscp->fs_info.fi_mntflags & CFS_NOACL) == 0) &&
 260             (cachefs_vtype_aclok(vp)) &&
 261             ((cp->c_metadata.md_flags & MD_ACL) == 0)) {
 262                 error = cachefs_cacheacl(cp, NULL);
 263                 if (error != 0)
 264                         goto out;
 265         }
 266 
 267         /* directory */
 268         if (vp->v_type == VDIR) {
 269                 if (cp->c_metadata.md_flags & MD_POPULATED)
 270                         goto out;
 271 
 272                 if (error = cachefs_dir_fill(cp, cr))
 273                         goto out;
 274         }
 275 
 276         /* regular file */
 277         else if (vp->v_type == VREG) {
 278                 if (cp->c_metadata.md_flags & MD_POPULATED)
 279                         goto out;
 280 
 281                 if (cp->c_backvp == NULL) {
 282                         error = cachefs_getbackvp(fscp, cp);
 283                         if (error)
 284                                 goto out;
 285                 }
 286                 if (cp->c_frontvp == NULL) {
 287                         error = cachefs_getfrontfile(cp);
 288                         if (error)
 289                                 goto out;
 290                 }
 291                 /* populate the file */
 292                 off = (offset_t)0;
 293                 cnode_size = cp->c_attr.va_size;
 294                 while (off < cnode_size) {
 295                         if (!cachefs_check_allocmap(cp, off)) {
 296                                 u_offset_t popoff;
 297                                 size_t popsize;
 298 
 299                                 cachefs_cluster_allocmap(off, &popoff,
 300                                     &popsize, (size_t)DEF_POP_SIZE, cp);
 301                                 if (popsize != 0) {
 302                                         error = cachefs_populate(cp, popoff,
 303                                             popsize, cp->c_frontvp,
 304                                             cp->c_backvp, cp->c_size, cr);
 305                                         if (error)
 306                                                 goto out;
 307                                         else
 308                                                 cp->c_flags |= (CN_UPDATED |
 309                                                     CN_NEED_FRONT_SYNC |
 310                                                     CN_POPULATION_PENDING);
 311                                         popsize = popsize - (off - popoff);
 312                                 }
 313                         }
 314                         off += PAGESIZE;
 315                 }
 316         }
 317 
 318         /* symbolic link */
 319         else if (vp->v_type == VLNK) {
 320                 if (cp->c_metadata.md_flags & (MD_POPULATED | MD_FASTSYMLNK))
 321                         goto out;
 322 
 323                 /* get the sym link contents from the back fs */
 324                 error = cachefs_readlink_back(cp, cr, &buf, &buflen);
 325                 if (error)
 326                         goto out;
 327 
 328                 /* try to cache the sym link */
 329                 error = cachefs_stuffsymlink(cp, buf, buflen);
 330                 cachefs_kmem_free(buf, MAXPATHLEN);
 331         }
 332 
 333         /* assume that all other types fit in the attributes */
 334 
 335 out:
 336         /* get the rl slot if needed */
 337         if ((error == 0) && (cp->c_metadata.md_rlno == 0)) {
 338                 rl_ent.rl_fileno = cp->c_id.cid_fileno;
 339                 rl_ent.rl_local = (cp->c_id.cid_flags & CFS_CID_LOCAL) ? 1 : 0;
 340                 rl_ent.rl_fsid = fscp->fs_cfsid;
 341                 rl_ent.rl_attrc = 0;
 342                 cp->c_metadata.md_rltype = CACHEFS_RL_NONE;
 343                 error = cachefs_rl_alloc(fscp->fs_cache, &rl_ent,
 344                     &cp->c_metadata.md_rlno);
 345                 if (error == 0)
 346                         error = filegrp_ffhold(cp->c_filegrp);
 347         }
 348 
 349         /* mark the file as packed */
 350         if (error == 0) {
 351                 /* modified takes precedence over packed */
 352                 if (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED) {
 353                         cachefs_rlent_moveto(fscp->fs_cache,
 354                             CACHEFS_RL_PACKED, cp->c_metadata.md_rlno,
 355                             cp->c_metadata.md_frontblks);
 356                         cp->c_metadata.md_rltype = CACHEFS_RL_PACKED;
 357                 }
 358                 cp->c_metadata.md_flags |= MD_PACKED;
 359                 cp->c_flags |= CN_UPDATED;
 360         }
 361 
 362         mutex_exit(&cp->c_statelock);
 363         rw_exit(&cp->c_rwlock);
 364 
 365         return (error);
 366 }
 367 
 368 /*
 369  * Unpack a file from the cache
 370  *      dvp is the directory the file resides in.
 371  *      name is the name of the file.
 372  *      Returns 0 or an error if could not perform the operation.
 373  */
 374 int
 375 cachefs_unpack(struct vnode *dvp, char *name, cred_t *cr)
 376 {
 377         fscache_t *fscp = C_TO_FSCACHE(VTOC(dvp));
 378         int error = 0;
 379         int connected = 0;
 380         vnode_t *vp;
 381 
 382         /* Return error if NFSv4 is the backfs (no caching) */
 383         if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
 384                 goto out;
 385         }
 386 
 387         for (;;) {
 388                 /* get access to the file system */
 389                 error = cachefs_cd_access(fscp, connected, 0);
 390                 if (error)
 391                         break;
 392 
 393                 /* lookup the file name */
 394                 error = cachefs_lookup_common(dvp, name, &vp, NULL, 0, NULL,
 395                     cr);
 396                 if (error == 0) {
 397                         error = cachefs_unpack_common(vp);
 398                         VN_RELE(vp);
 399                 }
 400                 if (CFS_TIMEOUT(fscp, error)) {
 401                         if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
 402                                 cachefs_cd_release(fscp);
 403                                 cachefs_cd_timedout(fscp);
 404                                 connected = 0;
 405                                 continue;
 406                         } else {
 407                                 cachefs_cd_release(fscp);
 408                                 connected = 1;
 409                                 continue;
 410                         }
 411                 }
 412                 cachefs_cd_release(fscp);
 413                 break;
 414         }
 415 out:
 416         return (error);
 417 }
 418 
 419 /*
 420  * Unpacks the file belonging to the passed in vnode.
 421  */
 422 static int
 423 cachefs_unpack_common(vnode_t *vp)
 424 {
 425         cnode_t *cp = VTOC(vp);
 426         fscache_t *fscp = C_TO_FSCACHE(cp);
 427         int error = 0;
 428 
 429         mutex_enter(&cp->c_statelock);
 430 
 431         /* nothing to do if not packed */
 432         if ((cp->c_metadata.md_flags & MD_PACKED) == 0)
 433                 goto out;
 434 
 435         /* nothing to do if cannot modify cache */
 436         if ((cp->c_filegrp->fg_flags & CFS_FG_WRITE) == 0) {
 437                 error = EROFS;
 438                 goto out;
 439         }
 440 
 441         /* mark file as no longer packed */
 442         ASSERT(cp->c_metadata.md_rlno);
 443         cp->c_metadata.md_flags &= ~MD_PACKED;
 444         cp->c_flags |= CN_UPDATED;
 445 
 446         /* done if file has been modified */
 447         if (cp->c_metadata.md_rltype == CACHEFS_RL_MODIFIED)
 448                 goto out;
 449 
 450         /* if there is no front file */
 451         if ((cp->c_metadata.md_flags & MD_FILE) == 0) {
 452                 /* nuke front file resources */
 453                 filegrp_ffrele(cp->c_filegrp);
 454                 cachefs_rlent_moveto(fscp->fs_cache,
 455                     CACHEFS_RL_FREE, cp->c_metadata.md_rlno, 0);
 456                 cp->c_metadata.md_rlno = 0;
 457                 cp->c_metadata.md_rltype = CACHEFS_RL_NONE;
 458         }
 459 
 460         /* else move the front file to the active list */
 461         else {
 462                 cachefs_rlent_moveto(fscp->fs_cache,
 463                     CACHEFS_RL_ACTIVE, cp->c_metadata.md_rlno,
 464                     cp->c_metadata.md_frontblks);
 465                 cp->c_metadata.md_rltype = CACHEFS_RL_ACTIVE;
 466         }
 467 
 468 out:
 469         mutex_exit(&cp->c_statelock);
 470         return (error);
 471 }
 472 
 473 /*
 474  * Returns packing information on a file.
 475  *      dvp is the directory the file resides in.
 476  *      name is the name of the file.
 477  *      *statusp is set to the status of the file
 478  *      Returns 0 or an error if could not perform the operation.
 479  */
 480 int
 481 cachefs_packinfo(struct vnode *dvp, char *name, int *statusp, cred_t *cr)
 482 {
 483         fscache_t *fscp = C_TO_FSCACHE(VTOC(dvp));
 484         struct vnode *vp;
 485         struct cnode *cp;
 486         int error;
 487         int connected = 0;
 488 
 489         *statusp = 0;
 490 
 491         /*
 492          * Return if NFSv4 is the backfs (no caching).
 493          */
 494         if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
 495                 goto out;
 496         }
 497 
 498         for (;;) {
 499                 /* get access to the file system */
 500                 error = cachefs_cd_access(fscp, connected, 0);
 501                 if (error)
 502                         break;
 503 
 504                 /* lookup the file name */
 505                 error = cachefs_lookup_common(dvp, name, &vp, NULL, 0, NULL,
 506                     cr);
 507                 if (CFS_TIMEOUT(fscp, error)) {
 508                         if (fscp->fs_cdconnected == CFS_CD_CONNECTED) {
 509                                 cachefs_cd_release(fscp);
 510                                 cachefs_cd_timedout(fscp);
 511                                 connected = 0;
 512                                 continue;
 513                         } else {
 514                                 cachefs_cd_release(fscp);
 515                                 connected = 1;
 516                                 continue;
 517                         }
 518                 }
 519                 if (error)
 520                         break;
 521                 cp = VTOC(vp);
 522 
 523                 mutex_enter(&cp->c_statelock);
 524                 if (cp->c_metadata.md_flags & MD_PACKED)
 525                         *statusp |= CACHEFS_PACKED_FILE;
 526                 if (cp->c_metadata.md_flags & (MD_POPULATED | MD_FASTSYMLNK))
 527                         *statusp |= CACHEFS_PACKED_DATA;
 528                 else if ((vp->v_type != VREG) &&
 529                     (vp->v_type != VDIR) &&
 530                     (vp->v_type != VLNK))
 531                         *statusp |= CACHEFS_PACKED_DATA;
 532                 else if (cp->c_size == 0)
 533                         *statusp |= CACHEFS_PACKED_DATA;
 534                 if (cp->c_flags & CN_NOCACHE)
 535                         *statusp |= CACHEFS_PACKED_NOCACHE;
 536                 mutex_exit(&cp->c_statelock);
 537 
 538                 VN_RELE(vp);
 539                 cachefs_cd_release(fscp);
 540                 break;
 541         }
 542 
 543 out:
 544         return (error);
 545 }
 546 
 547 /*
 548  * Finds all packed files in the cache and unpacks them.
 549  */
 550 int
 551 cachefs_unpackall(vnode_t *vp)
 552 {
 553         fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
 554         cachefscache_t *cachep = fscp->fs_cache;
 555         int error;
 556 
 557         /*
 558          * Return if NFSv4 is the backfs (no caching).
 559          */
 560         if (CFS_ISFS_BACKFS_NFSV4(fscp)) {
 561                 goto out;
 562         }
 563 
 564         error = cachefs_unpackall_list(cachep, CACHEFS_RL_PACKED);
 565         if (error)
 566                 goto out;
 567         error = cachefs_unpackall_list(cachep, CACHEFS_RL_PACKED_PENDING);
 568 out:
 569         return (error);
 570 }
 571 
 572 /*
 573  * Finds all packed files on the specified list and unpacks them.
 574  */
 575 static int
 576 cachefs_unpackall_list(cachefscache_t *cachep, enum cachefs_rl_type type)
 577 {
 578         fscache_t *fscp = NULL;
 579         cnode_t *cp;
 580         int error = 0;
 581         rl_entry_t rl_ent;
 582         cfs_cid_t cid;
 583 
 584         rl_ent.rl_current = type;
 585         for (;;) {
 586                 /* get the next entry on the specified resource list */
 587                 error = cachefs_rlent_data(cachep, &rl_ent, NULL);
 588                 if (error) {
 589                         error = 0;
 590                         break;
 591                 }
 592 
 593                 /* if the fscp we have does not match */
 594                 if ((fscp == NULL) || (fscp->fs_cfsid != rl_ent.rl_fsid)) {
 595                         if (fscp) {
 596                                 cachefs_cd_release(fscp);
 597                                 fscache_rele(fscp);
 598                                 fscp = NULL;
 599                         }
 600 
 601                         /* get the file system cache object for this fsid */
 602                         mutex_enter(&cachep->c_fslistlock);
 603                         fscp = fscache_list_find(cachep, rl_ent.rl_fsid);
 604                         if (fscp == NULL) {
 605                                 fscp = fscache_create(cachep);
 606                                 error = fscache_activate(fscp, rl_ent.rl_fsid,
 607                                     NULL, NULL, 0);
 608                                 if (error) {
 609                                         cmn_err(CE_WARN,
 610                                             "cachefs: cache error, run fsck\n");
 611                                         fscache_destroy(fscp);
 612                                         fscp = NULL;
 613                                         mutex_exit(&cachep->c_fslistlock);
 614                                         break;
 615                                 }
 616                                 fscache_list_add(cachep, fscp);
 617                         }
 618                         fscache_hold(fscp);
 619                         mutex_exit(&cachep->c_fslistlock);
 620 
 621                         /* get access to the file system */
 622                         error = cachefs_cd_access(fscp, 0, 0);
 623                         if (error) {
 624                                 fscache_rele(fscp);
 625                                 fscp = NULL;
 626                                 break;
 627                         }
 628                 }
 629 
 630                 /* get the cnode for the file */
 631                 cid.cid_fileno = rl_ent.rl_fileno;
 632                 cid.cid_flags = rl_ent.rl_local ? CFS_CID_LOCAL : 0;
 633                 error = cachefs_cnode_make(&cid, fscp,
 634                     NULL, NULL, NULL, kcred, 0, &cp);
 635                 if (error) {
 636 #ifdef CFSDEBUG
 637                         CFS_DEBUG(CFSDEBUG_IOCTL)
 638                                 printf("cachefs: cul: could not find %llu\n",
 639                                     (u_longlong_t)cid.cid_fileno);
 640                         delay(5*hz);
 641 #endif
 642                         continue;
 643                 }
 644 
 645                 /* unpack the file */
 646                 (void) cachefs_unpack_common(CTOV(cp));
 647                 VN_RELE(CTOV(cp));
 648         }
 649 
 650         /* free up allocated resources */
 651         if (fscp) {
 652                 cachefs_cd_release(fscp);
 653                 fscache_rele(fscp);
 654         }
 655         return (error);
 656 }
 657 
 658 /*
 659  * Identifies this process as the cachefsd.
 660  * Stays this way until close is done.
 661  */
 662 int
 663 /*ARGSUSED*/
 664 cachefs_io_daemonid(vnode_t *vp, void *dinp, void *doutp)
 665 {
 666         int error = 0;
 667 
 668         fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
 669         cachefscache_t *cachep = fscp->fs_cache;
 670 
 671         mutex_enter(&fscp->fs_cdlock);
 672 
 673         /* can only do this on the root of the file system */
 674         if (vp != fscp->fs_rootvp)
 675                 error = ENOENT;
 676 
 677         /* else if there already is a daemon running */
 678         else if (fscp->fs_cddaemonid)
 679                 error = EBUSY;
 680 
 681         /* else use the pid to identify the daemon */
 682         else {
 683                 fscp->fs_cddaemonid = ttoproc(curthread)->p_pid;
 684                 cv_broadcast(&fscp->fs_cdwaitcv);
 685         }
 686 
 687         mutex_exit(&fscp->fs_cdlock);
 688 
 689         if (error == 0) {
 690                 /* the daemon that takes care of root is special */
 691                 if (fscp->fs_flags & CFS_FS_ROOTFS) {
 692                         mutex_enter(&cachep->c_contentslock);
 693                         ASSERT(cachep->c_rootdaemonid == 0);
 694                         cachep->c_rootdaemonid = fscp->fs_cddaemonid;
 695                         mutex_exit(&cachep->c_contentslock);
 696                 }
 697         }
 698         return (error);
 699 }
 700 
 701 /*
 702  * Returns the current state in doutp
 703  */
 704 int
 705 /*ARGSUSED*/
 706 cachefs_io_stateget(vnode_t *vp, void *dinp, void *doutp)
 707 {
 708         fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
 709         int *statep = (int *)doutp;
 710         int state;
 711 
 712         /*
 713          * Only called in support of disconnectable operation, so assert
 714          * that this is not called when NFSv4 is the backfilesytem.
 715          */
 716         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
 717 
 718         mutex_enter(&fscp->fs_cdlock);
 719         switch (fscp->fs_cdconnected) {
 720         case CFS_CD_CONNECTED:
 721                 state = CFS_FS_CONNECTED;
 722                 break;
 723         case CFS_CD_DISCONNECTED:
 724                 state = CFS_FS_DISCONNECTED;
 725                 break;
 726         case CFS_CD_RECONNECTING:
 727                 state = CFS_FS_RECONNECTING;
 728                 break;
 729         default:
 730                 ASSERT(0);
 731                 break;
 732         }
 733         mutex_exit(&fscp->fs_cdlock);
 734 
 735         *statep = state;
 736         return (0);
 737 }
 738 
 739 /*
 740  * Sets the state of the file system.
 741  */
 742 int
 743 /*ARGSUSED*/
 744 cachefs_io_stateset(vnode_t *vp, void *dinp, void *doutp)
 745 {
 746         fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
 747         int error = 0;
 748         int nosig = 1;
 749         int state = *(int *)dinp;
 750 
 751         /*
 752          * State should not be changeable and always be connected if
 753          * NFSv4 is in use.
 754          */
 755         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
 756 
 757         /* wait until the file system is quiet */
 758         mutex_enter(&fscp->fs_cdlock);
 759         if (fscp->fs_cdtransition == 1) {
 760                 /* if someone is already changing the state */
 761                 mutex_exit(&fscp->fs_cdlock);
 762                 return (0);
 763         }
 764         fscp->fs_cdtransition = 1;
 765         while (nosig && (fscp->fs_cdrefcnt != 0)) {
 766                 nosig = cv_wait_sig(&fscp->fs_cdwaitcv, &fscp->fs_cdlock);
 767         }
 768         if (!nosig) {
 769                 fscp->fs_cdtransition = 0;
 770                 cv_broadcast(&fscp->fs_cdwaitcv);
 771                 mutex_exit(&fscp->fs_cdlock);
 772                 return (EINTR);
 773         }
 774         mutex_exit(&fscp->fs_cdlock);
 775 
 776         switch (state) {
 777         case CFS_FS_CONNECTED:
 778                 /* done if already in this state */
 779                 if (fscp->fs_cdconnected == CFS_CD_CONNECTED)
 780                         break;
 781 
 782                 mutex_enter(&fscp->fs_cdlock);
 783                 fscp->fs_cdconnected = CFS_CD_CONNECTED;
 784                 mutex_exit(&fscp->fs_cdlock);
 785 
 786                 /* fix up modified files */
 787                 cachefs_modified_fix(fscp);
 788 
 789 #if 0
 790                 if (fscp->fs_hostname != NULL)
 791                         printf("\ncachefs:server          - %s",
 792                             fscp->fs_hostname);
 793                 if (fscp->fs_mntpt != NULL)
 794                         printf("\ncachefs:mount point     - %s",
 795                             fscp->fs_mntpt);
 796                 if (fscp->fs_backfsname != NULL)
 797                         printf("\ncachefs:back filesystem - %s",
 798                             fscp->fs_backfsname);
 799                 printf("\nok\n");
 800 #else
 801                 if (fscp->fs_hostname && fscp->fs_backfsname)
 802                         printf("cachefs: %s:%s ok\n",
 803                             fscp->fs_hostname, fscp->fs_backfsname);
 804                 else
 805                         printf("cachefs: server ok\n");
 806 #endif
 807 
 808                 /* allow deletion of renamed open files to proceed */
 809                 cachefs_cnode_traverse(fscp, allow_pendrm);
 810                 break;
 811 
 812         case CFS_FS_DISCONNECTED:
 813                 /* done if already in this state */
 814                 if (fscp->fs_cdconnected == CFS_CD_DISCONNECTED)
 815                         break;
 816 
 817                 /* drop all back vps */
 818                 cachefs_cnode_traverse(fscp, drop_backvp);
 819 
 820 
 821                 mutex_enter(&fscp->fs_cdlock);
 822                 fscp->fs_cdconnected = CFS_CD_DISCONNECTED;
 823                 mutex_exit(&fscp->fs_cdlock);
 824 
 825 #if 0
 826                 if (fscp->fs_hostname != NULL)
 827                         printf("\ncachefs:server          - %s",
 828                             fscp->fs_hostname);
 829                 if (fscp->fs_mntpt != NULL)
 830                         printf("\ncachefs:mount point     - %s",
 831                             fscp->fs_mntpt);
 832                 if (fscp->fs_backfsname != NULL)
 833                         printf("\ncachefs:back filesystem - %s",
 834                             fscp->fs_backfsname);
 835                 printf("\nnot responding still trying\n");
 836 #else
 837                 if (fscp->fs_hostname && fscp->fs_backfsname)
 838                         printf("cachefs: %s:%s not responding still trying\n",
 839                             fscp->fs_hostname, fscp->fs_backfsname);
 840                 else
 841                         printf("cachefs: server not responding still trying\n");
 842 #endif
 843                 break;
 844 
 845         case CFS_FS_RECONNECTING:
 846                 /* done if already in this state */
 847                 if (fscp->fs_cdconnected == CFS_CD_RECONNECTING)
 848                         break;
 849 
 850                 /*
 851                  * Before we enter disconnected state we sync all metadata,
 852                  * this allows us to read metadata directly in subsequent
 853                  * calls so we don't need to allocate cnodes when
 854                  * we just need metadata information.
 855                  */
 856                 /* XXX bob: need to eliminate this */
 857                 cachefs_cnode_traverse(fscp, sync_metadata);
 858 
 859                 mutex_enter(&fscp->fs_cdlock);
 860                 fscp->fs_cdconnected = CFS_CD_RECONNECTING;
 861                 mutex_exit(&fscp->fs_cdlock);
 862 
 863                 /* no longer need dlog active */
 864                 cachefs_dlog_teardown(fscp);
 865                 break;
 866 
 867         default:
 868                 error = ENOTTY;
 869                 break;
 870         }
 871 
 872         mutex_enter(&fscp->fs_cdlock);
 873         fscp->fs_cdtransition = 0;
 874         cv_broadcast(&fscp->fs_cdwaitcv);
 875         mutex_exit(&fscp->fs_cdlock);
 876         return (error);
 877 }
 878 
 879 /*
 880  * Blocks until the file system switches
 881  * out of the connected state.
 882  */
 883 int
 884 /*ARGSUSED*/
 885 cachefs_io_xwait(vnode_t *vp, void *dinp, void *doutp)
 886 {
 887         fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
 888         int nosig = 1;
 889 
 890         /*
 891          * Only called in support of disconnectable operation, so assert
 892          * that this is not used when NFSv4 is the backfilesytem.
 893          */
 894         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
 895 
 896         mutex_enter(&fscp->fs_cdlock);
 897         while (nosig &&
 898             (fscp->fs_cdconnected == CFS_CD_CONNECTED)) {
 899                 nosig = cv_wait_sig(&fscp->fs_cdwaitcv, &fscp->fs_cdlock);
 900         }
 901         mutex_exit(&fscp->fs_cdlock);
 902         if (!nosig)
 903                 return (EINTR);
 904 
 905         return (0);
 906 }
 907 
 908 #define RL_HEAD(cachep, type) \
 909         (&(cachep->c_rlinfo.rl_items[CACHEFS_RL_INDEX(type)]))
 910 
 911 /*
 912  * Returns some statistics about the cache.
 913  */
 914 #define CFS_STAT_FACTOR         (MAXBSIZE / 1024)
 915 int
 916 /*ARGSUSED*/
 917 cachefs_io_getstats(vnode_t *vp, void *dinp, void *doutp)
 918 {
 919         fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
 920         cachefscache_t *cachep = fscp->fs_cache;
 921         struct statvfs64 sb;
 922         fsblkcnt64_t avail = 0;
 923         fsblkcnt64_t blocks;
 924         int error;
 925         cachefsio_getstats_t *gsp = (cachefsio_getstats_t *)doutp;
 926 
 927         /* determine number of blocks available to the cache */
 928         error = VFS_STATVFS(cachep->c_dirvp->v_vfsp, &sb);
 929         if (error == 0) {
 930                 blocks = (fsblkcnt64_t)(cachep->c_label.cl_maxblks -
 931                     cachep->c_usage.cu_blksused);
 932                 if ((longlong_t)blocks < (longlong_t)0)
 933                         blocks = (fsblkcnt64_t)0;
 934                 avail = (sb.f_bfree * sb.f_frsize) / MAXBSIZE;
 935                 if (blocks < avail)
 936                         avail = blocks;
 937         }
 938 
 939         gsp->gs_total = cachep->c_usage.cu_blksused * CFS_STAT_FACTOR;
 940         gsp->gs_gc = RL_HEAD(cachep, CACHEFS_RL_GC)->rli_blkcnt *
 941                 CFS_STAT_FACTOR;
 942         gsp->gs_active = RL_HEAD(cachep, CACHEFS_RL_ACTIVE)->rli_blkcnt *
 943                 CFS_STAT_FACTOR;
 944         gsp->gs_packed = RL_HEAD(cachep, CACHEFS_RL_PACKED)->rli_blkcnt *
 945                 CFS_STAT_FACTOR;
 946         gsp->gs_free = (long)(avail * CFS_STAT_FACTOR);
 947         gsp->gs_gctime = cachep->c_rlinfo.rl_gctime;
 948         return (0);
 949 }
 950 
 951 /*
 952  * This looks to see if the specified file exists in the cache.
 953  *      0 is returned if it exists
 954  *      ENOENT is returned if it doesn't exist.
 955  */
 956 int
 957 /*ARGSUSED*/
 958 cachefs_io_exists(vnode_t *vp, void *dinp, void *doutp)
 959 {
 960         fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
 961         cnode_t *cp = NULL;
 962         int error;
 963         cfs_cid_t *cidp = (cfs_cid_t *)dinp;
 964 
 965         /*
 966          * Only called in support of disconnectable operation, so assert
 967          * that this is not called when NFSv4 is the backfilesytem.
 968          */
 969         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
 970 
 971         /* find the cnode of the file */
 972         error = cachefs_cnode_make(cidp, fscp,
 973             NULL, NULL, NULL, kcred, 0, &cp);
 974         if (error)
 975                 return (ENOENT);
 976 
 977         if ((cp->c_flags & (CN_DESTROY | CN_NOCACHE)) ||
 978             !(cp->c_metadata.md_flags & (MD_POPULATED | MD_FASTSYMLNK)))
 979                 error = ENOENT;
 980 
 981         VN_RELE(CTOV(cp));
 982         return  (error);
 983 
 984 }
 985 
 986 /*
 987  * Moves the specified file to the lost+found directory for the
 988  * cached file system.
 989  * Invalidates cached data and attributes.
 990  * Returns 0 or an error if could not perform operation.
 991  */
 992 int
 993 cachefs_io_lostfound(vnode_t *vp, void *dinp, void *doutp)
 994 {
 995         int error;
 996         cnode_t *cp = NULL;
 997         fscache_t *fscp;
 998         cachefscache_t *cachep;
 999         cachefsio_lostfound_arg_t *lfp;
1000         cachefsio_lostfound_return_t *rp;
1001 
1002         lfp = (cachefsio_lostfound_arg_t *)dinp;
1003         rp = (cachefsio_lostfound_return_t *)doutp;
1004 
1005         fscp = C_TO_FSCACHE(VTOC(vp));
1006         cachep = fscp->fs_cache;
1007 
1008         ASSERT((cachep->c_flags & (CACHE_NOCACHE|CACHE_NOFILL)) == 0);
1009 
1010         /*
1011          * Only called in support of disconnectable operation, so assert
1012          * that this is not called when NFSv4 is the backfilesytem.
1013          */
1014         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1015 
1016         /* find the cnode of the file */
1017         error = cachefs_cnode_make(&lfp->lf_cid, fscp,
1018             NULL, NULL, NULL, kcred, 0, &cp);
1019         if (error) {
1020                 error = ENOENT;
1021                 goto out;
1022         }
1023 
1024         mutex_enter(&cp->c_statelock);
1025 
1026         /* must be regular file and modified */
1027         if ((cp->c_attr.va_type != VREG) ||
1028             (cp->c_metadata.md_rltype != CACHEFS_RL_MODIFIED)) {
1029                 mutex_exit(&cp->c_statelock);
1030                 error = EINVAL;
1031                 goto out;
1032         }
1033 
1034         /* move to lost+found */
1035         error = cachefs_cnode_lostfound(cp, lfp->lf_name);
1036         mutex_exit(&cp->c_statelock);
1037 
1038         if (error == 0)
1039                 (void) strcpy(rp->lf_name, lfp->lf_name);
1040 out:
1041         if (cp)
1042                 VN_RELE(CTOV(cp));
1043 
1044         return (error);
1045 }
1046 
1047 /*
1048  * Given a cid, returns info about the file in the cache.
1049  */
1050 int
1051 cachefs_io_getinfo(vnode_t *vp, void *dinp, void *doutp)
1052 {
1053         fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
1054         struct cnode *dcp = NULL;
1055         struct cnode *cp = NULL;
1056         struct vattr va;
1057         u_offset_t blockoff = 0;
1058         struct fbuf *fbp;
1059         int offset = 0;
1060         int error = 0;
1061         cfs_cid_t *fcidp;
1062         cachefsio_getinfo_t *infop;
1063 
1064         /*
1065          * Only called in support of disconnectable operation, so assert
1066          * that this is not called when NFSv4 is the backfilesytem.
1067          */
1068         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1069 
1070         fcidp = (cfs_cid_t *)dinp;
1071         infop = (cachefsio_getinfo_t *)doutp;
1072 
1073         /* find the cnode of the file */
1074         error = cachefs_cnode_make(fcidp, fscp, NULL, NULL, NULL,
1075             kcred, 0, &cp);
1076         if (error) {
1077                 error = ENOENT;
1078                 goto out;
1079         }
1080 
1081         infop->gi_cid = *fcidp;
1082         infop->gi_modified = (cp->c_metadata.md_rltype == CACHEFS_RL_MODIFIED);
1083         CACHEFS_VATTR_TO_CFS_VATTR_COPY(&cp->c_attr, &infop->gi_attr, error);
1084         infop->gi_pcid = cp->c_metadata.md_parent;
1085         infop->gi_name[0] = '\0';
1086         infop->gi_seq = cp->c_metadata.md_seq;
1087         if (error || (cp->c_metadata.md_parent.cid_fileno == 0))
1088                 goto out;
1089 
1090         /* try to get the cnode of the parent dir */
1091         error = cachefs_cnode_make(&cp->c_metadata.md_parent, fscp,
1092             NULL, NULL, NULL, kcred, 0, &dcp);
1093         if (error) {
1094                 error = 0;
1095                 goto out;
1096         }
1097 
1098         /* make sure a directory and populated */
1099         if ((((dcp->c_flags & CN_ASYNC_POPULATE) == 0) ||
1100             ((dcp->c_metadata.md_flags & MD_POPULATED) == 0)) &&
1101             (CTOV(dcp)->v_type == VDIR)) {
1102                 error = 0;
1103                 goto out;
1104         }
1105 
1106         /* get the front file */
1107         if (dcp->c_frontvp == NULL) {
1108                 mutex_enter(&dcp->c_statelock);
1109                 error = cachefs_getfrontfile(dcp);
1110                 mutex_exit(&dcp->c_statelock);
1111                 if (error) {
1112                         error = 0;
1113                         goto out;
1114                 }
1115 
1116                 /* make sure frontvp is still populated */
1117                 if ((dcp->c_metadata.md_flags & MD_POPULATED) == 0) {
1118                         error = 0;
1119                         goto out;
1120                 }
1121         }
1122 
1123         /* Get the length of the directory */
1124         va.va_mask = AT_SIZE;
1125         error = VOP_GETATTR(dcp->c_frontvp, &va, 0, kcred, NULL);
1126         if (error) {
1127                 error = 0;
1128                 goto out;
1129         }
1130 
1131         /* XXX bob: change this to use cachfs_dir_read */
1132         /* We have found the parent, now we open the dir and look for file */
1133         while (blockoff < va.va_size) {
1134                 offset = 0;
1135                 error = fbread(dcp->c_frontvp, (offset_t)blockoff, MAXBSIZE,
1136                                                 S_OTHER, &fbp);
1137                 if (error)
1138                         goto out;
1139                 while (offset < MAXBSIZE && (blockoff + offset) < va.va_size) {
1140                         struct c_dirent *dep;
1141                         dep = (struct c_dirent *)((uintptr_t)fbp->fb_addr +
1142                                                                         offset);
1143                         if ((dep->d_flag & CDE_VALID) &&
1144                             (bcmp(&dep->d_id, &infop->gi_cid,
1145                             sizeof (cfs_cid_t)) == 0)) {
1146                                 /* found the name */
1147                                 (void) strcpy(infop->gi_name, dep->d_name);
1148                                 fbrelse(fbp, S_OTHER);
1149                                 goto out;
1150                         }
1151                         offset += dep->d_length;
1152                 }
1153                 fbrelse(fbp, S_OTHER);
1154                 fbp = NULL;
1155                 blockoff += MAXBSIZE;
1156 
1157         }
1158 out:
1159         if (cp)
1160                 VN_RELE(CTOV(cp));
1161         if (dcp)
1162                 VN_RELE(CTOV(dcp));
1163         return (error);
1164 }
1165 
1166 /*
1167  * Given a file number, this functions returns the fid
1168  * for the back file system.
1169  * Returns ENOENT if file does not exist.
1170  * Returns ENOMSG if fid is not valid, ie: local file.
1171  */
1172 int
1173 cachefs_io_cidtofid(vnode_t *vp, void *dinp, void *doutp)
1174 {
1175         fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
1176         cnode_t *cp = NULL;
1177         int error;
1178         cfs_cid_t *cidp = (cfs_cid_t *)dinp;
1179         cfs_fid_t *fidp = (cfs_fid_t *)doutp;
1180 
1181         /*
1182          * Only called in support of disconnectable operation, so assert
1183          * that this is not called when NFSv4 is the backfilesytem.
1184          */
1185         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1186 
1187         /* get the cnode for the file */
1188         error = cachefs_cnode_make(cidp, fscp, NULL, NULL, NULL, kcred, 0, &cp);
1189         if (error)
1190                 goto out;
1191 
1192         /* if local file, fid is a local fid and is not valid */
1193         if (cp->c_id.cid_flags & CFS_CID_LOCAL) {
1194                 error = ENOMSG;
1195                 goto out;
1196         }
1197 
1198         /* copy out the fid */
1199         CACHEFS_FID_COPY(&cp->c_cookie, fidp);
1200 
1201 out:
1202         if (cp)
1203                 VN_RELE(CTOV(cp));
1204         return  (error);
1205 }
1206 
1207 /*
1208  * This performs a getattr on the back file system given
1209  * a fid that is passed in.
1210  *
1211  * The backfid is in gafid->cg_backfid, the creds to use for
1212  * this operation are in gafid->cg_cred.  The attributes are
1213  * returned in gafid->cg_attr
1214  *
1215  * the error returned is 0 if successful, nozero if not
1216  */
1217 int
1218 cachefs_io_getattrfid(vnode_t *vp, void *dinp, void *doutp)
1219 {
1220         vnode_t *backvp = NULL;
1221         fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
1222         int error = 0;
1223         cred_t  *cr;
1224         cachefsio_getattrfid_t *gafid;
1225         fid_t   *tmpfidp;
1226         vattr_t *tmpvap;
1227         cfs_vattr_t *attrp;
1228         CACHEFS_DECL(fid_t, tmpfid);
1229         CACHEFS_DECL(vattr_t, va);
1230 
1231         /*
1232          * Only called in support of disconnectable operation, so assert
1233          * that this is not called when NFSv4 is the backfilesytem.
1234          */
1235         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1236 
1237         gafid = (cachefsio_getattrfid_t *)dinp;
1238         attrp = (cfs_vattr_t *)doutp;
1239 
1240         /* Get a vnode for the back file */
1241         CACHEFS_TMPPTR_SET(&gafid->cg_backfid, &tmpfid, tmpfidp, fid_t);
1242         CACHEFS_FID_COPYIN(&gafid->cg_backfid, tmpfidp);
1243         error = VFS_VGET(fscp->fs_backvfsp, &backvp, tmpfidp);
1244         if (error)
1245                 return (error);
1246 
1247         cr = conj_cred(&gafid->cg_cred);
1248         CACHEFS_TMPPTR_SET(attrp, &va, tmpvap, vattr_t);
1249         tmpvap->va_mask = AT_ALL;
1250         error = VOP_GETATTR(backvp, tmpvap, 0, cr, NULL);
1251         CACHEFS_VATTR_COPYOUT(tmpvap, attrp, error);
1252         crfree(cr);
1253 
1254         /* VFS_VGET performs a VN_HOLD on the vp */
1255         VN_RELE(backvp);
1256 
1257         return (error);
1258 }
1259 
1260 
1261 /*
1262  * This performs a getattr on the back file system.  Instead of
1263  * passing the fid to perform the gettr on we are given the
1264  * parent directory fid and a name.
1265  */
1266 int
1267 cachefs_io_getattrname(vnode_t *vp, void *dinp, void *doutp)
1268 {
1269         vnode_t *pbackvp = NULL;
1270         vnode_t *cbackvp = NULL;
1271         fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
1272         int error = 0;
1273         cred_t  *cr;
1274         fid_t   *tmpfidp;
1275         vattr_t *tmpvap;
1276         cachefsio_getattrname_arg_t *gap;
1277         cachefsio_getattrname_return_t *retp;
1278         CACHEFS_DECL(fid_t, tmpfid);
1279         CACHEFS_DECL(vattr_t, va);
1280 
1281         /*
1282          * Only called in support of disconnectable operation, so assert
1283          * that this is not called when NFSv4 is the backfilesytem.
1284          */
1285         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1286 
1287         gap = (cachefsio_getattrname_arg_t *)dinp;
1288         retp = (cachefsio_getattrname_return_t *)doutp;
1289 
1290         /* Get a vnode for the parent directory */
1291         CACHEFS_TMPPTR_SET(&gap->cg_dir, &tmpfid, tmpfidp, fid_t);
1292         CACHEFS_FID_COPYIN(&gap->cg_dir, tmpfidp);
1293         error = VFS_VGET(fscp->fs_backvfsp, &pbackvp, tmpfidp);
1294         if (error)
1295                 return (error);
1296 
1297         /* lookup the file name */
1298         cr = conj_cred(&gap->cg_cred);
1299         error = VOP_LOOKUP(pbackvp, gap->cg_name, &cbackvp,
1300             (struct pathname *)NULL, 0, (vnode_t *)NULL, cr, NULL, NULL, NULL);
1301         if (error) {
1302                 crfree(cr);
1303                 VN_RELE(pbackvp);
1304                 return (error);
1305         }
1306 
1307         CACHEFS_TMPPTR_SET(&retp->cg_attr, &va, tmpvap, vattr_t);
1308         tmpvap->va_mask = AT_ALL;
1309         error = VOP_GETATTR(cbackvp, tmpvap, 0, cr, NULL);
1310         CACHEFS_VATTR_COPYOUT(tmpvap, &retp->cg_attr, error);
1311         if (!error) {
1312                 CACHEFS_TMPPTR_SET(&retp->cg_fid, &tmpfid, tmpfidp, fid_t);
1313                 tmpfidp->fid_len = MAXFIDSZ;
1314                 error = VOP_FID(cbackvp, tmpfidp, NULL);
1315                 CACHEFS_FID_COPYOUT(tmpfidp, &retp->cg_fid);
1316         }
1317 
1318         crfree(cr);
1319         VN_RELE(cbackvp);
1320         VN_RELE(pbackvp);
1321         return (error);
1322 }
1323 
1324 /*
1325  * This will return the fid of the root of this mount point.
1326  */
1327 int
1328 /*ARGSUSED*/
1329 cachefs_io_rootfid(vnode_t *vp, void *dinp, void *doutp)
1330 {
1331         fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
1332         cfs_fid_t *rootfid = (cfs_fid_t *)doutp;
1333 
1334         /*
1335          * Only called in support of disconnectable operation, so assert
1336          * that this is not called when NFSv4 is the backfilesytem.
1337          */
1338         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1339 
1340         CACHEFS_FID_COPY(&VTOC(fscp->fs_rootvp)->c_metadata.md_cookie, rootfid);
1341         return (0);
1342 }
1343 
1344 /*
1345  * Pushes the data associated with a file back to the file server.
1346  */
1347 int
1348 cachefs_io_pushback(vnode_t *vp, void *dinp, void *doutp)
1349 {
1350         vnode_t *backvp = NULL;
1351         fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
1352         caddr_t buffer = NULL;
1353         int error = 0;
1354         cnode_t *cp;
1355         size_t amt;
1356         u_offset_t size;
1357         vattr_t va;
1358         offset_t off;
1359         cred_t *cr = NULL;
1360         fid_t   *tmpfidp;
1361         cachefsio_pushback_arg_t *pbp;
1362         cachefsio_pushback_return_t *retp;
1363         CACHEFS_DECL(fid_t, tmpfid);
1364 
1365         /*
1366          * Only called in support of disconnectable operation, so assert
1367          * that this is not called when NFSv4 is the backfilesytem.
1368          */
1369         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1370 
1371         pbp = (cachefsio_pushback_arg_t *)dinp;
1372         retp = (cachefsio_pushback_return_t *)doutp;
1373 
1374         cr = conj_cred(&pbp->pb_cred);
1375 
1376         /* get the backvp to push to */
1377         CACHEFS_TMPPTR_SET(&pbp->pb_fid, &tmpfid, tmpfidp, fid_t);
1378         CACHEFS_FID_COPYIN(&pbp->pb_fid, tmpfidp);
1379         error = VFS_VGET(fscp->fs_backvfsp, &backvp, tmpfidp);
1380         if (error) {
1381                 backvp = NULL;
1382                 goto out;
1383         }
1384 
1385         /* Get the cnode for the file we are to push back */
1386         error = cachefs_cnode_make(&pbp->pb_cid, fscp,
1387             NULL, NULL, NULL, cr, 0, &cp);
1388         if (error) {
1389                 goto out;
1390         }
1391 
1392         /* must be a regular file */
1393         if (cp->c_attr.va_type != VREG) {
1394                 error = EINVAL;
1395                 goto out;
1396         }
1397 
1398         mutex_enter(&cp->c_statelock);
1399 
1400         /* get the front file */
1401         if (cp->c_frontvp == NULL) {
1402                 error = cachefs_getfrontfile(cp);
1403                 if (error) {
1404                         mutex_exit(&cp->c_statelock);
1405                         goto out;
1406                 }
1407         }
1408 
1409         /* better be populated */
1410         if ((cp->c_metadata.md_flags & MD_POPULATED) == 0) {
1411                 mutex_exit(&cp->c_statelock);
1412                 error = EINVAL;
1413                 goto out;
1414         }
1415 
1416         /* do open so NFS gets correct creds on writes */
1417         error = VOP_OPEN(&backvp, FWRITE, cr, NULL);
1418         if (error) {
1419                 mutex_exit(&cp->c_statelock);
1420                 goto out;
1421         }
1422 
1423         buffer = cachefs_kmem_alloc(MAXBSIZE, KM_SLEEP);
1424 
1425         /* Read the data from the cache and write it to the server */
1426         /* XXX why not use segmapio? */
1427         off = 0;
1428         for (size = cp->c_size; size != 0; size -= amt) {
1429                 if (size > MAXBSIZE)
1430                         amt = MAXBSIZE;
1431                 else
1432                         amt = size;
1433 
1434                 /* read a block of data from the front file */
1435                 error = vn_rdwr(UIO_READ, cp->c_frontvp, buffer,
1436                         amt, off, UIO_SYSSPACE, 0, RLIM_INFINITY, cr, 0);
1437                 if (error) {
1438                         mutex_exit(&cp->c_statelock);
1439                         goto out;
1440                 }
1441 
1442                 /* write the block of data to the back file */
1443                 error = vn_rdwr(UIO_WRITE, backvp, buffer, amt, off,
1444                         UIO_SYSSPACE, 0, RLIM_INFINITY, cr, 0);
1445                 if (error) {
1446                         mutex_exit(&cp->c_statelock);
1447                         goto out;
1448                 }
1449                 off += amt;
1450         }
1451 
1452         error = VOP_FSYNC(backvp, FSYNC, cr, NULL);
1453         if (error == 0)
1454                 error = VOP_CLOSE(backvp, FWRITE, 1, (offset_t)0, cr, NULL);
1455         if (error) {
1456                 mutex_exit(&cp->c_statelock);
1457                 goto out;
1458         }
1459 
1460         cp->c_metadata.md_flags |= MD_PUSHDONE;
1461         cp->c_metadata.md_flags &= ~MD_PUTPAGE;
1462         cp->c_metadata.md_flags |= MD_NEEDATTRS;
1463         cp->c_flags |= CN_UPDATED;
1464         mutex_exit(&cp->c_statelock);
1465 
1466         /*
1467          * if we have successfully stored the data, we need the
1468          * new ctime and mtimes.
1469          */
1470         va.va_mask = AT_ALL;
1471         error = VOP_GETATTR(backvp, &va, 0, cr, NULL);
1472         if (error)
1473                 goto out;
1474         CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->pb_ctime, error);
1475         CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->pb_mtime, error);
1476 
1477 out:
1478         if (buffer)
1479                 cachefs_kmem_free(buffer, MAXBSIZE);
1480         if (cp)
1481                 VN_RELE(CTOV(cp));
1482         if (backvp)
1483                 VN_RELE(backvp);
1484         if (cr)
1485                 crfree(cr);
1486         return (error);
1487 }
1488 
1489 /*
1490  * Create a file on the back file system.
1491  */
1492 int
1493 cachefs_io_create(vnode_t *vp, void *dinp, void *doutp)
1494 {
1495         vnode_t *dvp = NULL;
1496         vnode_t *cvp = NULL;
1497         cnode_t *cp = NULL;
1498         fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
1499         vattr_t va, *tmpvap;
1500         int error = 0;
1501         cred_t *cr = NULL;
1502         fid_t   *tmpfidp;
1503         cachefsio_create_arg_t *crp;
1504         cachefsio_create_return_t *retp;
1505         CACHEFS_DECL(fid_t, tmpfid);
1506 
1507         /*
1508          * Only called in support of disconnectable operation, so assert
1509          * that this is not called when NFSv4 is the backfilesytem.
1510          */
1511         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1512 
1513         crp = (cachefsio_create_arg_t *)dinp;
1514         retp = (cachefsio_create_return_t *)doutp;
1515 
1516         /* get a vnode for the parent directory  */
1517         CACHEFS_TMPPTR_SET(&crp->cr_backfid, &tmpfid, tmpfidp, fid_t);
1518         CACHEFS_FID_COPYIN(&crp->cr_backfid, tmpfidp);
1519         error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
1520         if (error)
1521                 goto out;
1522 
1523         cr = conj_cred(&crp->cr_cred);
1524 
1525         /* do the create */
1526         CACHEFS_TMPPTR_SET(&crp->cr_va, &va, tmpvap, vattr_t);
1527         CACHEFS_VATTR_COPYIN(&crp->cr_va, tmpvap);
1528         error = VOP_CREATE(dvp, crp->cr_name, tmpvap,
1529             crp->cr_exclusive, crp->cr_mode, &cvp, cr, 0, NULL, NULL);
1530         if (error)
1531                 goto out;
1532 
1533         /* get the fid of the file */
1534         CACHEFS_TMPPTR_SET(&retp->cr_newfid, &tmpfid, tmpfidp, fid_t);
1535         tmpfidp->fid_len = MAXFIDSZ;
1536         error = VOP_FID(cvp, tmpfidp, NULL);
1537         if (error)
1538                 goto out;
1539         CACHEFS_FID_COPYOUT(tmpfidp, &retp->cr_newfid);
1540 
1541         /* get attributes for the file */
1542         va.va_mask = AT_ALL;
1543         error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
1544         if (error)
1545                 goto out;
1546         CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->cr_ctime, error);
1547         CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->cr_mtime, error);
1548         if (error)
1549                 goto out;
1550 
1551         /* update the cnode for this file with the new info */
1552         error = cachefs_cnode_make(&crp->cr_cid, fscp,
1553             NULL, NULL, NULL, cr, 0, &cp);
1554         if (error) {
1555                 error = 0;
1556                 goto out;
1557         }
1558 
1559         mutex_enter(&cp->c_statelock);
1560         ASSERT(cp->c_id.cid_flags & CFS_CID_LOCAL);
1561         cp->c_attr.va_nodeid = va.va_nodeid;
1562         cp->c_metadata.md_flags |= MD_CREATEDONE;
1563         cp->c_metadata.md_flags |= MD_NEEDATTRS;
1564         cp->c_metadata.md_cookie = *tmpfidp;
1565         cp->c_flags |= CN_UPDATED;
1566         mutex_exit(&cp->c_statelock);
1567 
1568 out:
1569         if (cr)
1570                 crfree(cr);
1571         if (dvp)
1572                 VN_RELE(dvp);
1573         if (cvp)
1574                 VN_RELE(cvp);
1575         if (cp)
1576                 VN_RELE(CTOV(cp));
1577         return (error);
1578 }
1579 
1580 /*
1581  * Remove a file on the back file system.
1582  * Returns 0 or an error if could not perform operation.
1583  */
1584 int
1585 cachefs_io_remove(vnode_t *vp, void *dinp, void *doutp)
1586 {
1587         vnode_t *dvp = NULL;
1588         vnode_t *cvp;
1589         cred_t *cr = NULL;
1590         vattr_t va;
1591         fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
1592         int error;
1593         fid_t child_fid, *child_fidp;
1594         cachefsio_remove_t *rmp = (cachefsio_remove_t *)dinp;
1595         cfs_timestruc_t *ctimep = (cfs_timestruc_t *)doutp;
1596 
1597         /*
1598          * Only called in support of disconnectable operation, so assert
1599          * that this is not called when NFSv4 is the backfilesytem.
1600          */
1601         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1602 
1603         /* Get a vnode for the directory */
1604         CACHEFS_TMPPTR_SET(&rmp->rm_fid, &child_fid, child_fidp, fid_t);
1605         CACHEFS_FID_COPYIN(&rmp->rm_fid, child_fidp);
1606         error = VFS_VGET(fscp->fs_backvfsp, &dvp, child_fidp);
1607         if (error) {
1608                 dvp = NULL;
1609                 goto out;
1610         }
1611 
1612         cr = conj_cred(&rmp->rm_cred);
1613 
1614         /* if the caller wants the ctime after the remove */
1615         if (ctimep) {
1616                 error = VOP_LOOKUP(dvp, rmp->rm_name, &cvp, NULL, 0, NULL, cr,
1617                         NULL, NULL, NULL);
1618                 if (error == 0) {
1619                         child_fid.fid_len = MAXFIDSZ;
1620                         error = VOP_FID(cvp, &child_fid, NULL);
1621                         VN_RELE(cvp);
1622                 }
1623                 if (error)
1624                         goto out;
1625         }
1626 
1627         /* do the remove */
1628         error = VOP_REMOVE(dvp, rmp->rm_name, cr, NULL, 0);
1629         if (error)
1630                 goto out;
1631 
1632         /* get the new ctime if requested */
1633         if (ctimep) {
1634                 error = VFS_VGET(fscp->fs_backvfsp, &cvp, &child_fid);
1635                 if (error == 0) {
1636                         va.va_mask = AT_ALL;
1637                         error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
1638                         if (error == 0) {
1639                                 CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime,
1640                                         ctimep, error);
1641                         }
1642                         VN_RELE(cvp);
1643                 }
1644                 cachefs_iosetneedattrs(fscp, &rmp->rm_cid);
1645         }
1646 
1647 out:
1648         if (cr)
1649                 crfree(cr);
1650         if (dvp)
1651                 VN_RELE(dvp);
1652         return (error);
1653 }
1654 
1655 /*
1656  * Perform a link on the back file system.
1657  * Returns 0 or an error if could not perform operation.
1658  */
1659 int
1660 cachefs_io_link(vnode_t *vp, void *dinp, void *doutp)
1661 {
1662         vnode_t *dvp = NULL;
1663         vnode_t *lvp = NULL;
1664         vattr_t va;
1665         fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
1666         int error = 0;
1667         cred_t *cr = NULL;
1668         fid_t *tmpfidp;
1669         cachefsio_link_t *linkp = (cachefsio_link_t *)dinp;
1670         cfs_timestruc_t *ctimep = (cfs_timestruc_t *)doutp;
1671         CACHEFS_DECL(fid_t, tmpfid);
1672 
1673         /*
1674          * Only called in support of disconnectable operation, so assert
1675          * that this is not called when NFSv4 is the backfilesytem.
1676          */
1677         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1678 
1679         /* Get a vnode parent directory */
1680         CACHEFS_TMPPTR_SET(&linkp->ln_dirfid, &tmpfid, tmpfidp, fid_t);
1681         CACHEFS_FID_COPYIN(&linkp->ln_dirfid, tmpfidp);
1682         error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
1683         if (error) {
1684                 dvp = NULL;
1685                 goto out;
1686         }
1687 
1688         /* Get a vnode file to link to */
1689         CACHEFS_TMPPTR_SET(&linkp->ln_filefid, &tmpfid, tmpfidp, fid_t);
1690         CACHEFS_FID_COPYIN(&linkp->ln_filefid, tmpfidp);
1691         error = VFS_VGET(fscp->fs_backvfsp, &lvp, tmpfidp);
1692         if (error) {
1693                 lvp = NULL;
1694                 goto out;
1695         }
1696 
1697         cr = conj_cred(&linkp->ln_cred);
1698 
1699         /* do the link */
1700         error = VOP_LINK(dvp, lvp, linkp->ln_name, cr, NULL, 0);
1701         if (error)
1702                 goto out;
1703 
1704         /* get the ctime */
1705         va.va_mask = AT_ALL;
1706         error = VOP_GETATTR(lvp, &va, 0, cr, NULL);
1707         if (error)
1708                 goto out;
1709         CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, ctimep, error);
1710         if (error)
1711                 goto out;
1712 
1713         cachefs_iosetneedattrs(fscp, &linkp->ln_cid);
1714 out:
1715         if (cr)
1716                 crfree(cr);
1717         if (dvp)
1718                 VN_RELE(dvp);
1719         if (lvp)
1720                 VN_RELE(lvp);
1721         return (error);
1722 }
1723 
1724 /*
1725  * Rename the file on the back file system.
1726  * Returns 0 or an error if could not perform operation.
1727  */
1728 int
1729 cachefs_io_rename(vnode_t *vp, void *dinp, void *doutp)
1730 {
1731         vnode_t *odvp = NULL;
1732         vnode_t *ndvp = NULL;
1733         cred_t *cr = NULL;
1734         vnode_t *cvp = NULL;
1735         vattr_t va;
1736         fscache_t  *fscp = C_TO_FSCACHE(VTOC(vp));
1737         int error = 0;
1738         fid_t child_fid, *child_fidp;
1739         cachefsio_rename_arg_t *rnp;
1740         cachefsio_rename_return_t *retp;
1741 
1742         /*
1743          * Only called in support of disconnectable operation, so assert
1744          * that this is not called when NFSv4 is the backfilesytem.
1745          */
1746         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1747 
1748         rnp = (cachefsio_rename_arg_t *)dinp;
1749         retp = (cachefsio_rename_return_t *)doutp;
1750 
1751         /* Get vnode of old parent directory */
1752         CACHEFS_TMPPTR_SET(&rnp->rn_olddir, &child_fid, child_fidp, fid_t);
1753         CACHEFS_FID_COPYIN(&rnp->rn_olddir, child_fidp);
1754         error = VFS_VGET(fscp->fs_backvfsp, &odvp, child_fidp);
1755         if (error) {
1756                 odvp = NULL;
1757                 goto out;
1758         }
1759 
1760         /* Get vnode of new parent directory */
1761         CACHEFS_TMPPTR_SET(&rnp->rn_newdir, &child_fid, child_fidp, fid_t);
1762         CACHEFS_FID_COPYIN(&rnp->rn_newdir, child_fidp);
1763         error = VFS_VGET(fscp->fs_backvfsp, &ndvp, child_fidp);
1764         if (error) {
1765                 ndvp = NULL;
1766                 goto out;
1767         }
1768 
1769         cr = conj_cred(&rnp->rn_cred);
1770 
1771         /* if the caller wants the ctime of the target after deletion */
1772         if (rnp->rn_del_getctime) {
1773                 error = VOP_LOOKUP(ndvp, rnp->rn_newname, &cvp, NULL, 0,
1774                     NULL, cr, NULL, NULL, NULL);
1775                 if (error) {
1776                         cvp = NULL; /* paranoia */
1777                         goto out;
1778                 }
1779 
1780                 child_fid.fid_len = MAXFIDSZ;
1781                 error = VOP_FID(cvp, &child_fid, NULL);
1782                 if (error)
1783                         goto out;
1784                 VN_RELE(cvp);
1785                 cvp = NULL;
1786         }
1787 
1788         /* do the rename */
1789         error = VOP_RENAME(odvp, rnp->rn_oldname, ndvp, rnp->rn_newname, cr,
1790                 NULL, 0);
1791         if (error)
1792                 goto out;
1793 
1794         /* get the new ctime on the renamed file */
1795         error = VOP_LOOKUP(ndvp, rnp->rn_newname, &cvp, NULL, 0, NULL, cr,
1796                 NULL, NULL, NULL);
1797         if (error)
1798                 goto out;
1799 
1800         va.va_mask = AT_ALL;
1801         error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
1802         if (error)
1803                 goto out;
1804         CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->rn_ctime, error);
1805         VN_RELE(cvp);
1806         cvp = NULL;
1807         if (error)
1808                 goto out;
1809 
1810         cachefs_iosetneedattrs(fscp, &rnp->rn_cid);
1811 
1812         /* get the new ctime if requested of the deleted target */
1813         if (rnp->rn_del_getctime) {
1814                 error = VFS_VGET(fscp->fs_backvfsp, &cvp, &child_fid);
1815                 if (error) {
1816                         cvp = NULL;
1817                         goto out;
1818                 }
1819                 va.va_mask = AT_ALL;
1820                 error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
1821                 if (error)
1822                         goto out;
1823                 CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->rn_del_ctime,
1824                         error);
1825                 VN_RELE(cvp);
1826                 cvp = NULL;
1827                 if (error)
1828                         goto out;
1829                 cachefs_iosetneedattrs(fscp, &rnp->rn_del_cid);
1830         }
1831 
1832 out:
1833         if (cr)
1834                 crfree(cr);
1835         if (cvp)
1836                 VN_RELE(cvp);
1837         if (odvp)
1838                 VN_RELE(odvp);
1839         if (ndvp)
1840                 VN_RELE(ndvp);
1841         return (error);
1842 }
1843 
1844 /*
1845  * Make a directory on the backfs.
1846  * Returns 0 or an error if could not perform operation.
1847  */
1848 int
1849 cachefs_io_mkdir(vnode_t *vp, void *dinp, void *doutp)
1850 {
1851         vnode_t *dvp = NULL;
1852         vnode_t *cvp = NULL;
1853         cnode_t *cp = NULL;
1854         fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
1855         int error = 0;
1856         cred_t *cr = NULL;
1857         fid_t   *tmpfidp;
1858         vattr_t va, *tmpvap;
1859         cachefsio_mkdir_t *mdirp = (cachefsio_mkdir_t *)dinp;
1860         cfs_fid_t *fidp = (cfs_fid_t *)doutp;
1861         CACHEFS_DECL(fid_t, tmpfid);
1862 
1863         /*
1864          * Only called in support of disconnectable operation, so assert
1865          * that this is not called when NFSv4 is the backfilesytem.
1866          */
1867         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1868 
1869         /* Get vnode of parent directory */
1870         CACHEFS_TMPPTR_SET(&mdirp->md_dirfid, &tmpfid, tmpfidp, fid_t);
1871         CACHEFS_FID_COPYIN(&mdirp->md_dirfid, tmpfidp);
1872         error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
1873         if (error) {
1874                 dvp = NULL;
1875                 goto out;
1876         }
1877 
1878         cr = conj_cred(&mdirp->md_cred);
1879 
1880         /* make the directory */
1881         CACHEFS_TMPPTR_SET(&mdirp->md_vattr, &va, tmpvap, vattr_t);
1882         CACHEFS_VATTR_COPYIN(&mdirp->md_vattr, tmpvap);
1883         error = VOP_MKDIR(dvp, mdirp->md_name, tmpvap, &cvp, cr, NULL, 0, NULL);
1884         if (error) {
1885                 if (error != EEXIST)
1886                         goto out;
1887 
1888                 /* if the directory already exists, then use it */
1889                 error = VOP_LOOKUP(dvp, mdirp->md_name, &cvp,
1890                     NULL, 0, NULL, cr, NULL, NULL, NULL);
1891                 if (error) {
1892                         cvp = NULL;
1893                         goto out;
1894                 }
1895                 if (cvp->v_type != VDIR) {
1896                         error = EINVAL;
1897                         goto out;
1898                 }
1899         }
1900 
1901         /* get the fid of the directory */
1902         CACHEFS_TMPPTR_SET(fidp, &tmpfid, tmpfidp, fid_t);
1903         tmpfidp->fid_len = MAXFIDSZ;
1904         error = VOP_FID(cvp, tmpfidp, NULL);
1905         if (error)
1906                 goto out;
1907         CACHEFS_FID_COPYOUT(tmpfidp, fidp);
1908 
1909         /* get attributes of the directory */
1910         va.va_mask = AT_ALL;
1911         error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
1912         if (error)
1913                 goto out;
1914 
1915         /* update the cnode for this dir with the new fid */
1916         error = cachefs_cnode_make(&mdirp->md_cid, fscp,
1917             NULL, NULL, NULL, cr, 0, &cp);
1918         if (error) {
1919                 error = 0;
1920                 goto out;
1921         }
1922         mutex_enter(&cp->c_statelock);
1923         ASSERT(cp->c_id.cid_flags & CFS_CID_LOCAL);
1924         cp->c_metadata.md_cookie = *tmpfidp;
1925         cp->c_metadata.md_flags |= MD_CREATEDONE;
1926         cp->c_metadata.md_flags |= MD_NEEDATTRS;
1927         cp->c_attr.va_nodeid = va.va_nodeid;
1928         cp->c_flags |= CN_UPDATED;
1929         mutex_exit(&cp->c_statelock);
1930 out:
1931         if (cr)
1932                 crfree(cr);
1933         if (dvp)
1934                 VN_RELE(dvp);
1935         if (cvp)
1936                 VN_RELE(cvp);
1937         if (cp)
1938                 VN_RELE(CTOV(cp));
1939         return (error);
1940 }
1941 
1942 /*
1943  * Perform a rmdir on the back file system.
1944  * Returns 0 or an error if could not perform operation.
1945  */
1946 int
1947 /*ARGSUSED*/
1948 cachefs_io_rmdir(vnode_t *vp, void *dinp, void *doutp)
1949 {
1950         vnode_t *dvp = NULL;
1951         fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
1952         int error;
1953         cred_t *cr;
1954         fid_t   *tmpfidp;
1955         cachefsio_rmdir_t *rdp = (cachefsio_rmdir_t *)dinp;
1956         CACHEFS_DECL(fid_t, tmpfid);
1957 
1958         /*
1959          * Only called in support of disconnectable operation, so assert
1960          * that this is not called when NFSv4 is the backfilesytem.
1961          */
1962         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1963 
1964         /* Get a vnode for the back file */
1965         CACHEFS_TMPPTR_SET(&rdp->rd_dirfid, &tmpfid, tmpfidp, fid_t);
1966         CACHEFS_FID_COPYIN(&rdp->rd_dirfid, tmpfidp);
1967         error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
1968         if (error) {
1969                 dvp = NULL;
1970                 return (error);
1971         }
1972 
1973         cr = conj_cred(&rdp->rd_cred);
1974         error = VOP_RMDIR(dvp, rdp->rd_name, dvp, cr, NULL, 0);
1975         crfree(cr);
1976 
1977         VN_RELE(dvp);
1978         return (error);
1979 }
1980 
1981 /*
1982  * create a symlink on the back file system
1983  * Returns 0 or an error if could not perform operation.
1984  */
1985 int
1986 cachefs_io_symlink(vnode_t *vp, void *dinp, void *doutp)
1987 {
1988         vnode_t *dvp = NULL;
1989         vnode_t *svp = NULL;
1990         cnode_t *cp = NULL;
1991         fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
1992         fid_t   *tmpfidp;
1993         vattr_t va, *tmpvap;
1994         int error = 0;
1995         cred_t *cr = NULL;
1996         cachefsio_symlink_arg_t *symp;
1997         cachefsio_symlink_return_t *retp;
1998         CACHEFS_DECL(fid_t, tmpfid);
1999 
2000         /*
2001          * Only called in support of disconnectable operation, so assert
2002          * that this is not called when NFSv4 is the backfilesytem.
2003          */
2004         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
2005 
2006         symp = (cachefsio_symlink_arg_t *)dinp;
2007         retp = (cachefsio_symlink_return_t *)doutp;
2008 
2009         /* get a vnode for the back directory */
2010         CACHEFS_TMPPTR_SET(&symp->sy_dirfid, &tmpfid, tmpfidp, fid_t);
2011         CACHEFS_FID_COPYIN(&symp->sy_dirfid, tmpfidp);
2012         error = VFS_VGET(fscp->fs_backvfsp, &dvp, tmpfidp);
2013         if (error) {
2014                 dvp = NULL;
2015                 goto out;
2016         }
2017 
2018         cr = conj_cred(&symp->sy_cred);
2019 
2020         /* create the symlink */
2021         CACHEFS_TMPPTR_SET(&symp->sy_vattr, &va, tmpvap, vattr_t);
2022         CACHEFS_VATTR_COPYIN(&symp->sy_vattr, tmpvap);
2023         error = VOP_SYMLINK(dvp, symp->sy_name, tmpvap,
2024             symp->sy_link, cr, NULL, 0);
2025         if (error)
2026                 goto out;
2027 
2028         /* get the vnode for the symlink */
2029         error = VOP_LOOKUP(dvp, symp->sy_name, &svp, NULL, 0, NULL, cr,
2030                 NULL, NULL, NULL);
2031         if (error)
2032                 goto out;
2033 
2034         /* get the attributes of the symlink */
2035         va.va_mask = AT_ALL;
2036         error = VOP_GETATTR(svp, &va, 0, cr, NULL);
2037         if (error)
2038                 goto out;
2039         CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sy_ctime, error);
2040         CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->sy_mtime, error);
2041         if (error)
2042                 goto out;
2043 
2044         /* get the fid */
2045         CACHEFS_TMPPTR_SET(&retp->sy_newfid, &tmpfid, tmpfidp, fid_t);
2046         tmpfidp->fid_len = MAXFIDSZ;
2047         error = VOP_FID(svp, tmpfidp, NULL);
2048         if (error)
2049                 goto out;
2050         CACHEFS_FID_COPYOUT(tmpfidp, &retp->sy_newfid);
2051 
2052         /* update the cnode for this file with the new info */
2053         error = cachefs_cnode_make(&symp->sy_cid, fscp,
2054             NULL, NULL, NULL, cr, 0, &cp);
2055         if (error) {
2056                 error = 0;
2057                 goto out;
2058         }
2059         mutex_enter(&cp->c_statelock);
2060         ASSERT(cp->c_id.cid_flags & CFS_CID_LOCAL);
2061         cp->c_metadata.md_cookie = *tmpfidp;
2062         cp->c_metadata.md_flags |= MD_CREATEDONE;
2063         cp->c_metadata.md_flags |= MD_NEEDATTRS;
2064         cp->c_attr.va_nodeid = va.va_nodeid;
2065         cp->c_flags |= CN_UPDATED;
2066         mutex_exit(&cp->c_statelock);
2067 
2068 out:
2069         if (cr)
2070                 crfree(cr);
2071         if (dvp)
2072                 VN_RELE(dvp);
2073         if (svp)
2074                 VN_RELE(svp);
2075         if (cp)
2076                 VN_RELE(CTOV(cp));
2077         return (error);
2078 }
2079 
2080 /*
2081  * Perform setattr on the back file system.
2082  * Returns 0 or an error if could not perform operation.
2083  */
2084 int
2085 cachefs_io_setattr(vnode_t *vp, void *dinp, void *doutp)
2086 {
2087         vnode_t *cvp = NULL;
2088         fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
2089         fid_t   *tmpfidp;
2090         vattr_t va, *tmpvap;
2091         int error = 0;
2092         cred_t *cr = NULL;
2093         cachefsio_setattr_arg_t *sap;
2094         cachefsio_setattr_return_t *retp;
2095         CACHEFS_DECL(fid_t, tmpfid);
2096 
2097         /*
2098          * Only called in support of disconnectable operation, so assert
2099          * that this is not called when NFSv4 is the backfilesytem.
2100          */
2101         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
2102 
2103         sap = (cachefsio_setattr_arg_t *)dinp;
2104         retp = (cachefsio_setattr_return_t *)doutp;
2105 
2106         /* get a vnode for the back directory */
2107         CACHEFS_TMPPTR_SET(&sap->sa_backfid, &tmpfid, tmpfidp, fid_t);
2108         CACHEFS_FID_COPYIN(&sap->sa_backfid, tmpfidp);
2109         error = VFS_VGET(fscp->fs_backvfsp, &cvp, tmpfidp);
2110         if (error) {
2111                 cvp = NULL;
2112                 goto out;
2113         }
2114 
2115         cr = conj_cred(&sap->sa_cred);
2116 
2117         /* perform the setattr */
2118         CACHEFS_TMPPTR_SET(&sap->sa_vattr, &va, tmpvap, vattr_t);
2119         CACHEFS_VATTR_COPYIN(&sap->sa_vattr, tmpvap);
2120         error = VOP_SETATTR(cvp, tmpvap, 0, cr, NULL);
2121         if (error)
2122                 goto out;
2123 
2124         /* get the new ctime and mtime */
2125         va.va_mask = AT_ALL;
2126         error = VOP_GETATTR(cvp, &va, 0, cr, NULL);
2127         if (error)
2128                 goto out;
2129         CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sa_ctime, error);
2130         CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->sa_mtime, error);
2131         if (error)
2132                 goto out;
2133 
2134         cachefs_iosetneedattrs(fscp, &sap->sa_cid);
2135 out:
2136         if (cr)
2137                 crfree(cr);
2138         if (cvp)
2139                 VN_RELE(cvp);
2140         return (error);
2141 }
2142 
2143 int
2144 cachefs_io_setsecattr(vnode_t *vp, void *dinp, void *doutp)
2145 {
2146         int error = 0;
2147         fscache_t *fscp = C_TO_FSCACHE(VTOC(vp));
2148         vnode_t *tvp = NULL;
2149         vsecattr_t vsec;
2150         vattr_t va;
2151         cred_t *cr = NULL;
2152         fid_t   *tmpfidp;
2153         cachefsio_setsecattr_arg_t *ssap;
2154         cachefsio_setsecattr_return_t *retp;
2155         CACHEFS_DECL(fid_t, tmpfid);
2156 
2157         /*
2158          * Only called in support of disconnectable operation, so assert
2159          * that this is not called when NFSv4 is the backfilesytem.
2160          */
2161         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
2162 
2163         ssap = (cachefsio_setsecattr_arg_t *)dinp;
2164         retp = (cachefsio_setsecattr_return_t *)doutp;
2165 
2166         /* get vnode of back file to do VOP_SETSECATTR to */
2167         CACHEFS_TMPPTR_SET(&ssap->sc_backfid, &tmpfid, tmpfidp, fid_t);
2168         CACHEFS_FID_COPYIN(&ssap->sc_backfid, tmpfidp);
2169         error = VFS_VGET(fscp->fs_backvfsp, &tvp, tmpfidp);
2170         if (error != 0) {
2171                 tvp = NULL;
2172                 goto out;
2173         }
2174 
2175         /* get the creds */
2176         cr = conj_cred(&ssap->sc_cred);
2177 
2178         /* form the vsecattr_t */
2179         vsec.vsa_mask = ssap->sc_mask;
2180         vsec.vsa_aclcnt = ssap->sc_aclcnt;
2181         vsec.vsa_dfaclcnt = ssap->sc_dfaclcnt;
2182         vsec.vsa_aclentp = ssap->sc_acl;
2183         vsec.vsa_dfaclentp = ssap->sc_acl + ssap->sc_aclcnt;
2184 
2185         /* set the ACL */
2186         (void) VOP_RWLOCK(tvp, V_WRITELOCK_TRUE, NULL);
2187         error = VOP_SETSECATTR(tvp, &vsec, 0, cr, NULL);
2188         VOP_RWUNLOCK(tvp, V_WRITELOCK_TRUE, NULL);
2189         if (error != 0)
2190                 goto out;
2191 
2192         /* get the new ctime and mtime */
2193         va.va_mask = AT_ALL;
2194         error = VOP_GETATTR(tvp, &va, 0, cr, NULL);
2195         if (error)
2196                 goto out;
2197         CACHEFS_TS_TO_CFS_TS_COPY(&va.va_ctime, &retp->sc_ctime, error);
2198         CACHEFS_TS_TO_CFS_TS_COPY(&va.va_mtime, &retp->sc_mtime, error);
2199         if (error)
2200                 goto out;
2201 
2202         cachefs_iosetneedattrs(fscp, &ssap->sc_cid);
2203 out:
2204 
2205         if (cr != NULL)
2206                 crfree(cr);
2207         if (tvp != NULL)
2208                 VN_RELE(tvp);
2209 
2210         return (error);
2211 }
2212 
2213 static void
2214 sync_metadata(cnode_t *cp)
2215 {
2216         if (cp->c_flags & (CN_STALE | CN_DESTROY))
2217                 return;
2218         (void) cachefs_sync_metadata(cp);
2219 }
2220 
2221 static void
2222 drop_backvp(cnode_t *cp)
2223 {
2224         if (cp->c_backvp) {
2225                 mutex_enter(&cp->c_statelock);
2226                 if (cp->c_backvp) {
2227                         /* dump any pages, may be a dirty one */
2228                         (void) VOP_PUTPAGE(cp->c_backvp, (offset_t)0, 0,
2229                             B_INVAL | B_TRUNC, kcred, NULL);
2230                 }
2231                 mutex_exit(&cp->c_statelock);
2232         }
2233 }
2234 
2235 static void
2236 allow_pendrm(cnode_t *cp)
2237 {
2238         if (cp->c_flags & CN_PENDRM) {
2239                 mutex_enter(&cp->c_statelock);
2240                 if (cp->c_flags & CN_PENDRM) {
2241                         cp->c_flags &= ~CN_PENDRM;
2242                         VN_RELE(CTOV(cp));
2243                 }
2244                 mutex_exit(&cp->c_statelock);
2245         }
2246 }
2247 
2248 static void
2249 cachefs_modified_fix(fscache_t *fscp)
2250 {
2251         cnode_t *cp;
2252         int error = 0;
2253         rl_entry_t rl_ent;
2254         cfs_cid_t cid;
2255         cachefscache_t *cachep = fscp->fs_cache;
2256         enum cachefs_rl_type type;
2257         cachefs_metadata_t *mdp;
2258         int timedout = 0;
2259         struct vattr va;
2260 
2261         /* XXX just return if fs is in error ro mode */
2262 
2263         /* lock out other users of the MF list */
2264         mutex_enter(&cachep->c_mflock);
2265 
2266         /* move the modified entries for this file system to the MF list */
2267         cachefs_move_modified_to_mf(cachep, fscp);
2268 
2269         rl_ent.rl_current = CACHEFS_RL_MF;
2270         for (;;) {
2271                 /* get the next entry on the MF list */
2272                 error = cachefs_rlent_data(cachep, &rl_ent, NULL);
2273                 if (error) {
2274                         error = 0;
2275                         break;
2276                 }
2277                 ASSERT(fscp->fs_cfsid == rl_ent.rl_fsid);
2278 
2279                 /* get the cnode for the file */
2280                 cid.cid_fileno = rl_ent.rl_fileno;
2281                 cid.cid_flags = rl_ent.rl_local ? CFS_CID_LOCAL : 0;
2282                 error = cachefs_cnode_make(&cid, fscp,
2283                     NULL, NULL, NULL, kcred, 0, &cp);
2284                 if (error) {
2285 #ifdef CFSDEBUG
2286                         CFS_DEBUG(CFSDEBUG_IOCTL)
2287                                 printf("cachefs: mf: could not find %llu\n",
2288                                     (u_longlong_t)cid.cid_fileno);
2289                         delay(5*hz);
2290 #endif
2291                         /* XXX this will loop forever, maybe put fs in */
2292                         /*   ro mode */
2293                         continue;
2294                 }
2295 
2296                 mutex_enter(&cp->c_statelock);
2297 
2298                 mdp = &cp->c_metadata;
2299 
2300                 /* if a regular file that has not been pushed */
2301                 if ((cp->c_attr.va_type == VREG) &&
2302                     (((mdp->md_flags & (MD_PUSHDONE | MD_PUTPAGE)) ==
2303                     MD_PUTPAGE))) {
2304                         /* move the file to lost+found */
2305                         error = cachefs_cnode_lostfound(cp, NULL);
2306                         if (error) {
2307                                 /* XXX put fs in ro mode */
2308                                 /* XXX need to drain MF list */
2309                                 panic("lostfound failed %d", error);
2310                         }
2311                         mutex_exit(&cp->c_statelock);
2312                         VN_RELE(CTOV(cp));
2313                         continue;
2314                 }
2315 
2316                 /* if a local file */
2317                 if (cp->c_id.cid_flags & CFS_CID_LOCAL) {
2318                         /* if the file was not created */
2319                         if ((cp->c_metadata.md_flags & MD_CREATEDONE) == 0) {
2320                                 /* do not allow cnode to be used */
2321                                 cachefs_cnode_stale(cp);
2322                                 mutex_exit(&cp->c_statelock);
2323                                 VN_RELE(CTOV(cp));
2324                                 continue;
2325                         }
2326 
2327                         /* save the local fileno for later getattrs */
2328                         mdp->md_localfileno = cp->c_id.cid_fileno;
2329                         mutex_exit(&cp->c_statelock);
2330 
2331                         /* register the mapping from old to new fileno */
2332                         mutex_enter(&fscp->fs_fslock);
2333                         cachefs_inum_register(fscp, cp->c_attr.va_nodeid,
2334                             mdp->md_localfileno);
2335                         cachefs_inum_register(fscp, mdp->md_localfileno, 0);
2336                         mutex_exit(&fscp->fs_fslock);
2337 
2338                         /* move to new location in the cache */
2339                         cachefs_cnode_move(cp);
2340                         mutex_enter(&cp->c_statelock);
2341                 }
2342 
2343                 /* else if a modified file that needs to have its mode fixed */
2344                 else if ((cp->c_metadata.md_flags & MD_FILE) &&
2345                     (cp->c_attr.va_type == VREG)) {
2346 
2347                         if (cp->c_frontvp == NULL)
2348                                 (void) cachefs_getfrontfile(cp);
2349                         if (cp->c_frontvp) {
2350                                 /* mark file as no longer modified */
2351                                 va.va_mode = 0666;
2352                                 va.va_mask = AT_MODE;
2353                                 error = VOP_SETATTR(cp->c_frontvp, &va,
2354                                     0, kcred, NULL);
2355                                 if (error) {
2356                                         cmn_err(CE_WARN,
2357                                             "Cannot change ff mode.\n");
2358                                 }
2359                         }
2360                 }
2361 
2362 
2363                 /* if there is a rl entry, put it on the correct list */
2364                 if (mdp->md_rlno) {
2365                         if (mdp->md_flags & MD_PACKED) {
2366                                 if ((mdp->md_flags & MD_POPULATED) ||
2367                                     ((mdp->md_flags & MD_FILE) == 0))
2368                                         type = CACHEFS_RL_PACKED;
2369                                 else
2370                                         type = CACHEFS_RL_PACKED_PENDING;
2371                                 cachefs_rlent_moveto(fscp->fs_cache, type,
2372                                     mdp->md_rlno, mdp->md_frontblks);
2373                                 mdp->md_rltype = type;
2374                         } else if (mdp->md_flags & MD_FILE) {
2375                                 type = CACHEFS_RL_ACTIVE;
2376                                 cachefs_rlent_moveto(fscp->fs_cache, type,
2377                                     mdp->md_rlno, mdp->md_frontblks);
2378                                 mdp->md_rltype = type;
2379                         } else {
2380                                 type = CACHEFS_RL_FREE;
2381                                 cachefs_rlent_moveto(fscp->fs_cache, type,
2382                                     mdp->md_rlno, 0);
2383                                 filegrp_ffrele(cp->c_filegrp);
2384                                 mdp->md_rlno = 0;
2385                                 mdp->md_rltype = CACHEFS_RL_NONE;
2386                         }
2387                 }
2388                 mdp->md_flags &= ~(MD_CREATEDONE | MD_PUTPAGE |
2389                     MD_PUSHDONE | MD_MAPPING);
2390 
2391                 /* if a directory, populate it */
2392                 if (CTOV(cp)->v_type == VDIR) {
2393                         /* XXX hack for now */
2394                         mdp->md_flags |= MD_INVALREADDIR;
2395                         dnlc_purge_vp(CTOV(cp));
2396 
2397                         mdp->md_flags |= MD_NEEDATTRS;
2398                 }
2399 
2400                 if (!timedout) {
2401                         error = CFSOP_CHECK_COBJECT(fscp, cp, 0, kcred);
2402                         if (CFS_TIMEOUT(fscp, error))
2403                                 timedout = 1;
2404                         else if ((error == 0) &&
2405                             ((fscp->fs_info.fi_mntflags & CFS_NOACL) == 0)) {
2406                                 if (cachefs_vtype_aclok(CTOV(cp)) &&
2407                                     ((cp->c_flags & CN_NOCACHE) == 0))
2408                                         (void) cachefs_cacheacl(cp, NULL);
2409                         }
2410                 }
2411 
2412                 cp->c_flags |= CN_UPDATED;
2413                 mutex_exit(&cp->c_statelock);
2414                 VN_RELE(CTOV(cp));
2415         }
2416         mutex_exit(&cachep->c_mflock);
2417 }
2418 
2419 void
2420 cachefs_inum_register(fscache_t *fscp, ino64_t real, ino64_t fake)
2421 {
2422         cachefs_inum_trans_t *tbl;
2423         int toff, thop;
2424         int i;
2425 
2426         ASSERT(MUTEX_HELD(&fscp->fs_fslock));
2427 
2428         /*
2429          * first, see if an empty slot exists.
2430          */
2431 
2432         for (i = 0; i < fscp->fs_inum_size; i++)
2433                 if (fscp->fs_inum_trans[i].cit_real == 0)
2434                         break;
2435 
2436         /*
2437          * if there are no empty slots, try to grow the table.
2438          */
2439 
2440         if (i >= fscp->fs_inum_size) {
2441                 cachefs_inum_trans_t *oldtbl;
2442                 int oldsize, newsize = 0;
2443 
2444                 /*
2445                  * try to fetch a new table size that's bigger than
2446                  * our current size
2447                  */
2448 
2449                 for (i = 0; cachefs_hash_sizes[i] != 0; i++)
2450                         if (cachefs_hash_sizes[i] > fscp->fs_inum_size) {
2451                                 newsize = cachefs_hash_sizes[i];
2452                                 break;
2453                         }
2454 
2455                 /*
2456                  * if we're out of larger twin-primes, give up.  thus,
2457                  * the inode numbers in some directory entries might
2458                  * change at reconnect, and disagree with what stat()
2459                  * says.  this isn't worth panicing over, but it does
2460                  * merit a warning message.
2461                  */
2462                 if (newsize == 0) {
2463                         /* only print hash table warning once */
2464                         if ((fscp->fs_flags & CFS_FS_HASHPRINT) == 0) {
2465                                 cmn_err(CE_WARN,
2466                                     "cachefs: inode hash table full\n");
2467                                 fscp->fs_flags |= CFS_FS_HASHPRINT;
2468                         }
2469                         return;
2470                 }
2471 
2472                 /* set up this fscp with a new hash table */
2473 
2474                 oldtbl = fscp->fs_inum_trans;
2475                 oldsize = fscp->fs_inum_size;
2476                 fscp->fs_inum_size = newsize;
2477                 fscp->fs_inum_trans = (cachefs_inum_trans_t *)
2478                     cachefs_kmem_zalloc(sizeof (cachefs_inum_trans_t) * newsize,
2479                         KM_SLEEP);
2480 
2481                 /*
2482                  * re-insert all of the old values.  this will never
2483                  * go more than one level into recursion-land.
2484                  */
2485 
2486                 for (i = 0; i < oldsize; i++) {
2487                         tbl = oldtbl + i;
2488                         if (tbl->cit_real != 0) {
2489                                 cachefs_inum_register(fscp, tbl->cit_real,
2490                                     tbl->cit_fake);
2491                         } else {
2492                                 ASSERT(0);
2493                         }
2494                 }
2495 
2496                 if (oldsize > 0)
2497                         cachefs_kmem_free(oldtbl, oldsize *
2498                             sizeof (cachefs_inum_trans_t));
2499         }
2500 
2501         /*
2502          * compute values for the hash table.  see ken rosen's
2503          * `elementary number theory and its applications' for one
2504          * description of double hashing.
2505          */
2506 
2507         toff = (int)(real % fscp->fs_inum_size);
2508         thop = (int)(real % (fscp->fs_inum_size - 2)) + 1;
2509 
2510         /*
2511          * since we know the hash table isn't full when we get here,
2512          * this loop shouldn't terminate except via the `break'.
2513          */
2514 
2515         for (i = 0; i < fscp->fs_inum_size; i++) {
2516                 tbl = fscp->fs_inum_trans + toff;
2517                 if ((tbl->cit_real == 0) || (tbl->cit_real == real)) {
2518                         tbl->cit_real = real;
2519                         tbl->cit_fake = fake;
2520                         break;
2521                 }
2522 
2523                 toff += thop;
2524                 toff %= fscp->fs_inum_size;
2525         }
2526         ASSERT(i < fscp->fs_inum_size);
2527 }
2528 
2529 /*
2530  * given an inode number, map it to the inode number that should be
2531  * put in a directory entry before its copied out.
2532  *
2533  * don't call this function unless there is a fscp->fs_inum_trans
2534  * table that has real entries in it!
2535  */
2536 
2537 ino64_t
2538 cachefs_inum_real2fake(fscache_t *fscp, ino64_t real)
2539 {
2540         cachefs_inum_trans_t *tbl;
2541         ino64_t rc = real;
2542         int toff, thop;
2543         int i;
2544 
2545         ASSERT(fscp->fs_inum_size > 0);
2546         ASSERT(MUTEX_HELD(&fscp->fs_fslock));
2547 
2548         toff = (int)(real % fscp->fs_inum_size);
2549         thop = (int)(real % (fscp->fs_inum_size - 2)) + 1;
2550 
2551         for (i = 0; i < fscp->fs_inum_size; i++) {
2552                 tbl = fscp->fs_inum_trans + toff;
2553 
2554                 if (tbl->cit_real == 0) {
2555                         break;
2556                 } else if (tbl->cit_real == real) {
2557                         rc = tbl->cit_fake;
2558                         break;
2559                 }
2560 
2561                 toff += thop;
2562                 toff %= fscp->fs_inum_size;
2563         }
2564 
2565         return (rc);
2566 }
2567 
2568 /*
2569  * Passed a cid, finds the cnode and sets the MD_NEEDATTRS bit
2570  * in the metadata.
2571  */
2572 static void
2573 cachefs_iosetneedattrs(fscache_t *fscp, cfs_cid_t *cidp)
2574 {
2575         int error;
2576         cnode_t *cp;
2577 
2578         error = cachefs_cnode_make(cidp, fscp,
2579             NULL, NULL, NULL, kcred, 0, &cp);
2580         if (error)
2581                 return;
2582 
2583         mutex_enter(&cp->c_statelock);
2584         cp->c_metadata.md_flags |= MD_NEEDATTRS;
2585         cp->c_flags |= CN_UPDATED;
2586         mutex_exit(&cp->c_statelock);
2587 
2588         VN_RELE(CTOV(cp));
2589 }