namei: Ignore misplaced files
authorAndrew Deason <adeason@sinenomine.net>
Fri, 30 Aug 2013 19:21:16 +0000 (14:21 -0500)
committerD Brashear <shadow@your-file-system.com>
Wed, 5 Feb 2014 15:06:44 +0000 (07:06 -0800)
The namei salvaging/ListViceInodes code currently ignores files where
we cannot derive an inode number from a given filename. However, if a
file is a valid inode filename, but is in the wrong directory, we
still record it. This can cause the salvager to abort, since it
assumes inode e.g. 12345 is present, but when it tries to open 12345,
namei translates the inode to a nonexistant path, and we bail out.

It is unknown how a namei directory structure can reach this state,
but try to handle it. To be on the safe side, just ignore the files,
and log a message about them. That way, if the files are required for
reconstructing the volume or contain important data, they are still
available if needed. And if they contain incorrect or old data, we
don't screw up the volume by trying to use them.

Thanks to Sabah S. Salih for reporting a related issue.

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

src/vol/namei_ops.c

index 4e845b6..05d20e9 100644 (file)
@@ -1719,7 +1719,7 @@ namei_SetLinkCount(FdHandle_t * fdP, Inode ino, int count, int locked)
 
 /* ListViceInodes - write inode data to a results file. */
 static int DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
-                      VolumeId volid);
+                      IHandle_t *myIH);
 static int DecodeVolumeName(char *name, VolumeId *vid);
 static int namei_ListAFSSubDirs(IHandle_t * dirIH,
                                int (*write_fun) (FD_t,
@@ -1982,7 +1982,7 @@ _namei_examine_special(char * path1,
     int ret = 0;
     struct ViceInodeInfo info;
 
-    if (DecodeInode(path1, dname, &info, myIH->ih_vid) < 0) {
+    if (DecodeInode(path1, dname, &info, myIH) < 0) {
        ret = 0;
        goto error;
     }
@@ -2073,7 +2073,7 @@ _namei_examine_reg(char * path3,
     int dirl; /* Windows-only (one level hash dir) */
 #endif
 
-    if (DecodeInode(path3, dname, &info, myIH->ih_vid) < 0) {
+    if (DecodeInode(path3, dname, &info, myIH) < 0) {
        goto error;
     }
 
@@ -2732,7 +2732,7 @@ DecodeVolumeName(char *name, VolumeId *vid)
 #ifdef AFS_NT40_ENV
 static int
 DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
-           VolumeId volid)
+           IHandle_t *myIH)
 {
     char fpath[512];
     int tag, vno;
@@ -2742,6 +2742,7 @@ DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
     char stmp[16];
     FdHandle_t linkHandle;
     char dirl;
+    VolumeId volid = myIH->ih_vid;
 
     snprintf(fpath, sizeof(fpath), "%s" OS_DIRSEP "%s", dpath, name);
 
@@ -2808,12 +2809,16 @@ DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
 #else
 static int
 DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
-           VolumeId volid)
+           IHandle_t *myIH)
 {
     char fpath[512];
     struct afs_stat_st status;
+    struct afs_stat_st checkstatus;
     int parm, tag;
     lb64_string_t check;
+    VolumeId volid = myIH->ih_vid;
+    IHandle_t tmpih;
+    namei_t nameiname;
 
     snprintf(fpath, sizeof(fpath), "%s" OS_DIRSEP "%s", dpath, name);
 
@@ -2828,6 +2833,36 @@ DecodeInode(char *dpath, char *name, struct ViceInodeInfo *info,
     if (strcmp(name, check))
        return -1;
 
+    /* Check if the _full_ path is correct, to ensure we can actually open this
+     * file later. Otherwise, the salvager can choke. */
+    memset(&tmpih, 0, sizeof(tmpih));
+    tmpih.ih_dev = myIH->ih_dev;
+    tmpih.ih_vid = myIH->ih_vid;
+    tmpih.ih_ino = info->inodeNumber;
+    namei_HandleToName(&nameiname, &tmpih);
+    if ((afs_stat(nameiname.n_path, &checkstatus) < 0) ||
+        checkstatus.st_ino != status.st_ino ||
+        checkstatus.st_size != status.st_size) {
+       static int logged;
+       /* log something for this case, since this means the filename looks
+        * like a valid inode, but it's just in the wrong place. That's pretty
+        * strange. */
+       if (!logged) {
+           logged = 1;
+           Log("Note:\n");
+           Log("  Seemingly-misplaced files have been found, which I am\n");
+           Log("  ignoring for now. If you cannot salvage the relevant volume,\n");
+           Log("  you may try manually moving them to their correct location.\n");
+           Log("  If the relevant volume seems fine, and these files do not\n");
+           Log("  appear to contain important data, you can probably manually\n");
+           Log("  delete them, or leave them alone. Contact your local OpenAFS\n");
+           Log("  expert if you are unsure.\n");
+       }
+       Log("Ignoring misplaced file in volume group %u: %s (should be %s)\n",
+           (unsigned)myIH->ih_vid, fpath, nameiname.n_path);
+       return -1;
+    }
+
     if ((info->inodeNumber & NAMEI_INODESPECIAL) == NAMEI_INODESPECIAL) {
        parm = ((info->inodeNumber >> NAMEI_UNIQSHIFT) & NAMEI_UNIQMASK);
        tag = (int)((info->inodeNumber >> NAMEI_TAGSHIFT) & NAMEI_TAGMASK);
@@ -3016,7 +3051,7 @@ namei_ConvertROtoRWvolume(char *pname, VolumeId volumeId)
        if (*dp->d_name == '.')
            continue;
 #endif
-       if (DecodeInode(dir_name, dp->d_name, &info, ih->ih_vid) < 0) {
+       if (DecodeInode(dir_name, dp->d_name, &info, ih) < 0) {
            Log("1 namei_ConvertROtoRWvolume: DecodeInode failed for %s" OS_DIRSEP "%s\n",
                dir_name, dp->d_name);
            closedir(dirp);