linux-xfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Allison Henderson <allison.henderson@oracle.com>
To: "Darrick J. Wong" <darrick.wong@oracle.com>
Cc: linux-xfs@vger.kernel.org
Subject: Re: [PATCH 21/21] xfsprogs: implement the upper half of parent pointers
Date: Tue, 8 May 2018 18:47:14 -0700	[thread overview]
Message-ID: <1e72dd78-8ab7-2bd9-3fc7-1b697d932787@oracle.com> (raw)
In-Reply-To: <20180509014450.GF11261@magnolia>

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

  reply	other threads:[~2018-05-09  1:47 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
2018-05-08  4:40 ` [PATCH 01/21] xfsprogs: Move xfs_attr.h to libxfs Allison Henderson
2018-05-08 17:18   ` Darrick J. Wong
2018-05-08  4:41 ` [PATCH 02/21] xfsprogs: Add trans toggle to attr routines Allison Henderson
2018-05-08  4:41 ` [PATCH 03/21] xfsprogs: Add attibute set and helper functions Allison Henderson
2018-05-08  4:41 ` [PATCH 04/21] xfsprogs: Add attibute remove " Allison Henderson
2018-05-08  4:41 ` [PATCH 05/21] xfsprogs: Set up infastructure for deferred attribute operations Allison Henderson
2018-05-08  4:41 ` [PATCH 06/21] xfsprogs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred Allison Henderson
2018-05-08  4:41 ` [PATCH 07/21] xfsprogs: Remove all strlen calls in all xfs_attr_* functions for attr names Allison Henderson
2018-05-08  4:41 ` [PATCH 08/21] xfsprogs: get directory offset when adding directory name Allison Henderson
2018-05-08  4:41 ` [PATCH 09/21] xfsprogs: get directory offset when removing " Allison Henderson
2018-05-08  4:41 ` [PATCH 10/21] xfsprogs: get directory offset when replacing a " Allison Henderson
2018-05-08  4:41 ` [PATCH 11/21] xfsprogs: add parent pointer support to attribute code Allison Henderson
2018-05-08  4:41 ` [PATCH 12/21] xfsprogs: define parent pointer xattr format Allison Henderson
2018-05-08  4:41 ` [PATCH 13/21] xfsprogs: extent transaction reservations for parent attributes Allison Henderson
2018-05-08  4:41 ` [PATCH 14/21] xfsprogs: parent pointer attribute creation Allison Henderson
2018-05-08  4:41 ` [PATCH 15/21] xfsprogs: Add the parent pointer support to the superblock version 5 Allison Henderson
2018-05-08  4:41 ` [PATCH 16/21] xfsprogs: Add parent pointer ioctl Allison Henderson
2018-05-08  4:41 ` [PATCH 17/21] xfsprogs: Add delayed attributes error tag Allison Henderson
2018-05-08 17:21   ` Darrick J. Wong
2018-05-08 20:17     ` Eric Sandeen
2018-05-08  4:41 ` [PATCH 18/21] xfsprogs: Add parent pointer flag to cmd Allison Henderson
2018-05-08 17:25   ` Darrick J. Wong
2018-05-08 19:02     ` Allison Henderson
2018-05-08 22:44       ` Darrick J. Wong
2018-05-08  4:41 ` [PATCH 19/21] xfsprogs: Remove single byte array from struct parent Allison Henderson
2018-05-08 17:32   ` Darrick J. Wong
2018-05-08  4:41 ` [PATCH 20/21] xfsprogs: Add parent pointers during protofile creation Allison Henderson
2018-05-08 17:43   ` Darrick J. Wong
2018-05-08 19:28     ` Allison Henderson
2018-05-08 20:39     ` Eric Sandeen
2018-05-08 21:14       ` Allison Henderson
2018-05-08 21:17         ` Eric Sandeen
2018-05-08 21:57           ` Allison Henderson
2018-05-08 22:27             ` Eric Sandeen
2018-05-08  4:41 ` [PATCH 21/21] xfsprogs: implement the upper half of parent pointers Allison Henderson
2018-05-08 17:45   ` Darrick J. Wong
2018-05-09  1:39     ` Allison Henderson
2018-05-09  1:44       ` Darrick J. Wong
2018-05-09  1:47         ` Allison Henderson [this message]
2018-05-08 20:52   ` Eric Sandeen
2018-05-08 23:04     ` Darrick J. Wong
2018-05-08 23:13       ` Allison Henderson
2018-05-09  1:22         ` Darrick J. Wong
2018-05-09  1:32           ` Allison Henderson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1e72dd78-8ab7-2bd9-3fc7-1b697d932787@oracle.com \
    --to=allison.henderson@oracle.com \
    --cc=darrick.wong@oracle.com \
    --cc=linux-xfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).