/*@printflike@*/ extern void Log(const char *format, ...);
/* Forward declarations */
-static Volume *attach2(Error * ec, VolId vid, char *path,
- register struct VolumeHeader *header,
+static Volume *attach2(Error * ec, VolId volumeId, char *path,
struct DiskPartition64 *partp, Volume * vp,
int isbusy, int mode);
static void ReallyFreeVolume(Volume * vp);
VAttachVolumeByName_r(Error * ec, char *partition, char *name, int mode)
{
register Volume *vp = NULL;
- int fd, n;
- struct afs_stat status;
- struct VolumeDiskHeader diskHeader;
- struct VolumeHeader iheader;
struct DiskPartition64 *partp;
char path[64];
int isbusy = 0;
strcat(path, "/");
strcat(path, name);
- if ((fd = afs_open(path, O_RDONLY)) == -1 || afs_fstat(fd, &status) == -1) {
- Log("VAttachVolume: Failed to open %s (errno %d)\n", path, errno);
- if (fd > -1)
- close(fd);
- *ec = VNOVOL;
- VOL_LOCK;
- goto done;
- }
- n = read(fd, &diskHeader, sizeof(diskHeader));
- close(fd);
- if (n != sizeof(diskHeader)
- || diskHeader.stamp.magic != VOLUMEHEADERMAGIC) {
- Log("VAttachVolume: Error reading volume header %s\n", path);
- *ec = VSALVAGE;
- VOL_LOCK;
- goto done;
- }
- if (diskHeader.stamp.version != VOLUMEHEADERVERSION) {
- Log("VAttachVolume: Volume %s, version number is incorrect; volume needs salvaged\n", path);
- *ec = VSALVAGE;
- VOL_LOCK;
- goto done;
- }
-
- DiskToVolumeHeader(&iheader, &diskHeader);
-#ifdef FSSYNC_BUILD_CLIENT
- if (VCanUseFSSYNC() && mode != V_SECRETLY && mode != V_PEEK) {
- SYNC_response res;
- memset(&res, 0, sizeof(res));
-
- VOL_LOCK;
- if (FSYNC_VolOp(iheader.id, partition, FSYNC_VOL_NEEDVOLUME, mode, &res)
- != SYNC_OK) {
-
- if (res.hdr.reason == FSYNC_SALVAGE) {
- Log("VAttachVolume: file server says volume %u is salvaging\n",
- iheader.id);
- *ec = VSALVAGING;
- } else {
- Log("VAttachVolume: attach of volume %u apparently denied by file server\n",
- iheader.id);
- *ec = VNOVOL; /* XXXX */
- }
-
- goto done;
- }
- VOL_UNLOCK;
- }
-#endif
if (!vp) {
vp = (Volume *) calloc(1, sizeof(Volume));
/* attach2 is entered without any locks, and returns
* with vol_glock_mutex held */
- vp = attach2(ec, volumeId, path, &iheader, partp, vp, isbusy, mode);
+ vp = attach2(ec, volumeId, path, partp, vp, isbusy, mode);
if (VCanUseFSSYNC() && vp) {
if ((mode == V_VOLUPD) || (VolumeWriteable(vp) && (mode == V_CLONE))) {
* notified the fileserver; don't online it now */
if (*ec != VSALVAGING)
#endif /* AFS_DEMAND_ATTACH_FS */
- FSYNC_VolOp(iheader.id, partition, FSYNC_VOL_ON, 0, NULL);
+ FSYNC_VolOp(volumeId, partition, FSYNC_VOL_ON, 0, NULL);
} else
#endif
if (programType == fileServer && vp) {
VAttachVolumeByVp_r(Error * ec, Volume * vp, int mode)
{
char name[VMAXPATHLEN];
- int fd, n, reserve = 0;
- struct afs_stat status;
- struct VolumeDiskHeader diskHeader;
- struct VolumeHeader iheader;
+ int reserve = 0;
struct DiskPartition64 *partp;
char path[64];
int isbusy = 0;
*ec = 0;
-
- /* compute path to disk header,
- * read in header,
- * and verify magic and version stamps */
+ /* compute path to disk header */
strcpy(path, VPartitionPath(partp));
VOL_UNLOCK;
strcat(path, "/");
strcat(path, name);
- if ((fd = afs_open(path, O_RDONLY)) == -1 || afs_fstat(fd, &status) == -1) {
- Log("VAttachVolume: Failed to open %s (errno %d)\n", path, errno);
- if (fd > -1)
- close(fd);
- *ec = VNOVOL;
- VOL_LOCK;
- goto done;
- }
- n = read(fd, &diskHeader, sizeof(diskHeader));
- close(fd);
- if (n != sizeof(diskHeader)
- || diskHeader.stamp.magic != VOLUMEHEADERMAGIC) {
- Log("VAttachVolume: Error reading volume header %s\n", path);
- *ec = VSALVAGE;
- VOL_LOCK;
- goto done;
- }
- if (diskHeader.stamp.version != VOLUMEHEADERVERSION) {
- Log("VAttachVolume: Volume %s, version number is incorrect; volume needs salvaged\n", path);
- *ec = VSALVAGE;
- VOL_LOCK;
- goto done;
- }
-
- /* convert on-disk header format to in-memory header format */
- DiskToVolumeHeader(&iheader, &diskHeader);
/* do volume attach
*
* NOTE: attach2 is entered without any locks, and returns
* with vol_glock_mutex held */
- vp = attach2(ec, volumeId, path, &iheader, partp, vp, isbusy, mode);
+ vp = attach2(ec, volumeId, path, partp, vp, isbusy, mode);
/*
* the event that an error was encountered, or
}
#endif /* AFS_DEMAND_ATTACH_FS */
-/*
- * called without any locks held
- * returns with vol_glock_mutex held
+/**
+ * read in a vol header, possibly lock the vol header, and possibly check out
+ * the vol header from the fileserver, as part of volume attachment.
+ *
+ * @param[out] ec error code
+ * @param[in] vp volume pointer object
+ * @param[in] partp disk partition object of the attaching partition
+ * @param[in] mode attachment mode such as V_VOLUPD, V_DUMP, etc (see
+ * volume.h)
+ * @param[in] peek 1 to just try to read in the volume header and make sure
+ * we don't try to lock the vol, or check it out from
+ * FSSYNC or anything like that; 0 otherwise, for 'normal'
+ * operation
+ *
+ * @note As part of DAFS volume attachment, the volume header may be either
+ * read- or write-locked to ensure mutual exclusion of certain volume
+ * operations. In some cases in order to determine whether we need to
+ * read- or write-lock the header, we need to read in the header to see
+ * if the volume is RW or not. So, if we read in the header under a
+ * read-lock and determine that we actually need a write-lock on the
+ * volume header, this function will drop the read lock, acquire a write
+ * lock, and read the header in again.
*/
-private Volume *
-attach2(Error * ec, VolId volumeId, char *path, register struct VolumeHeader * header,
- struct DiskPartition64 * partp, register Volume * vp, int isbusy, int mode)
-{
- vp->specialStatus = (byte) (isbusy ? VBUSY : 0);
- IH_INIT(vp->vnodeIndex[vLarge].handle, partp->device, header->parent,
- header->largeVnodeIndex);
- IH_INIT(vp->vnodeIndex[vSmall].handle, partp->device, header->parent,
- header->smallVnodeIndex);
- IH_INIT(vp->diskDataHandle, partp->device, header->parent,
- header->volumeInfo);
- IH_INIT(vp->linkHandle, partp->device, header->parent, header->linkTable);
- vp->shuttingDown = 0;
- vp->goingOffline = 0;
- vp->nUsers = 1;
+static void
+attach_volume_header(Error *ec, Volume *vp, struct DiskPartition64 *partp,
+ int mode, int peek)
+{
+ struct VolumeDiskHeader diskHeader;
+ struct VolumeHeader header;
+ int code;
+ int first_try = 1;
+ int lock_tries = 0, checkout_tries = 0;
+ int retry;
+ VolumeId volid = vp->hashid;
+#ifdef FSSYNC_BUILD_CLIENT
+ int checkout, done_checkout = 0;
+#endif /* FSSYNC_BUILD_CLIENT */
#ifdef AFS_DEMAND_ATTACH_FS
- vp->stats.last_attach = FT_ApproxTime();
- vp->stats.attaches++;
+ int locktype = 0, use_locktype = -1;
+#endif /* AFS_DEMAND_ATTACH_FS */
+
+ retry:
+ retry = 0;
+ *ec = 0;
+
+ if (lock_tries > VOL_MAX_CHECKOUT_RETRIES) {
+ Log("VAttachVolume: retried too many times trying to lock header for "
+ "vol %lu part %s; giving up\n", afs_printable_uint32_lu(volid),
+ VPartitionPath(partp));
+ *ec = VNOVOL;
+ goto done;
+ }
+ if (checkout_tries > VOL_MAX_CHECKOUT_RETRIES) {
+ Log("VAttachVolume: retried too many times trying to checkout "
+ "vol %lu part %s; giving up\n", afs_printable_uint32_lu(volid),
+ VPartitionPath(partp));
+ *ec = VNOVOL;
+ goto done;
+ }
+
+ if (VReadVolumeDiskHeader(volid, partp, NULL)) {
+ /* short-circuit the 'volume does not exist' case */
+ *ec = VNOVOL;
+ goto done;
+ }
+
+#ifdef FSSYNC_BUILD_CLIENT
+ checkout = !done_checkout;
+ done_checkout = 1;
+ if (!peek && checkout && VMustCheckoutVolume(mode)) {
+ SYNC_response res;
+ memset(&res, 0, sizeof(res));
+
+ if (FSYNC_VolOp(volid, VPartitionPath(partp), FSYNC_VOL_NEEDVOLUME, mode, &res)
+ != SYNC_OK) {
+
+ if (res.hdr.reason == FSYNC_SALVAGE) {
+ Log("VAttachVolume: file server says volume %lu is salvaging\n",
+ afs_printable_uint32_lu(volid));
+ *ec = VSALVAGING;
+ } else {
+ Log("VAttachVolume: attach of volume %lu apparently denied by file server\n",
+ afs_printable_uint32_lu(volid));
+ *ec = VNOVOL; /* XXXX */
+ }
+ goto done;
+ }
+ }
#endif
- VOL_LOCK;
- IncUInt64(&VStats.attaches);
- vp->cacheCheck = ++VolumeCacheCheck;
- /* just in case this ever rolls over */
- if (!vp->cacheCheck)
- vp->cacheCheck = ++VolumeCacheCheck;
- GetVolumeHeader(vp);
- VOL_UNLOCK;
+#ifdef AFS_DEMAND_ATTACH_FS
+ if (use_locktype < 0) {
+ /* don't know whether vol is RO or RW; assume it's RO and we can retry
+ * if it turns out to be RW */
+ locktype = VVolLockType(mode, 0);
+
+ } else {
+ /* a previous try says we should use use_locktype to lock the volume,
+ * so use that */
+ locktype = use_locktype;
+ }
+
+ if (!peek && locktype) {
+ code = VLockVolumeNB(vp, locktype);
+ if (code) {
+ if (code == EBUSY) {
+ Log("VAttachVolume: another program has vol %lu locked\n",
+ afs_printable_uint32_lu(volid));
+ } else {
+ Log("VAttachVolume: error %d trying to lock vol %lu\n",
+ code, afs_printable_uint32_lu(volid));
+ }
+
+ *ec = VNOVOL;
+ goto done;
+ }
+ }
+#endif /* AFS_DEMAND_ATTACH_FS */
+
+ code = VReadVolumeDiskHeader(volid, partp, &diskHeader);
+ if (code) {
+ if (code == EIO) {
+ *ec = VSALVAGE;
+ } else {
+ *ec = VNOVOL;
+ }
+ goto done;
+ }
+
+ DiskToVolumeHeader(&header, &diskHeader);
+
+ IH_INIT(vp->vnodeIndex[vLarge].handle, partp->device, header.parent,
+ header.largeVnodeIndex);
+ IH_INIT(vp->vnodeIndex[vSmall].handle, partp->device, header.parent,
+ header.smallVnodeIndex);
+ IH_INIT(vp->diskDataHandle, partp->device, header.parent,
+ header.volumeInfo);
+ IH_INIT(vp->linkHandle, partp->device, header.parent, header.linkTable);
+
+ if (first_try) {
+ /* only need to do this once */
+ VOL_LOCK;
+ GetVolumeHeader(vp);
+ VOL_UNLOCK;
+ }
#if defined(AFS_DEMAND_ATTACH_FS) && defined(FSSYNC_BUILD_CLIENT)
/* demand attach changes the V_PEEK mechanism
* to demand attach fileservers. However, I'm trying
* to limit the number of common code changes)
*/
- if (programType != fileServer && mode == V_PEEK) {
+ if (VCanUseFSSYNC() && (mode == V_PEEK || peek)) {
SYNC_response res;
res.payload.len = sizeof(VolumeDiskData);
res.payload.buf = &vp->header->diskstuff;
- if (FSYNC_VolOp(volumeId,
+ if (FSYNC_VolOp(vp->hashid,
partp->name,
FSYNC_VOL_QUERY_HDR,
FSYNC_WHATEVER,
#endif /* AFS_DEMAND_ATTACH_FS */
if (*ec) {
- Log("VAttachVolume: Error reading diskDataHandle vol header %s; error=%u\n", path, *ec);
+ Log("VAttachVolume: Error reading diskDataHandle header for vol %lu; "
+ "error=%u\n", afs_printable_uint32_lu(volid), *ec);
+ goto done;
}
#ifdef AFS_DEMAND_ATTACH_FS
# ifdef FSSYNC_BUILD_CLIENT
disk_header_loaded:
-#endif
- if (!*ec) {
+# endif /* FSSYNC_BUILD_CLIENT */
- /* check for pending volume operations */
- if (vp->pending_vol_op) {
- /* see if the pending volume op requires exclusive access */
- switch (vp->pending_vol_op->vol_op_state) {
- case FSSYNC_VolOpPending:
- /* this should never happen */
- assert(vp->pending_vol_op->vol_op_state != FSSYNC_VolOpPending);
- break;
+ /* if the lock type we actually used to lock the volume is different than
+ * the lock type we should have used, retry with the lock type we should
+ * use */
+ use_locktype = VVolLockType(mode, VolumeWriteable(vp));
+ if (locktype != use_locktype) {
+ retry = 1;
+ lock_tries++;
+ }
+#endif /* AFS_DEMAND_ATTACH_FS */
+
+ *ec = 0;
+
+ done:
+#if defined(AFS_DEMAND_ATTACH_FS) && defined(FSSYNC_BUILD_CLIENT)
+ if (!peek && *ec == 0 && retry == 0 && VMustCheckoutVolume(mode)) {
+
+ code = FSYNC_VerifyCheckout(volid, VPartitionPath(partp), FSYNC_VOL_NEEDVOLUME, mode);
+
+ if (code == SYNC_DENIED) {
+ /* must retry checkout; fileserver no longer thinks we have
+ * the volume */
+ retry = 1;
+ checkout_tries++;
+ done_checkout = 0;
+
+ } else if (code != SYNC_OK) {
+ *ec = VNOVOL;
+ }
+ }
+#endif /* AFS_DEMAND_ATTACH_FS && FSSYNC_BUILD_CLIENT */
+
+ if (*ec || retry) {
+ /* either we are going to be called again for a second pass, or we
+ * encountered an error; clean up in either case */
+
+#ifdef AFS_DEMAND_ATTACH_FS
+ if ((V_attachFlags(vp) & VOL_LOCKED)) {
+ VUnlockVolume(vp);
+ }
+#endif /* AFS_DEMAND_ATTACH_FS */
+ if (vp->linkHandle) {
+ IH_RELEASE(vp->vnodeIndex[vLarge].handle);
+ IH_RELEASE(vp->vnodeIndex[vSmall].handle);
+ IH_RELEASE(vp->diskDataHandle);
+ IH_RELEASE(vp->linkHandle);
+ }
+ }
+
+ if (*ec) {
+ return;
+ }
+ if (retry) {
+ first_try = 0;
+ goto retry;
+ }
+}
+
+#ifdef AFS_DEMAND_ATTACH_FS
+static void
+attach_check_vop(Error *ec, VolumeId volid, struct DiskPartition64 *partp,
+ Volume *vp)
+{
+ *ec = 0;
+
+ if (vp->pending_vol_op) {
+
+ VOL_LOCK;
+
+ if (vp->pending_vol_op->vol_op_state == FSSYNC_VolOpRunningUnknown) {
+ int code;
+ code = VVolOpLeaveOnlineNoHeader_r(vp, vp->pending_vol_op);
+ if (code == 1) {
+ vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOnline;
+ } else if (code == 0) {
+ vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOffline;
+
+ } else {
+ /* we need the vol header to determine if the volume can be
+ * left online for the vop, so... get the header */
+
+ VOL_UNLOCK;
+
+ /* attach header with peek=1 to avoid checking out the volume
+ * or locking it; we just want the header info, we're not
+ * messing with the volume itself at all */
+ attach_volume_header(ec, vp, partp, V_PEEK, 1);
+ if (*ec) {
+ return;
+ }
+
+ VOL_LOCK;
- case FSSYNC_VolOpRunningUnknown:
if (VVolOpLeaveOnline_r(vp, vp->pending_vol_op)) {
vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOnline;
- break;
} else {
vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOffline;
- /* fall through to take volume offline */
}
- case FSSYNC_VolOpRunningOffline:
- /* mark the volume down */
- *ec = VOFFLINE;
- VChangeState_r(vp, VOL_STATE_UNATTACHED);
- if (V_offlineMessage(vp)[0] == '\0')
- strlcpy(V_offlineMessage(vp),
- "A volume utility is running.",
- sizeof(V_offlineMessage(vp)));
- V_offlineMessage(vp)[sizeof(V_offlineMessage(vp)) - 1] = '\0';
-
- /* check to see if we should set the specialStatus flag */
- if (VVolOpSetVBusy_r(vp, vp->pending_vol_op)) {
- vp->specialStatus = VBUSY;
- }
- default:
- break;
+ /* make sure we grab a new vol header and re-open stuff on
+ * actual attachment; we can't keep the data we grabbed, since
+ * it was not done under a lock and thus not safe */
+ FreeVolumeHeader(vp);
+ VReleaseVolumeHandles_r(vp);
+ }
+ }
+ /* see if the pending volume op requires exclusive access */
+ switch (vp->pending_vol_op->vol_op_state) {
+ case FSSYNC_VolOpPending:
+ /* this should never happen */
+ assert(vp->pending_vol_op->vol_op_state != FSSYNC_VolOpPending);
+ break;
+
+ case FSSYNC_VolOpRunningUnknown:
+ /* this should never happen; we resolved 'unknown' above */
+ assert(vp->pending_vol_op->vol_op_state != FSSYNC_VolOpRunningUnknown);
+ break;
+
+ case FSSYNC_VolOpRunningOffline:
+ /* mark the volume down */
+ *ec = VOFFLINE;
+ VChangeState_r(vp, VOL_STATE_UNATTACHED);
+
+ /* do not set V_offlineMessage here; we don't have ownership of
+ * the volume (and probably do not have the header loaded), so we
+ * can't alter the disk header */
+
+ /* check to see if we should set the specialStatus flag */
+ if (VVolOpSetVBusy_r(vp, vp->pending_vol_op)) {
+ vp->specialStatus = VBUSY;
}
+ break;
+
+ default:
+ break;
}
+ VOL_UNLOCK;
+ }
+}
+#endif /* AFS_DEMAND_ATTACH_FS */
+
+/**
+ * volume attachment helper function.
+ *
+ * @param[out] ec error code
+ * @param[in] volumeId volume ID of the attaching volume
+ * @param[in] path full path to the volume header .vol file
+ * @param[in] partp disk partition object for the attaching partition
+ * @param[in] vp volume object; vp->hashid, vp->device, vp->partition,
+ * vp->vnode_list, and V_attachCV (for DAFS) should already
+ * be initialized
+ * @param[in] isbusy 1 if vp->specialStatus should be set to VBUSY; that is,
+ * if there is a volume operation running for this volume
+ * that should set the volume to VBUSY during its run. 0
+ * otherwise. (see VVolOpSetVBusy_r)
+ * @param[in] mode attachment mode such as V_VOLUPD, V_DUMP, etc (see
+ * volume.h)
+ *
+ * @return pointer to the semi-attached volume pointer
+ * @retval NULL an error occurred (check value of *ec)
+ * @retval vp volume successfully attaching
+ *
+ * @pre no locks held
+ *
+ * @post VOL_LOCK held
+ */
+static Volume *
+attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
+ Volume * vp, int isbusy, int mode)
+{
+ /* have we read in the header successfully? */
+ int read_header = 0;
+
+ /* should we FreeVolume(vp) instead of VCheckFree(vp) in the error
+ * cleanup? */
+ int forcefree = 0;
+
+ *ec = 0;
+
+ vp->vnodeIndex[vLarge].handle = NULL;
+ vp->vnodeIndex[vSmall].handle = NULL;
+ vp->diskDataHandle = NULL;
+ vp->linkHandle = NULL;
+
+#ifdef AFS_DEMAND_ATTACH_FS
+ attach_check_vop(ec, volumeId, partp, vp);
+ if (!*ec) {
+ attach_volume_header(ec, vp, partp, mode, 0);
+ }
+#else
+ attach_volume_header(ec, vp, partp, mode, 0);
+#endif /* !AFS_DEMAND_ATTACH_FS */
+
+ if (*ec == VNOVOL) {
+ /* if the volume doesn't exist, skip straight to 'error' so we don't
+ * request a salvage */
+ goto error;
+ }
+
+ if (!*ec) {
+ read_header = 1;
+
+ vp->specialStatus = (byte) (isbusy ? VBUSY : 0);
+ vp->shuttingDown = 0;
+ vp->goingOffline = 0;
+ vp->nUsers = 1;
+#ifdef AFS_DEMAND_ATTACH_FS
+ vp->stats.last_attach = FT_ApproxTime();
+ vp->stats.attaches++;
+#endif
+
+ VOL_LOCK;
+ IncUInt64(&VStats.attaches);
+ vp->cacheCheck = ++VolumeCacheCheck;
+ /* just in case this ever rolls over */
+ if (!vp->cacheCheck)
+ vp->cacheCheck = ++VolumeCacheCheck;
+ VOL_UNLOCK;
+
+#ifdef AFS_DEMAND_ATTACH_FS
V_attachFlags(vp) |= VOL_HDR_LOADED;
vp->stats.last_hdr_load = vp->stats.last_attach;
- }
#endif /* AFS_DEMAND_ATTACH_FS */
+ }
if (!*ec) {
struct IndexFileHeader iHead;
#else /* AFS_DEMAND_ATTACH_FS */
*ec = VSALVAGE;
#endif /* AFS_DEMAND_ATTACH_FS */
+
goto error;
}
VChangeState_r(vp, VOL_STATE_ERROR);
vp->nUsers = 0;
#endif /* AFS_DEMAND_ATTACH_FS */
- FreeVolume(vp);
Log("VAttachVolume: volume %s is junk; it should be destroyed at next salvage\n", path);
*ec = VNOVOL;
- return NULL;
+ forcefree = 1;
+ goto error;
}
}
AddVolumeToHashTable(vp, V_id(vp));
#ifdef AFS_DEMAND_ATTACH_FS
+ if (VCanUnlockAttached() && (V_attachFlags(vp) & VOL_LOCKED)) {
+ VUnlockVolume(vp);
+ }
if ((programType != fileServer) ||
(V_inUse(vp) == fileServer)) {
AddVolumeToVByPList_r(vp);
VChangeState_r(vp, VOL_STATE_UNATTACHED);
}
#endif
+
return vp;
error:
}
#endif /* AFS_DEMAND_ATTACH_FS */
- VReleaseVolumeHandles_r(vp);
+ if (read_header) {
+ VReleaseVolumeHandles_r(vp);
+ }
#ifdef AFS_DEMAND_ATTACH_FS
VCheckSalvage(vp);
- VCheckFree(vp);
+ if (forcefree) {
+ FreeVolume(vp);
+ } else {
+ VCheckFree(vp);
+ }
#else /* !AFS_DEMAND_ATTACH_FS */
FreeVolume(vp);
#endif /* !AFS_DEMAND_ATTACH_FS */
}
#endif
- 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)
- Log("Volume %u: couldn't reread volume header\n",
- vp->hashid);
-#ifdef AFS_DEMAND_ATTACH_FS
- if (VCanScheduleSalvage()) {
- VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_INVALIDATE_HEADER);
- } else {
- FreeVolume(vp);
- vp = NULL;
- }
-#else /* AFS_DEMAND_ATTACH_FS */
- FreeVolume(vp);
- vp = NULL;
-#endif /* AFS_DEMAND_ATTACH_FS */
- break;
- }
-
#ifdef AFS_DEMAND_ATTACH_FS
/*
- * this test MUST happen after the volume header is loaded
+ * this test MUST happen after VAttachVolymeByVp, so vol_op_state is
+ * not VolOpRunningUnknown (attach2 would have converted it to Online
+ * or Offline)
*/
/* only valid before/during demand attachment */
break;
}
#endif /* 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)
+ Log("Volume %u: couldn't reread volume header\n",
+ vp->hashid);
+#ifdef AFS_DEMAND_ATTACH_FS
+ if (VCanScheduleSalvage()) {
+ VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_INVALIDATE_HEADER);
+ } else {
+ FreeVolume(vp);
+ vp = NULL;
+ }
+#else /* AFS_DEMAND_ATTACH_FS */
+ FreeVolume(vp);
+ vp = NULL;
+#endif /* AFS_DEMAND_ATTACH_FS */
+ break;
+ }
VGET_CTR_INC(V7);
if (vp->shuttingDown) {
IH_REALLYCLOSE(vp->linkHandle);
#ifdef AFS_DEMAND_ATTACH_FS
+ if ((V_attachFlags(vp) & VOL_LOCKED)) {
+ VUnlockVolume(vp);
+ }
+
VOL_LOCK;
VChangeState_r(vp, state_save);
#endif
IH_RELEASE(vp->linkHandle);
#ifdef AFS_DEMAND_ATTACH_FS
+ if ((V_attachFlags(vp) & VOL_LOCKED)) {
+ VUnlockVolume(vp);
+ }
+
VOL_LOCK;
VChangeState_r(vp, state_save);
#endif
}
/**
+ * same as VVolOpLeaveOnline_r, but does not require a volume with an attached
+ * header.
+ *
+ * @param[in] vp volume object
+ * @param[in] vopinfo volume operation info object
+ *
+ * @return whether it is safe to leave volume online
+ * @retval 0 it is NOT SAFE to leave the volume online
+ * @retval 1 it is safe to leave the volume online during the operation
+ * @retval -1 unsure; volume header is required in order to know whether or
+ * not is is safe to leave the volume online
+ *
+ * @pre VOL_LOCK is held
+ *
+ * @internal volume package internal use only
+ */
+int
+VVolOpLeaveOnlineNoHeader_r(Volume * vp, FSSYNC_VolOp_info * vopinfo)
+{
+ /* follow the logic in VVolOpLeaveOnline_r; this is the same, except
+ * assume that we don't know VolumeWriteable; return -1 if the answer
+ * depends on VolumeWriteable */
+
+ if (vopinfo->vol_op_state == FSSYNC_VolOpRunningOnline) {
+ return 1;
+ }
+ if (vopinfo->com.command == FSYNC_VOL_NEEDVOLUME &&
+ vopinfo->com.reason == V_READONLY) {
+
+ return 1;
+ }
+ if (vopinfo->com.command == FSYNC_VOL_NEEDVOLUME &&
+ (vopinfo->com.reason == V_CLONE ||
+ vopinfo->com.reason == V_DUMP)) {
+
+ /* must know VolumeWriteable */
+ return -1;
+ }
+ return 0;
+}
+
+/**
* determine whether VBUSY should be set during this volume operation.
*
* @param[in] vp volume object
* @retval 0 volume salvage will occur
* @retval 1 volume salvage could not be scheduled
*
- * @note DAFS fileserver only
+ * @note DAFS only
*
- * @note this call does not synchronously schedule a volume salvage. rather,
- * it sets volume state so that when volume refcounts reach zero, a
- * volume salvage will occur. by "refcounts", we mean both nUsers and
- * nWaiters must be zero.
+ * @note in the fileserver, this call does not synchronously schedule a volume
+ * salvage. rather, it sets volume state so that when volume refcounts
+ * reach zero, a volume salvage will occur. by "refcounts", we mean both
+ * nUsers and nWaiters must be zero.
*
* @internal volume package internal use only.
*/
{
int code = 0;
/*
- * for DAFS volume utilities, transition to error state
- * (at some point in the future, we should consider
- * making volser talk to salsrv)
+ * for DAFS volume utilities that are not supposed to schedule salvages,
+ * just transition to error state instead
*/
if (!VCanScheduleSalvage()) {
VChangeState_r(vp, VOL_STATE_ERROR);
vp->salvage.reason = reason;
vp->stats.last_salvage = FT_ApproxTime();
- if (programType == fileServer && vp->header && VIsSalvager(V_inUse(vp))) {
- /* Right now we can't tell for sure if this indicates a
- * salvage is running, or if a running salvage crashed, so
- * we always ERROR the volume in case a salvage is running.
- * Once we get rid of the partition lock and instead lock
- * individual volume header files for salvages, we will
- * probably be able to tell if a salvage is running, and we
- * can do away with this behavior. */
- /* Note that we can avoid this check for non-fileserver programs,
- * since they must lock the partition in order to attach a volume.
- * Since the salvager also locks the partition to salvage, we
- * could not have reached this point for non-fileservers if this
- * volume was being salvaged; so we assume it is not. */
- Log("VRequestSalvage: volume %u appears to be salvaging, but we\n", vp->hashid);
- Log(" didn't request a salvage. Forcing it offline waiting for the\n");
- Log(" salvage to finish; if you are sure no salvage is running,\n");
- Log(" run a salvage manually.\n");
-
- /* make sure neither VScheduleSalvage_r nor
- * VUpdateSalvagePriority_r try to schedule another salvage */
- vp->salvage.requested = vp->salvage.scheduled = 0;
-
- /* these stats aren't correct, but doing this makes them
- * slightly closer to being correct */
- vp->stats.salvages++;
- vp->stats.last_salvage_req = FT_ApproxTime();
- IncUInt64(&VStats.salvages);
-
- VChangeState_r(vp, VOL_STATE_ERROR);
- *ec = VSALVAGE;
- code = 1;
+ /* Note that it is not possible for us to reach this point if a
+ * salvage is already running on this volume (even if the fileserver
+ * was restarted during the salvage). If a salvage were running, the
+ * salvager would have write-locked the volume header file, so when
+ * we tried to lock the volume header, the lock would have failed,
+ * and we would have failed during attachment prior to calling
+ * VRequestSalvage. So we know that we can schedule salvages without
+ * fear of a salvage already running for this volume. */
- } else if (vp->stats.salvages < SALVAGE_COUNT_MAX) {
+ if (vp->stats.salvages < SALVAGE_COUNT_MAX) {
VChangeState_r(vp, VOL_STATE_SALVAGING);
*ec = VSALVAGING;
} else {