diff --git a/src/viced/afsfileprocs.c b/src/viced/afsfileprocs.c index 0bb0ea3593..39a534216f 100644 --- a/src/viced/afsfileprocs.c +++ b/src/viced/afsfileprocs.c @@ -1220,6 +1220,26 @@ RXStore_AccessList(Vnode * targetptr, struct AFSOpaque *AccessList) } /*RXStore_AccessList */ +static int +CheckLink(Volume *volptr, FdHandle_t *fdP, const char *descr) +{ + int code; + afs_ino_str_t ino; + + code = FDH_ISUNLINKED(fdP); + if (code < 0) { + ViceLog(0, ("CopyOnWrite: error fstating volume %u inode %s (%s), errno %d\n", + V_id(volptr), PrintInode(ino, fdP->fd_ih->ih_ino), descr, errno)); + return -1; + } + if (code) { + ViceLog(0, ("CopyOnWrite corruption prevention: detected zero nlink for " + "volume %u inode %s (%s), forcing volume offline\n", + V_id(volptr), PrintInode(ino, fdP->fd_ih->ih_ino), descr)); + return -1; + } + return 0; +} /* In our current implementation, each successive data store (new file * data version) creates a new inode. This function creates the new @@ -1300,6 +1320,20 @@ CopyOnWrite(Vnode * targetptr, Volume * volptr, afs_foff_t off, afs_fsize_t len) newFdP = IH_OPEN(newH); opr_Assert(newFdP != NULL); + rc = CheckLink(volptr, targFdP, "source"); + if (!rc) { + rc = CheckLink(volptr, newFdP, "dest"); + } + if (rc) { + FDH_REALLYCLOSE(newFdP); + IH_RELEASE(newH); + FDH_REALLYCLOSE(targFdP); + IH_DEC(V_linkHandle(volptr), ino, V_parentId(volptr)); + free(buff); + VTakeOffline(volptr); + return VSALVAGE; + } + done = off; while (size > 0) { if (size > COPYBUFFSIZE) { /* more than a buffer */