#else
# include <opr/lockstub.h>
#endif
+#include <opr/ffs.h>
+#include <opr/jhash.h>
#include <afs/afsint.h>
#ifndef AFS_NT40_ENV
#if !defined(AFS_SGI_ENV)
-#ifdef AFS_OSF_ENV
-#include <ufs/fs.h>
-#else /* AFS_OSF_ENV */
#ifdef AFS_VFSINCL_ENV
#define VFS
#ifdef AFS_SUN5_ENV
#include <sys/fs.h>
#endif
#endif /* AFS_VFSINCL_ENV */
-#endif /* AFS_OSF_ENV */
#endif /* AFS_SGI_ENV */
#endif /* !AFS_NT40_ENV */
int vol_attach_threads = 1;
#endif /* AFS_PTHREAD_ENV */
-/* start-time configurable I/O parameters */
-ih_init_params vol_io_params;
-
#ifdef AFS_DEMAND_ATTACH_FS
pthread_mutex_t vol_salvsync_mutex;
*/
static int vol_shutting_down = 0;
-#ifdef AFS_OSF_ENV
-extern void *calloc(), *realloc();
-#endif
-
/* Forward declarations */
static Volume *attach2(Error * ec, VolumeId volumeId, char *path,
struct DiskPartition64 *partp, Volume * vp,
static void FreeVolumeHeader(Volume * vp);
static void AddVolumeToHashTable(Volume * vp, VolumeId hashid);
static void DeleteVolumeFromHashTable(Volume * vp);
-#if 0
-static int VHold(Volume * vp);
-#endif
static int VHold_r(Volume * vp);
static void VGetBitmap_r(Error * ec, Volume * vp, VnodeClass class);
static void VReleaseVolumeHandles_r(Volume * vp);
static Volume * GetVolume(Error * ec, Error * client_ec, VolumeId volumeId,
Volume * hint, const struct timespec *ts);
-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;
* an AVL or splay tree might work a lot better, but we'll just increase
* the default hash table size for now
*/
-#define DEFAULT_VOLUME_HASH_SIZE 256 /* Must be a power of 2!! */
-#define DEFAULT_VOLUME_HASH_MASK (DEFAULT_VOLUME_HASH_SIZE-1)
-#define VOLUME_HASH(volumeId) (volumeId&(VolumeHashTable.Mask))
+#define DEFAULT_VOLUME_HASH_BITS 10
+#define DEFAULT_VOLUME_HASH_SIZE opr_jhash_size(DEFAULT_VOLUME_HASH_BITS)
+#define DEFAULT_VOLUME_HASH_MASK opr_jhash_mask(DEFAULT_VOLUME_HASH_BITS)
+#define VOLUME_HASH(volumeId) \
+ (opr_jhash_int(volumeId, 0) & VolumeHashTable.Mask)
/*
* turn volume hash chains into partially ordered lists.
*/
#define VOLUME_HASH_REORDER_CHAIN_THRESH (VOLUME_HASH_REORDER_THRESHOLD / 2)
+/*
+ * The per volume uniquifier is bumped by 200 and and written to disk
+ * every 200 file creates.
+ */
+#define VOLUME_UPDATE_UNIQUIFIER_BUMP 200
+
#include "rx/rx_queue.h"
static void VInitVolumeHash(void);
-#ifndef AFS_HAVE_FFS
-/* This macro is used where an ffs() call does not exist. Was in util/ffs.c */
-ffs(x)
-{
- afs_int32 ffs_i;
- afs_int32 ffs_tmp = x;
- if (ffs_tmp == 0)
- return (-1);
- else
- for (ffs_i = 1;; ffs_i++) {
- if (ffs_tmp & 1)
- return (ffs_i);
- else
- ffs_tmp >>= 1;
- }
-}
-#endif /* !AFS_HAVE_FFS */
-
#ifdef AFS_PTHREAD_ENV
/**
* disk partition queue element
void
VOptDefaults(ProgramType pt, VolumePackageOptions *opts)
{
- opts->nLargeVnodes = opts->nSmallVnodes = 5;
- opts->volcache = 0;
+ memset(opts, 0, sizeof(*opts));
- opts->canScheduleSalvage = 0;
- opts->canUseFSSYNC = 0;
- opts->canUseSALVSYNC = 0;
+ opts->nLargeVnodes = opts->nSmallVnodes = 5;
- opts->interrupt_rxcall = NULL;
opts->offline_timeout = -1;
opts->offline_shutdown_timeout = -1;
opts->usage_threshold = 128;
#ifdef FAST_RESTART
opts->unsafe_attach = 1;
-#else /* !FAST_RESTART */
- opts->unsafe_attach = 0;
-#endif /* !FAST_RESTART */
+#endif
switch (pt) {
case fileServer:
(*(vp ? nAttached : nUnattached))++;
if (error == VOFFLINE)
Log("Volume %d stays offline (/vice/offline/%s exists)\n", VolumeNumber(dp->d_name), dp->d_name);
- else if (LogLevel >= 5) {
+ else if (GetLogLevel() >= 5) {
Log("Partition %s: attached volume %d (%s)\n",
diskP->name, VolumeNumber(dp->d_name),
dp->d_name);
for (queue_Scan(&VolumeHashTable.Table[i],vp,np,Volume)) {
code = VHold_r(vp);
if (code == 0) {
- if (LogLevel >= 5)
+ if (GetLogLevel() >= 5)
Log("VShutdown: Attempting to take volume %" AFS_VOLID_FMT " offline.\n",
afs_printable_VolumeId_lu(vp->hashid));
{
struct rx_queue * q = queue_First(&dp->vol_list, rx_queue);
int i = 0;
+ const char *pass_strs[4] = {"{un/pre}attached vols", "vols w/ vol header loaded", "vols w/o vol header loaded", "vols with exclusive state"};
- while (ShutdownVolumeWalk_r(dp, pass, &q))
+ while (ShutdownVolumeWalk_r(dp, pass, &q)) {
i++;
+ if (0 == i%100) {
+ Log("VShutdownByPartition: ... shut down %d volumes on %s in pass %d (%s)\n", i, VPartitionPath(dp), pass, pass_strs[pass]);
+ }
+ }
return i;
}
(V_attachState(vp) != VOL_STATE_PREATTACHED)) {
break;
}
+ AFS_FALLTHROUGH;
case 1:
if ((V_attachState(vp) == VOL_STATE_ATTACHED) &&
(vp->header == NULL)) {
break;
}
+ AFS_FALLTHROUGH;
case 2:
if (VIsExclusiveState(V_attachState(vp))) {
break;
}
+ AFS_FALLTHROUGH;
case 3:
*idx = nqp;
DeleteVolumeFromVByPList_r(vp);
VCreateReservation_r(vp);
- if (LogLevel >= 5) {
- Log("VShutdownVolume_r: vid=%" AFS_VOLID_FMT ", device=%d, state=%hu\n",
+ if (GetLogLevel() >= 5) {
+ Log("VShutdownVolume_r: vid=%" AFS_VOLID_FMT ", device=%d, state=%u\n",
afs_printable_VolumeId_lu(vp->hashid), vp->partition->device,
- V_attachState(vp));
+ (unsigned int) V_attachState(vp));
}
/* wait for other blocking ops to finish */
case VOL_STATE_PREATTACHED:
case VOL_STATE_ERROR:
VChangeState_r(vp, VOL_STATE_UNATTACHED);
+ break;
case VOL_STATE_UNATTACHED:
case VOL_STATE_DELETED:
break;
case VOL_STATE_ATTACHED:
code = VHold_r(vp);
if (!code) {
- if (LogLevel >= 5)
+ if (GetLogLevel() >= 5)
Log("VShutdown: Attempting to take volume %" AFS_VOLID_FMT " offline.\n",
afs_printable_VolumeId_lu(vp->hashid));
return NULL;
}
+ /* ensure that any vp we pass to VPreAttachVolumeByVp_r
+ * is NOT in exclusive state.
+ */
+ retry:
vp = VLookupVolume_r(ec, volumeId, NULL);
+
if (*ec) {
return NULL;
}
+ if (vp && VIsExclusiveState(V_attachState(vp))) {
+ VCreateReservation_r(vp);
+ VWaitExclusiveState_r(vp);
+ VCancelReservation_r(vp);
+ vp = NULL;
+ goto retry; /* look up volume again */
+ }
+
+ /* vp == NULL or vp not exclusive both OK */
+
return VPreAttachVolumeByVp_r(ec, partp, vp, volumeId);
}
*
* @pre VOL_LOCK is held.
*
+ * @pre vp (if specified) must not be in exclusive state.
+ *
* @warning Returned volume object pointer does not have to
* equal the pointer passed in as argument vp. There
* are potential race conditions which can result in
*ec = 0;
+ /* don't proceed unless it's safe */
+ if (vp) {
+ opr_Assert(!VIsExclusiveState(V_attachState(vp)));
+ }
+
/* check to see if pre-attach already happened */
if (vp &&
(V_attachState(vp) != VOL_STATE_UNATTACHED) &&
VLRU_Init_Node_r(vp);
VChangeState_r(vp, VOL_STATE_PREATTACHED);
- if (LogLevel >= 5)
+ if (GetLogLevel() >= 5)
Log("VPreAttachVolumeByVp_r: volume %" AFS_VOLID_FMT " pre-attached\n", afs_printable_VolumeId_lu(vp->hashid));
done:
goto done;
}
}
- if (LogLevel)
+ if (GetLogLevel() != 0)
Log("VOnline: volume %" AFS_VOLID_FMT " (%s) attached and online\n", afs_printable_VolumeId_lu(V_id(vp)),
V_name(vp));
}
goto done;
}
}
- if (LogLevel)
+ if (GetLogLevel() != 0)
Log("VOnline: volume %" AFS_VOLID_FMT " (%s) attached and online\n",
afs_printable_VolumeId_lu(V_id(vp)), V_name(vp));
done:
FreeVolumeHeader(vp);
} else if (!V_inService(vp)) {
Log("Volume %lu offline: not in service\n", afs_printable_uint32_lu(V_id(vp)));
+ /* the volume is offline and should be unattached */
+ *ec = VOFFLINE;
+ error_state = VOL_STATE_UNATTACHED;
FreeVolumeHeader(vp);
} else {
Log("Volume %lu offline: needs salvage\n", afs_printable_uint32_lu(V_id(vp)));
V_checkoutMode(vp) = mode;
}
- AddVolumeToHashTable(vp, V_id(vp));
+ AddVolumeToHashTable(vp, vp->hashid);
#ifdef AFS_DEMAND_ATTACH_FS
if (VCanUnlockAttached() && (V_attachFlags(vp) & VOL_LOCKED)) {
VUnlockVolume(vp);
locked_error:
#ifdef AFS_DEMAND_ATTACH_FS
if (!VIsErrorState(V_attachState(vp))) {
- if (VIsErrorState(error_state)) {
+ if (programType != fileServer && *ec == VNOVOL) {
+ /* do not log anything in this case; it is common for
+ * non-fileserver programs to fail here with VNOVOL, since that
+ * is what happens when they simply try to use a volume, but that
+ * volume doesn't exist. */
+
+ } else if (VIsErrorState(error_state)) {
Log("attach2: forcing vol %" AFS_VOLID_FMT " to error state (state %u flags 0x%x ec %d)\n",
afs_printable_VolumeId_lu(vp->hashid), V_attachState(vp),
V_attachFlags(vp), *ec);
#endif /* !AFS_PTHREAD_ENV */
-#if 0
-static int
-VHold(Volume * vp)
-{
- int retVal;
- VOL_LOCK;
- retVal = VHold_r(vp);
- VOL_UNLOCK;
- return retVal;
-}
-#endif
-
static afs_int32
VIsGoingOffline_r(struct Volume *vp)
{
const struct timespec *timeout)
{
Volume *vp = hint;
- /* pull this profiling/debugging code out of regular builds */
-#ifdef notdef
-#define VGET_CTR_INC(x) x++
- unsigned short V0 = 0, V1 = 0, V2 = 0, V3 = 0, V5 = 0, V6 =
- 0, V7 = 0, V8 = 0, V9 = 0;
- unsigned short V10 = 0, V11 = 0, V12 = 0, V13 = 0, V14 = 0, V15 = 0;
-#else
-#define VGET_CTR_INC(x)
-#endif
#ifdef AFS_DEMAND_ATTACH_FS
Volume *avp, * rvp = hint;
#endif
*ec = 0;
if (client_ec)
*client_ec = 0;
- VGET_CTR_INC(V0);
vp = VLookupVolume_r(ec, volumeId, vp);
if (*ec) {
#endif /* AFS_DEMAND_ATTACH_FS */
if (!vp) {
- VGET_CTR_INC(V1);
if (VInit < 2) {
- VGET_CTR_INC(V2);
/* Until we have reached an initialization level of 2
* we don't know whether this volume exists or not.
* We can't sleep and retry later because before a volume
break;
}
- VGET_CTR_INC(V3);
IncUInt64(&VStats.hdr_gets);
#ifdef AFS_DEMAND_ATTACH_FS
LoadVolumeHeader(ec, vp);
if (*ec) {
- VGET_CTR_INC(V6);
/* Only log the error if it was a totally unexpected error. Simply
* a missing inode is likely to be caused by the volume being deleted */
- if (errno != ENXIO || LogLevel)
+ if (errno != ENXIO || GetLogLevel() != 0)
Log("Volume %" AFS_VOLID_FMT ": couldn't reread volume header\n",
afs_printable_VolumeId_lu(vp->hashid));
#ifdef AFS_DEMAND_ATTACH_FS
break;
}
- VGET_CTR_INC(V7);
if (vp->shuttingDown) {
- VGET_CTR_INC(V8);
*ec = VNOVOL;
vp = NULL;
break;
}
if (programType == fileServer) {
- VGET_CTR_INC(V9);
if (vp->goingOffline) {
if (timeout && VTimedOut(timeout)) {
/* we've timed out; don't wait for the vol */
} else {
- VGET_CTR_INC(V10);
#ifdef AFS_DEMAND_ATTACH_FS
/* wait for the volume to go offline */
if (V_attachState(vp) == VOL_STATE_GOING_OFFLINE) {
}
}
if (vp->specialStatus) {
- VGET_CTR_INC(V11);
*ec = vp->specialStatus;
} else if (V_inService(vp) == 0 || V_blessed(vp) == 0) {
- VGET_CTR_INC(V12);
*ec = VNOVOL;
} else if (V_inUse(vp) == 0 || vp->goingOffline) {
- VGET_CTR_INC(V13);
*ec = VOFFLINE;
- } else {
- VGET_CTR_INC(V14);
}
}
break;
}
- VGET_CTR_INC(V15);
#ifdef AFS_DEMAND_ATTACH_FS
/* if no error, bump nUsers */
#endif /* AFS_DEMAND_ATTACH_FS */
for(queue_Scan(&vp->rx_call_list, cbv, ncbv, VCallByVol)) {
- if (LogLevel > 0) {
+ if (GetLogLevel() != 0) {
struct rx_peer *peer;
char hoststr[16];
peer = rx_PeerOf(rx_ConnectionOf(cbv->call));
* which the file server would attempt to put on line
*/
FSYNC_VolOp(volume, tpartp->name, useDone, 0, NULL);
- /* XXX this code path is only hit by volume utilities, thus
- * V_BreakVolumeCallbacks will always be NULL. if we really
- * want to break callbacks in this path we need to use FSYNC_VolOp() */
-#ifdef notdef
- /* Dettaching it so break all callbacks on it */
- if (V_BreakVolumeCallbacks) {
- Log("volume %u detached; breaking all call backs\n", volume);
- (*V_BreakVolumeCallbacks) (volume);
- }
-#endif
}
#endif /* FSSYNC_BUILD_CLIENT */
}
#endif
*ec = 0;
- if (programType == fileServer)
- V_uniquifier(vp) =
- (V_inUse(vp) ? V_nextVnodeUnique(vp) +
- 200 : V_nextVnodeUnique(vp));
+ if (programType == fileServer) {
+ if (!V_inUse(vp)) {
+ V_uniquifier(vp) = V_nextVnodeUnique(vp);
+ } else {
+ V_uniquifier(vp) =
+ V_nextVnodeUnique(vp) + VOLUME_UPDATE_UNIQUIFIER_BUMP;
+ if (V_uniquifier(vp) < V_nextVnodeUnique(vp)) {
+ /* uniquifier rolled over; reset the counters */
+ V_nextVnodeUnique(vp) = 2; /* 1 is reserved for the root vnode */
+ V_uniquifier(vp) =
+ V_nextVnodeUnique(vp) + VOLUME_UPDATE_UNIQUIFIER_BUMP;
+ }
+ }
+ }
#ifdef AFS_DEMAND_ATTACH_FS
state_save = VChangeState_r(vp, VOL_STATE_UPDATING);
VUpdateVolume_r(&error, vp, 0);
VCloseVolumeHandles_r(vp);
- if (LogLevel) {
+ if (GetLogLevel() != 0) {
if (V_offlineMessage(vp)[0]) {
Log("VOffline: Volume %lu (%s) is now offline (%s)\n",
afs_printable_uint32_lu(V_id(vp)), V_name(vp),
V_inUse(vp) = 0;
VUpdateVolume_r(&error, vp, 0);
VCloseVolumeHandles_r(vp);
- if (LogLevel) {
+ if (GetLogLevel() != 0) {
if (V_offlineMessage(vp)[0]) {
Log("VOffline: Volume %lu (%s) is now offline (%s)\n",
afs_printable_uint32_lu(V_id(vp)), V_name(vp),
*ec = VSALVAGE;
code = 1;
}
+ if ((flags & VOL_SALVAGE_NO_OFFLINE)) {
+ /* Here, we free the header for the volume, but make sure to only
+ * do this if VOL_SALVAGE_NO_OFFLINE is specified. The reason for
+ * this requires a bit of explanation.
+ *
+ * Normally, the volume header will be freed when the volume goes
+ * goes offline. However, if VOL_SALVAGE_NO_OFFLINE has been
+ * specified, the volume was in the process of being attached when
+ * we discovered that it needed salvaging. Thus, the volume will
+ * never go offline, since it never went fully online in the first
+ * place. Specifically, we do not call VOfflineForSalvage_r above,
+ * and we never get rid of the volume via VPutVolume_r; the volume
+ * has not been initialized enough for those to work.
+ *
+ * So instead, explicitly free the volume header here. If we do not
+ * do this, we are wasting a header that some other volume could be
+ * using, since the header remains attached to the volume. Also if
+ * we do not free the header here, we end up with a volume where
+ * nUsers == 0, but the volume has a header that is not on the
+ * header LRU. Some code expects that all nUsers == 0 volumes have
+ * their header on the header LRU (or have no header).
+ *
+ * Also note that we must not free the volume header here if
+ * VOL_SALVAGE_NO_OFFLINE is not set. Since, if
+ * VOL_SALVAGE_NO_OFFLINE is not set, someone else may have a
+ * reference to this volume, and they assume they can use the
+ * volume's header. If we free the volume out from under them, they
+ * can easily segfault.
+ */
+ FreeVolumeHeader(vp);
+ }
}
return code;
}
index->bitmapOffset = (afs_uint32) (bp - index->bitmap);
while (*bp == 0xff)
bp++;
- o = ffs(~*bp) - 1; /* ffs is documented in BSTRING(3) */
+ o = opr_ffs(~*bp) - 1;
*bp |= (1 << o);
ret = ((bp - index->bitmap) * 8 + o);
#ifdef AFS_DEMAND_ATTACH_FS
done:
#ifdef AFS_DEMAND_ATTACH_FS
- VCancelReservation_r(vp);
+ if (flags & VOL_FREE_BITMAP_WAIT) {
+ VCancelReservation_r(vp);
+ }
#endif
return; /* make the compiler happy for non-DAFS */
}
opr_Assert(file != NULL);
vnode = malloc(vcp->diskSize);
opr_Assert(vnode != NULL);
- size = OS_SIZE(fdP->fd_fd);
+ size = FDH_SIZE(fdP);
opr_Assert(size != -1);
nVnodes = (size <= vcp->diskSize ? 0 : size - vcp->diskSize)
>> vcp->logSize;
/* setup the timing constants */
VLRU_ComputeConstants();
- /* XXX put inside LogLevel check? */
+ /* XXX put inside log level check? */
Log("VLRU: starting scanner with the following configuration parameters:\n");
Log("VLRU: offlining volumes after minimum of %d seconds of inactivity\n", VLRU_offline_thresh);
Log("VLRU: running VLRU soft detach pass every %d seconds\n", VLRU_offline_interval);
}
if (!VInit) {
- VolumeHashTable.Size = 1 << logsize;
- VolumeHashTable.Mask = VolumeHashTable.Size - 1;
+ VolumeHashTable.Size = opr_jhash_size(logsize);
+ VolumeHashTable.Mask = opr_jhash_mask(logsize);
} else {
/* we can't yet support runtime modification of this
* parameter. we'll need a configuration rwlock to
head->len++;
vp->hashid = hashid;
queue_Append(head, vp);
- vp->vnodeHashOffset = VolumeHashOffset_r();
}
/**