0

Using debugfs to check free inodes (list got from dumpe2fs), I observed that most of them have a bad type status, except for a few ones which are regular. I'd like to check them all to see how many and which of them have a different status.

Therefore I made a little python/pexpect program which starts debugfs and interactively sends stat <inode> requests for all those free inodes to find which or them have other that bad type status.

However, it appears that my program is going to need about 2 years to get all the requested information. What faster way could I use to get those inodes content ?

Optionally, I would be glad to get information about why free inodes can have a regular status

Camion
  • 1,264
  • 9
  • 22
  • Programs like `fsck` open the raw disk device and read the inode data directly. – Barmar Jul 10 '21 at 05:13
  • Yes, that's what `debugfs` does too, but `fsck` doesn't report what i'm looking for and reading it on inode at a time with `debugfs` turns out being too slow. – Camion Jul 10 '21 at 06:22
  • That's why I'm suggesting you write a program that reads the disk device directly, just like they do. – Barmar Jul 10 '21 at 06:47
  • Well, it's true that as a last option, i could try to patch debugfs to dump all free inodes in one shot... – Camion Jul 10 '21 at 07:03
  • That's another option. SO isn't a design discussion forum. You need to post a problem with actual code that you've written. – Barmar Jul 10 '21 at 07:06
  • Well, my code is not relevant here: it works as it should and is a bit long (~450 lines) to be posted here. The problem is only about the tools I use which makes it too slow. What I'm asking is about which libraries or other tools that could do the trick without having to rewrite a whole c program. – Camion Jul 10 '21 at 07:34
  • I'm talking about the new code that you're trying to write in place of that, because it's too slow. – Barmar Jul 10 '21 at 07:34
  • Look at the source code of `debugfs` to see what libraries it uses. I suspect there aren't any, so it's all just hand-written in those tools. You'll either have to write your own program from scratch, or modify `debugfs`. – Barmar Jul 10 '21 at 07:36

1 Answers1

0

Since I didn't get any simple solution, I ended up patching debugfs by adding a new function do_rstat based on do_stat in debugfs/debugfs.c. Kind of like this :

void do_rstat(int argc, char *argv[])
{
        ext3_ino_t      ifrom, ito, inode;
        struct ext3_inode * inode_buf;
        errcode_t r;

        if (argc<4) {
                fprintf(stderr, "do_rstat: needs an inodes range (3 arguments).\n");
                return;
        }

        if (check_fs_open(argv[1]))
                return;

        if (string_to_inode_range(argv[2], argv[2], &ifrom, &ito) & 0x2) {
                fprintf(stderr, "do_rstat: invalid inodes range.\n");
                return;
        }

        inode_buf = (struct ext3_inode *)
                        malloc(EXT3_INODE_SIZE(current_fs->super));
        if (!inode_buf) {
                fprintf(stderr, "do_rstat: can't allocate buffer\n");
                return;
        }

        for (inode = ifrom; inode<ito; inode++) {
                r = debugfs_read_inode_full(inode, inode_buf, argv[1],
                                                EXT3_INODE_SIZE(current_fs->super));
                if (r) {
                        FILE    *out;
                        out = open_pager();
                        fprintf(out, "%13ud ERROR %ld\n\n", inode, r);
                        close_pager(out);
                } else
                        dump_inode(inode, inode_buf);
        }

        free(inode_buf);
        return;
}

(However, I won't detail it here because it's quite specific to my needs, but I also replaced the dump_inode(inode, inode_buf); call to get the output on one line with fixed width fields in order to remove the need for pattern matching in the calling program). In order to do that, I inspired myself from the dump_inode and dump_inode_internal functions.

and I also needed to add two functions in debugfs/util.c

/*
 * This routine is used whenever a command needs to turn an <ino> string
 * into an inode.
 */
ext2_ino_t string_to_inode_number(char *str)
{
        ext2_ino_t      ino;
        int             len = strlen(str);
        char            *end;

        if ((len<2) || (str[0] != '<') || (str[len-1] != '>')) return 0;
        ino=strtoul(str+1, &end, 0);
        if (*end!='>') return -1;
        return ino;
}
               
/*
 * This routine is used whenever a command needs to turn 2 <ino> strings
 * into an inodes range ( [ino1, ino2[ ).
 */
int string_to_inode_range(char *str1, char *str2, ext2_ino_t *ino1, ext2_ino_t *ino2)
{
        int invalid = 0;
        ext2_ino_t inox;

        *ino1 = string_to_inode_number(str1);
        *ino2 = string_to_inode_number(str2);
        if (*ino2 == -1) {
                *ino2 = current_fs->super->s_inodes_count+1;
                invalid |= 0x1;
        }
        if (*ino1 >= *ino2) {
                inox = *ino1;
                *ino1 = *ino2;
                *ino2 = inox;
                invalid |= 0x2;
        }
        if (*ino1 <= 0) {
                *ino1 = 1;
                invalid |= 0x4;
        }
        if (*ino2 > current_fs->super->s_inodes_count+1) {
                *ino2 = current_fs->super->s_inodes_count+1;
                invalid |= 0x8;
        }
        return invalid;
}

I needed to add their prototypes in debugfs/debugfs.h

extern ext2_ino_t string_to_inode_number(char *str);
extern int string_to_inode_range(char *str1, char *str2, ext2_ino_t *ino1, ext2_ino_t *ino2);

and i also added an entry for the new commant in debug_commands.ct:

request do_rstat, "Show inodes information ",
        show_inodes_info, rstat;

and when I call it, i need to make sure the output is piped (like in | cat), in order to deactivate the annoying pager.

eg:

> debugfs -cD -R 'rstat <100> <200>' /dev/sdXXX | cat

(Don't forget that /dev/sdXXX must not be mounted)

Camion
  • 1,264
  • 9
  • 22