#define VFORMAT "V%010lu.vol"
#define VMAXPATHLEN 64 /* Maximum length (including null) of a volume
* external path name */
-
-/* Values for connect parameter to VInitVolumePackage */
-#define CONNECT_FS 1
-#define DONT_CONNECT_FS 0
common_prolog(struct cmd_syndesc * as, struct state * state)
{
register struct cmd_item *ti;
+ VolumePackageOptions opts;
#ifdef AFS_NT40_ENV
if (afs_winsockInit() < 0) {
}
#endif
- VInitVolumePackage(debugUtility, 1, 1,
- DONT_CONNECT_FS, 0);
+ VOptDefaults(debugUtility, &opts);
+ VInitVolumePackage2(debugUtility, &opts);
DInit(1);
if ((ti = as->parms[COMMON_PARMS_OFFSET].items)) { /* -reason */
programType = salvager;
} else if (!strcmp(ti->data, "salvageServer")) {
programType = salvageServer;
+ } else if (!strcmp(ti->data, "volumeServer")) {
+ programType = volumeServer;
+ } else if (!strcmp(ti->data, "volumeSalvager")) {
+ programType = volumeSalvager;
} else {
programType = (ProgramType) atoi(ti->data);
}
int curLimit;
time_t t;
afs_uint32 rx_bindhost;
+ VolumePackageOptions opts;
#ifdef AFS_AIX32_ENV
struct sigaction nsa;
* will be available "real soon now". Worry about whether we can satisfy the
* calls in the volume package itself.
*/
- if (VInitVolumePackage(fileServer, large, nSmallVns, 0, volcache)) {
+ VOptDefaults(fileServer, &opts);
+ opts.nLargeVnodes = large;
+ opts.nSmallVnodes = nSmallVns;
+ opts.volcache = volcache;
+
+ if (VInitVolumePackage2(fileServer, &opts)) {
ViceLog(0,
("Shutting down: errors encountered initializing volume package\n"));
VShutdown();
common_prolog(struct cmd_syndesc * as, struct state * state)
{
register struct cmd_item *ti;
+ VolumePackageOptions opts;
#ifdef AFS_NT40_ENV
if (afs_winsockInit() < 0) {
}
#endif
- VInitVolumePackage(debugUtility, 1, 1,
- DONT_CONNECT_FS, 0);
+ VOptDefaults(debugUtility, &opts);
+ VInitVolumePackage2(debugUtility, &opts);
DInit(1);
if ((ti = as->parms[COMMON_PARMS_OFFSET].items)) { /* -reason */
programType = salvager;
} else if (!strcmp(ti->data, "salvageServer")) {
programType = salvageServer;
+ } else if (!strcmp(ti->data, "volumeServer")) {
+ programType = volumeServer;
+ } else if (!strcmp(ti->data, "volumeSalvager")) {
+ programType = volumeSalvager;
} else {
programType = (ProgramType) atoi(ti->data);
}
afs_int32 code;
SYNC_response res;
SALVSYNC_response_hdr sres;
+ VolumePackageOptions opts;
- VInitVolumePackage(volumeUtility, 5, 5, DONT_CONNECT_FS, 0);
+ VOptDefaults(volumeUtility, &opts);
+ VInitVolumePackage2(volumeUtility, &opts);
SALVSYNC_clientInit();
code = SALVSYNC_SalvageVolume(vid, pname, SALVSYNC_SALVAGE, SALVSYNC_OPERATOR, 0, NULL);
pthread_t tid;
pthread_attr_t attrs;
int slot;
+ VolumePackageOptions opts;
/* All entries to the log will be appended. Useful if there are
* multiple salvagers appending to the log.
/* Get and hold a lock for the duration of the salvage to make sure
* that no other salvage runs at the same time. The routine
- * VInitVolumePackage (called below) makes sure that a file server or
+ * VInitVolumePackage2 (called below) makes sure that a file server or
* other volume utilities don't interfere with the salvage.
*/
child_slot = (int *) malloc(Parallel * sizeof(int));
assert(child_slot != NULL);
memset(child_slot, 0, Parallel * sizeof(int));
-
+
/* initialize things */
- VInitVolumePackage(salvageServer, 5, 5,
- 1, 0);
+ VOptDefaults(salvageServer, &opts);
+ VInitVolumePackage2(salvageServer, &opts);
DInit(10);
queue_Init(&pending_q);
queue_Init(&log_cleanup_queue);
register struct cmd_item *ti;
char pname[100], *temp;
afs_int32 seenpart = 0, seenvol = 0, vid = 0;
+ ProgramType pt;
#ifdef FAST_RESTART
afs_int32 seenany = 0;
#endif
+ VolumePackageOptions opts;
struct DiskPartition64 *partP;
#ifdef AFS_SGI_VNODE_GLUE
}
}
#endif
- VInitVolumePackage(seenvol ? volumeUtility : salvager, 5, 5,
- DONT_CONNECT_FS, 0);
+
+ if (seenvol) {
+ pt = volumeSalvager;
+ } else {
+ pt = salvager;
+ }
+
+ VOptDefaults(pt, &opts);
+ VInitVolumePackage2(pt, &opts);
DInit(10);
#ifdef AFS_NT40_ENV
if (myjob.cj_number != NOT_CHILD) {
/* Get and hold a lock for the duration of the salvage to make sure
* that no other salvage runs at the same time. The routine
- * VInitVolumePackage (called below) makes sure that a file server or
+ * VInitVolumePackage2 (called below) makes sure that a file server or
* other volume utilities don't interfere with the salvage.
*/
get_salvage_lock = 1;
int argc;
char **argv;
{
- VInitVolumePackage(1, 0, 0, 0, 0);
+ VolumePackageOptions opts;
+
+ VOptDefaults(1, &opts);
+ VInitVolumePackage2(1, &opts);
VPrintDiskStats();
}
Error ec;
int bless, unbless, nofssync;
int volumeId;
+ VolumePackageOptions opts;
+ ProgramType pt;
volumeId = atoi(as->parms[0].items->data);
bless = !!(as->parms[1].items);
exit(1);
}
- if (VInitVolumePackage(nofssync ? salvager : volumeUtility, 5, 5, 1, 0)) {
+ if (nofssync) {
+ pt = salvager;
+ } else {
+ pt = volumeUtility;
+ }
+
+ VOptDefaults(pt, &opts);
+ opts.canUseFSSYNC = !nofssync;
+
+ if (VInitVolumePackage2(pt, &opts)) {
fprintf(stderr,"Unable to initialize volume package\n");
exit(1);
}
/* Pathname for server id definitions--the server id is used to allocate volume numbers */
#define SERVERLISTPATH "/vice/db/servers"
-
-/* Values for connect parameter to VInitVolumePackage */
-#define CONNECT_FS 1
-#define DONT_CONNECT_FS 0
int LogLevel; /* Vice loglevel--not defined as extern so that it will be
* defined when not linked with vice, XXXX */
ProgramType programType; /* The type of program using the package */
+static VolumePackageOptions vol_opts;
/* extended volume package statistics */
VolPkgStats VStats;
/***************************************************/
/* Startup routines */
/***************************************************/
+/**
+ * assign default values to a VolumePackageOptions struct.
+ *
+ * Always call this on a VolumePackageOptions struct first, then set any
+ * specific options you want, then call VInitVolumePackage2.
+ *
+ * @param[in] pt caller's program type
+ * @param[out] opts volume package options
+ */
+void
+VOptDefaults(ProgramType pt, VolumePackageOptions *opts)
+{
+ opts->nLargeVnodes = opts->nSmallVnodes = 5;
+ opts->volcache = 0;
+
+ opts->canScheduleSalvage = 0;
+ opts->canUseFSSYNC = 0;
+ opts->canUseSALVSYNC = 0;
+
+ switch (pt) {
+ case fileServer:
+ opts->canScheduleSalvage = 1;
+ opts->canUseSALVSYNC = 1;
+ break;
+
+ case salvageServer:
+ opts->canUseFSSYNC = 1;
+ break;
+
+ case volumeServer:
+ opts->nLargeVnodes = 0;
+ opts->nSmallVnodes = 0;
+
+ opts->canUseFSSYNC = 1;
+ break;
+
+ default:
+ /* noop */
+ break;
+ }
+}
int
-VInitVolumePackage(ProgramType pt, afs_uint32 nLargeVnodes, afs_uint32 nSmallVnodes,
- int connect, afs_uint32 volcache)
+VInitVolumePackage2(ProgramType pt, VolumePackageOptions * opts)
{
int errors = 0; /* Number of errors while finding vice partitions. */
programType = pt;
+ vol_opts = *opts;
memset(&VStats, 0, sizeof(VStats));
VStats.hdr_cache_size = 200;
}
#endif
#if defined(AFS_DEMAND_ATTACH_FS) && defined(SALVSYNC_BUILD_CLIENT)
- if (programType == fileServer) {
+ if (VCanUseSALVSYNC()) {
/* establish a connection to the salvager at this point */
assert(VConnectSALV() != 0);
}
#endif /* AFS_DEMAND_ATTACH_FS */
- if (volcache > VStats.hdr_cache_size)
- VStats.hdr_cache_size = volcache;
+ if (opts->volcache > VStats.hdr_cache_size)
+ VStats.hdr_cache_size = opts->volcache;
VInitVolumeHeaderCache(VStats.hdr_cache_size);
- VInitVnodes(vLarge, nLargeVnodes);
- VInitVnodes(vSmall, nSmallVnodes);
+ VInitVnodes(vLarge, opts->nLargeVnodes);
+ VInitVnodes(vSmall, opts->nSmallVnodes);
errors = VAttachPartitions();
}
#ifdef FSSYNC_BUILD_CLIENT
- if (programType == volumeUtility && connect) {
+ if (VCanUseFSSYNC()) {
if (!VConnectFS()) {
- Log("Unable to connect to file server; will retry at need\n");
- /*exit(1);*/
- }
- }
#ifdef AFS_DEMAND_ATTACH_FS
- else if (programType == salvageServer) {
- if (!VConnectFS()) {
- Log("Unable to connect to file server; aborted\n");
- exit(1);
+ if (programType == salvageServer) {
+ Log("Unable to connect to file server; aborted\n");
+ exit(1);
+ }
+#endif /* AFS_DEMAND_ATTACH_FS */
+ Log("Unable to connect to file server; will retry at need\n");
}
}
-#endif /* AFS_DEMAND_ATTACH_FS */
#endif /* FSSYNC_BUILD_CLIENT */
return 0;
}
goto done;
}
- if (programType == volumeUtility) {
+ if (VRequiresPartLock()) {
assert(VInit == 3);
VLockPartition_r(partition);
} else if (programType == fileServer) {
DiskToVolumeHeader(&iheader, &diskHeader);
#ifdef FSSYNC_BUILD_CLIENT
- if (programType == volumeUtility && mode != V_SECRETLY && mode != V_PEEK) {
+ if (VCanUseFSSYNC() && mode != V_SECRETLY && mode != V_PEEK) {
VOL_LOCK;
if (FSYNC_VolOp(iheader.id, partition, FSYNC_VOL_NEEDVOLUME, mode, NULL)
!= SYNC_OK) {
* with vol_glock_mutex held */
vp = attach2(ec, volumeId, path, &iheader, partp, vp, isbusy, mode);
- if (programType == volumeUtility && vp) {
+ if (VCanUseFSSYNC() && vp) {
if ((mode == V_VOLUPD) || (VolumeWriteable(vp) && (mode == V_CLONE))) {
/* mark volume header as in use so that volser crashes lead to a
* salvage attempt */
* fix is for the server to allow the return of readonly volumes
* that it doesn't think are really checked out. */
#ifdef FSSYNC_BUILD_CLIENT
- if (programType == volumeUtility && vp == NULL &&
+ if (VCanUseFSSYNC() && vp == NULL &&
mode != V_SECRETLY && mode != V_PEEK) {
FSYNC_VolOp(iheader.id, partition, FSYNC_VOL_ON, 0, NULL);
} else
}
done:
- if (programType == volumeUtility) {
+ if (VRequiresPartLock()) {
VUnlockPartition_r(partition);
}
if (*ec) {
#if defined(AFS_DEMAND_ATTACH_FS)
if (*ec && ((*ec != VOFFLINE) || (V_attachState(vp) != VOL_STATE_UNATTACHED))) {
VOL_LOCK;
- if (programType == fileServer) {
+ if (VCanScheduleSalvage()) {
VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_INVALIDATE_HEADER);
vp->nUsers = 0;
} else {
vp->specialStatus = 0;
VOL_LOCK;
#if defined(AFS_DEMAND_ATTACH_FS)
- if (programType == fileServer) {
+ if (VCanScheduleSalvage()) {
VRequestSalvage_r(ec, vp, SALVSYNC_NEEDED, VOL_SALVAGE_INVALIDATE_HEADER);
vp->nUsers = 0;
} else {
}
VOL_LOCK;
- if (programType == fileServer) {
+ if (VShouldCheckInUse(mode)) {
#ifndef FAST_RESTART
if (V_inUse(vp) && VolumeWriteable(vp)) {
if (!V_needsSalvaged(vp)) {
}
#endif /* FAST_RESTART */
- if (V_destroyMe(vp) == DESTROY_ME) {
+ if (programType == fileServer && V_destroyMe(vp) == DESTROY_ME) {
+ /* Only check destroyMe if we are the fileserver, since the
+ * volserver et al sometimes need to work with volumes with
+ * destroyMe set. Examples are 'temporary' volumes the
+ * volserver creates, and when we create a volume (destroyMe
+ * is set on creation; sometimes a separate volserver
+ * transaction is created to clear destroyMe).
+ */
+
#if defined(AFS_DEMAND_ATTACH_FS)
/* schedule a salvage so the volume goes away on disk */
VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_INVALIDATE_HEADER);
Log("Volume %u: couldn't reread volume header\n",
vp->hashid);
#ifdef AFS_DEMAND_ATTACH_FS
- if (programType == fileServer) {
+ if (VCanScheduleSalvage()) {
VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_INVALIDATE_HEADER);
} else {
FreeVolume(vp);
VolumeId vid = V_id(vp);
#endif
- assert(programType != volumeUtility);
+ assert(programType != volumeUtility && programType != volumeServer);
if (!V_inUse(vp)) {
VPutVolume_r(vp);
return;
int useDone = FSYNC_VOL_ON;
*ec = 0; /* always "succeeds" */
- if (programType == volumeUtility) {
+ if (VCanUseFSSYNC()) {
notifyServer = vp->needsPutBack;
if (V_destroyMe(vp) == DESTROY_ME)
useDone = FSYNC_VOL_DONE;
* is not technically detached until the refcounts reach zero
*/
#ifdef FSSYNC_BUILD_CLIENT
- if (programType == volumeUtility && notifyServer) {
+ if (VCanUseFSSYNC() && notifyServer) {
/*
* Note: The server is not notified in the case of a bogus volume
* explicitly to make it possible to create a volume, do a partial
#endif
/* Too time consuming and unnecessary for the volserver */
- if (programType != volumeUtility) {
+ if (programType == fileServer) {
IH_CONDSYNC(vp->vnodeIndex[vLarge].handle);
IH_CONDSYNC(vp->vnodeIndex[vSmall].handle);
IH_CONDSYNC(vp->diskDataHandle);
#endif
/* Too time consuming and unnecessary for the volserver */
- if (programType != volumeUtility) {
+ if (programType == fileServer) {
IH_CONDSYNC(vp->vnodeIndex[vLarge].handle);
IH_CONDSYNC(vp->vnodeIndex[vSmall].handle);
IH_CONDSYNC(vp->diskDataHandle);
* (at some point in the future, we should consider
* making volser talk to salsrv)
*/
- if (programType != fileServer) {
+ if (!VCanScheduleSalvage()) {
VChangeState_r(vp, VOL_STATE_ERROR);
*ec = VSALVAGE;
return 1;
/***************************************************/
/* This must be called by any volume utility which needs to run while the
- file server is also running. This is separated from VInitVolumePackage so
+ file server is also running. This is separated from VInitVolumePackage2 so
that a utility can fork--and each of the children can independently
initialize communication with the file server */
#ifdef FSSYNC_BUILD_CLIENT
* @param[in] option tunable option to modify
* @param[in] val new value for tunable parameter
*
- * @pre @c VInitVolumePackage has not yet been called.
+ * @pre @c VInitVolumePackage2 has not yet been called.
*
* @post tunable parameter is modified
*
}
/* don't start the scanner until VLRU_offline_thresh
- * plus a small delay for VInitVolumePackage to finish
+ * plus a small delay for VInitVolumePackage2 to finish
* has gone by */
sleep(VLRU_offline_thresh + 60);
* @retval 0 success
* @retval -1 failure
*
- * @pre MUST be called prior to VInitVolumePackage
+ * @pre MUST be called prior to VInitVolumePackage2
*
* @post Volume Hash Table will have 2^logsize buckets
*/
VOL_UNLOCK;
}
#endif /* AFS_DEMAND_ATTACH_FS */
+
+afs_int32
+VCanScheduleSalvage(void)
+{
+ return vol_opts.canScheduleSalvage;
+}
+
+afs_int32
+VCanUseFSSYNC(void)
+{
+ return vol_opts.canUseFSSYNC;
+}
+
+afs_int32
+VCanUseSALVSYNC(void)
+{
+ return vol_opts.canUseSALVSYNC;
+}
*/
typedef enum {
fileServer = 1, /**< the fileserver process */
- volumeUtility = 2, /**< volserver, or a
- * single volume salvager (non-dafs) */
+ volumeUtility = 2, /**< any miscellaneous volume utility */
salvager = 3, /**< standalone whole-partition salvager */
salvageServer = 4, /**< dafs online salvager */
- debugUtility = 5 /**< fssync-debug or similar utility */
+ debugUtility = 5, /**< fssync-debug or similar utility */
+ volumeServer = 6, /**< the volserver process */
+ volumeSalvager = 7, /**< the standalone single-volume salvager */
} ProgramType;
extern ProgramType programType; /* The type of program using the package */
#endif /* AFS_DEMAND_ATTACH_FS */
+typedef struct VolumePackageOptions {
+ afs_uint32 nLargeVnodes; /**< size of large vnode cache */
+ afs_uint32 nSmallVnodes; /**< size of small vnode cache */
+ afs_uint32 volcache; /**< size of volume header cache */
+
+ afs_int32 canScheduleSalvage; /**< can we schedule salvages? (DAFS) */
+ /* (if 'no', we will just error out if we
+ * find a bad vol) */
+ afs_int32 canUseFSSYNC; /**< can we use the FSSYNC channel? */
+ afs_int32 canUseSALVSYNC; /**< can we use the SALVSYNC channel? (DAFS) */
+} VolumePackageOptions;
/* Magic numbers and version stamps for each type of file */
#define VOLUMEHEADERMAGIC ((bit32)0x88a1bb3c)
extern void VCloseVnodeFiles_r(Volume * vp);
extern struct DiskPartition64 *VGetPartition(char *name, int abortp);
extern struct DiskPartition64 *VGetPartition_r(char *name, int abortp);
-extern int VInitVolumePackage(ProgramType pt, afs_uint32 nLargeVnodes,
- afs_uint32 nSmallVnodes, int connect, afs_uint32 volcache);
+extern void VOptDefaults(ProgramType pt, VolumePackageOptions * opts);
+extern int VInitVolumePackage2(ProgramType pt, VolumePackageOptions * opts);
extern int VInitAttachVolumes(ProgramType pt);
extern void DiskToVolumeHeader(VolumeHeader_t * h, VolumeDiskHeader_t * dh);
extern void VolumeHeaderToDisk(VolumeDiskHeader_t * dh, VolumeHeader_t * h);
extern void VPurgeVolume(Error * ec, Volume * vp);
+extern afs_int32 VCanScheduleSalvage(void);
+extern afs_int32 VCanUseFSSYNC(void);
+extern afs_int32 VCanUseSALVSYNC(void);
/* Naive formula relating number of file size to number of 1K blocks in file */
/* Note: we charge 1 block for 0 length files so the user can't store
switch(type) {
case salvager:
case salvageServer:
+ case volumeSalvager:
return 1;
default:
return 0;
}
}
+/**
+ * tells caller whether or not we need to lock the entire partition when
+ * attaching a volume.
+ *
+ * @return whether or not we need to lock the partition
+ * @retval 0 no, we do not
+ * @retval 1 yes, we do
+ */
+static_inline int
+VRequiresPartLock(void)
+{
+ switch (programType) {
+ case volumeServer:
+ case volumeUtility:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * tells caller whether we should check the inUse field in the volume
+ * header when attaching a volume.
+ *
+ * If we check inUse, that generally means we will salvage the volume
+ * (or put it in an error state) if we detect that another program
+ * claims to be using the volume when we try to attach. We don't always
+ * want to do that, since sometimes we know that the volume may be in
+ * use by another program, e.g. when we are attaching with V_PEEK, and
+ * we don't care.
+ *
+ * @param mode the mode of attachment for the volume
+ *
+ * @return whether or not we should check inUse
+ * @retval 0 no, we should not check inUse
+ * @retval 1 yes, we should check inUse
+ */
+static_inline int
+VShouldCheckInUse(int mode)
+{
+ if (programType == fileServer) {
+ return 1;
+ }
+ if (VCanUseFSSYNC() && mode != V_SECRETLY && mode != V_PEEK) {
+ /* If we can FSSYNC, we assume we checked out the volume from
+ * the fileserver, so inUse should not be set. If we checked out
+ * with V_SECRETLY or V_PEEK, though, we didn't ask the
+ * fileserver, so don't check inUse. */
+ return 1;
+ }
+ return 0;
+}
+
/***************************************************/
/* demand attach fs state machine routines */
/***************************************************/
{
register struct cmd_syndesc *ts;
afs_int32 code;
+ VolumePackageOptions opts;
- VInitVolumePackage(volumeUtility, 5, 5, DONT_CONNECT_FS, 0);
+ VOptDefaults(volumeUtility, &opts);
+ VInitVolumePackage2(volumeUtility, &opts);
ts = cmd_CreateSyntax(NULL, handleit, NULL,
"Dump a volume to a 'vos dump' format file without using volserver");
int bufSize = 0; /* temp variable to read in udp socket buf size */
afs_uint32 host = ntohl(INADDR_ANY);
char *auditFileName = NULL;
+ VolumePackageOptions opts;
#ifdef AFS_AIX32_ENV
/*
exit(1);
}
#endif
- /* Open VolserLog and map stdout, stderr into it; VInitVolumePackage can
+ /* Open VolserLog and map stdout, stderr into it; VInitVolumePackage2 can
log, so we need to do this here */
OpenLog(AFSDIR_SERVER_VOLSERLOG_FILEPATH);
- VInitVolumePackage(volumeUtility, 0, 0, CONNECT_FS, 0);
+ VOptDefaults(volumeServer, &opts);
+ VInitVolumePackage2(volumeServer, &opts);
/* For nuke() */
Lock_Init(&localLock);
DInit(40);