Message ID | 1525754479-12177-22-git-send-email-allison.henderson@oracle.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
On Mon, May 07, 2018 at 09:41:19PM -0700, Allison Henderson wrote: > From: "Darrick J. Wong" <darrick.wong@oracle.com> > > Add ioctl definitions to libxfs, build the necessary helpers into > libfrog and libhandle to iterate parents (and parent paths), then wire > up xfs_scrub to be able to query parent pointers from userspace. The > goal of this patch is to exercise userspace, and is nowhere near a > complete solution. A basic xfs_io parent command implementation > replaces ... whatever that is that's there now. > > Totally missing: actual support in libxfs for working with parent ptrs > straight off the disk (mkfs, xfs_db, xfs_repair). > > [achender: Minor syntax adjustments to sew solution in actual support > in libxfs for working with parent ptrs] > > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> > Signed-off-by: Allison Henderson <allison.henderson@oracle.com> > --- > include/handle.h | 2 + > include/parent.h | 18 ++ > include/path.h | 19 +++ > io/parent.c | 471 ++++++++++++++--------------------------------------- > libfrog/paths.c | 136 ++++++++++++++++ > libhandle/Makefile | 2 +- > libhandle/handle.c | 7 +- > libhandle/parent.c | 325 ++++++++++++++++++++++++++++++++++++ > libxfs/xfs_fs.h | 8 + > scrub/inodes.c | 26 +++ > scrub/inodes.h | 2 + > scrub/phase5.c | 9 +- > 12 files changed, 661 insertions(+), 364 deletions(-) > > diff --git a/include/handle.h b/include/handle.h > index 49f1441..00aa43d 100644 > --- a/include/handle.h > +++ b/include/handle.h > @@ -52,6 +52,8 @@ extern int fssetdm_by_handle (void *__hanp, size_t __hlen, > > void fshandle_destroy(void); > > +int handle_to_fsfd(void *hanp, char **path); > + > #ifdef __cplusplus > } > #endif > diff --git a/include/parent.h b/include/parent.h > index 85cef85..33f8d85 100644 > --- a/include/parent.h > +++ b/include/parent.h > @@ -28,4 +28,22 @@ typedef struct parent_cursor { > __u32 opaque[4]; /* an opaque cookie */ > } parent_cursor_t; > > +struct path_list; > + > +typedef int (*walk_pptr_fn)(struct xfs_pptr_info *pi, struct xfs_parent_ptr *pptr, > + void *arg); > +typedef int (*walk_ppath_fn)(const char *mntpt, struct path_list *path, > + void *arg); > + > +#define WALK_PPTRS_ABORT 1 > +int fd_walk_pptrs(int fd, walk_pptr_fn fn, void *arg); > +int handle_walk_pptrs(void *hanp, size_t hanlen, walk_pptr_fn fn, void *arg); > + > +#define WALK_PPATHS_ABORT 1 > +int fd_walk_ppaths(int fd, walk_ppath_fn fn, void *arg); > +int handle_walk_ppaths(void *hanp, size_t hanlen, walk_ppath_fn fn, void *arg); > + > +int fd_to_path(int fd, char *path, size_t pathlen); > +int handle_to_path(void *hanp, size_t hlen, char *path, size_t pathlen); > + > #endif > diff --git a/include/path.h b/include/path.h > index 88dc44b..cbe4e19 100644 > --- a/include/path.h > +++ b/include/path.h > @@ -70,4 +70,23 @@ typedef struct fs_cursor { > extern void fs_cursor_initialise(char *__dir, uint __flags, fs_cursor_t *__cp); > extern fs_path_t *fs_cursor_next_entry(fs_cursor_t *__cp); > > +/* Path information. */ > + > +struct path_list; > +struct path_component; > + > +struct path_component *path_component_init(const char *name); > +void path_component_free(struct path_component *pc); > +int path_component_change(struct path_component *pc, void *name, > + size_t namelen); > + > +struct path_list *path_list_init(void); > +void path_list_free(struct path_list *path); > +void path_list_add_parent_component(struct path_list *path, > + struct path_component *pc); > +void path_list_add_component(struct path_list *path, struct path_component *pc); > +void path_list_del_component(struct path_list *path, struct path_component *pc); > + > +ssize_t path_list_to_string(struct path_list *path, char *buf, size_t buflen); > + > #endif /* __PATH_H__ */ > diff --git a/io/parent.c b/io/parent.c > index 55b8b49..ad51fe6 100644 > --- a/io/parent.c > +++ b/io/parent.c > @@ -21,366 +21,105 @@ > #include "path.h" > #include "parent.h" > #include "handle.h" > -#include "jdm.h" > #include "init.h" > #include "io.h" > > -#define PARENTBUF_SZ 16384 > -#define BSTATBUF_SZ 16384 > - > static cmdinfo_t parent_cmd; > -static int verbose_flag; > -static int err_status; > -static __u64 inodes_checked; > static char *mntpt; > > -/* > - * check out a parent entry to see if the values seem valid > - */ > -static void > -check_parent_entry(xfs_bstat_t *bstatp, parent_t *parent) > -{ > - int sts; > - char fullpath[PATH_MAX]; > - struct stat statbuf; > - char *str; > - > - snprintf(fullpath, parent->p_reclen, _("%s%s"), mntpt, > - ((char*)parent)+sizeof(struct parent)); > - > - sts = lstat(fullpath, &statbuf); > - if (sts != 0) { > - fprintf(stderr, > - _("inode-path for inode: %llu is incorrect - path \"%s\" non-existent\n"), > - (unsigned long long) bstatp->bs_ino, fullpath); > - if (verbose_flag) { > - fprintf(stderr, > - _("path \"%s\" does not stat for inode: %llu; err = %s\n"), > - fullpath, > - (unsigned long long) bstatp->bs_ino, > - strerror(errno)); > - } > - err_status++; > - return; > - } else { > - if (verbose_flag > 1) { > - printf(_("path \"%s\" found\n"), fullpath); > - } > - } > - > - if (statbuf.st_ino != bstatp->bs_ino) { > - fprintf(stderr, > - _("inode-path for inode: %llu is incorrect - wrong inode#\n"), > - (unsigned long long) bstatp->bs_ino); > - if (verbose_flag) { > - fprintf(stderr, > - _("ino mismatch for path \"%s\" %llu vs %llu\n"), > - fullpath, > - (unsigned long long)statbuf.st_ino, > - (unsigned long long)bstatp->bs_ino); > - } > - err_status++; > - return; > - } else if (verbose_flag > 1) { > - printf(_("inode number match: %llu\n"), > - (unsigned long long)statbuf.st_ino); > - } > - > - /* get parent path */ > - str = strrchr(fullpath, '/'); > - *str = '\0'; > - sts = stat(fullpath, &statbuf); > - if (sts != 0) { > - fprintf(stderr, > - _("parent path \"%s\" does not stat: %s\n"), > - fullpath, > - strerror(errno)); > - err_status++; > - return; > - } else { > - if (parent->p_ino != statbuf.st_ino) { > - fprintf(stderr, > - _("inode-path for inode: %llu is incorrect - wrong parent inode#\n"), > - (unsigned long long) bstatp->bs_ino); > - if (verbose_flag) { > - fprintf(stderr, > - _("ino mismatch for path \"%s\" %llu vs %llu\n"), > - fullpath, > - (unsigned long long)parent->p_ino, > - (unsigned long long)statbuf.st_ino); > - } > - err_status++; > - return; > - } else { > - if (verbose_flag > 1) { > - printf(_("parent ino match for %llu\n"), > - (unsigned long long) parent->p_ino); > - } > - } > - } > -} > - > -static void > -check_parents(parent_t *parentbuf, size_t *parentbuf_size, > - jdm_fshandle_t *fshandlep, xfs_bstat_t *statp) > -{ > - int error, i; > - __u32 count; > - parent_t *entryp; > - > - do { > - error = jdm_parentpaths(fshandlep, statp, parentbuf, *parentbuf_size, &count); > - > - if (error == ERANGE) { > - *parentbuf_size *= 2; > - parentbuf = (parent_t *)realloc(parentbuf, *parentbuf_size); > - } else if (error) { > - fprintf(stderr, _("parentpaths failed for ino %llu: %s\n"), > - (unsigned long long) statp->bs_ino, > - strerror(errno)); > - err_status++; > - break; > - } > - } while (error == ERANGE); > - > - > - if (count == 0) { > - /* no links for inode - something wrong here */ > - fprintf(stderr, _("inode-path for inode: %llu is missing\n"), > - (unsigned long long) statp->bs_ino); > - err_status++; > - } > - > - entryp = parentbuf; > - for (i = 0; i < count; i++) { > - check_parent_entry(statp, entryp); > - entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); > - } > -} > - > static int > -do_bulkstat(parent_t *parentbuf, size_t *parentbuf_size, xfs_bstat_t *bstatbuf, > - int fsfd, jdm_fshandle_t *fshandlep) > +pptr_print( > + struct xfs_pptr_info *pi, > + struct xfs_parent_ptr *pptr, > + void *arg) > { > - __s32 buflenout; > - __u64 lastino = 0; > - xfs_bstat_t *p; > - xfs_bstat_t *endp; > - xfs_fsop_bulkreq_t bulkreq; > - struct stat mntstat; > + char buf[XFS_PPTR_MAXNAMELEN + 1]; > > - if (stat(mntpt, &mntstat)) { > - fprintf(stderr, _("can't stat mount point \"%s\": %s\n"), > - mntpt, strerror(errno)); > - return 1; > + if (pi->pi_flags & XFS_PPTR_OFLAG_ROOT) { > + printf(_("Root directory.\n")); > + return 0; > } > > - bulkreq.lastip = &lastino; > - bulkreq.icount = BSTATBUF_SZ; > - bulkreq.ubuffer = (void *)bstatbuf; > - bulkreq.ocount = &buflenout; > - > - while (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT, &bulkreq) == 0) { > - if (*(bulkreq.ocount) == 0) { > - return 0; > - } > - for (p = bstatbuf, endp = bstatbuf + *bulkreq.ocount; p < endp; p++) { > - > - /* inode being modified, get synced data with iget */ > - if ( (!p->bs_nlink || !p->bs_mode) && p->bs_ino != 0 ) { > - > - if (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) < 0) { > - fprintf(stderr, > - _("failed to get bulkstat information for inode %llu\n"), > - (unsigned long long) p->bs_ino); > - continue; > - } > - if (!p->bs_nlink || !p->bs_mode || !p->bs_ino) { > - fprintf(stderr, > - _("failed to get valid bulkstat information for inode %llu\n"), > - (unsigned long long) p->bs_ino); > - continue; > - } > - } > - > - /* skip root */ > - if (p->bs_ino == mntstat.st_ino) { > - continue; > - } > - > - if (verbose_flag > 1) { > - printf(_("checking inode %llu\n"), > - (unsigned long long) p->bs_ino); > - } > - > - /* print dotted progress */ > - if ((inodes_checked % 100) == 0 && verbose_flag == 1) { > - printf("."); fflush(stdout); > - } > - inodes_checked++; > - > - check_parents(parentbuf, parentbuf_size, fshandlep, p); > - } > - > - }/*while*/ > - > - fprintf(stderr, _("syssgi bulkstat failed: %s\n"), strerror(errno)); > - return 1; > + memcpy(buf, pptr->xpp_name, pptr->xpp_namelen); > + buf[pptr->xpp_namelen] = 0; > + printf(_("p_ino = %llu\n"), (unsigned long long)pptr->xpp_ino); > + printf(_("p_gen = %u\n"), (unsigned int)pptr->xpp_gen); > + printf(_("p_reclen = %u\n"), (unsigned int)pptr->xpp_namelen); > + printf(_("p_name = \"%s\"\n\n"), buf); > + return 0; > } > > -static int > -parent_check(void) > +int > +print_parents( > + struct xfs_handle *handle) > { > - int fsfd; > - jdm_fshandle_t *fshandlep; > - parent_t *parentbuf; > - size_t parentbuf_size = PARENTBUF_SZ; > - xfs_bstat_t *bstatbuf; > - > - err_status = 0; > - inodes_checked = 0; > - > - sync(); > - > - fsfd = file->fd; > - > - fshandlep = jdm_getfshandle(mntpt); > - if (fshandlep == NULL) { > - fprintf(stderr, _("unable to open \"%s\" for jdm: %s\n"), > - mntpt, > - strerror(errno)); > - return 1; > - } > - > - /* allocate buffers */ > - bstatbuf = (xfs_bstat_t *)calloc(BSTATBUF_SZ, sizeof(xfs_bstat_t)); > - parentbuf = (parent_t *)malloc(parentbuf_size); > - if (!bstatbuf || !parentbuf) { > - fprintf(stderr, _("unable to allocate buffers: %s\n"), > - strerror(errno)); > - err_status = 1; > - goto out; > - } > + int ret; > > - if (do_bulkstat(parentbuf, &parentbuf_size, bstatbuf, fsfd, fshandlep) != 0) > - err_status++; > - > - if (err_status > 0) > - fprintf(stderr, _("num errors: %d\n"), err_status); > + if (handle) > + ret = handle_walk_pptrs(handle, sizeof(*handle), pptr_print, > + NULL); > else > - printf(_("succeeded checking %llu inodes\n"), > - (unsigned long long) inodes_checked); > - > -out: > - free(bstatbuf); > - free(parentbuf); > - free(fshandlep); > - return err_status; > -} > + ret = fd_walk_pptrs(file->fd, pptr_print, NULL); > + if (ret) > + perror(file->name); > > -static void > -print_parent_entry(parent_t *parent, int fullpath) > -{ > - printf(_("p_ino = %llu\n"), (unsigned long long) parent->p_ino); > - printf(_("p_gen = %u\n"), parent->p_gen); > - printf(_("p_reclen = %u\n"), parent->p_reclen); > - if (fullpath) > - printf(_("p_name = \"%s%s\"\n"), mntpt, > - ((char*)parent)+sizeof(struct parent)); > - else > - printf(_("p_name = \"%s\"\n"), > - ((char*)parent)+sizeof(struct parent)); > + return 0; > } > > static int > -parent_list(int fullpath) > -{ > - void *handlep = NULL; > - size_t handlen; > - int error, i; > - int retval = 1; > - __u32 count; > - parent_t *entryp; > - parent_t *parentbuf = NULL; > - char *path = file->name; > - int pb_size = PARENTBUF_SZ; > - > - /* XXXX for linux libhandle version - to set libhandle fsfd cache */ > - { > - void *fshandle; > - size_t fshlen; > - > - if (path_to_fshandle(mntpt, &fshandle, &fshlen) != 0) { > - fprintf(stderr, _("%s: failed path_to_fshandle \"%s\": %s\n"), > - progname, path, strerror(errno)); > - goto error; > - } > - free_handle(fshandle, fshlen); > - } > - > - if (path_to_handle(path, &handlep, &handlen) != 0) { > - fprintf(stderr, _("%s: path_to_handle failed for \"%s\"\n"), progname, path); > - goto error; > - } > - > - do { > - parentbuf = (parent_t *)realloc(parentbuf, pb_size); > - if (!parentbuf) { > - fprintf(stderr, _("%s: unable to allocate parent buffer: %s\n"), > - progname, strerror(errno)); > - goto error; > - } > +path_print( > + const char *mntpt, > + struct path_list *path, > + void *arg) { > > - if (fullpath) { > - error = parentpaths_by_handle(handlep, > - handlen, > - parentbuf, > - pb_size, > - &count); > - } else { > - error = parents_by_handle(handlep, > - handlen, > - parentbuf, > - pb_size, > - &count); > - } > - if (error == ERANGE) { > - pb_size *= 2; > - } else if (error) { > - fprintf(stderr, _("%s: %s call failed for \"%s\": %s\n"), > - progname, fullpath ? "parentpaths" : "parents", > - path, strerror(errno)); > - goto error; > - } > - } while (error == ERANGE); > + char buf[PATH_MAX]; > + size_t len = PATH_MAX; > + int ret; > > - if (count == 0) { > - /* no links for inode - something wrong here */ > - fprintf(stderr, _("%s: inode-path is missing\n"), progname); > - goto error; > + ret = snprintf(buf, len, "%s", mntpt); > + if (ret != strlen(mntpt)) { > + errno = ENOMEM; > + return -1; > } > > - entryp = parentbuf; > - for (i = 0; i < count; i++) { > - print_parent_entry(entryp, fullpath); > - entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); > - } > + ret = path_list_to_string(path, buf + ret, len - ret); > + if (ret < 0) > + return ret; > + return 0; > +} > > - retval = 0; > -error: > - free(handlep); > - free(parentbuf); > - return retval; > +int > +print_paths( > + struct xfs_handle *handle) > +{ > + int ret; > + > + if (handle) > + ret = handle_walk_ppaths(handle, sizeof(*handle), path_print, > + NULL); > + else > + ret = fd_walk_ppaths(file->fd, path_print, NULL); > + if (ret) > + perror(file->name); > + return 0; > } > > int > -parent_f(int argc, char **argv) > +parent_f( > + int argc, > + char **argv) > { > - int c; > - int listpath_flag = 0; > - int check_flag = 0; > - fs_path_t *fs; > - static int tab_init; > + struct xfs_handle handle; > + void *hanp = NULL; > + size_t hlen; > + struct fs_path *fs; > + char *p; > + uint64_t ino = 0; > + uint32_t gen = 0; > + int c; > + int listpath_flag = 0; > + int ret; > + static int tab_init; > > if (!tab_init) { > tab_init = 1; > @@ -394,46 +133,72 @@ parent_f(int argc, char **argv) > } > mntpt = fs->fs_dir; > > - verbose_flag = 0; > - > - while ((c = getopt(argc, argv, "cpv")) != EOF) { > + while ((c = getopt(argc, argv, "p")) != EOF) { > switch (c) { > - case 'c': > - check_flag = 1; > - break; > case 'p': > listpath_flag = 1; > break; > - case 'v': > - verbose_flag++; > - break; > default: > return command_usage(&parent_cmd); > } > } > > - if (!check_flag && !listpath_flag) /* default case */ > - exitcode = parent_list(listpath_flag); > - else { > - if (listpath_flag) > - exitcode = parent_list(listpath_flag); > - if (check_flag) > - exitcode = parent_check(); > + /* > + * Always initialize the fshandle table because we need it for > + * the ppaths functions to work. > + */ > + ret = path_to_fshandle((char *)mntpt, &hanp, &hlen); > + if (ret) { > + perror(mntpt); > + return 0; > + } > + > + if (optind + 2 == argc) { > + ino = strtoull(argv[optind], &p, 0); > + if (*p != '\0' || ino == 0) { > + fprintf(stderr, > + _("Bad inode number '%s'.\n"), > + argv[optind]); > + return 0; > + } > + gen = strtoul(argv[optind + 1], &p, 0); > + if (*p != '\0') { > + fprintf(stderr, > + _("Bad generation number '%s'.\n"), > + argv[optind + 1]); > + return 0; > + } > + > + memcpy(&handle, hanp, sizeof(handle)); > + handle.ha_fid.fid_len = sizeof(xfs_fid_t) - > + sizeof(handle.ha_fid.fid_len); > + handle.ha_fid.fid_pad = 0; > + handle.ha_fid.fid_ino = ino; > + handle.ha_fid.fid_gen = gen; > + > } > > + if (listpath_flag) > + exitcode = print_paths(ino ? &handle : NULL); > + else > + exitcode = print_parents(ino ? &handle : NULL); > + > + if (hanp) > + free_handle(hanp, hlen); > + > return 0; > } > > static void > parent_help(void) > { > - printf(_( > +printf(_( > "\n" > " list the current file's parents and their filenames\n" > "\n" > -" -c -- check the current file's file system for parent consistency\n" > -" -p -- list the current file's parents and their full paths\n" > -" -v -- verbose mode\n" > +" -p -- list the current file's paths up to the root\n" > +"\n" > +"If ino and gen are supplied, use them instead.\n" > "\n")); > } > > @@ -444,9 +209,9 @@ parent_init(void) > parent_cmd.cfunc = parent_f; > parent_cmd.argmin = 0; > parent_cmd.argmax = -1; > - parent_cmd.args = _("[-cpv]"); > + parent_cmd.args = _("[-p] [ino gen]"); > parent_cmd.flags = CMD_NOMAP_OK; > - parent_cmd.oneline = _("print or check parent inodes"); > + parent_cmd.oneline = _("print parent inodes"); > parent_cmd.help = parent_help; > > if (expert) > diff --git a/libfrog/paths.c b/libfrog/paths.c > index c7895e9..9fb0140 100644 > --- a/libfrog/paths.c > +++ b/libfrog/paths.c > @@ -27,6 +27,7 @@ > #include "path.h" > #include "input.h" > #include "project.h" > +#include "list.h" > #include <limits.h> > > extern char *progname; > @@ -632,3 +633,138 @@ fs_table_insert_project_path( > exit(1); > } > } > + > + > +/* Structured path components. */ > + > +struct path_list { > + struct list_head p_head; > +}; > + > +struct path_component { > + struct list_head pc_list; > + char *pc_fname; > +}; > + > +/* Initialize a path component with a given name. */ > +struct path_component * > +path_component_init( > + const char *name) > +{ > + struct path_component *pc; > + > + pc = malloc(sizeof(struct path_component)); > + if (!pc) > + return NULL; > + INIT_LIST_HEAD(&pc->pc_list); > + pc->pc_fname = strdup(name); > + if (!pc->pc_fname) { > + free(pc); > + return NULL; > + } > + return pc; > +} > + > +/* Free a path component. */ > +void > +path_component_free( > + struct path_component *pc) > +{ > + free(pc->pc_fname); > + free(pc); > +} > + > +/* Change a path component's filename. */ > +int > +path_component_change( > + struct path_component *pc, > + void *name, > + size_t namelen) > +{ > + void *p; > + > + p = realloc(pc->pc_fname, namelen + 1); > + if (!p) > + return -1; > + pc->pc_fname = p; > + memcpy(pc->pc_fname, name, namelen); > + pc->pc_fname[namelen] = 0; > + return 0; > +} > + > +/* Initialize a pathname. */ > +struct path_list * > +path_list_init(void) > +{ > + struct path_list *path; > + > + path = malloc(sizeof(struct path_list)); > + if (!path) > + return NULL; > + INIT_LIST_HEAD(&path->p_head); > + return path; > +} > + > +/* Empty out a pathname. */ > +void > +path_list_free( > + struct path_list *path) > +{ > + struct path_component *pos; > + struct path_component *n; > + > + list_for_each_entry_safe(pos, n, &path->p_head, pc_list) { > + path_list_del_component(path, pos); > + path_component_free(pos); > + } > + free(path); > +} > + > +/* Add a parent component to a pathname. */ > +void > +path_list_add_parent_component( > + struct path_list *path, > + struct path_component *pc) > +{ > + list_add(&pc->pc_list, &path->p_head); > +} > + > +/* Add a component to a pathname. */ > +void > +path_list_add_component( > + struct path_list *path, > + struct path_component *pc) > +{ > + list_add_tail(&pc->pc_list, &path->p_head); > +} > + > +/* Remove a component from a pathname. */ > +void > +path_list_del_component( > + struct path_list *path, > + struct path_component *pc) > +{ > + list_del_init(&pc->pc_list); > +} > + > +/* Convert a pathname into a string. */ > +ssize_t > +path_list_to_string( > + struct path_list *path, > + char *buf, > + size_t buflen) > +{ > + struct path_component *pos; > + ssize_t bytes = 0; > + int ret; > + > + list_for_each_entry(pos, &path->p_head, pc_list) { > + ret = snprintf(buf, buflen, "/%s", pos->pc_fname); > + if (ret != 1 + strlen(pos->pc_fname)) > + return -1; > + bytes += ret; > + buf += ret; > + buflen -= ret; > + } > + return bytes; > +} > diff --git a/libhandle/Makefile b/libhandle/Makefile > index fe1a2af..d3cea41 100644 > --- a/libhandle/Makefile > +++ b/libhandle/Makefile > @@ -16,7 +16,7 @@ else > LTLDFLAGS += -Wl,--version-script,libhandle.sym > endif > > -CFILES = handle.c jdm.c > +CFILES = handle.c jdm.c parent.c > LSRCFILES = libhandle.sym > > default: ltdepend $(LTLIBRARY) > diff --git a/libhandle/handle.c b/libhandle/handle.c > index 878d14d..a70fa32 100644 > --- a/libhandle/handle.c > +++ b/libhandle/handle.c > @@ -41,7 +41,6 @@ typedef union { > } comarg_t; > > static int obj_to_handle(char *, int, unsigned int, comarg_t, void**, size_t*); > -static int handle_to_fsfd(void *, char **); > static char *path_to_fspath(char *path); > > > @@ -214,8 +213,10 @@ handle_to_fshandle( > return 0; > } > > -static int > -handle_to_fsfd(void *hanp, char **path) > +int > +handle_to_fsfd( > + void *hanp, > + char **path) > { > struct fdhash *fdhp; > > diff --git a/libhandle/parent.c b/libhandle/parent.c > new file mode 100644 > index 0000000..f6be3bd > --- /dev/null > +++ b/libhandle/parent.c > @@ -0,0 +1,325 @@ > +/* > + * Copyright (C) 2017 Oracle. All Rights Reserved. > + * > + * Author: Darrick J. Wong <darrick.wong@oracle.com> > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version 2 > + * of the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it would be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write the Free Software Foundation, > + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. > + */ > +#include "platform_defs.h" > +#include "xfs.h" > +#include "xfs_arch.h" > +#include "list.h" > +#include "path.h" > +#include "handle.h" > +#include "parent.h" > + > +/* Allocate a buffer large enough for some parent pointer records. */ > +static inline struct xfs_pptr_info * > +xfs_pptr_alloc( > + size_t nr_ptrs) > +{ > + struct xfs_pptr_info *pi; > + > + pi = malloc(XFS_PPTR_INFO_SIZEOF(nr_ptrs)); > + if (!pi) > + return NULL; > + memset(pi, 0, sizeof(struct xfs_pptr_info)); > + pi->pi_ptrs_size = nr_ptrs; > + return pi; > +} > + > +/* Walk all parents of the given file handle. */ > +static int > +handle_walk_parents( > + int fd, > + struct xfs_handle *handle, > + walk_pptr_fn fn, > + void *arg) > +{ > + struct xfs_pptr_info *pi; > + struct xfs_parent_ptr *p; > + unsigned int i; > + ssize_t ret = -1; > + > + pi = xfs_pptr_alloc(4); > + if (!pi) > + return -1; > + > + if (handle) { > + memcpy(&pi->pi_handle, handle, sizeof(struct xfs_handle)); > + pi->pi_flags = XFS_PPTR_IFLAG_HANDLE; > + } > + > + ret = ioctl(fd, XFS_IOC_GETPPOINTER, pi); > + while (!ret) { > + if (pi->pi_flags & XFS_PPTR_OFLAG_ROOT) { > + ret = fn(pi, NULL, arg); > + break; > + } > + if (pi->pi_ptrs_used == 0) > + break; > + for (i = 0; i < pi->pi_ptrs_used; i++) { > + p = XFS_PPINFO_TO_PP(pi, i); > + ret = fn(pi, p, arg); > + if (ret) > + goto out_pi; > + } > + ret = ioctl(fd, XFS_IOC_GETPPOINTER, pi); > + } > + > +out_pi: > + free(pi); > + return ret; > +} > + > +/* Walk all parent pointers of this handle. */ > +int > +handle_walk_pptrs( > + void *hanp, > + size_t hlen, > + walk_pptr_fn fn, > + void *arg) > +{ > + char *mntpt; > + int fd; > + > + if (hlen != sizeof(struct xfs_handle)) { > + errno = EINVAL; > + return -1; > + } > + > + fd = handle_to_fsfd(hanp, &mntpt); > + if (fd < 0) > + return -1; > + > + return handle_walk_parents(fd, hanp, fn, arg); > +} > + > +/* Walk all parent pointers of this fd. */ > +int > +fd_walk_pptrs( > + int fd, > + walk_pptr_fn fn, > + void *arg) > +{ > + return handle_walk_parents(fd, NULL, fn, arg); > +} > + > +struct walk_ppaths_info { > + walk_ppath_fn fn; > + void *arg; > + char *mntpt; > + struct path_list *path; > + int fd; > +}; > + > +struct walk_ppath_level_info { > + struct xfs_handle newhandle; > + struct path_component *pc; > + struct walk_ppaths_info *wpi; > +}; > + > +static int handle_walk_parent_paths(struct walk_ppaths_info *wpi, > + struct xfs_handle *handle); > + > +static int > +handle_walk_parent_path_ptr( > + struct xfs_pptr_info *pi, > + struct xfs_parent_ptr *p, > + void *arg) > +{ > + struct walk_ppath_level_info *wpli = arg; > + struct walk_ppaths_info *wpi = wpli->wpi; > + unsigned int i; > + int ret = 0; > + > + if (pi->pi_flags & XFS_PPTR_OFLAG_ROOT) > + return wpi->fn(wpi->mntpt, wpi->path, wpi->arg); > + > + for (i = 0; i < pi->pi_ptrs_used; i++) { > + p = XFS_PPINFO_TO_PP(pi, i); > + ret = path_component_change(wpli->pc, p->xpp_name, > + p->xpp_namelen); > + if (ret) > + break; > + wpli->newhandle.ha_fid.fid_ino = p->xpp_ino; > + wpli->newhandle.ha_fid.fid_gen = p->xpp_gen; > + path_list_add_parent_component(wpi->path, wpli->pc); > + ret = handle_walk_parent_paths(wpi, &wpli->newhandle); > + path_list_del_component(wpi->path, wpli->pc); > + if (ret) > + break; > + } > + > + return ret; > +} > + > +/* > + * Recursively walk all parents of the given file handle; if we hit the > + * fs root then we call the associated function with the constructed path. > + */ > +static int > +handle_walk_parent_paths( > + struct walk_ppaths_info *wpi, > + struct xfs_handle *handle) > +{ > + struct walk_ppath_level_info *wpli; > + int ret; > + > + wpli = malloc(sizeof(struct walk_ppath_level_info)); > + if (!wpli) > + return -1; > + wpli->pc = path_component_init(""); > + if (!wpli->pc) { > + free(wpli); > + return -1; > + } > + wpli->wpi = wpi; > + memcpy(&wpli->newhandle, handle, sizeof(struct xfs_handle)); > + > + ret = handle_walk_parents(wpi->fd, handle, handle_walk_parent_path_ptr, > + wpli); > + > + path_component_free(wpli->pc); > + free(wpli); > + return ret; > +} > + > +/* > + * Call the given function on all known paths from the vfs root to the inode > + * described in the handle. > + */ > +int > +handle_walk_ppaths( > + void *hanp, > + size_t hlen, > + walk_ppath_fn fn, > + void *arg) > +{ > + struct walk_ppaths_info wpi; > + ssize_t ret; > + > + if (hlen != sizeof(struct xfs_handle)) { > + errno = EINVAL; > + return -1; > + } > + > + wpi.fd = handle_to_fsfd(hanp, &wpi.mntpt); > + if (wpi.fd < 0) > + return -1; > + wpi.path = path_list_init(); > + if (!wpi.path) > + return -1; > + wpi.fn = fn; > + wpi.arg = arg; > + > + ret = handle_walk_parent_paths(&wpi, hanp); > + path_list_free(wpi.path); > + > + return ret; > +} > + > +/* > + * Call the given function on all known paths from the vfs root to the inode > + * referred to by the file description. > + */ > +int > +fd_walk_ppaths( > + int fd, > + walk_ppath_fn fn, > + void *arg) > +{ > + struct walk_ppaths_info wpi; > + void *hanp; > + size_t hlen; > + int fsfd; > + int ret; > + > + ret = fd_to_handle(fd, &hanp, &hlen); > + if (ret) > + return ret; > + > + fsfd = handle_to_fsfd(hanp, &wpi.mntpt); > + if (fsfd < 0) > + return -1; > + wpi.fd = fd; > + wpi.path = path_list_init(); > + if (!wpi.path) > + return -1; > + wpi.fn = fn; > + wpi.arg = arg; > + > + ret = handle_walk_parent_paths(&wpi, hanp); > + path_list_free(wpi.path); > + > + return ret; > +} > + > +struct path_walk_info { > + char *buf; > + size_t len; > +}; > + > +/* Helper that stringifies the first full path that we find. */ > +static int > +handle_to_path_walk( > + const char *mntpt, > + struct path_list *path, > + void *arg) > +{ > + struct path_walk_info *pwi = arg; > + int ret; > + > + ret = snprintf(pwi->buf, pwi->len, "%s", mntpt); > + if (ret != strlen(mntpt)) { > + errno = ENOMEM; > + return -1; > + } > + > + ret = path_list_to_string(path, pwi->buf + ret, pwi->len - ret); > + if (ret < 0) > + return ret; > + > + return WALK_PPATHS_ABORT; > +} > + > +/* Return any eligible path to this file handle. */ > +int > +handle_to_path( > + void *hanp, > + size_t hlen, > + char *path, > + size_t pathlen) > +{ > + struct path_walk_info pwi; > + > + pwi.buf = path; > + pwi.len = pathlen; > + return handle_walk_ppaths(hanp, hlen, handle_to_path_walk, &pwi); > +} > + > +/* Return any eligible path to this file description. */ > +int > +fd_to_path( > + int fd, > + char *path, > + size_t pathlen) > +{ > + struct path_walk_info pwi; > + > + pwi.buf = path; > + pwi.len = pathlen; > + return fd_walk_ppaths(fd, handle_to_path_walk, &pwi); > +} > diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h > index e3ce233..aa613f9 100644 > --- a/libxfs/xfs_fs.h > +++ b/libxfs/xfs_fs.h > @@ -610,6 +610,14 @@ struct xfs_pptr_info { > #define XFS_PPINFO_TO_PP(info, idx) \ > (&(((struct xfs_parent_ptr *)((char *)(info) + sizeof(*(info))))[(idx)])) > > +#define XFS_PPTR_ALL_IFLAGS (XFS_PPTR_IFLAG_HANDLE) > + > +/* partial results only */ > +#define XFS_PPTR_OFLAG_PARTIAL (1U << 0) > + > +/* target was the root directory */ > +#define XFS_PPTR_OFLAG_ROOT (1U << 1) Uhoh, I forgot about this chunk, which should be in the kernel patches somewhere I guess... --D > + > /* > * ioctl limits > */ > diff --git a/scrub/inodes.c b/scrub/inodes.c > index ccfb9e0..3fbcd1a 100644 > --- a/scrub/inodes.c > +++ b/scrub/inodes.c > @@ -31,6 +31,7 @@ > #include "xfs_scrub.h" > #include "common.h" > #include "inodes.h" > +#include "parent.h" > > /* > * Iterate a range of inodes. > @@ -293,3 +294,28 @@ xfs_open_handle( > return open_by_fshandle(handle, sizeof(*handle), > O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NOCTTY); > } > + > +/* Construct a description for an inode. */ > +void > +xfs_scrub_ino_descr( > + struct scrub_ctx *ctx, > + struct xfs_handle *handle, > + char *buf, > + size_t buflen) > +{ > + uint64_t ino; > + xfs_agnumber_t agno; > + xfs_agino_t agino; > + int ret; > + > + ret = handle_to_path(handle, sizeof(struct xfs_handle), buf, buflen); > + if (ret >= 0) > + return; > + > + ino = handle->ha_fid.fid_ino; > + agno = ino / (1ULL << (ctx->inopblog + ctx->agblklog)); > + agino = ino % (1ULL << (ctx->inopblog + ctx->agblklog)); > + snprintf(buf, buflen, _("inode %"PRIu64" (%u/%u)"), ino, agno, > + agino); > +} > + > diff --git a/scrub/inodes.h b/scrub/inodes.h > index 693cb05..e94de0a 100644 > --- a/scrub/inodes.h > +++ b/scrub/inodes.h > @@ -28,5 +28,7 @@ bool xfs_scan_all_inodes(struct scrub_ctx *ctx, xfs_inode_iter_fn fn, > void *arg); > > int xfs_open_handle(struct xfs_handle *handle); > +void xfs_scrub_ino_descr(struct scrub_ctx *ctx, struct xfs_handle *handle, > + char *buf, size_t buflen); > > #endif /* XFS_SCRUB_INODES_H_ */ > diff --git a/scrub/phase5.c b/scrub/phase5.c > index 01038f7..ecaaaaa 100644 > --- a/scrub/phase5.c > +++ b/scrub/phase5.c > @@ -245,16 +245,11 @@ xfs_scrub_connections( > void *arg) > { > bool *pmoveon = arg; > - char descr[DESCR_BUFSZ]; > + char descr[PATH_MAX]; > bool moveon = true; > - xfs_agnumber_t agno; > - xfs_agino_t agino; > int fd = -1; > > - agno = bstat->bs_ino / (1ULL << (ctx->inopblog + ctx->agblklog)); > - agino = bstat->bs_ino % (1ULL << (ctx->inopblog + ctx->agblklog)); > - snprintf(descr, DESCR_BUFSZ, _("inode %"PRIu64" (%u/%u)"), > - (uint64_t)bstat->bs_ino, agno, agino); > + xfs_scrub_ino_descr(ctx, handle, descr, PATH_MAX); > background_sleep(); > > /* Warn about naming problems in xattrs. */ > -- > 2.7.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 5/7/18 11:41 PM, Allison Henderson wrote: > From: "Darrick J. Wong" <darrick.wong@oracle.com> > > Add ioctl definitions to libxfs, build the necessary helpers into > libfrog and libhandle to iterate parents (and parent paths), then wire > up xfs_scrub to be able to query parent pointers from userspace. The > goal of this patch is to exercise userspace, and is nowhere near a > complete solution. A basic xfs_io parent command implementation > replaces ... whatever that is that's there now. I wonder if it'd be better to send a patch to nuke the current parent code, and then another to add back something that works. Same result in the end, but it doesn't look like you're trying to fix old code; the patch itself is pretty meaningless since it diffs against nonfunctional(?) code. Not a huge deal, just a thought. -Eric -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, May 08, 2018 at 03:52:37PM -0500, Eric Sandeen wrote: > On 5/7/18 11:41 PM, Allison Henderson wrote: > > From: "Darrick J. Wong" <darrick.wong@oracle.com> > > > > Add ioctl definitions to libxfs, build the necessary helpers into > > libfrog and libhandle to iterate parents (and parent paths), then wire > > up xfs_scrub to be able to query parent pointers from userspace. The > > goal of this patch is to exercise userspace, and is nowhere near a > > complete solution. A basic xfs_io parent command implementation > > replaces ... whatever that is that's there now. > > I wonder if it'd be better to send a patch to nuke the current parent code, > and then another to add back something that works. Same result in the end, > but it doesn't look like you're trying to fix old code; the patch itself is > pretty meaningless since it diffs against nonfunctional(?) code. Trouble is, it's exported as a shared library in the xfslibs-dev package (should that be libxfs-dev?) so depending on how conservative you like to be we can't just rip it out. (Though I suppose even Linus has occasionally allowed people to rip and replace kernel/user ABIs when they can demonstrate that it was so broken it never worked for anybody, ever. :P) > Not a huge deal, just a thought. Yeah, this patch was quite quick and dirty when I wrote it, on the assumption that tons of other stuff was going to need reorganization by the time there was a need to land this. --D > -Eric > -- > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 05/08/2018 04:04 PM, Darrick J. Wong wrote: > On Tue, May 08, 2018 at 03:52:37PM -0500, Eric Sandeen wrote: >> On 5/7/18 11:41 PM, Allison Henderson wrote: >>> From: "Darrick J. Wong" <darrick.wong@oracle.com> >>> >>> Add ioctl definitions to libxfs, build the necessary helpers into >>> libfrog and libhandle to iterate parents (and parent paths), then wire >>> up xfs_scrub to be able to query parent pointers from userspace. The >>> goal of this patch is to exercise userspace, and is nowhere near a >>> complete solution. A basic xfs_io parent command implementation >>> replaces ... whatever that is that's there now. >> >> I wonder if it'd be better to send a patch to nuke the current parent code, >> and then another to add back something that works. Same result in the end, >> but it doesn't look like you're trying to fix old code; the patch itself is >> pretty meaningless since it diffs against nonfunctional(?) code. > > Trouble is, it's exported as a shared library in the xfslibs-dev package > (should that be libxfs-dev?) so depending on how conservative you like > to be we can't just rip it out. > > (Though I suppose even Linus has occasionally allowed people to rip and > replace kernel/user ABIs when they can demonstrate that it was so broken > it never worked for anybody, ever. :P) > >> Not a huge deal, just a thought. > > Yeah, this patch was quite quick and dirty when I wrote it, on the > assumption that tons of other stuff was going to need reorganization by > the time there was a need to land this. > > --D Oh, would you prefer I not include it then? I do have an xfstest that's using it, but it's not a giant gap to close. I just assumed you probably had a reason for the api you set up. :-) > >> -Eric >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, May 08, 2018 at 04:13:49PM -0700, Allison Henderson wrote: > > > On 05/08/2018 04:04 PM, Darrick J. Wong wrote: > > On Tue, May 08, 2018 at 03:52:37PM -0500, Eric Sandeen wrote: > > > On 5/7/18 11:41 PM, Allison Henderson wrote: > > > > From: "Darrick J. Wong" <darrick.wong@oracle.com> > > > > > > > > Add ioctl definitions to libxfs, build the necessary helpers into > > > > libfrog and libhandle to iterate parents (and parent paths), then wire > > > > up xfs_scrub to be able to query parent pointers from userspace. The > > > > goal of this patch is to exercise userspace, and is nowhere near a > > > > complete solution. A basic xfs_io parent command implementation > > > > replaces ... whatever that is that's there now. > > > > > > I wonder if it'd be better to send a patch to nuke the current parent code, > > > and then another to add back something that works. Same result in the end, > > > but it doesn't look like you're trying to fix old code; the patch itself is > > > pretty meaningless since it diffs against nonfunctional(?) code. > > > > Trouble is, it's exported as a shared library in the xfslibs-dev package > > (should that be libxfs-dev?) so depending on how conservative you like > > to be we can't just rip it out. > > > > (Though I suppose even Linus has occasionally allowed people to rip and > > replace kernel/user ABIs when they can demonstrate that it was so broken > > it never worked for anybody, ever. :P) > > > > > Not a huge deal, just a thought. > > > > Yeah, this patch was quite quick and dirty when I wrote it, on the > > assumption that tons of other stuff was going to need reorganization by > > the time there was a need to land this. > > > > --D > > Oh, would you prefer I not include it then? I do have an xfstest that's > using it, but it's not a giant gap to close. I just assumed you probably > had a reason for the api you set up. :-) I prefer my new APIs. None of this parse my way through variable-length records in a buffer crap, just call my callback function for every pptr you find. But I might be biased. :) Let's have a look at what we'd be killing off: > typedef struct parent { > __u64 p_ino; > __u32 p_gen; > __u16 p_reclen; > char p_name[1]; > } parent_t; > > typedef struct parent_cursor { > __u32 opaque[4]; /* an opaque cookie */ > } parent_cursor_t; > > extern int > jdm_parents( jdm_fshandle_t *fshp, > xfs_bstat_t *statp, > struct parent *bufp, size_t bufsz, > unsigned int *count); > > extern int > jdm_parentpaths( jdm_fshandle_t *fshp, > xfs_bstat_t *statp, > struct parent *bufp, size_t bufsz, > unsigned int *count); I suppose it wouldn't be hard to emulate these with the other code, but do we care? --D > > > > > > -Eric > > > -- > > > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in > > > the body of a message to majordomo@vger.kernel.org > > > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 05/08/2018 06:22 PM, Darrick J. Wong wrote: > On Tue, May 08, 2018 at 04:13:49PM -0700, Allison Henderson wrote: >> >> >> On 05/08/2018 04:04 PM, Darrick J. Wong wrote: >>> On Tue, May 08, 2018 at 03:52:37PM -0500, Eric Sandeen wrote: >>>> On 5/7/18 11:41 PM, Allison Henderson wrote: >>>>> From: "Darrick J. Wong" <darrick.wong@oracle.com> >>>>> >>>>> Add ioctl definitions to libxfs, build the necessary helpers into >>>>> libfrog and libhandle to iterate parents (and parent paths), then wire >>>>> up xfs_scrub to be able to query parent pointers from userspace. The >>>>> goal of this patch is to exercise userspace, and is nowhere near a >>>>> complete solution. A basic xfs_io parent command implementation >>>>> replaces ... whatever that is that's there now. >>>> >>>> I wonder if it'd be better to send a patch to nuke the current parent code, >>>> and then another to add back something that works. Same result in the end, >>>> but it doesn't look like you're trying to fix old code; the patch itself is >>>> pretty meaningless since it diffs against nonfunctional(?) code. >>> >>> Trouble is, it's exported as a shared library in the xfslibs-dev package >>> (should that be libxfs-dev?) so depending on how conservative you like >>> to be we can't just rip it out. >>> >>> (Though I suppose even Linus has occasionally allowed people to rip and >>> replace kernel/user ABIs when they can demonstrate that it was so broken >>> it never worked for anybody, ever. :P) >>> >>>> Not a huge deal, just a thought. >>> >>> Yeah, this patch was quite quick and dirty when I wrote it, on the >>> assumption that tons of other stuff was going to need reorganization by >>> the time there was a need to land this. >>> >>> --D >> >> Oh, would you prefer I not include it then? I do have an xfstest that's >> using it, but it's not a giant gap to close. I just assumed you probably >> had a reason for the api you set up. :-) > > I prefer my new APIs. None of this parse my way through variable-length > records in a buffer crap, just call my callback function for every pptr > you find. But I might be biased. :) > > Let's have a look at what we'd be killing off: > >> typedef struct parent { >> __u64 p_ino; >> __u32 p_gen; >> __u16 p_reclen; >> char p_name[1]; >> } parent_t; >> >> typedef struct parent_cursor { >> __u32 opaque[4]; /* an opaque cookie */ >> } parent_cursor_t; >> >> extern int >> jdm_parents( jdm_fshandle_t *fshp, >> xfs_bstat_t *statp, >> struct parent *bufp, size_t bufsz, >> unsigned int *count); >> >> extern int >> jdm_parentpaths( jdm_fshandle_t *fshp, >> xfs_bstat_t *statp, >> struct parent *bufp, size_t bufsz, >> unsigned int *count); > > I suppose it wouldn't be hard to emulate these with the other code, but > do we care? > > --D Alrighty, I can clean those in the next revision then. Allison > >> >>> >>>> -Eric >>>> -- >>>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in >>>> the body of a message to majordomo@vger.kernel.org >>>> More majordomo info at https://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=ZYhT49wgnXi-BAqQb6XvZtIJlZmC9-GTIfYkkgzS3x8&s=oDk5xa1iaNp87c2xfX0TDTQc9Hs9-RraSgWXeoZvQkU&e= >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at https://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=ZYhT49wgnXi-BAqQb6XvZtIJlZmC9-GTIfYkkgzS3x8&s=oDk5xa1iaNp87c2xfX0TDTQc9Hs9-RraSgWXeoZvQkU&e= > -- > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at https://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=ZYhT49wgnXi-BAqQb6XvZtIJlZmC9-GTIfYkkgzS3x8&s=oDk5xa1iaNp87c2xfX0TDTQc9Hs9-RraSgWXeoZvQkU&e= > -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 05/08/2018 10:45 AM, Darrick J. Wong wrote: > On Mon, May 07, 2018 at 09:41:19PM -0700, Allison Henderson wrote: >> From: "Darrick J. Wong" <darrick.wong@oracle.com> >> >> Add ioctl definitions to libxfs, build the necessary helpers into >> libfrog and libhandle to iterate parents (and parent paths), then wire >> up xfs_scrub to be able to query parent pointers from userspace. The >> goal of this patch is to exercise userspace, and is nowhere near a >> complete solution. A basic xfs_io parent command implementation >> replaces ... whatever that is that's there now. >> >> Totally missing: actual support in libxfs for working with parent ptrs >> straight off the disk (mkfs, xfs_db, xfs_repair). >> >> [achender: Minor syntax adjustments to sew solution in actual support >> in libxfs for working with parent ptrs] >> >> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> >> Signed-off-by: Allison Henderson <allison.henderson@oracle.com> >> --- >> include/handle.h | 2 + >> include/parent.h | 18 ++ >> include/path.h | 19 +++ >> io/parent.c | 471 ++++++++++++++--------------------------------------- >> libfrog/paths.c | 136 ++++++++++++++++ >> libhandle/Makefile | 2 +- >> libhandle/handle.c | 7 +- >> libhandle/parent.c | 325 ++++++++++++++++++++++++++++++++++++ >> libxfs/xfs_fs.h | 8 + >> scrub/inodes.c | 26 +++ >> scrub/inodes.h | 2 + >> scrub/phase5.c | 9 +- >> 12 files changed, 661 insertions(+), 364 deletions(-) >> >> diff --git a/include/handle.h b/include/handle.h >> index 49f1441..00aa43d 100644 >> --- a/include/handle.h >> +++ b/include/handle.h >> @@ -52,6 +52,8 @@ extern int fssetdm_by_handle (void *__hanp, size_t __hlen, >> >> void fshandle_destroy(void); >> >> +int handle_to_fsfd(void *hanp, char **path); >> + >> #ifdef __cplusplus >> } >> #endif >> diff --git a/include/parent.h b/include/parent.h >> index 85cef85..33f8d85 100644 >> --- a/include/parent.h >> +++ b/include/parent.h >> @@ -28,4 +28,22 @@ typedef struct parent_cursor { >> __u32 opaque[4]; /* an opaque cookie */ >> } parent_cursor_t; >> >> +struct path_list; >> + >> +typedef int (*walk_pptr_fn)(struct xfs_pptr_info *pi, struct xfs_parent_ptr *pptr, >> + void *arg); >> +typedef int (*walk_ppath_fn)(const char *mntpt, struct path_list *path, >> + void *arg); >> + >> +#define WALK_PPTRS_ABORT 1 >> +int fd_walk_pptrs(int fd, walk_pptr_fn fn, void *arg); >> +int handle_walk_pptrs(void *hanp, size_t hanlen, walk_pptr_fn fn, void *arg); >> + >> +#define WALK_PPATHS_ABORT 1 >> +int fd_walk_ppaths(int fd, walk_ppath_fn fn, void *arg); >> +int handle_walk_ppaths(void *hanp, size_t hanlen, walk_ppath_fn fn, void *arg); >> + >> +int fd_to_path(int fd, char *path, size_t pathlen); >> +int handle_to_path(void *hanp, size_t hlen, char *path, size_t pathlen); >> + >> #endif >> diff --git a/include/path.h b/include/path.h >> index 88dc44b..cbe4e19 100644 >> --- a/include/path.h >> +++ b/include/path.h >> @@ -70,4 +70,23 @@ typedef struct fs_cursor { >> extern void fs_cursor_initialise(char *__dir, uint __flags, fs_cursor_t *__cp); >> extern fs_path_t *fs_cursor_next_entry(fs_cursor_t *__cp); >> >> +/* Path information. */ >> + >> +struct path_list; >> +struct path_component; >> + >> +struct path_component *path_component_init(const char *name); >> +void path_component_free(struct path_component *pc); >> +int path_component_change(struct path_component *pc, void *name, >> + size_t namelen); >> + >> +struct path_list *path_list_init(void); >> +void path_list_free(struct path_list *path); >> +void path_list_add_parent_component(struct path_list *path, >> + struct path_component *pc); >> +void path_list_add_component(struct path_list *path, struct path_component *pc); >> +void path_list_del_component(struct path_list *path, struct path_component *pc); >> + >> +ssize_t path_list_to_string(struct path_list *path, char *buf, size_t buflen); >> + >> #endif /* __PATH_H__ */ >> diff --git a/io/parent.c b/io/parent.c >> index 55b8b49..ad51fe6 100644 >> --- a/io/parent.c >> +++ b/io/parent.c >> @@ -21,366 +21,105 @@ >> #include "path.h" >> #include "parent.h" >> #include "handle.h" >> -#include "jdm.h" >> #include "init.h" >> #include "io.h" >> >> -#define PARENTBUF_SZ 16384 >> -#define BSTATBUF_SZ 16384 >> - >> static cmdinfo_t parent_cmd; >> -static int verbose_flag; >> -static int err_status; >> -static __u64 inodes_checked; >> static char *mntpt; >> >> -/* >> - * check out a parent entry to see if the values seem valid >> - */ >> -static void >> -check_parent_entry(xfs_bstat_t *bstatp, parent_t *parent) >> -{ >> - int sts; >> - char fullpath[PATH_MAX]; >> - struct stat statbuf; >> - char *str; >> - >> - snprintf(fullpath, parent->p_reclen, _("%s%s"), mntpt, >> - ((char*)parent)+sizeof(struct parent)); >> - >> - sts = lstat(fullpath, &statbuf); >> - if (sts != 0) { >> - fprintf(stderr, >> - _("inode-path for inode: %llu is incorrect - path \"%s\" non-existent\n"), >> - (unsigned long long) bstatp->bs_ino, fullpath); >> - if (verbose_flag) { >> - fprintf(stderr, >> - _("path \"%s\" does not stat for inode: %llu; err = %s\n"), >> - fullpath, >> - (unsigned long long) bstatp->bs_ino, >> - strerror(errno)); >> - } >> - err_status++; >> - return; >> - } else { >> - if (verbose_flag > 1) { >> - printf(_("path \"%s\" found\n"), fullpath); >> - } >> - } >> - >> - if (statbuf.st_ino != bstatp->bs_ino) { >> - fprintf(stderr, >> - _("inode-path for inode: %llu is incorrect - wrong inode#\n"), >> - (unsigned long long) bstatp->bs_ino); >> - if (verbose_flag) { >> - fprintf(stderr, >> - _("ino mismatch for path \"%s\" %llu vs %llu\n"), >> - fullpath, >> - (unsigned long long)statbuf.st_ino, >> - (unsigned long long)bstatp->bs_ino); >> - } >> - err_status++; >> - return; >> - } else if (verbose_flag > 1) { >> - printf(_("inode number match: %llu\n"), >> - (unsigned long long)statbuf.st_ino); >> - } >> - >> - /* get parent path */ >> - str = strrchr(fullpath, '/'); >> - *str = '\0'; >> - sts = stat(fullpath, &statbuf); >> - if (sts != 0) { >> - fprintf(stderr, >> - _("parent path \"%s\" does not stat: %s\n"), >> - fullpath, >> - strerror(errno)); >> - err_status++; >> - return; >> - } else { >> - if (parent->p_ino != statbuf.st_ino) { >> - fprintf(stderr, >> - _("inode-path for inode: %llu is incorrect - wrong parent inode#\n"), >> - (unsigned long long) bstatp->bs_ino); >> - if (verbose_flag) { >> - fprintf(stderr, >> - _("ino mismatch for path \"%s\" %llu vs %llu\n"), >> - fullpath, >> - (unsigned long long)parent->p_ino, >> - (unsigned long long)statbuf.st_ino); >> - } >> - err_status++; >> - return; >> - } else { >> - if (verbose_flag > 1) { >> - printf(_("parent ino match for %llu\n"), >> - (unsigned long long) parent->p_ino); >> - } >> - } >> - } >> -} >> - >> -static void >> -check_parents(parent_t *parentbuf, size_t *parentbuf_size, >> - jdm_fshandle_t *fshandlep, xfs_bstat_t *statp) >> -{ >> - int error, i; >> - __u32 count; >> - parent_t *entryp; >> - >> - do { >> - error = jdm_parentpaths(fshandlep, statp, parentbuf, *parentbuf_size, &count); >> - >> - if (error == ERANGE) { >> - *parentbuf_size *= 2; >> - parentbuf = (parent_t *)realloc(parentbuf, *parentbuf_size); >> - } else if (error) { >> - fprintf(stderr, _("parentpaths failed for ino %llu: %s\n"), >> - (unsigned long long) statp->bs_ino, >> - strerror(errno)); >> - err_status++; >> - break; >> - } >> - } while (error == ERANGE); >> - >> - >> - if (count == 0) { >> - /* no links for inode - something wrong here */ >> - fprintf(stderr, _("inode-path for inode: %llu is missing\n"), >> - (unsigned long long) statp->bs_ino); >> - err_status++; >> - } >> - >> - entryp = parentbuf; >> - for (i = 0; i < count; i++) { >> - check_parent_entry(statp, entryp); >> - entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); >> - } >> -} >> - >> static int >> -do_bulkstat(parent_t *parentbuf, size_t *parentbuf_size, xfs_bstat_t *bstatbuf, >> - int fsfd, jdm_fshandle_t *fshandlep) >> +pptr_print( >> + struct xfs_pptr_info *pi, >> + struct xfs_parent_ptr *pptr, >> + void *arg) >> { >> - __s32 buflenout; >> - __u64 lastino = 0; >> - xfs_bstat_t *p; >> - xfs_bstat_t *endp; >> - xfs_fsop_bulkreq_t bulkreq; >> - struct stat mntstat; >> + char buf[XFS_PPTR_MAXNAMELEN + 1]; >> >> - if (stat(mntpt, &mntstat)) { >> - fprintf(stderr, _("can't stat mount point \"%s\": %s\n"), >> - mntpt, strerror(errno)); >> - return 1; >> + if (pi->pi_flags & XFS_PPTR_OFLAG_ROOT) { >> + printf(_("Root directory.\n")); >> + return 0; >> } >> >> - bulkreq.lastip = &lastino; >> - bulkreq.icount = BSTATBUF_SZ; >> - bulkreq.ubuffer = (void *)bstatbuf; >> - bulkreq.ocount = &buflenout; >> - >> - while (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT, &bulkreq) == 0) { >> - if (*(bulkreq.ocount) == 0) { >> - return 0; >> - } >> - for (p = bstatbuf, endp = bstatbuf + *bulkreq.ocount; p < endp; p++) { >> - >> - /* inode being modified, get synced data with iget */ >> - if ( (!p->bs_nlink || !p->bs_mode) && p->bs_ino != 0 ) { >> - >> - if (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) < 0) { >> - fprintf(stderr, >> - _("failed to get bulkstat information for inode %llu\n"), >> - (unsigned long long) p->bs_ino); >> - continue; >> - } >> - if (!p->bs_nlink || !p->bs_mode || !p->bs_ino) { >> - fprintf(stderr, >> - _("failed to get valid bulkstat information for inode %llu\n"), >> - (unsigned long long) p->bs_ino); >> - continue; >> - } >> - } >> - >> - /* skip root */ >> - if (p->bs_ino == mntstat.st_ino) { >> - continue; >> - } >> - >> - if (verbose_flag > 1) { >> - printf(_("checking inode %llu\n"), >> - (unsigned long long) p->bs_ino); >> - } >> - >> - /* print dotted progress */ >> - if ((inodes_checked % 100) == 0 && verbose_flag == 1) { >> - printf("."); fflush(stdout); >> - } >> - inodes_checked++; >> - >> - check_parents(parentbuf, parentbuf_size, fshandlep, p); >> - } >> - >> - }/*while*/ >> - >> - fprintf(stderr, _("syssgi bulkstat failed: %s\n"), strerror(errno)); >> - return 1; >> + memcpy(buf, pptr->xpp_name, pptr->xpp_namelen); >> + buf[pptr->xpp_namelen] = 0; >> + printf(_("p_ino = %llu\n"), (unsigned long long)pptr->xpp_ino); >> + printf(_("p_gen = %u\n"), (unsigned int)pptr->xpp_gen); >> + printf(_("p_reclen = %u\n"), (unsigned int)pptr->xpp_namelen); >> + printf(_("p_name = \"%s\"\n\n"), buf); >> + return 0; >> } >> >> -static int >> -parent_check(void) >> +int >> +print_parents( >> + struct xfs_handle *handle) >> { >> - int fsfd; >> - jdm_fshandle_t *fshandlep; >> - parent_t *parentbuf; >> - size_t parentbuf_size = PARENTBUF_SZ; >> - xfs_bstat_t *bstatbuf; >> - >> - err_status = 0; >> - inodes_checked = 0; >> - >> - sync(); >> - >> - fsfd = file->fd; >> - >> - fshandlep = jdm_getfshandle(mntpt); >> - if (fshandlep == NULL) { >> - fprintf(stderr, _("unable to open \"%s\" for jdm: %s\n"), >> - mntpt, >> - strerror(errno)); >> - return 1; >> - } >> - >> - /* allocate buffers */ >> - bstatbuf = (xfs_bstat_t *)calloc(BSTATBUF_SZ, sizeof(xfs_bstat_t)); >> - parentbuf = (parent_t *)malloc(parentbuf_size); >> - if (!bstatbuf || !parentbuf) { >> - fprintf(stderr, _("unable to allocate buffers: %s\n"), >> - strerror(errno)); >> - err_status = 1; >> - goto out; >> - } >> + int ret; >> >> - if (do_bulkstat(parentbuf, &parentbuf_size, bstatbuf, fsfd, fshandlep) != 0) >> - err_status++; >> - >> - if (err_status > 0) >> - fprintf(stderr, _("num errors: %d\n"), err_status); >> + if (handle) >> + ret = handle_walk_pptrs(handle, sizeof(*handle), pptr_print, >> + NULL); >> else >> - printf(_("succeeded checking %llu inodes\n"), >> - (unsigned long long) inodes_checked); >> - >> -out: >> - free(bstatbuf); >> - free(parentbuf); >> - free(fshandlep); >> - return err_status; >> -} >> + ret = fd_walk_pptrs(file->fd, pptr_print, NULL); >> + if (ret) >> + perror(file->name); >> >> -static void >> -print_parent_entry(parent_t *parent, int fullpath) >> -{ >> - printf(_("p_ino = %llu\n"), (unsigned long long) parent->p_ino); >> - printf(_("p_gen = %u\n"), parent->p_gen); >> - printf(_("p_reclen = %u\n"), parent->p_reclen); >> - if (fullpath) >> - printf(_("p_name = \"%s%s\"\n"), mntpt, >> - ((char*)parent)+sizeof(struct parent)); >> - else >> - printf(_("p_name = \"%s\"\n"), >> - ((char*)parent)+sizeof(struct parent)); >> + return 0; >> } >> >> static int >> -parent_list(int fullpath) >> -{ >> - void *handlep = NULL; >> - size_t handlen; >> - int error, i; >> - int retval = 1; >> - __u32 count; >> - parent_t *entryp; >> - parent_t *parentbuf = NULL; >> - char *path = file->name; >> - int pb_size = PARENTBUF_SZ; >> - >> - /* XXXX for linux libhandle version - to set libhandle fsfd cache */ >> - { >> - void *fshandle; >> - size_t fshlen; >> - >> - if (path_to_fshandle(mntpt, &fshandle, &fshlen) != 0) { >> - fprintf(stderr, _("%s: failed path_to_fshandle \"%s\": %s\n"), >> - progname, path, strerror(errno)); >> - goto error; >> - } >> - free_handle(fshandle, fshlen); >> - } >> - >> - if (path_to_handle(path, &handlep, &handlen) != 0) { >> - fprintf(stderr, _("%s: path_to_handle failed for \"%s\"\n"), progname, path); >> - goto error; >> - } >> - >> - do { >> - parentbuf = (parent_t *)realloc(parentbuf, pb_size); >> - if (!parentbuf) { >> - fprintf(stderr, _("%s: unable to allocate parent buffer: %s\n"), >> - progname, strerror(errno)); >> - goto error; >> - } >> +path_print( >> + const char *mntpt, >> + struct path_list *path, >> + void *arg) { >> >> - if (fullpath) { >> - error = parentpaths_by_handle(handlep, >> - handlen, >> - parentbuf, >> - pb_size, >> - &count); >> - } else { >> - error = parents_by_handle(handlep, >> - handlen, >> - parentbuf, >> - pb_size, >> - &count); >> - } >> - if (error == ERANGE) { >> - pb_size *= 2; >> - } else if (error) { >> - fprintf(stderr, _("%s: %s call failed for \"%s\": %s\n"), >> - progname, fullpath ? "parentpaths" : "parents", >> - path, strerror(errno)); >> - goto error; >> - } >> - } while (error == ERANGE); >> + char buf[PATH_MAX]; >> + size_t len = PATH_MAX; >> + int ret; >> >> - if (count == 0) { >> - /* no links for inode - something wrong here */ >> - fprintf(stderr, _("%s: inode-path is missing\n"), progname); >> - goto error; >> + ret = snprintf(buf, len, "%s", mntpt); >> + if (ret != strlen(mntpt)) { >> + errno = ENOMEM; >> + return -1; >> } >> >> - entryp = parentbuf; >> - for (i = 0; i < count; i++) { >> - print_parent_entry(entryp, fullpath); >> - entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); >> - } >> + ret = path_list_to_string(path, buf + ret, len - ret); >> + if (ret < 0) >> + return ret; >> + return 0; >> +} >> >> - retval = 0; >> -error: >> - free(handlep); >> - free(parentbuf); >> - return retval; >> +int >> +print_paths( >> + struct xfs_handle *handle) >> +{ >> + int ret; >> + >> + if (handle) >> + ret = handle_walk_ppaths(handle, sizeof(*handle), path_print, >> + NULL); >> + else >> + ret = fd_walk_ppaths(file->fd, path_print, NULL); >> + if (ret) >> + perror(file->name); >> + return 0; >> } >> >> int >> -parent_f(int argc, char **argv) >> +parent_f( >> + int argc, >> + char **argv) >> { >> - int c; >> - int listpath_flag = 0; >> - int check_flag = 0; >> - fs_path_t *fs; >> - static int tab_init; >> + struct xfs_handle handle; >> + void *hanp = NULL; >> + size_t hlen; >> + struct fs_path *fs; >> + char *p; >> + uint64_t ino = 0; >> + uint32_t gen = 0; >> + int c; >> + int listpath_flag = 0; >> + int ret; >> + static int tab_init; >> >> if (!tab_init) { >> tab_init = 1; >> @@ -394,46 +133,72 @@ parent_f(int argc, char **argv) >> } >> mntpt = fs->fs_dir; >> >> - verbose_flag = 0; >> - >> - while ((c = getopt(argc, argv, "cpv")) != EOF) { >> + while ((c = getopt(argc, argv, "p")) != EOF) { >> switch (c) { >> - case 'c': >> - check_flag = 1; >> - break; >> case 'p': >> listpath_flag = 1; >> break; >> - case 'v': >> - verbose_flag++; >> - break; >> default: >> return command_usage(&parent_cmd); >> } >> } >> >> - if (!check_flag && !listpath_flag) /* default case */ >> - exitcode = parent_list(listpath_flag); >> - else { >> - if (listpath_flag) >> - exitcode = parent_list(listpath_flag); >> - if (check_flag) >> - exitcode = parent_check(); >> + /* >> + * Always initialize the fshandle table because we need it for >> + * the ppaths functions to work. >> + */ >> + ret = path_to_fshandle((char *)mntpt, &hanp, &hlen); >> + if (ret) { >> + perror(mntpt); >> + return 0; >> + } >> + >> + if (optind + 2 == argc) { >> + ino = strtoull(argv[optind], &p, 0); >> + if (*p != '\0' || ino == 0) { >> + fprintf(stderr, >> + _("Bad inode number '%s'.\n"), >> + argv[optind]); >> + return 0; >> + } >> + gen = strtoul(argv[optind + 1], &p, 0); >> + if (*p != '\0') { >> + fprintf(stderr, >> + _("Bad generation number '%s'.\n"), >> + argv[optind + 1]); >> + return 0; >> + } >> + >> + memcpy(&handle, hanp, sizeof(handle)); >> + handle.ha_fid.fid_len = sizeof(xfs_fid_t) - >> + sizeof(handle.ha_fid.fid_len); >> + handle.ha_fid.fid_pad = 0; >> + handle.ha_fid.fid_ino = ino; >> + handle.ha_fid.fid_gen = gen; >> + >> } >> >> + if (listpath_flag) >> + exitcode = print_paths(ino ? &handle : NULL); >> + else >> + exitcode = print_parents(ino ? &handle : NULL); >> + >> + if (hanp) >> + free_handle(hanp, hlen); >> + >> return 0; >> } >> >> static void >> parent_help(void) >> { >> - printf(_( >> +printf(_( >> "\n" >> " list the current file's parents and their filenames\n" >> "\n" >> -" -c -- check the current file's file system for parent consistency\n" >> -" -p -- list the current file's parents and their full paths\n" >> -" -v -- verbose mode\n" >> +" -p -- list the current file's paths up to the root\n" >> +"\n" >> +"If ino and gen are supplied, use them instead.\n" >> "\n")); >> } >> >> @@ -444,9 +209,9 @@ parent_init(void) >> parent_cmd.cfunc = parent_f; >> parent_cmd.argmin = 0; >> parent_cmd.argmax = -1; >> - parent_cmd.args = _("[-cpv]"); >> + parent_cmd.args = _("[-p] [ino gen]"); >> parent_cmd.flags = CMD_NOMAP_OK; >> - parent_cmd.oneline = _("print or check parent inodes"); >> + parent_cmd.oneline = _("print parent inodes"); >> parent_cmd.help = parent_help; >> >> if (expert) >> diff --git a/libfrog/paths.c b/libfrog/paths.c >> index c7895e9..9fb0140 100644 >> --- a/libfrog/paths.c >> +++ b/libfrog/paths.c >> @@ -27,6 +27,7 @@ >> #include "path.h" >> #include "input.h" >> #include "project.h" >> +#include "list.h" >> #include <limits.h> >> >> extern char *progname; >> @@ -632,3 +633,138 @@ fs_table_insert_project_path( >> exit(1); >> } >> } >> + >> + >> +/* Structured path components. */ >> + >> +struct path_list { >> + struct list_head p_head; >> +}; >> + >> +struct path_component { >> + struct list_head pc_list; >> + char *pc_fname; >> +}; >> + >> +/* Initialize a path component with a given name. */ >> +struct path_component * >> +path_component_init( >> + const char *name) >> +{ >> + struct path_component *pc; >> + >> + pc = malloc(sizeof(struct path_component)); >> + if (!pc) >> + return NULL; >> + INIT_LIST_HEAD(&pc->pc_list); >> + pc->pc_fname = strdup(name); >> + if (!pc->pc_fname) { >> + free(pc); >> + return NULL; >> + } >> + return pc; >> +} >> + >> +/* Free a path component. */ >> +void >> +path_component_free( >> + struct path_component *pc) >> +{ >> + free(pc->pc_fname); >> + free(pc); >> +} >> + >> +/* Change a path component's filename. */ >> +int >> +path_component_change( >> + struct path_component *pc, >> + void *name, >> + size_t namelen) >> +{ >> + void *p; >> + >> + p = realloc(pc->pc_fname, namelen + 1); >> + if (!p) >> + return -1; >> + pc->pc_fname = p; >> + memcpy(pc->pc_fname, name, namelen); >> + pc->pc_fname[namelen] = 0; >> + return 0; >> +} >> + >> +/* Initialize a pathname. */ >> +struct path_list * >> +path_list_init(void) >> +{ >> + struct path_list *path; >> + >> + path = malloc(sizeof(struct path_list)); >> + if (!path) >> + return NULL; >> + INIT_LIST_HEAD(&path->p_head); >> + return path; >> +} >> + >> +/* Empty out a pathname. */ >> +void >> +path_list_free( >> + struct path_list *path) >> +{ >> + struct path_component *pos; >> + struct path_component *n; >> + >> + list_for_each_entry_safe(pos, n, &path->p_head, pc_list) { >> + path_list_del_component(path, pos); >> + path_component_free(pos); >> + } >> + free(path); >> +} >> + >> +/* Add a parent component to a pathname. */ >> +void >> +path_list_add_parent_component( >> + struct path_list *path, >> + struct path_component *pc) >> +{ >> + list_add(&pc->pc_list, &path->p_head); >> +} >> + >> +/* Add a component to a pathname. */ >> +void >> +path_list_add_component( >> + struct path_list *path, >> + struct path_component *pc) >> +{ >> + list_add_tail(&pc->pc_list, &path->p_head); >> +} >> + >> +/* Remove a component from a pathname. */ >> +void >> +path_list_del_component( >> + struct path_list *path, >> + struct path_component *pc) >> +{ >> + list_del_init(&pc->pc_list); >> +} >> + >> +/* Convert a pathname into a string. */ >> +ssize_t >> +path_list_to_string( >> + struct path_list *path, >> + char *buf, >> + size_t buflen) >> +{ >> + struct path_component *pos; >> + ssize_t bytes = 0; >> + int ret; >> + >> + list_for_each_entry(pos, &path->p_head, pc_list) { >> + ret = snprintf(buf, buflen, "/%s", pos->pc_fname); >> + if (ret != 1 + strlen(pos->pc_fname)) >> + return -1; >> + bytes += ret; >> + buf += ret; >> + buflen -= ret; >> + } >> + return bytes; >> +} >> diff --git a/libhandle/Makefile b/libhandle/Makefile >> index fe1a2af..d3cea41 100644 >> --- a/libhandle/Makefile >> +++ b/libhandle/Makefile >> @@ -16,7 +16,7 @@ else >> LTLDFLAGS += -Wl,--version-script,libhandle.sym >> endif >> >> -CFILES = handle.c jdm.c >> +CFILES = handle.c jdm.c parent.c >> LSRCFILES = libhandle.sym >> >> default: ltdepend $(LTLIBRARY) >> diff --git a/libhandle/handle.c b/libhandle/handle.c >> index 878d14d..a70fa32 100644 >> --- a/libhandle/handle.c >> +++ b/libhandle/handle.c >> @@ -41,7 +41,6 @@ typedef union { >> } comarg_t; >> >> static int obj_to_handle(char *, int, unsigned int, comarg_t, void**, size_t*); >> -static int handle_to_fsfd(void *, char **); >> static char *path_to_fspath(char *path); >> >> >> @@ -214,8 +213,10 @@ handle_to_fshandle( >> return 0; >> } >> >> -static int >> -handle_to_fsfd(void *hanp, char **path) >> +int >> +handle_to_fsfd( >> + void *hanp, >> + char **path) >> { >> struct fdhash *fdhp; >> >> diff --git a/libhandle/parent.c b/libhandle/parent.c >> new file mode 100644 >> index 0000000..f6be3bd >> --- /dev/null >> +++ b/libhandle/parent.c >> @@ -0,0 +1,325 @@ >> +/* >> + * Copyright (C) 2017 Oracle. All Rights Reserved. >> + * >> + * Author: Darrick J. Wong <darrick.wong@oracle.com> >> + * >> + * This program is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU General Public License >> + * as published by the Free Software Foundation; either version 2 >> + * of the License, or (at your option) any later version. >> + * >> + * This program is distributed in the hope that it would be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program; if not, write the Free Software Foundation, >> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. >> + */ >> +#include "platform_defs.h" >> +#include "xfs.h" >> +#include "xfs_arch.h" >> +#include "list.h" >> +#include "path.h" >> +#include "handle.h" >> +#include "parent.h" >> + >> +/* Allocate a buffer large enough for some parent pointer records. */ >> +static inline struct xfs_pptr_info * >> +xfs_pptr_alloc( >> + size_t nr_ptrs) >> +{ >> + struct xfs_pptr_info *pi; >> + >> + pi = malloc(XFS_PPTR_INFO_SIZEOF(nr_ptrs)); >> + if (!pi) >> + return NULL; >> + memset(pi, 0, sizeof(struct xfs_pptr_info)); >> + pi->pi_ptrs_size = nr_ptrs; >> + return pi; >> +} >> + >> +/* Walk all parents of the given file handle. */ >> +static int >> +handle_walk_parents( >> + int fd, >> + struct xfs_handle *handle, >> + walk_pptr_fn fn, >> + void *arg) >> +{ >> + struct xfs_pptr_info *pi; >> + struct xfs_parent_ptr *p; >> + unsigned int i; >> + ssize_t ret = -1; >> + >> + pi = xfs_pptr_alloc(4); >> + if (!pi) >> + return -1; >> + >> + if (handle) { >> + memcpy(&pi->pi_handle, handle, sizeof(struct xfs_handle)); >> + pi->pi_flags = XFS_PPTR_IFLAG_HANDLE; >> + } >> + >> + ret = ioctl(fd, XFS_IOC_GETPPOINTER, pi); >> + while (!ret) { >> + if (pi->pi_flags & XFS_PPTR_OFLAG_ROOT) { >> + ret = fn(pi, NULL, arg); >> + break; >> + } >> + if (pi->pi_ptrs_used == 0) >> + break; >> + for (i = 0; i < pi->pi_ptrs_used; i++) { >> + p = XFS_PPINFO_TO_PP(pi, i); >> + ret = fn(pi, p, arg); >> + if (ret) >> + goto out_pi; >> + } >> + ret = ioctl(fd, XFS_IOC_GETPPOINTER, pi); >> + } >> + >> +out_pi: >> + free(pi); >> + return ret; >> +} >> + >> +/* Walk all parent pointers of this handle. */ >> +int >> +handle_walk_pptrs( >> + void *hanp, >> + size_t hlen, >> + walk_pptr_fn fn, >> + void *arg) >> +{ >> + char *mntpt; >> + int fd; >> + >> + if (hlen != sizeof(struct xfs_handle)) { >> + errno = EINVAL; >> + return -1; >> + } >> + >> + fd = handle_to_fsfd(hanp, &mntpt); >> + if (fd < 0) >> + return -1; >> + >> + return handle_walk_parents(fd, hanp, fn, arg); >> +} >> + >> +/* Walk all parent pointers of this fd. */ >> +int >> +fd_walk_pptrs( >> + int fd, >> + walk_pptr_fn fn, >> + void *arg) >> +{ >> + return handle_walk_parents(fd, NULL, fn, arg); >> +} >> + >> +struct walk_ppaths_info { >> + walk_ppath_fn fn; >> + void *arg; >> + char *mntpt; >> + struct path_list *path; >> + int fd; >> +}; >> + >> +struct walk_ppath_level_info { >> + struct xfs_handle newhandle; >> + struct path_component *pc; >> + struct walk_ppaths_info *wpi; >> +}; >> + >> +static int handle_walk_parent_paths(struct walk_ppaths_info *wpi, >> + struct xfs_handle *handle); >> + >> +static int >> +handle_walk_parent_path_ptr( >> + struct xfs_pptr_info *pi, >> + struct xfs_parent_ptr *p, >> + void *arg) >> +{ >> + struct walk_ppath_level_info *wpli = arg; >> + struct walk_ppaths_info *wpi = wpli->wpi; >> + unsigned int i; >> + int ret = 0; >> + >> + if (pi->pi_flags & XFS_PPTR_OFLAG_ROOT) >> + return wpi->fn(wpi->mntpt, wpi->path, wpi->arg); >> + >> + for (i = 0; i < pi->pi_ptrs_used; i++) { >> + p = XFS_PPINFO_TO_PP(pi, i); >> + ret = path_component_change(wpli->pc, p->xpp_name, >> + p->xpp_namelen); >> + if (ret) >> + break; >> + wpli->newhandle.ha_fid.fid_ino = p->xpp_ino; >> + wpli->newhandle.ha_fid.fid_gen = p->xpp_gen; >> + path_list_add_parent_component(wpi->path, wpli->pc); >> + ret = handle_walk_parent_paths(wpi, &wpli->newhandle); >> + path_list_del_component(wpi->path, wpli->pc); >> + if (ret) >> + break; >> + } >> + >> + return ret; >> +} >> + >> +/* >> + * Recursively walk all parents of the given file handle; if we hit the >> + * fs root then we call the associated function with the constructed path. >> + */ >> +static int >> +handle_walk_parent_paths( >> + struct walk_ppaths_info *wpi, >> + struct xfs_handle *handle) >> +{ >> + struct walk_ppath_level_info *wpli; >> + int ret; >> + >> + wpli = malloc(sizeof(struct walk_ppath_level_info)); >> + if (!wpli) >> + return -1; >> + wpli->pc = path_component_init(""); >> + if (!wpli->pc) { >> + free(wpli); >> + return -1; >> + } >> + wpli->wpi = wpi; >> + memcpy(&wpli->newhandle, handle, sizeof(struct xfs_handle)); >> + >> + ret = handle_walk_parents(wpi->fd, handle, handle_walk_parent_path_ptr, >> + wpli); >> + >> + path_component_free(wpli->pc); >> + free(wpli); >> + return ret; >> +} >> + >> +/* >> + * Call the given function on all known paths from the vfs root to the inode >> + * described in the handle. >> + */ >> +int >> +handle_walk_ppaths( >> + void *hanp, >> + size_t hlen, >> + walk_ppath_fn fn, >> + void *arg) >> +{ >> + struct walk_ppaths_info wpi; >> + ssize_t ret; >> + >> + if (hlen != sizeof(struct xfs_handle)) { >> + errno = EINVAL; >> + return -1; >> + } >> + >> + wpi.fd = handle_to_fsfd(hanp, &wpi.mntpt); >> + if (wpi.fd < 0) >> + return -1; >> + wpi.path = path_list_init(); >> + if (!wpi.path) >> + return -1; >> + wpi.fn = fn; >> + wpi.arg = arg; >> + >> + ret = handle_walk_parent_paths(&wpi, hanp); >> + path_list_free(wpi.path); >> + >> + return ret; >> +} >> + >> +/* >> + * Call the given function on all known paths from the vfs root to the inode >> + * referred to by the file description. >> + */ >> +int >> +fd_walk_ppaths( >> + int fd, >> + walk_ppath_fn fn, >> + void *arg) >> +{ >> + struct walk_ppaths_info wpi; >> + void *hanp; >> + size_t hlen; >> + int fsfd; >> + int ret; >> + >> + ret = fd_to_handle(fd, &hanp, &hlen); >> + if (ret) >> + return ret; >> + >> + fsfd = handle_to_fsfd(hanp, &wpi.mntpt); >> + if (fsfd < 0) >> + return -1; >> + wpi.fd = fd; >> + wpi.path = path_list_init(); >> + if (!wpi.path) >> + return -1; >> + wpi.fn = fn; >> + wpi.arg = arg; >> + >> + ret = handle_walk_parent_paths(&wpi, hanp); >> + path_list_free(wpi.path); >> + >> + return ret; >> +} >> + >> +struct path_walk_info { >> + char *buf; >> + size_t len; >> +}; >> + >> +/* Helper that stringifies the first full path that we find. */ >> +static int >> +handle_to_path_walk( >> + const char *mntpt, >> + struct path_list *path, >> + void *arg) >> +{ >> + struct path_walk_info *pwi = arg; >> + int ret; >> + >> + ret = snprintf(pwi->buf, pwi->len, "%s", mntpt); >> + if (ret != strlen(mntpt)) { >> + errno = ENOMEM; >> + return -1; >> + } >> + >> + ret = path_list_to_string(path, pwi->buf + ret, pwi->len - ret); >> + if (ret < 0) >> + return ret; >> + >> + return WALK_PPATHS_ABORT; >> +} >> + >> +/* Return any eligible path to this file handle. */ >> +int >> +handle_to_path( >> + void *hanp, >> + size_t hlen, >> + char *path, >> + size_t pathlen) >> +{ >> + struct path_walk_info pwi; >> + >> + pwi.buf = path; >> + pwi.len = pathlen; >> + return handle_walk_ppaths(hanp, hlen, handle_to_path_walk, &pwi); >> +} >> + >> +/* Return any eligible path to this file description. */ >> +int >> +fd_to_path( >> + int fd, >> + char *path, >> + size_t pathlen) >> +{ >> + struct path_walk_info pwi; >> + >> + pwi.buf = path; >> + pwi.len = pathlen; >> + return fd_walk_ppaths(fd, handle_to_path_walk, &pwi); >> +} >> diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h >> index e3ce233..aa613f9 100644 >> --- a/libxfs/xfs_fs.h >> +++ b/libxfs/xfs_fs.h >> @@ -610,6 +610,14 @@ struct xfs_pptr_info { >> #define XFS_PPINFO_TO_PP(info, idx) \ >> (&(((struct xfs_parent_ptr *)((char *)(info) + sizeof(*(info))))[(idx)])) >> >> +#define XFS_PPTR_ALL_IFLAGS (XFS_PPTR_IFLAG_HANDLE) >> + >> +/* partial results only */ >> +#define XFS_PPTR_OFLAG_PARTIAL (1U << 0) >> + >> +/* target was the root directory */ >> +#define XFS_PPTR_OFLAG_ROOT (1U << 1) > > Uhoh, I forgot about this chunk, which should be in the kernel patches > somewhere I guess... > > --D > Do we want to keep these? Should I add behavior of these in the kernel side set? Allison >> + >> /* >> * ioctl limits >> */ >> diff --git a/scrub/inodes.c b/scrub/inodes.c >> index ccfb9e0..3fbcd1a 100644 >> --- a/scrub/inodes.c >> +++ b/scrub/inodes.c >> @@ -31,6 +31,7 @@ >> #include "xfs_scrub.h" >> #include "common.h" >> #include "inodes.h" >> +#include "parent.h" >> >> /* >> * Iterate a range of inodes. >> @@ -293,3 +294,28 @@ xfs_open_handle( >> return open_by_fshandle(handle, sizeof(*handle), >> O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NOCTTY); >> } >> + >> +/* Construct a description for an inode. */ >> +void >> +xfs_scrub_ino_descr( >> + struct scrub_ctx *ctx, >> + struct xfs_handle *handle, >> + char *buf, >> + size_t buflen) >> +{ >> + uint64_t ino; >> + xfs_agnumber_t agno; >> + xfs_agino_t agino; >> + int ret; >> + >> + ret = handle_to_path(handle, sizeof(struct xfs_handle), buf, buflen); >> + if (ret >= 0) >> + return; >> + >> + ino = handle->ha_fid.fid_ino; >> + agno = ino / (1ULL << (ctx->inopblog + ctx->agblklog)); >> + agino = ino % (1ULL << (ctx->inopblog + ctx->agblklog)); >> + snprintf(buf, buflen, _("inode %"PRIu64" (%u/%u)"), ino, agno, >> + agino); >> +} >> + >> diff --git a/scrub/inodes.h b/scrub/inodes.h >> index 693cb05..e94de0a 100644 >> --- a/scrub/inodes.h >> +++ b/scrub/inodes.h >> @@ -28,5 +28,7 @@ bool xfs_scan_all_inodes(struct scrub_ctx *ctx, xfs_inode_iter_fn fn, >> void *arg); >> >> int xfs_open_handle(struct xfs_handle *handle); >> +void xfs_scrub_ino_descr(struct scrub_ctx *ctx, struct xfs_handle *handle, >> + char *buf, size_t buflen); >> >> #endif /* XFS_SCRUB_INODES_H_ */ >> diff --git a/scrub/phase5.c b/scrub/phase5.c >> index 01038f7..ecaaaaa 100644 >> --- a/scrub/phase5.c >> +++ b/scrub/phase5.c >> @@ -245,16 +245,11 @@ xfs_scrub_connections( >> void *arg) >> { >> bool *pmoveon = arg; >> - char descr[DESCR_BUFSZ]; >> + char descr[PATH_MAX]; >> bool moveon = true; >> - xfs_agnumber_t agno; >> - xfs_agino_t agino; >> int fd = -1; >> >> - agno = bstat->bs_ino / (1ULL << (ctx->inopblog + ctx->agblklog)); >> - agino = bstat->bs_ino % (1ULL << (ctx->inopblog + ctx->agblklog)); >> - snprintf(descr, DESCR_BUFSZ, _("inode %"PRIu64" (%u/%u)"), >> - (uint64_t)bstat->bs_ino, agno, agino); >> + xfs_scrub_ino_descr(ctx, handle, descr, PATH_MAX); >> background_sleep(); >> >> /* Warn about naming problems in xattrs. */ >> -- >> 2.7.4 >> >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
> On 05/08/2018 10:45 AM, Darrick J. Wong wrote: > > On Mon, May 07, 2018 at 09:41:19PM -0700, Allison Henderson wrote: > > > From: "Darrick J. Wong" <darrick.wong@oracle.com> > > > > > > Add ioctl definitions to libxfs, build the necessary helpers into > > > libfrog and libhandle to iterate parents (and parent paths), then wire > > > up xfs_scrub to be able to query parent pointers from userspace. The > > > goal of this patch is to exercise userspace, and is nowhere near a > > > complete solution. A basic xfs_io parent command implementation > > > replaces ... whatever that is that's there now. > > > > > > Totally missing: actual support in libxfs for working with parent ptrs > > > straight off the disk (mkfs, xfs_db, xfs_repair). > > > > > > [achender: Minor syntax adjustments to sew solution in actual support > > > in libxfs for working with parent ptrs] > > > > > > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> > > > Signed-off-by: Allison Henderson <allison.henderson@oracle.com> > > > --- > > > include/handle.h | 2 + > > > include/parent.h | 18 ++ > > > include/path.h | 19 +++ > > > io/parent.c | 471 ++++++++++++++--------------------------------------- > > > libfrog/paths.c | 136 ++++++++++++++++ > > > libhandle/Makefile | 2 +- > > > libhandle/handle.c | 7 +- > > > libhandle/parent.c | 325 ++++++++++++++++++++++++++++++++++++ > > > libxfs/xfs_fs.h | 8 + > > > scrub/inodes.c | 26 +++ > > > scrub/inodes.h | 2 + > > > scrub/phase5.c | 9 +- > > > 12 files changed, 661 insertions(+), 364 deletions(-) > > > > > > diff --git a/include/handle.h b/include/handle.h > > > index 49f1441..00aa43d 100644 > > > --- a/include/handle.h > > > +++ b/include/handle.h > > > @@ -52,6 +52,8 @@ extern int fssetdm_by_handle (void *__hanp, size_t __hlen, > > > void fshandle_destroy(void); > > > +int handle_to_fsfd(void *hanp, char **path); > > > + > > > #ifdef __cplusplus > > > } > > > #endif > > > diff --git a/include/parent.h b/include/parent.h > > > index 85cef85..33f8d85 100644 > > > --- a/include/parent.h > > > +++ b/include/parent.h > > > @@ -28,4 +28,22 @@ typedef struct parent_cursor { > > > __u32 opaque[4]; /* an opaque cookie */ > > > } parent_cursor_t; > > > +struct path_list; > > > + > > > +typedef int (*walk_pptr_fn)(struct xfs_pptr_info *pi, struct xfs_parent_ptr *pptr, > > > + void *arg); > > > +typedef int (*walk_ppath_fn)(const char *mntpt, struct path_list *path, > > > + void *arg); > > > + > > > +#define WALK_PPTRS_ABORT 1 > > > +int fd_walk_pptrs(int fd, walk_pptr_fn fn, void *arg); > > > +int handle_walk_pptrs(void *hanp, size_t hanlen, walk_pptr_fn fn, void *arg); > > > + > > > +#define WALK_PPATHS_ABORT 1 > > > +int fd_walk_ppaths(int fd, walk_ppath_fn fn, void *arg); > > > +int handle_walk_ppaths(void *hanp, size_t hanlen, walk_ppath_fn fn, void *arg); > > > + > > > +int fd_to_path(int fd, char *path, size_t pathlen); > > > +int handle_to_path(void *hanp, size_t hlen, char *path, size_t pathlen); > > > + > > > #endif > > > diff --git a/include/path.h b/include/path.h > > > index 88dc44b..cbe4e19 100644 > > > --- a/include/path.h > > > +++ b/include/path.h > > > @@ -70,4 +70,23 @@ typedef struct fs_cursor { > > > extern void fs_cursor_initialise(char *__dir, uint __flags, fs_cursor_t *__cp); > > > extern fs_path_t *fs_cursor_next_entry(fs_cursor_t *__cp); > > > +/* Path information. */ > > > + > > > +struct path_list; > > > +struct path_component; > > > + > > > +struct path_component *path_component_init(const char *name); > > > +void path_component_free(struct path_component *pc); > > > +int path_component_change(struct path_component *pc, void *name, > > > + size_t namelen); > > > + > > > +struct path_list *path_list_init(void); > > > +void path_list_free(struct path_list *path); > > > +void path_list_add_parent_component(struct path_list *path, > > > + struct path_component *pc); > > > +void path_list_add_component(struct path_list *path, struct path_component *pc); > > > +void path_list_del_component(struct path_list *path, struct path_component *pc); > > > + > > > +ssize_t path_list_to_string(struct path_list *path, char *buf, size_t buflen); > > > + > > > #endif /* __PATH_H__ */ > > > diff --git a/io/parent.c b/io/parent.c > > > index 55b8b49..ad51fe6 100644 > > > --- a/io/parent.c > > > +++ b/io/parent.c > > > @@ -21,366 +21,105 @@ > > > #include "path.h" > > > #include "parent.h" > > > #include "handle.h" > > > -#include "jdm.h" > > > #include "init.h" > > > #include "io.h" > > > -#define PARENTBUF_SZ 16384 > > > -#define BSTATBUF_SZ 16384 > > > - > > > static cmdinfo_t parent_cmd; > > > -static int verbose_flag; > > > -static int err_status; > > > -static __u64 inodes_checked; > > > static char *mntpt; > > > -/* > > > - * check out a parent entry to see if the values seem valid > > > - */ > > > -static void > > > -check_parent_entry(xfs_bstat_t *bstatp, parent_t *parent) > > > -{ > > > - int sts; > > > - char fullpath[PATH_MAX]; > > > - struct stat statbuf; > > > - char *str; > > > - > > > - snprintf(fullpath, parent->p_reclen, _("%s%s"), mntpt, > > > - ((char*)parent)+sizeof(struct parent)); > > > - > > > - sts = lstat(fullpath, &statbuf); > > > - if (sts != 0) { > > > - fprintf(stderr, > > > - _("inode-path for inode: %llu is incorrect - path \"%s\" non-existent\n"), > > > - (unsigned long long) bstatp->bs_ino, fullpath); > > > - if (verbose_flag) { > > > - fprintf(stderr, > > > - _("path \"%s\" does not stat for inode: %llu; err = %s\n"), > > > - fullpath, > > > - (unsigned long long) bstatp->bs_ino, > > > - strerror(errno)); > > > - } > > > - err_status++; > > > - return; > > > - } else { > > > - if (verbose_flag > 1) { > > > - printf(_("path \"%s\" found\n"), fullpath); > > > - } > > > - } > > > - > > > - if (statbuf.st_ino != bstatp->bs_ino) { > > > - fprintf(stderr, > > > - _("inode-path for inode: %llu is incorrect - wrong inode#\n"), > > > - (unsigned long long) bstatp->bs_ino); > > > - if (verbose_flag) { > > > - fprintf(stderr, > > > - _("ino mismatch for path \"%s\" %llu vs %llu\n"), > > > - fullpath, > > > - (unsigned long long)statbuf.st_ino, > > > - (unsigned long long)bstatp->bs_ino); > > > - } > > > - err_status++; > > > - return; > > > - } else if (verbose_flag > 1) { > > > - printf(_("inode number match: %llu\n"), > > > - (unsigned long long)statbuf.st_ino); > > > - } > > > - > > > - /* get parent path */ > > > - str = strrchr(fullpath, '/'); > > > - *str = '\0'; > > > - sts = stat(fullpath, &statbuf); > > > - if (sts != 0) { > > > - fprintf(stderr, > > > - _("parent path \"%s\" does not stat: %s\n"), > > > - fullpath, > > > - strerror(errno)); > > > - err_status++; > > > - return; > > > - } else { > > > - if (parent->p_ino != statbuf.st_ino) { > > > - fprintf(stderr, > > > - _("inode-path for inode: %llu is incorrect - wrong parent inode#\n"), > > > - (unsigned long long) bstatp->bs_ino); > > > - if (verbose_flag) { > > > - fprintf(stderr, > > > - _("ino mismatch for path \"%s\" %llu vs %llu\n"), > > > - fullpath, > > > - (unsigned long long)parent->p_ino, > > > - (unsigned long long)statbuf.st_ino); > > > - } > > > - err_status++; > > > - return; > > > - } else { > > > - if (verbose_flag > 1) { > > > - printf(_("parent ino match for %llu\n"), > > > - (unsigned long long) parent->p_ino); > > > - } > > > - } > > > - } > > > -} > > > - > > > -static void > > > -check_parents(parent_t *parentbuf, size_t *parentbuf_size, > > > - jdm_fshandle_t *fshandlep, xfs_bstat_t *statp) > > > -{ > > > - int error, i; > > > - __u32 count; > > > - parent_t *entryp; > > > - > > > - do { > > > - error = jdm_parentpaths(fshandlep, statp, parentbuf, *parentbuf_size, &count); > > > - > > > - if (error == ERANGE) { > > > - *parentbuf_size *= 2; > > > - parentbuf = (parent_t *)realloc(parentbuf, *parentbuf_size); > > > - } else if (error) { > > > - fprintf(stderr, _("parentpaths failed for ino %llu: %s\n"), > > > - (unsigned long long) statp->bs_ino, > > > - strerror(errno)); > > > - err_status++; > > > - break; > > > - } > > > - } while (error == ERANGE); > > > - > > > - > > > - if (count == 0) { > > > - /* no links for inode - something wrong here */ > > > - fprintf(stderr, _("inode-path for inode: %llu is missing\n"), > > > - (unsigned long long) statp->bs_ino); > > > - err_status++; > > > - } > > > - > > > - entryp = parentbuf; > > > - for (i = 0; i < count; i++) { > > > - check_parent_entry(statp, entryp); > > > - entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); > > > - } > > > -} > > > - > > > static int > > > -do_bulkstat(parent_t *parentbuf, size_t *parentbuf_size, xfs_bstat_t *bstatbuf, > > > - int fsfd, jdm_fshandle_t *fshandlep) > > > +pptr_print( > > > + struct xfs_pptr_info *pi, > > > + struct xfs_parent_ptr *pptr, > > > + void *arg) > > > { > > > - __s32 buflenout; > > > - __u64 lastino = 0; > > > - xfs_bstat_t *p; > > > - xfs_bstat_t *endp; > > > - xfs_fsop_bulkreq_t bulkreq; > > > - struct stat mntstat; > > > + char buf[XFS_PPTR_MAXNAMELEN + 1]; > > > - if (stat(mntpt, &mntstat)) { > > > - fprintf(stderr, _("can't stat mount point \"%s\": %s\n"), > > > - mntpt, strerror(errno)); > > > - return 1; > > > + if (pi->pi_flags & XFS_PPTR_OFLAG_ROOT) { > > > + printf(_("Root directory.\n")); > > > + return 0; > > > } > > > - bulkreq.lastip = &lastino; > > > - bulkreq.icount = BSTATBUF_SZ; > > > - bulkreq.ubuffer = (void *)bstatbuf; > > > - bulkreq.ocount = &buflenout; > > > - > > > - while (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT, &bulkreq) == 0) { > > > - if (*(bulkreq.ocount) == 0) { > > > - return 0; > > > - } > > > - for (p = bstatbuf, endp = bstatbuf + *bulkreq.ocount; p < endp; p++) { > > > - > > > - /* inode being modified, get synced data with iget */ > > > - if ( (!p->bs_nlink || !p->bs_mode) && p->bs_ino != 0 ) { > > > - > > > - if (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) < 0) { > > > - fprintf(stderr, > > > - _("failed to get bulkstat information for inode %llu\n"), > > > - (unsigned long long) p->bs_ino); > > > - continue; > > > - } > > > - if (!p->bs_nlink || !p->bs_mode || !p->bs_ino) { > > > - fprintf(stderr, > > > - _("failed to get valid bulkstat information for inode %llu\n"), > > > - (unsigned long long) p->bs_ino); > > > - continue; > > > - } > > > - } > > > - > > > - /* skip root */ > > > - if (p->bs_ino == mntstat.st_ino) { > > > - continue; > > > - } > > > - > > > - if (verbose_flag > 1) { > > > - printf(_("checking inode %llu\n"), > > > - (unsigned long long) p->bs_ino); > > > - } > > > - > > > - /* print dotted progress */ > > > - if ((inodes_checked % 100) == 0 && verbose_flag == 1) { > > > - printf("."); fflush(stdout); > > > - } > > > - inodes_checked++; > > > - > > > - check_parents(parentbuf, parentbuf_size, fshandlep, p); > > > - } > > > - > > > - }/*while*/ > > > - > > > - fprintf(stderr, _("syssgi bulkstat failed: %s\n"), strerror(errno)); > > > - return 1; > > > + memcpy(buf, pptr->xpp_name, pptr->xpp_namelen); > > > + buf[pptr->xpp_namelen] = 0; > > > + printf(_("p_ino = %llu\n"), (unsigned long long)pptr->xpp_ino); > > > + printf(_("p_gen = %u\n"), (unsigned int)pptr->xpp_gen); > > > + printf(_("p_reclen = %u\n"), (unsigned int)pptr->xpp_namelen); > > > + printf(_("p_name = \"%s\"\n\n"), buf); > > > + return 0; > > > } > > > -static int > > > -parent_check(void) > > > +int > > > +print_parents( > > > + struct xfs_handle *handle) > > > { > > > - int fsfd; > > > - jdm_fshandle_t *fshandlep; > > > - parent_t *parentbuf; > > > - size_t parentbuf_size = PARENTBUF_SZ; > > > - xfs_bstat_t *bstatbuf; > > > - > > > - err_status = 0; > > > - inodes_checked = 0; > > > - > > > - sync(); > > > - > > > - fsfd = file->fd; > > > - > > > - fshandlep = jdm_getfshandle(mntpt); > > > - if (fshandlep == NULL) { > > > - fprintf(stderr, _("unable to open \"%s\" for jdm: %s\n"), > > > - mntpt, > > > - strerror(errno)); > > > - return 1; > > > - } > > > - > > > - /* allocate buffers */ > > > - bstatbuf = (xfs_bstat_t *)calloc(BSTATBUF_SZ, sizeof(xfs_bstat_t)); > > > - parentbuf = (parent_t *)malloc(parentbuf_size); > > > - if (!bstatbuf || !parentbuf) { > > > - fprintf(stderr, _("unable to allocate buffers: %s\n"), > > > - strerror(errno)); > > > - err_status = 1; > > > - goto out; > > > - } > > > + int ret; > > > - if (do_bulkstat(parentbuf, &parentbuf_size, bstatbuf, fsfd, fshandlep) != 0) > > > - err_status++; > > > - > > > - if (err_status > 0) > > > - fprintf(stderr, _("num errors: %d\n"), err_status); > > > + if (handle) > > > + ret = handle_walk_pptrs(handle, sizeof(*handle), pptr_print, > > > + NULL); > > > else > > > - printf(_("succeeded checking %llu inodes\n"), > > > - (unsigned long long) inodes_checked); > > > - > > > -out: > > > - free(bstatbuf); > > > - free(parentbuf); > > > - free(fshandlep); > > > - return err_status; > > > -} > > > + ret = fd_walk_pptrs(file->fd, pptr_print, NULL); > > > + if (ret) > > > + perror(file->name); > > > -static void > > > -print_parent_entry(parent_t *parent, int fullpath) > > > -{ > > > - printf(_("p_ino = %llu\n"), (unsigned long long) parent->p_ino); > > > - printf(_("p_gen = %u\n"), parent->p_gen); > > > - printf(_("p_reclen = %u\n"), parent->p_reclen); > > > - if (fullpath) > > > - printf(_("p_name = \"%s%s\"\n"), mntpt, > > > - ((char*)parent)+sizeof(struct parent)); > > > - else > > > - printf(_("p_name = \"%s\"\n"), > > > - ((char*)parent)+sizeof(struct parent)); > > > + return 0; > > > } > > > static int > > > -parent_list(int fullpath) > > > -{ > > > - void *handlep = NULL; > > > - size_t handlen; > > > - int error, i; > > > - int retval = 1; > > > - __u32 count; > > > - parent_t *entryp; > > > - parent_t *parentbuf = NULL; > > > - char *path = file->name; > > > - int pb_size = PARENTBUF_SZ; > > > - > > > - /* XXXX for linux libhandle version - to set libhandle fsfd cache */ > > > - { > > > - void *fshandle; > > > - size_t fshlen; > > > - > > > - if (path_to_fshandle(mntpt, &fshandle, &fshlen) != 0) { > > > - fprintf(stderr, _("%s: failed path_to_fshandle \"%s\": %s\n"), > > > - progname, path, strerror(errno)); > > > - goto error; > > > - } > > > - free_handle(fshandle, fshlen); > > > - } > > > - > > > - if (path_to_handle(path, &handlep, &handlen) != 0) { > > > - fprintf(stderr, _("%s: path_to_handle failed for \"%s\"\n"), progname, path); > > > - goto error; > > > - } > > > - > > > - do { > > > - parentbuf = (parent_t *)realloc(parentbuf, pb_size); > > > - if (!parentbuf) { > > > - fprintf(stderr, _("%s: unable to allocate parent buffer: %s\n"), > > > - progname, strerror(errno)); > > > - goto error; > > > - } > > > +path_print( > > > + const char *mntpt, > > > + struct path_list *path, > > > + void *arg) { > > > - if (fullpath) { > > > - error = parentpaths_by_handle(handlep, > > > - handlen, > > > - parentbuf, > > > - pb_size, > > > - &count); > > > - } else { > > > - error = parents_by_handle(handlep, > > > - handlen, > > > - parentbuf, > > > - pb_size, > > > - &count); > > > - } > > > - if (error == ERANGE) { > > > - pb_size *= 2; > > > - } else if (error) { > > > - fprintf(stderr, _("%s: %s call failed for \"%s\": %s\n"), > > > - progname, fullpath ? "parentpaths" : "parents", > > > - path, strerror(errno)); > > > - goto error; > > > - } > > > - } while (error == ERANGE); > > > + char buf[PATH_MAX]; > > > + size_t len = PATH_MAX; > > > + int ret; > > > - if (count == 0) { > > > - /* no links for inode - something wrong here */ > > > - fprintf(stderr, _("%s: inode-path is missing\n"), progname); > > > - goto error; > > > + ret = snprintf(buf, len, "%s", mntpt); > > > + if (ret != strlen(mntpt)) { > > > + errno = ENOMEM; > > > + return -1; > > > } > > > - entryp = parentbuf; > > > - for (i = 0; i < count; i++) { > > > - print_parent_entry(entryp, fullpath); > > > - entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); > > > - } > > > + ret = path_list_to_string(path, buf + ret, len - ret); > > > + if (ret < 0) > > > + return ret; > > > + return 0; > > > +} > > > - retval = 0; > > > -error: > > > - free(handlep); > > > - free(parentbuf); > > > - return retval; > > > +int > > > +print_paths( > > > + struct xfs_handle *handle) > > > +{ > > > + int ret; > > > + > > > + if (handle) > > > + ret = handle_walk_ppaths(handle, sizeof(*handle), path_print, > > > + NULL); > > > + else > > > + ret = fd_walk_ppaths(file->fd, path_print, NULL); > > > + if (ret) > > > + perror(file->name); > > > + return 0; > > > } > > > int > > > -parent_f(int argc, char **argv) > > > +parent_f( > > > + int argc, > > > + char **argv) > > > { > > > - int c; > > > - int listpath_flag = 0; > > > - int check_flag = 0; > > > - fs_path_t *fs; > > > - static int tab_init; > > > + struct xfs_handle handle; > > > + void *hanp = NULL; > > > + size_t hlen; > > > + struct fs_path *fs; > > > + char *p; > > > + uint64_t ino = 0; > > > + uint32_t gen = 0; > > > + int c; > > > + int listpath_flag = 0; > > > + int ret; > > > + static int tab_init; > > > if (!tab_init) { > > > tab_init = 1; > > > @@ -394,46 +133,72 @@ parent_f(int argc, char **argv) > > > } > > > mntpt = fs->fs_dir; > > > - verbose_flag = 0; > > > - > > > - while ((c = getopt(argc, argv, "cpv")) != EOF) { > > > + while ((c = getopt(argc, argv, "p")) != EOF) { > > > switch (c) { > > > - case 'c': > > > - check_flag = 1; > > > - break; > > > case 'p': > > > listpath_flag = 1; > > > break; > > > - case 'v': > > > - verbose_flag++; > > > - break; > > > default: > > > return command_usage(&parent_cmd); > > > } > > > } > > > - if (!check_flag && !listpath_flag) /* default case */ > > > - exitcode = parent_list(listpath_flag); > > > - else { > > > - if (listpath_flag) > > > - exitcode = parent_list(listpath_flag); > > > - if (check_flag) > > > - exitcode = parent_check(); > > > + /* > > > + * Always initialize the fshandle table because we need it for > > > + * the ppaths functions to work. > > > + */ > > > + ret = path_to_fshandle((char *)mntpt, &hanp, &hlen); > > > + if (ret) { > > > + perror(mntpt); > > > + return 0; > > > + } > > > + > > > + if (optind + 2 == argc) { > > > + ino = strtoull(argv[optind], &p, 0); > > > + if (*p != '\0' || ino == 0) { > > > + fprintf(stderr, > > > + _("Bad inode number '%s'.\n"), > > > + argv[optind]); > > > + return 0; > > > + } > > > + gen = strtoul(argv[optind + 1], &p, 0); > > > + if (*p != '\0') { > > > + fprintf(stderr, > > > + _("Bad generation number '%s'.\n"), > > > + argv[optind + 1]); > > > + return 0; > > > + } > > > + > > > + memcpy(&handle, hanp, sizeof(handle)); > > > + handle.ha_fid.fid_len = sizeof(xfs_fid_t) - > > > + sizeof(handle.ha_fid.fid_len); > > > + handle.ha_fid.fid_pad = 0; > > > + handle.ha_fid.fid_ino = ino; > > > + handle.ha_fid.fid_gen = gen; > > > + > > > } > > > + if (listpath_flag) > > > + exitcode = print_paths(ino ? &handle : NULL); > > > + else > > > + exitcode = print_parents(ino ? &handle : NULL); > > > + > > > + if (hanp) > > > + free_handle(hanp, hlen); > > > + > > > return 0; > > > } > > > static void > > > parent_help(void) > > > { > > > - printf(_( > > > +printf(_( > > > "\n" > > > " list the current file's parents and their filenames\n" > > > "\n" > > > -" -c -- check the current file's file system for parent consistency\n" > > > -" -p -- list the current file's parents and their full paths\n" > > > -" -v -- verbose mode\n" > > > +" -p -- list the current file's paths up to the root\n" > > > +"\n" > > > +"If ino and gen are supplied, use them instead.\n" > > > "\n")); > > > } > > > @@ -444,9 +209,9 @@ parent_init(void) > > > parent_cmd.cfunc = parent_f; > > > parent_cmd.argmin = 0; > > > parent_cmd.argmax = -1; > > > - parent_cmd.args = _("[-cpv]"); > > > + parent_cmd.args = _("[-p] [ino gen]"); > > > parent_cmd.flags = CMD_NOMAP_OK; > > > - parent_cmd.oneline = _("print or check parent inodes"); > > > + parent_cmd.oneline = _("print parent inodes"); > > > parent_cmd.help = parent_help; > > > if (expert) > > > diff --git a/libfrog/paths.c b/libfrog/paths.c > > > index c7895e9..9fb0140 100644 > > > --- a/libfrog/paths.c > > > +++ b/libfrog/paths.c > > > @@ -27,6 +27,7 @@ > > > #include "path.h" > > > #include "input.h" > > > #include "project.h" > > > +#include "list.h" > > > #include <limits.h> > > > extern char *progname; > > > @@ -632,3 +633,138 @@ fs_table_insert_project_path( > > > exit(1); > > > } > > > } > > > + > > > + > > > +/* Structured path components. */ > > > + > > > +struct path_list { > > > + struct list_head p_head; > > > +}; > > > + > > > +struct path_component { > > > + struct list_head pc_list; > > > + char *pc_fname; > > > +}; > > > + > > > +/* Initialize a path component with a given name. */ > > > +struct path_component * > > > +path_component_init( > > > + const char *name) > > > +{ > > > + struct path_component *pc; > > > + > > > + pc = malloc(sizeof(struct path_component)); > > > + if (!pc) > > > + return NULL; > > > + INIT_LIST_HEAD(&pc->pc_list); > > > + pc->pc_fname = strdup(name); > > > + if (!pc->pc_fname) { > > > + free(pc); > > > + return NULL; > > > + } > > > + return pc; > > > +} > > > + > > > +/* Free a path component. */ > > > +void > > > +path_component_free( > > > + struct path_component *pc) > > > +{ > > > + free(pc->pc_fname); > > > + free(pc); > > > +} > > > + > > > +/* Change a path component's filename. */ > > > +int > > > +path_component_change( > > > + struct path_component *pc, > > > + void *name, > > > + size_t namelen) > > > +{ > > > + void *p; > > > + > > > + p = realloc(pc->pc_fname, namelen + 1); > > > + if (!p) > > > + return -1; > > > + pc->pc_fname = p; > > > + memcpy(pc->pc_fname, name, namelen); > > > + pc->pc_fname[namelen] = 0; > > > + return 0; > > > +} > > > + > > > +/* Initialize a pathname. */ > > > +struct path_list * > > > +path_list_init(void) > > > +{ > > > + struct path_list *path; > > > + > > > + path = malloc(sizeof(struct path_list)); > > > + if (!path) > > > + return NULL; > > > + INIT_LIST_HEAD(&path->p_head); > > > + return path; > > > +} > > > + > > > +/* Empty out a pathname. */ > > > +void > > > +path_list_free( > > > + struct path_list *path) > > > +{ > > > + struct path_component *pos; > > > + struct path_component *n; > > > + > > > + list_for_each_entry_safe(pos, n, &path->p_head, pc_list) { > > > + path_list_del_component(path, pos); > > > + path_component_free(pos); > > > + } > > > + free(path); > > > +} > > > + > > > +/* Add a parent component to a pathname. */ > > > +void > > > +path_list_add_parent_component( > > > + struct path_list *path, > > > + struct path_component *pc) > > > +{ > > > + list_add(&pc->pc_list, &path->p_head); > > > +} > > > + > > > +/* Add a component to a pathname. */ > > > +void > > > +path_list_add_component( > > > + struct path_list *path, > > > + struct path_component *pc) > > > +{ > > > + list_add_tail(&pc->pc_list, &path->p_head); > > > +} > > > + > > > +/* Remove a component from a pathname. */ > > > +void > > > +path_list_del_component( > > > + struct path_list *path, > > > + struct path_component *pc) > > > +{ > > > + list_del_init(&pc->pc_list); > > > +} > > > + > > > +/* Convert a pathname into a string. */ > > > +ssize_t > > > +path_list_to_string( > > > + struct path_list *path, > > > + char *buf, > > > + size_t buflen) > > > +{ > > > + struct path_component *pos; > > > + ssize_t bytes = 0; > > > + int ret; > > > + > > > + list_for_each_entry(pos, &path->p_head, pc_list) { > > > + ret = snprintf(buf, buflen, "/%s", pos->pc_fname); > > > + if (ret != 1 + strlen(pos->pc_fname)) > > > + return -1; > > > + bytes += ret; > > > + buf += ret; > > > + buflen -= ret; > > > + } > > > + return bytes; > > > +} > > > diff --git a/libhandle/Makefile b/libhandle/Makefile > > > index fe1a2af..d3cea41 100644 > > > --- a/libhandle/Makefile > > > +++ b/libhandle/Makefile > > > @@ -16,7 +16,7 @@ else > > > LTLDFLAGS += -Wl,--version-script,libhandle.sym > > > endif > > > -CFILES = handle.c jdm.c > > > +CFILES = handle.c jdm.c parent.c > > > LSRCFILES = libhandle.sym > > > default: ltdepend $(LTLIBRARY) > > > diff --git a/libhandle/handle.c b/libhandle/handle.c > > > index 878d14d..a70fa32 100644 > > > --- a/libhandle/handle.c > > > +++ b/libhandle/handle.c > > > @@ -41,7 +41,6 @@ typedef union { > > > } comarg_t; > > > static int obj_to_handle(char *, int, unsigned int, comarg_t, void**, size_t*); > > > -static int handle_to_fsfd(void *, char **); > > > static char *path_to_fspath(char *path); > > > @@ -214,8 +213,10 @@ handle_to_fshandle( > > > return 0; > > > } > > > -static int > > > -handle_to_fsfd(void *hanp, char **path) > > > +int > > > +handle_to_fsfd( > > > + void *hanp, > > > + char **path) > > > { > > > struct fdhash *fdhp; > > > diff --git a/libhandle/parent.c b/libhandle/parent.c > > > new file mode 100644 > > > index 0000000..f6be3bd > > > --- /dev/null > > > +++ b/libhandle/parent.c > > > @@ -0,0 +1,325 @@ > > > +/* > > > + * Copyright (C) 2017 Oracle. All Rights Reserved. > > > + * > > > + * Author: Darrick J. Wong <darrick.wong@oracle.com> > > > + * > > > + * This program is free software; you can redistribute it and/or > > > + * modify it under the terms of the GNU General Public License > > > + * as published by the Free Software Foundation; either version 2 > > > + * of the License, or (at your option) any later version. > > > + * > > > + * This program is distributed in the hope that it would be useful, > > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > > + * GNU General Public License for more details. > > > + * > > > + * You should have received a copy of the GNU General Public License > > > + * along with this program; if not, write the Free Software Foundation, > > > + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. > > > + */ > > > +#include "platform_defs.h" > > > +#include "xfs.h" > > > +#include "xfs_arch.h" > > > +#include "list.h" > > > +#include "path.h" > > > +#include "handle.h" > > > +#include "parent.h" > > > + > > > +/* Allocate a buffer large enough for some parent pointer records. */ > > > +static inline struct xfs_pptr_info * > > > +xfs_pptr_alloc( > > > + size_t nr_ptrs) > > > +{ > > > + struct xfs_pptr_info *pi; > > > + > > > + pi = malloc(XFS_PPTR_INFO_SIZEOF(nr_ptrs)); > > > + if (!pi) > > > + return NULL; > > > + memset(pi, 0, sizeof(struct xfs_pptr_info)); > > > + pi->pi_ptrs_size = nr_ptrs; > > > + return pi; > > > +} > > > + > > > +/* Walk all parents of the given file handle. */ > > > +static int > > > +handle_walk_parents( > > > + int fd, > > > + struct xfs_handle *handle, > > > + walk_pptr_fn fn, > > > + void *arg) > > > +{ > > > + struct xfs_pptr_info *pi; > > > + struct xfs_parent_ptr *p; > > > + unsigned int i; > > > + ssize_t ret = -1; > > > + > > > + pi = xfs_pptr_alloc(4); > > > + if (!pi) > > > + return -1; > > > + > > > + if (handle) { > > > + memcpy(&pi->pi_handle, handle, sizeof(struct xfs_handle)); > > > + pi->pi_flags = XFS_PPTR_IFLAG_HANDLE; > > > + } > > > + > > > + ret = ioctl(fd, XFS_IOC_GETPPOINTER, pi); > > > + while (!ret) { > > > + if (pi->pi_flags & XFS_PPTR_OFLAG_ROOT) { > > > + ret = fn(pi, NULL, arg); > > > + break; > > > + } > > > + if (pi->pi_ptrs_used == 0) > > > + break; > > > + for (i = 0; i < pi->pi_ptrs_used; i++) { > > > + p = XFS_PPINFO_TO_PP(pi, i); > > > + ret = fn(pi, p, arg); > > > + if (ret) > > > + goto out_pi; > > > + } > > > + ret = ioctl(fd, XFS_IOC_GETPPOINTER, pi); > > > + } > > > + > > > +out_pi: > > > + free(pi); > > > + return ret; > > > +} > > > + > > > +/* Walk all parent pointers of this handle. */ > > > +int > > > +handle_walk_pptrs( > > > + void *hanp, > > > + size_t hlen, > > > + walk_pptr_fn fn, > > > + void *arg) > > > +{ > > > + char *mntpt; > > > + int fd; > > > + > > > + if (hlen != sizeof(struct xfs_handle)) { > > > + errno = EINVAL; > > > + return -1; > > > + } > > > + > > > + fd = handle_to_fsfd(hanp, &mntpt); > > > + if (fd < 0) > > > + return -1; > > > + > > > + return handle_walk_parents(fd, hanp, fn, arg); > > > +} > > > + > > > +/* Walk all parent pointers of this fd. */ > > > +int > > > +fd_walk_pptrs( > > > + int fd, > > > + walk_pptr_fn fn, > > > + void *arg) > > > +{ > > > + return handle_walk_parents(fd, NULL, fn, arg); > > > +} > > > + > > > +struct walk_ppaths_info { > > > + walk_ppath_fn fn; > > > + void *arg; > > > + char *mntpt; > > > + struct path_list *path; > > > + int fd; > > > +}; > > > + > > > +struct walk_ppath_level_info { > > > + struct xfs_handle newhandle; > > > + struct path_component *pc; > > > + struct walk_ppaths_info *wpi; > > > +}; > > > + > > > +static int handle_walk_parent_paths(struct walk_ppaths_info *wpi, > > > + struct xfs_handle *handle); > > > + > > > +static int > > > +handle_walk_parent_path_ptr( > > > + struct xfs_pptr_info *pi, > > > + struct xfs_parent_ptr *p, > > > + void *arg) > > > +{ > > > + struct walk_ppath_level_info *wpli = arg; > > > + struct walk_ppaths_info *wpi = wpli->wpi; > > > + unsigned int i; > > > + int ret = 0; > > > + > > > + if (pi->pi_flags & XFS_PPTR_OFLAG_ROOT) > > > + return wpi->fn(wpi->mntpt, wpi->path, wpi->arg); > > > + > > > + for (i = 0; i < pi->pi_ptrs_used; i++) { > > > + p = XFS_PPINFO_TO_PP(pi, i); > > > + ret = path_component_change(wpli->pc, p->xpp_name, > > > + p->xpp_namelen); > > > + if (ret) > > > + break; > > > + wpli->newhandle.ha_fid.fid_ino = p->xpp_ino; > > > + wpli->newhandle.ha_fid.fid_gen = p->xpp_gen; > > > + path_list_add_parent_component(wpi->path, wpli->pc); > > > + ret = handle_walk_parent_paths(wpi, &wpli->newhandle); > > > + path_list_del_component(wpi->path, wpli->pc); > > > + if (ret) > > > + break; > > > + } > > > + > > > + return ret; > > > +} > > > + > > > +/* > > > + * Recursively walk all parents of the given file handle; if we hit the > > > + * fs root then we call the associated function with the constructed path. > > > + */ > > > +static int > > > +handle_walk_parent_paths( > > > + struct walk_ppaths_info *wpi, > > > + struct xfs_handle *handle) > > > +{ > > > + struct walk_ppath_level_info *wpli; > > > + int ret; > > > + > > > + wpli = malloc(sizeof(struct walk_ppath_level_info)); > > > + if (!wpli) > > > + return -1; > > > + wpli->pc = path_component_init(""); > > > + if (!wpli->pc) { > > > + free(wpli); > > > + return -1; > > > + } > > > + wpli->wpi = wpi; > > > + memcpy(&wpli->newhandle, handle, sizeof(struct xfs_handle)); > > > + > > > + ret = handle_walk_parents(wpi->fd, handle, handle_walk_parent_path_ptr, > > > + wpli); > > > + > > > + path_component_free(wpli->pc); > > > + free(wpli); > > > + return ret; > > > +} > > > + > > > +/* > > > + * Call the given function on all known paths from the vfs root to the inode > > > + * described in the handle. > > > + */ > > > +int > > > +handle_walk_ppaths( > > > + void *hanp, > > > + size_t hlen, > > > + walk_ppath_fn fn, > > > + void *arg) > > > +{ > > > + struct walk_ppaths_info wpi; > > > + ssize_t ret; > > > + > > > + if (hlen != sizeof(struct xfs_handle)) { > > > + errno = EINVAL; > > > + return -1; > > > + } > > > + > > > + wpi.fd = handle_to_fsfd(hanp, &wpi.mntpt); > > > + if (wpi.fd < 0) > > > + return -1; > > > + wpi.path = path_list_init(); > > > + if (!wpi.path) > > > + return -1; > > > + wpi.fn = fn; > > > + wpi.arg = arg; > > > + > > > + ret = handle_walk_parent_paths(&wpi, hanp); > > > + path_list_free(wpi.path); > > > + > > > + return ret; > > > +} > > > + > > > +/* > > > + * Call the given function on all known paths from the vfs root to the inode > > > + * referred to by the file description. > > > + */ > > > +int > > > +fd_walk_ppaths( > > > + int fd, > > > + walk_ppath_fn fn, > > > + void *arg) > > > +{ > > > + struct walk_ppaths_info wpi; > > > + void *hanp; > > > + size_t hlen; > > > + int fsfd; > > > + int ret; > > > + > > > + ret = fd_to_handle(fd, &hanp, &hlen); > > > + if (ret) > > > + return ret; > > > + > > > + fsfd = handle_to_fsfd(hanp, &wpi.mntpt); > > > + if (fsfd < 0) > > > + return -1; > > > + wpi.fd = fd; > > > + wpi.path = path_list_init(); > > > + if (!wpi.path) > > > + return -1; > > > + wpi.fn = fn; > > > + wpi.arg = arg; > > > + > > > + ret = handle_walk_parent_paths(&wpi, hanp); > > > + path_list_free(wpi.path); > > > + > > > + return ret; > > > +} > > > + > > > +struct path_walk_info { > > > + char *buf; > > > + size_t len; > > > +}; > > > + > > > +/* Helper that stringifies the first full path that we find. */ > > > +static int > > > +handle_to_path_walk( > > > + const char *mntpt, > > > + struct path_list *path, > > > + void *arg) > > > +{ > > > + struct path_walk_info *pwi = arg; > > > + int ret; > > > + > > > + ret = snprintf(pwi->buf, pwi->len, "%s", mntpt); > > > + if (ret != strlen(mntpt)) { > > > + errno = ENOMEM; > > > + return -1; > > > + } > > > + > > > + ret = path_list_to_string(path, pwi->buf + ret, pwi->len - ret); > > > + if (ret < 0) > > > + return ret; > > > + > > > + return WALK_PPATHS_ABORT; > > > +} > > > + > > > +/* Return any eligible path to this file handle. */ > > > +int > > > +handle_to_path( > > > + void *hanp, > > > + size_t hlen, > > > + char *path, > > > + size_t pathlen) > > > +{ > > > + struct path_walk_info pwi; > > > + > > > + pwi.buf = path; > > > + pwi.len = pathlen; > > > + return handle_walk_ppaths(hanp, hlen, handle_to_path_walk, &pwi); > > > +} > > > + > > > +/* Return any eligible path to this file description. */ > > > +int > > > +fd_to_path( > > > + int fd, > > > + char *path, > > > + size_t pathlen) > > > +{ > > > + struct path_walk_info pwi; > > > + > > > + pwi.buf = path; > > > + pwi.len = pathlen; > > > + return fd_walk_ppaths(fd, handle_to_path_walk, &pwi); > > > +} > > > diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h > > > index e3ce233..aa613f9 100644 > > > --- a/libxfs/xfs_fs.h > > > +++ b/libxfs/xfs_fs.h > > > @@ -610,6 +610,14 @@ struct xfs_pptr_info { > > > #define XFS_PPINFO_TO_PP(info, idx) \ > > > (&(((struct xfs_parent_ptr *)((char *)(info) + sizeof(*(info))))[(idx)])) > > > +#define XFS_PPTR_ALL_IFLAGS (XFS_PPTR_IFLAG_HANDLE) > > > + > > > +/* partial results only */ > > > +#define XFS_PPTR_OFLAG_PARTIAL (1U << 0) > > > + > > > +/* target was the root directory */ > > > +#define XFS_PPTR_OFLAG_ROOT (1U << 1) > > > > Uhoh, I forgot about this chunk, which should be in the kernel patches > > somewhere I guess... > > > > --D > > > > Do we want to keep these? Should I add behavior of these in the kernel side > set? I don't even remember why OFLAG_PARTIAL exists, it can certainly go. OFLAG_ROOT is returned for the root directory so that callers can distinguish it from an unlinked inode (which also has no parents). --D > > Allison > > > > + > > > /* > > > * ioctl limits > > > */ > > > diff --git a/scrub/inodes.c b/scrub/inodes.c > > > index ccfb9e0..3fbcd1a 100644 > > > --- a/scrub/inodes.c > > > +++ b/scrub/inodes.c > > > @@ -31,6 +31,7 @@ > > > #include "xfs_scrub.h" > > > #include "common.h" > > > #include "inodes.h" > > > +#include "parent.h" > > > /* > > > * Iterate a range of inodes. > > > @@ -293,3 +294,28 @@ xfs_open_handle( > > > return open_by_fshandle(handle, sizeof(*handle), > > > O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NOCTTY); > > > } > > > + > > > +/* Construct a description for an inode. */ > > > +void > > > +xfs_scrub_ino_descr( > > > + struct scrub_ctx *ctx, > > > + struct xfs_handle *handle, > > > + char *buf, > > > + size_t buflen) > > > +{ > > > + uint64_t ino; > > > + xfs_agnumber_t agno; > > > + xfs_agino_t agino; > > > + int ret; > > > + > > > + ret = handle_to_path(handle, sizeof(struct xfs_handle), buf, buflen); > > > + if (ret >= 0) > > > + return; > > > + > > > + ino = handle->ha_fid.fid_ino; > > > + agno = ino / (1ULL << (ctx->inopblog + ctx->agblklog)); > > > + agino = ino % (1ULL << (ctx->inopblog + ctx->agblklog)); > > > + snprintf(buf, buflen, _("inode %"PRIu64" (%u/%u)"), ino, agno, > > > + agino); > > > +} > > > + > > > diff --git a/scrub/inodes.h b/scrub/inodes.h > > > index 693cb05..e94de0a 100644 > > > --- a/scrub/inodes.h > > > +++ b/scrub/inodes.h > > > @@ -28,5 +28,7 @@ bool xfs_scan_all_inodes(struct scrub_ctx *ctx, xfs_inode_iter_fn fn, > > > void *arg); > > > int xfs_open_handle(struct xfs_handle *handle); > > > +void xfs_scrub_ino_descr(struct scrub_ctx *ctx, struct xfs_handle *handle, > > > + char *buf, size_t buflen); > > > #endif /* XFS_SCRUB_INODES_H_ */ > > > diff --git a/scrub/phase5.c b/scrub/phase5.c > > > index 01038f7..ecaaaaa 100644 > > > --- a/scrub/phase5.c > > > +++ b/scrub/phase5.c > > > @@ -245,16 +245,11 @@ xfs_scrub_connections( > > > void *arg) > > > { > > > bool *pmoveon = arg; > > > - char descr[DESCR_BUFSZ]; > > > + char descr[PATH_MAX]; > > > bool moveon = true; > > > - xfs_agnumber_t agno; > > > - xfs_agino_t agino; > > > int fd = -1; > > > - agno = bstat->bs_ino / (1ULL << (ctx->inopblog + ctx->agblklog)); > > > - agino = bstat->bs_ino % (1ULL << (ctx->inopblog + ctx->agblklog)); > > > - snprintf(descr, DESCR_BUFSZ, _("inode %"PRIu64" (%u/%u)"), > > > - (uint64_t)bstat->bs_ino, agno, agino); > > > + xfs_scrub_ino_descr(ctx, handle, descr, PATH_MAX); > > > background_sleep(); > > > /* Warn about naming problems in xattrs. */ > > > -- > > > 2.7.4 > > > > > > -- > > > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in > > > the body of a message to majordomo@vger.kernel.org > > > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 05/08/2018 06:44 PM, Darrick J. Wong wrote: > >> On 05/08/2018 10:45 AM, Darrick J. Wong wrote: >>> On Mon, May 07, 2018 at 09:41:19PM -0700, Allison Henderson wrote: >>>> From: "Darrick J. Wong" <darrick.wong@oracle.com> >>>> >>>> Add ioctl definitions to libxfs, build the necessary helpers into >>>> libfrog and libhandle to iterate parents (and parent paths), then wire >>>> up xfs_scrub to be able to query parent pointers from userspace. The >>>> goal of this patch is to exercise userspace, and is nowhere near a >>>> complete solution. A basic xfs_io parent command implementation >>>> replaces ... whatever that is that's there now. >>>> >>>> Totally missing: actual support in libxfs for working with parent ptrs >>>> straight off the disk (mkfs, xfs_db, xfs_repair). >>>> >>>> [achender: Minor syntax adjustments to sew solution in actual support >>>> in libxfs for working with parent ptrs] >>>> >>>> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> >>>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com> >>>> --- >>>> include/handle.h | 2 + >>>> include/parent.h | 18 ++ >>>> include/path.h | 19 +++ >>>> io/parent.c | 471 ++++++++++++++--------------------------------------- >>>> libfrog/paths.c | 136 ++++++++++++++++ >>>> libhandle/Makefile | 2 +- >>>> libhandle/handle.c | 7 +- >>>> libhandle/parent.c | 325 ++++++++++++++++++++++++++++++++++++ >>>> libxfs/xfs_fs.h | 8 + >>>> scrub/inodes.c | 26 +++ >>>> scrub/inodes.h | 2 + >>>> scrub/phase5.c | 9 +- >>>> 12 files changed, 661 insertions(+), 364 deletions(-) >>>> >>>> diff --git a/include/handle.h b/include/handle.h >>>> index 49f1441..00aa43d 100644 >>>> --- a/include/handle.h >>>> +++ b/include/handle.h >>>> @@ -52,6 +52,8 @@ extern int fssetdm_by_handle (void *__hanp, size_t __hlen, >>>> void fshandle_destroy(void); >>>> +int handle_to_fsfd(void *hanp, char **path); >>>> + >>>> #ifdef __cplusplus >>>> } >>>> #endif >>>> diff --git a/include/parent.h b/include/parent.h >>>> index 85cef85..33f8d85 100644 >>>> --- a/include/parent.h >>>> +++ b/include/parent.h >>>> @@ -28,4 +28,22 @@ typedef struct parent_cursor { >>>> __u32 opaque[4]; /* an opaque cookie */ >>>> } parent_cursor_t; >>>> +struct path_list; >>>> + >>>> +typedef int (*walk_pptr_fn)(struct xfs_pptr_info *pi, struct xfs_parent_ptr *pptr, >>>> + void *arg); >>>> +typedef int (*walk_ppath_fn)(const char *mntpt, struct path_list *path, >>>> + void *arg); >>>> + >>>> +#define WALK_PPTRS_ABORT 1 >>>> +int fd_walk_pptrs(int fd, walk_pptr_fn fn, void *arg); >>>> +int handle_walk_pptrs(void *hanp, size_t hanlen, walk_pptr_fn fn, void *arg); >>>> + >>>> +#define WALK_PPATHS_ABORT 1 >>>> +int fd_walk_ppaths(int fd, walk_ppath_fn fn, void *arg); >>>> +int handle_walk_ppaths(void *hanp, size_t hanlen, walk_ppath_fn fn, void *arg); >>>> + >>>> +int fd_to_path(int fd, char *path, size_t pathlen); >>>> +int handle_to_path(void *hanp, size_t hlen, char *path, size_t pathlen); >>>> + >>>> #endif >>>> diff --git a/include/path.h b/include/path.h >>>> index 88dc44b..cbe4e19 100644 >>>> --- a/include/path.h >>>> +++ b/include/path.h >>>> @@ -70,4 +70,23 @@ typedef struct fs_cursor { >>>> extern void fs_cursor_initialise(char *__dir, uint __flags, fs_cursor_t *__cp); >>>> extern fs_path_t *fs_cursor_next_entry(fs_cursor_t *__cp); >>>> +/* Path information. */ >>>> + >>>> +struct path_list; >>>> +struct path_component; >>>> + >>>> +struct path_component *path_component_init(const char *name); >>>> +void path_component_free(struct path_component *pc); >>>> +int path_component_change(struct path_component *pc, void *name, >>>> + size_t namelen); >>>> + >>>> +struct path_list *path_list_init(void); >>>> +void path_list_free(struct path_list *path); >>>> +void path_list_add_parent_component(struct path_list *path, >>>> + struct path_component *pc); >>>> +void path_list_add_component(struct path_list *path, struct path_component *pc); >>>> +void path_list_del_component(struct path_list *path, struct path_component *pc); >>>> + >>>> +ssize_t path_list_to_string(struct path_list *path, char *buf, size_t buflen); >>>> + >>>> #endif /* __PATH_H__ */ >>>> diff --git a/io/parent.c b/io/parent.c >>>> index 55b8b49..ad51fe6 100644 >>>> --- a/io/parent.c >>>> +++ b/io/parent.c >>>> @@ -21,366 +21,105 @@ >>>> #include "path.h" >>>> #include "parent.h" >>>> #include "handle.h" >>>> -#include "jdm.h" >>>> #include "init.h" >>>> #include "io.h" >>>> -#define PARENTBUF_SZ 16384 >>>> -#define BSTATBUF_SZ 16384 >>>> - >>>> static cmdinfo_t parent_cmd; >>>> -static int verbose_flag; >>>> -static int err_status; >>>> -static __u64 inodes_checked; >>>> static char *mntpt; >>>> -/* >>>> - * check out a parent entry to see if the values seem valid >>>> - */ >>>> -static void >>>> -check_parent_entry(xfs_bstat_t *bstatp, parent_t *parent) >>>> -{ >>>> - int sts; >>>> - char fullpath[PATH_MAX]; >>>> - struct stat statbuf; >>>> - char *str; >>>> - >>>> - snprintf(fullpath, parent->p_reclen, _("%s%s"), mntpt, >>>> - ((char*)parent)+sizeof(struct parent)); >>>> - >>>> - sts = lstat(fullpath, &statbuf); >>>> - if (sts != 0) { >>>> - fprintf(stderr, >>>> - _("inode-path for inode: %llu is incorrect - path \"%s\" non-existent\n"), >>>> - (unsigned long long) bstatp->bs_ino, fullpath); >>>> - if (verbose_flag) { >>>> - fprintf(stderr, >>>> - _("path \"%s\" does not stat for inode: %llu; err = %s\n"), >>>> - fullpath, >>>> - (unsigned long long) bstatp->bs_ino, >>>> - strerror(errno)); >>>> - } >>>> - err_status++; >>>> - return; >>>> - } else { >>>> - if (verbose_flag > 1) { >>>> - printf(_("path \"%s\" found\n"), fullpath); >>>> - } >>>> - } >>>> - >>>> - if (statbuf.st_ino != bstatp->bs_ino) { >>>> - fprintf(stderr, >>>> - _("inode-path for inode: %llu is incorrect - wrong inode#\n"), >>>> - (unsigned long long) bstatp->bs_ino); >>>> - if (verbose_flag) { >>>> - fprintf(stderr, >>>> - _("ino mismatch for path \"%s\" %llu vs %llu\n"), >>>> - fullpath, >>>> - (unsigned long long)statbuf.st_ino, >>>> - (unsigned long long)bstatp->bs_ino); >>>> - } >>>> - err_status++; >>>> - return; >>>> - } else if (verbose_flag > 1) { >>>> - printf(_("inode number match: %llu\n"), >>>> - (unsigned long long)statbuf.st_ino); >>>> - } >>>> - >>>> - /* get parent path */ >>>> - str = strrchr(fullpath, '/'); >>>> - *str = '\0'; >>>> - sts = stat(fullpath, &statbuf); >>>> - if (sts != 0) { >>>> - fprintf(stderr, >>>> - _("parent path \"%s\" does not stat: %s\n"), >>>> - fullpath, >>>> - strerror(errno)); >>>> - err_status++; >>>> - return; >>>> - } else { >>>> - if (parent->p_ino != statbuf.st_ino) { >>>> - fprintf(stderr, >>>> - _("inode-path for inode: %llu is incorrect - wrong parent inode#\n"), >>>> - (unsigned long long) bstatp->bs_ino); >>>> - if (verbose_flag) { >>>> - fprintf(stderr, >>>> - _("ino mismatch for path \"%s\" %llu vs %llu\n"), >>>> - fullpath, >>>> - (unsigned long long)parent->p_ino, >>>> - (unsigned long long)statbuf.st_ino); >>>> - } >>>> - err_status++; >>>> - return; >>>> - } else { >>>> - if (verbose_flag > 1) { >>>> - printf(_("parent ino match for %llu\n"), >>>> - (unsigned long long) parent->p_ino); >>>> - } >>>> - } >>>> - } >>>> -} >>>> - >>>> -static void >>>> -check_parents(parent_t *parentbuf, size_t *parentbuf_size, >>>> - jdm_fshandle_t *fshandlep, xfs_bstat_t *statp) >>>> -{ >>>> - int error, i; >>>> - __u32 count; >>>> - parent_t *entryp; >>>> - >>>> - do { >>>> - error = jdm_parentpaths(fshandlep, statp, parentbuf, *parentbuf_size, &count); >>>> - >>>> - if (error == ERANGE) { >>>> - *parentbuf_size *= 2; >>>> - parentbuf = (parent_t *)realloc(parentbuf, *parentbuf_size); >>>> - } else if (error) { >>>> - fprintf(stderr, _("parentpaths failed for ino %llu: %s\n"), >>>> - (unsigned long long) statp->bs_ino, >>>> - strerror(errno)); >>>> - err_status++; >>>> - break; >>>> - } >>>> - } while (error == ERANGE); >>>> - >>>> - >>>> - if (count == 0) { >>>> - /* no links for inode - something wrong here */ >>>> - fprintf(stderr, _("inode-path for inode: %llu is missing\n"), >>>> - (unsigned long long) statp->bs_ino); >>>> - err_status++; >>>> - } >>>> - >>>> - entryp = parentbuf; >>>> - for (i = 0; i < count; i++) { >>>> - check_parent_entry(statp, entryp); >>>> - entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); >>>> - } >>>> -} >>>> - >>>> static int >>>> -do_bulkstat(parent_t *parentbuf, size_t *parentbuf_size, xfs_bstat_t *bstatbuf, >>>> - int fsfd, jdm_fshandle_t *fshandlep) >>>> +pptr_print( >>>> + struct xfs_pptr_info *pi, >>>> + struct xfs_parent_ptr *pptr, >>>> + void *arg) >>>> { >>>> - __s32 buflenout; >>>> - __u64 lastino = 0; >>>> - xfs_bstat_t *p; >>>> - xfs_bstat_t *endp; >>>> - xfs_fsop_bulkreq_t bulkreq; >>>> - struct stat mntstat; >>>> + char buf[XFS_PPTR_MAXNAMELEN + 1]; >>>> - if (stat(mntpt, &mntstat)) { >>>> - fprintf(stderr, _("can't stat mount point \"%s\": %s\n"), >>>> - mntpt, strerror(errno)); >>>> - return 1; >>>> + if (pi->pi_flags & XFS_PPTR_OFLAG_ROOT) { >>>> + printf(_("Root directory.\n")); >>>> + return 0; >>>> } >>>> - bulkreq.lastip = &lastino; >>>> - bulkreq.icount = BSTATBUF_SZ; >>>> - bulkreq.ubuffer = (void *)bstatbuf; >>>> - bulkreq.ocount = &buflenout; >>>> - >>>> - while (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT, &bulkreq) == 0) { >>>> - if (*(bulkreq.ocount) == 0) { >>>> - return 0; >>>> - } >>>> - for (p = bstatbuf, endp = bstatbuf + *bulkreq.ocount; p < endp; p++) { >>>> - >>>> - /* inode being modified, get synced data with iget */ >>>> - if ( (!p->bs_nlink || !p->bs_mode) && p->bs_ino != 0 ) { >>>> - >>>> - if (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) < 0) { >>>> - fprintf(stderr, >>>> - _("failed to get bulkstat information for inode %llu\n"), >>>> - (unsigned long long) p->bs_ino); >>>> - continue; >>>> - } >>>> - if (!p->bs_nlink || !p->bs_mode || !p->bs_ino) { >>>> - fprintf(stderr, >>>> - _("failed to get valid bulkstat information for inode %llu\n"), >>>> - (unsigned long long) p->bs_ino); >>>> - continue; >>>> - } >>>> - } >>>> - >>>> - /* skip root */ >>>> - if (p->bs_ino == mntstat.st_ino) { >>>> - continue; >>>> - } >>>> - >>>> - if (verbose_flag > 1) { >>>> - printf(_("checking inode %llu\n"), >>>> - (unsigned long long) p->bs_ino); >>>> - } >>>> - >>>> - /* print dotted progress */ >>>> - if ((inodes_checked % 100) == 0 && verbose_flag == 1) { >>>> - printf("."); fflush(stdout); >>>> - } >>>> - inodes_checked++; >>>> - >>>> - check_parents(parentbuf, parentbuf_size, fshandlep, p); >>>> - } >>>> - >>>> - }/*while*/ >>>> - >>>> - fprintf(stderr, _("syssgi bulkstat failed: %s\n"), strerror(errno)); >>>> - return 1; >>>> + memcpy(buf, pptr->xpp_name, pptr->xpp_namelen); >>>> + buf[pptr->xpp_namelen] = 0; >>>> + printf(_("p_ino = %llu\n"), (unsigned long long)pptr->xpp_ino); >>>> + printf(_("p_gen = %u\n"), (unsigned int)pptr->xpp_gen); >>>> + printf(_("p_reclen = %u\n"), (unsigned int)pptr->xpp_namelen); >>>> + printf(_("p_name = \"%s\"\n\n"), buf); >>>> + return 0; >>>> } >>>> -static int >>>> -parent_check(void) >>>> +int >>>> +print_parents( >>>> + struct xfs_handle *handle) >>>> { >>>> - int fsfd; >>>> - jdm_fshandle_t *fshandlep; >>>> - parent_t *parentbuf; >>>> - size_t parentbuf_size = PARENTBUF_SZ; >>>> - xfs_bstat_t *bstatbuf; >>>> - >>>> - err_status = 0; >>>> - inodes_checked = 0; >>>> - >>>> - sync(); >>>> - >>>> - fsfd = file->fd; >>>> - >>>> - fshandlep = jdm_getfshandle(mntpt); >>>> - if (fshandlep == NULL) { >>>> - fprintf(stderr, _("unable to open \"%s\" for jdm: %s\n"), >>>> - mntpt, >>>> - strerror(errno)); >>>> - return 1; >>>> - } >>>> - >>>> - /* allocate buffers */ >>>> - bstatbuf = (xfs_bstat_t *)calloc(BSTATBUF_SZ, sizeof(xfs_bstat_t)); >>>> - parentbuf = (parent_t *)malloc(parentbuf_size); >>>> - if (!bstatbuf || !parentbuf) { >>>> - fprintf(stderr, _("unable to allocate buffers: %s\n"), >>>> - strerror(errno)); >>>> - err_status = 1; >>>> - goto out; >>>> - } >>>> + int ret; >>>> - if (do_bulkstat(parentbuf, &parentbuf_size, bstatbuf, fsfd, fshandlep) != 0) >>>> - err_status++; >>>> - >>>> - if (err_status > 0) >>>> - fprintf(stderr, _("num errors: %d\n"), err_status); >>>> + if (handle) >>>> + ret = handle_walk_pptrs(handle, sizeof(*handle), pptr_print, >>>> + NULL); >>>> else >>>> - printf(_("succeeded checking %llu inodes\n"), >>>> - (unsigned long long) inodes_checked); >>>> - >>>> -out: >>>> - free(bstatbuf); >>>> - free(parentbuf); >>>> - free(fshandlep); >>>> - return err_status; >>>> -} >>>> + ret = fd_walk_pptrs(file->fd, pptr_print, NULL); >>>> + if (ret) >>>> + perror(file->name); >>>> -static void >>>> -print_parent_entry(parent_t *parent, int fullpath) >>>> -{ >>>> - printf(_("p_ino = %llu\n"), (unsigned long long) parent->p_ino); >>>> - printf(_("p_gen = %u\n"), parent->p_gen); >>>> - printf(_("p_reclen = %u\n"), parent->p_reclen); >>>> - if (fullpath) >>>> - printf(_("p_name = \"%s%s\"\n"), mntpt, >>>> - ((char*)parent)+sizeof(struct parent)); >>>> - else >>>> - printf(_("p_name = \"%s\"\n"), >>>> - ((char*)parent)+sizeof(struct parent)); >>>> + return 0; >>>> } >>>> static int >>>> -parent_list(int fullpath) >>>> -{ >>>> - void *handlep = NULL; >>>> - size_t handlen; >>>> - int error, i; >>>> - int retval = 1; >>>> - __u32 count; >>>> - parent_t *entryp; >>>> - parent_t *parentbuf = NULL; >>>> - char *path = file->name; >>>> - int pb_size = PARENTBUF_SZ; >>>> - >>>> - /* XXXX for linux libhandle version - to set libhandle fsfd cache */ >>>> - { >>>> - void *fshandle; >>>> - size_t fshlen; >>>> - >>>> - if (path_to_fshandle(mntpt, &fshandle, &fshlen) != 0) { >>>> - fprintf(stderr, _("%s: failed path_to_fshandle \"%s\": %s\n"), >>>> - progname, path, strerror(errno)); >>>> - goto error; >>>> - } >>>> - free_handle(fshandle, fshlen); >>>> - } >>>> - >>>> - if (path_to_handle(path, &handlep, &handlen) != 0) { >>>> - fprintf(stderr, _("%s: path_to_handle failed for \"%s\"\n"), progname, path); >>>> - goto error; >>>> - } >>>> - >>>> - do { >>>> - parentbuf = (parent_t *)realloc(parentbuf, pb_size); >>>> - if (!parentbuf) { >>>> - fprintf(stderr, _("%s: unable to allocate parent buffer: %s\n"), >>>> - progname, strerror(errno)); >>>> - goto error; >>>> - } >>>> +path_print( >>>> + const char *mntpt, >>>> + struct path_list *path, >>>> + void *arg) { >>>> - if (fullpath) { >>>> - error = parentpaths_by_handle(handlep, >>>> - handlen, >>>> - parentbuf, >>>> - pb_size, >>>> - &count); >>>> - } else { >>>> - error = parents_by_handle(handlep, >>>> - handlen, >>>> - parentbuf, >>>> - pb_size, >>>> - &count); >>>> - } >>>> - if (error == ERANGE) { >>>> - pb_size *= 2; >>>> - } else if (error) { >>>> - fprintf(stderr, _("%s: %s call failed for \"%s\": %s\n"), >>>> - progname, fullpath ? "parentpaths" : "parents", >>>> - path, strerror(errno)); >>>> - goto error; >>>> - } >>>> - } while (error == ERANGE); >>>> + char buf[PATH_MAX]; >>>> + size_t len = PATH_MAX; >>>> + int ret; >>>> - if (count == 0) { >>>> - /* no links for inode - something wrong here */ >>>> - fprintf(stderr, _("%s: inode-path is missing\n"), progname); >>>> - goto error; >>>> + ret = snprintf(buf, len, "%s", mntpt); >>>> + if (ret != strlen(mntpt)) { >>>> + errno = ENOMEM; >>>> + return -1; >>>> } >>>> - entryp = parentbuf; >>>> - for (i = 0; i < count; i++) { >>>> - print_parent_entry(entryp, fullpath); >>>> - entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); >>>> - } >>>> + ret = path_list_to_string(path, buf + ret, len - ret); >>>> + if (ret < 0) >>>> + return ret; >>>> + return 0; >>>> +} >>>> - retval = 0; >>>> -error: >>>> - free(handlep); >>>> - free(parentbuf); >>>> - return retval; >>>> +int >>>> +print_paths( >>>> + struct xfs_handle *handle) >>>> +{ >>>> + int ret; >>>> + >>>> + if (handle) >>>> + ret = handle_walk_ppaths(handle, sizeof(*handle), path_print, >>>> + NULL); >>>> + else >>>> + ret = fd_walk_ppaths(file->fd, path_print, NULL); >>>> + if (ret) >>>> + perror(file->name); >>>> + return 0; >>>> } >>>> int >>>> -parent_f(int argc, char **argv) >>>> +parent_f( >>>> + int argc, >>>> + char **argv) >>>> { >>>> - int c; >>>> - int listpath_flag = 0; >>>> - int check_flag = 0; >>>> - fs_path_t *fs; >>>> - static int tab_init; >>>> + struct xfs_handle handle; >>>> + void *hanp = NULL; >>>> + size_t hlen; >>>> + struct fs_path *fs; >>>> + char *p; >>>> + uint64_t ino = 0; >>>> + uint32_t gen = 0; >>>> + int c; >>>> + int listpath_flag = 0; >>>> + int ret; >>>> + static int tab_init; >>>> if (!tab_init) { >>>> tab_init = 1; >>>> @@ -394,46 +133,72 @@ parent_f(int argc, char **argv) >>>> } >>>> mntpt = fs->fs_dir; >>>> - verbose_flag = 0; >>>> - >>>> - while ((c = getopt(argc, argv, "cpv")) != EOF) { >>>> + while ((c = getopt(argc, argv, "p")) != EOF) { >>>> switch (c) { >>>> - case 'c': >>>> - check_flag = 1; >>>> - break; >>>> case 'p': >>>> listpath_flag = 1; >>>> break; >>>> - case 'v': >>>> - verbose_flag++; >>>> - break; >>>> default: >>>> return command_usage(&parent_cmd); >>>> } >>>> } >>>> - if (!check_flag && !listpath_flag) /* default case */ >>>> - exitcode = parent_list(listpath_flag); >>>> - else { >>>> - if (listpath_flag) >>>> - exitcode = parent_list(listpath_flag); >>>> - if (check_flag) >>>> - exitcode = parent_check(); >>>> + /* >>>> + * Always initialize the fshandle table because we need it for >>>> + * the ppaths functions to work. >>>> + */ >>>> + ret = path_to_fshandle((char *)mntpt, &hanp, &hlen); >>>> + if (ret) { >>>> + perror(mntpt); >>>> + return 0; >>>> + } >>>> + >>>> + if (optind + 2 == argc) { >>>> + ino = strtoull(argv[optind], &p, 0); >>>> + if (*p != '\0' || ino == 0) { >>>> + fprintf(stderr, >>>> + _("Bad inode number '%s'.\n"), >>>> + argv[optind]); >>>> + return 0; >>>> + } >>>> + gen = strtoul(argv[optind + 1], &p, 0); >>>> + if (*p != '\0') { >>>> + fprintf(stderr, >>>> + _("Bad generation number '%s'.\n"), >>>> + argv[optind + 1]); >>>> + return 0; >>>> + } >>>> + >>>> + memcpy(&handle, hanp, sizeof(handle)); >>>> + handle.ha_fid.fid_len = sizeof(xfs_fid_t) - >>>> + sizeof(handle.ha_fid.fid_len); >>>> + handle.ha_fid.fid_pad = 0; >>>> + handle.ha_fid.fid_ino = ino; >>>> + handle.ha_fid.fid_gen = gen; >>>> + >>>> } >>>> + if (listpath_flag) >>>> + exitcode = print_paths(ino ? &handle : NULL); >>>> + else >>>> + exitcode = print_parents(ino ? &handle : NULL); >>>> + >>>> + if (hanp) >>>> + free_handle(hanp, hlen); >>>> + >>>> return 0; >>>> } >>>> static void >>>> parent_help(void) >>>> { >>>> - printf(_( >>>> +printf(_( >>>> "\n" >>>> " list the current file's parents and their filenames\n" >>>> "\n" >>>> -" -c -- check the current file's file system for parent consistency\n" >>>> -" -p -- list the current file's parents and their full paths\n" >>>> -" -v -- verbose mode\n" >>>> +" -p -- list the current file's paths up to the root\n" >>>> +"\n" >>>> +"If ino and gen are supplied, use them instead.\n" >>>> "\n")); >>>> } >>>> @@ -444,9 +209,9 @@ parent_init(void) >>>> parent_cmd.cfunc = parent_f; >>>> parent_cmd.argmin = 0; >>>> parent_cmd.argmax = -1; >>>> - parent_cmd.args = _("[-cpv]"); >>>> + parent_cmd.args = _("[-p] [ino gen]"); >>>> parent_cmd.flags = CMD_NOMAP_OK; >>>> - parent_cmd.oneline = _("print or check parent inodes"); >>>> + parent_cmd.oneline = _("print parent inodes"); >>>> parent_cmd.help = parent_help; >>>> if (expert) >>>> diff --git a/libfrog/paths.c b/libfrog/paths.c >>>> index c7895e9..9fb0140 100644 >>>> --- a/libfrog/paths.c >>>> +++ b/libfrog/paths.c >>>> @@ -27,6 +27,7 @@ >>>> #include "path.h" >>>> #include "input.h" >>>> #include "project.h" >>>> +#include "list.h" >>>> #include <limits.h> >>>> extern char *progname; >>>> @@ -632,3 +633,138 @@ fs_table_insert_project_path( >>>> exit(1); >>>> } >>>> } >>>> + >>>> + >>>> +/* Structured path components. */ >>>> + >>>> +struct path_list { >>>> + struct list_head p_head; >>>> +}; >>>> + >>>> +struct path_component { >>>> + struct list_head pc_list; >>>> + char *pc_fname; >>>> +}; >>>> + >>>> +/* Initialize a path component with a given name. */ >>>> +struct path_component * >>>> +path_component_init( >>>> + const char *name) >>>> +{ >>>> + struct path_component *pc; >>>> + >>>> + pc = malloc(sizeof(struct path_component)); >>>> + if (!pc) >>>> + return NULL; >>>> + INIT_LIST_HEAD(&pc->pc_list); >>>> + pc->pc_fname = strdup(name); >>>> + if (!pc->pc_fname) { >>>> + free(pc); >>>> + return NULL; >>>> + } >>>> + return pc; >>>> +} >>>> + >>>> +/* Free a path component. */ >>>> +void >>>> +path_component_free( >>>> + struct path_component *pc) >>>> +{ >>>> + free(pc->pc_fname); >>>> + free(pc); >>>> +} >>>> + >>>> +/* Change a path component's filename. */ >>>> +int >>>> +path_component_change( >>>> + struct path_component *pc, >>>> + void *name, >>>> + size_t namelen) >>>> +{ >>>> + void *p; >>>> + >>>> + p = realloc(pc->pc_fname, namelen + 1); >>>> + if (!p) >>>> + return -1; >>>> + pc->pc_fname = p; >>>> + memcpy(pc->pc_fname, name, namelen); >>>> + pc->pc_fname[namelen] = 0; >>>> + return 0; >>>> +} >>>> + >>>> +/* Initialize a pathname. */ >>>> +struct path_list * >>>> +path_list_init(void) >>>> +{ >>>> + struct path_list *path; >>>> + >>>> + path = malloc(sizeof(struct path_list)); >>>> + if (!path) >>>> + return NULL; >>>> + INIT_LIST_HEAD(&path->p_head); >>>> + return path; >>>> +} >>>> + >>>> +/* Empty out a pathname. */ >>>> +void >>>> +path_list_free( >>>> + struct path_list *path) >>>> +{ >>>> + struct path_component *pos; >>>> + struct path_component *n; >>>> + >>>> + list_for_each_entry_safe(pos, n, &path->p_head, pc_list) { >>>> + path_list_del_component(path, pos); >>>> + path_component_free(pos); >>>> + } >>>> + free(path); >>>> +} >>>> + >>>> +/* Add a parent component to a pathname. */ >>>> +void >>>> +path_list_add_parent_component( >>>> + struct path_list *path, >>>> + struct path_component *pc) >>>> +{ >>>> + list_add(&pc->pc_list, &path->p_head); >>>> +} >>>> + >>>> +/* Add a component to a pathname. */ >>>> +void >>>> +path_list_add_component( >>>> + struct path_list *path, >>>> + struct path_component *pc) >>>> +{ >>>> + list_add_tail(&pc->pc_list, &path->p_head); >>>> +} >>>> + >>>> +/* Remove a component from a pathname. */ >>>> +void >>>> +path_list_del_component( >>>> + struct path_list *path, >>>> + struct path_component *pc) >>>> +{ >>>> + list_del_init(&pc->pc_list); >>>> +} >>>> + >>>> +/* Convert a pathname into a string. */ >>>> +ssize_t >>>> +path_list_to_string( >>>> + struct path_list *path, >>>> + char *buf, >>>> + size_t buflen) >>>> +{ >>>> + struct path_component *pos; >>>> + ssize_t bytes = 0; >>>> + int ret; >>>> + >>>> + list_for_each_entry(pos, &path->p_head, pc_list) { >>>> + ret = snprintf(buf, buflen, "/%s", pos->pc_fname); >>>> + if (ret != 1 + strlen(pos->pc_fname)) >>>> + return -1; >>>> + bytes += ret; >>>> + buf += ret; >>>> + buflen -= ret; >>>> + } >>>> + return bytes; >>>> +} >>>> diff --git a/libhandle/Makefile b/libhandle/Makefile >>>> index fe1a2af..d3cea41 100644 >>>> --- a/libhandle/Makefile >>>> +++ b/libhandle/Makefile >>>> @@ -16,7 +16,7 @@ else >>>> LTLDFLAGS += -Wl,--version-script,libhandle.sym >>>> endif >>>> -CFILES = handle.c jdm.c >>>> +CFILES = handle.c jdm.c parent.c >>>> LSRCFILES = libhandle.sym >>>> default: ltdepend $(LTLIBRARY) >>>> diff --git a/libhandle/handle.c b/libhandle/handle.c >>>> index 878d14d..a70fa32 100644 >>>> --- a/libhandle/handle.c >>>> +++ b/libhandle/handle.c >>>> @@ -41,7 +41,6 @@ typedef union { >>>> } comarg_t; >>>> static int obj_to_handle(char *, int, unsigned int, comarg_t, void**, size_t*); >>>> -static int handle_to_fsfd(void *, char **); >>>> static char *path_to_fspath(char *path); >>>> @@ -214,8 +213,10 @@ handle_to_fshandle( >>>> return 0; >>>> } >>>> -static int >>>> -handle_to_fsfd(void *hanp, char **path) >>>> +int >>>> +handle_to_fsfd( >>>> + void *hanp, >>>> + char **path) >>>> { >>>> struct fdhash *fdhp; >>>> diff --git a/libhandle/parent.c b/libhandle/parent.c >>>> new file mode 100644 >>>> index 0000000..f6be3bd >>>> --- /dev/null >>>> +++ b/libhandle/parent.c >>>> @@ -0,0 +1,325 @@ >>>> +/* >>>> + * Copyright (C) 2017 Oracle. All Rights Reserved. >>>> + * >>>> + * Author: Darrick J. Wong <darrick.wong@oracle.com> >>>> + * >>>> + * This program is free software; you can redistribute it and/or >>>> + * modify it under the terms of the GNU General Public License >>>> + * as published by the Free Software Foundation; either version 2 >>>> + * of the License, or (at your option) any later version. >>>> + * >>>> + * This program is distributed in the hope that it would be useful, >>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >>>> + * GNU General Public License for more details. >>>> + * >>>> + * You should have received a copy of the GNU General Public License >>>> + * along with this program; if not, write the Free Software Foundation, >>>> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. >>>> + */ >>>> +#include "platform_defs.h" >>>> +#include "xfs.h" >>>> +#include "xfs_arch.h" >>>> +#include "list.h" >>>> +#include "path.h" >>>> +#include "handle.h" >>>> +#include "parent.h" >>>> + >>>> +/* Allocate a buffer large enough for some parent pointer records. */ >>>> +static inline struct xfs_pptr_info * >>>> +xfs_pptr_alloc( >>>> + size_t nr_ptrs) >>>> +{ >>>> + struct xfs_pptr_info *pi; >>>> + >>>> + pi = malloc(XFS_PPTR_INFO_SIZEOF(nr_ptrs)); >>>> + if (!pi) >>>> + return NULL; >>>> + memset(pi, 0, sizeof(struct xfs_pptr_info)); >>>> + pi->pi_ptrs_size = nr_ptrs; >>>> + return pi; >>>> +} >>>> + >>>> +/* Walk all parents of the given file handle. */ >>>> +static int >>>> +handle_walk_parents( >>>> + int fd, >>>> + struct xfs_handle *handle, >>>> + walk_pptr_fn fn, >>>> + void *arg) >>>> +{ >>>> + struct xfs_pptr_info *pi; >>>> + struct xfs_parent_ptr *p; >>>> + unsigned int i; >>>> + ssize_t ret = -1; >>>> + >>>> + pi = xfs_pptr_alloc(4); >>>> + if (!pi) >>>> + return -1; >>>> + >>>> + if (handle) { >>>> + memcpy(&pi->pi_handle, handle, sizeof(struct xfs_handle)); >>>> + pi->pi_flags = XFS_PPTR_IFLAG_HANDLE; >>>> + } >>>> + >>>> + ret = ioctl(fd, XFS_IOC_GETPPOINTER, pi); >>>> + while (!ret) { >>>> + if (pi->pi_flags & XFS_PPTR_OFLAG_ROOT) { >>>> + ret = fn(pi, NULL, arg); >>>> + break; >>>> + } >>>> + if (pi->pi_ptrs_used == 0) >>>> + break; >>>> + for (i = 0; i < pi->pi_ptrs_used; i++) { >>>> + p = XFS_PPINFO_TO_PP(pi, i); >>>> + ret = fn(pi, p, arg); >>>> + if (ret) >>>> + goto out_pi; >>>> + } >>>> + ret = ioctl(fd, XFS_IOC_GETPPOINTER, pi); >>>> + } >>>> + >>>> +out_pi: >>>> + free(pi); >>>> + return ret; >>>> +} >>>> + >>>> +/* Walk all parent pointers of this handle. */ >>>> +int >>>> +handle_walk_pptrs( >>>> + void *hanp, >>>> + size_t hlen, >>>> + walk_pptr_fn fn, >>>> + void *arg) >>>> +{ >>>> + char *mntpt; >>>> + int fd; >>>> + >>>> + if (hlen != sizeof(struct xfs_handle)) { >>>> + errno = EINVAL; >>>> + return -1; >>>> + } >>>> + >>>> + fd = handle_to_fsfd(hanp, &mntpt); >>>> + if (fd < 0) >>>> + return -1; >>>> + >>>> + return handle_walk_parents(fd, hanp, fn, arg); >>>> +} >>>> + >>>> +/* Walk all parent pointers of this fd. */ >>>> +int >>>> +fd_walk_pptrs( >>>> + int fd, >>>> + walk_pptr_fn fn, >>>> + void *arg) >>>> +{ >>>> + return handle_walk_parents(fd, NULL, fn, arg); >>>> +} >>>> + >>>> +struct walk_ppaths_info { >>>> + walk_ppath_fn fn; >>>> + void *arg; >>>> + char *mntpt; >>>> + struct path_list *path; >>>> + int fd; >>>> +}; >>>> + >>>> +struct walk_ppath_level_info { >>>> + struct xfs_handle newhandle; >>>> + struct path_component *pc; >>>> + struct walk_ppaths_info *wpi; >>>> +}; >>>> + >>>> +static int handle_walk_parent_paths(struct walk_ppaths_info *wpi, >>>> + struct xfs_handle *handle); >>>> + >>>> +static int >>>> +handle_walk_parent_path_ptr( >>>> + struct xfs_pptr_info *pi, >>>> + struct xfs_parent_ptr *p, >>>> + void *arg) >>>> +{ >>>> + struct walk_ppath_level_info *wpli = arg; >>>> + struct walk_ppaths_info *wpi = wpli->wpi; >>>> + unsigned int i; >>>> + int ret = 0; >>>> + >>>> + if (pi->pi_flags & XFS_PPTR_OFLAG_ROOT) >>>> + return wpi->fn(wpi->mntpt, wpi->path, wpi->arg); >>>> + >>>> + for (i = 0; i < pi->pi_ptrs_used; i++) { >>>> + p = XFS_PPINFO_TO_PP(pi, i); >>>> + ret = path_component_change(wpli->pc, p->xpp_name, >>>> + p->xpp_namelen); >>>> + if (ret) >>>> + break; >>>> + wpli->newhandle.ha_fid.fid_ino = p->xpp_ino; >>>> + wpli->newhandle.ha_fid.fid_gen = p->xpp_gen; >>>> + path_list_add_parent_component(wpi->path, wpli->pc); >>>> + ret = handle_walk_parent_paths(wpi, &wpli->newhandle); >>>> + path_list_del_component(wpi->path, wpli->pc); >>>> + if (ret) >>>> + break; >>>> + } >>>> + >>>> + return ret; >>>> +} >>>> + >>>> +/* >>>> + * Recursively walk all parents of the given file handle; if we hit the >>>> + * fs root then we call the associated function with the constructed path. >>>> + */ >>>> +static int >>>> +handle_walk_parent_paths( >>>> + struct walk_ppaths_info *wpi, >>>> + struct xfs_handle *handle) >>>> +{ >>>> + struct walk_ppath_level_info *wpli; >>>> + int ret; >>>> + >>>> + wpli = malloc(sizeof(struct walk_ppath_level_info)); >>>> + if (!wpli) >>>> + return -1; >>>> + wpli->pc = path_component_init(""); >>>> + if (!wpli->pc) { >>>> + free(wpli); >>>> + return -1; >>>> + } >>>> + wpli->wpi = wpi; >>>> + memcpy(&wpli->newhandle, handle, sizeof(struct xfs_handle)); >>>> + >>>> + ret = handle_walk_parents(wpi->fd, handle, handle_walk_parent_path_ptr, >>>> + wpli); >>>> + >>>> + path_component_free(wpli->pc); >>>> + free(wpli); >>>> + return ret; >>>> +} >>>> + >>>> +/* >>>> + * Call the given function on all known paths from the vfs root to the inode >>>> + * described in the handle. >>>> + */ >>>> +int >>>> +handle_walk_ppaths( >>>> + void *hanp, >>>> + size_t hlen, >>>> + walk_ppath_fn fn, >>>> + void *arg) >>>> +{ >>>> + struct walk_ppaths_info wpi; >>>> + ssize_t ret; >>>> + >>>> + if (hlen != sizeof(struct xfs_handle)) { >>>> + errno = EINVAL; >>>> + return -1; >>>> + } >>>> + >>>> + wpi.fd = handle_to_fsfd(hanp, &wpi.mntpt); >>>> + if (wpi.fd < 0) >>>> + return -1; >>>> + wpi.path = path_list_init(); >>>> + if (!wpi.path) >>>> + return -1; >>>> + wpi.fn = fn; >>>> + wpi.arg = arg; >>>> + >>>> + ret = handle_walk_parent_paths(&wpi, hanp); >>>> + path_list_free(wpi.path); >>>> + >>>> + return ret; >>>> +} >>>> + >>>> +/* >>>> + * Call the given function on all known paths from the vfs root to the inode >>>> + * referred to by the file description. >>>> + */ >>>> +int >>>> +fd_walk_ppaths( >>>> + int fd, >>>> + walk_ppath_fn fn, >>>> + void *arg) >>>> +{ >>>> + struct walk_ppaths_info wpi; >>>> + void *hanp; >>>> + size_t hlen; >>>> + int fsfd; >>>> + int ret; >>>> + >>>> + ret = fd_to_handle(fd, &hanp, &hlen); >>>> + if (ret) >>>> + return ret; >>>> + >>>> + fsfd = handle_to_fsfd(hanp, &wpi.mntpt); >>>> + if (fsfd < 0) >>>> + return -1; >>>> + wpi.fd = fd; >>>> + wpi.path = path_list_init(); >>>> + if (!wpi.path) >>>> + return -1; >>>> + wpi.fn = fn; >>>> + wpi.arg = arg; >>>> + >>>> + ret = handle_walk_parent_paths(&wpi, hanp); >>>> + path_list_free(wpi.path); >>>> + >>>> + return ret; >>>> +} >>>> + >>>> +struct path_walk_info { >>>> + char *buf; >>>> + size_t len; >>>> +}; >>>> + >>>> +/* Helper that stringifies the first full path that we find. */ >>>> +static int >>>> +handle_to_path_walk( >>>> + const char *mntpt, >>>> + struct path_list *path, >>>> + void *arg) >>>> +{ >>>> + struct path_walk_info *pwi = arg; >>>> + int ret; >>>> + >>>> + ret = snprintf(pwi->buf, pwi->len, "%s", mntpt); >>>> + if (ret != strlen(mntpt)) { >>>> + errno = ENOMEM; >>>> + return -1; >>>> + } >>>> + >>>> + ret = path_list_to_string(path, pwi->buf + ret, pwi->len - ret); >>>> + if (ret < 0) >>>> + return ret; >>>> + >>>> + return WALK_PPATHS_ABORT; >>>> +} >>>> + >>>> +/* Return any eligible path to this file handle. */ >>>> +int >>>> +handle_to_path( >>>> + void *hanp, >>>> + size_t hlen, >>>> + char *path, >>>> + size_t pathlen) >>>> +{ >>>> + struct path_walk_info pwi; >>>> + >>>> + pwi.buf = path; >>>> + pwi.len = pathlen; >>>> + return handle_walk_ppaths(hanp, hlen, handle_to_path_walk, &pwi); >>>> +} >>>> + >>>> +/* Return any eligible path to this file description. */ >>>> +int >>>> +fd_to_path( >>>> + int fd, >>>> + char *path, >>>> + size_t pathlen) >>>> +{ >>>> + struct path_walk_info pwi; >>>> + >>>> + pwi.buf = path; >>>> + pwi.len = pathlen; >>>> + return fd_walk_ppaths(fd, handle_to_path_walk, &pwi); >>>> +} >>>> diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h >>>> index e3ce233..aa613f9 100644 >>>> --- a/libxfs/xfs_fs.h >>>> +++ b/libxfs/xfs_fs.h >>>> @@ -610,6 +610,14 @@ struct xfs_pptr_info { >>>> #define XFS_PPINFO_TO_PP(info, idx) \ >>>> (&(((struct xfs_parent_ptr *)((char *)(info) + sizeof(*(info))))[(idx)])) >>>> +#define XFS_PPTR_ALL_IFLAGS (XFS_PPTR_IFLAG_HANDLE) >>>> + >>>> +/* partial results only */ >>>> +#define XFS_PPTR_OFLAG_PARTIAL (1U << 0) >>>> + >>>> +/* target was the root directory */ >>>> +#define XFS_PPTR_OFLAG_ROOT (1U << 1) >>> >>> Uhoh, I forgot about this chunk, which should be in the kernel patches >>> somewhere I guess... >>> >>> --D >>> >> >> Do we want to keep these? Should I add behavior of these in the kernel side >> set? > > I don't even remember why OFLAG_PARTIAL exists, it can certainly go. > > OFLAG_ROOT is returned for the root directory so that callers can > distinguish it from an unlinked inode (which also has no parents). > > --D > Ok, I'll keep that one then. Thx! >> >> Allison >> >>>> + >>>> /* >>>> * ioctl limits >>>> */ >>>> diff --git a/scrub/inodes.c b/scrub/inodes.c >>>> index ccfb9e0..3fbcd1a 100644 >>>> --- a/scrub/inodes.c >>>> +++ b/scrub/inodes.c >>>> @@ -31,6 +31,7 @@ >>>> #include "xfs_scrub.h" >>>> #include "common.h" >>>> #include "inodes.h" >>>> +#include "parent.h" >>>> /* >>>> * Iterate a range of inodes. >>>> @@ -293,3 +294,28 @@ xfs_open_handle( >>>> return open_by_fshandle(handle, sizeof(*handle), >>>> O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NOCTTY); >>>> } >>>> + >>>> +/* Construct a description for an inode. */ >>>> +void >>>> +xfs_scrub_ino_descr( >>>> + struct scrub_ctx *ctx, >>>> + struct xfs_handle *handle, >>>> + char *buf, >>>> + size_t buflen) >>>> +{ >>>> + uint64_t ino; >>>> + xfs_agnumber_t agno; >>>> + xfs_agino_t agino; >>>> + int ret; >>>> + >>>> + ret = handle_to_path(handle, sizeof(struct xfs_handle), buf, buflen); >>>> + if (ret >= 0) >>>> + return; >>>> + >>>> + ino = handle->ha_fid.fid_ino; >>>> + agno = ino / (1ULL << (ctx->inopblog + ctx->agblklog)); >>>> + agino = ino % (1ULL << (ctx->inopblog + ctx->agblklog)); >>>> + snprintf(buf, buflen, _("inode %"PRIu64" (%u/%u)"), ino, agno, >>>> + agino); >>>> +} >>>> + >>>> diff --git a/scrub/inodes.h b/scrub/inodes.h >>>> index 693cb05..e94de0a 100644 >>>> --- a/scrub/inodes.h >>>> +++ b/scrub/inodes.h >>>> @@ -28,5 +28,7 @@ bool xfs_scan_all_inodes(struct scrub_ctx *ctx, xfs_inode_iter_fn fn, >>>> void *arg); >>>> int xfs_open_handle(struct xfs_handle *handle); >>>> +void xfs_scrub_ino_descr(struct scrub_ctx *ctx, struct xfs_handle *handle, >>>> + char *buf, size_t buflen); >>>> #endif /* XFS_SCRUB_INODES_H_ */ >>>> diff --git a/scrub/phase5.c b/scrub/phase5.c >>>> index 01038f7..ecaaaaa 100644 >>>> --- a/scrub/phase5.c >>>> +++ b/scrub/phase5.c >>>> @@ -245,16 +245,11 @@ xfs_scrub_connections( >>>> void *arg) >>>> { >>>> bool *pmoveon = arg; >>>> - char descr[DESCR_BUFSZ]; >>>> + char descr[PATH_MAX]; >>>> bool moveon = true; >>>> - xfs_agnumber_t agno; >>>> - xfs_agino_t agino; >>>> int fd = -1; >>>> - agno = bstat->bs_ino / (1ULL << (ctx->inopblog + ctx->agblklog)); >>>> - agino = bstat->bs_ino % (1ULL << (ctx->inopblog + ctx->agblklog)); >>>> - snprintf(descr, DESCR_BUFSZ, _("inode %"PRIu64" (%u/%u)"), >>>> - (uint64_t)bstat->bs_ino, agno, agino); >>>> + xfs_scrub_ino_descr(ctx, handle, descr, PATH_MAX); >>>> background_sleep(); >>>> /* Warn about naming problems in xattrs. */ >>>> -- >>>> 2.7.4 >>>> >>>> -- >>>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in >>>> the body of a message to majordomo@vger.kernel.org >>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/include/handle.h b/include/handle.h index 49f1441..00aa43d 100644 --- a/include/handle.h +++ b/include/handle.h @@ -52,6 +52,8 @@ extern int fssetdm_by_handle (void *__hanp, size_t __hlen, void fshandle_destroy(void); +int handle_to_fsfd(void *hanp, char **path); + #ifdef __cplusplus } #endif diff --git a/include/parent.h b/include/parent.h index 85cef85..33f8d85 100644 --- a/include/parent.h +++ b/include/parent.h @@ -28,4 +28,22 @@ typedef struct parent_cursor { __u32 opaque[4]; /* an opaque cookie */ } parent_cursor_t; +struct path_list; + +typedef int (*walk_pptr_fn)(struct xfs_pptr_info *pi, struct xfs_parent_ptr *pptr, + void *arg); +typedef int (*walk_ppath_fn)(const char *mntpt, struct path_list *path, + void *arg); + +#define WALK_PPTRS_ABORT 1 +int fd_walk_pptrs(int fd, walk_pptr_fn fn, void *arg); +int handle_walk_pptrs(void *hanp, size_t hanlen, walk_pptr_fn fn, void *arg); + +#define WALK_PPATHS_ABORT 1 +int fd_walk_ppaths(int fd, walk_ppath_fn fn, void *arg); +int handle_walk_ppaths(void *hanp, size_t hanlen, walk_ppath_fn fn, void *arg); + +int fd_to_path(int fd, char *path, size_t pathlen); +int handle_to_path(void *hanp, size_t hlen, char *path, size_t pathlen); + #endif diff --git a/include/path.h b/include/path.h index 88dc44b..cbe4e19 100644 --- a/include/path.h +++ b/include/path.h @@ -70,4 +70,23 @@ typedef struct fs_cursor { extern void fs_cursor_initialise(char *__dir, uint __flags, fs_cursor_t *__cp); extern fs_path_t *fs_cursor_next_entry(fs_cursor_t *__cp); +/* Path information. */ + +struct path_list; +struct path_component; + +struct path_component *path_component_init(const char *name); +void path_component_free(struct path_component *pc); +int path_component_change(struct path_component *pc, void *name, + size_t namelen); + +struct path_list *path_list_init(void); +void path_list_free(struct path_list *path); +void path_list_add_parent_component(struct path_list *path, + struct path_component *pc); +void path_list_add_component(struct path_list *path, struct path_component *pc); +void path_list_del_component(struct path_list *path, struct path_component *pc); + +ssize_t path_list_to_string(struct path_list *path, char *buf, size_t buflen); + #endif /* __PATH_H__ */ diff --git a/io/parent.c b/io/parent.c index 55b8b49..ad51fe6 100644 --- a/io/parent.c +++ b/io/parent.c @@ -21,366 +21,105 @@ #include "path.h" #include "parent.h" #include "handle.h" -#include "jdm.h" #include "init.h" #include "io.h" -#define PARENTBUF_SZ 16384 -#define BSTATBUF_SZ 16384 - static cmdinfo_t parent_cmd; -static int verbose_flag; -static int err_status; -static __u64 inodes_checked; static char *mntpt; -/* - * check out a parent entry to see if the values seem valid - */ -static void -check_parent_entry(xfs_bstat_t *bstatp, parent_t *parent) -{ - int sts; - char fullpath[PATH_MAX]; - struct stat statbuf; - char *str; - - snprintf(fullpath, parent->p_reclen, _("%s%s"), mntpt, - ((char*)parent)+sizeof(struct parent)); - - sts = lstat(fullpath, &statbuf); - if (sts != 0) { - fprintf(stderr, - _("inode-path for inode: %llu is incorrect - path \"%s\" non-existent\n"), - (unsigned long long) bstatp->bs_ino, fullpath); - if (verbose_flag) { - fprintf(stderr, - _("path \"%s\" does not stat for inode: %llu; err = %s\n"), - fullpath, - (unsigned long long) bstatp->bs_ino, - strerror(errno)); - } - err_status++; - return; - } else { - if (verbose_flag > 1) { - printf(_("path \"%s\" found\n"), fullpath); - } - } - - if (statbuf.st_ino != bstatp->bs_ino) { - fprintf(stderr, - _("inode-path for inode: %llu is incorrect - wrong inode#\n"), - (unsigned long long) bstatp->bs_ino); - if (verbose_flag) { - fprintf(stderr, - _("ino mismatch for path \"%s\" %llu vs %llu\n"), - fullpath, - (unsigned long long)statbuf.st_ino, - (unsigned long long)bstatp->bs_ino); - } - err_status++; - return; - } else if (verbose_flag > 1) { - printf(_("inode number match: %llu\n"), - (unsigned long long)statbuf.st_ino); - } - - /* get parent path */ - str = strrchr(fullpath, '/'); - *str = '\0'; - sts = stat(fullpath, &statbuf); - if (sts != 0) { - fprintf(stderr, - _("parent path \"%s\" does not stat: %s\n"), - fullpath, - strerror(errno)); - err_status++; - return; - } else { - if (parent->p_ino != statbuf.st_ino) { - fprintf(stderr, - _("inode-path for inode: %llu is incorrect - wrong parent inode#\n"), - (unsigned long long) bstatp->bs_ino); - if (verbose_flag) { - fprintf(stderr, - _("ino mismatch for path \"%s\" %llu vs %llu\n"), - fullpath, - (unsigned long long)parent->p_ino, - (unsigned long long)statbuf.st_ino); - } - err_status++; - return; - } else { - if (verbose_flag > 1) { - printf(_("parent ino match for %llu\n"), - (unsigned long long) parent->p_ino); - } - } - } -} - -static void -check_parents(parent_t *parentbuf, size_t *parentbuf_size, - jdm_fshandle_t *fshandlep, xfs_bstat_t *statp) -{ - int error, i; - __u32 count; - parent_t *entryp; - - do { - error = jdm_parentpaths(fshandlep, statp, parentbuf, *parentbuf_size, &count); - - if (error == ERANGE) { - *parentbuf_size *= 2; - parentbuf = (parent_t *)realloc(parentbuf, *parentbuf_size); - } else if (error) { - fprintf(stderr, _("parentpaths failed for ino %llu: %s\n"), - (unsigned long long) statp->bs_ino, - strerror(errno)); - err_status++; - break; - } - } while (error == ERANGE); - - - if (count == 0) { - /* no links for inode - something wrong here */ - fprintf(stderr, _("inode-path for inode: %llu is missing\n"), - (unsigned long long) statp->bs_ino); - err_status++; - } - - entryp = parentbuf; - for (i = 0; i < count; i++) { - check_parent_entry(statp, entryp); - entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); - } -} - static int -do_bulkstat(parent_t *parentbuf, size_t *parentbuf_size, xfs_bstat_t *bstatbuf, - int fsfd, jdm_fshandle_t *fshandlep) +pptr_print( + struct xfs_pptr_info *pi, + struct xfs_parent_ptr *pptr, + void *arg) { - __s32 buflenout; - __u64 lastino = 0; - xfs_bstat_t *p; - xfs_bstat_t *endp; - xfs_fsop_bulkreq_t bulkreq; - struct stat mntstat; + char buf[XFS_PPTR_MAXNAMELEN + 1]; - if (stat(mntpt, &mntstat)) { - fprintf(stderr, _("can't stat mount point \"%s\": %s\n"), - mntpt, strerror(errno)); - return 1; + if (pi->pi_flags & XFS_PPTR_OFLAG_ROOT) { + printf(_("Root directory.\n")); + return 0; } - bulkreq.lastip = &lastino; - bulkreq.icount = BSTATBUF_SZ; - bulkreq.ubuffer = (void *)bstatbuf; - bulkreq.ocount = &buflenout; - - while (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT, &bulkreq) == 0) { - if (*(bulkreq.ocount) == 0) { - return 0; - } - for (p = bstatbuf, endp = bstatbuf + *bulkreq.ocount; p < endp; p++) { - - /* inode being modified, get synced data with iget */ - if ( (!p->bs_nlink || !p->bs_mode) && p->bs_ino != 0 ) { - - if (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) < 0) { - fprintf(stderr, - _("failed to get bulkstat information for inode %llu\n"), - (unsigned long long) p->bs_ino); - continue; - } - if (!p->bs_nlink || !p->bs_mode || !p->bs_ino) { - fprintf(stderr, - _("failed to get valid bulkstat information for inode %llu\n"), - (unsigned long long) p->bs_ino); - continue; - } - } - - /* skip root */ - if (p->bs_ino == mntstat.st_ino) { - continue; - } - - if (verbose_flag > 1) { - printf(_("checking inode %llu\n"), - (unsigned long long) p->bs_ino); - } - - /* print dotted progress */ - if ((inodes_checked % 100) == 0 && verbose_flag == 1) { - printf("."); fflush(stdout); - } - inodes_checked++; - - check_parents(parentbuf, parentbuf_size, fshandlep, p); - } - - }/*while*/ - - fprintf(stderr, _("syssgi bulkstat failed: %s\n"), strerror(errno)); - return 1; + memcpy(buf, pptr->xpp_name, pptr->xpp_namelen); + buf[pptr->xpp_namelen] = 0; + printf(_("p_ino = %llu\n"), (unsigned long long)pptr->xpp_ino); + printf(_("p_gen = %u\n"), (unsigned int)pptr->xpp_gen); + printf(_("p_reclen = %u\n"), (unsigned int)pptr->xpp_namelen); + printf(_("p_name = \"%s\"\n\n"), buf); + return 0; } -static int -parent_check(void) +int +print_parents( + struct xfs_handle *handle) { - int fsfd; - jdm_fshandle_t *fshandlep; - parent_t *parentbuf; - size_t parentbuf_size = PARENTBUF_SZ; - xfs_bstat_t *bstatbuf; - - err_status = 0; - inodes_checked = 0; - - sync(); - - fsfd = file->fd; - - fshandlep = jdm_getfshandle(mntpt); - if (fshandlep == NULL) { - fprintf(stderr, _("unable to open \"%s\" for jdm: %s\n"), - mntpt, - strerror(errno)); - return 1; - } - - /* allocate buffers */ - bstatbuf = (xfs_bstat_t *)calloc(BSTATBUF_SZ, sizeof(xfs_bstat_t)); - parentbuf = (parent_t *)malloc(parentbuf_size); - if (!bstatbuf || !parentbuf) { - fprintf(stderr, _("unable to allocate buffers: %s\n"), - strerror(errno)); - err_status = 1; - goto out; - } + int ret; - if (do_bulkstat(parentbuf, &parentbuf_size, bstatbuf, fsfd, fshandlep) != 0) - err_status++; - - if (err_status > 0) - fprintf(stderr, _("num errors: %d\n"), err_status); + if (handle) + ret = handle_walk_pptrs(handle, sizeof(*handle), pptr_print, + NULL); else - printf(_("succeeded checking %llu inodes\n"), - (unsigned long long) inodes_checked); - -out: - free(bstatbuf); - free(parentbuf); - free(fshandlep); - return err_status; -} + ret = fd_walk_pptrs(file->fd, pptr_print, NULL); + if (ret) + perror(file->name); -static void -print_parent_entry(parent_t *parent, int fullpath) -{ - printf(_("p_ino = %llu\n"), (unsigned long long) parent->p_ino); - printf(_("p_gen = %u\n"), parent->p_gen); - printf(_("p_reclen = %u\n"), parent->p_reclen); - if (fullpath) - printf(_("p_name = \"%s%s\"\n"), mntpt, - ((char*)parent)+sizeof(struct parent)); - else - printf(_("p_name = \"%s\"\n"), - ((char*)parent)+sizeof(struct parent)); + return 0; } static int -parent_list(int fullpath) -{ - void *handlep = NULL; - size_t handlen; - int error, i; - int retval = 1; - __u32 count; - parent_t *entryp; - parent_t *parentbuf = NULL; - char *path = file->name; - int pb_size = PARENTBUF_SZ; - - /* XXXX for linux libhandle version - to set libhandle fsfd cache */ - { - void *fshandle; - size_t fshlen; - - if (path_to_fshandle(mntpt, &fshandle, &fshlen) != 0) { - fprintf(stderr, _("%s: failed path_to_fshandle \"%s\": %s\n"), - progname, path, strerror(errno)); - goto error; - } - free_handle(fshandle, fshlen); - } - - if (path_to_handle(path, &handlep, &handlen) != 0) { - fprintf(stderr, _("%s: path_to_handle failed for \"%s\"\n"), progname, path); - goto error; - } - - do { - parentbuf = (parent_t *)realloc(parentbuf, pb_size); - if (!parentbuf) { - fprintf(stderr, _("%s: unable to allocate parent buffer: %s\n"), - progname, strerror(errno)); - goto error; - } +path_print( + const char *mntpt, + struct path_list *path, + void *arg) { - if (fullpath) { - error = parentpaths_by_handle(handlep, - handlen, - parentbuf, - pb_size, - &count); - } else { - error = parents_by_handle(handlep, - handlen, - parentbuf, - pb_size, - &count); - } - if (error == ERANGE) { - pb_size *= 2; - } else if (error) { - fprintf(stderr, _("%s: %s call failed for \"%s\": %s\n"), - progname, fullpath ? "parentpaths" : "parents", - path, strerror(errno)); - goto error; - } - } while (error == ERANGE); + char buf[PATH_MAX]; + size_t len = PATH_MAX; + int ret; - if (count == 0) { - /* no links for inode - something wrong here */ - fprintf(stderr, _("%s: inode-path is missing\n"), progname); - goto error; + ret = snprintf(buf, len, "%s", mntpt); + if (ret != strlen(mntpt)) { + errno = ENOMEM; + return -1; } - entryp = parentbuf; - for (i = 0; i < count; i++) { - print_parent_entry(entryp, fullpath); - entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); - } + ret = path_list_to_string(path, buf + ret, len - ret); + if (ret < 0) + return ret; + return 0; +} - retval = 0; -error: - free(handlep); - free(parentbuf); - return retval; +int +print_paths( + struct xfs_handle *handle) +{ + int ret; + + if (handle) + ret = handle_walk_ppaths(handle, sizeof(*handle), path_print, + NULL); + else + ret = fd_walk_ppaths(file->fd, path_print, NULL); + if (ret) + perror(file->name); + return 0; } int -parent_f(int argc, char **argv) +parent_f( + int argc, + char **argv) { - int c; - int listpath_flag = 0; - int check_flag = 0; - fs_path_t *fs; - static int tab_init; + struct xfs_handle handle; + void *hanp = NULL; + size_t hlen; + struct fs_path *fs; + char *p; + uint64_t ino = 0; + uint32_t gen = 0; + int c; + int listpath_flag = 0; + int ret; + static int tab_init; if (!tab_init) { tab_init = 1; @@ -394,46 +133,72 @@ parent_f(int argc, char **argv) } mntpt = fs->fs_dir; - verbose_flag = 0; - - while ((c = getopt(argc, argv, "cpv")) != EOF) { + while ((c = getopt(argc, argv, "p")) != EOF) { switch (c) { - case 'c': - check_flag = 1; - break; case 'p': listpath_flag = 1; break; - case 'v': - verbose_flag++; - break; default: return command_usage(&parent_cmd); } } - if (!check_flag && !listpath_flag) /* default case */ - exitcode = parent_list(listpath_flag); - else { - if (listpath_flag) - exitcode = parent_list(listpath_flag); - if (check_flag) - exitcode = parent_check(); + /* + * Always initialize the fshandle table because we need it for + * the ppaths functions to work. + */ + ret = path_to_fshandle((char *)mntpt, &hanp, &hlen); + if (ret) { + perror(mntpt); + return 0; + } + + if (optind + 2 == argc) { + ino = strtoull(argv[optind], &p, 0); + if (*p != '\0' || ino == 0) { + fprintf(stderr, + _("Bad inode number '%s'.\n"), + argv[optind]); + return 0; + } + gen = strtoul(argv[optind + 1], &p, 0); + if (*p != '\0') { + fprintf(stderr, + _("Bad generation number '%s'.\n"), + argv[optind + 1]); + return 0; + } + + memcpy(&handle, hanp, sizeof(handle)); + handle.ha_fid.fid_len = sizeof(xfs_fid_t) - + sizeof(handle.ha_fid.fid_len); + handle.ha_fid.fid_pad = 0; + handle.ha_fid.fid_ino = ino; + handle.ha_fid.fid_gen = gen; + } + if (listpath_flag) + exitcode = print_paths(ino ? &handle : NULL); + else + exitcode = print_parents(ino ? &handle : NULL); + + if (hanp) + free_handle(hanp, hlen); + return 0; } static void parent_help(void) { - printf(_( +printf(_( "\n" " list the current file's parents and their filenames\n" "\n" -" -c -- check the current file's file system for parent consistency\n" -" -p -- list the current file's parents and their full paths\n" -" -v -- verbose mode\n" +" -p -- list the current file's paths up to the root\n" +"\n" +"If ino and gen are supplied, use them instead.\n" "\n")); } @@ -444,9 +209,9 @@ parent_init(void) parent_cmd.cfunc = parent_f; parent_cmd.argmin = 0; parent_cmd.argmax = -1; - parent_cmd.args = _("[-cpv]"); + parent_cmd.args = _("[-p] [ino gen]"); parent_cmd.flags = CMD_NOMAP_OK; - parent_cmd.oneline = _("print or check parent inodes"); + parent_cmd.oneline = _("print parent inodes"); parent_cmd.help = parent_help; if (expert) diff --git a/libfrog/paths.c b/libfrog/paths.c index c7895e9..9fb0140 100644 --- a/libfrog/paths.c +++ b/libfrog/paths.c @@ -27,6 +27,7 @@ #include "path.h" #include "input.h" #include "project.h" +#include "list.h" #include <limits.h> extern char *progname; @@ -632,3 +633,138 @@ fs_table_insert_project_path( exit(1); } } + + +/* Structured path components. */ + +struct path_list { + struct list_head p_head; +}; + +struct path_component { + struct list_head pc_list; + char *pc_fname; +}; + +/* Initialize a path component with a given name. */ +struct path_component * +path_component_init( + const char *name) +{ + struct path_component *pc; + + pc = malloc(sizeof(struct path_component)); + if (!pc) + return NULL; + INIT_LIST_HEAD(&pc->pc_list); + pc->pc_fname = strdup(name); + if (!pc->pc_fname) { + free(pc); + return NULL; + } + return pc; +} + +/* Free a path component. */ +void +path_component_free( + struct path_component *pc) +{ + free(pc->pc_fname); + free(pc); +} + +/* Change a path component's filename. */ +int +path_component_change( + struct path_component *pc, + void *name, + size_t namelen) +{ + void *p; + + p = realloc(pc->pc_fname, namelen + 1); + if (!p) + return -1; + pc->pc_fname = p; + memcpy(pc->pc_fname, name, namelen); + pc->pc_fname[namelen] = 0; + return 0; +} + +/* Initialize a pathname. */ +struct path_list * +path_list_init(void) +{ + struct path_list *path; + + path = malloc(sizeof(struct path_list)); + if (!path) + return NULL; + INIT_LIST_HEAD(&path->p_head); + return path; +} + +/* Empty out a pathname. */ +void +path_list_free( + struct path_list *path) +{ + struct path_component *pos; + struct path_component *n; + + list_for_each_entry_safe(pos, n, &path->p_head, pc_list) { + path_list_del_component(path, pos); + path_component_free(pos); + } + free(path); +} + +/* Add a parent component to a pathname. */ +void +path_list_add_parent_component( + struct path_list *path, + struct path_component *pc) +{ + list_add(&pc->pc_list, &path->p_head); +} + +/* Add a component to a pathname. */ +void +path_list_add_component( + struct path_list *path, + struct path_component *pc) +{ + list_add_tail(&pc->pc_list, &path->p_head); +} + +/* Remove a component from a pathname. */ +void +path_list_del_component( + struct path_list *path, + struct path_component *pc) +{ + list_del_init(&pc->pc_list); +} + +/* Convert a pathname into a string. */ +ssize_t +path_list_to_string( + struct path_list *path, + char *buf, + size_t buflen) +{ + struct path_component *pos; + ssize_t bytes = 0; + int ret; + + list_for_each_entry(pos, &path->p_head, pc_list) { + ret = snprintf(buf, buflen, "/%s", pos->pc_fname); + if (ret != 1 + strlen(pos->pc_fname)) + return -1; + bytes += ret; + buf += ret; + buflen -= ret; + } + return bytes; +} diff --git a/libhandle/Makefile b/libhandle/Makefile index fe1a2af..d3cea41 100644 --- a/libhandle/Makefile +++ b/libhandle/Makefile @@ -16,7 +16,7 @@ else LTLDFLAGS += -Wl,--version-script,libhandle.sym endif -CFILES = handle.c jdm.c +CFILES = handle.c jdm.c parent.c LSRCFILES = libhandle.sym default: ltdepend $(LTLIBRARY) diff --git a/libhandle/handle.c b/libhandle/handle.c index 878d14d..a70fa32 100644 --- a/libhandle/handle.c +++ b/libhandle/handle.c @@ -41,7 +41,6 @@ typedef union { } comarg_t; static int obj_to_handle(char *, int, unsigned int, comarg_t, void**, size_t*); -static int handle_to_fsfd(void *, char **); static char *path_to_fspath(char *path); @@ -214,8 +213,10 @@ handle_to_fshandle( return 0; } -static int -handle_to_fsfd(void *hanp, char **path) +int +handle_to_fsfd( + void *hanp, + char **path) { struct fdhash *fdhp; diff --git a/libhandle/parent.c b/libhandle/parent.c new file mode 100644 index 0000000..f6be3bd --- /dev/null +++ b/libhandle/parent.c @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2017 Oracle. All Rights Reserved. + * + * Author: Darrick J. Wong <darrick.wong@oracle.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "platform_defs.h" +#include "xfs.h" +#include "xfs_arch.h" +#include "list.h" +#include "path.h" +#include "handle.h" +#include "parent.h" + +/* Allocate a buffer large enough for some parent pointer records. */ +static inline struct xfs_pptr_info * +xfs_pptr_alloc( + size_t nr_ptrs) +{ + struct xfs_pptr_info *pi; + + pi = malloc(XFS_PPTR_INFO_SIZEOF(nr_ptrs)); + if (!pi) + return NULL; + memset(pi, 0, sizeof(struct xfs_pptr_info)); + pi->pi_ptrs_size = nr_ptrs; + return pi; +} + +/* Walk all parents of the given file handle. */ +static int +handle_walk_parents( + int fd, + struct xfs_handle *handle, + walk_pptr_fn fn, + void *arg) +{ + struct xfs_pptr_info *pi; + struct xfs_parent_ptr *p; + unsigned int i; + ssize_t ret = -1; + + pi = xfs_pptr_alloc(4); + if (!pi) + return -1; + + if (handle) { + memcpy(&pi->pi_handle, handle, sizeof(struct xfs_handle)); + pi->pi_flags = XFS_PPTR_IFLAG_HANDLE; + } + + ret = ioctl(fd, XFS_IOC_GETPPOINTER, pi); + while (!ret) { + if (pi->pi_flags & XFS_PPTR_OFLAG_ROOT) { + ret = fn(pi, NULL, arg); + break; + } + if (pi->pi_ptrs_used == 0) + break; + for (i = 0; i < pi->pi_ptrs_used; i++) { + p = XFS_PPINFO_TO_PP(pi, i); + ret = fn(pi, p, arg); + if (ret) + goto out_pi; + } + ret = ioctl(fd, XFS_IOC_GETPPOINTER, pi); + } + +out_pi: + free(pi); + return ret; +} + +/* Walk all parent pointers of this handle. */ +int +handle_walk_pptrs( + void *hanp, + size_t hlen, + walk_pptr_fn fn, + void *arg) +{ + char *mntpt; + int fd; + + if (hlen != sizeof(struct xfs_handle)) { + errno = EINVAL; + return -1; + } + + fd = handle_to_fsfd(hanp, &mntpt); + if (fd < 0) + return -1; + + return handle_walk_parents(fd, hanp, fn, arg); +} + +/* Walk all parent pointers of this fd. */ +int +fd_walk_pptrs( + int fd, + walk_pptr_fn fn, + void *arg) +{ + return handle_walk_parents(fd, NULL, fn, arg); +} + +struct walk_ppaths_info { + walk_ppath_fn fn; + void *arg; + char *mntpt; + struct path_list *path; + int fd; +}; + +struct walk_ppath_level_info { + struct xfs_handle newhandle; + struct path_component *pc; + struct walk_ppaths_info *wpi; +}; + +static int handle_walk_parent_paths(struct walk_ppaths_info *wpi, + struct xfs_handle *handle); + +static int +handle_walk_parent_path_ptr( + struct xfs_pptr_info *pi, + struct xfs_parent_ptr *p, + void *arg) +{ + struct walk_ppath_level_info *wpli = arg; + struct walk_ppaths_info *wpi = wpli->wpi; + unsigned int i; + int ret = 0; + + if (pi->pi_flags & XFS_PPTR_OFLAG_ROOT) + return wpi->fn(wpi->mntpt, wpi->path, wpi->arg); + + for (i = 0; i < pi->pi_ptrs_used; i++) { + p = XFS_PPINFO_TO_PP(pi, i); + ret = path_component_change(wpli->pc, p->xpp_name, + p->xpp_namelen); + if (ret) + break; + wpli->newhandle.ha_fid.fid_ino = p->xpp_ino; + wpli->newhandle.ha_fid.fid_gen = p->xpp_gen; + path_list_add_parent_component(wpi->path, wpli->pc); + ret = handle_walk_parent_paths(wpi, &wpli->newhandle); + path_list_del_component(wpi->path, wpli->pc); + if (ret) + break; + } + + return ret; +} + +/* + * Recursively walk all parents of the given file handle; if we hit the + * fs root then we call the associated function with the constructed path. + */ +static int +handle_walk_parent_paths( + struct walk_ppaths_info *wpi, + struct xfs_handle *handle) +{ + struct walk_ppath_level_info *wpli; + int ret; + + wpli = malloc(sizeof(struct walk_ppath_level_info)); + if (!wpli) + return -1; + wpli->pc = path_component_init(""); + if (!wpli->pc) { + free(wpli); + return -1; + } + wpli->wpi = wpi; + memcpy(&wpli->newhandle, handle, sizeof(struct xfs_handle)); + + ret = handle_walk_parents(wpi->fd, handle, handle_walk_parent_path_ptr, + wpli); + + path_component_free(wpli->pc); + free(wpli); + return ret; +} + +/* + * Call the given function on all known paths from the vfs root to the inode + * described in the handle. + */ +int +handle_walk_ppaths( + void *hanp, + size_t hlen, + walk_ppath_fn fn, + void *arg) +{ + struct walk_ppaths_info wpi; + ssize_t ret; + + if (hlen != sizeof(struct xfs_handle)) { + errno = EINVAL; + return -1; + } + + wpi.fd = handle_to_fsfd(hanp, &wpi.mntpt); + if (wpi.fd < 0) + return -1; + wpi.path = path_list_init(); + if (!wpi.path) + return -1; + wpi.fn = fn; + wpi.arg = arg; + + ret = handle_walk_parent_paths(&wpi, hanp); + path_list_free(wpi.path); + + return ret; +} + +/* + * Call the given function on all known paths from the vfs root to the inode + * referred to by the file description. + */ +int +fd_walk_ppaths( + int fd, + walk_ppath_fn fn, + void *arg) +{ + struct walk_ppaths_info wpi; + void *hanp; + size_t hlen; + int fsfd; + int ret; + + ret = fd_to_handle(fd, &hanp, &hlen); + if (ret) + return ret; + + fsfd = handle_to_fsfd(hanp, &wpi.mntpt); + if (fsfd < 0) + return -1; + wpi.fd = fd; + wpi.path = path_list_init(); + if (!wpi.path) + return -1; + wpi.fn = fn; + wpi.arg = arg; + + ret = handle_walk_parent_paths(&wpi, hanp); + path_list_free(wpi.path); + + return ret; +} + +struct path_walk_info { + char *buf; + size_t len; +}; + +/* Helper that stringifies the first full path that we find. */ +static int +handle_to_path_walk( + const char *mntpt, + struct path_list *path, + void *arg) +{ + struct path_walk_info *pwi = arg; + int ret; + + ret = snprintf(pwi->buf, pwi->len, "%s", mntpt); + if (ret != strlen(mntpt)) { + errno = ENOMEM; + return -1; + } + + ret = path_list_to_string(path, pwi->buf + ret, pwi->len - ret); + if (ret < 0) + return ret; + + return WALK_PPATHS_ABORT; +} + +/* Return any eligible path to this file handle. */ +int +handle_to_path( + void *hanp, + size_t hlen, + char *path, + size_t pathlen) +{ + struct path_walk_info pwi; + + pwi.buf = path; + pwi.len = pathlen; + return handle_walk_ppaths(hanp, hlen, handle_to_path_walk, &pwi); +} + +/* Return any eligible path to this file description. */ +int +fd_to_path( + int fd, + char *path, + size_t pathlen) +{ + struct path_walk_info pwi; + + pwi.buf = path; + pwi.len = pathlen; + return fd_walk_ppaths(fd, handle_to_path_walk, &pwi); +} diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h index e3ce233..aa613f9 100644 --- a/libxfs/xfs_fs.h +++ b/libxfs/xfs_fs.h @@ -610,6 +610,14 @@ struct xfs_pptr_info { #define XFS_PPINFO_TO_PP(info, idx) \ (&(((struct xfs_parent_ptr *)((char *)(info) + sizeof(*(info))))[(idx)])) +#define XFS_PPTR_ALL_IFLAGS (XFS_PPTR_IFLAG_HANDLE) + +/* partial results only */ +#define XFS_PPTR_OFLAG_PARTIAL (1U << 0) + +/* target was the root directory */ +#define XFS_PPTR_OFLAG_ROOT (1U << 1) + /* * ioctl limits */ diff --git a/scrub/inodes.c b/scrub/inodes.c index ccfb9e0..3fbcd1a 100644 --- a/scrub/inodes.c +++ b/scrub/inodes.c @@ -31,6 +31,7 @@ #include "xfs_scrub.h" #include "common.h" #include "inodes.h" +#include "parent.h" /* * Iterate a range of inodes. @@ -293,3 +294,28 @@ xfs_open_handle( return open_by_fshandle(handle, sizeof(*handle), O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NOCTTY); } + +/* Construct a description for an inode. */ +void +xfs_scrub_ino_descr( + struct scrub_ctx *ctx, + struct xfs_handle *handle, + char *buf, + size_t buflen) +{ + uint64_t ino; + xfs_agnumber_t agno; + xfs_agino_t agino; + int ret; + + ret = handle_to_path(handle, sizeof(struct xfs_handle), buf, buflen); + if (ret >= 0) + return; + + ino = handle->ha_fid.fid_ino; + agno = ino / (1ULL << (ctx->inopblog + ctx->agblklog)); + agino = ino % (1ULL << (ctx->inopblog + ctx->agblklog)); + snprintf(buf, buflen, _("inode %"PRIu64" (%u/%u)"), ino, agno, + agino); +} + diff --git a/scrub/inodes.h b/scrub/inodes.h index 693cb05..e94de0a 100644 --- a/scrub/inodes.h +++ b/scrub/inodes.h @@ -28,5 +28,7 @@ bool xfs_scan_all_inodes(struct scrub_ctx *ctx, xfs_inode_iter_fn fn, void *arg); int xfs_open_handle(struct xfs_handle *handle); +void xfs_scrub_ino_descr(struct scrub_ctx *ctx, struct xfs_handle *handle, + char *buf, size_t buflen); #endif /* XFS_SCRUB_INODES_H_ */ diff --git a/scrub/phase5.c b/scrub/phase5.c index 01038f7..ecaaaaa 100644 --- a/scrub/phase5.c +++ b/scrub/phase5.c @@ -245,16 +245,11 @@ xfs_scrub_connections( void *arg) { bool *pmoveon = arg; - char descr[DESCR_BUFSZ]; + char descr[PATH_MAX]; bool moveon = true; - xfs_agnumber_t agno; - xfs_agino_t agino; int fd = -1; - agno = bstat->bs_ino / (1ULL << (ctx->inopblog + ctx->agblklog)); - agino = bstat->bs_ino % (1ULL << (ctx->inopblog + ctx->agblklog)); - snprintf(descr, DESCR_BUFSZ, _("inode %"PRIu64" (%u/%u)"), - (uint64_t)bstat->bs_ino, agno, agino); + xfs_scrub_ino_descr(ctx, handle, descr, PATH_MAX); background_sleep(); /* Warn about naming problems in xattrs. */