All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/21] xfsprogs: parent pointers v1
@ 2018-05-08  4:40 Allison Henderson
  2018-05-08  4:40 ` [PATCH 01/21] xfsprogs: Move xfs_attr.h to libxfs Allison Henderson
                   ` (20 more replies)
  0 siblings, 21 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:40 UTC (permalink / raw)
  To: linux-xfs

This is the first revision of the parent pointer patch set for xfsprogs.  The
goal of the set is to enable use of the parent pointer feature on the kernel
side, and provide basic user space utilities.

The first 17 patches synchronize libxfs with changes seen the kernel space patch.
I will pick up the reviews from that series and mirror them here.  Next
three patches plumb in the command line flag and changes to the protofile.  Last
patch I picked up from an earlier series Darrick to print out walk through pptrs
and print them.

As always, comments and feedback are appreciated.  Thank you!


Allison Henderson (20):
  xfsprogs: Move xfs_attr.h to libxfs
  xfsprogs: Add trans toggle to attr routines
  xfsprogs: Add attibute set and helper functions
  xfsprogs: Add attibute remove and helper functions
  xfsprogs: Set up infastructure for deferred attribute operations
  xfsprogs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
  xfsprogs: Remove all strlen calls in all xfs_attr_* functions for attr
    names.
  xfsprogs: get directory offset when adding directory name
  xfsprogs: get directory offset when removing directory name
  xfsprogs: get directory offset when replacing a directory name
  xfsprogs: add parent pointer support to attribute code
  xfsprogs: define parent pointer xattr format
  xfsprogs: extent transaction reservations for parent attributes
  xfsprogs: parent pointer attribute creation
  xfsprogs: Add the parent pointer support to the superblock version 5.
  xfsprogs: Add parent pointer ioctl
  xfsprogs: Add delayed attributes error tag
  xfsprogs: Add parent pointer flag to cmd
  xfsprogs: Remove single byte array from struct parent
  xfsprogs: Add parent pointers during protofile creation

Darrick J. Wong (1):
  xfsprogs: implement the upper half of parent pointers

 include/handle.h        |   2 +
 include/parent.h        |  19 +-
 include/path.h          |  19 ++
 io/inject.c             |   1 +
 io/parent.c             | 468 ++++++++++++----------------------------------
 libfrog/paths.c         | 136 ++++++++++++++
 libhandle/Makefile      |   2 +-
 libhandle/handle.c      |   7 +-
 libhandle/parent.c      | 325 ++++++++++++++++++++++++++++++++
 libxfs/Makefile         |   3 +
 libxfs/xfs_attr.c       | 481 ++++++++++++++++++++++++++++++++----------------
 libxfs/xfs_attr.h       | 191 +++++++++++++++++++
 libxfs/xfs_attr_leaf.c  |  13 +-
 libxfs/xfs_attr_leaf.h  |   8 +-
 libxfs/xfs_bmap.c       |  49 +++--
 libxfs/xfs_bmap.h       |   1 +
 libxfs/xfs_da_btree.h   |   1 +
 libxfs/xfs_da_format.h  |  38 +++-
 libxfs/xfs_defer.h      |   1 +
 libxfs/xfs_dir2.c       |  41 +++--
 libxfs/xfs_dir2.h       |  10 +-
 libxfs/xfs_dir2_block.c |   9 +-
 libxfs/xfs_dir2_leaf.c  |   8 +-
 libxfs/xfs_dir2_node.c  |   8 +-
 libxfs/xfs_dir2_sf.c    |   6 +
 libxfs/xfs_errortag.h   |   5 +-
 libxfs/xfs_format.h     |  10 +-
 libxfs/xfs_fs.h         |  47 +++++
 libxfs/xfs_log_format.h |  44 ++++-
 libxfs/xfs_parent.c     | 178 ++++++++++++++++++
 libxfs/xfs_parent.h     |  38 ++++
 libxfs/xfs_sb.c         |   2 +
 libxfs/xfs_trans_resv.c | 111 ++++++++---
 libxfs/xfs_trans_resv.h |   1 +
 libxfs/xfs_types.h      |   1 +
 mkfs/proto.c            |  58 ++++--
 mkfs/xfs_mkfs.c         |  16 +-
 repair/attr_repair.c    |  16 +-
 repair/phase6.c         |  54 +++---
 scrub/inodes.c          |  26 +++
 scrub/inodes.h          |   2 +
 scrub/phase5.c          |   9 +-
 42 files changed, 1802 insertions(+), 663 deletions(-)
 create mode 100644 libhandle/parent.c
 create mode 100644 libxfs/xfs_attr.h
 create mode 100644 libxfs/xfs_parent.c
 create mode 100644 libxfs/xfs_parent.h

-- 
2.7.4


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH 01/21] xfsprogs: Move xfs_attr.h to libxfs
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
@ 2018-05-08  4:40 ` 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
                   ` (19 subsequent siblings)
  20 siblings, 1 reply; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:40 UTC (permalink / raw)
  To: linux-xfs

This patch moves fs/xfs/xfs_attr.h to fs/xfs/libxfs/xfs_attr.h
since xfs_attr.c is in libxfs.  We will need these later in
xfsprogs.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 libxfs/Makefile   |   1 +
 libxfs/xfs_attr.h | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 158 insertions(+)

diff --git a/libxfs/Makefile b/libxfs/Makefile
index 0470f5f..75ce980 100644
--- a/libxfs/Makefile
+++ b/libxfs/Makefile
@@ -21,6 +21,7 @@ HFILES = \
 	xfs_ag_resv.h \
 	xfs_alloc.h \
 	xfs_alloc_btree.h \
+	xfs_attr.h \
 	xfs_attr_leaf.h \
 	xfs_attr_sf.h \
 	xfs_bit.h \
diff --git a/libxfs/xfs_attr.h b/libxfs/xfs_attr.h
new file mode 100644
index 0000000..8abf398
--- /dev/null
+++ b/libxfs/xfs_attr.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2000,2002-2003,2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ * 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
+ */
+#ifndef __XFS_ATTR_H__
+#define	__XFS_ATTR_H__
+
+struct xfs_inode;
+struct xfs_da_args;
+struct xfs_attr_list_context;
+
+/*
+ * Large attribute lists are structured around Btrees where all the data
+ * elements are in the leaf nodes.  Attribute names are hashed into an int,
+ * then that int is used as the index into the Btree.  Since the hashval
+ * of an attribute name may not be unique, we may have duplicate keys.
+ * The internal links in the Btree are logical block offsets into the file.
+ *
+ * Small attribute lists use a different format and are packed as tightly
+ * as possible so as to fit into the literal area of the inode.
+ */
+
+/*========================================================================
+ * External interfaces
+ *========================================================================*/
+
+
+#define ATTR_DONTFOLLOW	0x0001	/* -- unused, from IRIX -- */
+#define ATTR_ROOT	0x0002	/* use attrs in root (trusted) namespace */
+#define ATTR_TRUST	0x0004	/* -- unused, from IRIX -- */
+#define ATTR_SECURE	0x0008	/* use attrs in security namespace */
+#define ATTR_CREATE	0x0010	/* pure create: fail if attr already exists */
+#define ATTR_REPLACE	0x0020	/* pure set: fail if attr does not exist */
+
+#define ATTR_INCOMPLETE	0x4000	/* [kernel] return INCOMPLETE attr keys */
+
+#define XFS_ATTR_FLAGS \
+	{ ATTR_DONTFOLLOW, 	"DONTFOLLOW" }, \
+	{ ATTR_ROOT,		"ROOT" }, \
+	{ ATTR_TRUST,		"TRUST" }, \
+	{ ATTR_SECURE,		"SECURE" }, \
+	{ ATTR_CREATE,		"CREATE" }, \
+	{ ATTR_REPLACE,		"REPLACE" }, \
+	{ ATTR_KERNOTIME,	"KERNOTIME" }, \
+	{ ATTR_KERNOVAL,	"KERNOVAL" }, \
+	{ ATTR_INCOMPLETE,	"INCOMPLETE" }
+
+/*
+ * The maximum size (into the kernel or returned from the kernel) of an
+ * attribute value or the buffer used for an attr_list() call.  Larger
+ * sizes will result in an ERANGE return code.
+ */
+#define	ATTR_MAX_VALUELEN	(64*1024)	/* max length of a value */
+
+/*
+ * Define how lists of attribute names are returned to the user from
+ * the attr_list() call.  A large, 32bit aligned, buffer is passed in
+ * along with its size.  We put an array of offsets at the top that each
+ * reference an attrlist_ent_t and pack the attrlist_ent_t's at the bottom.
+ */
+typedef struct attrlist {
+	__s32	al_count;	/* number of entries in attrlist */
+	__s32	al_more;	/* T/F: more attrs (do call again) */
+	__s32	al_offset[1];	/* byte offsets of attrs [var-sized] */
+} attrlist_t;
+
+/*
+ * Show the interesting info about one attribute.  This is what the
+ * al_offset[i] entry points to.
+ */
+typedef struct attrlist_ent {	/* data from attr_list() */
+	__u32	a_valuelen;	/* number bytes in value of attr */
+	char	a_name[1];	/* attr name (NULL terminated) */
+} attrlist_ent_t;
+
+/*
+ * Given a pointer to the (char*) buffer containing the attr_list() result,
+ * and an index, return a pointer to the indicated attribute in the buffer.
+ */
+#define	ATTR_ENTRY(buffer, index)		\
+	((attrlist_ent_t *)			\
+	 &((char *)buffer)[ ((attrlist_t *)(buffer))->al_offset[index] ])
+
+/*
+ * Kernel-internal version of the attrlist cursor.
+ */
+typedef struct attrlist_cursor_kern {
+	__u32	hashval;	/* hash value of next entry to add */
+	__u32	blkno;		/* block containing entry (suggestion) */
+	__u32	offset;		/* offset in list of equal-hashvals */
+	__u16	pad1;		/* padding to match user-level */
+	__u8	pad2;		/* padding to match user-level */
+	__u8	initted;	/* T/F: cursor has been initialized */
+} attrlist_cursor_kern_t;
+
+
+/*========================================================================
+ * Structure used to pass context around among the routines.
+ *========================================================================*/
+
+
+/* void; state communicated via *context */
+typedef void (*put_listent_func_t)(struct xfs_attr_list_context *, int,
+			      unsigned char *, int, int);
+
+typedef struct xfs_attr_list_context {
+	struct xfs_trans		*tp;
+	struct xfs_inode		*dp;		/* inode */
+	struct attrlist_cursor_kern	*cursor;	/* position in list */
+	char				*alist;		/* output buffer */
+	int				seen_enough;	/* T/F: seen enough of list? */
+	ssize_t				count;		/* num used entries */
+	int				dupcnt;		/* count dup hashvals seen */
+	int				bufsize;	/* total buffer size */
+	int				firstu;		/* first used byte in buffer */
+	int				flags;		/* from VOP call */
+	int				resynch;	/* T/F: resynch with cursor */
+	put_listent_func_t		put_listent;	/* list output fmt function */
+	int				index;		/* index into output buffer */
+} xfs_attr_list_context_t;
+
+
+/*========================================================================
+ * Function prototypes for the kernel.
+ *========================================================================*/
+
+/*
+ * Overall external interface routines.
+ */
+int xfs_attr_inactive(struct xfs_inode *dp);
+int xfs_attr_list_int_ilocked(struct xfs_attr_list_context *);
+int xfs_attr_list_int(struct xfs_attr_list_context *);
+int xfs_inode_hasattr(struct xfs_inode *ip);
+int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
+int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
+		 unsigned char *value, int *valuelenp, int flags);
+int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
+		 unsigned char *value, int valuelen, int flags);
+int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
+int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
+		  int flags, struct attrlist_cursor_kern *cursor);
+
+
+#endif	/* __XFS_ATTR_H__ */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 02/21] xfsprogs: Add trans toggle to attr routines
  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  4:41 ` Allison Henderson
  2018-05-08  4:41 ` [PATCH 03/21] xfsprogs: Add attibute set and helper functions Allison Henderson
                   ` (18 subsequent siblings)
  20 siblings, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

This patch adds a roll_trans parameter to all attribute routines.
Calling functions may pass true to roll transactions as normal,
or false to hold them.  We will need this later for delayed
attribute operations.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 libxfs/xfs_attr.c      | 144 +++++++++++++++++++++++++++----------------------
 libxfs/xfs_attr_leaf.c |  12 +++--
 libxfs/xfs_attr_leaf.h |   8 +--
 3 files changed, 90 insertions(+), 74 deletions(-)

diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c
index a4bde02..359fba1 100644
--- a/libxfs/xfs_attr.c
+++ b/libxfs/xfs_attr.c
@@ -50,21 +50,21 @@
 /*
  * Internal routines when attribute list fits inside the inode.
  */
-STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
+STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args, bool roll_trans);
 
 /*
  * Internal routines when attribute list is one block.
  */
 STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
-STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
-STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
+STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args, bool roll_trans);
+STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args, bool roll_trans);
 
 /*
  * Internal routines when attribute list is more than one block.
  */
 STATIC int xfs_attr_node_get(xfs_da_args_t *args);
-STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
-STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
+STATIC int xfs_attr_node_addname(xfs_da_args_t *args, bool roll_trans);
+STATIC int xfs_attr_node_removename(xfs_da_args_t *args, bool roll_trans);
 STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
 STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
 
@@ -292,7 +292,7 @@ xfs_attr_set(
 		 * Try to add the attr to the attribute list in
 		 * the inode.
 		 */
-		error = xfs_attr_shortform_addname(&args);
+		error = xfs_attr_shortform_addname(&args, true);
 		if (error != -ENOSPC) {
 			/*
 			 * Commit the shortform mods, and we're done.
@@ -351,9 +351,9 @@ xfs_attr_set(
 	}
 
 	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
-		error = xfs_attr_leaf_addname(&args);
+		error = xfs_attr_leaf_addname(&args, true);
 	else
-		error = xfs_attr_node_addname(&args);
+		error = xfs_attr_node_addname(&args, true);
 	if (error)
 		goto out;
 
@@ -448,11 +448,11 @@ xfs_attr_remove(
 		error = -ENOATTR;
 	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
 		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
-		error = xfs_attr_shortform_remove(&args);
+		error = xfs_attr_shortform_remove(&args, true);
 	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
-		error = xfs_attr_leaf_removename(&args);
+		error = xfs_attr_leaf_removename(&args, true);
 	} else {
-		error = xfs_attr_node_removename(&args);
+		error = xfs_attr_node_removename(&args, true);
 	}
 
 	if (error)
@@ -493,7 +493,7 @@ out:
  * This is the external routine.
  */
 STATIC int
-xfs_attr_shortform_addname(xfs_da_args_t *args)
+xfs_attr_shortform_addname(xfs_da_args_t *args, bool roll_trans)
 {
 	int newsize, forkoff, retval;
 
@@ -505,7 +505,7 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
 	} else if (retval == -EEXIST) {
 		if (args->flags & ATTR_CREATE)
 			return retval;
-		retval = xfs_attr_shortform_remove(args);
+		retval = xfs_attr_shortform_remove(args, roll_trans);
 		ASSERT(retval == 0);
 	}
 
@@ -520,7 +520,7 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
 	if (!forkoff)
 		return -ENOSPC;
 
-	xfs_attr_shortform_add(args, forkoff);
+	xfs_attr_shortform_add(args, forkoff, roll_trans);
 	return 0;
 }
 
@@ -536,7 +536,7 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
  * if bmap_one_block() says there is only one block (ie: no remote blks).
  */
 STATIC int
-xfs_attr_leaf_addname(xfs_da_args_t *args)
+xfs_attr_leaf_addname(xfs_da_args_t *args, bool roll_trans)
 {
 	xfs_inode_t *dp;
 	struct xfs_buf *bp;
@@ -599,36 +599,42 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
 		 * can manage its own transactions.
 		 */
 		xfs_defer_init(args->dfops, args->firstblock);
-		error = xfs_attr3_leaf_to_node(args);
-		if (error)
-			goto out_defer_cancel;
-		xfs_defer_ijoin(args->dfops, dp);
-		error = xfs_defer_finish(&args->trans, args->dfops);
+		error = xfs_attr3_leaf_to_node(args, roll_trans);
 		if (error)
 			goto out_defer_cancel;
+		if (roll_trans) {
+			xfs_defer_ijoin(args->dfops, dp);
+			error = xfs_defer_finish(&args->trans, args->dfops);
+			if (error)
+				goto out_defer_cancel;
 
-		/*
-		 * Commit the current trans (including the inode) and start
-		 * a new one.
-		 */
-		error = xfs_trans_roll_inode(&args->trans, dp);
-		if (error)
-			return error;
+			/*
+			 * Commit the current trans (including the inode) and start
+			 * a new one.
+			 */
+			error = xfs_trans_roll_inode(&args->trans, dp);
+			if (error)
+				return error;
+		}
 
 		/*
 		 * Fob the whole rest of the problem off on the Btree code.
 		 */
-		error = xfs_attr_node_addname(args);
+		error = xfs_attr_node_addname(args, roll_trans);
+
 		return error;
 	}
 
-	/*
-	 * Commit the transaction that added the attr name so that
-	 * later routines can manage their own transactions.
-	 */
-	error = xfs_trans_roll_inode(&args->trans, dp);
-	if (error)
-		return error;
+
+	if (roll_trans) {
+		/*
+		 * Commit the transaction that added the attr name so that
+		 * later routines can manage their own transactions.
+		 */
+		error = xfs_trans_roll_inode(&args->trans, dp);
+		if (error)
+			return error;
+	}
 
 	/*
 	 * If there was an out-of-line value, allocate the blocks we
@@ -686,9 +692,9 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
 		/*
 		 * If the result is small enough, shrink it all into the inode.
 		 */
-		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
+		if ((forkoff = xfs_attr_shortform_allfit(bp, dp)) && roll_trans) {
 			xfs_defer_init(args->dfops, args->firstblock);
-			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
+			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff, roll_trans);
 			/* bp is gone due to xfs_da_shrink_inode */
 			if (error)
 				goto out_defer_cancel;
@@ -722,7 +728,7 @@ out_defer_cancel:
  * if bmap_one_block() says there is only one block (ie: no remote blks).
  */
 STATIC int
-xfs_attr_leaf_removename(xfs_da_args_t *args)
+xfs_attr_leaf_removename(xfs_da_args_t *args, bool roll_trans)
 {
 	xfs_inode_t *dp;
 	struct xfs_buf *bp;
@@ -750,9 +756,9 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
 	/*
 	 * If the result is small enough, shrink it all into the inode.
 	 */
-	if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
+	if ((forkoff = xfs_attr_shortform_allfit(bp, dp)) && roll_trans) {
 		xfs_defer_init(args->dfops, args->firstblock);
-		error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
+		error = xfs_attr3_leaf_to_shortform(bp, args, forkoff, roll_trans);
 		/* bp is gone due to xfs_da_shrink_inode */
 		if (error)
 			goto out_defer_cancel;
@@ -814,7 +820,7 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
  * add a whole extra layer of confusion on top of that.
  */
 STATIC int
-xfs_attr_node_addname(xfs_da_args_t *args)
+xfs_attr_node_addname(xfs_da_args_t *args, bool roll_trans)
 {
 	xfs_da_state_t *state;
 	xfs_da_state_blk_t *blk;
@@ -880,21 +886,23 @@ restart:
 			xfs_da_state_free(state);
 			state = NULL;
 			xfs_defer_init(args->dfops, args->firstblock);
-			error = xfs_attr3_leaf_to_node(args);
+			error = xfs_attr3_leaf_to_node(args, roll_trans);
 			if (error)
 				goto out_defer_cancel;
 			xfs_defer_ijoin(args->dfops, dp);
-			error = xfs_defer_finish(&args->trans, args->dfops);
-			if (error)
-				goto out_defer_cancel;
-
-			/*
-			 * Commit the node conversion and start the next
-			 * trans in the chain.
-			 */
-			error = xfs_trans_roll_inode(&args->trans, dp);
-			if (error)
-				goto out;
+			if (roll_trans) {
+				error = xfs_defer_finish(&args->trans, args->dfops);
+				if (error)
+					goto out_defer_cancel;
+
+				/*
+				 * Commit the node conversion and start the next
+				 * trans in the chain.
+				 */
+				error = xfs_trans_roll_inode(&args->trans, dp);
+				if (error)
+					goto out;
+			}
 
 			goto restart;
 		}
@@ -910,9 +918,11 @@ restart:
 		if (error)
 			goto out_defer_cancel;
 		xfs_defer_ijoin(args->dfops, dp);
-		error = xfs_defer_finish(&args->trans, args->dfops);
-		if (error)
-			goto out_defer_cancel;
+		if (roll_trans) {
+			error = xfs_defer_finish(&args->trans, args->dfops);
+			if (error)
+				goto out_defer_cancel;
+		}
 	} else {
 		/*
 		 * Addition succeeded, update Btree hashvals.
@@ -931,9 +941,11 @@ restart:
 	 * Commit the leaf addition or btree split and start the next
 	 * trans in the chain.
 	 */
-	error = xfs_trans_roll_inode(&args->trans, dp);
-	if (error)
-		goto out;
+	if (roll_trans) {
+		error = xfs_trans_roll_inode(&args->trans, dp);
+		if (error)
+			goto out;
+	}
 
 	/*
 	 * If there was an out-of-line value, allocate the blocks we
@@ -1008,9 +1020,11 @@ restart:
 			if (error)
 				goto out_defer_cancel;
 			xfs_defer_ijoin(args->dfops, dp);
-			error = xfs_defer_finish(&args->trans, args->dfops);
-			if (error)
-				goto out_defer_cancel;
+			if (roll_trans) {
+				error = xfs_defer_finish(&args->trans, args->dfops);
+				if (error)
+					goto out_defer_cancel;
+			}
 		}
 
 		/*
@@ -1049,7 +1063,7 @@ out_defer_cancel:
  * the root node (a special case of an intermediate node).
  */
 STATIC int
-xfs_attr_node_removename(xfs_da_args_t *args)
+xfs_attr_node_removename(xfs_da_args_t *args, bool roll_trans)
 {
 	xfs_da_state_t *state;
 	xfs_da_state_blk_t *blk;
@@ -1158,9 +1172,9 @@ xfs_attr_node_removename(xfs_da_args_t *args)
 		if (error)
 			goto out;
 
-		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
+		if ((forkoff = xfs_attr_shortform_allfit(bp, dp)) && roll_trans) {
 			xfs_defer_init(args->dfops, args->firstblock);
-			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
+			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff, roll_trans);
 			/* bp is gone due to xfs_da_shrink_inode */
 			if (error)
 				goto out_defer_cancel;
diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c
index c3682eb..ef53215 100644
--- a/libxfs/xfs_attr_leaf.c
+++ b/libxfs/xfs_attr_leaf.c
@@ -541,7 +541,7 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
  * Overflow from the inode has already been checked for.
  */
 void
-xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
+xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff, bool roll_trans)
 {
 	xfs_attr_shortform_t *sf;
 	xfs_attr_sf_entry_t *sfe;
@@ -613,7 +613,7 @@ xfs_attr_fork_remove(
  * Remove an attribute from the shortform attribute list structure.
  */
 int
-xfs_attr_shortform_remove(xfs_da_args_t *args)
+xfs_attr_shortform_remove(xfs_da_args_t *args, bool roll_trans)
 {
 	xfs_attr_shortform_t *sf;
 	xfs_attr_sf_entry_t *sfe;
@@ -965,7 +965,8 @@ int
 xfs_attr3_leaf_to_shortform(
 	struct xfs_buf		*bp,
 	struct xfs_da_args	*args,
-	int			forkoff)
+	int			forkoff,
+	bool			roll_trans)
 {
 	struct xfs_attr_leafblock *leaf;
 	struct xfs_attr3_icleaf_hdr ichdr;
@@ -1034,7 +1035,7 @@ xfs_attr3_leaf_to_shortform(
 		nargs.valuelen = be16_to_cpu(name_loc->valuelen);
 		nargs.hashval = be32_to_cpu(entry->hashval);
 		nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags);
-		xfs_attr_shortform_add(&nargs, forkoff);
+		xfs_attr_shortform_add(&nargs, forkoff, roll_trans);
 	}
 	error = 0;
 
@@ -1048,7 +1049,8 @@ out:
  */
 int
 xfs_attr3_leaf_to_node(
-	struct xfs_da_args	*args)
+	struct xfs_da_args	*args,
+	bool			roll_trans)
 {
 	struct xfs_attr_leafblock *leaf;
 	struct xfs_attr3_icleaf_hdr icleafhdr;
diff --git a/libxfs/xfs_attr_leaf.h b/libxfs/xfs_attr_leaf.h
index 4da08af..b5dea0e 100644
--- a/libxfs/xfs_attr_leaf.h
+++ b/libxfs/xfs_attr_leaf.h
@@ -45,12 +45,12 @@ typedef struct xfs_attr_inactive_list {
  * Internal routines when attribute fork size < XFS_LITINO(mp).
  */
 void	xfs_attr_shortform_create(struct xfs_da_args *args);
-void	xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff);
+void	xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff, bool roll_trans);
 int	xfs_attr_shortform_lookup(struct xfs_da_args *args);
 int	xfs_attr_shortform_getvalue(struct xfs_da_args *args);
 int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
 			struct xfs_buf **leaf_bp);
-int	xfs_attr_shortform_remove(struct xfs_da_args *args);
+int	xfs_attr_shortform_remove(struct xfs_da_args *args, bool roll_trans);
 int	xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
 int	xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes);
 xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_inode *ip);
@@ -59,9 +59,9 @@ void	xfs_attr_fork_remove(struct xfs_inode *ip, struct xfs_trans *tp);
 /*
  * Internal routines when attribute fork size == XFS_LBSIZE(mp).
  */
-int	xfs_attr3_leaf_to_node(struct xfs_da_args *args);
+int	xfs_attr3_leaf_to_node(struct xfs_da_args *args, bool roll_trans);
 int	xfs_attr3_leaf_to_shortform(struct xfs_buf *bp,
-				   struct xfs_da_args *args, int forkoff);
+				   struct xfs_da_args *args, int forkoff, bool roll_trans);
 int	xfs_attr3_leaf_clearflag(struct xfs_da_args *args);
 int	xfs_attr3_leaf_setflag(struct xfs_da_args *args);
 int	xfs_attr3_leaf_flipflags(struct xfs_da_args *args);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 03/21] xfsprogs: Add attibute set and helper functions
  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  4:41 ` [PATCH 02/21] xfsprogs: Add trans toggle to attr routines Allison Henderson
@ 2018-05-08  4:41 ` Allison Henderson
  2018-05-08  4:41 ` [PATCH 04/21] xfsprogs: Add attibute remove " Allison Henderson
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

This patch adds xfs_attr_set_args and xfs_bmap_set_attrforkoff.
These sub-routines set the attributes specified in @args.
We will use this later for setting parent pointers as a deferred
attribute operation.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 libxfs/xfs_attr.c | 217 +++++++++++++++++++++++++++++++++---------------------
 libxfs/xfs_attr.h |   2 +
 libxfs/xfs_bmap.c |  49 +++++++-----
 libxfs/xfs_bmap.h |   1 +
 4 files changed, 165 insertions(+), 104 deletions(-)

diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c
index 359fba1..3386799 100644
--- a/libxfs/xfs_attr.c
+++ b/libxfs/xfs_attr.c
@@ -163,6 +163,134 @@ xfs_attr_get(
 }
 
 /*
+ * Set the attribute specified in @args. In the case of the parent attribute
+ * being set, we do not want to roll the transaction on shortform-to-leaf
+ * conversion, as the attribute must be added in the same transaction as the
+ * parent directory modifications. Hence @roll_trans needs to be set
+ * appropriately to control whether the transaction is committed during this
+ * function.
+ */
+int
+xfs_attr_set_args(
+	struct xfs_da_args	*args,
+	int			flags,
+	struct xfs_buf          *leaf_bp,
+	bool			roll_trans)
+{
+	struct xfs_inode	*dp = args->dp;
+	struct xfs_mount        *mp = dp->i_mount;
+	int			error = 0;
+	int			err2 = 0;
+	int			sf_size;
+
+	/*
+	 * New inodes setting the parent pointer attr will
+	 * not have an attribute fork yet. So set the attribute
+	 * fork appropriately
+	 */
+	if (XFS_IFORK_Q((args->dp)) == 0) {
+		sf_size = sizeof(struct xfs_attr_sf_hdr) +
+		     XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
+		xfs_bmap_set_attrforkoff(args->dp, sf_size, NULL);
+		args->dp->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
+		args->dp->i_afp->if_flags = XFS_IFEXTENTS;
+	}
+
+	xfs_trans_ijoin(args->trans, dp, 0);
+	/*
+	 * If the attribute list is non-existent or a shortform list,
+	 * upgrade it to a single-leaf-block attribute list.
+	 */
+	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
+	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
+	     dp->i_d.di_anextents == 0)) {
+
+		/*
+		 * Build initial attribute list (if required).
+		 */
+		if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
+			xfs_attr_shortform_create(args);
+
+		/*
+		 * Try to add the attr to the attribute list in the inode.
+		 */
+		error = xfs_attr_shortform_addname(args, roll_trans);
+		if (error != -ENOSPC) {
+			if (roll_trans) {
+				/*
+				 * Commit the shortform mods, and we're done.
+				 * NOTE: this is also the error path (EEXIST, etc).
+				 */
+				ASSERT(args->trans != NULL);
+
+				/*
+				 * If this is a synchronous mount, make sure that
+				 * the transaction goes to disk before returning
+				 * to the user.
+				 */
+				if (mp->m_flags & XFS_MOUNT_WSYNC)
+					xfs_trans_set_sync(args->trans);
+
+				if (!error && (flags & ATTR_KERNOTIME) == 0)
+					xfs_trans_ichgtime(args->trans, dp,
+							   XFS_ICHGTIME_CHG);
+
+				err2 = xfs_trans_commit(args->trans);
+				error = error ? error : err2;
+			}
+			goto out;
+		}
+
+		/*
+		 * It won't fit in the shortform, transform to a leaf block.
+		 * GROT: another possible req'mt for a double-split btree op.
+		 */
+		error = xfs_attr_shortform_to_leaf(args, &leaf_bp);
+		if (error)
+			goto out;
+
+		xfs_defer_bjoin(args->dfops, leaf_bp);
+		xfs_defer_ijoin(args->dfops, dp);
+		if (roll_trans) {
+			/*
+			 * Prevent the leaf buffer from being unlocked so that a
+			 * concurrent AIL push cannot grab the half-baked leaf
+			 * buffer and run into problems with the write verifier.
+			 */
+			xfs_trans_bhold(args->trans, leaf_bp);
+
+			error = xfs_defer_finish(&args->trans, args->dfops);
+			if (error) {
+				args->trans = NULL;
+				goto out;
+			}
+
+			/*
+			 * Commit the leaf transformation.  We'll need another
+			 * (linked) transaction to add the new attribute to the
+			 * leaf.
+			 */
+			error = xfs_trans_roll_inode(&args->trans, dp);
+			if (error)
+				goto out;
+			xfs_defer_ijoin(args->dfops, dp);
+			xfs_trans_bjoin(args->trans, leaf_bp);
+				leaf_bp = NULL;
+		}
+	}
+
+	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
+		error = xfs_attr_leaf_addname(args, roll_trans);
+	else
+		error = xfs_attr_node_addname(args, roll_trans);
+	if (error)
+		goto out;
+
+out:
+	return error;
+}
+
+/*
  * Calculate how many blocks we need for the new attribute,
  */
 STATIC int
@@ -213,7 +341,7 @@ xfs_attr_set(
 	struct xfs_trans_res	tres;
 	xfs_fsblock_t		firstblock;
 	int			rsvd = (flags & ATTR_ROOT) != 0;
-	int			error, err2, local;
+	int			error, local;
 
 	XFS_STATS_INC(mp, xs_attr_set);
 
@@ -274,88 +402,11 @@ xfs_attr_set(
 
 	xfs_trans_ijoin(args.trans, dp, 0);
 
-	/*
-	 * If the attribute list is non-existent or a shortform list,
-	 * upgrade it to a single-leaf-block attribute list.
-	 */
-	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
-	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
-	     dp->i_d.di_anextents == 0)) {
-
-		/*
-		 * Build initial attribute list (if required).
-		 */
-		if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
-			xfs_attr_shortform_create(&args);
-
-		/*
-		 * Try to add the attr to the attribute list in
-		 * the inode.
-		 */
-		error = xfs_attr_shortform_addname(&args, true);
-		if (error != -ENOSPC) {
-			/*
-			 * Commit the shortform mods, and we're done.
-			 * NOTE: this is also the error path (EEXIST, etc).
-			 */
-			ASSERT(args.trans != NULL);
-
-			/*
-			 * If this is a synchronous mount, make sure that
-			 * the transaction goes to disk before returning
-			 * to the user.
-			 */
-			if (mp->m_flags & XFS_MOUNT_WSYNC)
-				xfs_trans_set_sync(args.trans);
-
-			if (!error && (flags & ATTR_KERNOTIME) == 0) {
-				xfs_trans_ichgtime(args.trans, dp,
-							XFS_ICHGTIME_CHG);
-			}
-			err2 = xfs_trans_commit(args.trans);
-			xfs_iunlock(dp, XFS_ILOCK_EXCL);
-
-			return error ? error : err2;
-		}
-
-		/*
-		 * It won't fit in the shortform, transform to a leaf block.
-		 * GROT: another possible req'mt for a double-split btree op.
-		 */
-		xfs_defer_init(args.dfops, args.firstblock);
-		error = xfs_attr_shortform_to_leaf(&args, &leaf_bp);
-		if (error)
-			goto out_defer_cancel;
-		/*
-		 * Prevent the leaf buffer from being unlocked so that a
-		 * concurrent AIL push cannot grab the half-baked leaf
-		 * buffer and run into problems with the write verifier.
-		 */
-		xfs_trans_bhold(args.trans, leaf_bp);
-		xfs_defer_bjoin(args.dfops, leaf_bp);
-		xfs_defer_ijoin(args.dfops, dp);
-		error = xfs_defer_finish(&args.trans, args.dfops);
-		if (error)
-			goto out_defer_cancel;
-
-		/*
-		 * Commit the leaf transformation.  We'll need another (linked)
-		 * transaction to add the new attribute to the leaf, which
-		 * means that we have to hold & join the leaf buffer here too.
-		 */
-		error = xfs_trans_roll_inode(&args.trans, dp);
-		if (error)
-			goto out;
-		xfs_trans_bjoin(args.trans, leaf_bp);
-		leaf_bp = NULL;
-	}
+	xfs_defer_init(args.dfops, args.firstblock);
+	error = xfs_attr_set_args(&args, flags, leaf_bp, true);
 
-	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
-		error = xfs_attr_leaf_addname(&args, true);
-	else
-		error = xfs_attr_node_addname(&args, true);
 	if (error)
-		goto out;
+		goto out_defer_cancel;
 
 	/*
 	 * If this is a synchronous mount, make sure that the
@@ -364,9 +415,6 @@ xfs_attr_set(
 	if (mp->m_flags & XFS_MOUNT_WSYNC)
 		xfs_trans_set_sync(args.trans);
 
-	if ((flags & ATTR_KERNOTIME) == 0)
-		xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
-
 	/*
 	 * Commit the last in the sequence of transactions.
 	 */
@@ -378,7 +426,6 @@ xfs_attr_set(
 
 out_defer_cancel:
 	xfs_defer_cancel(&dfops);
-out:
 	if (leaf_bp)
 		xfs_trans_brelse(args.trans, leaf_bp);
 	if (args.trans)
diff --git a/libxfs/xfs_attr.h b/libxfs/xfs_attr.h
index 8abf398..adb1619 100644
--- a/libxfs/xfs_attr.h
+++ b/libxfs/xfs_attr.h
@@ -149,6 +149,8 @@ int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
 		 unsigned char *value, int *valuelenp, int flags);
 int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
 		 unsigned char *value, int valuelen, int flags);
+int xfs_attr_set_args(struct xfs_da_args *args, int flags,
+			struct xfs_buf *leaf_bp, bool roll_trans);
 int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
 int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
 		  int flags, struct attrlist_cursor_kern *cursor);
diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c
index afc569c..79fcaf0 100644
--- a/libxfs/xfs_bmap.c
+++ b/libxfs/xfs_bmap.c
@@ -1022,6 +1022,34 @@ xfs_bmap_add_attrfork_local(
 	return -EFSCORRUPTED;
 }
 
+/* Set an inode attr fork off based on the format */
+int
+xfs_bmap_set_attrforkoff(
+	struct xfs_inode	*ip,
+	int			size,
+	int			*version)
+{
+	switch (ip->i_d.di_format) {
+	case XFS_DINODE_FMT_DEV:
+		ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3;
+		break;
+	case XFS_DINODE_FMT_LOCAL:
+	case XFS_DINODE_FMT_EXTENTS:
+	case XFS_DINODE_FMT_BTREE:
+		ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size);
+		if (!ip->i_d.di_forkoff)
+			ip->i_d.di_forkoff = xfs_default_attroffset(ip) >> 3;
+		else if ((ip->i_mount->m_flags & XFS_MOUNT_ATTR2) && version)
+			*version = 2;
+		break;
+	default:
+		ASSERT(0);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 /*
  * Convert inode from non-attributed to attributed.
  * Must not be in a transaction, ip must not be locked.
@@ -1075,26 +1103,9 @@ xfs_bmap_add_attrfork(
 
 	xfs_trans_ijoin(tp, ip, 0);
 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-
-	switch (ip->i_d.di_format) {
-	case XFS_DINODE_FMT_DEV:
-		ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3;
-		break;
-	case XFS_DINODE_FMT_LOCAL:
-	case XFS_DINODE_FMT_EXTENTS:
-	case XFS_DINODE_FMT_BTREE:
-		ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size);
-		if (!ip->i_d.di_forkoff)
-			ip->i_d.di_forkoff = xfs_default_attroffset(ip) >> 3;
-		else if (mp->m_flags & XFS_MOUNT_ATTR2)
-			version = 2;
-		break;
-	default:
-		ASSERT(0);
-		error = -EINVAL;
+	error = xfs_bmap_set_attrforkoff(ip, size, &version);
+	if (error)
 		goto trans_cancel;
-	}
-
 	ASSERT(ip->i_afp == NULL);
 	ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
 	ip->i_afp->if_flags = XFS_IFEXTENTS;
diff --git a/libxfs/xfs_bmap.h b/libxfs/xfs_bmap.h
index e36d757..f7e51e6 100644
--- a/libxfs/xfs_bmap.h
+++ b/libxfs/xfs_bmap.h
@@ -191,6 +191,7 @@ void	xfs_trim_extent(struct xfs_bmbt_irec *irec, xfs_fileoff_t bno,
 		xfs_filblks_t len);
 void	xfs_trim_extent_eof(struct xfs_bmbt_irec *, struct xfs_inode *);
 int	xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd);
+int	xfs_bmap_set_attrforkoff(struct xfs_inode *ip, int size, int *version);
 void	xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork);
 void	xfs_bmap_add_free(struct xfs_mount *mp, struct xfs_defer_ops *dfops,
 			  xfs_fsblock_t bno, xfs_filblks_t len,
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 04/21] xfsprogs: Add attibute remove and helper functions
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (2 preceding siblings ...)
  2018-05-08  4:41 ` [PATCH 03/21] xfsprogs: Add attibute set and helper functions Allison Henderson
@ 2018-05-08  4:41 ` Allison Henderson
  2018-05-08  4:41 ` [PATCH 05/21] xfsprogs: Set up infastructure for deferred attribute operations Allison Henderson
                   ` (16 subsequent siblings)
  20 siblings, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

This patch adds xfs_attr_remove_args. This sub-routine removes
the attributes specified in @args. We will use this later for setting
parent pointers as a deferred attribute operation.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 libxfs/xfs_attr.c | 43 +++++++++++++++++++++++++++++++++----------
 libxfs/xfs_attr.h |  1 +
 2 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c
index 3386799..0869bb1 100644
--- a/libxfs/xfs_attr.c
+++ b/libxfs/xfs_attr.c
@@ -291,6 +291,34 @@ out:
 }
 
 /*
+ * Remove the attribute specified in @args.
+ */
+int
+xfs_attr_remove_args(
+	struct xfs_da_args      *args,
+	int			flags,
+	bool                    roll_trans)
+{
+	struct xfs_inode	*dp = args->dp;
+	int			error;
+
+	xfs_trans_ijoin(args->trans, dp, 0);
+
+	if (!xfs_inode_hasattr(dp)) {
+		error = -ENOATTR;
+	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
+		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
+		error = xfs_attr_shortform_remove(args, roll_trans);
+	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+		error = xfs_attr_leaf_removename(args, roll_trans);
+	} else {
+		error = xfs_attr_node_removename(args, roll_trans);
+	}
+
+	return error;
+}
+
+/*
  * Calculate how many blocks we need for the new attribute,
  */
 STATIC int
@@ -434,6 +462,7 @@ out_defer_cancel:
 	return error;
 }
 
+
 /*
  * Generic handler routine to remove a name from an attribute list.
  * Transitions attribute list from Btree to shortform as necessary.
@@ -490,17 +519,9 @@ xfs_attr_remove(
 	 * blocks not allocate in the common case.
 	 */
 	xfs_trans_ijoin(args.trans, dp, 0);
+	xfs_defer_init(args.dfops, args.firstblock);
 
-	if (!xfs_inode_hasattr(dp)) {
-		error = -ENOATTR;
-	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
-		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
-		error = xfs_attr_shortform_remove(&args, true);
-	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
-		error = xfs_attr_leaf_removename(&args, true);
-	} else {
-		error = xfs_attr_node_removename(&args, true);
-	}
+	error = xfs_attr_remove_args(&args, flags, true);
 
 	if (error)
 		goto out;
@@ -525,6 +546,8 @@ xfs_attr_remove(
 	return error;
 
 out:
+	xfs_defer_cancel(&dfops);
+
 	if (args.trans)
 		xfs_trans_cancel(args.trans);
 	xfs_iunlock(dp, XFS_ILOCK_EXCL);
diff --git a/libxfs/xfs_attr.h b/libxfs/xfs_attr.h
index adb1619..de2b99f 100644
--- a/libxfs/xfs_attr.h
+++ b/libxfs/xfs_attr.h
@@ -152,6 +152,7 @@ int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
 int xfs_attr_set_args(struct xfs_da_args *args, int flags,
 			struct xfs_buf *leaf_bp, bool roll_trans);
 int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
+int xfs_attr_remove_args(struct xfs_da_args *args, int flags, bool roll_trans);
 int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
 		  int flags, struct attrlist_cursor_kern *cursor);
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 05/21] xfsprogs: Set up infastructure for deferred attribute operations
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (3 preceding siblings ...)
  2018-05-08  4:41 ` [PATCH 04/21] xfsprogs: Add attibute remove " Allison Henderson
@ 2018-05-08  4:41 ` Allison Henderson
  2018-05-08  4:41 ` [PATCH 06/21] xfsprogs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred Allison Henderson
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

This patch adds two new log item types for setting or
removing attributes as deferred operations.  The
xfs_attri_log_item logs an intent to set or remove an
attribute.  The corresponding xfs_attrd_log_item holds
a reference to the xfs_attri_log_item and is freed once
the transaction is done.  Both log items use a generic
xfs_attr_log_format structure that contains the attribute
name, value, flags, inode, and an op_flag that indicates
if the operations is a set or remove.

At the moment, this feature will only be used by the parent
pointer patch set which uses attributes to store information
about an inodes parent.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 libxfs/xfs_attr.c       |  5 +++--
 libxfs/xfs_attr.h       | 24 +++++++++++++++++++++++-
 libxfs/xfs_defer.h      |  1 +
 libxfs/xfs_log_format.h | 44 ++++++++++++++++++++++++++++++++++++++++++--
 libxfs/xfs_types.h      |  1 +
 5 files changed, 70 insertions(+), 5 deletions(-)

diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c
index 0869bb1..1d19f64 100644
--- a/libxfs/xfs_attr.c
+++ b/libxfs/xfs_attr.c
@@ -36,6 +36,7 @@
 #include "xfs_attr_remote.h"
 #include "xfs_trans_space.h"
 #include "xfs_trace.h"
+#include "xfs_attr_item.h"
 
 /*
  * xfs_attr.c
@@ -69,7 +70,7 @@ STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
 STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
 
 
-STATIC int
+int
 xfs_attr_args_init(
 	struct xfs_da_args	*args,
 	struct xfs_inode	*dp,
@@ -321,7 +322,7 @@ xfs_attr_remove_args(
 /*
  * Calculate how many blocks we need for the new attribute,
  */
-STATIC int
+int
 xfs_attr_calc_size(
 	struct xfs_da_args	*args,
 	int			*local)
diff --git a/libxfs/xfs_attr.h b/libxfs/xfs_attr.h
index de2b99f..eebfad7 100644
--- a/libxfs/xfs_attr.h
+++ b/libxfs/xfs_attr.h
@@ -87,6 +87,26 @@ typedef struct attrlist_ent {	/* data from attr_list() */
 } attrlist_ent_t;
 
 /*
+ * List of attrs to commit later.
+ */
+struct xfs_attr_item {
+	struct xfs_inode  *xattri_ip;
+	uint32_t	  xattri_op_flags;
+	uint32_t	  xattri_value_len;   /* length of value */
+	uint32_t	  xattri_name_len;    /* length of name */
+	uint32_t	  xattri_flags;       /* attr flags */
+	struct list_head  xattri_list;
+
+	/*
+	 * A byte array follows the header containing the file name and
+	 * attribute value.
+	 */
+};
+
+#define XFS_ATTR_ITEM_SIZEOF(namelen, valuelen)	\
+	(sizeof(struct xfs_attr_item) + (namelen) + (valuelen))
+
+/*
  * Given a pointer to the (char*) buffer containing the attr_list() result,
  * and an index, return a pointer to the indicated attribute in the buffer.
  */
@@ -155,6 +175,8 @@ int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
 int xfs_attr_remove_args(struct xfs_da_args *args, int flags, bool roll_trans);
 int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
 		  int flags, struct attrlist_cursor_kern *cursor);
-
+int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
+		       const unsigned char *name, int flags);
+int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
 
 #endif	/* __XFS_ATTR_H__ */
diff --git a/libxfs/xfs_defer.h b/libxfs/xfs_defer.h
index 045beac..11e1690 100644
--- a/libxfs/xfs_defer.h
+++ b/libxfs/xfs_defer.h
@@ -55,6 +55,7 @@ enum xfs_defer_ops_type {
 	XFS_DEFER_OPS_TYPE_REFCOUNT,
 	XFS_DEFER_OPS_TYPE_RMAP,
 	XFS_DEFER_OPS_TYPE_FREE,
+	XFS_DEFER_OPS_TYPE_ATTR,
 	XFS_DEFER_OPS_TYPE_MAX,
 };
 
diff --git a/libxfs/xfs_log_format.h b/libxfs/xfs_log_format.h
index 349d9f8..291e5ff 100644
--- a/libxfs/xfs_log_format.h
+++ b/libxfs/xfs_log_format.h
@@ -116,7 +116,12 @@ static inline uint xlog_get_cycle(char *ptr)
 #define XLOG_REG_TYPE_CUD_FORMAT	24
 #define XLOG_REG_TYPE_BUI_FORMAT	25
 #define XLOG_REG_TYPE_BUD_FORMAT	26
-#define XLOG_REG_TYPE_MAX		26
+#define XLOG_REG_TYPE_ATTRI_FORMAT	27
+#define XLOG_REG_TYPE_ATTRD_FORMAT	28
+#define XLOG_REG_TYPE_ATTR_NAME	29
+#define XLOG_REG_TYPE_ATTR_VALUE	30
+#define XLOG_REG_TYPE_MAX		31
+
 
 /*
  * Flags to log operation header
@@ -239,6 +244,8 @@ typedef struct xfs_trans_header {
 #define	XFS_LI_CUD		0x1243
 #define	XFS_LI_BUI		0x1244	/* bmbt update intent */
 #define	XFS_LI_BUD		0x1245
+#define	XFS_LI_ATTRI		0x1246  /* attr set/remove intent*/
+#define	XFS_LI_ATTRD		0x1247  /* attr set/remove done */
 
 #define XFS_LI_TYPE_DESC \
 	{ XFS_LI_EFI,		"XFS_LI_EFI" }, \
@@ -254,7 +261,9 @@ typedef struct xfs_trans_header {
 	{ XFS_LI_CUI,		"XFS_LI_CUI" }, \
 	{ XFS_LI_CUD,		"XFS_LI_CUD" }, \
 	{ XFS_LI_BUI,		"XFS_LI_BUI" }, \
-	{ XFS_LI_BUD,		"XFS_LI_BUD" }
+	{ XFS_LI_BUD,		"XFS_LI_BUD" }, \
+	{ XFS_LI_ATTRI,		"XFS_LI_ATTRI" }, \
+	{ XFS_LI_ATTRD,		"XFS_LI_ATTRD" }
 
 /*
  * Inode Log Item Format definitions.
@@ -852,4 +861,35 @@ struct xfs_icreate_log {
 	__be32		icl_gen;	/* inode generation number to use */
 };
 
+/*
+ * Flags for deferred attribute operations.
+ * Upper bits are flags, lower byte is type code
+ */
+#define XFS_ATTR_OP_FLAGS_SET		1	/* Set the attribute */
+#define XFS_ATTR_OP_FLAGS_REMOVE	2	/* Remove the attribute */
+#define XFS_ATTR_OP_FLAGS_TYPE_MASK	0x0FF	/* Flags type mask */
+
+/*
+ * This is the structure used to lay out an attr log item in the
+ * log.
+ */
+struct xfs_attri_log_format {
+	uint16_t	alfi_type;	/* attri log item type */
+	uint16_t	alfi_size;	/* size of this item */
+	uint32_t	__pad;		/* pad to 64 bit aligned */
+	uint64_t	alfi_id;	/* attri identifier */
+	xfs_ino_t       alfi_ino;	/* the inode for this attr operation */
+	uint32_t        alfi_op_flags;	/* marks the op as a set or remove */
+	uint32_t        alfi_name_len;	/* attr name length */
+	uint32_t        alfi_value_len;	/* attr value length */
+	uint32_t        alfi_attr_flags;/* attr flags */
+};
+
+struct xfs_attrd_log_format {
+	uint16_t	alfd_type;	/* attrd log item type */
+	uint16_t	alfd_size;	/* size of this item */
+	uint32_t	__pad;		/* pad to 64 bit aligned */
+	uint64_t	alfd_alf_id;	/* id of corresponding attrd */
+};
+
 #endif /* __XFS_LOG_FORMAT_H__ */
diff --git a/libxfs/xfs_types.h b/libxfs/xfs_types.h
index 3c56069..2905ce3 100644
--- a/libxfs/xfs_types.h
+++ b/libxfs/xfs_types.h
@@ -23,6 +23,7 @@ typedef uint32_t	prid_t;		/* project ID */
 typedef uint32_t	xfs_agblock_t;	/* blockno in alloc. group */
 typedef uint32_t	xfs_agino_t;	/* inode # within allocation grp */
 typedef uint32_t	xfs_extlen_t;	/* extent length in blocks */
+typedef uint32_t	xfs_attrlen_t;	/* attr length */
 typedef uint32_t	xfs_agnumber_t;	/* allocation group number */
 typedef int32_t		xfs_extnum_t;	/* # of extents in a file */
 typedef int16_t		xfs_aextnum_t;	/* # extents in an attribute fork */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 06/21] xfsprogs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (4 preceding siblings ...)
  2018-05-08  4:41 ` [PATCH 05/21] xfsprogs: Set up infastructure for deferred attribute operations Allison Henderson
@ 2018-05-08  4:41 ` 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
                   ` (14 subsequent siblings)
  20 siblings, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

These routines set up set and start a new deferred attribute
operation.  These functions are meant to be called by other
code needing to initiate a deferred attribute operation.  We
will use these routines later in the parent pointer patches.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 libxfs/xfs_attr.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 libxfs/xfs_attr.h |  5 ++++
 2 files changed, 75 insertions(+)

diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c
index 1d19f64..f6b69c8 100644
--- a/libxfs/xfs_attr.c
+++ b/libxfs/xfs_attr.c
@@ -37,6 +37,7 @@
 #include "xfs_trans_space.h"
 #include "xfs_trace.h"
 #include "xfs_attr_item.h"
+#include "xfs_attr.h"
 
 /*
  * xfs_attr.c
@@ -463,6 +464,42 @@ out_defer_cancel:
 	return error;
 }
 
+/* Sets an attribute for an inode as a deferred operation */
+int
+xfs_attr_set_deferred(
+	struct xfs_inode	*dp,
+	struct xfs_defer_ops    *dfops,
+	void			*name,
+	unsigned int		namelen,
+	void			*value,
+	unsigned int		valuelen,
+	int			flags)
+{
+
+	struct xfs_attr_item	*new;
+	char			*name_value;
+
+	if (!namelen || !valuelen) {
+		ASSERT(0);
+		return -EFSCORRUPTED;
+	}
+
+	new = kmem_alloc(XFS_ATTR_ITEM_SIZEOF(namelen, valuelen),
+			 KM_SLEEP|KM_NOFS);
+	name_value = ((char *)new) + sizeof(struct xfs_attr_item);
+	memset(new, 0, XFS_ATTR_ITEM_SIZEOF(namelen, valuelen));
+	new->xattri_ip = dp;
+	new->xattri_op_flags = XFS_ATTR_OP_FLAGS_SET;
+	new->xattri_name_len = namelen;
+	new->xattri_value_len = valuelen;
+	new->xattri_flags = flags;
+	memcpy(&name_value[0], name, namelen);
+	memcpy(&name_value[namelen], value, valuelen);
+
+	xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
+
+	return 0;
+}
 
 /*
  * Generic handler routine to remove a name from an attribute list.
@@ -555,6 +592,39 @@ out:
 	return error;
 }
 
+/* Removes an attribute for an inode as a deferred operation */
+int
+xfs_attr_remove_deferred(
+	struct xfs_inode        *dp,
+	struct xfs_defer_ops    *dfops,
+	void			*name,
+	unsigned int		namelen,
+	int                     flags)
+{
+
+	struct xfs_attr_item	*new;
+	char			*name_value;
+
+	if (!namelen) {
+		ASSERT(0);
+		return -EFSCORRUPTED;
+	}
+
+	new = kmem_alloc(XFS_ATTR_ITEM_SIZEOF(namelen, 0), KM_SLEEP|KM_NOFS);
+	name_value = ((char *)new) + sizeof(struct xfs_attr_item);
+	memset(new, 0, XFS_ATTR_ITEM_SIZEOF(namelen, 0));
+	new->xattri_ip = dp;
+	new->xattri_op_flags = XFS_ATTR_OP_FLAGS_REMOVE;
+	new->xattri_name_len = namelen;
+	new->xattri_value_len = 0;
+	new->xattri_flags = flags;
+	memcpy(name_value, name, namelen);
+
+	xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
+
+	return 0;
+}
+
 /*========================================================================
  * External routines when attribute list is inside the inode
  *========================================================================*/
diff --git a/libxfs/xfs_attr.h b/libxfs/xfs_attr.h
index eebfad7..c706976 100644
--- a/libxfs/xfs_attr.h
+++ b/libxfs/xfs_attr.h
@@ -178,5 +178,10 @@ int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
 int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
 		       const unsigned char *name, int flags);
 int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
+int xfs_attr_set_deferred(struct xfs_inode *dp, struct xfs_defer_ops *dfops,
+			  void *name, unsigned int name_len, void *value,
+			  unsigned int valuelen, int flags);
+int xfs_attr_remove_deferred(struct xfs_inode *dp, struct xfs_defer_ops *dfops,
+			    void *name, unsigned int namelen, int flags);
 
 #endif	/* __XFS_ATTR_H__ */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 07/21] xfsprogs: Remove all strlen calls in all xfs_attr_* functions for attr names.
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (5 preceding siblings ...)
  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 ` Allison Henderson
  2018-05-08  4:41 ` [PATCH 08/21] xfsprogs: get directory offset when adding directory name Allison Henderson
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

Parent pointer attributes use a binary name, so strlen will not work.
Calling functions will need to pass in the name length

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 libxfs/xfs_attr.c | 12 ++++++++----
 libxfs/xfs_attr.h | 10 ++++++----
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c
index f6b69c8..f83aa33 100644
--- a/libxfs/xfs_attr.c
+++ b/libxfs/xfs_attr.c
@@ -76,6 +76,7 @@ xfs_attr_args_init(
 	struct xfs_da_args	*args,
 	struct xfs_inode	*dp,
 	const unsigned char	*name,
+	size_t			namelen,
 	int			flags)
 {
 
@@ -88,7 +89,7 @@ xfs_attr_args_init(
 	args->dp = dp;
 	args->flags = flags;
 	args->name = name;
-	args->namelen = strlen((const char *)name);
+	args->namelen = namelen;
 	if (args->namelen >= MAXNAMELEN)
 		return -EFAULT;		/* match IRIX behaviour */
 
@@ -134,6 +135,7 @@ int
 xfs_attr_get(
 	struct xfs_inode	*ip,
 	const unsigned char	*name,
+	size_t			namelen,
 	unsigned char		*value,
 	int			*valuelenp,
 	int			flags)
@@ -147,7 +149,7 @@ xfs_attr_get(
 	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, ip, name, flags);
+	error = xfs_attr_args_init(&args, ip, name, namelen, flags);
 	if (error)
 		return error;
 
@@ -360,6 +362,7 @@ int
 xfs_attr_set(
 	struct xfs_inode	*dp,
 	const unsigned char	*name,
+	size_t			namelen,
 	unsigned char		*value,
 	int			valuelen,
 	int			flags)
@@ -378,7 +381,7 @@ xfs_attr_set(
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, dp, name, flags);
+	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
 	if (error)
 		return error;
 
@@ -509,6 +512,7 @@ int
 xfs_attr_remove(
 	struct xfs_inode	*dp,
 	const unsigned char	*name,
+	size_t			namelen,
 	int			flags)
 {
 	struct xfs_mount	*mp = dp->i_mount;
@@ -522,7 +526,7 @@ xfs_attr_remove(
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, dp, name, flags);
+	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
 	if (error)
 		return error;
 
diff --git a/libxfs/xfs_attr.h b/libxfs/xfs_attr.h
index c706976..d23cf4a 100644
--- a/libxfs/xfs_attr.h
+++ b/libxfs/xfs_attr.h
@@ -166,17 +166,19 @@ int xfs_attr_list_int(struct xfs_attr_list_context *);
 int xfs_inode_hasattr(struct xfs_inode *ip);
 int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
 int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
-		 unsigned char *value, int *valuelenp, int flags);
+		size_t namelen, unsigned char *value, int *valuelenp,
+		int flags);
 int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
-		 unsigned char *value, int valuelen, int flags);
+		size_t namelen, unsigned char *value, int valuelen, int flags);
 int xfs_attr_set_args(struct xfs_da_args *args, int flags,
 			struct xfs_buf *leaf_bp, bool roll_trans);
-int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
+int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
+		size_t namelen, int flags);
 int xfs_attr_remove_args(struct xfs_da_args *args, int flags, bool roll_trans);
 int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
 		  int flags, struct attrlist_cursor_kern *cursor);
 int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
-		       const unsigned char *name, int flags);
+		       const unsigned char *name, size_t namelen, int flags);
 int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
 int xfs_attr_set_deferred(struct xfs_inode *dp, struct xfs_defer_ops *dfops,
 			  void *name, unsigned int name_len, void *value,
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 08/21] xfsprogs: get directory offset when adding directory name
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (6 preceding siblings ...)
  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 ` Allison Henderson
  2018-05-08  4:41 ` [PATCH 09/21] xfsprogs: get directory offset when removing " Allison Henderson
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

Return the directory offset information when adding an entry to the
directory.

This offset will be used as the parent pointer offset in xfs_create,
xfs_symlink, xfs_link and xfs_rename.

[dchinner: forward ported and cleaned up]
[dchinner: no s-o-b from Mark]
[bfoster: rebased, use args->geo in dir code]
[achender: rebased, chaged __uint32_t to xfs_dir2_dataptr_t]

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 libxfs/xfs_da_btree.h   |  1 +
 libxfs/xfs_dir2.c       |  9 +++++++--
 libxfs/xfs_dir2.h       |  3 ++-
 libxfs/xfs_dir2_block.c |  1 +
 libxfs/xfs_dir2_leaf.c  |  2 ++
 libxfs/xfs_dir2_node.c  |  2 ++
 libxfs/xfs_dir2_sf.c    |  2 ++
 mkfs/proto.c            |  3 ++-
 repair/phase6.c         | 17 +++++++++--------
 9 files changed, 28 insertions(+), 12 deletions(-)

diff --git a/libxfs/xfs_da_btree.h b/libxfs/xfs_da_btree.h
index ae6de17..bce96d6 100644
--- a/libxfs/xfs_da_btree.h
+++ b/libxfs/xfs_da_btree.h
@@ -86,6 +86,7 @@ typedef struct xfs_da_args {
 	int		rmtvaluelen2;	/* remote attr value length in bytes */
 	int		op_flags;	/* operation flags */
 	enum xfs_dacmp	cmpresult;	/* name compare result for lookups */
+	xfs_dir2_dataptr_t offset;	/* OUT: offset in directory */
 } xfs_da_args_t;
 
 /*
diff --git a/libxfs/xfs_dir2.c b/libxfs/xfs_dir2.c
index d82eaab..cd67e1b 100644
--- a/libxfs/xfs_dir2.c
+++ b/libxfs/xfs_dir2.c
@@ -255,7 +255,8 @@ xfs_dir_createname(
 	xfs_ino_t		inum,		/* new entry inode number */
 	xfs_fsblock_t		*first,		/* bmap's firstblock */
 	struct xfs_defer_ops	*dfops,		/* bmap's freeblock list */
-	xfs_extlen_t		total)		/* bmap's total block count */
+	xfs_extlen_t		total,		/* bmap's total block count */
+	xfs_dir2_dataptr_t	*offset)	/* OUT entry's dir offset */
 {
 	struct xfs_da_args	*args;
 	int			rval;
@@ -311,6 +312,10 @@ xfs_dir_createname(
 		rval = xfs_dir2_node_addname(args);
 
 out_free:
+	/* return the location that this entry was place in the parent inode */
+	if (offset)
+		*offset = args->offset;
+
 	kmem_free(args);
 	return rval;
 }
@@ -557,7 +562,7 @@ xfs_dir_canenter(
 	xfs_inode_t	*dp,
 	struct xfs_name	*name)		/* name of entry to add */
 {
-	return xfs_dir_createname(tp, dp, name, 0, NULL, NULL, 0);
+	return xfs_dir_createname(tp, dp, name, 0, NULL, NULL, 0, NULL);
 }
 
 /*
diff --git a/libxfs/xfs_dir2.h b/libxfs/xfs_dir2.h
index 388d67c..378c654 100644
--- a/libxfs/xfs_dir2.h
+++ b/libxfs/xfs_dir2.h
@@ -131,7 +131,8 @@ extern int xfs_dir_init(struct xfs_trans *tp, struct xfs_inode *dp,
 extern int xfs_dir_createname(struct xfs_trans *tp, struct xfs_inode *dp,
 				struct xfs_name *name, xfs_ino_t inum,
 				xfs_fsblock_t *first,
-				struct xfs_defer_ops *dfops, xfs_extlen_t tot);
+				struct xfs_defer_ops *dfops, xfs_extlen_t tot,
+				xfs_dir2_dataptr_t *offset);
 extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
 				struct xfs_name *name, xfs_ino_t *inum,
 				struct xfs_name *ci_name);
diff --git a/libxfs/xfs_dir2_block.c b/libxfs/xfs_dir2_block.c
index e2c524e..4815d26 100644
--- a/libxfs/xfs_dir2_block.c
+++ b/libxfs/xfs_dir2_block.c
@@ -549,6 +549,7 @@ xfs_dir2_block_addname(
 	dp->d_ops->data_put_ftype(dep, args->filetype);
 	tagp = dp->d_ops->data_entry_tag_p(dep);
 	*tagp = cpu_to_be16((char *)dep - (char *)hdr);
+	args->offset = xfs_dir2_byte_to_dataptr((char *)dep - (char *)hdr);
 	/*
 	 * Clean up the bestfree array and log the header, tail, and entry.
 	 */
diff --git a/libxfs/xfs_dir2_leaf.c b/libxfs/xfs_dir2_leaf.c
index 60f7eb2..949e798 100644
--- a/libxfs/xfs_dir2_leaf.c
+++ b/libxfs/xfs_dir2_leaf.c
@@ -887,6 +887,8 @@ xfs_dir2_leaf_addname(
 	dp->d_ops->data_put_ftype(dep, args->filetype);
 	tagp = dp->d_ops->data_entry_tag_p(dep);
 	*tagp = cpu_to_be16((char *)dep - (char *)hdr);
+	args->offset = xfs_dir2_db_off_to_dataptr(args->geo, use_block,
+						(char *)dep - (char *)hdr);
 	/*
 	 * Need to scan fix up the bestfree table.
 	 */
diff --git a/libxfs/xfs_dir2_node.c b/libxfs/xfs_dir2_node.c
index 6d7986c..697e37e 100644
--- a/libxfs/xfs_dir2_node.c
+++ b/libxfs/xfs_dir2_node.c
@@ -2032,6 +2032,8 @@ xfs_dir2_node_addname_int(
 	dp->d_ops->data_put_ftype(dep, args->filetype);
 	tagp = dp->d_ops->data_entry_tag_p(dep);
 	*tagp = cpu_to_be16((char *)dep - (char *)hdr);
+	args->offset = xfs_dir2_db_off_to_dataptr(args->geo, dbno,
+						  (char *)dep - (char *)hdr);
 	xfs_dir2_data_log_entry(args, dbp, dep);
 	/*
 	 * Rescan the block for bestfree if needed.
diff --git a/libxfs/xfs_dir2_sf.c b/libxfs/xfs_dir2_sf.c
index fbb9482..e601208 100644
--- a/libxfs/xfs_dir2_sf.c
+++ b/libxfs/xfs_dir2_sf.c
@@ -403,6 +403,7 @@ xfs_dir2_sf_addname_easy(
 	memcpy(sfep->name, args->name, sfep->namelen);
 	dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
 	dp->d_ops->sf_put_ftype(sfep, args->filetype);
+	args->offset = xfs_dir2_byte_to_dataptr(offset);
 
 	/*
 	 * Update the header and inode.
@@ -494,6 +495,7 @@ xfs_dir2_sf_addname_hard(
 	memcpy(sfep->name, args->name, sfep->namelen);
 	dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
 	dp->d_ops->sf_put_ftype(sfep, args->filetype);
+	args->offset = xfs_dir2_byte_to_dataptr(offset);
 	sfp->count++;
 	if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)
 		sfp->i8count++;
diff --git a/mkfs/proto.c b/mkfs/proto.c
index bc38345..67c228a 100644
--- a/mkfs/proto.c
+++ b/mkfs/proto.c
@@ -331,7 +331,8 @@ newdirent(
 
 	rsv = XFS_DIRENTER_SPACE_RES(mp, name->len);
 
-	error = -libxfs_dir_createname(tp, pip, name, inum, first, dfops, rsv);
+	error = -libxfs_dir_createname(tp, pip, name, inum, first, dfops, rsv,
+				       NULL);
 	if (error)
 		fail(_("directory createname error"), error);
 }
diff --git a/repair/phase6.c b/repair/phase6.c
index 498a3b5..b41cc2b 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -1061,7 +1061,7 @@ mk_orphanage(xfs_mount_t *mp)
 	 * create the actual entry
 	 */
 	error = -libxfs_dir_createname(tp, pip, &xname, ip->i_ino, &first,
-					&dfops, nres);
+					&dfops, nres, NULL);
 	if (error)
 		do_error(
 		_("can't make %s, createname error %d\n"),
@@ -1170,7 +1170,7 @@ mv_orphanage(
 
 			libxfs_defer_init(&dfops, &first);
 			err = -libxfs_dir_createname(tp, orphanage_ip, &xname,
-						ino, &first, &dfops, nres);
+						ino, &first, &dfops, nres, NULL);
 			if (err)
 				do_error(
 	_("name create failed in %s (%d), filesystem may be out of space\n"),
@@ -1183,7 +1183,7 @@ mv_orphanage(
 			libxfs_trans_log_inode(tp, orphanage_ip, XFS_ILOG_CORE);
 
 			err = -libxfs_dir_createname(tp, ino_p, &xfs_name_dotdot,
-					orphanage_ino, &first, &dfops, nres);
+					orphanage_ino, &first, &dfops, nres, NULL);
 			if (err)
 				do_error(
 	_("creation of .. entry failed (%d), filesystem may be out of space\n"),
@@ -1214,7 +1214,7 @@ mv_orphanage(
 			libxfs_defer_init(&dfops, &first);
 
 			err = -libxfs_dir_createname(tp, orphanage_ip, &xname,
-						ino, &first, &dfops, nres);
+						ino, &first, &dfops, nres, NULL);
 			if (err)
 				do_error(
 	_("name create failed in %s (%d), filesystem may be out of space\n"),
@@ -1270,7 +1270,7 @@ mv_orphanage(
 
 		libxfs_defer_init(&dfops, &first);
 		err = -libxfs_dir_createname(tp, orphanage_ip, &xname, ino,
-						&first, &dfops, nres);
+						&first, &dfops, nres, NULL);
 		if (err)
 			do_error(
 	_("name create failed in %s (%d), filesystem may be out of space\n"),
@@ -1408,7 +1408,8 @@ longform_dir2_rebuild(
 
 		libxfs_defer_init(&dfops, &firstblock);
 		error = -libxfs_dir_createname(tp, ip, &p->name, p->inum,
-						&firstblock, &dfops, nres);
+						&firstblock, &dfops, nres,
+						NULL);
 		if (error) {
 			do_warn(
 _("name create failed in ino %" PRIu64 " (%d), filesystem may be out of space\n"),
@@ -3011,7 +3012,7 @@ process_dir_inode(
 		libxfs_defer_init(&dfops, &first);
 
 		error = -libxfs_dir_createname(tp, ip, &xfs_name_dotdot,
-					ip->i_ino, &first, &dfops, nres);
+					ip->i_ino, &first, &dfops, nres, NULL);
 		if (error)
 			do_error(
 	_("can't make \"..\" entry in root inode %" PRIu64 ", createname error %d\n"), ino, error);
@@ -3069,7 +3070,7 @@ process_dir_inode(
 			libxfs_defer_init(&dfops, &first);
 
 			error = -libxfs_dir_createname(tp, ip, &xfs_name_dot,
-					ip->i_ino, &first, &dfops, nres);
+					ip->i_ino, &first, &dfops, nres, NULL);
 			if (error)
 				do_error(
 	_("can't make \".\" entry in dir ino %" PRIu64 ", createname error %d\n"),
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 09/21] xfsprogs: get directory offset when removing directory name
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (7 preceding siblings ...)
  2018-05-08  4:41 ` [PATCH 08/21] xfsprogs: get directory offset when adding directory name Allison Henderson
@ 2018-05-08  4:41 ` Allison Henderson
  2018-05-08  4:41 ` [PATCH 10/21] xfsprogs: get directory offset when replacing a " Allison Henderson
                   ` (11 subsequent siblings)
  20 siblings, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

Return the directory offset information when removing an entry to the
directory.

This offset will be used as the parent pointer offset in xfs_remove.

[dchinner: forward ported and cleaned up]
[achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
       Changed typedefs to raw struct types]

Signed-off-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 libxfs/xfs_dir2.c       | 16 ++++++++++------
 libxfs/xfs_dir2.h       |  4 +++-
 libxfs/xfs_dir2_block.c |  4 ++--
 libxfs/xfs_dir2_leaf.c  |  5 +++--
 libxfs/xfs_dir2_node.c  |  5 +++--
 libxfs/xfs_dir2_sf.c    |  2 ++
 6 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/libxfs/xfs_dir2.c b/libxfs/xfs_dir2.c
index cd67e1b..ef9fba6 100644
--- a/libxfs/xfs_dir2.c
+++ b/libxfs/xfs_dir2.c
@@ -431,13 +431,14 @@ out_free:
  */
 int
 xfs_dir_removename(
-	xfs_trans_t	*tp,
-	xfs_inode_t	*dp,
-	struct xfs_name	*name,
-	xfs_ino_t	ino,
-	xfs_fsblock_t	*first,		/* bmap's firstblock */
+	struct xfs_trans	*tp,
+	struct xfs_inode	*dp,
+	struct xfs_name		*name,
+	xfs_ino_t		ino,
+	xfs_fsblock_t		*first,		/* bmap's firstblock */
 	struct xfs_defer_ops	*dfops,		/* bmap's freeblock list */
-	xfs_extlen_t	total)		/* bmap's total block count */
+	xfs_extlen_t		total,		/* bmap's total block count */
+	xfs_dir2_dataptr_t	*offset)	/* OUT: offset in directory */
 {
 	struct xfs_da_args *args;
 	int		rval;
@@ -484,6 +485,9 @@ xfs_dir_removename(
 	else
 		rval = xfs_dir2_node_removename(args);
 out_free:
+	if (offset)
+		*offset = args->offset;
+
 	kmem_free(args);
 	return rval;
 }
diff --git a/libxfs/xfs_dir2.h b/libxfs/xfs_dir2.h
index 378c654..e2cd70b 100644
--- a/libxfs/xfs_dir2.h
+++ b/libxfs/xfs_dir2.h
@@ -139,7 +139,9 @@ extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
 extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
 				struct xfs_name *name, xfs_ino_t ino,
 				xfs_fsblock_t *first,
-				struct xfs_defer_ops *dfops, xfs_extlen_t tot);
+				struct xfs_defer_ops *dfops,
+				xfs_extlen_t tot,
+				xfs_dir2_dataptr_t *offset);
 extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
 				struct xfs_name *name, xfs_ino_t inum,
 				xfs_fsblock_t *first,
diff --git a/libxfs/xfs_dir2_block.c b/libxfs/xfs_dir2_block.c
index 4815d26..e7ce6a9 100644
--- a/libxfs/xfs_dir2_block.c
+++ b/libxfs/xfs_dir2_block.c
@@ -788,9 +788,9 @@ xfs_dir2_block_removename(
 	/*
 	 * Point to the data entry using the leaf entry.
 	 */
+	args->offset = be32_to_cpu(blp[ent].address);
 	dep = (xfs_dir2_data_entry_t *)((char *)hdr +
-			xfs_dir2_dataptr_to_off(args->geo,
-						be32_to_cpu(blp[ent].address)));
+			xfs_dir2_dataptr_to_off(args->geo, args->offset));
 	/*
 	 * Mark the data entry's space free.
 	 */
diff --git a/libxfs/xfs_dir2_leaf.c b/libxfs/xfs_dir2_leaf.c
index 949e798..8cca19e 100644
--- a/libxfs/xfs_dir2_leaf.c
+++ b/libxfs/xfs_dir2_leaf.c
@@ -1407,9 +1407,10 @@ xfs_dir2_leaf_removename(
 	 * Point to the leaf entry, use that to point to the data entry.
 	 */
 	lep = &ents[index];
-	db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address));
+	args->offset = be32_to_cpu(lep->address);
+	db = xfs_dir2_dataptr_to_db(args->geo, args->offset);
 	dep = (xfs_dir2_data_entry_t *)((char *)hdr +
-		xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address)));
+		xfs_dir2_dataptr_to_off(args->geo, args->offset));
 	needscan = needlog = 0;
 	oldbest = be16_to_cpu(bf[0].length);
 	ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
diff --git a/libxfs/xfs_dir2_node.c b/libxfs/xfs_dir2_node.c
index 697e37e..e4ca481 100644
--- a/libxfs/xfs_dir2_node.c
+++ b/libxfs/xfs_dir2_node.c
@@ -1248,9 +1248,10 @@ xfs_dir2_leafn_remove(
 	/*
 	 * Extract the data block and offset from the entry.
 	 */
-	db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address));
+	args->offset = be32_to_cpu(lep->address);
+	db = xfs_dir2_dataptr_to_db(args->geo, args->offset);
 	ASSERT(dblk->blkno == db);
-	off = xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address));
+	off = xfs_dir2_dataptr_to_off(args->geo, args->offset);
 	ASSERT(dblk->index == off);
 
 	/*
diff --git a/libxfs/xfs_dir2_sf.c b/libxfs/xfs_dir2_sf.c
index e601208..8013ddd 100644
--- a/libxfs/xfs_dir2_sf.c
+++ b/libxfs/xfs_dir2_sf.c
@@ -915,6 +915,8 @@ xfs_dir2_sf_removename(
 								XFS_CMP_EXACT) {
 			ASSERT(dp->d_ops->sf_get_ino(sfp, sfep) ==
 			       args->inumber);
+			args->offset = xfs_dir2_byte_to_dataptr(
+						xfs_dir2_sf_get_offset(sfep));
 			break;
 		}
 	}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 10/21] xfsprogs: get directory offset when replacing a directory name
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (8 preceding siblings ...)
  2018-05-08  4:41 ` [PATCH 09/21] xfsprogs: get directory offset when removing " Allison Henderson
@ 2018-05-08  4:41 ` Allison Henderson
  2018-05-08  4:41 ` [PATCH 11/21] xfsprogs: add parent pointer support to attribute code Allison Henderson
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

Return the directory offset information when replacing an entry to the
directory.

This offset will be used as the parent pointer offset in xfs_rename.

[dchinner: forward ported and cleaned up]
[achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
       Changed typedefs to raw struct types]

Signed-off-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 libxfs/xfs_dir2.c       | 16 ++++++++++------
 libxfs/xfs_dir2.h       |  3 ++-
 libxfs/xfs_dir2_block.c |  4 ++--
 libxfs/xfs_dir2_leaf.c  |  1 +
 libxfs/xfs_dir2_node.c  |  1 +
 libxfs/xfs_dir2_sf.c    |  2 ++
 repair/phase6.c         |  2 +-
 7 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/libxfs/xfs_dir2.c b/libxfs/xfs_dir2.c
index ef9fba6..57894c8 100644
--- a/libxfs/xfs_dir2.c
+++ b/libxfs/xfs_dir2.c
@@ -497,13 +497,14 @@ out_free:
  */
 int
 xfs_dir_replace(
-	xfs_trans_t	*tp,
-	xfs_inode_t	*dp,
-	struct xfs_name	*name,		/* name of entry to replace */
-	xfs_ino_t	inum,		/* new inode number */
-	xfs_fsblock_t	*first,		/* bmap's firstblock */
+	struct xfs_trans	*tp,
+	struct xfs_inode	*dp,
+	struct xfs_name		*name,		/* name of entry to replace */
+	xfs_ino_t		inum,		/* new inode number */
+	xfs_fsblock_t		*first,		/* bmap's firstblock */
 	struct xfs_defer_ops	*dfops,		/* bmap's freeblock list */
-	xfs_extlen_t	total)		/* bmap's total block count */
+	xfs_extlen_t		total,		/* bmap's total block count */
+	xfs_dir2_dataptr_t	*offset)	/* OUT: offset in directory */
 {
 	struct xfs_da_args *args;
 	int		rval;
@@ -553,6 +554,9 @@ xfs_dir_replace(
 	else
 		rval = xfs_dir2_node_replace(args);
 out_free:
+	if (offset)
+		*offset = args->offset;
+
 	kmem_free(args);
 	return rval;
 }
diff --git a/libxfs/xfs_dir2.h b/libxfs/xfs_dir2.h
index e2cd70b..cb6fda0 100644
--- a/libxfs/xfs_dir2.h
+++ b/libxfs/xfs_dir2.h
@@ -145,7 +145,8 @@ extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
 extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
 				struct xfs_name *name, xfs_ino_t inum,
 				xfs_fsblock_t *first,
-				struct xfs_defer_ops *dfops, xfs_extlen_t tot);
+				struct xfs_defer_ops *dfops, xfs_extlen_t tot,
+				xfs_dir2_dataptr_t *offset);
 extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp,
 				struct xfs_name *name);
 
diff --git a/libxfs/xfs_dir2_block.c b/libxfs/xfs_dir2_block.c
index e7ce6a9..34d6a0d 100644
--- a/libxfs/xfs_dir2_block.c
+++ b/libxfs/xfs_dir2_block.c
@@ -862,9 +862,9 @@ xfs_dir2_block_replace(
 	/*
 	 * Point to the data entry we need to change.
 	 */
+	args->offset = be32_to_cpu(blp[ent].address);
 	dep = (xfs_dir2_data_entry_t *)((char *)hdr +
-			xfs_dir2_dataptr_to_off(args->geo,
-						be32_to_cpu(blp[ent].address)));
+			xfs_dir2_dataptr_to_off(args->geo, args->offset));
 	ASSERT(be64_to_cpu(dep->inumber) != args->inumber);
 	/*
 	 * Change the inode number to the new value.
diff --git a/libxfs/xfs_dir2_leaf.c b/libxfs/xfs_dir2_leaf.c
index 8cca19e..ee16fc4 100644
--- a/libxfs/xfs_dir2_leaf.c
+++ b/libxfs/xfs_dir2_leaf.c
@@ -1542,6 +1542,7 @@ xfs_dir2_leaf_replace(
 	/*
 	 * Point to the data entry.
 	 */
+	args->offset = be32_to_cpu(lep->address);
 	dep = (xfs_dir2_data_entry_t *)
 	      ((char *)dbp->b_addr +
 	       xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address)));
diff --git a/libxfs/xfs_dir2_node.c b/libxfs/xfs_dir2_node.c
index e4ca481..e604b1c 100644
--- a/libxfs/xfs_dir2_node.c
+++ b/libxfs/xfs_dir2_node.c
@@ -2247,6 +2247,7 @@ xfs_dir2_node_replace(
 		hdr = state->extrablk.bp->b_addr;
 		ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
 		       hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC));
+		args->offset = be32_to_cpu(lep->address);
 		dep = (xfs_dir2_data_entry_t *)
 		      ((char *)hdr +
 		       xfs_dir2_dataptr_to_off(args->geo,
diff --git a/libxfs/xfs_dir2_sf.c b/libxfs/xfs_dir2_sf.c
index 8013ddd..11561a9 100644
--- a/libxfs/xfs_dir2_sf.c
+++ b/libxfs/xfs_dir2_sf.c
@@ -1041,6 +1041,8 @@ xfs_dir2_sf_replace(
 				ASSERT(args->inumber != ino);
 				dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
 				dp->d_ops->sf_put_ftype(sfep, args->filetype);
+				args->offset = xfs_dir2_byte_to_dataptr(
+						  xfs_dir2_sf_get_offset(sfep));
 				break;
 			}
 		}
diff --git a/repair/phase6.c b/repair/phase6.c
index b41cc2b..4fedb35 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -1233,7 +1233,7 @@ mv_orphanage(
 			if (entry_ino_num != orphanage_ino)  {
 				err = -libxfs_dir_replace(tp, ino_p,
 						&xfs_name_dotdot, orphanage_ino,
-						&first, &dfops, nres);
+						&first, &dfops, nres, NULL);
 				if (err)
 					do_error(
 	_("name replace op failed (%d), filesystem may be out of space\n"),
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 11/21] xfsprogs: add parent pointer support to attribute code
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (9 preceding siblings ...)
  2018-05-08  4:41 ` [PATCH 10/21] xfsprogs: get directory offset when replacing a " Allison Henderson
@ 2018-05-08  4:41 ` Allison Henderson
  2018-05-08  4:41 ` [PATCH 12/21] xfsprogs: define parent pointer xattr format Allison Henderson
                   ` (9 subsequent siblings)
  20 siblings, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

Add the new parent attribute type. XFS_ATTR_PARENT is used only for
parent pointer entries; it uses reserved blocks like XFS_ATTR_ROOT.

[dchinner: forward ported and cleaned up]
[achender: rebased]

Signed-off-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 libxfs/xfs_attr.c      |  2 +-
 libxfs/xfs_attr.h      |  2 ++
 libxfs/xfs_attr_leaf.c |  1 +
 libxfs/xfs_da_format.h | 12 ++++++++----
 4 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c
index f83aa33..b1f5db6 100644
--- a/libxfs/xfs_attr.c
+++ b/libxfs/xfs_attr.c
@@ -373,7 +373,7 @@ xfs_attr_set(
 	struct xfs_defer_ops	dfops;
 	struct xfs_trans_res	tres;
 	xfs_fsblock_t		firstblock;
-	int			rsvd = (flags & ATTR_ROOT) != 0;
+	bool			rsvd = (flags & (ATTR_ROOT | ATTR_PARENT)) != 0;
 	int			error, local;
 
 	XFS_STATS_INC(mp, xs_attr_set);
diff --git a/libxfs/xfs_attr.h b/libxfs/xfs_attr.h
index d23cf4a..f388f5f 100644
--- a/libxfs/xfs_attr.h
+++ b/libxfs/xfs_attr.h
@@ -44,6 +44,7 @@ struct xfs_attr_list_context;
 #define ATTR_SECURE	0x0008	/* use attrs in security namespace */
 #define ATTR_CREATE	0x0010	/* pure create: fail if attr already exists */
 #define ATTR_REPLACE	0x0020	/* pure set: fail if attr does not exist */
+#define ATTR_PARENT	0x0040	/*  use attrs in parent namespace */
 
 #define ATTR_INCOMPLETE	0x4000	/* [kernel] return INCOMPLETE attr keys */
 
@@ -54,6 +55,7 @@ struct xfs_attr_list_context;
 	{ ATTR_SECURE,		"SECURE" }, \
 	{ ATTR_CREATE,		"CREATE" }, \
 	{ ATTR_REPLACE,		"REPLACE" }, \
+	{ ATTR_PARENT,		"PARENT" }, \
 	{ ATTR_KERNOTIME,	"KERNOTIME" }, \
 	{ ATTR_KERNOVAL,	"KERNOVAL" }, \
 	{ ATTR_INCOMPLETE,	"INCOMPLETE" }
diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c
index ef53215..b037788 100644
--- a/libxfs/xfs_attr_leaf.c
+++ b/libxfs/xfs_attr_leaf.c
@@ -37,6 +37,7 @@
 #include "xfs_trace.h"
 #include "xfs_cksum.h"
 #include "xfs_dir2.h"
+#include "xfs_attr.h"
 
 
 /*
diff --git a/libxfs/xfs_da_format.h b/libxfs/xfs_da_format.h
index 7e77299..9bd2e6b 100644
--- a/libxfs/xfs_da_format.h
+++ b/libxfs/xfs_da_format.h
@@ -758,24 +758,28 @@ struct xfs_attr3_icleaf_hdr {
 #define	XFS_ATTR_LOCAL_BIT	0	/* attr is stored locally */
 #define	XFS_ATTR_ROOT_BIT	1	/* limit access to trusted attrs */
 #define	XFS_ATTR_SECURE_BIT	2	/* limit access to secure attrs */
+#define 	XFS_ATTR_PARENT_BIT	3	/* parent pointer secure attrs */
 #define	XFS_ATTR_INCOMPLETE_BIT	7	/* attr in middle of create/delete */
 #define XFS_ATTR_LOCAL		(1 << XFS_ATTR_LOCAL_BIT)
 #define XFS_ATTR_ROOT		(1 << XFS_ATTR_ROOT_BIT)
 #define XFS_ATTR_SECURE		(1 << XFS_ATTR_SECURE_BIT)
+#define XFS_ATTR_PARENT		(1 << XFS_ATTR_PARENT_BIT)
 #define XFS_ATTR_INCOMPLETE	(1 << XFS_ATTR_INCOMPLETE_BIT)
 
 /*
  * Conversion macros for converting namespace bits from argument flags
  * to ondisk flags.
  */
-#define XFS_ATTR_NSP_ARGS_MASK		(ATTR_ROOT | ATTR_SECURE)
-#define XFS_ATTR_NSP_ONDISK_MASK	(XFS_ATTR_ROOT | XFS_ATTR_SECURE)
+#define XFS_ATTR_NSP_ARGS_MASK		(ATTR_ROOT | ATTR_SECURE | XFS_ATTR_PARENT)
+#define XFS_ATTR_NSP_ONDISK_MASK	(XFS_ATTR_ROOT | XFS_ATTR_SECURE | XFS_ATTR_PARENT)
 #define XFS_ATTR_NSP_ONDISK(flags)	((flags) & XFS_ATTR_NSP_ONDISK_MASK)
 #define XFS_ATTR_NSP_ARGS(flags)	((flags) & XFS_ATTR_NSP_ARGS_MASK)
 #define XFS_ATTR_NSP_ARGS_TO_ONDISK(x)	(((x) & ATTR_ROOT ? XFS_ATTR_ROOT : 0) |\
-					 ((x) & ATTR_SECURE ? XFS_ATTR_SECURE : 0))
+					 ((x) & ATTR_SECURE ? XFS_ATTR_SECURE : 0) | \
+					 ((x) & ATTR_PARENT ? XFS_ATTR_PARENT : 0))
 #define XFS_ATTR_NSP_ONDISK_TO_ARGS(x)	(((x) & XFS_ATTR_ROOT ? ATTR_ROOT : 0) |\
-					 ((x) & XFS_ATTR_SECURE ? ATTR_SECURE : 0))
+					 ((x) & XFS_ATTR_SECURE ? ATTR_SECURE : 0) | \
+					 ((x) & XFS_ATTR_PARENT ? ATTR_PARENT : 0))
 
 /*
  * Alignment for namelist and valuelist entries (since they are mixed
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 12/21] xfsprogs: define parent pointer xattr format
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (10 preceding siblings ...)
  2018-05-08  4:41 ` [PATCH 11/21] xfsprogs: add parent pointer support to attribute code Allison Henderson
@ 2018-05-08  4:41 ` Allison Henderson
  2018-05-08  4:41 ` [PATCH 13/21] xfsprogs: extent transaction reservations for parent attributes Allison Henderson
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

We need to define the parent pointer attribute format before we
start adding support for it into all the code that needs to use it.
The EA format we will use encodes the following information:

    name={parent inode #, parent inode generation, dirent offset}
    value={dirent filename}

The inode/gen gives all the information we need to reliably identify
the parent without requiring child->parent lock ordering, and allows
userspace to do pathname component level reconstruction without the
kernel ever needing to verify the parent itself as part of ioctl
calls.

By using the dirent offset in the EA name, we have a method of
knowing the exact parent pointer EA we need to modify/remove in
rename/unlink without an unbound EA name search.

By keeping the dirent name in the value, we have enough information
to be able to validate and reconstruct damaged directory trees.
While the diroffset of a filename alone is not unique enough to
identify the child, the {diroffset,filename,child_inode} tuple is
sufficient. That is, if the diroffset gets reused and points to a
different filename, we can detect that from the contents of EA. If a
link of the same name is created, then we can check whether it
points at the same inode as the parent EA we current have.

[achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
       changed p_ino to xfs_ino_t and p_namelen to uint8_t,
       moved to xfs_da_format for xfs_dir2_dataptr_t]

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong<darrick.wong@oracle.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 libxfs/xfs_da_format.h | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/libxfs/xfs_da_format.h b/libxfs/xfs_da_format.h
index 9bd2e6b..d1c1221 100644
--- a/libxfs/xfs_da_format.h
+++ b/libxfs/xfs_da_format.h
@@ -878,11 +878,35 @@ struct xfs_attr3_rmt_hdr {
 #define XFS_ATTR3_RMT_BUF_SPACE(mp, bufsize)	\
 	((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \
 			sizeof(struct xfs_attr3_rmt_hdr) : 0))
-
 /* Number of bytes in a directory block. */
 static inline unsigned int xfs_dir2_dirblock_bytes(struct xfs_sb *sbp)
 {
 	return 1 << (sbp->sb_blocklog + sbp->sb_dirblklog);
 }
 
+/*
+ * Parent pointer attribute format definition
+ *
+ * EA name encodes the parent inode number, generation and the offset of
+ * the dirent that points to the child inode. The EA value contains the
+ * same name as the dirent in the parent directory.
+ */
+struct xfs_parent_name_rec {
+	__be64  p_ino;
+	__be32  p_gen;
+	__be32  p_diroffset;
+};
+
+/*
+ * incore version of the above, also contains name pointers so callers
+ * can pass/obtain all the parent pointer information in a single structure
+ */
+struct xfs_parent_name_irec {
+	xfs_ino_t		p_ino;
+	uint32_t		p_gen;
+	xfs_dir2_dataptr_t	p_diroffset;
+	const char		*p_name;
+	uint8_t			p_namelen;
+};
+
 #endif /* __XFS_DA_FORMAT_H__ */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 13/21] xfsprogs: extent transaction reservations for parent attributes
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (11 preceding siblings ...)
  2018-05-08  4:41 ` [PATCH 12/21] xfsprogs: define parent pointer xattr format Allison Henderson
@ 2018-05-08  4:41 ` Allison Henderson
  2018-05-08  4:41 ` [PATCH 14/21] xfsprogs: parent pointer attribute creation Allison Henderson
                   ` (7 subsequent siblings)
  20 siblings, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

We need to add, remove or modify parent pointer attributes during
create/link/unlink/rename operations atomically with the dirents in the parent
directories being modified. This means they need to be modified in the same
transaction as the parent directories, and so we need to add the required
space for the attribute modifications to the transaction reservations.

[achender: rebased, added xfs_sb_version_hasparent stub]

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 libxfs/xfs_format.h     |   5 +++
 libxfs/xfs_trans_resv.c | 111 ++++++++++++++++++++++++++++++++++++++----------
 libxfs/xfs_trans_resv.h |   1 +
 3 files changed, 94 insertions(+), 23 deletions(-)

diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index 4854893..de8b14a 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -559,6 +559,11 @@ static inline bool xfs_sb_version_hasreflink(struct xfs_sb *sbp)
 		(sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_REFLINK);
 }
 
+static inline bool xfs_sb_version_hasparent(struct xfs_sb *sbp)
+{
+	return false; /* We'll enable this at the end of the set */
+}
+
 /*
  * end of superblock version macros
  */
diff --git a/libxfs/xfs_trans_resv.c b/libxfs/xfs_trans_resv.c
index 3cebb90..232245c 100644
--- a/libxfs/xfs_trans_resv.c
+++ b/libxfs/xfs_trans_resv.c
@@ -788,29 +788,30 @@ xfs_calc_sb_reservation(
 	return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize);
 }
 
+/*
+ * Namespace reservations.
+ *
+ * These get tricky when parent pointers are enabled as we have attribute
+ * modifications occurring from within these transactions. Rather than confuse
+ * each of these reservation calculations with the conditional attribute
+ * reservations, add them here in a clear and concise manner. This assumes that
+ * the attribute reservations have already been calculated.
+ *
+ * Note that we only include the static attribute reservation here; the runtime
+ * reservation will have to be modified by the size of the attributes being
+ * added/removed/modified. See the comments on the attribute reservation
+ * calculations for more details.
+ *
+ * Note for rename: rename will vastly overestimate requirements. This will be
+ * addressed later when modifications are made to ensure parent attribute
+ * modifications can be done atomically with the rename operation.
+ */
 void
-xfs_trans_resv_calc(
+xfs_calc_namespace_reservations(
 	struct xfs_mount	*mp,
 	struct xfs_trans_resv	*resp)
 {
-	/*
-	 * The following transactions are logged in physical format and
-	 * require a permanent reservation on space.
-	 */
-	resp->tr_write.tr_logres = xfs_calc_write_reservation(mp);
-	if (xfs_sb_version_hasreflink(&mp->m_sb))
-		resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK;
-	else
-		resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT;
-	resp->tr_write.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
-
-	resp->tr_itruncate.tr_logres = xfs_calc_itruncate_reservation(mp);
-	if (xfs_sb_version_hasreflink(&mp->m_sb))
-		resp->tr_itruncate.tr_logcount =
-				XFS_ITRUNCATE_LOG_COUNT_REFLINK;
-	else
-		resp->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT;
-	resp->tr_itruncate.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+	ASSERT(resp->tr_attrsetm.tr_logres > 0);
 
 	resp->tr_rename.tr_logres = xfs_calc_rename_reservation(mp);
 	resp->tr_rename.tr_logcount = XFS_RENAME_LOG_COUNT;
@@ -832,15 +833,77 @@ xfs_trans_resv_calc(
 	resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT;
 	resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
 
+	resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp);
+	resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT;
+	resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+	xfs_calc_parent_ptr_reservations(mp);
+}
+
+void xfs_calc_parent_ptr_reservations(struct xfs_mount     *mp)
+{
+	struct xfs_trans_resv   *resp = M_RES(mp);
+
+	/* Calculate extra space needed for parent pointer attributes */
+	if (!xfs_sb_version_hasparent(&mp->m_sb))
+		return;
+
+	/* rename can add/remove/modify 2 parent attributes */
+	resp->tr_rename.tr_logres += 2 * max(resp->tr_attrsetm.tr_logres,
+					 resp->tr_attrrm.tr_logres);
+	resp->tr_rename.tr_logcount += 2 * max(resp->tr_attrsetm.tr_logcount,
+					   resp->tr_attrrm.tr_logcount);
+
+	/* create will add 1 parent attribute */
+	resp->tr_create.tr_logres += resp->tr_attrsetm.tr_logres;
+	resp->tr_create.tr_logcount += resp->tr_attrsetm.tr_logcount;
+
+	/* mkdir will add 1 parent attribute */
+	resp->tr_mkdir.tr_logres += resp->tr_attrsetm.tr_logres;
+	resp->tr_mkdir.tr_logcount += resp->tr_attrsetm.tr_logcount;
+
+	/* link will add 1 parent attribute */
+	resp->tr_link.tr_logres += resp->tr_attrsetm.tr_logres;
+	resp->tr_link.tr_logcount += resp->tr_attrsetm.tr_logcount;
+
+	/* symlink will add 1 parent attribute */
+	resp->tr_symlink.tr_logres += resp->tr_attrsetm.tr_logres;
+	resp->tr_symlink.tr_logcount += resp->tr_attrsetm.tr_logcount;
+
+	/* remove will remove 1 parent attribute */
+	resp->tr_remove.tr_logres += resp->tr_attrrm.tr_logres;
+	resp->tr_remove.tr_logcount += resp->tr_attrrm.tr_logcount;
+}
+
+void
+xfs_trans_resv_calc(
+	struct xfs_mount	*mp,
+	struct xfs_trans_resv	*resp)
+{
+	/*
+	 * The following transactions are logged in physical format and
+	 * require a permanent reservation on space.
+	 */
+	resp->tr_write.tr_logres = xfs_calc_write_reservation(mp);
+	if (xfs_sb_version_hasreflink(&mp->m_sb))
+		resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK;
+	else
+		resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT;
+	resp->tr_write.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+	resp->tr_itruncate.tr_logres = xfs_calc_itruncate_reservation(mp);
+	if (xfs_sb_version_hasreflink(&mp->m_sb))
+		resp->tr_itruncate.tr_logcount =
+				XFS_ITRUNCATE_LOG_COUNT_REFLINK;
+	else
+		resp->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT;
+	resp->tr_itruncate.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
 	resp->tr_create_tmpfile.tr_logres =
 			xfs_calc_create_tmpfile_reservation(mp);
 	resp->tr_create_tmpfile.tr_logcount = XFS_CREATE_TMPFILE_LOG_COUNT;
 	resp->tr_create_tmpfile.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
 
-	resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp);
-	resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT;
-	resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
-
 	resp->tr_ifree.tr_logres = xfs_calc_ifree_reservation(mp);
 	resp->tr_ifree.tr_logcount = XFS_INACTIVE_LOG_COUNT;
 	resp->tr_ifree.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
@@ -872,6 +935,8 @@ xfs_trans_resv_calc(
 		resp->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT;
 	resp->tr_qm_dqalloc.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
 
+	xfs_calc_namespace_reservations(mp, resp);
+
 	/*
 	 * The following transactions are logged in logical format with
 	 * a default log count.
diff --git a/libxfs/xfs_trans_resv.h b/libxfs/xfs_trans_resv.h
index b7e5357..c7190d6 100644
--- a/libxfs/xfs_trans_resv.h
+++ b/libxfs/xfs_trans_resv.h
@@ -105,5 +105,6 @@ struct xfs_trans_resv {
 
 void xfs_trans_resv_calc(struct xfs_mount *mp, struct xfs_trans_resv *resp);
 uint xfs_allocfree_log_count(struct xfs_mount *mp, uint num_ops);
+void xfs_calc_parent_ptr_reservations(struct xfs_mount *mp);
 
 #endif	/* __XFS_TRANS_RESV_H__ */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 14/21] xfsprogs: parent pointer attribute creation
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (12 preceding siblings ...)
  2018-05-08  4:41 ` [PATCH 13/21] xfsprogs: extent transaction reservations for parent attributes Allison Henderson
@ 2018-05-08  4:41 ` Allison Henderson
  2018-05-08  4:41 ` [PATCH 15/21] xfsprogs: Add the parent pointer support to the superblock version 5 Allison Henderson
                   ` (6 subsequent siblings)
  20 siblings, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

Add parent pointer attribute during xfs_create, and
subroutines to initialize attributes

Kernel create routines take advantage of deferred attributes,
where as libxfs routines will add parent pointers directly.

[bfoster: rebase, use VFS inode generation]
[achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
       fixed some null pointer bugs,
       merged error handling patch,
       added subroutines to handle attribute initialization,
       remove unnecessary ENOSPC handling in xfs_attr_set_first_parent]

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 libxfs/Makefile     |   2 +
 libxfs/xfs_parent.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 libxfs/xfs_parent.h |  36 +++++++++++
 3 files changed, 206 insertions(+)

diff --git a/libxfs/Makefile b/libxfs/Makefile
index 75ce980..6fdcdf7 100644
--- a/libxfs/Makefile
+++ b/libxfs/Makefile
@@ -37,6 +37,7 @@ HFILES = \
 	xfs_ialloc_btree.h \
 	xfs_inode_buf.h \
 	xfs_inode_fork.h \
+	xfs_parent.h \
 	xfs_quota_defs.h \
 	xfs_refcount.h \
 	xfs_refcount_btree.h \
@@ -89,6 +90,7 @@ CFILES = cache.c \
 	xfs_inode_fork.c \
 	xfs_ialloc_btree.c \
 	xfs_log_rlimit.c \
+	xfs_parent.c \
 	xfs_refcount.c \
 	xfs_refcount_btree.c \
 	xfs_rmap.c \
diff --git a/libxfs/xfs_parent.c b/libxfs/xfs_parent.c
new file mode 100644
index 0000000..b8ec1f6
--- /dev/null
+++ b/libxfs/xfs_parent.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2015 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 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
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "platform_defs.h"
+#include "xfs_arch.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "list.h"
+#include "xfs_shared.h"
+#include "xfs_trans_resv.h"
+#include "radix-tree.h"
+#include "atomic.h"
+#include "xfs_mount.h"
+#include "xfs_da_format.h"
+#include "xfs_bmap_btree.h"
+#include "cache.h"
+#include "xfs_cksum.h"
+#include "libxfs_io.h"
+#include "xfs_inode.h"
+#include "xfs_trace.h"
+#include "xfs_trans.h"
+#include "xfs_attr.h"
+#include "xfs_da_btree.h"
+#include "xfs_attr_sf.h"
+#include "libxfs_api_defs.h"
+
+/*
+ * Parent pointer attribute handling.
+ *
+ * Because the attribute value is a filename component, it will never be longer
+ * than 255 bytes. This means the attribute will always be a local format
+ * attribute as it is xfs_attr_leaf_entsize_local_max() for v5 filesystems will
+ * always be larger than this (max is 75% of block size).
+ *
+ * Creating a new parent attribute will always create a new attribute - there
+ * should never, ever be an existing attribute in the tree for a new inode.
+ * ENOSPC behaviour is problematic - creating the inode without the parent
+ * pointer is effectively a corruption, so we allow parent attribute creation
+ * to dip into the reserve block pool to avoid unexpected ENOSPC errors from
+ * occurring.
+ */
+
+
+/* Initializes a xfs_parent_name_rec to be stored as an attribute name */
+void
+xfs_init_parent_name_rec(
+			struct xfs_parent_name_rec	*rec,
+			xfs_ino_t			p_ino,
+			uint32_t			p_gen,
+			uint32_t			p_diroffset)
+{
+	rec->p_ino = cpu_to_be64(p_ino);
+	rec->p_gen = cpu_to_be32(p_gen);
+	rec->p_diroffset = cpu_to_be32(p_diroffset);
+}
+
+/* Initializes a xfs_parent_name_irec from an xfs_parent_name_rec */
+void
+xfs_init_parent_name_irec(
+			struct xfs_parent_name_irec	*irec,
+			struct xfs_parent_name_rec	*rec)
+{
+	irec->p_ino = be64_to_cpu(rec->p_ino);
+	irec->p_gen = be32_to_cpu(rec->p_gen);
+	irec->p_diroffset = be32_to_cpu(rec->p_diroffset);
+}
+
+/*
+ * Directly add a parent pointer instead of as a deferred operation
+ * Currently only used during protofile creation
+ */
+int
+xfs_parent_add(
+	struct xfs_inode	*parent,
+	struct xfs_inode	*child,
+	struct xfs_name		*child_name,
+	uint32_t		diroffset,
+	xfs_fsblock_t		*firstblock,
+	struct xfs_defer_ops	*dfops)
+{
+	struct xfs_parent_name_rec	rec;
+	int				error;
+	struct xfs_da_args		args;
+	int				flags = ATTR_PARENT;
+	int				local = 0;
+	int				rsvd = 0;
+	struct xfs_buf			*leaf_bp = NULL;
+	struct xfs_trans_res		tres;
+	struct xfs_mount		*mp = child->i_mount;
+
+	xfs_init_parent_name_rec(&rec, parent->i_ino,
+				 VFS_I(parent)->i_generation, diroffset);
+
+	error = xfs_attr_args_init(&args, child, (const unsigned char *)&rec,
+				   sizeof(rec), flags);
+	if (error)
+		return error;
+
+	args.hashval = xfs_da_hashname(args.name, args.namelen);
+	args.value = (char *)child_name->name;
+	args.valuelen = child_name->len;
+	args.dfops = dfops;
+	args.op_flags = XFS_DA_OP_OKNOENT | XFS_DA_OP_ADDNAME;
+	args.firstblock = firstblock;
+	args.total = xfs_attr_calc_size(&args, &local);
+	args.trans = &tres;
+	ASSERT(local);
+
+       tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
+                        M_RES(mp)->tr_attrsetrt.tr_logres * args.total;
+       tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
+       tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
+
+       /*
+        * Root fork attributes can use reserved data blocks for this
+        * operation if necessary
+        */
+       error = xfs_trans_alloc(mp, &tres, args.total, 0,
+                               rsvd ? XFS_TRANS_RESERVE : 0, &args.trans);
+       if (error)
+               goto out;
+
+
+	/*
+	 * If the inode doesn't have an attribute fork, add one.
+	 * (inode must not be locked when we call this routine)
+	 */
+	if (XFS_IFORK_Q(child) == 0) {
+		int sf_size = sizeof(xfs_attr_sf_hdr_t) +
+			XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, args.valuelen);
+
+		error = xfs_bmap_add_attrfork(child, sf_size, rsvd);
+		if (error)
+			return error;
+	}
+
+	error = xfs_attr_set_args(&args, flags, leaf_bp, false);
+
+
+       if (error)
+               goto out;
+
+       xfs_trans_log_inode(args.trans, child, XFS_ILOG_CORE);
+
+       return error;
+
+out:
+       if (args.trans)
+               xfs_trans_cancel(args.trans);
+
+	return error;
+}
+
diff --git a/libxfs/xfs_parent.h b/libxfs/xfs_parent.h
new file mode 100644
index 0000000..298562b
--- /dev/null
+++ b/libxfs/xfs_parent.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Oracle, Inc.
+ * All Rights Reserved.
+ *
+ * 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.
+ *
+ * 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.
+ */
+#ifndef	__XFS_PARENT_H__
+#define	__XFS_PARENT_H__
+
+#include "xfs_da_format.h"
+#include "xfs_format.h"
+
+/*
+ * Parent pointer attribute prototypes
+ */
+void xfs_init_parent_name_rec(struct xfs_parent_name_rec *rec,
+			      xfs_ino_t p_ino, uint32_t p_gen,
+			      uint32_t p_diroffset);
+void xfs_init_parent_name_irec(struct xfs_parent_name_irec *irec,
+			       struct xfs_parent_name_rec *rec);
+
+int xfs_parent_add(struct xfs_trans *tp, struct xfs_inode *parent,
+		   struct xfs_inode *child, struct xfs_name *child_name,
+		   uint32_t diroffset, xfs_fsblock_t *firstblock,
+		   struct xfs_defer_ops *dfops);
+#endif	/* __XFS_PARENT_H__ */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 15/21] xfsprogs: Add the parent pointer support to the superblock version 5.
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (13 preceding siblings ...)
  2018-05-08  4:41 ` [PATCH 14/21] xfsprogs: parent pointer attribute creation Allison Henderson
@ 2018-05-08  4:41 ` Allison Henderson
  2018-05-08  4:41 ` [PATCH 16/21] xfsprogs: Add parent pointer ioctl Allison Henderson
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

[dchinner: forward ported and cleaned up]
[achender: rebased and added parent pointer attribute to
           compatible attributes mask]

Signed-off-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 libxfs/xfs_format.h | 7 +++++--
 libxfs/xfs_fs.h     | 1 +
 libxfs/xfs_sb.c     | 2 ++
 3 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h
index de8b14a..05431b0 100644
--- a/libxfs/xfs_format.h
+++ b/libxfs/xfs_format.h
@@ -462,10 +462,12 @@ xfs_sb_has_compat_feature(
 #define XFS_SB_FEAT_RO_COMPAT_FINOBT   (1 << 0)		/* free inode btree */
 #define XFS_SB_FEAT_RO_COMPAT_RMAPBT   (1 << 1)		/* reverse map btree */
 #define XFS_SB_FEAT_RO_COMPAT_REFLINK  (1 << 2)		/* reflinked files */
+#define XFS_SB_FEAT_RO_COMPAT_PARENT	(1 << 3)		/* parent inode ptr */
 #define XFS_SB_FEAT_RO_COMPAT_ALL \
 		(XFS_SB_FEAT_RO_COMPAT_FINOBT | \
 		 XFS_SB_FEAT_RO_COMPAT_RMAPBT | \
-		 XFS_SB_FEAT_RO_COMPAT_REFLINK)
+		 XFS_SB_FEAT_RO_COMPAT_REFLINK| \
+		 XFS_SB_FEAT_RO_COMPAT_PARENT)
 #define XFS_SB_FEAT_RO_COMPAT_UNKNOWN	~XFS_SB_FEAT_RO_COMPAT_ALL
 static inline bool
 xfs_sb_has_ro_compat_feature(
@@ -561,7 +563,8 @@ static inline bool xfs_sb_version_hasreflink(struct xfs_sb *sbp)
 
 static inline bool xfs_sb_version_hasparent(struct xfs_sb *sbp)
 {
-	return false; /* We'll enable this at the end of the set */
+	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 &&
+		(sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_PARENT));
 }
 
 /*
diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h
index 86a379f..0c6f9fa 100644
--- a/libxfs/xfs_fs.h
+++ b/libxfs/xfs_fs.h
@@ -243,6 +243,7 @@ typedef struct xfs_fsop_resblks {
 #define XFS_FSOP_GEOM_FLAGS_SPINODES	0x40000	/* sparse inode chunks	*/
 #define XFS_FSOP_GEOM_FLAGS_RMAPBT	0x80000	/* reverse mapping btree */
 #define XFS_FSOP_GEOM_FLAGS_REFLINK	0x100000 /* files can share blocks */
+#define XFS_FSOP_GEOM_FLAGS_PARENT	0x200000 /* parent pointers */
 
 /*
  * Minimum and maximum sizes need for growth checks.
diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c
index e8dd463..1c5b6e7 100644
--- a/libxfs/xfs_sb.c
+++ b/libxfs/xfs_sb.c
@@ -940,6 +940,8 @@ xfs_fs_geometry(
 		geo->flags |= XFS_FSOP_GEOM_FLAGS_RMAPBT;
 	if (xfs_sb_version_hasreflink(sbp))
 		geo->flags |= XFS_FSOP_GEOM_FLAGS_REFLINK;
+	if(xfs_sb_version_hasparent(sbp))
+		geo->flags |= XFS_FSOP_GEOM_FLAGS_PARENT;
 	if (xfs_sb_version_hassector(sbp))
 		geo->logsectsize = sbp->sb_logsectsize;
 	else
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 16/21] xfsprogs: Add parent pointer ioctl
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (14 preceding siblings ...)
  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 ` Allison Henderson
  2018-05-08  4:41 ` [PATCH 17/21] xfsprogs: Add delayed attributes error tag Allison Henderson
                   ` (4 subsequent siblings)
  20 siblings, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

This patch adds a new file ioctl to retrieve the parent
pointer of a given inode

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 libxfs/xfs_fs.h     | 38 ++++++++++++++++++++++++++++++++++++++
 libxfs/xfs_parent.c | 10 ++++++++++
 libxfs/xfs_parent.h |  2 ++
 3 files changed, 50 insertions(+)

diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h
index 0c6f9fa..e3ce233 100644
--- a/libxfs/xfs_fs.h
+++ b/libxfs/xfs_fs.h
@@ -573,6 +573,43 @@ struct xfs_scrub_metadata {
 				 XFS_SCRUB_OFLAG_WARNING)
 #define XFS_SCRUB_FLAGS_ALL	(XFS_SCRUB_FLAGS_IN | XFS_SCRUB_FLAGS_OUT)
 
+#define XFS_PPTR_MAXNAMELEN				255
+
+/* return parents of the handle, not the open fd */
+#define XFS_PPTR_IFLAG_HANDLE  (1U << 0)
+
+/* Get an inode parent pointer through ioctl */
+struct xfs_parent_ptr {
+	__u64		xpp_ino;			/* Inode */
+	__u32		xpp_gen;			/* Inode generation */
+	__u32		xpp_diroffset;			/* Directory offset */
+	__u32		xpp_namelen;			/* File name length */
+	__u8		xpp_name[XFS_PPTR_MAXNAMELEN];	/* File name */
+};
+
+/* Iterate though an inodes parent pointers */
+struct xfs_pptr_info {
+	struct xfs_handle		pi_handle;
+	struct xfs_attrlist_cursor	pi_cursor;
+	__u32				pi_flags;
+	__u32				pi_reserved;
+	__u32				pi_ptrs_size;
+	__u32				pi_ptrs_used;
+	__u64				pi_reserved2[6];
+
+	/*
+	 * An array of struct xfs_pptr follows the header
+	 * information. Use XFS_PPINFO_TO_PP() to access the
+	 * parent pointer array entries.
+	 */
+};
+
+#define XFS_PPTR_INFO_SIZEOF(nr_ptrs) sizeof (struct xfs_pptr_info) + \
+				      nr_ptrs * sizeof(struct xfs_parent_ptr)
+
+#define XFS_PPINFO_TO_PP(info, idx)    \
+	(&(((struct xfs_parent_ptr *)((char *)(info) + sizeof(*(info))))[(idx)]))
+
 /*
  * ioctl limits
  */
@@ -616,6 +653,7 @@ struct xfs_scrub_metadata {
 #define XFS_IOC_FREE_EOFBLOCKS	_IOR ('X', 58, struct xfs_fs_eofblocks)
 /*	XFS_IOC_GETFSMAP ------ hoisted 59         */
 #define XFS_IOC_SCRUB_METADATA	_IOWR('X', 60, struct xfs_scrub_metadata)
+#define XFS_IOC_GETPPOINTER	_IOR ('X', 61, struct xfs_parent_ptr)
 
 /*
  * ioctl commands that replace IRIX syssgi()'s
diff --git a/libxfs/xfs_parent.c b/libxfs/xfs_parent.c
index b8ec1f6..368830b 100644
--- a/libxfs/xfs_parent.c
+++ b/libxfs/xfs_parent.c
@@ -39,6 +39,16 @@
 #include "xfs_attr_sf.h"
 #include "libxfs_api_defs.h"
 
+/* Initializes a xfs_parent_ptr from an xfs_parent_name_rec */
+void
+xfs_init_parent_ptr(struct xfs_parent_ptr		*xpp,
+		     struct xfs_parent_name_rec	*rec)
+{
+	xpp->xpp_ino = be64_to_cpu(rec->p_ino);
+	xpp->xpp_gen = be32_to_cpu(rec->p_gen);
+	xpp->xpp_diroffset = be32_to_cpu(rec->p_diroffset);
+}
+
 /*
  * Parent pointer attribute handling.
  *
diff --git a/libxfs/xfs_parent.h b/libxfs/xfs_parent.h
index 298562b..1a321db 100644
--- a/libxfs/xfs_parent.h
+++ b/libxfs/xfs_parent.h
@@ -33,4 +33,6 @@ int xfs_parent_add(struct xfs_trans *tp, struct xfs_inode *parent,
 		   struct xfs_inode *child, struct xfs_name *child_name,
 		   uint32_t diroffset, xfs_fsblock_t *firstblock,
 		   struct xfs_defer_ops *dfops);
+void xfs_init_parent_ptr(struct xfs_parent_ptr *xpp,
+			 struct xfs_parent_name_rec *rec);
 #endif	/* __XFS_PARENT_H__ */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 17/21] xfsprogs: Add delayed attributes error tag
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (15 preceding siblings ...)
  2018-05-08  4:41 ` [PATCH 16/21] xfsprogs: Add parent pointer ioctl Allison Henderson
@ 2018-05-08  4:41 ` Allison Henderson
  2018-05-08 17:21   ` Darrick J. Wong
  2018-05-08  4:41 ` [PATCH 18/21] xfsprogs: Add parent pointer flag to cmd Allison Henderson
                   ` (3 subsequent siblings)
  20 siblings, 1 reply; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 io/inject.c           | 1 +
 libxfs/xfs_errortag.h | 5 ++++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/io/inject.c b/io/inject.c
index fc3cf25..2d6cc9c 100644
--- a/io/inject.c
+++ b/io/inject.c
@@ -63,6 +63,7 @@ error_tag(char *name)
 		{ XFS_ERRTAG_LOG_BAD_CRC,		"log_bad_crc" },
 		{ XFS_ERRTAG_LOG_ITEM_PIN,		"log_item_pin" },
 		{ XFS_ERRTAG_BUF_LRU_REF,		"buf_lru_ref" },
+		{ XFS_ERRTAG_DELAYED_ATTR,		"delayed_attr" },
 		{ XFS_ERRTAG_MAX,			NULL }
 	};
 	int	count;
diff --git a/libxfs/xfs_errortag.h b/libxfs/xfs_errortag.h
index bc1789d..f606ab6 100644
--- a/libxfs/xfs_errortag.h
+++ b/libxfs/xfs_errortag.h
@@ -65,7 +65,8 @@
 #define XFS_ERRTAG_LOG_BAD_CRC				29
 #define XFS_ERRTAG_LOG_ITEM_PIN				30
 #define XFS_ERRTAG_BUF_LRU_REF				31
-#define XFS_ERRTAG_MAX					32
+#define XFS_ERRTAG_DELAYED_ATTR			32
+#define XFS_ERRTAG_MAX					33
 
 /*
  * Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
@@ -102,5 +103,7 @@
 #define XFS_RANDOM_LOG_BAD_CRC				1
 #define XFS_RANDOM_LOG_ITEM_PIN				1
 #define XFS_RANDOM_BUF_LRU_REF				2
+#define XFS_RANDOM_DELAYED_ATTR			1
 
 #endif /* __XFS_ERRORTAG_H_ */
+
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 18/21] xfsprogs: Add parent pointer flag to cmd
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (16 preceding siblings ...)
  2018-05-08  4:41 ` [PATCH 17/21] xfsprogs: Add delayed attributes error tag Allison Henderson
@ 2018-05-08  4:41 ` Allison Henderson
  2018-05-08 17:25   ` Darrick J. Wong
  2018-05-08  4:41 ` [PATCH 19/21] xfsprogs: Remove single byte array from struct parent Allison Henderson
                   ` (2 subsequent siblings)
  20 siblings, 1 reply; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 mkfs/xfs_mkfs.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 78d0ce5..554e1bf 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -129,6 +129,7 @@ enum {
 	M_UUID,
 	M_RMAPBT,
 	M_REFLINK,
+	M_PARENT,
 	M_MAX_OPTS,
 };
 
@@ -663,6 +664,7 @@ struct opt_params mopts = {
 		[M_UUID] = "uuid",
 		[M_RMAPBT] = "rmapbt",
 		[M_REFLINK] = "reflink",
+		[M_PARENT] = "parent",
 	},
 	.subopt_params = {
 		{ .index = M_CRC,
@@ -693,6 +695,13 @@ struct opt_params mopts = {
 		  .maxval = 1,
 		  .defaultval = 1,
 		},
+		{ .index = M_PARENT,
+		  .conflicts = { {NULL, LAST_CONFLICT } },
+		  .minval = 0,
+		  .maxval = 1,
+		  .defaultval = 0,
+		},
+
 	},
 };
 
@@ -865,7 +874,7 @@ usage( void )
 {
 	fprintf(stderr, _("Usage: %s\n\
 /* blocksize */		[-b size=num]\n\
-/* metadata */		[-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1]\n\
+/* metadata */		[-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1,parent=0|1]\n\
 /* data subvol */	[-d agcount=n,agsize=n,file,name=xxx,size=num,\n\
 			    (sunit=value,swidth=value|su=num,sw=num|noalign),\n\
 			    sectsize=num\n\
@@ -1586,6 +1595,9 @@ meta_opts_parser(
 	case M_REFLINK:
 		cli->sb_feat.reflink = getnum(value, opts, subopt);
 		break;
+	case M_PARENT:
+		cli->sb_feat.parent_pointers = getnum(value, &mopts, M_PARENT);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -2887,6 +2899,8 @@ sb_set_features(
 		sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_RMAPBT;
 	if (fp->reflink)
 		sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_REFLINK;
+	if (fp->parent_pointers)
+		sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_PARENT;
 
 	/*
 	 * Sparse inode chunk support has two main inode alignment requirements.
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 19/21] xfsprogs: Remove single byte array from struct parent
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (17 preceding siblings ...)
  2018-05-08  4:41 ` [PATCH 18/21] xfsprogs: Add parent pointer flag to cmd Allison Henderson
@ 2018-05-08  4:41 ` 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  4:41 ` [PATCH 21/21] xfsprogs: implement the upper half of parent pointers Allison Henderson
  20 siblings, 1 reply; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

Variable sized arrays implemented this way may cause
corruptions depending on how different compilers pack
the structure.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 include/parent.h | 1 -
 io/parent.c      | 9 ++++++---
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/include/parent.h b/include/parent.h
index f338f96..85cef85 100644
--- a/include/parent.h
+++ b/include/parent.h
@@ -22,7 +22,6 @@ typedef struct parent {
 	__u64	p_ino;
 	__u32	p_gen;
 	__u16	p_reclen;
-	char	p_name[1];
 } parent_t;
 
 typedef struct parent_cursor {
diff --git a/io/parent.c b/io/parent.c
index 1968516..55b8b49 100644
--- a/io/parent.c
+++ b/io/parent.c
@@ -45,7 +45,8 @@ check_parent_entry(xfs_bstat_t *bstatp, parent_t *parent)
 	struct stat statbuf;
 	char *str;
 
-	sprintf(fullpath, _("%s%s"), mntpt, parent->p_name);
+	snprintf(fullpath, parent->p_reclen, _("%s%s"), mntpt,
+				((char*)parent)+sizeof(struct parent));
 
 	sts = lstat(fullpath, &statbuf);
 	if (sts != 0) {
@@ -284,9 +285,11 @@ print_parent_entry(parent_t *parent, int fullpath)
 	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, parent->p_name);
+		printf(_("p_name   = \"%s%s\"\n"), mntpt,
+					((char*)parent)+sizeof(struct parent));
 	else
-		printf(_("p_name   = \"%s\"\n"), parent->p_name);
+		printf(_("p_name   = \"%s\"\n"),
+					((char*)parent)+sizeof(struct parent));
 }
 
 static int
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 20/21] xfsprogs: Add parent pointers during protofile creation
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (18 preceding siblings ...)
  2018-05-08  4:41 ` [PATCH 19/21] xfsprogs: Remove single byte array from struct parent Allison Henderson
@ 2018-05-08  4:41 ` Allison Henderson
  2018-05-08 17:43   ` Darrick J. Wong
  2018-05-08  4:41 ` [PATCH 21/21] xfsprogs: implement the upper half of parent pointers Allison Henderson
  20 siblings, 1 reply; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 mkfs/proto.c         | 59 ++++++++++++++++++++++++++++++++++------------------
 repair/attr_repair.c | 16 ++------------
 repair/phase6.c      | 47 +++++++++++++++++++++++++----------------
 3 files changed, 70 insertions(+), 52 deletions(-)

diff --git a/mkfs/proto.c b/mkfs/proto.c
index 67c228a..3e4fd33 100644
--- a/mkfs/proto.c
+++ b/mkfs/proto.c
@@ -19,6 +19,7 @@
 #include "libxfs.h"
 #include <sys/stat.h>
 #include "xfs_multidisk.h"
+#include "xfs_parent.h"
 
 /*
  * Prototypes for internal functions.
@@ -318,23 +319,25 @@ newregfile(
 
 static void
 newdirent(
-	xfs_mount_t	*mp,
-	xfs_trans_t	*tp,
-	xfs_inode_t	*pip,
-	struct xfs_name	*name,
-	xfs_ino_t	inum,
-	xfs_fsblock_t	*first,
-	struct xfs_defer_ops	*dfops)
+	xfs_mount_t		*mp,
+	xfs_trans_t		*tp,
+	xfs_inode_t		*pip,
+	struct xfs_name		*name,
+	struct xfs_inode	*ip,
+	xfs_fsblock_t		*first,
+	struct xfs_defer_ops	*dfops,
+	xfs_dir2_dataptr_t      *offset)
 {
-	int	error;
-	int	rsv;
+	int			error;
+	int			rsv;
 
 	rsv = XFS_DIRENTER_SPACE_RES(mp, name->len);
 
-	error = -libxfs_dir_createname(tp, pip, name, inum, first, dfops, rsv,
-				       NULL);
+	error = -libxfs_dir_createname(tp, pip, name, ip->i_ino, first, dfops, rsv,
+				       offset);
 	if (error)
 		fail(_("directory createname error"), error);
+
 }
 
 static void
@@ -387,6 +390,7 @@ parseproto(
 	cred_t		creds;
 	char		*value;
 	struct xfs_name	xname;
+	xfs_dir2_dataptr_t offset;
 
 	memset(&creds, 0, sizeof(creds));
 	mstr = getstr(pp);
@@ -470,7 +474,7 @@ parseproto(
 			free(buf);
 		libxfs_trans_ijoin(tp, pip, 0);
 		xname.type = XFS_DIR3_FT_REG_FILE;
-		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
+		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
 		break;
 
 	case IF_RESERVED:			/* pre-allocated space only */
@@ -493,7 +497,7 @@ parseproto(
 		libxfs_trans_ijoin(tp, pip, 0);
 
 		xname.type = XFS_DIR3_FT_REG_FILE;
-		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
+		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
 		libxfs_trans_log_inode(tp, ip, flags);
 
 		libxfs_defer_ijoin(&dfops, ip);
@@ -516,7 +520,7 @@ parseproto(
 		}
 		libxfs_trans_ijoin(tp, pip, 0);
 		xname.type = XFS_DIR3_FT_BLKDEV;
-		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
+		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
 		flags |= XFS_ILOG_DEV;
 		break;
 
@@ -530,7 +534,7 @@ parseproto(
 			fail(_("Inode allocation failed"), error);
 		libxfs_trans_ijoin(tp, pip, 0);
 		xname.type = XFS_DIR3_FT_CHRDEV;
-		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
+		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
 		flags |= XFS_ILOG_DEV;
 		break;
 
@@ -542,7 +546,7 @@ parseproto(
 			fail(_("Inode allocation failed"), error);
 		libxfs_trans_ijoin(tp, pip, 0);
 		xname.type = XFS_DIR3_FT_FIFO;
-		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
+		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
 		break;
 	case IF_SYMLINK:
 		buf = getstr(pp);
@@ -555,7 +559,7 @@ parseproto(
 		flags |= newfile(tp, ip, &dfops, &first, 1, 1, buf, len);
 		libxfs_trans_ijoin(tp, pip, 0);
 		xname.type = XFS_DIR3_FT_SYMLINK;
-		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
+		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
 		break;
 	case IF_DIRECTORY:
 		tp = getres(mp, 0);
@@ -572,8 +576,8 @@ parseproto(
 		} else {
 			libxfs_trans_ijoin(tp, pip, 0);
 			xname.type = XFS_DIR3_FT_DIR;
-			newdirent(mp, tp, pip, &xname, ip->i_ino,
-				  &first, &dfops);
+			newdirent(mp, tp, pip, &xname, ip,
+				  &first, &dfops, &offset);
 			inc_nlink(VFS_I(pip));
 			libxfs_trans_log_inode(tp, pip, XFS_ILOG_CORE);
 		}
@@ -612,8 +616,23 @@ parseproto(
 		fail(_("Error encountered creating file from prototype file"),
 			error);
 	}
-	libxfs_trans_commit(tp);
+        libxfs_trans_commit(tp);
+
+	if (xfs_sb_version_hasparent(&mp->m_sb)) {
+		error = xfs_parent_add(tp, pip, ip, &xname, offset, &first, &dfops);
+		if (error)
+			fail(_("Error creating parent pointer"), error);
+
+		libxfs_trans_log_inode(tp, ip, flags);
+		libxfs_defer_ijoin(&dfops, ip);
+		error = -libxfs_defer_finish(&tp, &dfops);
+		if (error)
+			fail(_("Directory creation failed"), error);
+		libxfs_trans_commit(tp);
+	}
+
 	IRELE(ip);
+	
 }
 
 void
diff --git a/repair/attr_repair.c b/repair/attr_repair.c
index 8b1b8a7..e5ff3b0 100644
--- a/repair/attr_repair.c
+++ b/repair/attr_repair.c
@@ -305,16 +305,6 @@ process_shortform_attr(
 			}
 		}
 
-		/* namecheck checks for / and null terminated for file names.
-		 * attributes names currently follow the same rules.
-		*/
-		if (namecheck((char *)&currententry->nameval[0],
-						currententry->namelen))  {
-			do_warn(
-	_("entry contains illegal character in shortform attribute name\n"));
-			junkit = 1;
-		}
-
 		if (currententry->flags & XFS_ATTR_INCOMPLETE) {
 			do_warn(
 	_("entry has INCOMPLETE flag on in shortform attribute\n"));
@@ -470,8 +460,7 @@ process_leaf_attr_local(
 	xfs_attr_leaf_name_local_t *local;
 
 	local = xfs_attr3_leaf_name_local(leaf, i);
-	if (local->namelen == 0 || namecheck((char *)&local->nameval[0],
-							local->namelen)) {
+	if (local->namelen == 0) {
 		do_warn(
 	_("attribute entry %d in attr block %u, inode %" PRIu64 " has bad name (namelen = %d)\n"),
 			i, da_bno, ino, local->namelen);
@@ -525,8 +514,7 @@ process_leaf_attr_remote(
 
 	remotep = xfs_attr3_leaf_name_remote(leaf, i);
 
-	if (remotep->namelen == 0 || namecheck((char *)&remotep->name[0],
-						remotep->namelen) ||
+	if (remotep->namelen == 0 ||
 			be32_to_cpu(entry->hashval) !=
 				libxfs_da_hashname((unsigned char *)&remotep->name[0],
 						remotep->namelen) ||
diff --git a/repair/phase6.c b/repair/phase6.c
index 4fedb35..b861b3b 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -29,6 +29,7 @@
 #include "dinode.h"
 #include "progress.h"
 #include "versions.h"
+#include "xfs_parent.h"
 
 static struct cred		zerocr;
 static struct fsxattr 		zerofsx;
@@ -962,19 +963,20 @@ mk_root_dir(xfs_mount_t *mp)
 static xfs_ino_t
 mk_orphanage(xfs_mount_t *mp)
 {
-	xfs_ino_t	ino;
-	xfs_trans_t	*tp;
-	xfs_inode_t	*ip;
-	xfs_inode_t	*pip;
-	xfs_fsblock_t	first;
-	ino_tree_node_t	*irec;
-	int		ino_offset = 0;
-	int		i;
-	int		error;
+	xfs_ino_t		ino;
+	xfs_trans_t		*tp;
+	xfs_inode_t		*ip;
+	xfs_inode_t		*pip;
+	xfs_fsblock_t		first;
+	ino_tree_node_t		*irec;
+	int			ino_offset = 0;
+	int			i;
+	int			error;
 	struct xfs_defer_ops	dfops;
-	const int	mode = 0755;
-	int		nres;
-	struct xfs_name	xname;
+	const int		mode = 0755;
+	int			nres;
+	struct xfs_name		xname;
+	xfs_dir2_dataptr_t      offset;
 
 	/*
 	 * check for an existing lost+found first, if it exists, return
@@ -1061,7 +1063,7 @@ mk_orphanage(xfs_mount_t *mp)
 	 * create the actual entry
 	 */
 	error = -libxfs_dir_createname(tp, pip, &xname, ip->i_ino, &first,
-					&dfops, nres, NULL);
+					&dfops, nres, &offset);
 	if (error)
 		do_error(
 		_("can't make %s, createname error %d\n"),
@@ -1089,6 +1091,14 @@ mk_orphanage(xfs_mount_t *mp)
 			ORPHANAGE, error);
 	}
 
+        libxfs_trans_commit(tp);
+        if (xfs_sb_version_hasparent(&mp->m_sb)) {
+                error = xfs_parent_add(tp, pip, ip, &xname, offset,
+				       &first, &dfops);
+                if (error)
+                        do_error(_("Error creating parent pointer: %d\n"),
+				 error);
+        }
 
 	libxfs_trans_commit(tp);
 	IRELE(ip);
@@ -1120,6 +1130,7 @@ mv_orphanage(
 	ino_tree_node_t		*irec;
 	int			ino_offset = 0;
 	struct xfs_name		xname;
+	xfs_dir2_dataptr_t      offset;
 
 	xname.name = fname;
 	xname.len = snprintf((char *)fname, sizeof(fname), "%llu",
@@ -1170,7 +1181,7 @@ mv_orphanage(
 
 			libxfs_defer_init(&dfops, &first);
 			err = -libxfs_dir_createname(tp, orphanage_ip, &xname,
-						ino, &first, &dfops, nres, NULL);
+						ino, &first, &dfops, nres, &offset);
 			if (err)
 				do_error(
 	_("name create failed in %s (%d), filesystem may be out of space\n"),
@@ -1183,7 +1194,7 @@ mv_orphanage(
 			libxfs_trans_log_inode(tp, orphanage_ip, XFS_ILOG_CORE);
 
 			err = -libxfs_dir_createname(tp, ino_p, &xfs_name_dotdot,
-					orphanage_ino, &first, &dfops, nres, NULL);
+					orphanage_ino, &first, &dfops, nres, &offset);
 			if (err)
 				do_error(
 	_("creation of .. entry failed (%d), filesystem may be out of space\n"),
@@ -1214,7 +1225,7 @@ mv_orphanage(
 			libxfs_defer_init(&dfops, &first);
 
 			err = -libxfs_dir_createname(tp, orphanage_ip, &xname,
-						ino, &first, &dfops, nres, NULL);
+						ino, &first, &dfops, nres, &offset);
 			if (err)
 				do_error(
 	_("name create failed in %s (%d), filesystem may be out of space\n"),
@@ -1233,7 +1244,7 @@ mv_orphanage(
 			if (entry_ino_num != orphanage_ino)  {
 				err = -libxfs_dir_replace(tp, ino_p,
 						&xfs_name_dotdot, orphanage_ino,
-						&first, &dfops, nres, NULL);
+						&first, &dfops, nres, &offset);
 				if (err)
 					do_error(
 	_("name replace op failed (%d), filesystem may be out of space\n"),
@@ -1270,7 +1281,7 @@ mv_orphanage(
 
 		libxfs_defer_init(&dfops, &first);
 		err = -libxfs_dir_createname(tp, orphanage_ip, &xname, ino,
-						&first, &dfops, nres, NULL);
+						&first, &dfops, nres, &offset);
 		if (err)
 			do_error(
 	_("name create failed in %s (%d), filesystem may be out of space\n"),
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 21/21] xfsprogs: implement the upper half of parent pointers
  2018-05-08  4:40 [PATCH 00/21] xfsprogs: parent pointers v1 Allison Henderson
                   ` (19 preceding siblings ...)
  2018-05-08  4:41 ` [PATCH 20/21] xfsprogs: Add parent pointers during protofile creation Allison Henderson
@ 2018-05-08  4:41 ` Allison Henderson
  2018-05-08 17:45   ` Darrick J. Wong
  2018-05-08 20:52   ` Eric Sandeen
  20 siblings, 2 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08  4:41 UTC (permalink / raw)
  To: linux-xfs

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)
+
 /*
  * 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


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* Re: [PATCH 01/21] xfsprogs: Move xfs_attr.h to libxfs
  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
  0 siblings, 0 replies; 45+ messages in thread
From: Darrick J. Wong @ 2018-05-08 17:18 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

On Mon, May 07, 2018 at 09:40:59PM -0700, Allison Henderson wrote:
> Subject: [PATCH 01/21] xfsprogs: Move xfs_attr.h to libxfs

For libxfs patches ported over from the kernel I just leave the subject
as is:

    xfs: Move xfs_attr.h to libxfs

so that it's more obvious which patches start the surgery on the
utilities themselves:

    mkfs.xfs: Add parent pointer flag to cmd

Also as an aside if you need to create a new patch for something that's
in libxfs but not in the kernel libxfs then I tag it as such:

    libxfs: defrobulate the widgets

--D

> This patch moves fs/xfs/xfs_attr.h to fs/xfs/libxfs/xfs_attr.h
> since xfs_attr.c is in libxfs.  We will need these later in
> xfsprogs.
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  libxfs/Makefile   |   1 +
>  libxfs/xfs_attr.h | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 158 insertions(+)
> 
> diff --git a/libxfs/Makefile b/libxfs/Makefile
> index 0470f5f..75ce980 100644
> --- a/libxfs/Makefile
> +++ b/libxfs/Makefile
> @@ -21,6 +21,7 @@ HFILES = \
>  	xfs_ag_resv.h \
>  	xfs_alloc.h \
>  	xfs_alloc_btree.h \
> +	xfs_attr.h \
>  	xfs_attr_leaf.h \
>  	xfs_attr_sf.h \
>  	xfs_bit.h \
> diff --git a/libxfs/xfs_attr.h b/libxfs/xfs_attr.h
> new file mode 100644
> index 0000000..8abf398
> --- /dev/null
> +++ b/libxfs/xfs_attr.h
> @@ -0,0 +1,157 @@
> +/*
> + * Copyright (c) 2000,2002-2003,2005 Silicon Graphics, Inc.
> + * All Rights Reserved.
> + *
> + * 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.
> + *
> + * 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
> + */
> +#ifndef __XFS_ATTR_H__
> +#define	__XFS_ATTR_H__
> +
> +struct xfs_inode;
> +struct xfs_da_args;
> +struct xfs_attr_list_context;
> +
> +/*
> + * Large attribute lists are structured around Btrees where all the data
> + * elements are in the leaf nodes.  Attribute names are hashed into an int,
> + * then that int is used as the index into the Btree.  Since the hashval
> + * of an attribute name may not be unique, we may have duplicate keys.
> + * The internal links in the Btree are logical block offsets into the file.
> + *
> + * Small attribute lists use a different format and are packed as tightly
> + * as possible so as to fit into the literal area of the inode.
> + */
> +
> +/*========================================================================
> + * External interfaces
> + *========================================================================*/
> +
> +
> +#define ATTR_DONTFOLLOW	0x0001	/* -- unused, from IRIX -- */
> +#define ATTR_ROOT	0x0002	/* use attrs in root (trusted) namespace */
> +#define ATTR_TRUST	0x0004	/* -- unused, from IRIX -- */
> +#define ATTR_SECURE	0x0008	/* use attrs in security namespace */
> +#define ATTR_CREATE	0x0010	/* pure create: fail if attr already exists */
> +#define ATTR_REPLACE	0x0020	/* pure set: fail if attr does not exist */
> +
> +#define ATTR_INCOMPLETE	0x4000	/* [kernel] return INCOMPLETE attr keys */
> +
> +#define XFS_ATTR_FLAGS \
> +	{ ATTR_DONTFOLLOW, 	"DONTFOLLOW" }, \
> +	{ ATTR_ROOT,		"ROOT" }, \
> +	{ ATTR_TRUST,		"TRUST" }, \
> +	{ ATTR_SECURE,		"SECURE" }, \
> +	{ ATTR_CREATE,		"CREATE" }, \
> +	{ ATTR_REPLACE,		"REPLACE" }, \
> +	{ ATTR_KERNOTIME,	"KERNOTIME" }, \
> +	{ ATTR_KERNOVAL,	"KERNOVAL" }, \
> +	{ ATTR_INCOMPLETE,	"INCOMPLETE" }
> +
> +/*
> + * The maximum size (into the kernel or returned from the kernel) of an
> + * attribute value or the buffer used for an attr_list() call.  Larger
> + * sizes will result in an ERANGE return code.
> + */
> +#define	ATTR_MAX_VALUELEN	(64*1024)	/* max length of a value */
> +
> +/*
> + * Define how lists of attribute names are returned to the user from
> + * the attr_list() call.  A large, 32bit aligned, buffer is passed in
> + * along with its size.  We put an array of offsets at the top that each
> + * reference an attrlist_ent_t and pack the attrlist_ent_t's at the bottom.
> + */
> +typedef struct attrlist {
> +	__s32	al_count;	/* number of entries in attrlist */
> +	__s32	al_more;	/* T/F: more attrs (do call again) */
> +	__s32	al_offset[1];	/* byte offsets of attrs [var-sized] */
> +} attrlist_t;
> +
> +/*
> + * Show the interesting info about one attribute.  This is what the
> + * al_offset[i] entry points to.
> + */
> +typedef struct attrlist_ent {	/* data from attr_list() */
> +	__u32	a_valuelen;	/* number bytes in value of attr */
> +	char	a_name[1];	/* attr name (NULL terminated) */
> +} attrlist_ent_t;
> +
> +/*
> + * Given a pointer to the (char*) buffer containing the attr_list() result,
> + * and an index, return a pointer to the indicated attribute in the buffer.
> + */
> +#define	ATTR_ENTRY(buffer, index)		\
> +	((attrlist_ent_t *)			\
> +	 &((char *)buffer)[ ((attrlist_t *)(buffer))->al_offset[index] ])
> +
> +/*
> + * Kernel-internal version of the attrlist cursor.
> + */
> +typedef struct attrlist_cursor_kern {
> +	__u32	hashval;	/* hash value of next entry to add */
> +	__u32	blkno;		/* block containing entry (suggestion) */
> +	__u32	offset;		/* offset in list of equal-hashvals */
> +	__u16	pad1;		/* padding to match user-level */
> +	__u8	pad2;		/* padding to match user-level */
> +	__u8	initted;	/* T/F: cursor has been initialized */
> +} attrlist_cursor_kern_t;
> +
> +
> +/*========================================================================
> + * Structure used to pass context around among the routines.
> + *========================================================================*/
> +
> +
> +/* void; state communicated via *context */
> +typedef void (*put_listent_func_t)(struct xfs_attr_list_context *, int,
> +			      unsigned char *, int, int);
> +
> +typedef struct xfs_attr_list_context {
> +	struct xfs_trans		*tp;
> +	struct xfs_inode		*dp;		/* inode */
> +	struct attrlist_cursor_kern	*cursor;	/* position in list */
> +	char				*alist;		/* output buffer */
> +	int				seen_enough;	/* T/F: seen enough of list? */
> +	ssize_t				count;		/* num used entries */
> +	int				dupcnt;		/* count dup hashvals seen */
> +	int				bufsize;	/* total buffer size */
> +	int				firstu;		/* first used byte in buffer */
> +	int				flags;		/* from VOP call */
> +	int				resynch;	/* T/F: resynch with cursor */
> +	put_listent_func_t		put_listent;	/* list output fmt function */
> +	int				index;		/* index into output buffer */
> +} xfs_attr_list_context_t;
> +
> +
> +/*========================================================================
> + * Function prototypes for the kernel.
> + *========================================================================*/
> +
> +/*
> + * Overall external interface routines.
> + */
> +int xfs_attr_inactive(struct xfs_inode *dp);
> +int xfs_attr_list_int_ilocked(struct xfs_attr_list_context *);
> +int xfs_attr_list_int(struct xfs_attr_list_context *);
> +int xfs_inode_hasattr(struct xfs_inode *ip);
> +int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
> +int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
> +		 unsigned char *value, int *valuelenp, int flags);
> +int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
> +		 unsigned char *value, int valuelen, int flags);
> +int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
> +int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
> +		  int flags, struct attrlist_cursor_kern *cursor);
> +
> +
> +#endif	/* __XFS_ATTR_H__ */
> -- 
> 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

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 17/21] xfsprogs: Add delayed attributes error tag
  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
  0 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2018-05-08 17:21 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

On Mon, May 07, 2018 at 09:41:15PM -0700, Allison Henderson wrote:
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>

Needs a commit message.  Eric might also want the xfs_io bit as a
separate patch to keep this one as close to the kernel patch as
possible.

(Though really, it's a single line, maybe not...)

--D

> ---
>  io/inject.c           | 1 +
>  libxfs/xfs_errortag.h | 5 ++++-
>  2 files changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/io/inject.c b/io/inject.c
> index fc3cf25..2d6cc9c 100644
> --- a/io/inject.c
> +++ b/io/inject.c
> @@ -63,6 +63,7 @@ error_tag(char *name)
>  		{ XFS_ERRTAG_LOG_BAD_CRC,		"log_bad_crc" },
>  		{ XFS_ERRTAG_LOG_ITEM_PIN,		"log_item_pin" },
>  		{ XFS_ERRTAG_BUF_LRU_REF,		"buf_lru_ref" },
> +		{ XFS_ERRTAG_DELAYED_ATTR,		"delayed_attr" },
>  		{ XFS_ERRTAG_MAX,			NULL }
>  	};
>  	int	count;
> diff --git a/libxfs/xfs_errortag.h b/libxfs/xfs_errortag.h
> index bc1789d..f606ab6 100644
> --- a/libxfs/xfs_errortag.h
> +++ b/libxfs/xfs_errortag.h
> @@ -65,7 +65,8 @@
>  #define XFS_ERRTAG_LOG_BAD_CRC				29
>  #define XFS_ERRTAG_LOG_ITEM_PIN				30
>  #define XFS_ERRTAG_BUF_LRU_REF				31
> -#define XFS_ERRTAG_MAX					32
> +#define XFS_ERRTAG_DELAYED_ATTR			32
> +#define XFS_ERRTAG_MAX					33
>  
>  /*
>   * Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
> @@ -102,5 +103,7 @@
>  #define XFS_RANDOM_LOG_BAD_CRC				1
>  #define XFS_RANDOM_LOG_ITEM_PIN				1
>  #define XFS_RANDOM_BUF_LRU_REF				2
> +#define XFS_RANDOM_DELAYED_ATTR			1
>  
>  #endif /* __XFS_ERRORTAG_H_ */
> +
> -- 
> 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

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 18/21] xfsprogs: Add parent pointer flag to cmd
  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
  0 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2018-05-08 17:25 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

On Mon, May 07, 2018 at 09:41:16PM -0700, Allison Henderson wrote:
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>

Needs commit message:

mkfs: enable formatting with parent pointers

Wire up parent pointer support in mkfs via the '-m parent' parameter.

Signed-off-by: <etc>

> ---
>  mkfs/xfs_mkfs.c | 16 +++++++++++++++-
>  1 file changed, 15 insertions(+), 1 deletion(-)
> 
> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
> index 78d0ce5..554e1bf 100644
> --- a/mkfs/xfs_mkfs.c
> +++ b/mkfs/xfs_mkfs.c
> @@ -129,6 +129,7 @@ enum {
>  	M_UUID,
>  	M_RMAPBT,
>  	M_REFLINK,
> +	M_PARENT,

Hmm, is this better off in the naming section?

e.g. "mkfs.xfs -n parent=1"

>  	M_MAX_OPTS,
>  };
>  
> @@ -663,6 +664,7 @@ struct opt_params mopts = {
>  		[M_UUID] = "uuid",
>  		[M_RMAPBT] = "rmapbt",
>  		[M_REFLINK] = "reflink",
> +		[M_PARENT] = "parent",
>  	},
>  	.subopt_params = {
>  		{ .index = M_CRC,
> @@ -693,6 +695,13 @@ struct opt_params mopts = {
>  		  .maxval = 1,
>  		  .defaultval = 1,
>  		},
> +		{ .index = M_PARENT,
> +		  .conflicts = { {NULL, LAST_CONFLICT } },
> +		  .minval = 0,
> +		  .maxval = 1,
> +		  .defaultval = 0,

This (misleadingly named) field is the default value if you pass the
argument without explicitly assigning a value, i.e.

# mkfs.xfs -m parent /dev/sda

sets parent to whatever defaultval is.  In this case you'd get no parent
pointers, which is a little surprising.

And, uh, seeing as people keep getting this wrong maybe we should rename
it?

> +		},
> +
>  	},
>  };
>  
> @@ -865,7 +874,7 @@ usage( void )
>  {
>  	fprintf(stderr, _("Usage: %s\n\
>  /* blocksize */		[-b size=num]\n\
> -/* metadata */		[-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1]\n\
> +/* metadata */		[-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1,parent=0|1]\n\
>  /* data subvol */	[-d agcount=n,agsize=n,file,name=xxx,size=num,\n\
>  			    (sunit=value,swidth=value|su=num,sw=num|noalign),\n\
>  			    sectsize=num\n\
> @@ -1586,6 +1595,9 @@ meta_opts_parser(
>  	case M_REFLINK:
>  		cli->sb_feat.reflink = getnum(value, opts, subopt);
>  		break;
> +	case M_PARENT:
> +		cli->sb_feat.parent_pointers = getnum(value, &mopts, M_PARENT);
> +		break;
>  	default:
>  		return -EINVAL;
>  	}
> @@ -2887,6 +2899,8 @@ sb_set_features(
>  		sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_RMAPBT;
>  	if (fp->reflink)
>  		sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_REFLINK;
> +	if (fp->parent_pointers)
> +		sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_PARENT;

Otherwise looks ok to me....

--D

>  
>  	/*
>  	 * Sparse inode chunk support has two main inode alignment requirements.
> -- 
> 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

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 19/21] xfsprogs: Remove single byte array from struct parent
  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
  0 siblings, 0 replies; 45+ messages in thread
From: Darrick J. Wong @ 2018-05-08 17:32 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

On Mon, May 07, 2018 at 09:41:17PM -0700, Allison Henderson wrote:
> Variable sized arrays implemented this way may cause
> corruptions depending on how different compilers pack
> the structure.
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  include/parent.h | 1 -
>  io/parent.c      | 9 ++++++---
>  2 files changed, 6 insertions(+), 4 deletions(-)
> 
> diff --git a/include/parent.h b/include/parent.h
> index f338f96..85cef85 100644
> --- a/include/parent.h
> +++ b/include/parent.h
> @@ -22,7 +22,6 @@ typedef struct parent {
>  	__u64	p_ino;
>  	__u32	p_gen;
>  	__u16	p_reclen;
> -	char	p_name[1];
>  } parent_t;

Two options here: Either we finally fix up this part of libhandle to
talk to the kernel ioctls (whether or not we use the new apis in the
'upper half' patch at the end of this series to provide that emulation)
or just deprecate and kill all this old parent pointer stuff since it
has never worked on Linux.

FWIW struct parent is an in-core structure exposed via libhandle so (a)
we can't change it and (b) the padding problems don't exist.

--D

>  
>  typedef struct parent_cursor {
> diff --git a/io/parent.c b/io/parent.c
> index 1968516..55b8b49 100644
> --- a/io/parent.c
> +++ b/io/parent.c
> @@ -45,7 +45,8 @@ check_parent_entry(xfs_bstat_t *bstatp, parent_t *parent)
>  	struct stat statbuf;
>  	char *str;
>  
> -	sprintf(fullpath, _("%s%s"), mntpt, parent->p_name);
> +	snprintf(fullpath, parent->p_reclen, _("%s%s"), mntpt,
> +				((char*)parent)+sizeof(struct parent));
>  
>  	sts = lstat(fullpath, &statbuf);
>  	if (sts != 0) {
> @@ -284,9 +285,11 @@ print_parent_entry(parent_t *parent, int fullpath)
>  	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, parent->p_name);
> +		printf(_("p_name   = \"%s%s\"\n"), mntpt,
> +					((char*)parent)+sizeof(struct parent));
>  	else
> -		printf(_("p_name   = \"%s\"\n"), parent->p_name);
> +		printf(_("p_name   = \"%s\"\n"),
> +					((char*)parent)+sizeof(struct parent));
>  }
>  
>  static int
> -- 
> 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

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 20/21] xfsprogs: Add parent pointers during protofile creation
  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
  0 siblings, 2 replies; 45+ messages in thread
From: Darrick J. Wong @ 2018-05-08 17:43 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

On Mon, May 07, 2018 at 09:41:18PM -0700, Allison Henderson wrote:
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  mkfs/proto.c         | 59 ++++++++++++++++++++++++++++++++++------------------
>  repair/attr_repair.c | 16 ++------------

Separate patches for separate utilities, please.

>  repair/phase6.c      | 47 +++++++++++++++++++++++++----------------
>  3 files changed, 70 insertions(+), 52 deletions(-)
> 
> diff --git a/mkfs/proto.c b/mkfs/proto.c
> index 67c228a..3e4fd33 100644
> --- a/mkfs/proto.c
> +++ b/mkfs/proto.c
> @@ -19,6 +19,7 @@
>  #include "libxfs.h"
>  #include <sys/stat.h>
>  #include "xfs_multidisk.h"
> +#include "xfs_parent.h"
>  
>  /*
>   * Prototypes for internal functions.
> @@ -318,23 +319,25 @@ newregfile(
>  
>  static void
>  newdirent(
> -	xfs_mount_t	*mp,
> -	xfs_trans_t	*tp,
> -	xfs_inode_t	*pip,
> -	struct xfs_name	*name,
> -	xfs_ino_t	inum,
> -	xfs_fsblock_t	*first,
> -	struct xfs_defer_ops	*dfops)
> +	xfs_mount_t		*mp,

While you're changing these lines, get rid of the _t usage when
appropriate.

	struct xfs_trans	*tp,

Here and elsewhere in the patch.

> +	xfs_trans_t		*tp,
> +	xfs_inode_t		*pip,
> +	struct xfs_name		*name,
> +	struct xfs_inode	*ip,
> +	xfs_fsblock_t		*first,
> +	struct xfs_defer_ops	*dfops,
> +	xfs_dir2_dataptr_t      *offset)
>  {
> -	int	error;
> -	int	rsv;
> +	int			error;
> +	int			rsv;
>  
>  	rsv = XFS_DIRENTER_SPACE_RES(mp, name->len);
>  
> -	error = -libxfs_dir_createname(tp, pip, name, inum, first, dfops, rsv,
> -				       NULL);
> +	error = -libxfs_dir_createname(tp, pip, name, ip->i_ino, first, dfops, rsv,
> +				       offset);
>  	if (error)
>  		fail(_("directory createname error"), error);
> +
>  }
>  
>  static void
> @@ -387,6 +390,7 @@ parseproto(
>  	cred_t		creds;
>  	char		*value;
>  	struct xfs_name	xname;
> +	xfs_dir2_dataptr_t offset;
>  
>  	memset(&creds, 0, sizeof(creds));
>  	mstr = getstr(pp);
> @@ -470,7 +474,7 @@ parseproto(
>  			free(buf);
>  		libxfs_trans_ijoin(tp, pip, 0);
>  		xname.type = XFS_DIR3_FT_REG_FILE;
> -		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
> +		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
>  		break;
>  
>  	case IF_RESERVED:			/* pre-allocated space only */
> @@ -493,7 +497,7 @@ parseproto(
>  		libxfs_trans_ijoin(tp, pip, 0);
>  
>  		xname.type = XFS_DIR3_FT_REG_FILE;
> -		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
> +		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
>  		libxfs_trans_log_inode(tp, ip, flags);
>  
>  		libxfs_defer_ijoin(&dfops, ip);
> @@ -516,7 +520,7 @@ parseproto(
>  		}
>  		libxfs_trans_ijoin(tp, pip, 0);
>  		xname.type = XFS_DIR3_FT_BLKDEV;
> -		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
> +		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
>  		flags |= XFS_ILOG_DEV;
>  		break;
>  
> @@ -530,7 +534,7 @@ parseproto(
>  			fail(_("Inode allocation failed"), error);
>  		libxfs_trans_ijoin(tp, pip, 0);
>  		xname.type = XFS_DIR3_FT_CHRDEV;
> -		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
> +		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
>  		flags |= XFS_ILOG_DEV;
>  		break;
>  
> @@ -542,7 +546,7 @@ parseproto(
>  			fail(_("Inode allocation failed"), error);
>  		libxfs_trans_ijoin(tp, pip, 0);
>  		xname.type = XFS_DIR3_FT_FIFO;
> -		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
> +		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
>  		break;
>  	case IF_SYMLINK:
>  		buf = getstr(pp);
> @@ -555,7 +559,7 @@ parseproto(
>  		flags |= newfile(tp, ip, &dfops, &first, 1, 1, buf, len);
>  		libxfs_trans_ijoin(tp, pip, 0);
>  		xname.type = XFS_DIR3_FT_SYMLINK;
> -		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
> +		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
>  		break;
>  	case IF_DIRECTORY:
>  		tp = getres(mp, 0);
> @@ -572,8 +576,8 @@ parseproto(
>  		} else {
>  			libxfs_trans_ijoin(tp, pip, 0);
>  			xname.type = XFS_DIR3_FT_DIR;
> -			newdirent(mp, tp, pip, &xname, ip->i_ino,
> -				  &first, &dfops);
> +			newdirent(mp, tp, pip, &xname, ip,
> +				  &first, &dfops, &offset);
>  			inc_nlink(VFS_I(pip));
>  			libxfs_trans_log_inode(tp, pip, XFS_ILOG_CORE);
>  		}
> @@ -612,8 +616,23 @@ parseproto(
>  		fail(_("Error encountered creating file from prototype file"),
>  			error);
>  	}
> -	libxfs_trans_commit(tp);
> +        libxfs_trans_commit(tp);
> +
> +	if (xfs_sb_version_hasparent(&mp->m_sb)) {
> +		error = xfs_parent_add(tp, pip, ip, &xname, offset, &first, &dfops);

Definitely can't keep using tp after committing the transaction.

> +		if (error)
> +			fail(_("Error creating parent pointer"), error);
> +
> +		libxfs_trans_log_inode(tp, ip, flags);
> +		libxfs_defer_ijoin(&dfops, ip);
> +		error = -libxfs_defer_finish(&tp, &dfops);
> +		if (error)
> +			fail(_("Directory creation failed"), error);
> +		libxfs_trans_commit(tp);

Also, if you add libxfs_trans_commit calls they probably ought to have
return values checked in case some day libxfs_trans_commit starts
returning error codes.

> +	}
> +
>  	IRELE(ip);
> +	
>  }
>  
>  void
> diff --git a/repair/attr_repair.c b/repair/attr_repair.c
> index 8b1b8a7..e5ff3b0 100644
> --- a/repair/attr_repair.c
> +++ b/repair/attr_repair.c
> @@ -305,16 +305,6 @@ process_shortform_attr(
>  			}
>  		}
>  
> -		/* namecheck checks for / and null terminated for file names.
> -		 * attributes names currently follow the same rules.
> -		*/
> -		if (namecheck((char *)&currententry->nameval[0],

Why remove the namecheck calls?  It's only the ATTR_PARENT attributes
where we want to skip the null-in-name checks, right?

> -						currententry->namelen))  {
> -			do_warn(
> -	_("entry contains illegal character in shortform attribute name\n"));
> -			junkit = 1;
> -		}
> -
>  		if (currententry->flags & XFS_ATTR_INCOMPLETE) {
>  			do_warn(
>  	_("entry has INCOMPLETE flag on in shortform attribute\n"));
> @@ -470,8 +460,7 @@ process_leaf_attr_local(
>  	xfs_attr_leaf_name_local_t *local;
>  
>  	local = xfs_attr3_leaf_name_local(leaf, i);
> -	if (local->namelen == 0 || namecheck((char *)&local->nameval[0],
> -							local->namelen)) {
> +	if (local->namelen == 0) {
>  		do_warn(
>  	_("attribute entry %d in attr block %u, inode %" PRIu64 " has bad name (namelen = %d)\n"),
>  			i, da_bno, ino, local->namelen);
> @@ -525,8 +514,7 @@ process_leaf_attr_remote(
>  
>  	remotep = xfs_attr3_leaf_name_remote(leaf, i);
>  
> -	if (remotep->namelen == 0 || namecheck((char *)&remotep->name[0],
> -						remotep->namelen) ||
> +	if (remotep->namelen == 0 ||
>  			be32_to_cpu(entry->hashval) !=
>  				libxfs_da_hashname((unsigned char *)&remotep->name[0],
>  						remotep->namelen) ||
> diff --git a/repair/phase6.c b/repair/phase6.c
> index 4fedb35..b861b3b 100644
> --- a/repair/phase6.c
> +++ b/repair/phase6.c
> @@ -29,6 +29,7 @@
>  #include "dinode.h"
>  #include "progress.h"
>  #include "versions.h"
> +#include "xfs_parent.h"
>  
>  static struct cred		zerocr;
>  static struct fsxattr 		zerofsx;
> @@ -962,19 +963,20 @@ mk_root_dir(xfs_mount_t *mp)
>  static xfs_ino_t
>  mk_orphanage(xfs_mount_t *mp)
>  {
> -	xfs_ino_t	ino;
> -	xfs_trans_t	*tp;
> -	xfs_inode_t	*ip;
> -	xfs_inode_t	*pip;
> -	xfs_fsblock_t	first;
> -	ino_tree_node_t	*irec;
> -	int		ino_offset = 0;
> -	int		i;
> -	int		error;
> +	xfs_ino_t		ino;
> +	xfs_trans_t		*tp;
> +	xfs_inode_t		*ip;
> +	xfs_inode_t		*pip;
> +	xfs_fsblock_t		first;
> +	ino_tree_node_t		*irec;
> +	int			ino_offset = 0;
> +	int			i;
> +	int			error;
>  	struct xfs_defer_ops	dfops;
> -	const int	mode = 0755;
> -	int		nres;
> -	struct xfs_name	xname;
> +	const int		mode = 0755;
> +	int			nres;
> +	struct xfs_name		xname;
> +	xfs_dir2_dataptr_t      offset;
>  
>  	/*
>  	 * check for an existing lost+found first, if it exists, return
> @@ -1061,7 +1063,7 @@ mk_orphanage(xfs_mount_t *mp)
>  	 * create the actual entry
>  	 */
>  	error = -libxfs_dir_createname(tp, pip, &xname, ip->i_ino, &first,
> -					&dfops, nres, NULL);
> +					&dfops, nres, &offset);
>  	if (error)
>  		do_error(
>  		_("can't make %s, createname error %d\n"),
> @@ -1089,6 +1091,14 @@ mk_orphanage(xfs_mount_t *mp)
>  			ORPHANAGE, error);
>  	}
>  
> +        libxfs_trans_commit(tp);
> +        if (xfs_sb_version_hasparent(&mp->m_sb)) {
> +                error = xfs_parent_add(tp, pip, ip, &xname, offset,

When you want to use libxfs functions from outside of libxfs (namely
within mkfs/repair/whatever) the convention is to add a #define in
libxfs_api_defs.h:

#define libxfs_parent_add	xfs_parent_add

And then in the utility program the usage should be:

error = -libxfs_parent_add(...);

Because libxfs functions return negative numbers for errors (kernel
style) but the rest of the C world expects positive error codes.

In theory xfs/437 should complain about this (though for all I know it
could be busted).

--D

> +				       &first, &dfops);
> +                if (error)
> +                        do_error(_("Error creating parent pointer: %d\n"),
> +				 error);
> +        }
>  
>  	libxfs_trans_commit(tp);
>  	IRELE(ip);
> @@ -1120,6 +1130,7 @@ mv_orphanage(
>  	ino_tree_node_t		*irec;
>  	int			ino_offset = 0;
>  	struct xfs_name		xname;
> +	xfs_dir2_dataptr_t      offset;
>  
>  	xname.name = fname;
>  	xname.len = snprintf((char *)fname, sizeof(fname), "%llu",
> @@ -1170,7 +1181,7 @@ mv_orphanage(
>  
>  			libxfs_defer_init(&dfops, &first);
>  			err = -libxfs_dir_createname(tp, orphanage_ip, &xname,
> -						ino, &first, &dfops, nres, NULL);
> +						ino, &first, &dfops, nres, &offset);
>  			if (err)
>  				do_error(
>  	_("name create failed in %s (%d), filesystem may be out of space\n"),
> @@ -1183,7 +1194,7 @@ mv_orphanage(
>  			libxfs_trans_log_inode(tp, orphanage_ip, XFS_ILOG_CORE);
>  
>  			err = -libxfs_dir_createname(tp, ino_p, &xfs_name_dotdot,
> -					orphanage_ino, &first, &dfops, nres, NULL);
> +					orphanage_ino, &first, &dfops, nres, &offset);
>  			if (err)
>  				do_error(
>  	_("creation of .. entry failed (%d), filesystem may be out of space\n"),
> @@ -1214,7 +1225,7 @@ mv_orphanage(
>  			libxfs_defer_init(&dfops, &first);
>  
>  			err = -libxfs_dir_createname(tp, orphanage_ip, &xname,
> -						ino, &first, &dfops, nres, NULL);
> +						ino, &first, &dfops, nres, &offset);
>  			if (err)
>  				do_error(
>  	_("name create failed in %s (%d), filesystem may be out of space\n"),
> @@ -1233,7 +1244,7 @@ mv_orphanage(
>  			if (entry_ino_num != orphanage_ino)  {
>  				err = -libxfs_dir_replace(tp, ino_p,
>  						&xfs_name_dotdot, orphanage_ino,
> -						&first, &dfops, nres, NULL);
> +						&first, &dfops, nres, &offset);
>  				if (err)
>  					do_error(
>  	_("name replace op failed (%d), filesystem may be out of space\n"),
> @@ -1270,7 +1281,7 @@ mv_orphanage(
>  
>  		libxfs_defer_init(&dfops, &first);
>  		err = -libxfs_dir_createname(tp, orphanage_ip, &xname, ino,
> -						&first, &dfops, nres, NULL);
> +						&first, &dfops, nres, &offset);
>  		if (err)
>  			do_error(
>  	_("name create failed in %s (%d), filesystem may be out of space\n"),
> -- 
> 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

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 21/21] xfsprogs: implement the upper half of parent pointers
  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-08 20:52   ` Eric Sandeen
  1 sibling, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2018-05-08 17:45 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

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

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 18/21] xfsprogs: Add parent pointer flag to cmd
  2018-05-08 17:25   ` Darrick J. Wong
@ 2018-05-08 19:02     ` Allison Henderson
  2018-05-08 22:44       ` Darrick J. Wong
  0 siblings, 1 reply; 45+ messages in thread
From: Allison Henderson @ 2018-05-08 19:02 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 05/08/2018 10:25 AM, Darrick J. Wong wrote:
> On Mon, May 07, 2018 at 09:41:16PM -0700, Allison Henderson wrote:
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> Needs commit message:
>
> mkfs: enable formatting with parent pointers
>
> Wire up parent pointer support in mkfs via the '-m parent' parameter.
>
> Signed-off-by: <etc>
Ok, will update
>> ---
>>   mkfs/xfs_mkfs.c | 16 +++++++++++++++-
>>   1 file changed, 15 insertions(+), 1 deletion(-)
>>
>> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
>> index 78d0ce5..554e1bf 100644
>> --- a/mkfs/xfs_mkfs.c
>> +++ b/mkfs/xfs_mkfs.c
>> @@ -129,6 +129,7 @@ enum {
>>   	M_UUID,
>>   	M_RMAPBT,
>>   	M_REFLINK,
>> +	M_PARENT,
> Hmm, is this better off in the naming section?
>
> e.g. "mkfs.xfs -n parent=1"
I suppose it could fit there too if that's preferred.  I wasnt really 
sure which section it fit best to :-)
>>   	M_MAX_OPTS,
>>   };
>>   
>> @@ -663,6 +664,7 @@ struct opt_params mopts = {
>>   		[M_UUID] = "uuid",
>>   		[M_RMAPBT] = "rmapbt",
>>   		[M_REFLINK] = "reflink",
>> +		[M_PARENT] = "parent",
>>   	},
>>   	.subopt_params = {
>>   		{ .index = M_CRC,
>> @@ -693,6 +695,13 @@ struct opt_params mopts = {
>>   		  .maxval = 1,
>>   		  .defaultval = 1,
>>   		},
>> +		{ .index = M_PARENT,
>> +		  .conflicts = { {NULL, LAST_CONFLICT } },
>> +		  .minval = 0,
>> +		  .maxval = 1,
>> +		  .defaultval = 0,
> This (misleadingly named) field is the default value if you pass the
> argument without explicitly assigning a value, i.e.
>
> # mkfs.xfs -m parent /dev/sda
>
> sets parent to whatever defaultval is.  In this case you'd get no parent
> pointers, which is a little surprising.
>
> And, uh, seeing as people keep getting this wrong maybe we should rename
> it?
Oh I see.  That is a little odd, is there really a better name though?  
Maybe just a comment or something might make it more clear.
>> +		},
>> +
>>   	},
>>   };
>>   
>> @@ -865,7 +874,7 @@ usage( void )
>>   {
>>   	fprintf(stderr, _("Usage: %s\n\
>>   /* blocksize */		[-b size=num]\n\
>> -/* metadata */		[-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1]\n\
>> +/* metadata */		[-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1,parent=0|1]\n\
>>   /* data subvol */	[-d agcount=n,agsize=n,file,name=xxx,size=num,\n\
>>   			    (sunit=value,swidth=value|su=num,sw=num|noalign),\n\
>>   			    sectsize=num\n\
>> @@ -1586,6 +1595,9 @@ meta_opts_parser(
>>   	case M_REFLINK:
>>   		cli->sb_feat.reflink = getnum(value, opts, subopt);
>>   		break;
>> +	case M_PARENT:
>> +		cli->sb_feat.parent_pointers = getnum(value, &mopts, M_PARENT);
>> +		break;
>>   	default:
>>   		return -EINVAL;
>>   	}
>> @@ -2887,6 +2899,8 @@ sb_set_features(
>>   		sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_RMAPBT;
>>   	if (fp->reflink)
>>   		sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_REFLINK;
>> +	if (fp->parent_pointers)
>> +		sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_PARENT;
> Otherwise looks ok to me....
>
> --D
Alrighty, thx!
>>   
>>   	/*
>>   	 * Sparse inode chunk support has two main inode alignment requirements.
>> -- 
>> 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  https://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=2DFx03tmCKRPVndQLwf1P1u0PChkNowVFyXqzZ_arE8&s=JiwNEPlNO54aLxRtPd9mGL_lKU8dpX4T6ECMmDQhc70&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=2DFx03tmCKRPVndQLwf1P1u0PChkNowVFyXqzZ_arE8&s=JiwNEPlNO54aLxRtPd9mGL_lKU8dpX4T6ECMmDQhc70&e=


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 20/21] xfsprogs: Add parent pointers during protofile creation
  2018-05-08 17:43   ` Darrick J. Wong
@ 2018-05-08 19:28     ` Allison Henderson
  2018-05-08 20:39     ` Eric Sandeen
  1 sibling, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-08 19:28 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 05/08/2018 10:43 AM, Darrick J. Wong wrote:
> On Mon, May 07, 2018 at 09:41:18PM -0700, Allison Henderson wrote:
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
>>   mkfs/proto.c         | 59 ++++++++++++++++++++++++++++++++++------------------
>>   repair/attr_repair.c | 16 ++------------
> Separate patches for separate utilities, please.
>
>>   repair/phase6.c      | 47 +++++++++++++++++++++++++----------------
>>   3 files changed, 70 insertions(+), 52 deletions(-)
>>
>> diff --git a/mkfs/proto.c b/mkfs/proto.c
>> index 67c228a..3e4fd33 100644
>> --- a/mkfs/proto.c
>> +++ b/mkfs/proto.c
>> @@ -19,6 +19,7 @@
>>   #include "libxfs.h"
>>   #include <sys/stat.h>
>>   #include "xfs_multidisk.h"
>> +#include "xfs_parent.h"
>>   
>>   /*
>>    * Prototypes for internal functions.
>> @@ -318,23 +319,25 @@ newregfile(
>>   
>>   static void
>>   newdirent(
>> -	xfs_mount_t	*mp,
>> -	xfs_trans_t	*tp,
>> -	xfs_inode_t	*pip,
>> -	struct xfs_name	*name,
>> -	xfs_ino_t	inum,
>> -	xfs_fsblock_t	*first,
>> -	struct xfs_defer_ops	*dfops)
>> +	xfs_mount_t		*mp,
> While you're changing these lines, get rid of the _t usage when
> appropriate.
>
> 	struct xfs_trans	*tp,
>
> Here and elsewhere in the patch.
Sure, will do
>
>> +	xfs_trans_t		*tp,
>> +	xfs_inode_t		*pip,
>> +	struct xfs_name		*name,
>> +	struct xfs_inode	*ip,
>> +	xfs_fsblock_t		*first,
>> +	struct xfs_defer_ops	*dfops,
>> +	xfs_dir2_dataptr_t      *offset)
>>   {
>> -	int	error;
>> -	int	rsv;
>> +	int			error;
>> +	int			rsv;
>>   
>>   	rsv = XFS_DIRENTER_SPACE_RES(mp, name->len);
>>   
>> -	error = -libxfs_dir_createname(tp, pip, name, inum, first, dfops, rsv,
>> -				       NULL);
>> +	error = -libxfs_dir_createname(tp, pip, name, ip->i_ino, first, dfops, rsv,
>> +				       offset);
>>   	if (error)
>>   		fail(_("directory createname error"), error);
>> +
>>   }
>>   
>>   static void
>> @@ -387,6 +390,7 @@ parseproto(
>>   	cred_t		creds;
>>   	char		*value;
>>   	struct xfs_name	xname;
>> +	xfs_dir2_dataptr_t offset;
>>   
>>   	memset(&creds, 0, sizeof(creds));
>>   	mstr = getstr(pp);
>> @@ -470,7 +474,7 @@ parseproto(
>>   			free(buf);
>>   		libxfs_trans_ijoin(tp, pip, 0);
>>   		xname.type = XFS_DIR3_FT_REG_FILE;
>> -		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
>> +		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
>>   		break;
>>   
>>   	case IF_RESERVED:			/* pre-allocated space only */
>> @@ -493,7 +497,7 @@ parseproto(
>>   		libxfs_trans_ijoin(tp, pip, 0);
>>   
>>   		xname.type = XFS_DIR3_FT_REG_FILE;
>> -		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
>> +		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
>>   		libxfs_trans_log_inode(tp, ip, flags);
>>   
>>   		libxfs_defer_ijoin(&dfops, ip);
>> @@ -516,7 +520,7 @@ parseproto(
>>   		}
>>   		libxfs_trans_ijoin(tp, pip, 0);
>>   		xname.type = XFS_DIR3_FT_BLKDEV;
>> -		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
>> +		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
>>   		flags |= XFS_ILOG_DEV;
>>   		break;
>>   
>> @@ -530,7 +534,7 @@ parseproto(
>>   			fail(_("Inode allocation failed"), error);
>>   		libxfs_trans_ijoin(tp, pip, 0);
>>   		xname.type = XFS_DIR3_FT_CHRDEV;
>> -		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
>> +		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
>>   		flags |= XFS_ILOG_DEV;
>>   		break;
>>   
>> @@ -542,7 +546,7 @@ parseproto(
>>   			fail(_("Inode allocation failed"), error);
>>   		libxfs_trans_ijoin(tp, pip, 0);
>>   		xname.type = XFS_DIR3_FT_FIFO;
>> -		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
>> +		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
>>   		break;
>>   	case IF_SYMLINK:
>>   		buf = getstr(pp);
>> @@ -555,7 +559,7 @@ parseproto(
>>   		flags |= newfile(tp, ip, &dfops, &first, 1, 1, buf, len);
>>   		libxfs_trans_ijoin(tp, pip, 0);
>>   		xname.type = XFS_DIR3_FT_SYMLINK;
>> -		newdirent(mp, tp, pip, &xname, ip->i_ino, &first, &dfops);
>> +		newdirent(mp, tp, pip, &xname, ip, &first, &dfops, &offset);
>>   		break;
>>   	case IF_DIRECTORY:
>>   		tp = getres(mp, 0);
>> @@ -572,8 +576,8 @@ parseproto(
>>   		} else {
>>   			libxfs_trans_ijoin(tp, pip, 0);
>>   			xname.type = XFS_DIR3_FT_DIR;
>> -			newdirent(mp, tp, pip, &xname, ip->i_ino,
>> -				  &first, &dfops);
>> +			newdirent(mp, tp, pip, &xname, ip,
>> +				  &first, &dfops, &offset);
>>   			inc_nlink(VFS_I(pip));
>>   			libxfs_trans_log_inode(tp, pip, XFS_ILOG_CORE);
>>   		}
>> @@ -612,8 +616,23 @@ parseproto(
>>   		fail(_("Error encountered creating file from prototype file"),
>>   			error);
>>   	}
>> -	libxfs_trans_commit(tp);
>> +        libxfs_trans_commit(tp);
>> +
>> +	if (xfs_sb_version_hasparent(&mp->m_sb)) {
>> +		error = xfs_parent_add(tp, pip, ip, &xname, offset, &first, &dfops);
> Definitely can't keep using tp after committing the transaction.
>
>> +		if (error)
>> +			fail(_("Error creating parent pointer"), error);
>> +
>> +		libxfs_trans_log_inode(tp, ip, flags);
>> +		libxfs_defer_ijoin(&dfops, ip);
>> +		error = -libxfs_defer_finish(&tp, &dfops);
>> +		if (error)
>> +			fail(_("Directory creation failed"), error);
>> +		libxfs_trans_commit(tp);
> Also, if you add libxfs_trans_commit calls they probably ought to have
> return values checked in case some day libxfs_trans_commit starts
> returning error codes.
Alrighty, will fix
>> +	}
>> +
>>   	IRELE(ip);
>> +	
>>   }
>>   
>>   void
>> diff --git a/repair/attr_repair.c b/repair/attr_repair.c
>> index 8b1b8a7..e5ff3b0 100644
>> --- a/repair/attr_repair.c
>> +++ b/repair/attr_repair.c
>> @@ -305,16 +305,6 @@ process_shortform_attr(
>>   			}
>>   		}
>>   
>> -		/* namecheck checks for / and null terminated for file names.
>> -		 * attributes names currently follow the same rules.
>> -		*/
>> -		if (namecheck((char *)&currententry->nameval[0],
> Why remove the namecheck calls?  It's only the ATTR_PARENT attributes
> where we want to skip the null-in-name checks, right?
Oh, I had forgotten about this.  I'll add something to make it exclude 
only pptrs
>
>> -						currententry->namelen))  {
>> -			do_warn(
>> -	_("entry contains illegal character in shortform attribute name\n"));
>> -			junkit = 1;
>> -		}
>> -
>>   		if (currententry->flags & XFS_ATTR_INCOMPLETE) {
>>   			do_warn(
>>   	_("entry has INCOMPLETE flag on in shortform attribute\n"));
>> @@ -470,8 +460,7 @@ process_leaf_attr_local(
>>   	xfs_attr_leaf_name_local_t *local;
>>   
>>   	local = xfs_attr3_leaf_name_local(leaf, i);
>> -	if (local->namelen == 0 || namecheck((char *)&local->nameval[0],
>> -							local->namelen)) {
>> +	if (local->namelen == 0) {
>>   		do_warn(
>>   	_("attribute entry %d in attr block %u, inode %" PRIu64 " has bad name (namelen = %d)\n"),
>>   			i, da_bno, ino, local->namelen);
>> @@ -525,8 +514,7 @@ process_leaf_attr_remote(
>>   
>>   	remotep = xfs_attr3_leaf_name_remote(leaf, i);
>>   
>> -	if (remotep->namelen == 0 || namecheck((char *)&remotep->name[0],
>> -						remotep->namelen) ||
>> +	if (remotep->namelen == 0 ||
>>   			be32_to_cpu(entry->hashval) !=
>>   				libxfs_da_hashname((unsigned char *)&remotep->name[0],
>>   						remotep->namelen) ||
>> diff --git a/repair/phase6.c b/repair/phase6.c
>> index 4fedb35..b861b3b 100644
>> --- a/repair/phase6.c
>> +++ b/repair/phase6.c
>> @@ -29,6 +29,7 @@
>>   #include "dinode.h"
>>   #include "progress.h"
>>   #include "versions.h"
>> +#include "xfs_parent.h"
>>   
>>   static struct cred		zerocr;
>>   static struct fsxattr 		zerofsx;
>> @@ -962,19 +963,20 @@ mk_root_dir(xfs_mount_t *mp)
>>   static xfs_ino_t
>>   mk_orphanage(xfs_mount_t *mp)
>>   {
>> -	xfs_ino_t	ino;
>> -	xfs_trans_t	*tp;
>> -	xfs_inode_t	*ip;
>> -	xfs_inode_t	*pip;
>> -	xfs_fsblock_t	first;
>> -	ino_tree_node_t	*irec;
>> -	int		ino_offset = 0;
>> -	int		i;
>> -	int		error;
>> +	xfs_ino_t		ino;
>> +	xfs_trans_t		*tp;
>> +	xfs_inode_t		*ip;
>> +	xfs_inode_t		*pip;
>> +	xfs_fsblock_t		first;
>> +	ino_tree_node_t		*irec;
>> +	int			ino_offset = 0;
>> +	int			i;
>> +	int			error;
>>   	struct xfs_defer_ops	dfops;
>> -	const int	mode = 0755;
>> -	int		nres;
>> -	struct xfs_name	xname;
>> +	const int		mode = 0755;
>> +	int			nres;
>> +	struct xfs_name		xname;
>> +	xfs_dir2_dataptr_t      offset;
>>   
>>   	/*
>>   	 * check for an existing lost+found first, if it exists, return
>> @@ -1061,7 +1063,7 @@ mk_orphanage(xfs_mount_t *mp)
>>   	 * create the actual entry
>>   	 */
>>   	error = -libxfs_dir_createname(tp, pip, &xname, ip->i_ino, &first,
>> -					&dfops, nres, NULL);
>> +					&dfops, nres, &offset);
>>   	if (error)
>>   		do_error(
>>   		_("can't make %s, createname error %d\n"),
>> @@ -1089,6 +1091,14 @@ mk_orphanage(xfs_mount_t *mp)
>>   			ORPHANAGE, error);
>>   	}
>>   
>> +        libxfs_trans_commit(tp);
>> +        if (xfs_sb_version_hasparent(&mp->m_sb)) {
>> +                error = xfs_parent_add(tp, pip, ip, &xname, offset,
> When you want to use libxfs functions from outside of libxfs (namely
> within mkfs/repair/whatever) the convention is to add a #define in
> libxfs_api_defs.h:
>
> #define libxfs_parent_add	xfs_parent_add
>
> And then in the utility program the usage should be:
>
> error = -libxfs_parent_add(...);
>
> Because libxfs functions return negative numbers for errors (kernel
> style) but the rest of the C world expects positive error codes.
>
> In theory xfs/437 should complain about this (though for all I know it
> could be busted).
>
> --D
I see, I will get libxfs_api_defs updated then.  Thx for the review!

Allison
>> +				       &first, &dfops);
>> +                if (error)
>> +                        do_error(_("Error creating parent pointer: %d\n"),
>> +				 error);
>> +        }
>>   
>>   	libxfs_trans_commit(tp);
>>   	IRELE(ip);
>> @@ -1120,6 +1130,7 @@ mv_orphanage(
>>   	ino_tree_node_t		*irec;
>>   	int			ino_offset = 0;
>>   	struct xfs_name		xname;
>> +	xfs_dir2_dataptr_t      offset;
>>   
>>   	xname.name = fname;
>>   	xname.len = snprintf((char *)fname, sizeof(fname), "%llu",
>> @@ -1170,7 +1181,7 @@ mv_orphanage(
>>   
>>   			libxfs_defer_init(&dfops, &first);
>>   			err = -libxfs_dir_createname(tp, orphanage_ip, &xname,
>> -						ino, &first, &dfops, nres, NULL);
>> +						ino, &first, &dfops, nres, &offset);
>>   			if (err)
>>   				do_error(
>>   	_("name create failed in %s (%d), filesystem may be out of space\n"),
>> @@ -1183,7 +1194,7 @@ mv_orphanage(
>>   			libxfs_trans_log_inode(tp, orphanage_ip, XFS_ILOG_CORE);
>>   
>>   			err = -libxfs_dir_createname(tp, ino_p, &xfs_name_dotdot,
>> -					orphanage_ino, &first, &dfops, nres, NULL);
>> +					orphanage_ino, &first, &dfops, nres, &offset);
>>   			if (err)
>>   				do_error(
>>   	_("creation of .. entry failed (%d), filesystem may be out of space\n"),
>> @@ -1214,7 +1225,7 @@ mv_orphanage(
>>   			libxfs_defer_init(&dfops, &first);
>>   
>>   			err = -libxfs_dir_createname(tp, orphanage_ip, &xname,
>> -						ino, &first, &dfops, nres, NULL);
>> +						ino, &first, &dfops, nres, &offset);
>>   			if (err)
>>   				do_error(
>>   	_("name create failed in %s (%d), filesystem may be out of space\n"),
>> @@ -1233,7 +1244,7 @@ mv_orphanage(
>>   			if (entry_ino_num != orphanage_ino)  {
>>   				err = -libxfs_dir_replace(tp, ino_p,
>>   						&xfs_name_dotdot, orphanage_ino,
>> -						&first, &dfops, nres, NULL);
>> +						&first, &dfops, nres, &offset);
>>   				if (err)
>>   					do_error(
>>   	_("name replace op failed (%d), filesystem may be out of space\n"),
>> @@ -1270,7 +1281,7 @@ mv_orphanage(
>>   
>>   		libxfs_defer_init(&dfops, &first);
>>   		err = -libxfs_dir_createname(tp, orphanage_ip, &xname, ino,
>> -						&first, &dfops, nres, NULL);
>> +						&first, &dfops, nres, &offset);
>>   		if (err)
>>   			do_error(
>>   	_("name create failed in %s (%d), filesystem may be out of space\n"),
>> -- 
>> 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


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 17/21] xfsprogs: Add delayed attributes error tag
  2018-05-08 17:21   ` Darrick J. Wong
@ 2018-05-08 20:17     ` Eric Sandeen
  0 siblings, 0 replies; 45+ messages in thread
From: Eric Sandeen @ 2018-05-08 20:17 UTC (permalink / raw)
  To: Darrick J. Wong, Allison Henderson; +Cc: linux-xfs



On 5/8/18 12:21 PM, Darrick J. Wong wrote:
> On Mon, May 07, 2018 at 09:41:15PM -0700, Allison Henderson wrote:
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> 
> Needs a commit message.  Eric might also want the xfs_io bit as a
> separate patch to keep this one as close to the kernel patch as
> possible.
> 
> (Though really, it's a single line, maybe not...)

I generally port libxfs to xfsprogs after it's hit the kernel, and then
fix stuff up as needed, which usually means "fix it so it builds again."

Stuff like this would get missed under that plan, so yes, a separate
patch to "enhance" xfs_io like this would be appreciated, to be sure
I don't miss it.

Thanks,
-Eric

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 20/21] xfsprogs: Add parent pointers during protofile creation
  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
  1 sibling, 1 reply; 45+ messages in thread
From: Eric Sandeen @ 2018-05-08 20:39 UTC (permalink / raw)
  To: Darrick J. Wong, Allison Henderson; +Cc: linux-xfs



On 5/8/18 12:43 PM, Darrick J. Wong wrote:
> On Mon, May 07, 2018 at 09:41:18PM -0700, Allison Henderson wrote:
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
>>  mkfs/proto.c         | 59 ++++++++++++++++++++++++++++++++++------------------
>>  repair/attr_repair.c | 16 ++------------
>>  repair/phase6.c      | 47 +++++++++++++++++++++++++----------------

> Separate patches for separate utilities, please.

Or at least patch per functional change; it's not at all clear to me how protofile
creation has anything to do with xfs_repair, and there's nothing in the commit
log to help me figure it out.  :)

(I think it doesn't have anything to do w/ protofile creation, and the repair
patches are fixing up orphanage entry creation; the attr_repair changes seem
like some third thing that I don't grok yet, sorry - removing namecheck() for
some reason?).

-Eric
 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 21/21] xfsprogs: implement the upper half of parent pointers
  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-08 20:52   ` Eric Sandeen
  2018-05-08 23:04     ` Darrick J. Wong
  1 sibling, 1 reply; 45+ messages in thread
From: Eric Sandeen @ 2018-05-08 20:52 UTC (permalink / raw)
  To: Allison Henderson, linux-xfs

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

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 20/21] xfsprogs: Add parent pointers during protofile creation
  2018-05-08 20:39     ` Eric Sandeen
@ 2018-05-08 21:14       ` Allison Henderson
  2018-05-08 21:17         ` Eric Sandeen
  0 siblings, 1 reply; 45+ messages in thread
From: Allison Henderson @ 2018-05-08 21:14 UTC (permalink / raw)
  To: Eric Sandeen, Darrick J. Wong; +Cc: linux-xfs



On 05/08/2018 01:39 PM, Eric Sandeen wrote:
> 
> 
> On 5/8/18 12:43 PM, Darrick J. Wong wrote:
>> On Mon, May 07, 2018 at 09:41:18PM -0700, Allison Henderson wrote:
>>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>>> ---
>>>   mkfs/proto.c         | 59 ++++++++++++++++++++++++++++++++++------------------
>>>   repair/attr_repair.c | 16 ++------------
>>>   repair/phase6.c      | 47 +++++++++++++++++++++++++----------------
> 
>> Separate patches for separate utilities, please.
> 
> Or at least patch per functional change; it's not at all clear to me how protofile
> creation has anything to do with xfs_repair, and there's nothing in the commit
> log to help me figure it out.  :)
> 
> (I think it doesn't have anything to do w/ protofile creation, and the repair
> patches are fixing up orphanage entry creation; the attr_repair changes seem
> like some third thing that I don't grok yet, sorry - removing namecheck() for
> some reason?).
> 
> -Eric

Ok, it took me a minute to remember why I did this too.  We had ended up 
adding a parameter to libxfs_dir_createname to get the offset needed for 
creating the parent pointer in the protofile, and I ended up following 
the compiler errors back around the repair code that uses the same 
function calls as well.

Maybe I should make a separate patch just for the offset like the kernel 
space set does, and then have two smaller patches for the protofile and 
repair code.

Allison

>   
> --
> 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=DwIDaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=RAhvaxRO4Y3BuEWfKCiKHMUeNpZj53frHeTCh1R64dU&s=KTNiitB11SrpPwMvBXEQzon_G1JLFHAd69coCAKx8_Y&e=
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 20/21] xfsprogs: Add parent pointers during protofile creation
  2018-05-08 21:14       ` Allison Henderson
@ 2018-05-08 21:17         ` Eric Sandeen
  2018-05-08 21:57           ` Allison Henderson
  0 siblings, 1 reply; 45+ messages in thread
From: Eric Sandeen @ 2018-05-08 21:17 UTC (permalink / raw)
  To: Allison Henderson, Darrick J. Wong; +Cc: linux-xfs



On 5/8/18 4:14 PM, Allison Henderson wrote:
> 
> 
> On 05/08/2018 01:39 PM, Eric Sandeen wrote:
>>
>>
>> On 5/8/18 12:43 PM, Darrick J. Wong wrote:
>>> On Mon, May 07, 2018 at 09:41:18PM -0700, Allison Henderson wrote:
>>>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>>>> ---
>>>>   mkfs/proto.c         | 59 ++++++++++++++++++++++++++++++++++------------------
>>>>   repair/attr_repair.c | 16 ++------------
>>>>   repair/phase6.c      | 47 +++++++++++++++++++++++++----------------
>>
>>> Separate patches for separate utilities, please.
>>
>> Or at least patch per functional change; it's not at all clear to me how protofile
>> creation has anything to do with xfs_repair, and there's nothing in the commit
>> log to help me figure it out.  :)
>>
>> (I think it doesn't have anything to do w/ protofile creation, and the repair
>> patches are fixing up orphanage entry creation; the attr_repair changes seem
>> like some third thing that I don't grok yet, sorry - removing namecheck() for
>> some reason?).
>>
>> -Eric
> 
> Ok, it took me a minute to remember why I did this too.  We had ended up adding a parameter to libxfs_dir_createname to get the offset needed for creating the parent pointer in the protofile, and I ended up following the compiler errors back around the repair code that uses the same function calls as well.

Except that this patch isn't fixing the parameter count, it's changing it from NULL, right?

@@ -1170,7 +1181,7 @@ mv_orphanage(
 
 			libxfs_defer_init(&dfops, &first);
 			err = -libxfs_dir_createname(tp, orphanage_ip, &xname,
-						ino, &first, &dfops, nres, NULL);
+						ino, &first, &dfops, nres, &offset);


...I wonder if there's much hope for doing this series in a bisectable way.  :)

> Maybe I should make a separate patch just for the offset like the kernel space set does, and then have two smaller patches for the protofile and repair code.

That might be good.  Any hint about what the attr_repair.c changes are?

Thanks,
-Eric

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 20/21] xfsprogs: Add parent pointers during protofile creation
  2018-05-08 21:17         ` Eric Sandeen
@ 2018-05-08 21:57           ` Allison Henderson
  2018-05-08 22:27             ` Eric Sandeen
  0 siblings, 1 reply; 45+ messages in thread
From: Allison Henderson @ 2018-05-08 21:57 UTC (permalink / raw)
  To: Eric Sandeen, Darrick J. Wong; +Cc: linux-xfs

On 05/08/2018 02:17 PM, Eric Sandeen wrote:
> 
> 
> On 5/8/18 4:14 PM, Allison Henderson wrote:
>>
>>
>> On 05/08/2018 01:39 PM, Eric Sandeen wrote:
>>>
>>>
>>> On 5/8/18 12:43 PM, Darrick J. Wong wrote:
>>>> On Mon, May 07, 2018 at 09:41:18PM -0700, Allison Henderson wrote:
>>>>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>>>>> ---
>>>>>    mkfs/proto.c         | 59 ++++++++++++++++++++++++++++++++++------------------
>>>>>    repair/attr_repair.c | 16 ++------------
>>>>>    repair/phase6.c      | 47 +++++++++++++++++++++++++----------------
>>>
>>>> Separate patches for separate utilities, please.
>>>
>>> Or at least patch per functional change; it's not at all clear to me how protofile
>>> creation has anything to do with xfs_repair, and there's nothing in the commit
>>> log to help me figure it out.  :)
>>>
>>> (I think it doesn't have anything to do w/ protofile creation, and the repair
>>> patches are fixing up orphanage entry creation; the attr_repair changes seem
>>> like some third thing that I don't grok yet, sorry - removing namecheck() for
>>> some reason?).
>>>
>>> -Eric
>>
>> Ok, it took me a minute to remember why I did this too.  We had ended up adding a parameter to libxfs_dir_createname to get the offset needed for creating the parent pointer in the protofile, and I ended up following the compiler errors back around the repair code that uses the same function calls as well.
> 
> Except that this patch isn't fixing the parameter count, it's changing it from NULL, right?
> 
> @@ -1170,7 +1181,7 @@ mv_orphanage(
>   
>   			libxfs_defer_init(&dfops, &first);
>   			err = -libxfs_dir_createname(tp, orphanage_ip, &xname,
> -						ino, &first, &dfops, nres, NULL);
> +						ino, &first, &dfops, nres, &offset);
> 
> 
> ...I wonder if there's much hope for doing this series in a bisectable way.  :)
> 
>> Maybe I should make a separate patch just for the offset like the kernel space set does, and then have two smaller patches for the protofile and repair code.
> 
> That might be good.  Any hint about what the attr_repair.c changes are?
> 
> Thanks,
> -Eric
> 
Oh, you're right.  I probably just tracked it down then.  Reasoning that 
anything using it would likely need the pptr update to go along with it. 
It can still be a separate patch though.

The changes in repair/attr_repair.c are because the parent pointer names 
are not strings, they are the binary {ino, gen, diroffset}.  So it 
doesnt make sense to run a name check on them.  I'll try to get 
something added to only skip the check for pptrs though.

Allison


^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 20/21] xfsprogs: Add parent pointers during protofile creation
  2018-05-08 21:57           ` Allison Henderson
@ 2018-05-08 22:27             ` Eric Sandeen
  0 siblings, 0 replies; 45+ messages in thread
From: Eric Sandeen @ 2018-05-08 22:27 UTC (permalink / raw)
  To: Allison Henderson, Darrick J. Wong; +Cc: linux-xfs

On 5/8/18 4:57 PM, Allison Henderson wrote:
> On 05/08/2018 02:17 PM, Eric Sandeen wrote:

...

>>> Ok, it took me a minute to remember why I did this too.  We had ended up adding a parameter to libxfs_dir_createname to get the offset needed for creating the parent pointer in the protofile, and I ended up following the compiler errors back around the repair code that uses the same function calls as well.
>>
>> Except that this patch isn't fixing the parameter count, it's changing it from NULL, right?
>>
>> @@ -1170,7 +1181,7 @@ mv_orphanage(
>>                 libxfs_defer_init(&dfops, &first);
>>               err = -libxfs_dir_createname(tp, orphanage_ip, &xname,
>> -                        ino, &first, &dfops, nres, NULL);
>> +                        ino, &first, &dfops, nres, &offset);
>>
>>
>> ...I wonder if there's much hope for doing this series in a bisectable way.  :)
>>
>>> Maybe I should make a separate patch just for the offset like the kernel space set does, and then have two smaller patches for the protofile and repair code.
>>
>> That might be good.  Any hint about what the attr_repair.c changes are?
>>
>> Thanks,
>> -Eric
>>
> Oh, you're right.  I probably just tracked it down then.  Reasoning that anything using it would likely need the pptr update to go along with it. It can still be a separate patch though.

It's fine by me if the commit is something like "xfsprogs: update parent pointers in mkfs and repair"

It's just confusing to have a terse commit log stating that it does one thing, and in fact it is doing 3 unrelated things.

> The changes in repair/attr_repair.c are because the parent pointer names are not strings, they are the binary {ino, gen, diroffset}.  So it doesnt make sense to run a name check on them.  I'll try to get something added to only skip the check for pptrs though.

Ah, that makes sense (and sounds necessary) - we can't skip the check on every attribute name just because it might possibly be a parent pointer.

Thanks,
-Eric

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 18/21] xfsprogs: Add parent pointer flag to cmd
  2018-05-08 19:02     ` Allison Henderson
@ 2018-05-08 22:44       ` Darrick J. Wong
  0 siblings, 0 replies; 45+ messages in thread
From: Darrick J. Wong @ 2018-05-08 22:44 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

On Tue, May 08, 2018 at 12:02:29PM -0700, Allison Henderson wrote:
> On 05/08/2018 10:25 AM, Darrick J. Wong wrote:
> > On Mon, May 07, 2018 at 09:41:16PM -0700, Allison Henderson wrote:
> > > Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> > Needs commit message:
> > 
> > mkfs: enable formatting with parent pointers
> > 
> > Wire up parent pointer support in mkfs via the '-m parent' parameter.
> > 
> > Signed-off-by: <etc>
> Ok, will update
> > > ---
> > >   mkfs/xfs_mkfs.c | 16 +++++++++++++++-
> > >   1 file changed, 15 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
> > > index 78d0ce5..554e1bf 100644
> > > --- a/mkfs/xfs_mkfs.c
> > > +++ b/mkfs/xfs_mkfs.c
> > > @@ -129,6 +129,7 @@ enum {
> > >   	M_UUID,
> > >   	M_RMAPBT,
> > >   	M_REFLINK,
> > > +	M_PARENT,
> > Hmm, is this better off in the naming section?
> > 
> > e.g. "mkfs.xfs -n parent=1"
> I suppose it could fit there too if that's preferred.  I wasnt really sure
> which section it fit best to :-)

<shrug> -n is where we put the other naming and directory related stuff.

> > >   	M_MAX_OPTS,
> > >   };
> > > @@ -663,6 +664,7 @@ struct opt_params mopts = {
> > >   		[M_UUID] = "uuid",
> > >   		[M_RMAPBT] = "rmapbt",
> > >   		[M_REFLINK] = "reflink",
> > > +		[M_PARENT] = "parent",
> > >   	},
> > >   	.subopt_params = {
> > >   		{ .index = M_CRC,
> > > @@ -693,6 +695,13 @@ struct opt_params mopts = {
> > >   		  .maxval = 1,
> > >   		  .defaultval = 1,
> > >   		},
> > > +		{ .index = M_PARENT,
> > > +		  .conflicts = { {NULL, LAST_CONFLICT } },
> > > +		  .minval = 0,
> > > +		  .maxval = 1,
> > > +		  .defaultval = 0,
> > This (misleadingly named) field is the default value if you pass the
> > argument without explicitly assigning a value, i.e.
> > 
> > # mkfs.xfs -m parent /dev/sda
> > 
> > sets parent to whatever defaultval is.  In this case you'd get no parent
> > pointers, which is a little surprising.
> > 
> > And, uh, seeing as people keep getting this wrong maybe we should rename
> > it?
> Oh I see.  That is a little odd, is there really a better name though? 
> Maybe just a comment or something might make it more clear.

"implied_default"
"implicit_default"
"valueIfNotExplicitlySpecified"
"m_thevalueassignedifnovalueisgiven"

(No, please not those last two...)

--D

> > > +		},
> > > +
> > >   	},
> > >   };
> > > @@ -865,7 +874,7 @@ usage( void )
> > >   {
> > >   	fprintf(stderr, _("Usage: %s\n\
> > >   /* blocksize */		[-b size=num]\n\
> > > -/* metadata */		[-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1]\n\
> > > +/* metadata */		[-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1,parent=0|1]\n\
> > >   /* data subvol */	[-d agcount=n,agsize=n,file,name=xxx,size=num,\n\
> > >   			    (sunit=value,swidth=value|su=num,sw=num|noalign),\n\
> > >   			    sectsize=num\n\
> > > @@ -1586,6 +1595,9 @@ meta_opts_parser(
> > >   	case M_REFLINK:
> > >   		cli->sb_feat.reflink = getnum(value, opts, subopt);
> > >   		break;
> > > +	case M_PARENT:
> > > +		cli->sb_feat.parent_pointers = getnum(value, &mopts, M_PARENT);
> > > +		break;
> > >   	default:
> > >   		return -EINVAL;
> > >   	}
> > > @@ -2887,6 +2899,8 @@ sb_set_features(
> > >   		sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_RMAPBT;
> > >   	if (fp->reflink)
> > >   		sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_REFLINK;
> > > +	if (fp->parent_pointers)
> > > +		sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_PARENT;
> > Otherwise looks ok to me....
> > 
> > --D
> Alrighty, thx!
> > >   	/*
> > >   	 * Sparse inode chunk support has two main inode alignment requirements.
> > > -- 
> > > 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  https://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=2DFx03tmCKRPVndQLwf1P1u0PChkNowVFyXqzZ_arE8&s=JiwNEPlNO54aLxRtPd9mGL_lKU8dpX4T6ECMmDQhc70&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=2DFx03tmCKRPVndQLwf1P1u0PChkNowVFyXqzZ_arE8&s=JiwNEPlNO54aLxRtPd9mGL_lKU8dpX4T6ECMmDQhc70&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

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 21/21] xfsprogs: implement the upper half of parent pointers
  2018-05-08 20:52   ` Eric Sandeen
@ 2018-05-08 23:04     ` Darrick J. Wong
  2018-05-08 23:13       ` Allison Henderson
  0 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2018-05-08 23:04 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: Allison Henderson, linux-xfs

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

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 21/21] xfsprogs: implement the upper half of parent pointers
  2018-05-08 23:04     ` Darrick J. Wong
@ 2018-05-08 23:13       ` Allison Henderson
  2018-05-09  1:22         ` Darrick J. Wong
  0 siblings, 1 reply; 45+ messages in thread
From: Allison Henderson @ 2018-05-08 23:13 UTC (permalink / raw)
  To: Darrick J. Wong, Eric Sandeen; +Cc: linux-xfs



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

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 21/21] xfsprogs: implement the upper half of parent pointers
  2018-05-08 23:13       ` Allison Henderson
@ 2018-05-09  1:22         ` Darrick J. Wong
  2018-05-09  1:32           ` Allison Henderson
  0 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2018-05-09  1:22 UTC (permalink / raw)
  To: Allison Henderson; +Cc: Eric Sandeen, linux-xfs

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

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 21/21] xfsprogs: implement the upper half of parent pointers
  2018-05-09  1:22         ` Darrick J. Wong
@ 2018-05-09  1:32           ` Allison Henderson
  0 siblings, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-09  1:32 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: Eric Sandeen, linux-xfs



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=
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 21/21] xfsprogs: implement the upper half of parent pointers
  2018-05-08 17:45   ` Darrick J. Wong
@ 2018-05-09  1:39     ` Allison Henderson
  2018-05-09  1:44       ` Darrick J. Wong
  0 siblings, 1 reply; 45+ messages in thread
From: Allison Henderson @ 2018-05-09  1:39 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

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

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 21/21] xfsprogs: implement the upper half of parent pointers
  2018-05-09  1:39     ` Allison Henderson
@ 2018-05-09  1:44       ` Darrick J. Wong
  2018-05-09  1:47         ` Allison Henderson
  0 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2018-05-09  1:44 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs


> 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

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 21/21] xfsprogs: implement the upper half of parent pointers
  2018-05-09  1:44       ` Darrick J. Wong
@ 2018-05-09  1:47         ` Allison Henderson
  0 siblings, 0 replies; 45+ messages in thread
From: Allison Henderson @ 2018-05-09  1:47 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

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

^ permalink raw reply	[flat|nested] 45+ messages in thread

end of thread, other threads:[~2018-05-09  1:47 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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
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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.