hammer2 - Add destroy-inum directive
authorMatthew Dillon <dillon@apollo.backplane.com>
Wed, 1 Aug 2018 17:14:46 +0000 (10:14 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Wed, 1 Aug 2018 17:14:46 +0000 (10:14 -0700)
* Add support for destroying screwed up inodes (e.g. inodes with CRC
  failures and such).

  hammer2 -s filesystem destroy-inum inode_number

  This will attempt to destroy an inode number without reading it,
  allowing the removal of dead inodes from a corrupted filesystem.

* This is similar to 'hammer2 destroy path', which destroys dead
  directory entries, but acts on the inode instead of on the
  directory entry.

sbin/hammer2/cmd_destroy.c
sbin/hammer2/hammer2.h
sbin/hammer2/main.c
sys/vfs/hammer2/hammer2.h
sys/vfs/hammer2/hammer2_ioctl.c
sys/vfs/hammer2/hammer2_xops.c

index 5f5bf07..8d4e8e7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2017-2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Matthew Dillon <dillon@dragonflybsd.org>
@@ -86,3 +86,30 @@ pathdir(const char *path, const char **lastp)
 
        return fd;
 }
+
+int
+cmd_destroy_inum(const char *sel_path, int ac, const char **av)
+{
+       hammer2_ioc_destroy_t destroy;
+       int i;
+       int fd;
+
+       fd = hammer2_ioctl_handle(sel_path);
+       if (fd < 0)
+               return 1;
+
+       printf("deleting inodes on %s\n", sel_path);
+       for (i = 0; i < ac; ++i) {
+               bzero(&destroy, sizeof(destroy));
+               destroy.cmd = HAMMER2_DELETE_INUM;
+               destroy.inum = strtoul(av[i], NULL, 0);
+               printf("%16jd ", (intmax_t)destroy.inum);
+               if (ioctl(fd, HAMMER2IOC_DESTROY, &destroy) < 0)
+                       printf("%s\n", strerror(errno));
+               else
+                       printf("ok\n");
+       }
+       close(fd);
+
+       return 0;
+}
index 82b5150..2b882aa 100644 (file)
@@ -145,6 +145,7 @@ int cmd_leaf(const char *sel_path);
 int cmd_shell(const char *hostname);
 int cmd_debugspan(const char *hostname);
 int cmd_destroy_path(int ac, const char **av);
+int cmd_destroy_inum(const char *sel_path, int ac, const char **av);
 int cmd_dumpchain(const char *path, u_int flags);
 int cmd_show(const char *devpath, int dofreemap);
 int cmd_rsainit(const char *dir_path);
index bcbce7e..fa44860 100644 (file)
@@ -207,6 +207,12 @@ main(int ac, char **av)
                                "Specify one or more paths to destroy\n");
                }
                ecode = cmd_destroy_path(ac - 1, (const char **)(void *)&av[1]);
+       } else if (strcmp(av[0], "destroy-inum") == 0) {
+               if (ac < 2) {
+                       fprintf(stderr,
+                               "Specify one or more inode numbers to destroy\n");
+               }
+               ecode = cmd_destroy_inum(sel_path, ac - 1, (const char **)(void *)&av[1]);
        } else if (strcmp(av[0], "hash") == 0) {
                ecode = cmd_hash(ac - 1, (const char **)(void *)&av[1]);
        } else if (strcmp(av[0], "info") == 0) {
@@ -507,7 +513,9 @@ usage(int code)
                        "Dump in-memory chain topo from\n"
                        "NOTE: ONFLUSH flag is 0x200\n"
                "    destroy <path>*              "
-                       "Destroy a directory entry (only use if inode bad)\n"
+                       "Destroy directory entries (only use if inode bad)\n"
+               "    destroy-inum <inum>*              "
+                       "Destroy inodes (only use if inode bad)\n"
                "    disconnect <target>          "
                        "Del cluster link\n"
                "    hash filename*               "
index ae70bb4..91905f4 100644 (file)
@@ -1690,6 +1690,7 @@ void hammer2_xop_nrename(hammer2_thread_t *thr, hammer2_xop_t *xop);
 void hammer2_xop_scanlhc(hammer2_thread_t *thr, hammer2_xop_t *xop);
 void hammer2_xop_scanall(hammer2_thread_t *thr, hammer2_xop_t *xop);
 void hammer2_xop_lookup(hammer2_thread_t *thr, hammer2_xop_t *xop);
+void hammer2_xop_delete(hammer2_thread_t *thr, hammer2_xop_t *xop);
 void hammer2_inode_xop_mkdirent(hammer2_thread_t *thr, hammer2_xop_t *xop);
 void hammer2_inode_xop_create(hammer2_thread_t *thr, hammer2_xop_t *xop);
 void hammer2_inode_xop_destroy(hammer2_thread_t *thr, hammer2_xop_t *xop);
index 9bb8f1f..6ad2a5f 100644 (file)
@@ -1198,21 +1198,13 @@ hammer2_ioctl_destroy(hammer2_inode_t *ip, void *data)
                hammer2_pfs_memory_wait(ip, 0);
                hammer2_trans_init(pmp, 0);
 
-               xop = hammer2_xop_alloc(pmp->iroot, 0);
+               xop = hammer2_xop_alloc(pmp->iroot, HAMMER2_XOP_MODIFYING);
                xop->lhc = iocd->inum;
-               hammer2_xop_start(&xop->head, hammer2_xop_lookup);
+               hammer2_xop_start(&xop->head, hammer2_xop_delete);
                error = hammer2_xop_collect(&xop->head, 0);
-               if (error == 0) {
-                       ip = hammer2_inode_get(pmp, NULL, &xop->head, -1);
-                       hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP);
-                       if (ip) {
-                               ip->meta.nlinks = 1;
-                               hammer2_inode_unlink_finisher(ip, 0);
-                               hammer2_inode_unlock(ip);
-                       }
-               } else {
-                       hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP);
-               }
+               error = hammer2_error_to_errno(error);
+               hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP);
+               hammer2_trans_done(pmp, 1);
                }
                break;
        default:
index af20a33..0391b35 100644 (file)
@@ -834,8 +834,6 @@ done:
 
 /*
  * Generic lookup of a specific key.
- *
- * Used by the inode hidden directory code to find the hidden directory.
  */
 void
 hammer2_xop_lookup(hammer2_thread_t *thr, hammer2_xop_t *arg)
@@ -883,6 +881,54 @@ done:
        }
 }
 
+void
+hammer2_xop_delete(hammer2_thread_t *thr, hammer2_xop_t *arg)
+{
+       hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
+       hammer2_chain_t *parent;
+       hammer2_chain_t *chain;
+       hammer2_key_t key_next;
+       int error = 0;
+
+       parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
+                                    HAMMER2_RESOLVE_ALWAYS);
+       chain = NULL;
+       if (parent == NULL) {
+               error = HAMMER2_ERROR_EIO;
+               goto done;
+       }
+
+       /*
+        * Lookup all possibly conflicting directory entries, the feed
+        * inherits the chain's lock so do not unlock it on the iteration.
+        */
+       chain = hammer2_chain_lookup(&parent, &key_next,
+                                    xop->lhc, xop->lhc,
+                                    &error,
+                                    HAMMER2_LOOKUP_NODATA);
+       if (error == 0) {
+               if (chain)
+                       error = chain->error;
+               else
+                       error = HAMMER2_ERROR_ENOENT;
+       }
+       if (chain) {
+               error = hammer2_chain_delete(parent, chain, xop->head.mtid,
+                                            HAMMER2_DELETE_PERMANENT);
+       }
+       hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
+
+done:
+       if (chain) {
+               hammer2_chain_unlock(chain);
+               hammer2_chain_drop(chain);
+       }
+       if (parent) {
+               hammer2_chain_unlock(parent);
+               hammer2_chain_drop(parent);
+       }
+}
+
 /*
  * Generic scan
  *