"Fossies" - the Fresh Open Source Software Archive

Member "coda-6.9.5/coda-src/venus/vol_vcb.cc" (1 Aug 2007, 14686 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_vcb.cc" see the Fossies "Dox" file reference documentation.

    1 /* BLURB gpl
    2 
    3                            Coda File System
    4                               Release 6
    5 
    6           Copyright (c) 1987-2003 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 
   22 /*
   23  *  Code relating to volume callbacks.
   24  */
   25 
   26 #ifdef __cplusplus
   27 extern "C" {
   28 #endif
   29 
   30 #include <stdio.h>
   31 #include <sys/types.h>
   32 #include <struct.h>
   33 #include <unistd.h>
   34 #include <stdlib.h>
   35 #include <netinet/in.h>
   36 
   37 #include <rpc2/rpc2.h>
   38 
   39 #ifdef __cplusplus
   40 }
   41 #endif
   42 
   43 /* interfaces */
   44 #include <vice.h>
   45 
   46 /* from venus */
   47 #include "comm.h"
   48 #include "fso.h"
   49 #include "mariner.h"
   50 #include "mgrp.h"
   51 #include "venuscb.h"
   52 #include "venusvol.h"
   53 #include "venus.private.h"
   54 #include "vproc.h"
   55 #include "worker.h"
   56 
   57 
   58 int vcbbreaks = 0;  /* count of broken volume callbacks */
   59 char VCBEnabled = 1;    /* use VCBs by default */
   60 
   61 
   62 int vdb::CallBackBreak(Volid *volid)
   63 {
   64     int rc = 0;
   65     volent *v = VDB->Find(volid);
   66 
   67     if (!v) return 0;
   68 
   69     if (v->IsReplicated()) {
   70     repvol *vp = (repvol *)v;
   71         rc = vp->CallBackBreak();
   72     }
   73     if (rc) vcbbreaks++;
   74 
   75     v->release();
   76 
   77     return(rc);
   78 }
   79 
   80 
   81 /*
   82  * GetVolAttr - Get a volume version stamp (or validate one if
   83  * present) and get a callback.  If validating, and there are
   84  * other volumes that need validating, do them too.
   85  */
   86 int repvol::GetVolAttr(uid_t uid)
   87 {
   88     LOG(100, ("repvol::GetVolAttr: %s, vid = 0x%x\n", name, vid));
   89 
   90     VOL_ASSERT(this, IsReachable());
   91 
   92     unsigned int i;
   93     int code = 0;
   94 
   95     /* Acquire an Mgroup. */
   96     mgrpent *m = 0;
   97     code = GetMgrp(&m, uid);
   98     if (code != 0) goto RepExit;
   99 
  100     long cbtemp; cbtemp = cbbreaks;
  101     {
  102     /* 
  103      * if we're fetching (as opposed to validating) volume state, 
  104      * we must first ensure all cached file state from this volume 
  105      * is valid (i.e., our cached state corresponds to the version 
  106      * information we will get).  If the file state can't be 
  107      * validated, we bail.
  108      */
  109     if (VV_Cmp(&VVV, &NullVV) == VV_EQ) {
  110         if ((code = ValidateFSOs())) 
  111         goto RepExit;
  112 
  113         RPC2_Integer VS;
  114         ARG_MARSHALL(OUT_MODE, RPC2_Integer, VSvar, VS, VSG_MEMBERS);
  115 
  116         CallBackStatus CBStatus;
  117         ARG_MARSHALL(OUT_MODE, CallBackStatus, CBStatusvar, CBStatus, VSG_MEMBERS);
  118 
  119         /* Make the RPC call. */
  120         MarinerLog("store::GetVolVS %s\n", name);
  121         MULTI_START_MESSAGE(ViceGetVolVS_OP);
  122         code = (int) MRPC_MakeMulti(ViceGetVolVS_OP, ViceGetVolVS_PTR,
  123                     VSG_MEMBERS, m->rocc.handles,
  124                     m->rocc.retcodes, m->rocc.MIp, 0, 0,
  125                     vid, VSvar_ptrs, CBStatusvar_ptrs);
  126         MULTI_END_MESSAGE(ViceGetVolVS_OP);
  127         MarinerLog("store::getvolvs done\n");
  128 
  129         /* Collate responses from individual servers and decide what to do next. */
  130         code = Collate_NonMutating(m, code);
  131         MULTI_RECORD_STATS(ViceGetVolVS_OP);
  132 
  133         if (code != 0) goto RepExit;
  134 
  135         if (cbtemp == cbbreaks) 
  136         CollateVCB(m, VSvar_bufs, CBStatusvar_bufs);
  137         } else {
  138         /* 
  139          * Figure out how many volumes to validate.
  140          * We can do this every call because there are a small number of volumes.
  141          * We send the server its version stamp, it its slot and sends back yea or nay.
  142          */
  143         int nVols = 0;
  144         ViceVolumeIdStruct VidList[MAX_PIGGY_VALIDATIONS];
  145 
  146         /* 
  147          * To minimize bandwidth, we should not send full version vectors
  148          * to each server.  We could send each server its version stamp,
  149          * but that would be extremely messy for multicast (which assumes
  150          * the same message goes to all destinations).  We compromise by
  151          * sending all the version stamps to each server.  If we had true
  152          * multicast, this would be cheaper than sending a set of unicasts
  153          * each with a different version stamp. The array is a BS because
  154          * there isn't a one to one correspondence between it and the
  155          * volume ID list. Besides, I hate introducing those damn
  156          * structures.
  157          */
  158         RPC2_CountedBS VSBS;
  159         VSBS.SeqLen = 0;
  160         VSBS.SeqBody = (RPC2_ByteSeq) malloc(MAX_PIGGY_VALIDATIONS * VSG_MEMBERS * sizeof(RPC2_Integer));
  161 
  162         /* 
  163          * this is a BS instead of an array because the RPC2 array
  164          * implementation requires array elements to be structures. In the
  165          * case of VFlags, that would be a real waste of space (which is
  166          * going over the wire).
  167          */
  168         signed char VFlags[MAX_PIGGY_VALIDATIONS];
  169         RPC2_BoundedBS VFlagBS;
  170         VFlagBS.MaxSeqLen = 0;
  171         VFlagBS.SeqLen = 0;
  172         VFlagBS.SeqBody = (RPC2_ByteSeq) VFlags;
  173 
  174         /* 
  175          * validate volumes that:
  176          * - are replicated
  177          * - are in the same vsg
  178          * - are in the hoarding state
  179          * - want a volume callback (includes check for presence of one)
  180          * - have a non-null version vector for comparison
  181          *
  182          * Note that we may not pick up a volume for validation after a
  183          * partition if the volume has not yet been demoted (i.e. the
  184          * demotion_pending flag is set).  If the volume is awaiting
  185          * demotion, it may appear to still have a callback when viewed
  186          * "externally" as we do here. This does not violate correctness,
  187          * because if an object is referenced in the volume the demotion
  188          * will be taken first.  
  189          *
  190          * We do not bother checking the stamps for volumes not in the
  191          * hoarding state; when the transition is taken to the hoarding
  192          * state the volume will be demoted and the callback cleared
  193          * anyway.
  194          */
  195         repvol_iterator next;
  196         repvol *rv;
  197 
  198         /* one of the following should be this volume. */
  199         while ((rv = next()) && (nVols < MAX_PIGGY_VALIDATIONS)) 
  200             {
  201                 /* Check whether the volume is hosted by the same VSG as the
  202                  * current volume */
  203                 if (vsg != rv->vsg)
  204                     continue;
  205 
  206         if ((!rv->IsReachable()) || !rv->WantCallBack() ||
  207                     VV_Cmp(&rv->VVV, &NullVV) == VV_EQ)
  208                     continue;
  209 
  210                 LOG(1000, ("volent::GetVolAttr: packing volume %s, vid %p, vvv:\n",
  211                            rv->GetName(), rv->GetVolumeId()));
  212                 if (LogLevel >= 1000) FPrintVV(logFile, &rv->VVV);
  213 
  214                 VidList[nVols].Vid = rv->GetVolumeId();
  215                 for (i = 0; i < vsg->MaxVSG(); i++) {
  216                     *((RPC2_Unsigned *)&((char *)VSBS.SeqBody)[VSBS.SeqLen]) =
  217                         htonl((&rv->VVV.Versions.Site0)[i]);
  218                     VSBS.SeqLen += sizeof(RPC2_Unsigned);
  219                 }
  220                 nVols++;
  221             }
  222 
  223         /* 
  224          * nVols could be 0 here if someone else got into this routine and
  225          * validated while we were descheduled...such as in getmgrp.
  226          */
  227         if (nVols == 0) {
  228         free(VSBS.SeqBody);
  229             goto RepExit;
  230             }
  231 
  232         VFlagBS.MaxSeqLen = nVols;
  233 
  234         LOG(100, ("volent::GetVolAttr: %s, sending %d version stamps\n", name, nVols));
  235 
  236         ARG_MARSHALL_BS(IN_OUT_MODE, RPC2_BoundedBS, VFlagvar, VFlagBS,
  237                 VSG_MEMBERS, VENUS_MAXBSLEN);
  238 
  239         /* Make the RPC call. */
  240         MarinerLog("store::ValidateVols %s [%d]\n", name, nVols);
  241         MULTI_START_MESSAGE(ViceValidateVols_OP);
  242         code = (int) MRPC_MakeMulti(ViceValidateVols_OP, ViceValidateVols_PTR,
  243                     VSG_MEMBERS, m->rocc.handles,
  244                     m->rocc.retcodes, m->rocc.MIp, 0, 0,
  245                     nVols, VidList, &VSBS, VFlagvar_ptrs);
  246         MULTI_END_MESSAGE(ViceValidateVols_OP);
  247         MarinerLog("store::validatevols done\n");
  248 
  249         /* Collate responses from individual servers and decide what to do next. */
  250         code = Collate_NonMutating(m, code);
  251         MULTI_RECORD_STATS(ViceValidateVols_OP);
  252         free(VSBS.SeqBody);
  253 
  254         if (code) {
  255         ClearCallBack();
  256         Recov_BeginTrans();
  257            RVMLIB_REC_OBJECT(VVV);
  258            VVV = NullVV;
  259         Recov_EndTrans(MAXFP);
  260         goto RepExit;
  261         }
  262 
  263         unsigned int numVFlags = 0;
  264         for (i = 0; i < vsg->MaxVSG(); i++) {
  265         if (m->rocc.hosts[i].s_addr != 0) {
  266             if (numVFlags == 0) {
  267             /* unset, copy in one response */
  268             ARG_UNMARSHALL_BS(VFlagvar, VFlagBS, i);
  269             numVFlags = (unsigned) VFlagBS.SeqLen;
  270             } else {
  271             /* "and" in results from other servers. note VFlagBS.SeqBody == VFlags. */
  272             for (int j = 0; j < nVols; j++) {
  273                 if ((VFlags[j] == -1) || ((signed char) VFlagvar_bufs[i].SeqBody[j] == -1))
  274                 VFlags[j] = -1;
  275                 else 
  276                 VFlags[j] &= VFlagvar_bufs[i].SeqBody[j];
  277             }
  278             }
  279                 }
  280             }
  281 
  282 
  283         LOG(10, ("volent::GetVolAttr: ValidateVols (%s), %d vids sent, %d checked\n",
  284               name, nVols, numVFlags));
  285             
  286             volent *v;
  287         Volid volid;
  288         volid.Realm = realm->Id();
  289 
  290         /* now set status of volumes */
  291         for (i = 0; i < numVFlags; i++)  { /* look up the object */
  292         volid.Volume = VidList[i].Vid;
  293         v = VDB->Find(&volid);
  294         if (!v) {
  295             LOG(0, ("volent::GetVolAttr: couldn't find vid 0x%x\n", 
  296                 VidList[i].Vid));
  297             continue;
  298         }
  299 
  300         CODA_ASSERT(v->IsReplicated());
  301         repvol *vp = (repvol *)v;
  302 
  303         switch (VFlags[i]) {
  304         case 1:  /* OK, callback */
  305             if (cbtemp == cbbreaks) {
  306             LOG(1000, ("volent::GetVolAttr: vid 0x%x valid\n",
  307                    vp->GetVolumeId()));
  308             vp->SetCallBack();
  309 
  310             /* validate cached access rights for the caller */
  311             struct dllist_head *p;
  312             list_for_each(p, vp->fso_list) {
  313                 fsobj *f=list_entry_plusplus(p, fsobj, vol_handle);
  314                 if (!f->IsDir())
  315                 continue;
  316 
  317                 f->PromoteAcRights(ANYUSER_UID);
  318                 f->PromoteAcRights(uid);
  319             }
  320             } 
  321             break;
  322         case 0:  /* OK, no callback */
  323             LOG(0, ("volent::GetVolAttr: vid 0x%x valid, no "
  324                 "callback\n", vp->GetVolumeId()));
  325             vp->ClearCallBack();
  326             break;
  327         default:  /* not OK */
  328             LOG(1, ("volent::GetVolAttr: vid 0x%x invalid\n",
  329                 vp->GetVolumeId()));
  330             vp->ClearCallBack();
  331             Recov_BeginTrans();
  332             RVMLIB_REC_OBJECT(vp->VVV);
  333             vp->VVV = NullVV;   
  334             Recov_EndTrans(MAXFP);
  335             break;
  336         }
  337         v->release();
  338         }
  339         }
  340     }
  341 
  342 RepExit:
  343     if (m) m->Put();
  344     
  345     return(code);
  346 }
  347 
  348 
  349 /* collate version stamp and callback status out parameters from servers */
  350 void repvol::CollateVCB(mgrpent *m, RPC2_Integer *sbufs, CallBackStatus *cbufs)
  351 {
  352     unsigned int i;
  353     CallBackStatus collatedCB = CallBackSet;
  354 
  355     if (LogLevel >= 100) {
  356     fprintf(logFile, "volent::CollateVCB: vid %08x Current VVV:\n", vid);
  357         FPrintVV(logFile, &VVV);
  358 
  359     fprintf(logFile, "volent::CollateVCB: Version stamps returned:");
  360     for (i = 0; i < vsg->MaxVSG(); i++)
  361         if (m->rocc.hosts[i].s_addr != 0) 
  362         fprintf(logFile, " %u", sbufs[i]);
  363 
  364     fprintf(logFile, "\nvolent::CollateVCB: Callback status returned:");
  365     for (i = 0; i < vsg->MaxVSG(); i++) 
  366         if (m->rocc.hosts[i].s_addr != 0)
  367             fprintf(logFile, " %u", cbufs[i]);
  368 
  369     fprintf(logFile, "\n");
  370     fflush(logFile);
  371     }
  372 
  373     for (i = 0; i < vsg->MaxVSG(); i++) {
  374     if (m->rocc.hosts[i].s_addr != 0 && (cbufs[i] != CallBackSet))
  375         collatedCB = NoCallBack;
  376     }
  377 
  378     if (collatedCB == CallBackSet) {
  379     SetCallBack();
  380     Recov_BeginTrans();
  381         RVMLIB_REC_OBJECT(VVV);
  382         for (i = 0; i < vsg->MaxVSG(); i++)
  383             if (m->rocc.hosts[i].s_addr != 0)
  384            (&VVV.Versions.Site0)[i] = sbufs[i];
  385     Recov_EndTrans(MAXFP);
  386     } else {
  387     ClearCallBack();
  388 
  389     /* check if any of the returned stamps are zero.
  390        If so, server said stamp invalid. */
  391         for (i = 0; i < vsg->MaxVSG(); i++)
  392         if (m->rocc.hosts[i].s_addr != 0 && (sbufs[i] == 0)) {
  393         Recov_BeginTrans();
  394            RVMLIB_REC_OBJECT(VVV);
  395            VVV = NullVV;
  396         Recov_EndTrans(MAXFP);
  397         break;
  398         }
  399     }
  400 
  401     return;
  402 }
  403 
  404 
  405 /*
  406  * Ensure all cached state from volume "vol" is valid.
  407  * Returns success if it is able to do this, an errno otherwise.
  408  *
  409  * Error handling is simple: if one occurs, quit and propagate.
  410  * There's no volume synchronization because we've already
  411  * done it. 
  412  * 
  413  * complications: 
  414  * - this can't be called from fsdb::Get (a reasonable place)
  415  *   unless the target fid is known, because this routine calls
  416  *   fsdb::Get on potentially everything.
  417  */
  418 int repvol::ValidateFSOs()
  419 {
  420     int code = 0;
  421 
  422     LOG(100, ("repvol::ValidateFSOs: vid = 0x%x\n", vid));
  423 
  424     vproc *vp = VprocSelf();
  425 
  426     struct dllist_head *p, *next;
  427     for(p = fso_list.next; p != &fso_list; p = next) {
  428     fsobj *n = NULL, *f = list_entry_plusplus(p, fsobj, vol_handle);
  429     next = p->next;
  430 
  431     if (DYING(f) || (STATUSVALID(f) && (!HAVEDATA(f) || DATAVALID(f))))
  432         continue;
  433 
  434     if (next != &fso_list) {
  435         n = list_entry_plusplus(next, fsobj, vol_handle);
  436         FSO_HOLD(n);
  437     }
  438 
  439     int whatToGet = 0;
  440     if (!STATUSVALID(f)) 
  441         whatToGet = RC_STATUS;
  442 
  443     if (HAVEDATA(f) && !DATAVALID(f)) 
  444         whatToGet |= RC_DATA;
  445 
  446     LOG(100, ("volent::ValidateFSOs: vget(%s, %x, %d)\n",
  447           FID_(&f->fid), whatToGet, f->stat.Length));
  448 
  449     fsobj *tf = 0;
  450     code = FSDB->Get(&tf, &f->fid, vp->u.u_uid, whatToGet);
  451     FSDB->Put(&tf);
  452 
  453     if (n) FSO_RELE(n);
  454 
  455     LOG(100, ("volent::ValidateFSOs: vget returns %s\n", VenusRetStr(code)));
  456     if (code == EINCONS)
  457         k_Purge(&f->fid, 1);
  458     if (code) 
  459         break;
  460     }
  461     return(code);
  462 }
  463 
  464 
  465 void repvol::PackVS(int nstamps, RPC2_CountedBS *BS)
  466 {
  467     BS->SeqLen = 0;
  468     BS->SeqBody = (RPC2_ByteSeq) malloc(nstamps * sizeof(RPC2_Integer));
  469 
  470     for (int i = 0; i < nstamps; i++) {
  471     *((RPC2_Unsigned *)&((char *)BS->SeqBody)[BS->SeqLen]) =
  472         (&VVV.Versions.Site0)[i];
  473     BS->SeqLen += sizeof(RPC2_Unsigned);
  474     }
  475     return;
  476 }
  477 
  478 
  479 int repvol::CallBackBreak()
  480 {
  481     /*
  482      * Track vcb's broken for this volume. Total vcb's broken is 
  483      * accumulated in vdb::CallbackBreak.
  484      */
  485 
  486     int rc = (VCBStatus == CallBackSet);
  487 
  488     if (rc) {
  489     VCBStatus = NoCallBack;
  490     
  491     Recov_BeginTrans();
  492         RVMLIB_REC_OBJECT(VVV);
  493         VVV = NullVV;   
  494     Recov_EndTrans(MAXFP);
  495     }
  496 
  497     return(rc);    
  498 }
  499 
  500 
  501 void repvol::ClearCallBack()
  502 {
  503     VCBStatus = NoCallBack;
  504 }
  505 
  506 
  507 void repvol::SetCallBack()
  508 {
  509     VCBStatus = CallBackSet;
  510 }
  511 
  512 
  513 int repvol::WantCallBack()
  514 {
  515     /* 
  516      * This is a policy module that decides if a volume 
  517      * callback is worth acquiring.  This is a naive policy,
  518      * with a minimal threshold for files.  One could use
  519      * CallBackClears as an approximation to the partition
  520      * rate (p), and CallbackBreaks as an approximation
  521      * to the mutation rate (m). 
  522      */
  523     struct dllist_head *p;
  524     int count = 0;
  525 
  526     if (VCBStatus != NoCallBack)
  527     return 0;
  528     
  529     /* this used to be (fso_list->count() > 1) */
  530     list_for_each(p, fso_list) {
  531     if (++count > 1)
  532         return 1;
  533     }
  534 
  535     return 0;
  536 }