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/vfs.h>
  34 #include <sys/vnode.h>
  35 #include <sys/pathname.h>
  36 #include <sys/uio.h>
  37 #include <sys/tiuser.h>
  38 #include <sys/sysmacros.h>
  39 #include <sys/kmem.h>
  40 #include <sys/mount.h>
  41 #include <sys/ioctl.h>
  42 #include <sys/statvfs.h>
  43 #include <sys/errno.h>
  44 #include <sys/debug.h>
  45 #include <sys/cmn_err.h>
  46 #include <sys/utsname.h>
  47 #include <sys/bootconf.h>
  48 #include <sys/modctl.h>
  49 #include <sys/file.h>
  50 #include <sys/stat.h>
  51 
  52 #include <vm/hat.h>
  53 #include <vm/as.h>
  54 #include <vm/page.h>
  55 #include <vm/pvn.h>
  56 #include <vm/seg.h>
  57 #include <vm/seg_map.h>
  58 #include <vm/seg_vn.h>
  59 #include <vm/rm.h>
  60 #include <sys/fs/cachefs_fs.h>
  61 #include <sys/fs/cachefs_log.h>
  62 
  63 struct kmem_cache *cachefs_filegrp_cache = NULL;
  64 
  65 #if (defined(_SYSCALL32_IMPL) || defined(_LP64))
  66 
  67 #define CACHEFS_ALLOC_CFS_METADATA(p, inp)                              \
  68         p = cachefs_kmem_zalloc(sizeof (struct cfs_cachefs_metadata), KM_SLEEP)
  69 
  70 #define CACHEFS_FREE_CFS_METADATA(p)                                    \
  71         cachefs_kmem_free(p, sizeof (struct cfs_cachefs_metadata))
  72 
  73 /* CACHEFS_COPY_COMMON_METADATA_FIELDS - common code for the metadata copy */
  74 #define CACHEFS_COPY_COMMON_METADATA_FIELDS(inmdp, outmdp)              \
  75         (outmdp)->md_aclclass = (inmdp)->md_aclclass;                     \
  76         CACHEFS_FID_COPY(&(inmdp)->md_cookie, &(outmdp)->md_cookie);      \
  77         (outmdp)->md_flags = (inmdp)->md_flags;                           \
  78         (outmdp)->md_rlno = (inmdp)->md_rlno;                             \
  79         (outmdp)->md_rltype = (inmdp)->md_rltype;                 \
  80         (outmdp)->md_consttype = (inmdp)->md_consttype;                   \
  81         CACHEFS_FID_COPY(&(inmdp)->md_fid, &(outmdp)->md_fid);            \
  82         (outmdp)->md_frontblks = (inmdp)->md_frontblks;                   \
  83         (outmdp)->md_gen = (inmdp)->md_gen;                               \
  84         (outmdp)->md_parent = (inmdp)->md_parent;                 \
  85         (outmdp)->md_resettimes = (inmdp)->md_resettimes;         \
  86         (outmdp)->md_localfileno = (inmdp)->md_localfileno;               \
  87         (outmdp)->md_resetfileno = (inmdp)->md_resetfileno;               \
  88         (outmdp)->md_seq = (inmdp)->md_seq;                               \
  89         (outmdp)->md_allocents = (inmdp)->md_allocents;                   \
  90         bcopy(&(inmdp)->md_allocinfo, &(outmdp)->md_allocinfo,            \
  91             MIN(sizeof (inmdp)->md_allocinfo, sizeof (outmdp)->md_allocinfo))
  92 
  93 #define CACHEFS_COPY_METADATA_TO_CFS_METADATA(inmdp, outmdp, error)     \
  94         CACHEFS_VATTR_TO_CFS_VATTR_COPY(&(inmdp)->md_vattr,              \
  95                 &(outmdp)->md_vattr, error);                             \
  96         CACHEFS_TS_TO_CFS_TS_COPY(&(inmdp)->md_timestamp,                \
  97                 &(outmdp)->md_timestamp, error);                 \
  98         CACHEFS_TS_TO_CFS_TS_COPY(&(inmdp)->md_x_time,                   \
  99                 &(outmdp)->md_x_time, error);                            \
 100         CACHEFS_TS_TO_CFS_TS_COPY(&(inmdp)->md_localmtime,               \
 101                 &(outmdp)->md_localmtime, error);                        \
 102         CACHEFS_TS_TO_CFS_TS_COPY(&(inmdp)->md_localctime,               \
 103                 &(outmdp)->md_localctime, error);                        \
 104         CACHEFS_COPY_COMMON_METADATA_FIELDS(inmdp, outmdp)
 105 
 106 #define CACHEFS_COPY_CFS_METADATA_TO_METADATA(inmdp, outmdp)            \
 107         CACHEFS_CFS_VATTR_TO_VATTR_COPY(&(inmdp)->md_vattr,              \
 108                 &(outmdp)->md_vattr);                                    \
 109         CACHEFS_CFS_TS_TO_TS_COPY(&(inmdp)->md_timestamp,                \
 110                 &(outmdp)->md_timestamp);                                \
 111         CACHEFS_CFS_TS_TO_TS_COPY(&(inmdp)->md_x_time,                   \
 112                 &(outmdp)->md_x_time);                                   \
 113         CACHEFS_CFS_TS_TO_TS_COPY(&(inmdp)->md_localmtime,               \
 114                 &(outmdp)->md_localmtime);                               \
 115         CACHEFS_CFS_TS_TO_TS_COPY(&(inmdp)->md_localctime,               \
 116                 &(outmdp)->md_localctime);                               \
 117         CACHEFS_COPY_COMMON_METADATA_FIELDS(inmdp, outmdp)
 118 
 119 #else /* not (_SYSCALL32_IMPL || _LP64) */
 120 
 121 #define CACHEFS_ALLOC_CFS_METADATA(p, inp)                              \
 122         p = (cfs_cachefs_metadata_t *)(inp)
 123 
 124 #define CACHEFS_FREE_CFS_METADATA(p)
 125 
 126 #define CACHEFS_COPY_METADATA_TO_CFS_METADATA(inmdp, outmdp, error)
 127 
 128 #define CACHEFS_COPY_CFS_METADATA_TO_METADATA(inmdp, outmdp)
 129 
 130 #endif /* _SYSCALL32_IMPL || _LP64 */
 131 
 132 /* forward references */
 133 int filegrp_write_space(vnode_t *vp, offset_t offset, ssize_t cnt);
 134 int filegrpattr_find(struct filegrp *fgp);
 135 int filegrpattr_create(struct filegrp *fgp);
 136 
 137 int
 138 /*ARGSUSED*/
 139 filegrp_cache_create(void *voidp, void *cdrarg, int kmflags)
 140 {
 141         filegrp_t *fgp = (filegrp_t *)voidp;
 142 
 143         mutex_init(&fgp->fg_mutex, NULL, MUTEX_DEFAULT, NULL);
 144         mutex_init(&fgp->fg_cnodelock, NULL, MUTEX_DEFAULT, NULL);
 145         return (0);
 146 }
 147 
 148 void
 149 /*ARGSUSED*/
 150 filegrp_cache_destroy(void *voidp, void *cdrarg)
 151 {
 152         filegrp_t *fgp = (filegrp_t *)voidp;
 153 
 154         mutex_destroy(&fgp->fg_mutex);
 155         mutex_destroy(&fgp->fg_cnodelock);
 156 }
 157 
 158 /*
 159  * ------------------------------------------------------------------
 160  *
 161  *              filegrp_create
 162  *
 163  * Description:
 164  *      Creates a filegrp object for the specified fscache.
 165  *      The CFS_FG_ALLOC_{ATTR, FILE} bits will be set in fg_flags
 166  *      if the cache is in NOCACHE and NOFILL mode or if
 167  *      the directory does not exist yet.
 168  *      The filegrp object maintains a reference to the specified
 169  *      fscache.
 170  * Arguments:
 171  *      fscp    fscache to create the file group in
 172  *      cidp    start cid for the file group
 173  * Returns:
 174  *      Returns the created filegrp object.
 175  * Preconditions:
 176  *      precond(fscp)
 177  *      precond(cidp)
 178  *      precond(fscp->fs_info.fi_fgsize > 0)
 179  */
 180 #define Bugid_1249206_notfixed
 181 #ifdef Bugid_1249206_notfixed
 182 int bugid_1249206 = 0;
 183 #endif
 184 filegrp_t *
 185 filegrp_create(struct fscache *fscp, cfs_cid_t *cidp)
 186 {
 187         filegrp_t *fgp;
 188         int fgsize;
 189         int flags;
 190         ino64_t nfgsize;
 191 
 192         fgsize = fscp->fs_info.fi_fgsize;
 193 
 194         fgp = (filegrp_t *)
 195             kmem_cache_alloc(cachefs_filegrp_cache, KM_SLEEP);
 196 
 197         fgp->fg_flags = CFS_FG_ALLOC_ATTR | CFS_FG_ALLOC_FILE;
 198         fgp->fg_count = 0;
 199         fgp->fg_id = *cidp;
 200 #ifdef Bugid_1249206_notfixed
 201         if (bugid_1249206)
 202                 cmn_err(CE_CONT, "fg_id assigned value is %" PRId64 "\n",
 203                     fgp->fg_id.cid_fileno);
 204 #endif
 205         nfgsize = (fgp->fg_id.cid_fileno / (ino64_t)fgsize);
 206         fgp->fg_id.cid_fileno = (ino64_t)(nfgsize * (ino64_t)fgsize);
 207 #ifdef Bugid_1249206_notfixed
 208         if (bugid_1249206) {
 209                 cmn_err(CE_CONT,
 210                     "cid_fileno for fscp %p fgp %p is %" PRId64 "\n",
 211                     (void *)fscp, (void *)fgp,
 212                     fgp->fg_id.cid_fileno);
 213                 cmn_err(CE_CONT,
 214                     "sent fileno is %" PRId64 " fgsize %d nfgsize %" PRId64
 215                     "\n", cidp->cid_fileno, fgsize, nfgsize);
 216         }
 217 #endif
 218         fgp->fg_fscp = fscp;
 219         fgp->fg_cnodelist = NULL;
 220         fgp->fg_next = NULL;
 221         fgp->fg_dirvp = NULL;
 222         fgp->fg_attrvp = NULL;
 223         fgp->fg_header = NULL;
 224         fgp->fg_offsets = NULL;
 225         fgp->fg_alloclist = NULL;
 226 
 227         fgp->fg_headersize = (uint_t)sizeof (struct attrcache_header) +
 228             (fgsize * (uint_t)sizeof (struct attrcache_index)) +
 229             ((fgsize + 7) >> 3);
 230 
 231         fgp->fg_filesize = fgp->fg_headersize +
 232             (fgsize * (uint_t)sizeof (struct cfs_cachefs_metadata));
 233 
 234         flags = fscp->fs_flags;
 235         if (flags & CFS_FS_READ) {
 236                 fgp->fg_flags |= CFS_FG_READ;
 237                 if (flags & CFS_FS_WRITE) {
 238                         fgp->fg_flags |= CFS_FG_WRITE;
 239                 }
 240         }
 241 
 242         if (fgp->fg_flags & CFS_FG_READ) {
 243                 /* find the attrcache file and frontfile directory */
 244                 (void) filegrpattr_find(fgp);
 245 
 246                 /*
 247                  * XXX: we can tell from the file count in the attrcache
 248                  * whether we can expect to find a front file dir or
 249                  * not.  If not, we can save the lookup here...
 250                  */
 251                 (void) filegrpdir_find(fgp);
 252         }
 253 
 254         return (fgp);
 255 }
 256 
 257 /*
 258  * ------------------------------------------------------------------
 259  *
 260  *              filegrp_destroy
 261  *
 262  * Description:
 263  *      Destroys the filegrp object and releases any kernel
 264  *      resource associated with it.
 265  *      Additionally if the on disk file group directory does
 266  *      not contain any front files it is removed.
 267  * Arguments:
 268  *      fgp     filegrp object to destroy
 269  * Returns:
 270  * Preconditions:
 271  *      precond(fgp is a valid filegrp object)
 272  *      precond(fgp->fg_count == 0)
 273  *      precond(fgp->fg_next == NULL)
 274  */
 275 
 276 void
 277 filegrp_destroy(filegrp_t *fgp)
 278 {
 279         struct fscache *fscp = fgp->fg_fscp;
 280         char name[CFS_FRONTFILE_NAME_SIZE];
 281         char *fname;
 282         int error;
 283 
 284         ASSERT(fgp->fg_count == 0);
 285         ASSERT(fgp->fg_next == NULL);
 286 
 287         if (fgp->fg_attrvp) {
 288                 if (fgp->fg_flags & CFS_FG_UPDATED) {
 289                         error = filegrp_sync(fgp);
 290                         if (error)
 291                                 cmn_err(CE_WARN,
 292                                     "cachefs: UFS error on cache, "
 293                                     "run fsck %d", error);
 294                 }
 295                 VN_RELE(fgp->fg_attrvp);
 296         }
 297         if (fgp->fg_header) {
 298                 /*
 299                  * If there are no attrcache entries in use and
 300                  * if we can modify the cache.
 301                  */
 302                 if ((fgp->fg_header->ach_count == 0) &&
 303                     (fgp->fg_flags & CFS_FG_WRITE)) {
 304                         ASSERT(fgp->fg_header->ach_nffs == 0);
 305 
 306                         /* remove attrcache file from the rl list */
 307                         ASSERT(fgp->fg_header->ach_rl_current ==
 308                             CACHEFS_RL_GC);
 309 #ifdef CFSDEBUG
 310                         cachefs_rlent_verify(fscp->fs_cache, CACHEFS_RL_GC,
 311                             fgp->fg_header->ach_rlno);
 312 #endif /* CFSDEBUG */
 313 
 314                         /*
 315                          * XXX sam: since we're blowing away the
 316                          * attrcache file, i guess i don't need to set
 317                          * ach_rl_current to CACHEFS_RL_NONE and
 318                          * sync the attrcache file, right?
 319                          *
 320                          * fgp->fg_header->ach_rl_current = CACHEFS_RL_NONE;
 321                          * fgp->fg_flags |= CFS_FG_UPDATED;
 322                          */
 323 
 324                         /* remove the attrcache file */
 325                         make_ascii_name(&fgp->fg_id, name);
 326                         fname = name;
 327                         error = VOP_REMOVE(fscp->fs_fsattrdir, fname, kcred,
 328                             NULL, 0);
 329                         if (error) {
 330                                 cmn_err(CE_WARN,
 331                                     "cachefs: error in cache, run fsck");
 332                         } else {
 333                                 cachefs_freefile(fscp->fs_cache);
 334                                 cachefs_freeblocks(fscp->fs_cache,
 335                                     fgp->fg_header->ach_nblks, CACHEFS_RL_GC);
 336                                 cachefs_rlent_moveto(fscp->fs_cache,
 337                                     CACHEFS_RL_FREE, fgp->fg_header->ach_rlno,
 338                                     0);
 339                         }
 340                 }
 341                 cachefs_kmem_free(fgp->fg_header, fgp->fg_headersize);
 342         }
 343         if (fgp->fg_dirvp) {
 344                 VN_RELE(fgp->fg_dirvp);
 345         }
 346         kmem_cache_free(cachefs_filegrp_cache, fgp);
 347 }
 348 
 349 /*
 350  * ------------------------------------------------------------------
 351  *
 352  *              filegrp_allocattr
 353  *
 354  * Description:
 355  *      Tries to find the attrcache file for the given filegroup.
 356  *      If the file does not yet exist it is created.
 357  * Arguments:
 358  *      fgp     filegrp object
 359  * Returns:
 360  *      Returns 0 on success, an errno value on failure.
 361  * Preconditions:
 362  *      precond(fgp is a valid filegrp object)
 363  */
 364 
 365 int
 366 filegrp_allocattr(filegrp_t *fgp)
 367 {
 368         int error = 0;
 369 
 370         mutex_enter(&fgp->fg_mutex);
 371 
 372         /* if we do not yet have the attrcache file */
 373         if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
 374                 /* fail if we tried to create it but failed previously */
 375                 if (fgp->fg_flags & CFS_FG_NOCACHE) {
 376                         error = ENOENT;
 377                         goto out;
 378                 }
 379 
 380                 /* fail if we cannot read from the cache */
 381                 if ((fgp->fg_flags & CFS_FG_READ) == 0) {
 382                         error = ENOENT;
 383                         goto out;
 384                 }
 385 
 386                 /* try to find the attrcache file in the cache */
 387                 error = filegrpattr_find(fgp);
 388                 if (error == ENOENT) {
 389                         /* fail if we cannot create the attrcache file */
 390                         if ((fgp->fg_flags & CFS_FG_WRITE) == 0) {
 391                                 error = ENOENT;
 392                                 goto out;
 393                         }
 394 
 395                         /* try to create the attrcache file */
 396                         error = filegrpattr_create(fgp);
 397                 }
 398         }
 399 out:
 400         mutex_exit(&fgp->fg_mutex);
 401 
 402         return (error);
 403 }
 404 
 405 /*
 406  * ------------------------------------------------------------------
 407  *
 408  *              filegrp_hold
 409  *
 410  * Description:
 411  *      Increments the number of references to this filegrp object.
 412  * Arguments:
 413  *      fgp     filegrp object to reference
 414  * Returns:
 415  * Preconditions:
 416  *      precond(fgp is a valid filegrp object)
 417  */
 418 
 419 void
 420 filegrp_hold(filegrp_t *fgp)
 421 {
 422         mutex_enter(&fgp->fg_mutex);
 423 
 424         fgp->fg_count++;
 425 
 426         /* remove attrcache file from the rl list if necessary */
 427         if ((fgp->fg_flags & CFS_FG_WRITE) &&
 428             (fgp->fg_header != NULL) &&
 429             (fgp->fg_header->ach_rl_current == CACHEFS_RL_GC)) {
 430 #ifdef CFSDEBUG
 431                 cachefs_rlent_verify(fgp->fg_fscp->fs_cache,
 432                     CACHEFS_RL_GC, fgp->fg_header->ach_rlno);
 433 #endif /* CFSDEBUG */
 434                 cachefs_rlent_moveto(fgp->fg_fscp->fs_cache,
 435                     CACHEFS_RL_ATTRFILE, fgp->fg_header->ach_rlno,
 436                     fgp->fg_header->ach_nblks);
 437                 fgp->fg_header->ach_rl_current = CACHEFS_RL_ATTRFILE;
 438                 fgp->fg_flags |= CFS_FG_UPDATED;
 439         }
 440 
 441         mutex_exit(&fgp->fg_mutex);
 442 }
 443 
 444 /*
 445  * ------------------------------------------------------------------
 446  *
 447  *              filegrp_rele
 448  *
 449  * Description:
 450  *      Decrements the number of references to this filegrp object.
 451  * Arguments:
 452  *      fgp     filegrp object to dereference
 453  * Returns:
 454  * Preconditions:
 455  *      precond(fgp is a valid filegrp object)
 456  *      precond(number of references to filegrp is > 0)
 457  */
 458 
 459 void
 460 filegrp_rele(filegrp_t *fgp)
 461 {
 462         mutex_enter(&fgp->fg_mutex);
 463         ASSERT(fgp->fg_count > 0);
 464 
 465         /* move attrcache file to the rl list if necessary */
 466         if (((fgp->fg_flags & CFS_FG_ALLOC_ATTR) == 0) &&
 467             (fgp->fg_flags & CFS_FG_WRITE) &&
 468             (fgp->fg_header->ach_rl_current != CACHEFS_RL_GC) &&
 469             (fgp->fg_count == 1) &&
 470             (fgp->fg_header->ach_nffs == 0)) {
 471 #ifdef CFSDEBUG
 472                 cachefs_rlent_verify(fgp->fg_fscp->fs_cache,
 473                     CACHEFS_RL_ATTRFILE, fgp->fg_header->ach_rlno);
 474 #endif /* CFSDEBUG */
 475                 cachefs_rlent_moveto(fgp->fg_fscp->fs_cache,
 476                     CACHEFS_RL_GC, fgp->fg_header->ach_rlno,
 477                     fgp->fg_header->ach_nblks);
 478                 fgp->fg_header->ach_rl_current = CACHEFS_RL_GC;
 479                 fgp->fg_flags |= CFS_FG_UPDATED;
 480         }
 481 
 482         fgp->fg_count--;
 483 
 484         mutex_exit(&fgp->fg_mutex);
 485 
 486 }
 487 
 488 /*
 489  * ------------------------------------------------------------------
 490  *
 491  *              filegrp_ffhold
 492  *
 493  * Description:
 494  *      Increments the count of the number of front files for
 495  *      this filegrp by one.
 496  * Arguments:
 497  *      fgp     filegrp object to reference
 498  * Returns:
 499  *      Returns 0 for success or a non-zero errno.
 500  * Preconditions:
 501  *      precond(fgp is a valid filegrp object)
 502  *      precond(number of references to filegrp is > 0)
 503  *      precond(filegrp is writable)
 504  */
 505 
 506 int
 507 filegrp_ffhold(filegrp_t *fgp)
 508 {
 509         int error = 0;
 510 
 511         cachefs_cache_dirty(fgp->fg_fscp->fs_cache, 1);
 512 
 513         mutex_enter(&fgp->fg_mutex);
 514         ASSERT(fgp->fg_flags & CFS_FG_WRITE);
 515         ASSERT(fgp->fg_count > 0);
 516 
 517         /* if the filegrp is no good, bail out with warning */
 518         if (fgp->fg_flags & CFS_FG_NOCACHE) {
 519                 error = EINVAL;
 520                 goto out;
 521         }
 522 
 523         /* if we do not have the directory vp yet */
 524         if (fgp->fg_flags & CFS_FG_ALLOC_FILE) {
 525 
 526                 /* create the directory if necessary */
 527                 if (fgp->fg_header->ach_nffs == 0) {
 528                         error = filegrpdir_create(fgp);
 529                         if (error)
 530                                 goto out;
 531                 }
 532 
 533                 /* else find the directory */
 534                 else {
 535                         error = filegrpdir_find(fgp);
 536                         if (error) {
 537 #ifdef CFSDEBUG
 538                                 CFS_DEBUG(CFSDEBUG_FILEGRP)
 539                                         printf("ffhold: no dir, errno %d, "
 540                                             "fileno %llx\n",
 541                                 error, (u_longlong_t)fgp->fg_id.cid_fileno);
 542 #endif
 543                                 goto out;
 544                         }
 545                 }
 546         }
 547         ASSERT(fgp->fg_dirvp);
 548 
 549 #ifdef CFSDEBUG
 550         if (fgp->fg_header->ach_nffs == 0) {
 551                 ASSERT(fgp->fg_header->ach_rl_current == CACHEFS_RL_ATTRFILE);
 552                 cachefs_rlent_verify(fgp->fg_fscp->fs_cache,
 553                     CACHEFS_RL_ATTRFILE, fgp->fg_header->ach_rlno);
 554 
 555                 /*
 556                  * XXX sam: this used to remove from the active list,
 557                  * and put on `NONE'.  now, we're on
 558                  * CACHEFS_RL_ATTRFILE if either count or nffs is
 559                  * nonzero; CACHEFS_RL_GC otherwise.  since we just
 560                  * asserted that we're not on CACHEFS_RL_GC, there's
 561                  * nothing more to do.  right?
 562                  */
 563         }
 564 #endif /* CFSDEBUG */
 565 
 566         fgp->fg_header->ach_nffs++;
 567         fgp->fg_flags |= CFS_FG_UPDATED;
 568         ASSERT(fgp->fg_header->ach_nffs <= fgp->fg_header->ach_count);
 569 
 570 out:
 571         mutex_exit(&fgp->fg_mutex);
 572 
 573         return (error);
 574 }
 575 
 576 /*
 577  * ------------------------------------------------------------------
 578  *
 579  *              filegrp_ffrele
 580  *
 581  * Description:
 582  *      Decrements the count of the number of front files for
 583  *      this filegrp by one.
 584  * Arguments:
 585  *      fgp     filegrp object to dereference
 586  * Returns:
 587  * Preconditions:
 588  *      precond(fgp is a valid filegrp object)
 589  *      precond(filegrp is writable)
 590  *      precond(number of references to filegrp is > 0)
 591  *      precond(number of front file references is > 0)
 592  */
 593 
 594 void
 595 filegrp_ffrele(filegrp_t *fgp)
 596 {
 597         char name[CFS_FRONTFILE_NAME_SIZE];
 598         char *fname;
 599         struct fscache *fscp = fgp->fg_fscp;
 600         int error = 0;
 601 
 602         /* if the filegrp is corrupt, bail out with warning */
 603         if (fgp->fg_flags & CFS_FG_NOCACHE) {
 604                 return;
 605         }
 606 
 607         cachefs_cache_dirty(fgp->fg_fscp->fs_cache, 1);
 608 
 609         mutex_enter(&fgp->fg_mutex);
 610         ASSERT(fgp->fg_flags & CFS_FG_WRITE);
 611         ASSERT((fgp->fg_flags & CFS_FG_ALLOC_FILE) == 0);
 612         ASSERT(fgp->fg_dirvp != NULL);
 613         ASSERT(fgp->fg_count > 0);
 614         ASSERT(fgp->fg_header->ach_nffs > 0);
 615         ASSERT(fgp->fg_header->ach_nffs <= fgp->fg_header->ach_count);
 616 
 617         fgp->fg_header->ach_nffs--;
 618         fgp->fg_flags |= CFS_FG_UPDATED;
 619 
 620         if (fgp->fg_header->ach_nffs == 0) {
 621                 make_ascii_name(&fgp->fg_id, name);
 622                 fname = name;
 623                 error = VOP_RMDIR(fscp->fs_fscdirvp, fname,
 624                     fscp->fs_fscdirvp, kcred, NULL, 0);
 625                 if (error == 0) {
 626                         cachefs_freefile(fscp->fs_cache);
 627                         cachefs_freeblocks(fscp->fs_cache, 1,
 628                             fgp->fg_header->ach_rl_current);
 629                         VN_RELE(fgp->fg_dirvp);
 630                         fgp->fg_dirvp = NULL;
 631                         fgp->fg_flags |= CFS_FG_ALLOC_FILE;
 632                 } else {
 633                         fgp->fg_flags |= CFS_FG_NOCACHE;
 634                         cmn_err(CE_WARN, "cachefs_ffrele:"
 635                             " frontfs cache error %d, run fsck", error);
 636                 }
 637 
 638                 /*
 639                  * XXX sam: this used to move from `NONE' to
 640                  * `CACHEFS_RL_ACTIVE'.  now, we're on
 641                  * CACHEFS_RL_ATTRFILE if count and/or nffs is
 642                  * nonzero, and CACHEFS_RL_GC otherwise.  since we
 643                  * just asserted that count > 0, there's nothing to
 644                  * do.  right?
 645                  */
 646 #ifdef CFSDEBUG
 647                 cachefs_rlent_verify(fgp->fg_fscp->fs_cache,
 648                     CACHEFS_RL_ATTRFILE, fgp->fg_header->ach_rlno);
 649 #endif /* CFSDEBUG */
 650         }
 651         mutex_exit(&fgp->fg_mutex);
 652 }
 653 
 654 /*
 655  * ------------------------------------------------------------------
 656  *
 657  *              filegrp_sync
 658  *
 659  * Description:
 660  *      Writes the file group's attrcache header to the attrcache
 661  *      file if necessary and syncs it.
 662  * Arguments:
 663  *      fgp     filegrp object
 664  * Returns:
 665  *      Returns 0 on success, an errno value on failure.
 666  * Preconditions:
 667  *      precond(fgp is a valid filegrp object)
 668  */
 669 
 670 int
 671 filegrp_sync(filegrp_t *fgp)
 672 {
 673         int error = 0;
 674 
 675         mutex_enter(&fgp->fg_mutex);
 676 
 677         if (((fgp->fg_flags & CFS_FG_UPDATED) == 0) ||
 678             (fgp->fg_flags & CFS_FG_ALLOC_ATTR) ||
 679                 CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp)) {
 680                 mutex_exit(&fgp->fg_mutex);
 681                 return (0);
 682         }
 683 
 684         ASSERT(fgp->fg_header->ach_nffs <= fgp->fg_header->ach_count);
 685 
 686         error = vn_rdwr(UIO_WRITE, fgp->fg_attrvp, (caddr_t)fgp->fg_header,
 687             fgp->fg_headersize, 0LL, UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY,
 688             kcred, NULL);
 689 
 690         if (error == 0)
 691                 error = VOP_FSYNC(fgp->fg_attrvp, FSYNC, kcred, NULL);
 692 
 693         if (error == 0)
 694                 fgp->fg_flags &= ~CFS_FG_UPDATED;
 695 
 696         mutex_exit(&fgp->fg_mutex);
 697 
 698         return (error);
 699 }
 700 
 701 /*
 702  * ------------------------------------------------------------------
 703  *
 704  *              filegrp_read_metadata
 705  *
 706  * Description:
 707  *      Reads the metadata for the specified file from the attrcache
 708  *      file belonging to the filegrp object.  Note that the md_rltype
 709  *      field may be incorrect if (cachep->c_flags & CACHE_CHECK_RLTYPE);
 710  *      in this case, if you care about md_rltype, you should double-check
 711  *      if rl_type is CACHEFS_RL_ACTIVE; cachefs_move_active_to_rl may have
 712  *      moved it without telling us.
 713  * Arguments:
 714  *      fgp     filegrp object
 715  *      cidp    the file to search for
 716  *      mdp     set to the metadata for the fileno
 717  * Returns:
 718  *      Returns 0 on success, an errno value on failure.
 719  * Preconditions:
 720  *      precond(fgp is a valid filegrp object)
 721  *      precond(mdp)
 722  *      precond(slotp)
 723  */
 724 
 725 int
 726 filegrp_read_metadata(filegrp_t *fgp, cfs_cid_t *cidp,
 727     struct cachefs_metadata *mdp)
 728 {
 729         int slot;
 730         int error;
 731         int index;
 732         struct cfs_cachefs_metadata     *tmpmdp;
 733 
 734         ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0);
 735 
 736         mutex_enter(&fgp->fg_mutex);
 737         if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
 738                 mutex_exit(&fgp->fg_mutex);
 739                 return (ENOENT);
 740         }
 741 
 742         slot = filegrp_cid_to_slot(fgp, cidp);
 743         if (slot == 0) {
 744                 mutex_exit(&fgp->fg_mutex);
 745                 return (ENOENT);
 746         }
 747 
 748 
 749         /* see if metadata was ever written */
 750         index = (int)(cidp->cid_fileno - fgp->fg_id.cid_fileno);
 751         if (fgp->fg_offsets[index].ach_written == 0) {
 752                 mutex_exit(&fgp->fg_mutex);
 753                 return (ENOENT);
 754         }
 755 
 756         CACHEFS_ALLOC_CFS_METADATA(tmpmdp, mdp);
 757 
 758         error = vn_rdwr(UIO_READ, fgp->fg_attrvp,
 759             (caddr_t)tmpmdp, sizeof (struct cfs_cachefs_metadata),
 760             (offset_t)slot,
 761             UIO_SYSSPACE, 0, (long long)0, kcred, NULL);
 762         if (error) {
 763                 cmn_err(CE_WARN,
 764                     "cachefs_read_metadata:"
 765                     " frontfs cache error %d, run fsck", error);
 766         }
 767         CACHEFS_COPY_CFS_METADATA_TO_METADATA(tmpmdp, mdp);
 768         CACHEFS_FREE_CFS_METADATA(tmpmdp);
 769 
 770         mutex_exit(&fgp->fg_mutex);
 771         return (error);
 772 }
 773 
 774 /*
 775  * ------------------------------------------------------------------
 776  *
 777  *              filegrp_create_metadata
 778  *
 779  * Description:
 780  *      Allocates a slot for the specified fileno.
 781  * Arguments:
 782  *      fgp     filegrp object
 783  *      cidp    the file to allocate a slot for
 784  * Returns:
 785  *      Returns 0 on success, an errno value on failure.
 786  * Preconditions:
 787  *      precond(fgp is a valid filegrp object)
 788  */
 789 
 790 int
 791 filegrp_create_metadata(filegrp_t *fgp, struct cachefs_metadata *md,
 792     cfs_cid_t *cidp)
 793 {
 794         struct fscache *fscp = fgp->fg_fscp;
 795         cachefscache_t *cachep = fscp->fs_cache;
 796         int slot;
 797         int bitno;
 798         uchar_t mask;
 799         int last;
 800         int xx;
 801         int index;
 802 
 803         ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0);
 804 
 805         cachefs_cache_dirty(cachep, 1);
 806 
 807         mutex_enter(&fgp->fg_mutex);
 808 
 809         if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
 810                 mutex_exit(&fgp->fg_mutex);
 811                 return (ENOENT);
 812         }
 813 
 814         slot = filegrp_cid_to_slot(fgp, cidp);
 815         if (slot) {
 816                 mutex_exit(&fgp->fg_mutex);
 817                 return (0);
 818         }
 819 
 820         index = (int)(cidp->cid_fileno - fgp->fg_id.cid_fileno);
 821 
 822         ASSERT(index < fgp->fg_fscp->fs_info.fi_fgsize);
 823 
 824         last = (((fgp->fg_fscp->fs_info.fi_fgsize + 7) & ~(7)) / 8);
 825         for (xx = 0; xx < last; xx++) {
 826                 if (fgp->fg_alloclist[xx] != (uchar_t)0xff) {
 827                         for (mask = 1, bitno = 0; bitno < 8; bitno++) {
 828                                 if ((mask & fgp->fg_alloclist[xx]) == 0) {
 829                                         slot = (xx * 8) + bitno;
 830                                         goto found;
 831                                 }
 832                                 mask <<= 1;
 833                         }
 834                 }
 835         }
 836 found:
 837         if (xx == last) {
 838                 cmn_err(CE_WARN, "cachefs: attrcache error, run fsck");
 839                 mutex_exit(&fgp->fg_mutex);
 840                 return (ENOMEM);
 841         }
 842 
 843         slot = (slot * (int)sizeof (struct cfs_cachefs_metadata)) +
 844                 fgp->fg_headersize;
 845 
 846         ASSERT(fgp->fg_header->ach_nffs <= fgp->fg_header->ach_count);
 847         fgp->fg_header->ach_count++;
 848         fgp->fg_offsets[index].ach_offset = slot;
 849         fgp->fg_offsets[index].ach_written = 0;
 850         fgp->fg_alloclist[xx] |= mask;
 851         fgp->fg_flags |= CFS_FG_UPDATED;
 852 
 853         mutex_exit(&fgp->fg_mutex);
 854 
 855         if (CACHEFS_LOG_LOGGING(cachep, CACHEFS_LOG_MDCREATE))
 856                 cachefs_log_mdcreate(cachep, 0,
 857                     fscp->fs_cfsvfsp, &md->md_cookie, cidp->cid_fileno,
 858                     fgp->fg_header->ach_count);
 859 
 860         return (0);
 861 }
 862 
 863 /*
 864  * ------------------------------------------------------------------
 865  *
 866  *              filegrp_write_metadata
 867  *
 868  * Description:
 869  *      Writes metadata to the slot held by file.
 870  * Arguments:
 871  *      fgp     filegrp object
 872  *      cidp    the file to write the metadata for
 873  *      mdp     the metadata to write
 874  * Returns:
 875  *      Returns 0 on success, an errno value on failure.
 876  * Preconditions:
 877  *      precond(fgp is a valid filegrp object)
 878  *      precond(mdp)
 879  */
 880 int
 881 filegrp_write_metadata(filegrp_t *fgp, cfs_cid_t *cidp,
 882     struct cachefs_metadata *mdp)
 883 {
 884         int error = 0;
 885         int slot;
 886         blkcnt64_t nblks;
 887         int index;
 888         struct fscache *fscp = fgp->fg_fscp;
 889         struct cfs_cachefs_metadata     *tmpmdp;
 890 
 891         ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0);
 892 
 893         cachefs_cache_dirty(fscp->fs_cache, 1);
 894         mutex_enter(&fgp->fg_mutex);
 895 
 896         if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
 897                 error = ENOENT;
 898                 goto out;
 899         }
 900 
 901         slot = filegrp_cid_to_slot(fgp, cidp);
 902         if (slot == 0) {
 903                 error = ENOENT;
 904                 goto out;
 905         }
 906 
 907         /* allocate blocks for the data if necessary */
 908         nblks = slot + sizeof (struct cfs_cachefs_metadata);
 909         nblks = (nblks + MAXBSIZE - 1) / MAXBSIZE;
 910         nblks -= fgp->fg_header->ach_nblks;
 911         if (nblks > 0) {
 912                 error = cachefs_allocblocks(fscp->fs_cache, nblks,
 913                     fgp->fg_header->ach_rl_current);
 914                 if (error)
 915                         goto out;
 916                 error = filegrp_write_space(fgp->fg_attrvp,
 917                         (offset_t)fgp->fg_header->ach_nblks * MAXBSIZE,
 918                         nblks * MAXBSIZE);
 919                 if (error) {
 920                         cachefs_freeblocks(fscp->fs_cache, nblks,
 921                             fgp->fg_header->ach_rl_current);
 922                         goto out;
 923                 }
 924         } else
 925                 nblks = 0;
 926 
 927         CACHEFS_ALLOC_CFS_METADATA(tmpmdp, mdp);
 928         CACHEFS_COPY_METADATA_TO_CFS_METADATA(mdp, tmpmdp, error);
 929         /* write the metadata */
 930         if (!error)
 931                 error = vn_rdwr(UIO_WRITE, fgp->fg_attrvp, (caddr_t)tmpmdp,
 932                         sizeof (struct cfs_cachefs_metadata), (offset_t)slot,
 933                         UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY, kcred, NULL);
 934 
 935         CACHEFS_FREE_CFS_METADATA(tmpmdp);
 936 
 937         if (error) {
 938                 if (error == EOVERFLOW) {
 939                         cmn_err(CE_WARN, "cachefs_write_metadata:"
 940                             " time/dev overflow error %d", error);
 941                 } else if (error != ENOSPC) {
 942                         cmn_err(CE_WARN,
 943                             "cachefs: UFS write error %d, run fsck",
 944                             error);
 945                 }
 946                 cachefs_freeblocks(fscp->fs_cache, nblks,
 947                     fgp->fg_header->ach_rl_current);
 948                 goto out;
 949         }
 950 
 951         /* mark metadata as having been written */
 952         index = (int)(cidp->cid_fileno - fgp->fg_id.cid_fileno);
 953         fgp->fg_offsets[index].ach_written = 1;
 954 
 955         /* update number of blocks used by the attrcache file */
 956         fgp->fg_header->ach_nblks += nblks;
 957 
 958         /* force sync to be done eventually */
 959         fgp->fg_flags |= CFS_FG_UPDATED;
 960 
 961 out:
 962         mutex_exit(&fgp->fg_mutex);
 963         return (error);
 964 }
 965 
 966 /*
 967  * ------------------------------------------------------------------
 968  *
 969  *              filegrp_destroy_metadata
 970  *
 971  * Description:
 972  *      Destroys the metadata associated with the specified file.
 973  * Arguments:
 974  *      fgp     filegrp object
 975  *      cidp    the file to destroy the metadata for
 976  * Returns:
 977  *      Returns 0 on success, an errno value on failure.
 978  * Preconditions:
 979  *      precond(fgp is a valid filegrp object)
 980  */
 981 
 982 int
 983 filegrp_destroy_metadata(filegrp_t *fgp, cfs_cid_t *cidp)
 984 {
 985         int i;
 986         int bitno;
 987         uchar_t mask = 1;
 988 
 989         int slot;
 990 
 991         ASSERT(CFS_ISFS_BACKFS_NFSV4(fgp->fg_fscp) == 0);
 992 
 993         cachefs_cache_dirty(fgp->fg_fscp->fs_cache, 1);
 994         mutex_enter(&fgp->fg_mutex);
 995 
 996         if (fgp->fg_flags & CFS_FG_ALLOC_ATTR) {
 997                 mutex_exit(&fgp->fg_mutex);
 998                 return (ENOENT);
 999         }
1000 
1001         slot = filegrp_cid_to_slot(fgp, cidp);
1002         if (slot == 0) {
1003                 mutex_exit(&fgp->fg_mutex);
1004                 return (ENOENT);
1005         }
1006 
1007         i = (int)(cidp->cid_fileno - fgp->fg_id.cid_fileno);
1008         fgp->fg_offsets[i].ach_offset = 0;
1009         fgp->fg_offsets[i].ach_written = 0;
1010         i = (slot - fgp->fg_headersize) /
1011                 (int)sizeof (struct cfs_cachefs_metadata);
1012         bitno = i & 7;
1013         i = i >> 3;
1014         mask <<= bitno;
1015         if (fgp->fg_alloclist[i] & mask)
1016                 fgp->fg_alloclist[i] &= ~mask;
1017         else
1018                 cmn_err(CE_WARN,
1019                     "filegrp_destroy_metadata:"
1020                     " fileno %" PRId64 " slot %d-%d fgp %p not allocated",
1021                     cidp->cid_fileno, i, bitno, (void *)fgp);
1022 
1023         fgp->fg_header->ach_count--;
1024         ASSERT(fgp->fg_header->ach_nffs <= fgp->fg_header->ach_count);
1025         fgp->fg_flags |= CFS_FG_UPDATED;
1026         mutex_exit(&fgp->fg_mutex);
1027 
1028         return (0);
1029 }
1030 
1031 /*
1032  * ------------------------------------------------------------------
1033  *
1034  *              filegrp_list_find
1035  *
1036  * Description:
1037  *      Looks for the filegrp that owns the specified file
1038  *      on the fscp filegrp lists.
1039  *      The fscp->fs_fslock must be held while this routine is called.
1040  *      By convention the filegrp object returned may be used as
1041  *      long as the fs_fslock is held.  To use the filegrp after
1042  *      dropping fs_fslock, call filegrp_hold.
1043  * Arguments:
1044  *      fscp    fscache object
1045  *      cidp    the file to search on
1046  * Returns:
1047  *      Returns the filegrp object if found, NULL if not.
1048  * Preconditions:
1049  *      precond(fscp is a valid fscache object)
1050  */
1051 
1052 filegrp_t *
1053 filegrp_list_find(struct fscache *fscp, cfs_cid_t *cidp)
1054 {
1055         int fgsize = fscp->fs_info.fi_fgsize;
1056         struct filegrp *fgp;
1057         ino64_t fxx;
1058         int findex;
1059         ino64_t fileno;
1060 
1061         ASSERT(MUTEX_HELD(&fscp->fs_fslock));
1062 
1063         /* get fileno of filegrp */
1064         fxx = (ino64_t)(cidp->cid_fileno / fgsize);
1065         fileno = fxx * fgsize;
1066 
1067         /* hash into array of file groups */
1068         findex = (int)(fxx & (CFS_FS_FGP_BUCKET_SIZE - 1));
1069 
1070         /* search set of file groups for this hash bucket */
1071         for (fgp = fscp->fs_filegrp[findex];
1072             fgp != NULL;
1073             fgp = fgp->fg_next) {
1074                 if ((fgp->fg_id.cid_fileno == fileno) &&
1075                     (fgp->fg_id.cid_flags == cidp->cid_flags))
1076                         break;
1077         }
1078 
1079         return (fgp);
1080 }
1081 
1082 /*
1083  * ------------------------------------------------------------------
1084  *
1085  *              filegrp_list_add
1086  *
1087  * Description:
1088  *      Adds the filegrp to the list of filegrps in the fscp.
1089  *      The fscp->fs_fslock must be held while this routine is called.
1090  * Arguments:
1091  *      fscp    fscache object
1092  *      fgp     filegrp object
1093  * Returns:
1094  * Preconditions:
1095  *      precond(fscp is a valid fscache object)
1096  *      precond(fgp is a valid filegrp object)
1097  *      precond(fgp is not already on a list of filegrps)
1098  */
1099 
1100 void
1101 filegrp_list_add(struct fscache *fscp, filegrp_t *fgp)
1102 {
1103         int findex;
1104         int fgsize = fscp->fs_info.fi_fgsize;
1105 
1106         ASSERT(MUTEX_HELD(&fscp->fs_fslock));
1107         ASSERT(fgp->fg_next == NULL);
1108 
1109         /* hash into array of file groups */
1110         findex = (int)((fgp->fg_id.cid_fileno / fgsize) &
1111             (CFS_FS_FGP_BUCKET_SIZE - 1));
1112 
1113         fgp->fg_next = fscp->fs_filegrp[findex];
1114         fscp->fs_filegrp[findex] = fgp;
1115         fscp->fs_ref++;
1116 }
1117 
1118 /*
1119  * ------------------------------------------------------------------
1120  *
1121  *              filegrp_list_remove
1122  *
1123  * Description:
1124  *      Removes the filegrp from the list of filegrps in the fscp.
1125  *      The fscp->fs_fslock must be held while this routine is called.
1126  * Arguments:
1127  *      fscp    fscache object
1128  *      fgp     filegrp object
1129  * Returns:
1130  * Preconditions:
1131  *      precond(fscp is a valid fscache object)
1132  *      precond(fgp is a valid filegrp object)
1133  *      precond(fgp is on the list of filegrps in fscp)
1134  */
1135 
1136 void
1137 filegrp_list_remove(struct fscache *fscp, filegrp_t *fgp)
1138 {
1139         struct filegrp *fp;
1140         struct filegrp **pfgp;
1141         int found = 0;
1142         int findex;
1143         int fgsize = fscp->fs_info.fi_fgsize;
1144 
1145         ASSERT(MUTEX_HELD(&fscp->fs_fslock));
1146 
1147         /* hash into array of file groups */
1148         findex = (int)((fgp->fg_id.cid_fileno / fgsize) &
1149             (CFS_FS_FGP_BUCKET_SIZE - 1));
1150         fp = fscp->fs_filegrp[findex];
1151         pfgp = &fscp->fs_filegrp[findex];
1152 
1153         while (fp != NULL) {
1154                 if (fp == fgp) {
1155                         *pfgp = fp->fg_next;
1156                         fp->fg_next = NULL;
1157                         found++;
1158                         break;
1159                 }
1160                 pfgp = &fp->fg_next;
1161                 fp = fp->fg_next;
1162         }
1163         ASSERT(found);
1164         fscp->fs_ref--;
1165 }
1166 
1167 /*
1168  * ------------------------------------------------------------------
1169  *
1170  *              filegrp_list_gc
1171  *
1172  * Description:
1173  *      Traverses the filegrp lists and throws away any filegrps that are
1174  *      not in use.
1175  *      The fscp->fs_fslock must be held while this routine is called.
1176  * Arguments:
1177  *      fscp    fscache object
1178  * Returns:
1179  * Preconditions:
1180  *      precond(fscp is a valid fscache object)
1181  */
1182 
1183 void
1184 filegrp_list_gc(struct fscache *fscp)
1185 {
1186         struct filegrp *next, *fgp;
1187         int xx;
1188 
1189         ASSERT(MUTEX_HELD(&fscp->fs_fslock));
1190 
1191         for (xx = 0; xx < CFS_FS_FGP_BUCKET_SIZE; xx++) {
1192                 for (fgp = fscp->fs_filegrp[xx]; fgp != NULL; fgp = next) {
1193                         next = fgp->fg_next;
1194                         mutex_enter(&fgp->fg_mutex);
1195                         if (fgp->fg_count > 0) {
1196                                 mutex_exit(&fgp->fg_mutex);
1197                                 continue;
1198                         }
1199                         mutex_exit(&fgp->fg_mutex);
1200                         filegrp_list_remove(fscp, fgp);
1201                         filegrp_destroy(fgp);
1202                 }
1203         }
1204 }
1205 
1206 /*
1207  * ------------------------------------------------------------------
1208  *
1209  *              filegrp_setup
1210  *
1211  * Description:
1212  *      Perform initialization actions on the given filegrp.
1213  *      The fgp->fg_mutex must be held while this routine is called.
1214  * Arguments:
1215  *      fgp     filegrp object
1216  *      flags   flags to be OR'ed into the fgp flags field
1217  *      dorl    indicates whether filegrp should be removed from rl or not
1218  * Returns:
1219  * Preconditions:
1220  *      precond(fgp is a valid filegrp object)
1221  */
1222 static void
1223 filegrp_setup(struct filegrp *fgp, int flags, int dorl)
1224 {
1225         ASSERT(MUTEX_HELD(&fgp->fg_mutex));
1226 
1227         /* turn on the specified flags */
1228         if (flags)
1229                 fgp->fg_flags |= flags;
1230 
1231         /* if the attrcache file exists, find it */
1232         if (fgp->fg_flags & CFS_FG_ALLOC_ATTR)
1233                 (void) filegrpattr_find(fgp);
1234 
1235         /* if the attrcache directory exists, find it */
1236         if (((fgp->fg_flags & CFS_FG_ALLOC_ATTR) == 0) &&
1237             (fgp->fg_flags & CFS_FG_ALLOC_FILE) &&
1238             (fgp->fg_header->ach_nffs > 0)) {
1239                 (void) filegrpdir_find(fgp);
1240         }
1241 
1242         /* move from gc list to attrfile list if necessary */
1243         if ((dorl != 0) &&
1244             ((fgp->fg_flags & CFS_FG_ALLOC_ATTR) == 0) &&
1245             (fgp->fg_header->ach_rl_current == CACHEFS_RL_GC)) {
1246                 ASSERT(fgp->fg_header->ach_nffs == 0);
1247                 if (fgp->fg_count > 0) {
1248 #ifdef CFSDEBUG
1249                         cachefs_rlent_verify(fgp->fg_fscp->fs_cache,
1250                             CACHEFS_RL_GC, fgp->fg_header->ach_rlno);
1251 #endif /* CFSDEBUG */
1252                         cachefs_rlent_moveto(fgp->fg_fscp->fs_cache,
1253                             CACHEFS_RL_ATTRFILE, fgp->fg_header->ach_rlno,
1254                             fgp->fg_header->ach_nblks);
1255                         fgp->fg_header->ach_rl_current = CACHEFS_RL_ATTRFILE;
1256                         fgp->fg_flags |= CFS_FG_UPDATED;
1257                 }
1258         }
1259 }
1260 
1261 /*
1262  * ------------------------------------------------------------------
1263  *
1264  *              filegrp_list_enable_caching_ro
1265  *
1266  * Description:
1267  *      Traverses the filegrp lists and enables the
1268  *      use of the cache read-only.
1269  *      The fscp->fs_fslock must be held while this routine is called.
1270  * Arguments:
1271  *      fscp    fscache object
1272  * Returns:
1273  * Preconditions:
1274  *      precond(fscp is a valid fscache object)
1275  */
1276 
1277 void
1278 filegrp_list_enable_caching_ro(struct fscache *fscp)
1279 {
1280         struct filegrp *fgp;
1281         int xx;
1282 
1283         ASSERT(MUTEX_HELD(&fscp->fs_fslock));
1284 
1285         for (xx = 0; xx < CFS_FS_FGP_BUCKET_SIZE; xx++) {
1286                 for (fgp = fscp->fs_filegrp[xx]; fgp != NULL;
1287                     fgp = fgp->fg_next) {
1288                         mutex_enter(&fgp->fg_mutex);
1289                         filegrp_setup(fgp, 0, 0);
1290                         mutex_exit(&fgp->fg_mutex);
1291                 }
1292         }
1293 }
1294 
1295 /*
1296  * ------------------------------------------------------------------
1297  *
1298  *              filegrp_list_enable_caching_rw
1299  *
1300  * Description:
1301  *      Traverses the filegrp lists and enables the
1302  *      use of the cache read-write.
1303  *      The fscp->fs_fslock must be held while this routine is called.
1304  * Arguments:
1305  *      fscp    fscache object
1306  * Returns:
1307  * Preconditions:
1308  *      precond(fscp is a valid fscache object)
1309  *      precond(all filegrps must be in the read-only state)
1310  */
1311 
1312 void
1313 filegrp_list_enable_caching_rw(struct fscache *fscp)
1314 {
1315         struct filegrp *fgp;
1316         int xx;
1317 
1318         ASSERT(MUTEX_HELD(&fscp->fs_fslock));
1319 
1320         for (xx = 0; xx < CFS_FS_FGP_BUCKET_SIZE; xx++) {
1321                 for (fgp = fscp->fs_filegrp[xx]; fgp != NULL;
1322                     fgp = fgp->fg_next) {
1323                         mutex_enter(&fgp->fg_mutex);
1324                         filegrp_setup(fgp, CFS_FG_READ|CFS_FG_WRITE, 1);
1325                         mutex_exit(&fgp->fg_mutex);
1326                 }
1327         }
1328 }
1329 
1330 /*
1331  * ------------------------------------------------------------------
1332  *
1333  *              filegrpdir_find
1334  *
1335  * Description:
1336  *      Tries to find the filegrp frontfile directory in the cache.
1337  *      If found CFS_FG_ALLOC_FILE is turned off.
1338  *      This routine should not be called if CFS_FG_ALLOC_FILE is
1339  *      already off.
1340  * Arguments:
1341  *      fgp     filegrp object
1342  * Returns:
1343  *      Returns 0 on success, an errno value on failure.
1344  * Preconditions:
1345  *      precond(fgp is a valid filegrp object)
1346  */
1347 
1348 int
1349 filegrpdir_find(filegrp_t *fgp)
1350 {
1351         int error;
1352         vnode_t *dirvp;
1353         char name[CFS_FRONTFILE_NAME_SIZE];
1354         char *fname;
1355         struct fscache *fscp = fgp->fg_fscp;
1356 
1357         if (fgp->fg_flags & CFS_FG_ALLOC_ATTR)
1358                 return (ENOENT);
1359         ASSERT(fgp->fg_flags & CFS_FG_ALLOC_FILE);
1360 
1361         make_ascii_name(&fgp->fg_id, name);
1362         fname = name;
1363         error = VOP_LOOKUP(fscp->fs_fscdirvp, fname, &dirvp, NULL,
1364                         0, NULL, kcred, NULL, NULL, NULL);
1365         if (error == 0) {
1366                 fgp->fg_dirvp = dirvp;
1367                 fgp->fg_flags &= ~CFS_FG_ALLOC_FILE;
1368 #ifdef CFSDEBUG
1369                 if (fgp->fg_header->ach_nffs == 0) {
1370                         CFS_DEBUG(CFSDEBUG_FILEGRP)
1371                                 printf("filegrpdir_find: "
1372                                     "%s found but no front files\n", fname);
1373                 }
1374 #endif
1375         }
1376 #ifdef CFSDEBUG
1377         else if (fgp->fg_header->ach_nffs != 0) {
1378                 CFS_DEBUG(CFSDEBUG_FILEGRP)
1379                         printf("filegrpdir_find: "
1380                                 "%s NOT found but %d front files\n",
1381                                 fname, fgp->fg_header->ach_nffs);
1382         }
1383 #endif
1384         return (error);
1385 }
1386 
1387 /*
1388  * ------------------------------------------------------------------
1389  *
1390  *              filegrparttr_find
1391  *
1392  * Description:
1393  *      Tries to find the attrcache file for the given filegrp.
1394  *      If found the header information is read in and
1395  *      CFS_FG_ALLOC_ATTR is turned off.
1396  *      This routine should not be called if CFS_FG_ALLOC_ATTR is
1397  *      already off.
1398  * Arguments:
1399  *      fgp     filegrp object
1400  * Returns:
1401  *      Returns 0 on success, an errno value on failure.
1402  * Preconditions:
1403  *      precond(fgp is a valid filegrp object)
1404  *      precond(fgp is readable)
1405  */
1406 
1407 int
1408 filegrpattr_find(struct filegrp *fgp)
1409 {
1410         int error = 0;
1411         struct fscache *fscp = fgp->fg_fscp;
1412         cachefscache_t *cachep = fscp->fs_cache;
1413         vnode_t *attrvp;
1414         struct attrcache_header *ahp;
1415         char name[CFS_FRONTFILE_NAME_SIZE];
1416         char *fname;
1417 
1418         if (fgp->fg_flags & CFS_FG_NOCACHE)
1419                 return (ENOENT);
1420 
1421         ASSERT(fgp->fg_flags & CFS_FG_ALLOC_ATTR);
1422         make_ascii_name(&fgp->fg_id, name);
1423         fname = name;
1424         error = VOP_LOOKUP(fscp->fs_fsattrdir, fname,
1425             &attrvp, NULL, 0, NULL, kcred, NULL, NULL, NULL);
1426         if (error) {
1427                 return (error);
1428         }
1429         ahp = (struct attrcache_header *)cachefs_kmem_zalloc(
1430             fgp->fg_headersize, KM_SLEEP);
1431 
1432         error = vn_rdwr(UIO_READ, attrvp, (caddr_t)ahp,
1433                                 fgp->fg_headersize, 0LL, UIO_SYSSPACE,
1434                         0, (rlim64_t)RLIM_INFINITY, kcred, NULL);
1435         if (error) {
1436                 cmn_err(CE_WARN, "cachefs: Read attrcache error %d, run fsck",
1437                     error);
1438                 cachefs_kmem_free(ahp, fgp->fg_headersize);
1439                 fgp->fg_flags |= CFS_FG_NOCACHE;
1440                 VN_RELE(attrvp);
1441         } else {
1442                 ASSERT(ahp->ach_nffs <= ahp->ach_count);
1443                 fgp->fg_attrvp = attrvp;
1444                 fgp->fg_header = ahp;
1445                 fgp->fg_offsets = (struct attrcache_index *)(ahp + 1);
1446                 fgp->fg_alloclist = ((uchar_t *)fgp->fg_offsets) +
1447                         (fscp->fs_info.fi_fgsize *
1448                         sizeof (struct attrcache_index));
1449                 fgp->fg_flags &= ~CFS_FG_ALLOC_ATTR;
1450 
1451                 if ((cachep->c_flags & CACHE_CHECK_RLTYPE) &&
1452                     (ahp->ach_rl_current == CACHEFS_RL_ATTRFILE)) {
1453                         rl_entry_t *rlp, rl;
1454 
1455                         mutex_enter(&cachep->c_contentslock);
1456                         error = cachefs_rl_entry_get(cachep, ahp->ach_rlno,
1457                                                                         &rlp);
1458                         if (error) {
1459                                 mutex_exit(&cachep->c_contentslock);
1460                                 cachefs_kmem_free(ahp, fgp->fg_headersize);
1461                                 fgp->fg_flags |= CFS_FG_NOCACHE;
1462                                 VN_RELE(attrvp);
1463                                 return (error);
1464                         }
1465 
1466                         rl = *rlp;
1467                         mutex_exit(&cachep->c_contentslock);
1468 
1469                         if (rl.rl_current != ahp->ach_rl_current) {
1470                                 ahp->ach_rl_current = rl.rl_current;
1471                                 fgp->fg_flags |= CFS_FG_UPDATED;
1472                         }
1473                 }
1474 
1475                 /* if the attr file is on the rl */
1476                 if (fgp->fg_header->ach_rl_current == CACHEFS_RL_GC) {
1477 #ifdef CFSDEBUG
1478                         if (fgp->fg_flags & CFS_FG_WRITE)
1479                                 cachefs_rlent_verify(fgp->fg_fscp->fs_cache,
1480                                     CACHEFS_RL_GC,
1481                                     fgp->fg_header->ach_rlno);
1482 #endif /* CFSDEBUG */
1483                         if ((fgp->fg_count > 0) &&
1484                             (fgp->fg_flags & CFS_FG_WRITE)) {
1485                                 /* remove from rl, put on active */
1486                                 cachefs_rlent_moveto(fgp->fg_fscp->fs_cache,
1487                                     CACHEFS_RL_ATTRFILE,
1488                                     fgp->fg_header->ach_rlno,
1489                                     fgp->fg_header->ach_nblks);
1490                                 fgp->fg_header->ach_rl_current =
1491                                     CACHEFS_RL_ATTRFILE;
1492                                 fgp->fg_flags |= CFS_FG_UPDATED;
1493                         }
1494                 } else {
1495                         ASSERT(fgp->fg_header->ach_rl_current ==
1496                             CACHEFS_RL_ATTRFILE);
1497 #ifdef CFSDEBUG
1498                         if (fgp->fg_flags & CFS_FG_WRITE)
1499                                 cachefs_rlent_verify(fgp->fg_fscp->fs_cache,
1500                                     CACHEFS_RL_ATTRFILE,
1501                                     fgp->fg_header->ach_rlno);
1502 #endif /* CFSDEBUG */
1503                 }
1504         }
1505 
1506         return (error);
1507 }
1508 
1509 /*
1510  * ------------------------------------------------------------------
1511  *
1512  *              filegrpdir_create
1513  *
1514  * Description:
1515  *      Creates the filegrp directory in the cache.
1516  *      If created CFS_FG_ALLOC_FILE is turned off.
1517  *      This routine should not be called if CFS_FG_ALLOC_FILE is
1518  *      already off.
1519  * Arguments:
1520  *      fgp     filegrp object
1521  * Returns:
1522  *      Returns 0 on success, an errno value on failure.
1523  * Preconditions:
1524  *      precond(fgp is a valid filegrp object)
1525  *      precond(filegrp is writeable)
1526  */
1527 
1528 int
1529 filegrpdir_create(filegrp_t *fgp)
1530 {
1531         int error;
1532         vnode_t *dirvp = NULL;
1533         struct vattr *attrp = NULL;
1534         char name[CFS_FRONTFILE_NAME_SIZE];
1535         char *fname;
1536         struct fscache *fscp = fgp->fg_fscp;
1537 
1538         ASSERT(fgp->fg_flags & CFS_FG_WRITE);
1539         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
1540         ASSERT(MUTEX_HELD(&fgp->fg_mutex));
1541 
1542         if (fgp->fg_flags & (CFS_FG_ALLOC_ATTR | CFS_FG_NOCACHE))
1543                 return (ENOENT);
1544 
1545         /* allocate a 1 block file for the directory */
1546         error = cachefs_allocfile(fscp->fs_cache);
1547         if (error) {
1548                 return (error);
1549         }
1550         error = cachefs_allocblocks(fscp->fs_cache, 1,
1551             fgp->fg_header->ach_rl_current);
1552         if (error) {
1553                 cachefs_freefile(fscp->fs_cache);
1554                 return (error);
1555         }
1556 
1557         /*
1558          * Construct a name for this file group directory and then do a mkdir
1559          */
1560         make_ascii_name(&fgp->fg_id, name);
1561         fname = name;
1562         attrp = (struct vattr *)cachefs_kmem_alloc(sizeof (struct vattr),
1563                         KM_SLEEP);
1564         attrp->va_mode = S_IFDIR | 0777;
1565         attrp->va_uid = 0;
1566         attrp->va_gid = 0;
1567         attrp->va_type = VDIR;
1568         attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
1569         error = VOP_MKDIR(fscp->fs_fscdirvp, fname, attrp, &dirvp, kcred, NULL,
1570             0, NULL);
1571         if (error) {
1572                 fgp->fg_flags |= CFS_FG_NOCACHE;
1573                 cachefs_freefile(fscp->fs_cache);
1574                 cachefs_freeblocks(fscp->fs_cache, 1,
1575                     fgp->fg_header->ach_rl_current);
1576         } else {
1577                 fgp->fg_dirvp = dirvp;
1578                 fgp->fg_flags &= ~CFS_FG_ALLOC_FILE;
1579         }
1580 
1581         if (attrp)
1582                 cachefs_kmem_free(attrp, sizeof (*attrp));
1583 
1584         return (error);
1585 }
1586 
1587 /*
1588  * ------------------------------------------------------------------
1589  *
1590  *              filegrpattr_create
1591  *
1592  * Description:
1593  *      Creates the attrcache file for the given filegrp.
1594  *      If created CFS_FG_ALLOC_ATTR is turned off.
1595  *      This routine should not be called if CFS_FG_ALLOC_ATTR is
1596  *      already off.
1597  * Arguments:
1598  *      fgp     filegrp object
1599  * Returns:
1600  *      Returns 0 on success, an errno value on failure.
1601  * Preconditions:
1602  *      precond(fgp is a valid filegrp object)
1603  *      precond(filegrp is writable)
1604  */
1605 
1606 int
1607 filegrpattr_create(struct filegrp *fgp)
1608 {
1609         int error;
1610         vnode_t *attrvp = NULL;
1611         struct attrcache_header *ahp = NULL;
1612         int nblks = 0;
1613         int gotrlent = 0;
1614         struct vattr *attrp = NULL;
1615         char name[CFS_FRONTFILE_NAME_SIZE];
1616         char *fname;
1617         struct fscache *fscp = fgp->fg_fscp;
1618         rl_entry_t rl_ent;
1619 
1620         ASSERT(fgp->fg_flags & CFS_FG_WRITE);
1621 
1622         if (fgp->fg_flags & CFS_FG_NOCACHE)
1623                 return (ENOENT);
1624 
1625         cachefs_cache_dirty(fscp->fs_cache, 1);
1626 
1627         /* allocate a file for the attrcache */
1628         error = cachefs_allocfile(fscp->fs_cache);
1629         if (error) {
1630                 goto out;
1631         }
1632 
1633         make_ascii_name(&fgp->fg_id, name);
1634         fname = name;
1635         attrp = cachefs_kmem_alloc(sizeof (struct vattr), KM_SLEEP);
1636         attrp->va_mode = S_IFREG | 0666;
1637         attrp->va_uid = 0;
1638         attrp->va_gid = 0;
1639         attrp->va_type = VREG;
1640         attrp->va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
1641         error = VOP_CREATE(fscp->fs_fsattrdir, fname, attrp, EXCL, 0666,
1642                         &attrvp, kcred, 0, NULL, NULL);
1643         if (error) {
1644                 cachefs_freefile(fscp->fs_cache);
1645                 goto out;
1646         }
1647 
1648         /* alloc blocks for the attrcache header */
1649         nblks = (fgp->fg_headersize + MAXBSIZE - 1) / MAXBSIZE;
1650         error = cachefs_allocblocks(fscp->fs_cache, nblks, CACHEFS_RL_NONE);
1651         if (error) {
1652                 nblks = 0;
1653                 goto out;
1654         }
1655 
1656         /* Construct an attrcache header */
1657         ahp = cachefs_kmem_zalloc(fgp->fg_headersize, KM_SLEEP);
1658 
1659         /* write out the header to allocate space on ufs */
1660         error = vn_rdwr(UIO_WRITE, attrvp, (caddr_t)ahp,
1661         fgp->fg_headersize, 0LL, UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY,
1662                 kcred, NULL);
1663         if (error)
1664                 goto out;
1665         error = filegrp_write_space(attrvp, (offset_t)fgp->fg_headersize,
1666                 (nblks * MAXBSIZE) - fgp->fg_headersize);
1667         if (error)
1668                 goto out;
1669         error = VOP_FSYNC(attrvp, FSYNC, kcred, NULL);
1670         if (error)
1671                 goto out;
1672 
1673         /* allocate an rl entry and mark it as an attrcache entry */
1674         rl_ent.rl_fileno = fgp->fg_id.cid_fileno;
1675         rl_ent.rl_local = (fgp->fg_id.cid_flags & CFS_CID_LOCAL) ? 1 : 0;
1676         rl_ent.rl_fsid = fscp->fs_cfsid;
1677         rl_ent.rl_attrc = 1;
1678         error = cachefs_rl_alloc(fscp->fs_cache, &rl_ent, &ahp->ach_rlno);
1679         if (error)
1680                 goto out;
1681         gotrlent = 1;
1682         if (fgp->fg_count == 0) {
1683                 /* put on the gc */
1684                 cachefs_rlent_moveto(fgp->fg_fscp->fs_cache, CACHEFS_RL_GC,
1685                     ahp->ach_rlno, nblks);
1686                 ahp->ach_rl_current = CACHEFS_RL_GC;
1687         } else {
1688                 /* put on attrfile list */
1689                 cachefs_rlent_moveto(fgp->fg_fscp->fs_cache,
1690                     CACHEFS_RL_ATTRFILE, ahp->ach_rlno, nblks);
1691                 ahp->ach_rl_current = CACHEFS_RL_ATTRFILE;
1692         }
1693 
1694 out:
1695         if (error) {
1696                 fgp->fg_flags |= CFS_FG_NOCACHE;
1697                 if (attrvp) {
1698                         VN_RELE(attrvp);
1699                         (void) VOP_REMOVE(fscp->fs_fsattrdir, fname, kcred,
1700                             NULL, 0);
1701                         cachefs_freefile(fscp->fs_cache);
1702                 }
1703                 if (nblks)
1704                         cachefs_freeblocks(fscp->fs_cache, nblks,
1705                             CACHEFS_RL_NONE);
1706                 if (gotrlent)
1707                         cachefs_rlent_moveto(fscp->fs_cache,
1708                             CACHEFS_RL_FREE, ahp->ach_rlno, 0);
1709                 if (ahp)
1710                         cachefs_kmem_free(ahp, fgp->fg_headersize);
1711         } else {
1712                 fgp->fg_attrvp = attrvp;
1713                 fgp->fg_header = ahp;
1714                 fgp->fg_offsets = (struct attrcache_index *)(ahp + 1);
1715                 fgp->fg_alloclist = ((uchar_t *)fgp->fg_offsets) +
1716                         (fscp->fs_info.fi_fgsize *
1717                         sizeof (struct attrcache_index));
1718                 ahp->ach_count = 0;
1719                 ahp->ach_nffs = 0;
1720                 ahp->ach_nblks = nblks;
1721                 fgp->fg_flags &= ~CFS_FG_ALLOC_ATTR;
1722                 fgp->fg_flags |= CFS_FG_UPDATED;
1723         }
1724 
1725         if (attrp)
1726                 cachefs_kmem_free(attrp, sizeof (*attrp));
1727 
1728         return (error);
1729 }
1730 
1731 /*
1732  * ------------------------------------------------------------------
1733  *
1734  *              filegrp_cid_to_slot
1735  *
1736  * Description:
1737  *      Takes a file and returns the offset to the metadata
1738  *      slot for the specified filegrp.
1739  * Arguments:
1740  *      fgp     filegrp object
1741  *      cidp    file to map to an offset
1742  * Returns:
1743  *      Returns the offset or 0 if the slot is not allocated yet
1744  *      or it is invalid.
1745  * Preconditions:
1746  *      precond(fgp is a valid filegrp object)
1747  *      precond(fgp is not ALLOC_PENDING or NOCACHE)
1748  */
1749 
1750 int
1751 filegrp_cid_to_slot(filegrp_t *fgp, cfs_cid_t *cidp)
1752 {
1753         int xx;
1754         int slot;
1755         int index;
1756 
1757         index = (int)(cidp->cid_fileno - fgp->fg_id.cid_fileno);
1758 
1759         if (index > fgp->fg_fscp->fs_info.fi_fgsize) {
1760                 cmn_err(CE_WARN, "cachefs: attrcache error, run fsck");
1761                 return (0);
1762         }
1763 
1764         slot = fgp->fg_offsets[index].ach_offset;
1765         if (slot == 0)
1766                 return (0);
1767 
1768         xx = fgp->fg_filesize - (int)sizeof (struct cfs_cachefs_metadata);
1769         if ((slot < fgp->fg_headersize) || (xx < slot)) {
1770                 cmn_err(CE_WARN, "cachefs: attrcache error, run fsck");
1771                 return (0);
1772         }
1773 
1774         return (slot);
1775 }
1776 
1777 /*
1778  *
1779  *              filegrp_write_space
1780  *
1781  * Description:
1782  *      Writes garbage data to the specified file starting
1783  *      at the specified location for the specified number of bytes.
1784  *      slot for the specified filegrp.
1785  * Arguments:
1786  *      vp      vnode to write to
1787  *      offset  offset to write at
1788  *      cnt     number of bytes to write
1789  * Returns:
1790  *      Returns 0 for success or on error the result of the
1791  *      last vn_rdwr call.
1792  * Preconditions:
1793  *      precond(vp)
1794  */
1795 
1796 int
1797 filegrp_write_space(vnode_t *vp, offset_t offset, ssize_t cnt)
1798 {
1799         char *bufp;
1800         int xx;
1801         int error = 0;
1802 
1803         bufp = (char *)cachefs_kmem_zalloc(MAXBSIZE, KM_SLEEP);
1804         while (cnt > 0) {
1805                 if (cnt > MAXBSIZE)
1806                         xx = MAXBSIZE;
1807                 else
1808                         xx = (int)cnt;
1809                 error = vn_rdwr(UIO_WRITE, vp, (caddr_t)bufp,
1810                 xx, offset, UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY,
1811                         kcred, NULL);
1812                 if (error)
1813                         break;
1814                 offset += xx;
1815                 cnt -= xx;
1816         }
1817         cachefs_kmem_free(bufp, MAXBSIZE);
1818         return (error);
1819 }