vos-getsize-20030619
authorNathan Neulinger <nneul@umr.edu>
Thu, 19 Jun 2003 17:06:58 +0000 (17:06 +0000)
committerDerrick Brashear <shadow@dementia.org>
Thu, 19 Jun 2003 17:06:58 +0000 (17:06 +0000)
FIXES 1574

ported basically verbatim from work by ilya@ccmr.cornell.edu and
mitch@ccmr.cornell.edu.

add estimator of dump size support to vos/volserver

src/volser/dumpstuff.c
src/volser/volint.xg
src/volser/volprocs.c
src/volser/vos.c
src/volser/vsprocs.c

index ad98ad7..c239315 100644 (file)
@@ -92,6 +92,17 @@ static int ReadVnodes(register struct iod *iodp, Volume *vp,
 static bit32 volser_WriteFile(int vn, struct iod *iodp, FdHandle_t *handleP,
                              Error *status);
 
+static int SizeDumpDumpHeader(register struct iod *iodp, register Volume *vp,
+                             afs_int32 fromtime, register struct volintSize *size);
+static int SizeDumpPartial(register struct iod *iodp, register Volume *vp,
+                          afs_int32 fromtime, int dumpAllDirs,
+                          register struct volintSize *size);
+static int SizeDumpVnodeIndex(register struct iod *iodp, Volume *vp,
+                             VnodeClass class, afs_int32 fromtime, int forcedump,
+                             register struct volintSize *size);
+static int SizeDumpVnode(register struct iod *iodp, struct VnodeDiskObject *v,
+                        int volid, int vnodeNumber, int dumpEverything,
+                        register struct volintSize *size);
 
 static void iod_Init(register struct iod *iodp, register struct rx_call *call)
 {
@@ -1154,3 +1165,211 @@ static int ReadDumpHeader(register struct iod *iodp, struct DumpHeader *hp)
     iod_ungetc(iodp, tag);
     return 1;
 }
+
+
+/* ----- Below are the calls that calculate dump size ----- */
+
+static int SizeDumpVolumeHeader(register struct iod *iodp, register Volume *vp, register struct volintSize *v_size)
+{
+    int code = 0;
+    static char nullString[1] = "";  /*The ``contents'' of motd*/
+
+/*     if (!code) code = DumpTag(iodp, D_VOLUMEHEADER); */
+    v_size->dump_size += 1;
+/*     if (!code) {code = DumpInt32(iodp, 'i',V_id(vp));} */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'v',V_stamp(vp).version); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpString(iodp, 'n',V_name(vp)); */
+    v_size->dump_size += (2 + strlen(V_name(vp)));
+/*     if (!code) code = DumpBool(iodp, 's',V_inService(vp)); */
+    v_size->dump_size += 2;
+/*     if (!code) code = DumpBool(iodp, 'b',V_blessed(vp)); */
+    v_size->dump_size += 2;
+/*     if (!code) code = DumpInt32(iodp, 'u',V_uniquifier(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpByte(iodp, 't',(byte)V_type(vp)); */
+    v_size->dump_size += 2;
+/*     if (!code){ code = DumpInt32(iodp, 'p',V_parentId(vp));} */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'c',V_cloneId(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'q',V_maxquota(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'm',V_minquota(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'd',V_diskused(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'f',V_filecount(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'a', V_accountNumber(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'o', V_owner(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'C',V_creationDate(vp));      /\* Rw volume creation date *\/ */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'A',V_accessDate(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'U',V_updateDate(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'E',V_expirationDate(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'B',V_backupDate(vp));                /\* Rw volume backup clone date *\/ */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpString(iodp, 'O',V_offlineMessage(vp)); */
+    v_size->dump_size += (2 + strlen(V_offlineMessage(vp)));
+/*     /\* */
+/*      * We do NOT dump the detailed volume statistics residing in the old */
+/*      * motd field, since we cannot tell from the info in a dump whether */
+/*      * statistics data has been put there.  Instead, we dump a null string, */
+/*      * just as if that was what the motd contained. */
+/*      *\/ */
+/*     if (!code) code = DumpString(iodp, 'M', nullString); */
+    v_size->dump_size += (2 + strlen(nullString));
+/*     if (!code) code = DumpArrayInt32(iodp, 'W', (afs_uint32 *)V_weekUse(vp), sizeof(V_weekUse(vp))/sizeof(V_weekUse(vp)[0])); */
+    v_size->dump_size += (3 + 4*(sizeof(V_weekUse(vp))/sizeof(V_weekUse(vp)[0])));
+/*     if (!code) code = DumpInt32(iodp, 'D', V_dayUseDate(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'Z', V_dayUse(vp)); */
+    v_size->dump_size += 5;
+    return code;
+}
+
+static int SizeDumpEnd(register struct iod *iodp, register struct volintSize *v_size)
+{
+    int code = 0;
+    v_size->dump_size += 5;
+    return code;
+}
+
+int SizeDumpVolume(register struct rx_call *call, register Volume *vp, afs_int32 fromtime,
+                  int dumpAllDirs, register struct volintSize *v_size)
+{
+    struct iod iod;
+    int code = 0;
+    register struct iod *iodp = (struct iod *)0;
+//    iod_Init(iodp, call);
+
+    if (!code) code = SizeDumpDumpHeader(iodp, vp, fromtime, v_size);
+    if (!code) code = SizeDumpPartial(iodp, vp, fromtime, dumpAllDirs, v_size);
+    if (!code) code = SizeDumpEnd(iodp, v_size);
+    
+    return code;
+}
+
+static int SizeDumpDumpHeader(register struct iod *iodp, register Volume *vp, afs_int32 fromtime,
+                             register struct volintSize *v_size)
+{
+    int code = 0;
+    int UseLatestReadOnlyClone = 1;
+    afs_int32 dumpTimes[2];
+//    iodp->device = vp->device;
+//    iodp->parentId = V_parentId(vp);
+//    iodp->dumpPartition = vp->partition;
+
+    v_size->dump_size = 0; /* initialize the size */
+/*     if (!code) code = DumpDouble(iodp, D_DUMPHEADER, DUMPBEGINMAGIC, DUMPVERSION); */
+    v_size->dump_size += 9;
+/*     if (!code) code = DumpInt32(iodp, 'v', UseLatestReadOnlyClone? V_id(vp): V_parentId(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpString(iodp, 'n',V_name(vp)); */
+    v_size->dump_size += (2 + strlen(V_name(vp)));
+/*     dumpTimes[0] = fromtime; */
+/*     dumpTimes[1] = V_backupDate(vp);        /\* Until the time the clone was made *\/ */
+/*     if (!code) code = DumpArrayInt32(iodp, 't', (afs_uint32 *)dumpTimes, 2); */
+    v_size->dump_size += (3 + 4*2);
+    return code;
+}
+
+static int SizeDumpVnode(register struct iod *iodp, struct VnodeDiskObject *v, int volid, int vnodeNumber, int dumpEverything,
+                    register struct volintSize *v_size)
+{
+    int code = 0;
+
+    if (!v || v->type == vNull)
+       return code;
+/*     if (!code) code = DumpDouble(iodp, D_VNODE, vnodeNumber, v->uniquifier); */
+    v_size->dump_size += 9;
+    if (!dumpEverything)
+        return code;
+/*     if (!code)  code = DumpByte(iodp, 't',(byte)v->type); */
+    v_size->dump_size += 2;
+/*     if (!code) code = DumpShort(iodp, 'l', v->linkCount); /\* May not need this *\/ */
+    v_size->dump_size += 3;
+/*     if (!code) code = DumpInt32(iodp, 'v', v->dataVersion); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'm', v->unixModifyTime); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'a', v->author); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'o', v->owner); */
+    v_size->dump_size += 5;
+/*     if (!code && v->group) code = DumpInt32(iodp, 'g', v->group);   /\* default group is 0 *\/ */
+    if(v->group)     v_size->dump_size += 5;
+/*     if (!code) code = DumpShort(iodp, 'b', v->modeBits); */
+    v_size->dump_size += 3;
+/*     if (!code) code = DumpInt32(iodp, 'p', v->parent); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 's', v->serverModifyTime); */
+    v_size->dump_size += 5;
+    if (v->type == vDirectory) {
+/*     acl_HtonACL(VVnodeDiskACL(v)); */
+/*     if (!code) code = DumpByteString(iodp, 'A', (byte *) VVnodeDiskACL(v), VAclDiskSize(v)); */
+       v_size->dump_size += 1 + VAclDiskSize(v);
+    }
+
+    if (VNDISK_GET_INO(v)) {
+       v_size->dump_size += (v->length + 5);
+    } 
+    return code;
+}
+
+/* A partial dump (no dump header) */
+static int SizeDumpPartial(register struct iod *iodp, register Volume *vp, afs_int32 fromtime, int dumpAllDirs,
+                          register struct volintSize *v_size)
+{
+    int code = 0;
+    if (!code) code = SizeDumpVolumeHeader(iodp, vp, v_size);
+    if (!code) code = SizeDumpVnodeIndex(iodp, vp, vLarge, fromtime, dumpAllDirs, v_size);
+    if (!code) code = SizeDumpVnodeIndex(iodp, vp, vSmall, fromtime, 0, v_size);
+    return code;
+}
+
+static int SizeDumpVnodeIndex(register struct iod *iodp, Volume *vp, VnodeClass class, afs_int32 fromtime,
+                             int forcedump, register struct volintSize *v_size)
+{
+    register int code = 0;
+    register struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
+    char buf[SIZEOF_LARGEDISKVNODE];
+    struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
+    StreamHandle_t *file;
+    FdHandle_t *fdP;
+    int size;
+    int flag;
+    register int vnodeIndex, nVnodes;
+
+    fdP = IH_OPEN(vp->vnodeIndex[class].handle);
+    assert(fdP != NULL);
+    file = FDH_FDOPEN(fdP, "r+");
+    assert(file != NULL);
+    size = OS_SIZE(fdP->fd_fd);
+    assert(size != -1);
+   nVnodes = (size / vcp->diskSize) - 1;
+    if (nVnodes > 0) {
+       assert((nVnodes+1)*vcp->diskSize == size);
+       assert(STREAM_SEEK(file, vcp->diskSize, 0) == 0);
+    }
+    else nVnodes = 0;
+    for (vnodeIndex = 0; nVnodes && STREAM_READ(vnode, vcp->diskSize, 1, file) == 1 && !code;
+      nVnodes--, vnodeIndex++) {
+       flag = forcedump || (vnode->serverModifyTime >= fromtime);
+       /* Note:  the >= test is very important since some old volumes may not have
+          a serverModifyTime.  For an epoch dump, this results in 0>=0 test, which
+          does dump the file! */
+       if (!code) code = SizeDumpVnode(iodp, vnode, V_id(vp), bitNumberToVnodeNumber(vnodeIndex, class), flag, v_size);
+    }
+    STREAM_CLOSE(file);
+    FDH_CLOSE(fdP);
+    return code;
+}
+
index a467757..cfa5155 100644 (file)
@@ -48,6 +48,7 @@ statindex 16
 #define            VOLXLISTPARTITIONS  127
 #define            VOLFORWARDMULTIPLE  128
 #define     VOLCONVERTRO        65536
+#define     VOLGETSIZE          65537
 
 const SIZE = 1024;
 
@@ -216,6 +217,11 @@ struct replica {
        struct destServer server;
 };
 
+/*  Various size parameters of the volume  */
+struct volintSize {
+    afs_uint64 dump_size;
+};
+
 typedef  replica manyDests<>;
 typedef  afs_int32 manyResults<>;
 typedef  transDebugInfo transDebugEntries<>;
@@ -396,3 +402,9 @@ proc ConvertROtoRWvolume(
   IN afs_int32 partid,
   IN afs_int32 volid
 ) = VOLCONVERTRO;
+
+proc GetSize(
+  IN afs_int32 fromTrans,
+  IN afs_int32 fromDate,
+  OUT struct volintSize *size
+) = VOLGETSIZE;
index 20658a6..9ffffcd 100644 (file)
@@ -2801,6 +2801,33 @@ afs_int32 SAFSVolConvertROtoRWvolume(acid, partId, volumeId)
 #endif /* AFS_NAMEI_ENV */
 }
 
+afs_int32 SAFSVolGetSize (acid, fromTrans, fromDate, size)
+struct rx_call *acid;
+afs_int32 fromTrans;
+afs_int32 fromDate;
+register struct volintSize *size;
+{
+    int code = 0;
+    register struct volser_trans *tt;
+    char caller[MAXKTCNAMELEN];
+
+    if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;/*not a super user*/
+    tt = FindTrans(fromTrans);
+    if (!tt) return ENOENT;
+    if (tt->vflags & VTDeleted) {
+       TRELE(tt);
+       return ENOENT;
+    }
+    strcpy(tt->lastProcName,"GetSize"); 
+    tt->rxCallPtr = acid; 
+    code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size);        /* measure volume's data */
+    tt->rxCallPtr = (struct rx_call *)0; 
+    if(TRELE(tt)) return VOLSERTRELE_ERROR; 
+    
+/*    osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);  */
+    return code;
+}
+
 /* GetPartName - map partid (a decimal number) into pname (a string)
  * Since for NT we actually want to return the drive name, we map through the
  * partition struct.
index d1f9519..d3140f1 100644 (file)
@@ -4334,6 +4334,80 @@ register struct cmd_syndesc *as;
     return code;
 }
 
+static Sizes(as)
+register struct cmd_syndesc *as;
+{
+    afs_int32 avolid, aserver, apart,voltype,fromdate=0,code, err, i;
+    struct nvldbentry entry;
+    volintSize vol_size;
+    
+    rx_SetRxDeadTime(60 * 10);
+    for (i = 0; i<MAXSERVERS; i++) {
+       struct rx_connection *rxConn = ubik_GetRPCConn(cstruct,i);
+       if (rxConn == 0) break;
+       rx_SetConnDeadTime(rxConn, rx_connDeadTime);
+       if (rxConn->service)  rxConn->service->connDeadTime = rx_connDeadTime;
+    }
+    
+    avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
+    if (avolid == 0) {
+       if (err) PrintError("", err);
+       else  fprintf(STDERR, "vos: can't find volume '%s'\n", as->parms[0].items->data);
+       return ENOENT;
+    }
+    
+    if (as->parms[1].items || as->parms[2].items) {
+       if (!as->parms[1].items || !as->parms[2].items) {
+           fprintf(STDERR, "Must specify both -server and -partition options\n");
+           return -1;
+       }
+       aserver = GetServer(as->parms[2].items->data);
+       if (aserver == 0) {
+           fprintf(STDERR, "Invalid server name\n");
+           return -1;
+       }
+       apart = volutil_GetPartitionID(as->parms[1].items->data);
+       if (apart < 0) {
+           fprintf(STDERR, "Invalid partition name\n");
+           return -1;
+       }
+    } else {
+       code = GetVolumeInfo(avolid, &aserver, &apart, &voltype, &entry);
+       if (code) return code;
+    }
+
+    fromdate = 0;
+    
+    if (as->parms[4].items && strcmp(as->parms[4].items->data,"0")) {
+       code = ktime_DateToInt32(as->parms[4].items->data, &fromdate);
+       if (code) {
+           fprintf(STDERR,"vos: failed to parse date '%s' (error=%d))\n",
+                   as->parms[1].items->data, code);
+           return code;
+       }
+    }
+
+    fprintf(STDOUT, "Volume: %s\n", as->parms[0].items->data);
+    
+    if(as->parms[3].items) /* do the dump estimate */
+    {
+       vol_size.dump_size = 0;
+       code = UV_GetSize(avolid, aserver, apart, fromdate, &vol_size);
+       if (code) {
+           PrintDiagnostics("size", code);
+           return code;
+       }
+       /* presumably the size info is now gathered in pntr */
+       /* now we display it */
+       
+       fprintf(STDOUT,"dump_size: %llu\n", vol_size.dump_size);
+    }
+    
+    /* Display info */
+    
+    return 0;
+}
+
 PrintDiagnostics(astring, acode)
     char *astring;
     afs_int32 acode;
@@ -4643,6 +4717,14 @@ char **argv; {
     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL, "don't ask");
     COMMONPARMS;
 
+    ts = cmd_CreateSyntax("size", Sizes, 0, "obtain various sizes of the volume.");
+    cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
+    cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
+    cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL,  "machine name");
+    cmd_AddParm(ts, "-dump", CMD_FLAG, CMD_OPTIONAL, "Obtain the size of the dump");
+    cmd_AddParm(ts, "-time", CMD_SINGLE, CMD_OPTIONAL, "dump from time");
+    COMMONPARMS;
+
     code = cmd_Dispatch(argc, argv);
     if (rxInitDone) {
        /* Shut down the ubik_client and rx connections */
index 39f7f02..ebe614c 100644 (file)
@@ -5657,6 +5657,45 @@ int UV_SetVolumeInfo(afs_int32 server, afs_int32 partition, afs_int32 volid, vol
   return(error);
 }
 
+int UV_GetSize(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart, 
+       afs_int32 fromdate, struct volintSize *vol_size)
+{
+   struct rx_connection *aconn = (struct rx_connection *)0;
+   afs_int32 tid=0, rcode=0;
+   afs_int32 code, error = 0;
+
+
+   /* get connections to the servers */
+   aconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
+
+   VPRINT1("Starting transaction on volume %u...", afromvol);
+   code = AFSVolTransCreate(aconn, afromvol, afrompart, ITBusy, &tid);
+   EGOTO1(error_exit, code, "Could not start transaction on the volume %u to be measured\n", afromvol);
+   VDONE;
+
+   VPRINT1("Getting size of volume on volume %u...", afromvol);
+   code = AFSVolGetSize(aconn, tid, fromdate, vol_size);
+   EGOTO(error_exit, code, "Could not start the measurement process \n");
+   VDONE;
+      
+ error_exit:
+   if (tid) {
+      VPRINT1("Ending transaction on volume %u...", afromvol);
+      code = AFSVolEndTrans(aconn, tid, &rcode);
+      if (code || rcode) {
+        fprintf(STDERR,"Could not end transaction on the volume %u\n", afromvol);
+        fprintf(STDERR,"error codes: %d and %d\n", code, rcode);
+        if (!error) error = (code?code:rcode);
+      }
+      VDONE;
+   }
+   if (aconn)
+      rx_DestroyConnection(aconn);
+
+   PrintError("", error);
+   return(error);
+}
+
 /*maps the host addresses in <old > (present in network byte order) to
  that in< new> (present in host byte order )*/
 void MapNetworkToHost(struct nvldbentry *old, struct nvldbentry *new)