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, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 1994-2003 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 /*
  30  * Methods of the cfsd_fscache class.
  31  */
  32 
  33 #include <stdio.h>
  34 #include <stdlib.h>
  35 #include <string.h>
  36 #include <stddef.h>
  37 #include <thread.h>
  38 #include <synch.h>
  39 #include <errno.h>
  40 #include <unistd.h>
  41 #include <stdarg.h>
  42 #include <limits.h>
  43 #include <fcntl.h>
  44 #include <locale.h>
  45 #include <nfs/nfs.h>
  46 #include <sys/utsname.h>
  47 #include <sys/param.h>
  48 #include <sys/stat.h>
  49 #include <sys/mount.h>
  50 #include <sys/types.h>
  51 #include <sys/wait.h>
  52 #include <rpc/rpc.h>
  53 #include <mdbug/mdbug.h>
  54 #include <sys/fs/cachefs_fs.h>
  55 #include <sys/fs/cachefs_dlog.h>
  56 #include <sys/fs/cachefs_ioctl.h>
  57 #include "cfsd.h"
  58 #include "cfsd_kmod.h"
  59 #include "cfsd_maptbl.h"
  60 #include "cfsd_logfile.h"
  61 #include "cfsd_logelem.h"
  62 #include "cfsd_fscache.h"
  63 
  64 /*
  65  * -----------------------------------------------------------------
  66  *                      cfsd_fscache_create
  67  *
  68  * Description:
  69  * Arguments:
  70  *      name
  71  *      cachepath
  72  * Returns:
  73  * Preconditions:
  74  *      precond(name)
  75  *      precond(cachepath)
  76  */
  77 cfsd_fscache_object_t *
  78 cfsd_fscache_create(const char *name, const char *cachepath,
  79         int fscacheid)
  80 {
  81         cfsd_fscache_object_t *fscache_object_p;
  82         int xx;
  83 
  84         dbug_enter("cfsd_fscache_create");
  85 
  86         dbug_precond(name);
  87         dbug_precond(cachepath);
  88 
  89         fscache_object_p = cfsd_calloc(sizeof (cfsd_fscache_object_t));
  90         strlcpy(fscache_object_p->i_name, name,
  91             sizeof (fscache_object_p->i_name));
  92         strlcpy(fscache_object_p->i_cachepath, cachepath,
  93             sizeof (fscache_object_p->i_cachepath));
  94         fscache_object_p->i_fscacheid = fscacheid;
  95         fscache_object_p->i_refcnt = 0;
  96         fscache_object_p->i_disconnectable = 0;
  97         fscache_object_p->i_mounted = 0;
  98         fscache_object_p->i_threaded = 0;
  99         fscache_object_p->i_connected = 0;
 100         fscache_object_p->i_reconcile = 0;
 101         fscache_object_p->i_changes = 0;
 102         fscache_object_p->i_simdis = 0;
 103         fscache_object_p->i_tryunmount = 0;
 104         fscache_object_p->i_backunmount = 0;
 105         fscache_object_p->i_time_state = 0;
 106         fscache_object_p->i_time_mnt = 0;
 107         fscache_object_p->i_modify = 1;
 108 
 109         fscache_object_p->i_threadid = 0;
 110         fscache_object_p->i_ofd = -1;
 111 
 112         fscache_object_p->i_next = NULL;
 113 
 114         /* initialize the locking mutex */
 115         xx = mutex_init(&fscache_object_p->i_lock, USYNC_THREAD, NULL);
 116         dbug_assert(xx == 0);
 117 
 118         xx = cond_init(&fscache_object_p->i_cvwait, USYNC_THREAD, 0);
 119         dbug_assert(xx == 0);
 120 
 121         dbug_leave("cfsd_fscache_create");
 122         return (fscache_object_p);
 123 }
 124 
 125 /*
 126  * -----------------------------------------------------------------
 127  *                      cfsd_fscache_destroy
 128  *
 129  * Description:
 130  * Arguments:
 131  * Returns:
 132  * Preconditions:
 133  */
 134 void
 135 cfsd_fscache_destroy(cfsd_fscache_object_t *fscache_object_p)
 136 {
 137         int xx;
 138 
 139         dbug_enter("cfsd_fscache_destroy");
 140 
 141         dbug_precond(fscache_object_p);
 142         /* dbug_assert(fscache_object_p->i_refcnt == 0); */
 143 
 144         /* close down the message file descriptor */
 145         if (fscache_object_p->i_ofd >= 0) {
 146                 if (close(fscache_object_p->i_ofd))
 147                         dbug_print(("error", "cannot close fscache fd error %d",
 148                             errno));
 149                 fscache_object_p->i_ofd = -1;
 150         }
 151 
 152         /* destroy the locking mutex */
 153         xx = mutex_destroy(&fscache_object_p->i_lock);
 154         dbug_assert(xx == 0);
 155 
 156         /* destroy the conditional variable */
 157         xx = cond_destroy(&fscache_object_p->i_cvwait);
 158         dbug_assert(xx == 0);
 159 
 160         cfsd_free(fscache_object_p);
 161 
 162         dbug_leave("cfsd_fscache_destroy");
 163 }
 164 
 165 /*
 166  * -----------------------------------------------------------------
 167  *                      fscache_lock
 168  *
 169  * Description:
 170  * Arguments:
 171  * Returns:
 172  * Preconditions:
 173  */
 174 void
 175 fscache_lock(cfsd_fscache_object_t *fscache_object_p)
 176 {
 177         dbug_enter("fscache_lock");
 178 
 179         dbug_precond(fscache_object_p);
 180         mutex_lock(&fscache_object_p->i_lock);
 181         dbug_leave("fscache_lock");
 182 }
 183 
 184 /*
 185  * -----------------------------------------------------------------
 186  *                      fscache_unlock
 187  *
 188  * Description:
 189  * Arguments:
 190  * Returns:
 191  * Preconditions:
 192  */
 193 void
 194 fscache_unlock(cfsd_fscache_object_t *fscache_object_p)
 195 {
 196         dbug_enter("fscache_unlock");
 197 
 198         dbug_precond(fscache_object_p);
 199         mutex_unlock(&fscache_object_p->i_lock);
 200         dbug_leave("fscache_unlock");
 201 }
 202 
 203 /*
 204  * -----------------------------------------------------------------
 205  *                      fscache_setup
 206  *
 207  * Description:
 208  * Arguments:
 209  * Returns:
 210  * Preconditions:
 211  */
 212 void
 213 fscache_setup(cfsd_fscache_object_t *fscache_object_p)
 214 {
 215         char *tmp;
 216         char cfs_mnt_filename[MAXPATHLEN];
 217         FILE *fin;
 218         /*
 219          * Line input buffer allows for type field (magic number size
 220          * of 50 is historic), the field separator ": ", a large value
 221          * (again historic) and a '\n' character.
 222          */
 223         char type[50];
 224         char value[MAXPATHLEN * 4];
 225         char buf[sizeof (type) + 2 + sizeof (value) + 1];
 226         int err = 0;
 227         int xx;
 228         char *options[] = { "snr", "disconnectable", NULL };
 229         char *strp = buf;
 230         char *dummy;
 231         struct stat64 sinfo;
 232         time_t mtime;
 233 
 234         dbug_enter("fscache_setup");
 235         dbug_precond(fscache_object_p);
 236 
 237         fscache_object_p->i_modify++;
 238         fscache_object_p->i_disconnectable = 0;
 239         fscache_object_p->i_connected = 0;
 240         fscache_object_p->i_reconcile = 0;
 241         fscache_object_p->i_changes = 0;
 242         fscache_object_p->i_time_state = 0;
 243         fscache_object_p->i_time_mnt = 0;
 244         fscache_object_p->i_mntpt[0] = '\0';
 245         fscache_object_p->i_backfs[0] = '\0';
 246         fscache_object_p->i_backpath[0] = '\0';
 247         fscache_object_p->i_backfstype[0] = '\0';
 248         fscache_object_p->i_cfsopt[0] = '\0';
 249         fscache_object_p->i_bfsopt[0] = '\0';
 250 
 251         snprintf(cfs_mnt_filename, sizeof (cfs_mnt_filename), "%s/%s/%s",
 252             fscache_object_p->i_cachepath, fscache_object_p->i_name,
 253             CACHEFS_MNT_FILE);
 254 
 255         /* open for reading the file with the mount information */
 256         fin = fopen(cfs_mnt_filename, "r");
 257         if (fin == NULL) {
 258                 dbug_print(("err", "could not open %s, %d", cfs_mnt_filename,
 259                     errno));
 260                 dbug_leave("fscache_setup");
 261                 return;
 262         }
 263         /* get the modify time of the mount file */
 264         if (fstat64(fileno(fin), &sinfo) == -1) {
 265                 dbug_print(("err", "could not stat %s, %d", cfs_mnt_filename,
 266                     errno));
 267                 if (fclose(fin))
 268                         dbug_print(("err", "cannot close %s, %d",
 269                             cfs_mnt_filename, errno));
 270                 dbug_leave("fscache_setup");
 271                 return;
 272         }
 273         mtime = sinfo.st_mtime;
 274 
 275         /* read the mount information from the file */
 276         while (fgets(buf, sizeof (buf), fin) != NULL) {
 277                 tmp = strtok(buf, ":");
 278                 if (strlcpy(type, tmp, sizeof (type)) >= sizeof (type)) {
 279                         /* Buffer Overflow */
 280                         dbug_print(("err", "overflow in type field"
 281                             " of file %s", cfs_mnt_filename));
 282                         if (fclose(fin))
 283                                 dbug_print(("err", "cannot close %s, %d",
 284                                     cfs_mnt_filename, errno));
 285                         dbug_leave("fscache_setup");
 286                         return;
 287                 }
 288                 tmp = strtok(NULL, "\n");
 289                 if (tmp != NULL && *tmp == ' ') {
 290                         /*
 291                          * There is a valid value string so skip
 292                          * the space after the ":".
 293                          */
 294                         tmp++;
 295                         if (strlcpy(value, tmp, sizeof (value))
 296                             >= sizeof (value)) {
 297                                 /* Buffer Overflow */
 298                                 dbug_print(("err",
 299                                     "overflow in value field"
 300                                     " of file %s", cfs_mnt_filename));
 301                                 if (fclose(fin))
 302                                         dbug_print(("err",
 303                                             "cannot close %s, %d",
 304                                             cfs_mnt_filename, errno));
 305                                 dbug_leave("fscache_setup");
 306                                 return;
 307                         }
 308                 } else {
 309                         value[0] = '\0';
 310                 }
 311                 dbug_print(("info", "\"%s\" \"%s\"", type, value));
 312                 if (strcmp(type, "cachedir") == 0) {
 313                         if (strcmp(fscache_object_p->i_cachepath, value) != 0) {
 314                                 err = 1;
 315                                 dbug_print(("err", "caches do not match %s, %s",
 316                                     fscache_object_p->i_cachepath, buf));
 317                         }
 318                 } else if (strcmp(type, "mnt_point") == 0) {
 319                         strlcpy(fscache_object_p->i_mntpt, value,
 320                             sizeof (fscache_object_p->i_mntpt));
 321                 } else if (strcmp(type, "special") == 0) {
 322                         strlcpy(fscache_object_p->i_backfs, value,
 323                             sizeof (fscache_object_p->i_backfs));
 324                 } else if (strcmp(type, "backpath") == 0) {
 325                         strlcpy(fscache_object_p->i_backpath, value,
 326                             sizeof (fscache_object_p->i_backpath));
 327                 } else if (strcmp(type, "backfstype") == 0) {
 328                         strlcpy(fscache_object_p->i_backfstype, value,
 329                             sizeof (fscache_object_p->i_backfstype));
 330                 } else if (strcmp(type, "cacheid") == 0) {
 331                         if (strcmp(fscache_object_p->i_name, value) != 0) {
 332                                 err = 1;
 333                                 dbug_print(("err", "ids do not match %s, %s",
 334                                     fscache_object_p->i_name, value));
 335                         }
 336                 } else if (strcmp(type, "cachefs_options") == 0) {
 337                         strlcpy(fscache_object_p->i_cfsopt, value,
 338                             sizeof (fscache_object_p->i_cfsopt));
 339                 } else if (strcmp(type, "backfs_options") == 0) {
 340                         strlcpy(fscache_object_p->i_bfsopt, value,
 341                             sizeof (fscache_object_p->i_bfsopt));
 342                 } else if (strcmp(type, "mount_time") == 0) {
 343                         continue;
 344                 } else {
 345                         dbug_print(("err", "unknown keyword \"%s\"", type));
 346                         err = 1;
 347                 }
 348         }
 349         if (fclose(fin))
 350                 dbug_print(("err", "cannot close %s, %d",
 351                     cfs_mnt_filename, errno));
 352 
 353         /* see if this is a file system that is disconnectable */
 354         if ((err == 0) &&
 355                 (fscache_object_p->i_backfs[0] &&
 356                 fscache_object_p->i_cfsopt[0])) {
 357                 strlcpy(buf, fscache_object_p->i_cfsopt, sizeof (buf));
 358                 while (*strp != '\0') {
 359                         xx = getsubopt(&strp, options, &dummy);
 360                         if (xx != -1) {
 361                                 fscache_object_p->i_disconnectable = 1;
 362                                 break;
 363                         }
 364                 }
 365         }
 366 
 367         /*
 368          * open up a fd on the sysmsg so we have a place to write
 369          * log rolling errors
 370          */
 371         if (fscache_object_p->i_disconnectable) {
 372                 if (fscache_object_p->i_ofd < 0)
 373                         fscache_object_p->i_ofd = open("/dev/sysmsg",
 374                             O_WRONLY);
 375                 if (fscache_object_p->i_ofd < 0) {
 376                         fprintf(stderr,
 377                             gettext("cachefsd: File system %s cannot be"
 378                             " disconnected.\n"),
 379                             fscache_object_p->i_mntpt);
 380                         fprintf(stderr,
 381                             gettext("cachefsd: Cannot open /dev/sysmsg\n"));
 382                         fscache_object_p->i_disconnectable = 0;
 383                 }
 384         }
 385 
 386         /* see if the file system is mounted */
 387         snprintf(cfs_mnt_filename, sizeof (cfs_mnt_filename), "%s/%s/%s",
 388             fscache_object_p->i_cachepath, fscache_object_p->i_name,
 389             CACHEFS_UNMNT_FILE);
 390         if (stat64(cfs_mnt_filename, &sinfo) == 0) {
 391                 fscache_object_p->i_mounted = 0;
 392                 mtime = sinfo.st_mtime;
 393         } else
 394                 fscache_object_p->i_mounted = 1;
 395 
 396         /* save the time of the last mount or unmount */
 397         fscache_object_p->i_time_mnt = mtime;
 398 
 399         dbug_print(("info", "disconnectable == %d, mounted == %d",
 400             fscache_object_p->i_disconnectable,
 401             fscache_object_p->i_mounted));
 402         dbug_leave("fscache_setup");
 403 }
 404 
 405 /*
 406  * -----------------------------------------------------------------
 407  *                      fscache_process
 408  *
 409  * Description:
 410  * Arguments:
 411  * Returns:
 412  * Preconditions:
 413  */
 414 void
 415 fscache_process(cfsd_fscache_object_t *fscache_object_p)
 416 {
 417         int xx;
 418         int changes;
 419         cfsd_kmod_object_t *kmod_object_p;
 420         int setup = 1;
 421         int state;
 422 
 423         dbug_enter("fscache_process");
 424         dbug_precond(fscache_object_p);
 425 
 426         kmod_object_p = cfsd_kmod_create();
 427         for (;;) {
 428                 fscache_lock(fscache_object_p);
 429                 fscache_object_p->i_time_state = time(NULL);
 430                 fscache_object_p->i_modify++;
 431 
 432                 /* if we should try to unmount the file system */
 433                 if (fscache_object_p->i_tryunmount) {
 434                         /* shut down the interface to the kmod */
 435                         if (setup == 0) {
 436                                 kmod_shutdown(kmod_object_p);
 437                                 setup = 1;
 438                         }
 439 
 440                         /* try to unmount the file system */
 441                         if (umount(fscache_object_p->i_mntpt) == -1) {
 442                                 xx = errno;
 443                                 dbug_print(("info", "unmount failed %s",
 444                                     strerror(xx)));
 445                         } else {
 446                                 fscache_object_p->i_mounted = 0;
 447                         }
 448 
 449                         /* wake up thread blocked in fscache_unmount */
 450                         fscache_object_p->i_tryunmount = 0;
 451                         xx = cond_broadcast(&fscache_object_p->i_cvwait);
 452                         dbug_assert(xx == 0);
 453 
 454                         /* all done if unmount succeeded */
 455                         if (fscache_object_p->i_mounted == 0) {
 456                                 fscache_unlock(fscache_object_p);
 457                                 break;
 458                         }
 459                 }
 460 
 461                 if (setup) {
 462                         setup = 0;
 463                         /*
 464                          * make an interface into the cachefs kmod for
 465                          * this fs
 466                          */
 467                         xx = kmod_setup(kmod_object_p,
 468                             fscache_object_p->i_mntpt);
 469                         if (xx != 0) {
 470                                 dbug_print(("err",
 471                                     "setup of kmod interface failed %d", xx));
 472                                 fscache_object_p->i_disconnectable = 0;
 473                                 fscache_object_p->i_modify++;
 474                                 fscache_unlock(fscache_object_p);
 475                                 break;
 476                         }
 477 
 478                         /* verify that we got the file system we expected XXX */
 479                 }
 480 
 481                 /* get the current state of the file system */
 482                 state = kmod_stateget(kmod_object_p);
 483 
 484                 if (fscache_object_p->i_simdis && (state == CFS_FS_CONNECTED)) {
 485                         dbug_print(("simdis", "simulating disconnection on %s",
 486                             fscache_object_p->i_mntpt));
 487                         xx = kmod_stateset(kmod_object_p, CFS_FS_DISCONNECTED);
 488                         dbug_assert(xx == 0);
 489                         state = kmod_stateget(kmod_object_p);
 490                         dbug_assert(state == CFS_FS_DISCONNECTED);
 491                 }
 492                 fscache_unlock(fscache_object_p);
 493 
 494                 switch (state) {
 495                 case CFS_FS_CONNECTED:
 496                         fscache_lock(fscache_object_p);
 497                         fscache_object_p->i_connected = 1;
 498                         fscache_object_p->i_reconcile = 0;
 499                         fscache_object_p->i_modify++;
 500                         fscache_unlock(fscache_object_p);
 501 
 502                         /* wait for fs to switch to disconnecting */
 503                         dbug_print(("info", "about to xwait"));
 504                         xx = kmod_xwait(kmod_object_p);
 505                         if (xx == EINTR) {
 506                                 dbug_print(("info", "a. EINTR from xwait"));
 507                                 continue;
 508                         }
 509                         dbug_assert(xx == 0);
 510                         state = kmod_stateget(kmod_object_p);
 511                         dbug_assert(state == CFS_FS_DISCONNECTED);
 512                         break;
 513 
 514                 case CFS_FS_DISCONNECTED:
 515                         fscache_lock(fscache_object_p);
 516                         fscache_object_p->i_connected = 0;
 517                         fscache_object_p->i_reconcile = 0;
 518                         fscache_object_p->i_modify++;
 519                         fscache_unlock(fscache_object_p);
 520 
 521                         /* wait until we are reconnected */
 522                         fscache_server_alive(fscache_object_p, kmod_object_p);
 523                         if (fscache_object_p->i_tryunmount)
 524                                 continue;
 525 
 526                         /* switch to reconnecting mode */
 527                         xx = kmod_stateset(kmod_object_p, CFS_FS_RECONNECTING);
 528                         dbug_assert(xx == 0);
 529                         break;
 530 
 531                 case CFS_FS_RECONNECTING:
 532                         fscache_lock(fscache_object_p);
 533                         fscache_object_p->i_connected = 1;
 534                         fscache_object_p->i_reconcile = 1;
 535                         fscache_object_p->i_modify++;
 536                         changes = fscache_object_p->i_changes;
 537                         fscache_unlock(fscache_object_p);
 538 
 539                         /* roll the log */
 540                         xx = fscache_roll(fscache_object_p, kmod_object_p);
 541                         if (xx) {
 542                                 dbug_assert(xx == ETIMEDOUT);
 543                                 /* switch to disconnected */
 544                                 xx = kmod_stateset(kmod_object_p,
 545                                     CFS_FS_DISCONNECTED);
 546                                 dbug_assert(xx == 0);
 547                         } else {
 548                                 /* switch to connected */
 549                                 xx = kmod_stateset(kmod_object_p,
 550                                     CFS_FS_CONNECTED);
 551                                 dbug_assert(xx == 0);
 552                                 changes = 0;
 553                         }
 554 
 555                         fscache_lock(fscache_object_p);
 556                         fscache_object_p->i_reconcile = 0;
 557                         fscache_changes(fscache_object_p, changes);
 558                         fscache_object_p->i_modify++;
 559                         fscache_unlock(fscache_object_p);
 560 
 561                         break;
 562 
 563                 default:
 564                         dbug_assert(0);
 565                         break;
 566                 }
 567         }
 568         cfsd_kmod_destroy(kmod_object_p);
 569         dbug_leave("fscache_process");
 570 }
 571 
 572 /*
 573  *                      fscache_simdisconnect
 574  *
 575  * Description:
 576  *      Simulates disconnection or reconnects from a simulated disconnection.
 577  * Arguments:
 578  *      disconnect      1 means disconnect, !1 means connect
 579  * Returns:
 580  *      Returns 0 for success, !0 on an error
 581  * Preconditions:
 582  */
 583 int
 584 fscache_simdisconnect(cfsd_fscache_object_t *fscache_object_p, int disconnect)
 585 {
 586 
 587         int xx;
 588         int ret = 0;
 589         char *strp;
 590         int tcon;
 591         int trec;
 592 
 593         dbug_enter("fscache_simdisconnect");
 594         dbug_precond(fscache_object_p);
 595 
 596         strp = disconnect ? "disconnection" : "reconnection";
 597 
 598         dbug_print(("simdis", "About to simulate %s", strp));
 599 
 600         fscache_lock(fscache_object_p);
 601 
 602         if (disconnect) {
 603                 /* if file system cannot be disconnected */
 604                 if (fscache_object_p->i_disconnectable == 0) {
 605                         ret = 1;
 606                         goto out;
 607                 }
 608 
 609                 /* if file system is already disconnected */
 610                 if (fscache_object_p->i_connected == 0) {
 611                         ret = 2;
 612                         goto out;
 613                 }
 614                 fscache_object_p->i_simdis = 1;
 615         } else {
 616                 /* if file system is already connected */
 617                 if (fscache_object_p->i_connected) {
 618                         ret = 1;
 619                         goto out;
 620                 }
 621 
 622                 /* if file system is not "simulated" disconnected */
 623                 if (fscache_object_p->i_simdis == 0) {
 624                         ret = 2;
 625                         goto out;
 626                 }
 627                 fscache_object_p->i_simdis = 0;
 628         }
 629 
 630         /* if fs thread not running */
 631         if (fscache_object_p->i_threaded == 0) {
 632                 if (fscache_object_p->i_mounted) {
 633                         dbug_print(("simdis", "thread not running"));
 634                         ret = -1;
 635                 } else {
 636                         if (fscache_object_p->i_simdis)
 637                                 fscache_object_p->i_connected = 0;
 638                         else
 639                                 fscache_object_p->i_connected = 1;
 640                 }
 641                 goto out;
 642         }
 643 
 644         /* get the attention of the thread */
 645         dbug_print(("info", "thread %d, killing %d with sigusr1",
 646             thr_self(), fscache_object_p->i_threadid));
 647         xx = thr_kill(fscache_object_p->i_threadid, SIGUSR1);
 648         if (xx) {
 649                 dbug_print(("simdis", "thr_kill failed %d, threadid %d",
 650                     xx, fscache_object_p->i_threadid));
 651                 ret = -1;
 652         }
 653 
 654 out:
 655         fscache_unlock(fscache_object_p);
 656 
 657         if (ret == 0) {
 658                 for (;;) {
 659                         dbug_print(("simdis", "     waiting for simulated %s",
 660                             strp));
 661                         fscache_lock(fscache_object_p);
 662                         tcon = fscache_object_p->i_connected;
 663                         trec = fscache_object_p->i_reconcile;
 664                         fscache_unlock(fscache_object_p);
 665                         if (disconnect) {
 666                                 if (tcon == 0)
 667                                         break;
 668                         } else {
 669                                 if ((tcon == 1) && (trec == 0))
 670                                         break;
 671                         }
 672                         cfsd_sleep(1);
 673                 }
 674                 dbug_print(("simdis", "DONE waiting for simulated %s", strp));
 675         } else {
 676                 dbug_print(("simdis", "simulated %s failed %d", strp, ret));
 677         }
 678 
 679         dbug_leave("fscache_simdisconnect");
 680         return (ret);
 681 }
 682 
 683 /*
 684  *                      fscache_unmount
 685  *
 686  * Description:
 687  *      Called to unmount the file system.
 688  * Arguments:
 689  * Returns:
 690  *      Returns 0 if the unmount is successful
 691  *              EIO if an error
 692  *              EBUSY if did not unmount because busy
 693  *              EAGAIN if umounted but should not unmount nfs mount
 694  *              ENOTSUP -  forced unmount is not supported by cachefs
 695  * Preconditions:
 696  */
 697 
 698 int
 699 fscache_unmount(cfsd_fscache_object_t *fscache_object_p, int flag)
 700 {
 701         int xx;
 702         int ret = 0;
 703 
 704         dbug_enter("fscache_unmount");
 705         dbug_precond(fscache_object_p);
 706 
 707         fscache_lock(fscache_object_p);
 708 
 709         /* if there is a thread running */
 710         if (fscache_object_p->i_threaded) {
 711                 /* do not bother unmounting if rolling the log */
 712                 if (fscache_object_p->i_reconcile) {
 713                         ret = EBUSY;
 714                         goto out;
 715                 }
 716 
 717                 /* inform the thread to try the unmount */
 718                 fscache_object_p->i_tryunmount = 1;
 719                 fscache_object_p->i_modify++;
 720 
 721                 /* get the attention of the thread */
 722                 dbug_print(("info", "about to do umount kill"));
 723                 xx = thr_kill(fscache_object_p->i_threadid, SIGUSR1);
 724                 if (xx) {
 725                         dbug_print(("error", "thr_kill failed %d, threadid %d",
 726                             xx, fscache_object_p->i_threadid));
 727                         ret = EIO;
 728                         goto out;
 729                 }
 730 
 731                 /* wait for the thread to wake us up */
 732                 while (fscache_object_p->i_tryunmount) {
 733                         xx = cond_wait(&fscache_object_p->i_cvwait,
 734                             &fscache_object_p->i_lock);
 735                         dbug_print(("info", "cond_wait woke up %d %d",
 736                             xx, fscache_object_p->i_tryunmount));
 737                 }
 738 
 739                 /* if the file system is still mounted */
 740                 if (fscache_object_p->i_mounted)
 741                         ret = EBUSY;
 742         }
 743 
 744         /* else if there is no thread running */
 745         else {
 746                 /* try to unmount the file system */
 747                 if (umount2(fscache_object_p->i_mntpt, flag) == -1) {
 748                         xx = errno;
 749                         dbug_print(("info", "unmount failed %s",
 750                             strerror(xx)));
 751                         if (xx == EBUSY)
 752                                 ret = EBUSY;
 753                         else if (xx == ENOTSUP)
 754                                 ret = ENOTSUP;
 755                         else
 756                                 ret = EIO;
 757                 } else {
 758                         fscache_object_p->i_mounted = 0;
 759                         fscache_object_p->i_modify++;
 760                 }
 761         }
 762 out:
 763         fscache_unlock(fscache_object_p);
 764         dbug_leave("fscache_unmount");
 765         return (ret);
 766 }
 767 
 768 /*
 769  * -----------------------------------------------------------------
 770  *                      fscache_server_alive
 771  *
 772  * Description:
 773  * Arguments:
 774  * Returns:
 775  * Preconditions:
 776  */
 777 void
 778 fscache_server_alive(cfsd_fscache_object_t *fscache_object_p,
 779         cfsd_kmod_object_t *kmod_object_p)
 780 {
 781 
 782         int xx;
 783         cfs_fid_t rootfid;
 784         dl_cred_t cr;
 785         cfs_vattr_t va;
 786         char cfsopt[CFS_MAXMNTOPTLEN];
 787         int child_pid;
 788         int stat_loc;
 789 
 790         dbug_enter("fscache_server_alive");
 791 
 792         dbug_precond(fscache_object_p);
 793         dbug_precond(kmod_object_p);
 794 
 795         for (;;) {
 796                 /* wait for a little while */
 797                 if (fscache_object_p->i_simdis == 0)
 798                         cfsd_sleep(30);
 799                 /* if simulating disconnect */
 800                 fscache_lock(fscache_object_p);
 801                 while (fscache_object_p->i_simdis &&
 802                         !fscache_object_p->i_tryunmount) {
 803                         dbug_print(("simdis", "before calling cond_wait"));
 804                         xx = cond_wait(&fscache_object_p->i_cvwait,
 805                             &fscache_object_p->i_lock);
 806                         dbug_print(("simdis", "cond_wait woke up %d %d",
 807                             xx, fscache_object_p->i_simdis));
 808                 }
 809                 fscache_unlock(fscache_object_p);
 810 
 811                 if (fscache_object_p->i_tryunmount)
 812                         break;
 813 
 814                 /* see if the server is alive */
 815                 if (fscache_pingserver(fscache_object_p) == -1) {
 816                         /* dead server */
 817                         continue;
 818                 }
 819 
 820                 /* try to mount the back file system if needed */
 821                 if (fscache_object_p->i_backpath[0] == '\0') {
 822                         dbug_precond(fscache_object_p->i_cfsopt[0]);
 823                         dbug_precond(fscache_object_p->i_backfs[0]);
 824                         dbug_precond(fscache_object_p->i_mntpt[0]);
 825 
 826                         snprintf(cfsopt, sizeof (cfsopt), "%s,slide,remount",
 827                             fscache_object_p->i_cfsopt);
 828                         /*
 829                          * Mounting of a cachefs file system is done by calling
 830                          * out to /usr/lib/fs/cachefs/mount so that mounts
 831                          * done by the user, autofs and by us here in cachefsd
 832                          * are consistent.
 833                          */
 834                         switch ((child_pid = fork1())) {
 835                         case -1:
 836                                 /*
 837                                  * The original code used system()
 838                                  * but never checked for an error
 839                                  * occurring. The rest of the code
 840                                  * would suggest that "continue" is
 841                                  * the correct thing to do.
 842                                  */
 843                                 dbug_print(("info", "unable to fork mount "
 844                                     "process for back fs %s %d",
 845                                     fscache_object_p->i_backfs, errno));
 846                                 continue;
 847                         case 0:
 848                                 (void) setsid();
 849                                 execl("/usr/sbin/mount", "mount", "-F",
 850                                     "cachefs", "-o", cfsopt,
 851                                     fscache_object_p->i_backfs,
 852                                     fscache_object_p->i_mntpt, NULL);
 853                                 break;
 854                         default:
 855                                 (void) waitpid(child_pid, &stat_loc, WUNTRACED);
 856                         }
 857 
 858                 }
 859 
 860                 /* get the root fid of the file system */
 861                 xx = kmod_rootfid(kmod_object_p, &rootfid);
 862                 if (xx) {
 863                         dbug_print(("info", "could not mount back fs %s %d",
 864                             fscache_object_p->i_backfs, xx));
 865                         continue;
 866                 }
 867 
 868                 /* dummy up a fake kcred */
 869                 (void) memset(&cr, 0, sizeof (cr));
 870 
 871                 /* try to get attrs on the root */
 872                 xx = kmod_getattrfid(kmod_object_p, &rootfid, &cr, &va);
 873                 if ((xx == ETIMEDOUT) || (xx == EIO)) {
 874                         dbug_print(("info", "Bogus error %d", xx));
 875                         continue;
 876                 }
 877                 break;
 878         }
 879         dbug_leave("fscache_server_alive");
 880 }
 881 
 882 /*
 883  *                      fscache_pingserver
 884  *
 885  * Description:
 886  *      Trys to ping the nfs server to see if it is alive.
 887  * Arguments:
 888  * Returns:
 889  *      Returns 0 if it is alive, -1 if no answer.
 890  * Preconditions:
 891  */
 892 
 893 int
 894 fscache_pingserver(cfsd_fscache_object_t *fscache_object_p)
 895 {
 896 
 897         static struct timeval TIMEOUT = { 25, 0 };
 898         CLIENT *clnt;
 899         enum clnt_stat retval;
 900         int ret = 0;
 901         char hostname[sizeof (fscache_object_p->i_backfs)];
 902         char *cptr;
 903 
 904         dbug_enter("fscache_pingserver");
 905         dbug_precond(fscache_object_p);
 906 
 907         strlcpy(hostname, fscache_object_p->i_backfs, sizeof (hostname));
 908         if (cptr = strchr(hostname, ':'))
 909                 *cptr = '\0';
 910 
 911         dbug_assert(cptr != NULL);
 912         dbug_print(("info", "remote host '%s' before clnt_create", hostname));
 913 
 914         dbug_print(("info", "before clnt_create"));
 915         /* XXX this takes 75 seconds to time out */
 916         /* XXX should use lower level routines to reduce overhead */
 917         clnt = clnt_create(hostname, NFS_PROGRAM, NFS_VERSION, "udp");
 918         if (clnt == NULL) {
 919                 /* XXX what if this fails other than TIMEDOUT */
 920                 /* clnt_pcreateerror(hostname); */
 921                 dbug_print(("info", "clnt_create failed"));
 922                 ret = -1;
 923         } else {
 924                 dbug_print(("info", "before null rpc"));
 925                 /* XXX this takes 45 seconds to time out */
 926                 retval = clnt_call(clnt, 0, xdr_void, NULL, xdr_void, NULL,
 927                     TIMEOUT);
 928                 if (retval != RPC_SUCCESS) {
 929                         /* clnt_perror(clnt, "null rpc call failed"); */
 930                         dbug_print(("info", "null rpc call failed %d", retval));
 931                         ret = -1;
 932                 }
 933                 clnt_destroy(clnt);
 934         }
 935         dbug_leave("fscache_pingserver");
 936         return (ret);
 937 }
 938 
 939 /*
 940  *                      fscache_roll
 941  *
 942  * Description:
 943  *      Rolls the contents of the log to the server.
 944  * Arguments:
 945  *      kmodp   interface to kernel functions
 946  * Returns:
 947  *      Returns 0 for success or ETIMEDOUT if a timeout error occurred.
 948  * Preconditions:
 949  *      precond(kmodp)
 950  */
 951 int
 952 fscache_roll(cfsd_fscache_object_t *fscache_object_p,
 953         cfsd_kmod_object_t *kmod_object_p)
 954 {
 955         int error = 0;
 956         cfsd_logelem_object_t *logelem_object_p;
 957         char namebuf[MAXPATHLEN];
 958         char backupfile[MAXPATHLEN];
 959         int xx;
 960         cfs_dlog_entry_t *entp;
 961         off_t next_offset;
 962         ulong_t curseq = 0;
 963         int eof = 0;
 964         char *xp;
 965         cfsd_logfile_object_t *logfile_object_p;
 966         cfsd_maptbl_object_t *maptbl_object_p;
 967 
 968         dbug_enter("fscache_roll");
 969 
 970         dbug_precond(fscache_object_p);
 971         dbug_precond(kmod_object_p);
 972 
 973         /* map in the log file */
 974         logfile_object_p = cfsd_logfile_create();
 975 
 976         snprintf(namebuf, sizeof (namebuf), "%s/%s/%s",
 977             fscache_object_p->i_cachepath, fscache_object_p->i_name,
 978             CACHEFS_DLOG_FILE);
 979         xx = logfile_setup(logfile_object_p, namebuf, CFS_DLOG_ENTRY_MAXSIZE);
 980         if (xx) {
 981                 if (xx == ENOENT) {
 982                         cfsd_logfile_destroy(logfile_object_p);
 983                         dbug_leave("fscache_roll");
 984                         return (0);
 985                 }
 986                 fscache_fsproblem(fscache_object_p, kmod_object_p);
 987                 cfsd_logfile_destroy(logfile_object_p);
 988                 dbug_leave("fscache_roll");
 989                 return (0);
 990         }
 991 
 992         fscache_lock(fscache_object_p);
 993         fscache_changes(fscache_object_p, 1);
 994         fscache_unlock(fscache_object_p);
 995 
 996         /* create a hashed mapping table for changes to cids */
 997         maptbl_object_p = cfsd_maptbl_create();
 998         snprintf(namebuf, sizeof (namebuf), "%s/%s/%s",
 999             fscache_object_p->i_cachepath, fscache_object_p->i_name,
1000             CACHEFS_DMAP_FILE);
1001         xx = maptbl_setup(maptbl_object_p, namebuf);
1002         if (xx) {
1003                 fscache_fsproblem(fscache_object_p, kmod_object_p);
1004                 cfsd_logfile_destroy(logfile_object_p);
1005                 cfsd_maptbl_destroy(maptbl_object_p);
1006                 dbug_leave("fscache_roll");
1007                 return (0);
1008         }
1009 
1010         /*
1011          * lock is not needed because they are only used when
1012          * rolling the log by fscache_roll and fscache_addagain
1013          */
1014         fscache_object_p->i_again_offset = 0;
1015         fscache_object_p->i_again_seq = 0;
1016 
1017         /* Pass 1: collect all cid to fid mappings */
1018         next_offset = LOGFILE_ENTRY_START;
1019         for (;;) {
1020                 /* get a pointer to the next record */
1021                 xx = logfile_entry(logfile_object_p, next_offset, &entp);
1022                 if (xx == 1)
1023                         break;
1024                 if (xx == -1) {
1025                         fscache_fsproblem(fscache_object_p, kmod_object_p);
1026                         cfsd_logfile_destroy(logfile_object_p);
1027                         cfsd_maptbl_destroy(maptbl_object_p);
1028                         dbug_leave("fscache_roll");
1029                         return (0);
1030                 }
1031                 next_offset += entp->dl_len;
1032 
1033                 /* skip record if not valid */
1034                 if (entp->dl_valid != CFS_DLOG_VAL_COMMITTED)
1035                         continue;
1036 
1037                 /* create an object for the appropriate log type */
1038                 logelem_object_p = NULL;
1039                 switch (entp->dl_op) {
1040                 case CFS_DLOG_CREATE:
1041                 case CFS_DLOG_REMOVE:
1042                 case CFS_DLOG_LINK:
1043                 case CFS_DLOG_RENAME:
1044                 case CFS_DLOG_MKDIR:
1045                 case CFS_DLOG_RMDIR:
1046                 case CFS_DLOG_SYMLINK:
1047                 case CFS_DLOG_SETATTR:
1048                 case CFS_DLOG_SETSECATTR:
1049                 case CFS_DLOG_MODIFIED:
1050                 case CFS_DLOG_TRAILER:
1051                         break;
1052 
1053                 case CFS_DLOG_MAPFID:
1054                         dbug_print(("info", "mapfid"));
1055                         logelem_object_p = cfsd_logelem_mapfid_create(
1056                             maptbl_object_p, logfile_object_p,
1057                             kmod_object_p);
1058                         break;
1059 
1060                 default:
1061                         dbug_assert(0);
1062                         fscache_fsproblem(fscache_object_p, kmod_object_p);
1063                         break;
1064                 }
1065 
1066                 /* do not bother if ignoring the record */
1067                 if (logelem_object_p == NULL)
1068                         continue;
1069 
1070                 /* debuggging */
1071                 logelem_dump(logelem_object_p);
1072 
1073                 /* roll the entry */
1074                 xx = logelem_roll(logelem_object_p, (ulong_t *)NULL);
1075                 if (xx) {
1076                         fscache_fsproblem(fscache_object_p, kmod_object_p);
1077                         cfsd_logelem_destroy(logelem_object_p);
1078                         cfsd_maptbl_destroy(maptbl_object_p);
1079                         cfsd_logfile_destroy(logfile_object_p);
1080                         dbug_leave("fscache_roll");
1081                         return (0);
1082                 }
1083 
1084                 /* mark record as completed */
1085                 entp->dl_valid = CFS_DLOG_VAL_PROCESSED;
1086                 xx = logfile_sync(logfile_object_p);
1087                 if (xx) {
1088                         fscache_fsproblem(fscache_object_p, kmod_object_p);
1089                         cfsd_logelem_destroy(logelem_object_p);
1090                         cfsd_maptbl_destroy(maptbl_object_p);
1091                         cfsd_logfile_destroy(logfile_object_p);
1092                         dbug_leave("fscache_roll");
1093                         return (0);
1094                 }
1095 
1096                 /* destroy the object */
1097                 cfsd_logelem_destroy(logelem_object_p);
1098         }
1099 
1100         /* Pass 2: modify the back file system */
1101         next_offset = LOGFILE_ENTRY_START;
1102         for (;;) {
1103                 /* if we need the seq number of a deferred modify */
1104                 if (fscache_object_p->i_again_offset &&
1105                         (fscache_object_p->i_again_seq == 0)) {
1106 
1107                         /* get a pointer to the next record */
1108                         xx = logfile_entry(logfile_object_p,
1109                             fscache_object_p->i_again_offset, &entp);
1110                         if (xx == 1)
1111                                 break;
1112                         if (xx == -1) {
1113                                 fscache_fsproblem(fscache_object_p,
1114                                         kmod_object_p);
1115                                 cfsd_logfile_destroy(logfile_object_p);
1116                                 cfsd_maptbl_destroy(maptbl_object_p);
1117                                 dbug_leave("fscache_roll");
1118                                 return (0);
1119                         }
1120                         dbug_assert(entp->dl_op == CFS_DLOG_MODIFIED);
1121                         fscache_object_p->i_again_seq = entp->dl_seq;
1122                         dbug_assert(fscache_object_p->i_again_seq != 0);
1123                 }
1124 
1125                 /* get a pointer to the next record to process */
1126                 if (!eof) {
1127                         xx = logfile_entry(logfile_object_p, next_offset,
1128                             &entp);
1129                         if (xx == 1) {
1130                                 eof = 1;
1131                                 curseq = ULONG_MAX;
1132                         } else if (xx) {
1133                                 break;
1134                         } else {
1135                                 curseq = entp->dl_seq;
1136                         }
1137                 }
1138 
1139                 /* if its time to process a deferred modify entry */
1140                 if (fscache_object_p->i_again_seq &&
1141                     (eof || (fscache_object_p->i_again_seq < entp->dl_seq))) {
1142                         xx = logfile_entry(logfile_object_p,
1143                             fscache_object_p->i_again_offset, &entp);
1144                         if (xx)
1145                                 break;
1146                         dbug_assert(entp->dl_op == CFS_DLOG_MODIFIED);
1147                         curseq = entp->dl_seq;
1148                         fscache_object_p->i_again_offset =
1149                             entp->dl_u.dl_modify.dl_next;
1150                         fscache_object_p->i_again_seq = 0;
1151                         entp->dl_u.dl_modify.dl_next = -1;
1152                 } else if (eof) {
1153                         xx = 0;
1154                         break;
1155                 }
1156 
1157                 /* else move the offset to the next record */
1158                 else {
1159                         next_offset += entp->dl_len;
1160                 }
1161 
1162                 /* skip record if not valid */
1163                 if (entp->dl_valid != CFS_DLOG_VAL_COMMITTED)
1164                         continue;
1165 
1166                 /* process the record */
1167                 xx = fscache_rollone(fscache_object_p, kmod_object_p,
1168                     maptbl_object_p, logfile_object_p, curseq);
1169                 if (xx == ETIMEDOUT) {
1170                         /* timeout error, back to disconnected */
1171                         cfsd_maptbl_destroy(maptbl_object_p);
1172                         cfsd_logfile_destroy(logfile_object_p);
1173                         dbug_print(("info", "timeout error occurred"));
1174                         dbug_leave("fscache_roll");
1175                         return (xx);
1176                 } else if (xx == EIO) {
1177                         break;
1178                 } else if (xx == EAGAIN) {
1179                         continue;
1180                 } else if (xx) {
1181                         /* should never happen */
1182                         dbug_assert(0);
1183                         break;
1184                 } else {
1185                         /* mark record as completed */
1186                         entp->dl_valid = CFS_DLOG_VAL_PROCESSED;
1187                         xx = logfile_sync(logfile_object_p);
1188                         if (xx)
1189                                 break;
1190                 }
1191         }
1192 
1193         /* if an unrecoverable error occurred */
1194         if (xx) {
1195                 dbug_print(("error", "error processing log file"));
1196                 fscache_fsproblem(fscache_object_p, kmod_object_p);
1197         }
1198 
1199         /* dump stats about the hash table */
1200         maptbl_dumpstats(maptbl_object_p);
1201 
1202         /* dump stats about the log file */
1203         logfile_dumpstats(logfile_object_p);
1204 
1205         /* debugging hack, rename the log files */
1206 
1207         if (snprintf(namebuf, sizeof (namebuf), "%s/%s/%s",
1208             fscache_object_p->i_cachepath, fscache_object_p->i_name,
1209             CACHEFS_DLOG_FILE) > ((sizeof (backupfile)) - (sizeof (".bak")))) {
1210                 dbug_print(("error", "unable to create backup dlog_file "
1211                     "for %s, path name is too long", namebuf));
1212         } else {
1213                 /*
1214                  * No need to check return value from snprintf() as
1215                  * the previous check should suffice.
1216                  */
1217                 snprintf(backupfile, sizeof (backupfile), "%s.bak", namebuf);
1218                 if (rename(namebuf, backupfile) == -1) {
1219                         dbug_print(("error",
1220                             "unable to create backup dlog_file"));
1221                 }
1222         }
1223 
1224         if (snprintf(namebuf, sizeof (namebuf), "%s/%s/%s",
1225             fscache_object_p->i_cachepath, fscache_object_p->i_name,
1226             CACHEFS_DMAP_FILE) > ((sizeof (backupfile)) - (sizeof (".bak")))) {
1227                 dbug_print(("error", "unable to create backup dmap_file "
1228                     "for %s, path name is too long", namebuf));
1229         } else {
1230                 /*
1231                  * No need to check return value from snprintf() as
1232                  * the previous check should suffice.
1233                  */
1234                 snprintf(backupfile, sizeof (backupfile), "%s.bak", namebuf);
1235                 if (rename(namebuf, backupfile) == -1) {
1236                         dbug_print(("error",
1237                             "unable to create backup dmap_file"));
1238                 }
1239         }
1240 
1241         /* delete the log file */
1242         /* XXX */
1243 
1244         cfsd_maptbl_destroy(maptbl_object_p);
1245         cfsd_logfile_destroy(logfile_object_p);
1246         dbug_leave("fscache_roll");
1247         return (error);
1248 }
1249 
1250 /*
1251  *                      fscache_rollone
1252  *
1253  * Description:
1254  * Arguments:
1255  *      kmodp
1256  *      tblp
1257  *      lfp
1258  * Returns:
1259  *      Returns ...
1260  * Preconditions:
1261  *      precond(kmodp)
1262  *      precond(tblp)
1263  *      precond(lfp)
1264  */
1265 int
1266 fscache_rollone(cfsd_fscache_object_t *fscache_object_p,
1267         cfsd_kmod_object_t *kmod_object_p,
1268         cfsd_maptbl_object_t *maptbl_object_p,
1269         cfsd_logfile_object_t *logfile_object_p,
1270         ulong_t seq)
1271 {
1272         cfsd_logelem_object_t *logelem_object_p = NULL;
1273         cfs_dlog_entry_t *entp;
1274         int xx;
1275         char *strp;
1276 
1277         dbug_enter("fscache_rollone");
1278 
1279         dbug_precond(fscache_object_p);
1280         dbug_precond(kmod_object_p);
1281         dbug_precond(maptbl_object_p);
1282         dbug_precond(logfile_object_p);
1283 
1284         entp = logfile_object_p->i_cur_entry;
1285 
1286         /* create an object for the appropriate log type */
1287         switch (entp->dl_op) {
1288         case CFS_DLOG_CREATE:
1289                 dbug_print(("info", "create"));
1290                 logelem_object_p = cfsd_logelem_create_create(maptbl_object_p,
1291                     logfile_object_p, kmod_object_p);
1292                 break;
1293 
1294         case CFS_DLOG_REMOVE:
1295                 dbug_print(("info", "remove"));
1296                 logelem_object_p = cfsd_logelem_remove_create(maptbl_object_p,
1297                     logfile_object_p, kmod_object_p);
1298                 break;
1299 
1300         case CFS_DLOG_LINK:
1301                 dbug_print(("info", "link"));
1302                 logelem_object_p = cfsd_logelem_link_create(maptbl_object_p,
1303                     logfile_object_p, kmod_object_p);
1304                 break;
1305 
1306         case CFS_DLOG_RENAME:
1307                 dbug_print(("info", "rename"));
1308                 logelem_object_p = cfsd_logelem_rename_create(maptbl_object_p,
1309                     logfile_object_p, kmod_object_p);
1310                 break;
1311 
1312         case CFS_DLOG_MKDIR:
1313                 dbug_print(("info", "mkdir"));
1314                 logelem_object_p = cfsd_logelem_mkdir_create(maptbl_object_p,
1315                     logfile_object_p, kmod_object_p);
1316                 break;
1317 
1318         case CFS_DLOG_RMDIR:
1319                 dbug_print(("info", "rmdir"));
1320                 logelem_object_p = cfsd_logelem_rmdir_create(maptbl_object_p,
1321                     logfile_object_p, kmod_object_p);
1322                 break;
1323 
1324         case CFS_DLOG_SYMLINK:
1325                 dbug_print(("info", "symlink"));
1326                 logelem_object_p = cfsd_logelem_symlink_create(maptbl_object_p,
1327                     logfile_object_p, kmod_object_p);
1328                 break;
1329 
1330         case CFS_DLOG_SETATTR:
1331                 dbug_print(("info", "setattr"));
1332                 logelem_object_p = cfsd_logelem_setattr_create(maptbl_object_p,
1333                     logfile_object_p, kmod_object_p);
1334                 break;
1335 
1336         case CFS_DLOG_SETSECATTR:
1337                 dbug_print(("info", "setsecattr"));
1338                 logelem_object_p = cfsd_logelem_setsecattr_create(
1339                     maptbl_object_p, logfile_object_p, kmod_object_p);
1340                 break;
1341 
1342         case CFS_DLOG_MODIFIED:
1343                 dbug_print(("info", "modified"));
1344                 logelem_object_p = cfsd_logelem_modified_create(maptbl_object_p,
1345                     logfile_object_p, kmod_object_p);
1346                 break;
1347 
1348         case CFS_DLOG_MAPFID:
1349                 dbug_print(("info", "mapfid"));
1350                 break;
1351 
1352         case CFS_DLOG_TRAILER:
1353                 dbug_print(("info", "trailer"));
1354                 break;
1355 
1356         default:
1357                 dbug_assert(0);
1358                 dbug_leave("fscache_rollone");
1359                 return (EIO);
1360         }
1361 
1362         /* do not bother if ignoring the record */
1363         if (logelem_object_p == NULL) {
1364                 dbug_print(("info", "record ignored"));
1365                 dbug_leave("fscache_rollone");
1366                 return (0);
1367         }
1368 
1369         /* XXX debugging */
1370         logelem_dump(logelem_object_p);
1371 
1372         /* roll the entry */
1373         xx = logelem_roll(logelem_object_p, &seq);
1374 
1375         strp = logelem_object_p->i_messagep;
1376         if (strp) {
1377                 write(fscache_object_p->i_ofd, strp, strlen(strp));
1378                 dbug_print(("conflict", "%s", strp));
1379         }
1380 
1381         if (xx == EAGAIN) {
1382                 dbug_assert(entp->dl_op == CFS_DLOG_MODIFIED);
1383                 xx = fscache_addagain(fscache_object_p, logfile_object_p, seq);
1384                 if (xx == 0)
1385                         xx = EAGAIN;
1386         }
1387 
1388         /* destroy the object */
1389         cfsd_logelem_destroy(logelem_object_p);
1390 
1391         dbug_leave("fscache_rollone");
1392         return (xx);
1393 }
1394 
1395 /*
1396  *                      fscache_addagain
1397  *
1398  * Description:
1399  * Arguments:
1400  *      lfp
1401  * Returns:
1402  *      Returns ...
1403  * Preconditions:
1404  *      precond(lfp)
1405  */
1406 int
1407 fscache_addagain(cfsd_fscache_object_t *fscache_object_p,
1408         cfsd_logfile_object_t *logfile_object_p,
1409         ulong_t nseq)
1410 {
1411         int xx;
1412         cfs_dlog_entry_t *entp;
1413         off_t noffset;
1414         off_t prevoff = 0;
1415         off_t toff;
1416 
1417         dbug_enter("fscache_addagain");
1418 
1419         dbug_precond(fscache_object_p);
1420         dbug_precond(logfile_object_p);
1421 
1422         entp = logfile_object_p->i_cur_entry;
1423 
1424         noffset = logfile_object_p->i_cur_offset;
1425 
1426         dbug_assert(entp->dl_op == CFS_DLOG_MODIFIED);
1427         dbug_assert(nseq);
1428 
1429         /* both set or both zero */
1430         dbug_assert((!fscache_object_p->i_again_seq ^
1431             !fscache_object_p->i_again_offset) == 0);
1432 
1433         entp->dl_seq = nseq;
1434         /* simple case, first one on list */
1435         if ((fscache_object_p->i_again_seq == 0) ||
1436             (nseq < fscache_object_p->i_again_seq)) {
1437                 entp->dl_u.dl_modify.dl_next = fscache_object_p->i_again_offset;
1438                 fscache_object_p->i_again_seq = nseq;
1439                 fscache_object_p->i_again_offset = noffset;
1440                 dbug_leave("fscache_addagain");
1441                 return (0);
1442         }
1443 
1444         /* Search until we find the element on the list prior to the */
1445         /* insertion point. */
1446         for (toff = fscache_object_p->i_again_offset; toff != 0;
1447                 toff = entp->dl_u.dl_modify.dl_next) {
1448                 /* get pointer to next element on the list */
1449                 xx = logfile_entry(logfile_object_p, toff, &entp);
1450                 if (xx) {
1451                         dbug_leave("fscache_addagain");
1452                         return (xx);
1453                 }
1454                 dbug_assert(entp->dl_op == CFS_DLOG_MODIFIED);
1455 
1456                 /* done if we found the element after the insertion point */
1457                 if (nseq < entp->dl_seq)
1458                         break;
1459                 prevoff = toff;
1460         }
1461         dbug_assert(prevoff);
1462 
1463         /* get pointer to element prior to the insertion point */
1464         xx = logfile_entry(logfile_object_p, prevoff, &entp);
1465         if (xx) {
1466                 dbug_leave("fscache_addagain");
1467                 return (xx);
1468         }
1469         dbug_assert(entp->dl_op == CFS_DLOG_MODIFIED);
1470         dbug_assert(entp->dl_u.dl_modify.dl_next == toff);
1471 
1472         /* set element to point to our new element */
1473         entp->dl_u.dl_modify.dl_next = noffset;
1474 
1475         /* get pointer to our new element */
1476         xx = logfile_entry(logfile_object_p, noffset, &entp);
1477         if (xx) {
1478                 dbug_leave("fscache_addagain");
1479                 return (xx);
1480         }
1481         dbug_assert(entp->dl_op == CFS_DLOG_MODIFIED);
1482 
1483         /* set it to point to next link or end of list */
1484         entp->dl_u.dl_modify.dl_next = toff;
1485 
1486         /* return success */
1487         dbug_leave("fscache_addagain");
1488         return (0);
1489 }
1490 
1491 /*
1492  *                      fscache_fsproblem
1493  *
1494  * Description:
1495  * Arguments:
1496  *      kmodp
1497  * Returns:
1498  * Preconditions:
1499  *      precond(kmodp)
1500  */
1501 void
1502 fscache_fsproblem(cfsd_fscache_object_t *fscache_object_p,
1503         cfsd_kmod_object_t *kmod_object_p)
1504 {
1505 #if 0
1506         int xx;
1507 #endif
1508 
1509         dbug_enter("fscache_fsproblem");
1510 
1511         dbug_precond(fscache_object_p);
1512         dbug_precond(kmod_object_p);
1513 
1514 #if 0
1515         /* first try to put all modified files in lost+found */
1516         xx = kmod_lostfoundall(kmod_object_p);
1517         if (xx) {
1518                 /* if that failed, put file system in read-only mode */
1519                 kmod_rofs(kmod_object_p);
1520 #endif
1521                 fscache_lock(fscache_object_p);
1522                 fscache_object_p->i_disconnectable = 0;
1523                 fscache_object_p->i_modify++;
1524                 fscache_unlock(fscache_object_p);
1525 #if 0
1526         }
1527 #endif
1528         dbug_leave("fscache_fsproblem");
1529 }
1530 
1531 /*
1532  *                      fscache_changes
1533  *
1534  * Description:
1535  *      Used to specify whether or not there are changes to roll to the
1536  *      server.
1537  * Arguments:
1538  *      tt
1539  * Returns:
1540  * Preconditions:
1541  */
1542 void
1543 fscache_changes(cfsd_fscache_object_t *fscache_object_p, int tt)
1544 {
1545         dbug_enter("fscache_changes");
1546         dbug_precond(fscache_object_p);
1547         fscache_object_p->i_changes = tt;
1548         fscache_object_p->i_modify++;
1549         dbug_leave("fscache_changes");
1550 }