From 2578555d7e08131bf2fe4cdd0aa4b32567a76eb2 Mon Sep 17 00:00:00 2001 From: Andrew Deason Date: Tue, 15 Mar 2011 14:24:01 -0500 Subject: [PATCH] viced: Check vnode length on dir ops The commit aadf69eabb1962496fa93745ab560a5b48cacd61 added checks on vnode length whenever we read or write from a vnode. Add the same check on directory vnodes when we modify the directory (whenever entries are added or deleted). Change-Id: I8aa438941f840019bc541d5a978610c4f78330c8 Reviewed-on: http://gerrit.openafs.org/4233 Tested-by: BuildBot Reviewed-by: Derrick Brashear --- src/viced/afsfileprocs.c | 53 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/viced/afsfileprocs.c b/src/viced/afsfileprocs.c index 9ba8b88145..71ea49b912 100644 --- a/src/viced/afsfileprocs.c +++ b/src/viced/afsfileprocs.c @@ -277,11 +277,52 @@ SetVolumeSync(struct AFSVolSync *async, Volume * avol) FS_UNLOCK; } /*SetVolumeSync */ +/** + * Verify that the on-disk size for a vnode matches the length in the vnode + * index. + * + * @param[in] vp Volume pointer + * @param[in] vnp Vnode pointer + * @param[in] alen Size of the vnode on disk, if known. If unknown, give -1, + * and CheckLength itself will determine the on-disk size. + * + * @return operation status + * @retval 0 lengths match + * @retval nonzero Error; either the lengths do not match or there was an + * error determining the on-disk size. The volume should be + * taken offline and salvaged. + */ static int CheckLength(struct Volume *vp, struct Vnode *vnp, afs_sfsize_t alen) { afs_sfsize_t vlen; VN_GET_LEN(vlen, vnp); + + if (alen < 0) { + FdHandle_t *fdP; + + fdP = IH_OPEN(vnp->handle); + if (fdP == NULL) { + ViceLog(0, ("CheckLength: cannot open inode for fid %lu.%lu.%lu\n", + afs_printable_uint32_lu(vp->hashid), + afs_printable_uint32_lu(Vn_id(vnp)), + afs_printable_uint32_lu(vnp->disk.uniquifier))); + return -1; + } + alen = FDH_SIZE(fdP); + FDH_CLOSE(fdP); + if (alen < 0) { + afs_int64 alen64 = alen; + ViceLog(0, ("CheckLength: cannot get size for inode for fid " + "%lu.%lu.%lu; FDH_SIZE returned %" AFS_INT64_FMT "\n", + afs_printable_uint32_lu(vp->hashid), + afs_printable_uint32_lu(Vn_id(vnp)), + afs_printable_uint32_lu(vnp->disk.uniquifier), + alen64)); + return -1; + } + } + if (alen != vlen) { afs_int64 alen64 = alen, vlen64 = vlen; ViceLog(0, ("Fid %lu.%lu.%lu has inconsistent length (index " @@ -1368,6 +1409,12 @@ DeleteTarget(Vnode * parentptr, Volume * volptr, Vnode ** targetptr, /* watch for invalid names */ if (!strcmp(Name, ".") || !strcmp(Name, "..")) return (EINVAL); + + if (CheckLength(volptr, parentptr, -1)) { + VTakeOffline_r(volptr); + return VSALVAGE; + } + if (parentptr->disk.cloned) { ViceLog(25, ("DeleteTarget : CopyOnWrite called\n")); if ((errorCode = CopyOnWrite(parentptr, volptr, 0, MAXFSIZE))) { @@ -1779,6 +1826,12 @@ Alloc_NewVnode(Vnode * parentptr, DirHandle * dir, Volume * volptr, return (errorCode); } + if (CheckLength(volptr, parentptr, -1)) { + VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0); + VTakeOffline_r(volptr); + return VSALVAGE; + } + *targetptr = VAllocVnode(&errorCode, volptr, FileType); if (errorCode != 0) { VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);