vol: cmd comerr dir afs sgiefs
${COMPILE_PART1} vol ${COMPILE_PART2}
+tsalvaged: vol libafsrpc libafsauthent cmd util
+ set -x; \
+ if test "@DEMAND_ATTACH@" = "yes" ; then \
+ case ${SYS_NAME} in \
+ alpha_dux*|sgi_*|sun*_5*|rs_aix*|*linux*|hp_ux11*|ia64_hpux*|*fbsd*|*nbsd2*) \
+ ${COMPILE_PART1} tsalvaged ${COMPILE_PART2} ;; \
+ *_darwin_[1-6][0-9]) \
+ echo Not building MT tsalvaged for ${SYS_NAME} ;; \
+ *_darwin_*) \
+ ${COMPILE_PART1} tsalvaged ${COMPILE_PART2} ;; \
+ *) \
+ echo Not building MT tsalvaged for ${SYS_NAME} ;; \
+ esac \
+ else \
+ echo skipping tsalvaged ; \
+ fi
+
+
vlserver: cmd comerr vol audit vlserver_depinstall
${COMPILE_PART1} vlserver ${COMPILE_PART2}
jafsadm: libjafsadm
finale: project cmd comerr afsd butc tbutc @ENABLE_KERNEL_MODULE@ libuafs audit kauth log package \
- ptserver scout bu_utils ubik uss bozo vfsck volser tvolser \
+ ptserver scout bu_utils ubik uss bozo vfsck volser tvolser tsalvaged \
venus update xstat afsmonitor dauth rxdebug libafsrpc \
libafsauthent shlibafsrpc shlibafsauthent libadmin login man-pages
${COMPILE_PART1} finale ${COMPILE_PART2}
finale_nolibafs: project cmd comerr afsd butc tbutc libuafs audit kauth log package \
- ptserver scout bu_utils ubik uss bozo vfsck volser tvolser \
+ ptserver scout bu_utils ubik uss bozo vfsck volser tvolser tsalvaged \
venus update xstat afsmonitor dauth rxdebug libafsrpc \
libafsauthent shlibafsrpc shlibafsauthent libadmin login man-pages
${COMPILE_PART1} finale ${COMPILE_PART2}
-${COMPILE_PART1} tviced ${COMPILE_CLEAN}
-${COMPILE_PART1} volser ${COMPILE_CLEAN}
-${COMPILE_PART1} tvolser ${COMPILE_CLEAN}
+ -${COMPILE_PART1} tsalvaged ${COMPILE_CLEAN}
-${COMPILE_PART1} venus ${COMPILE_CLEAN}
-${COMPILE_PART1} venus/test ${COMPILE_CLEAN}
-${COMPILE_PART1} afsd ${COMPILE_CLEAN}
src/tests/Makefile \
src/tests/run-tests \
src/tests/OpenAFS/Dirpath.pm \
+ src/tsalvaged/Makefile \
src/tsm41/Makefile \
src/tviced/Makefile \
src/tvolser/Makefile \
[ --enable-fast-restart enable fast startup of file server without salvaging],, enable_fast_restart="no")
AC_ARG_ENABLE( bitmap-later,
[ --enable-bitmap-later enable fast startup of file server by not reading bitmap till needed],, enable_bitmap_later="no")
+AC_ARG_ENABLE( demand-attach-fs,
+[ --enable-demand-attach-fs enable Demand Attach Fileserver (please see documentation)],, enable_demand_attach_fs="no")
AC_ARG_ENABLE( full-vos-listvol-switch,
[ --disable-full-vos-listvol-switch disable vos full listvol switch for formatted output],, enable_full_vos_listvol_switch="yes")
AC_ARG_WITH(dux-kernel-headers,
AC_DEFINE(BITMAP_LATER, 1, [define if you want to salvager to check bitmasks later])
fi
+if test "$enable_demand_attach_fs" = "yes"; then
+ AC_DEFINE(DEMAND_ATTACH_ENABLE, 1, [define if you want the demand attach fileserver])
+ DEMAND_ATTACH="yes"
+else
+ DEMAND_ATTACH="no"
+fi
+AC_SUBST(DEMAND_ATTACH)
+
+if test "$enable_fast_restart" = "yes" &&
+ test "$enable_demand_attach_fs" = "yes" ; then
+ AC_MSG_ERROR([The Demand Attach and Fast Restart extensions are mutually exclusive. Demand Attach fileservers automatically salvage volumes in the background, thereby making Fast Restart pointless.])
+ exit 1
+fi
+
if test "$enable_full_vos_listvol_switch" = "yes"; then
AC_DEFINE(FULL_LISTVOL_SWITCH, 1, [define if you want to want listvol switch])
fi
src/tests/Makefile \
src/tests/run-tests \
src/tests/OpenAFS/Dirpath.pm \
+src/tsalvaged/Makefile \
src/tsm41/Makefile \
src/tviced/Makefile \
src/tvolser/Makefile \
cd test; $(MAKE)
clean:
- $(RM) -f *.o *.a copyauth setkey auth.h cellconfig.h acfg_errors.c ktc_errors.c core\
+ $(RM) -f *.o *.a copyauth setkey auth.h cellconfig.h acfg_errors.c ktc_errors.c core \
AFS_component_version_number.c
include ../config/Makefile.version
#include "bosint.h"
-#define MRAFS_OFFSET 9
-#define ADDPARMOFFSET 26
+/* command offsets for bos salvage command */
+#define MRAFS_OFFSET 10
+#define ADDPARMOFFSET 27
-static struct SalvageParms {
+/* MR-AFS salvage parameters */
+struct MRAFSSalvageParms {
afs_int32 Optdebug;
afs_int32 Optnowrite;
afs_int32 Optforce;
afs_int32 OptLogLevel;
afs_int32 OptRxDebug;
afs_uint32 OptResidencies;
-} mrafsParm;
+};
/* dummy routine for the audit work. It should do nothing since audits */
/* occur at the server level and bos is not a server. */
#define PARMBUFFERSSIZE 32
-static
-DoSalvage(aconn, aparm1, aparm2, aoutName, showlog, parallel, atmpDir,
- orphans)
- struct rx_connection *aconn;
- char *aoutName;
- char *aparm1;
- char *aparm2;
- afs_int32 showlog;
- char *parallel;
- char *atmpDir;
- char *orphans;
+static afs_int32
+DoSalvage(struct rx_connection * aconn, char * aparm1, char * aparm2,
+ char * aoutName, afs_int32 showlog, char * parallel,
+ char * atmpDir, char * orphans, int dafs,
+ struct MRAFSSalvageParms * mrafsParm)
{
register afs_int32 code;
char *parms[6];
parms[code] = "";
if (!aparm2)
aparm2 = "";
+
/* MUST pass canonical (wire-format) salvager path to bosserver */
- strncpy(tbuffer, AFSDIR_CANONICAL_SERVER_SALVAGER_FILEPATH, BOZO_BSSIZE);
if (*aparm2 != 0) {
- if ((strlen(tbuffer) + 1 + strlen(partName) + 1 + strlen(aparm2) +
- 1) > BOZO_BSSIZE) {
- printf("bos: command line too big\n");
- return (E2BIG);
+ /* single volume salvage */
+ if (dafs) {
+ /* for DAFS, we call the salvagserver binary with special options.
+ * in this mode, it simply uses SALVSYNC to tell the currently
+ * running salvageserver to offline and salvage the volume in question */
+ strncpy(tbuffer, AFSDIR_CANONICAL_SERVER_SALSRV_FILEPATH, BOZO_BSSIZE);
+
+ if ((strlen(tbuffer) + 9 + strlen(partName) + 1 + strlen(aparm2) +
+ 1) > BOZO_BSSIZE) {
+ printf("bos: command line too big\n");
+ return (E2BIG);
+ }
+
+ strcat(tbuffer, " -client ");
+ strcat(tbuffer, partName);
+ strcat(tbuffer, " ");
+ strcat(tbuffer, aparm2);
+ } else {
+ strncpy(tbuffer, AFSDIR_CANONICAL_SERVER_SALVAGER_FILEPATH, BOZO_BSSIZE);
+
+ if ((strlen(tbuffer) + 1 + strlen(partName) + 1 + strlen(aparm2) +
+ 1) > BOZO_BSSIZE) {
+ printf("bos: command line too big\n");
+ return (E2BIG);
+ }
+
+ strcat(tbuffer, " ");
+ strcat(tbuffer, partName);
+ strcat(tbuffer, " ");
+ strcat(tbuffer, aparm2);
}
- strcat(tbuffer, " ");
- strcat(tbuffer, partName);
- strcat(tbuffer, " ");
- strcat(tbuffer, aparm2);
} else {
+ /* partition salvage */
+ strncpy(tbuffer, AFSDIR_CANONICAL_SERVER_SALVAGER_FILEPATH, BOZO_BSSIZE);
if ((strlen(tbuffer) + 4 + strlen(partName) + 1) > BOZO_BSSIZE) {
printf("bos: command line too big\n");
return (E2BIG);
strcat(tbuffer, partName);
}
- /* add the parallel option if given */
- if (parallel != NULL) {
- if ((strlen(tbuffer) + 11 + strlen(parallel) + 1) > BOZO_BSSIZE) {
- printf("bos: command line too big\n");
- return (E2BIG);
+ /* For DAFS, specifying a single volume does not result in a standard
+ * salvager call. Instead, it simply results in a SALVSYNC call to the
+ * online salvager daemon. This interface does not give us the same rich
+ * set of call flags. Thus, we skip these steps for DAFS single-volume
+ * calls */
+ if (!dafs || (*aparm2 == 0)) {
+ /* add the parallel option if given */
+ if (parallel != NULL) {
+ if ((strlen(tbuffer) + 11 + strlen(parallel) + 1) > BOZO_BSSIZE) {
+ printf("bos: command line too big\n");
+ return (E2BIG);
+ }
+ strcat(tbuffer, " -parallel ");
+ strcat(tbuffer, parallel);
}
- strcat(tbuffer, " -parallel ");
- strcat(tbuffer, parallel);
- }
- /* add the tmpdir option if given */
- if (atmpDir != NULL) {
- if ((strlen(tbuffer) + 9 + strlen(atmpDir) + 1) > BOZO_BSSIZE) {
- printf("bos: command line too big\n");
- return (E2BIG);
+ /* add the tmpdir option if given */
+ if (atmpDir != NULL) {
+ if ((strlen(tbuffer) + 9 + strlen(atmpDir) + 1) > BOZO_BSSIZE) {
+ printf("bos: command line too big\n");
+ return (E2BIG);
+ }
+ strcat(tbuffer, " -tmpdir ");
+ strcat(tbuffer, atmpDir);
}
- strcat(tbuffer, " -tmpdir ");
- strcat(tbuffer, atmpDir);
- }
- /* add the orphans option if given */
- if (orphans != NULL) {
- if ((strlen(tbuffer) + 10 + strlen(orphans) + 1) > BOZO_BSSIZE) {
- printf("bos: command line too big\n");
- return (E2BIG);
+ /* add the orphans option if given */
+ if (orphans != NULL) {
+ if ((strlen(tbuffer) + 10 + strlen(orphans) + 1) > BOZO_BSSIZE) {
+ printf("bos: command line too big\n");
+ return (E2BIG);
+ }
+ strcat(tbuffer, " -orphans ");
+ strcat(tbuffer, orphans);
+ }
+
+ if (mrafsParm->Optdebug)
+ strcat(tbuffer, " -debug");
+ if (mrafsParm->Optnowrite)
+ strcat(tbuffer, " -nowrite");
+ if (mrafsParm->Optforce)
+ strcat(tbuffer, " -force");
+ if (mrafsParm->Optoktozap)
+ strcat(tbuffer, " -oktozap");
+ if (mrafsParm->Optrootfiles)
+ strcat(tbuffer, " -rootfiles");
+ if (mrafsParm->Optsalvagedirs)
+ strcat(tbuffer, " -salvagedirs");
+ if (mrafsParm->Optblockreads)
+ strcat(tbuffer, " -blockreads");
+ if (mrafsParm->OptListResidencies)
+ strcat(tbuffer, " -ListResidencies");
+ if (mrafsParm->OptSalvageRemote)
+ strcat(tbuffer, " -SalvageRemote");
+ if (mrafsParm->OptSalvageArchival)
+ strcat(tbuffer, " -SalvageArchival");
+ if (mrafsParm->OptIgnoreCheck)
+ strcat(tbuffer, " -IgnoreCheck");
+ if (mrafsParm->OptForceOnLine)
+ strcat(tbuffer, " -ForceOnLine");
+ if (mrafsParm->OptUseRootDirACL)
+ strcat(tbuffer, " -UseRootDirACL");
+ if (mrafsParm->OptTraceBadLinkCounts)
+ strcat(tbuffer, " -TraceBadLinkCounts");
+ if (mrafsParm->OptDontAskFS)
+ strcat(tbuffer, " -DontAskFS");
+ if (mrafsParm->OptLogLevel) {
+ sprintf(pbuffer, " -LogLevel %ld", mrafsParm->OptLogLevel);
+ strcat(tbuffer, pbuffer);
+ }
+ if (mrafsParm->OptRxDebug)
+ strcat(tbuffer, " -rxdebug");
+ if (mrafsParm->OptResidencies) {
+ sprintf(pbuffer, " -Residencies %lu", mrafsParm->OptResidencies);
+ strcat(tbuffer, pbuffer);
}
- strcat(tbuffer, " -orphans ");
- strcat(tbuffer, orphans);
- }
-
- if (mrafsParm.Optdebug)
- strcat(tbuffer, " -debug");
- if (mrafsParm.Optnowrite)
- strcat(tbuffer, " -nowrite");
- if (mrafsParm.Optforce)
- strcat(tbuffer, " -force");
- if (mrafsParm.Optoktozap)
- strcat(tbuffer, " -oktozap");
- if (mrafsParm.Optrootfiles)
- strcat(tbuffer, " -rootfiles");
- if (mrafsParm.Optsalvagedirs)
- strcat(tbuffer, " -salvagedirs");
- if (mrafsParm.Optblockreads)
- strcat(tbuffer, " -blockreads");
- if (mrafsParm.OptListResidencies)
- strcat(tbuffer, " -ListResidencies");
- if (mrafsParm.OptSalvageRemote)
- strcat(tbuffer, " -SalvageRemote");
- if (mrafsParm.OptSalvageArchival)
- strcat(tbuffer, " -SalvageArchival");
- if (mrafsParm.OptIgnoreCheck)
- strcat(tbuffer, " -IgnoreCheck");
- if (mrafsParm.OptForceOnLine)
- strcat(tbuffer, " -ForceOnLine");
- if (mrafsParm.OptUseRootDirACL)
- strcat(tbuffer, " -UseRootDirACL");
- if (mrafsParm.OptTraceBadLinkCounts)
- strcat(tbuffer, " -TraceBadLinkCounts");
- if (mrafsParm.OptDontAskFS)
- strcat(tbuffer, " -DontAskFS");
- if (mrafsParm.OptLogLevel) {
- sprintf(pbuffer, " -LogLevel %ld", mrafsParm.OptLogLevel);
- strcat(tbuffer, pbuffer);
- }
- if (mrafsParm.OptRxDebug)
- strcat(tbuffer, " -rxdebug");
- if (mrafsParm.OptResidencies) {
- sprintf(pbuffer, " -Residencies %lu", mrafsParm.OptResidencies);
- strcat(tbuffer, pbuffer);
}
parms[0] = tbuffer;
char tname[BOZO_BSSIZE];
afs_int32 newID;
extern struct ubik_client *cstruct;
- afs_int32 curGoal, showlog = 0, mrafs = 0;
+ afs_int32 curGoal, showlog = 0, dafs = 0, mrafs = 0;
char *parallel;
char *tmpDir;
char *orphans;
char *tp;
+ char * serviceName;
+ struct MRAFSSalvageParms mrafsParm;
memset(&mrafsParm, 0, sizeof(mrafsParm));
/* parm 0 is machine name, 1 is partition, 2 is volume, 3 is -all flag */
tconn = GetConn(as, 0);
- /* Find out whether fileserver is running MR-AFS (has a scanner instance) */
- /* XXX this should really be done some other way, potentially by RPC */
tp = &tname[0];
- if (code = BOZO_GetInstanceParm(tconn, "fs", 3, &tp) == 0)
- mrafs = 1;
+
+ /* find out whether fileserver is running demand attach fs */
+ if (code = BOZO_GetInstanceParm(tconn, "dafs", 0, &tp) == 0) {
+ dafs = 1;
+ serviceName = "dafs";
+ /* Find out whether fileserver is running MR-AFS (has a scanner instance) */
+ /* XXX this should really be done some other way, potentially by RPC */
+ if (code = BOZO_GetInstanceParm(tconn, serviceName, 4, &tp) == 0)
+ mrafs = 1;
+ } else {
+ serviceName = "fs";
+ /* Find out whether fileserver is running MR-AFS (has a scanner instance) */
+ /* XXX this should really be done some other way, potentially by RPC */
+ if (code = BOZO_GetInstanceParm(tconn, serviceName, 3, &tp) == 0)
+ mrafs = 1;
+ }
/* we can do a volume, a partition or the whole thing, but not mixtures
* thereof */
orphans = as->parms[8].items->data;
}
+ if (dafs) {
+ if (!as->parms[9].items) { /* -forceDAFS flag */
+ printf("This is a demand attach fileserver. Are you sure you want to proceed with a manual salvage?\n");
+ printf("must specify -forceDAFS flag in order to proceed.\n");
+ return EINVAL;
+ }
+ }
+
if (mrafs) {
if (as->parms[MRAFS_OFFSET].items)
mrafsParm.Optdebug = 1;
} else {
int stop = 0;
- for (i = 9; i < ADDPARMOFFSET; i++) {
+ for (i = MRAFS_OFFSET; i < ADDPARMOFFSET; i++) {
if (as->parms[i].items) {
printf(" %s only possible for MR-AFS fileserver.\n",
as->parms[i].name);
if (as->parms[4].items) {
/* salvage whole enchilada */
- curGoal = GetServerGoal(tconn, "fs");
+ curGoal = GetServerGoal(tconn, serviceName);
if (curGoal == BSTAT_NORMAL) {
- printf("bos: shutting down fs.\n");
- code = BOZO_SetTStatus(tconn, "fs", BSTAT_SHUTDOWN);
+ printf("bos: shutting down '%s'.\n", serviceName);
+ code = BOZO_SetTStatus(tconn, serviceName, BSTAT_SHUTDOWN);
if (code) {
- printf("bos: failed to stop 'fs' (%s)\n", em(code));
+ printf("bos: failed to stop '%s' (%s)\n", serviceName, em(code));
return code;
}
code = BOZO_WaitAll(tconn); /* wait for shutdown to complete */
/* now do the salvage operation */
printf("Starting salvage.\n");
rc = DoSalvage(tconn, NULL, NULL, outName, showlog, parallel, tmpDir,
- orphans);
+ orphans, dafs, &mrafsParm);
if (curGoal == BSTAT_NORMAL) {
- printf("bos: restarting fs.\n");
- code = BOZO_SetTStatus(tconn, "fs", BSTAT_NORMAL);
+ printf("bos: restarting %s.\n", serviceName);
+ code = BOZO_SetTStatus(tconn, serviceName, BSTAT_NORMAL);
if (code) {
- printf("bos: failed to restart 'fs' (%s)\n", em(code));
+ printf("bos: failed to restart '%s' (%s)\n", serviceName, em(code));
return code;
}
}
as->parms[1].items->data);
return -1;
}
- curGoal = GetServerGoal(tconn, "fs");
+ curGoal = GetServerGoal(tconn, serviceName);
/* salvage a whole partition (specified by parms[1]) */
if (curGoal == BSTAT_NORMAL) {
- printf("bos: shutting down fs.\n");
- code = BOZO_SetTStatus(tconn, "fs", BSTAT_SHUTDOWN);
+ printf("bos: shutting down '%s'.\n", serviceName);
+ code = BOZO_SetTStatus(tconn, serviceName, BSTAT_SHUTDOWN);
if (code) {
- printf("bos: can't stop 'fs' (%s)\n", em(code));
+ printf("bos: can't stop '%s' (%s)\n", serviceName, em(code));
return code;
}
code = BOZO_WaitAll(tconn); /* wait for shutdown to complete */
/* now do the salvage operation */
printf("Starting salvage.\n");
rc = DoSalvage(tconn, as->parms[1].items->data, NULL, outName,
- showlog, parallel, tmpDir, orphans);
+ showlog, parallel, tmpDir, orphans, dafs, &mrafsParm);
if (curGoal == BSTAT_NORMAL) {
- printf("bos: restarting fs.\n");
- code = BOZO_SetTStatus(tconn, "fs", BSTAT_NORMAL);
+ printf("bos: restarting '%s'.\n", serviceName);
+ code = BOZO_SetTStatus(tconn, serviceName, BSTAT_NORMAL);
if (code) {
- printf("bos: failed to restart 'fs' (%s)\n", em(code));
+ printf("bos: failed to restart '%s' (%s)\n", serviceName, em(code));
return code;
}
}
}
printf("Starting salvage.\n");
rc = DoSalvage(tconn, as->parms[1].items->data, tname, outName,
- showlog, parallel, tmpDir, orphans);
+ showlog, parallel, tmpDir, orphans, dafs, &mrafsParm);
if (rc)
return rc;
}
"directory to place tmp files");
cmd_AddParm(ts, "-orphans", CMD_SINGLE, CMD_OPTIONAL,
"ignore | remove | attach");
+ cmd_AddParm(ts, "-forceDAFS", CMD_FLAG, CMD_OPTIONAL,
+ "(DAFS) force salvage of demand attach fileserver");
cmd_AddParm(ts, "-debug", CMD_FLAG, CMD_OPTIONAL,
"(MR-AFS) Run in Debugging mode");
cmd_AddParm(ts, "-nowrite", CMD_FLAG, CMD_OPTIONAL,
#define BOZO_LWP_STACKSIZE 16000
extern int BOZO_ExecuteRequest();
extern int RXSTATS_ExecuteRequest();
-extern struct bnode_ops fsbnode_ops, ezbnode_ops, cronbnode_ops;
+extern struct bnode_ops fsbnode_ops, dafsbnode_ops, ezbnode_ops, cronbnode_ops;
void bozo_Log();
}
bnode_Register("fs", &fsbnode_ops, 3);
+ bnode_Register("dafs", &dafsbnode_ops, 4);
bnode_Register("simple", &ezbnode_ops, 1);
bnode_Register("cron", &cronbnode_ops, 2);
#include <afs/afsutil.h>
#include "bnode.h"
-static int fs_timeout(), fs_getstat(), fs_setstat(), fs_delete();
-static int fs_procexit(), fs_getstring(), fs_getparm(), fs_restartp();
-static int fs_hascore();
-struct bnode *fs_create();
-
-static SetNeedsClock();
-static NudgeProcs();
static int emergency = 0;
The needsSalvage flag is cleared when the salvager exits.
*/
-struct bnode_ops fsbnode_ops = {
- fs_create,
- fs_timeout,
- fs_getstat,
- fs_setstat,
- fs_delete,
- fs_procexit,
- fs_getstring,
- fs_getparm,
- fs_restartp,
- fs_hascore,
-};
-
struct fsbnode {
struct bnode b;
afs_int32 timeSDStarted; /* time shutdown operation started */
char *filecmd; /* command to start primary file server */
char *volcmd; /* command to start secondary vol server */
+ char *salsrvcmd; /* command to start salvageserver (demand attach fs) */
char *salcmd; /* command to start salvager */
char *scancmd; /* command to start scanner (MR-AFS) */
struct bnode_proc *fileProc; /* process for file server */
struct bnode_proc *volProc; /* process for vol server */
+ struct bnode_proc *salsrvProc; /* process for salvageserver (demand attach fs) */
struct bnode_proc *salProc; /* process for salvager */
struct bnode_proc *scanProc; /* process for scanner (MR-AFS) */
afs_int32 lastFileStart; /* last start for file */
afs_int32 lastVolStart; /* last start for vol */
+ afs_int32 lastSalsrvStart; /* last start for salvageserver (demand attach fs) */
afs_int32 lastScanStart; /* last start for scanner (MR-AFS) */
char fileRunning; /* file process is running */
char volRunning; /* volser is running */
+ char salsrvRunning; /* salvageserver is running (demand attach fs) */
char salRunning; /* salvager is running */
char scanRunning; /* scanner is running (MR_AFS) */
char fileSDW; /* file shutdown wait */
char volSDW; /* vol shutdown wait */
+ char salsrvSDW; /* salvageserver shutdown wait (demand attach fs) */
char salSDW; /* waiting for the salvager to shutdown */
char scanSDW; /* scanner shutdown wait (MR_AFS) */
char fileKillSent; /* kill signal has been sent */
char volKillSent;
+ char salsrvKillSent; /* kill signal has been sent (demand attach fs) */
char salKillSent;
char scanKillSent; /* kill signal has been sent (MR_AFS) */
char needsSalvage; /* salvage before running */
char needsClock; /* do we need clock ticks */
};
+
+
+struct bnode * fs_create(char *ainstance, char *afilecmd, char *avolcmd,
+ char *asalcmd, char *ascancmd);
+struct bnode * dafs_create(char *ainstance, char *afilecmd, char *avolcmd,
+ char * asalsrvcmd, char *asalcmd, char *ascancmd);
+
+static int fs_hascore(register struct ezbnode *abnode);
+static int fs_restartp(register struct fsbnode *abnode);
+static int SetSalFlag(register struct fsbnode *abnode, register int aflag);
+static int RestoreSalFlag(register struct fsbnode *abnode);
+static int fs_delete(struct fsbnode *abnode);
+static int fs_timeout(struct fsbnode *abnode);
+static int fs_getstat(struct fsbnode *abnode, afs_int32 * astatus);
+static int fs_setstat(register struct fsbnode *abnode, afs_int32 astatus);
+static int fs_procexit(struct fsbnode *abnode, struct bnode_proc *aproc);
+static int fs_getstring(struct fsbnode *abnode, char *abuffer, afs_int32 alen);
+
+
+static int fs_getparm(struct fsbnode *abnode, afs_int32 aindex,
+ char *abuffer, afs_int32 alen);
+static int dafs_getparm(struct fsbnode *abnode, afs_int32 aindex,
+ char *abuffer, afs_int32 alen);
+
+#ifdef AFS_NT40_ENV
+static void AppendExecutableExtension(char *cmd)
+#else
+#define AppendExecutableExtension(x)
+#endif
+
+static void SetNeedsClock(register struct fsbnode *ab);
+static int NudgeProcs(register struct fsbnode *abnode);
+
+
+
+struct bnode_ops fsbnode_ops = {
+ fs_create,
+ fs_timeout,
+ fs_getstat,
+ fs_setstat,
+ fs_delete,
+ fs_procexit,
+ fs_getstring,
+ fs_getparm,
+ fs_restartp,
+ fs_hascore,
+};
+
+/* demand attach fs bnode ops */
+struct bnode_ops dafsbnode_ops = {
+ dafs_create,
+ fs_timeout,
+ fs_getstat,
+ fs_setstat,
+ fs_delete,
+ fs_procexit,
+ fs_getstring,
+ dafs_getparm,
+ fs_restartp,
+ fs_hascore,
+};
+
+
/* Function to tell whether this bnode has a core file or not. You might
* think that this could be in bnode.c, and decide what core files to check
* for based on the bnode's coreName property, but that doesn't work because
if (access(tbuffer, 0) == 0)
return 1;
+ /* see if salvageserver left a core file */
+ bnode_CoreName(abnode, "salsrv", tbuffer);
+ if (access(tbuffer, 0) == 0)
+ return 1;
+
/* see if salvager left a core file */
bnode_CoreName(abnode, "salv", tbuffer);
if (access(tbuffer, 0) == 0)
if (code)
return code;
+ if (abnode->salsrvcmd) { /* only in demand attach fs */
+ /* now do same for salsrvcmd (demand attach fs) */
+ code = bnode_ParseLine(abnode->salsrvcmd, &tt);
+ if (code)
+ return 0;
+ if (!tt)
+ return 0;
+ code = stat(tt->key, &tstat);
+ if (code) {
+ bnode_FreeTokens(tt);
+ return 0;
+ }
+ if (tstat.st_ctime > abnode->lastScanStart)
+ code = 1;
+ else
+ code = 0;
+ bnode_FreeTokens(tt);
+ }
+
if (abnode->scancmd) { /* Only in MR-AFS */
/* now do same for scancmd (MR-AFS) */
code = bnode_ParseLine(abnode->scancmd, &tt);
char tbuffer[AFSDIR_PATH_MAX];
int fd;
- abnode->needsSalvage = aflag;
- strcompose(tbuffer, AFSDIR_PATH_MAX, AFSDIR_SERVER_LOCAL_DIRPATH, "/",
- SALFILE, abnode->b.name, NULL);
- if (aflag) {
- fd = open(tbuffer, O_CREAT | O_TRUNC | O_RDWR, 0666);
- close(fd);
- } else {
- unlink(tbuffer);
+ /* don't use the salvage flag for demand attach fs */
+ if (abnode->salsrvcmd == NULL) {
+ abnode->needsSalvage = aflag;
+ strcompose(tbuffer, AFSDIR_PATH_MAX, AFSDIR_SERVER_LOCAL_DIRPATH, "/",
+ SALFILE, abnode->b.name, NULL);
+ if (aflag) {
+ fd = open(tbuffer, O_CREAT | O_TRUNC | O_RDWR, 0666);
+ close(fd);
+ } else {
+ unlink(tbuffer);
+ }
}
return 0;
}
{
char tbuffer[AFSDIR_PATH_MAX];
- strcompose(tbuffer, AFSDIR_PATH_MAX, AFSDIR_SERVER_LOCAL_DIRPATH, "/",
- SALFILE, abnode->b.name, NULL);
- if (access(tbuffer, 0) == 0) {
- /* file exists, so need to salvage */
- abnode->needsSalvage = 1;
- } else {
+ /* never set needs salvage flag for demand attach fs */
+ if (abnode->salsrvcmd != NULL) {
abnode->needsSalvage = 0;
+ } else {
+ strcompose(tbuffer, AFSDIR_PATH_MAX, AFSDIR_SERVER_LOCAL_DIRPATH, "/",
+ SALFILE, abnode->b.name, NULL);
+ if (access(tbuffer, 0) == 0) {
+ /* file exists, so need to salvage */
+ abnode->needsSalvage = 1;
+ } else {
+ abnode->needsSalvage = 0;
+ }
}
return 0;
}
free(abnode->filecmd);
free(abnode->volcmd);
free(abnode->salcmd);
+ if (abnode->salsrvcmd)
+ free(abnode->salsrvcmd);
if (abnode->scancmd)
free(abnode->scancmd);
free(abnode);
char *fileCmdpath, *volCmdpath, *salCmdpath, *scanCmdpath;
int bailout = 0;
- fileCmdpath = volCmdpath = salCmdpath = NULL;
+ te = fileCmdpath = volCmdpath = salCmdpath = scanCmdpath = NULL;
/* construct local paths from canonical (wire-format) paths */
if (ConstructLocalBinPath(afilecmd, &fileCmdpath)) {
bozo_Log("BNODE: command path invalid '%s'\n", afilecmd);
bailout = 1;
+ goto done;
}
if (ConstructLocalBinPath(avolcmd, &volCmdpath)) {
bozo_Log("BNODE: command path invalid '%s'\n", avolcmd);
bailout = 1;
+ goto done;
}
if (ConstructLocalBinPath(asalcmd, &salCmdpath)) {
bozo_Log("BNODE: command path invalid '%s'\n", asalcmd);
bailout = 1;
+ goto done;
}
if (ascancmd && strlen(ascancmd)) {
if (ConstructLocalBinPath(ascancmd, &scanCmdpath)) {
bozo_Log("BNODE: command path invalid '%s'\n", ascancmd);
bailout = 1;
+ goto done;
}
}
if (!bailout) {
sscanf(fileCmdpath, "%s", cmdname);
-#ifdef AFS_NT40_ENV
AppendExecutableExtension(cmdname);
-#endif
if (stat(cmdname, &tstat)) {
bozo_Log("BNODE: file server binary '%s' not found\n", cmdname);
bailout = 1;
+ goto done;
}
sscanf(volCmdpath, "%s", cmdname);
-#ifdef AFS_NT40_ENV
AppendExecutableExtension(cmdname);
-#endif
if (stat(cmdname, &tstat)) {
bozo_Log("BNODE: volume server binary '%s' not found\n", cmdname);
bailout = 1;
+ goto done;
}
sscanf(salCmdpath, "%s", cmdname);
-#ifdef AFS_NT40_ENV
AppendExecutableExtension(cmdname);
-#endif
if (stat(cmdname, &tstat)) {
bozo_Log("BNODE: salvager binary '%s' not found\n", cmdname);
bailout = 1;
+ goto done;
}
if (ascancmd && strlen(ascancmd)) {
sscanf(scanCmdpath, "%s", cmdname);
-#ifdef AFS_NT40_ENV
AppendExecutableExtension(cmdname);
-#endif
if (stat(cmdname, &tstat)) {
bozo_Log("BNODE: scanner binary '%s' not found\n", cmdname);
bailout = 1;
+ goto done;
}
}
}
+ te = (struct fsbnode *)malloc(sizeof(struct fsbnode));
+ if (te == NULL) {
+ bailout = 1;
+ goto done;
+ }
+ memset(te, 0, sizeof(struct fsbnode));
+ te->filecmd = fileCmdpath;
+ te->volcmd = volCmdpath;
+ te->salsrvcmd = NULL;
+ te->salcmd = salCmdpath;
+ if (ascancmd && strlen(ascancmd))
+ te->scancmd = scanCmdpath;
+ else
+ te->scancmd = NULL;
+ if (bnode_InitBnode(te, &fsbnode_ops, ainstance) != 0) {
+ bailout = 1;
+ goto done;
+ }
+ bnode_SetTimeout(te, POLLTIME); /* ask for timeout activations every 10 seconds */
+ RestoreSalFlag(te); /* restore needsSalvage flag based on file's existence */
+ SetNeedsClock(te); /* compute needsClock field */
+
+ done:
if (bailout) {
- free(fileCmdpath);
- free(volCmdpath);
- free(salCmdpath);
+ if (te)
+ free(te);
+ if (fileCmdpath)
+ free(fileCmdpath);
+ if (volCmdpath)
+ free(volCmdpath);
+ if (salCmdpath)
+ free(salCmdpath);
+ if (scanCmdpath)
+ free(scanCmdpath);
return NULL;
}
+ return (struct bnode *)te;
+}
+
+/* create a demand attach fs bnode */
+struct bnode *
+dafs_create(char *ainstance, char *afilecmd, char *avolcmd,
+ char * asalsrvcmd, char *asalcmd, char *ascancmd)
+{
+ struct stat tstat;
+ register struct fsbnode *te;
+ char cmdname[AFSDIR_PATH_MAX];
+ char *fileCmdpath, *volCmdpath, *salsrvCmdpath, *salCmdpath, *scanCmdpath;
+ int bailout = 0;
+
+ te = fileCmdpath = volCmdpath = salsrvCmdpath = salCmdpath = scanCmdpath = NULL;
+
+ /* construct local paths from canonical (wire-format) paths */
+ if (ConstructLocalBinPath(afilecmd, &fileCmdpath)) {
+ bozo_Log("BNODE: command path invalid '%s'\n", afilecmd);
+ bailout = 1;
+ goto done;
+ }
+ if (ConstructLocalBinPath(avolcmd, &volCmdpath)) {
+ bozo_Log("BNODE: command path invalid '%s'\n", avolcmd);
+ bailout = 1;
+ goto done;
+ }
+ if (ConstructLocalBinPath(asalsrvcmd, &salsrvCmdpath)) {
+ bozo_Log("BNODE: command path invalid '%s'\n", asalsrvcmd);
+ bailout = 1;
+ goto done;
+ }
+ if (ConstructLocalBinPath(asalcmd, &salCmdpath)) {
+ bozo_Log("BNODE: command path invalid '%s'\n", asalcmd);
+ bailout = 1;
+ goto done;
+ }
+
+ if (ascancmd && strlen(ascancmd)) {
+ if (ConstructLocalBinPath(ascancmd, &scanCmdpath)) {
+ bozo_Log("BNODE: command path invalid '%s'\n", ascancmd);
+ bailout = 1;
+ goto done;
+ }
+ }
+
+ if (!bailout) {
+ sscanf(fileCmdpath, "%s", cmdname);
+ AppendExecutableExtension(cmdname);
+ if (stat(cmdname, &tstat)) {
+ bozo_Log("BNODE: file server binary '%s' not found\n", cmdname);
+ bailout = 1;
+ goto done;
+ }
+
+ sscanf(volCmdpath, "%s", cmdname);
+ AppendExecutableExtension(cmdname);
+ if (stat(cmdname, &tstat)) {
+ bozo_Log("BNODE: volume server binary '%s' not found\n", cmdname);
+ bailout = 1;
+ goto done;
+ }
+
+ sscanf(salsrvCmdpath, "%s", cmdname);
+ AppendExecutableExtension(cmdname);
+ if (stat(cmdname, &tstat)) {
+ bozo_Log("BNODE: salvageserver binary '%s' not found\n", cmdname);
+ bailout = 1;
+ goto done;
+ }
+
+ sscanf(salCmdpath, "%s", cmdname);
+ AppendExecutableExtension(cmdname);
+ if (stat(cmdname, &tstat)) {
+ bozo_Log("BNODE: salvager binary '%s' not found\n", cmdname);
+ bailout = 1;
+ goto done;
+ }
+
+ if (ascancmd && strlen(ascancmd)) {
+ sscanf(scanCmdpath, "%s", cmdname);
+ AppendExecutableExtension(cmdname);
+ if (stat(cmdname, &tstat)) {
+ bozo_Log("BNODE: scanner binary '%s' not found\n", cmdname);
+ bailout = 1;
+ goto done;
+ }
+ }
+ }
+
te = (struct fsbnode *)malloc(sizeof(struct fsbnode));
+ if (te == NULL) {
+ bailout = 1;
+ goto done;
+ }
memset(te, 0, sizeof(struct fsbnode));
te->filecmd = fileCmdpath;
te->volcmd = volCmdpath;
+ te->salsrvcmd = salsrvCmdpath;
te->salcmd = salCmdpath;
if (ascancmd && strlen(ascancmd))
te->scancmd = scanCmdpath;
else
te->scancmd = NULL;
- if (bnode_InitBnode(te, &fsbnode_ops, ainstance) != 0) {
- free(te);
- free(fileCmdpath);
- free(volCmdpath);
- free(salCmdpath);
- return NULL;
+ if (bnode_InitBnode(te, &dafsbnode_ops, ainstance) != 0) {
+ bailout = 1;
+ goto done;
}
bnode_SetTimeout(te, POLLTIME); /* ask for timeout activations every 10 seconds */
RestoreSalFlag(te); /* restore needsSalvage flag based on file's existence */
SetNeedsClock(te); /* compute needsClock field */
+
+ done:
+ if (bailout) {
+ if (te)
+ free(te);
+ if (fileCmdpath)
+ free(fileCmdpath);
+ if (volCmdpath)
+ free(volCmdpath);
+ if (salsrvCmdpath)
+ free(salsrvCmdpath);
+ if (salCmdpath)
+ free(salCmdpath);
+ if (scanCmdpath)
+ free(scanCmdpath);
+ return NULL;
+ }
+
return (struct bnode *)te;
}
FSSDTIME);
}
}
+ if (abnode->salsrvSDW) {
+ if (!abnode->salsrvKillSent && now - abnode->timeSDStarted > SDTIME) {
+ bnode_StopProc(abnode->salsrvProc, SIGKILL);
+ abnode->salsrvKillSent = 1;
+ bozo_Log
+ ("bos shutdown: salvageserver failed to shutdown within %d seconds\n",
+ SDTIME);
+ }
+ }
if (abnode->scanSDW) {
if (!abnode->scanKillSent && now - abnode->timeSDStarted > SDTIME) {
bnode_StopProc(abnode->scanProc, SIGKILL);
{
register afs_int32 temp;
if (abnode->volSDW || abnode->fileSDW || abnode->salSDW
- || abnode->scanSDW)
+ || abnode->scanSDW || abnode->salsrvSDW)
temp = BSTAT_SHUTTINGDOWN;
else if (abnode->salRunning)
temp = BSTAT_NORMAL;
else if (abnode->volRunning && abnode->fileRunning
- && (!abnode->scancmd || abnode->scanRunning))
+ && (!abnode->scancmd || abnode->scanRunning)
+ && (!abnode->salsrvcmd || abnode->salsrvRunning))
temp = BSTAT_NORMAL;
else if (!abnode->salRunning && !abnode->volRunning
- && !abnode->fileRunning && !abnode->scanRunning)
+ && !abnode->fileRunning && !abnode->scanRunning
+ && !abnode->salsrvRunning)
temp = BSTAT_SHUTDOWN;
else
temp = BSTAT_STARTINGUP;
abnode->scanRunning = 0;
abnode->scanSDW = 0;
abnode->scanKillSent = 0;
+ } else if (aproc == abnode->salsrvProc) {
+ abnode->salsrvProc = 0;
+ abnode->salsrvRunning = 0;
+ abnode->salsrvSDW = 0;
+ abnode->salsrvKillSent = 0;
}
/* now restart anyone who needs to restart */
}
/* make sure we're periodically checking the state if we need to */
-static int
+static void
SetNeedsClock(register struct fsbnode *ab)
{
if (ab->b.goal == 1 && ab->fileRunning && ab->volRunning
- && (!ab->scancmd || ab->scanRunning))
+ && (!ab->scancmd || ab->scanRunning)
+ && (!ab->salsrvcmd || ab->salsrvRunning))
ab->needsClock = 0; /* running normally */
else if (ab->b.goal == 0 && !ab->fileRunning && !ab->volRunning
- && !ab->salRunning && !ab->scanRunning)
+ && !ab->salRunning && !ab->scanRunning && !ab->salsrvRunning)
ab->needsClock = 0; /* halted normally */
else
ab->needsClock = 1; /* other */
abnode->volRunning = 1;
}
}
+ if (abnode->salsrvcmd) {
+ if (!abnode->salsrvRunning) {
+ abnode->lastSalsrvStart = FT_ApproxTime();
+ code =
+ bnode_NewProc(abnode, abnode->salsrvcmd, "salsrv",
+ &tp);
+ if (code == 0) {
+ abnode->salsrvProc = tp;
+ abnode->salsrvRunning = 1;
+ }
+ }
+ }
if (abnode->scancmd) {
if (!abnode->scanRunning) {
abnode->lastScanStart = FT_ApproxTime();
}
} else { /* file is not running */
/* see how to start */
- if (!abnode->needsSalvage) {
+ /* for demand attach fs, needsSalvage flag is ignored */
+ if (!abnode->needsSalvage || abnode->salsrvcmd) {
/* no crash apparent, just start up normally */
if (!abnode->fileRunning) {
abnode->lastFileStart = FT_ApproxTime();
abnode->volRunning = 1;
}
}
+ if (abnode->salsrvcmd && !abnode->salsrvRunning) {
+ abnode->lastSalsrvStart = FT_ApproxTime();
+ code =
+ bnode_NewProc(abnode, abnode->salsrvcmd, "salsrv",
+ &tp);
+ if (code == 0) {
+ abnode->salsrvProc = tp;
+ abnode->salsrvRunning = 1;
+ }
+ }
if (abnode->scancmd && !abnode->scanRunning) {
abnode->lastScanStart = FT_ApproxTime();
code =
abnode->volSDW = 1;
abnode->timeSDStarted = now;
}
+ if (abnode->salsrvRunning && !abnode->salsrvSDW) {
+ bnode_StopProc(abnode->salsrvProc, SIGTERM);
+ abnode->salsrvSDW = 1;
+ abnode->timeSDStarted = now;
+ }
if (abnode->scanRunning && !abnode->scanSDW) {
bnode_StopProc(abnode->scanProc, SIGTERM);
abnode->scanSDW = 1;
return BZDOM;
return 0;
}
+
+static int
+dafs_getparm(struct fsbnode *abnode, afs_int32 aindex, char *abuffer,
+ afs_int32 alen)
+{
+ if (aindex == 0)
+ strcpy(abuffer, abnode->filecmd);
+ else if (aindex == 1)
+ strcpy(abuffer, abnode->volcmd);
+ else if (aindex == 2)
+ strcpy(abuffer, abnode->salsrvcmd);
+ else if (aindex == 3)
+ strcpy(abuffer, abnode->salcmd);
+ else if (aindex == 4 && abnode->scancmd)
+ strcpy(abuffer, abnode->scancmd);
+ else
+ return BZDOM;
+ return 0;
+}
;;
esac
+
+
+dnl pthreads fixes
+case $AFS_SYSNAME in
+dnl we'll go ahead and turn on XOPEN2K and ISO_C99
+dnl if this causes problems, we should scale back to _XOPEN_SOURCE=500
+ *linux*)
+ MT_CFLAGS="${MT_CFLAGS} -D_XOPEN_SOURCE=600 -D_BSD_SOURCE"
+ ;;
+esac
+
+
dnl Disable the default for debugging/optimization if not enabled
if test "x$enable_debug_kernel" = "xno"; then
KERN_DBG=
#ifdef AFS_NAMEI_ENV
#define AFS_64BIT_IOPS_ENV 1
#endif
-#define BITMAP_LATER 1
-#define FAST_RESTART 1
#define AFS_HAVE_FLOCK_SYSID 1
#ifdef AFS_NAMEI_ENV
#define AFS_64BIT_IOPS_ENV 1
#endif
-#define BITMAP_LATER 1
-#define FAST_RESTART 1
#define AFS_HAVE_FLOCK_SYSID 1
#ifdef AFS_NAMEI_ENV
#define AFS_64BIT_IOPS_ENV 1
#endif
-#define BITMAP_LATER 1
-#define FAST_RESTART 1
#define AFS_HAVE_FLOCK_SYSID 1
typedef long long afs_int64;
typedef unsigned long long afs_uint64;
#endif
-#define ZeroInt64(a) (a) = 0
+#define ZeroInt64(a) (a = 0)
#define AssignInt64(a, b) *(b) = (a)
+#define IncInt64(a) (*(a))++
+#define IncUInt64(a) (*(a))++
+#define DecInt64(a) (*(a))--
+#define DecUInt64(a) (*(a))--
+#define GTInt64(a,b) ((a) > (b))
+#define GEInt64(a,b) ((a) >= (b))
+#define LEInt64(a,b) ((a) <= (b))
+#define LTInt64(a,b) ((a) < (b))
#define AddInt64(a,b,c) *(c) = (afs_int64)(a) + (afs_int64)(b)
#define AddUInt64(a,b,c) *(c) = (afs_uint64)(a) + (afs_uint64)(b)
#define SubtractInt64(a,b,c) *(c) = (afs_int64)(a) - (afs_int64)(b)
afs_uint32 low;
};
typedef struct u_Int64 afs_uint64;
-#define ZeroInt64(a) (a).high = (a).low = 0
+#define ZeroInt64(a) ((a).high = (a).low = 0)
#define AssignInt64(a, b) (b)->high = (a).high; (b)->low = (a).low
+#define IncInt64(a) ((++((a)->low)) ? 0 : (a)->high++ )
+#define IncUInt64(a) ((++((a)->low)) ? 0 : (a)->high++ )
+#define DecInt64(a) (((a)->low)-- ? 0 : (a)->high-- )
+#define DecUInt64(a) (((a)->low)-- ? 0 : (a)->high-- )
+#define GTInt64(a,b) (((a).high > (b).high) || (((a).high == (b).high) && ((a).low > (b).low)))
+#define GEInt64(a,b) (((a).high > (b).high) || (((a).high == (b).high) && ((a).low >= (b).low)))
+#define LEInt64(a,b) (((a).high < (b).high) || (((a).high == (b).high) && ((a).low <= (b).low)))
+#define LTInt64(a,b) (((a).high < (b).high) || (((a).high == (b).high) && ((a).low < (b).low)))
#define CompareInt64(a,b) (((afs_int32)(a).high - (afs_int32)(b).high) || (((a).high == (b).high) && ((a).low - (b).low)))
#define AddInt64(a, b, c) { afs_int64 _a, _b; _a = a; _b = b; (c)->low = _a.low + _b.low; (c)->high = _a.high + _b.high + ((c)->low < _b.low); }
#define SubtractInt64(a, b, c) { afs_int64 _a, _b; _a = a; _b = b; (c)->low = _a.low - _b.low; (c)->high = _a.high - _b.high - (_a.low < _b.low); }
};
typedef struct afsUUID afsUUID;
+/* for now, demand attach fileserver is only support on unix pthreads builds */
+#if defined(DEMAND_ATTACH_ENABLE) && defined(AFS_PTHREAD_ENV) && !defined(AFS_NT40_ENV)
+#define AFS_DEMAND_ATTACH_FS 1
+#endif
+
#endif /* OPENAFS_CONFIG_AFS_STDS_H */
#define _RXQSP(q1,q2,i,a,b,c,d,x,y) if (!queue_IsEnd(q1,i->c)) \
(((y->b->a=q2->a)->b=y->b), ((x->a->b=q2)->a=x->a), ((i->c=q1)->d=i))
+/* This one moves a chain of elements from (s) to (e) from its
+ * current position to either before or after element (i)
+ * if (a,b,x,y) is (prev,next,s,e) then chain is moved before (i)
+ * if (a,b,x,y) is (next,prev,e,s) then chain is moved after (i) */
+#define _RXQMV(i, s, e, a, b, x, y) if (i->a != y) \
+ (((e->next->prev=s->prev)->next=e->next), ((i->a->b=x)->a=i->a), ((y->b=i)->a=y))
+
/* Basic remove operation. Doesn't update the queue item to indicate it's been removed */
#define _RXQR(i) ((_RXQ(i)->prev->next=_RXQ(i)->next)->prev=_RXQ(i)->prev)
#define queue_Replace(q1,q2) if (queue_IsEmpty(q2)) queue_Init(q1); else \
(*_RXQ(q1) = *_RXQ(q2), _RXQ(q1)->next->prev = _RXQ(q1)->prev->next = _RXQ(q1), queue_Init(q2))
+/* move a chain of elements beginning at (s) and ending at (e) before node (i) */
+#define queue_MoveChainBefore(i, s, e) _RXQMV(_RXQ(i),_RXQ(s),_RXQ(e),prev,next,_RXQ(s),_RXQ(e))
+
+/* move a chain of elements beginning at (s) and ending at (e) after node (i) */
+#define queue_MoveChainAfter(i, s, e) _RXQMV(_RXQ(i),_RXQ(s),_RXQ(e),next,prev,_RXQ(e),_RXQ(s))
+
/* Remove a queue element (*i) from it's queue. The next field is 0'd, so that any further use of this q entry will hopefully cause a core dump. Multiple removes of the same queue item are not supported */
#define queue_Remove(i) (_RXQR(i), _RXQ(i)->next = 0)
/* Returns false if the item was removed from a queue OR is uninitialized (zero) */
#define queue_IsOnQueue(i) (_RXQ(i)->next != 0)
+/* Returns true if the item was removed from a queue OR is uninitialized (zero) */
+/* Return false if the queue item is currently in a queue */
+#define queue_IsNotOnQueue(i) (_RXQ(i)->next == 0)
+
/* Returns true if the queue item (i) is the first element of the queue (q) */
#define queue_IsFirst(q,i) (_RXQ(q)->first == _RXQ(i))
/* Returns true if the queue item (i) is the end of the queue (q), that is, i is the head of the queue */
#define queue_IsEnd(q,i) (_RXQ(q) == _RXQ(i))
+/* Returns false if the queue item (i) is the end of the queue (q), that is, i is the head of the queue */
+#define queue_IsNotEnd(q,i) (_RXQ(q) != _RXQ(i))
+
/* Prototypical loop to scan an entire queue forwards. q is the queue
* head, qe is the loop variable, next is a variable used to store the
* queue entry for the next iteration of the loop, s is the user's
!queue_IsEnd(q, qe); \
(qe) = (next), next = queue_Next(qe, s)
+/* similar to queue_Scan except start at element 'start' instead of the beginning */
+#define queue_ScanFrom(q, start, qe, next, s) \
+ (qe) = (struct s*)(start), next = queue_Next(qe, s); \
+ !queue_IsEnd(q, qe); \
+ (qe) = (next), next = queue_Next(qe, s)
+
/* This is similar to queue_Scan, but scans from the end of the queue to the beginning. Next is the previous queue entry. */
#define queue_ScanBackwards(q, qe, prev, s) \
(qe) = queue_Last(q, s), prev = queue_Prev(qe, s); \
!queue_IsEnd(q, qe); \
(qe) = prev, prev = queue_Prev(qe, s)
+/* This is similar to queue_ScanBackwards, but start at element 'start' instead of the end. Next is the previous queue entry. */
+#define queue_ScanBackwardsFrom(q, start, qe, prev, s) \
+ (qe) = (struct s*)(start), prev = queue_Prev(qe, s); \
+ !queue_IsEnd(q, qe); \
+ (qe) = prev, prev = queue_Prev(qe, s)
+
#define queue_Count(q, qe, nqe, s, n) \
for (n=0, queue_Scan(q, qe, nqe, s), n++) {}
#endif /* _RX_QUEUE_ */
--- /dev/null
+# Copyright 2000, International Business Machines Corporation and others.
+# All Rights Reserved.
+#
+# This software has been released under the terms of the IBM Public
+# License. For details, see the LICENSE file in the top-level source
+# directory or online at http://www.openafs.org/dl/license10.html
+#
+# Portions Copyright (c) 2003 Apple Computer, Inc.
+# Portions Copyright (c) 2006 Sine Nomine Associates
+
+srcdir=@srcdir@
+include @TOP_OBJDIR@/src/config/Makefile.config
+
+CC=${MT_CC}
+CFLAGS=${COMMON_CFLAGS} -I.. -DNINTERFACE ${MT_CFLAGS} -DRXDEBUG -DFSSYNC_BUILD_CLIENT \
+ -DSALVSYNC_BUILD_SERVER -DSALVSYNC_BUILD_CLIENT
+
+CCRULE=${CC} ${CFLAGS} -c $?
+
+VICED=../viced
+VLSERVER=../vlserver
+LWP=../lwp
+LIBACL=../libacl
+UTIL=../util
+DIR=../dir
+VOL=../vol
+FSINT=../fsint
+
+SALVAGEDOBJS=salvaged.o vol-salvage.o physio.o
+
+DIROBJS=buffer.o dir.o salvage.o
+
+LWPOBJS=lock.o threadname.o
+
+UTILOBJS=assert.o uuid.o serverLog.o fileutil.o netutils.o dirpath.o volparse.o flipbase64.o softsig.o fstab.o
+
+VLIBOBJS=vnode.o volume.o vutil.o partition.o fssync-client.o \
+ clone.o nuke.o devname.o listinodes.o ihandle.o \
+ namei_ops.o salvsync-server.o salvsync-client.o \
+ daemon_com.o
+
+OBJECTS= ${SALVAGEDOBJS} ${UTILOBJS} ${VLIBOBJS} ${DIROBJS} ${LWPOBJS}
+
+FSSDEBUG_OBJS = fssync-debug.o physio.o common.o ${UTILOBJS} ${VLIBOBJS} ${DIROBJS} ${LWPOBJS}
+
+SSSDEBUG_OBJS = salvsync-debug.o physio.o common.o ${UTILOBJS} ${VLIBOBJS} ${DIROBJS} ${LWPOBJS}
+
+LIBS=${TOP_LIBDIR}/libafsauthent.a ${TOP_LIBDIR}/libafsrpc.a ${TOP_LIBDIR}/util.a ${TOP_LIBDIR}/libcmd.a
+
+INSTALL_TARGS = ${DESTDIR}${afssrvlibexecdir}/salvageserver \
+ ${DESTDIR}${afssrvsbindir}/fssync-debug \
+ ${DESTDIR}${afssrvsbindir}/salvsync-debug
+
+DEST_TARGS = ${DEST}/root.server/usr/afs/bin/salvageserver \
+ ${DEST}/root.server/usr/afs/bin/fssync-debug \
+ ${DEST}/root.server/usr/afs/bin/salvsync-debug
+
+all: salvageserver fssync-debug salvsync-debug
+
+salvaged.o: ${VOL}/salvaged.c
+ ${CCRULE}
+
+vol-salvage.o: ${VOL}/vol-salvage.c
+ ${CCRULE}
+
+physio.o: ${VOL}/physio.c
+ ${CCRULE}
+
+fssync-debug.o: ${VOL}/fssync-debug.c
+ ${CCRULE}
+
+salvsync-debug.o: salvsync-debug.c
+ ${CCRULE}
+
+assert.o: ${UTIL}/assert.c
+ ${CCRULE}
+
+uuid.o: ${UTIL}/uuid.c
+ ${CCRULE}
+
+serverLog.o: ${UTIL}/serverLog.c
+ ${CCRULE}
+
+fileutil.o: ${UTIL}/fileutil.c
+ ${CCRULE}
+
+volparse.o: ${UTIL}/volparse.c
+ ${CCRULE}
+
+flipbase64.o: ${UTIL}/flipbase64.c
+ ${CCRULE}
+
+netutils.o: ${UTIL}/netutils.c
+ ${CCRULE}
+
+dirpath.o: ${UTIL}/dirpath.c
+ ${CCRULE}
+
+softsig.o: ${UTIL}/softsig.c
+ ${CCRULE}
+
+buffer.o: ${DIR}/buffer.c
+ ${CCRULE}
+
+dir.o: ${DIR}/dir.c
+ ${CCRULE}
+
+salvage.o: ${DIR}/salvage.c
+ ${CCRULE}
+
+lock.o: ${LWP}/lock.c
+ ${CCRULE}
+
+threadname.o: ${LWP}/threadname.c
+ ${CCRULE}
+
+vnode.o: ${VOL}/vnode.c
+ ${CCRULE}
+
+volume.o: ${VOL}/volume.c
+ ${CCRULE}
+
+vutil.o: ${VOL}/vutil.c
+ ${CCRULE}
+
+partition.o: ${VOL}/partition.c
+ ${CCRULE}
+
+fssync-client.o: ${VOL}/fssync-client.c
+ ${CCRULE}
+
+salvsync-server.o: ${VOL}/salvsync-server.c
+ ${CCRULE}
+
+salvsync-client.o: ${VOL}/salvsync-client.c
+ ${CCRULE}
+
+daemon_com.o: ${VOL}/daemon_com.c
+ ${CCRULE}
+
+clone.o: ${VOL}/clone.c
+ ${CCRULE}
+
+nuke.o: ${VOL}/nuke.c
+ ${CCRULE}
+
+devname.o: ${VOL}/devname.c
+ ${CCRULE}
+
+# only for darwin?
+fstab.o: ${UTIL}/fstab.c
+ ${CCRULE}
+
+common.o: ${VOL}/common.c
+ ${CCRULE}
+
+listinodes.o: ${VOL}/listinodes.c
+ ${CCRULE}
+
+ihandle.o: ${VOL}/ihandle.c
+ ${CCRULE}
+
+namei_ops.o: ${VOL}/namei_ops.c
+ ${CCRULE}
+
+salvageserver: ${OBJECTS} ${LIBS}
+ ${CC} ${LDFLAGS} -o salvageserver ${OBJECTS} ${LIBS} ${MT_LIBS} ${XLIBS}
+
+fssync-debug: ${FSSDEBUG_OBJS} ${LIBS}
+ ${CC} ${LDFLAGS} -o fssync-debug ${FSSDEBUG_OBJS} ${LIBS} ${MT_LIBS} ${XLIBS}
+
+salvsync-debug: ${SSSDEBUG_OBJS} ${LIBS}
+ ${CC} ${LDFLAGS} -o salvsync-debug ${SSSDEBUG_OBJS} ${LIBS} ${MT_LIBS} ${XLIBS}
+
+${DEST}/root.server/usr/afs/bin/salvageserver: salvageserver
+ ${INSTALL} -ns $? $@
+
+${DEST}/root.server/usr/afs/bin/fssync-debug: fssync-debug
+ ${INSTALL} -s $? $@
+
+${DEST}/root.server/usr/afs/bin/salvsync-debug: salvsync-debug
+ ${INSTALL} -s $? $@
+
+install: ${INSTALL_TARGS}
+
+clean:
+ $(RM) -f *.o salvageserver core AFS_component_version_number.c
+
+include ../config/Makefile.version
+
+${DESTDIR}${afssrvlibexecdir}/salvageserver: salvageserver
+ ${INSTALL} -ns $? $@
+
+${DESTDIR}${afssrvsbindir}/fssync-debug: fssync-debug
+ ${INSTALL} -s $? $@
+
+${DESTDIR}${afssrvsbindir}/salvsync-debug: salvsync-debug
+ ${INSTALL} -s $? $@
+
+dest: ${DEST_TARGS}
--- /dev/null
+/*
+ * Copyright 2006, Sine Nomine Associates and others.
+ * All Rights Reserved.
+ *
+ * This software has been released under the terms of the IBM Public
+ * License. For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+/* Main program file. Define globals. */
+#define MAIN 1
+
+/*
+ * salvsync debug tool
+ */
+
+
+#include <afsconfig.h>
+#include <afs/param.h>
+
+RCSID
+ ("$Header$");
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <errno.h>
+#ifdef AFS_NT40_ENV
+#include <io.h>
+#include <WINNT/afsevent.h>
+#else
+#include <sys/param.h>
+#include <sys/file.h>
+#ifndef ITIMER_REAL
+#include <sys/time.h>
+#endif /* ITIMER_REAL */
+#endif
+#include <rx/xdr.h>
+#include <afs/afsint.h>
+#include <afs/assert.h>
+
+
+#include <fcntl.h>
+
+#ifndef AFS_NT40_ENV
+#include <afs/osi_inode.h>
+#endif
+
+#include <afs/cmd.h>
+#include <afs/afsutil.h>
+#include <afs/fileutil.h>
+
+#include "nfs.h"
+#include "lwp.h"
+#include "lock.h"
+#include "ihandle.h"
+#include "vnode.h"
+#include "volume.h"
+#include "partition.h"
+#include "daemon_com.h"
+#include "salvsync.h"
+#ifdef AFS_NT40_ENV
+#include <pthread.h>
+#endif
+
+int VolumeChanged; /* hack to make dir package happy */
+
+
+#ifndef AFS_DEMAND_ATTACH_FS
+int
+main(int argc, char ** argv)
+{
+ fprintf(stderr, "*** salvsync-debug is only supported for OpenAFS builds with the demand-attach fileserver extension\n");
+ return -1;
+}
+#else /* AFS_DEMAND_ATTACH_FS */
+
+struct salv_state {
+ afs_uint32 prio;
+ afs_uint32 volume;
+ char partName[16];
+};
+
+struct state {
+ afs_int32 reason;
+ struct salv_state * sop;
+};
+
+static int common_prolog(struct cmd_syndesc *, struct state *);
+static int common_salv_prolog(struct cmd_syndesc *, struct state *);
+
+static int do_salvop(struct state *, afs_int32 command, SYNC_response * res);
+
+static char * response_code_to_string(afs_int32);
+static char * command_code_to_string(afs_int32);
+static char * reason_code_to_string(afs_int32);
+static char * program_type_to_string(afs_int32);
+static char * state_code_to_string(afs_int32);
+
+
+static int OpStats(struct cmd_syndesc * as, char * rock);
+static int OpSalvage(struct cmd_syndesc * as, char * rock);
+static int OpCancel(struct cmd_syndesc * as, char * rock);
+static int OpCancelAll(struct cmd_syndesc * as, char * rock);
+static int OpRaisePrio(struct cmd_syndesc * as, char * rock);
+static int OpQuery(struct cmd_syndesc * as, char * rock);
+
+
+#ifndef AFS_NT40_ENV
+#include "AFS_component_version_number.c"
+#endif
+#define MAX_ARGS 128
+
+#define COMMON_PARMS_OFFSET 13
+#define COMMON_PARMS(ts) \
+ cmd_Seek(ts, COMMON_PARMS_OFFSET); \
+ cmd_AddParm(ts, "-reason", CMD_SINGLE, CMD_OPTIONAL, "sync protocol reason code"); \
+ cmd_AddParm(ts, "-programtype", CMD_SINGLE, CMD_OPTIONAL, "program type code")
+
+#define COMMON_SALV_PARMS_OFFSET 10
+#define COMMON_SALV_PARMS(ts) \
+ cmd_Seek(ts, COMMON_SALV_PARMS_OFFSET); \
+ cmd_AddParm(ts, "-volumeid", CMD_SINGLE, 0, "volume id"); \
+ cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name"); \
+ cmd_AddParm(ts, "-priority", CMD_SINGLE, CMD_OPTIONAL, "priority")
+
+#define SALV_PARMS_DECL(ts) \
+ COMMON_SALV_PARMS(ts); \
+ COMMON_PARMS(ts)
+
+#define COMMON_PARMS_DECL(ts) \
+ COMMON_PARMS(ts)
+
+int
+main(int argc, char **argv)
+{
+ struct cmd_syndesc *ts;
+ int err = 0;
+ int i;
+ extern char cml_version_number[];
+
+ /* Initialize directory paths */
+ if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
+#ifdef AFS_NT40_ENV
+ ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
+#endif
+ fprintf(stderr, "%s: Unable to obtain AFS server directory.\n",
+ argv[0]);
+ exit(2);
+ }
+
+
+ ts = cmd_CreateSyntax("stats", OpStats, 0, "get salvageserver statistics (SALVSYNC_NOP opcode)");
+ COMMON_PARMS_DECL(ts);
+ cmd_CreateAlias(ts, "nop");
+
+ ts = cmd_CreateSyntax("salvage", OpSalvage, 0, "schedule a salvage (SALVSYNC_SALVAGE opcode)");
+ SALV_PARMS_DECL(ts);
+
+ ts = cmd_CreateSyntax("cancel", OpCancel, 0, "cancel a salvage (SALVSYNC_CANCEL opcode)");
+ SALV_PARMS_DECL(ts);
+
+ ts = cmd_CreateSyntax("raiseprio", OpRaisePrio, 0, "raise a salvage priority (SALVSYNC_RAISEPRIO opcode)");
+ SALV_PARMS_DECL(ts);
+ cmd_CreateAlias(ts, "rp");
+
+ ts = cmd_CreateSyntax("query", OpQuery, 0, "query salvage status (SALVSYNC_QUERY opcode)");
+ SALV_PARMS_DECL(ts);
+ cmd_CreateAlias(ts, "qry");
+
+ ts = cmd_CreateSyntax("kill", OpCancelAll, 0, "cancel all scheduled salvages (SALVSYNC_CANCELALL opcode)");
+ COMMON_PARMS_DECL(ts);
+
+ err = cmd_Dispatch(argc, argv);
+ exit(err);
+}
+
+static int
+common_prolog(struct cmd_syndesc * as, struct state * state)
+{
+ register struct cmd_item *ti;
+
+#ifdef AFS_NT40_ENV
+ if (afs_winsockInit() < 0) {
+ Exit(1);
+ }
+#endif
+
+ VInitVolumePackage(debugUtility, 1, 1,
+ DONT_CONNECT_FS, 0);
+ DInit(1);
+
+ if ((ti = as->parms[COMMON_PARMS_OFFSET].items)) { /* -reason */
+ state->reason = atoi(ti->data);
+ }
+ if ((ti = as->parms[COMMON_PARMS_OFFSET+1].items)) { /* -programtype */
+ if (!strcmp(ti->data, "fileServer")) {
+ programType = fileServer;
+ } else if (!strcmp(ti->data, "volumeUtility")) {
+ programType = volumeUtility;
+ } else if (!strcmp(ti->data, "salvager")) {
+ programType = salvager;
+ } else if (!strcmp(ti->data, "salvageServer")) {
+ programType = salvageServer;
+ } else {
+ programType = (ProgramType) atoi(ti->data);
+ }
+ }
+
+ VConnectSALV();
+
+ return 0;
+}
+
+static int
+common_salv_prolog(struct cmd_syndesc * as, struct state * state)
+{
+ register struct cmd_item *ti;
+ char pname[100], *temp;
+
+ state->sop = (struct salv_state *) calloc(1, sizeof(struct salv_state));
+ assert(state->sop != NULL);
+
+ if ((ti = as->parms[COMMON_SALV_PARMS_OFFSET].items)) { /* -volumeid */
+ state->sop->volume = atoi(ti->data);
+ } else {
+ fprintf(stderr, "required argument -volumeid not given\n");
+ }
+
+ if ((ti = as->parms[COMMON_SALV_PARMS_OFFSET+1].items)) { /* -partition */
+ strlcpy(state->sop->partName, ti->data, sizeof(state->sop->partName));
+ } else {
+ memset(state->sop->partName, 0, sizeof(state->sop->partName));
+ }
+
+ if ((ti = as->parms[COMMON_SALV_PARMS_OFFSET+2].items)) { /* -prio */
+ state->sop->prio = atoi(ti->data);
+ } else {
+ state->sop->prio = 0;
+ }
+
+ return 0;
+}
+
+static int
+do_salvop(struct state * state, afs_int32 command, SYNC_response * res)
+{
+ afs_int32 code;
+ SALVSYNC_response_hdr hdr_l, *hdr;
+ SYNC_response res_l;
+
+ if (!res) {
+ res = &res_l;
+ res->payload.len = sizeof(hdr_l);
+ res->payload.buf = hdr = &hdr_l;
+ } else {
+ hdr = (SALVSYNC_response_hdr *) res->payload.buf;
+ }
+
+ fprintf(stderr, "calling SALVSYNC_SalvageVolume with command code %d (%s)\n",
+ command, command_code_to_string(command));
+
+ code = SALVSYNC_SalvageVolume(state->sop->volume,
+ state->sop->partName,
+ command,
+ state->reason,
+ state->sop->prio,
+ res);
+
+ switch (code) {
+ case SYNC_OK:
+ case SYNC_DENIED:
+ break;
+ default:
+ fprintf(stderr, "possible sync protocol error. return code was %d\n", code);
+ }
+
+ fprintf(stderr, "SALVSYNC_SalvageVolume returned %d (%s)\n", code, response_code_to_string(code));
+ fprintf(stderr, "protocol response code was %d (%s)\n",
+ res->hdr.response, response_code_to_string(res->hdr.response));
+ fprintf(stderr, "protocol reason code was %d (%s)\n",
+ res->hdr.reason, reason_code_to_string(res->hdr.reason));
+
+ printf("state = {\n");
+ if (res->hdr.flags & SALVSYNC_FLAG_VOL_STATS_VALID) {
+ printf("\tstate = %d (%s)\n",
+ hdr->state, state_code_to_string(hdr->state));
+ printf("\tprio = %d\n", hdr->prio);
+ }
+ printf("\tsq_len = %d\n", hdr->sq_len);
+ printf("\tpq_len = %d\n", hdr->pq_len);
+ printf("}\n");
+
+ VDisconnectSALV();
+}
+
+static char *
+response_code_to_string(afs_int32 response)
+{
+ switch (response) {
+ case SYNC_OK:
+ return "SYNC_OK";
+ case SYNC_DENIED:
+ return "SYNC_DENIED";
+ case SYNC_COM_ERROR:
+ return "SYNC_COM_ERROR";
+ case SYNC_BAD_COMMAND:
+ return "SYNC_BAD_COMMAND";
+ case SYNC_FAILED:
+ return "SYNC_FAILED";
+ default:
+ return "**UNKNOWN**";
+ }
+}
+
+static char *
+command_code_to_string(afs_int32 command)
+{
+ switch (command) {
+ case SYNC_COM_CHANNEL_CLOSE:
+ return "SYNC_COM_CHANNEL_CLOSE";
+ case SALVSYNC_NOP:
+ return "SALVSYNC_NOP";
+ case SALVSYNC_SALVAGE:
+ return "SALVSYNC_SALVAGE";
+ case SALVSYNC_CANCEL:
+ return "SALVSYNC_CANCEL";
+ case SALVSYNC_RAISEPRIO:
+ return "SALVSYNC_RAISEPRIO";
+ case SALVSYNC_QUERY:
+ return "SALVSYNC_QUERY";
+ case SALVSYNC_CANCELALL:
+ return "SALVSYNC_CANCELLALL";
+ default:
+ return "**UNKNOWN**";
+ }
+}
+
+static char *
+reason_code_to_string(afs_int32 reason)
+{
+ switch (reason) {
+ case SALVSYNC_WHATEVER:
+ return "SALVSYNC_WHATEVER";
+ case SALVSYNC_ERROR:
+ return "SALVSYNC_ERROR";
+ case SALVSYNC_OPERATOR:
+ return "SALVSYNC_OPERATOR";
+ case SALVSYNC_SHUTDOWN:
+ return "SALVSYNC_SHUTDOWN";
+ case SALVSYNC_NEEDED:
+ return "SALVSYNC_NEEDED";
+ default:
+ return "**UNKNOWN**";
+ }
+}
+
+static char *
+program_type_to_string(afs_int32 type)
+{
+ switch ((ProgramType)type) {
+ case fileServer:
+ return "fileServer";
+ case volumeUtility:
+ return "volumeUtility";
+ case salvager:
+ return "salvager";
+ case salvageServer:
+ return "salvageServer";
+ default:
+ return "**UNKNOWN**";
+ }
+}
+
+static char *
+state_code_to_string(afs_int32 state)
+{
+ switch (state) {
+ case SALVSYNC_STATE_UNKNOWN:
+ return "SALVSYNC_STATE_UNKNOWN";
+ case SALVSYNC_STATE_QUEUED:
+ return "SALVSYNC_STATE_QUEUED";
+ case SALVSYNC_STATE_SALVAGING:
+ return "SALVSYNC_STATE_SALVAGING";
+ case SALVSYNC_STATE_ERROR:
+ return "SALVSYNC_STATE_ERROR";
+ case SALVSYNC_STATE_DONE:
+ return "SALVSYNC_STATE_DONE";
+ default:
+ return "**UNKNOWN**";
+ }
+}
+
+static int
+OpStats(struct cmd_syndesc * as, char * rock)
+{
+ struct state state;
+
+ common_prolog(as, &state);
+ common_salv_prolog(as, &state);
+
+ do_salvop(&state, SALVSYNC_NOP, NULL);
+
+ return 0;
+}
+
+static int
+OpSalvage(struct cmd_syndesc * as, char * rock)
+{
+ struct state state;
+
+ common_prolog(as, &state);
+ common_salv_prolog(as, &state);
+
+ do_salvop(&state, SALVSYNC_SALVAGE, NULL);
+
+ return 0;
+}
+
+static int
+OpCancel(struct cmd_syndesc * as, char * rock)
+{
+ struct state state;
+
+ common_prolog(as, &state);
+ common_salv_prolog(as, &state);
+
+ do_salvop(&state, SALVSYNC_CANCEL, NULL);
+
+ return 0;
+}
+
+static int
+OpCancelAll(struct cmd_syndesc * as, char * rock)
+{
+ struct state state;
+
+ common_prolog(as, &state);
+ common_salv_prolog(as, &state);
+
+ do_salvop(&state, SALVSYNC_CANCELALL, NULL);
+
+ return 0;
+}
+
+static int
+OpRaisePrio(struct cmd_syndesc * as, char * rock)
+{
+ struct state state;
+
+ common_prolog(as, &state);
+ common_salv_prolog(as, &state);
+
+ do_salvop(&state, SALVSYNC_RAISEPRIO, NULL);
+
+ return 0;
+}
+
+static int
+OpQuery(struct cmd_syndesc * as, char * rock)
+{
+ struct state state;
+
+ common_prolog(as, &state);
+ common_salv_prolog(as, &state);
+
+ do_salvop(&state, SALVSYNC_QUERY, NULL);
+
+ return 0;
+}
+
+#endif /* AFS_DEMAND_ATTACH_FS */
include @TOP_OBJDIR@/src/config/Makefile.config
CC=${MT_CC}
-CFLAGS=${COMMON_CFLAGS} -I.. -DNINTERFACE ${MT_CFLAGS} -DRXDEBUG
+CFLAGS=${COMMON_CFLAGS} -I.. -DNINTERFACE ${MT_CFLAGS} -DRXDEBUG -DFSSYNC_BUILD_SERVER -DSALVSYNC_BUILD_CLIENT
CCRULE=${CC} ${CFLAGS} -c $?
VOL=../vol
FSINT=../fsint
-VICEDOBJS=viced.o afsfileprocs.o host.o physio.o callback.o
+VICEDOBJS=viced.o afsfileprocs.o host.o physio.o callback.o serialize_state.o
VLSERVEROBJS=vldbint.cs.o vldbint.xdr.o
DIROBJS=buffer.o dir.o salvage.o
-VOLOBJS= vnode.o volume.o vutil.o partition.o fssync.o purge.o \
+VOLOBJS= vnode.o volume.o vutil.o partition.o fssync-server.o \
clone.o devname.o common.o ihandle.o listinodes.o namei_ops.o \
- fstab.o
+ fstab.o salvsync-client.o daemon_com.o
FSINTOBJS= afsaux.o afscbint.cs.o afsint.ss.o afsint.xdr.o
objects= ${VICEDOBJS} ${VLSERVEROBJS} ${LWPOBJS} ${LIBACLOBJS} \
${UTILOBJS} ${DIROBJS} ${VOLOBJS} ${FSINTOBJS}
+SDBGOBJS = state_analyzer.o uuid.o dirpath.o fileutil.o ${TOP_LIBDIR}/util.a
+
LIBS=${TOP_LIBDIR}/libafsauthent.a ${TOP_LIBDIR}/libafsrpc.a ${TOP_LIBDIR}/util.a
-all: fileserver
+all: fileserver state_analyzer
viced.o: ${VICED}/viced.c
${CCRULE}
callback.o: ${VICED}/callback.c
${CCRULE}
+serialize_state.o: ./serialize_state.c
+ ${CCRULE}
+
assert.o: ${UTIL}/assert.c
${CCRULE}
partition.o: ${VOL}/partition.c
${CCRULE}
-fssync.o: ${VOL}/fssync.c
+fssync-server.o: ${VOL}/fssync-server.c
+ ${CCRULE}
+
+fssync-client.o: ${VOL}/fssync-client.c
+ ${CCRULE}
+
+salvsync-client.o: ${VOL}/salvsync-client.c
${CCRULE}
-purge.o: ${VOL}/purge.c
+daemon_com.o: ${VOL}/daemon_com.c
${CCRULE}
clone.o: ${VOL}/clone.c
afsint.xdr.o: ${FSINT}/afsint.xdr.c
${CCRULE}
+state_analyzer.o: state_analyzer.c
+ ${CCRULE}
+
fileserver: ${objects} ${LIBS}
${CC} ${LDFLAGS} -o fileserver ${objects} ${LIBS} ${MT_LIBS} ${XLIBS}
+state_analyzer: ${SDBGOBJS}
+ ${CC} ${LDFLAGS} -o state_analyzer ${SDBGOBJS} ${MT_LIBS} ${XLIBS}
+
${DEST}/root.server/usr/afs/bin/fileserver: fileserver
${INSTALL} -ns $? $@
-install: ${DESTDIR}${afssrvlibexecdir}/fileserver
+${DEST}/root.server/usr/afs/bin/state_analyzer: state_analyzer
+ ${INSTALL} $? $@
+
+install: ${DESTDIR}${afssrvlibexecdir}/fileserver ${DESTDIR}${afssrvsbindir}/state_analyzer
clean:
- $(RM) -f *.o fileserver core AFS_component_version_number.c
+ $(RM) -f *.o fileserver state_analyzer core AFS_component_version_number.c
include ../config/Makefile.version
${DESTDIR}${afssrvlibexecdir}/fileserver: fileserver
${INSTALL} -ns $? $@
-dest: ${DEST}/root.server/usr/afs/bin/fileserver
+${DESTDIR}${afssrvsbindir}/state_analyzer: state_analyzer
+ ${INSTALL} $? $@
+
+dest: ${DEST}/root.server/usr/afs/bin/fileserver ${DEST}/root.server/usr/afs/bin/state_analyzer
# License. For details, see the LICENSE file in the top-level source
# directory or online at http://www.openafs.org/dl/license10.html
-AFSDEV_AUXCDEFINES = -DAFS_PTHREAD_ENV -DRXDEBUG
+AFSDEV_AUXCDEFINES = -DAFS_PTHREAD_ENV -DRXDEBUG -DFSSYNC_BUILD_SERVER
RELDIR=tviced
!INCLUDE ..\config\NTMakefile.$(SYS_NAME)
--- /dev/null
+/*
+ * Copyright 2006, Sine Nomine Associates and others.
+ * All Rights Reserved.
+ *
+ * This software has been released under the terms of the IBM Public
+ * License. For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+/*
+ * demand attach fs
+ * fileserver state serialization
+ */
+
+#include <afsconfig.h>
+#include <afs/param.h>
+
+RCSID
+ ("$Header$");
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <time.h> /* ANSI standard location for time stuff */
+#ifdef AFS_NT40_ENV
+#include <fcntl.h>
+#include <io.h>
+#else
+#include <sys/time.h>
+#include <sys/file.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
+#include <afs/assert.h>
+#include <sys/stat.h>
+
+#include <afs/stds.h>
+
+#include <rx/xdr.h>
+#include <lwp.h>
+#include <lock.h>
+#include <afs/afsint.h>
+#include <afs/rxgen_consts.h>
+#include <afs/nfs.h>
+#include <afs/errors.h>
+#include <afs/ihandle.h>
+#include <afs/vnode.h>
+#include <afs/volume.h>
+#include <afs/acl.h>
+#include <afs/ptclient.h>
+#include <afs/prs_fs.h>
+#include <afs/auth.h>
+#include <afs/afsutil.h>
+#include <rx/rx.h>
+#include <afs/cellconfig.h>
+#include <stdlib.h>
+
+#include "../viced/viced_prototypes.h"
+#include "../viced/viced.h"
+#include "../viced/host.h"
+#include "../viced/callback.h"
+#include "serialize_state.h"
+
+/*@+fcnmacros +macrofcndecl@*/
+#ifdef O_LARGEFILE
+#ifdef S_SPLINT_S
+extern off64_t afs_lseek(int FD, off64_t O, int F);
+#endif /*S_SPLINT_S */
+#define afs_lseek(FD, O, F) lseek64(FD, (off64_t)(O), F)
+#define afs_stat stat64
+#define afs_fstat fstat64
+#define afs_open open64
+#define afs_fopen fopen64
+#define afs_ftruncate ftruncate64
+#define afs_mmap mmap64
+#ifdef AFS_AIX_ENV
+extern void * mmap64(); /* ugly hack since aix build env appears to be somewhat broken */
+#endif
+#else /* !O_LARGEFILE */
+#ifdef S_SPLINT_S
+extern off_t afs_lseek(int FD, off_t O, int F);
+#endif /*S_SPLINT_S */
+#define afs_lseek(FD, O, F) lseek(FD, (off_t)(O), F)
+#define afs_stat stat
+#define afs_fstat fstat
+#define afs_open open
+#define afs_fopen fopen
+#define afs_ftruncate ftruncate
+#define afs_mmap mmap
+#endif /* !O_LARGEFILE */
+/*@=fcnmacros =macrofcndecl@*/
+
+
+#ifdef AFS_DEMAND_ATTACH_FS
+
+/*
+ * demand attach fs
+ * state dump routines
+ *
+ * in order to make state dump/restore as fast as possible,
+ * we use memory mapped files
+ *
+ * if this causes problems on certain platforms, the APIs
+ * have been written so that it will be very simple to go
+ * back to standard I/O for just those poorly written platforms
+ */
+#define FS_STATE_USE_MMAP
+
+
+#ifdef FS_STATE_USE_MMAP
+#define FS_STATE_INIT_FILESIZE (8 * 1024 * 1024) /* truncate to 8MB initially */
+#include <sys/mman.h>
+#endif
+
+static int fs_stateCreateDump(struct fs_dump_state * state);
+static int fs_stateLoadDump(struct fs_dump_state * state);
+static int fs_stateInvalidateDump(struct fs_dump_state * state);
+static int fs_stateCommitDump(struct fs_dump_state * state);
+static int fs_stateCloseDump(struct fs_dump_state * state);
+
+#ifdef FS_STATE_USE_MMAP
+static int fs_stateSizeFile(struct fs_dump_state * state);
+static int fs_stateResizeFile(struct fs_dump_state * state, size_t min_add);
+static int fs_stateTruncateFile(struct fs_dump_state * state);
+
+static int fs_stateMapFile(struct fs_dump_state * state);
+static int fs_stateUnmapFile(struct fs_dump_state * state);
+
+static int fs_stateIncCursor(struct fs_dump_state * state, size_t len);
+static int fs_stateCheckIOSafety(struct fs_dump_state * state,
+ size_t len);
+#endif
+
+static int fs_stateFillHeader(struct fs_state_header * hdr);
+static int fs_stateCheckHeader(struct fs_state_header * hdr);
+
+static int fs_stateAlloc(struct fs_dump_state * state);
+static int fs_stateFree(struct fs_dump_state * state);
+
+extern afsUUID FS_HostUUID;
+extern char cml_version_number[];
+
+/*
+ * demand attach fs
+ * save all fileserver state
+ */
+int
+fs_stateSave(void)
+{
+ int ret = 0, verified = 1;
+ struct fs_dump_state state;
+
+ /* save and restore need to be atomic wrt other host package operations */
+ H_LOCK;
+
+ ViceLog(0, ("fs_stateSave: commencing fileserver state dump\n"));
+
+ if (fs_stateAlloc(&state)) {
+ ViceLog(0, ("fs_stateSave: memory allocation failed; dump aborted\n"));
+ ret = 1;
+ goto done;
+ }
+
+ /* XXX
+ * on busy servers, these checks will inevitably fail since stuff drops H_LOCK
+ * all over the place (with structs left in inconsistent states) while RPCs to
+ * clients happen (grumble, grumble, the host package needs to be rewritten...)
+ *
+ * the current hack is to force the background threads that deal with host and
+ * callback state offline early in the shutdown process, do VShutdown, come
+ * back and wait for those threads to die, THEN do the state dump
+ *
+ * BUT, this still has one flaw -- what do we do about rx worker threads that
+ * are blocked in the host package making an RPC call to a cm???
+ *
+ * perhaps we need a refcounter that keeps track of threads blocked in rpc calls
+ * with H_LOCK dropped (and the host struct likely left in an inconsistent state)
+ *
+ * or better yet, we need to associate a state machine with each host object
+ * (kind of like demand attach Volume structures).
+ *
+ * sigh. I suspect we'll need to revisit this issue
+ */
+
+ if (fs_state.options.fs_state_verify_before_save) {
+ ViceLog(0, ("fs_stateSave: performing internal consistency checks before proceeding with state dump\n"));
+
+ if (h_stateVerify(&state)) {
+ ViceLog(0, ("fs_stateSave: error: host table consistency checks failed; state dump will not be marked clean\n"));
+ verified = 0;
+ ret = 1;
+ }
+
+ if (cb_stateVerify(&state)) {
+ ViceLog(0, ("fs_stateSave: error: callback table consistency checks failed; state dump will not be marked clean\n"));
+ verified = 0;
+ ret = 1;
+ }
+
+ /* if a consistency check asserted the bail flag, reset it */
+ state.bail = 0;
+
+ ViceLog(0, ("fs_stateSave: proceeding with dump\n"));
+ }
+
+ if (fs_stateCreateDump(&state)) {
+ ViceLog(0, ("fs_stateSave: error: dump create failed\n"));
+ ret = 1;
+ goto done;
+ }
+
+ if (h_stateSave(&state)) {
+ ViceLog(0, ("fs_stateSave: error: host state dump failed\n"));
+ ret = 1;
+ goto done;
+ }
+
+ if (cb_stateSave(&state)) {
+ ViceLog(0, ("fs_stateSave: error: callback state dump failed\n"));
+ ret = 1;
+ goto done;
+ }
+
+ if (!verified) {
+ state.bail = 1;
+ }
+
+ if (fs_stateCommitDump(&state)) {
+ ViceLog(0, ("fs_stateSave: error: dump commit failed\n"));
+ ret = 1;
+ goto done;
+ }
+
+ if (verified) {
+ ViceLog(0, ("fs_stateSave: fileserver state dump completed successfully\n"));
+ } else {
+ ViceLog(0, ("fs_stateSave: fileserver state dump completed, but not marked clean.\n"));
+ ViceLog(0, ("fs_stateSave: please save a copy of '%s' for use by technical support\n",
+ state.fn));
+ }
+
+ done:
+ if (state.fd >= 0)
+ fs_stateCloseDump(&state);
+ fs_stateFree(&state);
+ H_UNLOCK;
+ return ret;
+}
+
+/*
+ * demand attach fs
+ * restore all fileserver state
+ *
+ * this function must appear as one atomic operation to the host and callback
+ * packages, hence H_LOCK is held for the entirety of the process.
+ */
+int
+fs_stateRestore(void)
+{
+ int ret = 0;
+ struct fs_dump_state state;
+
+ /* save and restore need to be atomic wrt other host package operations */
+ H_LOCK;
+
+ ViceLog(0, ("fs_stateRestore: commencing fileserver state restore\n"));
+
+ if (fs_stateAlloc(&state)) {
+ ViceLog(0, ("fs_stateRestore: memory allocation failed\n"));
+ ret = 1;
+ goto done;
+ }
+
+ if (fs_stateLoadDump(&state)) {
+ ViceLog(0, ("fs_stateRestore: failed to load dump file '%s'\n", state.fn));
+ ret = 1;
+ goto done;
+ }
+
+ if (fs_stateInvalidateDump(&state)) {
+ ViceLog(0, ("fs_stateRestore: failed to invalidate dump file '%s'\n", state.fn));
+ ret = 1;
+ goto done;
+ }
+
+
+ if (state.flags.do_host_restore) {
+ if (h_stateRestore(&state)) {
+ ViceLog(0, ("fs_stateRestore: error: host state restore failed. exiting avoid further corruption\n"));
+ exit(0);
+ }
+ ViceLog(0, ("fs_stateRestore: host table restored\n"));
+
+ if (cb_stateRestore(&state)) {
+ ViceLog(0, ("fs_stateRestore: error: callback state restore failed. exiting to avoid further corruption\n"));
+ exit(0);
+ }
+ ViceLog(0, ("fs_stateRestore: FileEntry and CallBack tables restored\n"));
+
+ if (h_stateRestoreIndices(&state)) {
+ ViceLog(0, ("fs_stateRestore: error: host index remapping failed. exiting to avoid further corruption\n"));
+ exit(0);
+ }
+ ViceLog(0, ("fs_stateRestore: host table indices remapped\n"));
+
+ if (cb_stateRestoreIndices(&state)) {
+ ViceLog(0, ("fs_stateRestore: error: callback index remapping failed. exiting to avoid further corruption\n"));
+ exit(0);
+ }
+ ViceLog(0, ("fs_stateRestore: FileEntry and CallBack indices remapped\n"));
+ }
+
+ ViceLog(0, ("fs_stateRestore: restore phase complete\n"));
+
+ if (fs_state.options.fs_state_verify_after_restore) {
+ ViceLog(0, ("fs_stateRestore: beginning state verification phase\n"));
+
+ if (state.flags.do_host_restore) {
+ if (h_stateVerify(&state)) {
+ ViceLog(0, ("fs_stateRestore: error: host table consistency checks failed; exiting to avoid further corruption\n"));
+ exit(0);
+ }
+
+ if (cb_stateVerify(&state)) {
+ ViceLog(0, ("fs_stateRestore: error: callback table consistency checks failed; exiting to avoid further corruption\n"));
+ exit(0);
+ }
+ }
+
+ ViceLog(0, ("fs_stateRestore: fileserver state verification complete\n"));
+ }
+
+ ViceLog(0, ("fs_stateRestore: restore was successful\n"));
+
+ done:
+ if (state.fd >= 0) {
+ fs_stateInvalidateDump(&state);
+ fs_stateCloseDump(&state);
+ }
+ fs_stateFree(&state);
+ H_UNLOCK;
+ return ret;
+}
+
+static int
+fs_stateCreateDump(struct fs_dump_state * state)
+{
+ int fd, ret = 0;
+ char savedump[MAXPATHLEN];
+ struct afs_stat status;
+
+ afs_snprintf(savedump, sizeof(savedump), "%s.old", state->fn);
+
+ if (afs_stat(state->fn, &status) == 0) {
+ renamefile(state->fn, savedump);
+ }
+
+ if (((fd = afs_open(state->fn,
+ O_RDWR | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR)) == -1) ||
+ (afs_fstat(fd, &status) == -1)) {
+ ViceLog(0, ("fs_stateCreateDump: failed to create state dump file '%s'\n",
+ state->fn));
+ ret = 1;
+ goto done;
+ }
+
+ state->fd = fd;
+ state->mode = FS_STATE_DUMP_MODE;
+ memset(state->hdr, 0, sizeof(struct fs_state_header));
+ fs_stateIncEOF(state, sizeof(struct fs_state_header));
+
+#ifdef FS_STATE_USE_MMAP
+ if (fs_stateSizeFile(state)) {
+ ViceLog(0, ("fs_stateCreateDump: failed to resize state dump file '%s'\n",
+ state->fn));
+ ret = 1;
+ goto done;
+ }
+
+ if (fs_stateMapFile(state)) {
+ ViceLog(0, ("fs_stateCreateDump: failed to memory map state dump file '%s'\n",
+ state->fn));
+ ret = 1;
+ goto done;
+ }
+#endif
+
+ ret = fs_stateInvalidateDump(state);
+
+ done:
+ return ret;
+}
+
+static int
+fs_stateInvalidateDump(struct fs_dump_state * state)
+{
+ afs_uint64 z;
+ int ret = 0;
+ struct fs_state_header hdr;
+
+#ifdef FS_STATE_USE_MMAP
+ if (state->mmap.map == NULL) {
+ return 1;
+ }
+#endif
+
+ memcpy(&hdr, state->hdr, sizeof(hdr));
+ hdr.valid = 0;
+ ZeroInt64(z);
+
+ /* write a bogus header to flag dump in progress */
+ if (fs_stateWriteHeader(state, &z, &hdr, sizeof(hdr))) {
+ ViceLog(0, ("fs_stateInvalidateDump: failed to invalidate old dump file header '%s'\n",
+ state->fn));
+ ret = 1;
+ goto done;
+ }
+ if (fs_stateSync(state)) {
+ ViceLog(0, ("fs_stateInvalidateDump: failed to sync changes to disk\n"));
+ ret = 1;
+ goto done;
+ }
+
+ done:
+ return ret;
+}
+
+static int
+fs_stateCommitDump(struct fs_dump_state * state)
+{
+ afs_uint64 z;
+ int ret = 0;
+
+ ZeroInt64(z);
+
+#ifdef FS_STATE_USE_MMAP
+ if (fs_stateTruncateFile(state)) {
+ ViceLog(0, ("fs_stateCommitDump: failed to truncate dump file to proper size\n"));
+ ret = 1;
+ goto done;
+ }
+#endif
+
+ /* ensure that all pending data I/Os for the state file have been committed
+ * _before_ we make the metadata I/Os */
+ if (fs_stateSync(state)) {
+ ViceLog(0, ("fs_stateCommitDump: failed to sync changes to disk\n"));
+ ret = 1;
+ goto done;
+ }
+
+#ifdef FS_STATE_USE_MMAP
+ /* XXX madvise may not exist on all platforms, so
+ * we may need to add some ifdefs at some point... */
+ {
+ madvise((((char *)state->mmap.map) + sizeof(struct fs_state_header)),
+ state->mmap.size - sizeof(struct fs_state_header),
+ MADV_DONTNEED);
+ }
+#endif
+
+ /* build the header, and write it to disk */
+ fs_stateFillHeader(state->hdr);
+ if (state->bail) {
+ state->hdr->valid = 0;
+ }
+ if (fs_stateWriteHeader(state, &z, state->hdr, sizeof(struct fs_state_header))) {
+ ViceLog(0, ("fs_stateCommitDump: failed to write header to dump file '%s'\n",
+ state->fn));
+ ret = 1;
+ goto done;
+ }
+ if (fs_stateSync(state)) {
+ ViceLog(0, ("fs_stateCommitDump: failed to sync new header to disk\n"));
+ ret = 1;
+ goto done;
+ }
+
+ done:
+ return ret;
+}
+
+static int
+fs_stateLoadDump(struct fs_dump_state * state)
+{
+ afs_uint64 z;
+ int fd, ret = 0;
+ struct afs_stat status;
+ afs_int32 now = FT_ApproxTime();
+
+ ZeroInt64(z);
+
+ if ((fd = afs_open(state->fn, O_RDWR)) == -1 ||
+ (afs_fstat(fd, &status) == -1)) {
+ ViceLog(0, ("fs_stateLoadDump: failed to load state dump file '%s'\n",
+ state->fn));
+ ret = 1;
+ goto done;
+ }
+ state->fd = fd;
+ state->mode = FS_STATE_LOAD_MODE;
+ state->file_len = status.st_size;
+
+#ifdef FS_STATE_USE_MMAP
+ if (fs_stateMapFile(state)) {
+ ViceLog(0, ("fs_stateLoadDump: failed to memory map state dump file '%s'\n",
+ state->fn));
+ ret = 1;
+ goto done;
+ }
+#endif
+
+ if (fs_stateReadHeader(state, &z, state->hdr, sizeof(struct fs_state_header))) {
+ ViceLog(0, ("fs_stateLoadDump: failed to read header from dump file '%s'\n",
+ state->fn));
+ ret = 1;
+ goto done;
+ }
+
+ /* check the validity of the header */
+ if (fs_stateCheckHeader(state->hdr)) {
+ ViceLog(1, ("fs_stateLoadDump: header failed validity checks; not restoring '%s'\n",
+ state->fn));
+ ret = 1;
+ goto done;
+ }
+
+ if ((state->hdr->timestamp + HOST_STATE_VALID_WINDOW) >= now) {
+ state->flags.do_host_restore = 1;
+ } else {
+ ViceLog(0, ("fs_stateLoadDump: warning: dump is too old for host and callback restore; skipping those steps\n"));
+ }
+
+ done:
+ return ret;
+}
+
+static int
+fs_stateCloseDump(struct fs_dump_state * state)
+{
+#ifdef FS_STATE_USE_MMAP
+ fs_stateUnmapFile(state);
+#endif
+ close(state->fd);
+ return 0;
+}
+
+int
+fs_stateWrite(struct fs_dump_state * state,
+ void * buf, size_t len)
+{
+ int ret = 0;
+
+#ifdef FS_STATE_USE_MMAP
+ if (fs_stateCheckIOSafety(state, len)) {
+ if (fs_stateResizeFile(state, len)) {
+ ViceLog(0, ("fs_stateWrite: could not resize dump file '%s'\n",
+ state->fn));
+ ret = 1;
+ goto done;
+ }
+ }
+
+ memcpy(state->mmap.cursor, buf, len);
+ fs_stateIncCursor(state, len);
+#else
+ if (write(state->fd, buf, len) != len) {
+ ViceLog(0, ("fs_stateWrite: write failed\n"));
+ ret = 1;
+ goto done;
+ }
+#endif
+
+ done:
+ return ret;
+}
+
+int
+fs_stateRead(struct fs_dump_state * state,
+ void * buf, size_t len)
+{
+ int ret = 0;
+
+#ifdef FS_STATE_USE_MMAP
+ if (fs_stateCheckIOSafety(state, len)) {
+ ViceLog(0, ("fs_stateRead: read beyond EOF for dump file '%s'\n",
+ state->fn));
+ ret = 1;
+ goto done;
+ }
+
+ memcpy(buf, state->mmap.cursor, len);
+ fs_stateIncCursor(state, len);
+#else
+ if (read(state->fd, buf, len) != len) {
+ ViceLog(0, ("fs_stateRead: read failed\n"));
+ ret = 1;
+ goto done;
+ }
+#endif
+
+ done:
+ return ret;
+}
+
+int
+fs_stateWriteV(struct fs_dump_state * state,
+ struct iovec * iov, int niov)
+{
+ int i, ret = 0;
+ size_t len = 0;
+
+ for (i=0; i < niov; i++) {
+ len += iov[i].iov_len;
+ }
+
+#ifdef FS_STATE_USE_MMAP
+ if (fs_stateCheckIOSafety(state, len)) {
+ if (fs_stateResizeFile(state, len)) {
+ ViceLog(0, ("fs_stateWrite: could not resize dump file '%s'\n",
+ state->fn));
+ ret = 1;
+ goto done;
+ }
+ }
+
+ for (i=0; i < niov; i++) {
+ memcpy(state->mmap.cursor, iov[i].iov_base, iov[i].iov_len);
+ fs_stateIncCursor(state, iov[i].iov_len);
+ }
+#else
+ if (writev(state->fd, iov, niov) != len) {
+ ViceLog(0, ("fs_stateWriteV: write failed\n"));
+ ret = 1;
+ goto done;
+ }
+#endif
+
+ done:
+ return ret;
+}
+
+int
+fs_stateReadV(struct fs_dump_state * state,
+ struct iovec * iov, int niov)
+{
+ int i, ret = 0;
+ size_t len = 0;
+
+ for (i=0; i < niov; i++) {
+ len += iov[i].iov_len;
+ }
+
+#ifdef FS_STATE_USE_MMAP
+ if (fs_stateCheckIOSafety(state, len)) {
+ ViceLog(0, ("fs_stateRead: read beyond EOF for dump file '%s'\n",
+ state->fn));
+ ret = 1;
+ goto done;
+ }
+
+ for (i=0; i < niov; i++) {
+ memcpy(iov[i].iov_base, state->mmap.cursor, iov[i].iov_len);
+ fs_stateIncCursor(state, iov[i].iov_len);
+ }
+#else
+ if (readv(state->fd, iov, niov) != len) {
+ ViceLog(0, ("fs_stateReadV: read failed\n"));
+ ret = 1;
+ goto done;
+ }
+#endif
+
+ done:
+ return ret;
+}
+
+int
+fs_stateWriteHeader(struct fs_dump_state * state,
+ afs_uint64 * offset,
+ void * hdr, size_t len)
+{
+ int ret = 0;
+
+ if (fs_stateSeek(state, offset)) {
+ ViceLog(0, ("fs_stateWriteHeader: could not seek to correct position in dump file '%s'\n",
+ state->fn));
+ ret = 1;
+ goto done;
+ }
+
+ if (fs_stateWrite(state, hdr, len)) {
+ ViceLog(0, ("fs_stateWriteHeader: write failed\n"));
+ ret = 1;
+ goto done;
+ }
+
+ done:
+ return ret;
+}
+
+int
+fs_stateReadHeader(struct fs_dump_state * state,
+ afs_uint64 * offset,
+ void * hdr, size_t len)
+{
+ int ret = 0;
+
+ if (fs_stateSeek(state, offset)) {
+ ViceLog(0, ("fs_stateReadHeader: could not seek to correct position in dump file '%s'\n",
+ state->fn));
+ ret = 1;
+ goto done;
+ }
+
+ if (fs_stateRead(state, hdr,len)) {
+ ViceLog(0, ("fs_stateReadHeader: read failed\n"));
+ ret = 1;
+ goto done;
+ }
+
+ done:
+ return ret;
+}
+
+#ifdef FS_STATE_USE_MMAP
+static int
+fs_stateSizeFile(struct fs_dump_state * state)
+{
+ int ret = 0;
+ state->file_len = FS_STATE_INIT_FILESIZE;
+ if (afs_ftruncate(state->fd, state->file_len) != 0)
+ ret = 1;
+ return ret;
+}
+
+static int
+fs_stateResizeFile(struct fs_dump_state * state, size_t min_add)
+{
+ int ret = 0;
+ afs_foff_t inc;
+
+#ifdef FS_STATE_USE_MMAP
+ fs_stateUnmapFile(state);
+#endif
+
+ inc = ((min_add / FS_STATE_INIT_FILESIZE)+1) * FS_STATE_INIT_FILESIZE;
+ state->file_len += inc;
+
+ if (afs_ftruncate(state->fd, state->file_len) != 0) {
+ ViceLog(0, ("fs_stateResizeFile: truncate failed\n"));
+ ret = 1;
+ goto done;
+ }
+
+#ifdef FS_STATE_USE_MMAP
+ if (fs_stateMapFile(state)) {
+ ViceLog(0, ("fs_stateResizeFile: remapping memory mapped file failed\n"));
+ ret = 1;
+ goto done;
+ }
+#endif
+
+ done:
+ return ret;
+}
+
+static int
+fs_stateTruncateFile(struct fs_dump_state * state)
+{
+ int ret = 0;
+
+#ifdef AFS_LARGEFILE_ENV
+ if (afs_ftruncate(state->fd, state->eof_offset) != 0) {
+ ret = 1;
+ }
+#else
+ afs_uint32 hi, lo;
+ SplitInt64(state->eof_offset, hi, lo);
+ if (afs_ftruncate(state->fd, lo) != 0) {
+ ret = 1;
+ }
+#endif
+
+ return ret;
+}
+#endif
+
+#ifdef FS_STATE_USE_MMAP
+static int
+fs_stateMapFile(struct fs_dump_state * state)
+{
+ int ret = 0, flags;
+
+ switch(state->mode) {
+ case FS_STATE_LOAD_MODE:
+ flags = PROT_READ | PROT_WRITE; /* loading involves a header invalidation */
+ break;
+ case FS_STATE_DUMP_MODE:
+ flags = PROT_WRITE;
+ break;
+ default:
+ ViceLog(0, ("fs_stateMapFile: invalid dump state mode\n"));
+ return 1;
+ }
+
+ state->mmap.map = afs_mmap(NULL,
+ state->file_len,
+ flags,
+ MAP_SHARED,
+ state->fd,
+ 0);
+
+ if (state->mmap.map == MAP_FAILED) {
+ state->mmap.size = 0;
+ state->mmap.map = NULL;
+ ViceLog(0, ("fs_stateMapFile: failed to memory map file '%s'\n",
+ state->fn));
+ ret = 1;
+ goto done;
+ }
+
+ state->mmap.size = state->file_len;
+ state->mmap.cursor = state->mmap.map;
+ state->mmap.offset = 0;
+
+ /* for state loading, accesses will be sequential, so let's give
+ * the VM subsystem a heads up */
+ if (state->mode == FS_STATE_LOAD_MODE) {
+ /* XXX madvise may not exist on all platforms, so
+ * we may need to add some ifdefs at some point... */
+ flags = MADV_SEQUENTIAL | MADV_WILLNEED;
+#ifdef AFS_SUN510_ENV
+ flags |= MADV_ACCESS_LWP; /* added in solaris 9 12/02 */
+#endif
+ madvise(state->mmap.map, state->mmap.size, flags);
+ }
+
+ done:
+ return ret;
+}
+
+static int
+fs_stateUnmapFile(struct fs_dump_state * state)
+{
+ int ret = 0;
+
+ if (munmap(state->mmap.map, state->mmap.size) == -1) {
+ ViceLog(0, ("fs_stateUnmapFile: failed to unmap dump file '%s'\n",
+ state->fn));
+ ret = 1;
+ goto done;
+ }
+
+ done:
+ return ret;
+}
+#endif /* FS_STATE_USE_MMAP */
+
+#ifdef FS_STATE_USE_MMAP
+int
+fs_stateSync(struct fs_dump_state * state)
+{
+ int ret = 0;
+
+ msync(state->mmap.map, state->mmap.size, MS_SYNC);
+
+ done:
+ return ret;
+}
+#else /* !FS_STATE_USE_MMAP */
+int
+fs_stateSync(struct fs_dump_state * state)
+{
+ int ret = 0;
+
+ if (fsync(state->fd) == -1)
+ ret = 1;
+
+ done:
+ return ret;
+}
+#endif /* !FS_STATE_USE_MMAP */
+
+int
+fs_stateIncEOF(struct fs_dump_state * state, afs_int32 len)
+{
+ afs_uint64 temp;
+ FillInt64(temp, 0, len);
+ AddUInt64(state->eof_offset, temp, &state->eof_offset);
+ return 0;
+}
+
+#ifdef FS_STATE_USE_MMAP
+static int
+fs_stateIncCursor(struct fs_dump_state * state, size_t len)
+{
+ char * p;
+
+ state->mmap.offset += len;
+
+ p = (char *) state->mmap.cursor;
+ p += len;
+ state->mmap.cursor = (void *) p;
+
+ return 0;
+}
+
+static int
+fs_stateCheckIOSafety(struct fs_dump_state * state, size_t len)
+{
+ int ret = 0;
+
+ if ((state->mmap.offset + len) > state->mmap.size) {
+ ret = 1;
+ }
+ return ret;
+}
+#endif /* FS_STATE_USE_MMAP */
+
+#ifdef FS_STATE_USE_MMAP
+int
+fs_stateSeek(struct fs_dump_state * state, afs_uint64 * offset)
+{
+ int ret = 0;
+ char * p;
+ afs_uint32 hi, lo;
+
+ SplitInt64(*offset, hi, lo);
+
+ /* update cursor */
+ p = (char *) state->mmap.map;
+#ifdef AFS_64BIT_ENV
+ p += *offset;
+#else
+ p += lo;
+#endif
+ state->mmap.cursor = (void *) p;
+
+ /* update offset */
+#ifdef AFS_LARGEFILE_ENV
+ state->mmap.offset = *offset;
+#else
+ if (hi)
+ ret = 1;
+ state->mmap.offset = lo;
+#endif
+
+ return ret;
+}
+#else /* !FS_STATE_USE_MMAP */
+int
+fs_stateSeek(struct fs_dump_state * state, afs_uint64 * offset)
+{
+ int ret = 0;
+#ifndef AFS_LARGEFILE_ENV
+ afs_uint32 high, low;
+
+ SplitInt64(*offset, high, low);
+ if (high) {
+ ret = 1;
+ goto done;
+ }
+
+ if (afs_lseek(state->fd, low, SEEK_SET) == -1)
+ ret = 1;
+#else
+ if (afs_lseek(state->fd, *offset, SEEK_SET) == -1)
+ ret = 1;
+#endif
+ return ret;
+}
+#endif /* !FS_STATE_USE_MMAP */
+
+static int
+fs_stateFillHeader(struct fs_state_header * hdr)
+{
+ hdr->stamp.magic = FS_STATE_MAGIC;
+ hdr->stamp.version = FS_STATE_VERSION;
+#ifdef SYS_NAME_ID
+ hdr->sys_name = SYS_NAME_ID;
+#else
+ hdr->sys_name = 0xFFFFFFFF;
+#endif
+ hdr->timestamp = FT_ApproxTime();
+ hdr->server_uuid = FS_HostUUID;
+ hdr->valid = 1;
+#ifdef AFSBIG_ENDIAN
+ hdr->endianness = 1;
+#else
+ hdr->endianness = 0;
+#endif
+#ifdef FS_STATS_DETAILED
+ hdr->stats_detailed = 1;
+#else
+ hdr->stats_detailed = 0;
+#endif
+ if (strlcpy(hdr->server_version_string, cml_version_number, sizeof(hdr->server_version_string))
+ >= sizeof(hdr->server_version_string)) {
+ ViceLog(0, ("fs_stateFillHeader: WARNING -- cml_version_number field truncated\n"));
+ }
+ return 0;
+}
+
+static int
+fs_stateCheckHeader(struct fs_state_header * hdr)
+{
+ int ret = 0;
+
+ if (!hdr->valid) {
+ ViceLog(0, ("fs_stateCheckHeader: dump was previously flagged invalid\n"));
+ ret = 1;
+ }
+#ifdef AFSBIG_ENDIAN
+ else if (!hdr->endianness) {
+ ViceLog(0, ("fs_stateCheckHeader: wrong endianness\n"));
+ ret = 1;
+ }
+#else /* AFSLITTLE_ENDIAN */
+ else if (hdr->endianness) {
+ ViceLog(0, ("fs_stateCheckHeader: wrong endianness\n"));
+ ret = 1;
+ }
+#endif /* AFSLITTLE_ENDIAN */
+
+ else if (hdr->stamp.magic != FS_STATE_MAGIC) {
+ ViceLog(0, ("fs_stateCheckHeader: invalid dump header\n"));
+ ret = 1;
+ }
+ else if (hdr->stamp.version != FS_STATE_VERSION) {
+ ViceLog(0, ("fs_stateCheckHeader: unknown dump format version number\n"));
+ ret = 1;
+ }
+
+#ifdef FS_STATS_DETAILED
+ else if (!hdr->stats_detailed) {
+ ViceLog(0, ("fs_stateCheckHeader: wrong config flags\n"));
+ ret = 1;
+ }
+#else /* FS_STATS_DETAILED */
+ else if (hdr->stats_detailed) {
+ ViceLog(0, ("fs_stateCheckHeader: wrong config flags\n"));
+ ret = 1;
+ }
+#endif /* FS_STATS_DETAILED */
+
+ else if (!afs_uuid_equal(&hdr->server_uuid, &FS_HostUUID)) {
+ ViceLog(0, ("fs_stateCheckHeader: server UUID does not match this server's UUID\n"));
+ ret = 1;
+ }
+
+ /* the cml_version_string is included for informational purposes only. If someone ever
+ * wants to limit state dump reloading based upon the contents of this string, just
+ * uncomment the following code. uncommenting this code is _strongly discouraged_ because
+ * we already make use of the version stamps in the various dump headers to deal with
+ * data structure version incompatabilities.
+ else if (strncmp(hdr->server_version_string, cml_version_number,
+ sizeof(hdr->server_version_string)) != 0) {
+ ViceLog(0, ("fs_stateCheckHeader: dump from different server version\n"));
+ ret = 1;
+ }
+ */
+
+ else if (strncmp(hdr->server_version_string, cml_version_number,
+ sizeof(hdr->server_version_string)) != 0) {
+ ViceLog(0, ("fs_stateCheckHeader: dump from different server version ; attempting state reload anyway\n"));
+ }
+
+
+ return ret;
+}
+
+static int
+fs_stateAlloc(struct fs_dump_state * state)
+{
+ int ret = 0;
+ memset(state, 0, sizeof(struct fs_dump_state));
+ state->fd = -1;
+ state->fn = AFSDIR_SERVER_FSSTATE_FILEPATH;
+ state->hdr = (struct fs_state_header *)malloc(sizeof(struct fs_state_header));
+ state->h_hdr = (struct host_state_header *)malloc(sizeof(struct host_state_header));
+ state->cb_hdr = (struct callback_state_header *)malloc(sizeof(struct callback_state_header));
+ state->cb_timeout_hdr = (struct callback_state_timeout_header *)
+ malloc(sizeof(struct callback_state_timeout_header));
+ state->cb_fehash_hdr = (struct callback_state_fehash_header *)
+ malloc(sizeof(struct callback_state_fehash_header));
+ if ((state->hdr == NULL) || (state->h_hdr == NULL) || (state->cb_hdr == NULL) ||
+ (state->cb_timeout_hdr == NULL) || (state->cb_fehash_hdr == NULL))
+ ret = 1;
+ return ret;
+}
+
+static int
+fs_stateFree(struct fs_dump_state * state)
+{
+ if (state->hdr)
+ free(state->hdr);
+ if (state->h_hdr)
+ free(state->h_hdr);
+ if (state->cb_hdr)
+ free(state->cb_hdr);
+ if (state->cb_timeout_hdr)
+ free(state->cb_timeout_hdr);
+ if (state->cb_fehash_hdr)
+ free(state->cb_fehash_hdr);
+ if (state->h_map.entries)
+ free(state->h_map.entries);
+ if (state->fe_map.entries)
+ free(state->fe_map.entries);
+ if (state->cb_map.entries)
+ free(state->cb_map.entries);
+ return 0;
+}
+
+#endif /* AFS_DEMAND_ATTACH_FS */
--- /dev/null
+/*
+ * Copyright 2006, Sine Nomine Associates and others.
+ * All Rights Reserved.
+ *
+ * This software has been released under the terms of the IBM Public
+ * License. For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+/*
+ * demand attach fs
+ * fileserver state serialization
+ */
+
+#ifndef _AFS_TVICED_SERIALIZE_STATE_H
+#define _AFS_TVICED_SERIALIZE_STATE_H
+
+#ifdef AFS_DEMAND_ATTACH_FS
+
+#define FS_STATE_MAGIC 0x62FA841C
+#define FS_STATE_VERSION 2
+
+#define HOST_STATE_MAGIC 0x7B8C9DAE
+#define HOST_STATE_VERSION 2
+
+#define HOST_STATE_ENTRY_MAGIC 0xA8B9CADB
+
+#define CALLBACK_STATE_MAGIC 0x89DE67BC
+#define CALLBACK_STATE_VERSION 1
+
+#define CALLBACK_STATE_TIMEOUT_MAGIC 0x99DD5511
+#define CALLBACK_STATE_FEHASH_MAGIC 0x77BB33FF
+#define CALLBACK_STATE_ENTRY_MAGIC 0x54637281
+
+#define ACTIVE_VOLUME_STATE_MAGIC 0xAC7557CA
+#define ACTIVE_VOLUME_STATE_VERSION 1
+
+#define ACTIVE_VOLUME_STATE_AVEHASH_MAGIC 0xBADDF00D
+
+#define HOST_STATE_VALID_WINDOW 1800 /* 30 minutes */
+
+/*
+ * on-disk structures
+ */
+struct disk_version_stamp {
+ afs_uint32 magic;
+ afs_uint32 version;
+};
+
+/* 1024 byte header structure */
+struct fs_state_header {
+ struct disk_version_stamp stamp; /* version stamp */
+ afs_uint32 timestamp; /* timestamp of save */
+ afs_uint32 sys_name; /* sys name id for this machine */
+ afsUUID server_uuid; /* server's UUID */
+ byte valid; /* whether header contents are valid */
+ byte endianness; /* endianness sanity check (0 for LE, 1 for BE) */
+ byte stats_detailed; /* fs stats detailed sanity check */
+ byte padding1[1]; /* padding */
+ afs_uint32 reserved1[23]; /* for expansion */
+ afs_uint64 avol_offset; /* offset of active volumes structure */
+ afs_uint64 h_offset; /* offset of host_state_header structure */
+ afs_uint64 cb_offset; /* offset of callback_state_header structure */
+ afs_uint64 vlru_offset; /* offset of vlru state structure */
+ afs_uint32 reserved2[56]; /* for expansion */
+ char server_version_string[128]; /* version string from AFS_component_version_number.c */
+ afs_uint32 reserved3[128]; /* for expansion */
+};
+
+/*
+ * host package serialization
+ */
+
+/* 256 byte header for the host state data */
+struct host_state_header {
+ struct disk_version_stamp stamp; /* host state version stamp */
+ afs_uint32 records; /* number of stored host records */
+ afs_uint32 index_max; /* max index value encountered */
+ afs_uint32 reserved[60]; /* for expansion */
+};
+
+/* 32 byte host entry header */
+struct host_state_entry_header {
+ afs_uint32 magic; /* stamp */
+ afs_uint32 len; /* number of bytes in this record */
+ afs_uint32 interfaces; /* number of interfaces included in record */
+ afs_uint32 hcps; /* number of hcps entries in record */
+ afs_uint32 reserved[4];
+};
+
+/* 36 byte host entry structure */
+struct hostDiskEntry {
+ afs_uint32 host; /* IP address of host interface that is
+ * currently being used, in network
+ * byte order */
+ afs_uint16 port; /* port address of host */
+ afs_uint16 hostFlags; /* bit map */
+ byte Console; /* XXXX This host is a console */
+ byte hcpsfailed; /* Retry the cps call next time */
+ byte hcps_valid; /* prlist_val not null */
+#if FS_STATS_DETAILED
+ byte InSameNetwork; /*Is host's addr in the same network as
+ * the File Server's? */
+#else
+ byte padding1[1]; /* for padding */
+#endif /* FS_STATS_DETAILED */
+ afs_uint32 hcps_len; /* length of hcps */
+ afs_uint32 LastCall; /* time of last call from host */
+ afs_uint32 ActiveCall; /* time of any call but gettime */
+ afs_uint32 cpsCall; /* time of last cps call from this host */
+ afs_uint32 cblist; /* Call back list for this host */
+ afs_uint32 index; /* index for correlating w/ callback dumps */
+};
+
+/*
+ * callback package serialization
+ */
+
+/* 512 byte header */
+struct callback_state_header {
+ struct disk_version_stamp stamp; /* callback state version stamp */
+ afs_uint32 nFEs; /* number of FileEntry records */
+ afs_uint32 nCBs; /* number of CallBack records */
+ afs_uint32 fe_max; /* max FileEntry index */
+ afs_uint32 cb_max; /* max CallBack index */
+ afs_int32 tfirst; /* first valid timeout */
+ afs_uint32 reserved[115]; /* for expansion */
+ afs_uint64 timeout_offset; /* offset of timeout queue heads */
+ afs_uint64 fehash_offset; /* offset of file entry hash buckets */
+ afs_uint64 fe_offset; /* offset of first file entry */
+};
+
+/* 32 byte header */
+struct callback_state_timeout_header {
+ afs_uint32 magic; /* magic number for timeout header */
+ afs_uint32 len; /* total length of header and timeout records */
+ afs_uint32 records; /* number of timeout records */
+ afs_uint32 reserved[5];
+};
+
+/* 32 byte header */
+struct callback_state_fehash_header {
+ afs_uint32 magic; /* magic number for fehash header */
+ afs_uint32 len; /* total length of header and fehash bucket heads */
+ afs_uint32 records; /* number of hash buckets */
+ afs_uint32 reserved[5];
+};
+
+/* 32 byte header */
+struct callback_state_entry_header {
+ afs_uint32 magic; /* magic number for FE entry */
+ afs_uint32 len; /* number of bytes in this record */
+ afs_uint32 nCBs; /* number of callbacks for this FE */
+ afs_uint32 reserved[5];
+};
+
+struct FEDiskEntry {
+ struct FileEntry fe;
+ afs_uint32 index;
+};
+
+struct CBDiskEntry {
+ struct CallBack cb;
+ afs_uint32 index;
+};
+
+/*
+ * active volumes state serialization
+ *
+ * these structures are meant to support
+ * automated salvaging of active volumes
+ * in the event of a fileserver crash
+ */
+
+/* 512 byte header */
+struct active_volume_state_header {
+ struct disk_version_stamp stamp; /* callback state version stamp */
+ afs_uint32 nAVEs; /* number of ActiveVolumeEntry records */
+ afs_uint32 init_timestamp; /* timestamp of AVE initialization */
+ afs_uint32 update_timetamp; /* timestamp of last AVE update */
+ afs_uint32 reserved[119]; /* for expansion */
+ afs_uint64 avehash_offset; /* offset of active volume entry hash buckets */
+ afs_uint64 ave_offset; /* offset of first active volume entry */
+};
+
+/* 32 byte header */
+struct active_volume_state_avehash_header {
+ afs_uint32 magic; /* magic number for avehash header */
+ afs_uint32 len; /* total length of header and avehash bucket heads */
+ afs_uint32 records; /* number of hash buckets */
+ afs_uint32 reserved[5];
+};
+
+typedef afs_uint32 active_volume_state_avehash_entry;
+
+/* active volume entry */
+struct AVDiskEntry {
+ afs_uint32 volume;
+ afs_uint32 partition;
+ afs_uint32 hash_next;
+};
+
+
+/*
+ * dump runtime state
+ */
+struct idx_map_entry_t {
+ afs_uint32 old_idx; /* host hash id from last runtime */
+ afs_uint32 new_idx; /* host hash id for this runtime */
+};
+
+
+/* verification process sanity check constants
+ *
+ * make them fairly large so we don't get
+ * false positives
+ */
+#define FS_STATE_H_MAX_UUID_HASH_CHAIN_LEN 100000 /* max elements in a host uuid-hash chain */
+#define FS_STATE_H_MAX_ADDR_HASH_CHAIN_LEN 2000000 /* max elements in a host ipv4-hash chain */
+#define FS_STATE_FE_MAX_HASH_CHAIN_LEN 100000 /* max elements in a FE fid-hash chain */
+#define FS_STATE_FCB_MAX_LIST_LEN 100000 /* max elements in a per-FE CB list */
+#define FS_STATE_HCB_MAX_LIST_LEN 100000 /* max elements in a per-host CB list */
+#define FS_STATE_TCB_MAX_LIST_LEN 100000 /* max elements in a per-timeout CB list */
+
+
+/*
+ * main state serialization state structure
+ */
+
+struct fs_dump_state {
+ enum {
+ FS_STATE_DUMP_MODE,
+ FS_STATE_LOAD_MODE
+ } mode;
+ struct {
+ byte do_host_restore; /* whether host restore should be done */
+ byte some_steps_skipped; /* whether some steps were skipped */
+ byte warnings_generated; /* whether any warnings were generated during restore */
+ } flags;
+ afs_fsize_t file_len;
+ int fd; /* fd of the current dump file */
+ int bail; /* non-zero if something went wrong */
+ char * fn; /* name of the current dump file */
+ struct { /* memory map of dump file */
+ void * map;
+ void * cursor;
+ afs_foff_t offset;
+ afs_fsize_t size;
+ } mmap;
+ struct fs_state_header * hdr; /* main header */
+ struct host_state_header * h_hdr; /* header for host state data */
+ struct callback_state_header * cb_hdr; /* header for callback state data */
+ struct callback_state_timeout_header * cb_timeout_hdr;
+ struct callback_state_fehash_header * cb_fehash_hdr;
+ afs_uint64 eof_offset; /* current end of file offset */
+ struct {
+ int len; /* number of host entries in map */
+ struct idx_map_entry_t * entries;
+ } h_map;
+ struct {
+ int len;
+ struct idx_map_entry_t * entries;
+ } fe_map;
+ struct {
+ int len;
+ struct idx_map_entry_t * entries;
+ } cb_map;
+};
+
+
+/* prototypes */
+
+/* serialize_state.c */
+extern int fs_stateWrite(struct fs_dump_state * state,
+ void * buf, size_t len);
+extern int fs_stateRead(struct fs_dump_state * state,
+ void * buf, size_t len);
+extern int fs_stateWriteV(struct fs_dump_state * state,
+ struct iovec * iov, int niov);
+extern int fs_stateReadV(struct fs_dump_state * state,
+ struct iovec * iov, int niov);
+extern int fs_stateSync(struct fs_dump_state * state);
+extern int fs_stateWriteHeader(struct fs_dump_state * state,
+ afs_uint64 * offset,
+ void * hdr, size_t len);
+extern int fs_stateReadHeader(struct fs_dump_state * state,
+ afs_uint64 * offset,
+ void * hdr, size_t len);
+extern int fs_stateIncEOF(struct fs_dump_state * state,
+ afs_int32 len);
+extern int fs_stateSeek(struct fs_dump_state * state,
+ afs_uint64 * offset);
+
+/* host.c */
+extern int h_stateSave(struct fs_dump_state * state);
+extern int h_stateRestore(struct fs_dump_state * state);
+extern int h_stateRestoreIndices(struct fs_dump_state * state);
+extern int h_stateVerify(struct fs_dump_state * state);
+extern int h_OldToNew(struct fs_dump_state * state, afs_uint32 old, afs_uint32 * new);
+
+/* callback.c */
+extern int cb_stateSave(struct fs_dump_state * state);
+extern int cb_stateRestore(struct fs_dump_state * state);
+extern int cb_stateRestoreIndices(struct fs_dump_state * state);
+extern int cb_stateVerify(struct fs_dump_state * state);
+extern int cb_stateVerifyHCBList(struct fs_dump_state * state, struct host * host);
+extern int fe_OldToNew(struct fs_dump_state * state, afs_uint32 old, afs_uint32 * new);
+extern int cb_OldToNew(struct fs_dump_state * state, afs_uint32 old, afs_uint32 * new);
+
+#endif /* AFS_DEMAND_ATTACH_FS */
+#endif /* _AFS_TVICED_SERIALIZE_STATE_H */
--- /dev/null
+/*
+ * Copyright 2006, Sine Nomine Associates and others.
+ * All Rights Reserved.
+ *
+ * This software has been released under the terms of the IBM Public
+ * License. For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+/*
+ * demand attach fs
+ * fileserver state serialization
+ *
+ * state analyzer
+ */
+
+#include <afsconfig.h>
+#include <afs/param.h>
+
+RCSID
+ ("$Header$");
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/file.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <time.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
+
+#include <afs/stds.h>
+#include <rx/xdr.h>
+#include <afs/assert.h>
+#include <lwp.h>
+#include <lock.h>
+#include <afs/afsint.h>
+#include <afs/rxgen_consts.h>
+#include <afs/nfs.h>
+#include <afs/errors.h>
+#include <afs/ihandle.h>
+#include <afs/vnode.h>
+#include <afs/volume.h>
+#ifdef AFS_ATHENA_STDENV
+#include <krb.h>
+#endif
+#include <afs/acl.h>
+#include <afs/ptclient.h>
+#include <afs/prs_fs.h>
+#include <afs/auth.h>
+#include <afs/afsutil.h>
+#include <rx/rx.h>
+#include <afs/cellconfig.h>
+#include <stdlib.h>
+#include "../util/afsutil_prototypes.h"
+#include "../viced/viced.h"
+#include "../viced/host.h"
+#include "../viced/callback.h"
+#include "serialize_state.h"
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+/*@+fcnmacros +macrofcndecl@*/
+#ifdef O_LARGEFILE
+#ifdef S_SPLINT_S
+extern off64_t afs_lseek(int FD, off64_t O, int F);
+#endif /*S_SPLINT_S */
+#define afs_lseek(FD, O, F) lseek64(FD, (off64_t)(O), F)
+#define afs_stat stat64
+#define afs_fstat fstat64
+#define afs_open open64
+#define afs_fopen fopen64
+#define afs_mmap mmap64
+#ifdef AFS_AIX_ENV
+extern void * mmap64(); /* ugly hack since aix build env appears to be somewhat broken */
+#endif
+#else /* !O_LARGEFILE */
+#ifdef S_SPLINT_S
+extern off_t afs_lseek(int FD, off_t O, int F);
+#endif /*S_SPLINT_S */
+#define afs_lseek(FD, O, F) lseek(FD, (off_t)(O), F)
+#define afs_stat stat
+#define afs_fstat fstat
+#define afs_open open
+#define afs_fopen fopen
+#define afs_mmap mmap
+#endif /* !O_LARGEFILE */
+/*@=fcnmacros =macrofcndecl@*/
+
+
+#ifndef AFS_DEMAND_ATTACH_FS
+int
+main (int argc, char ** argv)
+{
+ fprintf(stderr, "%s is only supported for demand attach fileservers\n",
+ argv[0] ? argv[0] : "state analyzer");
+ return 1;
+}
+#else /* AFS_DEMAND_ATTACH_FS */
+
+static void usage(char * prog);
+static int openFile(char * path);
+static void initState(void);
+
+static void banner(void);
+static void prompt(void);
+
+static void print_help(void);
+static void print_global_help(void);
+static void print_h_help(void);
+static void print_fe_help(void);
+static void print_cb_help(void);
+
+static void dump_hdr(void);
+static void dump_h_hdr(void);
+static void dump_cb_hdr(void);
+
+static void dump_cb_timeout(void);
+static void dump_cb_fehash(void);
+
+static void dump_all_hes(void);
+static void dump_all_fes(void);
+static void dump_all_cbs(void);
+
+static void dump_he(afs_uint32 idx);
+static void dump_fe(afs_uint32 idx);
+static void dump_cb(afs_uint32 idx);
+static void dump_this_he(void);
+static void dump_this_fe(void);
+static void dump_this_cb(void);
+static void dump_next_he(void);
+static void dump_next_fe(void);
+static void dump_next_cb(void);
+static void dump_prev_he(void);
+static void dump_prev_fe(void);
+static void dump_prev_cb(void);
+static void dump_first_he(void);
+static void dump_first_fe(void);
+static void dump_first_cb(void);
+static void dump_last_he(void);
+static void dump_last_fe(void);
+static void dump_last_cb(void);
+static void dump_he_hdr(void);
+static void dump_he_entry(void);
+static void dump_he_interfaces(void);
+static void dump_he_hcps(void);
+static void dump_fe_hdr(void);
+static void dump_fe_entry(void);
+static void dump_cb_entry(void);
+
+static void hexdump_map(afs_uint32 offset, afs_uint32 len);
+
+static int get_hdr(void);
+static int get_h_hdr(void);
+static int get_cb_hdr(void);
+static int get_cb_timeout_hdr(void);
+static int get_cb_timeout(void);
+static int get_cb_fehash_hdr(void);
+static int get_cb_fehash(void);
+static int get_he(afs_uint32 idx);
+static int get_he_hdr(void);
+static int get_he_entry(void);
+static int get_fe(afs_uint32 idx);
+static int get_fe_hdr(void);
+static int get_fe_entry(void);
+static int get_cb(afs_uint32 idx);
+static int get_cb_entry(void);
+
+static int find_fe_by_index(afs_uint32 idx);
+static int find_cb_by_index(afs_uint32 idx);
+static int find_fe_by_fid(afs_uint32 vol, afs_uint32 vn, afs_uint32 uniq);
+
+
+static int dump_fd = -1;
+static void * map = NULL;
+static size_t map_len;
+
+static struct {
+ struct fs_state_header hdr;
+ struct host_state_header h_hdr;
+ struct callback_state_header cb_hdr;
+ struct callback_state_timeout_header timeout_hdr;
+ struct callback_state_fehash_header fehash_hdr;
+ afs_uint32 * timeout;
+ afs_uint32 * fehash;
+
+ /* pointers into the memory map */
+ void * hdr_p;
+ void * h_hdr_p;
+ void * cb_hdr_p;
+ void * timeout_hdr_p;
+ void * timeout_p;
+ void * fehash_hdr_p;
+ void * fehash_p;
+
+ byte hdr_valid;
+ byte h_hdr_valid;
+ byte cb_hdr_valid;
+ byte timeout_hdr_valid;
+ byte fehash_hdr_valid;
+} hdrs;
+
+static struct {
+ void * fh;
+ void * cursor;
+ void * ifp;
+ void * hcps;
+ struct host_state_entry_header hdr;
+ struct hostDiskEntry he;
+ afs_uint32 idx;
+ byte hdr_valid;
+ byte he_valid;
+} he_cursor;
+
+static struct {
+ void ** cursor;
+} he_cache;
+
+static struct {
+ void * ffe;
+ void * cursor;
+ void * fcb;
+ struct callback_state_entry_header hdr;
+ struct FEDiskEntry fe;
+ afs_uint32 idx;
+ byte hdr_valid;
+ byte fe_valid;
+} fe_cursor;
+
+static struct {
+ void ** cursor;
+} fe_cache;
+
+static struct {
+ void * cursor;
+ struct CBDiskEntry cb;
+ afs_uint32 idx;
+ byte cb_valid;
+} cb_cursor;
+
+static struct {
+ void ** cursor;
+} cb_cache;
+
+static void
+usage(char * prog)
+{
+ fprintf(stderr, "usage: %s [<state dump file>]\n");
+}
+
+int
+main(int argc, char ** argv)
+{
+ banner();
+
+ if (argc > 2 || (argc == 2 && !strcmp(argv[1], "-h"))) {
+ usage(argv[0]);
+ return 1;
+ }
+
+ initState();
+
+ if (argc > 1) {
+ if (openFile(argv[1]))
+ return 1;
+ } else {
+ if (openFile(AFSDIR_SERVER_FSSTATE_FILEPATH))
+ return 1;
+ }
+
+ prompt();
+ return 0;
+}
+
+
+static int
+openFile(char * path)
+{
+ int ret = 0;
+ struct afs_stat status;
+
+ dump_fd = afs_open(path, O_RDWR);
+ if (dump_fd == -1) {
+ fprintf(stderr, "dump file '%s' failed to open\n", path);
+ ret = 1;
+ goto done;
+ }
+
+ printf("opened dump file '%s'\n", path);
+
+ if (afs_fstat(dump_fd, &status) == -1) {
+ fprintf(stderr, "failed to stat file\n");
+ ret = 1;
+ goto done;
+ }
+
+ map_len = status.st_size;
+
+ map = afs_mmap(NULL, map_len, PROT_READ, MAP_SHARED, dump_fd, 0);
+ if (map == MAP_FAILED) {
+ fprintf(stderr, "failed to mmap file\n");
+ ret = 1;
+ goto done;
+ }
+
+ printf("mapped %d bytes at 0x%x\n", map_len, map);
+
+ done:
+ if (ret) {
+ if (map) {
+ munmap(map, map_len);
+ map = NULL;
+ }
+ if (dump_fd != -1) {
+ close(dump_fd);
+ dump_fd = -1;
+ }
+ }
+ return ret;
+}
+
+static void
+initState(void)
+{
+ hdrs.hdr_valid = hdrs.h_hdr_valid = hdrs.cb_hdr_valid = 0;
+ he_cursor.cursor = fe_cursor.cursor = cb_cursor.cursor = NULL;
+ he_cursor.fh = fe_cursor.ffe = fe_cursor.fcb = NULL;
+ he_cache.cursor = fe_cache.cursor = NULL;
+}
+
+static void
+banner(void)
+{
+ fprintf(stderr, "demand attach fs\n");
+ fprintf(stderr, "fileserver state analyzer\n");
+ fprintf(stderr, "version 0.1\n");
+}
+
+#define PROGNAME "fs state analyzer"
+
+static void
+prompt(void)
+{
+ char input[256];
+ char prev_input[256];
+ char * tok = NULL;
+ afs_uint32 x, y, z;
+ enum {
+ PR_GLOBAL_MODE,
+ PR_H_MODE,
+ PR_FE_MODE,
+ PR_CB_MODE
+ } mode = PR_GLOBAL_MODE, next_mode;
+
+ next_mode = mode;
+ input[0] = prev_input[0] = '\0';
+
+ while (1) {
+ if (!tok) {
+ switch(mode) {
+ case PR_GLOBAL_MODE:
+ printf(PROGNAME "> ");
+ break;
+ case PR_H_MODE:
+ printf(PROGNAME ": h(%d)> ", he_cursor.idx);
+ break;
+ case PR_FE_MODE:
+ printf(PROGNAME ": fe(%d)> ", fe_cursor.idx);
+ break;
+ case PR_CB_MODE:
+ printf(PROGNAME ": fe(%d):cb(%d)> ", fe_cursor.idx, cb_cursor.idx);
+ break;
+ default:
+ fprintf(stderr, "prompt state broken; aborting\n");
+ return;
+ }
+ gets(input);
+
+ if (!strcmp(input, "")) {
+ /* repeat last command */
+ if (!strcmp(prev_input, "")) {
+ continue;
+ }
+ strlcpy(input, prev_input, sizeof(input));
+ } else {
+ /* save command for repetition */
+ strlcpy(prev_input, input, sizeof(prev_input));
+ }
+
+ tok = strtok(input, " \t");
+ }
+ while (tok && !strcmp(tok, ";")) {
+ tok = strtok(NULL, "; \t");
+ }
+
+ if (!tok) {
+ continue;
+ }
+
+ if (!strcasecmp(tok, "exit")) {
+ return;
+ } else if (!strcasecmp(tok, "quit")) {
+ switch(mode) {
+ case PR_CB_MODE:
+ next_mode = PR_FE_MODE;
+ break;
+ case PR_FE_MODE:
+ case PR_H_MODE:
+ next_mode = PR_GLOBAL_MODE;
+ break;
+ default:
+ return;
+ }
+ } else if (!strcasecmp(tok, "h")) {
+ tok = strtok(NULL, " \t");
+ mode = PR_H_MODE;
+ if (!tok) {
+ next_mode = mode;
+ }
+ continue;
+ } else if (!strcasecmp(tok, "fe")) {
+ tok = strtok(NULL, " \t");
+ mode = PR_FE_MODE;
+ if (!tok) {
+ next_mode = mode;
+ }
+ continue;
+ } else if (!strcasecmp(tok, "fs")) {
+ tok = strtok(NULL, " \t");
+ mode = PR_GLOBAL_MODE;
+ if (!tok) {
+ next_mode = mode;
+ }
+ continue;
+ } else if (!strcasecmp(tok, "cb")) {
+ tok = strtok(NULL, " \t");
+ mode = PR_CB_MODE;
+ if (!tok) {
+ next_mode = mode;
+ }
+ continue;
+ } else if (!strcasecmp(tok, "help")) {
+ switch(mode) {
+ case PR_H_MODE:
+ print_h_help();
+ break;
+ case PR_FE_MODE:
+ print_fe_help();
+ break;
+ case PR_CB_MODE:
+ print_cb_help();
+ break;
+ default:
+ print_global_help();
+ }
+ print_help();
+ } else if (!strcasecmp(tok, "hexdump")) {
+ tok = strtok(NULL, " \t");
+ if (!tok) {
+ hexdump_map(0, map_len);
+ continue;
+ }
+ if (sscanf(tok, "%u", &x) != 1) {
+ fprintf(stderr, "hexdump parse error 1\n");
+ tok = NULL;
+ continue;
+ }
+ tok = strtok(NULL, " \t");
+ if (!tok) {
+ hexdump_map(x, map_len - x);
+ continue;
+ }
+ if (sscanf(tok, "%u", &y) != 1) {
+ fprintf(stderr, "hexdump parse error 2\n");
+ continue;
+ }
+ hexdump_map(x,y);
+ } else if (!strcasecmp(tok, "hdr")) {
+ switch(mode) {
+ case PR_H_MODE:
+ dump_h_hdr();
+ break;
+ case PR_FE_MODE:
+ dump_cb_hdr();
+ break;
+ case PR_CB_MODE:
+ dump_this_fe();
+ break;
+ default:
+ dump_hdr();
+ }
+ } else if (!strcasecmp(tok, "this")) {
+ switch(mode) {
+ case PR_H_MODE:
+ dump_this_he();
+ break;
+ case PR_FE_MODE:
+ dump_this_fe();
+ break;
+ case PR_CB_MODE:
+ dump_this_cb();
+ break;
+ default:
+ fprintf(stderr, "command not valid for this mode\n");
+ }
+ } else if (!strcasecmp(tok, "next")) {
+ switch(mode) {
+ case PR_H_MODE:
+ dump_next_he();
+ break;
+ case PR_FE_MODE:
+ dump_next_fe();
+ break;
+ case PR_CB_MODE:
+ dump_next_cb();
+ break;
+ default:
+ fprintf(stderr, "command not valid for this mode\n");
+ }
+ } else if (!strcasecmp(tok, "prev")) {
+ switch(mode) {
+ case PR_H_MODE:
+ dump_prev_he();
+ break;
+ case PR_FE_MODE:
+ dump_prev_fe();
+ break;
+ case PR_CB_MODE:
+ dump_prev_cb();
+ break;
+ default:
+ fprintf(stderr, "command not valid for this mode\n");
+ }
+ } else if (!strcasecmp(tok, "first")) {
+ switch(mode) {
+ case PR_H_MODE:
+ dump_first_he();
+ break;
+ case PR_FE_MODE:
+ dump_first_fe();
+ break;
+ case PR_CB_MODE:
+ dump_first_cb();
+ break;
+ default:
+ fprintf(stderr, "command not valid for this mode\n");
+ }
+ } else if (!strcasecmp(tok, "last")) {
+ switch(mode) {
+ case PR_H_MODE:
+ dump_last_he();
+ break;
+ case PR_FE_MODE:
+ dump_last_fe();
+ break;
+ case PR_CB_MODE:
+ dump_last_cb();
+ break;
+ default:
+ fprintf(stderr, "command not valid for this mode\n");
+ }
+ } else if (!strcasecmp(tok, "dump")) {
+ switch(mode) {
+ case PR_H_MODE:
+ dump_all_hes();
+ break;
+ case PR_FE_MODE:
+ dump_all_fes();
+ break;
+ case PR_CB_MODE:
+ dump_all_cbs();
+ break;
+ default:
+ fprintf(stderr, "command not valid for this mode\n");
+ }
+ } else if (!strcasecmp(tok, "find")) {
+ tok = strtok(NULL, " \t");
+ if (!tok || strcasecmp(tok, "by")) {
+ tok = NULL;
+ fprintf(stderr, "find syntax error 1 (%s)\n",
+ (tok) ? tok : "nil");
+ continue;
+ }
+ tok = strtok(NULL, " \t");
+ if (!tok) {
+ fprintf(stderr, "find syntax error 2\n");
+ continue;
+ }
+ switch(mode) {
+ case PR_H_MODE:
+ fprintf(stderr, "not implemented yet\n");
+ break;
+ case PR_FE_MODE:
+ if (!strcasecmp(tok, "index")) {
+ tok = strtok(NULL, " \t");
+ if (!tok || sscanf(tok, "%u", &x) != 1) {
+ tok = NULL;
+ fprintf(stderr, "find syntax error 3\n");
+ continue;
+ }
+ if (find_fe_by_index(x)) {
+ fprintf(stderr, "find returned no results\n");
+ }
+ } else if (!strcasecmp(tok, "fid")) {
+ tok = strtok(NULL, "(), \t");
+ if (!tok || sscanf(tok, "%u", &x) != 1) {
+ tok = NULL;
+ fprintf(stderr, "find syntax error 4\n");
+ continue;
+ }
+ tok = strtok(NULL, "(), \t");
+ if (!tok || sscanf(tok, "%u", &y) != 1) {
+ tok = NULL;
+ fprintf(stderr, "find syntax error 5\n");
+ continue;
+ }
+ tok = strtok(NULL, "(), \t");
+ if (!tok || sscanf(tok, "%u", &z) != 1) {
+ tok = NULL;
+ fprintf(stderr, "find syntax error 6\n");
+ continue;
+ }
+ if (find_fe_by_fid(x,y,z)) {
+ fprintf(stderr, "find returned no results\n");
+ }
+ } else {
+ fprintf(stderr, "unsupported filter type\n");
+ }
+ break;
+ case PR_CB_MODE:
+ if (!strcasecmp(tok, "index")) {
+ tok = strtok(NULL, " \t");
+ if (!tok || sscanf(tok, "%u", &x) != 1) {
+ tok = NULL;
+ fprintf(stderr, "find syntax error 3\n");
+ continue;
+ }
+ if (find_cb_by_index(x)) {
+ fprintf(stderr, "find returned no results\n");
+ }
+ } else {
+ fprintf(stderr, "unsupported filter type\n");
+ }
+ break;
+ default:
+ fprintf(stderr, "find not supported for this menu\n");
+ }
+ } else if (!strcspn(tok, "0123456789")) {
+ if (sscanf(tok, "%u", &x) == 1) {
+ switch(mode) {
+ case PR_H_MODE:
+ dump_he(x);
+ break;
+ case PR_FE_MODE:
+ dump_fe(x);
+ break;
+ case PR_CB_MODE:
+ dump_cb(x);
+ break;
+ default:
+ fprintf(stderr, "command not available from this menu\n");
+ }
+ } else {
+ fprintf(stderr, "input parse error ('%s')\n", tok);
+ }
+ } else if (mode == PR_FE_MODE) {
+ if (!strcmp(tok, "timeout")) {
+ dump_cb_timeout();
+ } else if (!strcmp(tok, "hash")) {
+ dump_cb_fehash();
+ }
+ } else {
+ fprintf(stderr, "unknown command\n");
+ }
+ tok = strtok(NULL, " \t");
+ mode = next_mode;
+ }
+}
+
+static void
+print_help(void)
+{
+ printf("\th <...> -- host menu commands\n");
+ printf("\tfe <...> -- FileEntry menu commands\n");
+ printf("\tcb <...> -- CallBack menu commands\n");
+ printf("\thexdump [<offset> [<len>]]\n\t\t -- hex dump the raw data\n");
+ printf("\tquit -- quit this menu\n");
+ printf("\texit -- exit the debugger\n");
+ printf("\thelp -- this help message\n");
+}
+
+static void
+print_global_help(void)
+{
+ printf("\thdr -- display the fs_state_header struct\n");
+}
+
+static void
+print_h_help(void)
+{
+ printf("\thdr -- display the host_state_header struct\n");
+ printf("\tfirst -- display the first host\n");
+ printf("\tprev -- display the previous host\n");
+ printf("\tthis -- display this host\n");
+ printf("\tnext -- display the next host\n");
+ printf("\tlast -- display the last host\n");
+ printf("\tdump -- display all hosts\n");
+}
+
+static void
+print_fe_help(void)
+{
+ printf("\thdr -- display the callback_state_header struct\n");
+ printf("\tfirst -- display the first FE\n");
+ printf("\tprev -- display the previous FE\n");
+ printf("\tthis -- display this FE\n");
+ printf("\tnext -- display the next FE\n");
+ printf("\tlast -- display the last FE\n");
+ printf("\tdump -- display all FEs\n");
+ printf("\ttimeout -- display the timeout queue heads\n");
+ printf("\thash -- display the file entry hash buckets\n");
+ printf("\tfind by index <id>\n\t\t -- find an fe by its array index\n");
+ printf("\tfind by fid <(vol,vnode,unique)>\n\t\t -- find an fe by its AFSFid\n");
+}
+
+static void
+print_cb_help(void)
+{
+ printf("\thdr -- display the callback_state_entry_header struct\n");
+ printf("\tfirst -- display the first CB\n");
+ printf("\tprev -- display the previous CB\n");
+ printf("\tthis -- display this CB\n");
+ printf("\tnext -- display the next CB\n");
+ printf("\tlast -- display the last CB\n");
+ printf("\tdump -- display all CBs\n");
+}
+
+#define DPFTB0 "\t"
+#define DPFTB1 "\t\t"
+#define DPFTB2 "\t\t\t"
+
+#define DPFOFF(addr) \
+ do { \
+ char * _p = (char *)addr; \
+ char * _m = (char *)map; \
+ printf("loading structure from address 0x%x (offset %u)\n", \
+ addr, _p-_m); \
+ } while (0)
+
+/* structs */
+#define DPFSO(T, name) printf(T "%s = {\n", name)
+#define DPFSO0(name) DPFSO(DPFTB0, name)
+#define DPFSO1(name) DPFSO(DPFTB1, name)
+#define DPFSC(T) printf(T "}\n")
+#define DPFSC0 DPFSC(DPFTB0)
+#define DPFSC1 DPFSC(DPFTB1)
+
+/* arrays */
+#define DPFAO(T1, T2, name) printf(T1 "%s =\n" T2 "{ ", name)
+#define DPFAO0(name) DPFAO(DPFTB0, DPFTB1, name)
+#define DPFAO1(name) DPFAO(DPFTB1, DPFTB2, name)
+#define DPFAC0 printf(" }\n")
+#define DPFAC1 DPFAC0
+#define DPFA1 printf(DPFTB1 " ")
+#define DPFA2 printf(DPFTB2 " ")
+#define DPFAN printf("\n")
+#define DPFALE(type, var) printf("%" type, var)
+#define DPFAE(type, var) printf("%" type ",\t", var)
+
+/* normal vars */
+#define DPFV(T, name, type, var) printf(T "%s = %" type "\n", name, var)
+#define DPFV1(name, type, var) DPFV(DPFTB1, name, type, var)
+#define DPFV2(name, type, var) DPFV(DPFTB2, name, type, var)
+
+/* hex */
+#define DPFX(T, name, var) printf(T "%s = 0x%x\n", name, var)
+#define DPFX1(name, var) DPFX(DPFTB1, name, var)
+#define DPFX2(name, var) DPFX(DPFTB2, name, var)
+
+/* strings */
+#define DPFS(T, name, var) printf(T "%s = \"%s\"\n", name, var)
+#define DPFS1(name, var) DPFS(DPFTB1, name, var)
+#define DPFS2(name, var) DPFS(DPFTB2, name, var)
+
+/* time */
+#define DPFT(T, name, var) \
+ do { \
+ char * last; \
+ printf(T "%s = \"%s\"\n", name, strtok_r(ctime(&(var)), "\r\n", &last)); \
+ } while(0)
+#define DPFT1(name, var) DPFT(DPFTB1, name, var)
+#define DPFT2(name, var) DPFT(DPFTB2, name, var)
+
+static void
+dump_hdr(void)
+{
+ char uuid_str[40];
+ afs_uint32 hi, lo;
+
+ if (get_hdr())
+ return;
+
+ DPFOFF(map);
+ DPFSO0("fs_state_header");
+ DPFSO1("stamp");
+ DPFX2("magic", hdrs.hdr.stamp.magic);
+ DPFV2("version", "u", hdrs.hdr.stamp.version);
+ DPFSC1;
+ DPFT1("timestamp", hdrs.hdr.timestamp);
+ DPFV1("sys_name", "u", hdrs.hdr.sys_name);
+
+ afsUUID_to_string(&hdrs.hdr.server_uuid, uuid_str, sizeof(uuid_str));
+ DPFS1("server_uuid", uuid_str);
+ DPFV1("valid", "d", hdrs.hdr.valid);
+ DPFV1("endianness", "d", hdrs.hdr.endianness);
+ DPFV1("stats_detailed", "d", hdrs.hdr.stats_detailed);
+
+ SplitInt64(hdrs.hdr.h_offset, hi, lo);
+ DPFSO1("h_offset");
+ DPFV2("hi", "u", hi);
+ DPFV2("lo", "u", lo);
+ DPFSC1;
+
+ SplitInt64(hdrs.hdr.cb_offset, hi, lo);
+ DPFSO1("cb_offset");
+ DPFV2("hi", "u", hi);
+ DPFV2("lo", "u", lo);
+ DPFSC1;
+
+ DPFS1("server_version_string", hdrs.hdr.server_version_string);
+ DPFSC0;
+
+ if (hdrs.hdr.stamp.magic != FS_STATE_MAGIC) {
+ fprintf(stderr, "* magic check failed\n");
+ }
+ if (hdrs.hdr.stamp.version != FS_STATE_VERSION) {
+ fprintf(stderr, "* version check failed\n");
+ }
+}
+
+static void
+dump_h_hdr(void)
+{
+ if (get_h_hdr())
+ return;
+
+ DPFOFF(hdrs.h_hdr_p);
+ DPFSO0("host_state_header");
+ DPFSO1("stamp");
+ DPFX2("magic", hdrs.h_hdr.stamp.magic);
+ DPFV2("version", "u", hdrs.h_hdr.stamp.version);
+ DPFSC1;
+ DPFV1("records", "u", hdrs.h_hdr.records);
+ DPFV1("index_max", "u", hdrs.h_hdr.index_max);
+ DPFSC0;
+
+ if (hdrs.h_hdr.stamp.magic != HOST_STATE_MAGIC) {
+ fprintf(stderr, "* magic check failed\n");
+ }
+ if (hdrs.h_hdr.stamp.version != HOST_STATE_VERSION) {
+ fprintf(stderr, "* version check failed\n");
+ }
+}
+
+static void
+dump_cb_hdr(void)
+{
+ afs_uint32 hi, lo;
+
+ if (get_cb_hdr())
+ return;
+
+ DPFOFF(hdrs.cb_hdr_p);
+ DPFSO0("callback_state_header");
+ DPFSO1("stamp");
+ DPFX2("magic", hdrs.cb_hdr.stamp.magic);
+ DPFV2("version", "u", hdrs.cb_hdr.stamp.version);
+ DPFSC1;
+ DPFV1("nFEs", "u", hdrs.cb_hdr.nFEs);
+ DPFV1("nCBs", "u", hdrs.cb_hdr.nCBs);
+ DPFV1("fe_max", "u", hdrs.cb_hdr.fe_max);
+ DPFV1("cb_max", "u", hdrs.cb_hdr.cb_max);
+ DPFV1("tfirst", "d", hdrs.cb_hdr.tfirst);
+
+ SplitInt64(hdrs.cb_hdr.timeout_offset, hi, lo);
+ DPFSO1("timeout_offset");
+ DPFV2("hi", "u", hi);
+ DPFV2("lo", "u", lo);
+ DPFSC1;
+
+ SplitInt64(hdrs.cb_hdr.fehash_offset, hi, lo);
+ DPFSO1("fehash_offset");
+ DPFV2("hi", "u", hi);
+ DPFV2("lo", "u", lo);
+ DPFSC1;
+
+ SplitInt64(hdrs.cb_hdr.fe_offset, hi, lo);
+ DPFSO1("fe_offset");
+ DPFV2("hi", "u", hi);
+ DPFV2("lo", "u", lo);
+ DPFSC1;
+
+ DPFSC0;
+
+ if (hdrs.cb_hdr.stamp.magic != CALLBACK_STATE_MAGIC) {
+ fprintf(stderr, "* magic check failed\n");
+ }
+ if (hdrs.cb_hdr.stamp.version != CALLBACK_STATE_VERSION) {
+ fprintf(stderr, "* version check failed\n");
+ }
+}
+
+static void
+dump_cb_timeout(void)
+{
+ int i;
+
+ if (get_cb_hdr())
+ return;
+
+ if (get_cb_timeout_hdr())
+ return;
+
+ if (get_cb_timeout())
+ return;
+
+ DPFOFF(hdrs.timeout_hdr_p);
+ DPFSO0("callback_state_timeout_header");
+ DPFX1("magic", hdrs.timeout_hdr.magic);
+ DPFV1("len", "u", hdrs.timeout_hdr.len);
+ DPFV1("records", "u", hdrs.timeout_hdr.records);
+ DPFSC0;
+
+ if (hdrs.timeout_hdr.magic != CALLBACK_STATE_TIMEOUT_MAGIC) {
+ fprintf(stderr, "* magic check failed\n");
+ }
+
+ DPFOFF(hdrs.timeout_p);
+ DPFAO0("timeout");
+ for (i = 0; i < 127; i++) {
+ DPFAE("u", hdrs.timeout[i]);
+ if ((i % 8) == 7) {
+ DPFAN;
+ DPFA1;
+ }
+ }
+ DPFALE("u", hdrs.timeout[127]);
+ DPFAC0;
+}
+
+static void
+dump_cb_fehash(void)
+{
+ int i;
+
+ if (get_cb_hdr())
+ return;
+
+ if (get_cb_fehash_hdr())
+ return;
+
+ if (get_cb_fehash())
+ return;
+
+ DPFOFF(hdrs.fehash_hdr_p);
+ DPFSO0("callback_state_fehash_header");
+ DPFX1("magic", hdrs.fehash_hdr.magic);
+ DPFV1("len", "u", hdrs.fehash_hdr.len);
+ DPFV1("records", "u", hdrs.fehash_hdr.records);
+ DPFSC0;
+
+ if (hdrs.fehash_hdr.magic != CALLBACK_STATE_FEHASH_MAGIC) {
+ fprintf(stderr, "* magic check failed\n");
+ }
+
+ DPFOFF(hdrs.fehash_p);
+ DPFAO0("fehash");
+ for (i = 0; i < hdrs.fehash_hdr.records - 1; i++) {
+ DPFAE("u", hdrs.fehash[i]);
+ if ((i % 8) == 7) {
+ DPFAN;
+ DPFA1;
+ }
+ }
+ DPFALE("u", hdrs.fehash[hdrs.fehash_hdr.records-1]);
+ DPFAC0;
+}
+
+static void
+dump_all_hes(void)
+{
+ int i;
+
+ if (get_h_hdr()) {
+ fprintf(stderr, "error getting host_state_header\n");
+ return;
+ }
+
+ for (i = 0; i < hdrs.h_hdr.records; i++) {
+ dump_he(i);
+ }
+}
+
+static void
+dump_all_fes(void)
+{
+ int i;
+
+ if (get_cb_hdr()) {
+ fprintf(stderr, "error getting callback_state_header\n");
+ return;
+ }
+
+ for (i = 0; i < hdrs.cb_hdr.nFEs; i++) {
+ dump_fe(i);
+ }
+}
+
+static void
+dump_all_cbs(void)
+{
+ int i;
+
+ if (get_fe_hdr()) {
+ fprintf(stderr, "error getting callback_state_entry_header\n");
+ return;
+ }
+
+ for (i = 0; i < fe_cursor.hdr.nCBs; i++) {
+ dump_cb(i);
+ }
+}
+
+static void
+dump_he(afs_uint32 idx)
+{
+ if (get_he(idx)) {
+ fprintf(stderr, "error getting he %d\n", idx);
+ return;
+ }
+
+ DPFOFF(he_cursor.cursor);
+ dump_he_hdr();
+ dump_he_entry();
+ dump_he_interfaces();
+ dump_he_hcps();
+}
+
+static void
+dump_fe(afs_uint32 idx)
+{
+ if (get_fe(idx)) {
+ fprintf(stderr, "error getting fe %d\n", idx);
+ return;
+ }
+
+ DPFOFF(fe_cursor.cursor);
+ dump_fe_hdr();
+ dump_fe_entry();
+}
+
+static void
+dump_cb(afs_uint32 idx)
+{
+ if (get_cb(idx)) {
+ fprintf(stderr, "error getting cb %d\n", idx);
+ return;
+ }
+
+ DPFOFF(cb_cursor.cursor);
+ dump_cb_entry();
+}
+
+static void
+dump_this_he(void)
+{
+ dump_he(he_cursor.idx);
+}
+
+static void
+dump_this_fe(void)
+{
+ dump_fe(fe_cursor.idx);
+}
+
+static void
+dump_this_cb(void)
+{
+ dump_cb(cb_cursor.idx);
+}
+
+static void
+dump_next_he(void)
+{
+ if (get_h_hdr()) {
+ fprintf(stderr, "error getting host_state_header\n");
+ return;
+ }
+
+ if ((he_cursor.idx + 1) >= hdrs.h_hdr.records) {
+ fprintf(stderr, "no more HEs\n");
+ return;
+ }
+
+ dump_he(he_cursor.idx+1);
+}
+
+static void
+dump_next_fe(void)
+{
+ if (get_cb_hdr()) {
+ fprintf(stderr, "error getting callback_state_header\n");
+ return;
+ }
+
+ if ((fe_cursor.idx + 1) >= hdrs.cb_hdr.nFEs) {
+ fprintf(stderr, "no more FEs\n");
+ return;
+ }
+
+ dump_fe(fe_cursor.idx+1);
+}
+
+static void
+dump_next_cb(void)
+{
+ if (get_fe_hdr()) {
+ fprintf(stderr, "error getting callback_state_entry_header\n");
+ return;
+ }
+
+ if ((cb_cursor.idx + 1) >= fe_cursor.hdr.nCBs) {
+ fprintf(stderr, "no more CBs\n");
+ return;
+ }
+
+ dump_cb(cb_cursor.idx+1);
+}
+
+static void
+dump_prev_he(void)
+{
+ if (!he_cursor.idx) {
+ fprintf(stderr, "no more HEs\n");
+ return;
+ }
+
+ dump_he(he_cursor.idx-1);
+}
+
+static void
+dump_prev_fe(void)
+{
+ if (!fe_cursor.idx) {
+ fprintf(stderr, "no more FEs\n");
+ return;
+ }
+
+ dump_fe(fe_cursor.idx-1);
+}
+
+static void
+dump_prev_cb(void)
+{
+ if (!cb_cursor.idx) {
+ fprintf(stderr, "no more CBs\n");
+ return;
+ }
+
+ dump_cb(cb_cursor.idx-1);
+}
+
+static void
+dump_first_fe(void)
+{
+ if (get_cb_hdr()) {
+ fprintf(stderr, "error getting callback_state_header\n");
+ return;
+ }
+
+ if (!hdrs.cb_hdr.nFEs) {
+ fprintf(stderr, "no FEs present\n");
+ return;
+ }
+
+ dump_fe(0);
+}
+
+static void
+dump_first_he(void)
+{
+ if (get_h_hdr()) {
+ fprintf(stderr, "error getting host_state_header\n");
+ return;
+ }
+
+ if (!hdrs.h_hdr.records) {
+ fprintf(stderr, "no HEs present\n");
+ return;
+ }
+
+ dump_he(0);
+}
+
+static void
+dump_first_cb(void)
+{
+ if (get_fe_hdr()) {
+ fprintf(stderr, "error getting callback_state_entry_header\n");
+ return;
+ }
+
+ if (!fe_cursor.hdr.nCBs) {
+ fprintf(stderr, "no CBs present\n");
+ return;
+ }
+
+ dump_cb(0);
+}
+
+static void
+dump_last_he(void)
+{
+ if (get_h_hdr()) {
+ fprintf(stderr, "error getting host_state_header\n");
+ return;
+ }
+
+ if (!hdrs.h_hdr.records) {
+ fprintf(stderr, "no HEs present\n");
+ return;
+ }
+
+ dump_he(hdrs.h_hdr.records-1);
+}
+
+static void
+dump_last_fe(void)
+{
+ if (get_cb_hdr()) {
+ fprintf(stderr, "error getting callback_state_header\n");
+ return;
+ }
+
+ if (!hdrs.cb_hdr.nFEs) {
+ fprintf(stderr, "no FEs present\n");
+ return;
+ }
+
+ dump_fe(hdrs.cb_hdr.nFEs-1);
+}
+
+static void
+dump_last_cb(void)
+{
+ if (get_fe_hdr()) {
+ fprintf(stderr, "error getting callback_state_entry_header\n");
+ return;
+ }
+
+ if (!fe_cursor.hdr.nCBs) {
+ fprintf(stderr, "no CBs present\n");
+ return;
+ }
+
+ dump_cb(fe_cursor.hdr.nCBs-1);
+}
+
+static void
+dump_he_hdr(void)
+{
+ DPFSO0("host_state_entry_header");
+ DPFX1("magic", he_cursor.hdr.magic);
+ DPFV1("len", "u", he_cursor.hdr.len);
+ DPFV1("interfaces", "u", he_cursor.hdr.interfaces);
+ DPFV1("hcps", "u", he_cursor.hdr.hcps);
+ DPFSC0;
+
+ if (he_cursor.hdr.magic != HOST_STATE_ENTRY_MAGIC) {
+ fprintf(stderr, "* magic check failed\n");
+ }
+}
+
+static void
+dump_he_entry(void)
+{
+ DPFSO0("hostDiskEntry");
+ DPFS1("host", afs_inet_ntoa(he_cursor.he.host));
+ DPFV1("port", "u", he_cursor.he.port);
+ DPFX1("hostFlags", he_cursor.he.hostFlags);
+ DPFV1("Console", "u", he_cursor.he.Console);
+ DPFV1("hcpsfailed", "u", he_cursor.he.hcpsfailed);
+ DPFV1("hcps_valid", "u", he_cursor.he.hcps_valid);
+ if (hdrs.hdr.stats_detailed) {
+#ifdef FS_STATS_DETAILED
+ DPFV1("InSameNetwork", "u", he_cursor.he.InSameNetwork);
+#else
+ DPFV1("InSameNetwork", "u", he_cursor.he.padding1[0]);
+#endif
+ }
+ DPFV1("hcps_len", "u", he_cursor.he.hcps_len);
+ DPFT1("LastCall", he_cursor.he.LastCall);
+ DPFT1("ActiveCall", he_cursor.he.ActiveCall);
+ DPFT1("cpsCall", he_cursor.he.cpsCall);
+ DPFV1("cblist", "u", he_cursor.he.cblist);
+ DPFV1("index", "u", he_cursor.he.index);
+ DPFSC0;
+}
+
+static void
+dump_he_interfaces(void)
+{
+ char temp_str[40];
+ struct Interface * ifp;
+ int len, i;
+
+ if (!he_cursor.hdr.interfaces)
+ return;
+
+ len = sizeof(struct Interface) + ((he_cursor.hdr.interfaces-1)*sizeof(struct AddrPort));
+ ifp = (struct Interface *) malloc(len);
+ assert(ifp != NULL);
+
+ memcpy(ifp, he_cursor.ifp, len);
+
+ DPFSO0("Interface");
+ DPFV1("numberOfInterfaces", "u", ifp->numberOfInterfaces);
+
+ afsUUID_to_string(&ifp->uuid, temp_str, sizeof(temp_str));
+ DPFS1("uuid", temp_str);
+ for (i = 0; i < he_cursor.hdr.interfaces; i++) {
+ snprintf(temp_str, sizeof(temp_str), "interface[%d]", i);
+ DPFSO1(temp_str);
+ DPFS2("addr", afs_inet_ntoa(ifp->interface[i].addr));
+ DPFV2("port", "u", ifp->interface[i].port);
+ DPFSC1;
+ }
+
+ DPFSC0;
+
+ if (he_cursor.hdr.interfaces != ifp->numberOfInterfaces) {
+ fprintf(stderr, "* interface count mismatch between header and Interface struct\n");
+ }
+ free(ifp);
+}
+
+static void
+dump_he_hcps(void)
+{
+ char temp_str[40];
+ afs_int32 * hcps;
+ int len, i;
+
+ if (!he_cursor.hdr.hcps)
+ return;
+
+ len = (he_cursor.hdr.hcps)*sizeof(afs_uint32);
+ hcps = (afs_int32 *) malloc(len);
+ assert(hcps != NULL);
+ memcpy(hcps, he_cursor.hcps, len);
+
+ DPFSO0("hcps");
+ DPFAO1("prlist_val");
+ for (i = 0; i < he_cursor.hdr.hcps - 1; i++) {
+ DPFAE("d", hcps[i]);
+ if ((i % 8) == 7) {
+ DPFAN;
+ DPFA2;
+ }
+ }
+ DPFALE("d", hcps[he_cursor.hdr.hcps-1]);
+ DPFAC1;
+ DPFSC0;
+ free(hcps);
+}
+
+static void
+dump_fe_hdr(void)
+{
+ DPFSO0("callback_state_entry_header");
+ DPFX1("magic", fe_cursor.hdr.magic);
+ DPFV1("len", "u", fe_cursor.hdr.len);
+ DPFV1("nCBs", "u", fe_cursor.hdr.nCBs);
+ DPFSC0;
+
+ if (fe_cursor.hdr.magic != CALLBACK_STATE_ENTRY_MAGIC) {
+ fprintf(stderr, "* magic check failed\n");
+ }
+}
+
+static void
+dump_fe_entry(void)
+{
+ DPFSO0("FEDiskEntry");
+ DPFSO1("fe");
+ DPFV2("vnode", "u", fe_cursor.fe.fe.vnode);
+ DPFV2("unique", "u", fe_cursor.fe.fe.unique);
+ DPFV2("volid", "u", fe_cursor.fe.fe.volid);
+ DPFV2("fnext", "u", fe_cursor.fe.fe.fnext);
+ DPFV2("ncbs", "u", fe_cursor.fe.fe.ncbs);
+ DPFV2("firstcb", "u", fe_cursor.fe.fe.firstcb);
+ DPFV2("status", "u", fe_cursor.fe.fe.status);
+ DPFSC1;
+ DPFV1("index", "u", fe_cursor.fe.index);
+ DPFSC0;
+}
+
+static void
+dump_cb_entry(void)
+{
+ DPFSO0("CBDiskEntry");
+ DPFSO1("cb");
+ DPFV2("cnext", "u", cb_cursor.cb.cb.cnext);
+ DPFV2("fhead", "u", cb_cursor.cb.cb.fhead);
+ DPFV2("thead", "u", (afs_uint32)cb_cursor.cb.cb.thead);
+ DPFV2("status", "u", (afs_uint32)cb_cursor.cb.cb.status);
+ DPFV2("hhead", "u", cb_cursor.cb.cb.hhead);
+ DPFV2("tprev", "u", cb_cursor.cb.cb.tprev);
+ DPFV2("tnext", "u", cb_cursor.cb.cb.tnext);
+ DPFV2("hprev", "u", cb_cursor.cb.cb.hprev);
+ DPFV2("hnext", "u", cb_cursor.cb.cb.hnext);
+ DPFSC1;
+ DPFV1("index", "u", cb_cursor.cb.index);
+ DPFSC0;
+}
+
+#define DPFHMS printf(" ")
+#define DPFHS printf(" ")
+#define DPFHN(offset) printf("\n%u\t", offset)
+#define DPFHD(x) printf("%02X ", x)
+#define DPFHE printf("\n")
+
+static void
+hexdump_map(afs_uint32 offset, afs_uint32 len)
+{
+ int i;
+ unsigned char * p = (unsigned char *)map;
+ afs_uint32 c32;
+
+ if (!len)
+ return;
+
+ if ((offset + len) > map_len) {
+ fprintf(stderr, "offset + length exceeds memory map size (%u > %u)\n",
+ offset+len, map_len);
+ return;
+ }
+
+ p += offset;
+ DPFOFF(p);
+ DPFHN(offset);
+
+ for (i = offset % 16; i > 0; i--) {
+ DPFHS;
+ }
+
+ for (i=0; i < len; i++, p++, offset++) {
+ if (!(offset % 16)) {
+ DPFHN(offset);
+ } else if (!(offset % 8)) {
+ DPFHMS;
+ }
+ DPFHD(*p);
+ }
+ DPFHE;
+}
+
+static int
+get_hdr(void)
+{
+ if (!hdrs.hdr_valid) {
+ if (map_len < sizeof(struct fs_state_header)) {
+ fprintf(stderr, "corrupt state dump: fs_state_header larger than memory map\n");
+ return 1;
+ }
+ memcpy(&hdrs.hdr, map, sizeof(hdrs.hdr));
+ hdrs.hdr_p = map;
+ hdrs.hdr_valid = 1;
+ }
+ return 0;
+}
+
+static int
+get_h_hdr(void)
+{
+ char * buf;
+ afs_uint32 hi, lo;
+
+ if (hdrs.h_hdr_valid)
+ return 0;
+
+ if (get_hdr())
+ return 1;
+
+ SplitInt64(hdrs.hdr.h_offset, hi, lo);
+
+ if (hi) {
+ fprintf(stderr, "hi offset bits set in h_offset; can't get host_state_header\n");
+ return 1;
+ }
+ if ((lo >= map_len) ||
+ ((lo + sizeof(struct host_state_header)) > map_len) ||
+ (lo + sizeof(struct host_state_header) < lo)) {
+ fprintf(stderr, "h_offset puts host_state_header beyond end of memory map\n");
+ return 1;
+ }
+
+ buf = (char *) map;
+ buf += lo;
+ memcpy(&hdrs.h_hdr, buf, sizeof(struct host_state_header));
+ hdrs.h_hdr_p = buf;
+ buf += sizeof(struct host_state_header);
+ he_cursor.fh = (void *)buf;
+ return 0;
+}
+
+static int
+get_cb_hdr(void)
+{
+ char * buf;
+ afs_uint32 hi, lo;
+
+ if (hdrs.cb_hdr_valid)
+ return 0;
+
+ if (get_hdr())
+ return 1;
+
+ SplitInt64(hdrs.hdr.cb_offset, hi, lo);
+
+ if (hi) {
+ fprintf(stderr, "hi offset bits set in cb_offset; can't get callback_state_header\n");
+ return 1;
+ }
+ if ((lo >= map_len) ||
+ ((lo + sizeof(struct callback_state_header)) > map_len) ||
+ (lo + sizeof(struct callback_state_header) < lo)) {
+ fprintf(stderr, "cb_offset puts callback_state_header beyond end of memory map\n");
+ return 1;
+ }
+
+ buf = (char *) map;
+ buf += lo;
+ memcpy(&hdrs.cb_hdr, buf, sizeof(struct callback_state_header));
+ hdrs.cb_hdr_p = buf;
+ hdrs.cb_hdr_valid = 1;
+
+ SplitInt64(hdrs.cb_hdr.fe_offset, hi, lo);
+
+ if (hi) {
+ fprintf(stderr, "hi offset bits set in fe_offset; can't get callback_state_entry_header\n");
+ return 1;
+ }
+ hi = lo + (hdrs.cb_hdr.nFEs * (sizeof(struct callback_state_entry_header) +
+ sizeof(struct FEDiskEntry)) +
+ hdrs.cb_hdr.nCBs * sizeof(struct CBDiskEntry));
+ if ((hi > map_len) ||
+ (lo > hi)) {
+ fprintf(stderr, "fe_offset puts callback_state_entry_header beyond end of memory map\n");
+ return 1;
+ }
+
+ buf = (char *) map;
+ buf += lo;
+ fe_cursor.ffe = (void *)buf;
+
+ return 0;
+}
+
+static int
+get_cb_timeout_hdr(void)
+{
+ char * buf;
+ afs_uint32 hi, lo;
+
+ if (hdrs.timeout_hdr_valid)
+ return 0;
+
+ if (get_cb_hdr())
+ return 1;
+
+ SplitInt64(hdrs.cb_hdr.timeout_offset, hi, lo);
+
+ if (hi) {
+ fprintf(stderr, "hi offset bits set in timeout_offset; can't get callback_state_timeout_header\n");
+ return 1;
+ }
+ if ((lo >= map_len) ||
+ ((lo + sizeof(struct callback_state_timeout_header)) > map_len) ||
+ (lo + sizeof(struct callback_state_timeout_header) < lo)) {
+ fprintf(stderr, "timeout_offset puts callback_state_timeout_header beyond end of memory map\n");
+ return 1;
+ }
+
+ buf = (char *) map;
+ buf += lo;
+ memcpy(&hdrs.timeout_hdr, buf, sizeof(struct callback_state_timeout_header));
+ hdrs.timeout_hdr_p = buf;
+ hdrs.timeout_hdr_valid = 1;
+ buf += sizeof(struct callback_state_timeout_header);
+ hdrs.timeout_p = buf;
+
+ return 0;
+}
+
+static int
+get_cb_timeout(void)
+{
+ char * buf;
+
+ if (hdrs.timeout)
+ return 0;
+
+ if (get_cb_timeout_hdr())
+ return 1;
+
+ hdrs.timeout = (afs_uint32 *) calloc(hdrs.timeout_hdr.records, sizeof(afs_uint32));
+ assert(hdrs.timeout != NULL);
+ memcpy(hdrs.timeout, hdrs.timeout_p, hdrs.timeout_hdr.records * sizeof(afs_uint32));
+ return 0;
+}
+
+static int
+get_cb_fehash_hdr(void)
+{
+ char * buf;
+ afs_uint32 hi, lo;
+
+ if (hdrs.fehash_hdr_valid)
+ return 0;
+
+ if (get_cb_hdr())
+ return 1;
+
+ SplitInt64(hdrs.cb_hdr.fehash_offset, hi, lo);
+
+ if (hi) {
+ fprintf(stderr, "hi offset bits set in fehash_offset; can't get callback_state_fehash_header\n");
+ return 1;
+ }
+ if ((lo >= map_len) ||
+ ((lo + sizeof(struct callback_state_fehash_header)) > map_len) ||
+ (lo + sizeof(struct callback_state_fehash_header) < lo)) {
+ fprintf(stderr, "timeout_offset puts callback_state_fehash_header beyond end of memory map\n");
+ return 1;
+ }
+
+ buf = (char *) map;
+ buf += lo;
+ memcpy(&hdrs.fehash_hdr, buf, sizeof(struct callback_state_fehash_header));
+ hdrs.fehash_hdr_p = buf;
+ hdrs.fehash_hdr_valid = 1;
+ buf += sizeof(struct callback_state_fehash_header);
+ hdrs.fehash_p = buf;
+
+ return 0;
+}
+
+static int
+get_cb_fehash(void)
+{
+ char * buf;
+
+ if (hdrs.fehash)
+ return 0;
+
+ if (get_cb_fehash_hdr())
+ return 1;
+
+ hdrs.fehash = (afs_uint32 *) calloc(hdrs.fehash_hdr.records, sizeof(afs_uint32));
+ assert(hdrs.fehash != NULL);
+ memcpy(hdrs.fehash, hdrs.fehash_p, hdrs.fehash_hdr.records * sizeof(afs_uint32));
+ return 0;
+}
+
+static int
+get_he(afs_uint32 idx)
+{
+ int i;
+ char * p;
+
+ if (get_h_hdr())
+ return 1;
+
+ if (idx >= hdrs.h_hdr.records)
+ return 1;
+
+ if (he_cursor.idx == idx && he_cursor.hdr_valid && he_cursor.he_valid)
+ return 0;
+
+ he_cursor.hdr_valid = he_cursor.he_valid = 0;
+
+ if (he_cache.cursor == NULL) {
+ he_cache.cursor = (void **) calloc(hdrs.h_hdr.records, sizeof(void *));
+ assert(he_cache.cursor != NULL);
+ }
+
+ if (idx && he_cache.cursor[idx-1] == NULL) {
+ for (i = 0; i < idx; i++) {
+ if (he_cache.cursor[i] == NULL) {
+ get_he(i);
+ }
+ }
+ }
+
+ if (!idx) {
+ he_cursor.cursor = he_cursor.fh;
+ } else if (he_cursor.cursor == he_cache.cursor[idx-1]) {
+ p = (char *)he_cursor.cursor;
+ p += he_cursor.hdr.len;
+ he_cursor.cursor = (void *)p;
+ } else {
+ he_cursor.cursor = he_cache.cursor[idx-1];
+ if (get_he_hdr())
+ return 1;
+ p = (char *)he_cursor.cursor;
+ p += he_cursor.hdr.len;
+ he_cursor.cursor = (void *)p;
+ }
+
+ he_cursor.idx = idx;
+ he_cache.cursor[idx] = he_cursor.cursor;
+
+ if (get_he_hdr())
+ return 1;
+ if (get_he_entry())
+ return 1;
+
+ return 0;
+}
+
+static int
+get_he_hdr(void)
+{
+ memcpy(&he_cursor.hdr, he_cursor.cursor, sizeof(struct host_state_entry_header));
+ he_cursor.hdr_valid = 1;
+ return 0;
+}
+
+static int
+get_he_entry(void)
+{
+ char * p;
+
+ if (!he_cursor.hdr_valid) {
+ if (get_he_hdr()) {
+ return 1;
+ }
+ }
+
+ p = (char *) he_cursor.cursor;
+ p += sizeof(struct host_state_entry_header);
+
+ memcpy(&he_cursor.he, p, sizeof(struct hostDiskEntry));
+
+ he_cursor.he_valid = 1;
+ p += sizeof(struct hostDiskEntry);
+ he_cursor.ifp = (void *)p;
+ if (he_cursor.hdr.interfaces) {
+ p += sizeof(struct Interface) + ((he_cursor.hdr.interfaces-1)*sizeof(struct AddrPort));
+ he_cursor.hcps = (void *)p;
+ } else {
+ he_cursor.hcps = he_cursor.ifp;
+ }
+ return 0;
+}
+
+static int
+get_fe(afs_uint32 idx)
+{
+ int i;
+ char * p;
+
+ cb_cursor.cb_valid = 0;
+
+ if (get_cb_hdr())
+ return 1;
+
+ if (idx >= hdrs.cb_hdr.nFEs)
+ return 1;
+
+ if (fe_cursor.idx == idx && fe_cursor.hdr_valid && fe_cursor.fe_valid)
+ return 0;
+
+ fe_cursor.hdr_valid = fe_cursor.fe_valid = 0;
+
+ if (fe_cache.cursor == NULL) {
+ fe_cache.cursor = (void **) calloc(hdrs.cb_hdr.nFEs, sizeof(void *));
+ assert(fe_cache.cursor != NULL);
+ }
+
+ if (idx && fe_cache.cursor[idx-1] == NULL) {
+ for (i = 0; i < idx; i++) {
+ if (fe_cache.cursor[i] == NULL) {
+ get_fe(i);
+ }
+ }
+ }
+
+ if (!idx) {
+ fe_cursor.cursor = fe_cursor.ffe;
+ } else if (fe_cursor.cursor == fe_cache.cursor[idx-1]) {
+ p = (char *)fe_cursor.cursor;
+ p += fe_cursor.hdr.len;
+ fe_cursor.cursor = (void *)p;
+ } else {
+ fe_cursor.cursor = fe_cache.cursor[idx-1];
+ if (get_fe_hdr())
+ return 1;
+ p = (char *)fe_cursor.cursor;
+ p += fe_cursor.hdr.len;
+ fe_cursor.cursor = (void *)p;
+ }
+
+ fe_cursor.idx = idx;
+ fe_cache.cursor[idx] = fe_cursor.cursor;
+
+ if (get_fe_hdr())
+ return 1;
+ if (get_fe_entry())
+ return 1;
+
+ return 0;
+}
+
+static int
+get_fe_hdr(void)
+{
+ memcpy(&fe_cursor.hdr, fe_cursor.cursor, sizeof(struct callback_state_entry_header));
+ fe_cursor.hdr_valid = 1;
+ return 0;
+}
+
+static int
+get_fe_entry(void)
+{
+ char * p;
+
+ if (!fe_cursor.hdr_valid) {
+ if (get_fe_hdr()) {
+ return 1;
+ }
+ }
+
+ p = (char *) fe_cursor.cursor;
+ p += sizeof(struct callback_state_entry_header);
+
+ memcpy(&fe_cursor.fe, p, sizeof(struct FEDiskEntry));
+
+ fe_cursor.fe_valid = 1;
+ p += sizeof(struct FEDiskEntry);
+ fe_cursor.fcb = (void *)p;
+ return 0;
+}
+
+static int
+get_cb(afs_uint32 idx)
+{
+ int i;
+ char * p;
+
+ if (get_fe(fe_cursor.idx))
+ return 1;
+
+ if (idx >= fe_cursor.hdr.nCBs)
+ return 1;
+
+ if (idx == cb_cursor.idx && cb_cursor.cb_valid)
+ return 0;
+
+ cb_cursor.cb_valid = 0;
+
+ p = (char *)fe_cursor.fcb;
+ p += idx * sizeof(struct CBDiskEntry);
+ cb_cursor.cursor = (void *)p;
+
+ cb_cursor.idx = idx;
+
+ if (get_cb_entry())
+ return 1;
+
+ return 0;
+}
+
+static int
+get_cb_entry(void)
+{
+ memcpy(&cb_cursor.cb, cb_cursor.cursor, sizeof(struct CBDiskEntry));
+ cb_cursor.cb_valid = 1;
+ return 0;
+}
+
+static int
+find_he_by_index(afs_uint32 idx)
+{
+ int i;
+
+ if (get_h_hdr()) {
+ return 1;
+ }
+
+ for (i = 0; i < hdrs.h_hdr.records; i++) {
+ if (get_he(i)) {
+ fprintf(stderr, "error getting he %d\n", i);
+ return 1;
+ }
+ if (he_cursor.he.index == idx)
+ break;
+ }
+
+ if (i < hdrs.h_hdr.records) {
+ dump_this_he();
+ return 0;
+ }
+ return 1;
+}
+
+static int
+find_fe_by_index(afs_uint32 idx)
+{
+ int i;
+
+ if (get_cb_hdr()) {
+ return 1;
+ }
+
+ for (i = 0; i < hdrs.cb_hdr.nFEs; i++) {
+ if (get_fe(i)) {
+ fprintf(stderr, "error getting fe %d\n", i);
+ return 1;
+ }
+ if (fe_cursor.fe.index == idx)
+ break;
+ }
+
+ if (i < hdrs.cb_hdr.nFEs) {
+ dump_this_fe();
+ return 0;
+ }
+ return 1;
+}
+
+static int
+find_fe_by_fid(afs_uint32 volid, afs_uint32 vnode, afs_uint32 unique)
+{
+ int i;
+
+ if (get_cb_hdr()) {
+ return 1;
+ }
+
+ for (i = 0; i < hdrs.cb_hdr.nFEs; i++) {
+ if (get_fe(i)) {
+ fprintf(stderr, "error getting fe %d\n", i);
+ return 1;
+ }
+ if ((fe_cursor.fe.fe.unique == unique) &&
+ (fe_cursor.fe.fe.volid == volid) &&
+ (fe_cursor.fe.fe.vnode == vnode))
+ break;
+ }
+
+ if (i < hdrs.cb_hdr.nFEs) {
+ dump_this_fe();
+ return 0;
+ }
+ return 1;
+}
+
+static int
+find_cb_by_index(afs_uint32 idx)
+{
+ int i;
+
+ if (get_fe_hdr()) {
+ return 1;
+ }
+
+ for (i = 0; i < fe_cursor.hdr.nCBs; i++) {
+ if (get_cb(i)) {
+ fprintf(stderr, "error getting cb %d\n", i);
+ return 1;
+ }
+ if (cb_cursor.cb.index == idx)
+ break;
+ }
+
+ if (i < fe_cursor.hdr.nCBs) {
+ dump_this_cb();
+ return 0;
+ }
+ return 1;
+}
+
+#endif /* AFS_DEMAND_ATTACH_FS */
HELPER_SPLINT=@HELPER_SPLINT@
CC=${MT_CC}
-CFLAGS=${COMMON_CFLAGS} -I.. -DNINTERFACE ${MT_CFLAGS} -DRXDEBUG
+CFLAGS=${COMMON_CFLAGS} -I.. -DNINTERFACE ${MT_CFLAGS} -DRXDEBUG -DFSSYNC_BUILD_CLIENT
CCRULE=${CC} ${CFLAGS} -c $?
DIROBJS=buffer.o dir.o salvage.o
-VOLOBJS= vnode.o volume.o vutil.o partition.o fssync.o purge.o \
- clone.o devname.o common.o ihandle.o listinodes.o namei_ops.o nuke.o
+VOLOBJS= vnode.o volume.o vutil.o partition.o fssync-client.o purge.o \
+ clone.o devname.o common.o ihandle.o listinodes.o \
+ namei_ops.o nuke.o salvsync-client.o daemon_com.o
FSINTOBJS=# afsaux.o afscbint.cs.o afsint.ss.o afsint.xdr.o
nuke.o: ${VOL}/nuke.c
${COMPILE}
-fssync.o: ${VOL}/fssync.c
+fssync-client.o: ${VOL}/fssync-client.c
+ ${COMPILE}
+
+salvsync-client.o: ${VOL}/salvsync-client.c
+ ${COMPILE}
+
+daemon_com.o: ${VOL}/daemon_com.c
${COMPILE}
purge.o: ${VOL}/purge.c
objects = assert.o base64.o casestrcpy.o ktime.o volparse.o hostparse.o \
hputil.o kreltime.o isathing.o get_krbrlm.o uuid.o serverLog.o \
dirpath.o fileutil.o netutils.o flipbase64.o fstab.o \
- afs_atomlist.o afs_lhash.o snprintf.o strlcat.o strlcpy.o \
+ afs_atomlist.o afs_lhash.o snprintf.o strlcat.o strlcpy.o strnlen.o \
daemon.o rxkstats.o ${REGEX_OBJ}
includes = \
strlcpy.o: ${srcdir}/strlcpy.c ${includes}
${CCOBJ} ${CFLAGS} -c ${srcdir}/strlcpy.c
+strnlen.o: ${srcdir}/strnlen.c ${includes}
+ ${CCOBJ} ${CFLAGS} -c ${srcdir}/strnlen.c
+
daemon.o: ${srcdir}/daemon.c ${includes}
${CCOBJ} ${CFLAGS} -c ${srcdir}/daemon.c
extern size_t strlcat(char *dst, const char *src, size_t siz);
#endif
+/* strn */
+extern size_t afs_strnlen(char * buf, size_t len);
+
/* sys.c */
extern void afs_ntohuuid(afsUUID * uuidp);
extern afs_int32 afs_uuid_create(afsUUID * uuid);
extern u_short afs_uuid_hash(afsUUID * uuid);
+#if !defined(KERNEL) && !defined(UKERNEL)
+extern int afsUUID_from_string(const char *str, afsUUID * uuid);
+extern int afsUUID_to_string(const afsUUID * uuid, char *str, size_t strsz);
+#endif
/* volparse.c */
extern afs_int32 volutil_GetPartitionID(char *aname);
pathp = dirPathArray[AFSDIR_SERVER_SLVGLOG_FILEPATH_ID];
AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_SLVGLOG_FILE);
+ pathp = dirPathArray[AFSDIR_SERVER_SALSRVLOG_FILEPATH_ID];
+ AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_SALSRVLOG_FILE);
+
pathp = dirPathArray[AFSDIR_SERVER_SALVAGER_FILEPATH_ID];
AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_BIN_DIR,
AFSDIR_SALVAGER_FILE);
+ pathp = dirPathArray[AFSDIR_SERVER_SALSRV_FILEPATH_ID];
+ AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_BIN_DIR,
+ AFSDIR_SALSRV_FILE);
+
pathp = dirPathArray[AFSDIR_SERVER_SLVGLOCK_FILEPATH_ID];
AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_SLVGLOCK_FILE);
pathp = dirPathArray[AFSDIR_SERVER_KRB_EXCL_FILEPATH_ID];
AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR, AFSDIR_KRB_EXCL_FILE);
+ pathp = dirPathArray[AFSDIR_SERVER_FSSTATE_FILEPATH_ID];
+ AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_FSSTATE_FILE);
+
/* client file paths */
#ifdef AFS_NT40_ENV
strcpy(dirPathArray[AFSDIR_CLIENT_THISCELL_FILEPATH_ID],
#define AFSDIR_VLOG_FILE "VLLog"
#define AFSDIR_CORE_FILE "core"
#define AFSDIR_SLVGLOG_FILE "SalvageLog"
+#define AFSDIR_SALSRVLOG_FILE "SalsrvLog"
#define AFSDIR_SALVAGER_FILE "salvager"
+#define AFSDIR_SALSRV_FILE "salvageserver"
#define AFSDIR_SLVGLOCK_FILE "salvage.lock"
#define AFSDIR_BOZCONF_FILE "BosConfig"
#define AFSDIR_BOZCONFNEW_FILE "BosConfig.new"
#define AFSDIR_FILELOG_FILE "FileLog"
#define AFSDIR_MIGRATE_LOGNAME "wtlog."
+#define AFSDIR_FSSTATE_FILE "fsstate.dat"
+
#define AFSDIR_CELLSERVDB_FILE_NTCLIENT "afsdcell.ini"
#define AFSDIR_NETINFO_FILE "NetInfo"
#define AFSDIR_CANONICAL_SERVER_SALVAGER_FILEPATH \
AFSDIR_CANONICAL_SERVER_BIN_DIRPATH "/" AFSDIR_SALVAGER_FILE
+#define AFSDIR_CANONICAL_SERVER_SALSRV_FILEPATH \
+AFSDIR_CANONICAL_SERVER_BIN_DIRPATH "/" AFSDIR_SALSRV_FILE
+
#define AFSDIR_CANONICAL_SERVER_SLVGLOG_FILEPATH \
AFSDIR_CANONICAL_SERVER_LOGS_DIRPATH "/" AFSDIR_SLVGLOG_FILE
+#define AFSDIR_CANONICAL_SERVER_SALSRVLOG_FILEPATH \
+AFSDIR_CANONICAL_SERVER_LOGS_DIRPATH "/" AFSDIR_SALSRVLOG_FILE
+
/* --------------------- Local path macros ---------------------- */
AFSDIR_SERVER_BIN_FILE_DIRPATH_ID,
AFSDIR_CLIENT_CELLALIAS_FILEPATH_ID,
AFSDIR_SERVER_KRB_EXCL_FILEPATH_ID,
+ AFSDIR_SERVER_SALSRV_FILEPATH_ID,
+ AFSDIR_SERVER_SALSRVLOG_FILEPATH_ID,
+ AFSDIR_SERVER_FSSTATE_FILEPATH_ID,
AFSDIR_PATHSTRING_MAX } afsdir_id_t;
/* getDirPath() returns a pointer to a string from an internal array of path strings
#define AFSDIR_SERVER_VLOG_FILEPATH getDirPath(AFSDIR_SERVER_VLOG_FILEPATH_ID)
#define AFSDIR_SERVER_CORELOG_FILEPATH getDirPath(AFSDIR_SERVER_CORELOG_FILEPATH_ID)
#define AFSDIR_SERVER_SLVGLOG_FILEPATH getDirPath(AFSDIR_SERVER_SLVGLOG_FILEPATH_ID)
+#define AFSDIR_SERVER_SALSRVLOG_FILEPATH getDirPath(AFSDIR_SERVER_SALSRVLOG_FILEPATH_ID)
#define AFSDIR_SERVER_SALVAGER_FILEPATH getDirPath(AFSDIR_SERVER_SALVAGER_FILEPATH_ID)
+#define AFSDIR_SERVER_SALSRV_FILEPATH getDirPath(AFSDIR_SERVER_SALSRV_FILEPATH_ID)
#define AFSDIR_SERVER_BOZCONF_FILEPATH getDirPath(AFSDIR_SERVER_BOZCONF_FILEPATH_ID)
#define AFSDIR_SERVER_BOZCONFNEW_FILEPATH getDirPath(AFSDIR_SERVER_BOZCONFNEW_FILEPATH_ID)
#define AFSDIR_SERVER_BOZINIT_FILEPATH getDirPath(AFSDIR_SERVER_BOZINIT_FILEPATH_ID)
#define AFSDIR_SERVER_THRESHOLD_CONSTANTS_FILEPATH getDirPath(AFSDIR_SERVER_THRESHOLD_CONSTANTS_FILEPATH_ID)
#define AFSDIR_SERVER_MIGRATELOG_FILEPATH getDirPath(AFSDIR_SERVER_MIGRATELOG_FILEPATH_ID)
#define AFSDIR_SERVER_KRB_EXCL_FILEPATH getDirPath(AFSDIR_SERVER_KRB_EXCL_FILEPATH_ID)
+#define AFSDIR_SERVER_FSSTATE_FILEPATH getDirPath(AFSDIR_SERVER_FSSTATE_FILEPATH_ID)
/* client file paths */
#define AFSDIR_CLIENT_THISCELL_FILEPATH getDirPath(AFSDIR_CLIENT_THISCELL_FILEPATH_ID)
#define AFSDIR_VLOG_FILE "VLLog"
#define AFSDIR_CORE_FILE "core"
#define AFSDIR_SLVGLOG_FILE "SalvageLog"
+#define AFSDIR_SALSRVLOG_FILE "SalsrvLog"
#define AFSDIR_SALVAGER_FILE "salvager"
+#define AFSDIR_SALSRV_FILE "salvageserver"
#define AFSDIR_SLVGLOCK_FILE "salvage.lock"
#define AFSDIR_BOZCONF_FILE "BosConfig"
#define AFSDIR_BOZCONFNEW_FILE "BosConfig.new"
#define AFSDIR_FILELOG_FILE "FileLog"
#define AFSDIR_MIGRATE_LOGNAME "wtlog."
+#define AFSDIR_FSSTATE_FILE "fsstate.dat"
+
#ifdef COMMENT
#define AFSDIR_CELLSERVDB_FILE_NTCLIENT "afsdcell.ini"
#else
#define AFSDIR_CANONICAL_SERVER_SALVAGER_FILEPATH \
AFSDIR_CANONICAL_SERVER_BIN_DIRPATH "/" AFSDIR_SALVAGER_FILE
+#define AFSDIR_CANONICAL_SERVER_SALSRV_FILEPATH \
+AFSDIR_CANONICAL_SERVER_BIN_DIRPATH "/" AFSDIR_SALSRV_FILE
+
#define AFSDIR_CANONICAL_SERVER_SLVGLOG_FILEPATH \
AFSDIR_CANONICAL_SERVER_LOGS_DIRPATH "/" AFSDIR_SLVGLOG_FILE
+#define AFSDIR_CANONICAL_SERVER_SALSRVLOG_FILEPATH \
+AFSDIR_CANONICAL_SERVER_LOGS_DIRPATH "/" AFSDIR_SALSRVLOG_FILE
+
/* --------------------- Local path macros ---------------------- */
AFSDIR_SERVER_BIN_FILE_DIRPATH_ID,
AFSDIR_CLIENT_CELLALIAS_FILEPATH_ID,
AFSDIR_SERVER_KRB_EXCL_FILEPATH_ID,
+ AFSDIR_SERVER_SALSRV_FILEPATH_ID,
+ AFSDIR_SERVER_SALSRVLOG_FILEPATH_ID,
+ AFSDIR_SERVER_FSSTATE_FILEPATH_ID,
AFSDIR_PATHSTRING_MAX
} afsdir_id_t;
#define AFSDIR_SERVER_VLOG_FILEPATH getDirPath(AFSDIR_SERVER_VLOG_FILEPATH_ID)
#define AFSDIR_SERVER_CORELOG_FILEPATH getDirPath(AFSDIR_SERVER_CORELOG_FILEPATH_ID)
#define AFSDIR_SERVER_SLVGLOG_FILEPATH getDirPath(AFSDIR_SERVER_SLVGLOG_FILEPATH_ID)
+#define AFSDIR_SERVER_SALSRVLOG_FILEPATH getDirPath(AFSDIR_SERVER_SALSRVLOG_FILEPATH_ID)
#define AFSDIR_SERVER_SALVAGER_FILEPATH getDirPath(AFSDIR_SERVER_SALVAGER_FILEPATH_ID)
+#define AFSDIR_SERVER_SALSRV_FILEPATH getDirPath(AFSDIR_SERVER_SALSRV_FILEPATH_ID)
#define AFSDIR_SERVER_BOZCONF_FILEPATH getDirPath(AFSDIR_SERVER_BOZCONF_FILEPATH_ID)
#define AFSDIR_SERVER_BOZCONFNEW_FILEPATH getDirPath(AFSDIR_SERVER_BOZCONFNEW_FILEPATH_ID)
#define AFSDIR_SERVER_BOZINIT_FILEPATH getDirPath(AFSDIR_SERVER_BOZINIT_FILEPATH_ID)
#define AFSDIR_SERVER_THRESHOLD_CONSTANTS_FILEPATH getDirPath(AFSDIR_SERVER_THRESHOLD_CONSTANTS_FILEPATH_ID)
#define AFSDIR_SERVER_MIGRATELOG_FILEPATH getDirPath(AFSDIR_SERVER_MIGRATELOG_FILEPATH_ID)
#define AFSDIR_SERVER_KRB_EXCL_FILEPATH getDirPath(AFSDIR_SERVER_KRB_EXCL_FILEPATH_ID)
+#define AFSDIR_SERVER_FSSTATE_FILEPATH getDirPath(AFSDIR_SERVER_FSSTATE_FILEPATH_ID)
/* client file paths */
#define AFSDIR_CLIENT_THISCELL_FILEPATH getDirPath(AFSDIR_CLIENT_THISCELL_FILEPATH_ID)
* to THIS server to find out where */
#define VIO 112 /* Vnode temporarily unaccessible, but not known
* to be permanently bad. */
+#define VSALVAGING 113 /* Volume is being salvaged (demand attach fs) */
#define VRESTRICTED 120 /* Volume is restricted from using one or more
* of the given residencies; do a
* vos examine to find out the current
--- /dev/null
+/*
+ * Copyright 2006, Sine Nomine Associates and others.
+ * All Rights Reserved.
+ *
+ * This software has been released under the terms of the IBM Public
+ * License. For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+/* strnlen.c - fixed length string length */
+
+#include <afsconfig.h>
+#include <afs/param.h>
+
+RCSID
+ ("$Header$");
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+
+size_t
+afs_strnlen(char * buf, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (buf[i] == '\0')
+ break;
+ }
+
+ return i;
+}
+
${TOP_INCDIR}/afs/afsint.h \
viced.h \
host.h \
+ callback.h \
fs_stats.h
objects=viced.o \
# License. For details, see the LICENSE file in the top-level source
# directory or online at http://www.openafs.org/dl/license10.html
+AFSDEV_AUXCDEFINES = -DFSSYNC_BUILD_SERVER
+
RELDIR=viced
!INCLUDE ..\config\NTMakefile.$(SYS_NAME)
!INCLUDE ..\config\NTMakefile.version
#include "viced_prototypes.h"
#include "viced.h"
#include "host.h"
+#include "callback.h"
#include <afs/unified_afs.h>
#include <afs/audit.h>
#include <afs/afsutil.h>
/*
* Externals used by the xstat code.
*/
-extern int VolumeCacheSize, VolumeGets, VolumeReplacements;
+extern VolPkgStats VStats;
extern int CEs, CEBlocks;
extern int HTs, HTBlocks;
CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
{
int fileCode = 0;
- int errorCode = -1;
+ afs_int32 local_errorCode, errorCode = -1;
static struct timeval restartedat = { 0, 0 };
if (fid->Volume == 0 || fid->Vnode == 0) /* not: || fid->Unique == 0) */
while (1) {
errorCode = 0;
- *volptr = VGetVolume(&errorCode, (afs_int32) fid->Volume);
+ *volptr = VGetVolume(&local_errorCode, &errorCode, (afs_int32) fid->Volume);
if (!errorCode) {
assert(*volptr);
break;
}
}
}
- /* allow read operations on busy volume */
- else if (errorCode == VBUSY && lock == READ_LOCK) {
+ /* allow read operations on busy volume.
+ * must check local_errorCode because demand attach fs
+ * can have local_errorCode == VSALVAGING, errorCode == VBUSY */
+ else if (local_errorCode == VBUSY && lock == READ_LOCK) {
errorCode = 0;
break;
} else if (errorCode)
wrlen, errno));
#ifdef FAST_RESTART /* if running in no-salvage, don't core the server */
ViceLog(0, ("CopyOnWrite failed: taking volume offline\n"));
+#elif defined(AFS_DEMAND_ATTACH_FS)
+ ViceLog(0, ("CopyOnWrite failed: requesting salvage\n"));
#else /* Avoid further corruption and try to get a core. */
assert(0);
#endif
static void
FillPerfValues(struct afs_PerfStats *a_perfP)
{ /*FillPerfValues */
-
+ afs_uint32 hi, lo;
int dir_Buffers; /*# buffers in use by dir package */
int dir_Calls; /*# read calls in dir package */
int dir_IOs; /*# I/O ops in dir package */
a_perfP->vcache_S_Gets = VnodeClassInfo[vSmall].gets;
a_perfP->vcache_S_Reads = VnodeClassInfo[vSmall].reads;
a_perfP->vcache_S_Writes = VnodeClassInfo[vSmall].writes;
- a_perfP->vcache_H_Entries = VolumeCacheSize;
- a_perfP->vcache_H_Gets = VolumeGets;
- a_perfP->vcache_H_Replacements = VolumeReplacements;
+ a_perfP->vcache_H_Entries = VStats.hdr_cache_size;
+ SplitInt64(VStats.hdr_gets, hi, lo);
+ a_perfP->vcache_H_Gets = lo;
+ SplitInt64(VStats.hdr_loads, hi, lo);
+ a_perfP->vcache_H_Replacements = lo;
/*
* Directory section.
* This software has been released under the terms of the IBM Public
* License. For details, see the LICENSE file in the top-level source
* directory or online at http://www.openafs.org/dl/license10.html
+ *
+ * Portions Copyright (c) 2006 Sine Nomine Associates
*/
/*
#include <afs/ptclient.h> /* need definition of prlist for host.h */
#include "host.h"
+#include "callback.h"
+#ifdef AFS_DEMAND_ATTACH_FS
+#include "../tviced/serialize_state.h"
+#endif /* AFS_DEMAND_ATTACH_FS */
+
extern afsUUID FS_HostUUID;
extern int hostCount;
-int ShowProblems = 1;
-
-/* Maximum number of call backs to break at once, single fid */
-/* There is some debate as to just how large this value should be */
-/* Ideally, it would be very very large, but I am afraid that the */
-/* cache managers will all send in their responses simultaneously, */
-/* thereby swamping the file server. As a result, something like */
-/* 10 or 15 might be a better bet. */
-#define MAX_CB_HOSTS 10
-
-/* max time to break a callback, otherwise client is dead or net is hosed */
-#define MAXCBT 25
-
-#define u_byte unsigned char
+static int ShowProblems = 1;
struct cbcounters cbstuff;
-struct cbstruct {
- struct host *hp;
- afs_uint32 thead;
-};
-
-struct FileEntry {
- afs_uint32 vnode;
- afs_uint32 unique;
- afs_uint32 volid;
- afs_uint32 fnext;
- afs_uint32 ncbs;
- afs_uint32 firstcb;
- afs_uint32 status;
- afs_uint32 spare;
-} *FE; /* Don't use FE[0] */
-#define FE_LATER 0x1
-
-struct CallBack {
- afs_uint32 cnext; /* Next call back entry */
- afs_uint32 fhead; /* Head of this call back chain */
- u_byte thead; /* Head of timeout chain */
- u_byte status; /* Call back status; see definitions, below */
- afs_uint32 hhead; /* Head of host table chain */
- afs_uint32 tprev, tnext; /* Timeout chain */
- afs_uint32 hprev, hnext; /* Chain from host table */
- unsigned short spare; /* make it a multiple of 32 bits. */
-} *CB; /* Don't use CB[0] */
-
-/* status values for status field of CallBack structure */
-#define CB_NORMAL 1 /* Normal call back */
-#define CB_DELAYED 2 /* Delayed call back due to rpc problems.
- * The call back entry will be added back to the
- * host list at the END of the list, so that
- * searching backwards in the list will find all
- * the (consecutive)host. delayed call back entries */
-#define CB_VOLUME 3 /* Callback for a volume */
-#define CB_BULK 4 /* Normal callbacks, handed out from FetchBulkStatus */
-
-/* call back indices to pointers, and vice-versa */
-#define itocb(i) ((i)?CB+(i):0)
-#define cbtoi(cbp) (!(cbp)?0:(cbp)-CB)
-
-/* file entry indices to pointers, and vice-versa */
-#define itofe(i) ((i)?FE+(i):0)
-#define fetoi(fep) (!(fep)?0:(fep)-FE)
-
-/* Timeouts: there are 128 possible timeout values in effect at any
- * given time. Each timeout represents timeouts in an interval of 128
- * seconds. So the maximum timeout for a call back is 128*128=16384
- * seconds, or 4 1/2 hours. The timeout cleanup stuff is called only
- * if space runs out or by the file server every 5 minutes. This 5
- * minute slack should be allowed for--so a maximum time of 4 hours
- * is safer.
- *
- * Timeouts must be chosen to correspond to an exact multiple
- * of 128, because all times are truncated to a 128 multiple, and
- * timed out if the current truncated time is <= to the truncated time
- * corresponding to the timeout queue.
- */
+static struct FileEntry * FE = NULL; /* don't use FE[0] */
+static struct CallBack * CB = NULL; /* don't use CB[0] */
-/* Unix time to Call Back time, and vice-versa. Call back time is
- in units of 128 seconds, corresponding to time queues. */
-#define CBtime(uxtime) ((uxtime)>>7)
-#define UXtime(cbtime) ((cbtime)<<7)
+static struct CallBack * CBfree = NULL;
+static struct FileEntry * FEfree = NULL;
-/* Given a Unix time, compute the closest Unix time that corresponds to
- a time queue, rounding up */
-#define TimeCeiling(uxtime) (((uxtime)+127)&~127)
/* Time to live for call backs depends upon number of users of the file.
* TimeOuts is indexed by this number/8 (using TimeOut macro). Times
/* minimum time given for a call back */
static int MinTimeOut = (7 * 60);
-#define TimeOutCutoff ((sizeof(TimeOuts)/sizeof(TimeOuts[0]))*8)
-#define TimeOut(nusers) ((nusers)>=TimeOutCutoff? MinTimeOut: TimeOuts[(nusers)>>3])
-
-/* time out at server is 3 minutes more than ws */
-#define ServerBias (3*60)
-
/* Heads of CB queues; a timeout index is 1+index into this array */
-static afs_uint32 timeout[128];
-
-/* Convert cbtime to timeout queue index */
-#define TIndex(cbtime) (((cbtime)&127)+1)
-
-/* Convert cbtime to pointer to timeout queue head */
-#define THead(cbtime) (&timeout[TIndex(cbtime)-1])
+static afs_uint32 timeout[CB_NUM_TIMEOUT_QUEUES];
static afs_int32 tfirst; /* cbtime of oldest unexpired call back time queue */
-/* Normalize index into timeout array so that two such indices will be
- ordered correctly, so that they can be compared to see which times
- sooner, or so that the difference in time out times between them
- can be computed. */
-#define TNorm(index) ((index)<TIndex(tfirst)?(index)+128:(index))
-
-/* This converts a timeout index into the actual time it will expire */
-#define TIndexToTime(index) (UXtime(TNorm(index) - TIndex(tfirst) + tfirst))
-
-
-/* Convert pointer to timeout queue head to index, and vice versa */
-#define ttoi(t) ((t-timeout)+1)
-#define itot(i) ((timeout)+(i-1))
/* 16 byte object get/free routines */
struct object {
struct object *next;
};
-struct VCBParams {
- struct cbstruct cba[MAX_CB_HOSTS]; /* re-entrant storage */
- unsigned int ncbas;
- afs_uint32 thead; /* head of timeout queue for youngest callback */
- struct AFSFid *fid;
-};
-
-struct CallBack *CBfree = 0;
-struct FileEntry *FEfree = 0;
-
/* Prototypes for static routines */
static struct FileEntry *FindFE(register AFSFid * fid);
static struct CallBack *iGetCB(register int *nused);
#define FreeCB(cb) iFreeCB((struct CallBack *)cb, &cbstuff.nCBs)
#define FreeFE(fe) iFreeFE((struct FileEntry *)fe, &cbstuff.nFEs)
+
/* Other protos - move out sometime */
void PrintCB(register struct CallBack *cb, afs_uint32 now);
-#define VHASH 512 /* Power of 2 */
-static afs_uint32 HashTable[VHASH]; /* File entry hash table */
-#define VHash(volume, unique) (((volume)+(unique))&(VHASH-1))
+static afs_uint32 HashTable[FEHASH_SIZE]; /* File entry hash table */
static struct FileEntry *
FindFE(register AFSFid * fid)
register int fei;
register struct FileEntry *fe;
- hash = VHash(fid->Volume, fid->Unique);
+ hash = FEHash(fid->Volume, fid->Unique);
for (fei = HashTable[hash]; fei; fei = fe->fnext) {
fe = itofe(fei);
if (fe->volid == fid->Volume && fe->unique == fid->Unique
if (!host->cblist) {
host->cblist = cb->hnext = cb->hprev = cbtoi(cb);
} else {
- register struct CallBack *hhp = itocb(host->cblist);
+ register struct CallBack *fcb = itocb(host->cblist);
- cb->hprev = hhp->hprev;
- cb->hnext = host->cblist;
- hhp->hprev = (itocb(hhp->hprev)->hnext = cbtoi(cb));
+ cb->hprev = fcb->hprev;
+ cb->hnext = cbtoi(fcb);
+ fcb->hprev = (itocb(fcb->hprev)->hnext = cbtoi(cb));
}
return 0;
}
/* N.B. This one also deletes the CB, and also possibly parent FE, so
* make sure that it is not on any other list before calling this
* routine */
-int Ccdelpt = 0, CcdelB = 0;
+static int Ccdelpt = 0, CcdelB = 0;
static int
CDelPtr(register struct FileEntry *fe, register afs_uint32 * cbp,
FDel(register struct FileEntry *fe)
{
register int fei = fetoi(fe);
- register afs_uint32 *p = &HashTable[VHash(fe->volid, fe->unique)];
+ register afs_uint32 *p = &HashTable[FEHash(fe->volid, fe->unique)];
while (*p && *p != fei)
p = &itofe(*p)->fnext;
return 0;
}
+/* initialize the callback package */
int
InitCallBack(int nblks)
{
tfirst = CBtime(FT_ApproxTime());
/* N.B. The "-1", below, is because
* FE[0] and CB[0] are not used--and not allocated */
- FE = ((struct FileEntry *)(calloc(nblks, sizeof(struct FileEntry)))) - 1;
+ FE = ((struct FileEntry *)(calloc(nblks, sizeof(struct FileEntry))));
if (!FE) {
ViceLog(0, ("Failed malloc in InitCallBack\n"));
assert(0);
}
+ FE--; /* FE[0] is supposed to point to junk */
cbstuff.nFEs = nblks;
while (cbstuff.nFEs)
FreeFE(&FE[cbstuff.nFEs]); /* This is correct */
- CB = ((struct CallBack *)(calloc(nblks, sizeof(struct CallBack)))) - 1;
+ CB = ((struct CallBack *)(calloc(nblks, sizeof(struct CallBack))));
if (!CB) {
ViceLog(0, ("Failed malloc in InitCallBack\n"));
assert(0);
}
+ CB--; /* CB[0] is supposed to point to junk */
cbstuff.nCBs = nblks;
while (cbstuff.nCBs)
FreeCB(&CB[cbstuff.nCBs]); /* This is correct */
fe->unique = fid->Unique;
fe->ncbs = 0;
fe->status = 0;
- hash = VHash(fid->Volume, fid->Unique);
+ hash = FEHash(fid->Volume, fid->Unique);
fe->fnext = HashTable[hash];
HashTable[hash] = fetoi(fe);
}
H_LOCK;
fid.Volume = volume, fid.Vnode = fid.Unique = 0;
- for (hash = 0; hash < VHASH; hash++) {
+ for (hash = 0; hash < FEHASH_SIZE; hash++) {
for (feip = &HashTable[hash]; (fe = itofe(*feip));) {
if (fe->volid == volume) {
register struct CallBack *cbnext;
BreakVolumeCallBacksLater(afs_uint32 volume)
{
int hash;
- afs_int32 *feip;
+ afs_uint32 *feip;
struct FileEntry *fe;
struct CallBack *cb;
struct host *host;
ViceLog(25, ("Setting later on volume %u\n", volume));
H_LOCK;
- for (hash = 0; hash < VHASH; hash++) {
+ for (hash = 0; hash < FEHASH_SIZE; hash++) {
for (feip = &HashTable[hash]; (fe = itofe(*feip)) != NULL; ) {
if (fe->volid == volume) {
register struct CallBack *cbnext;
FSYNC_LOCK;
fe->status |= FE_LATER;
FSYNC_UNLOCK;
- found++;
+ found = 1;
}
feip = &fe->fnext;
}
{
struct AFSFid fid;
int hash;
- afs_int32 *feip;
+ afs_uint32 *feip;
struct CallBack *cb;
struct FileEntry *fe = NULL;
struct FileEntry *myfe = NULL;
/* Pick the first volume we see to clean up */
fid.Volume = fid.Vnode = fid.Unique = 0;
- for (hash = 0; hash < VHASH; hash++) {
+ for (hash = 0; hash < FEHASH_SIZE; hash++) {
for (feip = &HashTable[hash]; (fe = itofe(*feip)) != NULL; ) {
if (fe && (fe->status & FE_LATER)
&& (fid.Volume == 0 || fid.Volume == fe->volid)) {
#ifndef INTERPRET_DUMP
+#ifdef AFS_DEMAND_ATTACH_FS
+/*
+ * demand attach fs
+ * callback state serialization
+ */
+static int cb_stateSaveTimeouts(struct fs_dump_state * state);
+static int cb_stateSaveFEHash(struct fs_dump_state * state);
+static int cb_stateSaveFEs(struct fs_dump_state * state);
+static int cb_stateSaveFE(struct fs_dump_state * state, struct FileEntry * fe);
+static int cb_stateRestoreTimeouts(struct fs_dump_state * state);
+static int cb_stateRestoreFEHash(struct fs_dump_state * state);
+static int cb_stateRestoreFEs(struct fs_dump_state * state);
+static int cb_stateRestoreFE(struct fs_dump_state * state);
+static int cb_stateRestoreCBs(struct fs_dump_state * state, struct FileEntry * fe,
+ struct iovec * iov, int niovecs);
+
+static int cb_stateVerifyFEHash(struct fs_dump_state * state);
+static int cb_stateVerifyFE(struct fs_dump_state * state, struct FileEntry * fe);
+static int cb_stateVerifyFCBList(struct fs_dump_state * state, struct FileEntry * fe);
+static int cb_stateVerifyTimeoutQueues(struct fs_dump_state * state);
+
+static int cb_stateFEToDiskEntry(struct FileEntry *, struct FEDiskEntry *);
+static int cb_stateDiskEntryToFE(struct fs_dump_state * state,
+ struct FEDiskEntry *, struct FileEntry *);
+
+static int cb_stateCBToDiskEntry(struct CallBack *, struct CBDiskEntry *);
+static int cb_stateDiskEntryToCB(struct fs_dump_state * state,
+ struct CBDiskEntry *, struct CallBack *);
+
+static int cb_stateFillHeader(struct callback_state_header * hdr);
+static int cb_stateCheckHeader(struct callback_state_header * hdr);
+
+static int cb_stateAllocMap(struct fs_dump_state * state);
+
+int
+cb_stateSave(struct fs_dump_state * state)
+{
+ int ret = 0;
+
+ AssignInt64(state->eof_offset, &state->hdr->cb_offset);
+
+ /* invalidate callback state header */
+ memset(state->cb_hdr, 0, sizeof(struct callback_state_header));
+ if (fs_stateWriteHeader(state, &state->hdr->cb_offset, state->cb_hdr,
+ sizeof(struct callback_state_header))) {
+ ret = 1;
+ goto done;
+ }
+
+ fs_stateIncEOF(state, sizeof(struct callback_state_header));
+
+ /* dump timeout state */
+ if (cb_stateSaveTimeouts(state)) {
+ ret = 1;
+ goto done;
+ }
+
+ /* dump fe hashtable state */
+ if (cb_stateSaveFEHash(state)) {
+ ret = 1;
+ goto done;
+ }
+
+ /* dump callback state */
+ if (cb_stateSaveFEs(state)) {
+ ret = 1;
+ goto done;
+ }
+
+ /* write the callback state header to disk */
+ cb_stateFillHeader(state->cb_hdr);
+ if (fs_stateWriteHeader(state, &state->hdr->cb_offset, state->cb_hdr,
+ sizeof(struct callback_state_header))) {
+ ret = 1;
+ goto done;
+ }
+
+ done:
+ return ret;
+}
+
+int
+cb_stateRestore(struct fs_dump_state * state)
+{
+ int ret = 0;
+
+ if (fs_stateReadHeader(state, &state->hdr->cb_offset, state->cb_hdr,
+ sizeof(struct callback_state_header))) {
+ ret = 1;
+ goto done;
+ }
+
+ if (cb_stateCheckHeader(state->cb_hdr)) {
+ ret = 1;
+ goto done;
+ }
+
+ if (cb_stateAllocMap(state)) {
+ ret = 1;
+ goto done;
+ }
+
+ if (cb_stateRestoreTimeouts(state)) {
+ ret = 1;
+ goto done;
+ }
+
+ if (cb_stateRestoreFEHash(state)) {
+ ret = 1;
+ goto done;
+ }
+
+ /* restore FEs and CBs from disk */
+ if (cb_stateRestoreFEs(state)) {
+ ret = 1;
+ goto done;
+ }
+
+ /* restore the timeout queue heads */
+ tfirst = state->cb_hdr->tfirst;
+
+ done:
+ return ret;
+}
+
+int
+cb_stateRestoreIndices(struct fs_dump_state * state)
+{
+ int i, ret = 0;
+ struct FileEntry * fe;
+ struct CallBack * cb;
+
+ /* restore indices in the FileEntry structures */
+ for (i = 1; i < state->fe_map.len; i++) {
+ if (state->fe_map.entries[i].new_idx) {
+ fe = itofe(state->fe_map.entries[i].new_idx);
+
+ /* restore the fe->fnext entry */
+ if (fe_OldToNew(state, fe->fnext, &fe->fnext)) {
+ ret = 1;
+ goto done;
+ }
+
+ /* restore the fe->firstcb entry */
+ if (cb_OldToNew(state, fe->firstcb, &fe->firstcb)) {
+ ret = 1;
+ goto done;
+ }
+ }
+ }
+
+ /* restore indices in the CallBack structures */
+ for (i = 1; i < state->cb_map.len; i++) {
+ if (state->cb_map.entries[i].new_idx) {
+ cb = itocb(state->cb_map.entries[i].new_idx);
+
+ /* restore the cb->cnext entry */
+ if (cb_OldToNew(state, cb->cnext, &cb->cnext)) {
+ ret = 1;
+ goto done;
+ }
+
+ /* restore the cb->fhead entry */
+ if (fe_OldToNew(state, cb->fhead, &cb->fhead)) {
+ ret = 1;
+ goto done;
+ }
+
+ /* restore the cb->hhead entry */
+ if (h_OldToNew(state, cb->hhead, &cb->hhead)) {
+ ret = 1;
+ goto done;
+ }
+
+ /* restore the cb->tprev entry */
+ if (cb_OldToNew(state, cb->tprev, &cb->tprev)) {
+ ret = 1;
+ goto done;
+ }
+
+ /* restore the cb->tnext entry */
+ if (cb_OldToNew(state, cb->tnext, &cb->tnext)) {
+ ret = 1;
+ goto done;
+ }
+
+ /* restore the cb->hprev entry */
+ if (cb_OldToNew(state, cb->hprev, &cb->hprev)) {
+ ret = 1;
+ goto done;
+ }
+
+ /* restore the cb->hnext entry */
+ if (cb_OldToNew(state, cb->hnext, &cb->hnext)) {
+ ret = 1;
+ goto done;
+ }
+ }
+ }
+
+ /* restore the timeout queue head indices */
+ for (i = 0; i < state->cb_timeout_hdr->records; i++) {
+ if (cb_OldToNew(state, timeout[i], &timeout[i])) {
+ ret = 1;
+ goto done;
+ }
+ }
+
+ /* restore the FE hash table queue heads */
+ for (i = 0; i < state->cb_fehash_hdr->records; i++) {
+ if (fe_OldToNew(state, HashTable[i], &HashTable[i])) {
+ ret = 1;
+ goto done;
+ }
+ }
+
+ done:
+ return ret;
+}
+
+int
+cb_stateVerify(struct fs_dump_state * state)
+{
+ int ret = 0;
+
+ if (cb_stateVerifyFEHash(state)) {
+ ret = 1;
+ }
+
+ if (cb_stateVerifyTimeoutQueues(state)) {
+ ret = 1;
+ }
+
+ done:
+ return ret;
+}
+
+static int
+cb_stateVerifyFEHash(struct fs_dump_state * state)
+{
+ int ret = 0, i;
+ struct FileEntry * fe;
+ afs_uint32 fei, chain_len;
+
+ for (i = 0; i < FEHASH_SIZE; i++) {
+ chain_len = 0;
+ for (fei = HashTable[i], fe = itofe(fei);
+ fe;
+ fei = fe->fnext, fe = itofe(fei)) {
+ if (fei > cbstuff.nblks) {
+ ViceLog(0, ("cb_stateVerifyFEHash: error: index out of range (fei=%d)\n", fei));
+ ret = 1;
+ break;
+ }
+ if (cb_stateVerifyFE(state, fe)) {
+ ret = 1;
+ }
+ if (chain_len > FS_STATE_FE_MAX_HASH_CHAIN_LEN) {
+ ViceLog(0, ("cb_stateVerifyFEHash: error: hash chain %d length exceeds %d; assuming there's a loop\n",
+ i, FS_STATE_FE_MAX_HASH_CHAIN_LEN));
+ ret = 1;
+ break;
+ }
+ chain_len++;
+ }
+ }
+
+ done:
+ return ret;
+}
+
+static int
+cb_stateVerifyFE(struct fs_dump_state * state, struct FileEntry * fe)
+{
+ int ret = 0;
+
+ if ((fe->firstcb && !fe->ncbs) ||
+ (!fe->firstcb && fe->ncbs)) {
+ ViceLog(0, ("cb_stateVerifyFE: error: fe->firstcb does not agree with fe->ncbs (fei=%d, fe->firstcb=%d, fe->ncbs=%d)\n",
+ fetoi(fe), fe->firstcb, fe->ncbs));
+ ret = 1;
+ }
+ if (cb_stateVerifyFCBList(state, fe)) {
+ ViceLog(0, ("cb_stateVerifyFE: error: FCBList failed verification (fei=%d)\n", fetoi(fe)));
+ ret = 1;
+ }
+
+ done:
+ return ret;
+}
+
+static int
+cb_stateVerifyFCBList(struct fs_dump_state * state, struct FileEntry * fe)
+{
+ int ret = 0;
+ afs_uint32 cbi, fei, chain_len = 0;
+ struct CallBack * cb;
+
+ fei = fetoi(fe);
+
+ for (cbi = fe->firstcb, cb = itocb(cbi);
+ cb;
+ cbi = cb->cnext, cb = itocb(cbi)) {
+ if (cbi > cbstuff.nblks) {
+ ViceLog(0, ("cb_stateVerifyFCBList: error: list index out of range (cbi=%d, ncbs=%d)\n",
+ cbi, cbstuff.nblks));
+ ret = 1;
+ goto done;
+ }
+ if (cb->fhead != fei) {
+ ViceLog(0, ("cb_stateVerifyFCBList: error: cb->fhead != fei (fei=%d, cb->fhead=%d)\n",
+ fei, cb->fhead));
+ ret = 1;
+ }
+ if (chain_len > FS_STATE_FCB_MAX_LIST_LEN) {
+ ViceLog(0, ("cb_stateVerifyFCBList: error: list length exceeds %d (fei=%d); assuming there's a loop\n",
+ FS_STATE_FCB_MAX_LIST_LEN, fei));
+ ret = 1;
+ goto done;
+ }
+ chain_len++;
+ }
+
+ if (fe->ncbs != chain_len) {
+ ViceLog(0, ("cb_stateVerifyFCBList: error: list length mismatch (len=%d, fe->ncbs=%d)\n",
+ chain_len, fe->ncbs));
+ ret = 1;
+ }
+
+ done:
+ return ret;
+}
+
+int
+cb_stateVerifyHCBList(struct fs_dump_state * state, struct host * host)
+{
+ int ret = 0;
+ afs_uint32 hi, chain_len, cbi;
+ struct CallBack *cb, *ncb;
+
+ hi = h_htoi(host);
+ chain_len = 0;
+
+ for (cbi = host->cblist, cb = itocb(cbi);
+ cb;
+ cbi = cb->hnext, cb = ncb) {
+ if (chain_len && (host->cblist == cbi)) {
+ /* we've wrapped around the circular list, and everything looks ok */
+ break;
+ }
+ if (cb->hhead != hi) {
+ ViceLog(0, ("cb_stateVerifyHCBList: error: incorrect cb->hhead (cbi=%d, h->index=%d, cb->hhead=%d)\n",
+ cbi, hi, cb->hhead));
+ ret = 1;
+ }
+ if (!cb->hprev || !cb->hnext) {
+ ViceLog(0, ("cb_stateVerifyHCBList: error: null index in circular list (cbi=%d, h->index=%d)\n",
+ cbi, hi));
+ ret = 1;
+ goto done;
+ }
+ if ((cb->hprev > cbstuff.nblks) ||
+ (cb->hnext > cbstuff.nblks)) {
+ ViceLog(0, ("cb_stateVerifyHCBList: error: list index out of range (cbi=%d, h->index=%d, cb->hprev=%d, cb->hnext=%d, nCBs=%d)\n",
+ cbi, hi, cb->hprev, cb->hnext, cbstuff.nblks));
+ ret = 1;
+ goto done;
+ }
+ ncb = itocb(cb->hnext);
+ if (cbi != ncb->hprev) {
+ ViceLog(0, ("cb_stateVerifyHCBList: error: corrupt linked list (cbi=%d, h->index=%d)\n",
+ cbi, hi));
+ ret = 1;
+ goto done;
+ }
+ if (chain_len > FS_STATE_HCB_MAX_LIST_LEN) {
+ ViceLog(0, ("cb_stateVerifyFCBList: error: list length exceeds %d (h->index=%d); assuming there's a loop\n",
+ FS_STATE_HCB_MAX_LIST_LEN, hi));
+ ret = 1;
+ goto done;
+ }
+ chain_len++;
+ }
+
+ done:
+ return ret;
+}
+
+static int
+cb_stateVerifyTimeoutQueues(struct fs_dump_state * state)
+{
+ int ret = 0, i;
+ afs_uint32 cbi, chain_len;
+ struct CallBack *cb, *ncb;
+
+ for (i = 0; i < CB_NUM_TIMEOUT_QUEUES; i++) {
+ chain_len = 0;
+ for (cbi = timeout[i], cb = itocb(cbi);
+ cb;
+ cbi = cb->tnext, cb = ncb) {
+ if (chain_len && (cbi == timeout[i])) {
+ /* we've wrapped around the circular list, and everything looks ok */
+ break;
+ }
+ if (cbi > cbstuff.nblks) {
+ ViceLog(0, ("cb_stateVerifyTimeoutQueues: error: list index out of range (cbi=%d, tindex=%d)\n",
+ cbi, i));
+ ret = 1;
+ break;
+ }
+ if (itot(cb->thead) != &timeout[i]) {
+ ViceLog(0, ("cb_stateVerifyTimeoutQueues: error: cb->thead points to wrong timeout queue (tindex=%d, cbi=%d, cb->thead=%d)\n",
+ i, cbi, cb->thead));
+ ret = 1;
+ }
+ if (!cb->tprev || !cb->tnext) {
+ ViceLog(0, ("cb_stateVerifyTimeoutQueues: null index in circular list (cbi=%d, tindex=%d)\n",
+ cbi, i));
+ ret = 1;
+ break;
+ }
+ if ((cb->tprev > cbstuff.nblks) ||
+ (cb->tnext > cbstuff.nblks)) {
+ ViceLog(0, ("cb_stateVerifyTimeoutQueues: list index out of range (cbi=%d, tindex=%d, cb->tprev=%d, cb->tnext=%d, nCBs=%d)\n",
+ cbi, i, cb->tprev, cb->tnext, cbstuff.nblks));
+ ret = 1;
+ break;
+ }
+ ncb = itocb(cb->tnext);
+ if (cbi != ncb->tprev) {
+ ViceLog(0, ("cb_stateVerifyTimeoutQueues: corrupt linked list (cbi=%d, tindex=%d)\n",
+ cbi, i));
+ ret = 1;
+ break;
+ }
+ if (chain_len > FS_STATE_TCB_MAX_LIST_LEN) {
+ ViceLog(0, ("cb_stateVerifyTimeoutQueues: list length exceeds %d (tindex=%d); assuming there's a loop\n",
+ FS_STATE_TCB_MAX_LIST_LEN, i));
+ ret = 1;
+ break;
+ }
+ chain_len++;
+ }
+ }
+
+ done:
+ return ret;
+}
+
+static int
+cb_stateSaveTimeouts(struct fs_dump_state * state)
+{
+ int ret = 0;
+ struct iovec iov[2];
+
+ AssignInt64(state->eof_offset, &state->cb_hdr->timeout_offset);
+
+ memset(state->cb_timeout_hdr, 0, sizeof(struct callback_state_fehash_header));
+ state->cb_timeout_hdr->magic = CALLBACK_STATE_TIMEOUT_MAGIC;
+ state->cb_timeout_hdr->records = CB_NUM_TIMEOUT_QUEUES;
+ state->cb_timeout_hdr->len = sizeof(struct callback_state_timeout_header) +
+ (state->cb_timeout_hdr->records * sizeof(afs_uint32));
+
+ iov[0].iov_base = (char *)state->cb_timeout_hdr;
+ iov[0].iov_len = sizeof(struct callback_state_timeout_header);
+ iov[1].iov_base = (char *)timeout;
+ iov[1].iov_len = sizeof(timeout);
+
+ if (fs_stateSeek(state, &state->cb_hdr->timeout_offset)) {
+ ret = 1;
+ goto done;
+ }
+
+ if (fs_stateWriteV(state, iov, 2)) {
+ ret = 1;
+ goto done;
+ }
+
+ fs_stateIncEOF(state, state->cb_timeout_hdr->len);
+
+ done:
+ return ret;
+}
+
+static int
+cb_stateRestoreTimeouts(struct fs_dump_state * state)
+{
+ int ret = 0, len;
+
+ if (fs_stateReadHeader(state, &state->cb_hdr->timeout_offset,
+ state->cb_timeout_hdr,
+ sizeof(struct callback_state_timeout_header))) {
+ ret = 1;
+ goto done;
+ }
+
+ if (state->cb_timeout_hdr->magic != CALLBACK_STATE_TIMEOUT_MAGIC) {
+ ret = 1;
+ goto done;
+ }
+ if (state->cb_timeout_hdr->records != CB_NUM_TIMEOUT_QUEUES) {
+ ret = 1;
+ goto done;
+ }
+
+ len = state->cb_timeout_hdr->records * sizeof(afs_uint32);
+
+ if (state->cb_timeout_hdr->len !=
+ (sizeof(struct callback_state_timeout_header) + len)) {
+ ret = 1;
+ goto done;
+ }
+
+ if (fs_stateRead(state, timeout, len)) {
+ ret = 1;
+ goto done;
+ }
+
+ done:
+ return ret;
+}
+
+static int
+cb_stateSaveFEHash(struct fs_dump_state * state)
+{
+ int ret = 0;
+ struct iovec iov[2];
+
+ AssignInt64(state->eof_offset, &state->cb_hdr->fehash_offset);
+
+ memset(state->cb_fehash_hdr, 0, sizeof(struct callback_state_fehash_header));
+ state->cb_fehash_hdr->magic = CALLBACK_STATE_FEHASH_MAGIC;
+ state->cb_fehash_hdr->records = FEHASH_SIZE;
+ state->cb_fehash_hdr->len = sizeof(struct callback_state_fehash_header) +
+ (state->cb_fehash_hdr->records * sizeof(afs_uint32));
+
+ iov[0].iov_base = (char *)state->cb_fehash_hdr;
+ iov[0].iov_len = sizeof(struct callback_state_fehash_header);
+ iov[1].iov_base = (char *)HashTable;
+ iov[1].iov_len = sizeof(HashTable);
+
+ if (fs_stateSeek(state, &state->cb_hdr->fehash_offset)) {
+ ret = 1;
+ goto done;
+ }
+
+ if (fs_stateWriteV(state, iov, 2)) {
+ ret = 1;
+ goto done;
+ }
+
+ fs_stateIncEOF(state, state->cb_fehash_hdr->len);
+
+ done:
+ return ret;
+}
+
+static int
+cb_stateRestoreFEHash(struct fs_dump_state * state)
+{
+ int ret = 0, len;
+
+ if (fs_stateReadHeader(state, &state->cb_hdr->fehash_offset,
+ state->cb_fehash_hdr,
+ sizeof(struct callback_state_fehash_header))) {
+ ret = 1;
+ goto done;
+ }
+
+ if (state->cb_fehash_hdr->magic != CALLBACK_STATE_FEHASH_MAGIC) {
+ ret = 1;
+ goto done;
+ }
+ if (state->cb_fehash_hdr->records != FEHASH_SIZE) {
+ ret = 1;
+ goto done;
+ }
+
+ len = state->cb_fehash_hdr->records * sizeof(afs_uint32);
+
+ if (state->cb_fehash_hdr->len !=
+ (sizeof(struct callback_state_fehash_header) + len)) {
+ ret = 1;
+ goto done;
+ }
+
+ if (fs_stateRead(state, HashTable, len)) {
+ ret = 1;
+ goto done;
+ }
+
+ done:
+ return ret;
+}
+
+static int
+cb_stateSaveFEs(struct fs_dump_state * state)
+{
+ int ret = 0;
+ register int fei, hash;
+ register struct FileEntry *fe;
+
+ AssignInt64(state->eof_offset, &state->cb_hdr->fe_offset);
+
+ for (hash = 0; hash < FEHASH_SIZE ; hash++) {
+ for (fei = HashTable[hash]; fei; fei = fe->fnext) {
+ fe = itofe(fei);
+ if (cb_stateSaveFE(state, fe)) {
+ ret = 1;
+ goto done;
+ }
+ }
+ }
+
+ done:
+ return ret;
+}
+
+static int
+cb_stateRestoreFEs(struct fs_dump_state * state)
+{
+ int count, nFEs, ret = 0;
+
+ nFEs = state->cb_hdr->nFEs;
+
+ for (count = 0; count < nFEs; count++) {
+ if (cb_stateRestoreFE(state)) {
+ ret = 1;
+ goto done;
+ }
+ }
+
+ done:
+ return ret;
+}
+
+static int
+cb_stateSaveFE(struct fs_dump_state * state, struct FileEntry * fe)
+{
+ int ret = 0, iovcnt, cbi, idx, len, written = 0;
+ afs_uint32 fei;
+ struct callback_state_entry_header hdr;
+ struct FEDiskEntry fedsk;
+ struct CBDiskEntry cbdsk[16];
+ struct iovec iov[16];
+ struct CallBack *cb;
+
+ fei = fetoi(fe);
+ if (fei > state->cb_hdr->fe_max) {
+ state->cb_hdr->fe_max = fei;
+ }
+
+ memset(&hdr, 0, sizeof(struct callback_state_entry_header));
+
+ if (cb_stateFEToDiskEntry(fe, &fedsk)) {
+ ret = 1;
+ goto done;
+ }
+
+ iov[0].iov_base = (char *)&hdr;
+ len = iov[0].iov_len = sizeof(hdr);
+ iov[1].iov_base = (char *)&fedsk;
+ len += iov[1].iov_len = sizeof(struct FEDiskEntry);
+ iovcnt = 2;
+
+ for (cbi = fe->firstcb, cb = itocb(cbi), idx = 2;
+ cb != NULL;
+ cbi = cb->cnext, cb = itocb(cbi), idx++, hdr.nCBs++) {
+ if (cbi > state->cb_hdr->cb_max) {
+ state->cb_hdr->cb_max = cbi;
+ }
+ if (cb_stateCBToDiskEntry(cb, &cbdsk[idx])) {
+ ret = 1;
+ goto done;
+ }
+ cbdsk[idx].index = cbi;
+ iov[idx].iov_base = (char *)&cbdsk[idx];
+ len += iov[idx].iov_len = sizeof(struct CBDiskEntry);
+ iovcnt++;
+ if ((iovcnt == 16) || (!cb->cnext)) {
+ if (fs_stateWriteV(state, iov, iovcnt)) {
+ ret = 1;
+ goto done;
+ }
+ written = 1;
+ iovcnt = 0;
+ len = 0;
+ }
+ }
+
+ hdr.magic = CALLBACK_STATE_ENTRY_MAGIC;
+ hdr.len = sizeof(hdr) + sizeof(struct FEDiskEntry) +
+ (hdr.nCBs * sizeof(struct CBDiskEntry));
+
+ if (!written) {
+ if (fs_stateWriteV(state, iov, iovcnt)) {
+ ret = 1;
+ goto done;
+ }
+ } else {
+ if (fs_stateWriteHeader(state, &state->eof_offset, &hdr, sizeof(hdr))) {
+ ret = 1;
+ goto done;
+ }
+ }
+
+ fs_stateIncEOF(state, hdr.len);
+
+ if (written) {
+ if (fs_stateSeek(state, &state->eof_offset)) {
+ ret = 1;
+ goto done;
+ }
+ }
+
+ state->cb_hdr->nFEs++;
+ state->cb_hdr->nCBs += hdr.nCBs;
+
+ done:
+ return ret;
+}
+
+static int
+cb_stateRestoreFE(struct fs_dump_state * state)
+{
+ int ret = 0, iovcnt, len, nCBs, idx;
+ struct callback_state_entry_header hdr;
+ struct FEDiskEntry fedsk;
+ struct CBDiskEntry cbdsk[16];
+ struct iovec iov[16];
+ struct FileEntry * fe;
+ struct CallBack * cb;
+
+ iov[0].iov_base = (char *)&hdr;
+ len = iov[0].iov_len = sizeof(hdr);
+ iov[1].iov_base = (char *)&fedsk;
+ len += iov[1].iov_len = sizeof(fedsk);
+ iovcnt = 2;
+
+ if (fs_stateReadV(state, iov, iovcnt)) {
+ ret = 1;
+ goto done;
+ }
+
+ if (hdr.magic != CALLBACK_STATE_ENTRY_MAGIC) {
+ ret = 1;
+ goto done;
+ }
+
+ fe = GetFE();
+ if (fe == NULL) {
+ ViceLog(0, ("cb_stateRestoreFE: ran out of free FileEntry structures\n"));
+ ret = 1;
+ goto done;
+ }
+
+ if (cb_stateDiskEntryToFE(state, &fedsk, fe)) {
+ ret = 1;
+ goto done;
+ }
+
+ if (hdr.nCBs) {
+ for (iovcnt = 0, idx = 0, len = 0, nCBs = 0;
+ nCBs < hdr.nCBs;
+ idx++, nCBs++) {
+ iov[idx].iov_base = (char *)&cbdsk[idx];
+ len += iov[idx].iov_len = sizeof(struct CBDiskEntry);
+ iovcnt++;
+ if ((iovcnt == 16) || (nCBs == hdr.nCBs - 1)) {
+ if (fs_stateReadV(state, iov, iovcnt)) {
+ ret = 1;
+ goto done;
+ }
+ if (cb_stateRestoreCBs(state, fe, iov, iovcnt)) {
+ ret = 1;
+ goto done;
+ }
+ len = 0;
+ iovcnt = 0;
+ }
+ }
+ }
+
+ done:
+ return ret;
+}
+
+static int
+cb_stateRestoreCBs(struct fs_dump_state * state, struct FileEntry * fe,
+ struct iovec * iov, int niovecs)
+{
+ int ret = 0, idx;
+ register struct CallBack * cb;
+ struct CBDiskEntry * cbdsk;
+ afs_uint32 fei;
+
+ fei = fetoi(fe);
+
+ for (idx = 0; idx < niovecs; idx++) {
+ cbdsk = (struct CBDiskEntry *) iov[idx].iov_base;
+ if ((cb = GetCB()) == NULL) {
+ ViceLog(0, ("cb_stateRestoreCBs: ran out of free CallBack structures\n"));
+ ret = 1;
+ goto done;
+ }
+ if (cb_stateDiskEntryToCB(state, cbdsk, cb)) {
+ ViceLog(0, ("cb_stateRestoreCBs: corrupt CallBack disk entry\n"));
+ ret = 1;
+ goto done;
+ }
+ }
+
+ done:
+ return ret;
+}
+
+
+static int
+cb_stateFillHeader(struct callback_state_header * hdr)
+{
+ hdr->stamp.magic = CALLBACK_STATE_MAGIC;
+ hdr->stamp.version = CALLBACK_STATE_VERSION;
+ hdr->tfirst = tfirst;
+ return 0;
+}
+
+static int
+cb_stateCheckHeader(struct callback_state_header * hdr)
+{
+ int ret = 0;
+
+ if (hdr->stamp.magic != CALLBACK_STATE_MAGIC) {
+ ret = 1;
+ } else if (hdr->stamp.version != CALLBACK_STATE_VERSION) {
+ ret = 1;
+ } else if ((hdr->nFEs > cbstuff.nblks) || (hdr->nCBs > cbstuff.nblks)) {
+ ViceLog(0, ("cb_stateCheckHeader: saved callback state larger than callback memory allocation\n"));
+ ret = 1;
+ }
+ return ret;
+}
+
+/* disk entry conversion routines */
+static int
+cb_stateFEToDiskEntry(struct FileEntry * in, struct FEDiskEntry * out)
+{
+ memcpy(&out->fe, in, sizeof(struct FileEntry));
+ out->index = fetoi(in);
+ return 0;
+}
+
+static int
+cb_stateDiskEntryToFE(struct fs_dump_state * state,
+ struct FEDiskEntry * in, struct FileEntry * out)
+{
+ int ret = 0;
+
+ memcpy(out, &in->fe, sizeof(struct FileEntry));
+
+ /* setup FE map entry */
+ if (!in->index || (in->index >= state->fe_map.len)) {
+ ViceLog(0, ("cb_stateDiskEntryToFE: index (%d) out of range",
+ in->index));
+ ret = 1;
+ goto done;
+ }
+ state->fe_map.entries[in->index].old_idx = in->index;
+ state->fe_map.entries[in->index].new_idx = fetoi(out);
+
+ done:
+ return ret;
+}
+
+static int
+cb_stateCBToDiskEntry(struct CallBack * in, struct CBDiskEntry * out)
+{
+ memcpy(&out->cb, in, sizeof(struct CallBack));
+ out->index = cbtoi(in);
+ return 0;
+}
+
+static int
+cb_stateDiskEntryToCB(struct fs_dump_state * state,
+ struct CBDiskEntry * in, struct CallBack * out)
+{
+ int ret = 0;
+
+ memcpy(out, &in->cb, sizeof(struct CallBack));
+
+ /* setup CB map entry */
+ if (!in->index || (in->index >= state->cb_map.len)) {
+ ViceLog(0, ("cb_stateDiskEntryToCB: index (%d) out of range\n",
+ in->index));
+ ret = 1;
+ goto done;
+ }
+ state->cb_map.entries[in->index].old_idx = in->index;
+ state->cb_map.entries[in->index].new_idx = cbtoi(out);
+
+ done:
+ return ret;
+}
+
+/* index map routines */
+static int
+cb_stateAllocMap(struct fs_dump_state * state)
+{
+ state->fe_map.len = state->cb_hdr->fe_max + 1;
+ state->cb_map.len = state->cb_hdr->cb_max + 1;
+ state->fe_map.entries = (struct idx_map_entry_t *)
+ calloc(state->fe_map.len, sizeof(struct idx_map_entry_t));
+ state->cb_map.entries = (struct idx_map_entry_t *)
+ calloc(state->cb_map.len, sizeof(struct idx_map_entry_t));
+ return ((state->fe_map.entries != NULL) && (state->cb_map.entries != NULL)) ? 0 : 1;
+}
+
+int
+fe_OldToNew(struct fs_dump_state * state, afs_uint32 old, afs_uint32 * new)
+{
+ int ret = 0;
+
+ /* FEs use a one-based indexing system, so old==0 implies no mapping */
+ if (!old) {
+ *new = 0;
+ goto done;
+ }
+
+ if (old >= state->fe_map.len) {
+ ViceLog(0, ("fe_OldToNew: index %d is out of range\n", old));
+ ret = 1;
+ } else if (state->fe_map.entries[old].old_idx != old) { /* sanity check */
+ ViceLog(0, ("fe_OldToNew: index %d points to an invalid FileEntry record\n", old));
+ ret = 1;
+ } else {
+ *new = state->fe_map.entries[old].new_idx;
+ }
+
+ done:
+ return ret;
+}
+
+int
+cb_OldToNew(struct fs_dump_state * state, afs_uint32 old, afs_uint32 * new)
+{
+ int ret = 0;
+
+ /* CBs use a one-based indexing system, so old==0 implies no mapping */
+ if (!old) {
+ *new = 0;
+ goto done;
+ }
+
+ if (old >= state->cb_map.len) {
+ ViceLog(0, ("cb_OldToNew: index %d is out of range\n", old));
+ ret = 1;
+ } else if (state->cb_map.entries[old].old_idx != old) { /* sanity check */
+ ViceLog(0, ("cb_OldToNew: index %d points to an invalid CallBack record\n", old));
+ ret = 1;
+ } else {
+ *new = state->cb_map.entries[old].new_idx;
+ }
+
+ done:
+ return ret;
+}
+#endif /* AFS_DEMAND_ATTACH_FS */
+
int
DumpCallBackState(void)
{
return 0;
}
-#endif
+#endif /* !INTERPRET_DUMP */
#ifdef INTERPRET_DUMP
struct CallBack *cb;
struct FileEntry *fe;
- for (hash = 0; hash < VHASH; hash++) {
+ for (hash = 0; hash < FEHASH_SIZE; hash++) {
for (feip = &HashTable[hash]; fe = itofe(*feip);) {
if (!vol || (fe->volid == vol)) {
register struct CallBack *cbnext;
H_UNLOCK;
}
}
+#ifdef AFS_DEMAND_ATTACH_FS
+ /* try to bail ASAP if the fileserver is shutting down */
+ FS_STATE_RDLOCK;
+ if (fs_state.mode == FS_MODE_SHUTDOWN) {
+ FS_STATE_UNLOCK;
+ multi_Abort;
+ }
+ FS_STATE_UNLOCK;
+#endif
}
multi_End_Ignore;
H_LOCK;
--- /dev/null
+/*
+ * Copyright 2000, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ *
+ * This software has been released under the terms of the IBM Public
+ * License. For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ *
+ * Portions Copyright (c) 2006 Sine Nomine Associates
+ */
+
+#ifndef _AFS_VICED_CALLBACK_H
+#define _AFS_VICED_CALLBACK_H
+
+/* Maximum number of call backs to break at once, single fid
+ * There is some debate as to just how large this value should be
+ * Ideally, it would be very very large, but I am afraid that the
+ * cache managers will all send in their responses simultaneously,
+ * thereby swamping the file server. As a result, something like
+ * 10 or 15 might be a better bet.
+ */
+#define MAX_CB_HOSTS 10
+
+/* max time to break a callback, otherwise client is dead or net is hosed */
+#define MAXCBT 25
+
+#define u_byte unsigned char
+
+struct cbcounters {
+ afs_int32 DeleteFiles;
+ afs_int32 DeleteCallBacks;
+ afs_int32 BreakCallBacks;
+ afs_int32 AddCallBacks;
+ afs_int32 GotSomeSpaces;
+ afs_int32 DeleteAllCallBacks;
+ afs_int32 nFEs, nCBs, nblks;
+ afs_int32 CBsTimedOut;
+ afs_int32 nbreakers;
+ afs_int32 GSS1, GSS2, GSS3, GSS4, GSS5;
+};
+extern struct cbcounters cbstuff;
+
+struct cbstruct {
+ struct host *hp;
+ afs_uint32 thead;
+};
+
+/* structure MUST be multiple of 8 bytes, otherwise the casts to
+ * struct object will have alignment issues on *P64 userspaces */
+struct FileEntry {
+ afs_uint32 vnode;
+ afs_uint32 unique;
+ afs_uint32 volid;
+ afs_uint32 fnext; /* index of next FE in hash chain */
+ afs_uint32 ncbs; /* number of callbacks for this FE */
+ afs_uint32 firstcb; /* index of first cb in per-FE list */
+ afs_uint32 status; /* status bits for this FE */
+ afs_uint32 spare;
+};
+#define FE_LATER 0x1
+
+/* structure MUST be multiple of 8 bytes, otherwise the casts to
+ * struct object will have alignment issues on *P64 userspaces */
+struct CallBack {
+ afs_uint32 cnext; /* index of next cb in per-FE list */
+ afs_uint32 fhead; /* index of associated FE */
+ u_byte thead; /* Head of timeout chain */
+ u_byte status; /* Call back status; see definitions, below */
+ unsigned short spare; /* ensure proper alignment */
+ afs_uint32 hhead; /* Head of host table chain */
+ afs_uint32 tprev, tnext; /* per-timeout circular list of callbacks */
+ afs_uint32 hprev, hnext; /* per-host circular list of callbacks */
+};
+
+struct VCBParams {
+ struct cbstruct cba[MAX_CB_HOSTS]; /* re-entrant storage */
+ unsigned int ncbas;
+ afs_uint32 thead; /* head of timeout queue for youngest callback */
+ struct AFSFid *fid;
+};
+
+
+/* callback hash macros */
+#define FEHASH_SIZE 512 /* Power of 2 */
+#define FEHASH_MASK (FEHASH_SIZE-1)
+#define FEHash(volume, unique) (((volume)+(unique))&(FEHASH_MASK))
+
+#define CB_NUM_TIMEOUT_QUEUES 128
+
+
+/* status values for status field of CallBack structure */
+#define CB_NORMAL 1 /* Normal call back */
+#define CB_DELAYED 2 /* Delayed call back due to rpc problems.
+ * The call back entry will be added back to the
+ * host list at the END of the list, so that
+ * searching backwards in the list will find all
+ * the (consecutive)host. delayed call back entries */
+#define CB_VOLUME 3 /* Callback for a volume */
+#define CB_BULK 4 /* Normal callbacks, handed out from FetchBulkStatus */
+
+/* call back indices to pointers, and vice-versa */
+#define itocb(i) ((i)?CB+(i):0)
+#define cbtoi(cbp) (!(cbp)?0:(cbp)-CB)
+
+/* file entry indices to pointers, and vice-versa */
+#define itofe(i) ((i)?FE+(i):0)
+#define fetoi(fep) (!(fep)?0:(fep)-FE)
+
+/* Timeouts: there are 128 possible timeout values in effect at any
+ * given time. Each timeout represents timeouts in an interval of 128
+ * seconds. So the maximum timeout for a call back is 128*128=16384
+ * seconds, or 4 1/2 hours. The timeout cleanup stuff is called only
+ * if space runs out or by the file server every 5 minutes. This 5
+ * minute slack should be allowed for--so a maximum time of 4 hours
+ * is safer.
+ *
+ * Timeouts must be chosen to correspond to an exact multiple
+ * of 128, because all times are truncated to a 128 multiple, and
+ * timed out if the current truncated time is <= to the truncated time
+ * corresponding to the timeout queue.
+ */
+
+/* Unix time to Call Back time, and vice-versa. Call back time is
+ in units of 128 seconds, corresponding to time queues. */
+#define CBtime(uxtime) ((uxtime)>>7)
+#define UXtime(cbtime) ((cbtime)<<7)
+
+/* Given a Unix time, compute the closest Unix time that corresponds to
+ a time queue, rounding up */
+#define TimeCeiling(uxtime) (((uxtime)+127)&~127)
+
+#define TimeOutCutoff ((sizeof(TimeOuts)/sizeof(TimeOuts[0]))*8)
+#define TimeOut(nusers) ((nusers)>=TimeOutCutoff? MinTimeOut: TimeOuts[(nusers)>>3])
+
+/* time out at server is 3 minutes more than ws */
+#define ServerBias (3*60)
+
+/* Convert cbtime to timeout queue index */
+#define TIndex(cbtime) (((cbtime)&127)+1)
+
+/* Convert cbtime to pointer to timeout queue head */
+#define THead(cbtime) (&timeout[TIndex(cbtime)-1])
+
+/* Normalize index into timeout array so that two such indices will be
+ ordered correctly, so that they can be compared to see which times
+ sooner, or so that the difference in time out times between them
+ can be computed. */
+#define TNorm(index) ((index)<TIndex(tfirst)?(index)+128:(index))
+
+/* This converts a timeout index into the actual time it will expire */
+#define TIndexToTime(index) (UXtime(TNorm(index) - TIndex(tfirst) + tfirst))
+
+
+/* Convert pointer to timeout queue head to index, and vice versa */
+#define ttoi(t) ((t-timeout)+1)
+#define itot(i) ((timeout)+(i-1))
+
+#endif /* _AFS_VICED_CALLBACK_H */
* This software has been released under the terms of the IBM Public
* License. For details, see the LICENSE file in the top-level source
* directory or online at http://www.openafs.org/dl/license10.html
+ *
+ * Portions Copyright (c) 2006 Sine Nomine Associates
*/
#include <afsconfig.h>
#include "viced_prototypes.h"
#include "viced.h"
#include "host.h"
-
+#include "callback.h"
+#ifdef AFS_DEMAND_ATTACH_FS
+#include "../util/afsutil_prototypes.h"
+#include "../tviced/serialize_state.h"
+#endif /* AFS_DEMAND_ATTACH_FS */
#ifdef AFS_PTHREAD_ENV
pthread_mutex_t host_glock_mutex;
int rxcon_ident_key;
int rxcon_client_key;
+static struct rx_securityClass *sc = NULL;
+
+static void h_SetupCallbackConn_r(struct host * host);
+static void h_AddHostToHashTable_r(afs_uint32 addr, afs_uint16 port, struct host * host);
+static void h_AddHostToUuidHashTable_r(afsUUID * uuid, struct host * host);
+static int h_DeleteHostFromHashTableByAddr_r(afs_uint32 addr, afs_uint16 port, struct host *host);
+
#define CESPERBLOCK 73
struct CEBlock { /* block of CESPERBLOCK file entries */
struct client entry[CESPERBLOCK];
{
register struct host *entry;
- if (HTFree == 0)
+ if (HTFree == NULL)
GetHTBlock();
- assert(HTFree != 0);
+ assert(HTFree != NULL);
entry = HTFree;
HTFree = entry->next;
HTs++;
free(host->hcps.prlist_val); /* this is for hostaclRefresh */
host->hcps.prlist_val = NULL;
host->hcps.prlist_len = 0;
- slept ? (host->cpsCall = FT_ApproxTime()) : (host->cpsCall = now);
+ host->cpsCall = slept ? (FT_ApproxTime()) : (now);
H_UNLOCK;
code = pr_GetHostCPS(ntohl(host->host), &host->hcps);
{
struct servent *serverentry;
struct host *host;
- static struct rx_securityClass *sc = 0;
afs_int32 now;
#if FS_STATS_DETAILED
afs_uint32 newHostAddr_HBO; /*New host IP addr, in host byte order */
host->host = rxr_HostOf(r_con);
host->port = rxr_PortOf(r_con);
- hashInsert_r(host->host, host->port, host);
+ h_AddHostToHashTable_r(host->host, host->port, host);
if (consolePort == 0) { /* find the portal number for console */
#if defined(AFS_OSF_ENV)
host->Console = 1;
/* Make a callback channel even for the console, on the off chance that it
* makes a request that causes a break call back. It shouldn't. */
- {
- if (!sc)
- sc = rxnull_NewClientSecurityObject();
- host->callback_rxcon =
- rx_NewConnection(host->host, host->port, 1, sc, 0);
- rx_SetConnDeadTime(host->callback_rxcon, 50);
- rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
- }
+ h_SetupCallbackConn_r(host);
now = host->LastCall = host->cpsCall = host->ActiveCall = FT_ApproxTime();
host->hostFlags = 0;
host->hcps.prlist_val = NULL;
host->hcps.prlist_len = 0;
- host->interface = 0;
+ host->interface = NULL;
#ifdef undef
host->hcpsfailed = 0; /* save cycles */
h_gethostcps(host); /* do this under host hold/lock */
#endif
- host->FirstClient = 0;
+ host->FirstClient = NULL;
h_Hold_r(host);
h_Lock_r(host);
h_InsertList_r(host); /* update global host List */
} /*h_Alloc_r */
+
+/* Make a callback channel even for the console, on the off chance that it
+ * makes a request that causes a break call back. It shouldn't. */
+static void
+h_SetupCallbackConn_r(struct host * host)
+{
+ if (!sc)
+ sc = rxnull_NewClientSecurityObject();
+ host->callback_rxcon =
+ rx_NewConnection(host->host, host->port, 1, sc, 0);
+ rx_SetConnDeadTime(host->callback_rxcon, 50);
+ rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
+}
+
/* Lookup a host given an IP address and UDP port number. */
/* hostaddr and hport are in network order */
/* Note: host should be released by caller if 0 == *heldp and non-null */
if (client) {
H_LOCK;
if (client->tcon == tcon)
- client->tcon = (struct rx_connection *)0;
+ client->tcon = NULL;
H_UNLOCK;
}
return 0;
H_UNLOCK;
for (i = 0; i < count; i++) {
held[i] = (*proc) (list[i], held[i], param);
- if (!held[i])
+ if (!H_ENUMERATE_ISSET_HELD(held[i]))
h_Release(list[i]); /* this might free up the host */
+ /* bail out of the enumeration early */
+ if (H_ENUMERATE_ISSET_BAIL(held[i]))
+ break;
}
free((void *)list);
free((void *)held);
h_Hold_r(enumstart);
for (host = enumstart; host; host = next, held = nheld) {
next = host->next;
- if (next && !(nheld = h_Held_r(next)))
+ if (next && !(nheld = h_Held_r(next)) && !H_ENUMERATE_ISSET_BAIL(held))
h_Hold_r(next);
held = (*proc) (host, held, param);
- if (!held)
+ if (!H_ENUMERATE_ISSET_HELD(held))
h_Release_r(host); /* this might free up the host */
+ if (H_ENUMERATE_ISSET_BAIL(held))
+ break;
}
} /*h_Enumerate_r */
/* inserts a new HashChain structure corresponding to this UUID */
-void
-hashInsertUuid_r(struct afsUUID *uuid, struct host *host)
+static void
+h_AddHostToUuidHashTable_r(struct afsUUID *uuid, struct host *host)
{
int index;
struct h_hashChain *chain;
/* insert into beginning of list for this bucket */
chain = (struct h_hashChain *)malloc(sizeof(struct h_hashChain));
if (!chain) {
- ViceLog(0, ("Failed malloc in hashInsertUuid_r\n"));
+ ViceLog(0, ("Failed malloc in h_AddHostToUuidHashTable_r\n"));
assert(0);
}
assert(chain);
/* inserts a new HashChain structure corresponding to this address */
-void
-hashInsert_r(afs_uint32 addr, afs_uint16 port, struct host *host)
+static void
+h_AddHostToHashTable_r(afs_uint32 addr, afs_uint16 port, struct host *host)
{
int index;
struct h_hashChain *chain;
/* insert into beginning of list for this bucket */
chain = (struct h_hashChain *)malloc(sizeof(struct h_hashChain));
if (!chain) {
- ViceLog(0, ("Failed malloc in hashInsert_r\n"));
+ ViceLog(0, ("Failed malloc in h_AddHostToHashTable_r\n"));
assert(0);
}
chain->hostPtr = host;
/*
* Create a hash table entry for this address
*/
- hashInsert_r(addr, port, host);
+ h_AddHostToHashTable_r(addr, port, host);
return 0;
}
/*
* Remove the hash table entry for this address
*/
- hashDelete_r(addr, port, host);
+ h_DeleteHostFromHashTableByAddr_r(addr, port, host);
return 0;
}
/* the new host is held and locked */
} else {
/* This really is a new host */
- hashInsertUuid_r(&identP->uuid, host);
+ h_AddHostToUuidHashTable_r(&identP->uuid, host);
cb_conn = host->callback_rxcon;
rx_GetConnection(cb_conn);
H_UNLOCK;
client->authClass = authClass; /* rx only */
client->sid = rxr_CidOf(tcon);
client->VenusEpoch = rxr_GetEpoch(tcon);
- client->CPS.prlist_val = 0;
+ client->CPS.prlist_val = NULL;
client->CPS.prlist_len = 0;
h_Unlock_r(host);
}
} /*h_DumpHosts */
+#ifdef AFS_DEMAND_ATTACH_FS
+/*
+ * demand attach fs
+ * host state serialization
+ */
+static int h_stateFillHeader(struct host_state_header * hdr);
+static int h_stateCheckHeader(struct host_state_header * hdr);
+static int h_stateAllocMap(struct fs_dump_state * state);
+static int h_stateSaveHost(register struct host * host, int held, struct fs_dump_state * state);
+static int h_stateRestoreHost(struct fs_dump_state * state);
+static int h_stateRestoreIndex(struct host * h, int held, struct fs_dump_state * state);
+static int h_stateVerifyHost(struct host * h, int held, struct fs_dump_state * state);
+static int h_stateVerifyAddrHash(struct fs_dump_state * state, struct host * h, afs_uint32 addr, afs_uint16 port);
+static int h_stateVerifyUuidHash(struct fs_dump_state * state, struct host * h);
+static void h_hostToDiskEntry_r(struct host * in, struct hostDiskEntry * out);
+static void h_diskEntryToHost_r(struct hostDiskEntry * in, struct host * out);
+
+
+/* this procedure saves all host state to disk for fast startup */
+int
+h_stateSave(struct fs_dump_state * state)
+{
+ AssignInt64(state->eof_offset, &state->hdr->h_offset);
+
+ /* XXX debug */
+ ViceLog(0, ("h_stateSave: hostCount=%d\n", hostCount));
+
+ /* invalidate host state header */
+ memset(state->h_hdr, 0, sizeof(struct host_state_header));
+
+ if (fs_stateWriteHeader(state, &state->hdr->h_offset, state->h_hdr,
+ sizeof(struct host_state_header))) {
+ state->bail = 1;
+ goto done;
+ }
+
+ fs_stateIncEOF(state, sizeof(struct host_state_header));
+
+ h_Enumerate_r(h_stateSaveHost, hostList, (char *)state);
+ if (state->bail) {
+ goto done;
+ }
+
+ h_stateFillHeader(state->h_hdr);
+
+ /* write the real header to disk */
+ state->bail = fs_stateWriteHeader(state, &state->hdr->h_offset, state->h_hdr,
+ sizeof(struct host_state_header));
+
+ done:
+ return state->bail;
+}
+
+/* demand attach fs
+ * host state serialization
+ *
+ * this procedure restores all host state from a disk for fast startup
+ */
+int
+h_stateRestore(struct fs_dump_state * state)
+{
+ int i, records;
+
+ /* seek to the right position and read in the host state header */
+ if (fs_stateReadHeader(state, &state->hdr->h_offset, state->h_hdr,
+ sizeof(struct host_state_header))) {
+ state->bail = 1;
+ goto done;
+ }
+
+ /* check the validity of the header */
+ if (h_stateCheckHeader(state->h_hdr)) {
+ state->bail = 1;
+ goto done;
+ }
+
+ records = state->h_hdr->records;
+
+ if (h_stateAllocMap(state)) {
+ state->bail = 1;
+ goto done;
+ }
+
+ /* iterate over records restoring host state */
+ for (i=0; i < records; i++) {
+ if (h_stateRestoreHost(state) != 0) {
+ state->bail = 1;
+ break;
+ }
+ }
+
+ done:
+ return state->bail;
+}
+
+int
+h_stateRestoreIndices(struct fs_dump_state * state)
+{
+ h_Enumerate_r(h_stateRestoreIndex, hostList, (char *)state);
+ return state->bail;
+}
+
+static int
+h_stateRestoreIndex(struct host * h, int held, struct fs_dump_state * state)
+{
+ if (cb_OldToNew(state, h->cblist, &h->cblist)) {
+ return H_ENUMERATE_BAIL(held);
+ }
+ return held;
+}
+
+int
+h_stateVerify(struct fs_dump_state * state)
+{
+ h_Enumerate_r(h_stateVerifyHost, hostList, (char *)state);
+ return state->bail;
+}
+
+static int
+h_stateVerifyHost(struct host * h, int held, struct fs_dump_state * state)
+{
+ int i;
+
+ if (h == NULL) {
+ ViceLog(0, ("h_stateVerifyHost: error: NULL host pointer in linked list\n"));
+ return H_ENUMERATE_BAIL(held);
+ }
+
+ if (h->interface) {
+ for (i = h->interface->numberOfInterfaces-1; i >= 0; i--) {
+ if (h_stateVerifyAddrHash(state, h, h->interface->interface[i].addr,
+ h->interface->interface[i].port)) {
+ state->bail = 1;
+ }
+ }
+ if (h_stateVerifyUuidHash(state, h)) {
+ state->bail = 1;
+ }
+ } else if (h_stateVerifyAddrHash(state, h, h->host, h->port)) {
+ state->bail = 1;
+ }
+
+ if (cb_stateVerifyHCBList(state, h)) {
+ state->bail = 1;
+ }
+
+ done:
+ return held;
+}
+
+static int
+h_stateVerifyAddrHash(struct fs_dump_state * state, struct host * h, afs_uint32 addr, afs_uint16 port)
+{
+ int ret = 0, found = 0;
+ struct host *host = NULL;
+ struct h_hashChain *chain;
+ int index = h_HashIndex(addr);
+ char tmp[16];
+ int chain_len = 0;
+
+ for (chain = hostHashTable[index]; chain; chain = chain->next) {
+ host = chain->hostPtr;
+ if (host == NULL) {
+ afs_inet_ntoa_r(addr, tmp);
+ ViceLog(0, ("h_stateVerifyAddrHash: error: addr hash chain has NULL host ptr (lookup addr %s)\n", tmp));
+ ret = 1;
+ goto done;
+ }
+ if ((chain->addr == addr) && (chain->port == port)) {
+ if (host != h) {
+ ViceLog(0, ("h_stateVerifyAddrHash: warning: addr hash entry points to different host struct (%d, %d)\n",
+ h->index, host->index));
+ state->flags.warnings_generated = 1;
+ }
+ found = 1;
+ break;
+ }
+ if (chain_len > FS_STATE_H_MAX_ADDR_HASH_CHAIN_LEN) {
+ ViceLog(0, ("h_stateVerifyAddrHash: error: hash chain length exceeds %d; assuming there's a loop\n",
+ FS_STATE_H_MAX_ADDR_HASH_CHAIN_LEN));
+ ret = 1;
+ goto done;
+ }
+ chain_len++;
+ }
+
+ if (!found) {
+ afs_inet_ntoa_r(addr, tmp);
+ if (state->mode == FS_STATE_LOAD_MODE) {
+ ViceLog(0, ("h_stateVerifyAddrHash: error: addr %s not found in hash\n", tmp));
+ ret = 1;
+ goto done;
+ } else {
+ ViceLog(0, ("h_stateVerifyAddrHash: warning: addr %s not found in hash\n", tmp));
+ state->flags.warnings_generated = 1;
+ }
+ }
+
+ done:
+ return ret;
+}
+
+static int
+h_stateVerifyUuidHash(struct fs_dump_state * state, struct host * h)
+{
+ int ret = 0, found = 0;
+ struct host *host = NULL;
+ struct h_hashChain *chain;
+ afsUUID * uuidp = &h->interface->uuid;
+ int index = h_UuidHashIndex(uuidp);
+ char tmp[40];
+ int chain_len = 0;
+
+ for (chain = hostUuidHashTable[index]; chain; chain = chain->next) {
+ host = chain->hostPtr;
+ if (host == NULL) {
+ afsUUID_to_string(uuidp, tmp, sizeof(tmp));
+ ViceLog(0, ("h_stateVerifyUuidHash: error: uuid hash chain has NULL host ptr (lookup uuid %s)\n", tmp));
+ ret = 1;
+ goto done;
+ }
+ if (host->interface &&
+ afs_uuid_equal(&host->interface->uuid, uuidp)) {
+ if (host != h) {
+ ViceLog(0, ("h_stateVerifyUuidHash: warning: uuid hash entry points to different host struct (%d, %d)\n",
+ h->index, host->index));
+ state->flags.warnings_generated = 1;
+ }
+ found = 1;
+ goto done;
+ }
+ if (chain_len > FS_STATE_H_MAX_UUID_HASH_CHAIN_LEN) {
+ ViceLog(0, ("h_stateVerifyUuidHash: error: hash chain length exceeds %d; assuming there's a loop\n",
+ FS_STATE_H_MAX_UUID_HASH_CHAIN_LEN));
+ ret = 1;
+ goto done;
+ }
+ chain_len++;
+ }
+
+ if (!found) {
+ afsUUID_to_string(uuidp, tmp, sizeof(tmp));
+ if (state->mode == FS_STATE_LOAD_MODE) {
+ ViceLog(0, ("h_stateVerifyUuidHash: error: uuid %s not found in hash\n", tmp));
+ ret = 1;
+ goto done;
+ } else {
+ ViceLog(0, ("h_stateVerifyUuidHash: warning: uuid %s not found in hash\n", tmp));
+ state->flags.warnings_generated = 1;
+ }
+ }
+
+ done:
+ return ret;
+}
+
+/* create the host state header structure */
+static int
+h_stateFillHeader(struct host_state_header * hdr)
+{
+ hdr->stamp.magic = HOST_STATE_MAGIC;
+ hdr->stamp.version = HOST_STATE_VERSION;
+}
+
+/* check the contents of the host state header structure */
+static int
+h_stateCheckHeader(struct host_state_header * hdr)
+{
+ int ret=0;
+
+ if (hdr->stamp.magic != HOST_STATE_MAGIC) {
+ ViceLog(0, ("check_host_state_header: invalid state header\n"));
+ ret = 1;
+ }
+ else if (hdr->stamp.version != HOST_STATE_VERSION) {
+ ViceLog(0, ("check_host_state_header: unknown version number\n"));
+ ret = 1;
+ }
+ return ret;
+}
+
+/* allocate the host id mapping table */
+static int
+h_stateAllocMap(struct fs_dump_state * state)
+{
+ state->h_map.len = state->h_hdr->index_max + 1;
+ state->h_map.entries = (struct idx_map_entry_t *)
+ calloc(state->h_map.len, sizeof(struct idx_map_entry_t));
+ return (state->h_map.entries != NULL) ? 0 : 1;
+}
+
+/* function called by h_Enumerate to save a host to disk */
+static int
+h_stateSaveHost(register struct host * host, int held, struct fs_dump_state * state)
+{
+ int i, if_len=0, hcps_len=0;
+ struct hostDiskEntry hdsk;
+ struct host_state_entry_header hdr;
+ struct Interface * ifp = NULL;
+ afs_int32 * hcps = NULL;
+ struct iovec iov[4];
+ int iovcnt = 2;
+
+ memset(&hdr, 0, sizeof(hdr));
+
+ if (state->h_hdr->index_max < host->index) {
+ state->h_hdr->index_max = host->index;
+ }
+
+ h_hostToDiskEntry_r(host, &hdsk);
+ if (host->interface) {
+ if_len = sizeof(struct Interface) +
+ ((host->interface->numberOfInterfaces-1) * sizeof(struct AddrPort));
+ ifp = (struct Interface *) malloc(if_len);
+ assert(ifp != NULL);
+ memcpy(ifp, host->interface, if_len);
+ hdr.interfaces = host->interface->numberOfInterfaces;
+ iov[iovcnt].iov_base = (char *) ifp;
+ iov[iovcnt].iov_len = if_len;
+ iovcnt++;
+ }
+ if (host->hcps.prlist_val) {
+ hdr.hcps = host->hcps.prlist_len;
+ hcps_len = hdr.hcps * sizeof(afs_int32);
+ hcps = (afs_int32 *) malloc(hcps_len);
+ assert(hcps != NULL);
+ memcpy(hcps, host->hcps.prlist_val, hcps_len);
+ iov[iovcnt].iov_base = (char *) hcps;
+ iov[iovcnt].iov_len = hcps_len;
+ iovcnt++;
+ }
+
+ if (hdsk.index > state->h_hdr->index_max)
+ state->h_hdr->index_max = hdsk.index;
+
+ hdr.len = sizeof(struct host_state_entry_header) +
+ sizeof(struct hostDiskEntry) + if_len + hcps_len;
+ hdr.magic = HOST_STATE_ENTRY_MAGIC;
+
+ iov[0].iov_base = (char *) &hdr;
+ iov[0].iov_len = sizeof(hdr);
+ iov[1].iov_base = (char *) &hdsk;
+ iov[1].iov_len = sizeof(struct hostDiskEntry);
+
+ if (fs_stateWriteV(state, iov, iovcnt)) {
+ ViceLog(0, ("h_stateSaveHost: failed to save host %d", host->index));
+ state->bail = 1;
+ }
+
+ fs_stateIncEOF(state, hdr.len);
+
+ state->h_hdr->records++;
+
+ done:
+ if (ifp)
+ free(ifp);
+ if (hcps)
+ free(hcps);
+ if (state->bail) {
+ return H_ENUMERATE_BAIL(held);
+ }
+ return held;
+}
+
+/* restores a host from disk */
+static int
+h_stateRestoreHost(struct fs_dump_state * state)
+{
+ int ifp_len=0, hcps_len=0, bail=0;
+ struct host_state_entry_header hdr;
+ struct hostDiskEntry hdsk;
+ struct host *host = NULL;
+ struct Interface *ifp = NULL;
+ afs_int32 * hcps = NULL;
+ struct iovec iov[3];
+ int iovcnt = 1;
+
+ if (fs_stateRead(state, &hdr, sizeof(hdr))) {
+ ViceLog(0, ("h_stateRestoreHost: failed to read host entry header from dump file '%s'\n",
+ state->fn));
+ bail = 1;
+ goto done;
+ }
+
+ if (hdr.magic != HOST_STATE_ENTRY_MAGIC) {
+ ViceLog(0, ("h_stateRestoreHost: fileserver state dump file '%s' is corrupt.\n",
+ state->fn));
+ bail = 1;
+ goto done;
+ }
+
+ iov[0].iov_base = (char *) &hdsk;
+ iov[0].iov_len = sizeof(struct hostDiskEntry);
+
+ if (hdr.interfaces) {
+ ifp_len = sizeof(struct Interface) +
+ ((hdr.interfaces-1) * sizeof(struct AddrPort));
+ ifp = (struct Interface *) malloc(ifp_len);
+ assert(ifp != NULL);
+ iov[iovcnt].iov_base = (char *) ifp;
+ iov[iovcnt].iov_len = ifp_len;
+ iovcnt++;
+ }
+ if (hdr.hcps) {
+ hcps_len = hdr.hcps * sizeof(afs_int32);
+ hcps = (afs_int32 *) malloc(hcps_len);
+ assert(hcps != NULL);
+ iov[iovcnt].iov_base = (char *) hcps;
+ iov[iovcnt].iov_len = hcps_len;
+ iovcnt++;
+ }
+
+ if ((ifp_len + hcps_len + sizeof(hdsk) + sizeof(hdr)) != hdr.len) {
+ ViceLog(0, ("h_stateRestoreHost: host entry header length fields are inconsistent\n"));
+ bail = 1;
+ goto done;
+ }
+
+ if (fs_stateReadV(state, iov, iovcnt)) {
+ ViceLog(0, ("h_stateRestoreHost: failed to read host entry\n"));
+ bail = 1;
+ goto done;
+ }
+
+ if (!hdr.hcps && hdsk.hcps_valid) {
+ /* valid, zero-length host cps ; does this ever happen? */
+ hcps = (afs_int32 *) malloc(sizeof(afs_int32));
+ assert(hcps != NULL);
+ }
+
+ host = GetHT();
+ assert(host != NULL);
+
+ if (ifp) {
+ host->interface = ifp;
+ }
+ if (hcps) {
+ host->hcps.prlist_val = hcps;
+ host->hcps.prlist_len = hdr.hcps;
+ }
+
+ h_diskEntryToHost_r(&hdsk, host);
+ h_SetupCallbackConn_r(host);
+
+ if (ifp) {
+ int i;
+ for (i = ifp->numberOfInterfaces-1; i >= 0; i--) {
+ h_AddHostToHashTable_r(ifp->interface[i].addr,
+ ifp->interface[i].port, host);
+ }
+ h_AddHostToUuidHashTable_r(&ifp->uuid, host);
+ } else {
+ h_AddHostToHashTable_r(host->host, host->port, host);
+ }
+ h_InsertList_r(host);
+
+ /* setup host id map entry */
+ state->h_map.entries[hdsk.index].old_idx = hdsk.index;
+ state->h_map.entries[hdsk.index].new_idx = host->index;
+
+ done:
+ if (bail) {
+ if (ifp)
+ free(ifp);
+ if (hcps)
+ free(hcps);
+ }
+ return bail;
+}
+
+/* serialize a host structure to disk */
+static void
+h_hostToDiskEntry_r(struct host * in, struct hostDiskEntry * out)
+{
+ out->host = in->host;
+ out->port = in->port;
+ out->hostFlags = in->hostFlags;
+ out->Console = in->Console;
+ out->hcpsfailed = in->hcpsfailed;
+ out->LastCall = in->LastCall;
+ out->ActiveCall = in->ActiveCall;
+ out->cpsCall = in->cpsCall;
+ out->cblist = in->cblist;
+#ifdef FS_STATS_DETAILED
+ out->InSameNetwork = in->InSameNetwork;
+#endif
+
+ /* special fields we save, but are not memcpy'd back on restore */
+ out->index = in->index;
+ out->hcps_len = in->hcps.prlist_len;
+ out->hcps_valid = (in->hcps.prlist_val == NULL) ? 0 : 1;
+}
+
+/* restore a host structure from disk */
+static void
+h_diskEntryToHost_r(struct hostDiskEntry * in, struct host * out)
+{
+ out->host = in->host;
+ out->port = in->port;
+ out->hostFlags = in->hostFlags;
+ out->Console = in->Console;
+ out->hcpsfailed = in->hcpsfailed;
+ out->LastCall = in->LastCall;
+ out->ActiveCall = in->ActiveCall;
+ out->cpsCall = in->cpsCall;
+ out->cblist = in->cblist;
+#ifdef FS_STATS_DETAILED
+ out->InSameNetwork = in->InSameNetwork;
+#endif
+}
+
+/* index translation routines */
+int
+h_OldToNew(struct fs_dump_state * state, afs_uint32 old, afs_uint32 * new)
+{
+ int ret = 0;
+
+ /* hosts use a zero-based index, so old==0 is valid */
+
+ if (old >= state->h_map.len) {
+ ViceLog(0, ("h_OldToNew: index %d is out of range\n", old));
+ ret = 1;
+ } else if (state->h_map.entries[old].old_idx != old) { /* sanity check */
+ ViceLog(0, ("h_OldToNew: index %d points to an invalid host record\n", old));
+ ret = 1;
+ } else {
+ *new = state->h_map.entries[old].new_idx;
+ }
+
+ done:
+ return ret;
+}
+#endif /* AFS_DEMAND_ATTACH_FS */
+
/*
* This counts the number of workstations, the number of active workstations,
* Since it can serialize them, and pile up, it should be a separate LWP
* from other events.
*/
-int
+static int
CheckHost(register struct host *host, int held)
{
register struct client *client;
struct rx_connection *cb_conn = NULL;
int code;
+#ifdef AFS_DEMAND_ATTACH_FS
+ /* kill the checkhost lwp ASAP during shutdown */
+ FS_STATE_RDLOCK;
+ if (fs_state.mode == FS_MODE_SHUTDOWN) {
+ FS_STATE_UNLOCK;
+ return H_ENUMERATE_BAIL(held);
+ }
+ FS_STATE_UNLOCK;
+#endif
+
/* Host is held by h_Enumerate */
H_LOCK;
for (client = host->FirstClient; client; client = client->next) {
* This routine is called roughly every 5 minutes.
*/
void
-h_CheckHosts()
+h_CheckHosts(void)
{
afs_uint32 now = FT_ApproxTime();
/* deleted a HashChain structure for this address and host */
/* returns 1 on success */
static int
-hashDelete_r(afs_uint32 addr, afs_uint16 port, struct host *host)
+h_DeleteHostFromHashTableByAddr_r(afs_uint32 addr, afs_uint16 port, struct host *host)
{
int flag;
register struct h_hashChain **hp, *th;
* This software has been released under the terms of the IBM Public
* License. For details, see the LICENSE file in the top-level source
* directory or online at http://www.openafs.org/dl/license10.html
+ *
+ * Portions Copyright (c) 2006 Sine Nomine Associates
*/
+#ifndef _AFS_VICED_HOST_H
+#define _AFS_VICED_HOST_H
+
#include "fs_stats.h" /*File Server stats package */
#ifdef AFS_PTHREAD_ENV
struct AddrPort interface[1];/* there are actually more than one here */
/* in network byte order */
};
+
struct host {
struct host *next, *prev; /* linked list of all hosts */
struct rx_connection *callback_rxcon; /* rx callback connection */
struct client *FirstClient; /* first connection from host */
afs_uint32 cpsCall; /* time of last cps call from this host */
struct Interface *interface; /* all alternate addr for client */
- afs_uint32 cblist; /* Call back list for this host */
+ afs_uint32 cblist; /* index of a cb in the per-host circular CB list */
/*
* These don't get zeroed, keep them at the end. If index doesn't
* follow an unsigned short then we need to pad to ensure that
/* Don't zero the lock */
#define CLIENT_TO_ZERO(C) ((int)(((char *)(&((C)->lock))-(char *)(C))))
+
/*
* key for the client structure stored in connection specific data
*/
struct Interface *MultiVerifyInterface_r();
extern int initInterfaceAddr_r(struct host *host, struct interfaceAddr *interf);
+#ifdef AFS_DEMAND_ATTACH_FS
+/*
+ * demand attach fs
+ * state serialization
+ */
+extern int h_SaveState(void);
+extern int h_RestoreState(void);
+#endif
+
+#define H_ENUMERATE_BAIL(held) ((held)|0x80000000)
+#define H_ENUMERATE_ISSET_BAIL(held) ((held)&0x80000000)
+#define H_ENUMERATE_ISSET_HELD(held) ((held)&0x7FFFFFFF)
+
struct host *(hosttableptrs[h_MAXHOSTTABLES]); /* Used by h_itoh */
#define h_htoi(host) ((host)->index) /* index isn't zeroed, no need to lock */
#define h_itoh(hostindex) (hosttableptrs[(hostindex)>>h_HTSHIFT]+((hostindex)&(h_HTSPERBLOCK-1)))
#define HFE_LATER 0x80 /* host has FE_LATER callbacks */
#define HERRORTRANS 0x100 /* do error translation */
-
+#endif /* _AFS_VICED_HOST_H */
* This software has been released under the terms of the IBM Public
* License. For details, see the LICENSE file in the top-level source
* directory or online at http://www.openafs.org/dl/license10.html
+ *
+ * Portions Copyright (c) 2006 Sine Nomine Associates
*/
/* viced.c - File Server main loop */
static void FlagMsg();
+#ifdef AFS_DEMAND_ATTACH_FS
+/*
+ * demand attach fs
+ * fileserver mode support
+ *
+ * during fileserver shutdown, we have to track the graceful shutdown of
+ * certain background threads before we are allowed to dump state to
+ * disk
+ */
+struct fs_state fs_state =
+ { FS_MODE_NORMAL,
+ 0,
+ 0,
+ 0,
+ 0,
+ { 1,1,1,1 },
+ PTHREAD_COND_INITIALIZER,
+ PTHREAD_RWLOCK_INITIALIZER
+ };
+#endif /* AFS_DEMAND_ATTACH_FS */
+
/*
* Home for the performance statistics.
*/
ViceLog(1, ("Starting five minute check process\n"));
setThreadId("FiveMinuteCheckLWP");
+
+#ifdef AFS_DEMAND_ATTACH_FS
+ FS_STATE_WRLOCK;
+ while (fs_state.mode == FS_MODE_NORMAL) {
+ fs_state.FiveMinuteLWP_tranquil = 1;
+ FS_STATE_UNLOCK;
+#else
while (1) {
+#endif
+
#ifdef AFS_PTHREAD_ENV
sleep(fiveminutes);
#else /* AFS_PTHREAD_ENV */
IOMGR_Sleep(fiveminutes);
#endif /* AFS_PTHREAD_ENV */
+#ifdef AFS_DEMAND_ATTACH_FS
+ FS_STATE_WRLOCK;
+ if (fs_state.mode != FS_MODE_NORMAL) {
+ break;
+ }
+ fs_state.FiveMinuteLWP_tranquil = 0;
+ FS_STATE_UNLOCK;
+#endif
+
/* close the log so it can be removed */
ReOpenLog(AFSDIR_SERVER_FILELOG_FILEPATH); /* don't trunc, just append */
ViceLog(2, ("Cleaning up timed out callbacks\n"));
afs_ctime(&now, tbuffer, sizeof(tbuffer))));
}
}
+#ifdef AFS_DEMAND_ATTACH_FS
+ FS_STATE_WRLOCK;
+#endif
}
+#ifdef AFS_DEMAND_ATTACH_FS
+ fs_state.FiveMinuteLWP_tranquil = 1;
+ FS_LOCK;
+ assert(pthread_cond_broadcast(&fs_state.worker_done_cv)==0);
+ FS_UNLOCK;
+ FS_STATE_UNLOCK;
+#endif
} /*FiveMinuteCheckLWP */
* other 5 minute activities because it may be delayed by timeouts when
* it probes the workstations
*/
+
static void
HostCheckLWP()
{
ViceLog(1, ("Starting Host check process\n"));
setThreadId("HostCheckLWP");
- while (1) {
+#ifdef AFS_DEMAND_ATTACH_FS
+ FS_STATE_WRLOCK;
+ while (fs_state.mode == FS_MODE_NORMAL) {
+ fs_state.HostCheckLWP_tranquil = 1;
+ FS_STATE_UNLOCK;
+#else
+ while(1) {
+#endif
+
#ifdef AFS_PTHREAD_ENV
sleep(fiveminutes);
#else /* AFS_PTHREAD_ENV */
IOMGR_Sleep(fiveminutes);
#endif /* AFS_PTHREAD_ENV */
+
+#ifdef AFS_DEMAND_ATTACH_FS
+ FS_STATE_WRLOCK;
+ if (fs_state.mode != FS_MODE_NORMAL) {
+ break;
+ }
+ fs_state.HostCheckLWP_tranquil = 0;
+ FS_STATE_UNLOCK;
+#endif
+
ViceLog(2, ("Checking for dead venii & clients\n"));
h_CheckHosts();
+
+#ifdef AFS_DEMAND_ATTACH_FS
+ FS_STATE_WRLOCK;
+#endif
}
+#ifdef AFS_DEMAND_ATTACH_FS
+ fs_state.HostCheckLWP_tranquil = 1;
+ FS_LOCK;
+ assert(pthread_cond_broadcast(&fs_state.worker_done_cv)==0);
+ FS_UNLOCK;
+ FS_STATE_UNLOCK;
+#endif
} /*HostCheckLWP */
/* This LWP does fsync checks every 5 minutes: it should not be used for
assert(pthread_mutex_init(&fsync_glock_mutex, NULL) == 0);
#endif
- while (1) {
+#ifdef AFS_DEMAND_ATTACH_FS
+ FS_STATE_WRLOCK;
+ while (fs_state.mode == FS_MODE_NORMAL) {
+ fs_state.FsyncCheckLWP_tranquil = 1;
+ FS_STATE_UNLOCK;
+#else
+ while(1) {
+#endif
FSYNC_LOCK;
#ifdef AFS_PTHREAD_ENV
/* rounding is fine */
ViceLog(0, ("LWP_WaitProcess returned %d\n", code));
#endif /* AFS_PTHREAD_ENV */
FSYNC_UNLOCK;
+
+#ifdef AFS_DEMAND_ATTACH_FS
+ FS_STATE_WRLOCK;
+ if (fs_state.mode != FS_MODE_NORMAL) {
+ break;
+ }
+ fs_state.FsyncCheckLWP_tranquil = 0;
+ FS_STATE_UNLOCK;
+#endif /* AFS_DEMAND_ATTACH_FS */
+
ViceLog(2, ("Checking for fsync events\n"));
do {
code = BreakLaterCallBacks();
} while (code != 0);
+#ifdef AFS_DEMAND_ATTACH_FS
+ FS_STATE_WRLOCK;
+#endif
}
+#ifdef AFS_DEMAND_ATTACH_FS
+ fs_state.FsyncCheckLWP_tranquil = 1;
+ FS_LOCK;
+ assert(pthread_cond_broadcast(&fs_state.worker_done_cv)==0);
+ FS_UNLOCK;
+ FS_STATE_UNLOCK;
+#endif /* AFS_DEMAND_ATTACH_FS */
}
/*------------------------------------------------------------------------
("Vice was last started at %s\n",
afs_ctime(&StartTime, tbuffer, sizeof(tbuffer))));
+#ifdef AFS_DEMAND_ATTACH_FS
+ /* XXX perhaps set extended stats verbosity flags
+ * based upon LogLevel ?? */
+ VPrintExtendedCacheStats(VOL_STATS_PER_CHAIN2);
+#endif
VPrintCacheStats();
VPrintDiskStats();
DStat(&dirbuff, &dircall, &dirio);
time_t now = time(0);
char tbuffer[32];
+ /* do not allows new reqests to be served from now on, all new requests
+ * are returned with an error code of RX_RESTARTING ( transient failure ) */
+ rx_SetRxTranquil(); /* dhruba */
+
+#ifdef AFS_DEMAND_ATTACH_FS
+ FS_STATE_WRLOCK;
+ fs_state.mode = FS_MODE_SHUTDOWN;
+ FS_STATE_UNLOCK;
+#endif
+
ViceLog(0,
("Shutting down file server at %s",
afs_ctime(&now, tbuffer, sizeof(tbuffer))));
if (!dopanic)
PrintCounters();
- /* do not allows new reqests to be served from now on, all new requests
- * are returned with an error code of RX_RESTARTING ( transient failure ) */
- rx_SetRxTranquil(); /* dhruba */
+ /* shut down volume package */
VShutdown();
+#ifdef AFS_DEMAND_ATTACH_FS
+ if (fs_state.options.fs_state_save) {
+ /*
+ * demand attach fs
+ * save fileserver state to disk */
+
+ /* make sure background threads have finished all of their asynchronous
+ * work on host and callback structures */
+ FS_STATE_RDLOCK;
+ while (!fs_state.FiveMinuteLWP_tranquil ||
+ !fs_state.HostCheckLWP_tranquil ||
+ !fs_state.FsyncCheckLWP_tranquil) {
+ FS_LOCK;
+ FS_STATE_UNLOCK;
+ ViceLog(0, ("waiting for background host/callback threads to quiesce before saving fileserver state...\n"));
+ assert(pthread_cond_wait(&fs_state.worker_done_cv, &fileproc_glock_mutex) == 0);
+ FS_UNLOCK;
+ FS_STATE_RDLOCK;
+ }
+
+ /* ok. it should now be fairly safe. let's do the state dump */
+ fs_stateSave();
+ }
+#endif /* AFS_DEMAND_ATTACH_FS */
+
if (debugFile) {
rx_PrintStats(debugFile);
fflush(debugFile);
static void
FlagMsg()
{
- char buffer[1024];
+ char buffer[2048];
/* default supports help flag */
strcat(buffer, "[-rxdbg (enable rx debugging)] ");
strcat(buffer, "[-rxdbge (enable rxevent debugging)] ");
strcat(buffer, "[-rxmaxmtu <bytes>] ");
-#if AFS_PTHREAD_ENV
- strcat(buffer, "[-vattachpar <number of volume attach threads>] ");
+#ifdef AFS_DEMAND_ATTACH_FS
+ strcat(buffer, "[-fs-state-dont-save (disable state save during shutdown)] ");
+ strcat(buffer, "[-fs-state-dont-restore (disable state restore during startup)] ");
+ strcat(buffer, "[-fs-state-verify <none|save|restore|both> (default is both)] ");
+ strcat(buffer, "[-vattachpar <max number of volume attach/shutdown threads> (default is 1)] ");
+ strcat(buffer, "[-vhashsize <log(2) of number of volume hash buckets> (default is 8)] ");
+ strcat(buffer, "[-vlrudisable (disable VLRU functionality)] ");
+ strcat(buffer, "[-vlruthresh <minutes before unused volumes become eligible for soft detach> (default is 2 hours)] ");
+ strcat(buffer, "[-vlruinterval <seconds between VLRU scans> (default is 2 minutes)] ");
+ strcat(buffer, "[-vlrumax <max volumes to soft detach in one VLRU scan> (default is 8)] ");
+#elif AFS_PTHREAD_ENV
+ strcat(buffer, "[-vattachpar <number of volume attach threads> (default is 1)] ");
#endif
#ifdef AFS_AIX32_ENV
strcat(buffer, "[-m <min percentage spare in partition>] ");
#ifdef AFS_PTHREAD_ENV
} else if (!strcmp(argv[i], "-vattachpar")) {
if ((i + 1) >= argc) {
- fprintf(stderr, "missing argument for -vattachpar\n");
+ fprintf(stderr, "missing argument for %s\n", argv[i]);
return -1;
}
vol_attach_threads = atoi(argv[++i]);
#endif /* AFS_PTHREAD_ENV */
+#ifdef AFS_DEMAND_ATTACH_FS
+ } else if (!strcmp(argv[i], "-fs-state-dont-save")) {
+ fs_state.options.fs_state_save = 0;
+ } else if (!strcmp(argv[i], "-fs-state-dont-restore")) {
+ fs_state.options.fs_state_restore = 0;
+ } else if (!strcmp(argv[i], "-fs-state-verify")) {
+ if ((i + 1) >= argc) {
+ fprintf(stderr, "missing argument for %s\n", argv[i]);
+ return -1;
+ }
+ i++;
+ if (!strcmp(argv[i], "none")) {
+ fs_state.options.fs_state_verify_before_save = 0;
+ fs_state.options.fs_state_verify_after_restore = 0;
+ } else if (!strcmp(argv[i], "save")) {
+ fs_state.options.fs_state_verify_after_restore = 0;
+ } else if (!strcmp(argv[i], "restore")) {
+ fs_state.options.fs_state_verify_before_save = 0;
+ } else if (!strcmp(argv[i], "both")) {
+ /* default */
+ } else {
+ fprintf(stderr, "invalid argument for %s\n", argv[i-1]);
+ return -1;
+ }
+ } else if (!strcmp(argv[i], "-vhashsize")) {
+ if ((i + 1) >= argc) {
+ fprintf(stderr, "missing argument for %s\n", argv[i]);
+ return -1;
+ }
+ VSetVolHashSize(atoi(argv[++i]));
+ } else if (!strcmp(argv[i], "-vlrudisable")) {
+ VLRU_SetOptions(VLRU_SET_ENABLED, 0);
+ } else if (!strcmp(argv[i], "-vlruthresh")) {
+ if ((i + 1) >= argc) {
+ fprintf(stderr, "missing argument for %s\n", argv[i]);
+ return -1;
+ }
+ VLRU_SetOptions(VLRU_SET_THRESH, 60*atoi(argv[++i]));
+ } else if (!strcmp(argv[i], "-vlruinterval")) {
+ if ((i + 1) >= argc) {
+ fprintf(stderr, "missing argument for %s\n", argv[i]);
+ return -1;
+ }
+ VLRU_SetOptions(VLRU_SET_INTERVAL, atoi(argv[++i]));
+ } else if (!strcmp(argv[i], "-vlrumax")) {
+ if ((i + 1) >= argc) {
+ fprintf(stderr, "missing argument for %s\n", argv[i]);
+ return -1;
+ }
+ VLRU_SetOptions(VLRU_SET_MAX, atoi(argv[++i]));
+#endif /* AFS_DEMAND_ATTACH_FS */
} else if (!strcmp(argv[i], "-s")) {
Sawsmall = 1;
if ((i + 1) >= argc) {
exit(1);
}
+#ifdef AFS_DEMAND_ATTACH_FS
+ if (fs_state.options.fs_state_restore) {
+ /*
+ * demand attach fs
+ * restore fileserver state */
+ fs_stateRestore();
+ }
+#endif /* AFS_DEMAND_ATTACH_FS */
+
/*
* We are done calling fopen/fdopen. It is safe to use a large
* of the file descriptor cache.
* This software has been released under the terms of the IBM Public
* License. For details, see the LICENSE file in the top-level source
* directory or online at http://www.openafs.org/dl/license10.html
+ *
+ * Portions Copyright (c) 2006 Sine Nomine Associates
*/
/* file.h - include file for the File Server */
* Start with clean version to sync test and dev trees.
* */
+#ifndef _AFS_VICED_VICED_H
+#define _AFS_VICED_VICED_H
+
#include <afs/afssyscalls.h>
#include <afs/afsutil.h>
#include "fs_stats.h" /*Defs for xstat-based statistics */
} DirHandle;
-struct cbcounters {
- int DeleteFiles;
- int DeleteCallBacks;
- int BreakCallBacks;
- int AddCallBacks;
- int GotSomeSpaces;
- int DeleteAllCallBacks;
- int nFEs, nCBs, nblks;
- int CBsTimedOut;
- int nbreakers;
- int GSS1, GSS2, GSS3, GSS4, GSS5;
-};
#define MAXCNTRS (AFS_HIGHEST_OPCODE+1)
#define FSYNC_LOCK
#define FSYNC_UNLOCK
#endif /* AFS_PTHREAD_ENV */
+
+
+#ifdef AFS_DEMAND_ATTACH_FS
+/*
+ * demand attach fs
+ * fileserver mode support
+ */
+struct fs_state {
+ volatile int mode;
+ volatile byte FiveMinuteLWP_tranquil; /* five minute check thread is shutdown or sleeping */
+ volatile byte HostCheckLWP_tranquil; /* host check thread is shutdown or sleeping */
+ volatile byte FsyncCheckLWP_tranquil; /* fsync check thread is shutdown or sleeping */
+ volatile byte salvsync_fatal_error; /* fatal error with salvsync comm */
+
+ /* some command-line options we use in
+ * various places
+ *
+ * these fields are immutable once we
+ * go multithreaded */
+ struct {
+ byte fs_state_save;
+ byte fs_state_restore;
+ byte fs_state_verify_before_save;
+ byte fs_state_verify_after_restore;
+ } options;
+
+ pthread_cond_t worker_done_cv;
+ pthread_rwlock_t state_lock;
+};
+
+extern struct fs_state fs_state;
+
+/* this lock is defined to be directly above FS_LOCK in the locking hierarchy */
+#define FS_STATE_RDLOCK assert(pthread_rwlock_rdlock(&fs_state.state_lock) == 0)
+#define FS_STATE_WRLOCK assert(pthread_rwlock_wrlock(&fs_state.state_lock) == 0)
+#define FS_STATE_UNLOCK assert(pthread_rwlock_unlock(&fs_state.state_lock) == 0)
+
+#define FS_MODE_NORMAL 0
+#define FS_MODE_SHUTDOWN 1
+#endif /* AFS_DEMAND_ATTACH_FS */
+
+
+#endif /* _AFS_VICED_VICED_H */
+/*
+ * Copyright 2000, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ *
+ * This software has been released under the terms of the IBM Public
+ * License. For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+#ifndef _AFS_VICED_VICED_PROTOTYPES_H
+#define _AFS_VICED_VICED_PROTOTYPES_H
+
extern int sendBufSize;
afs_int32 sys_error_to_et(afs_int32 in);
void init_sys_error_to_et(void);
+
+#ifdef AFS_DEMAND_ATTACH_FS
+/*
+ * demand attach fs
+ * fileserver state serialization
+ */
+extern int fs_stateSave(void);
+extern int fs_stateRestore(void);
+#endif /* AFS_DEMAND_ATTACH_FS */
+
+#endif /* _AFS_VICED_VICED_PROTOTYPES_H */
${TOP_LIBDIR}/libsys.a ${TOP_LIBDIR}/libdir.a \
${TOP_LIBDIR}/liblwp.a ${TOP_LIBDIR}/libacl.a
-CFLAGS = ${COMMON_CFLAGS} -D${SYS_NAME} ${FSINCLUDES} ${XCFLAGS} ${ARCHFLAGS}
+CFLAGS = ${COMMON_CFLAGS} -D${SYS_NAME} ${FSINCLUDES} ${XCFLAGS} ${ARCHFLAGS} -DFSSYNC_BUILD_SERVER -DFSSYNC_BUILD_CLIENT
-PUBLICHEADERS=nfs.h vnode.h viceinode.h volume.h voldefs.h partition.h\
- fssync.h ihandle.h namei_ops.h
+PUBLICHEADERS=nfs.h vnode.h viceinode.h volume.h voldefs.h partition.h \
+ fssync.h ihandle.h namei_ops.h salvsync.h daemon_com.h
-VLIBOBJS=vnode.o volume.o vutil.o partition.o fssync.o purge.o \
- clone.o nuke.o devname.o listinodes.o common.o ihandle.o \
- namei_ops.o
+VLIBOBJS=vnode.o volume.o vutil.o partition.o fssync-server.o fssync-client.o \
+ clone.o nuke.o devname.o listinodes.o common.o ihandle.o purge.o \
+ namei_ops.o salvsync-server.o salvsync-client.o daemon_com.o
-OBJECTS=${VLIBOBJS} physio.o vol-salvage.o vol-info.o vol-dump.o vol-bless.o
+OBJECTS=${VLIBOBJS} physio.o vol-salvage.o vol-info.o vol-dump.o vol-bless.o fssync-debug.o
all: gi \
${TOP_LIBDIR}/vlib.a \
${TOP_LIBDIR}/libvlib.a \
salvager \
volinfo \
+ fssync-debug \
$(FS_CONV_OSF40D) \
$(XFS_SIZE_CHECK) \
$(FS_CONV_SOL26) \
${TOP_INCDIR}/afs/voldefs.h \
${TOP_INCDIR}/afs/partition.h \
${TOP_INCDIR}/afs/fssync.h \
+ ${TOP_INCDIR}/afs/salvsync.h \
+ ${TOP_INCDIR}/afs/daemon_com.h \
${TOP_INCDIR}/afs/ihandle.h \
${TOP_INCDIR}/afs/namei_ops.h
${DESTDIR}${libdir}/afs/libvlib.a \
${DESTDIR}${afssrvlibexecdir}/salvager \
${DESTDIR}${afssrvsbindir}/volinfo \
+ ${DESTDIR}${afssrvsbindir}/fssync-debug \
$(install_FS_CONV_OSF40D) \
$(install_XFS_SIZE_CHECK) \
$(install_FS_CONV_SOL26) \
${DESTDIR}${includedir}/afs/voldefs.h \
${DESTDIR}${includedir}/afs/partition.h \
${DESTDIR}${includedir}/afs/fssync.h \
+ ${DESTDIR}${includedir}/afs/salvsync.h \
+ ${DESTDIR}${includedir}/afs/daemon_com.h \
${DESTDIR}${includedir}/afs/ihandle.h \
${DESTDIR}${includedir}/afs/namei_ops.h
${DEST}/root.server/usr/afs/bin/volinfo: volinfo
${INSTALL} -s $? $@
+${DEST}/root.server/usr/afs/bin/fssync-debug: fssync-debug
+ if test "@DEMAND_ATTACH@" = "no"; then \
+ ${INSTALL} -s $? $@ ; \
+ fi
+
${DEST}/lib/afs/vlib.a: vlib.a
${INSTALL} $? $@
${DEST}/include/afs/fssync.h: fssync.h
${INSTALL} $? $@
+${DEST}/include/afs/salvsync.h: salvsync.h
+ ${INSTALL} $? $@
+
+${DEST}/include/afs/daemon_com.h: daemon_com.h
+ ${INSTALL} $? $@
+
${DEST}/include/afs/ihandle.h: ihandle.h
${INSTALL} $? $@
${OBJECTS}: ${PUBLICHEADERS} ${TOP_INCDIR}/lwp.h ${TOP_INCDIR}/lock.h ${TOP_INCDIR}/afs/afsint.h vutils.h salvage.h AFS_component_version_number.c
vol-salvage.o vutil.o: volinodes.h
+vol-salvage.o salvager.o: vol-salvage.h
+vol-salvage.o: salvsync.h daemon_com.h
vlib.a: ${VLIBOBJS} AFS_component_version_number.o
$(RM) -f $@
$(RANLIB) $@
# new salvager: remove references to /vice by linking with novice.o
-salvager: vol-salvage.o physio.o vlib.a
- ${CC} ${LDFLAGS} -o salvager vol-salvage.o physio.o ${LIBS} ${XLIBS}
+salvager: vol-salvage.o physio.o vlib.a salvager.o ${LIBS}
+ ${CC} ${LDFLAGS} -o salvager vol-salvage.o physio.o salvager.o ${LIBS} ${XLIBS}
vol-salvage: vol-salvage.o
vol-info: vol-info.o physio.o ihandle.o
${CC} ${CFLAGS} -o volinfo vol-info.o physio.o \
ihandle.o ${LIBS} ${XLIBS}
+fssync-debug: fssync-debug.o physio.o AFS_component_version_number.c ${LIBS}
+ ${CC} ${LDFLAGS} -o fssync-debug fssync-debug.o physio.o ${LIBS} ${XLIBS}
+
vol-bless: vol-bless.o physio.o ihandle.o ${LIBS}
${CC} ${CFLAGS} -o vol-bless vol-bless.o physio.o ${LIBS} ${XLIBS}
-fs_conv_dux40D: fs_conv_411.o
+fs_conv_dux40D: fs_conv_411.o ${LIBS}
${CC} ${CFLAGS} ${TOP_LIBDIR}/libcmd.a -o fs_conv_dux40D fs_conv_411.o ${LIBS} ${XLIBS}
-fs_conv_sol26: fs_conv_411.o vlib.a
+fs_conv_sol26: fs_conv_411.o ${LIBS}
${CC} ${CFLAGS} ${TOP_LIBDIR}/libcmd.a -o fs_conv_sol26 fs_conv_411.o ${LIBS} ${XLIBS}
fs_conv_411.o: fs_conv_411.c AFS_component_version_number.c
${DESTDIR}${afssrvsbindir}/volinfo: volinfo
${INSTALL} -s $? $@
+${DESTDIR}${afssrvsbindir}/fssync-debug: fssync-debug
+ if test "@DEMAND_ATTACH@" = "no" ; then \
+ ${INSTALL} -s $? $@ ; \
+ fi
+
${DESTDIR}${includedir}/afs/nfs.h: nfs.h
${INSTALL} $? $@
${TOP_INCDIR}/afs/fssync.h: fssync.h
${INSTALL} $? $@
+${DESTDIR}${includedir}/afs/salvsync.h: salvsync.h
+ ${INSTALL} $? $@
+
+${TOP_INCDIR}/afs/salvsync.h: salvsync.h
+ ${INSTALL} $? $@
+
+${DESTDIR}${includedir}/afs/daemon_com.h: daemon_com.h
+ ${INSTALL} $? $@
+
+${TOP_INCDIR}/afs/daemon_com.h: daemon_com.h
+ ${INSTALL} $? $@
+
${DESTDIR}${includedir}/afs/ihandle.h: ihandle.h
${INSTALL} $? $@
${TOP_INCDIR}/afs/namei_ops.h: namei_ops.h
${INSTALL} $? $@
+${DESTDIR}${includedir}/afs/salvage.h: salvage.h
+ ${INSTALL} $? $@
+
+${TOP_INCDIR}/afs/salvage.h: salvage.h
+ ${INSTALL} $? $@
+
+${DESTDIR}${includedir}/afs/vol-salvage.h: vol-salvage.h
+ ${INSTALL} $? $@
+
+${TOP_INCDIR}/afs/vol-salvage.h: vol-salvage.h
+ ${INSTALL} $? $@
+
dest: \
${DEST}/lib/afs/vlib.a \
${DEST}/lib/afs/libvlib.a \
${DEST}/root.server/usr/afs/bin/salvager \
${DEST}/root.server/usr/afs/bin/volinfo \
+ ${DEST}/root.server/usr/afs/bin/fssync-debug \
$(dest_FS_CONV_OSF40D) \
$(dest_XFS_SIZE_CHECK) \
$(dest_FS_CONV_SOL26) \
${DEST}/include/afs/voldefs.h \
${DEST}/include/afs/partition.h \
${DEST}/include/afs/fssync.h \
+ ${DEST}/include/afs/salvsync.h \
+ ${DEST}/include/afs/daemon_com.h \
${DEST}/include/afs/ihandle.h \
${DEST}/include/afs/namei_ops.h
check-splint::
sh $(HELPER_SPLINT) $(CFLAGS) \
- vnode.c volume.c vutil.c partition.c fssync.c purge.c \
+ vnode.c volume.c vutil.c partition.c fssync-server.c fssync-client.c \
clone.c nuke.c devname.c listinodes.c common.c ihandle.c \
- namei_ops.c \
- physio.c vol-salvage.c vol-info.c vol-bless.c
+ namei_ops.c salvsync-server.c salvsync-client.c daemon_com.c purge.c \
+ physio.c vol-salvage.c vol-info.c vol-bless.c fssync-debug.c
# License. For details, see the LICENSE file in the top-level source
# directory or online at http://www.openafs.org/dl/license10.html
+AFSDEV_AUXCDEFINES = -DFSSYNC_BUILD_SERVER -DFSSYNC_BUILD_CLIENT
+
RELDIR=vol
!INCLUDE ..\config\NTMakefile.$(SYS_NAME)
!INCLUDE ..\config\NTMakefile.version
--- /dev/null
+/*
+ * Copyright 2006, Sine Nomine Associates and others.
+ * All Rights Reserved.
+ *
+ * This software has been released under the terms of the IBM Public
+ * License. For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+/*
+ * localhost interprocess communication for servers
+ *
+ * currently handled by a localhost socket
+ * (yes, this needs to be replaced someday)
+ */
+
+#ifndef _WIN32
+#define FD_SETSIZE 65536
+#endif
+
+#include <afsconfig.h>
+#include <afs/param.h>
+
+RCSID
+ ("$Header$");
+
+#include <sys/types.h>
+#include <stdio.h>
+#ifdef AFS_NT40_ENV
+#include <winsock2.h>
+#include <time.h>
+#else
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/time.h>
+#endif
+#include <errno.h>
+#include <assert.h>
+#include <signal.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
+
+
+#include <rx/xdr.h>
+#include <afs/afsint.h>
+#include "nfs.h"
+#include <afs/errors.h>
+#include "daemon_com.h"
+#include "lwp.h"
+#include "lock.h"
+#include <afs/afssyscalls.h>
+#include "ihandle.h"
+#include "vnode.h"
+#include "volume.h"
+#include "partition.h"
+#include <rx/rx_queue.h>
+
+/*@printflike@*/ extern void Log(const char *format, ...);
+
+#ifdef osi_Assert
+#undef osi_Assert
+#endif
+#define osi_Assert(e) (void)(e)
+
+int (*V_BreakVolumeCallbacks) ();
+
+#define MAXHANDLERS 4 /* Up to 4 clients; must be at least 2, so that
+ * move = dump+restore can run on single server */
+
+#define MAX_BIND_TRIES 5 /* Number of times to retry socket bind */
+
+static int getport(SYNC_client_state * state, struct sockaddr_in *addr);
+static int SYNC_ask_internal(SYNC_client_state * state, SYNC_command * com, SYNC_response * res);
+
+/* daemon com SYNC client interface */
+
+int
+SYNC_connect(SYNC_client_state * state)
+{
+ struct sockaddr_in addr;
+ /* I can't believe the following is needed for localhost connections!! */
+ static time_t backoff[] =
+ { 3, 3, 3, 5, 5, 5, 7, 15, 16, 24, 32, 40, 48, 0 };
+ time_t *timeout = &backoff[0];
+
+ if (state->fd >= 0) {
+ return 1;
+ }
+
+ for (;;) {
+ state->fd = getport(state, &addr);
+ if (connect(state->fd, (struct sockaddr *)&addr, sizeof(addr)) >= 0)
+ return 1;
+ if (!*timeout)
+ break;
+ if (!(*timeout & 1))
+ Log("SYNC_connect temporary failure (will retry)\n");
+ SYNC_disconnect(state);
+ sleep(*timeout++);
+ }
+ perror("SYNC_connect failed (giving up!)");
+ return 0;
+}
+
+int
+SYNC_disconnect(SYNC_client_state * state)
+{
+#ifdef AFS_NT40_ENV
+ closesocket(state->fd);
+#else
+ close(state->fd);
+#endif
+ state->fd = -1;
+ return 0;
+}
+
+afs_int32
+SYNC_closeChannel(SYNC_client_state * state)
+{
+ afs_int32 code;
+ SYNC_command com;
+ SYNC_response res;
+ SYNC_PROTO_BUF_DECL(ores);
+
+ if (state->fd == -1)
+ return SYNC_OK;
+
+ memset(&com, 0, sizeof(com));
+ memset(&res, 0, sizeof(res));
+
+ res.payload.len = SYNC_PROTO_MAX_LEN;
+ res.payload.buf = ores;
+
+ com.hdr.command = SYNC_COM_CHANNEL_CLOSE;
+ com.hdr.command_len = sizeof(SYNC_command_hdr);
+
+ /* in case the other end dropped, don't do any retries */
+ state->retry_limit = 0;
+ state->hard_timeout = 0;
+
+ code = SYNC_ask(state, &com, &res);
+
+ if (code == SYNC_OK) {
+ if (res.hdr.response != SYNC_OK) {
+ Log("SYNC_closeChannel: channel shutdown request denied; closing socket anyway\n");
+ } else if (!(res.hdr.flags & SYNC_FLAG_CHANNEL_SHUTDOWN)) {
+ Log("SYNC_closeChannel: channel shutdown request mishandled by server\n");
+ }
+ } else {
+ Log("SYNC_closeChannel: channel communications problem");
+ }
+
+ SYNC_disconnect(state);
+
+ return code;
+}
+
+int
+SYNC_reconnect(SYNC_client_state * state)
+{
+ SYNC_disconnect(state);
+ return SYNC_connect(state);
+}
+
+/* private function to fill in the sockaddr struct for us */
+static int
+getport(SYNC_client_state * state, struct sockaddr_in *addr)
+{
+ int sd;
+
+ memset(addr, 0, sizeof(*addr));
+ assert((sd = socket(AF_INET, SOCK_STREAM, 0)) >= 0);
+#ifdef STRUCT_SOCKADDR_HAS_SA_LEN
+ addr->sin_len = sizeof(struct sockaddr_in);
+#endif
+ addr->sin_addr.s_addr = htonl(0x7f000001);
+ addr->sin_family = AF_INET; /* was localhost->h_addrtype */
+ addr->sin_port = htons(state->port); /* XXXX htons not _really_ neccessary */
+
+ return sd;
+}
+
+afs_int32
+SYNC_ask(SYNC_client_state * state, SYNC_command * com, SYNC_response * res)
+{
+ int tries;
+ afs_uint32 now, timeout, code=SYNC_OK;
+
+ if (state->fatal_error) {
+ return SYNC_COM_ERROR;
+ }
+
+ if (state->fd == -1) {
+ SYNC_connect(state);
+ }
+
+ if (state->fd == -1) {
+ state->fatal_error = 1;
+ return SYNC_COM_ERROR;
+ }
+
+#ifdef AFS_DEMAND_ATTACH_FS
+ com->hdr.flags |= SYNC_FLAG_DAFS_EXTENSIONS;
+#endif
+
+ now = FT_ApproxTime();
+ timeout = now + state->hard_timeout;
+ for (tries = 0;
+ (tries <= state->retry_limit) && (now <= timeout);
+ tries++, now = FT_ApproxTime()) {
+ code = SYNC_ask_internal(state, com, res);
+ if (code == SYNC_OK) {
+ break;
+ } else if (code == SYNC_BAD_COMMAND) {
+ Log("SYNC_ask: protocol mismatch; make sure fileserver, volserver, salvageserver and salvager are same version\n");
+ break;
+ } else if (code == SYNC_COM_ERROR) {
+ Log("SYNC_ask: protocol communications failure; attempting reconnect to server\n");
+ SYNC_reconnect(state);
+ /* try again */
+ } else {
+ /* unknown (probably protocol-specific) response code, pass it up to the caller, and let them deal with it */
+ break;
+ }
+ }
+
+ if (code == SYNC_COM_ERROR) {
+ Log("SYNC_ask: fatal protocol error; disabling sync protocol to server running on port %d until next server restart\n",
+ state->port);
+ state->fatal_error = 1;
+ }
+
+ return code;
+}
+
+static afs_int32
+SYNC_ask_internal(SYNC_client_state * state, SYNC_command * com, SYNC_response * res)
+{
+ int n;
+ SYNC_PROTO_BUF_DECL(buf);
+#ifndef AFS_NT40_ENV
+ int iovcnt;
+ struct iovec iov[2];
+#endif
+
+ if (state->fd == -1) {
+ Log("SYNC_ask: invalid sync file descriptor\n");
+ res->hdr.response = SYNC_COM_ERROR;
+ goto done;
+ }
+
+ if (com->hdr.command_len > SYNC_PROTO_MAX_LEN) {
+ Log("SYNC_ask: internal SYNC buffer too small; please file a bug\n");
+ res->hdr.response = SYNC_COM_ERROR;
+ goto done;
+ }
+
+ com->hdr.proto_version = state->proto_version;
+
+ memcpy(buf, &com->hdr, sizeof(com->hdr));
+ if (com->payload.len) {
+ memcpy(buf + sizeof(com->hdr), com->payload.buf,
+ com->hdr.command_len - sizeof(com->hdr));
+ }
+
+#ifdef AFS_NT40_ENV
+ n = send(state->fd, buf, com->hdr.command_len, 0);
+ if (n != com->hdr.command_len) {
+ Log("SYNC_ask: write failed\n");
+ res->hdr.response = SYNC_COM_ERROR;
+ goto done;
+ }
+
+ n = recv(state->fd, buf, SYNC_PROTO_MAX_LEN, 0);
+ if (n == 0 || (n < 0 && WSAEINTR != WSAGetLastError())) {
+ Log("SYNC_ask: No response\n");
+ res->hdr.response = SYNC_COM_ERROR;
+ goto done;
+ }
+#else /* !AFS_NT40_ENV */
+ n = write(state->fd, buf, com->hdr.command_len);
+ if (com->hdr.command_len != n) {
+ Log("SYNC_ask: write failed\n");
+ res->hdr.response = SYNC_COM_ERROR;
+ goto done;
+ }
+
+ /* receive the response */
+ iov[0].iov_base = (char *)&res->hdr;
+ iov[0].iov_len = sizeof(res->hdr);
+ if (res->payload.len) {
+ iov[1].iov_base = (char *)res->payload.buf;
+ iov[1].iov_len = res->payload.len;
+ iovcnt = 2;
+ } else {
+ iovcnt = 1;
+ }
+ n = readv(state->fd, iov, iovcnt);
+ if (n == 0 || (n < 0 && errno != EINTR)) {
+ Log("SYNC_ask: No response\n");
+ res->hdr.response = SYNC_COM_ERROR;
+ goto done;
+ }
+#endif /* !AFS_NT40_ENV */
+
+ res->recv_len = n;
+
+ if (n < sizeof(res->hdr)) {
+ Log("SYNC_ask: response too short\n");
+ res->hdr.response = SYNC_COM_ERROR;
+ goto done;
+ }
+#ifdef AFS_NT40_ENV
+ memcpy(&res->hdr, buf, sizeof(res->hdr));
+#endif
+
+ if ((n - sizeof(res->hdr)) > res->payload.len) {
+ Log("SYNC_ask: response too long\n");
+ res->hdr.response = SYNC_COM_ERROR;
+ goto done;
+ }
+#ifdef AFS_NT40_ENV
+ memcpy(res->payload.buf, buf + sizeof(res->hdr), n - sizeof(res->hdr));
+#endif
+
+ if (res->hdr.response_len != n) {
+ Log("SYNC_ask: length field in response inconsistent\n");
+ res->hdr.response = SYNC_COM_ERROR;
+ goto done;
+ }
+ if (res->hdr.response == SYNC_DENIED) {
+ Log("SYNC_ask: negative response\n");
+ }
+
+ done:
+ return res->hdr.response;
+}
+
+
+/*
+ * daemon com SYNC server-side interfaces
+ */
+
+/* get a command */
+afs_int32
+SYNC_getCom(int fd, SYNC_command * com)
+{
+ int n;
+ afs_int32 code = SYNC_OK;
+#ifdef AFS_NT40_ENV
+ SYNC_PROTO_BUF_DECL(buf);
+#else
+ struct iovec iov[2];
+ int iovcnt;
+#endif
+
+#ifdef AFS_NT40_ENV
+ n = recv(fd, buf, SYNC_PROTO_MAX_LEN, 0);
+
+ if (n == 0 || (n < 0 && WSAEINTR != WSAGetLastError())) {
+ Log("SYNC_getCom: error receiving command\n");
+ code = SYNC_COM_ERROR;
+ goto done;
+ }
+#else /* !AFS_NT40_ENV */
+ iov[0].iov_base = (char *)&com->hdr;
+ iov[0].iov_len = sizeof(com->hdr);
+ if (com->payload.len) {
+ iov[1].iov_base = (char *)com->payload.buf;
+ iov[1].iov_len = com->payload.len;
+ iovcnt = 2;
+ } else {
+ iovcnt = 1;
+ }
+
+ n = readv(fd, iov, iovcnt);
+ if (n == 0 || (n < 0 && errno != EINTR)) {
+ Log("SYNC_getCom: error receiving command\n");
+ code = SYNC_COM_ERROR;
+ goto done;
+ }
+#endif /* !AFS_NT40_ENV */
+
+ com->recv_len = n;
+
+ if (n < sizeof(com->hdr)) {
+ Log("SYNC_getCom: command too short\n");
+ code = SYNC_COM_ERROR;
+ goto done;
+ }
+#ifdef AFS_NT40_ENV
+ memcpy(&com->hdr, buf, sizeof(com->hdr));
+#endif
+
+ if ((n - sizeof(com->hdr)) > com->payload.len) {
+ Log("SYNC_getCom: command too long\n");
+ code = SYNC_COM_ERROR;
+ goto done;
+ }
+#ifdef AFS_NT40_ENV
+ memcpy(com->payload.buf, buf + sizeof(com->hdr), n - sizeof(com->hdr));
+#endif
+
+ done:
+ return code;
+}
+
+/* put a response */
+afs_int32
+SYNC_putRes(int fd, SYNC_response * res)
+{
+ int n;
+ afs_int32 code = SYNC_OK;
+ SYNC_PROTO_BUF_DECL(buf);
+
+ if (res->hdr.response_len > (sizeof(res->hdr) + res->payload.len)) {
+ Log("SYNC_putRes: response_len field in response header inconsistent\n");
+ code = SYNC_COM_ERROR;
+ goto done;
+ }
+
+ if (res->hdr.response_len > SYNC_PROTO_MAX_LEN) {
+ Log("SYNC_putRes: internal SYNC buffer too small; please file a bug\n");
+ code = SYNC_COM_ERROR;
+ goto done;
+ }
+
+#ifdef AFS_DEMAND_ATTACH_FS
+ res->hdr.flags |= SYNC_FLAG_DAFS_EXTENSIONS;
+#endif
+
+ memcpy(buf, &res->hdr, sizeof(res->hdr));
+ if (res->payload.len) {
+ memcpy(buf + sizeof(res->hdr), res->payload.buf,
+ res->hdr.response_len - sizeof(res->hdr));
+ }
+
+#ifdef AFS_NT40_ENV
+ n = send(fd, buf, res->hdr.response_len, 0);
+#else /* !AFS_NT40_ENV */
+ n = write(fd, buf, res->hdr.response_len);
+#endif /* !AFS_NT40_ENV */
+
+ if (res->hdr.response_len != n) {
+ Log("SYNC_putRes: write failed\n");
+ res->hdr.response = SYNC_COM_ERROR;
+ goto done;
+ }
+
+ done:
+ return code;
+}
+
+/* return 0 for legal (null-terminated) string,
+ * 1 for illegal (unterminated) string */
+int
+SYNC_verifyProtocolString(char * buf, size_t len)
+{
+ int ret = 0;
+ size_t s_len;
+
+ s_len = afs_strnlen(buf, len);
+
+ return (s_len == len) ? 1 : 0;
+}
--- /dev/null
+/*
+ * Copyright 2006, Sine Nomine Associates and others.
+ * All Rights Reserved.
+ *
+ * This software has been released under the terms of the IBM Public
+ * License. For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+#ifndef _AFS_VOL_DAEMON_COM_H
+#define _AFS_VOL_DAEMON_COM_H
+
+/*
+ * SYNC protocol constants
+ */
+
+/* SYNC protocol command codes
+ *
+ * command codes 0-65535 are reserved for
+ * global SYNC package command codes
+ */
+#define SYNC_COM_CODE_USER_BASE 65536
+#define SYNC_COM_CODE_DECL(code) (SYNC_COM_CODE_USER_BASE+(code))
+
+/* general command codes */
+#define SYNC_COM_CHANNEL_CLOSE 0
+
+
+/* SYNC protocol response codes
+ *
+ * response codes 0-65535 are reserved for
+ * global SYNC package response codes
+ */
+#define SYNC_RES_CODE_USER_BASE 65536
+#define SYNC_RES_CODE_DECL(code) (SYNC_RES_CODE_USER_BASE+(code))
+
+/* general response codes */
+#define SYNC_OK 0 /* sync call returned ok */
+#define SYNC_DENIED 1 /* sync request denied by server */
+#define SYNC_COM_ERROR 2 /* sync protocol communicaions error */
+#define SYNC_BAD_COMMAND 3 /* sync command code not implemented by server */
+#define SYNC_FAILED 4 /* sync server-side procedure failed */
+
+
+/* SYNC protocol reason codes
+ *
+ * reason codes 0-65535 are reserved for
+ * global SYNC package reason codes
+ */
+#define SYNC_REASON_CODE_USER_BASE 65536
+#define SYNC_REASON_CODE_DECL(code) (SYNC_REASON_CODE_USER_BASE+(code))
+
+/* general reason codes */
+#define SYNC_REASON_NONE 0
+#define SYNC_REASON_MALFORMED_PACKET 1
+
+
+/* SYNC protocol flags
+ *
+ * flag bits 0-7 are reserved for
+ * global SYNC package flags
+ */
+#define SYNC_FLAG_CODE_USER_BASE 8
+#define SYNC_FLAG_CODE_DECL(code) (1 << (SYNC_FLAG_CODE_USER_BASE+(code)))
+
+/* general flag codes */
+#define SYNC_FLAG_CHANNEL_SHUTDOWN 0x1
+#define SYNC_FLAG_DAFS_EXTENSIONS 0x2 /* signal that other end of socket is compiled
+ * with demand attach extensions */
+
+/* SYNC protocol response buffers */
+#define SYNC_PROTO_MAX_LEN 768 /* maximum size of sync protocol message */
+
+/* use a large type to get proper buffer alignment so we can safely cast the pointer */