From 57984286f3d96cb2dbf0038dbc67d2f3c069e22e Mon Sep 17 00:00:00 2001 From: Andrew Deason Date: Fri, 19 Feb 2010 17:02:08 -0600 Subject: [PATCH 1/1] Add code for locking individual volumes on disk This adds the necessary APIs and associated changes to lock (on disk) an individual volume on a particular partition. Nothing yet calls these new functions. Change-Id: Ibfa00293e7411f3f48eabdecb13b7e80e126a1ff Reviewed-on: http://gerrit.openafs.org/1405 Tested-by: Andrew Deason Reviewed-by: Alistair Ferguson Tested-by: Derrick Brashear Reviewed-by: Derrick Brashear --- src/vol/partition.c | 5 +++ src/vol/partition.h | 2 + src/vol/volume.c | 51 +++++++++++++++++++++ src/vol/volume.h | 1 + src/vol/volume_inline.h | 117 +++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 175 insertions(+), 1 deletion(-) diff --git a/src/vol/partition.c b/src/vol/partition.c index 3268579..b874a21 100644 --- a/src/vol/partition.c +++ b/src/vol/partition.c @@ -185,6 +185,7 @@ struct DiskPartition64 *DiskPartitionList; #ifdef AFS_DEMAND_ATTACH_FS /* file to lock to conceptually "lock" the vol headers on a partition */ #define AFS_PARTLOCK_FILE ".volheaders.lock" +#define AFS_VOLUMELOCK_FILE ".volume.lock" static struct DiskPartition64 *DiskPartitionTable[VOLMAXPARTS+1]; @@ -292,6 +293,10 @@ VInitPartition_r(char *path, char *devname, Device dev) afs_snprintf(lockpath, MAXPATHLEN, "%s/" AFS_PARTLOCK_FILE, dp->name); lockpath[MAXPATHLEN] = '\0'; VLockFileInit(&dp->headerLockFile, lockpath); + + afs_snprintf(lockpath, MAXPATHLEN, "%s/" AFS_VOLUMELOCK_FILE, dp->name); + lockpath[MAXPATHLEN] = '\0'; + VLockFileInit(&dp->volLockFile, lockpath); } VDiskLockInit(&dp->headerLock, &dp->headerLockFile, 1); #endif /* AFS_DEMAND_ATTACH_FS */ diff --git a/src/vol/partition.h b/src/vol/partition.h index a36d453..15ee14c 100644 --- a/src/vol/partition.h +++ b/src/vol/partition.h @@ -133,6 +133,8 @@ struct DiskPartition64 { } vol_list; struct VLockFile headerLockFile; struct VDiskLock headerLock; /* lock for the collective headers on the partition */ + + struct VLockFile volLockFile; /* lock file for individual volume locks */ #endif /* AFS_DEMAND_ATTACH_FS */ }; diff --git a/src/vol/volume.c b/src/vol/volume.c index 38e173e..8a8308d 100644 --- a/src/vol/volume.c +++ b/src/vol/volume.c @@ -2385,6 +2385,57 @@ VAttachVolumeByVp_r(Error * ec, Volume * vp, int mode) return vp; } } + +/** + * lock a volume on disk (non-blocking). + * + * @param[in] vp The volume to lock + * @param[in] locktype READ_LOCK or WRITE_LOCK + * + * @return operation status + * @retval 0 success, lock was obtained + * @retval EBUSY a conflicting lock was held by another process + * @retval EIO error acquiring lock + * + * @pre If we're in the fileserver, vp is in an exclusive state + * + * @pre vp is not already locked + */ +static int +VLockVolumeNB(Volume *vp, int locktype) +{ + int code; + + assert(programType != fileServer || VIsExclusiveState(V_attachState(vp))); + assert(!(V_attachFlags(vp) & VOL_LOCKED)); + + code = VLockVolumeByIdNB(vp->hashid, vp->partition, locktype); + if (code == 0) { + V_attachFlags(vp) |= VOL_LOCKED; + } + + return code; +} + +/** + * unlock a volume on disk that was locked with VLockVolumeNB. + * + * @param[in] vp volume to unlock + * + * @pre If we're in the fileserver, vp is in an exclusive state + * + * @pre vp has already been locked + */ +static void +VUnlockVolume(Volume *vp) +{ + assert(programType != fileServer || VIsExclusiveState(V_attachState(vp))); + assert((V_attachFlags(vp) & VOL_LOCKED)); + + VUnlockVolumeById(vp->hashid, vp->partition); + + V_attachFlags(vp) &= ~VOL_LOCKED; +} #endif /* AFS_DEMAND_ATTACH_FS */ /* diff --git a/src/vol/volume.h b/src/vol/volume.h index e4fd892..ee66af2 100644 --- a/src/vol/volume.h +++ b/src/vol/volume.h @@ -194,6 +194,7 @@ enum VolFlags { VOL_IS_BUSY = 0x20, /**< volume is not to be free()d */ VOL_ON_VLRU = 0x40, /**< volume is on the VLRU */ VOL_HDR_DONTSALV = 0x80, /**< volume header DONTSALVAGE flag is set */ + VOL_LOCKED = 0x100, /**< volume is disk-locked (@see VLockVolumeNB) */ }; /* VPrintExtendedCacheStats flags */ diff --git a/src/vol/volume_inline.h b/src/vol/volume_inline.h index 2342b64..bfe5a7b 100644 --- a/src/vol/volume_inline.h +++ b/src/vol/volume_inline.h @@ -87,11 +87,126 @@ VShouldCheckInUse(int mode) return 0; } +#ifdef AFS_DEMAND_ATTACH_FS +/** + * acquire a non-blocking disk lock for a particular volume id. + * + * @param[in] volid the volume ID to lock + * @param[in] dp the partition on which 'volid' resides + * @param[in] locktype READ_LOCK or WRITE_LOCK + * + * @return operation status + * @retval 0 success, lock was obtained + * @retval EBUSY another process holds a conflicting lock + * @retval EIO error acquiring lock + * + * @note Use VLockVolumeNB instead, if possible; only use this directly if + * you are not dealing with 'Volume*'s and attached volumes and such + * + * @pre There must not be any other threads acquiring locks on the same volid + * and partition; the locks will not work correctly if two threads try to + * acquire locks for the same volume + */ +static_inline int +VLockVolumeByIdNB(VolumeId volid, struct DiskPartition64 *dp, int locktype) +{ + return VLockFileLock(&dp->volLockFile, volid, locktype, 1 /* nonblock */); +} + +/** + * release a lock acquired by VLockVolumeByIdNB. + * + * @param[in] volid the volume id to unlock + * @param[in] dp the partition on which 'volid' resides + * + * @pre volid was previously locked by VLockVolumeByIdNB + */ +static_inline void +VUnlockVolumeById(VolumeId volid, struct DiskPartition64 *dp) +{ + VLockFileUnlock(&dp->volLockFile, volid); +} + /***************************************************/ /* demand attach fs state machine routines */ /***************************************************/ -#ifdef AFS_DEMAND_ATTACH_FS +/** + * tells caller whether we need to keep volumes locked for the entire time we + * are using them, or if we can unlock volumes as soon as they are attached. + * + * @return whether we can unlock attached volumes or not + * @retval 1 yes, we can unlock attached volumes + * @retval 0 no, do not unlock volumes until we unattach them + */ +static_inline int +VCanUnlockAttached(void) +{ + switch(programType) { + case fileServer: + return 1; + default: + return 0; + } +} + +/** + * tells caller whether we need to lock a vol header with a write lock, a + * read lock, or if we do not need to lock it at all, when attaching. + * + * @param[in] mode volume attachment mode + * @param[in] writeable 1 if the volume is writable, 0 if not + * + * @return how we need to lock the vol header + * @retval 0 do not lock the vol header at all + * @retval READ_LOCK lock the vol header with a read lock + * @retval WRITE_LOCK lock the vol header with a write lock + * + * @note DAFS only (non-DAFS uses partition locks) + */ +static_inline int +VVolLockType(int mode, int writeable) +{ + switch (programType) { + case fileServer: + if (writeable) { + return WRITE_LOCK; + } + return READ_LOCK; + + case volumeSalvager: + case salvageServer: + case salvager: + return WRITE_LOCK; + + default: + /* volserver, vol utilies, etc */ + + switch (mode) { + case V_READONLY: + return READ_LOCK; + + case V_VOLUPD: + case V_SECRETLY: + return WRITE_LOCK; + + case V_CLONE: + case V_DUMP: + if (writeable) { + return WRITE_LOCK; + } + return READ_LOCK; + + case V_PEEK: + return 0; + + default: + assert(0 /* unknown checkout mode */); + return 0; + } + } +} + /** * tells caller whether or not the current state requires * exclusive access without holding glock. -- 1.9.4