Add code for locking individual volumes on disk
authorAndrew Deason <adeason@sinenomine.net>
Fri, 19 Feb 2010 23:02:08 +0000 (17:02 -0600)
committerDerrick Brashear <shadow@dementia.org>
Wed, 17 Mar 2010 17:27:55 +0000 (10:27 -0700)
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 <adeason@sinenomine.net>
Reviewed-by: Alistair Ferguson <alistair.ferguson@mac.com>
Tested-by: Derrick Brashear <shadow@dementia.org>
Reviewed-by: Derrick Brashear <shadow@dementia.org>

src/vol/partition.c
src/vol/partition.h
src/vol/volume.c
src/vol/volume.h
src/vol/volume_inline.h

index 3268579..b874a21 100644 (file)
@@ -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 */
index a36d453..15ee14c 100644 (file)
@@ -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 */
 };
 
index 38e173e..8a8308d 100644 (file)
@@ -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 */
 
 /*
index e4fd892..ee66af2 100644 (file)
@@ -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 */
index 2342b64..bfe5a7b 100644 (file)
@@ -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.