viced: Sanity check file link count during CoW
authorAndrew Deason <adeason@sinenomine.net>
Wed, 19 Dec 2012 00:49:49 +0000 (18:49 -0600)
committerDerrick Brashear <shadow@your-file-system.com>
Wed, 26 Dec 2012 19:39:45 +0000 (11:39 -0800)
A few ihandle bugs in the past have caused the CopyOnWrite code to
open cached file handles for files which have been deleted. When we
CoW, both of the files we're dealing with had better actually be on
disk, so bail out and flag an error if either of them appear unlinked.

FIXES 131530

Change-Id: I478871bb1b9b43fc0161bb4a255dd7b77d2a28ae
Reviewed-on: http://gerrit.openafs.org/8839
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Derrick Brashear <shadow@your-file-system.com>

src/viced/afsfileprocs.c

index 0bb0ea3..39a5342 100644 (file)
@@ -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 */