* [PATCHSET v3 0/2] xfs_db: add minimal directory navigation @ 2021-01-16 1:24 Darrick J. Wong 2021-01-16 1:24 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong 2021-01-16 1:24 ` [PATCH 2/2] xfs_db: add an ls command Darrick J. Wong 0 siblings, 2 replies; 8+ messages in thread From: Darrick J. Wong @ 2021-01-16 1:24 UTC (permalink / raw) To: sandeen, djwong; +Cc: linux-xfs Hi all, This patchset improves the usability of xfs_db by enabling users to navigate to inodes by path and to list the contents of directories. v2: Various cleanups and reorganizing suggested by dchinner v3: Rebase to 5.10-rc0 If you're going to start using this mess, you probably ought to just pull from my git trees, which are linked below. This is an extraordinary way to destroy everything. Enjoy! Comments and questions are, as always, welcome. --D xfsprogs git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=xfs_db-directory-navigation fstests git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfstests-dev.git/log/?h=xfs_db-directory-navigation --- db/Makefile | 3 db/command.c | 1 db/command.h | 1 db/namei.c | 612 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/libxfs_api_defs.h | 1 man/man8/xfs_db.8 | 20 ++ 6 files changed, 637 insertions(+), 1 deletion(-) create mode 100644 db/namei.c ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/2] xfs_db: add a directory path lookup command 2021-01-16 1:24 [PATCHSET v3 0/2] xfs_db: add minimal directory navigation Darrick J. Wong @ 2021-01-16 1:24 ` Darrick J. Wong 2021-01-20 12:35 ` Chandan Babu R 2021-01-16 1:24 ` [PATCH 2/2] xfs_db: add an ls command Darrick J. Wong 1 sibling, 1 reply; 8+ messages in thread From: Darrick J. Wong @ 2021-01-16 1:24 UTC (permalink / raw) To: sandeen, djwong; +Cc: linux-xfs From: Darrick J. Wong <djwong@kernel.org> Add a command to xfs_db so that we can navigate to inodes by path. Signed-off-by: Darrick J. Wong <djwong@kernel.org> --- db/Makefile | 3 - db/command.c | 1 db/command.h | 1 db/namei.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++++ man/man8/xfs_db.8 | 4 + 5 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 db/namei.c diff --git a/db/Makefile b/db/Makefile index 9d502bf0..beafb105 100644 --- a/db/Makefile +++ b/db/Makefile @@ -14,7 +14,8 @@ HFILES = addr.h agf.h agfl.h agi.h attr.h attrshort.h bit.h block.h bmap.h \ io.h logformat.h malloc.h metadump.h output.h print.h quit.h sb.h \ sig.h strvec.h text.h type.h write.h attrset.h symlink.h fsmap.h \ fuzz.h -CFILES = $(HFILES:.h=.c) btdump.c btheight.c convert.c info.c timelimit.c +CFILES = $(HFILES:.h=.c) btdump.c btheight.c convert.c info.c namei.c \ + timelimit.c LSRCFILES = xfs_admin.sh xfs_ncheck.sh xfs_metadump.sh LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBFROG) $(LIBUUID) $(LIBRT) $(LIBPTHREAD) diff --git a/db/command.c b/db/command.c index 43828369..02f778b9 100644 --- a/db/command.c +++ b/db/command.c @@ -131,6 +131,7 @@ init_commands(void) logformat_init(); io_init(); metadump_init(); + namei_init(); output_init(); print_init(); quit_init(); diff --git a/db/command.h b/db/command.h index 6913c817..498983ff 100644 --- a/db/command.h +++ b/db/command.h @@ -33,3 +33,4 @@ extern void btdump_init(void); extern void info_init(void); extern void btheight_init(void); extern void timelimit_init(void); +extern void namei_init(void); diff --git a/db/namei.c b/db/namei.c new file mode 100644 index 00000000..eebebe15 --- /dev/null +++ b/db/namei.c @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 Oracle. All Rights Reserved. + * Author: Darrick J. Wong <djwong@kernel.org> + */ +#include "libxfs.h" +#include "command.h" +#include "output.h" +#include "init.h" +#include "io.h" +#include "type.h" +#include "input.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "inode.h" + +/* Path lookup */ + +/* Key for looking up metadata inodes. */ +struct dirpath { + /* Array of string pointers. */ + char **path; + + /* Number of strings in path. */ + unsigned int depth; +}; + +static void +path_free( + struct dirpath *dirpath) +{ + unsigned int i; + + for (i = 0; i < dirpath->depth; i++) + free(dirpath->path[i]); + free(dirpath->path); + free(dirpath); +} + +/* Chop a freeform string path into a structured path. */ +static struct dirpath * +path_parse( + const char *path) +{ + struct dirpath *dirpath; + const char *p = path; + const char *endp = path + strlen(path); + + dirpath = calloc(sizeof(*dirpath), 1); + if (!dirpath) + return NULL; + + while (p < endp) { + char **new_path; + const char *next_slash; + + next_slash = strchr(p, '/'); + if (next_slash == p) { + p++; + continue; + } + if (!next_slash) + next_slash = endp; + + new_path = realloc(dirpath->path, + (dirpath->depth + 1) * sizeof(char *)); + if (!new_path) { + path_free(dirpath); + return NULL; + } + + dirpath->path = new_path; + dirpath->path[dirpath->depth] = strndup(p, next_slash - p); + dirpath->depth++; + + p = next_slash + 1; + } + + return dirpath; +} + +/* Given a directory and a structured path, walk the path and set the cursor. */ +static int +path_navigate( + struct xfs_mount *mp, + xfs_ino_t rootino, + struct dirpath *dirpath) +{ + struct xfs_inode *dp; + xfs_ino_t ino = rootino; + unsigned int i; + int error; + + error = -libxfs_iget(mp, NULL, ino, 0, &dp); + if (error) + return error; + + for (i = 0; i < dirpath->depth; i++) { + struct xfs_name xname = { + .name = dirpath->path[i], + .len = strlen(dirpath->path[i]), + }; + + if (!S_ISDIR(VFS_I(dp)->i_mode)) { + error = ENOTDIR; + goto rele; + } + + error = -libxfs_dir_lookup(NULL, dp, &xname, &ino, NULL); + if (error) + goto rele; + if (!xfs_verify_ino(mp, ino)) { + error = EFSCORRUPTED; + goto rele; + } + + libxfs_irele(dp); + dp = NULL; + + error = -libxfs_iget(mp, NULL, ino, 0, &dp); + switch (error) { + case EFSCORRUPTED: + case EFSBADCRC: + case 0: + break; + default: + return error; + } + } + + set_cur_inode(ino); +rele: + if (dp) + libxfs_irele(dp); + return error; +} + +/* Walk a directory path to an inode and set the io cursor to that inode. */ +static int +path_walk( + char *path) +{ + struct dirpath *dirpath; + char *p = path; + xfs_ino_t rootino = mp->m_sb.sb_rootino; + int error = 0; + + if (*p == '/') { + /* Absolute path, start from the root inode. */ + p++; + } else { + /* Relative path, start from current dir. */ + if (iocur_top->typ != &typtab[TYP_INODE] || + !S_ISDIR(iocur_top->mode)) + return ENOTDIR; + + rootino = iocur_top->ino; + } + + dirpath = path_parse(p); + if (!dirpath) + return ENOMEM; + + error = path_navigate(mp, rootino, dirpath); + if (error) + return error; + + path_free(dirpath); + return 0; +} + +static void +path_help(void) +{ + dbprintf(_( +"\n" +" Navigate to an inode via directory path.\n" + )); +} + +static int +path_f( + int argc, + char **argv) +{ + int c; + int error; + + while ((c = getopt(argc, argv, "")) != -1) { + switch (c) { + default: + path_help(); + return 0; + } + } + + error = path_walk(argv[optind]); + if (error) { + dbprintf("%s: %s\n", argv[optind], strerror(error)); + exitcode = 1; + } + + return 0; +} + +static struct cmdinfo path_cmd = { + .name = "path", + .altname = NULL, + .cfunc = path_f, + .argmin = 1, + .argmax = 1, + .canpush = 0, + .args = "", + .help = path_help, +}; + +void +namei_init(void) +{ + path_cmd.oneline = _("navigate to an inode by path"); + add_command(&path_cmd); +} diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 index 55388be6..4df265ec 100644 --- a/man/man8/xfs_db.8 +++ b/man/man8/xfs_db.8 @@ -831,6 +831,10 @@ See the .B print command. .TP +.BI "path " dir_path +Walk the directory tree to an inode using the supplied path. +Absolute and relative paths are supported. +.TP .B pop Pop location from the stack. .TP ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] xfs_db: add a directory path lookup command 2021-01-16 1:24 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong @ 2021-01-20 12:35 ` Chandan Babu R 2021-01-20 17:39 ` Darrick J. Wong 0 siblings, 1 reply; 8+ messages in thread From: Chandan Babu R @ 2021-01-20 12:35 UTC (permalink / raw) To: Darrick J. Wong; +Cc: sandeen, linux-xfs On 16 Jan 2021 at 06:54, Darrick J. Wong wrote: > From: Darrick J. Wong <djwong@kernel.org> > > Add a command to xfs_db so that we can navigate to inodes by path. > > Signed-off-by: Darrick J. Wong <djwong@kernel.org> > --- > db/Makefile | 3 - > db/command.c | 1 > db/command.h | 1 > db/namei.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++++ > man/man8/xfs_db.8 | 4 + > 5 files changed, 231 insertions(+), 1 deletion(-) > create mode 100644 db/namei.c > > > diff --git a/db/Makefile b/db/Makefile > index 9d502bf0..beafb105 100644 > --- a/db/Makefile > +++ b/db/Makefile > @@ -14,7 +14,8 @@ HFILES = addr.h agf.h agfl.h agi.h attr.h attrshort.h bit.h block.h bmap.h \ > io.h logformat.h malloc.h metadump.h output.h print.h quit.h sb.h \ > sig.h strvec.h text.h type.h write.h attrset.h symlink.h fsmap.h \ > fuzz.h > -CFILES = $(HFILES:.h=.c) btdump.c btheight.c convert.c info.c timelimit.c > +CFILES = $(HFILES:.h=.c) btdump.c btheight.c convert.c info.c namei.c \ > + timelimit.c > LSRCFILES = xfs_admin.sh xfs_ncheck.sh xfs_metadump.sh > > LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBFROG) $(LIBUUID) $(LIBRT) $(LIBPTHREAD) > diff --git a/db/command.c b/db/command.c > index 43828369..02f778b9 100644 > --- a/db/command.c > +++ b/db/command.c > @@ -131,6 +131,7 @@ init_commands(void) > logformat_init(); > io_init(); > metadump_init(); > + namei_init(); > output_init(); > print_init(); > quit_init(); > diff --git a/db/command.h b/db/command.h > index 6913c817..498983ff 100644 > --- a/db/command.h > +++ b/db/command.h > @@ -33,3 +33,4 @@ extern void btdump_init(void); > extern void info_init(void); > extern void btheight_init(void); > extern void timelimit_init(void); > +extern void namei_init(void); > diff --git a/db/namei.c b/db/namei.c > new file mode 100644 > index 00000000..eebebe15 > --- /dev/null > +++ b/db/namei.c > @@ -0,0 +1,223 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright (C) 2021 Oracle. All Rights Reserved. > + * Author: Darrick J. Wong <djwong@kernel.org> > + */ > +#include "libxfs.h" > +#include "command.h" > +#include "output.h" > +#include "init.h" > +#include "io.h" > +#include "type.h" > +#include "input.h" > +#include "faddr.h" > +#include "fprint.h" > +#include "field.h" > +#include "inode.h" > + > +/* Path lookup */ > + > +/* Key for looking up metadata inodes. */ > +struct dirpath { > + /* Array of string pointers. */ > + char **path; > + > + /* Number of strings in path. */ > + unsigned int depth; > +}; > + > +static void > +path_free( > + struct dirpath *dirpath) > +{ > + unsigned int i; > + > + for (i = 0; i < dirpath->depth; i++) > + free(dirpath->path[i]); > + free(dirpath->path); > + free(dirpath); > +} > + > +/* Chop a freeform string path into a structured path. */ > +static struct dirpath * > +path_parse( > + const char *path) > +{ > + struct dirpath *dirpath; > + const char *p = path; > + const char *endp = path + strlen(path); > + > + dirpath = calloc(sizeof(*dirpath), 1); > + if (!dirpath) > + return NULL; > + > + while (p < endp) { > + char **new_path; > + const char *next_slash; > + > + next_slash = strchr(p, '/'); > + if (next_slash == p) { > + p++; > + continue; > + } > + if (!next_slash) > + next_slash = endp; > + > + new_path = realloc(dirpath->path, > + (dirpath->depth + 1) * sizeof(char *)); > + if (!new_path) { > + path_free(dirpath); > + return NULL; > + } > + > + dirpath->path = new_path; > + dirpath->path[dirpath->depth] = strndup(p, next_slash - p); > + dirpath->depth++; > + > + p = next_slash + 1; > + } > + > + return dirpath; > +} > + > +/* Given a directory and a structured path, walk the path and set the cursor. */ > +static int > +path_navigate( > + struct xfs_mount *mp, > + xfs_ino_t rootino, > + struct dirpath *dirpath) > +{ > + struct xfs_inode *dp; > + xfs_ino_t ino = rootino; > + unsigned int i; > + int error; > + > + error = -libxfs_iget(mp, NULL, ino, 0, &dp); > + if (error) > + return error; > + > + for (i = 0; i < dirpath->depth; i++) { > + struct xfs_name xname = { > + .name = dirpath->path[i], > + .len = strlen(dirpath->path[i]), > + }; > + > + if (!S_ISDIR(VFS_I(dp)->i_mode)) { > + error = ENOTDIR; > + goto rele; > + } > + > + error = -libxfs_dir_lookup(NULL, dp, &xname, &ino, NULL); > + if (error) > + goto rele; > + if (!xfs_verify_ino(mp, ino)) { > + error = EFSCORRUPTED; > + goto rele; > + } > + > + libxfs_irele(dp); > + dp = NULL; > + > + error = -libxfs_iget(mp, NULL, ino, 0, &dp); > + switch (error) { > + case EFSCORRUPTED: > + case EFSBADCRC: > + case 0: > + break; > + default: > + return error; > + } > + } > + > + set_cur_inode(ino); > +rele: > + if (dp) > + libxfs_irele(dp); > + return error; > +} > + > +/* Walk a directory path to an inode and set the io cursor to that inode. */ > +static int > +path_walk( > + char *path) > +{ > + struct dirpath *dirpath; > + char *p = path; > + xfs_ino_t rootino = mp->m_sb.sb_rootino; > + int error = 0; > + > + if (*p == '/') { > + /* Absolute path, start from the root inode. */ > + p++; > + } else { > + /* Relative path, start from current dir. */ > + if (iocur_top->typ != &typtab[TYP_INODE] || > + !S_ISDIR(iocur_top->mode)) > + return ENOTDIR; > + > + rootino = iocur_top->ino; > + } > + > + dirpath = path_parse(p); > + if (!dirpath) > + return ENOMEM; > + > + error = path_navigate(mp, rootino, dirpath); > + if (error) > + return error; Memory pointed by dirpath (and its members) is not freed if the call to path_navigate() returns a non-zero error value. > + > + path_free(dirpath); > + return 0; > +} > + > +static void > +path_help(void) > +{ > + dbprintf(_( > +"\n" > +" Navigate to an inode via directory path.\n" > + )); > +} > + > +static int > +path_f( > + int argc, > + char **argv) > +{ > + int c; > + int error; > + > + while ((c = getopt(argc, argv, "")) != -1) { > + switch (c) { > + default: > + path_help(); > + return 0; > + } > + } > + > + error = path_walk(argv[optind]); > + if (error) { > + dbprintf("%s: %s\n", argv[optind], strerror(error)); > + exitcode = 1; > + } > + > + return 0; > +} > + > +static struct cmdinfo path_cmd = { > + .name = "path", > + .altname = NULL, > + .cfunc = path_f, > + .argmin = 1, > + .argmax = 1, > + .canpush = 0, > + .args = "", > + .help = path_help, > +}; > + > +void > +namei_init(void) > +{ > + path_cmd.oneline = _("navigate to an inode by path"); > + add_command(&path_cmd); > +} > diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 > index 55388be6..4df265ec 100644 > --- a/man/man8/xfs_db.8 > +++ b/man/man8/xfs_db.8 > @@ -831,6 +831,10 @@ See the > .B print > command. > .TP > +.BI "path " dir_path > +Walk the directory tree to an inode using the supplied path. > +Absolute and relative paths are supported. > +.TP > .B pop > Pop location from the stack. > .TP -- chandan ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] xfs_db: add a directory path lookup command 2021-01-20 12:35 ` Chandan Babu R @ 2021-01-20 17:39 ` Darrick J. Wong 0 siblings, 0 replies; 8+ messages in thread From: Darrick J. Wong @ 2021-01-20 17:39 UTC (permalink / raw) To: Chandan Babu R; +Cc: sandeen, linux-xfs On Wed, Jan 20, 2021 at 06:05:35PM +0530, Chandan Babu R wrote: > > On 16 Jan 2021 at 06:54, Darrick J. Wong wrote: > > From: Darrick J. Wong <djwong@kernel.org> > > > > Add a command to xfs_db so that we can navigate to inodes by path. > > > > Signed-off-by: Darrick J. Wong <djwong@kernel.org> > > --- > > db/Makefile | 3 - > > db/command.c | 1 > > db/command.h | 1 > > db/namei.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++++ > > man/man8/xfs_db.8 | 4 + > > 5 files changed, 231 insertions(+), 1 deletion(-) > > create mode 100644 db/namei.c > > > > > > diff --git a/db/Makefile b/db/Makefile > > index 9d502bf0..beafb105 100644 > > --- a/db/Makefile > > +++ b/db/Makefile > > @@ -14,7 +14,8 @@ HFILES = addr.h agf.h agfl.h agi.h attr.h attrshort.h bit.h block.h bmap.h \ > > io.h logformat.h malloc.h metadump.h output.h print.h quit.h sb.h \ > > sig.h strvec.h text.h type.h write.h attrset.h symlink.h fsmap.h \ > > fuzz.h > > -CFILES = $(HFILES:.h=.c) btdump.c btheight.c convert.c info.c timelimit.c > > +CFILES = $(HFILES:.h=.c) btdump.c btheight.c convert.c info.c namei.c \ > > + timelimit.c > > LSRCFILES = xfs_admin.sh xfs_ncheck.sh xfs_metadump.sh > > > > LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBFROG) $(LIBUUID) $(LIBRT) $(LIBPTHREAD) > > diff --git a/db/command.c b/db/command.c > > index 43828369..02f778b9 100644 > > --- a/db/command.c > > +++ b/db/command.c > > @@ -131,6 +131,7 @@ init_commands(void) > > logformat_init(); > > io_init(); > > metadump_init(); > > + namei_init(); > > output_init(); > > print_init(); > > quit_init(); > > diff --git a/db/command.h b/db/command.h > > index 6913c817..498983ff 100644 > > --- a/db/command.h > > +++ b/db/command.h > > @@ -33,3 +33,4 @@ extern void btdump_init(void); > > extern void info_init(void); > > extern void btheight_init(void); > > extern void timelimit_init(void); > > +extern void namei_init(void); > > diff --git a/db/namei.c b/db/namei.c > > new file mode 100644 > > index 00000000..eebebe15 > > --- /dev/null > > +++ b/db/namei.c > > @@ -0,0 +1,223 @@ <snip some of this out> > > +/* Walk a directory path to an inode and set the io cursor to that inode. */ > > +static int > > +path_walk( > > + char *path) > > +{ > > + struct dirpath *dirpath; > > + char *p = path; > > + xfs_ino_t rootino = mp->m_sb.sb_rootino; > > + int error = 0; > > + > > + if (*p == '/') { > > + /* Absolute path, start from the root inode. */ > > + p++; > > + } else { > > + /* Relative path, start from current dir. */ > > + if (iocur_top->typ != &typtab[TYP_INODE] || > > + !S_ISDIR(iocur_top->mode)) > > + return ENOTDIR; > > + > > + rootino = iocur_top->ino; > > + } > > + > > + dirpath = path_parse(p); > > + if (!dirpath) > > + return ENOMEM; > > + > > + error = path_navigate(mp, rootino, dirpath); > > + if (error) > > + return error; > > Memory pointed by dirpath (and its members) is not freed if the call to > path_navigate() returns a non-zero error value. Good catch, thanks! --D ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/2] xfs_db: add an ls command 2021-01-16 1:24 [PATCHSET v3 0/2] xfs_db: add minimal directory navigation Darrick J. Wong 2021-01-16 1:24 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong @ 2021-01-16 1:24 ` Darrick J. Wong 2021-01-20 15:24 ` Chandan Babu R 1 sibling, 1 reply; 8+ messages in thread From: Darrick J. Wong @ 2021-01-16 1:24 UTC (permalink / raw) To: sandeen, djwong; +Cc: linux-xfs From: Darrick J. Wong <djwong@kernel.org> Add to xfs_db the ability to list a directory. Signed-off-by: Darrick J. Wong <djwong@kernel.org> --- db/namei.c | 389 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/libxfs_api_defs.h | 1 man/man8/xfs_db.8 | 16 ++ 3 files changed, 406 insertions(+) diff --git a/db/namei.c b/db/namei.c index eebebe15..e75b5ebd 100644 --- a/db/namei.c +++ b/db/namei.c @@ -215,9 +215,398 @@ static struct cmdinfo path_cmd = { .help = path_help, }; +/* List a directory's entries. */ + +static const char *filetype_strings[XFS_DIR3_FT_MAX] = { + [XFS_DIR3_FT_UNKNOWN] = "unknown", + [XFS_DIR3_FT_REG_FILE] = "regular", + [XFS_DIR3_FT_DIR] = "directory", + [XFS_DIR3_FT_CHRDEV] = "chardev", + [XFS_DIR3_FT_BLKDEV] = "blkdev", + [XFS_DIR3_FT_FIFO] = "fifo", + [XFS_DIR3_FT_SOCK] = "socket", + [XFS_DIR3_FT_SYMLINK] = "symlink", + [XFS_DIR3_FT_WHT] = "whiteout", +}; + +static const char * +get_dstr( + struct xfs_mount *mp, + uint8_t filetype) +{ + if (!xfs_sb_version_hasftype(&mp->m_sb)) + return filetype_strings[XFS_DIR3_FT_UNKNOWN]; + + if (filetype >= XFS_DIR3_FT_MAX) + return filetype_strings[XFS_DIR3_FT_UNKNOWN]; + + return filetype_strings[filetype]; +} + +static void +dir_emit( + struct xfs_mount *mp, + xfs_dir2_dataptr_t off, + char *name, + ssize_t namelen, + xfs_ino_t ino, + uint8_t dtype) +{ + char *display_name; + struct xfs_name xname = { .name = name }; + const char *dstr = get_dstr(mp, dtype); + xfs_dahash_t hash; + bool good; + + if (namelen < 0) { + /* Negative length means that name is null-terminated. */ + display_name = name; + xname.len = strlen(name); + good = true; + } else { + /* + * Otherwise, name came from a directory entry, so we have to + * copy the string to a buffer so that we can add the null + * terminator. + */ + display_name = malloc(namelen + 1); + memcpy(display_name, name, namelen); + display_name[namelen] = 0; + xname.len = namelen; + good = libxfs_dir2_namecheck(name, namelen); + } + hash = libxfs_dir2_hashname(mp, &xname); + + dbprintf("%-10u %-18llu %-14s 0x%08llx %3d %s %s\n", off & 0xFFFFFFFF, + ino, dstr, hash, xname.len, + display_name, good ? _("(good)") : _("(corrupt)")); + + if (display_name != name) + free(display_name); +} + +static int +list_sfdir( + struct xfs_da_args *args) +{ + struct xfs_inode *dp = args->dp; + struct xfs_mount *mp = dp->i_mount; + struct xfs_da_geometry *geo = args->geo; + struct xfs_dir2_sf_entry *sfep; + struct xfs_dir2_sf_hdr *sfp; + xfs_ino_t ino; + xfs_dir2_dataptr_t off; + unsigned int i; + uint8_t filetype; + + sfp = (struct xfs_dir2_sf_hdr *)dp->i_df.if_u1.if_data; + + /* . and .. entries */ + off = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, + geo->data_entry_offset); + dir_emit(args->dp->i_mount, off, ".", -1, dp->i_ino, XFS_DIR3_FT_DIR); + + ino = libxfs_dir2_sf_get_parent_ino(sfp); + off = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, + geo->data_entry_offset + + libxfs_dir2_data_entsize(mp, sizeof(".") - 1)); + dir_emit(args->dp->i_mount, off, "..", -1, ino, XFS_DIR3_FT_DIR); + + /* Walk everything else. */ + sfep = xfs_dir2_sf_firstentry(sfp); + for (i = 0; i < sfp->count; i++) { + ino = libxfs_dir2_sf_get_ino(mp, sfp, sfep); + filetype = libxfs_dir2_sf_get_ftype(mp, sfep); + off = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, + xfs_dir2_sf_get_offset(sfep)); + + dir_emit(args->dp->i_mount, off, (char *)sfep->name, + sfep->namelen, ino, filetype); + sfep = libxfs_dir2_sf_nextentry(mp, sfp, sfep); + } + + return 0; +} + +/* List entries in block format directory. */ +static int +list_blockdir( + struct xfs_da_args *args) +{ + struct xfs_inode *dp = args->dp; + struct xfs_mount *mp = dp->i_mount; + struct xfs_buf *bp; + struct xfs_da_geometry *geo = mp->m_dir_geo; + xfs_dir2_dataptr_t diroff; + unsigned int offset; + unsigned int end; + int error; + + error = xfs_dir3_block_read(NULL, dp, &bp); + if (error) + return error; + + end = xfs_dir3_data_end_offset(geo, bp->b_addr); + for (offset = geo->data_entry_offset; offset < end;) { + struct xfs_dir2_data_unused *dup = bp->b_addr + offset; + struct xfs_dir2_data_entry *dep = bp->b_addr + offset; + uint8_t filetype; + + if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { + /* Unused entry */ + offset += be16_to_cpu(dup->length); + continue; + } + + /* Real entry */ + diroff = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, offset); + offset += libxfs_dir2_data_entsize(mp, dep->namelen); + filetype = libxfs_dir2_data_get_ftype(dp->i_mount, dep); + dir_emit(mp, diroff, (char *)dep->name, dep->namelen, + be64_to_cpu(dep->inumber), filetype); + } + + libxfs_trans_brelse(args->trans, bp); + return error; +} + +/* List entries in leaf format directory. */ +static int +list_leafdir( + struct xfs_da_args *args) +{ + struct xfs_bmbt_irec map; + struct xfs_iext_cursor icur; + struct xfs_inode *dp = args->dp; + struct xfs_mount *mp = dp->i_mount; + struct xfs_buf *bp = NULL; + struct xfs_ifork *ifp = XFS_IFORK_PTR(dp, XFS_DATA_FORK); + struct xfs_da_geometry *geo = mp->m_dir_geo; + xfs_dir2_off_t dirboff; + xfs_dablk_t dabno = 0; + int error = 0; + + /* Read extent map. */ + if (!(ifp->if_flags & XFS_IFEXTENTS)) { + error = -libxfs_iread_extents(NULL, dp, XFS_DATA_FORK); + if (error) + return error; + } + + while (dabno < geo->leafblk) { + unsigned int offset; + unsigned int length; + + /* Find mapping for leaf block. */ + if (!xfs_iext_lookup_extent(dp, ifp, dabno, &icur, &map)) + break; + if (map.br_startoff >= geo->leafblk) + break; + libxfs_trim_extent(&map, dabno, geo->leafblk - dabno); + + /* Read the directory block of that first mapping. */ + error = xfs_dir3_data_read(NULL, dp, map.br_startoff, 0, &bp); + if (error) + break; + + dirboff = xfs_dir2_da_to_byte(geo, map.br_startoff); + for (offset = geo->data_entry_offset; offset < geo->blksize;) { + struct xfs_dir2_data_entry *dep; + struct xfs_dir2_data_unused *dup; + uint8_t filetype; + + dup = bp->b_addr + offset; + dep = bp->b_addr + offset; + + if (be16_to_cpu(dup->freetag) == + XFS_DIR2_DATA_FREE_TAG) { + /* Skip unused entry */ + length = be16_to_cpu(dup->length); + offset += length; + continue; + } + + offset += libxfs_dir2_data_entsize(mp, dep->namelen); + filetype = libxfs_dir2_data_get_ftype(mp, dep); + + dir_emit(mp, xfs_dir2_byte_to_dataptr(dirboff + offset), + (char *)dep->name, dep->namelen, + be64_to_cpu(dep->inumber), filetype); + } + + dabno += XFS_DADDR_TO_FSB(mp, bp->b_length); + libxfs_buf_relse(bp); + bp = NULL; + } + + if (bp) + libxfs_buf_relse(bp); + + return error; +} + +/* Read the directory, display contents. */ +int +listdir( + struct xfs_inode *dp) +{ + struct xfs_da_args args = { + .dp = dp, + .geo = dp->i_mount->m_dir_geo, + }; + int error; + int isblock; + + if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) + return list_sfdir(&args); + + error = -libxfs_dir2_isblock(&args, &isblock); + if (error) + return error; + + if (isblock) + return list_blockdir(&args); + return list_leafdir(&args); +} + +/* List the inode number of the currently selected inode. */ +static int +inum_cur(void) +{ + if (iocur_top->typ != &typtab[TYP_INODE]) + return ENOENT; + + dbprintf("%llu\n", iocur_top->ino); + return 0; +} + +/* If the io cursor points to a directory, list its contents. */ +static int +ls_cur( + char *tag) +{ + struct xfs_inode *dp; + int error = 0; + + if (iocur_top->typ != &typtab[TYP_INODE] || + !S_ISDIR(iocur_top->mode)) + return ENOTDIR; + + error = -libxfs_iget(mp, NULL, iocur_top->ino, 0, &dp); + if (error) + return error; + + if (!S_ISDIR(VFS_I(dp)->i_mode)) { + error = ENOTDIR; + goto rele; + } + + /* List the contents of a directory. */ + if (tag) + dbprintf(_("%s:\n"), tag); + + error = listdir(dp); + if (error) + goto rele; + +rele: + libxfs_irele(dp); + return error; +} + +static void +ls_help(void) +{ + dbprintf(_( +"\n" +" List the contents of the currently selected directory inode.\n" +"\n" +" Options:\n" +" -i -- Resolve the given paths to their corresponding inode numbers.\n" +" If no paths are given, display the current inode number.\n" +"\n" +" Directory contents will be listed in the format:\n" +" dir_cookie inode_number type hash name_length name\n" + )); +} + +static int +ls_f( + int argc, + char **argv) +{ + bool inum_only = false; + int c; + int error = 0; + + while ((c = getopt(argc, argv, "i")) != -1) { + switch (c) { + case 'i': + inum_only = true; + break; + default: + ls_help(); + return 0; + } + } + + if (optind == argc) { + if (inum_only) + error = inum_cur(); + else + error = ls_cur(NULL); + if (error) { + dbprintf("%s\n", strerror(error)); + exitcode = 1; + } + + return 0; + } + + for (c = optind; c < argc; c++) { + push_cur(); + + error = path_walk(argv[c]); + if (error) + goto err_cur; + + if (inum_only) + error = inum_cur(); + else + error = ls_cur(argv[c]); + if (error) + goto err_cur; + + pop_cur(); + } + + return 0; +err_cur: + pop_cur(); + if (error) { + dbprintf("%s: %s\n", argv[c], strerror(error)); + exitcode = 1; + } + return 0; +} + +static struct cmdinfo ls_cmd = { + .name = "ls", + .altname = "l", + .cfunc = ls_f, + .argmin = 0, + .argmax = -1, + .canpush = 0, + .args = "[-i] [paths...]", + .help = ls_help, +}; + void namei_init(void) { path_cmd.oneline = _("navigate to an inode by path"); add_command(&path_cmd); + + ls_cmd.oneline = _("list directory contents"); + add_command(&ls_cmd); } diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 9492955d..9a00ce66 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -190,6 +190,7 @@ #define xfs_trans_resv_calc libxfs_trans_resv_calc #define xfs_trans_roll_inode libxfs_trans_roll_inode #define xfs_trans_roll libxfs_trans_roll +#define xfs_trim_extent libxfs_trim_extent #define xfs_verify_agbno libxfs_verify_agbno #define xfs_verify_agino libxfs_verify_agino diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 index 4df265ec..58727495 100644 --- a/man/man8/xfs_db.8 +++ b/man/man8/xfs_db.8 @@ -806,6 +806,22 @@ This makes it easier to find discrepancies in the reservation calculations between xfsprogs and the kernel, which will help when diagnosing minimum log size calculation errors. .TP +.BI "ls [\-i] [" paths "]..." +List the contents of a directory. +If a path resolves to a directory, the directory will be listed. +If no paths are supplied and the IO cursor points at a directory inode, +the contents of that directory will be listed. + +The output format is: +directory cookie, inode number, file type, hash, name length, name. +.RS 1.0i +.TP 0.4i +.B \-i +Resolve each of the given paths to an inode number and print that number. +If no paths are given and the IO cursor points to an inode, print the inode +number. +.RE +.TP .BI "metadump [\-egow] " filename Dumps metadata to a file. See .BR xfs_metadump (8) ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] xfs_db: add an ls command 2021-01-16 1:24 ` [PATCH 2/2] xfs_db: add an ls command Darrick J. Wong @ 2021-01-20 15:24 ` Chandan Babu R 0 siblings, 0 replies; 8+ messages in thread From: Chandan Babu R @ 2021-01-20 15:24 UTC (permalink / raw) To: Darrick J. Wong; +Cc: sandeen, linux-xfs On 16 Jan 2021 at 06:54, Darrick J. Wong wrote: > From: Darrick J. Wong <djwong@kernel.org> > > Add to xfs_db the ability to list a directory. > W.r.t logical correctness of the code, Reviewed-by: Chandan Babu R <chandanrlinux@gmail.com> > Signed-off-by: Darrick J. Wong <djwong@kernel.org> > --- > db/namei.c | 389 ++++++++++++++++++++++++++++++++++++++++++++++ > libxfs/libxfs_api_defs.h | 1 > man/man8/xfs_db.8 | 16 ++ > 3 files changed, 406 insertions(+) > > > diff --git a/db/namei.c b/db/namei.c > index eebebe15..e75b5ebd 100644 > --- a/db/namei.c > +++ b/db/namei.c > @@ -215,9 +215,398 @@ static struct cmdinfo path_cmd = { > .help = path_help, > }; > > +/* List a directory's entries. */ > + > +static const char *filetype_strings[XFS_DIR3_FT_MAX] = { > + [XFS_DIR3_FT_UNKNOWN] = "unknown", > + [XFS_DIR3_FT_REG_FILE] = "regular", > + [XFS_DIR3_FT_DIR] = "directory", > + [XFS_DIR3_FT_CHRDEV] = "chardev", > + [XFS_DIR3_FT_BLKDEV] = "blkdev", > + [XFS_DIR3_FT_FIFO] = "fifo", > + [XFS_DIR3_FT_SOCK] = "socket", > + [XFS_DIR3_FT_SYMLINK] = "symlink", > + [XFS_DIR3_FT_WHT] = "whiteout", > +}; > + > +static const char * > +get_dstr( > + struct xfs_mount *mp, > + uint8_t filetype) > +{ > + if (!xfs_sb_version_hasftype(&mp->m_sb)) > + return filetype_strings[XFS_DIR3_FT_UNKNOWN]; > + > + if (filetype >= XFS_DIR3_FT_MAX) > + return filetype_strings[XFS_DIR3_FT_UNKNOWN]; > + > + return filetype_strings[filetype]; > +} > + > +static void > +dir_emit( > + struct xfs_mount *mp, > + xfs_dir2_dataptr_t off, > + char *name, > + ssize_t namelen, > + xfs_ino_t ino, > + uint8_t dtype) > +{ > + char *display_name; > + struct xfs_name xname = { .name = name }; > + const char *dstr = get_dstr(mp, dtype); > + xfs_dahash_t hash; > + bool good; > + > + if (namelen < 0) { > + /* Negative length means that name is null-terminated. */ > + display_name = name; > + xname.len = strlen(name); > + good = true; > + } else { > + /* > + * Otherwise, name came from a directory entry, so we have to > + * copy the string to a buffer so that we can add the null > + * terminator. > + */ > + display_name = malloc(namelen + 1); > + memcpy(display_name, name, namelen); > + display_name[namelen] = 0; > + xname.len = namelen; > + good = libxfs_dir2_namecheck(name, namelen); > + } > + hash = libxfs_dir2_hashname(mp, &xname); > + > + dbprintf("%-10u %-18llu %-14s 0x%08llx %3d %s %s\n", off & 0xFFFFFFFF, > + ino, dstr, hash, xname.len, > + display_name, good ? _("(good)") : _("(corrupt)")); > + > + if (display_name != name) > + free(display_name); > +} > + > +static int > +list_sfdir( > + struct xfs_da_args *args) > +{ > + struct xfs_inode *dp = args->dp; > + struct xfs_mount *mp = dp->i_mount; > + struct xfs_da_geometry *geo = args->geo; > + struct xfs_dir2_sf_entry *sfep; > + struct xfs_dir2_sf_hdr *sfp; > + xfs_ino_t ino; > + xfs_dir2_dataptr_t off; > + unsigned int i; > + uint8_t filetype; > + > + sfp = (struct xfs_dir2_sf_hdr *)dp->i_df.if_u1.if_data; > + > + /* . and .. entries */ > + off = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, > + geo->data_entry_offset); > + dir_emit(args->dp->i_mount, off, ".", -1, dp->i_ino, XFS_DIR3_FT_DIR); > + > + ino = libxfs_dir2_sf_get_parent_ino(sfp); > + off = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, > + geo->data_entry_offset + > + libxfs_dir2_data_entsize(mp, sizeof(".") - 1)); > + dir_emit(args->dp->i_mount, off, "..", -1, ino, XFS_DIR3_FT_DIR); > + > + /* Walk everything else. */ > + sfep = xfs_dir2_sf_firstentry(sfp); > + for (i = 0; i < sfp->count; i++) { > + ino = libxfs_dir2_sf_get_ino(mp, sfp, sfep); > + filetype = libxfs_dir2_sf_get_ftype(mp, sfep); > + off = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, > + xfs_dir2_sf_get_offset(sfep)); > + > + dir_emit(args->dp->i_mount, off, (char *)sfep->name, > + sfep->namelen, ino, filetype); > + sfep = libxfs_dir2_sf_nextentry(mp, sfp, sfep); > + } > + > + return 0; > +} > + > +/* List entries in block format directory. */ > +static int > +list_blockdir( > + struct xfs_da_args *args) > +{ > + struct xfs_inode *dp = args->dp; > + struct xfs_mount *mp = dp->i_mount; > + struct xfs_buf *bp; > + struct xfs_da_geometry *geo = mp->m_dir_geo; > + xfs_dir2_dataptr_t diroff; > + unsigned int offset; > + unsigned int end; > + int error; > + > + error = xfs_dir3_block_read(NULL, dp, &bp); > + if (error) > + return error; > + > + end = xfs_dir3_data_end_offset(geo, bp->b_addr); > + for (offset = geo->data_entry_offset; offset < end;) { > + struct xfs_dir2_data_unused *dup = bp->b_addr + offset; > + struct xfs_dir2_data_entry *dep = bp->b_addr + offset; > + uint8_t filetype; > + > + if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { > + /* Unused entry */ > + offset += be16_to_cpu(dup->length); > + continue; > + } > + > + /* Real entry */ > + diroff = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, offset); > + offset += libxfs_dir2_data_entsize(mp, dep->namelen); > + filetype = libxfs_dir2_data_get_ftype(dp->i_mount, dep); > + dir_emit(mp, diroff, (char *)dep->name, dep->namelen, > + be64_to_cpu(dep->inumber), filetype); > + } > + > + libxfs_trans_brelse(args->trans, bp); > + return error; > +} > + > +/* List entries in leaf format directory. */ > +static int > +list_leafdir( > + struct xfs_da_args *args) > +{ > + struct xfs_bmbt_irec map; > + struct xfs_iext_cursor icur; > + struct xfs_inode *dp = args->dp; > + struct xfs_mount *mp = dp->i_mount; > + struct xfs_buf *bp = NULL; > + struct xfs_ifork *ifp = XFS_IFORK_PTR(dp, XFS_DATA_FORK); > + struct xfs_da_geometry *geo = mp->m_dir_geo; > + xfs_dir2_off_t dirboff; > + xfs_dablk_t dabno = 0; > + int error = 0; > + > + /* Read extent map. */ > + if (!(ifp->if_flags & XFS_IFEXTENTS)) { > + error = -libxfs_iread_extents(NULL, dp, XFS_DATA_FORK); > + if (error) > + return error; > + } > + > + while (dabno < geo->leafblk) { > + unsigned int offset; > + unsigned int length; > + > + /* Find mapping for leaf block. */ > + if (!xfs_iext_lookup_extent(dp, ifp, dabno, &icur, &map)) > + break; > + if (map.br_startoff >= geo->leafblk) > + break; > + libxfs_trim_extent(&map, dabno, geo->leafblk - dabno); > + > + /* Read the directory block of that first mapping. */ > + error = xfs_dir3_data_read(NULL, dp, map.br_startoff, 0, &bp); > + if (error) > + break; > + > + dirboff = xfs_dir2_da_to_byte(geo, map.br_startoff); > + for (offset = geo->data_entry_offset; offset < geo->blksize;) { > + struct xfs_dir2_data_entry *dep; > + struct xfs_dir2_data_unused *dup; > + uint8_t filetype; > + > + dup = bp->b_addr + offset; > + dep = bp->b_addr + offset; > + > + if (be16_to_cpu(dup->freetag) == > + XFS_DIR2_DATA_FREE_TAG) { > + /* Skip unused entry */ > + length = be16_to_cpu(dup->length); > + offset += length; > + continue; > + } > + > + offset += libxfs_dir2_data_entsize(mp, dep->namelen); > + filetype = libxfs_dir2_data_get_ftype(mp, dep); > + > + dir_emit(mp, xfs_dir2_byte_to_dataptr(dirboff + offset), > + (char *)dep->name, dep->namelen, > + be64_to_cpu(dep->inumber), filetype); > + } > + > + dabno += XFS_DADDR_TO_FSB(mp, bp->b_length); > + libxfs_buf_relse(bp); > + bp = NULL; > + } > + > + if (bp) > + libxfs_buf_relse(bp); > + > + return error; > +} > + > +/* Read the directory, display contents. */ > +int > +listdir( > + struct xfs_inode *dp) > +{ > + struct xfs_da_args args = { > + .dp = dp, > + .geo = dp->i_mount->m_dir_geo, > + }; > + int error; > + int isblock; > + > + if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) > + return list_sfdir(&args); > + > + error = -libxfs_dir2_isblock(&args, &isblock); > + if (error) > + return error; > + > + if (isblock) > + return list_blockdir(&args); > + return list_leafdir(&args); > +} > + > +/* List the inode number of the currently selected inode. */ > +static int > +inum_cur(void) > +{ > + if (iocur_top->typ != &typtab[TYP_INODE]) > + return ENOENT; > + > + dbprintf("%llu\n", iocur_top->ino); > + return 0; > +} > + > +/* If the io cursor points to a directory, list its contents. */ > +static int > +ls_cur( > + char *tag) > +{ > + struct xfs_inode *dp; > + int error = 0; > + > + if (iocur_top->typ != &typtab[TYP_INODE] || > + !S_ISDIR(iocur_top->mode)) > + return ENOTDIR; > + > + error = -libxfs_iget(mp, NULL, iocur_top->ino, 0, &dp); > + if (error) > + return error; > + > + if (!S_ISDIR(VFS_I(dp)->i_mode)) { > + error = ENOTDIR; > + goto rele; > + } > + > + /* List the contents of a directory. */ > + if (tag) > + dbprintf(_("%s:\n"), tag); > + > + error = listdir(dp); > + if (error) > + goto rele; > + > +rele: > + libxfs_irele(dp); > + return error; > +} > + > +static void > +ls_help(void) > +{ > + dbprintf(_( > +"\n" > +" List the contents of the currently selected directory inode.\n" > +"\n" > +" Options:\n" > +" -i -- Resolve the given paths to their corresponding inode numbers.\n" > +" If no paths are given, display the current inode number.\n" > +"\n" > +" Directory contents will be listed in the format:\n" > +" dir_cookie inode_number type hash name_length name\n" > + )); > +} > + > +static int > +ls_f( > + int argc, > + char **argv) > +{ > + bool inum_only = false; > + int c; > + int error = 0; > + > + while ((c = getopt(argc, argv, "i")) != -1) { > + switch (c) { > + case 'i': > + inum_only = true; > + break; > + default: > + ls_help(); > + return 0; > + } > + } > + > + if (optind == argc) { > + if (inum_only) > + error = inum_cur(); > + else > + error = ls_cur(NULL); > + if (error) { > + dbprintf("%s\n", strerror(error)); > + exitcode = 1; > + } > + > + return 0; > + } > + > + for (c = optind; c < argc; c++) { > + push_cur(); > + > + error = path_walk(argv[c]); > + if (error) > + goto err_cur; > + > + if (inum_only) > + error = inum_cur(); > + else > + error = ls_cur(argv[c]); > + if (error) > + goto err_cur; > + > + pop_cur(); > + } > + > + return 0; > +err_cur: > + pop_cur(); > + if (error) { > + dbprintf("%s: %s\n", argv[c], strerror(error)); > + exitcode = 1; > + } > + return 0; > +} > + > +static struct cmdinfo ls_cmd = { > + .name = "ls", > + .altname = "l", > + .cfunc = ls_f, > + .argmin = 0, > + .argmax = -1, > + .canpush = 0, > + .args = "[-i] [paths...]", > + .help = ls_help, > +}; > + > void > namei_init(void) > { > path_cmd.oneline = _("navigate to an inode by path"); > add_command(&path_cmd); > + > + ls_cmd.oneline = _("list directory contents"); > + add_command(&ls_cmd); > } > diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h > index 9492955d..9a00ce66 100644 > --- a/libxfs/libxfs_api_defs.h > +++ b/libxfs/libxfs_api_defs.h > @@ -190,6 +190,7 @@ > #define xfs_trans_resv_calc libxfs_trans_resv_calc > #define xfs_trans_roll_inode libxfs_trans_roll_inode > #define xfs_trans_roll libxfs_trans_roll > +#define xfs_trim_extent libxfs_trim_extent > > #define xfs_verify_agbno libxfs_verify_agbno > #define xfs_verify_agino libxfs_verify_agino > diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 > index 4df265ec..58727495 100644 > --- a/man/man8/xfs_db.8 > +++ b/man/man8/xfs_db.8 > @@ -806,6 +806,22 @@ This makes it easier to find discrepancies in the reservation calculations > between xfsprogs and the kernel, which will help when diagnosing minimum > log size calculation errors. > .TP > +.BI "ls [\-i] [" paths "]..." > +List the contents of a directory. > +If a path resolves to a directory, the directory will be listed. > +If no paths are supplied and the IO cursor points at a directory inode, > +the contents of that directory will be listed. > + > +The output format is: > +directory cookie, inode number, file type, hash, name length, name. > +.RS 1.0i > +.TP 0.4i > +.B \-i > +Resolve each of the given paths to an inode number and print that number. > +If no paths are given and the IO cursor points to an inode, print the inode > +number. > +.RE > +.TP > .BI "metadump [\-egow] " filename > Dumps metadata to a file. See > .BR xfs_metadump (8) -- chandan ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCHSET v3 0/2] xfs_db: add minimal directory navigation @ 2021-01-09 6:27 Darrick J. Wong 0 siblings, 0 replies; 8+ messages in thread From: Darrick J. Wong @ 2021-01-09 6:27 UTC (permalink / raw) To: sandeen, darrick.wong; +Cc: linux-xfs Hi all, This patchset improves the usability of xfs_db by enabling users to navigate to inodes by path and to list the contents of directories. v2: Various cleanups and reorganizing suggested by dchinner v3: Rebase to 5.10-rc0 If you're going to start using this mess, you probably ought to just pull from my git trees, which are linked below. This is an extraordinary way to destroy everything. Enjoy! Comments and questions are, as always, welcome. --D xfsprogs git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=xfs_db-directory-navigation fstests git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfstests-dev.git/log/?h=xfs_db-directory-navigation --- db/Makefile | 3 db/command.c | 1 db/command.h | 1 db/namei.c | 612 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/libxfs_api_defs.h | 1 man/man8/xfs_db.8 | 20 ++ 6 files changed, 637 insertions(+), 1 deletion(-) create mode 100644 db/namei.c ^ permalink raw reply [flat|nested] 8+ messages in thread
* 2020 NYE Patchbomb Guide! @ 2020-12-31 22:38 Darrick J. Wong 2020-12-31 22:46 ` [PATCHSET v3 0/2] xfs_db: add minimal directory navigation Darrick J. Wong 0 siblings, 1 reply; 8+ messages in thread From: Darrick J. Wong @ 2020-12-31 22:38 UTC (permalink / raw) To: xfs Hi folks, It's still the last day of 2020 in the US/Pacific timezone, which means it's time for me to patchbomb every new feature that's been sitting around in my development trees! Once a year I like to dump everything into the public archives to increase XFS' bus factor. However, there are 660 patches and 46 cover letters across my three development trees, so this year I'm only sending the guide and the cover letters. Just like last year, this guide lists each feature branch that's merged into the development tree, along with some notes to help readers figure out the real dependencies between branches. If you want to try out this code, you /really/ should pull from kernel.org: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git https://git.kernel.org/cgit/linux/kernel/git/djwong/xfstests-dev.git https://git.kernel.org/cgit/linux/kernel/git/djwong/xfs-documentation.git https://git.kernel.org/cgit/linux/kernel/git/djwong/xfs-linux.git ============== The kernel tree contains the following branches: pwork-parallelism ("xfs: increase pwork parallelism") Single patch to increase parallelism of background threads to handle high-iops storage. At this point in the branch the only piece to need this is quotacheck, and I haven't been able to show that parallel quotacheck is any faster due to the bottlenecks shifting to memory reclaim, but deferred inode inactivation will want this. scrub-fixes ("xfs: more scrub fixes") The usual pile of bug fixes and verification strengthening for scrub. reflink-speedups ("xfs: fix reflink inefficiencies") This independent series cleans up some warts with bunmapi when reflink is enabled, since we've now restructured various shortcomings in the defer ops code and the log that made some dirty hacks unnecessary. repair-reap-fixes ("xfs: fix online repair block reaping") repair-bitmap-rework ("xfs: rework online repair incore bitmap") repair-prep-for-bulk-loading ("xfs: prepare repair for bulk loading") scrub-rtsummary ("xfs: online scrubbing of realtime summary files") repair-ag-btrees ("xfs: online repair of AG btrees") repair-inodes ("xfs: online repair of inodes and extent maps") repair-quota ("xfs: online repair of quota and counters") corruption-health-reports ("xfs: report corruption to the health trackers") Here's the first part of online filesystem repair. Since last year, we've landed the btree bulk loading code, which shortened this story arc by one. However, I've also added the ability to check the realtime summary metadata, and strengthened the rebuilder code to check the sanity of the records it collects during a rebuild process. reclaim-space-harder ("xfs: try harder to reclaim space when we run out") eofblocks-consolidation ("xfs: consolidate posteof and cowblocks cleanup") deferred-inactivation ("xfs: deferred inode inactivation") I think I'll send these three branches for the next kernel. The third branch implements deferred inode inactivation, which is to say that we move all file deletion activities to background threads. This makes unlink calls return to userspace faster and should speed up mass deletions since we now process inodes in disk order instead of deletion order. The first series makes ENOSPC space reclamation push the filesystem harder so that it will behave the same after we push inode inactivation to a background workqueue. The second series combines garbage collection of speculative post-EOF blocks and COW extents into a single piece of code so that we can free up one radix tree tag bit. (None of this code require online repair...) indirect-health-reporting ("xfs: indirect health reporting") This series improves the metadata health reporting system so that it can remember health problems for principal filesystem objects whose incore representations had to be reclaimed. In other words, the per-AG state can remember the fact that an inode in that AG had problems, even if we have to reclaim the xfs_inode for that broken file. repair-hard-problems ("xfs: online repair hard problems") This branch contains harder repair problems, namely the ones that require full filesystem scans. These scans depend upon being able to shut down background operations temporarily, which is we need deferred inode inactivation (and part 1 of online repair) to solve these problems. realtime-bmap-intents ("xfs: widen BUI formats to support rt") expand-bmap-intent-usage ("xfs: support attrfork and unwritten BUIs") atomic-file-updates ("xfs: atomic file updates") A key part of the third installment of online filesystem repair will be the ability to switch the contents of xattrs, directories, rt metadata, and symbolic links atomically. For this, I developed a new high-level log operation to swap the extents of any two file forks and to resume the swap even if the system goes down during the operation. I also wired this up to a userspace ioctl so that user programs can commit file content updates atomically. repair-rtsummary ("xfs: online repair of realtime summaries") repair-xattrs ("xfs: online repair of extended attributes") repair-dirs ("xfs: online repair of directories") This third piece of online filesystem repair builds upon the atomic extent swap in the previous batch. It enables us to rebuild file-based metadata. inode-refactor ("xfs: hoist inode operations to libxfs") metadir ("xfs: metadata inode directories") The first branch in this series hoists all the inode allocation and freeing code to libxfs so that the second series can create arbitrary directory trees for metadata. This will also allow us to refactor all of the similar but not identical code in userspace so that file attributes can be inherited in a consistent manner when constructing a filesystem from a protofile. btree-ifork-records ("xfs: refactor btrees to support records in inode root") btree-dynamic-depth ("xfs: support dynamic btree cursor height") These three branches refactor the generic btree code to support using inode root areas for btree records, which will be needed for realtime rmap and reflink. refactor-rt-locking ("xfs: refactor realtime meta inode locking") reserve-rt-metadata-space ("xfs: enable in-core block reservation for rt metadata") Once I started running fstests on rmap/reflink-enabled rt filesystems, I noticed that I was running into weird deadlocks and space allocation failure issues that happened with the original rmap and reflink implementations. The first series refactors locking of rt metadata so that we can do it in a systematic way, and the second series extends the per-AG allocation code to work on realtime devices too. realtime-extfree-intents ("xfs: widen EFI format to support rt") realtime-rmap ("xfs: realtime reverse-mapping support") This series uses the metadata directory tree to add reverse mapping abilities to the realtime device, and using that rmap data to reconstruct realtime free space metadata. It depends on the six branches above. noalloc-ags ("xfs: noalloc allocation groups") A quick branch I whipped up while exploring online filesystem shrink, which gives us the ability to prevent allocations in an AG. It doesn't depend on any of the branches above it; this is just where it landed in my development tree. realtime-reflink ("xfs: reflink on the realtime device") realtime-reflink-extsize ("xfs: reflink with large realtime extents") This last series uses the metadata directory tree to create a new refcount btree for the realtime device. With that, we can support reflink on realtime devices. This requires every branch from inode-refactor to reserve-rt-metadata-space. ============== On the xfsprogs side of things, here are some significant branches that I would like to highlight. The branch groups do not depend on each other. xfs_db-directory-navigation ("xfs_db: add minimal directory navigation") This branch adds directory navigation and directory listing abilities to xfs_db. needsrepair ("xfs: add the ability to flag a fs for repair") fs-upgrades ("xfs_admin: support upgrading v5 filesystems") These two branches enable sysadmins to add (some) new features to existing V5 filesystems. repair-rebuild-forks ("xfs_repair: rebuild inode fork mappings") This branch teaches xfs_repair to rebuild inode fork mappings from rmap data. packaging-cleanups ("xfsprogs: packaging cleanups") bmap-utils ("xfsprogs: file write utility refactoring") A couple of cleanups for userspace. scrub-iscan-rebalance ("xfs_scrub: improve balancing of threads for inode scan") This is a major rework of inode scans in xfs_scrub. The first branch parallelises inode scans at a finer granularity -- now each worker thread deals with an inobt record, and not an entire AG. This reduces the amount of pending scrub work that can stall behind a single large fragmented file. xfs-scrub-fixes ("xfs_scrub: second fixes series") scrub-repair-data-deps ("xfs_scrub: track data dependencies for repairs") These last two restructure how we track metadata repair activities so that it is done on a per-fs principal (AGs, inodes) basis instead of tracking each repair individually. What this means is that we now preserve ordering dependencies between repair types. That makes us smart enough not to try to repair a directory if the data bmbt is still broken. ============== Finally, here some significant branches awaiting review for fstests: fuzz-baseline ("xfstests: establish baseline for fuzz tests") fuzzer-improvements ("xfstests: improve xfs fuzzing") more-fuzz-testing ("xfstests: strengthen fuzz testing") In these three branches, I rework the XFS metadata fuzz testing infrastructure to provide /some/ sort of a baseline golden output, and to be a bit more systematic about how it reports where it is in a fuzz process. I also rework the fuzz repair strategies so that they more closely follow the known reaction cases (no repair at all; online repair only; offline repair only; and online repair followed by offline repair if needed). dmerror-on-rt-devices ("common/dm*: support external log and rt devices") This makes it so that we can use dmerror and dmflakey for external log and realtime devices. With that, I hope you all have a happy new year! See you in 2021! --D ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCHSET v3 0/2] xfs_db: add minimal directory navigation 2020-12-31 22:38 2020 NYE Patchbomb Guide! Darrick J. Wong @ 2020-12-31 22:46 ` Darrick J. Wong 0 siblings, 0 replies; 8+ messages in thread From: Darrick J. Wong @ 2020-12-31 22:46 UTC (permalink / raw) To: sandeen, darrick.wong; +Cc: linux-xfs Hi all, Improve the usability of xfs_db by enabling users to navigate to inodes by path and to list the contents of directories. v2: Various cleanups and reorganizing suggested by dchinner v3: Rebase to 5.10-rc0 If you're going to start using this mess, you probably ought to just pull from my git trees, which are linked below. This is an extraordinary way to destroy everything. Enjoy! Comments and questions are, as always, welcome. --D xfsprogs git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=xfs_db-directory-navigation fstests git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfstests-dev.git/log/?h=xfs_db-directory-navigation --- db/Makefile | 3 db/command.c | 1 db/command.h | 1 db/namei.c | 612 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/libxfs_api_defs.h | 1 man/man8/xfs_db.8 | 20 ++ 6 files changed, 637 insertions(+), 1 deletion(-) create mode 100644 db/namei.c ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2021-01-20 18:46 UTC | newest] Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2021-01-16 1:24 [PATCHSET v3 0/2] xfs_db: add minimal directory navigation Darrick J. Wong 2021-01-16 1:24 ` [PATCH 1/2] xfs_db: add a directory path lookup command Darrick J. Wong 2021-01-20 12:35 ` Chandan Babu R 2021-01-20 17:39 ` Darrick J. Wong 2021-01-16 1:24 ` [PATCH 2/2] xfs_db: add an ls command Darrick J. Wong 2021-01-20 15:24 ` Chandan Babu R -- strict thread matches above, loose matches on Subject: below -- 2021-01-09 6:27 [PATCHSET v3 0/2] xfs_db: add minimal directory navigation Darrick J. Wong 2020-12-31 22:38 2020 NYE Patchbomb Guide! Darrick J. Wong 2020-12-31 22:46 ` [PATCHSET v3 0/2] xfs_db: add minimal directory navigation Darrick J. Wong
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).