vol: convert vnode macros to inline functions 97/12397/3
authorMichael Meffie <mmeffie@sinenomine.net>
Mon, 26 Sep 2016 15:19:13 +0000 (11:19 -0400)
committerBenjamin Kaduk <kaduk@mit.edu>
Sun, 25 Dec 2016 22:43:47 +0000 (17:43 -0500)
Convert the vnode macros to inline functions to fix integer overflows
for very large vnode numbers (and generally improve the code robustness
and readability).

The macro version of vnodeIndexOffset() will evaluate to an incorrect
offset for very large vnode numbers due to 32-bit integer overflow. The
vnode index file will then be corrupted when writing to the incorrect
offset.

In code paths where the vnode number incorrectly defined as a signed
32-bit integer, this change prevents vnodeIndexOffset() from evaluating
to a negative result when a vnode number is larger than 2^31.

Thanks to Mark Vitale for reporting and providing analysis.

Change-Id: Ia6e0f2d2f97fa1091e0b5a4029d40098692ee681
Reviewed-on: https://gerrit.openafs.org/12397
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>

src/vol/vnode.h

index d0f2c1d..b287573 100644 (file)
@@ -28,8 +28,25 @@ typedef struct ViceLock {
     int lockTime;
 } ViceLock;
 
-#define ViceLockCheckLocked(vptr) ((vptr)->lockTime == 0)
-#define ViceLockClear(vptr) ((vptr)->lockCount = (vptr)->lockTime = 0)
+/**
+ * Return non-zero if unlocked.
+ */
+static_inline int
+ViceLockCheckLocked(struct ViceLock *vptr)
+{
+    return (vptr->lockTime == 0);
+}
+
+/**
+ * Clear the lock.
+ */
+static_inline int
+ViceLockClear(struct ViceLock *vptr)
+{
+    vptr->lockCount = 0;
+    vptr->lockTime = 0;
+    return 0;
+}
 
 #define ROOTVNODE 1
 
@@ -67,15 +84,63 @@ struct VnodeClassInfo {
 
 extern struct VnodeClassInfo VnodeClassInfo[nVNODECLASSES];
 
-#define vnodeTypeToClass(type)  ((type) == vDirectory? vLarge: vSmall)
-#define vnodeIdToClass(vnodeId) ((vnodeId-1)&VNODECLASSMASK)
-#define vnodeIdToBitNumber(v) (((v)-1)>>VNODECLASSWIDTH)
-/* The following calculation allows for a header record at the beginning
-   of the index.  The header record is the same size as a vnode */
-#define vnodeIndexOffset(vcp,vnodeNumber) \
-    ((vnodeIdToBitNumber(vnodeNumber)+1)<<(vcp)->logSize)
-#define bitNumberToVnodeNumber(b,class) ((VnodeId)(((b)<<VNODECLASSWIDTH)+(class)+1))
-#define vnodeIsDirectory(vnodeNumber) (vnodeIdToClass(vnodeNumber) == vLarge)
+/**
+ * Return the vnode class (large or small) of this vnode type.
+ */
+static_inline VnodeClass
+vnodeTypeToClass(VnodeType vnodeType)
+{
+    return (vnodeType == vDirectory ? vLarge : vSmall);
+}
+
+/**
+ * Return the vnode type of this vnode number.
+ */
+static_inline VnodeClass
+vnodeIdToClass(VnodeId vnodeNumber)
+{
+    return ((vnodeNumber - 1) & VNODECLASSMASK);
+}
+
+/**
+ * Return the vnode index of this vnode number.
+ */
+static_inline afs_uint32
+vnodeIdToBitNumber(VnodeId vnodeNumber)
+{
+    return ((vnodeNumber - 1) >> VNODECLASSWIDTH);
+}
+
+/**
+ * Return the index file offset of this vnode class and number.
+ *
+ * The following calculation allows for a header record at the beginning of
+ * the index.  The header record is the same size as a vnode.
+ */
+static_inline afs_foff_t
+vnodeIndexOffset(struct VnodeClassInfo* vcp, VnodeId vnodeNumber)
+{
+    return (((afs_foff_t)(vnodeIdToBitNumber(vnodeNumber) + 1)) << vcp->logSize);
+}
+
+/**
+ * Return the vnode number of this vnode index.
+ */
+static_inline VnodeId
+bitNumberToVnodeNumber(afs_uint32 bitNumber, VnodeClass vnodeClass)
+{
+    return ((((VnodeId)bitNumber) << VNODECLASSWIDTH) + vnodeClass + 1);
+}
+
+/**
+ * Return non-zero if this vnode number is a directory.
+ */
+static_inline int
+vnodeIsDirectory(VnodeId vnodeNumber)
+{
+    return (vnodeIdToClass(vnodeNumber) == vLarge);
+}
+
 
 typedef struct VnodeDiskObject {
     unsigned int type:3;       /* Vnode is file, directory, symbolic link