"Fossies" - the Fresh Open Source Software Archive

Member "coda-6.9.5/coda-src/venus/vol_cml.cc" (23 Mar 2010, 114501 Bytes) of package /linux/misc/old/coda-6.9.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "vol_cml.cc" see the Fossies "Dox" file reference documentation.

    1 /* BLURB gpl
    2 
    3                 Coda File System
    4                 Release 6
    5 
    6         Copyright (c) 1987-2008 Carnegie Mellon University
    7             Additional copyrights listed below
    8 
    9 This  code  is  distributed "AS IS" without warranty of any kind under
   10 the terms of the GNU General Public Licence Version 2, as shown in the
   11 file  LICENSE.  The  technical and financial  contributors to Coda are
   12 listed in the file CREDITS.
   13 
   14             Additional copyrights
   15                 none currently
   16 
   17 #*/
   18 
   19 /*
   20  *
   21  *    Implementation of Venus' Client Modify Log.
   22  *
   23  */
   24 
   25 
   26 #ifdef __cplusplus
   27 extern "C" {
   28 #endif
   29 
   30 #ifdef HAVE_CONFIG_H
   31 #include <config.h>
   32 #endif
   33 
   34 #include <stdio.h>
   35 #include <fcntl.h>
   36 #include "coda_string.h"
   37 #include <sys/types.h>
   38 #include <stdarg.h>
   39 #include <struct.h>
   40 
   41 #include <unistd.h>
   42 #include <stdlib.h>
   43 
   44 #include <netinet/in.h>
   45 
   46 #include <lwp/lock.h>
   47 #include <rpc2/rpc2.h>
   48 #include <rpc2/se.h>
   49 #include <rpc2/multi.h>
   50 
   51 /* from dir */
   52 #include <codadir.h>
   53 
   54 extern int get_len(ARG **, PARM **, MODE);
   55 extern int struct_len(ARG **, PARM **);
   56 extern void pack(ARG *, PARM **, PARM **);
   57 extern void pack_struct(ARG *, PARM **, PARM **);
   58 /* interfaces */
   59 #include <vice.h>   
   60 #include <cml.h>    
   61 
   62 #include "archive.h"
   63 
   64 #ifdef __cplusplus
   65 }
   66 #endif
   67 
   68 /* from util */
   69 #include <dlist.h>
   70 
   71 /* from venus */
   72 #include "comm.h"
   73 #include "fso.h"
   74 #include "local.h"
   75 #include "mariner.h"
   76 #include "mgrp.h"
   77 #include "venus.private.h"
   78 #include "venuscb.h"
   79 #include "venusvol.h"
   80 #include "vproc.h"
   81 #include "worker.h"
   82 
   83 static int RLE_Size(ARG * ...);
   84 static void RLE_Pack(PARM **, ARG * ...);
   85 
   86 int LogOpts = 1;    /* perform log optimizations? */
   87 int allow_backfetch;    /* allow backfetches during reintegration */
   88 
   89 /*  *****  Client Modify Log Basic Routines  *****  */
   90 
   91 void ClientModifyLog::ResetTransient()
   92 {
   93     owner = UNSET_UID;
   94     entries = count();
   95     entriesHighWater = entries;
   96     bytes = _bytes();
   97     bytesHighWater = bytes;
   98     cancelFrozenEntries = 0;
   99 
  100     if (count() > 0) {
  101     /* Schedule a transition (to Reintegrating or Emulating) if log is non-empty. */
  102     strbase(repvol, this, CML)->flags.transition_pending = 1;
  103 
  104     /* Set owner. */
  105     cml_iterator next(*this, CommitOrder);
  106     cmlent *m;
  107     while ((m = next())) {
  108         if (owner == UNSET_UID) {
  109         owner = m->uid;
  110         }
  111         else {
  112         CODA_ASSERT(owner == m->uid);
  113         }
  114 
  115         m->ResetTransient();
  116     }
  117     CODA_ASSERT(owner != UNSET_UID);
  118     }
  119 }
  120 
  121 
  122 /* MUST be called from within transaction! */
  123 void ClientModifyLog::Clear()
  124 {
  125     rec_dlink *d;
  126 
  127     while ((d = list.first()))
  128     delete strbase(cmlent, d, handle);
  129 }
  130 
  131 
  132 long ClientModifyLog::_bytes() {
  133     cml_iterator next(*this);
  134     cmlent *e;
  135     long result = 0;
  136 
  137     while ((e = next()))
  138     result += e->bytes();
  139 
  140     return result;
  141 }
  142 
  143 
  144 void ClientModifyLog::IncGetStats(cmlstats& current, cmlstats& cancelled, int tid) {
  145     /* First, compute current statistics. */
  146     cml_iterator next(*this, CommitOrder);
  147     cmlent *m;
  148     memset(&current, 0, sizeof(current));
  149     memset(&cancelled, 0, sizeof(cancelled));
  150     while ((m = next())) {
  151     if (tid != UNSET_TID && m->GetTid() != tid) continue;
  152     if (m->opcode == CML_Store_OP) {
  153         current.store_count++;
  154         current.store_size += m->bytes();
  155         current.store_contents_size += (float)m->u.u_store.Length;
  156     }
  157     else {
  158         current.other_count++;
  159         current.other_size += m->bytes();
  160     }
  161     }
  162 
  163     cancelled = cancellations;
  164 }
  165 
  166 
  167 /* 
  168  * called after a reintegration failure to remove cmlents that would
  169  * have been cancelled had reintegration not been in progress.
  170  * Unfreezes records; cancel requires this.  Since this routine is
  171  * called only if the failure involved receiving a response from the
  172  * server (i.e., outcome is known), it is safe to unfreeze the records.  
  173  */
  174 void ClientModifyLog::CancelPending() {
  175     Recov_BeginTrans();
  176     int cancellation;
  177     do {
  178         cancellation = 0;
  179         cml_iterator next(*this);
  180         cmlent *m;
  181 
  182         while ((m = next())) {
  183         if (m->flags.cancellation_pending) {
  184             m->Thaw();
  185         
  186             CODA_ASSERT(m->cancel());
  187             cancellation = 1;
  188             break;
  189         }
  190         }
  191 
  192     } while (cancellation);
  193     Recov_EndTrans(MAXFP);
  194 }
  195 
  196 /*
  197  * called after reintegration success to clear cancellations
  198  * pending failure.  this is necessary because records in 
  199  * the log tail (not involved in reintegration) may be marked.
  200  */
  201 void ClientModifyLog::ClearPending() {
  202     cml_iterator next(*this);
  203     cmlent *m;
  204 
  205     while ((m = next()))
  206     if (m->flags.cancellation_pending) {
  207         Recov_BeginTrans();
  208            RVMLIB_REC_OBJECT(m->flags);
  209            m->flags.cancellation_pending = 0;
  210         Recov_EndTrans(MAXFP);
  211     }
  212 }
  213 
  214 
  215 /* 
  216  * Scans the log, cancelling stores for open-for-write files. 
  217  * Note it might delete a record out from under itself.
  218  */
  219 void ClientModifyLog::CancelStores()
  220 {
  221     cmlent *m, *n;
  222     cml_iterator next(*this, CommitOrder);
  223 
  224     m = next(); n = next();
  225     while (m) {
  226     m->cancelstore();
  227     m = n; 
  228     n = next();
  229     }
  230 }
  231 
  232 /* MUST be called from within a transaction */
  233 int cmlent::Freeze()
  234 {
  235     int err;
  236 
  237     /* already frozen, nothing to do */
  238     if (flags.frozen) return 0;
  239 
  240     if (opcode == CML_Store_OP)
  241     {
  242     /* make sure there is only one object of the store */    
  243     CODA_ASSERT(fid_bindings->count() == 1); 
  244 
  245     dlink *d = fid_bindings->first();   /* and only */
  246     binding *b = strbase(binding, d, binder_handle);
  247     fsobj *f = (fsobj *)b->bindee;
  248 
  249     /* sanity checks, this better be an fso */
  250     CODA_ASSERT(f && (f->MagicNumber == FSO_MagicNumber));
  251 
  252     err = f->MakeShadow();
  253     if (err) return err;
  254     }
  255 
  256     RVMLIB_REC_OBJECT(flags);
  257     flags.frozen = 1;
  258 
  259     return 0;
  260 }
  261 
  262 /* MUST be called from within a transaction */
  263 void cmlent::Thaw()
  264 {
  265     if (!IsFrozen()) return;
  266 
  267     if (opcode == CML_Store_OP)
  268     {
  269     /* make sure there is only one object of the store */    
  270     CODA_ASSERT(fid_bindings->count() == 1); 
  271 
  272     dlink *d = fid_bindings->first();   /* and only */
  273     binding *b = strbase(binding, d, binder_handle);
  274     fsobj *f = (fsobj *)b->bindee;
  275 
  276     /* sanity checks, this better be an fso */
  277     CODA_ASSERT(f && (f->MagicNumber == FSO_MagicNumber));
  278 
  279     /* no need to unlock, just get rid of shadow copy */
  280     if (f->shadow)
  281         f->RemoveShadow();
  282     }
  283 
  284     RVMLIB_REC_OBJECT(flags);
  285     flags.frozen = 0;
  286 }
  287 
  288 /* 
  289  * Scan the log for reintegrateable records, subject to the
  290  * reintegration time limit, and mark them with the given
  291  * tid. Note the time limit does not apply to ASRs.
  292  * The routine returns the number of records marked.
  293  */
  294 int ClientModifyLog::GetReintegrateable(int tid, unsigned long *reint_time,
  295                     int *nrecs)
  296 {
  297     repvol *vol = strbase(repvol, this, CML);
  298     cmlent *m;
  299     cml_iterator next(*this, CommitOrder);
  300     unsigned long this_time;
  301     unsigned long bw; /* bandwidth in bytes/sec */
  302     int err;
  303     int done = 1;
  304 
  305     *nrecs = 0;
  306 
  307     /* get the current bandwidth estimate */
  308     vol->GetBandwidth(&bw);
  309 
  310     while ((m = next())) {
  311     /* do not pack stores if we want to avoid backfetches */
  312     /* this has to be matched by a similar (but inverse) test in
  313      * PartialReintegrate, otherwise we would never be able to
  314      * reintegrate the Store operation */
  315     if (!allow_backfetch && m->opcode == CML_Store_OP) {
  316         done = 0;
  317         break;
  318     }
  319 
  320     if (m->ReintReady() != 0)
  321         break;
  322 
  323     this_time = m->ReintTime(bw);
  324 
  325     /* Only limit reintegration time when we are not forcing a
  326      * synchronous reintegration and and we have at least
  327      * one CML entry queued. --JH */
  328     if (!vol->IsSync() && *nrecs && this_time > *reint_time)
  329         break;
  330 
  331     /*
  332      * freeze the record to prevent cancellation.  Note that
  333      * reintegrating --> frozen, but the converse is not true.
  334      * Records are frozen until the outcome of a reintegration
  335      * is known; this may span multiple reintegration attempts
  336      * and different transactions.
  337      */
  338     Recov_BeginTrans();
  339     err = m->Freeze();
  340     Recov_EndTrans(MAXFP);
  341     if (err) break;
  342 
  343     /*
  344      * don't use the settid call because it is transactional.
  345      * Here the tid is transient.
  346      */
  347     m->tid = tid;
  348     *reint_time -= this_time;
  349 
  350     /*
  351      * By sending records in blocks of 100 CMLentries, we avoid
  352      * overloading the server. JH
  353      */
  354     if (++(*nrecs) == 100) {
  355         done = 0;
  356         break;
  357     }
  358     }
  359 
  360     LOG(0, ("ClientModifyLog::GetReintegrateable: (%s, %d) %d records, %d msec remaining\n", vol->name, tid, *nrecs, *reint_time));
  361     return done;
  362 }
  363 
  364 
  365 /*
  366  * check if there is a fat store blocking the head of the log.
  367  * if there is, mark it with the tid and return a pointer to it.
  368  * Note with a less pretty interface this could be rolled into
  369  * the routine above.
  370  */
  371 cmlent *ClientModifyLog::GetFatHead(int tid)
  372 {
  373     repvol *vol = strbase(repvol, this, CML);
  374     cmlent *m;
  375     cml_iterator next(*this, CommitOrder);
  376     unsigned long bw; /* bandwidth in bytes/sec */
  377 
  378     /* Get the first entry in the CML */
  379     m = next();
  380 
  381     /* The head of the CML must exists, and be a store operation */
  382     if (!m || m->opcode != CML_Store_OP)
  383     return NULL;
  384 
  385     /* If we already have a reintegration handle, or if the reintegration time
  386      * exceeds the limit, we need to do a partial reintegration of the store.
  387      * We always partially reintegrate if we want to avoid backfetches. */
  388     if (allow_backfetch && !m->HaveReintegrationHandle())
  389     {
  390     /* get the current bandwidth estimate */
  391     vol->GetBandwidth(&bw);
  392     if (m->ReintTime(bw) <= vol->ReintLimit)
  393         return NULL;
  394     }
  395 
  396     /*
  397      * Don't use the settid call because it is transactional.
  398      * Here the tid is transient.
  399      */
  400     m->tid = tid;
  401 
  402     /*
  403      * freeze the record to prevent cancellation.  Note that
  404      * reintegrating --> frozen, but the converse is not true.
  405      * Records are frozen until the outcome of a reintegration
  406      * is known; this may span multiple reintegration attempts
  407      * and different transactions.
  408      */
  409     Recov_BeginTrans();
  410     CODA_ASSERT(m->Freeze() == 0);
  411     Recov_EndTrans(MAXFP);
  412 
  413     return m;
  414 }
  415 
  416 
  417 /*
  418  * Mark the offending mle designated by the index.
  419  * If the index is -1, something really bad happened.
  420  * in that case mark 'em all.
  421  */
  422 void ClientModifyLog::MarkFailedMLE(int ix)
  423 {
  424     repvol *vol = strbase(repvol, this, CML);
  425     int i = 0;
  426 
  427     cml_iterator next(*this);
  428     cmlent *m;
  429     while ((m = next()))
  430     if (m->tid == vol->cur_reint_tid)
  431       if (i++ == ix || ix == -1) {
  432         char path[MAXPATHLEN], opmsg[1024];
  433         fsobj *conflict;
  434 
  435         m->GetLocalOpMsg(opmsg);
  436 
  437         LOG(0, ("ClientModifyLog::MarkFailedMLE: failed reintegrating: %s\n", opmsg));
  438 
  439         CODA_ASSERT((conflict = FSDB->Find(&m->u.u_repair.Fid)));
  440         conflict->GetPath(path, 1);
  441         //      k_Purge(&conflict->pfid, 1);
  442         k_Purge(&m->u.u_repair.Fid, 0);
  443 
  444         m->flags.failed = 1;
  445 
  446         LOG(0, ("ClientModifyLog::MarkFailedMLE: %s(%s) now in local/global conflict\n", path, FID_(&m->u.u_repair.Fid)));
  447         MarinerLog("ClientModifyLog::CONFLICT (local/global): %s (%s)\n",
  448                path, FID_(&m->u.u_repair.Fid));
  449       }
  450 }
  451 
  452 
  453 /*
  454  * Mark the record with the matching storeid-uniquifier
  455  * as already having been committed at the server.
  456  */
  457 void ClientModifyLog::MarkCommittedMLE(RPC2_Unsigned Uniquifier)
  458 {
  459     repvol *vol = strbase(repvol, this, CML);
  460 
  461     cml_iterator next(*this);
  462     cmlent *m;
  463     while ((m = next())) 
  464     if (m->tid == vol->cur_reint_tid && 
  465         m->sid.Uniquifier == Uniquifier)
  466         m->flags.committed = 1;
  467 }
  468 
  469 /*
  470   failedmle - the entry point of handling reintegration failure or
  471   local-global conflicts
  472 */
  473 /* 
  474  * Handle a non-retryable failure.  The offending record
  475  * was marked and may or may not still be there. 
  476  * Note that an abort may delete a record out from under us.
  477  */
  478 void ClientModifyLog::HandleFailedMLE(void)
  479 {
  480     cmlent *m, *n;
  481     cml_iterator next(*this, CommitOrder);
  482 
  483     n = next();
  484     while ((m = n) != NULL) {
  485         n = next();
  486 
  487         if (!m->flags.failed)
  488           continue;
  489 
  490         m->flags.failed = 0;    /* only do this once */
  491         m->SetRepairFlag();
  492     }
  493 }
  494 
  495 
  496 void ClientModifyLog::print(int fd)
  497 {
  498     fdprint(fd, "\tClientModifyLog: owner = %d, count = %d\n",
  499          owner, count());
  500 
  501     cmlstats current, cancelled;
  502     IncGetStats(current, cancelled);
  503     fdprint(fd, "\t  current stats: %4d  %10.1f  %10.1f  %4d  %10.1f\n",
  504         current.store_count, current.store_size / 1024.0,
  505         current.store_contents_size / 1024.0,
  506         current.other_count, current.other_size / 1024.0);
  507     fdprint(fd, "\tcancelled stats: %4d  %10.1f  %10.1f  %4d  %10.1f\n",
  508         cancelled.store_count, cancelled.store_size / 1024.0,
  509         cancelled.store_contents_size / 1024.0,
  510         cancelled.other_count, cancelled.other_size / 1024.0);
  511 
  512     cml_iterator next(*this, CommitOrder);
  513     cmlent *m;
  514     while ((m = next()))
  515     if (m->tid != -1)
  516         m->print(fd);
  517 }
  518 
  519 
  520 /* MUST be called from within transaction! */
  521 void *cmlent::operator new(size_t len) {
  522     cmlent *c = 0;
  523 
  524     LOG(1, ("cmlent::operator new()\n"));
  525 
  526     CODA_ASSERT(VDB->AllocatedMLEs < VDB->MaxMLEs);
  527 
  528     /* Get entry from free list or heap */
  529     if (VDB->mlefreelist.count() > 0)
  530     c = strbase(cmlent, VDB->mlefreelist.get(), handle);
  531     else
  532     c = (cmlent *)rvmlib_rec_malloc((int) len);
  533     CODA_ASSERT(c);
  534 
  535     /* Do bookkeeping */
  536     RVMLIB_REC_OBJECT(VDB->AllocatedMLEs);
  537     VDB->AllocatedMLEs++;
  538 
  539     return(c);
  540 }
  541 
  542 
  543 /* MUST be called from within transaction! */
  544 cmlent::cmlent(ClientModifyLog *Log, time_t Mtime, uid_t Uid, int op, int prepend ...)
  545 {
  546     LOG(1, ("cmlent::cmlent(...)\n"));
  547     RVMLIB_REC_OBJECT(*this);
  548     RPC2_String name, newname;
  549 
  550     log = Log;
  551     this->tid = -1;
  552     flags.to_be_repaired = 0;
  553     flags.frozen = 0;
  554     flags.cancellation_pending = 0;
  555     flags.prepended = prepend;
  556     if (prepend) log->list.prepend(&handle);
  557     else     log->list.append(&handle);
  558 
  559     Recov_GenerateStoreId(&sid);
  560     time = Mtime;
  561     uid = Uid;
  562 
  563     opcode = op;
  564     name = newname = NULL;
  565     Name = NewName = NULL;
  566     va_list ap;
  567     va_start(ap, prepend);
  568     switch(op) {
  569     case CML_Store_OP:
  570         u.u_store.Fid = *va_arg(ap, VenusFid *);
  571         u.u_store.Length = va_arg(ap, RPC2_Unsigned);
  572         memset(&u.u_store.RHandle, 0, sizeof(ViceReintHandle));
  573         u.u_store.Offset = 0;
  574         u.u_store.ReintPH.s_addr = 0;
  575         u.u_store.ReintPHix = -1;
  576         break;
  577 
  578     case CML_Utimes_OP:
  579         u.u_utimes.Fid = *va_arg(ap, VenusFid *);
  580         u.u_utimes.Date = va_arg(ap, Date_t);
  581         break;
  582 
  583     case CML_Chown_OP:
  584         u.u_chown.Fid = *va_arg(ap, VenusFid *);
  585         u.u_chown.Owner = va_arg(ap, UserId);
  586         break;
  587 
  588     case CML_Chmod_OP:
  589         u.u_chmod.Fid = *va_arg(ap, VenusFid *);
  590         u.u_chmod.Mode = va_arg(ap, RPC2_Unsigned);
  591         break;
  592 
  593     case CML_Create_OP:
  594         u.u_create.PFid = *va_arg(ap, VenusFid *);
  595         name = va_arg(ap, RPC2_String);
  596         u.u_create.CFid = *va_arg(ap, VenusFid *);
  597         u.u_create.Mode = va_arg(ap, RPC2_Unsigned);
  598         Name = Copy_RPC2_String(name);
  599         break;
  600 
  601     case CML_Remove_OP:
  602         u.u_remove.PFid = *va_arg(ap, VenusFid *);
  603         name = va_arg(ap, RPC2_String);
  604         u.u_remove.CFid = *va_arg(ap, VenusFid *);
  605         u.u_remove.LinkCount = va_arg(ap, int);
  606         Name = Copy_RPC2_String(name);
  607         break;
  608 
  609     case CML_Link_OP:
  610         u.u_link.PFid = *va_arg(ap, VenusFid *);
  611         name = va_arg(ap, RPC2_String);
  612         u.u_link.CFid = *va_arg(ap, VenusFid *);
  613         Name = Copy_RPC2_String(name);
  614         break;
  615 
  616     case CML_Rename_OP:
  617         u.u_rename.SPFid = *va_arg(ap, VenusFid *);
  618         name = va_arg(ap, RPC2_String);
  619         u.u_rename.TPFid = *va_arg(ap, VenusFid *);
  620         newname = va_arg(ap, RPC2_String);
  621         u.u_rename.SFid = *va_arg(ap, VenusFid *);
  622         Name = Copy_RPC2_String(name);
  623         NewName = Copy_RPC2_String(newname);
  624         break;
  625 
  626     case CML_MakeDir_OP:
  627         u.u_mkdir.PFid = *va_arg(ap, VenusFid *);
  628         name = va_arg(ap, RPC2_String);
  629         u.u_mkdir.CFid = *va_arg(ap, VenusFid *);
  630         u.u_mkdir.Mode = va_arg(ap, RPC2_Unsigned);
  631         Name = Copy_RPC2_String(name);
  632         break;
  633 
  634     case CML_RemoveDir_OP:
  635         u.u_rmdir.PFid = *va_arg(ap, VenusFid *);
  636         name = va_arg(ap, RPC2_String);
  637         u.u_rmdir.CFid = *va_arg(ap, VenusFid *);
  638         Name = Copy_RPC2_String(name);
  639         break;
  640 
  641     case CML_SymLink_OP:
  642         u.u_symlink.PFid = *va_arg(ap, VenusFid *);
  643         newname = va_arg(ap, RPC2_String);
  644         name = va_arg(ap, RPC2_String);
  645         u.u_symlink.CFid = *va_arg(ap, VenusFid *);
  646         u.u_symlink.Mode = va_arg(ap, RPC2_Unsigned);
  647         NewName = Copy_RPC2_String(newname);
  648         Name = Copy_RPC2_String(name); // content
  649         break;
  650 
  651     case CML_Repair_OP:
  652         u.u_repair.Fid = *va_arg(ap, VenusFid *);
  653         u.u_repair.Length = va_arg(ap, RPC2_Unsigned);
  654         u.u_repair.Date = va_arg(ap, Date_t);
  655         u.u_repair.Owner = va_arg(ap, UserId);
  656         u.u_repair.Mode = va_arg(ap, RPC2_Unsigned);
  657         break;
  658 
  659     default:
  660         print(logFile);
  661         CHOKE("cmlent::cmlent: bogus opcode (%d)", op);
  662     }
  663     va_end(ap);
  664 
  665     ResetTransient();
  666 
  667     /* Attach to fsobj's.  */
  668     AttachFidBindings();
  669 
  670     /* Update statistics for this CML */
  671     log->entries++;
  672     if (log->entries > log->entriesHighWater)
  673     log->entriesHighWater = log->entries;
  674     log->bytes += bytes();
  675     if (log->bytes > log->bytesHighWater)
  676     log->bytesHighWater = log->bytes;
  677 
  678     LOG(1, ("cmlent::cmlent: tid = (%x.%d), uid = %d, op = %s\n",
  679         sid.Host, sid.Uniquifier, uid, PRINT_MLETYPE(op)));
  680 }
  681 
  682 
  683 void cmlent::ResetTransient()
  684 {
  685     fid_bindings = 0;
  686 
  687     pred = 0;
  688     succ = 0;
  689     
  690     flags.failed = 0;
  691     flags.committed = 0;
  692 
  693     expansions = 0;
  694 
  695     switch(opcode) {
  696     case CML_Store_OP:
  697         u.u_store.VV = NullVV;
  698         break;
  699 
  700         case CML_Truncate_OP:
  701         u.u_truncate.VV = NullVV;
  702         break;
  703 
  704     case CML_Utimes_OP:
  705         u.u_utimes.VV = NullVV;
  706         break;
  707 
  708     case CML_Chown_OP:
  709         u.u_chown.VV = NullVV;
  710         break;
  711 
  712     case CML_Chmod_OP:
  713         u.u_chmod.VV = NullVV;
  714         break;
  715 
  716     case CML_Create_OP:
  717         u.u_create.PVV = NullVV;
  718         break;
  719 
  720     case CML_Remove_OP:
  721         u.u_remove.PVV = NullVV;
  722         u.u_remove.CVV = NullVV;
  723         break;
  724 
  725     case CML_Link_OP:
  726         u.u_link.PVV = NullVV;
  727         u.u_link.CVV = NullVV;
  728         break;
  729 
  730     case CML_Rename_OP:
  731         u.u_rename.SPVV = NullVV;
  732         u.u_rename.TPVV = NullVV;
  733         u.u_rename.SVV = NullVV;
  734         break;
  735 
  736     case CML_MakeDir_OP:
  737         u.u_mkdir.PVV = NullVV;
  738         break;
  739 
  740     case CML_RemoveDir_OP:
  741         u.u_rmdir.PVV = NullVV;
  742         u.u_rmdir.CVV = NullVV;
  743         break;
  744 
  745     case CML_SymLink_OP:
  746         u.u_symlink.PVV = NullVV;
  747         break;
  748 
  749         case CML_Repair_OP:
  750         u.u_repair.OVV = NullVV;
  751         break;
  752 
  753     default:
  754         print(logFile);
  755         CHOKE("cmlent::ResetTransient: bogus opcode (%d)", opcode);
  756     }
  757 }
  758 
  759 
  760 /* MUST be called from within transaction! */
  761 cmlent::~cmlent() {
  762     LOG(1, ("cmlent::~cmlent: tid = (%x.%d), uid = %d, op = %s\n",
  763          sid.Host, sid.Uniquifier, uid, PRINT_MLETYPE(opcode)));
  764 
  765     RVMLIB_REC_OBJECT(*this);
  766     long thisBytes = bytes();
  767 
  768     /* or should we assert on this cmlent not being frozen? -JH */
  769     Thaw();
  770 
  771     /* Detach from fsobj's. */
  772     DetachFidBindings();
  773 
  774     /* Free strings. */
  775     if (Name) Free_RPC2_String(Name);
  776     if (NewName) Free_RPC2_String(NewName);
  777     Name = NewName = NULL;
  778 
  779     CODA_ASSERT(log->list.remove(&handle) == &handle);
  780     /* update CML statistics */
  781     log->entries--;
  782     log->bytes -= thisBytes;
  783 
  784     log = 0;
  785 }
  786 
  787 /* MUST be called from within transaction! */
  788 void cmlent::operator delete(void *deadobj) {
  789     cmlent *c = (cmlent *)deadobj;
  790 
  791     LOG(1, ("cmlent::operator delete()\n"));
  792 
  793     /* Stick on free list or give back to heap. */
  794     if (VDB->mlefreelist.count() < MLENTMaxFreeEntries)
  795     VDB->mlefreelist.append((rec_dlink *)&c->handle);
  796     else
  797     rvmlib_rec_free(deadobj);
  798 
  799     RVMLIB_REC_OBJECT(VDB->AllocatedMLEs);
  800     VDB->AllocatedMLEs--;
  801 }
  802 
  803 long cmlent::bytes()
  804 {
  805     long result = sizeof(*this);
  806 
  807     if (Name)    result += strlen((char *)Name);
  808     if (NewName) result += strlen((char *)NewName);
  809 
  810     return result;
  811 }
  812 
  813 
  814 #define PRINTVV(fd, vv)\
  815     fdprint((fd), "[ %d %d %d %d %d %d %d %d ] [ %d %d ] [ %#x ]",\
  816     (vv).Versions.Site0, (vv).Versions.Site1,\
  817     (vv).Versions.Site2, (vv).Versions.Site3,\
  818     (vv).Versions.Site4, (vv).Versions.Site5,\
  819     (vv).Versions.Site6, (vv).Versions.Site7,\
  820     (vv).StoreId.Host, (vv).StoreId.Uniquifier, (vv).Flags);
  821 
  822 
  823 /* local-repair modification */
  824 void cmlent::print(int afd) {
  825     fdprint(afd, "\t%s : sid = (%x.%d), time = %d, uid = %d tid = %d bytes = %d\n",
  826          PRINT_MLETYPE(opcode), sid.Host, sid.Uniquifier, time, uid, tid, bytes());
  827     fdprint(afd, "\t\tpred = (%x, %d), succ = (%x, %d)\n",
  828          pred, (pred == 0 ? 0 : pred->count()),
  829          succ, (succ == 0 ? 0 : succ->count()));
  830     fdprint(afd, "\t\tto_be_repaired = %d\n", flags.to_be_repaired);
  831     fdprint(afd, "\t\tfrozen = %d, cancel = %d, failed = %d, committed = %d\n", 
  832         flags.frozen, flags.cancellation_pending, flags.failed,
  833         flags.committed);
  834     switch(opcode) {
  835     case CML_Store_OP:
  836         fdprint(afd, "\t\tfid = %s, length = %d\n",
  837             FID_(&u.u_store.Fid), u.u_store.Length);
  838         fdprint(afd, "\t\tvv = ");
  839         PRINTVV(afd, u.u_store.VV);
  840         fdprint(afd, "\n\t\trhandle = (%d,%d,%d)",
  841             u.u_store.RHandle.BirthTime,
  842             u.u_store.RHandle.Device,
  843             u.u_store.RHandle.Inode);
  844         fdprint(afd, "\tph = %s (%d)",
  845             inet_ntoa(u.u_store.ReintPH), u.u_store.ReintPHix);
  846         fdprint(afd, "\n");
  847         break;
  848 
  849     case CML_Utimes_OP:
  850         fdprint(afd, "\t\tfid = %s, utimes = %d\n",
  851             FID_(&u.u_utimes.Fid), u.u_utimes.Date);
  852         fdprint(afd, "\t\tvv = ");
  853         PRINTVV(afd, u.u_utimes.VV);
  854         fdprint(afd, "\n");
  855         break;
  856 
  857     case CML_Chown_OP:
  858         fdprint(afd, "\t\tfid = %s, chown = %d\n",
  859             FID_(&u.u_chown.Fid), u.u_chown.Owner);
  860         fdprint(afd, "\t\tvv = ");
  861         PRINTVV(afd, u.u_chown.VV);
  862         fdprint(afd, "\n");
  863         break;
  864 
  865     case CML_Chmod_OP:
  866         fdprint(afd, "\t\tfid = %s, chmod = %o\n",
  867             FID_(&u.u_chmod.Fid), u.u_chmod.Mode);
  868         fdprint(afd, "\t\tvv = ");
  869         PRINTVV(afd, u.u_chmod.VV);
  870         fdprint(afd, "\n");
  871         break;
  872 
  873     case CML_Create_OP:
  874         fdprint(afd, "\t\tpfid = %s, name = (%s)\n",
  875             FID_(&u.u_create.PFid), Name);
  876         fdprint(afd, "\t\tcfid = %s, mode = %o\n",
  877             FID_(&u.u_create.CFid), u.u_create.Mode);
  878         fdprint(afd, "\t\tpvv = ");
  879         PRINTVV(afd, u.u_create.PVV);
  880         fdprint(afd, "\n");
  881         break;
  882 
  883     case CML_Remove_OP:
  884         fdprint(afd, "\t\tpfid = %s, name = (%s)\n",
  885             FID_(&u.u_remove.PFid), Name);
  886         fdprint(afd, "\t\tcfid = %s\n", FID_(&u.u_remove.CFid));
  887         fdprint(afd, "\t\tpvv = ");
  888         PRINTVV(afd, u.u_remove.PVV);
  889         fdprint(afd, "\n\t\tcvv = ");
  890         PRINTVV(afd, u.u_remove.CVV);
  891         fdprint(afd, "\n");
  892         break;
  893 
  894     case CML_Link_OP:
  895         fdprint(afd, "\t\tpfid = %s, name = (%s)\n",
  896             FID_(&u.u_link.PFid), Name);
  897         fdprint(afd, "\t\tcfid = %s\n", FID_(&u.u_link.CFid));
  898         fdprint(afd, "\t\tpvv = ");
  899         PRINTVV(afd, u.u_link.PVV);
  900         fdprint(afd, "\n");
  901         fdprint(afd, "\t\tcvv = ");
  902         PRINTVV(afd, u.u_link.CVV);
  903         fdprint(afd, "\n");
  904         break;
  905 
  906     case CML_Rename_OP:
  907         fdprint(afd, "\t\tspfid = %s, sname = (%s)\n",
  908             FID_(&u.u_rename.SPFid), Name);
  909         fdprint(afd, "\t\ttpfid = %s, tname = (%s)\n",
  910             FID_(&u.u_rename.TPFid), NewName);
  911         fdprint(afd, "\t\tsfid = %s\n", FID_(&u.u_rename.SFid));
  912         fdprint(afd, "\t\tspvv = ");
  913         PRINTVV(afd, u.u_rename.SPVV);
  914         fdprint(afd, "\n");
  915         fdprint(afd, "\t\ttpvv = ");
  916         PRINTVV(afd, u.u_rename.TPVV);
  917         fdprint(afd, "\n");
  918         fdprint(afd, "\t\tsvv = ");
  919         PRINTVV(afd, u.u_rename.SVV);
  920         fdprint(afd, "\n");
  921         break;
  922 
  923     case CML_MakeDir_OP:
  924         fdprint(afd, "\t\tpfid = %s, name = (%s)\n",
  925             FID_(&u.u_mkdir.PFid), Name);
  926         fdprint(afd, "\t\tcfid = %s, mode = %o\n",
  927             FID_(&u.u_mkdir.CFid), u.u_mkdir.Mode);
  928         fdprint(afd, "\t\tpvv = ");
  929         PRINTVV(afd, u.u_mkdir.PVV);
  930         fdprint(afd, "\n");
  931         break;
  932 
  933     case CML_RemoveDir_OP:
  934         fdprint(afd, "\t\tpfid = %s, name = (%s)\n",
  935             FID_(&u.u_rmdir.PFid), Name);
  936         fdprint(afd, "\t\tcfid = %s\n", FID_(&u.u_rmdir.CFid));
  937         fdprint(afd, "\t\tpvv = ");
  938         PRINTVV(afd, u.u_rmdir.PVV);
  939         fdprint(afd, "\n");
  940         fdprint(afd, "\t\tcvv = ");
  941         PRINTVV(afd, u.u_rmdir.CVV);
  942         fdprint(afd, "\n");
  943         break;
  944 
  945     case CML_SymLink_OP:
  946         fdprint(afd, "\t\tpfid = %s, name = (%s)\n",
  947             FID_(&u.u_symlink.PFid), NewName);
  948         fdprint(afd, "\t\tcfid = %s, contents = (%s), mode = %o\n",
  949             FID_(&u.u_symlink.CFid), Name, u.u_symlink.Mode);
  950         fdprint(afd, "\t\tpvv = ");
  951         PRINTVV(afd, u.u_symlink.PVV);
  952         fdprint(afd, "\n");
  953         break;
  954 
  955         case CML_Repair_OP:
  956         fdprint(afd, "\t\tfid = %s, Length = %u\n",
  957             FID_(&u.u_repair.Fid), u.u_repair.Length);
  958         fdprint(afd, "\t\tattrs=[%d %d %o]\n",
  959             u.u_repair.Date, u.u_repair.Owner, u.u_repair.Mode);
  960         fdprint(afd, "\t\tOVV = ");
  961         PRINTVV(afd, u.u_repair.OVV);
  962         fdprint(afd, "\n");
  963         break;
  964 
  965     default:
  966         fdprint(afd, "cmlent::print: bogus opcode (%d)", opcode);
  967         break;
  968     }
  969 }
  970 
  971 
  972 /*  *****  Client Modify Log Emulation Routines  *****  */
  973 
  974 /* There is a log routine corresponding to each of the (normal) mutating Vice
  975  * operations, {Store, Truncate, Utimes, Chown, Chmod, Create, Remove, Link,
  976  * Rename, Mkdir, Rmdir, Symlink}. Note that the only failure mode for these
  977  * routines is log space exhausted (ENOSPC). Each of these routines MUST be
  978  * called from within transaction! */
  979 
  980 /* local-repair modification */
  981 int repvol::LogStore(time_t Mtime, uid_t uid, VenusFid *Fid, RPC2_Unsigned
  982                      NewLength, int prepend)
  983 {
  984     LOG(1, ("repvol::LogStore: %d, %d, (%s), %d %d\n",
  985          Mtime, uid, FID_(Fid), NewLength, prepend));
  986 
  987     if (LogOpts && !prepend) {
  988     /* Cancel stores, as long as they are not followed by chowns. */
  989     /* Cancel utimes'. */
  990     int cancellation;
  991     do {
  992         cancellation = 0;
  993         cmlent *chown_mle = 0;
  994         cml_iterator next(CML, AbortOrder, Fid);
  995         cmlent *m;
  996         while (!cancellation && (m = next())) {
  997         switch(m->opcode) {
  998             case CML_Store_OP:
  999             if (chown_mle == 0) {
 1000                 cancellation = m->cancel();
 1001             }
 1002             break;
 1003 
 1004             case CML_Utimes_OP:
 1005             cancellation = m->cancel();
 1006             break;
 1007 
 1008             case CML_Chown_OP:
 1009             if (chown_mle == 0)
 1010                 chown_mle = m;
 1011             break;
 1012         }
 1013         }
 1014     } while (cancellation);
 1015     }
 1016 
 1017     cmlent *store_mle = new cmlent(&CML, Mtime, uid, CML_Store_OP, prepend, Fid, NewLength);
 1018     return(store_mle == 0 ? ENOSPC : 0);
 1019 }
 1020 
 1021 
 1022 /* local-repair modification */
 1023 int repvol::LogSetAttr(time_t Mtime, uid_t uid, VenusFid *Fid, RPC2_Unsigned
 1024                        NewLength, Date_t NewDate, UserId NewOwner,
 1025                        RPC2_Unsigned NewMode, int prepend)
 1026 {
 1027     /* Record a separate log entry for each attribute that is being set. */
 1028     if (NewLength != (RPC2_Unsigned)-1) {
 1029     int code = LogTruncate(Mtime, uid, Fid, NewLength, prepend);
 1030     if (code != 0) return(code);
 1031     }
 1032     if (NewDate != (Date_t)-1) {
 1033     int code = LogUtimes(Mtime, uid, Fid, NewDate, prepend);
 1034     if (code != 0) return(code);
 1035     }
 1036     if (NewOwner != (UserId)-1) {
 1037     int code = LogChown(Mtime, uid, Fid, NewOwner, prepend);
 1038     if (code != 0) return(code);
 1039     }
 1040     if (NewMode != (RPC2_Unsigned)-1) {
 1041     int code = LogChmod(Mtime, uid, Fid, NewMode, prepend);
 1042     if (code != 0) return(code);
 1043     }
 1044 
 1045     return(0);
 1046 }
 1047 
 1048 
 1049 /* local-repair modification */
 1050 int repvol::LogTruncate(time_t Mtime, uid_t uid, VenusFid *Fid, RPC2_Unsigned
 1051                         NewLength, int prepend)
 1052 {
 1053     LOG(1, ("repvol::LogTruncate: %d, %d, (%s), %d %d\n",
 1054          Mtime, uid, FID_(Fid), NewLength, prepend));
 1055 
 1056     /* Treat truncates as stores for now. -JJK */
 1057     return(LogStore(Mtime, uid, Fid, NewLength, prepend));
 1058 }
 1059 
 1060 
 1061 /* local-repair modification */
 1062 int repvol::LogUtimes(time_t Mtime, uid_t uid, VenusFid *Fid, Date_t NewDate,
 1063                       int prepend)
 1064 {
 1065     LOG(1, ("repvol::LogUtimes: %d, %d, (%s), %d %d\n",
 1066          Mtime, uid, FID_(Fid), NewDate, prepend));
 1067 
 1068     if (LogOpts && !prepend) {
 1069     int cancellation;
 1070     do {
 1071         cancellation = 0;
 1072         cml_iterator next(CML, AbortOrder, Fid);
 1073         cmlent *m;
 1074         while (!cancellation && (m = next())) {
 1075         switch(m->opcode) {
 1076             case CML_Utimes_OP:
 1077             cancellation = m->cancel();
 1078             break;
 1079         }
 1080         }
 1081     } while (cancellation);
 1082     }
 1083 
 1084     cmlent *utimes_mle = new cmlent(&CML, Mtime, uid, CML_Utimes_OP, prepend, Fid, NewDate);
 1085     return(utimes_mle == 0 ? ENOSPC : 0);
 1086 }
 1087 
 1088 
 1089 /* local-repair modification */
 1090 int repvol::LogChown(time_t Mtime, uid_t uid, VenusFid *Fid, UserId NewOwner,
 1091                      int prepend)
 1092 {
 1093     LOG(1, ("repvol::LogChown: %d, %d, (%s), %d %d\n",
 1094          Mtime, uid, FID_(Fid), NewOwner, prepend));
 1095 
 1096     if (LogOpts && !prepend) {
 1097     int cancellation;
 1098     do {
 1099         cancellation = 0;
 1100         cml_iterator next(CML, AbortOrder, Fid);
 1101         cmlent *m;
 1102         while (!cancellation && (m = next())) {
 1103         switch(m->opcode) {
 1104             case CML_Chown_OP:
 1105             cancellation = m->cancel();
 1106             break;
 1107         }
 1108         }
 1109     } while (cancellation);
 1110     }
 1111 
 1112     cmlent *chown_mle = new cmlent(&CML, Mtime, uid, CML_Chown_OP, prepend, Fid, NewOwner);
 1113     return(chown_mle == 0 ? ENOSPC : 0);
 1114 }
 1115 
 1116 
 1117 /* local-repair modification */
 1118 int repvol::LogChmod(time_t Mtime, uid_t uid, VenusFid *Fid,
 1119                      RPC2_Unsigned NewMode, int prepend)
 1120 {
 1121     LOG(1, ("repvol::LogChmod: %d, %d, (%s), %o %d\n",
 1122          Mtime, uid, FID_(Fid), NewMode, prepend));
 1123 
 1124     if (LogOpts && !prepend) {
 1125     int cancellation;
 1126     do {
 1127         cancellation = 0;
 1128         cmlent *store_mle = 0;
 1129         cml_iterator next(CML, AbortOrder, Fid);
 1130         cmlent *m;
 1131         while (!cancellation && (m = next())) {
 1132         switch(m->opcode) {
 1133             case CML_Store_OP:
 1134             if (store_mle == 0)
 1135                 store_mle = m;
 1136             break;
 1137 
 1138             case CML_Chmod_OP:
 1139             if (store_mle == 0) {
 1140                 cancellation = m->cancel();
 1141             }
 1142             break;
 1143         }
 1144         }
 1145     } while (cancellation);
 1146     }
 1147 
 1148     cmlent *chmod_mle = new cmlent(&CML, Mtime, uid, CML_Chmod_OP, prepend, Fid, NewMode);
 1149     return(chmod_mle == 0 ? ENOSPC : 0);
 1150 }
 1151 
 1152 
 1153 /* local-repair modification */
 1154 int repvol::LogCreate(time_t Mtime, uid_t uid, VenusFid *PFid, char *Name,
 1155                       VenusFid *CFid, RPC2_Unsigned Mode, int prepend)
 1156 {
 1157     LOG(1, ("repvol::LogCreate: %d, %d, (%s), %s, (%s), %o %d\n",
 1158          Mtime, uid, FID_(PFid), Name, FID_(CFid), Mode, prepend));
 1159 
 1160     cmlent *create_mle = new cmlent(&CML, Mtime, uid, CML_Create_OP, prepend,
 1161                      PFid, Name, CFid, Mode);
 1162     return(create_mle == 0 ? ENOSPC : 0);
 1163 }
 1164 
 1165 
 1166 /* local-repair modification */
 1167 int repvol::LogRemove(time_t Mtime, uid_t uid, VenusFid *PFid, char *Name,
 1168                       const VenusFid *CFid, int LinkCount, int prepend)
 1169 {
 1170     LOG(1, ("repvol::LogRemove: %d, %d, (%s), %s, (%s), %d %d\n",
 1171          Mtime, uid, FID_(PFid), Name, FID_(CFid), LinkCount, prepend));
 1172 
 1173     int ObjectCreated = 0;
 1174 
 1175     if (LogOpts && !prepend) {
 1176     if (LinkCount == 1) {
 1177         /* 
 1178          * if the object was created here, we may be able to do an 
 1179          * identity cancellation.  However, if the create is frozen,
 1180          * we cannot cancel records involved in an identity cancellation,
 1181          * because the create may have already become visible at the servers.
 1182          * Mark such records in case reintegration fails.  Records for which 
 1183          * this remove is an overwrite may be cancelled either way.  If they 
 1184          * are frozen cmlent::cancel does the right thing.
 1185          */
 1186         int CreateReintegrating = 0;
 1187         {
 1188         cml_iterator next(CML, CommitOrder, CFid);
 1189         cmlent *m = next();
 1190         if (m &&
 1191             (m->opcode == CML_Create_OP || m->opcode == CML_SymLink_OP))
 1192         {
 1193             ObjectCreated = 1;
 1194             if (m->IsFrozen() && !(m->IsToBeRepaired()))
 1195             CreateReintegrating = 1;
 1196                 }    
 1197 /*
 1198         if (ObjectCreated) {
 1199             int code = LogUtimes(Mtime, uid, PFid, Mtime);
 1200             if (code != 0) return(code);
 1201         }
 1202 */
 1203         }
 1204 
 1205         int cancellation;
 1206         do {
 1207         cancellation = 0;
 1208         cml_iterator next(CML, AbortOrder, CFid);
 1209         cmlent *m;
 1210         while (!cancellation && (m = next())) {
 1211             switch(m->opcode) {
 1212             case CML_Store_OP:
 1213             case CML_Utimes_OP:
 1214             case CML_Chown_OP:
 1215             case CML_Chmod_OP:
 1216                 cancellation = m->cancel();
 1217                 break;
 1218 
 1219             case CML_Create_OP:
 1220             case CML_Remove_OP:
 1221             case CML_Link_OP:
 1222             case CML_Rename_OP:
 1223                         case CML_SymLink_OP:
 1224                             if (ObjectCreated) {
 1225                                 if (CreateReintegrating) {
 1226                                     RVMLIB_REC_OBJECT(m->flags);
 1227                                     m->flags.cancellation_pending = 1;
 1228                                 } else
 1229                                     cancellation = m->cancel();
 1230                             }
 1231                             break;
 1232 
 1233                 case CML_Repair_OP:
 1234                 break;
 1235 
 1236             default:
 1237                 CODA_ASSERT(0);
 1238             }
 1239         }
 1240         } while (cancellation);
 1241 
 1242         if (ObjectCreated && !CreateReintegrating) {
 1243         int size = (int) (sizeof(cmlent) + strlen(Name));    
 1244 
 1245         LOG(0/*10*/, ("repvol::LogRemove: record cancelled, %s, size = %d\n", 
 1246                 Name, size));
 1247         CML.cancellations.other_count++;
 1248         CML.cancellations.other_size += size;
 1249         return(0);
 1250         }
 1251     }
 1252     }
 1253 
 1254     cmlent *unlink_mle = new cmlent(&CML, Mtime, uid, CML_Remove_OP, prepend,
 1255                      PFid, Name, CFid, LinkCount);
 1256     if (ObjectCreated && unlink_mle) {  /* must be reintegrating */
 1257     RVMLIB_REC_OBJECT(unlink_mle->flags);
 1258     unlink_mle->flags.cancellation_pending = 1;    
 1259     }
 1260 
 1261     return(unlink_mle == 0 ? ENOSPC : 0);
 1262 }
 1263 
 1264 
 1265 /* local-repair modification */
 1266 int repvol::LogLink(time_t Mtime, uid_t uid, VenusFid *PFid, char *Name,
 1267                     VenusFid *CFid, int prepend) {
 1268     LOG(1, ("repvol::LogLink: %d, %d, (%s), %s, (%s) %d\n",
 1269          Mtime, uid, FID_(PFid), Name, FID_(CFid), prepend));
 1270 
 1271     cmlent *link_mle = new cmlent(&CML, Mtime, uid, CML_Link_OP, prepend,
 1272                    PFid, Name, CFid);
 1273     return(link_mle == 0 ? ENOSPC : 0);
 1274 }
 1275 
 1276 
 1277 /* local-repair modification */
 1278 int repvol::LogRename(time_t Mtime, uid_t uid, VenusFid *SPFid,
 1279                       char *OldName, VenusFid *TPFid, char *NewName,
 1280                       VenusFid *SFid, const VenusFid *TFid, int LinkCount,
 1281               int prepend)
 1282 {
 1283     /* Record "target remove" as a separate log entry. */
 1284     if (!FID_EQ(TFid, &NullFid)) {
 1285     int code;
 1286     if (ISDIR(*TFid))
 1287         code = LogRmdir(Mtime, uid, TPFid, NewName, TFid, prepend);
 1288     else
 1289         code = LogRemove(Mtime, uid, TPFid, NewName, TFid, LinkCount, prepend);
 1290     if (code != 0) return(code);
 1291 
 1292     }
 1293 
 1294     LOG(1, ("repvol::LogRename: %d, %d, (%s), %s, (%s), %s, (%s) %d\n",
 1295          Mtime, uid, FID_(SPFid), OldName, FID_(TPFid), NewName,
 1296          FID_(SFid), prepend));
 1297 
 1298     cmlent *rename_mle = new cmlent(&CML, Mtime, uid, CML_Rename_OP, prepend,
 1299                      SPFid, OldName, TPFid, NewName, SFid);
 1300     return(rename_mle == 0 ? ENOSPC : 0);
 1301 }
 1302 
 1303 
 1304 /* local-repair modification */
 1305 int repvol::LogMkdir(time_t Mtime, uid_t uid, VenusFid *PFid, char *Name,
 1306                      VenusFid *CFid, RPC2_Unsigned Mode, int prepend)
 1307 {
 1308     LOG(1, ("repvol::LogMkdir: %d, %d, (%s), %s, (%s), %o %d\n",
 1309          Mtime, uid, FID_(PFid), Name, FID_(CFid), Mode, prepend));
 1310 
 1311     cmlent *mkdir_mle = new cmlent(&CML, Mtime, uid, CML_MakeDir_OP, prepend,
 1312                     PFid, Name, CFid, Mode);
 1313     return(mkdir_mle == 0 ? ENOSPC : 0);
 1314 }
 1315 
 1316 
 1317 /* local-repair modification */
 1318 int repvol::LogRmdir(time_t Mtime, uid_t uid, VenusFid *PFid, char *Name,
 1319                      const VenusFid *CFid, int prepend) {
 1320     LOG(0, ("repvol::LogRmdir: %d, %d, (%s), %s, (%s) %d\n",
 1321          Mtime, uid, FID_(PFid), Name, FID_(CFid), prepend));
 1322 
 1323     int ObjectCreated = 0;
 1324     int DependentChildren = 0;
 1325 
 1326     if (LogOpts && !prepend) {
 1327     int CreateReintegrating = 0;    /* see comments in LogRemove */
 1328     {
 1329         cml_iterator next(CML, CommitOrder, CFid);
 1330         cmlent *m = next();
 1331         if (m && m->opcode == CML_MakeDir_OP)
 1332         {
 1333         ObjectCreated = 1;
 1334         if (m->IsFrozen())
 1335             CreateReintegrating = 1;
 1336         }
 1337         if (ObjectCreated) {
 1338         cml_iterator next(CML, AbortOrder, CFid);
 1339         cmlent *m;
 1340         while ((m = next()) && !DependentChildren) {
 1341             switch(m->opcode) {
 1342             case CML_Create_OP:
 1343             case CML_Remove_OP:
 1344             case CML_Link_OP:
 1345             case CML_RemoveDir_OP:
 1346             case CML_SymLink_OP:
 1347                 DependentChildren = 1;
 1348                 break;
 1349 
 1350             case CML_Rename_OP:
 1351                 if (!FID_EQ(CFid, &m->u.u_rename.SFid))
 1352                 DependentChildren = 1;
 1353                 break;
 1354 
 1355             case CML_MakeDir_OP:
 1356                 if (FID_EQ(CFid, &m->u.u_mkdir.PFid))
 1357                 DependentChildren = 1;
 1358                 break;
 1359             }
 1360         }
 1361         }
 1362 /*
 1363         if (ObjectCreated && !DependentChildren) {
 1364         int code = LogUtimes(Mtime, uid, PFid, Mtime);
 1365         if (code != 0) return(code);
 1366         }
 1367 */
 1368     }
 1369 
 1370     int cancellation;
 1371     do {
 1372         cancellation = 0;
 1373         cml_iterator next(CML, AbortOrder, CFid);
 1374         cmlent *m;
 1375         while (!cancellation && (m = next())) {
 1376         switch(m->opcode) {
 1377             case CML_Utimes_OP:
 1378             case CML_Chown_OP:
 1379             case CML_Chmod_OP:
 1380             cancellation = m->cancel();
 1381             break;
 1382 
 1383             case CML_Create_OP:
 1384             case CML_Remove_OP:
 1385             case CML_Link_OP:
 1386             case CML_Rename_OP:
 1387             case CML_MakeDir_OP:
 1388             case CML_RemoveDir_OP:
 1389                     case CML_SymLink_OP:
 1390                         if (ObjectCreated && !DependentChildren) {
 1391 #if 0 /* XXX: won't get optimized on reintegration conflict, cant repair! */
 1392                             if (CreateReintegrating) {
 1393                                 RVMLIB_REC_OBJECT(m->flags);
 1394                                 m->flags.cancellation_pending = 1;
 1395                             } else
 1396 #endif
 1397                                 cancellation = m->cancel();
 1398                         }
 1399                         break;
 1400 
 1401             case CML_Repair_OP:
 1402             break;
 1403 
 1404             default:
 1405             CODA_ASSERT(0);
 1406         }
 1407         }
 1408     } while (cancellation);
 1409 
 1410     if (ObjectCreated && !DependentChildren && !CreateReintegrating) {
 1411         int size = (int) (sizeof(cmlent) + strlen(Name));    
 1412 
 1413         LOG(0/*10*/, ("repvol::LogRmdir: record cancelled, %s, size = %d\n", 
 1414                 Name, size));
 1415 
 1416         CML.cancellations.other_count++;
 1417         CML.cancellations.other_size += size;
 1418         return(0);
 1419     }
 1420     }
 1421 
 1422     cmlent *rmdir_mle = new cmlent(&CML, Mtime, uid, CML_RemoveDir_OP, prepend,
 1423                     PFid, Name, CFid);
 1424 
 1425     if (ObjectCreated && !DependentChildren && rmdir_mle) {
 1426     RVMLIB_REC_OBJECT(rmdir_mle->flags);
 1427     rmdir_mle->flags.cancellation_pending = 1;
 1428     }
 1429     return(rmdir_mle == 0 ? ENOSPC : 0);
 1430 }
 1431 
 1432 
 1433 /* local-repair modification */
 1434 int repvol::LogSymlink(time_t Mtime, uid_t uid, VenusFid *PFid,
 1435                        char *Name, char *Contents, VenusFid *CFid,
 1436                        RPC2_Unsigned Mode, int prepend)
 1437 {
 1438     LOG(1, ("repvol::LogSymlink: %d, %d, (%s), %s, %s, (%s), %o %d\n",
 1439         Mtime, uid, FID_(PFid), Name, Contents, FID_(CFid), Mode, prepend));
 1440 
 1441     cmlent *symlink_mle = new cmlent(&CML, Mtime, uid, CML_SymLink_OP, prepend,
 1442                       PFid, Name, Contents, CFid, Mode);
 1443     return(symlink_mle == 0 ? ENOSPC : 0);
 1444 }
 1445 
 1446 /* local-repair modification */
 1447 int repvol::LogRepair(time_t Mtime, uid_t uid, VenusFid *Fid,
 1448                       RPC2_Unsigned Length, Date_t Date, UserId Owner,
 1449                       RPC2_Unsigned Mode, int prepend)
 1450 {
 1451     LOG(1, ("repvol::LogRepair: %d %d (%s) attrs [%u %d %u %o] %d\n",
 1452         Mtime, uid, FID_(Fid), Length, Date, Owner, Mode, prepend));
 1453 
 1454     cmlent *repair_mle = new cmlent(&CML, Mtime, uid, CML_Repair_OP, prepend,
 1455                     Fid, Length, Date, Owner, Mode, prepend);
 1456     return(repair_mle == 0 ? ENOSPC : 0);
 1457 }
 1458 
 1459 /* restore ``old values'' for attributes in fsobj. */
 1460 /* call from within a transaction. */
 1461 void repvol::RestoreObj(VenusFid *Fid)
 1462 {
 1463     fsobj *f = FSDB->Find(Fid);
 1464 
 1465     /* Length attribute. */
 1466     unsigned long Length = 0;
 1467     cmlent *lwriter = CML.LengthWriter(Fid);
 1468     if (!lwriter) {
 1469     FSO_ASSERT(f, f->CleanStat.Length != (unsigned long)-1);
 1470     Length = f->CleanStat.Length;
 1471     }
 1472     else {
 1473     VOL_ASSERT(this, lwriter->opcode == CML_Store_OP);
 1474     Length = lwriter->u.u_store.Length;
 1475     }
 1476     if (Length != f->stat.Length) {
 1477     RVMLIB_REC_OBJECT(f->stat.Length);
 1478     f->stat.Length = Length;
 1479     }
 1480 
 1481     /* Mtime attribute. */
 1482     Date_t Utimes;
 1483     cmlent *uwriter = CML.UtimesWriter(Fid);
 1484     if (uwriter == 0) {
 1485     FSO_ASSERT(f, f->CleanStat.Date != (Date_t)-1);
 1486     Utimes = f->CleanStat.Date;
 1487     }
 1488     else {
 1489     switch(uwriter->opcode) {
 1490         case CML_Store_OP:
 1491         case CML_Create_OP:
 1492         case CML_MakeDir_OP:
 1493         case CML_SymLink_OP:
 1494         case CML_Repair_OP:
 1495         case CML_Remove_OP:
 1496         case CML_Link_OP:
 1497         case CML_Rename_OP:
 1498         case CML_RemoveDir_OP:
 1499         Utimes = uwriter->time;
 1500         break;
 1501 
 1502         case CML_Utimes_OP:
 1503         Utimes = uwriter->u.u_utimes.Date;
 1504         break;
 1505 
 1506         default:
 1507         Utimes = (Date_t)-1;
 1508         VOL_ASSERT(this, 0);
 1509     }
 1510     }
 1511     if (Utimes != f->stat.Date) {
 1512     RVMLIB_REC_OBJECT(f->stat.Date);
 1513     f->stat.Date = Utimes;
 1514     }
 1515 }
 1516 
 1517 
 1518 cmlent *ClientModifyLog::LengthWriter(VenusFid *Fid) {
 1519     cml_iterator next(*this, AbortOrder, Fid);
 1520     cmlent *m;
 1521     while ((m = next())) {
 1522     if (m->opcode == CML_Store_OP || m->opcode == CML_Repair_OP)
 1523         return(m);
 1524     }
 1525 
 1526     /* Not found. */
 1527     return(0);
 1528 }
 1529 
 1530 
 1531 cmlent *ClientModifyLog::UtimesWriter(VenusFid *Fid) {
 1532     cml_iterator next(*this, AbortOrder, Fid);
 1533     cmlent *m;
 1534     while ((m = next())) {
 1535     switch(m->opcode) {
 1536         case CML_Store_OP:
 1537         case CML_Utimes_OP:
 1538         case CML_Create_OP:
 1539         case CML_MakeDir_OP:
 1540         case CML_SymLink_OP:
 1541         case CML_Repair_OP:
 1542         return(m);
 1543 
 1544         case CML_Remove_OP:
 1545         if (FID_EQ(Fid, &m->u.u_remove.PFid))
 1546             return(m);
 1547         break;
 1548 
 1549         case CML_Link_OP:
 1550         if (FID_EQ(Fid, &m->u.u_link.PFid))
 1551             return(m);
 1552         break;
 1553 
 1554         case CML_Rename_OP:
 1555         if (FID_EQ(Fid, &m->u.u_rename.SPFid) ||
 1556             FID_EQ(Fid, &m->u.u_rename.TPFid))
 1557             return(m);
 1558         break;
 1559 
 1560         case CML_RemoveDir_OP:
 1561         if (FID_EQ(Fid, &m->u.u_rmdir.PFid))
 1562             return(m);
 1563         break;
 1564 
 1565         default:
 1566         break;
 1567     }
 1568     }
 1569 
 1570     /* Not found. */
 1571     return(0);
 1572 }
 1573 
 1574 
 1575 /* local-repair modification */
 1576 /* MUST be called from within transaction! */
 1577 /* returns 1 if record was actually removed from log, 0 if not. */
 1578 int cmlent::cancel()
 1579 {
 1580     time_t curTime = Vtime();
 1581 
 1582     if (IsToBeRepaired()) {
 1583     if (log->cancelFrozenEntries && IsFrozen()) {
 1584         LOG(0, ("cmlent::cancel: frozen cmlent with local fid, thawing and cancelling\n"));
 1585         Thaw();
 1586     }
 1587     else {
 1588         LOG(0, ("cmlent::cancel: to_be_repaired cmlent, skip\n"));
 1589         return 0;
 1590     }
 1591     }
 1592 
 1593     /* 
 1594      * If this record is being reintegrated, just mark it for
 1595      * cancellation and we'll get to it later.
 1596      */
 1597     if (IsFrozen()) {
 1598         LOG(0, ("cmlent::cancel: cmlent frozen, skip\n"));
 1599         RVMLIB_REC_OBJECT(flags);   /* called from within transaction */
 1600         flags.cancellation_pending = 1;
 1601         return 0;
 1602     }
 1603 
 1604     LOG(10, ("cmlent::cancel: age = %d\n", curTime-time));
 1605     if (LogLevel >= 10) print(logFile);
 1606 
 1607     /* Parameters for possible utimes to be done AFTER cancelling this record. */
 1608     int DoUtimes = 0;
 1609     uid_t UtimesVuid;
 1610     VenusFid UtimesFid;
 1611     Date_t UtimesMtime;
 1612 
 1613     switch(opcode) {
 1614     case CML_Store_OP:
 1615         {
 1616         /* Cancelling store may permit cancellation of earlier chmod. */
 1617 
 1618         cmlent *pre_chmod_mle = 0;
 1619         cmlent *post_chmod_mle = 0;
 1620 
 1621         {
 1622         cml_iterator next(*(ClientModifyLog *)log, CommitOrder, &u.u_store.Fid, this);
 1623         cmlent *m;
 1624         while ((m = next())) {
 1625             if (m->opcode == CML_Chmod_OP) {
 1626                 post_chmod_mle = m;
 1627                 break;
 1628             }
 1629         }
 1630         }
 1631 
 1632         if (post_chmod_mle) {
 1633         cml_iterator next(*(ClientModifyLog *)log, AbortOrder, &u.u_store.Fid, this);
 1634         cmlent *m;
 1635         while ((m = next())) {
 1636             if (m->opcode == CML_Chmod_OP) {
 1637                 pre_chmod_mle = m;
 1638                 break;
 1639             }
 1640         }
 1641         }
 1642 
 1643         if (pre_chmod_mle && post_chmod_mle)
 1644         pre_chmod_mle->cancel();
 1645         }
 1646         break;
 1647 
 1648     case CML_Chown_OP:
 1649         {
 1650         /* Cancelling chown may permit cancellation of earlier store. */
 1651 
 1652         cmlent *pre_store_mle = 0;
 1653         cmlent *post_store_mle = 0;
 1654 
 1655         {
 1656         cml_iterator next(*(ClientModifyLog *)log, CommitOrder, &u.u_chown.Fid, this);
 1657         cmlent *m;
 1658         while ((m = next())) {
 1659             if (m->opcode == CML_Store_OP) {
 1660                 post_store_mle = m;
 1661                 break;
 1662             }
 1663         }
 1664         }
 1665 
 1666         if (post_store_mle) {
 1667         cml_iterator next(*(ClientModifyLog *)log, AbortOrder, &u.u_chown.Fid, this);
 1668         cmlent *m;
 1669         while ((m = next())) {
 1670             if (m->opcode == CML_Store_OP) {
 1671                 pre_store_mle = m;
 1672                 break;
 1673             }
 1674         }
 1675         }
 1676 
 1677         if (pre_store_mle && post_store_mle)
 1678         (void) pre_store_mle->cancel();
 1679         }
 1680         break;
 1681 
 1682     case CML_Create_OP:
 1683         {
 1684         cmlent *m = ((ClientModifyLog *)log)->UtimesWriter(&u.u_create.PFid);
 1685         CODA_ASSERT(m != 0);
 1686         if (m != this) {
 1687         DoUtimes = 1;
 1688         UtimesVuid = uid;
 1689         UtimesFid = u.u_create.PFid;
 1690         UtimesMtime = time;
 1691         }
 1692         }
 1693         break;
 1694 
 1695     case CML_Remove_OP:
 1696         {
 1697         cmlent *m = ((ClientModifyLog *)log)->UtimesWriter(&u.u_remove.PFid);
 1698         CODA_ASSERT(m != 0);
 1699         if (m != this) {
 1700         DoUtimes = 1;
 1701         UtimesVuid = uid;
 1702         UtimesFid = u.u_remove.PFid;
 1703         UtimesMtime = time;
 1704         }
 1705         }
 1706         break;
 1707 
 1708     case CML_Link_OP:
 1709         {
 1710         cmlent *m = ((ClientModifyLog *)log)->UtimesWriter(&u.u_link.PFid);
 1711         CODA_ASSERT(m != 0);
 1712         if (m != this) {
 1713         DoUtimes = 1;
 1714         UtimesVuid = uid;
 1715         UtimesFid = u.u_link.PFid;
 1716         UtimesMtime = time;
 1717         }
 1718         }
 1719         break;
 1720 
 1721     case CML_Rename_OP:
 1722         {
 1723         cmlent *m = ((ClientModifyLog *)log)->UtimesWriter(&u.u_rename.SPFid);
 1724         CODA_ASSERT(m != 0);
 1725         if (m != this) {
 1726         DoUtimes = 1;
 1727         UtimesVuid = uid;
 1728         UtimesFid = u.u_rename.SPFid;
 1729         UtimesMtime = time;
 1730         }
 1731 
 1732         if (!FID_EQ(&u.u_rename.SPFid, &u.u_rename.TPFid)) {
 1733         cmlent *m = ((ClientModifyLog *)log)->UtimesWriter(&u.u_rename.TPFid);
 1734         CODA_ASSERT(m != 0);
 1735 #if 0
 1736         if (m != this) {
 1737             /* Don't get uptight if this can't be done! */
 1738             repvol *vol = strbase(repvol, log, CML);
 1739             (void)vol->LogUtimes(time, uid, &u.u_rename.TPFid, time);
 1740         }
 1741 #endif
 1742         }
 1743         }
 1744         break;
 1745 
 1746     case CML_MakeDir_OP:
 1747       {
 1748         cmlent *pre_store_mle = 0;
 1749         cmlent *post_store_mle = 0;
 1750 
 1751         {
 1752           cml_iterator next(*(ClientModifyLog *)log, CommitOrder, &u.u_chown.Fid, this);
 1753           cmlent *m;
 1754           while ((m = next())) {
 1755         if (m->opcode == CML_Store_OP) {
 1756           post_store_mle = m;
 1757           break;
 1758         }
 1759           }
 1760         }
 1761 
 1762         if (post_store_mle) {
 1763           cml_iterator next(*(ClientModifyLog *)log, AbortOrder, &u.u_chown.Fid, this);
 1764           cmlent *m;
 1765           while ((m = next())) {
 1766         if (m->opcode == CML_Store_OP) {
 1767           pre_store_mle = m;
 1768           break;
 1769         }
 1770           }
 1771         }
 1772 
 1773         if (pre_store_mle && post_store_mle)
 1774           (void) pre_store_mle->cancel();
 1775       }
 1776       break;
 1777 
 1778     case CML_RemoveDir_OP:
 1779         {
 1780         cmlent *m = ((ClientModifyLog *)log)->UtimesWriter(&u.u_rmdir.PFid);
 1781         CODA_ASSERT(m != 0);
 1782         if (m != this) {
 1783         DoUtimes = 1;
 1784         UtimesVuid = uid;
 1785         UtimesFid = u.u_rmdir.PFid;
 1786         UtimesMtime = time;
 1787         }
 1788         }
 1789         break;
 1790 
 1791     case CML_SymLink_OP:
 1792         {
 1793         cmlent *m = ((ClientModifyLog *)log)->UtimesWriter(&u.u_symlink.PFid);
 1794         CODA_ASSERT(m != 0);
 1795         if (m != this) {
 1796         DoUtimes = 1;
 1797         UtimesVuid = uid;
 1798         UtimesFid = u.u_symlink.PFid;
 1799         UtimesMtime = time;
 1800         }
 1801         }
 1802         break;
 1803 
 1804         case CML_Repair_OP:
 1805         CODA_ASSERT(0);
 1806         break;
 1807     }
 1808 
 1809     if (opcode == CML_Store_OP) {
 1810     log->cancellations.store_count++;
 1811     log->cancellations.store_size += bytes();
 1812     log->cancellations.store_contents_size += u.u_store.Length;
 1813     }
 1814     else {
 1815     log->cancellations.other_count++;
 1816     log->cancellations.other_size += bytes();
 1817     }
 1818 
 1819     repvol *vol = strbase(repvol, log, CML);
 1820     vol->RecordsCancelled++;
 1821     delete this;
 1822 
 1823 #if 0
 1824     if (DoUtimes) {
 1825     int code = vol->LogUtimes(UtimesMtime, UtimesVuid, &UtimesFid, UtimesMtime);
 1826     CODA_ASSERT(code == 0);
 1827         vol->RecordsCancelled--;
 1828     }
 1829 #endif
 1830     return 1;
 1831 }
 1832 
 1833 
 1834 /* 
 1835  * If this record is a store corresponding to an open-for-write file,
 1836  * cancel it and restore the object's attributes to their old values.
 1837  */
 1838 int cmlent::cancelstore()
 1839 {
 1840     int cancelled = 0;
 1841     repvol *vol = strbase(repvol, log, CML);
 1842 
 1843     if (opcode == CML_Store_OP) {
 1844     dlink *d = fid_bindings->first();   /* and only */
 1845     binding *b = strbase(binding, d, binder_handle);
 1846     fsobj *f = (fsobj *)b->bindee;
 1847 
 1848     if (WRITING(f)) {
 1849         Recov_BeginTrans();
 1850         /* we could be partial/trickle reintegrating, so cancel may fail */
 1851         if (cancel())
 1852         vol->RestoreObj(&f->fid);
 1853         Recov_EndTrans(MAXFP);
 1854         cancelled = 1;
 1855     }
 1856     }
 1857     return cancelled;
 1858 }
 1859 
 1860 
 1861 /*  *****  Client Modify Log Reintegration Routines  *****  */
 1862 
 1863 /* must not be called from within a transaction */
 1864 /* Add timing and statistics gathering! */
 1865 int ClientModifyLog::IncReallocFids(int tid)
 1866 {
 1867     repvol *vol = strbase(repvol, this, CML);
 1868     LOG(1, ("ClientModifyLog::IncReallocFids: (%s) and tid = %d\n", 
 1869         vol->name, tid));
 1870 
 1871     int code = 0;
 1872     cml_iterator next(*this, CommitOrder);
 1873     cmlent *m;
 1874     while ((m = next())) {
 1875     if (m->GetTid() == tid)
 1876       code = m->realloc();
 1877     if (code != 0) break;
 1878     }
 1879     LOG(0, ("ClientModifyLog::IncReallocFids: (%s)\n", vol->name));
 1880     return(code);
 1881 }
 1882 
 1883 
 1884 /* MUST be called from within transaction! */
 1885 void ClientModifyLog::TranslateFid(VenusFid *OldFid, VenusFid *NewFid) 
 1886 {
 1887     cml_iterator next(*this, CommitOrder, OldFid);
 1888     cmlent *m;
 1889     while ((m = next()))
 1890     m->translatefid(OldFid, NewFid);
 1891 }
 1892 
 1893 
 1894 /* need not be called from within a transaction */
 1895 void ClientModifyLog::IncThread(int tid)
 1896 {
 1897     repvol *vol = strbase(repvol, this, CML);
 1898     LOG(1, ("ClientModifyLog::IncThread: (%s) tid = %d\n", 
 1899         vol->name, tid));
 1900 
 1901     /* Initialize "threading" state in dirty fsobj's. */
 1902     {
 1903     cml_iterator next(*this, CommitOrder);
 1904     cmlent *m;
 1905     while ((m = next()))
 1906         if (m->GetTid() == tid) {
 1907         /* we may do this more than once per object */
 1908         dlist_iterator next(*m->fid_bindings);
 1909         dlink *d;
 1910 
 1911         while ((d = next())) {
 1912             binding *b = strbase(binding, d, binder_handle);
 1913             fsobj *f = (fsobj *)b->bindee;
 1914 
 1915             /* sanity checks -- better be an fso */
 1916             CODA_ASSERT(f && (f->MagicNumber == FSO_MagicNumber));
 1917             f->tSid = f->stat.VV.StoreId;
 1918             }
 1919         }
 1920     }
 1921 
 1922     /* Thread version state according to commit order. */
 1923     {
 1924     cml_iterator next(*this, CommitOrder);
 1925     cmlent *m;
 1926     while ((m = next()))
 1927       if (m->GetTid() == tid)
 1928           m->thread();
 1929     }
 1930 
 1931     if (LogLevel >= 10)
 1932     print(logFile);
 1933 
 1934     LOG(0, ("ClientModifyLog::IncThread: (%s)\n", vol->name));
 1935 }
 1936 
 1937 /* Try to figure out if the cml is reintegrated `out of order', in that case we
 1938  * skip a test on the server that tries to avoid duplicate reintegrations. As a
 1939  * result such a reintegration will generate conflicts when it fails, but that
 1940  * is still better than the previous behaviour where cml entries were dropped.*/
 1941 int ClientModifyLog::OutOfOrder(int tid)
 1942 {
 1943     cml_iterator next(*this, CommitOrder);
 1944     cmlent *m;
 1945     int suspect = 0;
 1946 
 1947     while ((m = next())) {
 1948     if (m->flags.prepended)
 1949         return 1;
 1950     if (m->GetTid() != tid) { /* detect skipped entries */
 1951         suspect = 1;
 1952     } else if (suspect) /* found a tid after we skipped any cmlentries? */
 1953         return 1;
 1954     }
 1955     return 0;
 1956 }
 1957 
 1958 /* need not be called from within a transaction */
 1959 /* Munge the ClientModifyLog into a format suitable for reintegration. */
 1960 /* Caller is responsible for deallocating buffer! */
 1961 void ClientModifyLog::IncPack(char **bufp, int *bufsizep, int tid)
 1962 {
 1963     repvol *vol = strbase(repvol, this, CML);
 1964     LOG(1, ("ClientModifyLog::IncPack: (%s) and tid = %d\n", vol->name, tid));
 1965 
 1966     /* Compute size of buffer needed. */
 1967     {
 1968     int len = 0;
 1969     cml_iterator next(*this, CommitOrder);
 1970     cmlent *mle;
 1971     while ((mle = next()))
 1972       if (mle->GetTid() == tid)
 1973         len += mle->size();
 1974 
 1975     *bufsizep = len;
 1976     }
 1977 
 1978     /* Allocate such a buffer. */
 1979     *bufp = new char[*bufsizep];
 1980 
 1981     /* Pack according to commit order. */
 1982     {
 1983     PARM *_ptr = (PARM *)*bufp;
 1984     cml_iterator next(*this, CommitOrder);
 1985     cmlent *m;
 1986     while ((m = next()))
 1987       if (m->GetTid() == tid)
 1988         m->pack(&_ptr);
 1989     }
 1990 
 1991     LOG(0, ("ClientModifyLog::IncPack: (%s)\n", vol->name));
 1992 }
 1993 
 1994 
 1995 #define UNSET_INDEX -2
 1996 #define MAXSTALEDIRS 50
 1997 
 1998 /* MUST NOT be called from within transaction! */
 1999 int ClientModifyLog::COP1(char *buf, int bufsize, ViceVersionVector *UpdateSet,
 2000               int outoforder)
 2001 {
 2002     repvol *vol = strbase(repvol, this, CML);
 2003     int code = 0;
 2004     unsigned int i = 0;
 2005     mgrpent *m = 0;
 2006     
 2007     /* Set up the SE descriptor. */
 2008     SE_Descriptor sed;
 2009     memset(&sed, 0, sizeof(SE_Descriptor));
 2010     sed.Tag = SMARTFTP;
 2011     struct SFTP_Descriptor *sei = &sed.Value.SmartFTPD;
 2012     sei->TransmissionDirection = CLIENTTOSERVER;
 2013     sei->hashmark = 0;
 2014     sei->SeekOffset = 0;
 2015     sei->ByteQuota = -1;
 2016     sei->Tag = FILEINVM;
 2017     sei->FileInfo.ByAddr.vmfile.SeqLen = bufsize;
 2018     sei->FileInfo.ByAddr.vmfile.SeqBody = (RPC2_ByteSeq)buf;
 2019 
 2020     /* COP2 Piggybacking. */
 2021     long cbtemp; cbtemp = cbbreaks;
 2022     char PiggyData[COP2SIZE];
 2023     RPC2_CountedBS PiggyBS;
 2024     PiggyBS.SeqLen = 0;
 2025     PiggyBS.SeqBody = (RPC2_ByteSeq)PiggyData;
 2026 
 2027     /* VCB maintenance */
 2028     RPC2_Integer VS = 0;
 2029     CallBackStatus VCBStatus = NoCallBack;
 2030 
 2031     RPC2_Integer Index = UNSET_INDEX;
 2032     ViceFid StaleDirs[MAXSTALEDIRS];
 2033     RPC2_Integer MaxStaleDirs = MAXSTALEDIRS;
 2034     RPC2_Integer NumStaleDirs = 0;
 2035 
 2036     /* Acquire an Mgroup. */
 2037     code = vol->GetMgrp(&m, owner, (PIGGYCOP2 ? &PiggyBS : 0));
 2038     if (code != 0) goto Exit;
 2039 
 2040     /* abort reintegration if the user is not authenticated */
 2041     if (!m->IsAuthenticated()) {
 2042         code = ETIMEDOUT; /* treat this as an `spurious disconnection' */
 2043         goto Exit;
 2044     }
 2045 
 2046     /* XXX when we do not use backfetches the CML should be relatively small,
 2047      * so we can just as well reintegrate to all servers. Or is there still
 2048      * a point where weak reintegration is worth it? */
 2049     if (0 /* vol->IsWeaklyConnected() && m->vsg->NHosts() > 1 */) {
 2050     /* Pick a server and get a connection to it. */
 2051     int ph_ix; struct in_addr *phost;
 2052         phost = m->GetPrimaryHost(&ph_ix);
 2053     CODA_ASSERT(phost->s_addr != 0);
 2054 
 2055     connent *c = 0;
 2056         srvent *s = GetServer(phost, vol->GetRealmId());
 2057     code = s->GetConn(&c, owner);
 2058         PutServer(&s);
 2059     if (code != 0) goto Exit;
 2060     
 2061     /* don't bother with VCBs, will lose them on resolve anyway */
 2062     RPC2_CountedBS OldVS; 
 2063     OldVS.SeqLen = 0;
 2064     vol->ClearCallBack();
 2065 
 2066     /* Make the RPC call. */
 2067     MarinerLog("store::Reintegrate %s, (%d, %d)\n", 
 2068            vol->name, count(), bufsize);
 2069 
 2070     /* We do not piggy the COP2 entries in PiggyBS when talking to only a
 2071      * single server _as a result of weak connectivity_. We could do an
 2072      * explicit COP2 call here to ship the PiggyBS array. Or simply ignore
 2073      * them, so they will eventually be sent automatically or piggied on
 2074      * the next multirpc. --JH */
 2075 
 2076     if (PiggyBS.SeqLen) {
 2077         code = vol->COP2(m, &PiggyBS);
 2078         PiggyBS.SeqLen = 0;
 2079     }
 2080 
 2081     UNI_START_MESSAGE(ViceReintegrate_OP);
 2082     code = (int) ViceReintegrate(c->connid, vol->vid, bufsize, &Index,
 2083                      outoforder, MaxStaleDirs, &NumStaleDirs,
 2084                      StaleDirs, &OldVS, &VS,
 2085                      &VCBStatus, &PiggyBS, &sed);
 2086     UNI_END_MESSAGE(ViceReintegrate_OP);
 2087     MarinerLog("store::reintegrate done\n");
 2088 
 2089     code = vol->Collate(c, code, 0);
 2090     UNI_RECORD_STATS(ViceReintegrate_OP);
 2091     
 2092     /* 
 2093      * if the return code is EALREADY, the log records up to and
 2094      * including the one with the storeid that matches the 
 2095      * uniquifier in Index have been committed at the server.  
 2096      * Mark the last of those records.
 2097      */
 2098     if (code == EALREADY)
 2099         MarkCommittedMLE((RPC2_Unsigned) Index);
 2100 
 2101     /* if there is a semantic failure, mark the offending record */
 2102     if (code != 0 && code != EALREADY &&
 2103         code != ERETRY && code != EWOULDBLOCK && code != ETIMEDOUT) 
 2104         MarkFailedMLE((int) Index);
 2105     
 2106     if (code != 0) {
 2107         PutConn(&c);
 2108         goto Exit;
 2109     }
 2110 
 2111     bufsize += sed.Value.SmartFTPD.BytesTransferred;
 2112     LOG(10, ("ViceReintegrate: transferred %d bytes\n",
 2113          sed.Value.SmartFTPD.BytesTransferred));
 2114 
 2115     /* Purge off stale directory fids, if any. fsobj::Kill is idempotent. */
 2116     LOG(0, ("ClientModifyLog::COP1: %d stale dirs\n", NumStaleDirs));
 2117 
 2118     /* server may have found more stale dirs */
 2119     if (NumStaleDirs == MaxStaleDirs)
 2120         vol->ClearCallBack();
 2121 
 2122     for (int d = 0; d < NumStaleDirs; d++) {
 2123         VenusFid StaleDir;
 2124         MakeVenusFid(&StaleDir, vol->GetRealmId(), &StaleDirs[d]);
 2125         LOG(0, ("ClientModifyLog::COP1: stale dir %s\n",
 2126             FID_(&StaleDir)));
 2127         fsobj *f = FSDB->Find(&StaleDir);
 2128         if (!f) continue;
 2129 
 2130         Recov_BeginTrans();
 2131         f->Kill();
 2132         Recov_EndTrans(DMFP);
 2133     }
 2134 
 2135     /* Fashion the update set. */
 2136     InitVV(UpdateSet);
 2137     (&(UpdateSet->Versions.Site0))[ph_ix] = 1;
 2138 
 2139     /* Indicate that objects should be resolved on commit. */
 2140     vol->flags.resolve_me = 1;
 2141     PutConn(&c);
 2142     } else {
 2143     RPC2_CountedBS OldVS;
 2144     vol->PackVS(VSG_MEMBERS, &OldVS);
 2145 
 2146     /* Make multiple copies of the IN/OUT and OUT parameters. */
 2147     ARG_MARSHALL(IN_OUT_MODE, SE_Descriptor, sedvar, sed, VSG_MEMBERS);
 2148     ARG_MARSHALL(OUT_MODE, RPC2_Integer, VSvar, VS, VSG_MEMBERS);
 2149     ARG_MARSHALL(OUT_MODE, CallBackStatus, VCBStatusvar, VCBStatus, VSG_MEMBERS);
 2150     ARG_MARSHALL(OUT_MODE, RPC2_Integer, Indexvar, Index, VSG_MEMBERS);
 2151     ARG_MARSHALL(OUT_MODE, RPC2_Integer, NumStaleDirsvar, NumStaleDirs, VSG_MEMBERS);
 2152     ARG_MARSHALL_ARRAY(OUT_MODE, ViceFid, StaleDirsvar, 0, MaxStaleDirs, StaleDirs, VSG_MEMBERS);
 2153 
 2154     /* Make the RPC call. */
 2155     MarinerLog("store::Reintegrate %s, (%d, %d)\n", 
 2156            vol->name, count(), bufsize);
 2157 
 2158     MULTI_START_MESSAGE(ViceReintegrate_OP);
 2159     code = (int) MRPC_MakeMulti(ViceReintegrate_OP,
 2160                     ViceReintegrate_PTR,
 2161                     VSG_MEMBERS, m->rocc.handles,
 2162                     m->rocc.retcodes, m->rocc.MIp, 0, 0,
 2163                     vol->vid, bufsize, Indexvar_ptrs,
 2164                     outoforder,
 2165                     MaxStaleDirs, NumStaleDirsvar_ptrs, 
 2166                     StaleDirsvar_ptrs,
 2167                     &OldVS, VSvar_ptrs, VCBStatusvar_ptrs,
 2168                     &PiggyBS, sedvar_bufs);
 2169     MULTI_END_MESSAGE(ViceReintegrate_OP);
 2170 
 2171     MarinerLog("store::reintegrate done\n");
 2172 
 2173     /* Examine the return code to decide what to do next. */
 2174     code = vol->Collate_Reintegrate(m, code, UpdateSet);
 2175     MULTI_RECORD_STATS(ViceReintegrate_OP);
 2176 
 2177     free(OldVS.SeqBody);
 2178 
 2179     /* Collate the failure index.  Grab the smallest one. Take special
 2180      * care to treat the index different when an error is returned.
 2181      * This double usage of the index is really asking for trouble! */
 2182     for (i = 0; i < VSG_MEMBERS; i++) {
 2183         if (m->rocc.hosts[i].s_addr != 0) {
 2184         if ((code != EALREADY || m->rocc.retcodes[i] == EALREADY) &&
 2185             (Index == UNSET_INDEX || Index > Indexvar_bufs[i]))
 2186             Index = Indexvar_bufs[i];
 2187         }
 2188     }
 2189     
 2190     /* 
 2191      * if the return code is EALREADY, the log records up to and
 2192      * including the one with the storeid that matches the 
 2193      * uniquifier in Index have been committed at the server.  
 2194      * Mark the last of those records.
 2195      */
 2196     if (code == EALREADY)
 2197         MarkCommittedMLE((RPC2_Unsigned) Index);
 2198 
 2199     /* if there is a semantic failure, mark the offending record */
 2200     if (code != 0 && code != EALREADY &&
 2201         code != ERETRY && code != EWOULDBLOCK && code != ETIMEDOUT) 
 2202         MarkFailedMLE((int) Index);
 2203 
 2204     if (code == EASYRESOLVE) { code = 0; }
 2205     if (code != 0) goto Exit;
 2206 
 2207     /* Collate volume callback information */
 2208     if (cbtemp == cbbreaks)
 2209         vol->CollateVCB(m, VSvar_bufs, VCBStatusvar_bufs);
 2210 
 2211     /* Finalize COP2 Piggybacking. */
 2212     if (PIGGYCOP2) 
 2213         vol->ClearCOP2(&PiggyBS);
 2214 
 2215     /* Manually compute the OUT parameters from the mgrpent::Reintegrate() call! -JJK */
 2216     int dh_ix; dh_ix = -1;
 2217     (void)m->DHCheck(0, -1, &dh_ix);
 2218     bufsize = 0;
 2219     bufsize += sedvar_bufs[dh_ix].Value.SmartFTPD.BytesTransferred;
 2220     LOG(10, ("ViceReintegrate: transferred %d bytes\n",
 2221           sedvar_bufs[dh_ix].Value.SmartFTPD.BytesTransferred));
 2222 
 2223     /* 
 2224      * Deal with stale directory fids, if any.  If the client
 2225      * has a volume callback, stale directories must be purged.
 2226      * If not, purging the directories saves an inevitable 
 2227      * validation.  Finally, if the number of stale directories
 2228      * found is at maximum, clear the volume callback to be safe.
 2229      */
 2230     for (unsigned int rep = 0; rep < VSG_MEMBERS; rep++) 
 2231             /* did this server participate? */
 2232         if (m->rocc.hosts[rep].s_addr != 0) {
 2233         /* must look at all server feedback */
 2234         ARG_UNMARSHALL(NumStaleDirsvar, NumStaleDirs, rep);
 2235         ARG_UNMARSHALL_ARRAY(StaleDirsvar, NumStaleDirs, StaleDirs, rep);
 2236         LOG(0, ("ClientModifyLog::COP1: (replica %d) %d stale dirs\n", 
 2237             rep, NumStaleDirs));
 2238 
 2239         /* server may have found more stale dirs */
 2240         if (NumStaleDirs == MaxStaleDirs)
 2241             vol->ClearCallBack();
 2242 
 2243         /* purge them off.  fsobj::Kill is idempotent. */
 2244         for (int d = 0; d < NumStaleDirs; d++) {
 2245             VenusFid StaleDir;
 2246             MakeVenusFid(&StaleDir, vol->GetRealmId(), &StaleDirs[d]);
 2247             LOG(0, ("ClientModifyLog::COP1: stale dir %s\n", 
 2248                 FID_(&StaleDir)));
 2249             fsobj *f = FSDB->Find(&StaleDir);
 2250             if (!f) continue;
 2251 
 2252             Recov_BeginTrans();
 2253             f->Kill();
 2254             Recov_EndTrans(DMFP);
 2255         }
 2256         }
 2257     }
 2258 
 2259 Exit:
 2260     if (m) m->Put();
 2261     LOG(0, ("ClientModifyLog::COP1: (%s), %d bytes, returns %d, index = %d\n",
 2262          vol->name, bufsize, code, Index));
 2263     return(code);
 2264 }
 2265 
 2266 
 2267 /* Update the version state of fsobj's following successful reintegration. */
 2268 /* MUST NOT be called from within transaction! */
 2269 void ClientModifyLog::IncCommit(ViceVersionVector *UpdateSet, int Tid)
 2270 {
 2271     repvol *vol = strbase(repvol, this, CML);
 2272     LOG(1, ("ClientModifyLog::IncCommit: (%s) tid = %d\n", 
 2273         vol->name, Tid));
 2274 
 2275     CODA_ASSERT(count() > 0);
 2276 
 2277     Recov_BeginTrans();
 2278     rec_dlist_iterator next(list);
 2279     rec_dlink *d = next();          /* get first element */
 2280 
 2281     while (d) {
 2282         cmlent *m = strbase(cmlent, d, handle);
 2283         d = next(); /* advance d before it is un-listed by m->commit */
 2284         if (m->GetTid() == Tid) {
 2285         /* special case -- last of records already committed at server
 2286          * exit the loop when this has been committed */
 2287         if (m->flags.committed)
 2288             d = NULL;
 2289         m->commit(UpdateSet);
 2290         }
 2291     }
 2292     Recov_EndTrans(DMFP);
 2293 
 2294     /* flush COP2 for this volume */
 2295     vol->FlushCOP2();
 2296     vol->flags.resolve_me = 0;
 2297     LOG(0, ("ClientModifyLog::IncCommit: (%s)\n", vol->name));
 2298 }
 2299 
 2300 
 2301 /* Allocate a real fid for a locally created one, and translate all 
 2302    references. */
 2303 /* Must NOT be called from within transaction! */
 2304 int cmlent::realloc() 
 2305 {
 2306     repvol *vol = strbase(repvol, log, CML);
 2307     int code = 0;
 2308 
 2309     VenusFid OldFid;
 2310     VenusFid NewFid;
 2311     ViceDataType type;
 2312     RPC2_Unsigned AllocHost;
 2313     switch(opcode) {
 2314     case CML_Create_OP:
 2315         if (!FID_IsLocalFile(MakeViceFid(&u.u_create.CFid)))
 2316         goto Exit;
 2317         OldFid = u.u_create.CFid;
 2318         type = File;
 2319         break;
 2320 
 2321     case CML_MakeDir_OP:
 2322         if (!FID_IsLocalDir(MakeViceFid(&u.u_mkdir.CFid)))
 2323         goto Exit;
 2324         OldFid = u.u_mkdir.CFid;
 2325         type = Directory;
 2326         break;
 2327 
 2328     case CML_SymLink_OP:
 2329         if (!FID_IsLocalFile(MakeViceFid(&u.u_symlink.CFid)))
 2330         goto Exit;
 2331         OldFid = u.u_symlink.CFid;
 2332         type = SymbolicLink;
 2333         break;
 2334 
 2335     default:
 2336         goto Exit;
 2337     }
 2338 
 2339     code = vol->AllocFid(type, &NewFid, &AllocHost, uid, 1);
 2340     if (code == 0) {
 2341         Recov_BeginTrans();
 2342         vol->FidsRealloced++;
 2343 
 2344         /* Translate fids in log records. */
 2345         log->TranslateFid(&OldFid, &NewFid);
 2346 
 2347         /* Translate fid in the FSDB. */
 2348         if ((code = FSDB->TranslateFid(&OldFid, &NewFid)) != 0)
 2349             CHOKE("cmlent::realloc: couldn't translate %s -> %s (%d)",
 2350             FID_(&OldFid), FID_(&NewFid), code);
 2351         Recov_EndTrans(MAXFP);
 2352     }
 2353 
 2354 Exit:
 2355     return(code);
 2356 }
 2357 
 2358 
 2359 /* MUST be called from within transaction! */
 2360 void cmlent::translatefid(VenusFid *OldFid, VenusFid *NewFid)
 2361 {
 2362     int found = 0;          /* sanity checking */
 2363     RVMLIB_REC_OBJECT(u);
 2364     switch(opcode) {
 2365     case CML_Store_OP:
 2366         if (FID_EQ(&u.u_store.Fid, OldFid))
 2367         { u.u_store.Fid = *NewFid; found = 1; }
 2368         break;
 2369 
 2370     case CML_Utimes_OP:
 2371         if (FID_EQ(&u.u_utimes.Fid, OldFid))
 2372         { u.u_utimes.Fid = *NewFid; found = 1; }
 2373         break;
 2374 
 2375     case CML_Chown_OP:
 2376         if (FID_EQ(&u.u_chown.Fid, OldFid))
 2377         { u.u_chown.Fid = *NewFid; found = 1; }
 2378         break;
 2379 
 2380     case CML_Chmod_OP:
 2381         if (FID_EQ(&u.u_chmod.Fid, OldFid))
 2382         { u.u_chmod.Fid = *NewFid; found = 1; }
 2383         break;
 2384 
 2385     case CML_Create_OP:
 2386         if (FID_EQ(&u.u_create.PFid, OldFid))
 2387         { u.u_create.PFid = *NewFid; found = 1; }
 2388         if (FID_EQ(&u.u_create.CFid, OldFid))
 2389         { u.u_create.CFid = *NewFid; found = 1; }
 2390         break;
 2391 
 2392     case CML_Remove_OP:
 2393         if (FID_EQ(&u.u_remove.PFid, OldFid))
 2394         { u.u_remove.PFid = *NewFid; found = 1; }
 2395         if (FID_EQ(&u.u_remove.CFid, OldFid))
 2396         { u.u_remove.CFid = *NewFid; found = 1; }
 2397         break;
 2398 
 2399     case CML_Link_OP:
 2400         if (FID_EQ(&u.u_link.PFid, OldFid))
 2401         { u.u_link.PFid = *NewFid; found = 1; }
 2402         if (FID_EQ(&u.u_link.CFid, OldFid))
 2403         { u.u_link.CFid = *NewFid; found = 1; }
 2404         break;
 2405 
 2406     case CML_Rename_OP:
 2407         if (FID_EQ(&u.u_rename.SPFid, OldFid))
 2408         { u.u_rename.SPFid = *NewFid; found = 1; }
 2409         if (FID_EQ(&u.u_rename.TPFid, OldFid))
 2410         { u.u_rename.TPFid = *NewFid; found = 1; }
 2411         if (FID_EQ(&u.u_rename.SFid, OldFid))
 2412         { u.u_rename.SFid = *NewFid; found = 1; }
 2413         break;
 2414 
 2415     case CML_MakeDir_OP:
 2416         if (FID_EQ(&u.u_mkdir.PFid, OldFid))
 2417         { u.u_mkdir.PFid = *NewFid; found = 1; }
 2418         if (FID_EQ(&u.u_mkdir.CFid, OldFid))
 2419         { u.u_mkdir.CFid = *NewFid; found = 1; }
 2420         break;
 2421 
 2422     case CML_RemoveDir_OP:
 2423         if (FID_EQ(&u.u_rmdir.PFid, OldFid))
 2424         { u.u_rmdir.PFid = *NewFid; found = 1; }
 2425         if (FID_EQ(&u.u_rmdir.CFid, OldFid))
 2426         { u.u_rmdir.CFid = *NewFid; found = 1; }
 2427         break;
 2428 
 2429     case CML_SymLink_OP:
 2430         if (FID_EQ(&u.u_symlink.PFid, OldFid))
 2431         { u.u_symlink.PFid = *NewFid; found = 1; }
 2432         if (FID_EQ(&u.u_symlink.CFid, OldFid))
 2433         { u.u_symlink.CFid = *NewFid; found = 1; }
 2434         break;
 2435 
 2436         case CML_Repair_OP: /* Shouldn't be called for repair */ 
 2437     default:
 2438         CHOKE("cmlent::translatefid: bogus opcode (%d)", opcode);
 2439     }
 2440     if (!found) {
 2441     print(logFile);
 2442     CHOKE("cmlent::translatefid: (%s) not matched", FID_(OldFid));
 2443     }
 2444 }
 2445 
 2446 
 2447 /* local-repair modification */
 2448 void cmlent::thread() {
 2449     VenusFid *fids[3];
 2450     ViceVersionVector *vvs[3];
 2451 
 2452     GetVVandFids(vvs, fids);
 2453     for (int i = 0; i < 3; i++) {
 2454     VenusFid *fidp = fids[i];
 2455     if (fidp == 0) break;
 2456 
 2457     fsobj *f = FSDB->Find(fidp);
 2458     if (f == 0) {
 2459         print(logFile);
 2460         (strbase(repvol, log, CML))->print(logFile);
 2461         CHOKE("cmlent::thread: can't find (%s)", FID_(fidp));
 2462     }
 2463 
 2464     /* Thread the VVs. */
 2465     if (vvs[i] != 0) {
 2466         *(vvs[i]) = f->stat.VV;
 2467         vvs[i]->StoreId = f->tSid;
 2468     }
 2469     f->tSid = sid;
 2470     }
 2471 }
 2472 
 2473 
 2474 /* local-repair modification */
 2475 /* Computes amount of space a record will require when packed 
 2476    into an RPC buffer. */
 2477 int cmlent::size() 
 2478 {
 2479     int len = 0;
 2480     RPC2_CountedBS DummyCBS;
 2481     DummyCBS.SeqLen = 0;
 2482     DummyCBS.SeqBody = 0;
 2483 
 2484     len += (int) sizeof(RPC2_Integer);  /* Leave room for opcode. */
 2485     len += (int) sizeof(Date_t);        /* Leave room for modify time. */
 2486     switch(opcode) {
 2487     case CML_Create_OP:
 2488         len += RLE_Size(CML_Create_PTR, MakeViceFid(&u.u_create.PFid),
 2489                 &u.u_create.PVV, Name, (vuid_t)uid, u.u_create.Mode,
 2490                 MakeViceFid(&u.u_create.CFid), &sid);
 2491         break;
 2492 
 2493     case CML_Link_OP:
 2494         len += RLE_Size(CML_Link_PTR, MakeViceFid(&u.u_link.PFid),
 2495                 &u.u_link.PVV, Name, MakeViceFid(&u.u_link.CFid),
 2496                 &u.u_link.CVV, &sid);
 2497         break;
 2498 
 2499     case CML_MakeDir_OP:
 2500         len += RLE_Size(CML_MakeDir_PTR, MakeViceFid(&u.u_mkdir.PFid),
 2501                 &u.u_mkdir.PVV, Name, MakeViceFid(&u.u_mkdir.CFid),
 2502                 (vuid_t)uid, u.u_mkdir.Mode, &sid);
 2503         break;
 2504 
 2505     case CML_SymLink_OP:
 2506         len += RLE_Size(CML_SymLink_PTR, MakeViceFid(&u.u_symlink.PFid),
 2507                 &u.u_symlink.PVV, NewName, Name,
 2508                 MakeViceFid(&u.u_symlink.CFid), (vuid_t)uid,
 2509                 u.u_symlink.Mode, &sid);
 2510         break;
 2511 
 2512     case CML_Remove_OP:
 2513         len += RLE_Size(CML_Remove_PTR, MakeViceFid(&u.u_remove.PFid),
 2514                 &u.u_remove.PVV, Name, &u.u_remove.CVV, &sid);
 2515         break;
 2516 
 2517     case CML_RemoveDir_OP:
 2518         len += RLE_Size(CML_RemoveDir_PTR, MakeViceFid(&u.u_rmdir.PFid),
 2519                 &u.u_rmdir.PVV, Name, &u.u_rmdir.CVV, &sid);
 2520         break;
 2521 
 2522     case CML_Store_OP:
 2523         len += RLE_Size(CML_Store_PTR, MakeViceFid(&u.u_store.Fid),
 2524                 &u.u_store.VV, u.u_store.Length, &sid);
 2525         break;
 2526 
 2527     case CML_Utimes_OP:
 2528         len += RLE_Size(CML_Utimes_PTR, MakeViceFid(&u.u_utimes.Fid),
 2529                 &u.u_utimes.VV, u.u_utimes.Date, &sid);
 2530         break;
 2531 
 2532     case CML_Chown_OP:
 2533         len += RLE_Size(CML_Chown_PTR, MakeViceFid(&u.u_chown.Fid),
 2534                 &u.u_chown.VV, (vuid_t)u.u_chown.Owner, &sid);
 2535         break;
 2536 
 2537     case CML_Chmod_OP:
 2538         len += RLE_Size(CML_Chmod_PTR, MakeViceFid(&u.u_chmod.Fid),
 2539                 &u.u_chmod.VV, u.u_chmod.Mode, &sid);
 2540         break;
 2541 
 2542     case CML_Rename_OP:
 2543         len += RLE_Size(CML_Rename_PTR, MakeViceFid(&u.u_rename.SPFid),
 2544                 &u.u_rename.SPVV, Name,
 2545                 MakeViceFid(&u.u_rename.TPFid), &NullVV, NewName,
 2546                 &u.u_rename.SVV, &sid);
 2547         break;
 2548 
 2549     case CML_Repair_OP:
 2550         len += RLE_Size(CML_Repair_PTR, MakeViceFid(&u.u_repair.Fid),
 2551                 u.u_repair.Length, u.u_repair.Date,
 2552                 (vuid_t)u.u_repair.Owner, (vuid_t)u.u_repair.Owner,
 2553                 u.u_repair.Mode, &sid);
 2554         break;
 2555 
 2556     default:
 2557         CHOKE("cmlent::size: bogus opcode (%d)", opcode);
 2558     }
 2559 
 2560     return(len);
 2561 }
 2562 
 2563 
 2564 /* local-repair modification */
 2565 /* Pack this record into an RPC buffer for transmission to the server. */
 2566 void cmlent::pack(PARM **_ptr) {
 2567     /* We MUST recompute the size here since the MRPC size-computing routines */
 2568     /* modify static variables which are used in packing (i.e., XXX_PTR)! */
 2569     (void)size();
 2570 
 2571     ViceVersionVector TPVV;
 2572 
 2573     *(RPC2_Integer *)(*_ptr) = htonl(opcode); /* Stick in opcode. */
 2574     *_ptr = (PARM *)((char *)*_ptr + sizeof(RPC2_Integer));
 2575 
 2576     *(Date_t *)(*_ptr) = htonl(time);     /* Stick in modify time. */
 2577     *_ptr = (PARM *)((char *)*_ptr + sizeof(Date_t));
 2578 
 2579     switch(opcode) {
 2580     case CML_Create_OP:
 2581         RLE_Pack(_ptr, CML_Create_PTR, MakeViceFid(&u.u_create.PFid),
 2582              &u.u_create.PVV, Name, (vuid_t)uid, u.u_create.Mode,
 2583              MakeViceFid(&u.u_create.CFid), &sid);
 2584         break;
 2585 
 2586     case CML_Link_OP:
 2587         RLE_Pack(_ptr, CML_Link_PTR, MakeViceFid(&u.u_link.PFid),
 2588              &u.u_link.PVV, Name, MakeViceFid(&u.u_link.CFid),
 2589              &u.u_link.CVV, &sid);
 2590         break;
 2591 
 2592     case CML_MakeDir_OP:
 2593         RLE_Pack(_ptr, CML_MakeDir_PTR, MakeViceFid(&u.u_mkdir.PFid),
 2594              &u.u_mkdir.PVV, Name, MakeViceFid(&u.u_mkdir.CFid),
 2595              (vuid_t)uid, u.u_mkdir.Mode, &sid);
 2596         break;
 2597 
 2598     case CML_SymLink_OP:
 2599         RLE_Pack(_ptr, CML_SymLink_PTR, MakeViceFid(&u.u_symlink.PFid),
 2600              &u.u_symlink.PVV, NewName, Name,
 2601              MakeViceFid(&u.u_symlink.CFid), (vuid_t)uid,
 2602              u.u_symlink.Mode, &sid);
 2603         break;
 2604 
 2605     case CML_Remove_OP:
 2606         RLE_Pack(_ptr, CML_Remove_PTR, MakeViceFid(&u.u_remove.PFid),
 2607              &u.u_remove.PVV, Name, &u.u_remove.CVV, &sid);
 2608         break;
 2609 
 2610     case CML_RemoveDir_OP:
 2611         RLE_Pack(_ptr, CML_RemoveDir_PTR, MakeViceFid(&u.u_rmdir.PFid),
 2612              &u.u_rmdir.PVV, Name, &u.u_rmdir.CVV, &sid);
 2613         break;
 2614 
 2615     case CML_Store_OP:
 2616         RLE_Pack(_ptr, CML_Store_PTR, MakeViceFid(&u.u_store.Fid),
 2617              &u.u_store.VV, u.u_store.Length, &sid);
 2618         break;
 2619 
 2620     case CML_Utimes_OP:
 2621         RLE_Pack(_ptr, CML_Utimes_PTR, MakeViceFid(&u.u_utimes.Fid),
 2622              &u.u_utimes.VV, u.u_utimes.Date, &sid);
 2623         break;
 2624 
 2625     case CML_Chown_OP:
 2626         RLE_Pack(_ptr, CML_Chown_PTR, MakeViceFid(&u.u_chown.Fid),
 2627              &u.u_chown.VV, (vuid_t)u.u_chown.Owner, &sid);
 2628         break;
 2629 
 2630     case CML_Chmod_OP:
 2631         RLE_Pack(_ptr, CML_Chmod_PTR, MakeViceFid(&u.u_chmod.Fid),
 2632              &u.u_chmod.VV, u.u_chmod.Mode, &sid);
 2633         break;
 2634 
 2635     case CML_Rename_OP:
 2636         TPVV = FID_EQ(&u.u_rename.SPFid, &u.u_rename.TPFid) ?
 2637         u.u_rename.SPVV : u.u_rename.TPVV;
 2638         RLE_Pack(_ptr, CML_Rename_PTR, MakeViceFid(&u.u_rename.SPFid),
 2639              &u.u_rename.SPVV, Name, MakeViceFid(&u.u_rename.TPFid),
 2640              &TPVV, NewName, &u.u_rename.SVV, &sid);
 2641         break;
 2642 
 2643     case CML_Repair_OP:
 2644         RLE_Pack(_ptr, CML_Repair_PTR, MakeViceFid(&u.u_repair.Fid),
 2645              u.u_repair.Length, u.u_repair.Date,
 2646              (vuid_t)u.u_repair.Owner, (vuid_t)u.u_repair.Owner,
 2647              u.u_repair.Mode, &sid);
 2648         break;
 2649 
 2650     default:
 2651         CHOKE("cmlent::pack: bogus opcode (%d)", opcode);
 2652     }
 2653 }
 2654 
 2655 
 2656 /* local-repair modification */
 2657 /* MUST be called from within transaction! */
 2658 void cmlent::commit(ViceVersionVector *UpdateSet)
 2659 {
 2660     LOG(1, ("cmlent::commit: (%d)\n", tid));
 2661 
 2662     repvol *vol = strbase(repvol, log, CML);
 2663     vol->RecordsCommitted++;
 2664 
 2665     /* 
 2666      * Record StoreId/UpdateSet for objects involved in this operation ONLY 
 2667      * when this is the  FINAL mutation of the object.  Record a COP2 entry 
 2668      * only if this operation was final for ANY object! 
 2669      * Because of the addition of incremental reintegration, the final 
 2670      * mutation should be checked only within the bound of a single unit
 2671      * (identified by cmlent::tid) -luqi
 2672      */
 2673     int FinalMutationForAnyObject = 0;
 2674 
 2675     dlist_iterator next(*fid_bindings);
 2676     dlink *d;
 2677     while ((d = next())) {
 2678     binding *b = strbase(binding, d, binder_handle);
 2679     fsobj *f = (fsobj *)b->bindee;
 2680 
 2681     /* better be an fso */
 2682     CODA_ASSERT(f && (f->MagicNumber == FSO_MagicNumber));
 2683 
 2684 
 2685     if (vol->flags.resolve_me && vol->AVSGsize() > 1)
 2686         vol->ResSubmit(NULL, &f->fid);
 2687 
 2688     cmlent *FinalCmlent = f->FinalCmlent(tid);
 2689     if (FinalCmlent == this) {
 2690         LOG(10, ("cmlent::commit: FinalCmlent for %s\n", FID_(&f->fid)));
 2691         /* 
 2692          * if the final update removed the object, don't bother adding the
 2693          * COP2, but do update the version vector as in connected mode.
 2694          */
 2695         if (!(opcode == CML_Remove_OP && FID_EQ(&u.u_remove.CFid, &f->fid)) &&
 2696         !(opcode == CML_RemoveDir_OP && FID_EQ(&u.u_rmdir.CFid, &f->fid)))
 2697         FinalMutationForAnyObject = 1;
 2698 
 2699         RVMLIB_REC_OBJECT(f->stat.VV);
 2700         f->stat.VV.StoreId = sid;
 2701         AddVVs(&f->stat.VV, UpdateSet);
 2702     }
 2703     }
 2704     if (1 /* FinalMutationForAnyObject */) {
 2705     LOG(10, ("cmlent::commit: Add COP2 with sid = 0x%x.%x\n",
 2706          sid.Host, sid.Uniquifier));    
 2707     vol->AddCOP2(&sid, UpdateSet);
 2708     }
 2709 
 2710     delete this;
 2711 }
 2712 
 2713 
 2714 int cmlent::HaveReintegrationHandle()
 2715 {
 2716     return (opcode == CML_Store_OP && u.u_store.RHandle.BirthTime);
 2717 }
 2718 
 2719 
 2720 /* MUST NOT be called from within transaction! */
 2721 void cmlent::ClearReintegrationHandle()
 2722 {
 2723     CODA_ASSERT(opcode == CML_Store_OP);
 2724 
 2725     Recov_BeginTrans();
 2726     RVMLIB_REC_OBJECT(u);
 2727         memset(&u.u_store.RHandle, 0, sizeof(ViceReintHandle));
 2728     u.u_store.Offset = 0;
 2729     u.u_store.ReintPH.s_addr = 0;
 2730     u.u_store.ReintPHix = -1;
 2731    Recov_EndTrans(MAXFP);
 2732 }
 2733 
 2734 
 2735 int cmlent::DoneSending()
 2736 { 
 2737     int done = 0;
 2738 
 2739     if (HaveReintegrationHandle() &&
 2740     (u.u_store.Offset == u.u_store.Length))
 2741     done = 1;
 2742     
 2743     return(done);
 2744 }
 2745 
 2746 
 2747 int cmlent::GetReintegrationHandle()
 2748 {
 2749     repvol *vol = strbase(repvol, log, CML);
 2750     int code = 0;
 2751     mgrpent *m = 0;
 2752     int ph_ix;
 2753     struct in_addr phost;
 2754     connent *c = 0;
 2755     srvent *s = 0;
 2756 
 2757     /* Eventhough it might seem like a good idea, we should NOT! clear the
 2758      * reintegration handle here. There are 2 failure cases, one is that one
 2759      * replica is unreachable, the other is that all replicas died.
 2760      *
 2761      * In the first case, the SendReintegrateFragment rpc times out, we try to
 2762      * revalidate the handle with the same server which fails as well. We end
 2763      * up here trying to connect to another replica and if that succeeds we
 2764      * replace the existing handle with the new data and retry the
 2765      * reintegration from the beginning. On the second case everything is
 2766      * unreachable and we still have a usable handle to reconnect to the
 2767      * original server when the network comes back.
 2768      */
 2769 
 2770     /* Acquire an Mgroup. */
 2771     code = vol->GetMgrp(&m, log->owner);
 2772     if (code != 0) goto Exit;
 2773 
 2774     /* Pick a server and get a connection to it. */
 2775     phost = *m->GetPrimaryHost(&ph_ix);
 2776     CODA_ASSERT(phost.s_addr != 0);
 2777 
 2778     s = GetServer(&phost, vol->GetRealmId());
 2779     code = s->GetConn(&c, log->owner);
 2780     PutServer(&s);
 2781     if (code != 0) goto Exit;
 2782 
 2783     {
 2784     ViceReintHandle VR;
 2785 
 2786     /* Make the RPC call. */
 2787     MarinerLog("store::OpenReintHandle %s\n", vol->name);
 2788     UNI_START_MESSAGE(ViceOpenReintHandle_OP);
 2789     code = (int) ViceOpenReintHandle(c->connid, MakeViceFid(&u.u_store.Fid), &VR);
 2790     UNI_END_MESSAGE(ViceOpenReintHandle_OP);
 2791     MarinerLog("store::openreinthandle done\n");
 2792 
 2793     /* Examine the return code to decide what to do next. */
 2794     code = vol->Collate(c, code);
 2795     UNI_RECORD_STATS(ViceOpenReintHandle_OP);
 2796 
 2797     if (code != 0) goto Exit;
 2798 
 2799     /* Store the handle and the primary host */
 2800     Recov_BeginTrans();
 2801         RVMLIB_REC_OBJECT(u);
 2802         u.u_store.RHandle   = VR;
 2803         u.u_store.Offset    = 0;
 2804         u.u_store.ReintPH   = phost;
 2805         u.u_store.ReintPHix = ph_ix;
 2806     Recov_EndTrans(MAXFP);
 2807     }
 2808 
 2809 Exit:
 2810     PutConn(&c);
 2811     if (m) m->Put();
 2812     LOG(0, ("cmlent::GetReintegrationHandle: (%s), returns %s\n",
 2813          vol->name, VenusRetStr(code)));
 2814     return(code);
 2815 }
 2816 
 2817 
 2818 int cmlent::ValidateReintegrationHandle()
 2819 {
 2820     repvol *vol = strbase(repvol, log, CML);
 2821     int code = 0;
 2822     connent *c = 0;
 2823     RPC2_Unsigned Offset = 0;
 2824     
 2825     /* Acquire a connection. */
 2826     srvent *s = GetServer(&u.u_store.ReintPH, vol->GetRealmId());
 2827     code = s->GetConn(&c, log->owner);
 2828     PutServer(&s);
 2829     if (code != 0) goto Exit;
 2830 
 2831     {
 2832     /* Make the RPC call. */
 2833     MarinerLog("store::QueryReintHandle %s\n", vol->name);
 2834     UNI_START_MESSAGE(ViceQueryReintHandle_OP);
 2835     code = (int) ViceQueryReintHandle(c->connid, vol->vid,
 2836                       &u.u_store.RHandle, &Offset);
 2837     UNI_END_MESSAGE(ViceQueryReintHandle_OP);
 2838     MarinerLog("store::queryreinthandle done\n");
 2839 
 2840     /* Examine the return code to decide what to do next. */
 2841     code = vol->Collate(c, code);
 2842     UNI_RECORD_STATS(ViceQueryReintHandle_OP);
 2843 
 2844     if (code != 0) goto Exit;
 2845 
 2846     if (Offset > u.u_store.Length)
 2847         CHOKE("cmlent::QueryReintegrationHandle: offset > length! (%d, %d)\n",
 2848           Offset, u.u_store.Length);
 2849 
 2850     Recov_BeginTrans();
 2851         RVMLIB_REC_OBJECT(u);   
 2852         u.u_store.Offset = Offset;
 2853     Recov_EndTrans(MAXFP);
 2854     }
 2855 
 2856 Exit:
 2857     PutConn(&c);
 2858     LOG(0, ("cmlent::QueryReintegrationHandle: (%s), returns %s, offset %d\n",
 2859          vol->name, VenusRetStr(code), Offset));
 2860     return(code);
 2861 }
 2862 
 2863 
 2864 int cmlent::WriteReintegrationHandle(unsigned long *reint_time)
 2865 {
 2866     CODA_ASSERT(opcode == CML_Store_OP);
 2867     repvol *vol = strbase(repvol, log, CML);
 2868     int code = 0, fd = -1;
 2869     connent *c = 0;
 2870     fsobj *f = NULL;
 2871     RPC2_Unsigned length = u.u_store.Length - u.u_store.Offset;
 2872 
 2873     if (!vol->IsSync())
 2874     length = ReintAmount(reint_time);
 2875 
 2876     /* stop reintegration loop if we ran out of available reintegration time */
 2877     if (length == 0 && u.u_store.Offset != u.u_store.Length)
 2878     return ERETRY;
 2879 
 2880     /* Acquire a connection. */
 2881     srvent *s = GetServer(&u.u_store.ReintPH, vol->GetRealmId());
 2882     code = s->GetConn(&c, log->owner);
 2883     PutServer(&s);
 2884     if (code != 0) goto Exit;
 2885 
 2886     {
 2887     /* get the fso associated with this record */
 2888     binding *b = strbase(binding, fid_bindings->first(), binder_handle);
 2889     f = (fsobj *)b->bindee;
 2890     if (f == 0)
 2891         { code = ENOENT; goto Exit; }
 2892 
 2893     if (!f->shadow) 
 2894         CHOKE("cmlent::WriteReintegrationHandle: no shadow file! (%s)\n",
 2895           FID_(&f->fid));
 2896 
 2897     /* Sanity checks. */
 2898     if (!f->IsFile() || !HAVEALLDATA(f)) {
 2899         code = EINVAL;
 2900         goto Exit;
 2901     }
 2902 
 2903     /* Set up the SE descriptor. */
 2904     SE_Descriptor sed;
 2905         memset(&sed, 0, sizeof(SE_Descriptor));
 2906     {
 2907         sed.Tag = SMARTFTP;
 2908         struct SFTP_Descriptor *sei = &sed.Value.SmartFTPD;
 2909         sei->TransmissionDirection = CLIENTTOSERVER;
 2910         sei->hashmark = 0;
 2911         sei->SeekOffset = u.u_store.Offset;
 2912         sei->ByteQuota = length;
 2913 
 2914             /* and open the containerfile */
 2915         fd = f->shadow->Open(O_RDONLY);
 2916 
 2917             sei->Tag = FILEBYFD;
 2918             sei->FileInfo.ByFD.fd = fd;
 2919     }
 2920 
 2921     /* Notify Codacon */
 2922     MarinerLog("store::SendReintFragment %s, %s [%d] (%d/%d)\n", 
 2923            vol->name, f->GetComp(), NBLOCKS(length), 
 2924            u.u_store.Offset, u.u_store.Length);
 2925 
 2926     /* Make the RPC call. */
 2927     UNI_START_MESSAGE(ViceSendReintFragment_OP);
 2928     code = (int) ViceSendReintFragment(c->connid, vol->vid,
 2929                        &u.u_store.RHandle, length, &sed);
 2930     UNI_END_MESSAGE(ViceSendReintFragment_OP);
 2931     MarinerLog("store::sendreintfragment done\n");
 2932 
 2933     code = vol->Collate(c, code);
 2934     UNI_RECORD_STATS(ViceSendReintFragment_OP);
 2935 
 2936     if (code != 0) goto Exit;
 2937 
 2938     if ((long)length != sed.Value.SmartFTPD.BytesTransferred) 
 2939         CHOKE("cmlent::WriteReintegrateHandle: bytes mismatch (%d, %d)\n",
 2940             length, sed.Value.SmartFTPD.BytesTransferred);
 2941 
 2942     Recov_BeginTrans();
 2943         RVMLIB_REC_OBJECT(u);
 2944         u.u_store.Offset += length;
 2945     Recov_EndTrans(MAXFP);
 2946     }
 2947 
 2948  Exit:
 2949     if (fd != -1) f->shadow->Close(fd);
 2950 
 2951     PutConn(&c);
 2952     LOG(0, ("cmlent::WriteReintegrateHandle: (%s), %d bytes, returns %s, new offset %d\n",
 2953          vol->name, length, VenusRetStr(code), u.u_store.Offset));
 2954     return(code);
 2955 }
 2956 
 2957 
 2958 int cmlent::CloseReintegrationHandle(char *buf, int bufsize, 
 2959                      ViceVersionVector *UpdateSet)
 2960 {
 2961     repvol *vol = strbase(repvol, log, CML);
 2962     int code = 0;
 2963     connent *c = 0;
 2964     
 2965     /* Set up the SE descriptor. */
 2966     SE_Descriptor sed;
 2967     memset(&sed, 0, sizeof(SE_Descriptor));
 2968     sed.Tag = SMARTFTP;
 2969     struct SFTP_Descriptor *sei = &sed.Value.SmartFTPD;
 2970     sei->TransmissionDirection = CLIENTTOSERVER;
 2971     sei->hashmark = 0;
 2972     sei->SeekOffset = 0;
 2973     sei->ByteQuota = -1;
 2974     sei->Tag = FILEINVM;
 2975     sei->FileInfo.ByAddr.vmfile.SeqLen = bufsize;
 2976     sei->FileInfo.ByAddr.vmfile.SeqBody = (RPC2_ByteSeq)buf;
 2977 
 2978     long cbtemp; cbtemp = cbbreaks;
 2979     RPC2_Integer VS = 0;
 2980     CallBackStatus VCBStatus = NoCallBack;
 2981 
 2982     /* COP2 Piggybacking. */
 2983     char PiggyData[COP2SIZE];
 2984     RPC2_CountedBS empty_PiggyBS;
 2985     empty_PiggyBS.SeqLen = 0;
 2986     empty_PiggyBS.SeqBody = (RPC2_ByteSeq)PiggyData;
 2987 
 2988     /* Get a connection to the server. */
 2989     srvent *s = GetServer(&u.u_store.ReintPH, vol->GetRealmId());
 2990     code = s->GetConn(&c, log->owner);
 2991     PutServer(&s);
 2992     if (code != 0) goto Exit;
 2993 
 2994     /* don't bother with VCBs, will lose them on resolve anyway */
 2995     RPC2_CountedBS OldVS; 
 2996     OldVS.SeqLen = 0;
 2997     vol->ClearCallBack();
 2998 
 2999     /* Make the RPC call. */
 3000     MarinerLog("store::CloseReintHandle %s, (%d)\n", vol->name, bufsize);
 3001     UNI_START_MESSAGE(ViceCloseReintHandle_OP);
 3002     code = (int) ViceCloseReintHandle(c->connid, vol->vid, bufsize,
 3003                       &u.u_store.RHandle, &OldVS, &VS,
 3004                       &VCBStatus, &empty_PiggyBS, &sed);
 3005     UNI_END_MESSAGE(ViceCloseReintHandle_OP);
 3006     MarinerLog("store::closereinthandle done\n");
 3007 
 3008     code = vol->Collate(c, code, 0);
 3009     UNI_RECORD_STATS(ViceCloseReintHandle_OP);
 3010 
 3011     if (code != 0) goto Exit;
 3012 
 3013     LOG(0/*10*/, ("ViceCloseReintegrationHandle: transferred %d bytes\n",
 3014           sed.Value.SmartFTPD.BytesTransferred));
 3015 
 3016     /* Fashion the update set. */
 3017     InitVV(UpdateSet);
 3018     (&(UpdateSet->Versions.Site0))[u.u_store.ReintPHix] = 1;
 3019 
 3020     /* Indicate that objects should be resolved on commit. */
 3021     vol->flags.resolve_me = 1;
 3022 
 3023 Exit:
 3024     PutConn(&c);
 3025     LOG(0, ("cmlent::CloseReintegrationHandle: (%s), %d bytes, returns %s\n", 
 3026         vol->name, bufsize, VenusRetStr(code)));
 3027     return(code);
 3028 }
 3029 
 3030 
 3031 /* Estimate how much space we need to pack a CML entry.
 3032  * the va_arg unpacking is based on code from
 3033  * rpc2/rpc2-src/multi2.c:MRPC_MakeMulti */
 3034 static int RLE_Size(ARG *args ...)
 3035 {
 3036     PARM *parms;
 3037     int i, len = 0;
 3038     va_list ap;
 3039 
 3040     /* variable arguments can be in registers or on the stack and the alignment
 3041      * may differ based on the native size of the type. In order to more easily
 3042      * pass them on to other functions we pull them out first. */
 3043 
 3044     /* allocate an array to hold the arguments */
 3045     for (i = 0; args[i].mode != C_END; i++);
 3046     parms = (PARM *)malloc(i * sizeof(PARM) + 1);
 3047     CODA_ASSERT(parms != NULL);
 3048 
 3049     va_start(ap, args);
 3050     for (i = 0; args[i].mode != C_END; i++)
 3051     {
 3052         switch (args[i].type) {
 3053     case RPC2_INTEGER_TAG:
 3054         switch (args[i].mode) {
 3055         case IN_MODE:
 3056             parms[i].integer = va_arg(ap, RPC2_Integer);
 3057         break;
 3058         case OUT_MODE:
 3059         case IN_OUT_MODE:
 3060             parms[i].integerp = va_arg(ap, RPC2_Integer **);
 3061         default:
 3062         break;
 3063         }
 3064         break;
 3065     case RPC2_UNSIGNED_TAG:
 3066         switch (args[i].mode) {
 3067         case IN_MODE:
 3068             parms[i].unsgned = va_arg(ap, RPC2_Unsigned);
 3069         break;
 3070         case OUT_MODE:
 3071         case IN_OUT_MODE:
 3072             parms[i].unsgnedp = va_arg(ap, RPC2_Unsigned **);
 3073         default:
 3074         break;
 3075         }
 3076         break;
 3077     case RPC2_BYTE_TAG:
 3078         switch (args[i].mode) {
 3079         case IN_MODE:
 3080             parms[i].byte = (RPC2_Byte)va_arg(ap, int);
 3081         break;
 3082         case OUT_MODE:
 3083         case IN_OUT_MODE:
 3084             parms[i].bytep = va_arg(ap, RPC2_Byte **);
 3085         default:
 3086         break;
 3087         }
 3088         break;
 3089     case RPC2_STRING_TAG:
 3090         switch (args[i].mode) {
 3091         case IN_MODE:
 3092             parms[i].string = va_arg(ap, RPC2_String);
 3093         break;
 3094         case OUT_MODE:
 3095         case IN_OUT_MODE:
 3096             parms[i].stringp = va_arg(ap, RPC2_String **);
 3097         default:
 3098         break;
 3099         }
 3100         break;
 3101     case RPC2_COUNTEDBS_TAG:
 3102         switch (args[i].mode) {
 3103         case IN_MODE:
 3104             parms[i].cbs = va_arg(ap, RPC2_CountedBS *);
 3105         break;
 3106         case OUT_MODE:
 3107         case IN_OUT_MODE:
 3108             parms[i].cbsp = va_arg(ap, RPC2_CountedBS **);
 3109         default:
 3110         break;
 3111         }
 3112         break;
 3113     case RPC2_BOUNDEDBS_TAG:
 3114         switch (args[i].mode) {
 3115         case IN_MODE:
 3116             parms[i].bbs = va_arg(ap, RPC2_BoundedBS *);
 3117         break;
 3118         case OUT_MODE:
 3119         case IN_OUT_MODE:
 3120             parms[i].bbsp = va_arg(ap, RPC2_BoundedBS **);
 3121         default:
 3122         break;
 3123         }
 3124         break;
 3125     case RPC2_BULKDESCRIPTOR_TAG:
 3126         switch (args[i].mode) {
 3127         case IN_MODE:
 3128         case OUT_MODE:
 3129         case IN_OUT_MODE:
 3130             parms[i].sedp = va_arg(ap, SE_Descriptor *);
 3131         default:
 3132         break;
 3133         }
 3134         break;
 3135     case RPC2_ENCRYPTIONKEY_TAG:
 3136         switch (args[i].mode) {
 3137         case IN_MODE:
 3138             parms[i].key = va_arg(ap, RPC2_EncryptionKey *);
 3139         break;
 3140         case OUT_MODE:
 3141         case IN_OUT_MODE:
 3142             parms[i].keyp = va_arg(ap, RPC2_EncryptionKey **);
 3143         default:
 3144         break;
 3145         }
 3146         break;
 3147     case RPC2_STRUCT_TAG:
 3148         switch (args[i].mode) {
 3149         case IN_MODE:
 3150             parms[i].structp = va_arg(ap, union PARM *);
 3151         break;
 3152         case OUT_MODE:
 3153         case IN_OUT_MODE:
 3154             parms[i].structpp = va_arg(ap, union PARM **);
 3155         default:
 3156         break;
 3157         }
 3158         break;
 3159     case RPC2_ENUM_TAG:
 3160         switch (args[i].mode) {
 3161         case IN_MODE:
 3162             parms[i].integer = va_arg(ap, RPC2_Integer);
 3163         break;
 3164         case OUT_MODE:
 3165         case IN_OUT_MODE:
 3166             parms[i].integerp = va_arg(ap, RPC2_Integer **);
 3167         default:
 3168         break;
 3169         }
 3170         break;
 3171     case RPC2_DOUBLE_TAG:
 3172         /* not supported */
 3173         break;
 3174     }
 3175     }
 3176     va_end(ap);
 3177 
 3178     for (i = 0; args[i].mode != C_END; i++)
 3179     {
 3180     /* get_len and struct_len expect to be able to twiddle the arg and parm
 3181      * pointers when it recurses internally. */
 3182         ARG *xarg = &args[i];
 3183     PARM *xparm = &parms[i];
 3184 
 3185         switch (args[i].mode) {
 3186     case IN_MODE:
 3187     case IN_OUT_MODE:
 3188         switch (args[i].type) {
 3189         case RPC2_STRUCT_TAG:
 3190             len += struct_len(&xarg, &xparm);
 3191         break;
 3192         case RPC2_BULKDESCRIPTOR_TAG:
 3193             args[i].bound = 0;
 3194         break;
 3195         default:
 3196             args[i].bound = 0;
 3197         len += get_len(&xarg, &xparm, args[i].mode);
 3198         break;
 3199         }
 3200         break;
 3201     case OUT_MODE:
 3202         if (args[i].type == RPC2_BOUNDEDBS_TAG)
 3203             len += get_len(&xarg, &xparm, args[i].mode);
 3204     default:
 3205         break;
 3206     }
 3207     }
 3208 
 3209     free(parms);
 3210     return len;
 3211 }
 3212 
 3213 
 3214 /* Pack a CML entry. Looks surprisingly similar to RLE_Size, since most of the
 3215  * code deals with correctly unpacking the va_arg list. */
 3216 static void RLE_Pack(PARM **ptr, ARG *args ...)
 3217 {
 3218     PARM *parms;
 3219     int i;
 3220     va_list ap;
 3221 
 3222     /* variable arguments can be in registers or on the stack and the alignment
 3223      * may differ based on the native size of the type. In order to more easily
 3224      * pass them on to other functions we pull them out first. */
 3225 
 3226     /* allocate an array to hold the arguments */
 3227     for (i = 0; args[i].mode != C_END; i++);
 3228     parms = (PARM *)malloc(i * sizeof(PARM) + 1);
 3229     CODA_ASSERT(parms != NULL);
 3230 
 3231     va_start(ap, args);
 3232     for (i = 0; args[i].mode != C_END; i++)
 3233     {
 3234         switch (args[i].type) {
 3235     case RPC2_INTEGER_TAG:
 3236         switch (args[i].mode) {
 3237         case IN_MODE:
 3238             parms[i].integer = va_arg(ap, RPC2_Integer);
 3239         break;
 3240         case OUT_MODE:
 3241         case IN_OUT_MODE:
 3242             parms[i].integerp = va_arg(ap, RPC2_Integer **);
 3243         default:
 3244         break;
 3245         }
 3246         break;
 3247     case RPC2_UNSIGNED_TAG:
 3248         switch (args[i].mode) {
 3249         case IN_MODE:
 3250             parms[i].unsgned = va_arg(ap, RPC2_Unsigned);
 3251         break;
 3252         case OUT_MODE:
 3253         case IN_OUT_MODE:
 3254             parms[i].unsgnedp = va_arg(ap, RPC2_Unsigned **);
 3255         default:
 3256         break;
 3257         }
 3258         break;
 3259     case RPC2_BYTE_TAG:
 3260         switch (args[i].mode) {
 3261         case IN_MODE:
 3262             parms[i].byte = (RPC2_Byte)va_arg(ap, int);
 3263         break;
 3264         case OUT_MODE:
 3265         case IN_OUT_MODE:
 3266             parms[i].bytep = va_arg(ap, RPC2_Byte **);
 3267         default:
 3268         break;
 3269         }
 3270         break;
 3271     case RPC2_STRING_TAG:
 3272         switch (args[i].mode) {
 3273         case IN_MODE:
 3274             parms[i].string = va_arg(ap, RPC2_String);
 3275         break;
 3276         case OUT_MODE:
 3277         case IN_OUT_MODE:
 3278             parms[i].stringp = va_arg(ap, RPC2_String **);
 3279         default:
 3280         break;
 3281         }
 3282         break;
 3283     case RPC2_COUNTEDBS_TAG:
 3284         switch (args[i].mode) {
 3285         case IN_MODE:
 3286             parms[i].cbs = va_arg(ap, RPC2_CountedBS *);
 3287         break;
 3288         case OUT_MODE:
 3289         case IN_OUT_MODE:
 3290             parms[i].cbsp = va_arg(ap, RPC2_CountedBS **);
 3291         default:
 3292         break;
 3293         }
 3294         break;
 3295     case RPC2_BOUNDEDBS_TAG:
 3296         switch (args[i].mode) {
 3297         case IN_MODE:
 3298             parms[i].bbs = va_arg(ap, RPC2_BoundedBS *);
 3299         break;
 3300         case OUT_MODE:
 3301         case IN_OUT_MODE:
 3302             parms[i].bbsp = va_arg(ap, RPC2_BoundedBS **);
 3303         default:
 3304         break;
 3305         }
 3306         break;
 3307     case RPC2_BULKDESCRIPTOR_TAG:
 3308         switch (args[i].mode) {
 3309         case IN_MODE:
 3310         case OUT_MODE:
 3311         case IN_OUT_MODE:
 3312             parms[i].sedp = va_arg(ap, SE_Descriptor *);
 3313         default:
 3314         break;
 3315         }
 3316         break;
 3317     case RPC2_ENCRYPTIONKEY_TAG:
 3318         switch (args[i].mode) {
 3319         case IN_MODE:
 3320             parms[i].key = va_arg(ap, RPC2_EncryptionKey *);
 3321         break;
 3322         case OUT_MODE:
 3323         case IN_OUT_MODE:
 3324             parms[i].keyp = va_arg(ap, RPC2_EncryptionKey **);
 3325         default:
 3326         break;
 3327         }
 3328         break;
 3329     case RPC2_STRUCT_TAG:
 3330         switch (args[i].mode) {
 3331         case IN_MODE:
 3332             parms[i].structp = va_arg(ap, union PARM *);
 3333         break;
 3334         case OUT_MODE:
 3335         case IN_OUT_MODE:
 3336             parms[i].structpp = va_arg(ap, union PARM **);
 3337         default:
 3338         break;
 3339         }
 3340         break;
 3341     case RPC2_ENUM_TAG:
 3342         switch (args[i].mode) {
 3343         case IN_MODE:
 3344             parms[i].integer = va_arg(ap, RPC2_Integer);
 3345         break;
 3346         case OUT_MODE:
 3347         case IN_OUT_MODE:
 3348             parms[i].integerp = va_arg(ap, RPC2_Integer **);
 3349         default:
 3350         break;
 3351         }
 3352         break;
 3353     case RPC2_DOUBLE_TAG:
 3354         /* not supported */
 3355         break;
 3356     }
 3357     }
 3358     va_end(ap);
 3359 
 3360     for (i = 0; args[i].mode != C_END; i++)
 3361     {
 3362     /* pack and pack_struct expect to be able to twiddle the parm pointer
 3363      * when they recurse internally. */
 3364     PARM *xparm = &parms[i];
 3365 
 3366         switch (args[i].mode) {
 3367     case IN_MODE:
 3368     case IN_OUT_MODE:
 3369         switch (args[i].type) {
 3370         case RPC2_STRUCT_TAG:
 3371             pack_struct(&args[i], &xparm, ptr);
 3372         break;
 3373         case RPC2_BULKDESCRIPTOR_TAG:
 3374         break;
 3375         default:
 3376         pack(&args[i], &xparm, ptr);
 3377         break;
 3378         }
 3379         break;
 3380     case OUT_MODE:
 3381         if (args[i].type == RPC2_BOUNDEDBS_TAG)
 3382             pack(&args[i], &xparm, ptr);
 3383     default:
 3384         break;
 3385     }
 3386     }
 3387 }
 3388 
 3389 
 3390 /*  *****  Routines for Handling Inconsistencies and Safeguarding Against Catastrophe  *****  */
 3391 
 3392 int PathAltered(VenusFid *cfid, char *suffix, ClientModifyLog *CML, cmlent *starter)
 3393 {
 3394     char buf[MAXPATHLEN];
 3395     cml_iterator next(*CML, CommitOrder);
 3396     cmlent *m;
 3397 
 3398     /* can't use cml_iterator's prelude because we need to start from starter! */
 3399     while ((m = next())) {
 3400       if (m == starter)
 3401     break;
 3402     }
 3403 
 3404     while (m) {
 3405     if (m->opcode == CML_Remove_OP && FID_EQ(&m->u.u_remove.CFid, cfid)) {
 3406         /* when the cfid is removed, prepend suffix and replace cfid with its father */
 3407         if (suffix[0]) 
 3408           sprintf(buf, "%s/%s", m->Name, suffix);
 3409         else 
 3410           sprintf(buf, "%s", m->Name);
 3411         strcpy(suffix, buf);
 3412         *cfid = m->u.u_remove.PFid;
 3413         return 1;
 3414     }
 3415 
 3416     if (m->opcode == CML_RemoveDir_OP && FID_EQ(&m->u.u_rmdir.CFid, cfid)) {
 3417         /*
 3418          * when the current fid(directory) is removed, prepend suffix
 3419          * replace cfid with its father.
 3420          */
 3421         if (suffix[0])
 3422           sprintf(buf, "%s/%s", m->Name, suffix);
 3423         else
 3424           sprintf(buf, "%s", m->Name);
 3425         strcpy(suffix, buf);
 3426         *cfid = m->u.u_rmdir.PFid;
 3427         return 1;
 3428     }
 3429 
 3430     if (m->opcode == CML_Rename_OP && FID_EQ(&m->u.u_rename.SFid, cfid)) {
 3431         /*
 3432          * when the current fid is renamed, prepend the original name to
 3433          * suffix and replace cfid with the original father fid.
 3434          */
 3435         if (suffix[0])
 3436           sprintf(buf, "%s/%s", m->Name, suffix);
 3437         else
 3438           sprintf(buf, "%s", m->Name);
 3439         strcpy(suffix, buf);
 3440         *cfid = m->u.u_rename.SPFid;
 3441         return 1;
 3442     }
 3443     m = next();
 3444     }
 3445     return 0;
 3446 }
 3447 
 3448 /* local-repair modification */
 3449 void RecoverPathName(char *path, VenusFid *fid, ClientModifyLog *CML, cmlent *starter)
 3450 {
 3451     /* this algorithm is single-volume based */
 3452     CODA_ASSERT(path && fid && CML && starter);
 3453     LOG(100, ("RecoverPathName: fid = %s\n", FID_(fid)));
 3454 
 3455     VenusFid cfid = *fid;
 3456     char suffix[MAXPATHLEN];
 3457     char buf[MAXPATHLEN];
 3458 
 3459     suffix[0] = '\0';
 3460 
 3461     /* the loog invariant is "path(cfid)/suffix == path(fid)" */
 3462     while (! FID_IsVolRoot(&cfid) ) {
 3463     /* while the current fid is root of the volume */
 3464     if (!PathAltered(&cfid, suffix, CML, starter)) {
 3465         /*
 3466          * only deal with the situation when cfid has been not removed or
 3467          * renamed. otherwise, cfid and suffix has alread been adjusted by
 3468          * PathAltered to maintain the loop invariant. Note that the object
 3469          * corresponding to cfid now is guaranteed to be alive.
 3470          */
 3471         fsobj *f = FSDB->Find(&cfid);
 3472         if (f == NULL) {
 3473         LOG(0, ("RecoverPathName: fid = %s object no cached\n", FID_(&cfid)));
 3474         /* gcc-3.2 barfs about trigraps when it sees ? ? /, by
 3475          * splitting it up in two strings that are joined by the
 3476          * preprocessor we avoid this warning. */
 3477         sprintf(path, "??" "?/%s", suffix);
 3478         return;
 3479         }
 3480         if (suffix[0])
 3481           sprintf(buf, "%s/%s", f->comp, suffix);
 3482         else
 3483           sprintf(buf, "%s", f->comp);
 3484         strcpy(suffix, buf);
 3485 
 3486         /* going up to its parent */
 3487         if (f->IsRoot() && f->u.mtpoint) {
 3488         /* this must be the global-root-node of a local-repair subtree */
 3489         cfid = f->u.mtpoint->pfid;
 3490         } else {
 3491         cfid = f->pfid;
 3492         }
 3493     }
 3494     }
 3495     char prefix[MAXPATHLEN];
 3496     fsobj *f = FSDB->Find(&cfid);   /* find the root object of the lowest volume */
 3497     if (f == NULL) {
 3498     LOG(0, ("RecoverPathName: volume root %s not cached\n", FID_(&cfid)));
 3499     /* gcc-3.2 barfs about trigraps when it sees ? ? / */
 3500     sprintf(path, "??" "?/%s", suffix);
 3501     return;
 3502     }
 3503     f->GetPath(prefix, 1);
 3504     if (suffix[0])
 3505       sprintf(path, "%s/%s", prefix, suffix);
 3506     else
 3507       sprintf(path, "%s", prefix);
 3508 }
 3509 
 3510 
 3511 int repvol::CheckPointMLEs(uid_t uid, char *ckpdir) 
 3512 {
 3513     if (CML.count() == 0)
 3514     return(ENOENT);
 3515     if (CML.owner != uid && uid != V_UID)
 3516     return(EACCES);
 3517 
 3518     if ( rvmlib_in_transaction() ) {
 3519         CHOKE("CheckPointMLEs started while in transaction!");
 3520     }
 3521 
 3522     int code = CML.CheckPoint(ckpdir);
 3523     return(code);
 3524 }
 3525 
 3526 
 3527 /* MUST NOT be called from within transaction! */
 3528 int repvol::PurgeMLEs(uid_t uid)
 3529 {
 3530     if (CML.count() == 0)
 3531     return(ENOENT);
 3532     if (CML.owner != uid && uid != V_UID)
 3533     return(EACCES);
 3534     if (IsReplicated() && ((repvol *)this)->IsReintegrating())
 3535       return EACCES;
 3536 
 3537     LOG(0, ("volent::PurgeMLEs:(%s) (%x.%x)\n", name, realm->Id(), vid));
 3538 
 3539     /*
 3540      * Step 1 was removed on 7/8/05
 3541      */
 3542 
 3543     {   /*
 3544      * Step 2: cleanup everything in the CML, even there are records
 3545      * marked as to-be-repaired or repair-mutation.
 3546      */
 3547     cmlent *m;
 3548     rec_dlist_iterator next(CML.list, AbortOrder);
 3549     rec_dlink *d = next();  /* get the first (last) element */
 3550     while (1) {
 3551         if (!d) break;
 3552         m = strbase(cmlent, d, handle);
 3553         d = next();
 3554         Recov_BeginTrans();
 3555            if (m->IsToBeRepaired())
 3556               /* 
 3557                * this record must be associated with
 3558                * some local objects whose subtree root  
 3559                * is not in this volume. since we kill the
 3560                * local objects later, we use cmlent destructor
 3561                * instead of the cmlent::abort().
 3562                */
 3563               delete m;
 3564            else 
 3565               m->abort();
 3566         Recov_EndTrans(MAXFP);
 3567     }
 3568     VOL_ASSERT(this, CML.count() == 0);
 3569     }
 3570 
 3571     /*
 3572      * Step 3 was removed on 7/8/05
 3573      */
 3574 
 3575     /* trigger a volume state transition */
 3576     flags.transition_pending = 1;
 3577 
 3578     return(0);
 3579 }
 3580 
 3581 
 3582 int repvol::LastMLETime(unsigned long *time)
 3583 {
 3584     if (CML.count() == 0)
 3585     return(ENOENT);
 3586 
 3587     cmlent *lastmle = strbase(cmlent, CML.list.last(), handle);
 3588     *time = lastmle->time;
 3589 
 3590     return(0);
 3591 }
 3592 
 3593 struct WriteLinksHook {
 3594     VnodeId vnode;
 3595     Unique_t vunique;
 3596     const char *name;
 3597     ino_t inode;
 3598     uid_t uid;
 3599     nlink_t nlink;
 3600     time_t time;
 3601     FILE *fp;
 3602     int code;
 3603 };
 3604 
 3605 static int WriteLinks(struct DirEntry *de, void *arg)
 3606 {
 3607     VnodeId vnode;
 3608     Unique_t vunique;
 3609     char *name = de->name;
 3610     const char *comp;
 3611     size_t prefixlen;
 3612     char namebuf[CODA_MAXPATHLEN];
 3613     struct WriteLinksHook *hook = (struct WriteLinksHook *)arg;
 3614 
 3615     if (hook->code)
 3616     return 0;
 3617 
 3618     FID_NFid2Int(&de->fid, &vnode, &vunique);
 3619     if (vnode != hook->vnode || vunique != hook->vunique)
 3620     return 0;
 3621 
 3622     comp = strrchr(hook->name, '/') + 1;
 3623     CODA_ASSERT(comp != NULL);
 3624 
 3625     if (!!STREQ(comp, name)) return 0;
 3626 
 3627     prefixlen = comp - hook->name;
 3628 
 3629     strncpy(namebuf, hook->name, prefixlen);
 3630     strcpy(&namebuf[prefixlen], name);
 3631 
 3632     hook->code = archive_write_entry(hook->fp, hook->inode, 0100644, hook->uid,
 3633                      hook->nlink, hook->time, 0, namebuf,
 3634                      hook->name);
 3635     return 0;
 3636 }
 3637 
 3638 int cmlent::checkpoint(FILE *fp)
 3639 {
 3640     /* counter to create unique inode numbers in the generated archive file */
 3641     static int inode = 1;
 3642     char name[CODA_MAXPATHLEN];
 3643     size_t linklen;
 3644     nlink_t nlink;
 3645     fsobj *f;
 3646     int err;
 3647 
 3648     /* make sure our 'inode numbers' stay within in the valid range for cpio
 3649      * archives */
 3650     if (archive_type == CPIO_ODC && inode >= 01000000) inode = 1;
 3651 
 3652     switch(opcode) {
 3653     case CML_Store_OP:
 3654         {
 3655         /* Only checkpoint LAST store! */
 3656         cml_iterator next(*(ClientModifyLog *)log, AbortOrder,
 3657                   &u.u_store.Fid);
 3658         cmlent *m;
 3659         while ((m = next()) && m->opcode != CML_Store_OP) /* loop */;
 3660         CODA_ASSERT(m);
 3661         if (m != this) break;
 3662         }
 3663 
 3664         f = FSDB->Find(&u.u_store.Fid);
 3665         CODA_ASSERT(f);
 3666 
 3667         if (!HAVEALLDATA(f)) {
 3668         eprint("can't checkpoint (%s), no data", FID_(&u.u_store.Fid));
 3669         break;
 3670         }
 3671 
 3672         f->GetPath(name);
 3673 
 3674         /* Are we going to add hard-link entries for alternate names? */
 3675         nlink = f->pfso ? f->stat.LinkCount : 1;
 3676 
 3677         err = archive_write_entry(fp, inode, 0100644, uid, nlink, time,
 3678                       u.u_store.Length, name, NULL);
 3679         if (err) return err;
 3680 
 3681         /* write out file contents */
 3682         if (u.u_store.Length) {
 3683         err = archive_write_data(fp, f->data.file->Name());
 3684         if (err) return err;
 3685         }
 3686 
 3687         if (nlink > 1) {
 3688         struct WriteLinksHook hook;
 3689 
 3690         hook.vnode = f->fid.Vnode;
 3691         hook.vunique = f->fid.Unique;
 3692         hook.name = name;
 3693         hook.inode = inode;
 3694         hook.uid = uid;
 3695         hook.time = time;
 3696         hook.fp = fp;
 3697         hook.code = 0;
 3698 
 3699         DH_EnumerateDir(&f->pfso->data.dir->dh, WriteLinks,
 3700                 (void *)&hook);
 3701 
 3702         if (hook.code) return hook.code;
 3703         }
 3704 
 3705         inode++;
 3706         break;
 3707 
 3708     case CML_MakeDir_OP:
 3709         f = FSDB->Find(&u.u_mkdir.CFid);
 3710         CODA_ASSERT(f);
 3711 
 3712         f->GetPath(name);
 3713 
 3714         err = archive_write_entry(fp, inode, 040755, uid, 1, time, 0, name,
 3715                       NULL);
 3716         if (err) return err;
 3717 
 3718         inode++;
 3719         break;
 3720 
 3721     case CML_SymLink_OP:
 3722         f = FSDB->Find(&u.u_symlink.CFid);
 3723         CODA_ASSERT(f);
 3724 
 3725         f->GetPath(name);
 3726 
 3727         linklen = strlen((char *)Name);
 3728 
 3729         err = archive_write_entry(fp, inode, 0120777, uid, 1, time,
 3730                       linklen, name, (const char *)Name);
 3731         if (err) return err;
 3732 
 3733         inode++;
 3734         break;
 3735 
 3736     case CML_Repair_OP:
 3737         eprint("Not checkpointing file (%s) that was repaired\n",
 3738            FID_(&u.u_repair.Fid));
 3739         break;
 3740 
 3741     default:
 3742         break;
 3743     }
 3744     return 0;
 3745 }
 3746 
 3747 static void BackupOldFile(const char *name)
 3748 {
 3749     char oldname[MAXPATHLEN];
 3750 
 3751     CODA_ASSERT(strlen(name) < (MAXPATHLEN - 4));
 3752     strcpy(oldname, name);
 3753     strcat(oldname, ".old");
 3754 
 3755     ::rename(name, oldname);
 3756 }
 3757 
 3758 /* Returns {0, ENOSPC}. */
 3759 int ClientModifyLog::CheckPoint(char *ckpdir)
 3760 {
 3761     repvol *vol = strbase(repvol, this, CML);
 3762     LOG(1, ("ClientModifyLog::CheckPoint: (%s), cdir = %s\n",
 3763          vol->name, (ckpdir ? ckpdir : "")));
 3764 
 3765     int code = 0, n;
 3766 
 3767     /* the spool directory name */
 3768     char spoolname[MAXPATHLEN], *volname;
 3769 
 3770     if (ckpdir) strcpy(spoolname, ckpdir);
 3771     else    MakeUserSpoolDir(spoolname, owner);
 3772 
 3773     strcat(spoolname, "/");
 3774 
 3775     n = strlen(spoolname);
 3776     volname = spoolname + n;
 3777 
 3778     /* The last component of the name will be "<realm>_<volname>". */
 3779     n = snprintf(volname, MAXPATHLEN-n, "%s_%s", vol->realm->Name(), vol->name);
 3780     if (n < 0) return 0;
 3781 
 3782     /* remove characters with possibly unwanted side effects from the last
 3783      * component */
 3784     for (char *cp = volname; *cp; cp++)
 3785     if (*cp == ':' || *cp == '/' || *cp == '|' || *cp == '@')
 3786         *cp = '_';
 3787 
 3788     char ckpname[MAXPATHLEN], lname[MAXPATHLEN];
 3789     /* append .tar/.cpio and .cml */
 3790     strcpy(ckpname, spoolname);
 3791     if (archive_type == TAR_TAR || archive_type == TAR_USTAR)
 3792      strcat(ckpname, ".tar");
 3793     else strcat(ckpname, ".cpio");
 3794 
 3795     strcpy(lname, spoolname);
 3796     strcat(lname, ".cml");
 3797 
 3798     /* rename the old checkpoint file, if possible */
 3799     BackupOldFile(ckpname);
 3800     BackupOldFile(lname);
 3801 
 3802     FILE *dfp = NULL, *ofp = NULL;
 3803 
 3804     if ((dfp = fopen(ckpname, "w+")) == NULL) {
 3805     eprint("Couldn't open %s for checkpointing", ckpname);
 3806     return(ENOENT);
 3807     }
 3808 #ifndef __CYGWIN32__
 3809     ::fchown(fileno(dfp), owner, V_GID);
 3810 #else
 3811     ::chown(ckpname, owner, V_GID);
 3812 #endif
 3813     ::fchmod(fileno(dfp), 0600);
 3814 
 3815     if ((ofp = fopen(lname, "w+")) == NULL) {
 3816     eprint("Couldn't open %s for checkpointing", lname);
 3817     return(ENOENT);
 3818     }
 3819 #ifndef __CYGWIN32__
 3820     ::fchown(fileno(ofp), owner, V_GID);
 3821 #else
 3822     ::chown(lname, owner, V_GID);
 3823 #endif
 3824    ::fchmod(fileno(ofp), 0600);
 3825 
 3826     /*
 3827      * Iterate through the MLEs (in commit order), checkpointing each in turn.
 3828      * Lock the CML exclusively to prevent changes during checkpoint.  This is
 3829      * necessary because the thread yields during file write.  If at the time
 3830      * there is another thread doing mutations to the volume causing some of
 3831      * the elements in the CML being iterated to be canceled, venus will
 3832      * assertion fail.
 3833      */
 3834     ObtainWriteLock(&vol->CML_lock);
 3835     eprint("Checkpointing %s to %s and %s", vol->name, ckpname, lname);
 3836     cml_iterator next(*this, CommitOrder);
 3837     cmlent *m;
 3838     while ((m = next())) {
 3839     m->writeops(ofp);
 3840     if (code) continue;
 3841     code = m->checkpoint(dfp);
 3842     }
 3843     if (code) {
 3844     LOG(0, ("checkpointing of %s to %s failed (%d)",
 3845         vol->name, ckpname, code));
 3846     eprint("checkpointing of %s to %s failed (%d)",
 3847            vol->name, ckpname, code);
 3848     };
 3849     ReleaseWriteLock(&vol->CML_lock);
 3850 
 3851     /* Write the trailer block and flush the data. */
 3852     if (code == 0)
 3853     code = archive_write_trailer(dfp);
 3854 
 3855     /* Close the CKP file. */
 3856     fclose(dfp);
 3857     fclose(ofp);
 3858 
 3859     /* Unlink in the event of any error. */
 3860     if (code != 0) {
 3861     ::unlink(ckpname);
 3862     ::unlink(lname);
 3863     eprint("Couldn't successfully checkpoint %s and %s", ckpname, lname);
 3864     }
 3865 
 3866     return(code);
 3867 }
 3868 
 3869 
 3870 
 3871 /* Invalidate the fsobj's following unsuccessful reintegration. */
 3872 /* MUST NOT be called from within transaction! */
 3873 void ClientModifyLog::IncAbort(int Tid)
 3874 {
 3875     repvol *vol = strbase(repvol, this, CML);
 3876     LOG(0, ("ClientModifyLog::IncAbort: (%s) and tid = %d\n", vol->name, Tid));
 3877     /* eprint("IncAbort CML for %s and tid %d\n", vol->name, Tid); */
 3878 
 3879     CODA_ASSERT(count() > 0);
 3880 
 3881     Recov_BeginTrans();
 3882     rec_dlist_iterator next(list, AbortOrder);
 3883     rec_dlink *d = next();      /* get the first (last) element */
 3884 
 3885     while (1) {
 3886         if (!d) break;          /* list exhausted */
 3887         cmlent *m = strbase(cmlent, d, handle);
 3888         if (m->GetTid() == Tid) {
 3889         m->print(logFile);
 3890         d = next(); /* advance d before it is un-listed by m->abort() */
 3891         m->abort();
 3892         } else {
 3893         d = next();
 3894         }
 3895     }
 3896     Recov_EndTrans(DMFP);
 3897 }
 3898 
 3899 /* MUST be called from within transaction! */
 3900 void cmlent::abort()
 3901 {
 3902     repvol *vol = strbase(repvol, log, CML);
 3903     vol->RecordsAborted++;
 3904 
 3905     /* Step 1:  CODA_ASSERT that there are no edges emanating from this record. */
 3906     CODA_ASSERT(succ == 0 || succ->count() == 0);
 3907 
 3908     /* Step 2:  Kill fsos linked into this record */
 3909     dlist_iterator next(*fid_bindings);
 3910     dlink *d;
 3911 
 3912     while ((d = next())) {
 3913     binding *b = strbase(binding, d, binder_handle);
 3914     fsobj *f = (fsobj *)b->bindee;
 3915         
 3916     /* sanity checks */
 3917     CODA_ASSERT(f && (f->MagicNumber == FSO_MagicNumber));  /* better be an fso */
 3918 
 3919     f->Lock(WR);
 3920     f->Kill();
 3921 
 3922     FSDB->Put(&f);
 3923     }
 3924 
 3925     delete this;
 3926 }
 3927 
 3928 
 3929 /*  *****  Routines for Maintaining fsobj <--> cmlent Bindings  *****  */
 3930 
 3931 /* MUST be called from within transaction! */
 3932 void ClientModifyLog::AttachFidBindings()
 3933 {
 3934     cml_iterator next(*this);
 3935     cmlent *m;
 3936     while ((m = next()))
 3937     m->AttachFidBindings();
 3938 }
 3939 
 3940 
 3941 /* MUST be called from within transaction! */
 3942 void cmlent::AttachFidBindings()
 3943 {
 3944     VenusFid *fids[3];
 3945     GetAllFids(fids);
 3946 
 3947     for (int i = 0; i < 3; i++) {
 3948     VenusFid *fidp = fids[i];
 3949     if (fidp == 0) break;
 3950 
 3951     fsobj *f = FSDB->Find(fidp);
 3952     if (f == 0) {
 3953         print(logFile);
 3954         (strbase(repvol, log, CML))->print(logFile);
 3955         CHOKE("cmlent::AttachFidBindings: can't find (%s)", FID_(fidp));
 3956     }
 3957 
 3958     binding *b = new binding;
 3959     b->binder = this;
 3960     if (fid_bindings == 0)
 3961         fid_bindings = new dlist;
 3962     fid_bindings->append(&b->binder_handle);
 3963     f->AttachMleBinding(b);
 3964 
 3965     if (opcode == CML_Store_OP && IsFrozen())
 3966         f->MakeShadow();
 3967     }
 3968 }
 3969 
 3970 
 3971 void cmlent::DetachFidBindings()
 3972 {
 3973     if (fid_bindings == 0) return;
 3974 
 3975     dlink *d;
 3976     while ((d = fid_bindings->get())) {
 3977     binding *b = strbase(binding, d, binder_handle);
 3978     fsobj *f = (fsobj *)b->bindee;
 3979     f->DetachMleBinding(b);
 3980     b->binder = 0;
 3981     delete b;
 3982     }
 3983     delete fid_bindings;
 3984     fid_bindings = 0;
 3985 }
 3986 
 3987 void cmlent::getfids(VenusFid fid[3])
 3988 {
 3989     fid[0] = fid[1] = fid[2] = NullFid;
 3990     switch(opcode) {
 3991     case CML_Store_OP:     fid[0] = u.u_store.Fid;
 3992                break;
 3993     case CML_Utimes_OP:    fid[0] = u.u_utimes.Fid;
 3994                break;
 3995     case CML_Chown_OP:     fid[0] = u.u_chown.Fid;
 3996                break;
 3997     case CML_Chmod_OP:     fid[0] = u.u_chmod.Fid;
 3998                break;
 3999     case CML_Create_OP:    fid[0] = u.u_create.PFid;
 4000                fid[1] = u.u_create.CFid;
 4001                break;
 4002     case CML_Remove_OP:    fid[0] = u.u_remove.PFid;
 4003                fid[1] = u.u_remove.CFid;
 4004                break;
 4005     case CML_Link_OP:      fid[0] = u.u_link.PFid;
 4006                fid[1] = u.u_link.CFid;
 4007                break;
 4008     case CML_Rename_OP:    fid[0] = u.u_rename.SPFid;
 4009                fid[1] = u.u_rename.TPFid;
 4010                fid[2] = u.u_rename.SFid;
 4011                break;
 4012     case CML_MakeDir_OP:   fid[0] = u.u_mkdir.PFid;
 4013                fid[1] = u.u_mkdir.CFid;
 4014                break;
 4015     case CML_RemoveDir_OP: fid[0] = u.u_rmdir.PFid;
 4016                fid[1] = u.u_rmdir.CFid;
 4017                break;
 4018     case CML_SymLink_OP:   fid[0] = u.u_symlink.PFid;
 4019                fid[1] = u.u_symlink.CFid;
 4020                break;
 4021     case CML_Repair_OP:    fid[0] = u.u_repair.Fid;
 4022                break;
 4023     default:           break;
 4024     }
 4025 }
 4026 
 4027 void cmlent::writeops(FILE *fp)
 4028 {
 4029     char path[MAXPATHLEN], path2[MAXPATHLEN];
 4030     char msg[2 * MAXPATHLEN + 100];     // this is enough for writing one entry
 4031 
 4032     switch(opcode) {
 4033     case CML_Store_OP:
 4034     RecoverPathName(path, &u.u_store.Fid, log, this);
 4035     sprintf(msg, "Store \t%s (length = %d)", path, u.u_store.Length);
 4036     break;
 4037 
 4038     case CML_Utimes_OP:
 4039     RecoverPathName(path, &u.u_utimes.Fid, log, this);
 4040     sprintf(msg, "Utime \t%s", path);
 4041     break;
 4042 
 4043     case CML_Chown_OP:
 4044     RecoverPathName(path, &u.u_chown.Fid, log, this);
 4045     sprintf(msg, "Chown \t%s (owner = %d)", path, u.u_chown.Owner);
 4046     break;
 4047 
 4048     case CML_Chmod_OP:
 4049     RecoverPathName(path, &u.u_chmod.Fid, log, this);
 4050     sprintf(msg, "Chmod \t%s (mode = %o)", path, u.u_chmod.Mode);
 4051     break;
 4052 
 4053     case CML_Create_OP:
 4054     RecoverPathName(path, &u.u_create.CFid, log, this);
 4055     sprintf(msg, "Create \t%s", path);
 4056     break;
 4057 
 4058     case CML_Remove_OP:
 4059     RecoverPathName(path, &u.u_remove.CFid, log, this);
 4060     sprintf(msg, "Remove \t%s", path);
 4061     break;
 4062 
 4063     case CML_Link_OP:
 4064     RecoverPathName(path, &u.u_link.CFid, log, this);
 4065     sprintf(msg, "Link \t%s to %s", path, Name);
 4066     break;
 4067 
 4068     case CML_Rename_OP:
 4069     RecoverPathName(path, &u.u_rename.SPFid, log, this);
 4070     RecoverPathName(path2, &u.u_rename.TPFid, log, this);
 4071     sprintf(msg, "Rename \t%s/%s (to: %s/%s)", path, Name, path2, NewName);
 4072     break;
 4073 
 4074     case CML_MakeDir_OP:
 4075     RecoverPathName(path, &u.u_mkdir.CFid, log, this);
 4076     sprintf(msg, "Mkdir \t%s", path);
 4077     break;
 4078 
 4079     case CML_RemoveDir_OP:
 4080     RecoverPathName(path, &u.u_rmdir.CFid, log, this);
 4081     sprintf(msg, "Rmdir \t%s", path);
 4082     break;
 4083 
 4084     case CML_SymLink_OP:
 4085     RecoverPathName(path, &u.u_symlink.CFid, log, this);
 4086     sprintf(msg, "Symlink %s (--> %s)", path, Name);
 4087     break;
 4088 
 4089     case CML_Repair_OP:
 4090     sprintf(msg, "Disconnected Repair by an ASR for %s",
 4091         FID_(&u.u_repair.Fid));
 4092     break;
 4093     default:
 4094     break;
 4095     }
 4096     
 4097     fprintf(fp, "%s\n", msg);
 4098 }
 4099 
 4100 
 4101 /* this routine determines if a cmlent is old enough to reintegrate. */
 4102 int cmlent::Aged()
 4103 {
 4104     time_t curTime = Vtime();
 4105     repvol *vol = strbase(repvol, log, CML);
 4106 
 4107     if (vol->IsSync())
 4108     return 1;
 4109 
 4110     if ((curTime - time) >= vol->AgeLimit)
 4111     return 1;
 4112 
 4113     return 0;
 4114 }
 4115 
 4116 
 4117 /* 
 4118  * simpleminded routine to estimate the amount of time to reintegrate
 4119  * this record (in milleseconds), given an estimate of bandwidth in 
 4120  * bytes/second.
 4121  */
 4122 unsigned long cmlent::ReintTime(unsigned long bw) {
 4123     double time = 0;
 4124 
 4125     if (bw > 0) {
 4126     time = (double) size();
 4127     if (opcode == CML_Store_OP) 
 4128         time += u.u_store.Length;  /* might be large */
 4129 
 4130     time = time * 1000.0/ (double) bw;
 4131     }
 4132 
 4133     LOG(10, ("cmlent::ReintTime: bandwidth = %d bytes/sec, time = %d msec\n",
 4134         bw, (unsigned long) time));
 4135     if (LogLevel >= 10) print(logFile);
 4136 
 4137     return((unsigned long) time);
 4138 }
 4139 
 4140 
 4141 unsigned long cmlent::ReintAmount(unsigned long *reint_time)
 4142 {
 4143     repvol *vol = strbase(repvol, log, CML);
 4144     unsigned long amount, offset;
 4145     unsigned long bw;   /* bandwidth, in bytes/sec */
 4146 
 4147     CODA_ASSERT(opcode == CML_Store_OP);
 4148 
 4149     /*
 4150      * try to get a dynamic bw estimate.  If that doesn't
 4151      * work, fall back on the static estimate.
 4152      */
 4153     vol->GetBandwidth(&bw);
 4154     bw /= 8; /* scaled to reduce overflows */
 4155 
 4156     //amount = (*reint_time / 1000) * bw;
 4157     amount = (bw > 0) ? (*reint_time / 125) * bw : u.u_store.Length;
 4158 
 4159     offset = u.u_store.Offset;
 4160     if (offset + amount > u.u_store.Length)
 4161     amount = u.u_store.Length - offset;
 4162 
 4163     //*reint_time -= (amount / bw) * 1000;
 4164     *reint_time -= (bw > 0) ? (amount * 125) / bw : 0;
 4165     return amount;
 4166 }
 4167 
 4168 
 4169 /* reintegrating --> frozen */
 4170 int cmlent::IsReintegrating() 
 4171 {
 4172     repvol *vol = strbase(repvol, log, CML);
 4173 
 4174     if (vol->flags.reintegrating && IsFrozen() &&
 4175     (tid != UNSET_TID) && (tid == vol->cur_reint_tid))
 4176         return 1;
 4177 
 4178     return 0;
 4179 }
 4180 
 4181 
 4182 /*  *****  Modify Log Iterator  *****  */
 4183 
 4184 /*
 4185  *    1. This implementation assumes that a dlist_iterator can correctly iterate over a rec_dlist as well as a dlist!
 4186  *    2. Iterating over records referencing a particular fid is grossly inefficient and needs to be improved!
 4187  *    3. Iterating starting after a prelude is inefficient and needs to be improved (by augmenting dlist_iterator)!
 4188  */
 4189 
 4190 cml_iterator::cml_iterator(ClientModifyLog& Log, CmlIterOrder Order,
 4191                 const VenusFid *Fid, cmlent *Prelude) {
 4192     log = &Log;
 4193     order = Order;
 4194     fidp = Fid;
 4195     next = 0;
 4196     rec_next = 0;
 4197     if (fidp == 0) {
 4198     rec_next = new rec_dlist_iterator(log->list, order);
 4199     }
 4200     else {
 4201     fid = *Fid;
 4202     fsobj *f = FSDB->Find(&fid);
 4203     if (f == 0) {
 4204         CHOKE("cml_iterator::cml_iterator: can't find (%s)", FID_(&fid));
 4205     }
 4206     if (f->mle_bindings)
 4207         next = new dlist_iterator(*f->mle_bindings, order);
 4208     }
 4209 
 4210     /* Skip over prelude. */
 4211     prelude = Prelude;
 4212     if (prelude != 0) {
 4213     cmlent *m;
 4214     while ((m = (*this)()) && m != prelude)
 4215         ;
 4216     CODA_ASSERT(m != 0);
 4217     }
 4218 }
 4219 
 4220 
 4221 cml_iterator::~cml_iterator() {
 4222     if (next != 0)
 4223     delete next;
 4224     if (rec_next != 0)
 4225     delete rec_next;
 4226 }
 4227 
 4228 
 4229 cmlent *cml_iterator::operator()() {
 4230     for (;;) {
 4231     if (rec_next) {
 4232         rec_dlink *d = (*rec_next)();
 4233         if (d == 0) return(0);
 4234         cmlent *m = strbase(cmlent, d, handle);
 4235         return(m);
 4236     }
 4237     else {
 4238         if (next == 0) return(0);
 4239         dlink *d = (*next)();
 4240         if (d == 0) return(0);
 4241         binding *b = strbase(binding, d, bindee_handle);
 4242         cmlent *m = (cmlent *)b->binder;
 4243         switch(m->opcode) {
 4244         case CML_Store_OP:
 4245             if (FID_EQ(&m->u.u_store.Fid, &fid)) return(m);
 4246             break;
 4247 
 4248         case CML_Utimes_OP:
 4249             if (FID_EQ(&m->u.u_utimes.Fid, &fid)) return(m);
 4250             break;
 4251 
 4252         case CML_Chown_OP:
 4253             if (FID_EQ(&m->u.u_chown.Fid, &fid)) return(m);
 4254             break;
 4255 
 4256         case CML_Chmod_OP:
 4257             if (FID_EQ(&m->u.u_chmod.Fid, &fid)) return(m);
 4258             break;
 4259 
 4260         case CML_Create_OP:
 4261             if (FID_EQ(&m->u.u_create.PFid, &fid)) return(m);
 4262             if (FID_EQ(&m->u.u_create.CFid, &fid)) return(m);
 4263             break;
 4264 
 4265         case CML_Remove_OP:
 4266             if (FID_EQ(&m->u.u_remove.PFid, &fid)) return(m);
 4267             if (FID_EQ(&m->u.u_remove.CFid, &fid)) return(m);
 4268             break;
 4269 
 4270         case CML_Link_OP:
 4271             if (FID_EQ(&m->u.u_link.PFid, &fid)) return(m);
 4272             if (FID_EQ(&m->u.u_link.CFid, &fid)) return(m);
 4273             break;
 4274 
 4275         case CML_Rename_OP:
 4276             if (FID_EQ(&m->u.u_rename.SPFid, &fid)) return(m);
 4277             if (FID_EQ(&m->u.u_rename.TPFid, &fid)) return(m);
 4278             if (FID_EQ(&m->u.u_rename.SFid, &fid)) return(m);
 4279             break;
 4280 
 4281         case CML_MakeDir_OP:
 4282             if (FID_EQ(&m->u.u_mkdir.PFid, &fid)) return(m);
 4283             if (FID_EQ(&m->u.u_mkdir.CFid, &fid)) return(m);
 4284             break;
 4285 
 4286         case CML_RemoveDir_OP:
 4287             if (FID_EQ(&m->u.u_rmdir.PFid, &fid)) return(m);
 4288             if (FID_EQ(&m->u.u_rmdir.CFid, &fid)) return(m);
 4289             break;
 4290 
 4291         case CML_SymLink_OP:
 4292             if (FID_EQ(&m->u.u_symlink.PFid, &fid)) return(m);
 4293             if (FID_EQ(&m->u.u_symlink.CFid, &fid)) return(m);
 4294             break;
 4295 
 4296             case CML_Repair_OP:
 4297             if (FID_EQ(&m->u.u_repair.Fid, &fid)) return(m);
 4298             break;
 4299 
 4300         default:
 4301             CODA_ASSERT(0);
 4302         }
 4303     }
 4304     }
 4305 }
 4306 
 4307 /*
 4308  * Unmark all cmlent's to_be_repaired flag. Useful after DoRepair.
 4309  */
 4310 void ClientModifyLog::ClearToBeRepaired(void)
 4311 {
 4312     cmlent *m;
 4313     cml_iterator next(*this, CommitOrder);
 4314     int num = 0;
 4315 
 4316     while ((m = next()))
 4317       if (m->flags.to_be_repaired) {
 4318     Recov_BeginTrans();
 4319     RVMLIB_REC_OBJECT(m->flags);
 4320     m->flags.to_be_repaired = 0;
 4321     Recov_EndTrans(MAXFP);
 4322     num++;
 4323       }
 4324     LOG(0, ("ClientModifyLog::ClearRepairFlags: cleared %d entries\n", num));
 4325 }