vlserver: Return error when growing beyond 2 GiB
[openafs.git] / src / vlserver / vlutils.c
index 9067f08..d11917f 100644 (file)
@@ -397,6 +397,31 @@ CheckInit(struct ubik_trans *trans, int builddb)
     return 0;
 }
 
+/**
+ * Grow the eofPtr in the header by 'bump' bytes.
+ *
+ * @param[inout] cheader    VL header
+ * @param[in] bump         How many bytes to add to eofPtr
+ * @param[out] a_blockindex On success, set to the original eofPtr before we
+ *                         bumped it
+ * @return VL error codes
+ */
+static afs_int32
+grow_eofPtr(struct vlheader *cheader, afs_int32 bump, afs_int32 *a_blockindex)
+{
+    afs_int32 blockindex = ntohl(cheader->vital_header.eofPtr);
+
+    if (blockindex < 0 || blockindex >= MAX_AFS_INT32 - bump) {
+       VLog(0, ("Error: Tried to grow the VLDB beyond the 2GiB limit. Either "
+                "find a way to trim down your VLDB, or upgrade to a release "
+                "and database format that supports a larger VLDB.\n"));
+       return VL_IO;
+    }
+
+    *a_blockindex = blockindex;
+    cheader->vital_header.eofPtr = htonl(blockindex + bump);
+    return 0;
+}
 
 afs_int32
 GetExtentBlock(struct vl_ctx *ctx, afs_int32 base)
@@ -418,16 +443,17 @@ GetExtentBlock(struct vl_ctx *ctx, afs_int32 base)
 
        /* Write the full extension block at end of vldb */
        ctx->ex_addr[base]->ex_hdrflags = htonl(VLCONTBLOCK);
-       blockindex = ntohl(ctx->cheader->vital_header.eofPtr);
+       code = grow_eofPtr(ctx->cheader, VL_ADDREXTBLK_SIZE, &blockindex);
+       if (code)
+           ERROR_EXIT(VL_IO);
+
        code =
            vlwrite(ctx->trans, blockindex, (char *)ctx->ex_addr[base],
                    VL_ADDREXTBLK_SIZE);
        if (code)
            ERROR_EXIT(VL_IO);
 
-       /* Update the cheader.vitalheader structure on disk */
-       ctx->cheader->vital_header.eofPtr = blockindex + VL_ADDREXTBLK_SIZE;
-       ctx->cheader->vital_header.eofPtr = htonl(ctx->cheader->vital_header.eofPtr);
+
        code = write_vital_vlheader(ctx);
        if (code)
            ERROR_EXIT(VL_IO);
@@ -572,9 +598,11 @@ AllocBlock(struct vl_ctx *ctx, struct nvlentry *tentry)
            return 0;
        ctx->cheader->vital_header.freePtr = htonl(tentry->nextIdHash[0]);
     } else {
+       afs_int32 code;
        /* hosed, nothing on free list, grow file */
-       blockindex = ntohl(ctx->cheader->vital_header.eofPtr);  /* remember this guy */
-       ctx->cheader->vital_header.eofPtr = htonl(blockindex + sizeof(vlentry));
+       code = grow_eofPtr(ctx->cheader, sizeof(vlentry), &blockindex);
+       if (code)
+           return 0;
     }
     ctx->cheader->vital_header.allocs++;
     if (write_vital_vlheader(ctx))