From 6d23bbae9df78ecd98d0af2580cefe8c5bdd12c4 Mon Sep 17 00:00:00 2001 From: Andrew Deason Date: Fri, 29 Oct 2010 11:14:49 -0500 Subject: [PATCH] vol: Add interfaces for registering RX calls Add VGetVolumeWithCall and VPutVolumeWithCall, to associate RX calls with volume heavyweight references. Also add the interrupt_rxcall field to the volume package options structure. This also adds the VIsGoingOffline function, so a caller can tell when a volume is going offline. Reviewed-on: http://gerrit.openafs.org/3215 Reviewed-by: Derrick Brashear Tested-by: BuildBot (cherry picked from commit 33409b2c849d7fae3b10b3202bb15e338ae5b982) Change-Id: Ib50a17b3479453bbbaef571711ede7115b17318e Reviewed-on: http://gerrit.openafs.org/6265 Tested-by: BuildBot Reviewed-by: Derrick Brashear --- src/vol/volume.c | 165 +++++++++++++++++++++++++++++++++++++++- src/vol/volume.h | 23 +++++- src/vol/volume_inline.h | 1 + 3 files changed, 185 insertions(+), 4 deletions(-) diff --git a/src/vol/volume.c b/src/vol/volume.c index 37c2e44e5..ad5c1475d 100644 --- a/src/vol/volume.c +++ b/src/vol/volume.c @@ -511,6 +511,8 @@ VOptDefaults(ProgramType pt, VolumePackageOptions *opts) opts->canUseFSSYNC = 0; opts->canUseSALVSYNC = 0; + opts->interrupt_rxcall = NULL; + #ifdef FAST_RESTART opts->unsafe_attach = 1; #else /* !FAST_RESTART */ @@ -938,6 +940,7 @@ VInitVolumePackageThread(void *args) vp->partition = partition; vp->hashid = vid; queue_Init(&vp->vnode_list); + queue_Init(&vp->rx_call_list); CV_INIT(&V_attachCV(vp), "partattach", CV_DEFAULT, 0); vb->batch[vb->size++] = vp; @@ -2170,6 +2173,7 @@ VPreAttachVolumeByVp_r(Error * ec, osi_Assert(vp != NULL); memset(vp, 0, sizeof(Volume)); queue_Init(&vp->vnode_list); + queue_Init(&vp->rx_call_list); CV_INIT(&V_attachCV(vp), "vp attach", CV_DEFAULT, 0); } @@ -2399,6 +2403,7 @@ VAttachVolumeByName_r(Error * ec, char *partition, char *name, int mode) vp->device = partp->device; vp->partition = partp; queue_Init(&vp->vnode_list); + queue_Init(&vp->rx_call_list); #ifdef AFS_DEMAND_ATTACH_FS CV_INIT(&V_attachCV(vp), "vp attach", CV_DEFAULT, 0); #endif /* AFS_DEMAND_ATTACH_FS */ @@ -3053,8 +3058,8 @@ attach_check_vop(Error *ec, VolumeId volid, struct DiskPartition64 *partp, * @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 + * vp->vnode_list, vp->rx_call_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 @@ -3557,6 +3562,113 @@ VHold(Volume * vp) } #endif +static afs_int32 +VIsGoingOffline_r(struct Volume *vp) +{ + afs_int32 code = 0; + + if (vp->goingOffline) { + if (vp->specialStatus) { + code = vp->specialStatus; + } else if (V_inService(vp) == 0 || V_blessed(vp) == 0) { + code = VNOVOL; + } else { + code = VOFFLINE; + } + } + + return code; +} + +/** + * Tell the caller if a volume is waiting to go offline. + * + * @param[in] vp The volume we want to know about + * + * @return volume status + * @retval 0 volume is not waiting to go offline, go ahead and use it + * @retval nonzero volume is waiting to offline, and give the returned code + * as an error to anyone accessing the volume + * + * @pre VOL_LOCK is NOT held + * @pre caller holds a heavyweight reference on vp + */ +afs_int32 +VIsGoingOffline(struct Volume *vp) +{ + afs_int32 code; + + VOL_LOCK; + code = VIsGoingOffline_r(vp); + VOL_UNLOCK; + + return code; +} + +/** + * Register an RX call with a volume. + * + * @param[inout] ec Error code; if unset when passed in, may be set if + * the volume starts going offline + * @param[out] client_ec @see GetVolume + * @param[in] vp Volume struct + * @param[in] cbv VCallByVol struct containing the RX call to register + * + * @pre VOL_LOCK held + * @pre caller holds heavy ref on vp + * + * @internal + */ +static void +VRegisterCall_r(Error *ec, Error *client_ec, Volume *vp, struct VCallByVol *cbv) +{ + if (vp && cbv) { +#ifdef AFS_DEMAND_ATTACH_FS + if (!*ec) { + /* just in case the volume started going offline after we got the + * reference to it... otherwise, if the volume started going + * offline right at the end of GetVolume(), we might race with the + * RX call scanner, and return success and add our cbv to the + * rx_call_list _after_ the scanner has scanned the list. */ + *ec = VIsGoingOffline_r(vp); + if (client_ec) { + *client_ec = *ec; + } + } + + while (V_attachState(vp) == VOL_STATE_SCANNING_RXCALLS) { + VWaitStateChange_r(vp); + } +#endif /* AFS_DEMAND_ATTACH_FS */ + + queue_Prepend(&vp->rx_call_list, cbv); + } +} + +/** + * Deregister an RX call with a volume. + * + * @param[in] vp Volume struct + * @param[in] cbv VCallByVol struct containing the RX call to deregister + * + * @pre VOL_LOCK held + * @pre caller holds heavy ref on vp + * + * @internal + */ +static void +VDeregisterCall_r(Volume *vp, struct VCallByVol *cbv) +{ + if (cbv && queue_IsOnQueue(cbv)) { +#ifdef AFS_DEMAND_ATTACH_FS + while (V_attachState(vp) == VOL_STATE_SCANNING_RXCALLS) { + VWaitStateChange_r(vp); + } +#endif /* AFS_DEMAND_ATTACH_FS */ + + queue_Remove(cbv); + } +} /***************************************************/ /* get and put volume routines */ @@ -3601,6 +3713,22 @@ VPutVolume(Volume * vp) VOL_UNLOCK; } +/** + * Puts a volume reference obtained with VGetVolumeWithCall. + * + * @param[in] vp Volume struct + * @param[in] cbv VCallByVol struct given to VGetVolumeWithCall, or NULL if none + * + * @pre VOL_LOCK is NOT held + */ +void +VPutVolumeWithCall(Volume *vp, struct VCallByVol *cbv) +{ + VOL_LOCK; + VDeregisterCall_r(vp, cbv); + VPutVolume_r(vp); + VOL_UNLOCK; +} /* Get a pointer to an attached volume. The pointer is returned regardless of whether or not the volume is in service or on/off line. An error @@ -3629,6 +3757,39 @@ VGetVolumeTimed(Error * ec, Error * client_ec, VolId volumeId, return retVal; } +/** + * Get a volume reference associated with an RX call. + * + * @param[out] ec @see GetVolume + * @param[out] client_ec @see GetVolume + * @param[in] volumeId @see GetVolume + * @param[in] ts How long to wait for going-offline volumes (absolute time). + * If NULL, wait forever. If ts->tv_sec == 0, return immediately + * with an error if the volume is going offline. + * @param[in] cbv Contains an RX call to be associated with this volume + * reference. This call may be interrupted if the volume is + * requested to go offline while we hold a ref on it. Give NULL + * to not associate an RX call with this reference. + * + * @return @see GetVolume + * + * @note for LWP builds, ts must be NULL + * + * @note A reference obtained with this function MUST be put back with + * VPutVolumeWithCall + */ +Volume * +VGetVolumeWithCall(Error * ec, Error * client_ec, VolId volumeId, + const struct timespec *ts, struct VCallByVol *cbv) +{ + Volume *retVal; + VOL_LOCK; + retVal = GetVolume(ec, client_ec, volumeId, NULL, ts); + VRegisterCall_r(ec, client_ec, retVal, cbv); + VOL_UNLOCK; + return retVal; +} + Volume * VGetVolume_r(Error * ec, VolId volumeId) { diff --git a/src/vol/volume.h b/src/vol/volume.h index 3e0031422..713e8ef2d 100644 --- a/src/vol/volume.h +++ b/src/vol/volume.h @@ -206,9 +206,11 @@ typedef enum { VOL_STATE_SALVAGE_REQ = 21, /**< volume has been requested to be salvaged, * but is waiting for other users to go away * so it can be offlined */ + VOL_STATE_SCANNING_RXCALLS = 22, /**< volume is scanning vp->rx_call_list + * to interrupt RX calls */ /* please add new states directly above this line */ - VOL_STATE_FREED = 22, /**< debugging aid */ - VOL_STATE_COUNT = 23 /**< total number of valid states */ + VOL_STATE_FREED = 23, /**< debugging aid */ + VOL_STATE_COUNT = 24 /**< total number of valid states */ } VolState; /** @@ -280,6 +282,9 @@ typedef struct VolumePackageOptions { afs_int32 canUseSALVSYNC; /**< can we use the SALVSYNC channel? (DAFS) */ afs_int32 unsafe_attach; /**< can we bypass checking the inUse vol * header on attach? */ + void (*interrupt_rxcall) (struct rx_call *call, afs_int32 error); + /**< callback to interrupt RX calls accessing + * a going-offline volume */ } VolumePackageOptions; /* Magic numbers and version stamps for each type of file */ @@ -654,6 +659,14 @@ typedef struct VolumeVLRUState { } VolumeVLRUState; #endif /* AFS_DEMAND_ATTACH_FS */ +/** + * node for a volume's rx_call_list. + */ +struct VCallByVol { + struct rx_queue q; + struct rx_call *call; +}; + typedef struct Volume { struct rx_queue q; /* Volume hash chain pointers */ VolumeId hashid; /* Volume number -- for hash table lookup */ @@ -703,6 +716,8 @@ typedef struct Volume { * volume list--the list of volumes that will be * salvaged should the file server crash */ struct rx_queue vnode_list; /**< linked list of cached vnodes for this volume */ + struct rx_queue rx_call_list; /**< linked list of split RX calls using this + * volume (fileserver only) */ #ifdef AFS_DEMAND_ATTACH_FS VolState attach_state; /* what stage of attachment has been completed */ afs_uint32 attach_flags; /* flags related to attachment state */ @@ -800,8 +815,11 @@ extern char *VSalvageMessage; /* Canonical message when a volume is forced extern Volume *VGetVolume(Error * ec, Error * client_ec, VolId volumeId); extern Volume *VGetVolumeTimed(Error * ec, Error * client_ec, VolId volumeId, const struct timespec *ts); +extern Volume *VGetVolumeWithCall(Error * ec, Error * client_ec, VolId volumeId, + const struct timespec *ts, struct VCallByVol *cbv); extern Volume *VGetVolume_r(Error * ec, VolId volumeId); extern void VPutVolume(Volume *); +extern void VPutVolumeWithCall(Volume *vp, struct VCallByVol *cbv); extern void VPutVolume_r(Volume *); extern void VOffline(Volume * vp, char *message); extern void VOffline_r(Volume * vp, char *message); @@ -861,6 +879,7 @@ extern Volume * VLookupVolume_r(Error * ec, VolId volumeId, Volume * hint); extern void VGetVolumePath(Error * ec, VolId volumeId, char **partitionp, char **namep); extern char *vol_DevName(dev_t adev, char *wpath); +extern afs_int32 VIsGoingOffline(struct Volume *vp); struct VLockFile; extern void VLockFileInit(struct VLockFile *lf, const char *path); diff --git a/src/vol/volume_inline.h b/src/vol/volume_inline.h index 445dc3bf2..4bbfad8bf 100644 --- a/src/vol/volume_inline.h +++ b/src/vol/volume_inline.h @@ -302,6 +302,7 @@ VIsExclusiveState(VolState state) case VOL_STATE_VNODE_CLOSE: case VOL_STATE_VNODE_RELEASE: case VOL_STATE_VLRU_ADD: + case VOL_STATE_SCANNING_RXCALLS: return 1; default: return 0; -- 2.39.5