All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/17] Parent Pointers v4
@ 2017-11-17 18:21 Allison Henderson
  2017-11-17 18:21 ` [PATCH v3 01/17] Add helper functions xfs_attr_set_args and xfs_attr_remove_args Allison Henderson
                   ` (16 more replies)
  0 siblings, 17 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Henderson

Hi all,

This is the fourth version of parent pointer attributes for xfs. The goal of
this patch set is to add a parent pointer attribute to each inode.  The
attribute name containing the parent inode, generation, and directory offset,
while the  attribute value contains the file name.  This feature will enable
future optimizations for online scrub, or any other feature that could make
use of quickly deriving an inodes path from  the mount point.  This set also
introduces deferred attribute operations, though it is currently only used by
 the new parent pointer code.

I've integrated the suggestions made since v3, the biggest of which I think
was reducing the size of xfs_attr_log_item so that they didn't take up quite
so much space, as well as merging the deferred attribute set and create code
paths.  I've also added a patch that implements a new ioctl interface to return
the parent pointer to user space. I know Darrick already had some suggestions
for the new ioctl code that I still need to add, but I wanted to keep the rest
of the folks out here updated as to where I am with it now.

I'm still working on setting up some new xfstests for this patch set. I'll need
to get the appropriate changes mapped to xfsprogs first, but I will keep folks
updated as I go.

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

Allison Henderson

Allison Henderson (8):
  Add helper functions xfs_attr_set_args and xfs_attr_remove_args
  Set up infastructure for deferred attribute operations
  Add xfs_attr_set_defered and xfs_attr_remove_defered
  Remove all strlen calls in all xfs_attr_* functions for attr names.
  Add the extra space requirements for parent pointer attributes when
    calculating the minimum log size during mkfs
  Add parent pointers to rename
  Add the parent pointer support to the superblock version 5.
  Add parent pointer ioctl

Dave Chinner (5):
  xfs: define parent pointer xattr format
  xfs: extent transaction reservations for parent attributes
  xfs: parent pointer attribute creation
  xfs: add parent attributes to link
  xfs: remove parent pointers in unlink

Mark Tinguely (4):
  xfs: get directory offset when adding directory name
  xfs: get directory offset when removing directory name
  xfs: get directory offset when replacing a directory name
  xfs: add parent pointer support to attribute code

 fs/xfs/Makefile                |   3 +
 fs/xfs/libxfs/xfs_attr.c       | 481 +++++++++++++++++++++++++++-----------
 fs/xfs/libxfs/xfs_bmap.c       |  55 +++--
 fs/xfs/libxfs/xfs_bmap.h       |   1 +
 fs/xfs/libxfs/xfs_da_btree.h   |   1 +
 fs/xfs/libxfs/xfs_da_format.h  |  12 +-
 fs/xfs/libxfs/xfs_defer.h      |   1 +
 fs/xfs/libxfs/xfs_dir2.c       |  41 ++--
 fs/xfs/libxfs/xfs_dir2.h       |  10 +-
 fs/xfs/libxfs/xfs_dir2_block.c |   9 +-
 fs/xfs/libxfs/xfs_dir2_leaf.c  |   8 +-
 fs/xfs/libxfs/xfs_dir2_node.c  |   8 +-
 fs/xfs/libxfs/xfs_dir2_sf.c    |   6 +
 fs/xfs/libxfs/xfs_format.h     |  37 ++-
 fs/xfs/libxfs/xfs_fs.h         |   2 +
 fs/xfs/libxfs/xfs_log_format.h |  37 ++-
 fs/xfs/libxfs/xfs_log_rlimit.c |  34 +++
 fs/xfs/libxfs/xfs_parent.c     | 113 +++++++++
 fs/xfs/libxfs/xfs_trans_resv.c | 103 +++++++--
 fs/xfs/libxfs/xfs_types.h      |   1 +
 fs/xfs/xfs_acl.c               |  12 +-
 fs/xfs/xfs_attr.h              |  58 ++++-
 fs/xfs/xfs_attr_item.c         | 513 +++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_attr_item.h         | 117 ++++++++++
 fs/xfs/xfs_attr_list.c         |   3 +
 fs/xfs/xfs_fsops.c             |   4 +-
 fs/xfs/xfs_inode.c             | 141 ++++++++---
 fs/xfs/xfs_ioctl.c             |  61 ++++-
 fs/xfs/xfs_iops.c              |   6 +-
 fs/xfs/xfs_log_recover.c       | 140 +++++++++++
 fs/xfs/xfs_super.c             |   5 +
 fs/xfs/xfs_symlink.c           |   2 +-
 fs/xfs/xfs_trans.h             |  13 ++
 fs/xfs/xfs_trans_attr.c        | 288 +++++++++++++++++++++++
 fs/xfs/xfs_xattr.c             |  10 +-
 35 files changed, 2062 insertions(+), 274 deletions(-)
 create mode 100644 fs/xfs/libxfs/xfs_parent.c
 create mode 100644 fs/xfs/xfs_attr_item.c
 create mode 100644 fs/xfs/xfs_attr_item.h
 create mode 100644 fs/xfs/xfs_trans_attr.c

-- 
2.7.4


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

* [PATCH v3 01/17] Add helper functions xfs_attr_set_args and xfs_attr_remove_args
  2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
@ 2017-11-17 18:21 ` Allison Henderson
  2017-11-28 19:54   ` Darrick J. Wong
  2017-11-17 18:21 ` [PATCH v3 02/17] Set up infastructure for deferred attribute operations Allison Henderson
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Henderson

These sub-routines set or remove 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>
---
 fs/xfs/libxfs/xfs_attr.c | 335 ++++++++++++++++++++++++++++-------------------
 fs/xfs/libxfs/xfs_bmap.c |  55 ++++----
 fs/xfs/libxfs/xfs_bmap.h |   1 +
 fs/xfs/xfs_attr.h        |   2 +
 4 files changed, 236 insertions(+), 157 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 6249c92..e5f2960 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -168,6 +168,195 @@ 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,
+	bool			roll_trans)
+{
+	struct xfs_inode	*dp = args->dp;
+	struct xfs_mount        *mp = dp->i_mount;
+	struct xfs_trans_res    tres;
+	int			rsvd = 0;
+	int			error = 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;
+	}
+
+	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;
+
+	error = xfs_trans_reserve_quota_nblks(args->trans, dp, args->total, 0,
+					      rsvd ? XFS_QMOPT_RES_REGBLKS |
+						     XFS_QMOPT_FORCE_RES :
+						     XFS_QMOPT_RES_REGBLKS);
+	if (error)
+		goto out;
+
+	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);
+		if (error != -ENOSPC) {
+			ASSERT(args->trans);
+			if (!error && (flags & ATTR_KERNOTIME) == 0)
+				xfs_trans_ichgtime(args->trans, dp,
+						   XFS_ICHGTIME_CHG);
+			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);
+		if (error)
+			goto out;
+		xfs_defer_ijoin(args->dfops, dp);
+		if (roll_trans) {
+			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;
+		}
+	}
+
+	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
+		error = xfs_attr_leaf_addname(args);
+	else
+		error = xfs_attr_node_addname(args);
+	if (error)
+		goto out;
+
+	if ((flags & ATTR_KERNOTIME) == 0)
+		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
+
+	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
+out:
+	return error;
+}
+
+/*
+ * Remove the attribute specified in @args.
+ */
+int
+xfs_attr_remove_args(
+	struct xfs_da_args      *args,
+	int			flags)
+{
+	struct xfs_inode	*dp = args->dp;
+	struct xfs_mount	*mp = dp->i_mount;
+	int			error;
+	int                     rsvd = 0;
+
+	/*
+	 * Root fork attributes can use reserved data blocks for this
+	 * operation if necessary
+	 */
+	if (flags & ATTR_ROOT)
+		rsvd = XFS_TRANS_RESERVE;
+	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
+		XFS_ATTRRM_SPACE_RES(mp), 0, rsvd, &args->trans);
+
+	if (error)
+		goto out;
+
+	/*
+	 * No need to make quota reservations here. We expect to release some
+	 * blocks not allocate in the common case.
+	 */
+	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);
+	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+		error = xfs_attr_leaf_removename(args);
+	} else {
+		error = xfs_attr_node_removename(args);
+	}
+
+	if (error)
+		goto out;
+
+	/*
+	 * 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 ((flags & ATTR_KERNOTIME) == 0)
+		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
+
+	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
+
+	return error;
+
+out:
+	if (args->trans)
+		xfs_trans_cancel(args->trans);
+
+	return error;
+}
+
+/*
  * Calculate how many blocks we need for the new attribute,
  */
 STATIC int
@@ -214,10 +403,9 @@ xfs_attr_set(
 	struct xfs_mount	*mp = dp->i_mount;
 	struct xfs_da_args	args;
 	struct xfs_defer_ops	dfops;
-	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);
 
@@ -252,106 +440,11 @@ xfs_attr_set(
 			return error;
 	}
 
-	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)
-		return error;
-
 	xfs_ilock(dp, XFS_ILOCK_EXCL);
-	error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0,
-				rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
-				       XFS_QMOPT_RES_REGBLKS);
-	if (error) {
-		xfs_iunlock(dp, XFS_ILOCK_EXCL);
-		xfs_trans_cancel(args.trans);
-		return error;
-	}
-
-	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);
-		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);
-		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 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;
-
-	}
-
-	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
-		error = xfs_attr_leaf_addname(&args);
-	else
-		error = xfs_attr_node_addname(&args);
+	xfs_defer_init(args.dfops, args.firstblock);
+	error = xfs_attr_set_args(&args, flags, true);
 	if (error)
-		goto out;
+		goto out_defer_cancel;
 
 	/*
 	 * If this is a synchronous mount, make sure that the
@@ -360,9 +453,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.
 	 */
@@ -374,10 +464,6 @@ xfs_attr_set(
 
 out_defer_cancel:
 	xfs_defer_cancel(&dfops);
-	args.trans = NULL;
-out:
-	if (args.trans)
-		xfs_trans_cancel(args.trans);
 	xfs_iunlock(dp, XFS_ILOCK_EXCL);
 	return error;
 }
@@ -417,38 +503,18 @@ xfs_attr_remove(
 	 */
 	args.op_flags = XFS_DA_OP_OKNOENT;
 
-	error = xfs_qm_dqattach(dp, 0);
-	if (error)
-		return error;
-
-	/*
-	 * Root fork attributes can use reserved data blocks for this
-	 * operation if necessary
-	 */
-	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
-			XFS_ATTRRM_SPACE_RES(mp), 0,
-			(flags & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
-			&args.trans);
-	if (error)
-		return error;
-
 	xfs_ilock(dp, XFS_ILOCK_EXCL);
 	/*
 	 * No need to make quota reservations here. We expect to release some
 	 * blocks not allocate in the common case.
 	 */
 	xfs_trans_ijoin(args.trans, dp, 0);
+	xfs_defer_init(args.dfops, args.firstblock);
+	error = xfs_qm_dqattach_locked(dp, 0);
+	if (error)
+		return error;
 
-	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);
-	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
-		error = xfs_attr_leaf_removename(&args);
-	} else {
-		error = xfs_attr_node_removename(&args);
-	}
+	error = xfs_attr_remove_args(&args, flags);
 
 	if (error)
 		goto out;
@@ -460,9 +526,6 @@ xfs_attr_remove(
 	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.
 	 */
@@ -473,6 +536,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/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 8926379..7fa58fa 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -1066,6 +1066,37 @@ 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_UUID:
+		ip->i_d.di_forkoff = roundup(sizeof(uuid_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.
@@ -1119,29 +1150,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_UUID:
-		ip->i_d.di_forkoff = roundup(sizeof(uuid_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/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
index 502e0d8..5ca4a73 100644
--- a/fs/xfs/libxfs/xfs_bmap.h
+++ b/fs/xfs/libxfs/xfs_bmap.h
@@ -210,6 +210,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,
diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
index 5d5a5e2..8542606 100644
--- a/fs/xfs/xfs_attr.h
+++ b/fs/xfs/xfs_attr.h
@@ -149,7 +149,9 @@ 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, 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);
 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] 69+ messages in thread

* [PATCH v3 02/17] Set up infastructure for deferred attribute operations
  2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
  2017-11-17 18:21 ` [PATCH v3 01/17] Add helper functions xfs_attr_set_args and xfs_attr_remove_args Allison Henderson
@ 2017-11-17 18:21 ` Allison Henderson
  2017-11-28 19:45   ` Darrick J. Wong
  2017-11-17 18:21 ` [PATCH v3 03/17] Add xfs_attr_set_defered and xfs_attr_remove_defered Allison Henderson
                   ` (14 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Henderson

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>
---
 fs/xfs/Makefile                |   2 +
 fs/xfs/libxfs/xfs_attr.c       |   3 +-
 fs/xfs/libxfs/xfs_defer.h      |   1 +
 fs/xfs/libxfs/xfs_log_format.h |  37 ++-
 fs/xfs/libxfs/xfs_types.h      |   1 +
 fs/xfs/xfs_attr.h              |  22 +-
 fs/xfs/xfs_attr_item.c         | 513 +++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_attr_item.h         | 117 ++++++++++
 fs/xfs/xfs_log_recover.c       | 140 +++++++++++
 fs/xfs/xfs_super.c             |   1 +
 fs/xfs/xfs_trans.h             |  13 ++
 fs/xfs/xfs_trans_attr.c        | 288 +++++++++++++++++++++++
 12 files changed, 1134 insertions(+), 4 deletions(-)

diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index a6e955b..ec6486b 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -106,6 +106,7 @@ xfs-y				+= xfs_log.o \
 				   xfs_bmap_item.o \
 				   xfs_buf_item.o \
 				   xfs_extfree_item.o \
+				   xfs_attr_item.o \
 				   xfs_icreate_item.o \
 				   xfs_inode_item.o \
 				   xfs_refcount_item.o \
@@ -115,6 +116,7 @@ xfs-y				+= xfs_log.o \
 				   xfs_trans_bmap.o \
 				   xfs_trans_buf.o \
 				   xfs_trans_extfree.o \
+				   xfs_trans_attr.o \
 				   xfs_trans_inode.o \
 				   xfs_trans_refcount.o \
 				   xfs_trans_rmap.o \
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index e5f2960..716df0f 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -41,6 +41,7 @@
 #include "xfs_quota.h"
 #include "xfs_trans_space.h"
 #include "xfs_trace.h"
+#include "xfs_attr_item.h"
 
 /*
  * xfs_attr.c
@@ -74,7 +75,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,
diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h
index d4f046d..ef0f8bf 100644
--- a/fs/xfs/libxfs/xfs_defer.h
+++ b/fs/xfs/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/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
index 71de185..cecc27e 100644
--- a/fs/xfs/libxfs/xfs_log_format.h
+++ b/fs/xfs/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,28 @@ 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_attr_log_format {
+	uint64_t	alf_id;		/* attri identifier */
+	xfs_ino_t       alf_ino;	/* the inode for this attr operation */
+	uint32_t        alf_op_flags;	/* marks the op as a set or remove */
+	uint32_t        alf_name_len;	/* attr name length */
+	uint32_t        alf_value_len;	/* attr value length */
+	uint32_t        alf_attr_flags;	/* attr flags */
+	uint16_t	alf_type;	/* attri log item type */
+	uint16_t	alf_size;	/* size of this item */
+	uint32_t	alf_pad;	/* pad to 64 bit aligned */
+};
+
 #endif /* __XFS_LOG_FORMAT_H__ */
diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
index 0220159..5372063 100644
--- a/fs/xfs/libxfs/xfs_types.h
+++ b/fs/xfs/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 */
diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
index 8542606..3ef3c77 100644
--- a/fs/xfs/xfs_attr.h
+++ b/fs/xfs/xfs_attr.h
@@ -18,6 +18,8 @@
 #ifndef __XFS_ATTR_H__
 #define	__XFS_ATTR_H__
 
+#include "libxfs/xfs_defer.h"
+
 struct xfs_inode;
 struct xfs_da_args;
 struct xfs_attr_list_context;
@@ -87,6 +89,22 @@ 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 name and val */
+	uint32_t	  xattri_name_len;    /* length of name */
+	uint32_t	  xattri_flags;       /* attr flags */
+	struct list_head  xattri_list;
+	char              xattri_name_value[0];
+};
+
+#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.
  */
@@ -154,6 +172,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);
 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/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
new file mode 100644
index 0000000..0ba2a54
--- /dev/null
+++ b/fs/xfs/xfs_attr_item.c
@@ -0,0 +1,513 @@
+/*
+ * 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.
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_bit.h"
+#include "xfs_mount.h"
+#include "xfs_trans.h"
+#include "xfs_trans_priv.h"
+#include "xfs_buf_item.h"
+#include "xfs_attr_item.h"
+#include "xfs_log.h"
+#include "xfs_btree.h"
+#include "xfs_rmap.h"
+#include "xfs_inode.h"
+#include "xfs_icache.h"
+
+static inline struct xfs_attri_log_item *ATTRI_ITEM(struct xfs_log_item *lip)
+{
+	return container_of(lip, struct xfs_attri_log_item, item);
+}
+
+void
+xfs_attri_item_free(
+	struct xfs_attri_log_item	*attrip)
+{
+	kmem_free(attrip->item.li_lv_shadow);
+	kmem_free(attrip);
+}
+
+/*
+ * This returns the number of iovecs needed to log the given attri item.
+ * We only need 1 iovec for an attri item.  It just logs the attr_log_format
+ * structure.
+ */
+static inline int
+xfs_attri_item_sizeof(
+	struct xfs_attri_log_item *attrip)
+{
+	return sizeof(struct xfs_attr_log_format);
+}
+
+STATIC void
+xfs_attri_item_size(
+	struct xfs_log_item	*lip,
+	int			*nvecs,
+	int			*nbytes)
+{
+	struct xfs_attri_log_item       *attrip = ATTRI_ITEM(lip);
+
+	*nvecs += 1;
+	*nbytes += xfs_attri_item_sizeof(attrip);
+
+	if (attrip->name_len > 0) {
+		*nvecs += 1;
+		nbytes += ATTR_NVEC_SIZE(attrip->name_len);
+	}
+
+	if (attrip->value_len > 0) {
+		*nvecs += 1;
+		nbytes += ATTR_NVEC_SIZE(attrip->value_len);
+	}
+}
+
+/*
+ * This is called to fill in the vector of log iovecs for the
+ * given attri log item. We use only 1 iovec, and we point that
+ * at the attri_log_format structure embedded in the attri item.
+ * It is at this point that we assert that all of the attr
+ * slots in the attri item have been filled.
+ */
+STATIC void
+xfs_attri_item_format(
+	struct xfs_log_item	*lip,
+	struct xfs_log_vec	*lv)
+{
+	struct xfs_attri_log_item	*attrip = ATTRI_ITEM(lip);
+	struct xfs_log_iovec	*vecp = NULL;
+
+	attrip->format.alf_type = XFS_LI_ATTRI;
+	attrip->format.alf_size = 1;
+
+	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRI_FORMAT,
+			&attrip->format,
+			xfs_attri_item_sizeof(attrip));
+	if (attrip->name_len > 0)
+		xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_NAME,
+				attrip->name, ATTR_NVEC_SIZE(attrip->name_len));
+
+	if (attrip->value_len > 0)
+		xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_VALUE,
+				attrip->value,
+				ATTR_NVEC_SIZE(attrip->value_len));
+}
+
+
+/*
+ * Pinning has no meaning for an attri item, so just return.
+ */
+STATIC void
+xfs_attri_item_pin(
+	struct xfs_log_item	*lip)
+{
+}
+
+/*
+ * The unpin operation is the last place an ATTRI is manipulated in the log. It
+ * is either inserted in the AIL or aborted in the event of a log I/O error. In
+ * either case, the ATTRI transaction has been successfully committed to make it
+ * this far. Therefore, we expect whoever committed the ATTRI to either
+ * construct and commit the ATTRD or drop the ATTRD's reference in the event of
+ * error. Simply drop the log's ATTRI reference now that the log is done with
+ * it.
+ */
+STATIC void
+xfs_attri_item_unpin(
+	struct xfs_log_item	*lip,
+	int			remove)
+{
+	struct xfs_attri_log_item	*attrip = ATTRI_ITEM(lip);
+
+	xfs_attri_release(attrip);
+}
+
+/*
+ * attri items have no locking or pushing.  However, since ATTRIs are pulled
+ * from the AIL when their corresponding ATTRDs are committed to disk, their
+ * situation is very similar to being pinned.  Return XFS_ITEM_PINNED so that
+ * the caller will eventually flush the log.  This should help in getting the
+ * ATTRI out of the AIL.
+ */
+STATIC uint
+xfs_attri_item_push(
+	struct xfs_log_item	*lip,
+	struct list_head	*buffer_list)
+{
+	return XFS_ITEM_PINNED;
+}
+
+/*
+ * The ATTRI has been either committed or aborted if the transaction has been
+ * cancelled. If the transaction was cancelled, an ATTRD isn't going to be
+ * constructed and thus we free the ATTRI here directly.
+ */
+STATIC void
+xfs_attri_item_unlock(
+	struct xfs_log_item	*lip)
+{
+	if (lip->li_flags & XFS_LI_ABORTED)
+		xfs_attri_item_free(ATTRI_ITEM(lip));
+}
+
+/*
+ * The ATTRI is logged only once and cannot be moved in the log, so simply
+ * return the lsn at which it's been logged.
+ */
+STATIC xfs_lsn_t
+xfs_attri_item_committed(
+	struct xfs_log_item	*lip,
+	xfs_lsn_t		lsn)
+{
+	return lsn;
+}
+
+STATIC void
+xfs_attri_item_committing(
+	struct xfs_log_item	*lip,
+	xfs_lsn_t		lsn)
+{
+}
+
+/*
+ * This is the ops vector shared by all attri log items.
+ */
+static const struct xfs_item_ops xfs_attri_item_ops = {
+	.iop_size	= xfs_attri_item_size,
+	.iop_format	= xfs_attri_item_format,
+	.iop_pin	= xfs_attri_item_pin,
+	.iop_unpin	= xfs_attri_item_unpin,
+	.iop_unlock	= xfs_attri_item_unlock,
+	.iop_committed	= xfs_attri_item_committed,
+	.iop_push	= xfs_attri_item_push,
+	.iop_committing = xfs_attri_item_committing
+};
+
+
+/*
+ * Allocate and initialize an attri item
+ */
+struct xfs_attri_log_item *
+xfs_attri_init(
+	struct xfs_mount	*mp)
+
+{
+	struct xfs_attri_log_item	*attrip;
+	uint			size;
+
+	size = (uint)(sizeof(struct xfs_attri_log_item));
+	attrip = kmem_zalloc(size, KM_SLEEP);
+
+	xfs_log_item_init(mp, &(attrip->item), XFS_LI_ATTRI,
+			  &xfs_attri_item_ops);
+	attrip->format.alf_id = (uintptr_t)(void *)attrip;
+	atomic_set(&attrip->refcount, 2);
+
+	return attrip;
+}
+
+/*
+ * Copy an attr format buffer from the given buf, and into the destination
+ * attr format structure.
+ */
+int
+xfs_attr_copy_format(struct xfs_log_iovec *buf,
+		      struct xfs_attr_log_format *dst_attr_fmt)
+{
+	struct xfs_attr_log_format *src_attr_fmt = buf->i_addr;
+	uint len = sizeof(struct xfs_attr_log_format);
+
+	if (buf->i_len == len) {
+		memcpy((char *)dst_attr_fmt, (char *)src_attr_fmt, len);
+		return 0;
+	}
+	return -EFSCORRUPTED;
+}
+
+/*
+ * Freeing the attri requires that we remove it from the AIL if it has already
+ * been placed there. However, the ATTRI may not yet have been placed in the
+ * AIL when called by xfs_attri_release() from ATTRD processing due to the
+ * ordering of committed vs unpin operations in bulk insert operations. Hence
+ * the reference count to ensure only the last caller frees the ATTRI.
+ */
+void
+xfs_attri_release(
+	struct xfs_attri_log_item	*attrip)
+{
+	ASSERT(atomic_read(&attrip->refcount) > 0);
+	if (atomic_dec_and_test(&attrip->refcount)) {
+		xfs_trans_ail_remove(&attrip->item,
+				     SHUTDOWN_LOG_IO_ERROR);
+		xfs_attri_item_free(attrip);
+	}
+}
+
+static inline struct xfs_attrd_log_item *ATTRD_ITEM(struct xfs_log_item *lip)
+{
+	return container_of(lip, struct xfs_attrd_log_item, item);
+}
+
+STATIC void
+xfs_attrd_item_free(struct xfs_attrd_log_item *attrdp)
+{
+	kmem_free(attrdp->item.li_lv_shadow);
+	kmem_free(attrdp);
+}
+
+/*
+ * This returns the number of iovecs needed to log the given attrd item.
+ * We only need 1 iovec for an attrd item.  It just logs the attr_log_format
+ * structure.
+ */
+static inline int
+xfs_attrd_item_sizeof(
+	struct xfs_attrd_log_item *attrdp)
+{
+	return sizeof(struct xfs_attr_log_format);
+}
+
+STATIC void
+xfs_attrd_item_size(
+	struct xfs_log_item	*lip,
+	int			*nvecs,
+	int			*nbytes)
+{
+	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
+	*nvecs += 1;
+	*nbytes += xfs_attrd_item_sizeof(attrdp);
+
+	if (attrdp->name_len > 0) {
+		*nvecs += 1;
+		nbytes += attrdp->name_len;
+	}
+
+	if (attrdp->value_len > 0) {
+		*nvecs += 1;
+		nbytes += attrdp->value_len;
+	}
+}
+
+/*
+ * This is called to fill in the vector of log iovecs for the
+ * given attrd log item. We use only 1 iovec, and we point that
+ * at the attr_log_format structure embedded in the attrd item.
+ * It is at this point that we assert that all of the attr
+ * slots in the attrd item have been filled.
+ */
+STATIC void
+xfs_attrd_item_format(
+	struct xfs_log_item	*lip,
+	struct xfs_log_vec	*lv)
+{
+	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
+	struct xfs_log_iovec	*vecp = NULL;
+
+	attrdp->format.alf_type = XFS_LI_ATTRD;
+	attrdp->format.alf_size = 1;
+
+	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRD_FORMAT,
+			&attrdp->format,
+			xfs_attrd_item_sizeof(attrdp));
+}
+
+/*
+ * Pinning has no meaning for an attrd item, so just return.
+ */
+STATIC void
+xfs_attrd_item_pin(
+	struct xfs_log_item	*lip)
+{
+}
+
+/*
+ * Since pinning has no meaning for an attrd item, unpinning does
+ * not either.
+ */
+STATIC void
+xfs_attrd_item_unpin(
+	struct xfs_log_item	*lip,
+	int			remove)
+{
+}
+
+/*
+ * There isn't much you can do to push on an attrd item.  It is simply stuck
+ * waiting for the log to be flushed to disk.
+ */
+STATIC uint
+xfs_attrd_item_push(
+	struct xfs_log_item	*lip,
+	struct list_head	*buffer_list)
+{
+	return XFS_ITEM_PINNED;
+}
+
+/*
+ * The ATTRD is either committed or aborted if the transaction is cancelled. If
+ * the transaction is cancelled, drop our reference to the ATTRI and free the
+ * ATTRD.
+ */
+STATIC void
+xfs_attrd_item_unlock(
+	struct xfs_log_item	*lip)
+{
+	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
+
+	if (lip->li_flags & XFS_LI_ABORTED) {
+		xfs_attri_release(attrdp->attrip);
+		xfs_attrd_item_free(attrdp);
+	}
+}
+
+/*
+ * When the attrd item is committed to disk, all we need to do is delete our
+ * reference to our partner attri item and then free ourselves. Since we're
+ * freeing ourselves we must return -1 to keep the transaction code from
+ * further referencing this item.
+ */
+STATIC xfs_lsn_t
+xfs_attrd_item_committed(
+	struct xfs_log_item	*lip,
+	xfs_lsn_t		lsn)
+{
+	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
+
+	/*
+	 * Drop the ATTRI reference regardless of whether the ATTRD has been
+	 * aborted. Once the ATTRD transaction is constructed, it is the sole
+	 * responsibility of the ATTRD to release the ATTRI (even if the ATTRI
+	 * is aborted due to log I/O error).
+	 */
+	xfs_attri_release(attrdp->attrip);
+	xfs_attrd_item_free(attrdp);
+
+	return (xfs_lsn_t)-1;
+}
+
+STATIC void
+xfs_attrd_item_committing(
+	struct xfs_log_item	*lip,
+	xfs_lsn_t		lsn)
+{
+}
+
+/*
+ * This is the ops vector shared by all attrd log items.
+ */
+static const struct xfs_item_ops xfs_attrd_item_ops = {
+	.iop_size	= xfs_attrd_item_size,
+	.iop_format	= xfs_attrd_item_format,
+	.iop_pin	= xfs_attrd_item_pin,
+	.iop_unpin	= xfs_attrd_item_unpin,
+	.iop_unlock	= xfs_attrd_item_unlock,
+	.iop_committed	= xfs_attrd_item_committed,
+	.iop_push	= xfs_attrd_item_push,
+	.iop_committing = xfs_attrd_item_committing
+};
+
+/*
+ * Allocate and initialize an attrd item
+ */
+struct xfs_attrd_log_item *
+xfs_attrd_init(
+	struct xfs_mount	*mp,
+	struct xfs_attri_log_item	*attrip)
+
+{
+	struct xfs_attrd_log_item	*attrdp;
+	uint			size;
+
+	size = (uint)(sizeof(struct xfs_attrd_log_item));
+	attrdp = kmem_zalloc(size, KM_SLEEP);
+
+	xfs_log_item_init(mp, &attrdp->item, XFS_LI_ATTRD,
+			  &xfs_attrd_item_ops);
+	attrdp->attrip = attrip;
+	attrdp->format.alf_id = attrip->format.alf_id;
+
+	return attrdp;
+}
+
+/*
+ * Process an attr intent item that was recovered from
+ * the log.  We need to delete the attr that it describes.
+ */
+int
+xfs_attri_recover(
+	struct xfs_mount	*mp,
+	struct xfs_attri_log_item	*attrip)
+{
+	struct xfs_inode		*ip;
+	struct xfs_attrd_log_item	*attrdp;
+	struct xfs_trans	*tp;
+	int			error = 0;
+	struct xfs_attr_log_format	*attrp;
+
+	ASSERT(!test_bit(XFS_ATTRI_RECOVERED, &attrip->flags));
+
+	/*
+	 * First check the validity of the attr described by the
+	 * ATTRI.  If any are bad, then assume that all are bad and
+	 * just toss the ATTRI.  A valid attr must have a name length,
+	 * a value length, and either a "set" or "remove" op flag
+	 */
+	attrp = &attrip->format;
+	if (attrp->alf_value_len == 0 ||
+	    attrp->alf_name_len == 0 ||
+	    !(attrp->alf_op_flags == XFS_ATTR_OP_FLAGS_SET ||
+	     attrp->alf_op_flags == XFS_ATTR_OP_FLAGS_REMOVE) ) {
+		/*
+		 * This will pull the ATTRI from the AIL and
+		 * free the memory associated with it.
+		 */
+		set_bit(XFS_ATTRI_RECOVERED, &attrip->flags);
+		xfs_attri_release(attrip);
+		return -EIO;
+	}
+
+	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
+	if (error)
+		return error;
+	attrdp = xfs_trans_get_attrd(tp, attrip);
+	attrp = &attrip->format;
+
+	error = xfs_iget(mp, tp, attrp->alf_ino, 0, 0, &ip);
+	if (error)
+		return error;
+
+	error = xfs_trans_attr(tp, attrdp, ip,
+				attrp->alf_op_flags,
+				attrp->alf_attr_flags,
+				attrp->alf_name_len,
+				attrp->alf_value_len,
+				attrip->name,
+				attrip->value);
+	if (error)
+		goto abort_error;
+
+
+	set_bit(XFS_ATTRI_RECOVERED, &attrip->flags);
+	error = xfs_trans_commit(tp);
+	return error;
+
+abort_error:
+	xfs_trans_cancel(tp);
+	return error;
+}
diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h
new file mode 100644
index 0000000..774b56e
--- /dev/null
+++ b/fs/xfs/xfs_attr_item.h
@@ -0,0 +1,117 @@
+/*
+ * 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_ATTR_ITEM_H__
+#define	__XFS_ATTR_ITEM_H__
+
+/* kernel only ATTRI/ATTRD definitions */
+
+struct xfs_mount;
+struct kmem_zone;
+
+/*
+ * Max number of attrs in fast allocation path.
+ */
+#define XFS_ATTRI_MAX_FAST_ATTRS        1
+
+
+/*
+ * Define ATTR flag bits. Manipulated by set/clear/test_bit operators.
+ */
+#define	XFS_ATTRI_RECOVERED	1
+
+
+/* nvecs must be in multiples of 4 */
+#define ATTR_NVEC_SIZE(size) (size == sizeof(int32_t) ? sizeof(int32_t) : \
+				size + sizeof(int32_t) - \
+				(size % sizeof(int32_t)))
+
+/*
+ * This is the "attr intention" log item.  It is used to log the fact
+ * that some attrs need to be processed.  It is used in conjunction with the
+ * "attr done" log item described below.
+ *
+ * The ATTRI is reference counted so that it is not freed prior to both the
+ * ATTRI and ATTRD being committed and unpinned. This ensures the ATTRI is
+ * inserted into the AIL even in the event of out of order ATTRI/ATTRD
+ * processing. In other words, an ATTRI is born with two references:
+ *
+ *      1.) an ATTRI held reference to track ATTRI AIL insertion
+ *      2.) an ATTRD held reference to track ATTRD commit
+ *
+ * On allocation, both references are the responsibility of the caller. Once
+ * the ATTRI is added to and dirtied in a transaction, ownership of reference
+ * one transfers to the transaction. The reference is dropped once the ATTRI is
+ * inserted to the AIL or in the event of failure along the way (e.g., commit
+ * failure, log I/O error, etc.). Note that the caller remains responsible for
+ * the ATTRD reference under all circumstances to this point. The caller has no
+ * means to detect failure once the transaction is committed, however.
+ * Therefore, an ATTRD is required after this point, even in the event of
+ * unrelated failure.
+ *
+ * Once an ATTRD is allocated and dirtied in a transaction, reference two
+ * transfers to the transaction. The ATTRD reference is dropped once it reaches
+ * the unpin handler. Similar to the ATTRI, the reference also drops in the
+ * event of commit failure or log I/O errors. Note that the ATTRD is not
+ * inserted in the AIL, so at this point both the ATTI and ATTRD are freed.
+ */
+struct xfs_attri_log_item {
+	xfs_log_item_t			item;
+	atomic_t			refcount;
+	unsigned long			flags;	/* misc flags */
+	int				name_len;
+	void				*name;
+	int				value_len;
+	void				*value;
+	struct xfs_attr_log_format	format;
+};
+
+/*
+ * This is the "attr done" log item.  It is used to log
+ * the fact that some attrs earlier mentioned in an attri item
+ * have been freed.
+ */
+struct xfs_attrd_log_item {
+	struct xfs_log_item		item;
+	struct xfs_attri_log_item	*attrip;
+	uint				next_attr;
+	int				name_len;
+	void				*name;
+	int				value_len;
+	void				*value;
+	struct xfs_attr_log_format	format;
+};
+
+/*
+ * Max number of attrs in fast allocation path.
+ */
+#define	XFS_ATTRD_MAX_FAST_ATTRS	1
+
+extern struct kmem_zone	*xfs_attri_zone;
+extern struct kmem_zone	*xfs_attrd_zone;
+
+struct xfs_attri_log_item	*xfs_attri_init(struct xfs_mount *mp);
+struct xfs_attrd_log_item	*xfs_attrd_init(struct xfs_mount *mp,
+					struct xfs_attri_log_item *attrip);
+int xfs_attr_copy_format(struct xfs_log_iovec *buf,
+			 struct xfs_attr_log_format *dst_attri_fmt);
+void			xfs_attri_item_free(struct xfs_attri_log_item *attrip);
+void			xfs_attri_release(struct xfs_attri_log_item *attrip);
+
+int			xfs_attri_recover(struct xfs_mount *mp,
+					struct xfs_attri_log_item *attrip);
+
+#endif	/* __XFS_ATTR_ITEM_H__ */
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index ee34899..fd0e052 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -33,6 +33,7 @@
 #include "xfs_log_recover.h"
 #include "xfs_inode_item.h"
 #include "xfs_extfree_item.h"
+#include "xfs_attr_item.h"
 #include "xfs_trans_priv.h"
 #include "xfs_alloc.h"
 #include "xfs_ialloc.h"
@@ -1956,6 +1957,8 @@ xlog_recover_reorder_trans(
 		case XFS_LI_CUD:
 		case XFS_LI_BUI:
 		case XFS_LI_BUD:
+		case XFS_LI_ATTRI:
+		case XFS_LI_ATTRD:
 			trace_xfs_log_recover_item_reorder_tail(log,
 							trans, item, pass);
 			list_move_tail(&item->ri_list, &inode_list);
@@ -3489,6 +3492,92 @@ xlog_recover_efd_pass2(
 	return 0;
 }
 
+STATIC int
+xlog_recover_attri_pass2(
+	struct xlog                     *log,
+	struct xlog_recover_item        *item,
+	xfs_lsn_t                       lsn)
+{
+	int                             error;
+	struct xfs_mount                *mp = log->l_mp;
+	struct xfs_attri_log_item       *attrip;
+	struct xfs_attr_log_format     *attri_formatp;
+
+	attri_formatp = item->ri_buf[0].i_addr;
+
+	attrip = xfs_attri_init(mp);
+	error = xfs_attr_copy_format(&item->ri_buf[0], &attrip->format);
+	if (error) {
+		xfs_attri_item_free(attrip);
+		return error;
+	}
+
+	spin_lock(&log->l_ailp->xa_lock);
+	/*
+	 * The ATTRI has two references. One for the ATTRD and one for ATTRI to
+	 * ensure it makes it into the AIL. Insert the ATTRI into the AIL
+	 * directly and drop the ATTRI reference. Note that
+	 * xfs_trans_ail_update() drops the AIL lock.
+	 */
+	xfs_trans_ail_update(log->l_ailp, &attrip->item, lsn);
+	xfs_attri_release(attrip);
+	return 0;
+}
+
+
+/*
+ * This routine is called when an ATTRD format structure is found in a committed
+ * transaction in the log. Its purpose is to cancel the corresponding ATTRI if
+ * it was still in the log. To do this it searches the AIL for the ATTRI with
+ * an id equal to that in the ATTRD format structure. If we find it we drop
+ * the ATTRD reference, which removes the ATTRI from the AIL and frees it.
+ */
+STATIC int
+xlog_recover_attrd_pass2(
+	struct xlog                     *log,
+	struct xlog_recover_item        *item)
+{
+	struct xfs_attr_log_format    *attrd_formatp;
+	struct xfs_attri_log_item      *attrip = NULL;
+	struct xfs_log_item          *lip;
+	uint64_t                attri_id;
+	struct xfs_ail_cursor   cur;
+	struct xfs_ail          *ailp = log->l_ailp;
+
+	attrd_formatp = item->ri_buf[0].i_addr;
+	ASSERT((item->ri_buf[0].i_len ==
+				(sizeof(struct xfs_attr_log_format))));
+	attri_id = attrd_formatp->alf_id;
+
+	/*
+	 * Search for the ATTRI with the id in the ATTRD format structure in the
+	 * AIL.
+	 */
+	spin_lock(&ailp->xa_lock);
+	lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
+	while (lip != NULL) {
+		if (lip->li_type == XFS_LI_ATTRI) {
+			attrip = (struct xfs_attri_log_item *)lip;
+			if (attrip->format.alf_id == attri_id) {
+				/*
+				 * Drop the ATTRD reference to the ATTRI. This
+				 * removes the ATTRI from the AIL and frees it.
+				 */
+				spin_unlock(&ailp->xa_lock);
+				xfs_attri_release(attrip);
+				spin_lock(&ailp->xa_lock);
+				break;
+			}
+		}
+		lip = xfs_trans_ail_cursor_next(ailp, &cur);
+	}
+
+	xfs_trans_ail_cursor_done(&cur);
+	spin_unlock(&ailp->xa_lock);
+
+	return 0;
+}
+
 /*
  * This routine is called to create an in-core extent rmap update
  * item from the rui format structure which was logged on disk.
@@ -4108,6 +4197,10 @@ xlog_recover_commit_pass2(
 		return xlog_recover_efi_pass2(log, item, trans->r_lsn);
 	case XFS_LI_EFD:
 		return xlog_recover_efd_pass2(log, item);
+	case XFS_LI_ATTRI:
+		return xlog_recover_attri_pass2(log, item, trans->r_lsn);
+	case XFS_LI_ATTRD:
+		return xlog_recover_attrd_pass2(log, item);
 	case XFS_LI_RUI:
 		return xlog_recover_rui_pass2(log, item, trans->r_lsn);
 	case XFS_LI_RUD:
@@ -4669,6 +4762,49 @@ xlog_recover_cancel_efi(
 	spin_lock(&ailp->xa_lock);
 }
 
+/* Recover the ATTRI if necessary. */
+STATIC int
+xlog_recover_process_attri(
+	struct xfs_mount                *mp,
+	struct xfs_ail                  *ailp,
+	struct xfs_log_item             *lip)
+{
+	struct xfs_attri_log_item       *attrip;
+	int                             error;
+
+	/*
+	 * Skip ATTRIs that we've already processed.
+	 */
+	attrip = container_of(lip, struct xfs_attri_log_item, item);
+	if (test_bit(XFS_ATTRI_RECOVERED, &attrip->flags))
+		return 0;
+
+	spin_unlock(&ailp->xa_lock);
+	error = xfs_attri_recover(mp, attrip);
+	spin_lock(&ailp->xa_lock);
+
+	return error;
+}
+
+/* Release the ATTRI since we're cancelling everything. */
+STATIC void
+xlog_recover_cancel_attri(
+	struct xfs_mount                *mp,
+	struct xfs_ail                  *ailp,
+	struct xfs_log_item             *lip)
+{
+	struct xfs_attri_log_item         *attrip;
+
+	attrip = container_of(lip, struct xfs_attri_log_item, item);
+
+	spin_unlock(&ailp->xa_lock);
+	xfs_attri_release(attrip);
+	spin_lock(&ailp->xa_lock);
+}
+
+
+
+
 /* Recover the RUI if necessary. */
 STATIC int
 xlog_recover_process_rui(
@@ -4861,6 +4997,10 @@ xlog_recover_process_intents(
 		case XFS_LI_EFI:
 			error = xlog_recover_process_efi(log->l_mp, ailp, lip);
 			break;
+		case XFS_LI_ATTRI:
+			error = xlog_recover_process_attri(log->l_mp,
+							   ailp, lip);
+			break;
 		case XFS_LI_RUI:
 			error = xlog_recover_process_rui(log->l_mp, ailp, lip);
 			break;
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index f663022..ee68459 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -2024,6 +2024,7 @@ init_xfs_fs(void)
 	xfs_rmap_update_init_defer_op();
 	xfs_refcount_update_init_defer_op();
 	xfs_bmap_update_init_defer_op();
+	xfs_attr_init_defer_op();
 
 	xfs_dir_startup();
 
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 815b53d2..e094b05 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -40,6 +40,9 @@ struct xfs_cud_log_item;
 struct xfs_defer_ops;
 struct xfs_bui_log_item;
 struct xfs_bud_log_item;
+struct xfs_attrd_log_item;
+struct xfs_attri_log_item;
+
 
 typedef struct xfs_log_item {
 	struct list_head		li_ail;		/* AIL pointers */
@@ -223,12 +226,22 @@ void		xfs_trans_dirty_buf(struct xfs_trans *, struct xfs_buf *);
 void		xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
 
 void		xfs_extent_free_init_defer_op(void);
+void            xfs_attr_init_defer_op(void);
+
 struct xfs_efd_log_item	*xfs_trans_get_efd(struct xfs_trans *,
 				  struct xfs_efi_log_item *,
 				  uint);
 int		xfs_trans_free_extent(struct xfs_trans *,
 				      struct xfs_efd_log_item *, xfs_fsblock_t,
 				      xfs_extlen_t, struct xfs_owner_info *);
+struct xfs_attrd_log_item *
+xfs_trans_get_attrd(struct xfs_trans *tp,
+		    struct xfs_attri_log_item *attrip);
+int xfs_trans_attr(struct xfs_trans *tp, struct xfs_attrd_log_item *attrdp,
+			struct xfs_inode *ip, uint32_t attr_op_flags,
+			uint32_t flags, uint32_t name_len, uint32_t value_len,
+			char *name, char *value);
+
 int		xfs_trans_commit(struct xfs_trans *);
 int		xfs_trans_roll(struct xfs_trans **);
 int		xfs_trans_roll_inode(struct xfs_trans **, struct xfs_inode *);
diff --git a/fs/xfs/xfs_trans_attr.c b/fs/xfs/xfs_trans_attr.c
new file mode 100644
index 0000000..7c3290f
--- /dev/null
+++ b/fs/xfs/xfs_trans_attr.c
@@ -0,0 +1,288 @@
+/*
+ * 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.
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_bit.h"
+#include "xfs_mount.h"
+#include "xfs_defer.h"
+#include "xfs_trans.h"
+#include "xfs_trans_priv.h"
+#include "xfs_attr_item.h"
+#include "xfs_alloc.h"
+#include "xfs_bmap.h"
+#include "xfs_trace.h"
+#include "libxfs/xfs_da_format.h"
+#include "xfs_da_btree.h"
+#include "xfs_attr.h"
+#include "xfs_inode.h"
+#include "xfs_icache.h"
+#include "xfs_quota.h"
+
+/*
+ * This routine is called to allocate an "extent free done"
+ * log item that will hold nextents worth of extents.  The
+ * caller must use all nextents extents, because we are not
+ * flexible about this at all.
+ */
+struct xfs_attrd_log_item *
+xfs_trans_get_attrd(struct xfs_trans		*tp,
+		  struct xfs_attri_log_item	*attrip)
+{
+	struct xfs_attrd_log_item			*attrdp;
+
+	ASSERT(tp != NULL);
+
+	attrdp = xfs_attrd_init(tp->t_mountp, attrip);
+	ASSERT(attrdp != NULL);
+
+	/*
+	 * Get a log_item_desc to point at the new item.
+	 */
+	xfs_trans_add_item(tp, &attrdp->item);
+	return attrdp;
+}
+
+/*
+ * Delete an attr and log it to the ATTRD. Note that the transaction is marked
+ * dirty regardless of whether the attr delete succeeds or fails to support the
+ * ATTRI/ATTRD lifecycle rules.
+ */
+int
+xfs_trans_attr(
+	struct xfs_trans		*tp,
+	struct xfs_attrd_log_item	*attrdp,
+	struct xfs_inode		*ip,
+	uint32_t			op_flags,
+	uint32_t			flags,
+	uint32_t			name_len,
+	uint32_t			value_len,
+	char				*name,
+	char				*value)
+{
+	uint			next_attr;
+	struct xfs_attr_log_format *attrp;
+	int			error;
+	int                     local;
+	struct xfs_da_args      args;
+	struct xfs_defer_ops    dfops;
+	xfs_fsblock_t		firstblock = NULLFSBLOCK;
+
+	tp->t_flags |= XFS_TRANS_RESERVE;
+
+	error = xfs_attr_args_init(&args, ip, name, flags);
+	if (error)
+		return error;
+
+	xfs_ilock(ip, XFS_ILOCK_EXCL);
+	xfs_defer_init(&dfops, &firstblock);
+
+	args.name = name;
+	args.namelen = name_len;
+	args.hashval = xfs_da_hashname(args.name, args.namelen);
+	args.value = value;
+	args.valuelen = value_len;
+	args.dfops = &dfops;
+	args.firstblock = &firstblock;
+	args.op_flags = XFS_DA_OP_OKNOENT;
+	args.total = xfs_attr_calc_size(&args, &local);
+	args.trans = tp;
+	ASSERT(local);
+
+	error = xfs_qm_dqattach_locked(ip, 0);
+	if (error)
+		return error;
+
+	switch (op_flags) {
+		case XFS_ATTR_OP_FLAGS_SET:
+			args.op_flags |= XFS_DA_OP_ADDNAME;
+			error = xfs_attr_set_args(&args, flags, false);
+			break;
+		case XFS_ATTR_OP_FLAGS_REMOVE:
+			ASSERT(XFS_IFORK_Q((ip)));
+			error = xfs_attr_remove_args(&args, flags);
+			break;
+		default:
+			error = -EFSCORRUPTED;
+	}
+
+	if (error)
+		xfs_defer_cancel(&dfops);
+
+	xfs_iunlock(ip, XFS_ILOCK_EXCL);
+
+	/*
+	 * Mark the transaction dirty, even on error. This ensures the
+	 * transaction is aborted, which:
+	 *
+	 * 1.) releases the ATTRI and frees the ATTRD
+	 * 2.) shuts down the filesystem
+	 */
+	tp->t_flags |= XFS_TRANS_DIRTY;
+	attrdp->item.li_desc->lid_flags |= XFS_LID_DIRTY;
+
+	next_attr = attrdp->next_attr;
+	attrp = &(attrdp->format);
+	attrp->alf_ino = ip->i_ino;
+	attrp->alf_op_flags = op_flags;
+	attrp->alf_value_len = value_len;
+	attrp->alf_name_len = name_len;
+	attrp->alf_attr_flags = flags;
+
+	attrdp->name = name;
+	attrdp->value = value;
+	attrdp->name_len = name_len;
+	attrdp->value_len = value_len;
+	attrdp->next_attr++;
+
+	return error;
+}
+
+static int
+xfs_attr_diff_items(
+	void				*priv,
+	struct list_head		*a,
+	struct list_head		*b)
+{
+	return 0;
+}
+
+/* Get an ATTRI. */
+STATIC void *
+xfs_attr_create_intent(
+	struct xfs_trans		*tp,
+	unsigned int			count)
+{
+	struct xfs_attri_log_item		*attrip;
+
+	ASSERT(tp != NULL);
+	ASSERT(count > 0);
+
+	attrip = xfs_attri_init(tp->t_mountp);
+	ASSERT(attrip != NULL);
+
+	/*
+	 * Get a log_item_desc to point at the new item.
+	 */
+	xfs_trans_add_item(tp, &attrip->item);
+	return attrip;
+}
+
+/* Log an attr to the intent item. */
+STATIC void
+xfs_attr_log_item(
+	struct xfs_trans		*tp,
+	void				*intent,
+	struct list_head		*item)
+{
+	struct xfs_attri_log_item	*attrip = intent;
+	struct xfs_attr_item		*free;
+	struct xfs_attr_log_format	*attrp;
+
+	free = container_of(item, struct xfs_attr_item, xattri_list);
+
+	tp->t_flags |= XFS_TRANS_DIRTY;
+	attrip->item.li_desc->lid_flags |= XFS_LID_DIRTY;
+
+	attrp = &attrip->format;
+	attrp->alf_ino = free->xattri_ip->i_ino;
+	attrp->alf_op_flags = free->xattri_op_flags;
+	attrp->alf_value_len = free->xattri_value_len;
+	attrp->alf_name_len = free->xattri_name_len;
+	attrp->alf_attr_flags = free->xattri_flags;
+
+	attrip->name = &(free->xattri_name_value[0]);
+	attrip->value = &(free->xattri_name_value[free->xattri_name_len]);
+	attrip->name_len = free->xattri_name_len;
+	attrip->value_len = free->xattri_value_len;
+}
+
+/* Get an ATTRD so we can process all the attrs. */
+STATIC void *
+xfs_attr_create_done(
+	struct xfs_trans		*tp,
+	void				*intent,
+	unsigned int			count)
+{
+	return xfs_trans_get_attrd(tp, intent);
+}
+
+/* Process an attr. */
+STATIC int
+xfs_attr_finish_item(
+	struct xfs_trans		*tp,
+	struct xfs_defer_ops		*dop,
+	struct list_head		*item,
+	void				*done_item,
+	void				**state)
+{
+	struct xfs_attr_item	*free;
+	int				error;
+
+	free = container_of(item, struct xfs_attr_item, xattri_list);
+	error = xfs_trans_attr(tp, done_item,
+			free->xattri_ip,
+			free->xattri_op_flags,
+			free->xattri_flags,
+			free->xattri_name_len,
+			free->xattri_value_len,
+			&free->xattri_name_value[0],
+			&free->xattri_name_value[free->xattri_name_len]);
+	kmem_free(free);
+	return error;
+}
+
+/* Abort all pending ATTRs. */
+STATIC void
+xfs_attr_abort_intent(
+	void				*intent)
+{
+	xfs_attri_release(intent);
+}
+
+/* Cancel an attr */
+STATIC void
+xfs_attr_cancel_item(
+	struct list_head		*item)
+{
+	struct xfs_attr_item	*free;
+
+	free = container_of(item, struct xfs_attr_item, xattri_list);
+	kmem_free(free);
+}
+
+static const struct xfs_defer_op_type xfs_attr_defer_type = {
+	.type		= XFS_DEFER_OPS_TYPE_ATTR,
+	.max_items	= XFS_ATTRI_MAX_FAST_ATTRS,
+	.diff_items	= xfs_attr_diff_items,
+	.create_intent	= xfs_attr_create_intent,
+	.abort_intent	= xfs_attr_abort_intent,
+	.log_item	= xfs_attr_log_item,
+	.create_done	= xfs_attr_create_done,
+	.finish_item	= xfs_attr_finish_item,
+	.cancel_item	= xfs_attr_cancel_item,
+};
+
+/* Register the deferred op type. */
+void
+xfs_attr_init_defer_op(void)
+{
+	xfs_defer_init_op_type(&xfs_attr_defer_type);
+}
-- 
2.7.4


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

* [PATCH v3 03/17] Add xfs_attr_set_defered and xfs_attr_remove_defered
  2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
  2017-11-17 18:21 ` [PATCH v3 01/17] Add helper functions xfs_attr_set_args and xfs_attr_remove_args Allison Henderson
  2017-11-17 18:21 ` [PATCH v3 02/17] Set up infastructure for deferred attribute operations Allison Henderson
@ 2017-11-17 18:21 ` Allison Henderson
  2017-11-28 19:19   ` Darrick J. Wong
  2017-11-17 18:21 ` [PATCH v3 04/17] Remove all strlen calls in all xfs_attr_* functions for attr names Allison Henderson
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Henderson

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>
---
 fs/xfs/libxfs/xfs_attr.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_attr.h        |  5 ++++
 2 files changed, 67 insertions(+)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 716df0f..68dc7e04 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -469,6 +469,40 @@ xfs_attr_set(
 	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;
+
+	ASSERT(namelen != 0);
+	ASSERT(valuelen != 0);
+
+	new = kmem_alloc(XFS_ATTR_ITEM_SIZEOF(namelen, valuelen),
+			 KM_SLEEP|KM_NOFS);
+	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(&new->xattri_name_value[0], name, namelen);
+	memcpy(&new->xattri_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.
  * Transitions attribute list from Btree to shortform as necessary.
@@ -545,6 +579,34 @@ xfs_attr_remove(
 	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;
+
+	ASSERT(namelen != 0);
+
+	new = kmem_alloc(XFS_ATTR_ITEM_SIZEOF(namelen, 0), KM_SLEEP|KM_NOFS);
+	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(new->xattri_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/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
index 3ef3c77..8d4762a 100644
--- a/fs/xfs/xfs_attr.h
+++ b/fs/xfs/xfs_attr.h
@@ -175,5 +175,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] 69+ messages in thread

* [PATCH v3 04/17] Remove all strlen calls in all xfs_attr_* functions for attr names.
  2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
                   ` (2 preceding siblings ...)
  2017-11-17 18:21 ` [PATCH v3 03/17] Add xfs_attr_set_defered and xfs_attr_remove_defered Allison Henderson
@ 2017-11-17 18:21 ` Allison Henderson
  2017-11-28 19:10   ` Darrick J. Wong
  2017-11-17 18:21 ` [PATCH v3 05/17] xfs: get directory offset when adding directory name Allison Henderson
                   ` (12 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Henderson

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>
---
 fs/xfs/libxfs/xfs_attr.c | 12 ++++++++----
 fs/xfs/xfs_acl.c         | 12 +++++++-----
 fs/xfs/xfs_attr.h        | 10 ++++++----
 fs/xfs/xfs_ioctl.c       | 13 ++++++++++---
 fs/xfs/xfs_iops.c        |  6 ++++--
 fs/xfs/xfs_trans_attr.c  |  2 +-
 fs/xfs/xfs_xattr.c       | 10 +++++++---
 7 files changed, 43 insertions(+), 22 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 68dc7e04..61e8343 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -80,6 +80,7 @@ xfs_attr_args_init(
 	struct xfs_da_args	*args,
 	struct xfs_inode	*dp,
 	const unsigned char	*name,
+	size_t			namelen,
 	int			flags)
 {
 
@@ -92,7 +93,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 */
 
@@ -138,6 +139,7 @@ int
 xfs_attr_get(
 	struct xfs_inode	*ip,
 	const unsigned char	*name,
+	size_t			namelen,
 	unsigned char		*value,
 	int			*valuelenp,
 	int			flags)
@@ -151,7 +153,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;
 
@@ -397,6 +399,7 @@ int
 xfs_attr_set(
 	struct xfs_inode	*dp,
 	const unsigned char	*name,
+	size_t			namelen,
 	unsigned char		*value,
 	int			valuelen,
 	int			flags)
@@ -413,7 +416,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;
 
@@ -511,6 +514,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;
@@ -524,7 +528,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/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 3354140..d7ee630 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -153,8 +153,8 @@ xfs_get_acl(struct inode *inode, int type)
 	if (!xfs_acl)
 		return ERR_PTR(-ENOMEM);
 
-	error = xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl,
-							&len, ATTR_ROOT);
+	error = xfs_attr_get(ip, ea_name, strlen((const char *)ea_name),
+			     (unsigned char *)xfs_acl, &len, ATTR_ROOT);
 	if (error) {
 		/*
 		 * If the attribute doesn't exist make sure we have a negative
@@ -204,15 +204,17 @@ __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 		len -= sizeof(struct xfs_acl_entry) *
 			 (XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count);
 
-		error = xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
-				len, ATTR_ROOT);
+		error = xfs_attr_set(ip, ea_name, strlen((const char *)ea_name),
+				     (unsigned char *)xfs_acl, len, ATTR_ROOT);
 
 		kmem_free(xfs_acl);
 	} else {
 		/*
 		 * A NULL ACL argument means we want to remove the ACL.
 		 */
-		error = xfs_attr_remove(ip, ea_name, ATTR_ROOT);
+		error = xfs_attr_remove(ip, ea_name,
+					strlen((const char *)ea_name),
+					ATTR_ROOT);
 
 		/*
 		 * If the attribute didn't exist to start with that's fine.
diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
index 8d4762a..10fc466 100644
--- a/fs/xfs/xfs_attr.h
+++ b/fs/xfs/xfs_attr.h
@@ -164,16 +164,18 @@ 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, 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);
 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,
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index aa75389..4664314 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -448,6 +448,7 @@ xfs_attrmulti_attr_get(
 {
 	unsigned char		*kbuf;
 	int			error = -EFAULT;
+	size_t			namelen;
 
 	if (*len > XFS_XATTR_SIZE_MAX)
 		return -EINVAL;
@@ -455,7 +456,9 @@ xfs_attrmulti_attr_get(
 	if (!kbuf)
 		return -ENOMEM;
 
-	error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags);
+	namelen = strlen((const char *)name);
+	error = xfs_attr_get(XFS_I(inode), name, namelen,
+			     kbuf, (int *)len, flags);
 	if (error)
 		goto out_kfree;
 
@@ -477,6 +480,7 @@ xfs_attrmulti_attr_set(
 {
 	unsigned char		*kbuf;
 	int			error;
+	size_t			namelen;
 
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		return -EPERM;
@@ -487,7 +491,8 @@ xfs_attrmulti_attr_set(
 	if (IS_ERR(kbuf))
 		return PTR_ERR(kbuf);
 
-	error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags);
+	namelen = strlen((const char *)name);
+	error = xfs_attr_set(XFS_I(inode), name, namelen, kbuf, len, flags);
 	if (!error)
 		xfs_forget_acl(inode, name, flags);
 	kfree(kbuf);
@@ -501,10 +506,12 @@ xfs_attrmulti_attr_remove(
 	uint32_t		flags)
 {
 	int			error;
+	size_t			namelen;
 
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		return -EPERM;
-	error = xfs_attr_remove(XFS_I(inode), name, flags);
+	namelen = strlen((const char *)name);
+	error = xfs_attr_remove(XFS_I(inode), name, namelen, flags);
 	if (!error)
 		xfs_forget_acl(inode, name, flags);
 	return error;
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 17081c7..5247bfc 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -70,8 +70,10 @@ xfs_initxattrs(
 	int			error = 0;
 
 	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
-		error = xfs_attr_set(ip, xattr->name, xattr->value,
-				      xattr->value_len, ATTR_SECURE);
+		error = xfs_attr_set(ip, xattr->name,
+				     strlen((const char *)xattr->name),
+				     xattr->value, xattr->value_len,
+				     ATTR_SECURE);
 		if (error < 0)
 			break;
 	}
diff --git a/fs/xfs/xfs_trans_attr.c b/fs/xfs/xfs_trans_attr.c
index 7c3290f..da71cce 100644
--- a/fs/xfs/xfs_trans_attr.c
+++ b/fs/xfs/xfs_trans_attr.c
@@ -87,7 +87,7 @@ xfs_trans_attr(
 
 	tp->t_flags |= XFS_TRANS_RESERVE;
 
-	error = xfs_attr_args_init(&args, ip, name, flags);
+	error = xfs_attr_args_init(&args, ip, name, name_len, flags);
 	if (error)
 		return error;
 
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index 0594db4..10e58c6 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -38,6 +38,7 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
 	int xflags = handler->flags;
 	struct xfs_inode *ip = XFS_I(inode);
 	int error, asize = size;
+	size_t namelen = strlen((const char *)name);
 
 	/* Convert Linux syscall to XFS internal ATTR flags */
 	if (!size) {
@@ -45,7 +46,8 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
 		value = NULL;
 	}
 
-	error = xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags);
+	error = xfs_attr_get(ip, (unsigned char *)name, namelen, value,
+			     &asize, xflags);
 	if (error)
 		return error;
 	return asize;
@@ -81,6 +83,7 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
 	int			xflags = handler->flags;
 	struct xfs_inode	*ip = XFS_I(inode);
 	int			error;
+	size_t			namelen = strlen((const char *)name);
 
 	/* Convert Linux syscall to XFS internal ATTR flags */
 	if (flags & XATTR_CREATE)
@@ -89,8 +92,9 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
 		xflags |= ATTR_REPLACE;
 
 	if (!value)
-		return xfs_attr_remove(ip, (unsigned char *)name, xflags);
-	error = xfs_attr_set(ip, (unsigned char *)name,
+		return xfs_attr_remove(ip, (unsigned char *)name,
+				       namelen, xflags);
+	error = xfs_attr_set(ip, (unsigned char *)name, namelen,
 				(void *)value, size, xflags);
 	if (!error)
 		xfs_forget_acl(inode, name, xflags);
-- 
2.7.4


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

* [PATCH v3 05/17] xfs: get directory offset when adding directory name
  2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
                   ` (3 preceding siblings ...)
  2017-11-17 18:21 ` [PATCH v3 04/17] Remove all strlen calls in all xfs_attr_* functions for attr names Allison Henderson
@ 2017-11-17 18:21 ` Allison Henderson
  2017-11-28 19:07   ` Darrick J. Wong
  2017-11-17 18:21 ` [PATCH v3 06/17] xfs: get directory offset when removing " Allison Henderson
                   ` (11 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Mark Tinguely, Dave Chinner, Allison Henderson

From: Mark Tinguely <tinguely@sgi.com>

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>
---
 fs/xfs/libxfs/xfs_da_btree.h   | 1 +
 fs/xfs/libxfs/xfs_dir2.c       | 8 ++++++--
 fs/xfs/libxfs/xfs_dir2.h       | 3 ++-
 fs/xfs/libxfs/xfs_dir2_block.c | 1 +
 fs/xfs/libxfs/xfs_dir2_leaf.c  | 2 ++
 fs/xfs/libxfs/xfs_dir2_node.c  | 2 ++
 fs/xfs/libxfs/xfs_dir2_sf.c    | 2 ++
 fs/xfs/xfs_inode.c             | 9 +++++----
 fs/xfs/xfs_symlink.c           | 2 +-
 9 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
index ae6de17..bce96d6 100644
--- a/fs/xfs/libxfs/xfs_da_btree.h
+++ b/fs/xfs/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/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
index ccf9783..a1ca460 100644
--- a/fs/xfs/libxfs/xfs_dir2.c
+++ b/fs/xfs/libxfs/xfs_dir2.c
@@ -268,7 +268,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;
@@ -323,6 +324,9 @@ xfs_dir_createname(
 	else
 		rval = xfs_dir2_node_addname(args);
 
+	/* return the location that this entry was place in the parent inode */
+	if (offset)
+		*offset = args->offset;
 out_free:
 	kmem_free(args);
 	return rval;
@@ -570,7 +574,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/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
index 21c8f8b..e349900 100644
--- a/fs/xfs/libxfs/xfs_dir2.h
+++ b/fs/xfs/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/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
index 43c902f..79684d5 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -552,6 +552,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/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
index 27297a6..2ac7a7e 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -863,6 +863,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/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
index 682e2bf..8bc91f8 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -2022,6 +2022,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/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
index be8b975..489bdef 100644
--- a/fs/xfs/libxfs/xfs_dir2_sf.c
+++ b/fs/xfs/libxfs/xfs_dir2_sf.c
@@ -407,6 +407,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.
@@ -498,6 +499,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/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 4ec5b7f..3abcb17 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1252,7 +1252,8 @@ xfs_create(
 
 	error = xfs_dir_createname(tp, dp, name, ip->i_ino,
 					&first_block, &dfops, resblks ?
-					resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
+					resblks - XFS_IALLOC_SPACE_RES(mp) : 0,
+					NULL);
 	if (error) {
 		ASSERT(error != -ENOSPC);
 		goto out_trans_cancel;
@@ -1495,7 +1496,7 @@ xfs_link(
 	}
 
 	error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
-					&first_block, &dfops, resblks);
+				   &first_block, &dfops, resblks, NULL);
 	if (error)
 		goto error_return;
 	xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
@@ -3031,8 +3032,8 @@ xfs_rename(
 		 * to account for the ".." reference from the new entry.
 		 */
 		error = xfs_dir_createname(tp, target_dp, target_name,
-						src_ip->i_ino, &first_block,
-						&dfops, spaceres);
+					   src_ip->i_ino, &first_block, &dfops,
+					   spaceres, NULL);
 		if (error)
 			goto out_bmap_cancel;
 
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
index 68d3ca2..fc803ae 100644
--- a/fs/xfs/xfs_symlink.c
+++ b/fs/xfs/xfs_symlink.c
@@ -363,7 +363,7 @@ xfs_symlink(
 	 * Create the directory entry for the symlink.
 	 */
 	error = xfs_dir_createname(tp, dp, link_name, ip->i_ino,
-					&first_block, &dfops, resblks);
+				   &first_block, &dfops, resblks, NULL);
 	if (error)
 		goto out_bmap_cancel;
 	xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-- 
2.7.4


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

* [PATCH v3 06/17] xfs: get directory offset when removing directory name
  2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
                   ` (4 preceding siblings ...)
  2017-11-17 18:21 ` [PATCH v3 05/17] xfs: get directory offset when adding directory name Allison Henderson
@ 2017-11-17 18:21 ` Allison Henderson
  2017-11-28 19:05   ` Darrick J. Wong
  2017-11-17 18:21 ` [PATCH v3 07/17] xfs: get directory offset when replacing a " Allison Henderson
                   ` (10 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Mark Tinguely, Dave Chinner, Allison Henderson

From: Mark Tinguely <tinguely@sgi.com>

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]

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>
---
v2: Changed typedefs to raw struct types

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_dir2.c       | 15 +++++++++------
 fs/xfs/libxfs/xfs_dir2.h       |  4 +++-
 fs/xfs/libxfs/xfs_dir2_block.c |  4 ++--
 fs/xfs/libxfs/xfs_dir2_leaf.c  |  5 +++--
 fs/xfs/libxfs/xfs_dir2_node.c  |  5 +++--
 fs/xfs/libxfs/xfs_dir2_sf.c    |  2 ++
 fs/xfs/xfs_inode.c             |  7 ++++---
 7 files changed, 26 insertions(+), 16 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
index a1ca460..b647bf2 100644
--- a/fs/xfs/libxfs/xfs_dir2.c
+++ b/fs/xfs/libxfs/xfs_dir2.c
@@ -443,13 +443,14 @@ xfs_dir_lookup(
  */
 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;
@@ -495,6 +496,8 @@ xfs_dir_removename(
 		rval = xfs_dir2_leaf_removename(args);
 	else
 		rval = xfs_dir2_node_removename(args);
+	if (offset)
+		*offset = args->offset;
 out_free:
 	kmem_free(args);
 	return rval;
diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
index e349900..e1bd05d 100644
--- a/fs/xfs/libxfs/xfs_dir2.h
+++ b/fs/xfs/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/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
index 79684d5..4dbe2fc 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -791,9 +791,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/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
index 2ac7a7e..197e627 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -1383,9 +1383,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/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
index 8bc91f8..13d5244 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -1238,9 +1238,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/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
index 489bdef..9e90c22 100644
--- a/fs/xfs/libxfs/xfs_dir2_sf.c
+++ b/fs/xfs/libxfs/xfs_dir2_sf.c
@@ -919,6 +919,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;
 		}
 	}
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 3abcb17..358a98a 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2639,8 +2639,8 @@ xfs_remove(
 		goto out_trans_cancel;
 
 	xfs_defer_init(&dfops, &first_block);
-	error = xfs_dir_removename(tp, dp, name, ip->i_ino,
-					&first_block, &dfops, resblks);
+	error = xfs_dir_removename(tp, dp, name, ip->i_ino, &first_block,
+				   &dfops, resblks, NULL);
 	if (error) {
 		ASSERT(error != -ENOENT);
 		goto out_bmap_cancel;
@@ -3150,7 +3150,8 @@ xfs_rename(
 					&first_block, &dfops, spaceres);
 	} else
 		error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
-					   &first_block, &dfops, spaceres);
+					   &first_block, &dfops, spaceres,
+					   NULL);
 	if (error)
 		goto out_bmap_cancel;
 
-- 
2.7.4


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

* [PATCH v3 07/17] xfs: get directory offset when replacing a directory name
  2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
                   ` (5 preceding siblings ...)
  2017-11-17 18:21 ` [PATCH v3 06/17] xfs: get directory offset when removing " Allison Henderson
@ 2017-11-17 18:21 ` Allison Henderson
  2017-11-28 19:04   ` Darrick J. Wong
  2017-11-17 18:21 ` [PATCH v3 08/17] xfs: add parent pointer support to attribute code Allison Henderson
                   ` (9 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Mark Tinguely, Dave Chinner, Allison Henderson

From: Mark Tinguely <tinguely@sgi.com>

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]

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>
---
v2: Changed typedefs to raw struct types

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_dir2.c       | 16 ++++++++++------
 fs/xfs/libxfs/xfs_dir2.h       |  3 ++-
 fs/xfs/libxfs/xfs_dir2_block.c |  4 ++--
 fs/xfs/libxfs/xfs_dir2_leaf.c  |  1 +
 fs/xfs/libxfs/xfs_dir2_node.c  |  1 +
 fs/xfs/libxfs/xfs_dir2_sf.c    |  2 ++
 fs/xfs/xfs_inode.c             | 28 +++++++++++++---------------
 7 files changed, 31 insertions(+), 24 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
index b647bf2..25b370b 100644
--- a/fs/xfs/libxfs/xfs_dir2.c
+++ b/fs/xfs/libxfs/xfs_dir2.c
@@ -508,13 +508,14 @@ xfs_dir_removename(
  */
 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;
@@ -563,6 +564,9 @@ xfs_dir_replace(
 		rval = xfs_dir2_leaf_replace(args);
 	else
 		rval = xfs_dir2_node_replace(args);
+
+	if (offset)
+		*offset = args->offset;
 out_free:
 	kmem_free(args);
 	return rval;
diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
index e1bd05d..5cc0b3f 100644
--- a/fs/xfs/libxfs/xfs_dir2.h
+++ b/fs/xfs/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/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
index 4dbe2fc..69dfe64 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -865,9 +865,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/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
index 197e627..770b93f 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -1518,6 +1518,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/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
index 13d5244..860a612 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -2237,6 +2237,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/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
index 9e90c22..295458f 100644
--- a/fs/xfs/libxfs/xfs_dir2_sf.c
+++ b/fs/xfs/libxfs/xfs_dir2_sf.c
@@ -1045,6 +1045,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/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 358a98a..f7986d8 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2774,16 +2774,14 @@ xfs_cross_rename(
 	int		dp2_flags = 0;
 
 	/* Swap inode number for dirent in first parent */
-	error = xfs_dir_replace(tp, dp1, name1,
-				ip2->i_ino,
-				first_block, dfops, spaceres);
+	error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, first_block, dfops,
+				spaceres, NULL);
 	if (error)
 		goto out_trans_abort;
 
 	/* Swap inode number for dirent in second parent */
-	error = xfs_dir_replace(tp, dp2, name2,
-				ip1->i_ino,
-				first_block, dfops, spaceres);
+	error = xfs_dir_replace(tp, dp2, name2, ip1->i_ino, first_block, dfops,
+				spaceres, NULL);
 	if (error)
 		goto out_trans_abort;
 
@@ -2797,8 +2795,8 @@ xfs_cross_rename(
 
 		if (S_ISDIR(VFS_I(ip2)->i_mode)) {
 			error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot,
-						dp1->i_ino, first_block,
-						dfops, spaceres);
+						dp1->i_ino, first_block, dfops,
+						spaceres, NULL);
 			if (error)
 				goto out_trans_abort;
 
@@ -2824,8 +2822,8 @@ xfs_cross_rename(
 
 		if (S_ISDIR(VFS_I(ip1)->i_mode)) {
 			error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot,
-						dp2->i_ino, first_block,
-						dfops, spaceres);
+						dp2->i_ino, first_block, dfops,
+						spaceres, NULL);
 			if (error)
 				goto out_trans_abort;
 
@@ -3072,8 +3070,8 @@ xfs_rename(
 		 * name at the destination directory, remove it first.
 		 */
 		error = xfs_dir_replace(tp, target_dp, target_name,
-					src_ip->i_ino,
-					&first_block, &dfops, spaceres);
+					src_ip->i_ino, &first_block, &dfops,
+					spaceres, NULL);
 		if (error)
 			goto out_bmap_cancel;
 
@@ -3107,8 +3105,8 @@ xfs_rename(
 		 * directory.
 		 */
 		error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,
-					target_dp->i_ino,
-					&first_block, &dfops, spaceres);
+					target_dp->i_ino, &first_block, &dfops,
+					spaceres, NULL);
 		ASSERT(error != -EEXIST);
 		if (error)
 			goto out_bmap_cancel;
@@ -3147,7 +3145,7 @@ xfs_rename(
 	 */
 	if (wip) {
 		error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino,
-					&first_block, &dfops, spaceres);
+					&first_block, &dfops, spaceres, NULL);
 	} else
 		error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
 					   &first_block, &dfops, spaceres,
-- 
2.7.4


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

* [PATCH v3 08/17] xfs: add parent pointer support to attribute code
  2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
                   ` (6 preceding siblings ...)
  2017-11-17 18:21 ` [PATCH v3 07/17] xfs: get directory offset when replacing a " Allison Henderson
@ 2017-11-17 18:21 ` Allison Henderson
  2017-11-28 19:01   ` Darrick J. Wong
  2017-11-17 18:21 ` [PATCH v3 09/17] xfs: define parent pointer xattr format Allison Henderson
                   ` (8 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Mark Tinguely, Dave Chinner, Allison Henderson

From: Mark Tinguely <tinguely@sgi.com>

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>
---
 fs/xfs/libxfs/xfs_attr.c      |  2 +-
 fs/xfs/libxfs/xfs_da_format.h | 12 ++++++++----
 fs/xfs/xfs_attr.h             |  2 ++
 3 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 61e8343..9d4d883 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -408,7 +408,7 @@ xfs_attr_set(
 	struct xfs_da_args	args;
 	struct xfs_defer_ops	dfops;
 	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/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h
index 3771edc..5f94c84 100644
--- a/fs/xfs/libxfs/xfs_da_format.h
+++ b/fs/xfs/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
diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
index 10fc466..1f5c711 100644
--- a/fs/xfs/xfs_attr.h
+++ b/fs/xfs/xfs_attr.h
@@ -46,6 +46,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_KERNOTIME	0x1000	/* [kernel] don't update inode timestamps */
 #define ATTR_KERNOVAL	0x2000	/* [kernel] get attr size only, not value */
@@ -57,6 +58,7 @@ struct xfs_attr_list_context;
 	{ ATTR_SECURE,		"SECURE" }, \
 	{ ATTR_CREATE,		"CREATE" }, \
 	{ ATTR_REPLACE,		"REPLACE" }, \
+	{ ATTR_PARENT,		"PARENT" }, \
 	{ ATTR_KERNOTIME,	"KERNOTIME" }, \
 	{ ATTR_KERNOVAL,	"KERNOVAL" }
 
-- 
2.7.4


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

* [PATCH v3 09/17] xfs: define parent pointer xattr format
  2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
                   ` (7 preceding siblings ...)
  2017-11-17 18:21 ` [PATCH v3 08/17] xfs: add parent pointer support to attribute code Allison Henderson
@ 2017-11-17 18:21 ` Allison Henderson
  2017-11-28 18:59   ` Darrick J. Wong
  2017-11-17 18:21 ` [PATCH v3 10/17] xfs: extent transaction reservations for parent attributes Allison Henderson
                   ` (7 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Dave Chinner, Allison Henderson

From: Dave Chinner <dchinner@redhat.com>

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]

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
v2: changed p_ino to xfs_ino_t and p_namelen to uint8_t

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_format.h | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 23229f0..b9ea5bf 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -18,6 +18,8 @@
 #ifndef __XFS_FORMAT_H__
 #define __XFS_FORMAT_H__
 
+#include "xfs_da_format.h"
+
 /*
  * XFS On Disk Format Definitions
  *
@@ -1716,4 +1718,29 @@ struct xfs_acl {
 #define SGI_ACL_FILE_SIZE	(sizeof(SGI_ACL_FILE)-1)
 #define SGI_ACL_DEFAULT_SIZE	(sizeof(SGI_ACL_DEFAULT)-1)
 
+/*
+ * 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_FORMAT_H__ */
-- 
2.7.4


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

* [PATCH v3 10/17] xfs: extent transaction reservations for parent attributes
  2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
                   ` (8 preceding siblings ...)
  2017-11-17 18:21 ` [PATCH v3 09/17] xfs: define parent pointer xattr format Allison Henderson
@ 2017-11-17 18:21 ` Allison Henderson
  2017-11-28 18:58   ` Darrick J. Wong
  2017-11-17 18:21 ` [PATCH v3 11/17] Add the extra space requirements for parent pointer attributes when calculating the minimum log size during mkfs Allison Henderson
                   ` (6 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Dave Chinner, Allison Henderson

From: Dave Chinner <dchinner@redhat.com>

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>
---
 fs/xfs/libxfs/xfs_format.h     |   5 ++
 fs/xfs/libxfs/xfs_trans_resv.c | 103 ++++++++++++++++++++++++++++++++---------
 2 files changed, 85 insertions(+), 23 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index b9ea5bf..121862a 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -556,6 +556,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/fs/xfs/libxfs/xfs_trans_resv.c b/fs/xfs/libxfs/xfs_trans_resv.c
index 6bd916b..54399e2 100644
--- a/fs/xfs/libxfs/xfs_trans_resv.c
+++ b/fs/xfs/libxfs/xfs_trans_resv.c
@@ -802,29 +802,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;
@@ -846,15 +847,69 @@ 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;
+
+	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;
@@ -886,6 +941,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.
-- 
2.7.4


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

* [PATCH v3 11/17] Add the extra space requirements for parent pointer attributes when calculating the minimum log size during mkfs
  2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
                   ` (9 preceding siblings ...)
  2017-11-17 18:21 ` [PATCH v3 10/17] xfs: extent transaction reservations for parent attributes Allison Henderson
@ 2017-11-17 18:21 ` Allison Henderson
  2017-11-28 18:51   ` Darrick J. Wong
  2017-11-17 18:21 ` [PATCH v3 12/17] xfs: parent pointer attribute creation Allison Henderson
                   ` (5 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Henderson

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_log_rlimit.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/fs/xfs/libxfs/xfs_log_rlimit.c b/fs/xfs/libxfs/xfs_log_rlimit.c
index c105979..beec9bf 100644
--- a/fs/xfs/libxfs/xfs_log_rlimit.c
+++ b/fs/xfs/libxfs/xfs_log_rlimit.c
@@ -39,6 +39,40 @@ xfs_log_calc_max_attrsetm_res(
 {
 	int			size;
 	int			nblks;
+	struct xfs_trans_resv   *resp = M_RES(mp);
+
+	/* Calculate extra space needed for parent pointer attributes */
+	if (!xfs_sb_version_hasparent(&mp->m_sb)) {
+
+		/* 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;
+	}
+
 
 	size = xfs_attr_leaf_entsize_local_max(mp->m_attr_geo->blksize) -
 	       MAXNAMELEN - 1;
-- 
2.7.4


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

* [PATCH v3 12/17] xfs: parent pointer attribute creation
  2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
                   ` (10 preceding siblings ...)
  2017-11-17 18:21 ` [PATCH v3 11/17] Add the extra space requirements for parent pointer attributes when calculating the minimum log size during mkfs Allison Henderson
@ 2017-11-17 18:21 ` Allison Henderson
  2017-11-28 18:49   ` Darrick J. Wong
  2017-11-17 18:21 ` [PATCH v3 13/17] xfs: add parent attributes to link Allison Henderson
                   ` (4 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Dave Chinner, Allison Henderson

From: Dave Chinner <dchinner@redhat.com>

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

[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]

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
v2: remove unnecessary ENOSPC handling in xfs_attr_set_first_parent

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/Makefile            |  1 +
 fs/xfs/libxfs/xfs_parent.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_attr.h          | 15 +++++++-
 fs/xfs/xfs_inode.c         | 16 +++++++-
 4 files changed, 123 insertions(+), 2 deletions(-)

diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index ec6486b..3015bca 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -52,6 +52,7 @@ xfs-y				+= $(addprefix libxfs/, \
 				   xfs_inode_fork.o \
 				   xfs_inode_buf.o \
 				   xfs_log_rlimit.o \
+				   xfs_parent.o \
 				   xfs_ag_resv.o \
 				   xfs_rmap.o \
 				   xfs_rmap_btree.o \
diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
new file mode 100644
index 0000000..5eec0ab
--- /dev/null
+++ b/fs/xfs/libxfs/xfs_parent.c
@@ -0,0 +1,93 @@
+/*
+ * 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 "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_shared.h"
+#include "xfs_trans_resv.h"
+#include "xfs_mount.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_inode.h"
+#include "xfs_error.h"
+#include "xfs_trace.h"
+#include "xfs_trans.h"
+#include "xfs_attr.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,
+			unsigned long long int		p_ino,
+			unsigned int			p_gen,
+			unsigned int			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);
+}
+
+/*
+ * Add a parent record to an inode with existing parent records.
+ */
+int
+xfs_parent_add(
+	struct xfs_trans        *tp,
+	struct xfs_inode        *parent,
+	struct xfs_inode        *child,
+	struct xfs_name         *child_name,
+	uint32_t                diroffset,
+	struct xfs_defer_ops    *dfops,
+	xfs_fsblock_t           *firstblock)
+{
+	struct xfs_parent_name_rec rec;
+
+	xfs_init_parent_name_rec(&rec, parent->i_ino,
+		VFS_I(parent)->i_generation, diroffset);
+
+	return xfs_attr_set_deferred(child, dfops, &rec, sizeof(rec),
+		(void *)child_name->name, child_name->len, ATTR_PARENT);
+}
+
diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
index 1f5c711..09ef747 100644
--- a/fs/xfs/xfs_attr.h
+++ b/fs/xfs/xfs_attr.h
@@ -19,6 +19,8 @@
 #define	__XFS_ATTR_H__
 
 #include "libxfs/xfs_defer.h"
+#include "libxfs/xfs_da_format.h"
+#include "libxfs/xfs_format.h"
 
 struct xfs_inode;
 struct xfs_da_args;
@@ -184,5 +186,16 @@ int xfs_attr_set_deferred(struct xfs_inode *dp, struct xfs_defer_ops *dfops,
 			  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);
-
+/*
+ * Parent pointer attribute prototypes
+ */
+void xfs_init_parent_name_rec(struct xfs_parent_name_rec *rec,
+		unsigned long long int p_ino, unsigned int p_gen,
+		unsigned int  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,
+		xfs_dir2_dataptr_t diroffset, struct xfs_defer_ops *dfops,
+		xfs_fsblock_t *firstblock);
 #endif	/* __XFS_ATTR_H__ */
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index f7986d8..1c45c73 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1164,6 +1164,7 @@ xfs_create(
 	struct xfs_dquot	*pdqp = NULL;
 	struct xfs_trans_res	*tres;
 	uint			resblks;
+	xfs_dir2_dataptr_t	diroffset;
 
 	trace_xfs_create(dp, name);
 
@@ -1253,7 +1254,7 @@ xfs_create(
 	error = xfs_dir_createname(tp, dp, name, ip->i_ino,
 					&first_block, &dfops, resblks ?
 					resblks - XFS_IALLOC_SPACE_RES(mp) : 0,
-					NULL);
+					&diroffset);
 	if (error) {
 		ASSERT(error != -ENOSPC);
 		goto out_trans_cancel;
@@ -1272,6 +1273,19 @@ xfs_create(
 	}
 
 	/*
+	 * If we have parent pointers, we need to add the attribute containing
+	 * the parent information now. This must be done within the same
+	 * transaction the directory entry is created, while the new inode
+	 * contains nothing in the inode literal area.
+	 */
+	if (xfs_sb_version_hasparent(&mp->m_sb)) {
+		error = xfs_parent_add(tp, dp, ip, name, diroffset,
+					  &dfops, &first_block);
+		if (error)
+			goto out_bmap_cancel;
+	}
+
+	/*
 	 * If this is a synchronous mount, make sure that the
 	 * create transaction goes to disk before returning to
 	 * the user.
-- 
2.7.4


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

* [PATCH v3 13/17] xfs: add parent attributes to link
  2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
                   ` (11 preceding siblings ...)
  2017-11-17 18:21 ` [PATCH v3 12/17] xfs: parent pointer attribute creation Allison Henderson
@ 2017-11-17 18:21 ` Allison Henderson
  2017-11-28 18:37   ` Darrick J. Wong
  2017-11-17 18:21 ` [PATCH v3 14/17] xfs: remove parent pointers in unlink Allison Henderson
                   ` (3 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Dave Chinner, Allison Henderson

From: Dave Chinner <dchinner@redhat.com>

This patch modifies xfs_link to add a parent pointer to the inode.
xfs_link will also need to create an attribute fork if the inode does
not already have one.

[bfoster: rebase, use VFS inode fields, fix xfs_bmap_finish() usage]
[achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
	   fixed null pointer bugs]

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/xfs_inode.c | 61 +++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 47 insertions(+), 14 deletions(-)

diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 1c45c73..0ad843d 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1451,6 +1451,8 @@ xfs_link(
 	struct xfs_defer_ops	dfops;
 	xfs_fsblock_t           first_block;
 	int			resblks;
+	uint32_t		diroffset;
+	bool			first_parent = false;
 
 	trace_xfs_link(tdp, target_name);
 
@@ -1467,6 +1469,25 @@ xfs_link(
 	if (error)
 		goto std_return;
 
+	/*
+	 * If we have parent pointers and there is no attribute fork (i.e. we
+	 * are linking in a O_TMPFILE created inode) we need to add the
+	 * attribute fork to the inode. Because we may have an existing data
+	 * fork, we do this before we start the link transaction as adding an
+	 * attribute fork requires it's own transaction.
+	 */
+	if (xfs_sb_version_hasparent(&mp->m_sb) && !xfs_inode_hasattr(sip)) {
+		int sf_size = sizeof(struct xfs_attr_sf_hdr) +
+				XFS_ATTR_SF_ENTSIZE_BYNAME(
+					sizeof(struct xfs_parent_name_rec),
+					target_name->len);
+		ASSERT(VFS_I(sip)->i_nlink == 0);
+		error = xfs_bmap_add_attrfork(sip, sf_size, 0);
+		if (error)
+			goto std_return;
+		first_parent = true;
+	}
+
 	resblks = XFS_LINK_SPACE_RES(mp, target_name->len);
 	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, resblks, 0, 0, &tp);
 	if (error == -ENOSPC) {
@@ -1498,8 +1519,6 @@ xfs_link(
 			goto error_return;
 	}
 
-	xfs_defer_init(&dfops, &first_block);
-
 	/*
 	 * Handle initial link state of O_TMPFILE inode
 	 */
@@ -1509,36 +1528,50 @@ xfs_link(
 			goto error_return;
 	}
 
+	xfs_defer_init(&dfops, &first_block);
 	error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
-				   &first_block, &dfops, resblks, NULL);
+				   &first_block, &dfops, resblks, &diroffset);
 	if (error)
-		goto error_return;
+		goto out_defer_cancel;
 	xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 	xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
 
 	error = xfs_bumplink(tp, sip);
 	if (error)
-		goto error_return;
+		goto out_defer_cancel;
 
 	/*
-	 * If this is a synchronous mount, make sure that the
-	 * link transaction goes to disk before returning to
-	 * the user.
+	 * If we have parent pointers, we now need to add the parent record to
+	 * the attribute fork of the inode. If this is the initial parent
+	 * atribute, we need to create it correctly, otherwise we can just add
+	 * the parent to the inode.
+	 */
+	if (xfs_sb_version_hasparent(&mp->m_sb)) {
+		error = xfs_parent_add(tp, tdp, sip, target_name,
+				       diroffset, &dfops,
+				       &first_block);
+		if (error)
+			goto out_defer_cancel;
+	}
+
+	/*
+	 * If this is a synchronous mount, make sure that the link transaction
+	 * goes to disk before returning to the user.
 	 */
 	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
 		xfs_trans_set_sync(tp);
 
 	error = xfs_defer_finish(&tp, &dfops);
-	if (error) {
-		xfs_defer_cancel(&dfops);
-		goto error_return;
-	}
+	if (error)
+		goto out_defer_cancel;
 
 	return xfs_trans_commit(tp);
 
- error_return:
+out_defer_cancel:
+	xfs_defer_cancel(&dfops);
+error_return:
 	xfs_trans_cancel(tp);
- std_return:
+std_return:
 	return error;
 }
 
-- 
2.7.4


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

* [PATCH v3 14/17] xfs: remove parent pointers in unlink
  2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
                   ` (12 preceding siblings ...)
  2017-11-17 18:21 ` [PATCH v3 13/17] xfs: add parent attributes to link Allison Henderson
@ 2017-11-17 18:21 ` Allison Henderson
  2017-11-28 18:24   ` Darrick J. Wong
  2017-11-17 18:21 ` [PATCH v3 15/17] Add parent pointers to rename Allison Henderson
                   ` (2 subsequent siblings)
  16 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Dave Chinner, Allison Henderson

From: Dave Chinner <dchinner@redhat.com>

This patch removes the parent pointer attribute during unlink

[bfoster: rebase, use VFS inode generation]
[achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t
	   implemented xfs_attr_remove_parent]

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_parent.c | 20 ++++++++++++++++++++
 fs/xfs/xfs_attr.h          |  4 ++++
 fs/xfs/xfs_inode.c         | 10 +++++++++-
 3 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
index 5eec0ab..9278c89 100644
--- a/fs/xfs/libxfs/xfs_parent.c
+++ b/fs/xfs/libxfs/xfs_parent.c
@@ -91,3 +91,23 @@ xfs_parent_add(
 		(void *)child_name->name, child_name->len, ATTR_PARENT);
 }
 
+/*
+ * Remove a parent record from a child inode.
+ */
+int
+xfs_parent_remove(
+        struct xfs_trans        *tp,
+        struct xfs_inode        *parent,
+        struct xfs_inode        *child,
+        xfs_dir2_dataptr_t      diroffset,
+	struct xfs_defer_ops    *dfops,
+	xfs_fsblock_t           *firstblock)
+{
+	struct xfs_parent_name_rec rec;
+
+	xfs_init_parent_name_rec(&rec, parent->i_ino,
+		VFS_I(parent)->i_generation, diroffset);
+
+	return xfs_attr_remove_deferred(child, dfops, &rec, sizeof(rec),
+					ATTR_PARENT);
+}
diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
index 09ef747..0829687 100644
--- a/fs/xfs/xfs_attr.h
+++ b/fs/xfs/xfs_attr.h
@@ -198,4 +198,8 @@ int xfs_parent_add(struct xfs_trans *tp, struct xfs_inode *parent,
 		struct xfs_inode *child, struct xfs_name *child_name,
 		xfs_dir2_dataptr_t diroffset, struct xfs_defer_ops *dfops,
 		xfs_fsblock_t *firstblock);
+int xfs_parent_remove(struct xfs_trans *tp, struct xfs_inode *parent,
+		      struct xfs_inode *child, xfs_dir2_dataptr_t diroffset,
+		      struct xfs_defer_ops *dfops, xfs_fsblock_t *firstblock);
+
 #endif	/* __XFS_ATTR_H__ */
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 0ad843d..a289a40 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2607,6 +2607,7 @@ xfs_remove(
 	struct xfs_defer_ops	dfops;
 	xfs_fsblock_t           first_block;
 	uint			resblks;
+	uint32_t		dir_offset;
 
 	trace_xfs_remove(dp, name);
 
@@ -2687,12 +2688,19 @@ xfs_remove(
 
 	xfs_defer_init(&dfops, &first_block);
 	error = xfs_dir_removename(tp, dp, name, ip->i_ino, &first_block,
-				   &dfops, resblks, NULL);
+				   &dfops, resblks, &dir_offset);
 	if (error) {
 		ASSERT(error != -ENOENT);
 		goto out_bmap_cancel;
 	}
 
+	if (xfs_sb_version_hasparent(&mp->m_sb)) {
+		error = xfs_parent_remove(tp, dp, ip, dir_offset, &dfops,
+					  &first_block);
+		if (error)
+			goto out_bmap_cancel;
+	}
+
 	/*
 	 * If this is a synchronous mount, make sure that the
 	 * remove transaction goes to disk before returning to
-- 
2.7.4


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

* [PATCH v3 15/17] Add parent pointers to rename
  2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
                   ` (13 preceding siblings ...)
  2017-11-17 18:21 ` [PATCH v3 14/17] xfs: remove parent pointers in unlink Allison Henderson
@ 2017-11-17 18:21 ` Allison Henderson
  2017-11-28 18:20   ` Darrick J. Wong
  2017-11-17 18:21 ` [PATCH v3 16/17] Add the parent pointer support to the superblock version 5 Allison Henderson
  2017-11-17 18:21 ` [PATCH v3 17/17] Add parent pointer ioctl Allison Henderson
  16 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Henderson

This patch removes the old parent pointer attribute during the
rename operation, and re-adds the updated parent pointer

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_dir2.c |  6 ++++--
 fs/xfs/xfs_inode.c       | 26 ++++++++++++++++++++------
 2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
index 25b370b..ed25203 100644
--- a/fs/xfs/libxfs/xfs_dir2.c
+++ b/fs/xfs/libxfs/xfs_dir2.c
@@ -324,10 +324,11 @@ xfs_dir_createname(
 	else
 		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;
-out_free:
+
 	kmem_free(args);
 	return rval;
 }
@@ -496,9 +497,10 @@ xfs_dir_removename(
 		rval = xfs_dir2_leaf_removename(args);
 	else
 		rval = xfs_dir2_node_removename(args);
+out_free:
 	if (offset)
 		*offset = args->offset;
-out_free:
+
 	kmem_free(args);
 	return rval;
 }
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index a289a40..da5c761 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2984,6 +2984,8 @@ xfs_rename(
 	bool			src_is_directory = S_ISDIR(VFS_I(src_ip)->i_mode);
 	int			spaceres;
 	int			error;
+	xfs_dir2_dataptr_t	new_diroffset;
+	xfs_dir2_dataptr_t	old_diroffset;
 
 	trace_xfs_rename(src_dp, target_dp, src_name, target_name);
 
@@ -3086,13 +3088,12 @@ xfs_rename(
 		 */
 		error = xfs_dir_createname(tp, target_dp, target_name,
 					   src_ip->i_ino, &first_block, &dfops,
-					   spaceres, NULL);
+					   spaceres, &new_diroffset);
 		if (error)
 			goto out_bmap_cancel;
 
 		xfs_trans_ichgtime(tp, target_dp,
 					XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-
 		if (new_parent && src_is_directory) {
 			error = xfs_bumplink(tp, target_dp);
 			if (error)
@@ -3126,7 +3127,7 @@ xfs_rename(
 		 */
 		error = xfs_dir_replace(tp, target_dp, target_name,
 					src_ip->i_ino, &first_block, &dfops,
-					spaceres, NULL);
+					spaceres, &new_diroffset);
 		if (error)
 			goto out_bmap_cancel;
 
@@ -3161,7 +3162,7 @@ xfs_rename(
 		 */
 		error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,
 					target_dp->i_ino, &first_block, &dfops,
-					spaceres, NULL);
+					spaceres, &new_diroffset);
 		ASSERT(error != -EEXIST);
 		if (error)
 			goto out_bmap_cancel;
@@ -3200,11 +3201,12 @@ xfs_rename(
 	 */
 	if (wip) {
 		error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino,
-					&first_block, &dfops, spaceres, NULL);
+					&first_block, &dfops, spaceres,
+					&old_diroffset);
 	} else
 		error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
 					   &first_block, &dfops, spaceres,
-					   NULL);
+					   &old_diroffset);
 	if (error)
 		goto out_bmap_cancel;
 
@@ -3234,6 +3236,18 @@ xfs_rename(
 		VFS_I(wip)->i_state &= ~I_LINKABLE;
 	}
 
+	if (new_parent && xfs_sb_version_hasparent(&mp->m_sb)) {
+		error = xfs_parent_add(tp, target_dp, src_ip, target_name,
+				       new_diroffset, &dfops, &first_block);
+		if (error)
+			goto out_bmap_cancel;
+
+		error = xfs_parent_remove(tp, src_dp, src_ip,
+					  old_diroffset, &dfops, &first_block);
+		if (error)
+			goto out_bmap_cancel;
+	}
+
 	xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 	xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE);
 	if (new_parent)
-- 
2.7.4


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

* [PATCH v3 16/17] Add the parent pointer support to the superblock version 5.
  2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
                   ` (14 preceding siblings ...)
  2017-11-17 18:21 ` [PATCH v3 15/17] Add parent pointers to rename Allison Henderson
@ 2017-11-17 18:21 ` Allison Henderson
  2017-11-28 18:08   ` Darrick J. Wong
  2017-11-17 18:21 ` [PATCH v3 17/17] Add parent pointer ioctl Allison Henderson
  16 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Henderson, Mark Tinguely, Dave Chinner

[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>
---
v2: remove unrelated type clean up in xfs_format.h

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_format.h | 7 +++++--
 fs/xfs/libxfs/xfs_fs.h     | 1 +
 fs/xfs/xfs_fsops.c         | 4 +++-
 fs/xfs/xfs_super.c         | 4 ++++
 4 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 121862a..f3e3132 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -459,10 +459,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(
@@ -558,7 +560,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/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index 8c61f21..b8108f8 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -222,6 +222,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/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index 8f22fc5..9a0ce52 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -111,7 +111,9 @@ xfs_fs_geometry(
 			(xfs_sb_version_hasrmapbt(&mp->m_sb) ?
 				XFS_FSOP_GEOM_FLAGS_RMAPBT : 0) |
 			(xfs_sb_version_hasreflink(&mp->m_sb) ?
-				XFS_FSOP_GEOM_FLAGS_REFLINK : 0);
+				XFS_FSOP_GEOM_FLAGS_REFLINK : 0) |
+			(xfs_sb_version_hasparent(&mp->m_sb) ?
+				XFS_FSOP_GEOM_FLAGS_PARENT : 0);
 		geo->logsectsize = xfs_sb_version_hassector(&mp->m_sb) ?
 				mp->m_sb.sb_logsectsize : BBSIZE;
 		geo->rtsectsize = mp->m_sb.sb_blocksize;
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index ee68459..066266f 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1675,6 +1675,10 @@ xfs_fs_fill_super(
 	"EXPERIMENTAL reverse mapping btree feature enabled. Use at your own risk!");
 	}
 
+	if (xfs_sb_version_hasparent(&mp->m_sb))
+		xfs_alert(mp,
+	"EXPERIMENTAL parent pointer feature enabled. Use at your own risk!");
+
 	if (xfs_sb_version_hasreflink(&mp->m_sb))
 		xfs_alert(mp,
 	"EXPERIMENTAL reflink feature enabled. Use at your own risk!");
-- 
2.7.4


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

* [PATCH v3 17/17] Add parent pointer ioctl
  2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
                   ` (15 preceding siblings ...)
  2017-11-17 18:21 ` [PATCH v3 16/17] Add the parent pointer support to the superblock version 5 Allison Henderson
@ 2017-11-17 18:21 ` Allison Henderson
  2017-11-22 19:54   ` Allison Henderson
  2017-11-28 20:35   ` Darrick J. Wong
  16 siblings, 2 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-17 18:21 UTC (permalink / raw)
  To: linux-xfs; +Cc: Allison Henderson

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>
---
 fs/xfs/libxfs/xfs_attr.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/libxfs/xfs_fs.h   |  1 +
 fs/xfs/xfs_attr.h        |  2 ++
 fs/xfs/xfs_attr_list.c   |  3 +++
 fs/xfs/xfs_ioctl.c       | 48 +++++++++++++++++++++++++++++++++-
 5 files changed, 120 insertions(+), 1 deletion(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 9d4d883..d2be842 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -134,6 +134,73 @@ xfs_attr_get_ilocked(
 		return xfs_attr_node_get(args);
 }
 
+/*
+ * Get the parent pointer for a given inode
+ * Caller will need to allocate a buffer pointed to by xpnir->p_name
+ * and store the buffer size in xpnir->p_namelen.  The parent
+ * pointer will be stored in the given xfs_parent_name_irec
+ *
+ * Returns 0 on success and non zero on error
+ */
+int
+xfs_attr_get_parent_pointer(struct xfs_inode		*ip,
+			    struct xfs_parent_name_irec *xpnir)
+{
+	struct attrlist			*alist;
+	struct attrlist_ent		*aent;
+	struct attrlist_cursor_kern     cursor;
+	struct xfs_parent_name_rec	*xpnr;
+	char				*namebuf;
+	int                             error = 0;
+	unsigned int                    flags = ATTR_PARENT;
+
+	/* Allocate a buffer to store the attribute names */
+	namebuf = kmem_zalloc_large(XFS_XATTR_LIST_MAX, KM_SLEEP);
+	if (!namebuf)
+		return -ENOMEM;
+
+	/* Get all attribute names that have the ATTR_PARENT flag */
+	memset(&cursor, 0, sizeof(struct attrlist_cursor_kern));
+	error = xfs_attr_list(ip, namebuf, XFS_XATTR_LIST_MAX, flags, &cursor);
+	if (error)
+		goto out_kfree;
+
+	alist = (struct attrlist *)namebuf;
+
+	/* There should never be more than one parent pointer */
+	ASSERT(alist->al_count == 1);
+
+	aent = (struct attrlist_ent *) &namebuf[alist->al_offset[0]];
+	xpnr = (struct xfs_parent_name_rec *)(aent->a_name);
+
+	/*
+	 * The value of the parent pointer attribute should be the file name
+	 * So we check the value length of the attribute entry against the name
+	 * length of the parent name record to make sure the caller gave enough
+	 * buffer space to store the file name (plus a null terminator)
+	 */
+	if (aent->a_valuelen >= xpnir->p_namelen) {
+		error = -ERANGE;
+		goto out_kfree;
+	}
+
+	xpnir->p_namelen = aent->a_valuelen + 1;
+	memset((void *)(xpnir->p_name), 0, xpnir->p_namelen);
+	error = xfs_attr_get(ip, (char *)xpnr,
+			     sizeof(struct xfs_parent_name_rec),
+			     (unsigned char *)(xpnir->p_name),
+			     (int *)&(xpnir->p_namelen), flags);
+	if (error)
+		goto out_kfree;
+
+	xfs_init_parent_name_irec(xpnir, xpnr);
+
+out_kfree:
+	kmem_free(namebuf);
+
+	return error;
+}
+
 /* Retrieve an extended attribute by name, and its value. */
 int
 xfs_attr_get(
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index b8108f8..2f9ca2c 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -512,6 +512,7 @@ typedef struct xfs_swapext
 #define XFS_IOC_ZERO_RANGE	_IOW ('X', 57, struct xfs_flock64)
 #define XFS_IOC_FREE_EOFBLOCKS	_IOR ('X', 58, struct xfs_fs_eofblocks)
 /*	XFS_IOC_GETFSMAP ------ hoisted 59         */
+#define XFS_IOC_GETPPOINTER	_IOR ('X', 61, struct xfs_parent_name_irec)
 
 /*
  * ioctl commands that replace IRIX syssgi()'s
diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
index 0829687..0ec3458 100644
--- a/fs/xfs/xfs_attr.h
+++ b/fs/xfs/xfs_attr.h
@@ -172,6 +172,8 @@ int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
 		int flags);
 int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
 		size_t namelen, unsigned char *value, int valuelen, int flags);
+int xfs_attr_get_parent_pointer(struct xfs_inode *ip,
+				struct xfs_parent_name_irec *xpnir);
 int xfs_attr_set_args(struct xfs_da_args *args, int flags, bool roll_trans);
 int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
 		size_t namelen, int flags);
diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
index 7740c8a..78fc477 100644
--- a/fs/xfs/xfs_attr_list.c
+++ b/fs/xfs/xfs_attr_list.c
@@ -534,6 +534,9 @@ xfs_attr_put_listent(
 	if (((context->flags & ATTR_ROOT) == 0) !=
 	    ((flags & XFS_ATTR_ROOT) == 0))
 		return;
+	if (((context->flags & ATTR_PARENT) == 0) !=
+	    ((flags & XFS_ATTR_PARENT) == 0))
+		return;
 
 	arraytop = sizeof(*alist) +
 			context->count * sizeof(alist->al_offset[0]);
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 4664314..5492607 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -44,6 +44,7 @@
 #include "xfs_btree.h"
 #include <linux/fsmap.h>
 #include "xfs_fsmap.h"
+#include "xfs_attr.h"
 
 #include <linux/capability.h>
 #include <linux/cred.h>
@@ -1710,6 +1711,50 @@ xfs_ioc_getfsmap(
 	return 0;
 }
 
+/*
+ * IOCTL routine to get the parent pointer of an inode and return it to user
+ * space.  Caller must pass an struct xfs_parent_name_irec with a name buffer
+ * large enough to hold the file name.  Returns 0 on success or non-zero on
+ * failure
+ */
+STATIC int
+xfs_ioc_get_parent_pointer(
+	struct file			*filp,
+	void				__user *arg)
+{
+	struct inode			*inode = file_inode(filp);
+	struct xfs_inode		*ip = XFS_I(inode);
+	struct xfs_parent_name_irec	xpnir;
+	char				*uname;
+	char				*kname;
+	int				error = 0;
+
+	copy_from_user(&xpnir, arg, sizeof(struct xfs_parent_name_irec));
+	uname = (char *)xpnir.p_name;
+
+	/*
+	 * Use kernel space memory to get the parent pointer name.
+	 * We'll copy it to the user space name back when we're done
+	 */
+	kname = kmem_zalloc_large(xpnir.p_namelen, KM_SLEEP);
+	if (!kname)
+		return -ENOMEM;
+
+	xpnir.p_name = kname;
+	error = xfs_attr_get_parent_pointer(ip, &xpnir);
+
+	if (error)
+		goto out;
+
+	copy_to_user(uname, xpnir.p_name, xpnir.p_namelen);
+	xpnir.p_name = uname;
+	copy_to_user(arg, &xpnir, sizeof(struct xfs_parent_name_irec));
+
+out:
+	kmem_free(kname);
+	return error;
+}
+
 int
 xfs_ioc_swapext(
 	xfs_swapext_t	*sxp)
@@ -1866,7 +1911,8 @@ xfs_file_ioctl(
 		return xfs_ioc_getxflags(ip, arg);
 	case XFS_IOC_SETXFLAGS:
 		return xfs_ioc_setxflags(ip, filp, arg);
-
+	case XFS_IOC_GETPPOINTER:
+		return xfs_ioc_get_parent_pointer(filp, arg);
 	case XFS_IOC_FSSETDM: {
 		struct fsdmidata	dmi;
 
-- 
2.7.4


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

* Re: [PATCH v3 17/17] Add parent pointer ioctl
  2017-11-17 18:21 ` [PATCH v3 17/17] Add parent pointer ioctl Allison Henderson
@ 2017-11-22 19:54   ` Allison Henderson
  2017-11-22 21:07     ` Dave Chinner
  2017-11-22 21:13     ` Darrick J. Wong
  2017-11-28 20:35   ` Darrick J. Wong
  1 sibling, 2 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-22 19:54 UTC (permalink / raw)
  To: linux-xfs

On 11/17/2017 11:21 AM, Allison Henderson wrote:

> 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>
> ---
>   fs/xfs/libxfs/xfs_attr.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++
>   fs/xfs/libxfs/xfs_fs.h   |  1 +
>   fs/xfs/xfs_attr.h        |  2 ++
>   fs/xfs/xfs_attr_list.c   |  3 +++
>   fs/xfs/xfs_ioctl.c       | 48 +++++++++++++++++++++++++++++++++-
>   5 files changed, 120 insertions(+), 1 deletion(-)
>
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 9d4d883..d2be842 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -134,6 +134,73 @@ xfs_attr_get_ilocked(
>   		return xfs_attr_node_get(args);
>   }
>   
> +/*
> + * Get the parent pointer for a given inode
> + * Caller will need to allocate a buffer pointed to by xpnir->p_name
> + * and store the buffer size in xpnir->p_namelen.  The parent
> + * pointer will be stored in the given xfs_parent_name_irec
> + *
> + * Returns 0 on success and non zero on error
> + */
> +int
> +xfs_attr_get_parent_pointer(struct xfs_inode		*ip,
> +			    struct xfs_parent_name_irec *xpnir)
> +{
> +	struct attrlist			*alist;
> +	struct attrlist_ent		*aent;
> +	struct attrlist_cursor_kern     cursor;
> +	struct xfs_parent_name_rec	*xpnr;
> +	char				*namebuf;
> +	int                             error = 0;
> +	unsigned int                    flags = ATTR_PARENT;
> +
> +	/* Allocate a buffer to store the attribute names */
> +	namebuf = kmem_zalloc_large(XFS_XATTR_LIST_MAX, KM_SLEEP);
> +	if (!namebuf)
> +		return -ENOMEM;
> +
> +	/* Get all attribute names that have the ATTR_PARENT flag */
> +	memset(&cursor, 0, sizeof(struct attrlist_cursor_kern));
> +	error = xfs_attr_list(ip, namebuf, XFS_XATTR_LIST_MAX, flags, &cursor);
> +	if (error)
> +		goto out_kfree;
> +
> +	alist = (struct attrlist *)namebuf;
> +
> +	/* There should never be more than one parent pointer */
> +	ASSERT(alist->al_count == 1);
> +
> +	aent = (struct attrlist_ent *) &namebuf[alist->al_offset[0]];
> +	xpnr = (struct xfs_parent_name_rec *)(aent->a_name);
> +
> +	/*
> +	 * The value of the parent pointer attribute should be the file name
> +	 * So we check the value length of the attribute entry against the name
> +	 * length of the parent name record to make sure the caller gave enough
> +	 * buffer space to store the file name (plus a null terminator)
> +	 */
> +	if (aent->a_valuelen >= xpnir->p_namelen) {
> +		error = -ERANGE;
> +		goto out_kfree;
> +	}
> +
> +	xpnir->p_namelen = aent->a_valuelen + 1;
> +	memset((void *)(xpnir->p_name), 0, xpnir->p_namelen);
> +	error = xfs_attr_get(ip, (char *)xpnr,
> +			     sizeof(struct xfs_parent_name_rec),
> +			     (unsigned char *)(xpnir->p_name),
> +			     (int *)&(xpnir->p_namelen), flags);
> +	if (error)
> +		goto out_kfree;
> +
> +	xfs_init_parent_name_irec(xpnir, xpnr);
> +
> +out_kfree:
> +	kmem_free(namebuf);
> +
> +	return error;
> +}
I was thinking of moving this function else where.  It seems to generate 
a lot of compile issues when I apply it to xfsprogs because of the 
things it needs from xfs_attr.h.  Generally are patches to code in 
fs/xfs/libxfs not supposed to be including things outside libxfs?  Do I 
need to revise the series to avoid doing that? Thanks!

Allison
> +
>   /* Retrieve an extended attribute by name, and its value. */
>   int
>   xfs_attr_get(
> diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
> index b8108f8..2f9ca2c 100644
> --- a/fs/xfs/libxfs/xfs_fs.h
> +++ b/fs/xfs/libxfs/xfs_fs.h
> @@ -512,6 +512,7 @@ typedef struct xfs_swapext
>   #define XFS_IOC_ZERO_RANGE	_IOW ('X', 57, struct xfs_flock64)
>   #define XFS_IOC_FREE_EOFBLOCKS	_IOR ('X', 58, struct xfs_fs_eofblocks)
>   /*	XFS_IOC_GETFSMAP ------ hoisted 59         */
> +#define XFS_IOC_GETPPOINTER	_IOR ('X', 61, struct xfs_parent_name_irec)
>   
>   /*
>    * ioctl commands that replace IRIX syssgi()'s
> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
> index 0829687..0ec3458 100644
> --- a/fs/xfs/xfs_attr.h
> +++ b/fs/xfs/xfs_attr.h
> @@ -172,6 +172,8 @@ int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
>   		int flags);
>   int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
>   		size_t namelen, unsigned char *value, int valuelen, int flags);
> +int xfs_attr_get_parent_pointer(struct xfs_inode *ip,
> +				struct xfs_parent_name_irec *xpnir);
>   int xfs_attr_set_args(struct xfs_da_args *args, int flags, bool roll_trans);
>   int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
>   		size_t namelen, int flags);
> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
> index 7740c8a..78fc477 100644
> --- a/fs/xfs/xfs_attr_list.c
> +++ b/fs/xfs/xfs_attr_list.c
> @@ -534,6 +534,9 @@ xfs_attr_put_listent(
>   	if (((context->flags & ATTR_ROOT) == 0) !=
>   	    ((flags & XFS_ATTR_ROOT) == 0))
>   		return;
> +	if (((context->flags & ATTR_PARENT) == 0) !=
> +	    ((flags & XFS_ATTR_PARENT) == 0))
> +		return;
>   
>   	arraytop = sizeof(*alist) +
>   			context->count * sizeof(alist->al_offset[0]);
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index 4664314..5492607 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -44,6 +44,7 @@
>   #include "xfs_btree.h"
>   #include <linux/fsmap.h>
>   #include "xfs_fsmap.h"
> +#include "xfs_attr.h"
>   
>   #include <linux/capability.h>
>   #include <linux/cred.h>
> @@ -1710,6 +1711,50 @@ xfs_ioc_getfsmap(
>   	return 0;
>   }
>   
> +/*
> + * IOCTL routine to get the parent pointer of an inode and return it to user
> + * space.  Caller must pass an struct xfs_parent_name_irec with a name buffer
> + * large enough to hold the file name.  Returns 0 on success or non-zero on
> + * failure
> + */
> +STATIC int
> +xfs_ioc_get_parent_pointer(
> +	struct file			*filp,
> +	void				__user *arg)
> +{
> +	struct inode			*inode = file_inode(filp);
> +	struct xfs_inode		*ip = XFS_I(inode);
> +	struct xfs_parent_name_irec	xpnir;
> +	char				*uname;
> +	char				*kname;
> +	int				error = 0;
> +
> +	copy_from_user(&xpnir, arg, sizeof(struct xfs_parent_name_irec));
> +	uname = (char *)xpnir.p_name;
> +
> +	/*
> +	 * Use kernel space memory to get the parent pointer name.
> +	 * We'll copy it to the user space name back when we're done
> +	 */
> +	kname = kmem_zalloc_large(xpnir.p_namelen, KM_SLEEP);
> +	if (!kname)
> +		return -ENOMEM;
> +
> +	xpnir.p_name = kname;
> +	error = xfs_attr_get_parent_pointer(ip, &xpnir);
> +
> +	if (error)
> +		goto out;
> +
> +	copy_to_user(uname, xpnir.p_name, xpnir.p_namelen);
> +	xpnir.p_name = uname;
> +	copy_to_user(arg, &xpnir, sizeof(struct xfs_parent_name_irec));
> +
> +out:
> +	kmem_free(kname);
> +	return error;
> +}
> +
>   int
>   xfs_ioc_swapext(
>   	xfs_swapext_t	*sxp)
> @@ -1866,7 +1911,8 @@ xfs_file_ioctl(
>   		return xfs_ioc_getxflags(ip, arg);
>   	case XFS_IOC_SETXFLAGS:
>   		return xfs_ioc_setxflags(ip, filp, arg);
> -
> +	case XFS_IOC_GETPPOINTER:
> +		return xfs_ioc_get_parent_pointer(filp, arg);
>   	case XFS_IOC_FSSETDM: {
>   		struct fsdmidata	dmi;
>   


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

* Re: [PATCH v3 17/17] Add parent pointer ioctl
  2017-11-22 19:54   ` Allison Henderson
@ 2017-11-22 21:07     ` Dave Chinner
  2017-11-22 22:49       ` Allison Henderson
  2017-11-22 21:13     ` Darrick J. Wong
  1 sibling, 1 reply; 69+ messages in thread
From: Dave Chinner @ 2017-11-22 21:07 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

On Wed, Nov 22, 2017 at 12:54:45PM -0700, Allison Henderson wrote:
> On 11/17/2017 11:21 AM, Allison Henderson wrote:
> 
> >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>
> >---
> >  fs/xfs/libxfs/xfs_attr.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++
> >  fs/xfs/libxfs/xfs_fs.h   |  1 +
> >  fs/xfs/xfs_attr.h        |  2 ++
> >  fs/xfs/xfs_attr_list.c   |  3 +++
> >  fs/xfs/xfs_ioctl.c       | 48 +++++++++++++++++++++++++++++++++-
> >  5 files changed, 120 insertions(+), 1 deletion(-)
> >
> >diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> >index 9d4d883..d2be842 100644
> >--- a/fs/xfs/libxfs/xfs_attr.c
> >+++ b/fs/xfs/libxfs/xfs_attr.c
> >@@ -134,6 +134,73 @@ xfs_attr_get_ilocked(
> >  		return xfs_attr_node_get(args);
> >  }
> >+/*
> >+ * Get the parent pointer for a given inode
> >+ * Caller will need to allocate a buffer pointed to by xpnir->p_name
> >+ * and store the buffer size in xpnir->p_namelen.  The parent
> >+ * pointer will be stored in the given xfs_parent_name_irec
> >+ *
> >+ * Returns 0 on success and non zero on error
> >+ */
> >+int
> >+xfs_attr_get_parent_pointer(struct xfs_inode		*ip,
> >+			    struct xfs_parent_name_irec *xpnir)
> >+{
> >+	struct attrlist			*alist;
> >+	struct attrlist_ent		*aent;
> >+	struct attrlist_cursor_kern     cursor;
> >+	struct xfs_parent_name_rec	*xpnr;
> >+	char				*namebuf;
> >+	int                             error = 0;
> >+	unsigned int                    flags = ATTR_PARENT;
> >+
> >+	/* Allocate a buffer to store the attribute names */
> >+	namebuf = kmem_zalloc_large(XFS_XATTR_LIST_MAX, KM_SLEEP);
> >+	if (!namebuf)
> >+		return -ENOMEM;
> >+
> >+	/* Get all attribute names that have the ATTR_PARENT flag */
> >+	memset(&cursor, 0, sizeof(struct attrlist_cursor_kern));
> >+	error = xfs_attr_list(ip, namebuf, XFS_XATTR_LIST_MAX, flags, &cursor);
> >+	if (error)
> >+		goto out_kfree;
> >+
> >+	alist = (struct attrlist *)namebuf;
> >+
> >+	/* There should never be more than one parent pointer */
> >+	ASSERT(alist->al_count == 1);
> >+
> >+	aent = (struct attrlist_ent *) &namebuf[alist->al_offset[0]];
> >+	xpnr = (struct xfs_parent_name_rec *)(aent->a_name);
> >+
> >+	/*
> >+	 * The value of the parent pointer attribute should be the file name
> >+	 * So we check the value length of the attribute entry against the name
> >+	 * length of the parent name record to make sure the caller gave enough
> >+	 * buffer space to store the file name (plus a null terminator)
> >+	 */
> >+	if (aent->a_valuelen >= xpnir->p_namelen) {
> >+		error = -ERANGE;
> >+		goto out_kfree;
> >+	}
> >+
> >+	xpnir->p_namelen = aent->a_valuelen + 1;
> >+	memset((void *)(xpnir->p_name), 0, xpnir->p_namelen);
> >+	error = xfs_attr_get(ip, (char *)xpnr,
> >+			     sizeof(struct xfs_parent_name_rec),
> >+			     (unsigned char *)(xpnir->p_name),
> >+			     (int *)&(xpnir->p_namelen), flags);
> >+	if (error)
> >+		goto out_kfree;
> >+
> >+	xfs_init_parent_name_irec(xpnir, xpnr);
> >+
> >+out_kfree:
> >+	kmem_free(namebuf);
> >+
> >+	return error;
> >+}
> I was thinking of moving this function else where.  It seems to
> generate a lot of compile issues when I apply it to xfsprogs because
> of the things it needs from xfs_attr.h.  Generally are patches to
> code in fs/xfs/libxfs not supposed to be including things outside
> libxfs?  Do I need to revise the series to avoid doing that? Thanks!

In general, yes. More complex than that (e.g. userspace and kernel
have separate definitions of some structures like xfs_mount,
xfs_buf, etc), but we try to keep the libxfs code as encapsulated as
possible.

In terms of getting attrs to userspace, the equivalent attribute
listing code is in fs/xfs/xfs_attr_list.c, and that avoids all these
problems. I'd just move the xfs_attr_get_parent_pointer() function
there as ithis code should not be needed in userspace and it would
avoid all the userspace libxfs compile issues...

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v3 17/17] Add parent pointer ioctl
  2017-11-22 19:54   ` Allison Henderson
  2017-11-22 21:07     ` Dave Chinner
@ 2017-11-22 21:13     ` Darrick J. Wong
  2017-11-22 22:49       ` Allison Henderson
  1 sibling, 1 reply; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-22 21:13 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

On Wed, Nov 22, 2017 at 12:54:45PM -0700, Allison Henderson wrote:
> On 11/17/2017 11:21 AM, Allison Henderson wrote:
> 
> >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>
> >---
> >  fs/xfs/libxfs/xfs_attr.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++
> >  fs/xfs/libxfs/xfs_fs.h   |  1 +
> >  fs/xfs/xfs_attr.h        |  2 ++
> >  fs/xfs/xfs_attr_list.c   |  3 +++
> >  fs/xfs/xfs_ioctl.c       | 48 +++++++++++++++++++++++++++++++++-
> >  5 files changed, 120 insertions(+), 1 deletion(-)
> >
> >diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> >index 9d4d883..d2be842 100644
> >--- a/fs/xfs/libxfs/xfs_attr.c
> >+++ b/fs/xfs/libxfs/xfs_attr.c
> >@@ -134,6 +134,73 @@ xfs_attr_get_ilocked(
> >  		return xfs_attr_node_get(args);
> >  }
> >+/*
> >+ * Get the parent pointer for a given inode
> >+ * Caller will need to allocate a buffer pointed to by xpnir->p_name
> >+ * and store the buffer size in xpnir->p_namelen.  The parent
> >+ * pointer will be stored in the given xfs_parent_name_irec
> >+ *
> >+ * Returns 0 on success and non zero on error
> >+ */
> >+int
> >+xfs_attr_get_parent_pointer(struct xfs_inode		*ip,
> >+			    struct xfs_parent_name_irec *xpnir)
> >+{
> >+	struct attrlist			*alist;
> >+	struct attrlist_ent		*aent;
> >+	struct attrlist_cursor_kern     cursor;
> >+	struct xfs_parent_name_rec	*xpnr;
> >+	char				*namebuf;
> >+	int                             error = 0;
> >+	unsigned int                    flags = ATTR_PARENT;
> >+
> >+	/* Allocate a buffer to store the attribute names */
> >+	namebuf = kmem_zalloc_large(XFS_XATTR_LIST_MAX, KM_SLEEP);
> >+	if (!namebuf)
> >+		return -ENOMEM;
> >+
> >+	/* Get all attribute names that have the ATTR_PARENT flag */
> >+	memset(&cursor, 0, sizeof(struct attrlist_cursor_kern));
> >+	error = xfs_attr_list(ip, namebuf, XFS_XATTR_LIST_MAX, flags, &cursor);
> >+	if (error)
> >+		goto out_kfree;
> >+
> >+	alist = (struct attrlist *)namebuf;
> >+
> >+	/* There should never be more than one parent pointer */
> >+	ASSERT(alist->al_count == 1);

/me wonders, does this handle hardlinked files correctly?

> >+	aent = (struct attrlist_ent *) &namebuf[alist->al_offset[0]];
> >+	xpnr = (struct xfs_parent_name_rec *)(aent->a_name);
> >+
> >+	/*
> >+	 * The value of the parent pointer attribute should be the file name
> >+	 * So we check the value length of the attribute entry against the name
> >+	 * length of the parent name record to make sure the caller gave enough
> >+	 * buffer space to store the file name (plus a null terminator)
> >+	 */
> >+	if (aent->a_valuelen >= xpnir->p_namelen) {
> >+		error = -ERANGE;
> >+		goto out_kfree;
> >+	}
> >+
> >+	xpnir->p_namelen = aent->a_valuelen + 1;
> >+	memset((void *)(xpnir->p_name), 0, xpnir->p_namelen);
> >+	error = xfs_attr_get(ip, (char *)xpnr,
> >+			     sizeof(struct xfs_parent_name_rec),
> >+			     (unsigned char *)(xpnir->p_name),
> >+			     (int *)&(xpnir->p_namelen), flags);
> >+	if (error)
> >+		goto out_kfree;
> >+
> >+	xfs_init_parent_name_irec(xpnir, xpnr);
> >+
> >+out_kfree:
> >+	kmem_free(namebuf);
> >+
> >+	return error;
> >+}
> I was thinking of moving this function else where.  It seems to generate a
> lot of compile issues when I apply it to xfsprogs because of the things it
> needs from xfs_attr.h.

note: i forget what this function does exactly. :/

Heh.  Yeah, you might need to split the parent pointer code into
fs/xfs/libxfs/xfs_parent_ptr.c that handles all the internal work and a
fs/xfs/xfs_parent.c that glues the kernel to libxfs, similar to how the
directory code is split up.

IOWs, fs/xfs/libxfs/xfs_parent_ptr.c has routines to set/clear
xfs_parent_irec structures by modifying xattr data as appropriate; and
iterate all the theoretical xfs_parent_irecs based on what's in the
xattr data.

fs/xfs/xfs_parent.c then has all the glue code to connect the iterator
interface to ioctls, etc.

> Generally are patches to code in fs/xfs/libxfs not supposed to be
> including things outside libxfs?

You'd think so, but yesno. :P

In general we'd prefer libxfs to be as self-contained as possible so
that xfsprogs/kernel have exactly the same libxfs code.  OTOH the
practical reality of both libxfs's is that they sometimes need things
that are defined outside of libxfs.

That said, I'll now undercut my own point by noting that libxfs is
really just common code shared between the two codebases that want it.

> Do I need to revise the series to avoid doing that? Thanks!

So it's not a hard and fast rule, just more of a "minimize the libxfs
dependencies on the outer world" thing.

(Those outer world things force Eric to fix them up in whatever
odd way xfsprogs needs because it's userspace.)

--D

> 
> Allison
> >+
> >  /* Retrieve an extended attribute by name, and its value. */
> >  int
> >  xfs_attr_get(
> >diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
> >index b8108f8..2f9ca2c 100644
> >--- a/fs/xfs/libxfs/xfs_fs.h
> >+++ b/fs/xfs/libxfs/xfs_fs.h
> >@@ -512,6 +512,7 @@ typedef struct xfs_swapext
> >  #define XFS_IOC_ZERO_RANGE	_IOW ('X', 57, struct xfs_flock64)
> >  #define XFS_IOC_FREE_EOFBLOCKS	_IOR ('X', 58, struct xfs_fs_eofblocks)
> >  /*	XFS_IOC_GETFSMAP ------ hoisted 59         */
> >+#define XFS_IOC_GETPPOINTER	_IOR ('X', 61, struct xfs_parent_name_irec)
> >  /*
> >   * ioctl commands that replace IRIX syssgi()'s
> >diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
> >index 0829687..0ec3458 100644
> >--- a/fs/xfs/xfs_attr.h
> >+++ b/fs/xfs/xfs_attr.h
> >@@ -172,6 +172,8 @@ int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
> >  		int flags);
> >  int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
> >  		size_t namelen, unsigned char *value, int valuelen, int flags);
> >+int xfs_attr_get_parent_pointer(struct xfs_inode *ip,
> >+				struct xfs_parent_name_irec *xpnir);
> >  int xfs_attr_set_args(struct xfs_da_args *args, int flags, bool roll_trans);
> >  int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
> >  		size_t namelen, int flags);
> >diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
> >index 7740c8a..78fc477 100644
> >--- a/fs/xfs/xfs_attr_list.c
> >+++ b/fs/xfs/xfs_attr_list.c
> >@@ -534,6 +534,9 @@ xfs_attr_put_listent(
> >  	if (((context->flags & ATTR_ROOT) == 0) !=
> >  	    ((flags & XFS_ATTR_ROOT) == 0))
> >  		return;
> >+	if (((context->flags & ATTR_PARENT) == 0) !=
> >+	    ((flags & XFS_ATTR_PARENT) == 0))
> >+		return;
> >  	arraytop = sizeof(*alist) +
> >  			context->count * sizeof(alist->al_offset[0]);
> >diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> >index 4664314..5492607 100644
> >--- a/fs/xfs/xfs_ioctl.c
> >+++ b/fs/xfs/xfs_ioctl.c
> >@@ -44,6 +44,7 @@
> >  #include "xfs_btree.h"
> >  #include <linux/fsmap.h>
> >  #include "xfs_fsmap.h"
> >+#include "xfs_attr.h"
> >  #include <linux/capability.h>
> >  #include <linux/cred.h>
> >@@ -1710,6 +1711,50 @@ xfs_ioc_getfsmap(
> >  	return 0;
> >  }
> >+/*
> >+ * IOCTL routine to get the parent pointer of an inode and return it to user
> >+ * space.  Caller must pass an struct xfs_parent_name_irec with a name buffer
> >+ * large enough to hold the file name.  Returns 0 on success or non-zero on
> >+ * failure
> >+ */
> >+STATIC int
> >+xfs_ioc_get_parent_pointer(
> >+	struct file			*filp,
> >+	void				__user *arg)
> >+{
> >+	struct inode			*inode = file_inode(filp);
> >+	struct xfs_inode		*ip = XFS_I(inode);
> >+	struct xfs_parent_name_irec	xpnir;
> >+	char				*uname;
> >+	char				*kname;
> >+	int				error = 0;
> >+
> >+	copy_from_user(&xpnir, arg, sizeof(struct xfs_parent_name_irec));
> >+	uname = (char *)xpnir.p_name;
> >+
> >+	/*
> >+	 * Use kernel space memory to get the parent pointer name.
> >+	 * We'll copy it to the user space name back when we're done
> >+	 */
> >+	kname = kmem_zalloc_large(xpnir.p_namelen, KM_SLEEP);
> >+	if (!kname)
> >+		return -ENOMEM;
> >+
> >+	xpnir.p_name = kname;
> >+	error = xfs_attr_get_parent_pointer(ip, &xpnir);
> >+
> >+	if (error)
> >+		goto out;
> >+
> >+	copy_to_user(uname, xpnir.p_name, xpnir.p_namelen);
> >+	xpnir.p_name = uname;
> >+	copy_to_user(arg, &xpnir, sizeof(struct xfs_parent_name_irec));
> >+
> >+out:
> >+	kmem_free(kname);
> >+	return error;
> >+}
> >+
> >  int
> >  xfs_ioc_swapext(
> >  	xfs_swapext_t	*sxp)
> >@@ -1866,7 +1911,8 @@ xfs_file_ioctl(
> >  		return xfs_ioc_getxflags(ip, arg);
> >  	case XFS_IOC_SETXFLAGS:
> >  		return xfs_ioc_setxflags(ip, filp, arg);
> >-
> >+	case XFS_IOC_GETPPOINTER:
> >+		return xfs_ioc_get_parent_pointer(filp, arg);
> >  	case XFS_IOC_FSSETDM: {
> >  		struct fsdmidata	dmi;
> 
> --
> 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] 69+ messages in thread

* Re: [PATCH v3 17/17] Add parent pointer ioctl
  2017-11-22 21:07     ` Dave Chinner
@ 2017-11-22 22:49       ` Allison Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-22 22:49 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On 11/22/2017 02:07 PM, Dave Chinner wrote:

> On Wed, Nov 22, 2017 at 12:54:45PM -0700, Allison Henderson wrote:
>> On 11/17/2017 11:21 AM, Allison Henderson wrote:
>>
>>> 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>
>>> ---
>>>   fs/xfs/libxfs/xfs_attr.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>   fs/xfs/libxfs/xfs_fs.h   |  1 +
>>>   fs/xfs/xfs_attr.h        |  2 ++
>>>   fs/xfs/xfs_attr_list.c   |  3 +++
>>>   fs/xfs/xfs_ioctl.c       | 48 +++++++++++++++++++++++++++++++++-
>>>   5 files changed, 120 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>> index 9d4d883..d2be842 100644
>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>> @@ -134,6 +134,73 @@ xfs_attr_get_ilocked(
>>>   		return xfs_attr_node_get(args);
>>>   }
>>> +/*
>>> + * Get the parent pointer for a given inode
>>> + * Caller will need to allocate a buffer pointed to by xpnir->p_name
>>> + * and store the buffer size in xpnir->p_namelen.  The parent
>>> + * pointer will be stored in the given xfs_parent_name_irec
>>> + *
>>> + * Returns 0 on success and non zero on error
>>> + */
>>> +int
>>> +xfs_attr_get_parent_pointer(struct xfs_inode		*ip,
>>> +			    struct xfs_parent_name_irec *xpnir)
>>> +{
>>> +	struct attrlist			*alist;
>>> +	struct attrlist_ent		*aent;
>>> +	struct attrlist_cursor_kern     cursor;
>>> +	struct xfs_parent_name_rec	*xpnr;
>>> +	char				*namebuf;
>>> +	int                             error = 0;
>>> +	unsigned int                    flags = ATTR_PARENT;
>>> +
>>> +	/* Allocate a buffer to store the attribute names */
>>> +	namebuf = kmem_zalloc_large(XFS_XATTR_LIST_MAX, KM_SLEEP);
>>> +	if (!namebuf)
>>> +		return -ENOMEM;
>>> +
>>> +	/* Get all attribute names that have the ATTR_PARENT flag */
>>> +	memset(&cursor, 0, sizeof(struct attrlist_cursor_kern));
>>> +	error = xfs_attr_list(ip, namebuf, XFS_XATTR_LIST_MAX, flags, &cursor);
>>> +	if (error)
>>> +		goto out_kfree;
>>> +
>>> +	alist = (struct attrlist *)namebuf;
>>> +
>>> +	/* There should never be more than one parent pointer */
>>> +	ASSERT(alist->al_count == 1);
>>> +
>>> +	aent = (struct attrlist_ent *) &namebuf[alist->al_offset[0]];
>>> +	xpnr = (struct xfs_parent_name_rec *)(aent->a_name);
>>> +
>>> +	/*
>>> +	 * The value of the parent pointer attribute should be the file name
>>> +	 * So we check the value length of the attribute entry against the name
>>> +	 * length of the parent name record to make sure the caller gave enough
>>> +	 * buffer space to store the file name (plus a null terminator)
>>> +	 */
>>> +	if (aent->a_valuelen >= xpnir->p_namelen) {
>>> +		error = -ERANGE;
>>> +		goto out_kfree;
>>> +	}
>>> +
>>> +	xpnir->p_namelen = aent->a_valuelen + 1;
>>> +	memset((void *)(xpnir->p_name), 0, xpnir->p_namelen);
>>> +	error = xfs_attr_get(ip, (char *)xpnr,
>>> +			     sizeof(struct xfs_parent_name_rec),
>>> +			     (unsigned char *)(xpnir->p_name),
>>> +			     (int *)&(xpnir->p_namelen), flags);
>>> +	if (error)
>>> +		goto out_kfree;
>>> +
>>> +	xfs_init_parent_name_irec(xpnir, xpnr);
>>> +
>>> +out_kfree:
>>> +	kmem_free(namebuf);
>>> +
>>> +	return error;
>>> +}
>> I was thinking of moving this function else where.  It seems to
>> generate a lot of compile issues when I apply it to xfsprogs because
>> of the things it needs from xfs_attr.h.  Generally are patches to
>> code in fs/xfs/libxfs not supposed to be including things outside
>> libxfs?  Do I need to revise the series to avoid doing that? Thanks!
> In general, yes. More complex than that (e.g. userspace and kernel
> have separate definitions of some structures like xfs_mount,
> xfs_buf, etc), but we try to keep the libxfs code as encapsulated as
> possible.
>
> In terms of getting attrs to userspace, the equivalent attribute
> listing code is in fs/xfs/xfs_attr_list.c, and that avoids all these
> problems. I'd just move the xfs_attr_get_parent_pointer() function
> there as ithis code should not be needed in userspace and it would
> avoid all the userspace libxfs compile issues...
>
> Cheers,
>
> Dave.
Alrighty, that seems like a good place for it then.  Thank you!

Allison

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

* Re: [PATCH v3 17/17] Add parent pointer ioctl
  2017-11-22 21:13     ` Darrick J. Wong
@ 2017-11-22 22:49       ` Allison Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-22 22:49 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 11/22/2017 02:13 PM, Darrick J. Wong wrote:

> On Wed, Nov 22, 2017 at 12:54:45PM -0700, Allison Henderson wrote:
>> On 11/17/2017 11:21 AM, Allison Henderson wrote:
>>
>>> 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>
>>> ---
>>>   fs/xfs/libxfs/xfs_attr.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>   fs/xfs/libxfs/xfs_fs.h   |  1 +
>>>   fs/xfs/xfs_attr.h        |  2 ++
>>>   fs/xfs/xfs_attr_list.c   |  3 +++
>>>   fs/xfs/xfs_ioctl.c       | 48 +++++++++++++++++++++++++++++++++-
>>>   5 files changed, 120 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>> index 9d4d883..d2be842 100644
>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>> @@ -134,6 +134,73 @@ xfs_attr_get_ilocked(
>>>   		return xfs_attr_node_get(args);
>>>   }
>>> +/*
>>> + * Get the parent pointer for a given inode
>>> + * Caller will need to allocate a buffer pointed to by xpnir->p_name
>>> + * and store the buffer size in xpnir->p_namelen.  The parent
>>> + * pointer will be stored in the given xfs_parent_name_irec
>>> + *
>>> + * Returns 0 on success and non zero on error
>>> + */
>>> +int
>>> +xfs_attr_get_parent_pointer(struct xfs_inode		*ip,
>>> +			    struct xfs_parent_name_irec *xpnir)
>>> +{
>>> +	struct attrlist			*alist;
>>> +	struct attrlist_ent		*aent;
>>> +	struct attrlist_cursor_kern     cursor;
>>> +	struct xfs_parent_name_rec	*xpnr;
>>> +	char				*namebuf;
>>> +	int                             error = 0;
>>> +	unsigned int                    flags = ATTR_PARENT;
>>> +
>>> +	/* Allocate a buffer to store the attribute names */
>>> +	namebuf = kmem_zalloc_large(XFS_XATTR_LIST_MAX, KM_SLEEP);
>>> +	if (!namebuf)
>>> +		return -ENOMEM;
>>> +
>>> +	/* Get all attribute names that have the ATTR_PARENT flag */
>>> +	memset(&cursor, 0, sizeof(struct attrlist_cursor_kern));
>>> +	error = xfs_attr_list(ip, namebuf, XFS_XATTR_LIST_MAX, flags, &cursor);
>>> +	if (error)
>>> +		goto out_kfree;
>>> +
>>> +	alist = (struct attrlist *)namebuf;
>>> +
>>> +	/* There should never be more than one parent pointer */
>>> +	ASSERT(alist->al_count == 1);
> /me wonders, does this handle hardlinked files correctly?
Good question, I will try it out and maybe revise this area a bit. Maybe 
we need to be returning more than one parent pointer
>
>>> +	aent = (struct attrlist_ent *) &namebuf[alist->al_offset[0]];
>>> +	xpnr = (struct xfs_parent_name_rec *)(aent->a_name);
>>> +
>>> +	/*
>>> +	 * The value of the parent pointer attribute should be the file name
>>> +	 * So we check the value length of the attribute entry against the name
>>> +	 * length of the parent name record to make sure the caller gave enough
>>> +	 * buffer space to store the file name (plus a null terminator)
>>> +	 */
>>> +	if (aent->a_valuelen >= xpnir->p_namelen) {
>>> +		error = -ERANGE;
>>> +		goto out_kfree;
>>> +	}
>>> +
>>> +	xpnir->p_namelen = aent->a_valuelen + 1;
>>> +	memset((void *)(xpnir->p_name), 0, xpnir->p_namelen);
>>> +	error = xfs_attr_get(ip, (char *)xpnr,
>>> +			     sizeof(struct xfs_parent_name_rec),
>>> +			     (unsigned char *)(xpnir->p_name),
>>> +			     (int *)&(xpnir->p_namelen), flags);
>>> +	if (error)
>>> +		goto out_kfree;
>>> +
>>> +	xfs_init_parent_name_irec(xpnir, xpnr);
>>> +
>>> +out_kfree:
>>> +	kmem_free(namebuf);
>>> +
>>> +	return error;
>>> +}
>> I was thinking of moving this function else where.  It seems to generate a
>> lot of compile issues when I apply it to xfsprogs because of the things it
>> needs from xfs_attr.h.
> note: i forget what this function does exactly. :/
It just picks out the name tuple from the parent pointer attribute and 
and uses it to look up the attribute value (the file name).  All that 
gets stored in the xfs_parent_name_irec that the callers passes in.
>
> Heh.  Yeah, you might need to split the parent pointer code into
> fs/xfs/libxfs/xfs_parent_ptr.c that handles all the internal work and a
> fs/xfs/xfs_parent.c that glues the kernel to libxfs, similar to how the
> directory code is split up.
>
> IOWs, fs/xfs/libxfs/xfs_parent_ptr.c has routines to set/clear
> xfs_parent_irec structures by modifying xattr data as appropriate; and
> iterate all the theoretical xfs_parent_irecs based on what's in the
> xattr data.
>
> fs/xfs/xfs_parent.c then has all the glue code to connect the iterator
> interface to ioctls, etc.
Yeah, I may need to revisit some of that as I go about putting together 
what I need for new xfstests then
>> Generally are patches to code in fs/xfs/libxfs not supposed to be
>> including things outside libxfs?
> You'd think so, but yesno. :P
>
> In general we'd prefer libxfs to be as self-contained as possible so
> that xfsprogs/kernel have exactly the same libxfs code.  OTOH the
> practical reality of both libxfs's is that they sometimes need things
> that are defined outside of libxfs.
>
> That said, I'll now undercut my own point by noting that libxfs is
> really just common code shared between the two codebases that want it.
>
>> Do I need to revise the series to avoid doing that? Thanks!
> So it's not a hard and fast rule, just more of a "minimize the libxfs
> dependencies on the outer world" thing.
>
> (Those outer world things force Eric to fix them up in whatever
> odd way xfsprogs needs because it's userspace.)
>
> --D
Alrighty, I'll try to keep everything as much as possible.  Thanks all!

Allison

>> Allison
>>> +
>>>   /* Retrieve an extended attribute by name, and its value. */
>>>   int
>>>   xfs_attr_get(
>>> diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
>>> index b8108f8..2f9ca2c 100644
>>> --- a/fs/xfs/libxfs/xfs_fs.h
>>> +++ b/fs/xfs/libxfs/xfs_fs.h
>>> @@ -512,6 +512,7 @@ typedef struct xfs_swapext
>>>   #define XFS_IOC_ZERO_RANGE	_IOW ('X', 57, struct xfs_flock64)
>>>   #define XFS_IOC_FREE_EOFBLOCKS	_IOR ('X', 58, struct xfs_fs_eofblocks)
>>>   /*	XFS_IOC_GETFSMAP ------ hoisted 59         */
>>> +#define XFS_IOC_GETPPOINTER	_IOR ('X', 61, struct xfs_parent_name_irec)
>>>   /*
>>>    * ioctl commands that replace IRIX syssgi()'s
>>> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
>>> index 0829687..0ec3458 100644
>>> --- a/fs/xfs/xfs_attr.h
>>> +++ b/fs/xfs/xfs_attr.h
>>> @@ -172,6 +172,8 @@ int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
>>>   		int flags);
>>>   int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
>>>   		size_t namelen, unsigned char *value, int valuelen, int flags);
>>> +int xfs_attr_get_parent_pointer(struct xfs_inode *ip,
>>> +				struct xfs_parent_name_irec *xpnir);
>>>   int xfs_attr_set_args(struct xfs_da_args *args, int flags, bool roll_trans);
>>>   int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
>>>   		size_t namelen, int flags);
>>> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
>>> index 7740c8a..78fc477 100644
>>> --- a/fs/xfs/xfs_attr_list.c
>>> +++ b/fs/xfs/xfs_attr_list.c
>>> @@ -534,6 +534,9 @@ xfs_attr_put_listent(
>>>   	if (((context->flags & ATTR_ROOT) == 0) !=
>>>   	    ((flags & XFS_ATTR_ROOT) == 0))
>>>   		return;
>>> +	if (((context->flags & ATTR_PARENT) == 0) !=
>>> +	    ((flags & XFS_ATTR_PARENT) == 0))
>>> +		return;
>>>   	arraytop = sizeof(*alist) +
>>>   			context->count * sizeof(alist->al_offset[0]);
>>> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
>>> index 4664314..5492607 100644
>>> --- a/fs/xfs/xfs_ioctl.c
>>> +++ b/fs/xfs/xfs_ioctl.c
>>> @@ -44,6 +44,7 @@
>>>   #include "xfs_btree.h"
>>>   #include <linux/fsmap.h>
>>>   #include "xfs_fsmap.h"
>>> +#include "xfs_attr.h"
>>>   #include <linux/capability.h>
>>>   #include <linux/cred.h>
>>> @@ -1710,6 +1711,50 @@ xfs_ioc_getfsmap(
>>>   	return 0;
>>>   }
>>> +/*
>>> + * IOCTL routine to get the parent pointer of an inode and return it to user
>>> + * space.  Caller must pass an struct xfs_parent_name_irec with a name buffer
>>> + * large enough to hold the file name.  Returns 0 on success or non-zero on
>>> + * failure
>>> + */
>>> +STATIC int
>>> +xfs_ioc_get_parent_pointer(
>>> +	struct file			*filp,
>>> +	void				__user *arg)
>>> +{
>>> +	struct inode			*inode = file_inode(filp);
>>> +	struct xfs_inode		*ip = XFS_I(inode);
>>> +	struct xfs_parent_name_irec	xpnir;
>>> +	char				*uname;
>>> +	char				*kname;
>>> +	int				error = 0;
>>> +
>>> +	copy_from_user(&xpnir, arg, sizeof(struct xfs_parent_name_irec));
>>> +	uname = (char *)xpnir.p_name;
>>> +
>>> +	/*
>>> +	 * Use kernel space memory to get the parent pointer name.
>>> +	 * We'll copy it to the user space name back when we're done
>>> +	 */
>>> +	kname = kmem_zalloc_large(xpnir.p_namelen, KM_SLEEP);
>>> +	if (!kname)
>>> +		return -ENOMEM;
>>> +
>>> +	xpnir.p_name = kname;
>>> +	error = xfs_attr_get_parent_pointer(ip, &xpnir);
>>> +
>>> +	if (error)
>>> +		goto out;
>>> +
>>> +	copy_to_user(uname, xpnir.p_name, xpnir.p_namelen);
>>> +	xpnir.p_name = uname;
>>> +	copy_to_user(arg, &xpnir, sizeof(struct xfs_parent_name_irec));
>>> +
>>> +out:
>>> +	kmem_free(kname);
>>> +	return error;
>>> +}
>>> +
>>>   int
>>>   xfs_ioc_swapext(
>>>   	xfs_swapext_t	*sxp)
>>> @@ -1866,7 +1911,8 @@ xfs_file_ioctl(
>>>   		return xfs_ioc_getxflags(ip, arg);
>>>   	case XFS_IOC_SETXFLAGS:
>>>   		return xfs_ioc_setxflags(ip, filp, arg);
>>> -
>>> +	case XFS_IOC_GETPPOINTER:
>>> +		return xfs_ioc_get_parent_pointer(filp, arg);
>>>   	case XFS_IOC_FSSETDM: {
>>>   		struct fsdmidata	dmi;
>> --
>> 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=DwIDAw&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=G7N7y48j4ogYpf2u666QU1bTWEMPTiSyJA2qT5hBpkQ&s=OJkTAOSkzCECkmU6FhK-vc77mLJpqb65wuKPpdpCGSA&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=DwIDAw&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=G7N7y48j4ogYpf2u666QU1bTWEMPTiSyJA2qT5hBpkQ&s=OJkTAOSkzCECkmU6FhK-vc77mLJpqb65wuKPpdpCGSA&e=


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

* Re: [PATCH v3 16/17] Add the parent pointer support to the superblock version 5.
  2017-11-17 18:21 ` [PATCH v3 16/17] Add the parent pointer support to the superblock version 5 Allison Henderson
@ 2017-11-28 18:08   ` Darrick J. Wong
  2017-11-29 18:41     ` Allison Henderson
  0 siblings, 1 reply; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 18:08 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs, Mark Tinguely, Dave Chinner

On Fri, Nov 17, 2017 at 11:21:44AM -0700, Allison Henderson wrote:
> [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>
> ---
> v2: remove unrelated type clean up in xfs_format.h
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_format.h | 7 +++++--
>  fs/xfs/libxfs/xfs_fs.h     | 1 +
>  fs/xfs/xfs_fsops.c         | 4 +++-
>  fs/xfs/xfs_super.c         | 4 ++++
>  4 files changed, 13 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index 121862a..f3e3132 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -459,10 +459,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 */

Please make this line up, i.e.

#define XFS_SB_FEAT_RO_COMPAT_PARENT<three spaces>(1 << 3)<two tabs>/* parent inode ptr */

With that fixed,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

--D

>  #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(
> @@ -558,7 +560,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/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
> index 8c61f21..b8108f8 100644
> --- a/fs/xfs/libxfs/xfs_fs.h
> +++ b/fs/xfs/libxfs/xfs_fs.h
> @@ -222,6 +222,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/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
> index 8f22fc5..9a0ce52 100644
> --- a/fs/xfs/xfs_fsops.c
> +++ b/fs/xfs/xfs_fsops.c
> @@ -111,7 +111,9 @@ xfs_fs_geometry(
>  			(xfs_sb_version_hasrmapbt(&mp->m_sb) ?
>  				XFS_FSOP_GEOM_FLAGS_RMAPBT : 0) |
>  			(xfs_sb_version_hasreflink(&mp->m_sb) ?
> -				XFS_FSOP_GEOM_FLAGS_REFLINK : 0);
> +				XFS_FSOP_GEOM_FLAGS_REFLINK : 0) |
> +			(xfs_sb_version_hasparent(&mp->m_sb) ?
> +				XFS_FSOP_GEOM_FLAGS_PARENT : 0);
>  		geo->logsectsize = xfs_sb_version_hassector(&mp->m_sb) ?
>  				mp->m_sb.sb_logsectsize : BBSIZE;
>  		geo->rtsectsize = mp->m_sb.sb_blocksize;
> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> index ee68459..066266f 100644
> --- a/fs/xfs/xfs_super.c
> +++ b/fs/xfs/xfs_super.c
> @@ -1675,6 +1675,10 @@ xfs_fs_fill_super(
>  	"EXPERIMENTAL reverse mapping btree feature enabled. Use at your own risk!");
>  	}
>  
> +	if (xfs_sb_version_hasparent(&mp->m_sb))
> +		xfs_alert(mp,
> +	"EXPERIMENTAL parent pointer feature enabled. Use at your own risk!");
> +
>  	if (xfs_sb_version_hasreflink(&mp->m_sb))
>  		xfs_alert(mp,
>  	"EXPERIMENTAL reflink feature enabled. Use at your own risk!");
> -- 
> 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] 69+ messages in thread

* Re: [PATCH v3 15/17] Add parent pointers to rename
  2017-11-17 18:21 ` [PATCH v3 15/17] Add parent pointers to rename Allison Henderson
@ 2017-11-28 18:20   ` Darrick J. Wong
  2017-11-29 18:43     ` Allison Henderson
  0 siblings, 1 reply; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 18:20 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

On Fri, Nov 17, 2017 at 11:21:43AM -0700, Allison Henderson wrote:
> This patch removes the old parent pointer attribute during the
> rename operation, and re-adds the updated parent pointer
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_dir2.c |  6 ++++--
>  fs/xfs/xfs_inode.c       | 26 ++++++++++++++++++++------
>  2 files changed, 24 insertions(+), 8 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
> index 25b370b..ed25203 100644
> --- a/fs/xfs/libxfs/xfs_dir2.c
> +++ b/fs/xfs/libxfs/xfs_dir2.c
> @@ -324,10 +324,11 @@ xfs_dir_createname(
>  	else
>  		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;
> -out_free:
> +
>  	kmem_free(args);
>  	return rval;
>  }
> @@ -496,9 +497,10 @@ xfs_dir_removename(
>  		rval = xfs_dir2_leaf_removename(args);
>  	else
>  		rval = xfs_dir2_node_removename(args);
> +out_free:
>  	if (offset)
>  		*offset = args->offset;
> -out_free:
> +

Why do these labels need to be moved here?  The *offset = ... lines are
new, so why not put them in their final place in the patch that adds
those lines?

>  	kmem_free(args);
>  	return rval;
>  }
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index a289a40..da5c761 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -2984,6 +2984,8 @@ xfs_rename(
>  	bool			src_is_directory = S_ISDIR(VFS_I(src_ip)->i_mode);
>  	int			spaceres;
>  	int			error;
> +	xfs_dir2_dataptr_t	new_diroffset;
> +	xfs_dir2_dataptr_t	old_diroffset;
>  
>  	trace_xfs_rename(src_dp, target_dp, src_name, target_name);
>  
> @@ -3086,13 +3088,12 @@ xfs_rename(
>  		 */
>  		error = xfs_dir_createname(tp, target_dp, target_name,
>  					   src_ip->i_ino, &first_block, &dfops,
> -					   spaceres, NULL);
> +					   spaceres, &new_diroffset);
>  		if (error)
>  			goto out_bmap_cancel;
>  
>  		xfs_trans_ichgtime(tp, target_dp,
>  					XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
> -

Huh?

>  		if (new_parent && src_is_directory) {
>  			error = xfs_bumplink(tp, target_dp);
>  			if (error)
> @@ -3126,7 +3127,7 @@ xfs_rename(
>  		 */
>  		error = xfs_dir_replace(tp, target_dp, target_name,
>  					src_ip->i_ino, &first_block, &dfops,
> -					spaceres, NULL);
> +					spaceres, &new_diroffset);
>  		if (error)
>  			goto out_bmap_cancel;
>  
> @@ -3161,7 +3162,7 @@ xfs_rename(
>  		 */
>  		error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,
>  					target_dp->i_ino, &first_block, &dfops,
> -					spaceres, NULL);
> +					spaceres, &new_diroffset);
>  		ASSERT(error != -EEXIST);
>  		if (error)
>  			goto out_bmap_cancel;
> @@ -3200,11 +3201,12 @@ xfs_rename(
>  	 */
>  	if (wip) {
>  		error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino,
> -					&first_block, &dfops, spaceres, NULL);
> +					&first_block, &dfops, spaceres,
> +					&old_diroffset);
>  	} else
>  		error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
>  					   &first_block, &dfops, spaceres,
> -					   NULL);
> +					   &old_diroffset);
>  	if (error)
>  		goto out_bmap_cancel;
>  
> @@ -3234,6 +3236,18 @@ xfs_rename(
>  		VFS_I(wip)->i_state &= ~I_LINKABLE;
>  	}
>  
> +	if (new_parent && xfs_sb_version_hasparent(&mp->m_sb)) {

I'm confused about checking new_parent -- does this cause us to forget
to update the pptr for a rename within a directory?

I'm assuming that all of these directory operations will get their own
xfstests in time... (create a file, check pptr; hardlink a file, check
both pptrs; delete one of the links, check pptrs; check pptr after a
rename within a dir; check pptr after a rename between dirs; etc.)

--D

> +		error = xfs_parent_add(tp, target_dp, src_ip, target_name,
> +				       new_diroffset, &dfops, &first_block);
> +		if (error)
> +			goto out_bmap_cancel;
> +
> +		error = xfs_parent_remove(tp, src_dp, src_ip,
> +					  old_diroffset, &dfops, &first_block);
> +		if (error)
> +			goto out_bmap_cancel;
> +	}
> +
>  	xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
>  	xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE);
>  	if (new_parent)
> -- 
> 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] 69+ messages in thread

* Re: [PATCH v3 14/17] xfs: remove parent pointers in unlink
  2017-11-17 18:21 ` [PATCH v3 14/17] xfs: remove parent pointers in unlink Allison Henderson
@ 2017-11-28 18:24   ` Darrick J. Wong
  2017-11-29 18:44     ` Allison Henderson
  0 siblings, 1 reply; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 18:24 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs, Dave Chinner

On Fri, Nov 17, 2017 at 11:21:42AM -0700, Allison Henderson wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> This patch removes the parent pointer attribute during unlink
> 
> [bfoster: rebase, use VFS inode generation]
> [achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t
> 	   implemented xfs_attr_remove_parent]
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_parent.c | 20 ++++++++++++++++++++
>  fs/xfs/xfs_attr.h          |  4 ++++
>  fs/xfs/xfs_inode.c         | 10 +++++++++-
>  3 files changed, 33 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
> index 5eec0ab..9278c89 100644
> --- a/fs/xfs/libxfs/xfs_parent.c
> +++ b/fs/xfs/libxfs/xfs_parent.c
> @@ -91,3 +91,23 @@ xfs_parent_add(
>  		(void *)child_name->name, child_name->len, ATTR_PARENT);
>  }
>  
> +/*
> + * Remove a parent record from a child inode.
> + */
> +int
> +xfs_parent_remove(
> +        struct xfs_trans        *tp,

Unused parameter.

> +        struct xfs_inode        *parent,
> +        struct xfs_inode        *child,
> +        xfs_dir2_dataptr_t      diroffset,
> +	struct xfs_defer_ops    *dfops,

Inconsistent indenting here.

> +	xfs_fsblock_t           *firstblock)

Unused parameter.

> +{
> +	struct xfs_parent_name_rec rec;
> +
> +	xfs_init_parent_name_rec(&rec, parent->i_ino,
> +		VFS_I(parent)->i_generation, diroffset);

Two tabs, please...

> +
> +	return xfs_attr_remove_deferred(child, dfops, &rec, sizeof(rec),
> +					ATTR_PARENT);

...or this indentation style.

> +}
> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
> index 09ef747..0829687 100644
> --- a/fs/xfs/xfs_attr.h
> +++ b/fs/xfs/xfs_attr.h
> @@ -198,4 +198,8 @@ int xfs_parent_add(struct xfs_trans *tp, struct xfs_inode *parent,
>  		struct xfs_inode *child, struct xfs_name *child_name,
>  		xfs_dir2_dataptr_t diroffset, struct xfs_defer_ops *dfops,
>  		xfs_fsblock_t *firstblock);
> +int xfs_parent_remove(struct xfs_trans *tp, struct xfs_inode *parent,
> +		      struct xfs_inode *child, xfs_dir2_dataptr_t diroffset,
> +		      struct xfs_defer_ops *dfops, xfs_fsblock_t *firstblock);
> +
>  #endif	/* __XFS_ATTR_H__ */
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 0ad843d..a289a40 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -2607,6 +2607,7 @@ xfs_remove(
>  	struct xfs_defer_ops	dfops;
>  	xfs_fsblock_t           first_block;
>  	uint			resblks;
> +	uint32_t		dir_offset;

xfs_dir2_dataptr_t	dir_offset; ?

--D

>  
>  	trace_xfs_remove(dp, name);
>  
> @@ -2687,12 +2688,19 @@ xfs_remove(
>  
>  	xfs_defer_init(&dfops, &first_block);
>  	error = xfs_dir_removename(tp, dp, name, ip->i_ino, &first_block,
> -				   &dfops, resblks, NULL);
> +				   &dfops, resblks, &dir_offset);
>  	if (error) {
>  		ASSERT(error != -ENOENT);
>  		goto out_bmap_cancel;
>  	}
>  
> +	if (xfs_sb_version_hasparent(&mp->m_sb)) {
> +		error = xfs_parent_remove(tp, dp, ip, dir_offset, &dfops,
> +					  &first_block);
> +		if (error)
> +			goto out_bmap_cancel;
> +	}
> +
>  	/*
>  	 * If this is a synchronous mount, make sure that the
>  	 * remove transaction goes to disk before returning to
> -- 
> 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] 69+ messages in thread

* Re: [PATCH v3 13/17] xfs: add parent attributes to link
  2017-11-17 18:21 ` [PATCH v3 13/17] xfs: add parent attributes to link Allison Henderson
@ 2017-11-28 18:37   ` Darrick J. Wong
  2017-11-29 18:45     ` Allison Henderson
  0 siblings, 1 reply; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 18:37 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs, Dave Chinner

On Fri, Nov 17, 2017 at 11:21:41AM -0700, Allison Henderson wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> This patch modifies xfs_link to add a parent pointer to the inode.
> xfs_link will also need to create an attribute fork if the inode does
> not already have one.
> 
> [bfoster: rebase, use VFS inode fields, fix xfs_bmap_finish() usage]
> [achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
> 	   fixed null pointer bugs]
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  fs/xfs/xfs_inode.c | 61 +++++++++++++++++++++++++++++++++++++++++-------------
>  1 file changed, 47 insertions(+), 14 deletions(-)
> 
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 1c45c73..0ad843d 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -1451,6 +1451,8 @@ xfs_link(
>  	struct xfs_defer_ops	dfops;
>  	xfs_fsblock_t           first_block;
>  	int			resblks;
> +	uint32_t		diroffset;

xfs_dir2_dataptr_t?

> +	bool			first_parent = false;
>  
>  	trace_xfs_link(tdp, target_name);
>  
> @@ -1467,6 +1469,25 @@ xfs_link(
>  	if (error)
>  		goto std_return;
>  
> +	/*
> +	 * If we have parent pointers and there is no attribute fork (i.e. we
> +	 * are linking in a O_TMPFILE created inode) we need to add the
> +	 * attribute fork to the inode. Because we may have an existing data
> +	 * fork, we do this before we start the link transaction as adding an
> +	 * attribute fork requires it's own transaction.

About that -- does the deferred 'add xattr' operation have an implicit
assumption that the inode in question already has an attribute fork?  I
suppose so long as we're careful to ensure that we never queue up a
deferred op until after we've committed the transaction that adds the
attr fork then that assumption is ok.

(I think the xfs_trans_attr() function needs an ASSERT(xfs_inode_hasattr())
so we can check that assumption.)

> +	 */
> +	if (xfs_sb_version_hasparent(&mp->m_sb) && !xfs_inode_hasattr(sip)) {
> +		int sf_size = sizeof(struct xfs_attr_sf_hdr) +
> +				XFS_ATTR_SF_ENTSIZE_BYNAME(
> +					sizeof(struct xfs_parent_name_rec),
> +					target_name->len);
> +		ASSERT(VFS_I(sip)->i_nlink == 0);
> +		error = xfs_bmap_add_attrfork(sip, sf_size, 0);
> +		if (error)
> +			goto std_return;
> +		first_parent = true;
> +	}
> +
>  	resblks = XFS_LINK_SPACE_RES(mp, target_name->len);
>  	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, resblks, 0, 0, &tp);
>  	if (error == -ENOSPC) {
> @@ -1498,8 +1519,6 @@ xfs_link(
>  			goto error_return;
>  	}
>  
> -	xfs_defer_init(&dfops, &first_block);
> -
>  	/*
>  	 * Handle initial link state of O_TMPFILE inode
>  	 */
> @@ -1509,36 +1528,50 @@ xfs_link(
>  			goto error_return;
>  	}
>  
> +	xfs_defer_init(&dfops, &first_block);
>  	error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
> -				   &first_block, &dfops, resblks, NULL);
> +				   &first_block, &dfops, resblks, &diroffset);
>  	if (error)
> -		goto error_return;
> +		goto out_defer_cancel;

Oh good, you fixed the problem where xfs_defer_cancel doesn't get called
on the error jumpout.

>  	xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
>  	xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
>  
>  	error = xfs_bumplink(tp, sip);
>  	if (error)
> -		goto error_return;
> +		goto out_defer_cancel;
>  
>  	/*
> -	 * If this is a synchronous mount, make sure that the
> -	 * link transaction goes to disk before returning to
> -	 * the user.
> +	 * If we have parent pointers, we now need to add the parent record to
> +	 * the attribute fork of the inode. If this is the initial parent
> +	 * atribute, we need to create it correctly, otherwise we can just add

"attribute"

--D

> +	 * the parent to the inode.
> +	 */
> +	if (xfs_sb_version_hasparent(&mp->m_sb)) {
> +		error = xfs_parent_add(tp, tdp, sip, target_name,
> +				       diroffset, &dfops,
> +				       &first_block);
> +		if (error)
> +			goto out_defer_cancel;
> +	}
> +
> +	/*
> +	 * If this is a synchronous mount, make sure that the link transaction
> +	 * goes to disk before returning to the user.
>  	 */
>  	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
>  		xfs_trans_set_sync(tp);
>  
>  	error = xfs_defer_finish(&tp, &dfops);
> -	if (error) {
> -		xfs_defer_cancel(&dfops);
> -		goto error_return;
> -	}
> +	if (error)
> +		goto out_defer_cancel;
>  
>  	return xfs_trans_commit(tp);
>  
> - error_return:
> +out_defer_cancel:
> +	xfs_defer_cancel(&dfops);
> +error_return:
>  	xfs_trans_cancel(tp);
> - std_return:
> +std_return:
>  	return error;
>  }
>  
> -- 
> 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] 69+ messages in thread

* Re: [PATCH v3 12/17] xfs: parent pointer attribute creation
  2017-11-17 18:21 ` [PATCH v3 12/17] xfs: parent pointer attribute creation Allison Henderson
@ 2017-11-28 18:49   ` Darrick J. Wong
  2017-11-28 18:54     ` Darrick J. Wong
  0 siblings, 1 reply; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 18:49 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs, Dave Chinner

On Fri, Nov 17, 2017 at 11:21:40AM -0700, Allison Henderson wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Add parent pointer attribute during xfs_create, and
> subroutines to initialize attributes
> 
> [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]
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
> v2: remove unnecessary ENOSPC handling in xfs_attr_set_first_parent
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  fs/xfs/Makefile            |  1 +
>  fs/xfs/libxfs/xfs_parent.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++
>  fs/xfs/xfs_attr.h          | 15 +++++++-
>  fs/xfs/xfs_inode.c         | 16 +++++++-
>  4 files changed, 123 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
> index ec6486b..3015bca 100644
> --- a/fs/xfs/Makefile
> +++ b/fs/xfs/Makefile
> @@ -52,6 +52,7 @@ xfs-y				+= $(addprefix libxfs/, \
>  				   xfs_inode_fork.o \
>  				   xfs_inode_buf.o \
>  				   xfs_log_rlimit.o \
> +				   xfs_parent.o \
>  				   xfs_ag_resv.o \
>  				   xfs_rmap.o \
>  				   xfs_rmap_btree.o \
> diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
> new file mode 100644
> index 0000000..5eec0ab
> --- /dev/null
> +++ b/fs/xfs/libxfs/xfs_parent.c
> @@ -0,0 +1,93 @@
> +/*
> + * Copyright (c) 2015 Red Hat, Inc.
> + * All rights reserved.

/me sticks his hand in the hornet's nest: given how much Allison has
reworked the original pptr code to use deferred ops, maybe it's more
appropriate to have both the RH copyright for the original code and the
oracle copyright for the pptr stuff at the top of this file?

(Not a lawyer, don't play one on tv.)

> + *
> + * 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 "xfs_format.h"
> +#include "xfs_log_format.h"
> +#include "xfs_shared.h"
> +#include "xfs_trans_resv.h"
> +#include "xfs_mount.h"
> +#include "xfs_bmap_btree.h"
> +#include "xfs_inode.h"
> +#include "xfs_error.h"
> +#include "xfs_trace.h"
> +#include "xfs_trans.h"
> +#include "xfs_attr.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,
> +			unsigned long long int		p_ino,

xfs_ino_t ?

> +			unsigned int			p_gen,

uint32_t ?

> +			unsigned int			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);
> +}
> +
> +/*
> + * Add a parent record to an inode with existing parent records.
> + */
> +int
> +xfs_parent_add(
> +	struct xfs_trans        *tp,
> +	struct xfs_inode        *parent,
> +	struct xfs_inode        *child,
> +	struct xfs_name         *child_name,
> +	uint32_t                diroffset,
> +	struct xfs_defer_ops    *dfops,
> +	xfs_fsblock_t           *firstblock)

This function doesn't use tp or firstblock, so you can omit the parameters.

> +{
> +	struct xfs_parent_name_rec rec;
> +
> +	xfs_init_parent_name_rec(&rec, parent->i_ino,
> +		VFS_I(parent)->i_generation, diroffset);
> +
> +	return xfs_attr_set_deferred(child, dfops, &rec, sizeof(rec),
> +		(void *)child_name->name, child_name->len, ATTR_PARENT);
> +}

Do you think these functions will be useful for xfs_repair (and
xfs_scrub) to rebuild the parent pointers?  These three functions seem
like the sort of thing that could go into libxfs/xfs_parent.c to get
shared around.

I guess I did babble last week about moving pretty much everything
related to handling the pptr xattrs into libxfs so that the only code in
fs/xfs/xfs_parent.c is the ioctl implementation.  Maybe also an enhanced
"connect this file handle dentry to its parents" feature for file handle
users, though the current system hasn't generated a ton of complaints so
this might be unnecessary.

--D

> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
> index 1f5c711..09ef747 100644
> --- a/fs/xfs/xfs_attr.h
> +++ b/fs/xfs/xfs_attr.h
> @@ -19,6 +19,8 @@
>  #define	__XFS_ATTR_H__
>  
>  #include "libxfs/xfs_defer.h"
> +#include "libxfs/xfs_da_format.h"
> +#include "libxfs/xfs_format.h"
>  
>  struct xfs_inode;
>  struct xfs_da_args;
> @@ -184,5 +186,16 @@ int xfs_attr_set_deferred(struct xfs_inode *dp, struct xfs_defer_ops *dfops,
>  			  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);
> -
> +/*
> + * Parent pointer attribute prototypes
> + */
> +void xfs_init_parent_name_rec(struct xfs_parent_name_rec *rec,
> +		unsigned long long int p_ino, unsigned int p_gen,
> +		unsigned int  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,
> +		xfs_dir2_dataptr_t diroffset, struct xfs_defer_ops *dfops,
> +		xfs_fsblock_t *firstblock);
>  #endif	/* __XFS_ATTR_H__ */
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index f7986d8..1c45c73 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -1164,6 +1164,7 @@ xfs_create(
>  	struct xfs_dquot	*pdqp = NULL;
>  	struct xfs_trans_res	*tres;
>  	uint			resblks;
> +	xfs_dir2_dataptr_t	diroffset;
>  
>  	trace_xfs_create(dp, name);
>  
> @@ -1253,7 +1254,7 @@ xfs_create(
>  	error = xfs_dir_createname(tp, dp, name, ip->i_ino,
>  					&first_block, &dfops, resblks ?
>  					resblks - XFS_IALLOC_SPACE_RES(mp) : 0,
> -					NULL);
> +					&diroffset);
>  	if (error) {
>  		ASSERT(error != -ENOSPC);
>  		goto out_trans_cancel;
> @@ -1272,6 +1273,19 @@ xfs_create(
>  	}
>  
>  	/*
> +	 * If we have parent pointers, we need to add the attribute containing
> +	 * the parent information now. This must be done within the same
> +	 * transaction the directory entry is created, while the new inode
> +	 * contains nothing in the inode literal area.
> +	 */
> +	if (xfs_sb_version_hasparent(&mp->m_sb)) {
> +		error = xfs_parent_add(tp, dp, ip, name, diroffset,
> +					  &dfops, &first_block);
> +		if (error)
> +			goto out_bmap_cancel;
> +	}
> +
> +	/*
>  	 * If this is a synchronous mount, make sure that the
>  	 * create transaction goes to disk before returning to
>  	 * the user.
> -- 
> 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] 69+ messages in thread

* Re: [PATCH v3 11/17] Add the extra space requirements for parent pointer attributes when calculating the minimum log size during mkfs
  2017-11-17 18:21 ` [PATCH v3 11/17] Add the extra space requirements for parent pointer attributes when calculating the minimum log size during mkfs Allison Henderson
@ 2017-11-28 18:51   ` Darrick J. Wong
  2017-11-29 18:47     ` Allison Henderson
  0 siblings, 1 reply; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 18:51 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

On Fri, Nov 17, 2017 at 11:21:39AM -0700, Allison Henderson wrote:
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_log_rlimit.c | 34 ++++++++++++++++++++++++++++++++++
>  1 file changed, 34 insertions(+)
> 
> diff --git a/fs/xfs/libxfs/xfs_log_rlimit.c b/fs/xfs/libxfs/xfs_log_rlimit.c
> index c105979..beec9bf 100644
> --- a/fs/xfs/libxfs/xfs_log_rlimit.c
> +++ b/fs/xfs/libxfs/xfs_log_rlimit.c
> @@ -39,6 +39,40 @@ xfs_log_calc_max_attrsetm_res(
>  {
>  	int			size;
>  	int			nblks;
> +	struct xfs_trans_resv   *resp = M_RES(mp);
> +
> +	/* Calculate extra space needed for parent pointer attributes */
> +	if (!xfs_sb_version_hasparent(&mp->m_sb)) {

if (xfs_sb_version_hasparent()) ?

--D

> +
> +		/* 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;
> +	}
> +
>  
>  	size = xfs_attr_leaf_entsize_local_max(mp->m_attr_geo->blksize) -
>  	       MAXNAMELEN - 1;
> -- 
> 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] 69+ messages in thread

* Re: [PATCH v3 12/17] xfs: parent pointer attribute creation
  2017-11-28 18:49   ` Darrick J. Wong
@ 2017-11-28 18:54     ` Darrick J. Wong
  2017-11-29 18:46       ` Allison Henderson
  0 siblings, 1 reply; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 18:54 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs, Dave Chinner

On Tue, Nov 28, 2017 at 10:49:18AM -0800, Darrick J. Wong wrote:
> On Fri, Nov 17, 2017 at 11:21:40AM -0700, Allison Henderson wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > Add parent pointer attribute during xfs_create, and
> > subroutines to initialize attributes
> > 
> > [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]
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> > ---
> > v2: remove unnecessary ENOSPC handling in xfs_attr_set_first_parent
> > 
> > Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> > ---
> >  fs/xfs/Makefile            |  1 +
> >  fs/xfs/libxfs/xfs_parent.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++
> >  fs/xfs/xfs_attr.h          | 15 +++++++-
> >  fs/xfs/xfs_inode.c         | 16 +++++++-
> >  4 files changed, 123 insertions(+), 2 deletions(-)
> > 
> > diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
> > index ec6486b..3015bca 100644
> > --- a/fs/xfs/Makefile
> > +++ b/fs/xfs/Makefile
> > @@ -52,6 +52,7 @@ xfs-y				+= $(addprefix libxfs/, \
> >  				   xfs_inode_fork.o \
> >  				   xfs_inode_buf.o \
> >  				   xfs_log_rlimit.o \
> > +				   xfs_parent.o \
> >  				   xfs_ag_resv.o \
> >  				   xfs_rmap.o \
> >  				   xfs_rmap_btree.o \
> > diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
> > new file mode 100644
> > index 0000000..5eec0ab
> > --- /dev/null
> > +++ b/fs/xfs/libxfs/xfs_parent.c
> > @@ -0,0 +1,93 @@
> > +/*
> > + * Copyright (c) 2015 Red Hat, Inc.
> > + * All rights reserved.
> 
> /me sticks his hand in the hornet's nest: given how much Allison has
> reworked the original pptr code to use deferred ops, maybe it's more
> appropriate to have both the RH copyright for the original code and the
> oracle copyright for the pptr stuff at the top of this file?
> 
> (Not a lawyer, don't play one on tv.)
> 
> > + *
> > + * 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 "xfs_format.h"
> > +#include "xfs_log_format.h"
> > +#include "xfs_shared.h"
> > +#include "xfs_trans_resv.h"
> > +#include "xfs_mount.h"
> > +#include "xfs_bmap_btree.h"
> > +#include "xfs_inode.h"
> > +#include "xfs_error.h"
> > +#include "xfs_trace.h"
> > +#include "xfs_trans.h"
> > +#include "xfs_attr.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,
> > +			unsigned long long int		p_ino,
> 
> xfs_ino_t ?
> 
> > +			unsigned int			p_gen,
> 
> uint32_t ?
> 
> > +			unsigned int			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);
> > +}
> > +
> > +/*
> > + * Add a parent record to an inode with existing parent records.
> > + */
> > +int
> > +xfs_parent_add(
> > +	struct xfs_trans        *tp,
> > +	struct xfs_inode        *parent,
> > +	struct xfs_inode        *child,
> > +	struct xfs_name         *child_name,
> > +	uint32_t                diroffset,
> > +	struct xfs_defer_ops    *dfops,
> > +	xfs_fsblock_t           *firstblock)
> 
> This function doesn't use tp or firstblock, so you can omit the parameters.
> 
> > +{
> > +	struct xfs_parent_name_rec rec;
> > +
> > +	xfs_init_parent_name_rec(&rec, parent->i_ino,
> > +		VFS_I(parent)->i_generation, diroffset);
> > +
> > +	return xfs_attr_set_deferred(child, dfops, &rec, sizeof(rec),
> > +		(void *)child_name->name, child_name->len, ATTR_PARENT);
> > +}
> 
> Do you think these functions will be useful for xfs_repair (and
> xfs_scrub) to rebuild the parent pointers?  These three functions seem
> like the sort of thing that could go into libxfs/xfs_parent.c to get
> shared around.
> 
> I guess I did babble last week about moving pretty much everything
> related to handling the pptr xattrs into libxfs so that the only code in
> fs/xfs/xfs_parent.c is the ioctl implementation.  Maybe also an enhanced
> "connect this file handle dentry to its parents" feature for file handle
> users, though the current system hasn't generated a ton of complaints so
> this might be unnecessary.

Bah, /me fails to notice that this was added to libxfs/xfs_parent.c.
Please substitute the previous two paragraphs with:

Why are the function prototypes for these functions in fs/xfs/xfs_attr.h?
They ought to be in libxfs/xfs_parent.h.

--D

> --D
> 
> > diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
> > index 1f5c711..09ef747 100644
> > --- a/fs/xfs/xfs_attr.h
> > +++ b/fs/xfs/xfs_attr.h
> > @@ -19,6 +19,8 @@
> >  #define	__XFS_ATTR_H__
> >  
> >  #include "libxfs/xfs_defer.h"
> > +#include "libxfs/xfs_da_format.h"
> > +#include "libxfs/xfs_format.h"
> >  
> >  struct xfs_inode;
> >  struct xfs_da_args;
> > @@ -184,5 +186,16 @@ int xfs_attr_set_deferred(struct xfs_inode *dp, struct xfs_defer_ops *dfops,
> >  			  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);
> > -
> > +/*
> > + * Parent pointer attribute prototypes
> > + */
> > +void xfs_init_parent_name_rec(struct xfs_parent_name_rec *rec,
> > +		unsigned long long int p_ino, unsigned int p_gen,
> > +		unsigned int  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,
> > +		xfs_dir2_dataptr_t diroffset, struct xfs_defer_ops *dfops,
> > +		xfs_fsblock_t *firstblock);
> >  #endif	/* __XFS_ATTR_H__ */
> > diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> > index f7986d8..1c45c73 100644
> > --- a/fs/xfs/xfs_inode.c
> > +++ b/fs/xfs/xfs_inode.c
> > @@ -1164,6 +1164,7 @@ xfs_create(
> >  	struct xfs_dquot	*pdqp = NULL;
> >  	struct xfs_trans_res	*tres;
> >  	uint			resblks;
> > +	xfs_dir2_dataptr_t	diroffset;
> >  
> >  	trace_xfs_create(dp, name);
> >  
> > @@ -1253,7 +1254,7 @@ xfs_create(
> >  	error = xfs_dir_createname(tp, dp, name, ip->i_ino,
> >  					&first_block, &dfops, resblks ?
> >  					resblks - XFS_IALLOC_SPACE_RES(mp) : 0,
> > -					NULL);
> > +					&diroffset);
> >  	if (error) {
> >  		ASSERT(error != -ENOSPC);
> >  		goto out_trans_cancel;
> > @@ -1272,6 +1273,19 @@ xfs_create(
> >  	}
> >  
> >  	/*
> > +	 * If we have parent pointers, we need to add the attribute containing
> > +	 * the parent information now. This must be done within the same
> > +	 * transaction the directory entry is created, while the new inode
> > +	 * contains nothing in the inode literal area.
> > +	 */
> > +	if (xfs_sb_version_hasparent(&mp->m_sb)) {
> > +		error = xfs_parent_add(tp, dp, ip, name, diroffset,
> > +					  &dfops, &first_block);
> > +		if (error)
> > +			goto out_bmap_cancel;
> > +	}
> > +
> > +	/*
> >  	 * If this is a synchronous mount, make sure that the
> >  	 * create transaction goes to disk before returning to
> >  	 * the user.
> > -- 
> > 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] 69+ messages in thread

* Re: [PATCH v3 10/17] xfs: extent transaction reservations for parent attributes
  2017-11-17 18:21 ` [PATCH v3 10/17] xfs: extent transaction reservations for parent attributes Allison Henderson
@ 2017-11-28 18:58   ` Darrick J. Wong
  2017-11-29 18:48     ` Allison Henderson
  0 siblings, 1 reply; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 18:58 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs, Dave Chinner

On Fri, Nov 17, 2017 at 11:21:38AM -0700, Allison Henderson wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> 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>
> ---
>  fs/xfs/libxfs/xfs_format.h     |   5 ++
>  fs/xfs/libxfs/xfs_trans_resv.c | 103 ++++++++++++++++++++++++++++++++---------
>  2 files changed, 85 insertions(+), 23 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index b9ea5bf..121862a 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -556,6 +556,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/fs/xfs/libxfs/xfs_trans_resv.c b/fs/xfs/libxfs/xfs_trans_resv.c
> index 6bd916b..54399e2 100644
> --- a/fs/xfs/libxfs/xfs_trans_resv.c
> +++ b/fs/xfs/libxfs/xfs_trans_resv.c
> @@ -802,29 +802,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;
> @@ -846,15 +847,69 @@ 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;
> +
> +	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;

djwong, clearly reviewing patches in reverse order:

This looks pretty similar to the function in the next patch; can they
be combined into a single helper?

> +}
> +
> +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;
> @@ -886,6 +941,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.
> -- 
> 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] 69+ messages in thread

* Re: [PATCH v3 09/17] xfs: define parent pointer xattr format
  2017-11-17 18:21 ` [PATCH v3 09/17] xfs: define parent pointer xattr format Allison Henderson
@ 2017-11-28 18:59   ` Darrick J. Wong
  2017-11-29 18:48     ` Allison Henderson
  0 siblings, 1 reply; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 18:59 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs, Dave Chinner

On Fri, Nov 17, 2017 at 11:21:37AM -0700, Allison Henderson wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> 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]
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>

Looks ok,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

> ---
> v2: changed p_ino to xfs_ino_t and p_namelen to uint8_t
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_format.h | 27 +++++++++++++++++++++++++++
>  1 file changed, 27 insertions(+)
> 
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index 23229f0..b9ea5bf 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -18,6 +18,8 @@
>  #ifndef __XFS_FORMAT_H__
>  #define __XFS_FORMAT_H__
>  
> +#include "xfs_da_format.h"
> +
>  /*
>   * XFS On Disk Format Definitions
>   *
> @@ -1716,4 +1718,29 @@ struct xfs_acl {
>  #define SGI_ACL_FILE_SIZE	(sizeof(SGI_ACL_FILE)-1)
>  #define SGI_ACL_DEFAULT_SIZE	(sizeof(SGI_ACL_DEFAULT)-1)
>  
> +/*
> + * 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_FORMAT_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] 69+ messages in thread

* Re: [PATCH v3 08/17] xfs: add parent pointer support to attribute code
  2017-11-17 18:21 ` [PATCH v3 08/17] xfs: add parent pointer support to attribute code Allison Henderson
@ 2017-11-28 19:01   ` Darrick J. Wong
  2017-11-29 18:48     ` Allison Henderson
  0 siblings, 1 reply; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 19:01 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs, Mark Tinguely, Dave Chinner

On Fri, Nov 17, 2017 at 11:21:36AM -0700, Allison Henderson wrote:
> From: Mark Tinguely <tinguely@sgi.com>
> 
> 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>
> ---
>  fs/xfs/libxfs/xfs_attr.c      |  2 +-
>  fs/xfs/libxfs/xfs_da_format.h | 12 ++++++++----
>  fs/xfs/xfs_attr.h             |  2 ++
>  3 files changed, 11 insertions(+), 5 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 61e8343..9d4d883 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -408,7 +408,7 @@ xfs_attr_set(
>  	struct xfs_da_args	args;
>  	struct xfs_defer_ops	dfops;
>  	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/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h
> index 3771edc..5f94c84 100644
> --- a/fs/xfs/libxfs/xfs_da_format.h
> +++ b/fs/xfs/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 */

Please fix the indenting to be consistent with the previous line.

Also, I think you can drop the word 'secure' from the comment.

--D

>  #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
> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
> index 10fc466..1f5c711 100644
> --- a/fs/xfs/xfs_attr.h
> +++ b/fs/xfs/xfs_attr.h
> @@ -46,6 +46,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_KERNOTIME	0x1000	/* [kernel] don't update inode timestamps */
>  #define ATTR_KERNOVAL	0x2000	/* [kernel] get attr size only, not value */
> @@ -57,6 +58,7 @@ struct xfs_attr_list_context;
>  	{ ATTR_SECURE,		"SECURE" }, \
>  	{ ATTR_CREATE,		"CREATE" }, \
>  	{ ATTR_REPLACE,		"REPLACE" }, \
> +	{ ATTR_PARENT,		"PARENT" }, \
>  	{ ATTR_KERNOTIME,	"KERNOTIME" }, \
>  	{ ATTR_KERNOVAL,	"KERNOVAL" }
>  
> -- 
> 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] 69+ messages in thread

* Re: [PATCH v3 07/17] xfs: get directory offset when replacing a directory name
  2017-11-17 18:21 ` [PATCH v3 07/17] xfs: get directory offset when replacing a " Allison Henderson
@ 2017-11-28 19:04   ` Darrick J. Wong
  2017-11-29 18:49     ` Allison Henderson
  0 siblings, 1 reply; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 19:04 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs, Mark Tinguely, Dave Chinner

On Fri, Nov 17, 2017 at 11:21:35AM -0700, Allison Henderson wrote:
> From: Mark Tinguely <tinguely@sgi.com>
> 
> 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]
> 
> 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>
> ---
> v2: Changed typedefs to raw struct types
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_dir2.c       | 16 ++++++++++------
>  fs/xfs/libxfs/xfs_dir2.h       |  3 ++-
>  fs/xfs/libxfs/xfs_dir2_block.c |  4 ++--
>  fs/xfs/libxfs/xfs_dir2_leaf.c  |  1 +
>  fs/xfs/libxfs/xfs_dir2_node.c  |  1 +
>  fs/xfs/libxfs/xfs_dir2_sf.c    |  2 ++
>  fs/xfs/xfs_inode.c             | 28 +++++++++++++---------------
>  7 files changed, 31 insertions(+), 24 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
> index b647bf2..25b370b 100644
> --- a/fs/xfs/libxfs/xfs_dir2.c
> +++ b/fs/xfs/libxfs/xfs_dir2.c
> @@ -508,13 +508,14 @@ xfs_dir_removename(
>   */
>  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;
> @@ -563,6 +564,9 @@ xfs_dir_replace(
>  		rval = xfs_dir2_leaf_replace(args);
>  	else
>  		rval = xfs_dir2_node_replace(args);
> +
> +	if (offset)
> +		*offset = args->offset;
>  out_free:

FWIW I complained in the review for a subsequent patch about the out_free
label moving to above the "if (offset)" hunk.

--D

>  	kmem_free(args);
>  	return rval;
> diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
> index e1bd05d..5cc0b3f 100644
> --- a/fs/xfs/libxfs/xfs_dir2.h
> +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
> index 4dbe2fc..69dfe64 100644
> --- a/fs/xfs/libxfs/xfs_dir2_block.c
> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
> @@ -865,9 +865,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/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
> index 197e627..770b93f 100644
> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
> @@ -1518,6 +1518,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/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
> index 13d5244..860a612 100644
> --- a/fs/xfs/libxfs/xfs_dir2_node.c
> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
> @@ -2237,6 +2237,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/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
> index 9e90c22..295458f 100644
> --- a/fs/xfs/libxfs/xfs_dir2_sf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_sf.c
> @@ -1045,6 +1045,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/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 358a98a..f7986d8 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -2774,16 +2774,14 @@ xfs_cross_rename(
>  	int		dp2_flags = 0;
>  
>  	/* Swap inode number for dirent in first parent */
> -	error = xfs_dir_replace(tp, dp1, name1,
> -				ip2->i_ino,
> -				first_block, dfops, spaceres);
> +	error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, first_block, dfops,
> +				spaceres, NULL);
>  	if (error)
>  		goto out_trans_abort;
>  
>  	/* Swap inode number for dirent in second parent */
> -	error = xfs_dir_replace(tp, dp2, name2,
> -				ip1->i_ino,
> -				first_block, dfops, spaceres);
> +	error = xfs_dir_replace(tp, dp2, name2, ip1->i_ino, first_block, dfops,
> +				spaceres, NULL);
>  	if (error)
>  		goto out_trans_abort;
>  
> @@ -2797,8 +2795,8 @@ xfs_cross_rename(
>  
>  		if (S_ISDIR(VFS_I(ip2)->i_mode)) {
>  			error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot,
> -						dp1->i_ino, first_block,
> -						dfops, spaceres);
> +						dp1->i_ino, first_block, dfops,
> +						spaceres, NULL);
>  			if (error)
>  				goto out_trans_abort;
>  
> @@ -2824,8 +2822,8 @@ xfs_cross_rename(
>  
>  		if (S_ISDIR(VFS_I(ip1)->i_mode)) {
>  			error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot,
> -						dp2->i_ino, first_block,
> -						dfops, spaceres);
> +						dp2->i_ino, first_block, dfops,
> +						spaceres, NULL);
>  			if (error)
>  				goto out_trans_abort;
>  
> @@ -3072,8 +3070,8 @@ xfs_rename(
>  		 * name at the destination directory, remove it first.
>  		 */
>  		error = xfs_dir_replace(tp, target_dp, target_name,
> -					src_ip->i_ino,
> -					&first_block, &dfops, spaceres);
> +					src_ip->i_ino, &first_block, &dfops,
> +					spaceres, NULL);
>  		if (error)
>  			goto out_bmap_cancel;
>  
> @@ -3107,8 +3105,8 @@ xfs_rename(
>  		 * directory.
>  		 */
>  		error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,
> -					target_dp->i_ino,
> -					&first_block, &dfops, spaceres);
> +					target_dp->i_ino, &first_block, &dfops,
> +					spaceres, NULL);
>  		ASSERT(error != -EEXIST);
>  		if (error)
>  			goto out_bmap_cancel;
> @@ -3147,7 +3145,7 @@ xfs_rename(
>  	 */
>  	if (wip) {
>  		error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino,
> -					&first_block, &dfops, spaceres);
> +					&first_block, &dfops, spaceres, NULL);
>  	} else
>  		error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
>  					   &first_block, &dfops, spaceres,
> -- 
> 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] 69+ messages in thread

* Re: [PATCH v3 06/17] xfs: get directory offset when removing directory name
  2017-11-17 18:21 ` [PATCH v3 06/17] xfs: get directory offset when removing " Allison Henderson
@ 2017-11-28 19:05   ` Darrick J. Wong
  2017-11-29 18:49     ` Allison Henderson
  0 siblings, 1 reply; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 19:05 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs, Mark Tinguely, Dave Chinner

On Fri, Nov 17, 2017 at 11:21:34AM -0700, Allison Henderson wrote:
> From: Mark Tinguely <tinguely@sgi.com>
> 
> 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]
> 
> 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>
> ---
> v2: Changed typedefs to raw struct types
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_dir2.c       | 15 +++++++++------
>  fs/xfs/libxfs/xfs_dir2.h       |  4 +++-
>  fs/xfs/libxfs/xfs_dir2_block.c |  4 ++--
>  fs/xfs/libxfs/xfs_dir2_leaf.c  |  5 +++--
>  fs/xfs/libxfs/xfs_dir2_node.c  |  5 +++--
>  fs/xfs/libxfs/xfs_dir2_sf.c    |  2 ++
>  fs/xfs/xfs_inode.c             |  7 ++++---
>  7 files changed, 26 insertions(+), 16 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
> index a1ca460..b647bf2 100644
> --- a/fs/xfs/libxfs/xfs_dir2.c
> +++ b/fs/xfs/libxfs/xfs_dir2.c
> @@ -443,13 +443,14 @@ xfs_dir_lookup(
>   */
>  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;
> @@ -495,6 +496,8 @@ xfs_dir_removename(
>  		rval = xfs_dir2_leaf_removename(args);
>  	else
>  		rval = xfs_dir2_node_removename(args);
> +	if (offset)
> +		*offset = args->offset;
>  out_free:

FWIW I complain in a review of a later patch about this label moving
above the "if (offset)".

--D

>  	kmem_free(args);
>  	return rval;
> diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
> index e349900..e1bd05d 100644
> --- a/fs/xfs/libxfs/xfs_dir2.h
> +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
> index 79684d5..4dbe2fc 100644
> --- a/fs/xfs/libxfs/xfs_dir2_block.c
> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
> @@ -791,9 +791,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/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
> index 2ac7a7e..197e627 100644
> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
> @@ -1383,9 +1383,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/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
> index 8bc91f8..13d5244 100644
> --- a/fs/xfs/libxfs/xfs_dir2_node.c
> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
> @@ -1238,9 +1238,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/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
> index 489bdef..9e90c22 100644
> --- a/fs/xfs/libxfs/xfs_dir2_sf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_sf.c
> @@ -919,6 +919,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;
>  		}
>  	}
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 3abcb17..358a98a 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -2639,8 +2639,8 @@ xfs_remove(
>  		goto out_trans_cancel;
>  
>  	xfs_defer_init(&dfops, &first_block);
> -	error = xfs_dir_removename(tp, dp, name, ip->i_ino,
> -					&first_block, &dfops, resblks);
> +	error = xfs_dir_removename(tp, dp, name, ip->i_ino, &first_block,
> +				   &dfops, resblks, NULL);
>  	if (error) {
>  		ASSERT(error != -ENOENT);
>  		goto out_bmap_cancel;
> @@ -3150,7 +3150,8 @@ xfs_rename(
>  					&first_block, &dfops, spaceres);
>  	} else
>  		error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
> -					   &first_block, &dfops, spaceres);
> +					   &first_block, &dfops, spaceres,
> +					   NULL);
>  	if (error)
>  		goto out_bmap_cancel;
>  
> -- 
> 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] 69+ messages in thread

* Re: [PATCH v3 05/17] xfs: get directory offset when adding directory name
  2017-11-17 18:21 ` [PATCH v3 05/17] xfs: get directory offset when adding directory name Allison Henderson
@ 2017-11-28 19:07   ` Darrick J. Wong
  2017-11-29 18:50     ` Allison Henderson
  0 siblings, 1 reply; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 19:07 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs, Mark Tinguely, Dave Chinner

On Fri, Nov 17, 2017 at 11:21:33AM -0700, Allison Henderson wrote:
> From: Mark Tinguely <tinguely@sgi.com>
> 
> 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>
> ---
>  fs/xfs/libxfs/xfs_da_btree.h   | 1 +
>  fs/xfs/libxfs/xfs_dir2.c       | 8 ++++++--
>  fs/xfs/libxfs/xfs_dir2.h       | 3 ++-
>  fs/xfs/libxfs/xfs_dir2_block.c | 1 +
>  fs/xfs/libxfs/xfs_dir2_leaf.c  | 2 ++
>  fs/xfs/libxfs/xfs_dir2_node.c  | 2 ++
>  fs/xfs/libxfs/xfs_dir2_sf.c    | 2 ++
>  fs/xfs/xfs_inode.c             | 9 +++++----
>  fs/xfs/xfs_symlink.c           | 2 +-
>  9 files changed, 22 insertions(+), 8 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
> index ae6de17..bce96d6 100644
> --- a/fs/xfs/libxfs/xfs_da_btree.h
> +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
> index ccf9783..a1ca460 100644
> --- a/fs/xfs/libxfs/xfs_dir2.c
> +++ b/fs/xfs/libxfs/xfs_dir2.c
> @@ -268,7 +268,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;
> @@ -323,6 +324,9 @@ xfs_dir_createname(
>  	else
>  		rval = xfs_dir2_node_addname(args);
>  
> +	/* return the location that this entry was place in the parent inode */
> +	if (offset)
> +		*offset = args->offset;
>  out_free:

FWIW I think I complain later about this label moving in a subsequent
patch.... and you'll see this same comment two more times.  Downside of
reviewing in backwards order, I guess.

--D

>  	kmem_free(args);
>  	return rval;
> @@ -570,7 +574,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/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
> index 21c8f8b..e349900 100644
> --- a/fs/xfs/libxfs/xfs_dir2.h
> +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
> index 43c902f..79684d5 100644
> --- a/fs/xfs/libxfs/xfs_dir2_block.c
> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
> @@ -552,6 +552,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/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
> index 27297a6..2ac7a7e 100644
> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
> @@ -863,6 +863,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/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
> index 682e2bf..8bc91f8 100644
> --- a/fs/xfs/libxfs/xfs_dir2_node.c
> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
> @@ -2022,6 +2022,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/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
> index be8b975..489bdef 100644
> --- a/fs/xfs/libxfs/xfs_dir2_sf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_sf.c
> @@ -407,6 +407,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.
> @@ -498,6 +499,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/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 4ec5b7f..3abcb17 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -1252,7 +1252,8 @@ xfs_create(
>  
>  	error = xfs_dir_createname(tp, dp, name, ip->i_ino,
>  					&first_block, &dfops, resblks ?
> -					resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
> +					resblks - XFS_IALLOC_SPACE_RES(mp) : 0,
> +					NULL);
>  	if (error) {
>  		ASSERT(error != -ENOSPC);
>  		goto out_trans_cancel;
> @@ -1495,7 +1496,7 @@ xfs_link(
>  	}
>  
>  	error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
> -					&first_block, &dfops, resblks);
> +				   &first_block, &dfops, resblks, NULL);
>  	if (error)
>  		goto error_return;
>  	xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
> @@ -3031,8 +3032,8 @@ xfs_rename(
>  		 * to account for the ".." reference from the new entry.
>  		 */
>  		error = xfs_dir_createname(tp, target_dp, target_name,
> -						src_ip->i_ino, &first_block,
> -						&dfops, spaceres);
> +					   src_ip->i_ino, &first_block, &dfops,
> +					   spaceres, NULL);
>  		if (error)
>  			goto out_bmap_cancel;
>  
> diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
> index 68d3ca2..fc803ae 100644
> --- a/fs/xfs/xfs_symlink.c
> +++ b/fs/xfs/xfs_symlink.c
> @@ -363,7 +363,7 @@ xfs_symlink(
>  	 * Create the directory entry for the symlink.
>  	 */
>  	error = xfs_dir_createname(tp, dp, link_name, ip->i_ino,
> -					&first_block, &dfops, resblks);
> +				   &first_block, &dfops, resblks, NULL);
>  	if (error)
>  		goto out_bmap_cancel;
>  	xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
> -- 
> 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] 69+ messages in thread

* Re: [PATCH v3 04/17] Remove all strlen calls in all xfs_attr_* functions for attr names.
  2017-11-17 18:21 ` [PATCH v3 04/17] Remove all strlen calls in all xfs_attr_* functions for attr names Allison Henderson
@ 2017-11-28 19:10   ` Darrick J. Wong
  2017-11-29 18:50     ` Allison Henderson
  0 siblings, 1 reply; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 19:10 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

On Fri, Nov 17, 2017 at 11:21:32AM -0700, Allison Henderson wrote:
> 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>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 12 ++++++++----
>  fs/xfs/xfs_acl.c         | 12 +++++++-----
>  fs/xfs/xfs_attr.h        | 10 ++++++----
>  fs/xfs/xfs_ioctl.c       | 13 ++++++++++---
>  fs/xfs/xfs_iops.c        |  6 ++++--
>  fs/xfs/xfs_trans_attr.c  |  2 +-
>  fs/xfs/xfs_xattr.c       | 10 +++++++---
>  7 files changed, 43 insertions(+), 22 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 68dc7e04..61e8343 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -80,6 +80,7 @@ xfs_attr_args_init(
>  	struct xfs_da_args	*args,
>  	struct xfs_inode	*dp,
>  	const unsigned char	*name,
> +	size_t			namelen,
>  	int			flags)
>  {
>  
> @@ -92,7 +93,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 */
>  
> @@ -138,6 +139,7 @@ int
>  xfs_attr_get(
>  	struct xfs_inode	*ip,
>  	const unsigned char	*name,
> +	size_t			namelen,
>  	unsigned char		*value,
>  	int			*valuelenp,
>  	int			flags)
> @@ -151,7 +153,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;
>  
> @@ -397,6 +399,7 @@ int
>  xfs_attr_set(
>  	struct xfs_inode	*dp,
>  	const unsigned char	*name,
> +	size_t			namelen,
>  	unsigned char		*value,
>  	int			valuelen,
>  	int			flags)
> @@ -413,7 +416,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;
>  
> @@ -511,6 +514,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;
> @@ -524,7 +528,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/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
> index 3354140..d7ee630 100644
> --- a/fs/xfs/xfs_acl.c
> +++ b/fs/xfs/xfs_acl.c
> @@ -153,8 +153,8 @@ xfs_get_acl(struct inode *inode, int type)
>  	if (!xfs_acl)
>  		return ERR_PTR(-ENOMEM);
>  
> -	error = xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl,
> -							&len, ATTR_ROOT);
> +	error = xfs_attr_get(ip, ea_name, strlen((const char *)ea_name),

/me wonders if all these strlen calls actually need that cast?

--D

> +			     (unsigned char *)xfs_acl, &len, ATTR_ROOT);
>  	if (error) {
>  		/*
>  		 * If the attribute doesn't exist make sure we have a negative
> @@ -204,15 +204,17 @@ __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
>  		len -= sizeof(struct xfs_acl_entry) *
>  			 (XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count);
>  
> -		error = xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
> -				len, ATTR_ROOT);
> +		error = xfs_attr_set(ip, ea_name, strlen((const char *)ea_name),
> +				     (unsigned char *)xfs_acl, len, ATTR_ROOT);
>  
>  		kmem_free(xfs_acl);
>  	} else {
>  		/*
>  		 * A NULL ACL argument means we want to remove the ACL.
>  		 */
> -		error = xfs_attr_remove(ip, ea_name, ATTR_ROOT);
> +		error = xfs_attr_remove(ip, ea_name,
> +					strlen((const char *)ea_name),
> +					ATTR_ROOT);
>  
>  		/*
>  		 * If the attribute didn't exist to start with that's fine.
> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
> index 8d4762a..10fc466 100644
> --- a/fs/xfs/xfs_attr.h
> +++ b/fs/xfs/xfs_attr.h
> @@ -164,16 +164,18 @@ 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, 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);
>  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,
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index aa75389..4664314 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -448,6 +448,7 @@ xfs_attrmulti_attr_get(
>  {
>  	unsigned char		*kbuf;
>  	int			error = -EFAULT;
> +	size_t			namelen;
>  
>  	if (*len > XFS_XATTR_SIZE_MAX)
>  		return -EINVAL;
> @@ -455,7 +456,9 @@ xfs_attrmulti_attr_get(
>  	if (!kbuf)
>  		return -ENOMEM;
>  
> -	error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags);
> +	namelen = strlen((const char *)name);
> +	error = xfs_attr_get(XFS_I(inode), name, namelen,
> +			     kbuf, (int *)len, flags);
>  	if (error)
>  		goto out_kfree;
>  
> @@ -477,6 +480,7 @@ xfs_attrmulti_attr_set(
>  {
>  	unsigned char		*kbuf;
>  	int			error;
> +	size_t			namelen;
>  
>  	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>  		return -EPERM;
> @@ -487,7 +491,8 @@ xfs_attrmulti_attr_set(
>  	if (IS_ERR(kbuf))
>  		return PTR_ERR(kbuf);
>  
> -	error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags);
> +	namelen = strlen((const char *)name);
> +	error = xfs_attr_set(XFS_I(inode), name, namelen, kbuf, len, flags);
>  	if (!error)
>  		xfs_forget_acl(inode, name, flags);
>  	kfree(kbuf);
> @@ -501,10 +506,12 @@ xfs_attrmulti_attr_remove(
>  	uint32_t		flags)
>  {
>  	int			error;
> +	size_t			namelen;
>  
>  	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>  		return -EPERM;
> -	error = xfs_attr_remove(XFS_I(inode), name, flags);
> +	namelen = strlen((const char *)name);
> +	error = xfs_attr_remove(XFS_I(inode), name, namelen, flags);
>  	if (!error)
>  		xfs_forget_acl(inode, name, flags);
>  	return error;
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index 17081c7..5247bfc 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -70,8 +70,10 @@ xfs_initxattrs(
>  	int			error = 0;
>  
>  	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
> -		error = xfs_attr_set(ip, xattr->name, xattr->value,
> -				      xattr->value_len, ATTR_SECURE);
> +		error = xfs_attr_set(ip, xattr->name,
> +				     strlen((const char *)xattr->name),
> +				     xattr->value, xattr->value_len,
> +				     ATTR_SECURE);
>  		if (error < 0)
>  			break;
>  	}
> diff --git a/fs/xfs/xfs_trans_attr.c b/fs/xfs/xfs_trans_attr.c
> index 7c3290f..da71cce 100644
> --- a/fs/xfs/xfs_trans_attr.c
> +++ b/fs/xfs/xfs_trans_attr.c
> @@ -87,7 +87,7 @@ xfs_trans_attr(
>  
>  	tp->t_flags |= XFS_TRANS_RESERVE;
>  
> -	error = xfs_attr_args_init(&args, ip, name, flags);
> +	error = xfs_attr_args_init(&args, ip, name, name_len, flags);
>  	if (error)
>  		return error;
>  
> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
> index 0594db4..10e58c6 100644
> --- a/fs/xfs/xfs_xattr.c
> +++ b/fs/xfs/xfs_xattr.c
> @@ -38,6 +38,7 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>  	int xflags = handler->flags;
>  	struct xfs_inode *ip = XFS_I(inode);
>  	int error, asize = size;
> +	size_t namelen = strlen((const char *)name);
>  
>  	/* Convert Linux syscall to XFS internal ATTR flags */
>  	if (!size) {
> @@ -45,7 +46,8 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>  		value = NULL;
>  	}
>  
> -	error = xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags);
> +	error = xfs_attr_get(ip, (unsigned char *)name, namelen, value,
> +			     &asize, xflags);
>  	if (error)
>  		return error;
>  	return asize;
> @@ -81,6 +83,7 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>  	int			xflags = handler->flags;
>  	struct xfs_inode	*ip = XFS_I(inode);
>  	int			error;
> +	size_t			namelen = strlen((const char *)name);
>  
>  	/* Convert Linux syscall to XFS internal ATTR flags */
>  	if (flags & XATTR_CREATE)
> @@ -89,8 +92,9 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>  		xflags |= ATTR_REPLACE;
>  
>  	if (!value)
> -		return xfs_attr_remove(ip, (unsigned char *)name, xflags);
> -	error = xfs_attr_set(ip, (unsigned char *)name,
> +		return xfs_attr_remove(ip, (unsigned char *)name,
> +				       namelen, xflags);
> +	error = xfs_attr_set(ip, (unsigned char *)name, namelen,
>  				(void *)value, size, xflags);
>  	if (!error)
>  		xfs_forget_acl(inode, name, xflags);
> -- 
> 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] 69+ messages in thread

* Re: [PATCH v3 03/17] Add xfs_attr_set_defered and xfs_attr_remove_defered
  2017-11-17 18:21 ` [PATCH v3 03/17] Add xfs_attr_set_defered and xfs_attr_remove_defered Allison Henderson
@ 2017-11-28 19:19   ` Darrick J. Wong
  2017-11-29 18:50     ` Allison Henderson
  0 siblings, 1 reply; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 19:19 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

> Subject: [PATCH v3 03/17] Add xfs_attr_set_defered and xfs_attr_remove_defered

"deferred"

On Fri, Nov 17, 2017 at 11:21:31AM -0700, Allison Henderson wrote:
> 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>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++
>  fs/xfs/xfs_attr.h        |  5 ++++
>  2 files changed, 67 insertions(+)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 716df0f..68dc7e04 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -469,6 +469,40 @@ xfs_attr_set(
>  	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;
> +
> +	ASSERT(namelen != 0);
> +	ASSERT(valuelen != 0);

We should stop the fs dead in its tracks here...

if (!namelen || !valuelen) {
	ASSERT(0);
	return -EFSCORRUPTED;
}

> +
> +	new = kmem_alloc(XFS_ATTR_ITEM_SIZEOF(namelen, valuelen),
> +			 KM_SLEEP|KM_NOFS);
> +	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(&new->xattri_name_value[0], name, namelen);
> +	memcpy(&new->xattri_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.
>   * Transitions attribute list from Btree to shortform as necessary.
> @@ -545,6 +579,34 @@ xfs_attr_remove(
>  	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;
> +
> +	ASSERT(namelen != 0);

Same here.

> +
> +	new = kmem_alloc(XFS_ATTR_ITEM_SIZEOF(namelen, 0), KM_SLEEP|KM_NOFS);
> +	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(new->xattri_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/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
> index 3ef3c77..8d4762a 100644
> --- a/fs/xfs/xfs_attr.h
> +++ b/fs/xfs/xfs_attr.h
> @@ -175,5 +175,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);

All of these libxfs functions shouldn't be declared in a non-libxfs header.

--D

>  
>  #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] 69+ messages in thread

* Re: [PATCH v3 02/17] Set up infastructure for deferred attribute operations
  2017-11-17 18:21 ` [PATCH v3 02/17] Set up infastructure for deferred attribute operations Allison Henderson
@ 2017-11-28 19:45   ` Darrick J. Wong
  2017-11-29  1:19     ` Dave Chinner
  2017-11-29 18:51     ` Allison Henderson
  0 siblings, 2 replies; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 19:45 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

On Fri, Nov 17, 2017 at 11:21:30AM -0700, Allison Henderson wrote:
> 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>
> ---
>  fs/xfs/Makefile                |   2 +
>  fs/xfs/libxfs/xfs_attr.c       |   3 +-
>  fs/xfs/libxfs/xfs_defer.h      |   1 +
>  fs/xfs/libxfs/xfs_log_format.h |  37 ++-
>  fs/xfs/libxfs/xfs_types.h      |   1 +
>  fs/xfs/xfs_attr.h              |  22 +-
>  fs/xfs/xfs_attr_item.c         | 513 +++++++++++++++++++++++++++++++++++++++++
>  fs/xfs/xfs_attr_item.h         | 117 ++++++++++
>  fs/xfs/xfs_log_recover.c       | 140 +++++++++++
>  fs/xfs/xfs_super.c             |   1 +
>  fs/xfs/xfs_trans.h             |  13 ++
>  fs/xfs/xfs_trans_attr.c        | 288 +++++++++++++++++++++++
>  12 files changed, 1134 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
> index a6e955b..ec6486b 100644
> --- a/fs/xfs/Makefile
> +++ b/fs/xfs/Makefile
> @@ -106,6 +106,7 @@ xfs-y				+= xfs_log.o \
>  				   xfs_bmap_item.o \
>  				   xfs_buf_item.o \
>  				   xfs_extfree_item.o \
> +				   xfs_attr_item.o \
>  				   xfs_icreate_item.o \
>  				   xfs_inode_item.o \
>  				   xfs_refcount_item.o \
> @@ -115,6 +116,7 @@ xfs-y				+= xfs_log.o \
>  				   xfs_trans_bmap.o \
>  				   xfs_trans_buf.o \
>  				   xfs_trans_extfree.o \
> +				   xfs_trans_attr.o \
>  				   xfs_trans_inode.o \
>  				   xfs_trans_refcount.o \
>  				   xfs_trans_rmap.o \
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index e5f2960..716df0f 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -41,6 +41,7 @@
>  #include "xfs_quota.h"
>  #include "xfs_trans_space.h"
>  #include "xfs_trace.h"
> +#include "xfs_attr_item.h"
>  
>  /*
>   * xfs_attr.c
> @@ -74,7 +75,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,
> diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h
> index d4f046d..ef0f8bf 100644
> --- a/fs/xfs/libxfs/xfs_defer.h
> +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
> index 71de185..cecc27e 100644
> --- a/fs/xfs/libxfs/xfs_log_format.h
> +++ b/fs/xfs/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,28 @@ 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_attr_log_format {
> +	uint64_t	alf_id;		/* attri identifier */
> +	xfs_ino_t       alf_ino;	/* the inode for this attr operation */
> +	uint32_t        alf_op_flags;	/* marks the op as a set or remove */
> +	uint32_t        alf_name_len;	/* attr name length */
> +	uint32_t        alf_value_len;	/* attr value length */
> +	uint32_t        alf_attr_flags;	/* attr flags */
> +	uint16_t	alf_type;	/* attri log item type */
> +	uint16_t	alf_size;	/* size of this item */

Type and size should go first so that the self-identification
information ends up at the same byte offsets as the other log formats.
This makes it much easier to dissect dirty log contents by hand if
things get messy.

> +	uint32_t	alf_pad;	/* pad to 64 bit aligned */
> +};

While we can reuse the attr_log_format for the attr-done log item, we
can also use less space in the log if we condense that to:

struct xfs_attrd_log_format {
	uint16_t	alfd_type;	/* attrd log item type */
	uint16_t	alfd_size;	/* size of this item */
	uint32_t	__pad;
	uint64_t	alfd_alf_id;	/* id of corresponding attri */
};

16 bytes vs. 40.

>  #endif /* __XFS_LOG_FORMAT_H__ */
> diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
> index 0220159..5372063 100644
> --- a/fs/xfs/libxfs/xfs_types.h
> +++ b/fs/xfs/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 */
> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
> index 8542606..3ef3c77 100644
> --- a/fs/xfs/xfs_attr.h
> +++ b/fs/xfs/xfs_attr.h
> @@ -18,6 +18,8 @@
>  #ifndef __XFS_ATTR_H__
>  #define	__XFS_ATTR_H__
>  
> +#include "libxfs/xfs_defer.h"
> +
>  struct xfs_inode;
>  struct xfs_da_args;
>  struct xfs_attr_list_context;
> @@ -87,6 +89,22 @@ 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 name and val */
> +	uint32_t	  xattri_name_len;    /* length of name */
> +	uint32_t	  xattri_flags;       /* attr flags */
> +	struct list_head  xattri_list;
> +	char              xattri_name_value[0];
> +};
> +
> +#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.
>   */
> @@ -154,6 +172,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);
>  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/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
> new file mode 100644
> index 0000000..0ba2a54
> --- /dev/null
> +++ b/fs/xfs/xfs_attr_item.c
> @@ -0,0 +1,513 @@
> +/*
> + * 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.
> + */
> +#include "xfs.h"
> +#include "xfs_fs.h"
> +#include "xfs_format.h"
> +#include "xfs_log_format.h"
> +#include "xfs_trans_resv.h"
> +#include "xfs_bit.h"
> +#include "xfs_mount.h"
> +#include "xfs_trans.h"
> +#include "xfs_trans_priv.h"
> +#include "xfs_buf_item.h"
> +#include "xfs_attr_item.h"
> +#include "xfs_log.h"
> +#include "xfs_btree.h"
> +#include "xfs_rmap.h"
> +#include "xfs_inode.h"
> +#include "xfs_icache.h"
> +
> +static inline struct xfs_attri_log_item *ATTRI_ITEM(struct xfs_log_item *lip)
> +{
> +	return container_of(lip, struct xfs_attri_log_item, item);
> +}
> +
> +void
> +xfs_attri_item_free(
> +	struct xfs_attri_log_item	*attrip)
> +{
> +	kmem_free(attrip->item.li_lv_shadow);
> +	kmem_free(attrip);
> +}
> +
> +/*
> + * This returns the number of iovecs needed to log the given attri item.
> + * We only need 1 iovec for an attri item.  It just logs the attr_log_format
> + * structure.
> + */
> +static inline int
> +xfs_attri_item_sizeof(
> +	struct xfs_attri_log_item *attrip)
> +{
> +	return sizeof(struct xfs_attr_log_format);
> +}
> +
> +STATIC void
> +xfs_attri_item_size(
> +	struct xfs_log_item	*lip,
> +	int			*nvecs,
> +	int			*nbytes)
> +{
> +	struct xfs_attri_log_item       *attrip = ATTRI_ITEM(lip);
> +
> +	*nvecs += 1;
> +	*nbytes += xfs_attri_item_sizeof(attrip);
> +
> +	if (attrip->name_len > 0) {
> +		*nvecs += 1;
> +		nbytes += ATTR_NVEC_SIZE(attrip->name_len);
> +	}
> +
> +	if (attrip->value_len > 0) {
> +		*nvecs += 1;
> +		nbytes += ATTR_NVEC_SIZE(attrip->value_len);
> +	}
> +}
> +
> +/*
> + * This is called to fill in the vector of log iovecs for the
> + * given attri log item. We use only 1 iovec, and we point that
> + * at the attri_log_format structure embedded in the attri item.
> + * It is at this point that we assert that all of the attr
> + * slots in the attri item have been filled.
> + */
> +STATIC void
> +xfs_attri_item_format(
> +	struct xfs_log_item	*lip,
> +	struct xfs_log_vec	*lv)
> +{
> +	struct xfs_attri_log_item	*attrip = ATTRI_ITEM(lip);
> +	struct xfs_log_iovec	*vecp = NULL;
> +
> +	attrip->format.alf_type = XFS_LI_ATTRI;
> +	attrip->format.alf_size = 1;
> +
> +	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRI_FORMAT,
> +			&attrip->format,
> +			xfs_attri_item_sizeof(attrip));
> +	if (attrip->name_len > 0)
> +		xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_NAME,
> +				attrip->name, ATTR_NVEC_SIZE(attrip->name_len));
> +
> +	if (attrip->value_len > 0)
> +		xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_VALUE,
> +				attrip->value,
> +				ATTR_NVEC_SIZE(attrip->value_len));
> +}
> +
> +
> +/*
> + * Pinning has no meaning for an attri item, so just return.
> + */
> +STATIC void
> +xfs_attri_item_pin(
> +	struct xfs_log_item	*lip)
> +{
> +}
> +
> +/*
> + * The unpin operation is the last place an ATTRI is manipulated in the log. It
> + * is either inserted in the AIL or aborted in the event of a log I/O error. In
> + * either case, the ATTRI transaction has been successfully committed to make it
> + * this far. Therefore, we expect whoever committed the ATTRI to either
> + * construct and commit the ATTRD or drop the ATTRD's reference in the event of
> + * error. Simply drop the log's ATTRI reference now that the log is done with
> + * it.
> + */
> +STATIC void
> +xfs_attri_item_unpin(
> +	struct xfs_log_item	*lip,
> +	int			remove)
> +{
> +	struct xfs_attri_log_item	*attrip = ATTRI_ITEM(lip);
> +
> +	xfs_attri_release(attrip);
> +}
> +
> +/*
> + * attri items have no locking or pushing.  However, since ATTRIs are pulled
> + * from the AIL when their corresponding ATTRDs are committed to disk, their
> + * situation is very similar to being pinned.  Return XFS_ITEM_PINNED so that
> + * the caller will eventually flush the log.  This should help in getting the
> + * ATTRI out of the AIL.
> + */
> +STATIC uint
> +xfs_attri_item_push(
> +	struct xfs_log_item	*lip,
> +	struct list_head	*buffer_list)
> +{
> +	return XFS_ITEM_PINNED;
> +}
> +
> +/*
> + * The ATTRI has been either committed or aborted if the transaction has been
> + * cancelled. If the transaction was cancelled, an ATTRD isn't going to be
> + * constructed and thus we free the ATTRI here directly.
> + */
> +STATIC void
> +xfs_attri_item_unlock(
> +	struct xfs_log_item	*lip)
> +{
> +	if (lip->li_flags & XFS_LI_ABORTED)
> +		xfs_attri_item_free(ATTRI_ITEM(lip));
> +}
> +
> +/*
> + * The ATTRI is logged only once and cannot be moved in the log, so simply
> + * return the lsn at which it's been logged.
> + */
> +STATIC xfs_lsn_t
> +xfs_attri_item_committed(
> +	struct xfs_log_item	*lip,
> +	xfs_lsn_t		lsn)
> +{
> +	return lsn;
> +}
> +
> +STATIC void
> +xfs_attri_item_committing(
> +	struct xfs_log_item	*lip,
> +	xfs_lsn_t		lsn)
> +{
> +}
> +
> +/*
> + * This is the ops vector shared by all attri log items.
> + */
> +static const struct xfs_item_ops xfs_attri_item_ops = {
> +	.iop_size	= xfs_attri_item_size,
> +	.iop_format	= xfs_attri_item_format,
> +	.iop_pin	= xfs_attri_item_pin,
> +	.iop_unpin	= xfs_attri_item_unpin,
> +	.iop_unlock	= xfs_attri_item_unlock,
> +	.iop_committed	= xfs_attri_item_committed,
> +	.iop_push	= xfs_attri_item_push,
> +	.iop_committing = xfs_attri_item_committing
> +};
> +
> +
> +/*
> + * Allocate and initialize an attri item
> + */
> +struct xfs_attri_log_item *
> +xfs_attri_init(
> +	struct xfs_mount	*mp)
> +
> +{
> +	struct xfs_attri_log_item	*attrip;
> +	uint			size;
> +
> +	size = (uint)(sizeof(struct xfs_attri_log_item));
> +	attrip = kmem_zalloc(size, KM_SLEEP);
> +
> +	xfs_log_item_init(mp, &(attrip->item), XFS_LI_ATTRI,
> +			  &xfs_attri_item_ops);
> +	attrip->format.alf_id = (uintptr_t)(void *)attrip;
> +	atomic_set(&attrip->refcount, 2);
> +
> +	return attrip;
> +}
> +
> +/*
> + * Copy an attr format buffer from the given buf, and into the destination
> + * attr format structure.
> + */
> +int
> +xfs_attr_copy_format(struct xfs_log_iovec *buf,
> +		      struct xfs_attr_log_format *dst_attr_fmt)
> +{
> +	struct xfs_attr_log_format *src_attr_fmt = buf->i_addr;
> +	uint len = sizeof(struct xfs_attr_log_format);
> +
> +	if (buf->i_len == len) {
> +		memcpy((char *)dst_attr_fmt, (char *)src_attr_fmt, len);
> +		return 0;
> +	}
> +	return -EFSCORRUPTED;
> +}
> +
> +/*
> + * Freeing the attri requires that we remove it from the AIL if it has already
> + * been placed there. However, the ATTRI may not yet have been placed in the
> + * AIL when called by xfs_attri_release() from ATTRD processing due to the
> + * ordering of committed vs unpin operations in bulk insert operations. Hence
> + * the reference count to ensure only the last caller frees the ATTRI.
> + */
> +void
> +xfs_attri_release(
> +	struct xfs_attri_log_item	*attrip)
> +{
> +	ASSERT(atomic_read(&attrip->refcount) > 0);
> +	if (atomic_dec_and_test(&attrip->refcount)) {
> +		xfs_trans_ail_remove(&attrip->item,
> +				     SHUTDOWN_LOG_IO_ERROR);
> +		xfs_attri_item_free(attrip);
> +	}
> +}
> +
> +static inline struct xfs_attrd_log_item *ATTRD_ITEM(struct xfs_log_item *lip)
> +{
> +	return container_of(lip, struct xfs_attrd_log_item, item);
> +}
> +
> +STATIC void
> +xfs_attrd_item_free(struct xfs_attrd_log_item *attrdp)
> +{
> +	kmem_free(attrdp->item.li_lv_shadow);
> +	kmem_free(attrdp);
> +}
> +
> +/*
> + * This returns the number of iovecs needed to log the given attrd item.
> + * We only need 1 iovec for an attrd item.  It just logs the attr_log_format
> + * structure.
> + */
> +static inline int
> +xfs_attrd_item_sizeof(
> +	struct xfs_attrd_log_item *attrdp)
> +{
> +	return sizeof(struct xfs_attr_log_format);
> +}
> +
> +STATIC void
> +xfs_attrd_item_size(
> +	struct xfs_log_item	*lip,
> +	int			*nvecs,
> +	int			*nbytes)
> +{
> +	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
> +	*nvecs += 1;
> +	*nbytes += xfs_attrd_item_sizeof(attrdp);
> +
> +	if (attrdp->name_len > 0) {
> +		*nvecs += 1;
> +		nbytes += attrdp->name_len;
> +	}
> +
> +	if (attrdp->value_len > 0) {
> +		*nvecs += 1;
> +		nbytes += attrdp->value_len;
> +	}
> +}
> +
> +/*
> + * This is called to fill in the vector of log iovecs for the
> + * given attrd log item. We use only 1 iovec, and we point that
> + * at the attr_log_format structure embedded in the attrd item.
> + * It is at this point that we assert that all of the attr
> + * slots in the attrd item have been filled.
> + */
> +STATIC void
> +xfs_attrd_item_format(
> +	struct xfs_log_item	*lip,
> +	struct xfs_log_vec	*lv)
> +{
> +	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
> +	struct xfs_log_iovec	*vecp = NULL;
> +
> +	attrdp->format.alf_type = XFS_LI_ATTRD;
> +	attrdp->format.alf_size = 1;
> +
> +	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRD_FORMAT,
> +			&attrdp->format,
> +			xfs_attrd_item_sizeof(attrdp));
> +}
> +
> +/*
> + * Pinning has no meaning for an attrd item, so just return.
> + */
> +STATIC void
> +xfs_attrd_item_pin(
> +	struct xfs_log_item	*lip)
> +{
> +}
> +
> +/*
> + * Since pinning has no meaning for an attrd item, unpinning does
> + * not either.
> + */
> +STATIC void
> +xfs_attrd_item_unpin(
> +	struct xfs_log_item	*lip,
> +	int			remove)
> +{
> +}
> +
> +/*
> + * There isn't much you can do to push on an attrd item.  It is simply stuck
> + * waiting for the log to be flushed to disk.
> + */
> +STATIC uint
> +xfs_attrd_item_push(
> +	struct xfs_log_item	*lip,
> +	struct list_head	*buffer_list)
> +{
> +	return XFS_ITEM_PINNED;
> +}
> +
> +/*
> + * The ATTRD is either committed or aborted if the transaction is cancelled. If
> + * the transaction is cancelled, drop our reference to the ATTRI and free the
> + * ATTRD.
> + */
> +STATIC void
> +xfs_attrd_item_unlock(
> +	struct xfs_log_item	*lip)
> +{
> +	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
> +
> +	if (lip->li_flags & XFS_LI_ABORTED) {
> +		xfs_attri_release(attrdp->attrip);
> +		xfs_attrd_item_free(attrdp);
> +	}
> +}
> +
> +/*
> + * When the attrd item is committed to disk, all we need to do is delete our
> + * reference to our partner attri item and then free ourselves. Since we're
> + * freeing ourselves we must return -1 to keep the transaction code from
> + * further referencing this item.
> + */
> +STATIC xfs_lsn_t
> +xfs_attrd_item_committed(
> +	struct xfs_log_item	*lip,
> +	xfs_lsn_t		lsn)
> +{
> +	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
> +
> +	/*
> +	 * Drop the ATTRI reference regardless of whether the ATTRD has been
> +	 * aborted. Once the ATTRD transaction is constructed, it is the sole
> +	 * responsibility of the ATTRD to release the ATTRI (even if the ATTRI
> +	 * is aborted due to log I/O error).
> +	 */
> +	xfs_attri_release(attrdp->attrip);
> +	xfs_attrd_item_free(attrdp);
> +
> +	return (xfs_lsn_t)-1;
> +}
> +
> +STATIC void
> +xfs_attrd_item_committing(
> +	struct xfs_log_item	*lip,
> +	xfs_lsn_t		lsn)
> +{
> +}
> +
> +/*
> + * This is the ops vector shared by all attrd log items.
> + */
> +static const struct xfs_item_ops xfs_attrd_item_ops = {
> +	.iop_size	= xfs_attrd_item_size,
> +	.iop_format	= xfs_attrd_item_format,
> +	.iop_pin	= xfs_attrd_item_pin,
> +	.iop_unpin	= xfs_attrd_item_unpin,
> +	.iop_unlock	= xfs_attrd_item_unlock,
> +	.iop_committed	= xfs_attrd_item_committed,
> +	.iop_push	= xfs_attrd_item_push,
> +	.iop_committing = xfs_attrd_item_committing
> +};
> +
> +/*
> + * Allocate and initialize an attrd item
> + */
> +struct xfs_attrd_log_item *
> +xfs_attrd_init(
> +	struct xfs_mount	*mp,
> +	struct xfs_attri_log_item	*attrip)
> +
> +{
> +	struct xfs_attrd_log_item	*attrdp;
> +	uint			size;
> +
> +	size = (uint)(sizeof(struct xfs_attrd_log_item));
> +	attrdp = kmem_zalloc(size, KM_SLEEP);
> +
> +	xfs_log_item_init(mp, &attrdp->item, XFS_LI_ATTRD,
> +			  &xfs_attrd_item_ops);
> +	attrdp->attrip = attrip;
> +	attrdp->format.alf_id = attrip->format.alf_id;
> +
> +	return attrdp;
> +}
> +
> +/*
> + * Process an attr intent item that was recovered from
> + * the log.  We need to delete the attr that it describes.
> + */
> +int
> +xfs_attri_recover(
> +	struct xfs_mount	*mp,
> +	struct xfs_attri_log_item	*attrip)
> +{
> +	struct xfs_inode		*ip;
> +	struct xfs_attrd_log_item	*attrdp;
> +	struct xfs_trans	*tp;
> +	int			error = 0;
> +	struct xfs_attr_log_format	*attrp;
> +
> +	ASSERT(!test_bit(XFS_ATTRI_RECOVERED, &attrip->flags));
> +
> +	/*
> +	 * First check the validity of the attr described by the
> +	 * ATTRI.  If any are bad, then assume that all are bad and
> +	 * just toss the ATTRI.  A valid attr must have a name length,
> +	 * a value length, and either a "set" or "remove" op flag
> +	 */
> +	attrp = &attrip->format;
> +	if (attrp->alf_value_len == 0 ||
> +	    attrp->alf_name_len == 0 ||
> +	    !(attrp->alf_op_flags == XFS_ATTR_OP_FLAGS_SET ||
> +	     attrp->alf_op_flags == XFS_ATTR_OP_FLAGS_REMOVE) ) {
> +		/*
> +		 * This will pull the ATTRI from the AIL and
> +		 * free the memory associated with it.
> +		 */
> +		set_bit(XFS_ATTRI_RECOVERED, &attrip->flags);
> +		xfs_attri_release(attrip);
> +		return -EIO;
> +	}
> +
> +	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
> +	if (error)
> +		return error;
> +	attrdp = xfs_trans_get_attrd(tp, attrip);
> +	attrp = &attrip->format;
> +
> +	error = xfs_iget(mp, tp, attrp->alf_ino, 0, 0, &ip);
> +	if (error)
> +		return error;
> +
> +	error = xfs_trans_attr(tp, attrdp, ip,
> +				attrp->alf_op_flags,
> +				attrp->alf_attr_flags,
> +				attrp->alf_name_len,
> +				attrp->alf_value_len,
> +				attrip->name,
> +				attrip->value);
> +	if (error)
> +		goto abort_error;
> +
> +
> +	set_bit(XFS_ATTRI_RECOVERED, &attrip->flags);
> +	error = xfs_trans_commit(tp);
> +	return error;
> +
> +abort_error:
> +	xfs_trans_cancel(tp);
> +	return error;
> +}
> diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h
> new file mode 100644
> index 0000000..774b56e
> --- /dev/null
> +++ b/fs/xfs/xfs_attr_item.h
> @@ -0,0 +1,117 @@
> +/*
> + * 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_ATTR_ITEM_H__
> +#define	__XFS_ATTR_ITEM_H__
> +
> +/* kernel only ATTRI/ATTRD definitions */
> +
> +struct xfs_mount;
> +struct kmem_zone;
> +
> +/*
> + * Max number of attrs in fast allocation path.
> + */
> +#define XFS_ATTRI_MAX_FAST_ATTRS        1
> +
> +
> +/*
> + * Define ATTR flag bits. Manipulated by set/clear/test_bit operators.
> + */
> +#define	XFS_ATTRI_RECOVERED	1
> +
> +
> +/* nvecs must be in multiples of 4 */
> +#define ATTR_NVEC_SIZE(size) (size == sizeof(int32_t) ? sizeof(int32_t) : \
> +				size + sizeof(int32_t) - \
> +				(size % sizeof(int32_t)))
> +
> +/*
> + * This is the "attr intention" log item.  It is used to log the fact
> + * that some attrs need to be processed.  It is used in conjunction with the
> + * "attr done" log item described below.
> + *
> + * The ATTRI is reference counted so that it is not freed prior to both the
> + * ATTRI and ATTRD being committed and unpinned. This ensures the ATTRI is
> + * inserted into the AIL even in the event of out of order ATTRI/ATTRD
> + * processing. In other words, an ATTRI is born with two references:
> + *
> + *      1.) an ATTRI held reference to track ATTRI AIL insertion
> + *      2.) an ATTRD held reference to track ATTRD commit
> + *
> + * On allocation, both references are the responsibility of the caller. Once
> + * the ATTRI is added to and dirtied in a transaction, ownership of reference
> + * one transfers to the transaction. The reference is dropped once the ATTRI is
> + * inserted to the AIL or in the event of failure along the way (e.g., commit
> + * failure, log I/O error, etc.). Note that the caller remains responsible for
> + * the ATTRD reference under all circumstances to this point. The caller has no
> + * means to detect failure once the transaction is committed, however.
> + * Therefore, an ATTRD is required after this point, even in the event of
> + * unrelated failure.
> + *
> + * Once an ATTRD is allocated and dirtied in a transaction, reference two
> + * transfers to the transaction. The ATTRD reference is dropped once it reaches
> + * the unpin handler. Similar to the ATTRI, the reference also drops in the
> + * event of commit failure or log I/O errors. Note that the ATTRD is not
> + * inserted in the AIL, so at this point both the ATTI and ATTRD are freed.
> + */
> +struct xfs_attri_log_item {
> +	xfs_log_item_t			item;
> +	atomic_t			refcount;
> +	unsigned long			flags;	/* misc flags */
> +	int				name_len;
> +	void				*name;
> +	int				value_len;
> +	void				*value;
> +	struct xfs_attr_log_format	format;
> +};
> +
> +/*
> + * This is the "attr done" log item.  It is used to log
> + * the fact that some attrs earlier mentioned in an attri item
> + * have been freed.
> + */
> +struct xfs_attrd_log_item {
> +	struct xfs_log_item		item;
> +	struct xfs_attri_log_item	*attrip;
> +	uint				next_attr;
> +	int				name_len;
> +	void				*name;
> +	int				value_len;
> +	void				*value;
> +	struct xfs_attr_log_format	format;
> +};
> +
> +/*
> + * Max number of attrs in fast allocation path.
> + */
> +#define	XFS_ATTRD_MAX_FAST_ATTRS	1
> +
> +extern struct kmem_zone	*xfs_attri_zone;
> +extern struct kmem_zone	*xfs_attrd_zone;
> +
> +struct xfs_attri_log_item	*xfs_attri_init(struct xfs_mount *mp);
> +struct xfs_attrd_log_item	*xfs_attrd_init(struct xfs_mount *mp,
> +					struct xfs_attri_log_item *attrip);
> +int xfs_attr_copy_format(struct xfs_log_iovec *buf,
> +			 struct xfs_attr_log_format *dst_attri_fmt);
> +void			xfs_attri_item_free(struct xfs_attri_log_item *attrip);
> +void			xfs_attri_release(struct xfs_attri_log_item *attrip);
> +
> +int			xfs_attri_recover(struct xfs_mount *mp,
> +					struct xfs_attri_log_item *attrip);
> +
> +#endif	/* __XFS_ATTR_ITEM_H__ */
> diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
> index ee34899..fd0e052 100644
> --- a/fs/xfs/xfs_log_recover.c
> +++ b/fs/xfs/xfs_log_recover.c
> @@ -33,6 +33,7 @@
>  #include "xfs_log_recover.h"
>  #include "xfs_inode_item.h"
>  #include "xfs_extfree_item.h"
> +#include "xfs_attr_item.h"
>  #include "xfs_trans_priv.h"
>  #include "xfs_alloc.h"
>  #include "xfs_ialloc.h"
> @@ -1956,6 +1957,8 @@ xlog_recover_reorder_trans(
>  		case XFS_LI_CUD:
>  		case XFS_LI_BUI:
>  		case XFS_LI_BUD:
> +		case XFS_LI_ATTRI:
> +		case XFS_LI_ATTRD:
>  			trace_xfs_log_recover_item_reorder_tail(log,
>  							trans, item, pass);
>  			list_move_tail(&item->ri_list, &inode_list);
> @@ -3489,6 +3492,92 @@ xlog_recover_efd_pass2(
>  	return 0;
>  }
>  
> +STATIC int
> +xlog_recover_attri_pass2(
> +	struct xlog                     *log,
> +	struct xlog_recover_item        *item,
> +	xfs_lsn_t                       lsn)
> +{
> +	int                             error;
> +	struct xfs_mount                *mp = log->l_mp;
> +	struct xfs_attri_log_item       *attrip;
> +	struct xfs_attr_log_format     *attri_formatp;
> +
> +	attri_formatp = item->ri_buf[0].i_addr;
> +
> +	attrip = xfs_attri_init(mp);
> +	error = xfs_attr_copy_format(&item->ri_buf[0], &attrip->format);
> +	if (error) {
> +		xfs_attri_item_free(attrip);
> +		return error;
> +	}
> +
> +	spin_lock(&log->l_ailp->xa_lock);
> +	/*
> +	 * The ATTRI has two references. One for the ATTRD and one for ATTRI to
> +	 * ensure it makes it into the AIL. Insert the ATTRI into the AIL
> +	 * directly and drop the ATTRI reference. Note that
> +	 * xfs_trans_ail_update() drops the AIL lock.
> +	 */
> +	xfs_trans_ail_update(log->l_ailp, &attrip->item, lsn);
> +	xfs_attri_release(attrip);
> +	return 0;
> +}
> +
> +
> +/*
> + * This routine is called when an ATTRD format structure is found in a committed
> + * transaction in the log. Its purpose is to cancel the corresponding ATTRI if
> + * it was still in the log. To do this it searches the AIL for the ATTRI with
> + * an id equal to that in the ATTRD format structure. If we find it we drop
> + * the ATTRD reference, which removes the ATTRI from the AIL and frees it.
> + */
> +STATIC int
> +xlog_recover_attrd_pass2(
> +	struct xlog                     *log,
> +	struct xlog_recover_item        *item)
> +{
> +	struct xfs_attr_log_format    *attrd_formatp;
> +	struct xfs_attri_log_item      *attrip = NULL;
> +	struct xfs_log_item          *lip;
> +	uint64_t                attri_id;
> +	struct xfs_ail_cursor   cur;
> +	struct xfs_ail          *ailp = log->l_ailp;

Whoah, what happened to the indenting here?

> +
> +	attrd_formatp = item->ri_buf[0].i_addr;
> +	ASSERT((item->ri_buf[0].i_len ==
> +				(sizeof(struct xfs_attr_log_format))));
> +	attri_id = attrd_formatp->alf_id;
> +
> +	/*
> +	 * Search for the ATTRI with the id in the ATTRD format structure in the
> +	 * AIL.
> +	 */
> +	spin_lock(&ailp->xa_lock);
> +	lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
> +	while (lip != NULL) {
> +		if (lip->li_type == XFS_LI_ATTRI) {
> +			attrip = (struct xfs_attri_log_item *)lip;
> +			if (attrip->format.alf_id == attri_id) {
> +				/*
> +				 * Drop the ATTRD reference to the ATTRI. This
> +				 * removes the ATTRI from the AIL and frees it.
> +				 */
> +				spin_unlock(&ailp->xa_lock);
> +				xfs_attri_release(attrip);
> +				spin_lock(&ailp->xa_lock);
> +				break;
> +			}
> +		}
> +		lip = xfs_trans_ail_cursor_next(ailp, &cur);
> +	}
> +
> +	xfs_trans_ail_cursor_done(&cur);
> +	spin_unlock(&ailp->xa_lock);
> +
> +	return 0;
> +}
> +
>  /*
>   * This routine is called to create an in-core extent rmap update
>   * item from the rui format structure which was logged on disk.
> @@ -4108,6 +4197,10 @@ xlog_recover_commit_pass2(
>  		return xlog_recover_efi_pass2(log, item, trans->r_lsn);
>  	case XFS_LI_EFD:
>  		return xlog_recover_efd_pass2(log, item);
> +	case XFS_LI_ATTRI:
> +		return xlog_recover_attri_pass2(log, item, trans->r_lsn);
> +	case XFS_LI_ATTRD:
> +		return xlog_recover_attrd_pass2(log, item);
>  	case XFS_LI_RUI:
>  		return xlog_recover_rui_pass2(log, item, trans->r_lsn);
>  	case XFS_LI_RUD:
> @@ -4669,6 +4762,49 @@ xlog_recover_cancel_efi(
>  	spin_lock(&ailp->xa_lock);
>  }
>  
> +/* Recover the ATTRI if necessary. */
> +STATIC int
> +xlog_recover_process_attri(
> +	struct xfs_mount                *mp,
> +	struct xfs_ail                  *ailp,
> +	struct xfs_log_item             *lip)
> +{
> +	struct xfs_attri_log_item       *attrip;
> +	int                             error;
> +
> +	/*
> +	 * Skip ATTRIs that we've already processed.
> +	 */
> +	attrip = container_of(lip, struct xfs_attri_log_item, item);
> +	if (test_bit(XFS_ATTRI_RECOVERED, &attrip->flags))
> +		return 0;
> +
> +	spin_unlock(&ailp->xa_lock);
> +	error = xfs_attri_recover(mp, attrip);
> +	spin_lock(&ailp->xa_lock);
> +
> +	return error;
> +}
> +
> +/* Release the ATTRI since we're cancelling everything. */
> +STATIC void
> +xlog_recover_cancel_attri(
> +	struct xfs_mount                *mp,
> +	struct xfs_ail                  *ailp,
> +	struct xfs_log_item             *lip)
> +{
> +	struct xfs_attri_log_item         *attrip;
> +
> +	attrip = container_of(lip, struct xfs_attri_log_item, item);
> +
> +	spin_unlock(&ailp->xa_lock);
> +	xfs_attri_release(attrip);
> +	spin_lock(&ailp->xa_lock);
> +}
> +
> +
> +
> +
>  /* Recover the RUI if necessary. */
>  STATIC int
>  xlog_recover_process_rui(
> @@ -4861,6 +4997,10 @@ xlog_recover_process_intents(
>  		case XFS_LI_EFI:
>  			error = xlog_recover_process_efi(log->l_mp, ailp, lip);
>  			break;
> +		case XFS_LI_ATTRI:
> +			error = xlog_recover_process_attri(log->l_mp,
> +							   ailp, lip);
> +			break;
>  		case XFS_LI_RUI:
>  			error = xlog_recover_process_rui(log->l_mp, ailp, lip);
>  			break;
> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> index f663022..ee68459 100644
> --- a/fs/xfs/xfs_super.c
> +++ b/fs/xfs/xfs_super.c
> @@ -2024,6 +2024,7 @@ init_xfs_fs(void)
>  	xfs_rmap_update_init_defer_op();
>  	xfs_refcount_update_init_defer_op();
>  	xfs_bmap_update_init_defer_op();
> +	xfs_attr_init_defer_op();
>  
>  	xfs_dir_startup();
>  
> diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
> index 815b53d2..e094b05 100644
> --- a/fs/xfs/xfs_trans.h
> +++ b/fs/xfs/xfs_trans.h
> @@ -40,6 +40,9 @@ struct xfs_cud_log_item;
>  struct xfs_defer_ops;
>  struct xfs_bui_log_item;
>  struct xfs_bud_log_item;
> +struct xfs_attrd_log_item;
> +struct xfs_attri_log_item;
> +
>  
>  typedef struct xfs_log_item {
>  	struct list_head		li_ail;		/* AIL pointers */
> @@ -223,12 +226,22 @@ void		xfs_trans_dirty_buf(struct xfs_trans *, struct xfs_buf *);
>  void		xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
>  
>  void		xfs_extent_free_init_defer_op(void);
> +void            xfs_attr_init_defer_op(void);
> +
>  struct xfs_efd_log_item	*xfs_trans_get_efd(struct xfs_trans *,
>  				  struct xfs_efi_log_item *,
>  				  uint);
>  int		xfs_trans_free_extent(struct xfs_trans *,
>  				      struct xfs_efd_log_item *, xfs_fsblock_t,
>  				      xfs_extlen_t, struct xfs_owner_info *);
> +struct xfs_attrd_log_item *
> +xfs_trans_get_attrd(struct xfs_trans *tp,
> +		    struct xfs_attri_log_item *attrip);
> +int xfs_trans_attr(struct xfs_trans *tp, struct xfs_attrd_log_item *attrdp,
> +			struct xfs_inode *ip, uint32_t attr_op_flags,
> +			uint32_t flags, uint32_t name_len, uint32_t value_len,
> +			char *name, char *value);
> +
>  int		xfs_trans_commit(struct xfs_trans *);
>  int		xfs_trans_roll(struct xfs_trans **);
>  int		xfs_trans_roll_inode(struct xfs_trans **, struct xfs_inode *);
> diff --git a/fs/xfs/xfs_trans_attr.c b/fs/xfs/xfs_trans_attr.c
> new file mode 100644
> index 0000000..7c3290f
> --- /dev/null
> +++ b/fs/xfs/xfs_trans_attr.c
> @@ -0,0 +1,288 @@
> +/*
> + * 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.
> + */
> +#include "xfs.h"
> +#include "xfs_fs.h"
> +#include "xfs_shared.h"
> +#include "xfs_format.h"
> +#include "xfs_log_format.h"
> +#include "xfs_trans_resv.h"
> +#include "xfs_bit.h"
> +#include "xfs_mount.h"
> +#include "xfs_defer.h"
> +#include "xfs_trans.h"
> +#include "xfs_trans_priv.h"
> +#include "xfs_attr_item.h"
> +#include "xfs_alloc.h"
> +#include "xfs_bmap.h"
> +#include "xfs_trace.h"
> +#include "libxfs/xfs_da_format.h"
> +#include "xfs_da_btree.h"
> +#include "xfs_attr.h"
> +#include "xfs_inode.h"
> +#include "xfs_icache.h"
> +#include "xfs_quota.h"
> +
> +/*
> + * This routine is called to allocate an "extent free done"
> + * log item that will hold nextents worth of extents.  The
> + * caller must use all nextents extents, because we are not
> + * flexible about this at all.
> + */
> +struct xfs_attrd_log_item *
> +xfs_trans_get_attrd(struct xfs_trans		*tp,
> +		  struct xfs_attri_log_item	*attrip)
> +{
> +	struct xfs_attrd_log_item			*attrdp;
> +
> +	ASSERT(tp != NULL);
> +
> +	attrdp = xfs_attrd_init(tp->t_mountp, attrip);
> +	ASSERT(attrdp != NULL);
> +
> +	/*
> +	 * Get a log_item_desc to point at the new item.
> +	 */
> +	xfs_trans_add_item(tp, &attrdp->item);
> +	return attrdp;
> +}
> +
> +/*
> + * Delete an attr and log it to the ATTRD. Note that the transaction is marked
> + * dirty regardless of whether the attr delete succeeds or fails to support the
> + * ATTRI/ATTRD lifecycle rules.
> + */
> +int
> +xfs_trans_attr(
> +	struct xfs_trans		*tp,
> +	struct xfs_attrd_log_item	*attrdp,
> +	struct xfs_inode		*ip,
> +	uint32_t			op_flags,
> +	uint32_t			flags,
> +	uint32_t			name_len,
> +	uint32_t			value_len,
> +	char				*name,
> +	char				*value)
> +{
> +	uint			next_attr;
> +	struct xfs_attr_log_format *attrp;
> +	int			error;
> +	int                     local;
> +	struct xfs_da_args      args;
> +	struct xfs_defer_ops    dfops;
> +	xfs_fsblock_t		firstblock = NULLFSBLOCK;

Line the variable names up with the parameter names, please.

> +
> +	tp->t_flags |= XFS_TRANS_RESERVE;
> +
> +	error = xfs_attr_args_init(&args, ip, name, flags);
> +	if (error)
> +		return error;
> +
> +	xfs_ilock(ip, XFS_ILOCK_EXCL);
> +	xfs_defer_init(&dfops, &firstblock);

Uhoh.  In patch "xfs: log recovery should replay deferred ops in order"
we changed log intent item recovery to create a single defer_ops to
collect all of the new defer_ops that got created in the process of
recovering unfinished intent items that were dirty in the log.  The
reason for collecting the new deferred items is so that everything
replays in exactly the order they would have been finished had the
system not gone down.

Therefore, we have to pass the dfops created in
xlog_recover_process_intents all the way through the call chain
xlog_recover_process_attri -> xfs_attri_recover -> xfs_trans_attr.

I'll try to get that patch into -rc2 so that you don't have to carry
the fix patch in your tree, but be aware that you'll have to update this
at some point before the final version.

> +	args.name = name;
> +	args.namelen = name_len;
> +	args.hashval = xfs_da_hashname(args.name, args.namelen);
> +	args.value = value;
> +	args.valuelen = value_len;
> +	args.dfops = &dfops;
> +	args.firstblock = &firstblock;
> +	args.op_flags = XFS_DA_OP_OKNOENT;
> +	args.total = xfs_attr_calc_size(&args, &local);
> +	args.trans = tp;
> +	ASSERT(local);
> +
> +	error = xfs_qm_dqattach_locked(ip, 0);
> +	if (error)
> +		return error;
> +
> +	switch (op_flags) {
> +		case XFS_ATTR_OP_FLAGS_SET:
> +			args.op_flags |= XFS_DA_OP_ADDNAME;
> +			error = xfs_attr_set_args(&args, flags, false);
> +			break;
> +		case XFS_ATTR_OP_FLAGS_REMOVE:
> +			ASSERT(XFS_IFORK_Q((ip)));
> +			error = xfs_attr_remove_args(&args, flags);
> +			break;
> +		default:
> +			error = -EFSCORRUPTED;
> +	}
> +
> +	if (error)
> +		xfs_defer_cancel(&dfops);
> +
> +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
> +
> +	/*
> +	 * Mark the transaction dirty, even on error. This ensures the
> +	 * transaction is aborted, which:
> +	 *
> +	 * 1.) releases the ATTRI and frees the ATTRD
> +	 * 2.) shuts down the filesystem
> +	 */
> +	tp->t_flags |= XFS_TRANS_DIRTY;
> +	attrdp->item.li_desc->lid_flags |= XFS_LID_DIRTY;
> +
> +	next_attr = attrdp->next_attr;
> +	attrp = &(attrdp->format);
> +	attrp->alf_ino = ip->i_ino;
> +	attrp->alf_op_flags = op_flags;
> +	attrp->alf_value_len = value_len;
> +	attrp->alf_name_len = name_len;
> +	attrp->alf_attr_flags = flags;
> +
> +	attrdp->name = name;
> +	attrdp->value = value;
> +	attrdp->name_len = name_len;
> +	attrdp->value_len = value_len;
> +	attrdp->next_attr++;
> +
> +	return error;
> +}
> +
> +static int
> +xfs_attr_diff_items(
> +	void				*priv,
> +	struct list_head		*a,
> +	struct list_head		*b)
> +{
> +	return 0;
> +}
> +
> +/* Get an ATTRI. */
> +STATIC void *
> +xfs_attr_create_intent(
> +	struct xfs_trans		*tp,
> +	unsigned int			count)
> +{
> +	struct xfs_attri_log_item		*attrip;
> +
> +	ASSERT(tp != NULL);
> +	ASSERT(count > 0);

ASSERT(count == 1); here, right?

> +
> +	attrip = xfs_attri_init(tp->t_mountp);
> +	ASSERT(attrip != NULL);
> +
> +	/*
> +	 * Get a log_item_desc to point at the new item.
> +	 */
> +	xfs_trans_add_item(tp, &attrip->item);
> +	return attrip;
> +}
> +
> +/* Log an attr to the intent item. */
> +STATIC void
> +xfs_attr_log_item(
> +	struct xfs_trans		*tp,
> +	void				*intent,
> +	struct list_head		*item)
> +{
> +	struct xfs_attri_log_item	*attrip = intent;
> +	struct xfs_attr_item		*free;
> +	struct xfs_attr_log_format	*attrp;
> +
> +	free = container_of(item, struct xfs_attr_item, xattri_list);
> +
> +	tp->t_flags |= XFS_TRANS_DIRTY;
> +	attrip->item.li_desc->lid_flags |= XFS_LID_DIRTY;
> +
> +	attrp = &attrip->format;
> +	attrp->alf_ino = free->xattri_ip->i_ino;
> +	attrp->alf_op_flags = free->xattri_op_flags;
> +	attrp->alf_value_len = free->xattri_value_len;
> +	attrp->alf_name_len = free->xattri_name_len;
> +	attrp->alf_attr_flags = free->xattri_flags;
> +
> +	attrip->name = &(free->xattri_name_value[0]);
> +	attrip->value = &(free->xattri_name_value[free->xattri_name_len]);
> +	attrip->name_len = free->xattri_name_len;
> +	attrip->value_len = free->xattri_value_len;
> +}
> +
> +/* Get an ATTRD so we can process all the attrs. */
> +STATIC void *
> +xfs_attr_create_done(
> +	struct xfs_trans		*tp,
> +	void				*intent,
> +	unsigned int			count)
> +{
> +	return xfs_trans_get_attrd(tp, intent);
> +}
> +
> +/* Process an attr. */
> +STATIC int
> +xfs_attr_finish_item(
> +	struct xfs_trans		*tp,
> +	struct xfs_defer_ops		*dop,
> +	struct list_head		*item,
> +	void				*done_item,
> +	void				**state)
> +{
> +	struct xfs_attr_item	*free;
> +	int				error;
> +
> +	free = container_of(item, struct xfs_attr_item, xattri_list);
> +	error = xfs_trans_attr(tp, done_item,

Pass dop through to xfs_trans_attr, per the comment above.
We should /never/ be nesting defer_ops within a call stack.

> +			free->xattri_ip,
> +			free->xattri_op_flags,
> +			free->xattri_flags,
> +			free->xattri_name_len,
> +			free->xattri_value_len,
> +			&free->xattri_name_value[0],
> +			&free->xattri_name_value[free->xattri_name_len]);
> +	kmem_free(free);
> +	return error;
> +}
> +
> +/* Abort all pending ATTRs. */
> +STATIC void
> +xfs_attr_abort_intent(
> +	void				*intent)
> +{
> +	xfs_attri_release(intent);
> +}
> +
> +/* Cancel an attr */
> +STATIC void
> +xfs_attr_cancel_item(
> +	struct list_head		*item)
> +{
> +	struct xfs_attr_item	*free;
> +
> +	free = container_of(item, struct xfs_attr_item, xattri_list);
> +	kmem_free(free);
> +}
> +
> +static const struct xfs_defer_op_type xfs_attr_defer_type = {
> +	.type		= XFS_DEFER_OPS_TYPE_ATTR,
> +	.max_items	= XFS_ATTRI_MAX_FAST_ATTRS,
> +	.diff_items	= xfs_attr_diff_items,
> +	.create_intent	= xfs_attr_create_intent,
> +	.abort_intent	= xfs_attr_abort_intent,
> +	.log_item	= xfs_attr_log_item,
> +	.create_done	= xfs_attr_create_done,
> +	.finish_item	= xfs_attr_finish_item,
> +	.cancel_item	= xfs_attr_cancel_item,
> +};
> +
> +/* Register the deferred op type. */
> +void
> +xfs_attr_init_defer_op(void)
> +{
> +	xfs_defer_init_op_type(&xfs_attr_defer_type);
> +}
> -- 
> 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] 69+ messages in thread

* Re: [PATCH v3 01/17] Add helper functions xfs_attr_set_args and xfs_attr_remove_args
  2017-11-17 18:21 ` [PATCH v3 01/17] Add helper functions xfs_attr_set_args and xfs_attr_remove_args Allison Henderson
@ 2017-11-28 19:54   ` Darrick J. Wong
  2017-11-29  1:02     ` Dave Chinner
  2017-11-29 18:52     ` Allison Henderson
  0 siblings, 2 replies; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 19:54 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

On Fri, Nov 17, 2017 at 11:21:29AM -0700, Allison Henderson wrote:
> These sub-routines set or remove 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>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 335 ++++++++++++++++++++++++++++-------------------
>  fs/xfs/libxfs/xfs_bmap.c |  55 ++++----
>  fs/xfs/libxfs/xfs_bmap.h |   1 +
>  fs/xfs/xfs_attr.h        |   2 +
>  4 files changed, 236 insertions(+), 157 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 6249c92..e5f2960 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -168,6 +168,195 @@ 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.

We have sufficient space in the single transaction case to do both, right?

> + */
> +int
> +xfs_attr_set_args(
> +	struct xfs_da_args	*args,
> +	int			flags,
> +	bool			roll_trans)
> +{
> +	struct xfs_inode	*dp = args->dp;
> +	struct xfs_mount        *mp = dp->i_mount;
> +	struct xfs_trans_res    tres;
> +	int			rsvd = 0;
> +	int			error = 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;
> +	}
> +
> +	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;

/me raises eyebrows about declaring our own tres here, though it came
from the original code so I gues I can't complain too loudly.

(Primarily because we use the transaction reservations to calculate the
minimum log size, so I would think we'd want this one included in those
calculations...)

> +	/*
> +	 * 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;
> +
> +	error = xfs_trans_reserve_quota_nblks(args->trans, dp, args->total, 0,
> +					      rsvd ? XFS_QMOPT_RES_REGBLKS |
> +						     XFS_QMOPT_FORCE_RES :
> +						     XFS_QMOPT_RES_REGBLKS);
> +	if (error)
> +		goto out;
> +
> +	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);
> +		if (error != -ENOSPC) {
> +			ASSERT(args->trans);
> +			if (!error && (flags & ATTR_KERNOTIME) == 0)
> +				xfs_trans_ichgtime(args->trans, dp,
> +						   XFS_ICHGTIME_CHG);
> +			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);
> +		if (error)
> +			goto out;
> +		xfs_defer_ijoin(args->dfops, dp);
> +		if (roll_trans) {
> +			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;
> +		}
> +	}
> +
> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
> +		error = xfs_attr_leaf_addname(args);
> +	else
> +		error = xfs_attr_node_addname(args);
> +	if (error)
> +		goto out;
> +
> +	if ((flags & ATTR_KERNOTIME) == 0)
> +		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
> +
> +	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
> +out:
> +	return error;
> +}
> +
> +/*
> + * Remove the attribute specified in @args.
> + */
> +int
> +xfs_attr_remove_args(
> +	struct xfs_da_args      *args,
> +	int			flags)
> +{
> +	struct xfs_inode	*dp = args->dp;
> +	struct xfs_mount	*mp = dp->i_mount;
> +	int			error;
> +	int                     rsvd = 0;
> +
> +	/*
> +	 * Root fork attributes can use reserved data blocks for this
> +	 * operation if necessary
> +	 */
> +	if (flags & ATTR_ROOT)
> +		rsvd = XFS_TRANS_RESERVE;

Insert a blank line to separate these two...

> +	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
> +		XFS_ATTRRM_SPACE_RES(mp), 0, rsvd, &args->trans);
> +

...and remove this one since they're directly related.

> +	if (error)
> +		goto out;
> +
> +	/*
> +	 * No need to make quota reservations here. We expect to release some
> +	 * blocks not allocate in the common case.
> +	 */
> +	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);
> +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> +		error = xfs_attr_leaf_removename(args);
> +	} else {
> +		error = xfs_attr_node_removename(args);
> +	}
> +
> +	if (error)
> +		goto out;
> +
> +	/*
> +	 * 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 ((flags & ATTR_KERNOTIME) == 0)
> +		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
> +
> +	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
> +
> +	return error;
> +
> +out:
> +	if (args->trans)
> +		xfs_trans_cancel(args->trans);
> +
> +	return error;
> +}
> +
> +/*
>   * Calculate how many blocks we need for the new attribute,
>   */
>  STATIC int
> @@ -214,10 +403,9 @@ xfs_attr_set(
>  	struct xfs_mount	*mp = dp->i_mount;
>  	struct xfs_da_args	args;
>  	struct xfs_defer_ops	dfops;
> -	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);
>  
> @@ -252,106 +440,11 @@ xfs_attr_set(
>  			return error;
>  	}
>  
> -	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)
> -		return error;
> -
>  	xfs_ilock(dp, XFS_ILOCK_EXCL);
> -	error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0,
> -				rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
> -				       XFS_QMOPT_RES_REGBLKS);
> -	if (error) {
> -		xfs_iunlock(dp, XFS_ILOCK_EXCL);
> -		xfs_trans_cancel(args.trans);
> -		return error;
> -	}
> -
> -	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);
> -		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);
> -		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 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;
> -
> -	}
> -
> -	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
> -		error = xfs_attr_leaf_addname(&args);
> -	else
> -		error = xfs_attr_node_addname(&args);
> +	xfs_defer_init(args.dfops, args.firstblock);
> +	error = xfs_attr_set_args(&args, flags, true);
>  	if (error)
> -		goto out;
> +		goto out_defer_cancel;
>  
>  	/*
>  	 * If this is a synchronous mount, make sure that the
> @@ -360,9 +453,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.
>  	 */
> @@ -374,10 +464,6 @@ xfs_attr_set(
>  
>  out_defer_cancel:
>  	xfs_defer_cancel(&dfops);
> -	args.trans = NULL;
> -out:
> -	if (args.trans)
> -		xfs_trans_cancel(args.trans);
>  	xfs_iunlock(dp, XFS_ILOCK_EXCL);
>  	return error;
>  }
> @@ -417,38 +503,18 @@ xfs_attr_remove(
>  	 */
>  	args.op_flags = XFS_DA_OP_OKNOENT;
>  
> -	error = xfs_qm_dqattach(dp, 0);
> -	if (error)
> -		return error;
> -
> -	/*
> -	 * Root fork attributes can use reserved data blocks for this
> -	 * operation if necessary
> -	 */
> -	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
> -			XFS_ATTRRM_SPACE_RES(mp), 0,
> -			(flags & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
> -			&args.trans);
> -	if (error)
> -		return error;
> -
>  	xfs_ilock(dp, XFS_ILOCK_EXCL);
>  	/*
>  	 * No need to make quota reservations here. We expect to release some
>  	 * blocks not allocate in the common case.
>  	 */
>  	xfs_trans_ijoin(args.trans, dp, 0);
> +	xfs_defer_init(args.dfops, args.firstblock);
> +	error = xfs_qm_dqattach_locked(dp, 0);
> +	if (error)
> +		return error;
>  
> -	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);
> -	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> -		error = xfs_attr_leaf_removename(&args);
> -	} else {
> -		error = xfs_attr_node_removename(&args);
> -	}
> +	error = xfs_attr_remove_args(&args, flags);
>  
>  	if (error)
>  		goto out;
> @@ -460,9 +526,6 @@ xfs_attr_remove(
>  	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.
>  	 */
> @@ -473,6 +536,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/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
> index 8926379..7fa58fa 100644
> --- a/fs/xfs/libxfs/xfs_bmap.c
> +++ b/fs/xfs/libxfs/xfs_bmap.c
> @@ -1066,6 +1066,37 @@ 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_UUID:
> +		ip->i_d.di_forkoff = roundup(sizeof(uuid_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.
> @@ -1119,29 +1150,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_UUID:
> -		ip->i_d.di_forkoff = roundup(sizeof(uuid_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/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
> index 502e0d8..5ca4a73 100644
> --- a/fs/xfs/libxfs/xfs_bmap.h
> +++ b/fs/xfs/libxfs/xfs_bmap.h
> @@ -210,6 +210,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,
> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
> index 5d5a5e2..8542606 100644
> --- a/fs/xfs/xfs_attr.h
> +++ b/fs/xfs/xfs_attr.h
> @@ -149,7 +149,9 @@ 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, 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);

libxfs functions should be declared in a libxfs header, not here.

--D

>  int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>  		  int flags, struct attrlist_cursor_kern *cursor);
>  
> -- 
> 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] 69+ messages in thread

* Re: [PATCH v3 17/17] Add parent pointer ioctl
  2017-11-17 18:21 ` [PATCH v3 17/17] Add parent pointer ioctl Allison Henderson
  2017-11-22 19:54   ` Allison Henderson
@ 2017-11-28 20:35   ` Darrick J. Wong
  2017-11-29 18:52     ` Allison Henderson
  2017-11-29 21:37     ` Dave Chinner
  1 sibling, 2 replies; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-28 20:35 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

On Fri, Nov 17, 2017 at 11:21:45AM -0700, Allison Henderson wrote:
> 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>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++
>  fs/xfs/libxfs/xfs_fs.h   |  1 +
>  fs/xfs/xfs_attr.h        |  2 ++
>  fs/xfs/xfs_attr_list.c   |  3 +++
>  fs/xfs/xfs_ioctl.c       | 48 +++++++++++++++++++++++++++++++++-
>  5 files changed, 120 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 9d4d883..d2be842 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -134,6 +134,73 @@ xfs_attr_get_ilocked(
>  		return xfs_attr_node_get(args);
>  }
>  
> +/*
> + * Get the parent pointer for a given inode
> + * Caller will need to allocate a buffer pointed to by xpnir->p_name
> + * and store the buffer size in xpnir->p_namelen.  The parent
> + * pointer will be stored in the given xfs_parent_name_irec
> + *
> + * Returns 0 on success and non zero on error
> + */
> +int
> +xfs_attr_get_parent_pointer(struct xfs_inode		*ip,
> +			    struct xfs_parent_name_irec *xpnir)

Please fix the parameter list here.

> +{
> +	struct attrlist			*alist;
> +	struct attrlist_ent		*aent;
> +	struct attrlist_cursor_kern     cursor;
> +	struct xfs_parent_name_rec	*xpnr;
> +	char				*namebuf;
> +	int                             error = 0;
> +	unsigned int                    flags = ATTR_PARENT;
> +
> +	/* Allocate a buffer to store the attribute names */
> +	namebuf = kmem_zalloc_large(XFS_XATTR_LIST_MAX, KM_SLEEP);
> +	if (!namebuf)
> +		return -ENOMEM;
> +
> +	/* Get all attribute names that have the ATTR_PARENT flag */
> +	memset(&cursor, 0, sizeof(struct attrlist_cursor_kern));
> +	error = xfs_attr_list(ip, namebuf, XFS_XATTR_LIST_MAX, flags, &cursor);
> +	if (error)
> +		goto out_kfree;
> +
> +	alist = (struct attrlist *)namebuf;
> +
> +	/* There should never be more than one parent pointer */
> +	ASSERT(alist->al_count == 1);

As mentioned earlier, this is not true.  Files can have multiple parents.

> +	aent = (struct attrlist_ent *) &namebuf[alist->al_offset[0]];
> +	xpnr = (struct xfs_parent_name_rec *)(aent->a_name);
> +
> +	/*
> +	 * The value of the parent pointer attribute should be the file name
> +	 * So we check the value length of the attribute entry against the name
> +	 * length of the parent name record to make sure the caller gave enough
> +	 * buffer space to store the file name (plus a null terminator)
> +	 */
> +	if (aent->a_valuelen >= xpnir->p_namelen) {
> +		error = -ERANGE;
> +		goto out_kfree;
> +	}
> +
> +	xpnir->p_namelen = aent->a_valuelen + 1;
> +	memset((void *)(xpnir->p_name), 0, xpnir->p_namelen);
> +	error = xfs_attr_get(ip, (char *)xpnr,
> +			     sizeof(struct xfs_parent_name_rec),
> +			     (unsigned char *)(xpnir->p_name),
> +			     (int *)&(xpnir->p_namelen), flags);
> +	if (error)
> +		goto out_kfree;
> +
> +	xfs_init_parent_name_irec(xpnir, xpnr);
> +
> +out_kfree:
> +	kmem_free(namebuf);
> +
> +	return error;
> +}
> +
>  /* Retrieve an extended attribute by name, and its value. */
>  int
>  xfs_attr_get(
> diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
> index b8108f8..2f9ca2c 100644
> --- a/fs/xfs/libxfs/xfs_fs.h
> +++ b/fs/xfs/libxfs/xfs_fs.h
> @@ -512,6 +512,7 @@ typedef struct xfs_swapext
>  #define XFS_IOC_ZERO_RANGE	_IOW ('X', 57, struct xfs_flock64)
>  #define XFS_IOC_FREE_EOFBLOCKS	_IOR ('X', 58, struct xfs_fs_eofblocks)
>  /*	XFS_IOC_GETFSMAP ------ hoisted 59         */
> +#define XFS_IOC_GETPPOINTER	_IOR ('X', 61, struct xfs_parent_name_irec)

I don't think it's a good idea to expose internal data structures
directly to userspace, because that inhibits our ability to change the
in-core data structure.

Furthermore, hardlinked files can have multiple parent pointers, so it's
not going to suffice to return a single parent pointer entry.  Given
that there can be potentially 2^32 parents, we're going to need a data
structure for the ioctl to store (in an opaque manner) the attribute
iteration cursor and have space to pass back some number of parent
pointers.

(Yes, it's time to start talking about actual use cases...)

At a bare minimum, this is what I pictured for the "return parents of
the open file" ioctl:

#define XFS_PPTR_MAXNAMELEN		255

struct xfs_pptr {
	u64				pp_ino;
	u32				pp_gen;
	u8				pp_namelen;
	u8				pp_name[XFS_PPTR_MAXNAMELEN];
};

/* return parents of the handle, instead of the open fd */
#define XFS_PPTR_FLAG_HANDLE		(1u << 0)

struct xfs_pptr_info {
	struct xfs_fsop_handlereq	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];
	struct xfs_pptr			pi_ptrs[0];
};

#define XFS_PPTR_INFO_SIZEOF(ptrs)	(sizeof(struct xfs_pptr_info) + \
					((ptrs) * sizeof(struct xfs_pptr)));

static inline struct xfs_pptr_info *
xfs_pptr_alloc(
	size_t			nr_ptrs)
{
	struct xfs_pptr_info	*ppi;

	ppi = malloc(XFS_PPTR_INFO_SIZEOF(nr_ptrs));
	if (!ppi)
		return NULL;
	memset(ppi, 0, XFS_PPTR_INFO_SIZEOF(nr_ptrs));
	ppi->pi_ptrs_size = nr_ptrs;
	return ppi;
}

With the following example userspace program (that does no checking
whatsoever):

int main(int argc, char *argv[])
{
	struct xfs_pptr_info	*ppi;
	struct xfs_pptr		*pp;
	int			fd;

	fd = open(argv[1], O_RDONLY);
	ppi = xfs_pptr_alloc(32);

	while (ioctl(fd, XFS_IOC_GETPPOINTER, ppi) == 0 && ppi->pi_ptrs_used) {
		for (i = 0; i < ppi->pi_ptrs_used; i++) {
			printf("%llu:%u -> %s\n",
					ppi->pi_ptrs[i].pp_ino,
					ppi->pi_ptrs[i].pp_gen,
					ppi->pi_ptrs[i].pp_name);
		}
	}
}

Notice here how we the userspace structure contains an opaque attribute
list cursor, so we can keep coming back for more parent pointers until
we run out of xattrs (and pi_ptrs_used == 0).  The kernel will copy its
internal cursor out to the userspace buffer as an opaque cookie prior to
returning.

>From this simple implementation it shouldn't be difficult to finish the
parents_by_handle/parentpaths_by_handle functions in libhandle, though
given that they've never been implemented in Linux and we no longer care
about Irix, you've some flexibility to change those library functions if
that is convenient for setting up xfstests.

Speaking of xfstests... what are the initial test cases?  I figured at
least the following:

0) mkfs with protofile, make sure the parent records get created
1) create file, check parent records
2) hardlink file, check both parent records
3) delete one link of a hardlinked file, check parent records
4) hardlink a file a few thousand times, check that the iteration
   scheme laid out above actually works
5) rename a file within a directory, check the parent records
6) rename a file across directories, check the parent records
7) some sort of testing where we run out of space while updating pptrs
8) add some error injection knobs to make sure that pptr replay actually
   works correctly

Can you think of other test cases?

For xfs_scrub, we want to be able to query the parents of any (damaged)
inode we find in the filesystem.  If the inode is so damaged we can't
open it (or it's a special file) then scrub has to construct a file
handle and pass that in via pi_handle.

I /also/ wonder if there's any interest in having a fallback for
non-pptr filesystems that walks the dentry->d_parent links (like
d_paths() does) back to the root.  Such a fallback will only work on an
opened dir or a file opened by path (i.e. not a handle), however, which
limits its appeal.

--D

>  /*
>   * ioctl commands that replace IRIX syssgi()'s
> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
> index 0829687..0ec3458 100644
> --- a/fs/xfs/xfs_attr.h
> +++ b/fs/xfs/xfs_attr.h
> @@ -172,6 +172,8 @@ int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
>  		int flags);
>  int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
>  		size_t namelen, unsigned char *value, int valuelen, int flags);
> +int xfs_attr_get_parent_pointer(struct xfs_inode *ip,
> +				struct xfs_parent_name_irec *xpnir);
>  int xfs_attr_set_args(struct xfs_da_args *args, int flags, bool roll_trans);
>  int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
>  		size_t namelen, int flags);
> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
> index 7740c8a..78fc477 100644
> --- a/fs/xfs/xfs_attr_list.c
> +++ b/fs/xfs/xfs_attr_list.c
> @@ -534,6 +534,9 @@ xfs_attr_put_listent(
>  	if (((context->flags & ATTR_ROOT) == 0) !=
>  	    ((flags & XFS_ATTR_ROOT) == 0))
>  		return;
> +	if (((context->flags & ATTR_PARENT) == 0) !=
> +	    ((flags & XFS_ATTR_PARENT) == 0))
> +		return;
>  
>  	arraytop = sizeof(*alist) +
>  			context->count * sizeof(alist->al_offset[0]);
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index 4664314..5492607 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -44,6 +44,7 @@
>  #include "xfs_btree.h"
>  #include <linux/fsmap.h>
>  #include "xfs_fsmap.h"
> +#include "xfs_attr.h"
>  
>  #include <linux/capability.h>
>  #include <linux/cred.h>
> @@ -1710,6 +1711,50 @@ xfs_ioc_getfsmap(
>  	return 0;
>  }
>  
> +/*
> + * IOCTL routine to get the parent pointer of an inode and return it to user
> + * space.  Caller must pass an struct xfs_parent_name_irec with a name buffer
> + * large enough to hold the file name.  Returns 0 on success or non-zero on
> + * failure
> + */
> +STATIC int
> +xfs_ioc_get_parent_pointer(
> +	struct file			*filp,
> +	void				__user *arg)
> +{
> +	struct inode			*inode = file_inode(filp);
> +	struct xfs_inode		*ip = XFS_I(inode);
> +	struct xfs_parent_name_irec	xpnir;
> +	char				*uname;
> +	char				*kname;
> +	int				error = 0;
> +
> +	copy_from_user(&xpnir, arg, sizeof(struct xfs_parent_name_irec));
> +	uname = (char *)xpnir.p_name;
> +
> +	/*
> +	 * Use kernel space memory to get the parent pointer name.
> +	 * We'll copy it to the user space name back when we're done
> +	 */
> +	kname = kmem_zalloc_large(xpnir.p_namelen, KM_SLEEP);

Please sanity-check the amount of memory we try to allocate.

> +	if (!kname)
> +		return -ENOMEM;
> +
> +	xpnir.p_name = kname;
> +	error = xfs_attr_get_parent_pointer(ip, &xpnir);
> +
> +	if (error)
> +		goto out;
> +
> +	copy_to_user(uname, xpnir.p_name, xpnir.p_namelen);
> +	xpnir.p_name = uname;
> +	copy_to_user(arg, &xpnir, sizeof(struct xfs_parent_name_irec));
> +
> +out:
> +	kmem_free(kname);
> +	return error;
> +}
> +
>  int
>  xfs_ioc_swapext(
>  	xfs_swapext_t	*sxp)
> @@ -1866,7 +1911,8 @@ xfs_file_ioctl(
>  		return xfs_ioc_getxflags(ip, arg);
>  	case XFS_IOC_SETXFLAGS:
>  		return xfs_ioc_setxflags(ip, filp, arg);
> -
> +	case XFS_IOC_GETPPOINTER:
> +		return xfs_ioc_get_parent_pointer(filp, arg);
>  	case XFS_IOC_FSSETDM: {
>  		struct fsdmidata	dmi;
>  
> -- 
> 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] 69+ messages in thread

* Re: [PATCH v3 01/17] Add helper functions xfs_attr_set_args and xfs_attr_remove_args
  2017-11-28 19:54   ` Darrick J. Wong
@ 2017-11-29  1:02     ` Dave Chinner
  2017-11-29 18:52     ` Allison Henderson
  1 sibling, 0 replies; 69+ messages in thread
From: Dave Chinner @ 2017-11-29  1:02 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: Allison Henderson, linux-xfs

On Tue, Nov 28, 2017 at 11:54:21AM -0800, Darrick J. Wong wrote:
> On Fri, Nov 17, 2017 at 11:21:29AM -0700, Allison Henderson wrote:
> > These sub-routines set or remove 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>
> > ---
> >  fs/xfs/libxfs/xfs_attr.c | 335 ++++++++++++++++++++++++++++-------------------
> >  fs/xfs/libxfs/xfs_bmap.c |  55 ++++----
> >  fs/xfs/libxfs/xfs_bmap.h |   1 +
> >  fs/xfs/xfs_attr.h        |   2 +
> >  4 files changed, 236 insertions(+), 157 deletions(-)
> > 
> > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > index 6249c92..e5f2960 100644
> > --- a/fs/xfs/libxfs/xfs_attr.c
> > +++ b/fs/xfs/libxfs/xfs_attr.c
> > @@ -168,6 +168,195 @@ 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.
> 
> We have sufficient space in the single transaction case to do both, right?
> 
> > + */
> > +int
> > +xfs_attr_set_args(
> > +	struct xfs_da_args	*args,
> > +	int			flags,
> > +	bool			roll_trans)
> > +{
> > +	struct xfs_inode	*dp = args->dp;
> > +	struct xfs_mount        *mp = dp->i_mount;
> > +	struct xfs_trans_res    tres;
> > +	int			rsvd = 0;
> > +	int			error = 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;
> > +	}
> > +
> > +	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;
> 
> /me raises eyebrows about declaring our own tres here, though it came
> from the original code so I gues I can't complain too loudly.

Well, it takes into account the fact we don't log remote
attributes. Hence for inline attributes we need to include their
length in the log reservation, but we don't know what the length is
until we are actually adding the attribute to the block...

> (Primarily because we use the transaction reservations to calculate the
> minimum log size, so I would think we'd want this one included in those
> calculations...)

We do take that into account in xfs_log_calc_max_attrsetm_res().

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v3 02/17] Set up infastructure for deferred attribute operations
  2017-11-28 19:45   ` Darrick J. Wong
@ 2017-11-29  1:19     ` Dave Chinner
  2017-11-29 18:52       ` Allison Henderson
  2017-11-29 18:51     ` Allison Henderson
  1 sibling, 1 reply; 69+ messages in thread
From: Dave Chinner @ 2017-11-29  1:19 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: Allison Henderson, linux-xfs

On Tue, Nov 28, 2017 at 11:45:47AM -0800, Darrick J. Wong wrote:
> On Fri, Nov 17, 2017 at 11:21:30AM -0700, Allison Henderson wrote:
> > +/*
> > + * This is the structure used to lay out an attr log item in the
> > + * log.
> > + */
> > +struct xfs_attr_log_format {
> > +	uint64_t	alf_id;		/* attri identifier */
> > +	xfs_ino_t       alf_ino;	/* the inode for this attr operation */
> > +	uint32_t        alf_op_flags;	/* marks the op as a set or remove */
> > +	uint32_t        alf_name_len;	/* attr name length */
> > +	uint32_t        alf_value_len;	/* attr value length */
> > +	uint32_t        alf_attr_flags;	/* attr flags */
> > +	uint16_t	alf_type;	/* attri log item type */
> > +	uint16_t	alf_size;	/* size of this item */
> 
> Type and size should go first so that the self-identification
> information ends up at the same byte offsets as the other log formats.
> This makes it much easier to dissect dirty log contents by hand if
> things get messy.

I'll point out this is not a "nice to have" feature but a
requirement of the on-disk log format structures.

That is, log recovery assumes that every log format item it finds in
the log has it's type and size as the first two 16 bit fields in the
log format item so it can validate that a) it's a known log format
type, and b) knows how big the log format structure it is about to
decode is supposed to be.

>From fs/xfs/xfs_log_recovery.c:

/*
 * The next region to add is the start of a new region.  It could be
 * a whole region or it could be the first part of a new region.  Because
 * of this, the assumption here is that the type and size fields of all
 * format structures fit into the first 32 bits of the structure.
 *
 * This works because all regions must be 32 bit aligned.  Therefore, we
 * either have both fields or we have neither field.  In the case we have
 * neither field, the data part of the region is zero length.  We only have
 * a log_op_header and can throw away the header since a new one will appear
 * later.  If we have at least 4 bytes, then we can determine how many regions
 * will appear in the current log item.
 */
STATIC int
xlog_recover_add_to_trans(
.....

Also, see the use of the ITEM_TYPE() macro in
fs/xfs/xfs_log_recovery.c as another example of assuming the type
field is the first 16 bits of the log format structures....


Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v3 16/17] Add the parent pointer support to the superblock version 5.
  2017-11-28 18:08   ` Darrick J. Wong
@ 2017-11-29 18:41     ` Allison Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:41 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs, Mark Tinguely, Dave Chinner

On 11/28/2017 11:08 AM, Darrick J. Wong wrote:

> On Fri, Nov 17, 2017 at 11:21:44AM -0700, Allison Henderson wrote:
>> [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>
>> ---
>> v2: remove unrelated type clean up in xfs_format.h
>>
>> Signed-off-by: Allison Henderson<allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_format.h | 7 +++++--
>>   fs/xfs/libxfs/xfs_fs.h     | 1 +
>>   fs/xfs/xfs_fsops.c         | 4 +++-
>>   fs/xfs/xfs_super.c         | 4 ++++
>>   4 files changed, 13 insertions(+), 3 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
>> index 121862a..f3e3132 100644
>> --- a/fs/xfs/libxfs/xfs_format.h
>> +++ b/fs/xfs/libxfs/xfs_format.h
>> @@ -459,10 +459,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 */
> Please make this line up, i.e.
>
> #define XFS_SB_FEAT_RO_COMPAT_PARENT<three spaces>(1 << 3)<two tabs>/* parent inode ptr */
>
> With that fixed,
> Reviewed-by: Darrick J. Wong<darrick.wong@oracle.com>
>
> --D
Alrighty will do, thanks!
>>   #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(
>> @@ -558,7 +560,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/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
>> index 8c61f21..b8108f8 100644
>> --- a/fs/xfs/libxfs/xfs_fs.h
>> +++ b/fs/xfs/libxfs/xfs_fs.h
>> @@ -222,6 +222,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/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
>> index 8f22fc5..9a0ce52 100644
>> --- a/fs/xfs/xfs_fsops.c
>> +++ b/fs/xfs/xfs_fsops.c
>> @@ -111,7 +111,9 @@ xfs_fs_geometry(
>>   			(xfs_sb_version_hasrmapbt(&mp->m_sb) ?
>>   				XFS_FSOP_GEOM_FLAGS_RMAPBT : 0) |
>>   			(xfs_sb_version_hasreflink(&mp->m_sb) ?
>> -				XFS_FSOP_GEOM_FLAGS_REFLINK : 0);
>> +				XFS_FSOP_GEOM_FLAGS_REFLINK : 0) |
>> +			(xfs_sb_version_hasparent(&mp->m_sb) ?
>> +				XFS_FSOP_GEOM_FLAGS_PARENT : 0);
>>   		geo->logsectsize = xfs_sb_version_hassector(&mp->m_sb) ?
>>   				mp->m_sb.sb_logsectsize : BBSIZE;
>>   		geo->rtsectsize = mp->m_sb.sb_blocksize;
>> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
>> index ee68459..066266f 100644
>> --- a/fs/xfs/xfs_super.c
>> +++ b/fs/xfs/xfs_super.c
>> @@ -1675,6 +1675,10 @@ xfs_fs_fill_super(
>>   	"EXPERIMENTAL reverse mapping btree feature enabled. Use at your own risk!");
>>   	}
>>   
>> +	if (xfs_sb_version_hasparent(&mp->m_sb))
>> +		xfs_alert(mp,
>> +	"EXPERIMENTAL parent pointer feature enabled. Use at your own risk!");
>> +
>>   	if (xfs_sb_version_hasreflink(&mp->m_sb))
>>   		xfs_alert(mp,
>>   	"EXPERIMENTAL reflink feature enabled. Use at your own risk!");
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message tomajordomo@vger.kernel.org
>> More majordomo info athttp://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH v3 15/17] Add parent pointers to rename
  2017-11-28 18:20   ` Darrick J. Wong
@ 2017-11-29 18:43     ` Allison Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:43 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 11/28/2017 11:20 AM, Darrick J. Wong wrote:

> On Fri, Nov 17, 2017 at 11:21:43AM -0700, Allison Henderson wrote:
>> This patch removes the old parent pointer attribute during the
>> rename operation, and re-adds the updated parent pointer
>>
>> Signed-off-by: Allison Henderson<allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_dir2.c |  6 ++++--
>>   fs/xfs/xfs_inode.c       | 26 ++++++++++++++++++++------
>>   2 files changed, 24 insertions(+), 8 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
>> index 25b370b..ed25203 100644
>> --- a/fs/xfs/libxfs/xfs_dir2.c
>> +++ b/fs/xfs/libxfs/xfs_dir2.c
>> @@ -324,10 +324,11 @@ xfs_dir_createname(
>>   	else
>>   		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;
>> -out_free:
>> +
>>   	kmem_free(args);
>>   	return rval;
>>   }
>> @@ -496,9 +497,10 @@ xfs_dir_removename(
>>   		rval = xfs_dir2_leaf_removename(args);
>>   	else
>>   		rval = xfs_dir2_node_removename(args);
>> +out_free:
>>   	if (offset)
>>   		*offset = args->offset;
>> -out_free:
>> +
> Why do these labels need to be moved here?  The *offset = ... lines are
> new, so why not put them in their final place in the patch that adds
> those lines?
Ok, if I recall correctly, I think I had found a bug where the offset 
was not getting set when it should have, and fixed it when I added the 
rename patch to the original set.  I will fold these down into their 
respective patches.
>>   	kmem_free(args);
>>   	return rval;
>>   }
>> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
>> index a289a40..da5c761 100644
>> --- a/fs/xfs/xfs_inode.c
>> +++ b/fs/xfs/xfs_inode.c
>> @@ -2984,6 +2984,8 @@ xfs_rename(
>>   	bool			src_is_directory = S_ISDIR(VFS_I(src_ip)->i_mode);
>>   	int			spaceres;
>>   	int			error;
>> +	xfs_dir2_dataptr_t	new_diroffset;
>> +	xfs_dir2_dataptr_t	old_diroffset;
>>   
>>   	trace_xfs_rename(src_dp, target_dp, src_name, target_name);
>>   
>> @@ -3086,13 +3088,12 @@ xfs_rename(
>>   		 */
>>   		error = xfs_dir_createname(tp, target_dp, target_name,
>>   					   src_ip->i_ino, &first_block, &dfops,
>> -					   spaceres, NULL);
>> +					   spaceres, &new_diroffset);
>>   		if (error)
>>   			goto out_bmap_cancel;
>>   
>>   		xfs_trans_ichgtime(tp, target_dp,
>>   					XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
>> -
> Huh?
>
Sorry, will fix
>>   		if (new_parent && src_is_directory) {
>>   			error = xfs_bumplink(tp, target_dp);
>>   			if (error)
>> @@ -3126,7 +3127,7 @@ xfs_rename(
>>   		 */
>>   		error = xfs_dir_replace(tp, target_dp, target_name,
>>   					src_ip->i_ino, &first_block, &dfops,
>> -					spaceres, NULL);
>> +					spaceres, &new_diroffset);
>>   		if (error)
>>   			goto out_bmap_cancel;
>>   
>> @@ -3161,7 +3162,7 @@ xfs_rename(
>>   		 */
>>   		error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,
>>   					target_dp->i_ino, &first_block, &dfops,
>> -					spaceres, NULL);
>> +					spaceres, &new_diroffset);
>>   		ASSERT(error != -EEXIST);
>>   		if (error)
>>   			goto out_bmap_cancel;
>> @@ -3200,11 +3201,12 @@ xfs_rename(
>>   	 */
>>   	if (wip) {
>>   		error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino,
>> -					&first_block, &dfops, spaceres, NULL);
>> +					&first_block, &dfops, spaceres,
>> +					&old_diroffset);
>>   	} else
>>   		error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
>>   					   &first_block, &dfops, spaceres,
>> -					   NULL);
>> +					   &old_diroffset);
>>   	if (error)
>>   		goto out_bmap_cancel;
>>   
>> @@ -3234,6 +3236,18 @@ xfs_rename(
>>   		VFS_I(wip)->i_state &= ~I_LINKABLE;
>>   	}
>>   
>> +	if (new_parent && xfs_sb_version_hasparent(&mp->m_sb)) {
> I'm confused about checking new_parent -- does this cause us to forget
> to update the pptr for a rename within a directory?
>
> I'm assuming that all of these directory operations will get their own
> xfstests in time... (create a file, check pptr; hardlink a file, check
> both pptrs; delete one of the links, check pptrs; check pptr after a
> rename within a dir; check pptr after a rename between dirs; etc.)
>
> --D
Oh, initially I had added this with the thought that we update parent 
pointers when we get new parents, but I think you're right. We'll need 
to update if the name changes too.  I will take out the new_parent 
check.  Thx!
>> +		error = xfs_parent_add(tp, target_dp, src_ip, target_name,
>> +				       new_diroffset, &dfops, &first_block);
>> +		if (error)
>> +			goto out_bmap_cancel;
>> +
>> +		error = xfs_parent_remove(tp, src_dp, src_ip,
>> +					  old_diroffset, &dfops, &first_block);
>> +		if (error)
>> +			goto out_bmap_cancel;
>> +	}
>> +
>>   	xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
>>   	xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE);
>>   	if (new_parent)
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message tomajordomo@vger.kernel.org
>> More majordomo info athttp://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH v3 14/17] xfs: remove parent pointers in unlink
  2017-11-28 18:24   ` Darrick J. Wong
@ 2017-11-29 18:44     ` Allison Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:44 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs, Dave Chinner

On 11/28/2017 11:24 AM, Darrick J. Wong wrote:

> On Fri, Nov 17, 2017 at 11:21:42AM -0700, Allison Henderson wrote:
>> From: Dave Chinner<dchinner@redhat.com>
>>
>> This patch removes the parent pointer attribute during unlink
>>
>> [bfoster: rebase, use VFS inode generation]
>> [achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t
>> 	   implemented xfs_attr_remove_parent]
>>
>> Signed-off-by: Dave Chinner<dchinner@redhat.com>
>> Signed-off-by: Allison Henderson<allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_parent.c | 20 ++++++++++++++++++++
>>   fs/xfs/xfs_attr.h          |  4 ++++
>>   fs/xfs/xfs_inode.c         | 10 +++++++++-
>>   3 files changed, 33 insertions(+), 1 deletion(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
>> index 5eec0ab..9278c89 100644
>> --- a/fs/xfs/libxfs/xfs_parent.c
>> +++ b/fs/xfs/libxfs/xfs_parent.c
>> @@ -91,3 +91,23 @@ xfs_parent_add(
>>   		(void *)child_name->name, child_name->len, ATTR_PARENT);
>>   }
>>   
>> +/*
>> + * Remove a parent record from a child inode.
>> + */
>> +int
>> +xfs_parent_remove(
>> +        struct xfs_trans        *tp,
> Unused parameter.
>
>> +        struct xfs_inode        *parent,
>> +        struct xfs_inode        *child,
>> +        xfs_dir2_dataptr_t      diroffset,
>> +	struct xfs_defer_ops    *dfops,
> Inconsistent indenting here.
>
>> +	xfs_fsblock_t           *firstblock)
> Unused parameter.
>
>> +{
>> +	struct xfs_parent_name_rec rec;
>> +
>> +	xfs_init_parent_name_rec(&rec, parent->i_ino,
>> +		VFS_I(parent)->i_generation, diroffset);
> Two tabs, please...
>
>> +
>> +	return xfs_attr_remove_deferred(child, dfops, &rec, sizeof(rec),
>> +					ATTR_PARENT);
> ...or this indentation style.
>
>> +}
>> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
>> index 09ef747..0829687 100644
>> --- a/fs/xfs/xfs_attr.h
>> +++ b/fs/xfs/xfs_attr.h
>> @@ -198,4 +198,8 @@ int xfs_parent_add(struct xfs_trans *tp, struct xfs_inode *parent,
>>   		struct xfs_inode *child, struct xfs_name *child_name,
>>   		xfs_dir2_dataptr_t diroffset, struct xfs_defer_ops *dfops,
>>   		xfs_fsblock_t *firstblock);
>> +int xfs_parent_remove(struct xfs_trans *tp, struct xfs_inode *parent,
>> +		      struct xfs_inode *child, xfs_dir2_dataptr_t diroffset,
>> +		      struct xfs_defer_ops *dfops, xfs_fsblock_t *firstblock);
>> +
>>   #endif	/* __XFS_ATTR_H__ */
>> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
>> index 0ad843d..a289a40 100644
>> --- a/fs/xfs/xfs_inode.c
>> +++ b/fs/xfs/xfs_inode.c
>> @@ -2607,6 +2607,7 @@ xfs_remove(
>>   	struct xfs_defer_ops	dfops;
>>   	xfs_fsblock_t           first_block;
>>   	uint			resblks;
>> +	uint32_t		dir_offset;
> xfs_dir2_dataptr_t	dir_offset; ?
>
> --D
>
Alrighty, I'll fold all these in.  Thx!
>>   
>>   	trace_xfs_remove(dp, name);
>>   
>> @@ -2687,12 +2688,19 @@ xfs_remove(
>>   
>>   	xfs_defer_init(&dfops, &first_block);
>>   	error = xfs_dir_removename(tp, dp, name, ip->i_ino, &first_block,
>> -				   &dfops, resblks, NULL);
>> +				   &dfops, resblks, &dir_offset);
>>   	if (error) {
>>   		ASSERT(error != -ENOENT);
>>   		goto out_bmap_cancel;
>>   	}
>>   
>> +	if (xfs_sb_version_hasparent(&mp->m_sb)) {
>> +		error = xfs_parent_remove(tp, dp, ip, dir_offset, &dfops,
>> +					  &first_block);
>> +		if (error)
>> +			goto out_bmap_cancel;
>> +	}
>> +
>>   	/*
>>   	 * If this is a synchronous mount, make sure that the
>>   	 * remove transaction goes to disk before returning to
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message tomajordomo@vger.kernel.org
>> More majordomo info athttp://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH v3 13/17] xfs: add parent attributes to link
  2017-11-28 18:37   ` Darrick J. Wong
@ 2017-11-29 18:45     ` Allison Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:45 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs, Dave Chinner

On 11/28/2017 11:37 AM, Darrick J. Wong wrote:

> On Fri, Nov 17, 2017 at 11:21:41AM -0700, Allison Henderson wrote:
>> From: Dave Chinner<dchinner@redhat.com>
>>
>> This patch modifies xfs_link to add a parent pointer to the inode.
>> xfs_link will also need to create an attribute fork if the inode does
>> not already have one.
>>
>> [bfoster: rebase, use VFS inode fields, fix xfs_bmap_finish() usage]
>> [achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
>> 	   fixed null pointer bugs]
>>
>> Signed-off-by: Dave Chinner<dchinner@redhat.com>
>> Signed-off-by: Allison Henderson<allison.henderson@oracle.com>
>> ---
>>   fs/xfs/xfs_inode.c | 61 +++++++++++++++++++++++++++++++++++++++++-------------
>>   1 file changed, 47 insertions(+), 14 deletions(-)
>>
>> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
>> index 1c45c73..0ad843d 100644
>> --- a/fs/xfs/xfs_inode.c
>> +++ b/fs/xfs/xfs_inode.c
>> @@ -1451,6 +1451,8 @@ xfs_link(
>>   	struct xfs_defer_ops	dfops;
>>   	xfs_fsblock_t           first_block;
>>   	int			resblks;
>> +	uint32_t		diroffset;
> xfs_dir2_dataptr_t?
>
>> +	bool			first_parent = false;
>>   
>>   	trace_xfs_link(tdp, target_name);
>>   
>> @@ -1467,6 +1469,25 @@ xfs_link(
>>   	if (error)
>>   		goto std_return;
>>   
>> +	/*
>> +	 * If we have parent pointers and there is no attribute fork (i.e. we
>> +	 * are linking in a O_TMPFILE created inode) we need to add the
>> +	 * attribute fork to the inode. Because we may have an existing data
>> +	 * fork, we do this before we start the link transaction as adding an
>> +	 * attribute fork requires it's own transaction.
> About that -- does the deferred 'add xattr' operation have an implicit
> assumption that the inode in question already has an attribute fork?
No...  IIRC in one of the last review we talked about having the 
deferred attribute code take care
setting the forks so that we didnt have to have extra routines for 
setting the first parent.
So the v2 patch set used to have a xfs_attr_set_first_parent which in v3 
has now been removed and
folded into the first part of xfs_attr_set_args (in the first patch of 
the set).  Which probably means the
the below code can just come out since the condition it check for is 
never true I believe.

> I
> suppose so long as we're careful to ensure that we never queue up a
> deferred op until after we've committed the transaction that adds the
> attr fork then that assumption is ok.
I'll point in out in the appropriate patch rather than trying to 
describe it here.

> (I think the xfs_trans_attr() function needs an ASSERT(xfs_inode_hasattr())
> so we can check that assumption.)
>
>> +	 */
>> +	if (xfs_sb_version_hasparent(&mp->m_sb) && !xfs_inode_hasattr(sip)) {
>> +		int sf_size = sizeof(struct xfs_attr_sf_hdr) +
>> +				XFS_ATTR_SF_ENTSIZE_BYNAME(
>> +					sizeof(struct xfs_parent_name_rec),
>> +					target_name->len);
>> +		ASSERT(VFS_I(sip)->i_nlink == 0);
>> +		error = xfs_bmap_add_attrfork(sip, sf_size, 0);
>> +		if (error)
>> +			goto std_return;
>> +		first_parent = true;
>> +	}
>> +
>>   	resblks = XFS_LINK_SPACE_RES(mp, target_name->len);
>>   	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, resblks, 0, 0, &tp);
>>   	if (error == -ENOSPC) {
>> @@ -1498,8 +1519,6 @@ xfs_link(
>>   			goto error_return;
>>   	}
>>   
>> -	xfs_defer_init(&dfops, &first_block);
>> -
>>   	/*
>>   	 * Handle initial link state of O_TMPFILE inode
>>   	 */
>> @@ -1509,36 +1528,50 @@ xfs_link(
>>   			goto error_return;
>>   	}
>>   
>> +	xfs_defer_init(&dfops, &first_block);
>>   	error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
>> -				   &first_block, &dfops, resblks, NULL);
>> +				   &first_block, &dfops, resblks, &diroffset);
>>   	if (error)
>> -		goto error_return;
>> +		goto out_defer_cancel;
> Oh good, you fixed the problem where xfs_defer_cancel doesn't get called
> on the error jumpout.
>
>>   	xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
>>   	xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
>>   
>>   	error = xfs_bumplink(tp, sip);
>>   	if (error)
>> -		goto error_return;
>> +		goto out_defer_cancel;
>>   
>>   	/*
>> -	 * If this is a synchronous mount, make sure that the
>> -	 * link transaction goes to disk before returning to
>> -	 * the user.
>> +	 * If we have parent pointers, we now need to add the parent record to
>> +	 * the attribute fork of the inode. If this is the initial parent
>> +	 * atribute, we need to create it correctly, otherwise we can just add
> "attribute"
>
> --D
>
>> +	 * the parent to the inode.
>> +	 */
>> +	if (xfs_sb_version_hasparent(&mp->m_sb)) {
>> +		error = xfs_parent_add(tp, tdp, sip, target_name,
>> +				       diroffset, &dfops,
>> +				       &first_block);
>> +		if (error)
>> +			goto out_defer_cancel;
>> +	}
>> +
>> +	/*
>> +	 * If this is a synchronous mount, make sure that the link transaction
>> +	 * goes to disk before returning to the user.
>>   	 */
>>   	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
>>   		xfs_trans_set_sync(tp);
>>   
>>   	error = xfs_defer_finish(&tp, &dfops);
>> -	if (error) {
>> -		xfs_defer_cancel(&dfops);
>> -		goto error_return;
>> -	}
>> +	if (error)
>> +		goto out_defer_cancel;
>>   
>>   	return xfs_trans_commit(tp);
>>   
>> - error_return:
>> +out_defer_cancel:
>> +	xfs_defer_cancel(&dfops);
>> +error_return:
>>   	xfs_trans_cancel(tp);
>> - std_return:
>> +std_return:
>>   	return error;
>>   }
>>   
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message tomajordomo@vger.kernel.org
>> More majordomo info athttp://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH v3 12/17] xfs: parent pointer attribute creation
  2017-11-28 18:54     ` Darrick J. Wong
@ 2017-11-29 18:46       ` Allison Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:46 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs, Dave Chinner

On 11/28/2017 11:54 AM, Darrick J. Wong wrote:

> On Tue, Nov 28, 2017 at 10:49:18AM -0800, Darrick J. Wong wrote:
>> On Fri, Nov 17, 2017 at 11:21:40AM -0700, Allison Henderson wrote:
>>> From: Dave Chinner<dchinner@redhat.com>
>>>
>>> Add parent pointer attribute during xfs_create, and
>>> subroutines to initialize attributes
>>>
>>> [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]
>>>
>>> Signed-off-by: Dave Chinner<dchinner@redhat.com>
>>> Signed-off-by: Allison Henderson<allison.henderson@oracle.com>
>>> ---
>>> v2: remove unnecessary ENOSPC handling in xfs_attr_set_first_parent
>>>
>>> Signed-off-by: Allison Henderson<allison.henderson@oracle.com>
>>> ---
>>>   fs/xfs/Makefile            |  1 +
>>>   fs/xfs/libxfs/xfs_parent.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++
>>>   fs/xfs/xfs_attr.h          | 15 +++++++-
>>>   fs/xfs/xfs_inode.c         | 16 +++++++-
>>>   4 files changed, 123 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
>>> index ec6486b..3015bca 100644
>>> --- a/fs/xfs/Makefile
>>> +++ b/fs/xfs/Makefile
>>> @@ -52,6 +52,7 @@ xfs-y				+= $(addprefix libxfs/, \
>>>   				   xfs_inode_fork.o \
>>>   				   xfs_inode_buf.o \
>>>   				   xfs_log_rlimit.o \
>>> +				   xfs_parent.o \
>>>   				   xfs_ag_resv.o \
>>>   				   xfs_rmap.o \
>>>   				   xfs_rmap_btree.o \
>>> diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
>>> new file mode 100644
>>> index 0000000..5eec0ab
>>> --- /dev/null
>>> +++ b/fs/xfs/libxfs/xfs_parent.c
>>> @@ -0,0 +1,93 @@
>>> +/*
>>> + * Copyright (c) 2015 Red Hat, Inc.
>>> + * All rights reserved.
>> /me sticks his hand in the hornet's nest: given how much Allison has
>> reworked the original pptr code to use deferred ops, maybe it's more
>> appropriate to have both the RH copyright for the original code and the
>> oracle copyright for the pptr stuff at the top of this file?
>>
>> (Not a lawyer, don't play one on tv.)
>>
>>> + *
>>> + * 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 "xfs_format.h"
>>> +#include "xfs_log_format.h"
>>> +#include "xfs_shared.h"
>>> +#include "xfs_trans_resv.h"
>>> +#include "xfs_mount.h"
>>> +#include "xfs_bmap_btree.h"
>>> +#include "xfs_inode.h"
>>> +#include "xfs_error.h"
>>> +#include "xfs_trace.h"
>>> +#include "xfs_trans.h"
>>> +#include "xfs_attr.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,
>>> +			unsigned long long int		p_ino,
>> xfs_ino_t ?
>>
>>> +			unsigned int			p_gen,
>> uint32_t ?
Ok, I'll get these updated
>>> +			unsigned int			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);
>>> +}
>>> +
>>> +/*
>>> + * Add a parent record to an inode with existing parent records.
>>> + */
>>> +int
>>> +xfs_parent_add(
>>> +	struct xfs_trans        *tp,
>>> +	struct xfs_inode        *parent,
>>> +	struct xfs_inode        *child,
>>> +	struct xfs_name         *child_name,
>>> +	uint32_t                diroffset,
>>> +	struct xfs_defer_ops    *dfops,
>>> +	xfs_fsblock_t           *firstblock)
>> This function doesn't use tp or firstblock, so you can omit the parameters.
>>
>>> +{
>>> +	struct xfs_parent_name_rec rec;
>>> +
>>> +	xfs_init_parent_name_rec(&rec, parent->i_ino,
>>> +		VFS_I(parent)->i_generation, diroffset);
>>> +
>>> +	return xfs_attr_set_deferred(child, dfops, &rec, sizeof(rec),
>>> +		(void *)child_name->name, child_name->len, ATTR_PARENT);
>>> +}
>> Do you think these functions will be useful for xfs_repair (and
>> xfs_scrub) to rebuild the parent pointers?  These three functions seem
>> like the sort of thing that could go into libxfs/xfs_parent.c to get
>> shared around.
>>
>> I guess I did babble last week about moving pretty much everything
>> related to handling the pptr xattrs into libxfs so that the only code in
>> fs/xfs/xfs_parent.c is the ioctl implementation.  Maybe also an enhanced
>> "connect this file handle dentry to its parents" feature for file handle
>> users, though the current system hasn't generated a ton of complaints so
>> this might be unnecessary.
> Bah, /me fails to notice that this was added to libxfs/xfs_parent.c.
> Please substitute the previous two paragraphs with:
>
> Why are the function prototypes for these functions in fs/xfs/xfs_attr.h?
> They ought to be in libxfs/xfs_parent.h.
>
> --D
No worries, I think I had added them there next to the other
create routines before they got removed from the last version.
I will move them over to xfs_parent.h
>> --D
>>
>>> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
>>> index 1f5c711..09ef747 100644
>>> --- a/fs/xfs/xfs_attr.h
>>> +++ b/fs/xfs/xfs_attr.h
>>> @@ -19,6 +19,8 @@
>>>   #define	__XFS_ATTR_H__
>>>   
>>>   #include "libxfs/xfs_defer.h"
>>> +#include "libxfs/xfs_da_format.h"
>>> +#include "libxfs/xfs_format.h"
>>>   
>>>   struct xfs_inode;
>>>   struct xfs_da_args;
>>> @@ -184,5 +186,16 @@ int xfs_attr_set_deferred(struct xfs_inode *dp, struct xfs_defer_ops *dfops,
>>>   			  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);
>>> -
>>> +/*
>>> + * Parent pointer attribute prototypes
>>> + */
>>> +void xfs_init_parent_name_rec(struct xfs_parent_name_rec *rec,
>>> +		unsigned long long int p_ino, unsigned int p_gen,
>>> +		unsigned int  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,
>>> +		xfs_dir2_dataptr_t diroffset, struct xfs_defer_ops *dfops,
>>> +		xfs_fsblock_t *firstblock);
>>>   #endif	/* __XFS_ATTR_H__ */
>>> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
>>> index f7986d8..1c45c73 100644
>>> --- a/fs/xfs/xfs_inode.c
>>> +++ b/fs/xfs/xfs_inode.c
>>> @@ -1164,6 +1164,7 @@ xfs_create(
>>>   	struct xfs_dquot	*pdqp = NULL;
>>>   	struct xfs_trans_res	*tres;
>>>   	uint			resblks;
>>> +	xfs_dir2_dataptr_t	diroffset;
>>>   
>>>   	trace_xfs_create(dp, name);
>>>   
>>> @@ -1253,7 +1254,7 @@ xfs_create(
>>>   	error = xfs_dir_createname(tp, dp, name, ip->i_ino,
>>>   					&first_block, &dfops, resblks ?
>>>   					resblks - XFS_IALLOC_SPACE_RES(mp) : 0,
>>> -					NULL);
>>> +					&diroffset);
>>>   	if (error) {
>>>   		ASSERT(error != -ENOSPC);
>>>   		goto out_trans_cancel;
>>> @@ -1272,6 +1273,19 @@ xfs_create(
>>>   	}
>>>   
>>>   	/*
>>> +	 * If we have parent pointers, we need to add the attribute containing
>>> +	 * the parent information now. This must be done within the same
>>> +	 * transaction the directory entry is created, while the new inode
>>> +	 * contains nothing in the inode literal area.
>>> +	 */
>>> +	if (xfs_sb_version_hasparent(&mp->m_sb)) {
>>> +		error = xfs_parent_add(tp, dp, ip, name, diroffset,
>>> +					  &dfops, &first_block);
>>> +		if (error)
>>> +			goto out_bmap_cancel;
>>> +	}
>>> +
>>> +	/*
>>>   	 * If this is a synchronous mount, make sure that the
>>>   	 * create transaction goes to disk before returning to
>>>   	 * the user.
>>> -- 
>>> 2.7.4
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>>> the body of a message tomajordomo@vger.kernel.org
>>> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=pCNDoHbIEzOXYs_xG8vyNzjLRVTHUvJd0iTmeI0T0Nk&s=qkaTRZTOctSKb7vASgNK9EpEnLVhVPD_EU-pgcoZCOE&e=
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message tomajordomo@vger.kernel.org
>> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=pCNDoHbIEzOXYs_xG8vyNzjLRVTHUvJd0iTmeI0T0Nk&s=qkaTRZTOctSKb7vASgNK9EpEnLVhVPD_EU-pgcoZCOE&e=
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message tomajordomo@vger.kernel.org
> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=pCNDoHbIEzOXYs_xG8vyNzjLRVTHUvJd0iTmeI0T0Nk&s=qkaTRZTOctSKb7vASgNK9EpEnLVhVPD_EU-pgcoZCOE&e=


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

* Re: [PATCH v3 11/17] Add the extra space requirements for parent pointer attributes when calculating the minimum log size during mkfs
  2017-11-28 18:51   ` Darrick J. Wong
@ 2017-11-29 18:47     ` Allison Henderson
  2017-11-29 20:18       ` Darrick J. Wong
  0 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:47 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 11/28/2017 11:51 AM, Darrick J. Wong wrote:

> On Fri, Nov 17, 2017 at 11:21:39AM -0700, Allison Henderson wrote:
>> Signed-off-by: Allison Henderson<allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_log_rlimit.c | 34 ++++++++++++++++++++++++++++++++++
>>   1 file changed, 34 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_log_rlimit.c b/fs/xfs/libxfs/xfs_log_rlimit.c
>> index c105979..beec9bf 100644
>> --- a/fs/xfs/libxfs/xfs_log_rlimit.c
>> +++ b/fs/xfs/libxfs/xfs_log_rlimit.c
>> @@ -39,6 +39,40 @@ xfs_log_calc_max_attrsetm_res(
>>   {
>>   	int			size;
>>   	int			nblks;
>> +	struct xfs_trans_resv   *resp = M_RES(mp);
>> +
>> +	/* Calculate extra space needed for parent pointer attributes */
>> +	if (!xfs_sb_version_hasparent(&mp->m_sb)) {
> if (xfs_sb_version_hasparent()) ?
>
> --D
yeah I think you're right.   This means there's something wrong with the 
check then, because it appears to succeed.  I will debug that, it's 
probably the command line flag i added to mkfs.xfs to exercise it.
>> +
>> +		/* 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;
>> +	}
>> +
>>   
>>   	size = xfs_attr_leaf_entsize_local_max(mp->m_attr_geo->blksize) -
>>   	       MAXNAMELEN - 1;
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message tomajordomo@vger.kernel.org
>> More majordomo info athttp://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH v3 10/17] xfs: extent transaction reservations for parent attributes
  2017-11-28 18:58   ` Darrick J. Wong
@ 2017-11-29 18:48     ` Allison Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:48 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs, Dave Chinner

On 11/28/2017 11:58 AM, Darrick J. Wong wrote:

> On Fri, Nov 17, 2017 at 11:21:38AM -0700, Allison Henderson wrote:
>> From: Dave Chinner<dchinner@redhat.com>
>>
>> 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>
>> ---
>>   fs/xfs/libxfs/xfs_format.h     |   5 ++
>>   fs/xfs/libxfs/xfs_trans_resv.c | 103 ++++++++++++++++++++++++++++++++---------
>>   2 files changed, 85 insertions(+), 23 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
>> index b9ea5bf..121862a 100644
>> --- a/fs/xfs/libxfs/xfs_format.h
>> +++ b/fs/xfs/libxfs/xfs_format.h
>> @@ -556,6 +556,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/fs/xfs/libxfs/xfs_trans_resv.c b/fs/xfs/libxfs/xfs_trans_resv.c
>> index 6bd916b..54399e2 100644
>> --- a/fs/xfs/libxfs/xfs_trans_resv.c
>> +++ b/fs/xfs/libxfs/xfs_trans_resv.c
>> @@ -802,29 +802,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;
>> @@ -846,15 +847,69 @@ 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;
>> +
>> +	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;
> djwong, clearly reviewing patches in reverse order:
>
> This looks pretty similar to the function in the next patch; can they
> be combined into a single helper?
I think so, I'll see if I can get it consolidated
>> +}
>> +
>> +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;
>> @@ -886,6 +941,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.
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message tomajordomo@vger.kernel.org
>> More majordomo info athttp://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH v3 09/17] xfs: define parent pointer xattr format
  2017-11-28 18:59   ` Darrick J. Wong
@ 2017-11-29 18:48     ` Allison Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:48 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs, Dave Chinner

On 11/28/2017 11:59 AM, Darrick J. Wong wrote:

> On Fri, Nov 17, 2017 at 11:21:37AM -0700, Allison Henderson wrote:
>> From: Dave Chinner<dchinner@redhat.com>
>>
>> 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]
>>
>> Signed-off-by: Dave Chinner<dchinner@redhat.com>
>> Signed-off-by: Allison Henderson<allison.henderson@oracle.com>
> Looks ok,
> Reviewed-by: Darrick J. Wong<darrick.wong@oracle.com>
Great!  Thx!
>> ---
>> v2: changed p_ino to xfs_ino_t and p_namelen to uint8_t
>>
>> Signed-off-by: Allison Henderson<allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_format.h | 27 +++++++++++++++++++++++++++
>>   1 file changed, 27 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
>> index 23229f0..b9ea5bf 100644
>> --- a/fs/xfs/libxfs/xfs_format.h
>> +++ b/fs/xfs/libxfs/xfs_format.h
>> @@ -18,6 +18,8 @@
>>   #ifndef __XFS_FORMAT_H__
>>   #define __XFS_FORMAT_H__
>>   
>> +#include "xfs_da_format.h"
>> +
>>   /*
>>    * XFS On Disk Format Definitions
>>    *
>> @@ -1716,4 +1718,29 @@ struct xfs_acl {
>>   #define SGI_ACL_FILE_SIZE	(sizeof(SGI_ACL_FILE)-1)
>>   #define SGI_ACL_DEFAULT_SIZE	(sizeof(SGI_ACL_DEFAULT)-1)
>>   
>> +/*
>> + * 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_FORMAT_H__ */
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message tomajordomo@vger.kernel.org
>> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=xYa1QFkMf-mQloqcjnFtS8TgbN6yHRlagSEr85e-sHc&s=gZ018F2EivpOHk9ZyNrB0BzKsaeKTdLo1m3lLF21j6M&e=
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message tomajordomo@vger.kernel.org
> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=xYa1QFkMf-mQloqcjnFtS8TgbN6yHRlagSEr85e-sHc&s=gZ018F2EivpOHk9ZyNrB0BzKsaeKTdLo1m3lLF21j6M&e=


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

* Re: [PATCH v3 08/17] xfs: add parent pointer support to attribute code
  2017-11-28 19:01   ` Darrick J. Wong
@ 2017-11-29 18:48     ` Allison Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:48 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs, Mark Tinguely, Dave Chinner

On 11/28/2017 12:01 PM, Darrick J. Wong wrote:

> On Fri, Nov 17, 2017 at 11:21:36AM -0700, Allison Henderson wrote:
>> From: Mark Tinguely<tinguely@sgi.com>
>>
>> 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>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c      |  2 +-
>>   fs/xfs/libxfs/xfs_da_format.h | 12 ++++++++----
>>   fs/xfs/xfs_attr.h             |  2 ++
>>   3 files changed, 11 insertions(+), 5 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 61e8343..9d4d883 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -408,7 +408,7 @@ xfs_attr_set(
>>   	struct xfs_da_args	args;
>>   	struct xfs_defer_ops	dfops;
>>   	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/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h
>> index 3771edc..5f94c84 100644
>> --- a/fs/xfs/libxfs/xfs_da_format.h
>> +++ b/fs/xfs/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 */
> Please fix the indenting to be consistent with the previous line.
>
> Also, I think you can drop the word 'secure' from the comment.
>
> --D
Sure, will do
>>   #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
>> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
>> index 10fc466..1f5c711 100644
>> --- a/fs/xfs/xfs_attr.h
>> +++ b/fs/xfs/xfs_attr.h
>> @@ -46,6 +46,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_KERNOTIME	0x1000	/* [kernel] don't update inode timestamps */
>>   #define ATTR_KERNOVAL	0x2000	/* [kernel] get attr size only, not value */
>> @@ -57,6 +58,7 @@ struct xfs_attr_list_context;
>>   	{ ATTR_SECURE,		"SECURE" }, \
>>   	{ ATTR_CREATE,		"CREATE" }, \
>>   	{ ATTR_REPLACE,		"REPLACE" }, \
>> +	{ ATTR_PARENT,		"PARENT" }, \
>>   	{ ATTR_KERNOTIME,	"KERNOTIME" }, \
>>   	{ ATTR_KERNOVAL,	"KERNOVAL" }
>>   
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message tomajordomo@vger.kernel.org
>> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=cw4rl4ETYQ8y0D8yfJB2arjNQvUaE97_EYK7UNsCxbg&s=vn0vqNAj9GZS70-TE3qqHTrOdb_AKX0RTwcKODDodzQ&e=
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message tomajordomo@vger.kernel.org
> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=cw4rl4ETYQ8y0D8yfJB2arjNQvUaE97_EYK7UNsCxbg&s=vn0vqNAj9GZS70-TE3qqHTrOdb_AKX0RTwcKODDodzQ&e=


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

* Re: [PATCH v3 07/17] xfs: get directory offset when replacing a directory name
  2017-11-28 19:04   ` Darrick J. Wong
@ 2017-11-29 18:49     ` Allison Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:49 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs, Mark Tinguely, Dave Chinner

On 11/28/2017 12:04 PM, Darrick J. Wong wrote:

> On Fri, Nov 17, 2017 at 11:21:35AM -0700, Allison Henderson wrote:
>> From: Mark Tinguely<tinguely@sgi.com>
>>
>> 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]
>>
>> 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>
>> ---
>> v2: Changed typedefs to raw struct types
>>
>> Signed-off-by: Allison Henderson<allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_dir2.c       | 16 ++++++++++------
>>   fs/xfs/libxfs/xfs_dir2.h       |  3 ++-
>>   fs/xfs/libxfs/xfs_dir2_block.c |  4 ++--
>>   fs/xfs/libxfs/xfs_dir2_leaf.c  |  1 +
>>   fs/xfs/libxfs/xfs_dir2_node.c  |  1 +
>>   fs/xfs/libxfs/xfs_dir2_sf.c    |  2 ++
>>   fs/xfs/xfs_inode.c             | 28 +++++++++++++---------------
>>   7 files changed, 31 insertions(+), 24 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
>> index b647bf2..25b370b 100644
>> --- a/fs/xfs/libxfs/xfs_dir2.c
>> +++ b/fs/xfs/libxfs/xfs_dir2.c
>> @@ -508,13 +508,14 @@ xfs_dir_removename(
>>    */
>>   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;
>> @@ -563,6 +564,9 @@ xfs_dir_replace(
>>   		rval = xfs_dir2_leaf_replace(args);
>>   	else
>>   		rval = xfs_dir2_node_replace(args);
>> +
>> +	if (offset)
>> +		*offset = args->offset;
>>   out_free:
> FWIW I complained in the review for a subsequent patch about the out_free
> label moving to above the "if (offset)" hunk.
>
> --D
Ok, I'll get it folded in here
>>   	kmem_free(args);
>>   	return rval;
>> diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
>> index e1bd05d..5cc0b3f 100644
>> --- a/fs/xfs/libxfs/xfs_dir2.h
>> +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
>> index 4dbe2fc..69dfe64 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_block.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
>> @@ -865,9 +865,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/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
>> index 197e627..770b93f 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
>> @@ -1518,6 +1518,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/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
>> index 13d5244..860a612 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_node.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
>> @@ -2237,6 +2237,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/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
>> index 9e90c22..295458f 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_sf.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_sf.c
>> @@ -1045,6 +1045,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/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
>> index 358a98a..f7986d8 100644
>> --- a/fs/xfs/xfs_inode.c
>> +++ b/fs/xfs/xfs_inode.c
>> @@ -2774,16 +2774,14 @@ xfs_cross_rename(
>>   	int		dp2_flags = 0;
>>   
>>   	/* Swap inode number for dirent in first parent */
>> -	error = xfs_dir_replace(tp, dp1, name1,
>> -				ip2->i_ino,
>> -				first_block, dfops, spaceres);
>> +	error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, first_block, dfops,
>> +				spaceres, NULL);
>>   	if (error)
>>   		goto out_trans_abort;
>>   
>>   	/* Swap inode number for dirent in second parent */
>> -	error = xfs_dir_replace(tp, dp2, name2,
>> -				ip1->i_ino,
>> -				first_block, dfops, spaceres);
>> +	error = xfs_dir_replace(tp, dp2, name2, ip1->i_ino, first_block, dfops,
>> +				spaceres, NULL);
>>   	if (error)
>>   		goto out_trans_abort;
>>   
>> @@ -2797,8 +2795,8 @@ xfs_cross_rename(
>>   
>>   		if (S_ISDIR(VFS_I(ip2)->i_mode)) {
>>   			error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot,
>> -						dp1->i_ino, first_block,
>> -						dfops, spaceres);
>> +						dp1->i_ino, first_block, dfops,
>> +						spaceres, NULL);
>>   			if (error)
>>   				goto out_trans_abort;
>>   
>> @@ -2824,8 +2822,8 @@ xfs_cross_rename(
>>   
>>   		if (S_ISDIR(VFS_I(ip1)->i_mode)) {
>>   			error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot,
>> -						dp2->i_ino, first_block,
>> -						dfops, spaceres);
>> +						dp2->i_ino, first_block, dfops,
>> +						spaceres, NULL);
>>   			if (error)
>>   				goto out_trans_abort;
>>   
>> @@ -3072,8 +3070,8 @@ xfs_rename(
>>   		 * name at the destination directory, remove it first.
>>   		 */
>>   		error = xfs_dir_replace(tp, target_dp, target_name,
>> -					src_ip->i_ino,
>> -					&first_block, &dfops, spaceres);
>> +					src_ip->i_ino, &first_block, &dfops,
>> +					spaceres, NULL);
>>   		if (error)
>>   			goto out_bmap_cancel;
>>   
>> @@ -3107,8 +3105,8 @@ xfs_rename(
>>   		 * directory.
>>   		 */
>>   		error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,
>> -					target_dp->i_ino,
>> -					&first_block, &dfops, spaceres);
>> +					target_dp->i_ino, &first_block, &dfops,
>> +					spaceres, NULL);
>>   		ASSERT(error != -EEXIST);
>>   		if (error)
>>   			goto out_bmap_cancel;
>> @@ -3147,7 +3145,7 @@ xfs_rename(
>>   	 */
>>   	if (wip) {
>>   		error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino,
>> -					&first_block, &dfops, spaceres);
>> +					&first_block, &dfops, spaceres, NULL);
>>   	} else
>>   		error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
>>   					   &first_block, &dfops, spaceres,
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message tomajordomo@vger.kernel.org
>> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=OmnRnl5PP77MyfzpnPKFHs1VduH0GTb1IP9D8bssMT0&s=qI6-Zzze17jYSFlCUyua2MRuhxSgMoUvrV4u3VMMkko&e=
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message tomajordomo@vger.kernel.org
> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=OmnRnl5PP77MyfzpnPKFHs1VduH0GTb1IP9D8bssMT0&s=qI6-Zzze17jYSFlCUyua2MRuhxSgMoUvrV4u3VMMkko&e=


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

* Re: [PATCH v3 06/17] xfs: get directory offset when removing directory name
  2017-11-28 19:05   ` Darrick J. Wong
@ 2017-11-29 18:49     ` Allison Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:49 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs, Mark Tinguely, Dave Chinner

On 11/28/2017 12:05 PM, Darrick J. Wong wrote:

> On Fri, Nov 17, 2017 at 11:21:34AM -0700, Allison Henderson wrote:
>> From: Mark Tinguely<tinguely@sgi.com>
>>
>> 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]
>>
>> 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>
>> ---
>> v2: Changed typedefs to raw struct types
>>
>> Signed-off-by: Allison Henderson<allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_dir2.c       | 15 +++++++++------
>>   fs/xfs/libxfs/xfs_dir2.h       |  4 +++-
>>   fs/xfs/libxfs/xfs_dir2_block.c |  4 ++--
>>   fs/xfs/libxfs/xfs_dir2_leaf.c  |  5 +++--
>>   fs/xfs/libxfs/xfs_dir2_node.c  |  5 +++--
>>   fs/xfs/libxfs/xfs_dir2_sf.c    |  2 ++
>>   fs/xfs/xfs_inode.c             |  7 ++++---
>>   7 files changed, 26 insertions(+), 16 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
>> index a1ca460..b647bf2 100644
>> --- a/fs/xfs/libxfs/xfs_dir2.c
>> +++ b/fs/xfs/libxfs/xfs_dir2.c
>> @@ -443,13 +443,14 @@ xfs_dir_lookup(
>>    */
>>   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;
>> @@ -495,6 +496,8 @@ xfs_dir_removename(
>>   		rval = xfs_dir2_leaf_removename(args);
>>   	else
>>   		rval = xfs_dir2_node_removename(args);
>> +	if (offset)
>> +		*offset = args->offset;
>>   out_free:
> FWIW I complain in a review of a later patch about this label moving
> above the "if (offset)".
>
> --D
Alrighty, I'll fold it in here.  Thx!
>>   	kmem_free(args);
>>   	return rval;
>> diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
>> index e349900..e1bd05d 100644
>> --- a/fs/xfs/libxfs/xfs_dir2.h
>> +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
>> index 79684d5..4dbe2fc 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_block.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
>> @@ -791,9 +791,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/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
>> index 2ac7a7e..197e627 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
>> @@ -1383,9 +1383,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/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
>> index 8bc91f8..13d5244 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_node.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
>> @@ -1238,9 +1238,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/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
>> index 489bdef..9e90c22 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_sf.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_sf.c
>> @@ -919,6 +919,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;
>>   		}
>>   	}
>> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
>> index 3abcb17..358a98a 100644
>> --- a/fs/xfs/xfs_inode.c
>> +++ b/fs/xfs/xfs_inode.c
>> @@ -2639,8 +2639,8 @@ xfs_remove(
>>   		goto out_trans_cancel;
>>   
>>   	xfs_defer_init(&dfops, &first_block);
>> -	error = xfs_dir_removename(tp, dp, name, ip->i_ino,
>> -					&first_block, &dfops, resblks);
>> +	error = xfs_dir_removename(tp, dp, name, ip->i_ino, &first_block,
>> +				   &dfops, resblks, NULL);
>>   	if (error) {
>>   		ASSERT(error != -ENOENT);
>>   		goto out_bmap_cancel;
>> @@ -3150,7 +3150,8 @@ xfs_rename(
>>   					&first_block, &dfops, spaceres);
>>   	} else
>>   		error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
>> -					   &first_block, &dfops, spaceres);
>> +					   &first_block, &dfops, spaceres,
>> +					   NULL);
>>   	if (error)
>>   		goto out_bmap_cancel;
>>   
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message tomajordomo@vger.kernel.org
>> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=SFido2p7wk-upxZd3F1IYBhnhTXxEhm1z0kgoez1Z1o&s=_RhetEFcGr0rO6PClQan2EquBu2KJK77rWwerDaw25c&e=
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message tomajordomo@vger.kernel.org
> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=SFido2p7wk-upxZd3F1IYBhnhTXxEhm1z0kgoez1Z1o&s=_RhetEFcGr0rO6PClQan2EquBu2KJK77rWwerDaw25c&e=


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

* Re: [PATCH v3 05/17] xfs: get directory offset when adding directory name
  2017-11-28 19:07   ` Darrick J. Wong
@ 2017-11-29 18:50     ` Allison Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:50 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs, Mark Tinguely, Dave Chinner

On 11/28/2017 12:07 PM, Darrick J. Wong wrote:

> On Fri, Nov 17, 2017 at 11:21:33AM -0700, Allison Henderson wrote:
>> From: Mark Tinguely<tinguely@sgi.com>
>>
>> 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>
>> ---
>>   fs/xfs/libxfs/xfs_da_btree.h   | 1 +
>>   fs/xfs/libxfs/xfs_dir2.c       | 8 ++++++--
>>   fs/xfs/libxfs/xfs_dir2.h       | 3 ++-
>>   fs/xfs/libxfs/xfs_dir2_block.c | 1 +
>>   fs/xfs/libxfs/xfs_dir2_leaf.c  | 2 ++
>>   fs/xfs/libxfs/xfs_dir2_node.c  | 2 ++
>>   fs/xfs/libxfs/xfs_dir2_sf.c    | 2 ++
>>   fs/xfs/xfs_inode.c             | 9 +++++----
>>   fs/xfs/xfs_symlink.c           | 2 +-
>>   9 files changed, 22 insertions(+), 8 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
>> index ae6de17..bce96d6 100644
>> --- a/fs/xfs/libxfs/xfs_da_btree.h
>> +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
>> index ccf9783..a1ca460 100644
>> --- a/fs/xfs/libxfs/xfs_dir2.c
>> +++ b/fs/xfs/libxfs/xfs_dir2.c
>> @@ -268,7 +268,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;
>> @@ -323,6 +324,9 @@ xfs_dir_createname(
>>   	else
>>   		rval = xfs_dir2_node_addname(args);
>>   
>> +	/* return the location that this entry was place in the parent inode */
>> +	if (offset)
>> +		*offset = args->offset;
>>   out_free:
> FWIW I think I complain later about this label moving in a subsequent
> patch.... and you'll see this same comment two more times.  Downside of
> reviewing in backwards order, I guess.
>
> --D
>
No worries, I'll get it moved where it needs to be
>>   	kmem_free(args);
>>   	return rval;
>> @@ -570,7 +574,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/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
>> index 21c8f8b..e349900 100644
>> --- a/fs/xfs/libxfs/xfs_dir2.h
>> +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
>> index 43c902f..79684d5 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_block.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
>> @@ -552,6 +552,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/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
>> index 27297a6..2ac7a7e 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
>> @@ -863,6 +863,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/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
>> index 682e2bf..8bc91f8 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_node.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
>> @@ -2022,6 +2022,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/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
>> index be8b975..489bdef 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_sf.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_sf.c
>> @@ -407,6 +407,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.
>> @@ -498,6 +499,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/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
>> index 4ec5b7f..3abcb17 100644
>> --- a/fs/xfs/xfs_inode.c
>> +++ b/fs/xfs/xfs_inode.c
>> @@ -1252,7 +1252,8 @@ xfs_create(
>>   
>>   	error = xfs_dir_createname(tp, dp, name, ip->i_ino,
>>   					&first_block, &dfops, resblks ?
>> -					resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
>> +					resblks - XFS_IALLOC_SPACE_RES(mp) : 0,
>> +					NULL);
>>   	if (error) {
>>   		ASSERT(error != -ENOSPC);
>>   		goto out_trans_cancel;
>> @@ -1495,7 +1496,7 @@ xfs_link(
>>   	}
>>   
>>   	error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
>> -					&first_block, &dfops, resblks);
>> +				   &first_block, &dfops, resblks, NULL);
>>   	if (error)
>>   		goto error_return;
>>   	xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
>> @@ -3031,8 +3032,8 @@ xfs_rename(
>>   		 * to account for the ".." reference from the new entry.
>>   		 */
>>   		error = xfs_dir_createname(tp, target_dp, target_name,
>> -						src_ip->i_ino, &first_block,
>> -						&dfops, spaceres);
>> +					   src_ip->i_ino, &first_block, &dfops,
>> +					   spaceres, NULL);
>>   		if (error)
>>   			goto out_bmap_cancel;
>>   
>> diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
>> index 68d3ca2..fc803ae 100644
>> --- a/fs/xfs/xfs_symlink.c
>> +++ b/fs/xfs/xfs_symlink.c
>> @@ -363,7 +363,7 @@ xfs_symlink(
>>   	 * Create the directory entry for the symlink.
>>   	 */
>>   	error = xfs_dir_createname(tp, dp, link_name, ip->i_ino,
>> -					&first_block, &dfops, resblks);
>> +				   &first_block, &dfops, resblks, NULL);
>>   	if (error)
>>   		goto out_bmap_cancel;
>>   	xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message tomajordomo@vger.kernel.org
>> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=02ISa0rUacsoxueLmIUl9nJiJs3waUhjDqpEUPdTp9Y&s=uo_t9jIDLCSlKBgSmk2KhaRvYIkwpDH2sJeqhWGcSz8&e=
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message tomajordomo@vger.kernel.org
> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=02ISa0rUacsoxueLmIUl9nJiJs3waUhjDqpEUPdTp9Y&s=uo_t9jIDLCSlKBgSmk2KhaRvYIkwpDH2sJeqhWGcSz8&e=


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

* Re: [PATCH v3 04/17] Remove all strlen calls in all xfs_attr_* functions for attr names.
  2017-11-28 19:10   ` Darrick J. Wong
@ 2017-11-29 18:50     ` Allison Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:50 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 11/28/2017 12:10 PM, Darrick J. Wong wrote:

> On Fri, Nov 17, 2017 at 11:21:32AM -0700, Allison Henderson wrote:
>> 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>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 12 ++++++++----
>>   fs/xfs/xfs_acl.c         | 12 +++++++-----
>>   fs/xfs/xfs_attr.h        | 10 ++++++----
>>   fs/xfs/xfs_ioctl.c       | 13 ++++++++++---
>>   fs/xfs/xfs_iops.c        |  6 ++++--
>>   fs/xfs/xfs_trans_attr.c  |  2 +-
>>   fs/xfs/xfs_xattr.c       | 10 +++++++---
>>   7 files changed, 43 insertions(+), 22 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 68dc7e04..61e8343 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -80,6 +80,7 @@ xfs_attr_args_init(
>>   	struct xfs_da_args	*args,
>>   	struct xfs_inode	*dp,
>>   	const unsigned char	*name,
>> +	size_t			namelen,
>>   	int			flags)
>>   {
>>   
>> @@ -92,7 +93,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 */
>>   
>> @@ -138,6 +139,7 @@ int
>>   xfs_attr_get(
>>   	struct xfs_inode	*ip,
>>   	const unsigned char	*name,
>> +	size_t			namelen,
>>   	unsigned char		*value,
>>   	int			*valuelenp,
>>   	int			flags)
>> @@ -151,7 +153,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;
>>   
>> @@ -397,6 +399,7 @@ int
>>   xfs_attr_set(
>>   	struct xfs_inode	*dp,
>>   	const unsigned char	*name,
>> +	size_t			namelen,
>>   	unsigned char		*value,
>>   	int			valuelen,
>>   	int			flags)
>> @@ -413,7 +416,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;
>>   
>> @@ -511,6 +514,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;
>> @@ -524,7 +528,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/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
>> index 3354140..d7ee630 100644
>> --- a/fs/xfs/xfs_acl.c
>> +++ b/fs/xfs/xfs_acl.c
>> @@ -153,8 +153,8 @@ xfs_get_acl(struct inode *inode, int type)
>>   	if (!xfs_acl)
>>   		return ERR_PTR(-ENOMEM);
>>   
>> -	error = xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl,
>> -							&len, ATTR_ROOT);
>> +	error = xfs_attr_get(ip, ea_name, strlen((const char *)ea_name),
> /me wonders if all these strlen calls actually need that cast?
>
> --D
It may not, I'll see if they generate any warnings and pull them out if 
its quiet
>> +			     (unsigned char *)xfs_acl, &len, ATTR_ROOT);
>>   	if (error) {
>>   		/*
>>   		 * If the attribute doesn't exist make sure we have a negative
>> @@ -204,15 +204,17 @@ __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
>>   		len -= sizeof(struct xfs_acl_entry) *
>>   			 (XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count);
>>   
>> -		error = xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
>> -				len, ATTR_ROOT);
>> +		error = xfs_attr_set(ip, ea_name, strlen((const char *)ea_name),
>> +				     (unsigned char *)xfs_acl, len, ATTR_ROOT);
>>   
>>   		kmem_free(xfs_acl);
>>   	} else {
>>   		/*
>>   		 * A NULL ACL argument means we want to remove the ACL.
>>   		 */
>> -		error = xfs_attr_remove(ip, ea_name, ATTR_ROOT);
>> +		error = xfs_attr_remove(ip, ea_name,
>> +					strlen((const char *)ea_name),
>> +					ATTR_ROOT);
>>   
>>   		/*
>>   		 * If the attribute didn't exist to start with that's fine.
>> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
>> index 8d4762a..10fc466 100644
>> --- a/fs/xfs/xfs_attr.h
>> +++ b/fs/xfs/xfs_attr.h
>> @@ -164,16 +164,18 @@ 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, 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);
>>   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,
>> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
>> index aa75389..4664314 100644
>> --- a/fs/xfs/xfs_ioctl.c
>> +++ b/fs/xfs/xfs_ioctl.c
>> @@ -448,6 +448,7 @@ xfs_attrmulti_attr_get(
>>   {
>>   	unsigned char		*kbuf;
>>   	int			error = -EFAULT;
>> +	size_t			namelen;
>>   
>>   	if (*len > XFS_XATTR_SIZE_MAX)
>>   		return -EINVAL;
>> @@ -455,7 +456,9 @@ xfs_attrmulti_attr_get(
>>   	if (!kbuf)
>>   		return -ENOMEM;
>>   
>> -	error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags);
>> +	namelen = strlen((const char *)name);
>> +	error = xfs_attr_get(XFS_I(inode), name, namelen,
>> +			     kbuf, (int *)len, flags);
>>   	if (error)
>>   		goto out_kfree;
>>   
>> @@ -477,6 +480,7 @@ xfs_attrmulti_attr_set(
>>   {
>>   	unsigned char		*kbuf;
>>   	int			error;
>> +	size_t			namelen;
>>   
>>   	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>>   		return -EPERM;
>> @@ -487,7 +491,8 @@ xfs_attrmulti_attr_set(
>>   	if (IS_ERR(kbuf))
>>   		return PTR_ERR(kbuf);
>>   
>> -	error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags);
>> +	namelen = strlen((const char *)name);
>> +	error = xfs_attr_set(XFS_I(inode), name, namelen, kbuf, len, flags);
>>   	if (!error)
>>   		xfs_forget_acl(inode, name, flags);
>>   	kfree(kbuf);
>> @@ -501,10 +506,12 @@ xfs_attrmulti_attr_remove(
>>   	uint32_t		flags)
>>   {
>>   	int			error;
>> +	size_t			namelen;
>>   
>>   	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>>   		return -EPERM;
>> -	error = xfs_attr_remove(XFS_I(inode), name, flags);
>> +	namelen = strlen((const char *)name);
>> +	error = xfs_attr_remove(XFS_I(inode), name, namelen, flags);
>>   	if (!error)
>>   		xfs_forget_acl(inode, name, flags);
>>   	return error;
>> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
>> index 17081c7..5247bfc 100644
>> --- a/fs/xfs/xfs_iops.c
>> +++ b/fs/xfs/xfs_iops.c
>> @@ -70,8 +70,10 @@ xfs_initxattrs(
>>   	int			error = 0;
>>   
>>   	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
>> -		error = xfs_attr_set(ip, xattr->name, xattr->value,
>> -				      xattr->value_len, ATTR_SECURE);
>> +		error = xfs_attr_set(ip, xattr->name,
>> +				     strlen((const char *)xattr->name),
>> +				     xattr->value, xattr->value_len,
>> +				     ATTR_SECURE);
>>   		if (error < 0)
>>   			break;
>>   	}
>> diff --git a/fs/xfs/xfs_trans_attr.c b/fs/xfs/xfs_trans_attr.c
>> index 7c3290f..da71cce 100644
>> --- a/fs/xfs/xfs_trans_attr.c
>> +++ b/fs/xfs/xfs_trans_attr.c
>> @@ -87,7 +87,7 @@ xfs_trans_attr(
>>   
>>   	tp->t_flags |= XFS_TRANS_RESERVE;
>>   
>> -	error = xfs_attr_args_init(&args, ip, name, flags);
>> +	error = xfs_attr_args_init(&args, ip, name, name_len, flags);
>>   	if (error)
>>   		return error;
>>   
>> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
>> index 0594db4..10e58c6 100644
>> --- a/fs/xfs/xfs_xattr.c
>> +++ b/fs/xfs/xfs_xattr.c
>> @@ -38,6 +38,7 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>>   	int xflags = handler->flags;
>>   	struct xfs_inode *ip = XFS_I(inode);
>>   	int error, asize = size;
>> +	size_t namelen = strlen((const char *)name);
>>   
>>   	/* Convert Linux syscall to XFS internal ATTR flags */
>>   	if (!size) {
>> @@ -45,7 +46,8 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>>   		value = NULL;
>>   	}
>>   
>> -	error = xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags);
>> +	error = xfs_attr_get(ip, (unsigned char *)name, namelen, value,
>> +			     &asize, xflags);
>>   	if (error)
>>   		return error;
>>   	return asize;
>> @@ -81,6 +83,7 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>>   	int			xflags = handler->flags;
>>   	struct xfs_inode	*ip = XFS_I(inode);
>>   	int			error;
>> +	size_t			namelen = strlen((const char *)name);
>>   
>>   	/* Convert Linux syscall to XFS internal ATTR flags */
>>   	if (flags & XATTR_CREATE)
>> @@ -89,8 +92,9 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>>   		xflags |= ATTR_REPLACE;
>>   
>>   	if (!value)
>> -		return xfs_attr_remove(ip, (unsigned char *)name, xflags);
>> -	error = xfs_attr_set(ip, (unsigned char *)name,
>> +		return xfs_attr_remove(ip, (unsigned char *)name,
>> +				       namelen, xflags);
>> +	error = xfs_attr_set(ip, (unsigned char *)name, namelen,
>>   				(void *)value, size, xflags);
>>   	if (!error)
>>   		xfs_forget_acl(inode, name, xflags);
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message tomajordomo@vger.kernel.org
>> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=PIqW02S_a4Z1Jsl70xLj3mE36isVHVVP3_1LxDtWOjk&s=ZlbbDgc27LgTaOfhleUV5h90nVNn1q64Rae5Q2LJR_E&e=
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message tomajordomo@vger.kernel.org
> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=PIqW02S_a4Z1Jsl70xLj3mE36isVHVVP3_1LxDtWOjk&s=ZlbbDgc27LgTaOfhleUV5h90nVNn1q64Rae5Q2LJR_E&e=


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

* Re: [PATCH v3 03/17] Add xfs_attr_set_defered and xfs_attr_remove_defered
  2017-11-28 19:19   ` Darrick J. Wong
@ 2017-11-29 18:50     ` Allison Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:50 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 11/28/2017 12:19 PM, Darrick J. Wong wrote:

>> Subject: [PATCH v3 03/17] Add xfs_attr_set_defered and xfs_attr_remove_defered
> "deferred"
>
> On Fri, Nov 17, 2017 at 11:21:31AM -0700, Allison Henderson wrote:
>> 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>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++
>>   fs/xfs/xfs_attr.h        |  5 ++++
>>   2 files changed, 67 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 716df0f..68dc7e04 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -469,6 +469,40 @@ xfs_attr_set(
>>   	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;
>> +
>> +	ASSERT(namelen != 0);
>> +	ASSERT(valuelen != 0);
> We should stop the fs dead in its tracks here...
>
> if (!namelen || !valuelen) {
> 	ASSERT(0);
> 	return -EFSCORRUPTED;
> }
Sure.  I didnt think we continued to execute after a failed assert. Is 
the return statement reachable code?
>> +
>> +	new = kmem_alloc(XFS_ATTR_ITEM_SIZEOF(namelen, valuelen),
>> +			 KM_SLEEP|KM_NOFS);
>> +	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(&new->xattri_name_value[0], name, namelen);
>> +	memcpy(&new->xattri_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.
>>    * Transitions attribute list from Btree to shortform as necessary.
>> @@ -545,6 +579,34 @@ xfs_attr_remove(
>>   	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;
>> +
>> +	ASSERT(namelen != 0);
> Same here.
>
>> +
>> +	new = kmem_alloc(XFS_ATTR_ITEM_SIZEOF(namelen, 0), KM_SLEEP|KM_NOFS);
>> +	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(new->xattri_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/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
>> index 3ef3c77..8d4762a 100644
>> --- a/fs/xfs/xfs_attr.h
>> +++ b/fs/xfs/xfs_attr.h
>> @@ -175,5 +175,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);
> All of these libxfs functions shouldn't be declared in a non-libxfs header.
>
> --D
Ok, will move
>>   
>>   #endif	/* __XFS_ATTR_H__ */
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message tomajordomo@vger.kernel.org
>> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=Fpc-kg8nx9R7V_S5rLB6cTd7Q1hPGawg1Rion2qvk80&s=5zlzFr8rSR1c82zQ0g7vWVkvwHPG0JH4nii6W8HUe9M&e=
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message tomajordomo@vger.kernel.org
> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=Fpc-kg8nx9R7V_S5rLB6cTd7Q1hPGawg1Rion2qvk80&s=5zlzFr8rSR1c82zQ0g7vWVkvwHPG0JH4nii6W8HUe9M&e=


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

* Re: [PATCH v3 02/17] Set up infastructure for deferred attribute operations
  2017-11-28 19:45   ` Darrick J. Wong
  2017-11-29  1:19     ` Dave Chinner
@ 2017-11-29 18:51     ` Allison Henderson
  1 sibling, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:51 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 11/28/2017 12:45 PM, Darrick J. Wong wrote:

> On Fri, Nov 17, 2017 at 11:21:30AM -0700, Allison Henderson wrote:
>> 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>
>> ---
>>   fs/xfs/Makefile                |   2 +
>>   fs/xfs/libxfs/xfs_attr.c       |   3 +-
>>   fs/xfs/libxfs/xfs_defer.h      |   1 +
>>   fs/xfs/libxfs/xfs_log_format.h |  37 ++-
>>   fs/xfs/libxfs/xfs_types.h      |   1 +
>>   fs/xfs/xfs_attr.h              |  22 +-
>>   fs/xfs/xfs_attr_item.c         | 513 +++++++++++++++++++++++++++++++++++++++++
>>   fs/xfs/xfs_attr_item.h         | 117 ++++++++++
>>   fs/xfs/xfs_log_recover.c       | 140 +++++++++++
>>   fs/xfs/xfs_super.c             |   1 +
>>   fs/xfs/xfs_trans.h             |  13 ++
>>   fs/xfs/xfs_trans_attr.c        | 288 +++++++++++++++++++++++
>>   12 files changed, 1134 insertions(+), 4 deletions(-)
>>
>> diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
>> index a6e955b..ec6486b 100644
>> --- a/fs/xfs/Makefile
>> +++ b/fs/xfs/Makefile
>> @@ -106,6 +106,7 @@ xfs-y				+= xfs_log.o \
>>   				   xfs_bmap_item.o \
>>   				   xfs_buf_item.o \
>>   				   xfs_extfree_item.o \
>> +				   xfs_attr_item.o \
>>   				   xfs_icreate_item.o \
>>   				   xfs_inode_item.o \
>>   				   xfs_refcount_item.o \
>> @@ -115,6 +116,7 @@ xfs-y				+= xfs_log.o \
>>   				   xfs_trans_bmap.o \
>>   				   xfs_trans_buf.o \
>>   				   xfs_trans_extfree.o \
>> +				   xfs_trans_attr.o \
>>   				   xfs_trans_inode.o \
>>   				   xfs_trans_refcount.o \
>>   				   xfs_trans_rmap.o \
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index e5f2960..716df0f 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -41,6 +41,7 @@
>>   #include "xfs_quota.h"
>>   #include "xfs_trans_space.h"
>>   #include "xfs_trace.h"
>> +#include "xfs_attr_item.h"
>>   
>>   /*
>>    * xfs_attr.c
>> @@ -74,7 +75,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,
>> diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h
>> index d4f046d..ef0f8bf 100644
>> --- a/fs/xfs/libxfs/xfs_defer.h
>> +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
>> index 71de185..cecc27e 100644
>> --- a/fs/xfs/libxfs/xfs_log_format.h
>> +++ b/fs/xfs/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,28 @@ 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_attr_log_format {
>> +	uint64_t	alf_id;		/* attri identifier */
>> +	xfs_ino_t       alf_ino;	/* the inode for this attr operation */
>> +	uint32_t        alf_op_flags;	/* marks the op as a set or remove */
>> +	uint32_t        alf_name_len;	/* attr name length */
>> +	uint32_t        alf_value_len;	/* attr value length */
>> +	uint32_t        alf_attr_flags;	/* attr flags */
>> +	uint16_t	alf_type;	/* attri log item type */
>> +	uint16_t	alf_size;	/* size of this item */
> Type and size should go first so that the self-identification
> information ends up at the same byte offsets as the other log formats.
> This makes it much easier to dissect dirty log contents by hand if
> things get messy.
>
>> +	uint32_t	alf_pad;	/* pad to 64 bit aligned */
>> +};
> While we can reuse the attr_log_format for the attr-done log item, we
> can also use less space in the log if we condense that to:
>
> struct xfs_attrd_log_format {
> 	uint16_t	alfd_type;	/* attrd log item type */
> 	uint16_t	alfd_size;	/* size of this item */
> 	uint32_t	__pad;
> 	uint64_t	alfd_alf_id;	/* id of corresponding attri */
> };
>
> 16 bytes vs. 40.
Ok, that makes a lot of sense.  I'll get that updated
>>   #endif /* __XFS_LOG_FORMAT_H__ */
>> diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
>> index 0220159..5372063 100644
>> --- a/fs/xfs/libxfs/xfs_types.h
>> +++ b/fs/xfs/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 */
>> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
>> index 8542606..3ef3c77 100644
>> --- a/fs/xfs/xfs_attr.h
>> +++ b/fs/xfs/xfs_attr.h
>> @@ -18,6 +18,8 @@
>>   #ifndef __XFS_ATTR_H__
>>   #define	__XFS_ATTR_H__
>>   
>> +#include "libxfs/xfs_defer.h"
>> +
>>   struct xfs_inode;
>>   struct xfs_da_args;
>>   struct xfs_attr_list_context;
>> @@ -87,6 +89,22 @@ 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 name and val */
>> +	uint32_t	  xattri_name_len;    /* length of name */
>> +	uint32_t	  xattri_flags;       /* attr flags */
>> +	struct list_head  xattri_list;
>> +	char              xattri_name_value[0];
>> +};
>> +
>> +#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.
>>    */
>> @@ -154,6 +172,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);
>>   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/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
>> new file mode 100644
>> index 0000000..0ba2a54
>> --- /dev/null
>> +++ b/fs/xfs/xfs_attr_item.c
>> @@ -0,0 +1,513 @@
>> +/*
>> + * 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.
>> + */
>> +#include "xfs.h"
>> +#include "xfs_fs.h"
>> +#include "xfs_format.h"
>> +#include "xfs_log_format.h"
>> +#include "xfs_trans_resv.h"
>> +#include "xfs_bit.h"
>> +#include "xfs_mount.h"
>> +#include "xfs_trans.h"
>> +#include "xfs_trans_priv.h"
>> +#include "xfs_buf_item.h"
>> +#include "xfs_attr_item.h"
>> +#include "xfs_log.h"
>> +#include "xfs_btree.h"
>> +#include "xfs_rmap.h"
>> +#include "xfs_inode.h"
>> +#include "xfs_icache.h"
>> +
>> +static inline struct xfs_attri_log_item *ATTRI_ITEM(struct xfs_log_item *lip)
>> +{
>> +	return container_of(lip, struct xfs_attri_log_item, item);
>> +}
>> +
>> +void
>> +xfs_attri_item_free(
>> +	struct xfs_attri_log_item	*attrip)
>> +{
>> +	kmem_free(attrip->item.li_lv_shadow);
>> +	kmem_free(attrip);
>> +}
>> +
>> +/*
>> + * This returns the number of iovecs needed to log the given attri item.
>> + * We only need 1 iovec for an attri item.  It just logs the attr_log_format
>> + * structure.
>> + */
>> +static inline int
>> +xfs_attri_item_sizeof(
>> +	struct xfs_attri_log_item *attrip)
>> +{
>> +	return sizeof(struct xfs_attr_log_format);
>> +}
>> +
>> +STATIC void
>> +xfs_attri_item_size(
>> +	struct xfs_log_item	*lip,
>> +	int			*nvecs,
>> +	int			*nbytes)
>> +{
>> +	struct xfs_attri_log_item       *attrip = ATTRI_ITEM(lip);
>> +
>> +	*nvecs += 1;
>> +	*nbytes += xfs_attri_item_sizeof(attrip);
>> +
>> +	if (attrip->name_len > 0) {
>> +		*nvecs += 1;
>> +		nbytes += ATTR_NVEC_SIZE(attrip->name_len);
>> +	}
>> +
>> +	if (attrip->value_len > 0) {
>> +		*nvecs += 1;
>> +		nbytes += ATTR_NVEC_SIZE(attrip->value_len);
>> +	}
>> +}
>> +
>> +/*
>> + * This is called to fill in the vector of log iovecs for the
>> + * given attri log item. We use only 1 iovec, and we point that
>> + * at the attri_log_format structure embedded in the attri item.
>> + * It is at this point that we assert that all of the attr
>> + * slots in the attri item have been filled.
>> + */
>> +STATIC void
>> +xfs_attri_item_format(
>> +	struct xfs_log_item	*lip,
>> +	struct xfs_log_vec	*lv)
>> +{
>> +	struct xfs_attri_log_item	*attrip = ATTRI_ITEM(lip);
>> +	struct xfs_log_iovec	*vecp = NULL;
>> +
>> +	attrip->format.alf_type = XFS_LI_ATTRI;
>> +	attrip->format.alf_size = 1;
>> +
>> +	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRI_FORMAT,
>> +			&attrip->format,
>> +			xfs_attri_item_sizeof(attrip));
>> +	if (attrip->name_len > 0)
>> +		xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_NAME,
>> +				attrip->name, ATTR_NVEC_SIZE(attrip->name_len));
>> +
>> +	if (attrip->value_len > 0)
>> +		xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_VALUE,
>> +				attrip->value,
>> +				ATTR_NVEC_SIZE(attrip->value_len));
>> +}
>> +
>> +
>> +/*
>> + * Pinning has no meaning for an attri item, so just return.
>> + */
>> +STATIC void
>> +xfs_attri_item_pin(
>> +	struct xfs_log_item	*lip)
>> +{
>> +}
>> +
>> +/*
>> + * The unpin operation is the last place an ATTRI is manipulated in the log. It
>> + * is either inserted in the AIL or aborted in the event of a log I/O error. In
>> + * either case, the ATTRI transaction has been successfully committed to make it
>> + * this far. Therefore, we expect whoever committed the ATTRI to either
>> + * construct and commit the ATTRD or drop the ATTRD's reference in the event of
>> + * error. Simply drop the log's ATTRI reference now that the log is done with
>> + * it.
>> + */
>> +STATIC void
>> +xfs_attri_item_unpin(
>> +	struct xfs_log_item	*lip,
>> +	int			remove)
>> +{
>> +	struct xfs_attri_log_item	*attrip = ATTRI_ITEM(lip);
>> +
>> +	xfs_attri_release(attrip);
>> +}
>> +
>> +/*
>> + * attri items have no locking or pushing.  However, since ATTRIs are pulled
>> + * from the AIL when their corresponding ATTRDs are committed to disk, their
>> + * situation is very similar to being pinned.  Return XFS_ITEM_PINNED so that
>> + * the caller will eventually flush the log.  This should help in getting the
>> + * ATTRI out of the AIL.
>> + */
>> +STATIC uint
>> +xfs_attri_item_push(
>> +	struct xfs_log_item	*lip,
>> +	struct list_head	*buffer_list)
>> +{
>> +	return XFS_ITEM_PINNED;
>> +}
>> +
>> +/*
>> + * The ATTRI has been either committed or aborted if the transaction has been
>> + * cancelled. If the transaction was cancelled, an ATTRD isn't going to be
>> + * constructed and thus we free the ATTRI here directly.
>> + */
>> +STATIC void
>> +xfs_attri_item_unlock(
>> +	struct xfs_log_item	*lip)
>> +{
>> +	if (lip->li_flags & XFS_LI_ABORTED)
>> +		xfs_attri_item_free(ATTRI_ITEM(lip));
>> +}
>> +
>> +/*
>> + * The ATTRI is logged only once and cannot be moved in the log, so simply
>> + * return the lsn at which it's been logged.
>> + */
>> +STATIC xfs_lsn_t
>> +xfs_attri_item_committed(
>> +	struct xfs_log_item	*lip,
>> +	xfs_lsn_t		lsn)
>> +{
>> +	return lsn;
>> +}
>> +
>> +STATIC void
>> +xfs_attri_item_committing(
>> +	struct xfs_log_item	*lip,
>> +	xfs_lsn_t		lsn)
>> +{
>> +}
>> +
>> +/*
>> + * This is the ops vector shared by all attri log items.
>> + */
>> +static const struct xfs_item_ops xfs_attri_item_ops = {
>> +	.iop_size	= xfs_attri_item_size,
>> +	.iop_format	= xfs_attri_item_format,
>> +	.iop_pin	= xfs_attri_item_pin,
>> +	.iop_unpin	= xfs_attri_item_unpin,
>> +	.iop_unlock	= xfs_attri_item_unlock,
>> +	.iop_committed	= xfs_attri_item_committed,
>> +	.iop_push	= xfs_attri_item_push,
>> +	.iop_committing = xfs_attri_item_committing
>> +};
>> +
>> +
>> +/*
>> + * Allocate and initialize an attri item
>> + */
>> +struct xfs_attri_log_item *
>> +xfs_attri_init(
>> +	struct xfs_mount	*mp)
>> +
>> +{
>> +	struct xfs_attri_log_item	*attrip;
>> +	uint			size;
>> +
>> +	size = (uint)(sizeof(struct xfs_attri_log_item));
>> +	attrip = kmem_zalloc(size, KM_SLEEP);
>> +
>> +	xfs_log_item_init(mp, &(attrip->item), XFS_LI_ATTRI,
>> +			  &xfs_attri_item_ops);
>> +	attrip->format.alf_id = (uintptr_t)(void *)attrip;
>> +	atomic_set(&attrip->refcount, 2);
>> +
>> +	return attrip;
>> +}
>> +
>> +/*
>> + * Copy an attr format buffer from the given buf, and into the destination
>> + * attr format structure.
>> + */
>> +int
>> +xfs_attr_copy_format(struct xfs_log_iovec *buf,
>> +		      struct xfs_attr_log_format *dst_attr_fmt)
>> +{
>> +	struct xfs_attr_log_format *src_attr_fmt = buf->i_addr;
>> +	uint len = sizeof(struct xfs_attr_log_format);
>> +
>> +	if (buf->i_len == len) {
>> +		memcpy((char *)dst_attr_fmt, (char *)src_attr_fmt, len);
>> +		return 0;
>> +	}
>> +	return -EFSCORRUPTED;
>> +}
>> +
>> +/*
>> + * Freeing the attri requires that we remove it from the AIL if it has already
>> + * been placed there. However, the ATTRI may not yet have been placed in the
>> + * AIL when called by xfs_attri_release() from ATTRD processing due to the
>> + * ordering of committed vs unpin operations in bulk insert operations. Hence
>> + * the reference count to ensure only the last caller frees the ATTRI.
>> + */
>> +void
>> +xfs_attri_release(
>> +	struct xfs_attri_log_item	*attrip)
>> +{
>> +	ASSERT(atomic_read(&attrip->refcount) > 0);
>> +	if (atomic_dec_and_test(&attrip->refcount)) {
>> +		xfs_trans_ail_remove(&attrip->item,
>> +				     SHUTDOWN_LOG_IO_ERROR);
>> +		xfs_attri_item_free(attrip);
>> +	}
>> +}
>> +
>> +static inline struct xfs_attrd_log_item *ATTRD_ITEM(struct xfs_log_item *lip)
>> +{
>> +	return container_of(lip, struct xfs_attrd_log_item, item);
>> +}
>> +
>> +STATIC void
>> +xfs_attrd_item_free(struct xfs_attrd_log_item *attrdp)
>> +{
>> +	kmem_free(attrdp->item.li_lv_shadow);
>> +	kmem_free(attrdp);
>> +}
>> +
>> +/*
>> + * This returns the number of iovecs needed to log the given attrd item.
>> + * We only need 1 iovec for an attrd item.  It just logs the attr_log_format
>> + * structure.
>> + */
>> +static inline int
>> +xfs_attrd_item_sizeof(
>> +	struct xfs_attrd_log_item *attrdp)
>> +{
>> +	return sizeof(struct xfs_attr_log_format);
>> +}
>> +
>> +STATIC void
>> +xfs_attrd_item_size(
>> +	struct xfs_log_item	*lip,
>> +	int			*nvecs,
>> +	int			*nbytes)
>> +{
>> +	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
>> +	*nvecs += 1;
>> +	*nbytes += xfs_attrd_item_sizeof(attrdp);
>> +
>> +	if (attrdp->name_len > 0) {
>> +		*nvecs += 1;
>> +		nbytes += attrdp->name_len;
>> +	}
>> +
>> +	if (attrdp->value_len > 0) {
>> +		*nvecs += 1;
>> +		nbytes += attrdp->value_len;
>> +	}
>> +}
>> +
>> +/*
>> + * This is called to fill in the vector of log iovecs for the
>> + * given attrd log item. We use only 1 iovec, and we point that
>> + * at the attr_log_format structure embedded in the attrd item.
>> + * It is at this point that we assert that all of the attr
>> + * slots in the attrd item have been filled.
>> + */
>> +STATIC void
>> +xfs_attrd_item_format(
>> +	struct xfs_log_item	*lip,
>> +	struct xfs_log_vec	*lv)
>> +{
>> +	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
>> +	struct xfs_log_iovec	*vecp = NULL;
>> +
>> +	attrdp->format.alf_type = XFS_LI_ATTRD;
>> +	attrdp->format.alf_size = 1;
>> +
>> +	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRD_FORMAT,
>> +			&attrdp->format,
>> +			xfs_attrd_item_sizeof(attrdp));
>> +}
>> +
>> +/*
>> + * Pinning has no meaning for an attrd item, so just return.
>> + */
>> +STATIC void
>> +xfs_attrd_item_pin(
>> +	struct xfs_log_item	*lip)
>> +{
>> +}
>> +
>> +/*
>> + * Since pinning has no meaning for an attrd item, unpinning does
>> + * not either.
>> + */
>> +STATIC void
>> +xfs_attrd_item_unpin(
>> +	struct xfs_log_item	*lip,
>> +	int			remove)
>> +{
>> +}
>> +
>> +/*
>> + * There isn't much you can do to push on an attrd item.  It is simply stuck
>> + * waiting for the log to be flushed to disk.
>> + */
>> +STATIC uint
>> +xfs_attrd_item_push(
>> +	struct xfs_log_item	*lip,
>> +	struct list_head	*buffer_list)
>> +{
>> +	return XFS_ITEM_PINNED;
>> +}
>> +
>> +/*
>> + * The ATTRD is either committed or aborted if the transaction is cancelled. If
>> + * the transaction is cancelled, drop our reference to the ATTRI and free the
>> + * ATTRD.
>> + */
>> +STATIC void
>> +xfs_attrd_item_unlock(
>> +	struct xfs_log_item	*lip)
>> +{
>> +	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
>> +
>> +	if (lip->li_flags & XFS_LI_ABORTED) {
>> +		xfs_attri_release(attrdp->attrip);
>> +		xfs_attrd_item_free(attrdp);
>> +	}
>> +}
>> +
>> +/*
>> + * When the attrd item is committed to disk, all we need to do is delete our
>> + * reference to our partner attri item and then free ourselves. Since we're
>> + * freeing ourselves we must return -1 to keep the transaction code from
>> + * further referencing this item.
>> + */
>> +STATIC xfs_lsn_t
>> +xfs_attrd_item_committed(
>> +	struct xfs_log_item	*lip,
>> +	xfs_lsn_t		lsn)
>> +{
>> +	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
>> +
>> +	/*
>> +	 * Drop the ATTRI reference regardless of whether the ATTRD has been
>> +	 * aborted. Once the ATTRD transaction is constructed, it is the sole
>> +	 * responsibility of the ATTRD to release the ATTRI (even if the ATTRI
>> +	 * is aborted due to log I/O error).
>> +	 */
>> +	xfs_attri_release(attrdp->attrip);
>> +	xfs_attrd_item_free(attrdp);
>> +
>> +	return (xfs_lsn_t)-1;
>> +}
>> +
>> +STATIC void
>> +xfs_attrd_item_committing(
>> +	struct xfs_log_item	*lip,
>> +	xfs_lsn_t		lsn)
>> +{
>> +}
>> +
>> +/*
>> + * This is the ops vector shared by all attrd log items.
>> + */
>> +static const struct xfs_item_ops xfs_attrd_item_ops = {
>> +	.iop_size	= xfs_attrd_item_size,
>> +	.iop_format	= xfs_attrd_item_format,
>> +	.iop_pin	= xfs_attrd_item_pin,
>> +	.iop_unpin	= xfs_attrd_item_unpin,
>> +	.iop_unlock	= xfs_attrd_item_unlock,
>> +	.iop_committed	= xfs_attrd_item_committed,
>> +	.iop_push	= xfs_attrd_item_push,
>> +	.iop_committing = xfs_attrd_item_committing
>> +};
>> +
>> +/*
>> + * Allocate and initialize an attrd item
>> + */
>> +struct xfs_attrd_log_item *
>> +xfs_attrd_init(
>> +	struct xfs_mount	*mp,
>> +	struct xfs_attri_log_item	*attrip)
>> +
>> +{
>> +	struct xfs_attrd_log_item	*attrdp;
>> +	uint			size;
>> +
>> +	size = (uint)(sizeof(struct xfs_attrd_log_item));
>> +	attrdp = kmem_zalloc(size, KM_SLEEP);
>> +
>> +	xfs_log_item_init(mp, &attrdp->item, XFS_LI_ATTRD,
>> +			  &xfs_attrd_item_ops);
>> +	attrdp->attrip = attrip;
>> +	attrdp->format.alf_id = attrip->format.alf_id;
>> +
>> +	return attrdp;
>> +}
>> +
>> +/*
>> + * Process an attr intent item that was recovered from
>> + * the log.  We need to delete the attr that it describes.
>> + */
>> +int
>> +xfs_attri_recover(
>> +	struct xfs_mount	*mp,
>> +	struct xfs_attri_log_item	*attrip)
>> +{
>> +	struct xfs_inode		*ip;
>> +	struct xfs_attrd_log_item	*attrdp;
>> +	struct xfs_trans	*tp;
>> +	int			error = 0;
>> +	struct xfs_attr_log_format	*attrp;
>> +
>> +	ASSERT(!test_bit(XFS_ATTRI_RECOVERED, &attrip->flags));
>> +
>> +	/*
>> +	 * First check the validity of the attr described by the
>> +	 * ATTRI.  If any are bad, then assume that all are bad and
>> +	 * just toss the ATTRI.  A valid attr must have a name length,
>> +	 * a value length, and either a "set" or "remove" op flag
>> +	 */
>> +	attrp = &attrip->format;
>> +	if (attrp->alf_value_len == 0 ||
>> +	    attrp->alf_name_len == 0 ||
>> +	    !(attrp->alf_op_flags == XFS_ATTR_OP_FLAGS_SET ||
>> +	     attrp->alf_op_flags == XFS_ATTR_OP_FLAGS_REMOVE) ) {
>> +		/*
>> +		 * This will pull the ATTRI from the AIL and
>> +		 * free the memory associated with it.
>> +		 */
>> +		set_bit(XFS_ATTRI_RECOVERED, &attrip->flags);
>> +		xfs_attri_release(attrip);
>> +		return -EIO;
>> +	}
>> +
>> +	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
>> +	if (error)
>> +		return error;
>> +	attrdp = xfs_trans_get_attrd(tp, attrip);
>> +	attrp = &attrip->format;
>> +
>> +	error = xfs_iget(mp, tp, attrp->alf_ino, 0, 0, &ip);
>> +	if (error)
>> +		return error;
>> +
>> +	error = xfs_trans_attr(tp, attrdp, ip,
>> +				attrp->alf_op_flags,
>> +				attrp->alf_attr_flags,
>> +				attrp->alf_name_len,
>> +				attrp->alf_value_len,
>> +				attrip->name,
>> +				attrip->value);
>> +	if (error)
>> +		goto abort_error;
>> +
>> +
>> +	set_bit(XFS_ATTRI_RECOVERED, &attrip->flags);
>> +	error = xfs_trans_commit(tp);
>> +	return error;
>> +
>> +abort_error:
>> +	xfs_trans_cancel(tp);
>> +	return error;
>> +}
>> diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h
>> new file mode 100644
>> index 0000000..774b56e
>> --- /dev/null
>> +++ b/fs/xfs/xfs_attr_item.h
>> @@ -0,0 +1,117 @@
>> +/*
>> + * 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_ATTR_ITEM_H__
>> +#define	__XFS_ATTR_ITEM_H__
>> +
>> +/* kernel only ATTRI/ATTRD definitions */
>> +
>> +struct xfs_mount;
>> +struct kmem_zone;
>> +
>> +/*
>> + * Max number of attrs in fast allocation path.
>> + */
>> +#define XFS_ATTRI_MAX_FAST_ATTRS        1
>> +
>> +
>> +/*
>> + * Define ATTR flag bits. Manipulated by set/clear/test_bit operators.
>> + */
>> +#define	XFS_ATTRI_RECOVERED	1
>> +
>> +
>> +/* nvecs must be in multiples of 4 */
>> +#define ATTR_NVEC_SIZE(size) (size == sizeof(int32_t) ? sizeof(int32_t) : \
>> +				size + sizeof(int32_t) - \
>> +				(size % sizeof(int32_t)))
>> +
>> +/*
>> + * This is the "attr intention" log item.  It is used to log the fact
>> + * that some attrs need to be processed.  It is used in conjunction with the
>> + * "attr done" log item described below.
>> + *
>> + * The ATTRI is reference counted so that it is not freed prior to both the
>> + * ATTRI and ATTRD being committed and unpinned. This ensures the ATTRI is
>> + * inserted into the AIL even in the event of out of order ATTRI/ATTRD
>> + * processing. In other words, an ATTRI is born with two references:
>> + *
>> + *      1.) an ATTRI held reference to track ATTRI AIL insertion
>> + *      2.) an ATTRD held reference to track ATTRD commit
>> + *
>> + * On allocation, both references are the responsibility of the caller. Once
>> + * the ATTRI is added to and dirtied in a transaction, ownership of reference
>> + * one transfers to the transaction. The reference is dropped once the ATTRI is
>> + * inserted to the AIL or in the event of failure along the way (e.g., commit
>> + * failure, log I/O error, etc.). Note that the caller remains responsible for
>> + * the ATTRD reference under all circumstances to this point. The caller has no
>> + * means to detect failure once the transaction is committed, however.
>> + * Therefore, an ATTRD is required after this point, even in the event of
>> + * unrelated failure.
>> + *
>> + * Once an ATTRD is allocated and dirtied in a transaction, reference two
>> + * transfers to the transaction. The ATTRD reference is dropped once it reaches
>> + * the unpin handler. Similar to the ATTRI, the reference also drops in the
>> + * event of commit failure or log I/O errors. Note that the ATTRD is not
>> + * inserted in the AIL, so at this point both the ATTI and ATTRD are freed.
>> + */
>> +struct xfs_attri_log_item {
>> +	xfs_log_item_t			item;
>> +	atomic_t			refcount;
>> +	unsigned long			flags;	/* misc flags */
>> +	int				name_len;
>> +	void				*name;
>> +	int				value_len;
>> +	void				*value;
>> +	struct xfs_attr_log_format	format;
>> +};
>> +
>> +/*
>> + * This is the "attr done" log item.  It is used to log
>> + * the fact that some attrs earlier mentioned in an attri item
>> + * have been freed.
>> + */
>> +struct xfs_attrd_log_item {
>> +	struct xfs_log_item		item;
>> +	struct xfs_attri_log_item	*attrip;
>> +	uint				next_attr;
>> +	int				name_len;
>> +	void				*name;
>> +	int				value_len;
>> +	void				*value;
>> +	struct xfs_attr_log_format	format;
>> +};
>> +
>> +/*
>> + * Max number of attrs in fast allocation path.
>> + */
>> +#define	XFS_ATTRD_MAX_FAST_ATTRS	1
>> +
>> +extern struct kmem_zone	*xfs_attri_zone;
>> +extern struct kmem_zone	*xfs_attrd_zone;
>> +
>> +struct xfs_attri_log_item	*xfs_attri_init(struct xfs_mount *mp);
>> +struct xfs_attrd_log_item	*xfs_attrd_init(struct xfs_mount *mp,
>> +					struct xfs_attri_log_item *attrip);
>> +int xfs_attr_copy_format(struct xfs_log_iovec *buf,
>> +			 struct xfs_attr_log_format *dst_attri_fmt);
>> +void			xfs_attri_item_free(struct xfs_attri_log_item *attrip);
>> +void			xfs_attri_release(struct xfs_attri_log_item *attrip);
>> +
>> +int			xfs_attri_recover(struct xfs_mount *mp,
>> +					struct xfs_attri_log_item *attrip);
>> +
>> +#endif	/* __XFS_ATTR_ITEM_H__ */
>> diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
>> index ee34899..fd0e052 100644
>> --- a/fs/xfs/xfs_log_recover.c
>> +++ b/fs/xfs/xfs_log_recover.c
>> @@ -33,6 +33,7 @@
>>   #include "xfs_log_recover.h"
>>   #include "xfs_inode_item.h"
>>   #include "xfs_extfree_item.h"
>> +#include "xfs_attr_item.h"
>>   #include "xfs_trans_priv.h"
>>   #include "xfs_alloc.h"
>>   #include "xfs_ialloc.h"
>> @@ -1956,6 +1957,8 @@ xlog_recover_reorder_trans(
>>   		case XFS_LI_CUD:
>>   		case XFS_LI_BUI:
>>   		case XFS_LI_BUD:
>> +		case XFS_LI_ATTRI:
>> +		case XFS_LI_ATTRD:
>>   			trace_xfs_log_recover_item_reorder_tail(log,
>>   							trans, item, pass);
>>   			list_move_tail(&item->ri_list, &inode_list);
>> @@ -3489,6 +3492,92 @@ xlog_recover_efd_pass2(
>>   	return 0;
>>   }
>>   
>> +STATIC int
>> +xlog_recover_attri_pass2(
>> +	struct xlog                     *log,
>> +	struct xlog_recover_item        *item,
>> +	xfs_lsn_t                       lsn)
>> +{
>> +	int                             error;
>> +	struct xfs_mount                *mp = log->l_mp;
>> +	struct xfs_attri_log_item       *attrip;
>> +	struct xfs_attr_log_format     *attri_formatp;
>> +
>> +	attri_formatp = item->ri_buf[0].i_addr;
>> +
>> +	attrip = xfs_attri_init(mp);
>> +	error = xfs_attr_copy_format(&item->ri_buf[0], &attrip->format);
>> +	if (error) {
>> +		xfs_attri_item_free(attrip);
>> +		return error;
>> +	}
>> +
>> +	spin_lock(&log->l_ailp->xa_lock);
>> +	/*
>> +	 * The ATTRI has two references. One for the ATTRD and one for ATTRI to
>> +	 * ensure it makes it into the AIL. Insert the ATTRI into the AIL
>> +	 * directly and drop the ATTRI reference. Note that
>> +	 * xfs_trans_ail_update() drops the AIL lock.
>> +	 */
>> +	xfs_trans_ail_update(log->l_ailp, &attrip->item, lsn);
>> +	xfs_attri_release(attrip);
>> +	return 0;
>> +}
>> +
>> +
>> +/*
>> + * This routine is called when an ATTRD format structure is found in a committed
>> + * transaction in the log. Its purpose is to cancel the corresponding ATTRI if
>> + * it was still in the log. To do this it searches the AIL for the ATTRI with
>> + * an id equal to that in the ATTRD format structure. If we find it we drop
>> + * the ATTRD reference, which removes the ATTRI from the AIL and frees it.
>> + */
>> +STATIC int
>> +xlog_recover_attrd_pass2(
>> +	struct xlog                     *log,
>> +	struct xlog_recover_item        *item)
>> +{
>> +	struct xfs_attr_log_format    *attrd_formatp;
>> +	struct xfs_attri_log_item      *attrip = NULL;
>> +	struct xfs_log_item          *lip;
>> +	uint64_t                attri_id;
>> +	struct xfs_ail_cursor   cur;
>> +	struct xfs_ail          *ailp = log->l_ailp;
> Whoah, what happened to the indenting here?
Sorry, I'll go through and fix indenting...
>> +
>> +	attrd_formatp = item->ri_buf[0].i_addr;
>> +	ASSERT((item->ri_buf[0].i_len ==
>> +				(sizeof(struct xfs_attr_log_format))));
>> +	attri_id = attrd_formatp->alf_id;
>> +
>> +	/*
>> +	 * Search for the ATTRI with the id in the ATTRD format structure in the
>> +	 * AIL.
>> +	 */
>> +	spin_lock(&ailp->xa_lock);
>> +	lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
>> +	while (lip != NULL) {
>> +		if (lip->li_type == XFS_LI_ATTRI) {
>> +			attrip = (struct xfs_attri_log_item *)lip;
>> +			if (attrip->format.alf_id == attri_id) {
>> +				/*
>> +				 * Drop the ATTRD reference to the ATTRI. This
>> +				 * removes the ATTRI from the AIL and frees it.
>> +				 */
>> +				spin_unlock(&ailp->xa_lock);
>> +				xfs_attri_release(attrip);
>> +				spin_lock(&ailp->xa_lock);
>> +				break;
>> +			}
>> +		}
>> +		lip = xfs_trans_ail_cursor_next(ailp, &cur);
>> +	}
>> +
>> +	xfs_trans_ail_cursor_done(&cur);
>> +	spin_unlock(&ailp->xa_lock);
>> +
>> +	return 0;
>> +}
>> +
>>   /*
>>    * This routine is called to create an in-core extent rmap update
>>    * item from the rui format structure which was logged on disk.
>> @@ -4108,6 +4197,10 @@ xlog_recover_commit_pass2(
>>   		return xlog_recover_efi_pass2(log, item, trans->r_lsn);
>>   	case XFS_LI_EFD:
>>   		return xlog_recover_efd_pass2(log, item);
>> +	case XFS_LI_ATTRI:
>> +		return xlog_recover_attri_pass2(log, item, trans->r_lsn);
>> +	case XFS_LI_ATTRD:
>> +		return xlog_recover_attrd_pass2(log, item);
>>   	case XFS_LI_RUI:
>>   		return xlog_recover_rui_pass2(log, item, trans->r_lsn);
>>   	case XFS_LI_RUD:
>> @@ -4669,6 +4762,49 @@ xlog_recover_cancel_efi(
>>   	spin_lock(&ailp->xa_lock);
>>   }
>>   
>> +/* Recover the ATTRI if necessary. */
>> +STATIC int
>> +xlog_recover_process_attri(
>> +	struct xfs_mount                *mp,
>> +	struct xfs_ail                  *ailp,
>> +	struct xfs_log_item             *lip)
>> +{
>> +	struct xfs_attri_log_item       *attrip;
>> +	int                             error;
>> +
>> +	/*
>> +	 * Skip ATTRIs that we've already processed.
>> +	 */
>> +	attrip = container_of(lip, struct xfs_attri_log_item, item);
>> +	if (test_bit(XFS_ATTRI_RECOVERED, &attrip->flags))
>> +		return 0;
>> +
>> +	spin_unlock(&ailp->xa_lock);
>> +	error = xfs_attri_recover(mp, attrip);
>> +	spin_lock(&ailp->xa_lock);
>> +
>> +	return error;
>> +}
>> +
>> +/* Release the ATTRI since we're cancelling everything. */
>> +STATIC void
>> +xlog_recover_cancel_attri(
>> +	struct xfs_mount                *mp,
>> +	struct xfs_ail                  *ailp,
>> +	struct xfs_log_item             *lip)
>> +{
>> +	struct xfs_attri_log_item         *attrip;
>> +
>> +	attrip = container_of(lip, struct xfs_attri_log_item, item);
>> +
>> +	spin_unlock(&ailp->xa_lock);
>> +	xfs_attri_release(attrip);
>> +	spin_lock(&ailp->xa_lock);
>> +}
>> +
>> +
>> +
>> +
>>   /* Recover the RUI if necessary. */
>>   STATIC int
>>   xlog_recover_process_rui(
>> @@ -4861,6 +4997,10 @@ xlog_recover_process_intents(
>>   		case XFS_LI_EFI:
>>   			error = xlog_recover_process_efi(log->l_mp, ailp, lip);
>>   			break;
>> +		case XFS_LI_ATTRI:
>> +			error = xlog_recover_process_attri(log->l_mp,
>> +							   ailp, lip);
>> +			break;
>>   		case XFS_LI_RUI:
>>   			error = xlog_recover_process_rui(log->l_mp, ailp, lip);
>>   			break;
>> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
>> index f663022..ee68459 100644
>> --- a/fs/xfs/xfs_super.c
>> +++ b/fs/xfs/xfs_super.c
>> @@ -2024,6 +2024,7 @@ init_xfs_fs(void)
>>   	xfs_rmap_update_init_defer_op();
>>   	xfs_refcount_update_init_defer_op();
>>   	xfs_bmap_update_init_defer_op();
>> +	xfs_attr_init_defer_op();
>>   
>>   	xfs_dir_startup();
>>   
>> diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
>> index 815b53d2..e094b05 100644
>> --- a/fs/xfs/xfs_trans.h
>> +++ b/fs/xfs/xfs_trans.h
>> @@ -40,6 +40,9 @@ struct xfs_cud_log_item;
>>   struct xfs_defer_ops;
>>   struct xfs_bui_log_item;
>>   struct xfs_bud_log_item;
>> +struct xfs_attrd_log_item;
>> +struct xfs_attri_log_item;
>> +
>>   
>>   typedef struct xfs_log_item {
>>   	struct list_head		li_ail;		/* AIL pointers */
>> @@ -223,12 +226,22 @@ void		xfs_trans_dirty_buf(struct xfs_trans *, struct xfs_buf *);
>>   void		xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
>>   
>>   void		xfs_extent_free_init_defer_op(void);
>> +void            xfs_attr_init_defer_op(void);
>> +
>>   struct xfs_efd_log_item	*xfs_trans_get_efd(struct xfs_trans *,
>>   				  struct xfs_efi_log_item *,
>>   				  uint);
>>   int		xfs_trans_free_extent(struct xfs_trans *,
>>   				      struct xfs_efd_log_item *, xfs_fsblock_t,
>>   				      xfs_extlen_t, struct xfs_owner_info *);
>> +struct xfs_attrd_log_item *
>> +xfs_trans_get_attrd(struct xfs_trans *tp,
>> +		    struct xfs_attri_log_item *attrip);
>> +int xfs_trans_attr(struct xfs_trans *tp, struct xfs_attrd_log_item *attrdp,
>> +			struct xfs_inode *ip, uint32_t attr_op_flags,
>> +			uint32_t flags, uint32_t name_len, uint32_t value_len,
>> +			char *name, char *value);
>> +
>>   int		xfs_trans_commit(struct xfs_trans *);
>>   int		xfs_trans_roll(struct xfs_trans **);
>>   int		xfs_trans_roll_inode(struct xfs_trans **, struct xfs_inode *);
>> diff --git a/fs/xfs/xfs_trans_attr.c b/fs/xfs/xfs_trans_attr.c
>> new file mode 100644
>> index 0000000..7c3290f
>> --- /dev/null
>> +++ b/fs/xfs/xfs_trans_attr.c
>> @@ -0,0 +1,288 @@
>> +/*
>> + * 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.
>> + */
>> +#include "xfs.h"
>> +#include "xfs_fs.h"
>> +#include "xfs_shared.h"
>> +#include "xfs_format.h"
>> +#include "xfs_log_format.h"
>> +#include "xfs_trans_resv.h"
>> +#include "xfs_bit.h"
>> +#include "xfs_mount.h"
>> +#include "xfs_defer.h"
>> +#include "xfs_trans.h"
>> +#include "xfs_trans_priv.h"
>> +#include "xfs_attr_item.h"
>> +#include "xfs_alloc.h"
>> +#include "xfs_bmap.h"
>> +#include "xfs_trace.h"
>> +#include "libxfs/xfs_da_format.h"
>> +#include "xfs_da_btree.h"
>> +#include "xfs_attr.h"
>> +#include "xfs_inode.h"
>> +#include "xfs_icache.h"
>> +#include "xfs_quota.h"
>> +
>> +/*
>> + * This routine is called to allocate an "extent free done"
>> + * log item that will hold nextents worth of extents.  The
>> + * caller must use all nextents extents, because we are not
>> + * flexible about this at all.
>> + */
>> +struct xfs_attrd_log_item *
>> +xfs_trans_get_attrd(struct xfs_trans		*tp,
>> +		  struct xfs_attri_log_item	*attrip)
>> +{
>> +	struct xfs_attrd_log_item			*attrdp;
>> +
>> +	ASSERT(tp != NULL);
>> +
>> +	attrdp = xfs_attrd_init(tp->t_mountp, attrip);
>> +	ASSERT(attrdp != NULL);
>> +
>> +	/*
>> +	 * Get a log_item_desc to point at the new item.
>> +	 */
>> +	xfs_trans_add_item(tp, &attrdp->item);
>> +	return attrdp;
>> +}
>> +
>> +/*
>> + * Delete an attr and log it to the ATTRD. Note that the transaction is marked
>> + * dirty regardless of whether the attr delete succeeds or fails to support the
>> + * ATTRI/ATTRD lifecycle rules.
>> + */
>> +int
>> +xfs_trans_attr(
>> +	struct xfs_trans		*tp,
>> +	struct xfs_attrd_log_item	*attrdp,
>> +	struct xfs_inode		*ip,
>> +	uint32_t			op_flags,
>> +	uint32_t			flags,
>> +	uint32_t			name_len,
>> +	uint32_t			value_len,
>> +	char				*name,
>> +	char				*value)
>> +{
>> +	uint			next_attr;
>> +	struct xfs_attr_log_format *attrp;
>> +	int			error;
>> +	int                     local;
>> +	struct xfs_da_args      args;
>> +	struct xfs_defer_ops    dfops;
>> +	xfs_fsblock_t		firstblock = NULLFSBLOCK;
> Line the variable names up with the parameter names, please.
>
>> +
>> +	tp->t_flags |= XFS_TRANS_RESERVE;
>> +
>> +	error = xfs_attr_args_init(&args, ip, name, flags);
>> +	if (error)
>> +		return error;
>> +
>> +	xfs_ilock(ip, XFS_ILOCK_EXCL);
>> +	xfs_defer_init(&dfops, &firstblock);
> Uhoh.  In patch "xfs: log recovery should replay deferred ops in order"
> we changed log intent item recovery to create a single defer_ops to
> collect all of the new defer_ops that got created in the process of
> recovering unfinished intent items that were dirty in the log.  The
> reason for collecting the new deferred items is so that everything
> replays in exactly the order they would have been finished had the
> system not gone down.
>
> Therefore, we have to pass the dfops created in
> xlog_recover_process_intents all the way through the call chain
> xlog_recover_process_attri -> xfs_attri_recover -> xfs_trans_attr.
>
> I'll try to get that patch into -rc2 so that you don't have to carry
> the fix patch in your tree, but be aware that you'll have to update this
> at some point before the final version.
Got it.  Ok, thank you for the heads up :-)
>> +	args.name = name;
>> +	args.namelen = name_len;
>> +	args.hashval = xfs_da_hashname(args.name, args.namelen);
>> +	args.value = value;
>> +	args.valuelen = value_len;
>> +	args.dfops = &dfops;
>> +	args.firstblock = &firstblock;
>> +	args.op_flags = XFS_DA_OP_OKNOENT;
>> +	args.total = xfs_attr_calc_size(&args, &local);
>> +	args.trans = tp;
>> +	ASSERT(local);
>> +
>> +	error = xfs_qm_dqattach_locked(ip, 0);
>> +	if (error)
>> +		return error;
>> +
>> +	switch (op_flags) {
>> +		case XFS_ATTR_OP_FLAGS_SET:
>> +			args.op_flags |= XFS_DA_OP_ADDNAME;
>> +			error = xfs_attr_set_args(&args, flags, false);
>> +			break;
>> +		case XFS_ATTR_OP_FLAGS_REMOVE:
>> +			ASSERT(XFS_IFORK_Q((ip)));
>> +			error = xfs_attr_remove_args(&args, flags);
>> +			break;
>> +		default:
>> +			error = -EFSCORRUPTED;
>> +	}
>> +
>> +	if (error)
>> +		xfs_defer_cancel(&dfops);
>> +
>> +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
>> +
>> +	/*
>> +	 * Mark the transaction dirty, even on error. This ensures the
>> +	 * transaction is aborted, which:
>> +	 *
>> +	 * 1.) releases the ATTRI and frees the ATTRD
>> +	 * 2.) shuts down the filesystem
>> +	 */
>> +	tp->t_flags |= XFS_TRANS_DIRTY;
>> +	attrdp->item.li_desc->lid_flags |= XFS_LID_DIRTY;
>> +
>> +	next_attr = attrdp->next_attr;
>> +	attrp = &(attrdp->format);
>> +	attrp->alf_ino = ip->i_ino;
>> +	attrp->alf_op_flags = op_flags;
>> +	attrp->alf_value_len = value_len;
>> +	attrp->alf_name_len = name_len;
>> +	attrp->alf_attr_flags = flags;
>> +
>> +	attrdp->name = name;
>> +	attrdp->value = value;
>> +	attrdp->name_len = name_len;
>> +	attrdp->value_len = value_len;
>> +	attrdp->next_attr++;
>> +
>> +	return error;
>> +}
>> +
>> +static int
>> +xfs_attr_diff_items(
>> +	void				*priv,
>> +	struct list_head		*a,
>> +	struct list_head		*b)
>> +{
>> +	return 0;
>> +}
>> +
>> +/* Get an ATTRI. */
>> +STATIC void *
>> +xfs_attr_create_intent(
>> +	struct xfs_trans		*tp,
>> +	unsigned int			count)
>> +{
>> +	struct xfs_attri_log_item		*attrip;
>> +
>> +	ASSERT(tp != NULL);
>> +	ASSERT(count > 0);
> ASSERT(count == 1); here, right?
Yes, it should be 1:1
>> +
>> +	attrip = xfs_attri_init(tp->t_mountp);
>> +	ASSERT(attrip != NULL);
>> +
>> +	/*
>> +	 * Get a log_item_desc to point at the new item.
>> +	 */
>> +	xfs_trans_add_item(tp, &attrip->item);
>> +	return attrip;
>> +}
>> +
>> +/* Log an attr to the intent item. */
>> +STATIC void
>> +xfs_attr_log_item(
>> +	struct xfs_trans		*tp,
>> +	void				*intent,
>> +	struct list_head		*item)
>> +{
>> +	struct xfs_attri_log_item	*attrip = intent;
>> +	struct xfs_attr_item		*free;
>> +	struct xfs_attr_log_format	*attrp;
>> +
>> +	free = container_of(item, struct xfs_attr_item, xattri_list);
>> +
>> +	tp->t_flags |= XFS_TRANS_DIRTY;
>> +	attrip->item.li_desc->lid_flags |= XFS_LID_DIRTY;
>> +
>> +	attrp = &attrip->format;
>> +	attrp->alf_ino = free->xattri_ip->i_ino;
>> +	attrp->alf_op_flags = free->xattri_op_flags;
>> +	attrp->alf_value_len = free->xattri_value_len;
>> +	attrp->alf_name_len = free->xattri_name_len;
>> +	attrp->alf_attr_flags = free->xattri_flags;
>> +
>> +	attrip->name = &(free->xattri_name_value[0]);
>> +	attrip->value = &(free->xattri_name_value[free->xattri_name_len]);
>> +	attrip->name_len = free->xattri_name_len;
>> +	attrip->value_len = free->xattri_value_len;
>> +}
>> +
>> +/* Get an ATTRD so we can process all the attrs. */
>> +STATIC void *
>> +xfs_attr_create_done(
>> +	struct xfs_trans		*tp,
>> +	void				*intent,
>> +	unsigned int			count)
>> +{
>> +	return xfs_trans_get_attrd(tp, intent);
>> +}
>> +
>> +/* Process an attr. */
>> +STATIC int
>> +xfs_attr_finish_item(
>> +	struct xfs_trans		*tp,
>> +	struct xfs_defer_ops		*dop,
>> +	struct list_head		*item,
>> +	void				*done_item,
>> +	void				**state)
>> +{
>> +	struct xfs_attr_item	*free;
>> +	int				error;
>> +
>> +	free = container_of(item, struct xfs_attr_item, xattri_list);
>> +	error = xfs_trans_attr(tp, done_item,
> Pass dop through to xfs_trans_attr, per the comment above.
> We should /never/ be nesting defer_ops within a call stack.
Alrighty, will do
>> +			free->xattri_ip,
>> +			free->xattri_op_flags,
>> +			free->xattri_flags,
>> +			free->xattri_name_len,
>> +			free->xattri_value_len,
>> +			&free->xattri_name_value[0],
>> +			&free->xattri_name_value[free->xattri_name_len]);
>> +	kmem_free(free);
>> +	return error;
>> +}
>> +
>> +/* Abort all pending ATTRs. */
>> +STATIC void
>> +xfs_attr_abort_intent(
>> +	void				*intent)
>> +{
>> +	xfs_attri_release(intent);
>> +}
>> +
>> +/* Cancel an attr */
>> +STATIC void
>> +xfs_attr_cancel_item(
>> +	struct list_head		*item)
>> +{
>> +	struct xfs_attr_item	*free;
>> +
>> +	free = container_of(item, struct xfs_attr_item, xattri_list);
>> +	kmem_free(free);
>> +}
>> +
>> +static const struct xfs_defer_op_type xfs_attr_defer_type = {
>> +	.type		= XFS_DEFER_OPS_TYPE_ATTR,
>> +	.max_items	= XFS_ATTRI_MAX_FAST_ATTRS,
>> +	.diff_items	= xfs_attr_diff_items,
>> +	.create_intent	= xfs_attr_create_intent,
>> +	.abort_intent	= xfs_attr_abort_intent,
>> +	.log_item	= xfs_attr_log_item,
>> +	.create_done	= xfs_attr_create_done,
>> +	.finish_item	= xfs_attr_finish_item,
>> +	.cancel_item	= xfs_attr_cancel_item,
>> +};
>> +
>> +/* Register the deferred op type. */
>> +void
>> +xfs_attr_init_defer_op(void)
>> +{
>> +	xfs_defer_init_op_type(&xfs_attr_defer_type);
>> +}
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message tomajordomo@vger.kernel.org
>> More majordomo info athttp://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH v3 01/17] Add helper functions xfs_attr_set_args and xfs_attr_remove_args
  2017-11-28 19:54   ` Darrick J. Wong
  2017-11-29  1:02     ` Dave Chinner
@ 2017-11-29 18:52     ` Allison Henderson
  2017-11-29 22:34       ` Allison Henderson
  1 sibling, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:52 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 11/28/2017 12:54 PM, Darrick J. Wong wrote:

> On Fri, Nov 17, 2017 at 11:21:29AM -0700, Allison Henderson wrote:
>> These sub-routines set or remove 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>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 335 ++++++++++++++++++++++++++++-------------------
>>   fs/xfs/libxfs/xfs_bmap.c |  55 ++++----
>>   fs/xfs/libxfs/xfs_bmap.h |   1 +
>>   fs/xfs/xfs_attr.h        |   2 +
>>   4 files changed, 236 insertions(+), 157 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 6249c92..e5f2960 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -168,6 +168,195 @@ 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.
> We have sufficient space in the single transaction case to do both, right?
I will double check.  You mean modifying the directory and then setting 
the parent pointer?
>> + */
>> +int
>> +xfs_attr_set_args(
>> +	struct xfs_da_args	*args,
>> +	int			flags,
>> +	bool			roll_trans)
>> +{
>> +	struct xfs_inode	*dp = args->dp;
>> +	struct xfs_mount        *mp = dp->i_mount;
>> +	struct xfs_trans_res    tres;
>> +	int			rsvd = 0;
>> +	int			error = 0;
>> +	int			sf_size;
>> +

This is the code (below) I had referenced earlier that was folded in 
from xfs_set_first_parent in the last version of the set.
>> +	/*
>> +	 * 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;
>> +	}
>> +
>> +	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;
> /me raises eyebrows about declaring our own tres here, though it came
> from the original code so I gues I can't complain too loudly.
>
> (Primarily because we use the transaction reservations to calculate the
> minimum log size, so I would think we'd want this one included in those
> calculations...)
I believe that is done in patch 10 right?  We add one more transaction 
to the create operation for the parent pointer?  Should this one count 
for another?
>> +	/*
>> +	 * 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;
>> +
>> +	error = xfs_trans_reserve_quota_nblks(args->trans, dp, args->total, 0,
>> +					      rsvd ? XFS_QMOPT_RES_REGBLKS |
>> +						     XFS_QMOPT_FORCE_RES :
>> +						     XFS_QMOPT_RES_REGBLKS);
>> +	if (error)
>> +		goto out;
>> +
>> +	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);
>> +		if (error != -ENOSPC) {
>> +			ASSERT(args->trans);
>> +			if (!error && (flags & ATTR_KERNOTIME) == 0)
>> +				xfs_trans_ichgtime(args->trans, dp,
>> +						   XFS_ICHGTIME_CHG);
>> +			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);
>> +		if (error)
>> +			goto out;
>> +		xfs_defer_ijoin(args->dfops, dp);
>> +		if (roll_trans) {
>> +			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;
>> +		}
>> +	}
>> +
>> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
>> +		error = xfs_attr_leaf_addname(args);
>> +	else
>> +		error = xfs_attr_node_addname(args);
>> +	if (error)
>> +		goto out;
>> +
>> +	if ((flags & ATTR_KERNOTIME) == 0)
>> +		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
>> +
>> +	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
>> +out:
>> +	return error;
>> +}
>> +
>> +/*
>> + * Remove the attribute specified in @args.
>> + */
>> +int
>> +xfs_attr_remove_args(
>> +	struct xfs_da_args      *args,
>> +	int			flags)
>> +{
>> +	struct xfs_inode	*dp = args->dp;
>> +	struct xfs_mount	*mp = dp->i_mount;
>> +	int			error;
>> +	int                     rsvd = 0;
>> +
>> +	/*
>> +	 * Root fork attributes can use reserved data blocks for this
>> +	 * operation if necessary
>> +	 */
>> +	if (flags & ATTR_ROOT)
>> +		rsvd = XFS_TRANS_RESERVE;
> Insert a blank line to separate these two...
>
>> +	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
>> +		XFS_ATTRRM_SPACE_RES(mp), 0, rsvd, &args->trans);
>> +
> ...and remove this one since they're directly related.
ok, will do
>> +	if (error)
>> +		goto out;
>> +
>> +	/*
>> +	 * No need to make quota reservations here. We expect to release some
>> +	 * blocks not allocate in the common case.
>> +	 */
>> +	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);
>> +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> +		error = xfs_attr_leaf_removename(args);
>> +	} else {
>> +		error = xfs_attr_node_removename(args);
>> +	}
>> +
>> +	if (error)
>> +		goto out;
>> +
>> +	/*
>> +	 * 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 ((flags & ATTR_KERNOTIME) == 0)
>> +		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
>> +
>> +	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
>> +
>> +	return error;
>> +
>> +out:
>> +	if (args->trans)
>> +		xfs_trans_cancel(args->trans);
>> +
>> +	return error;
>> +}
>> +
>> +/*
>>    * Calculate how many blocks we need for the new attribute,
>>    */
>>   STATIC int
>> @@ -214,10 +403,9 @@ xfs_attr_set(
>>   	struct xfs_mount	*mp = dp->i_mount;
>>   	struct xfs_da_args	args;
>>   	struct xfs_defer_ops	dfops;
>> -	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);
>>   
>> @@ -252,106 +440,11 @@ xfs_attr_set(
>>   			return error;
>>   	}
>>   
>> -	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)
>> -		return error;
>> -
>>   	xfs_ilock(dp, XFS_ILOCK_EXCL);
>> -	error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0,
>> -				rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
>> -				       XFS_QMOPT_RES_REGBLKS);
>> -	if (error) {
>> -		xfs_iunlock(dp, XFS_ILOCK_EXCL);
>> -		xfs_trans_cancel(args.trans);
>> -		return error;
>> -	}
>> -
>> -	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);
>> -		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);
>> -		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 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;
>> -
>> -	}
>> -
>> -	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
>> -		error = xfs_attr_leaf_addname(&args);
>> -	else
>> -		error = xfs_attr_node_addname(&args);
>> +	xfs_defer_init(args.dfops, args.firstblock);
>> +	error = xfs_attr_set_args(&args, flags, true);
>>   	if (error)
>> -		goto out;
>> +		goto out_defer_cancel;
>>   
>>   	/*
>>   	 * If this is a synchronous mount, make sure that the
>> @@ -360,9 +453,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.
>>   	 */
>> @@ -374,10 +464,6 @@ xfs_attr_set(
>>   
>>   out_defer_cancel:
>>   	xfs_defer_cancel(&dfops);
>> -	args.trans = NULL;
>> -out:
>> -	if (args.trans)
>> -		xfs_trans_cancel(args.trans);
>>   	xfs_iunlock(dp, XFS_ILOCK_EXCL);
>>   	return error;
>>   }
>> @@ -417,38 +503,18 @@ xfs_attr_remove(
>>   	 */
>>   	args.op_flags = XFS_DA_OP_OKNOENT;
>>   
>> -	error = xfs_qm_dqattach(dp, 0);
>> -	if (error)
>> -		return error;
>> -
>> -	/*
>> -	 * Root fork attributes can use reserved data blocks for this
>> -	 * operation if necessary
>> -	 */
>> -	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
>> -			XFS_ATTRRM_SPACE_RES(mp), 0,
>> -			(flags & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
>> -			&args.trans);
>> -	if (error)
>> -		return error;
>> -
>>   	xfs_ilock(dp, XFS_ILOCK_EXCL);
>>   	/*
>>   	 * No need to make quota reservations here. We expect to release some
>>   	 * blocks not allocate in the common case.
>>   	 */
>>   	xfs_trans_ijoin(args.trans, dp, 0);
>> +	xfs_defer_init(args.dfops, args.firstblock);
>> +	error = xfs_qm_dqattach_locked(dp, 0);
>> +	if (error)
>> +		return error;
>>   
>> -	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);
>> -	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> -		error = xfs_attr_leaf_removename(&args);
>> -	} else {
>> -		error = xfs_attr_node_removename(&args);
>> -	}
>> +	error = xfs_attr_remove_args(&args, flags);
>>   
>>   	if (error)
>>   		goto out;
>> @@ -460,9 +526,6 @@ xfs_attr_remove(
>>   	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.
>>   	 */
>> @@ -473,6 +536,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/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
>> index 8926379..7fa58fa 100644
>> --- a/fs/xfs/libxfs/xfs_bmap.c
>> +++ b/fs/xfs/libxfs/xfs_bmap.c
>> @@ -1066,6 +1066,37 @@ 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_UUID:
>> +		ip->i_d.di_forkoff = roundup(sizeof(uuid_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.
>> @@ -1119,29 +1150,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_UUID:
>> -		ip->i_d.di_forkoff = roundup(sizeof(uuid_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/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
>> index 502e0d8..5ca4a73 100644
>> --- a/fs/xfs/libxfs/xfs_bmap.h
>> +++ b/fs/xfs/libxfs/xfs_bmap.h
>> @@ -210,6 +210,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,
>> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
>> index 5d5a5e2..8542606 100644
>> --- a/fs/xfs/xfs_attr.h
>> +++ b/fs/xfs/xfs_attr.h
>> @@ -149,7 +149,9 @@ 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, 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);
> libxfs functions should be declared in a libxfs header, not here.
Alrighty, will move.  Thx!
> --D
>
>>   int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>>   		  int flags, struct attrlist_cursor_kern *cursor);
>>   
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message tomajordomo@vger.kernel.org
>> More majordomo info athttp://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH v3 17/17] Add parent pointer ioctl
  2017-11-28 20:35   ` Darrick J. Wong
@ 2017-11-29 18:52     ` Allison Henderson
  2017-11-29 21:37     ` Dave Chinner
  1 sibling, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:52 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 11/28/2017 01:35 PM, Darrick J. Wong wrote:

> On Fri, Nov 17, 2017 at 11:21:45AM -0700, Allison Henderson wrote:
>> 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>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++
>>   fs/xfs/libxfs/xfs_fs.h   |  1 +
>>   fs/xfs/xfs_attr.h        |  2 ++
>>   fs/xfs/xfs_attr_list.c   |  3 +++
>>   fs/xfs/xfs_ioctl.c       | 48 +++++++++++++++++++++++++++++++++-
>>   5 files changed, 120 insertions(+), 1 deletion(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 9d4d883..d2be842 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -134,6 +134,73 @@ xfs_attr_get_ilocked(
>>   		return xfs_attr_node_get(args);
>>   }
>>   
>> +/*
>> + * Get the parent pointer for a given inode
>> + * Caller will need to allocate a buffer pointed to by xpnir->p_name
>> + * and store the buffer size in xpnir->p_namelen.  The parent
>> + * pointer will be stored in the given xfs_parent_name_irec
>> + *
>> + * Returns 0 on success and non zero on error
>> + */
>> +int
>> +xfs_attr_get_parent_pointer(struct xfs_inode		*ip,
>> +			    struct xfs_parent_name_irec *xpnir)
> Please fix the parameter list here.
>
>> +{
>> +	struct attrlist			*alist;
>> +	struct attrlist_ent		*aent;
>> +	struct attrlist_cursor_kern     cursor;
>> +	struct xfs_parent_name_rec	*xpnr;
>> +	char				*namebuf;
>> +	int                             error = 0;
>> +	unsigned int                    flags = ATTR_PARENT;
>> +
>> +	/* Allocate a buffer to store the attribute names */
>> +	namebuf = kmem_zalloc_large(XFS_XATTR_LIST_MAX, KM_SLEEP);
>> +	if (!namebuf)
>> +		return -ENOMEM;
>> +
>> +	/* Get all attribute names that have the ATTR_PARENT flag */
>> +	memset(&cursor, 0, sizeof(struct attrlist_cursor_kern));
>> +	error = xfs_attr_list(ip, namebuf, XFS_XATTR_LIST_MAX, flags, &cursor);
>> +	if (error)
>> +		goto out_kfree;
>> +
>> +	alist = (struct attrlist *)namebuf;
>> +
>> +	/* There should never be more than one parent pointer */
>> +	ASSERT(alist->al_count == 1);
> As mentioned earlier, this is not true.  Files can have multiple parents.
>
>> +	aent = (struct attrlist_ent *) &namebuf[alist->al_offset[0]];
>> +	xpnr = (struct xfs_parent_name_rec *)(aent->a_name);
>> +
>> +	/*
>> +	 * The value of the parent pointer attribute should be the file name
>> +	 * So we check the value length of the attribute entry against the name
>> +	 * length of the parent name record to make sure the caller gave enough
>> +	 * buffer space to store the file name (plus a null terminator)
>> +	 */
>> +	if (aent->a_valuelen >= xpnir->p_namelen) {
>> +		error = -ERANGE;
>> +		goto out_kfree;
>> +	}
>> +
>> +	xpnir->p_namelen = aent->a_valuelen + 1;
>> +	memset((void *)(xpnir->p_name), 0, xpnir->p_namelen);
>> +	error = xfs_attr_get(ip, (char *)xpnr,
>> +			     sizeof(struct xfs_parent_name_rec),
>> +			     (unsigned char *)(xpnir->p_name),
>> +			     (int *)&(xpnir->p_namelen), flags);
>> +	if (error)
>> +		goto out_kfree;
>> +
>> +	xfs_init_parent_name_irec(xpnir, xpnr);
>> +
>> +out_kfree:
>> +	kmem_free(namebuf);
>> +
>> +	return error;
>> +}
>> +
>>   /* Retrieve an extended attribute by name, and its value. */
>>   int
>>   xfs_attr_get(
>> diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
>> index b8108f8..2f9ca2c 100644
>> --- a/fs/xfs/libxfs/xfs_fs.h
>> +++ b/fs/xfs/libxfs/xfs_fs.h
>> @@ -512,6 +512,7 @@ typedef struct xfs_swapext
>>   #define XFS_IOC_ZERO_RANGE	_IOW ('X', 57, struct xfs_flock64)
>>   #define XFS_IOC_FREE_EOFBLOCKS	_IOR ('X', 58, struct xfs_fs_eofblocks)
>>   /*	XFS_IOC_GETFSMAP ------ hoisted 59         */
>> +#define XFS_IOC_GETPPOINTER	_IOR ('X', 61, struct xfs_parent_name_irec)
> I don't think it's a good idea to expose internal data structures
> directly to userspace, because that inhibits our ability to change the
> in-core data structure.
Yes, this part I already have that separated in my local copy
> Furthermore, hardlinked files can have multiple parent pointers, so it's
> not going to suffice to return a single parent pointer entry.  Given
> that there can be potentially 2^32 parents, we're going to need a data
> structure for the ioctl to store (in an opaque manner) the attribute
> iteration cursor and have space to pass back some number of parent
> pointers.
>
> (Yes, it's time to start talking about actual use cases...)
>
> At a bare minimum, this is what I pictured for the "return parents of
> the open file" ioctl:
>
> #define XFS_PPTR_MAXNAMELEN		255
>
> struct xfs_pptr {
> 	u64				pp_ino;
> 	u32				pp_gen;
> 	u8				pp_namelen;
> 	u8				pp_name[XFS_PPTR_MAXNAMELEN];
> };
>
> /* return parents of the handle, instead of the open fd */
> #define XFS_PPTR_FLAG_HANDLE		(1u << 0)
>
> struct xfs_pptr_info {
> 	struct xfs_fsop_handlereq	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];
> 	struct xfs_pptr			pi_ptrs[0];
> };
>
> #define XFS_PPTR_INFO_SIZEOF(ptrs)	(sizeof(struct xfs_pptr_info) + \
> 					((ptrs) * sizeof(struct xfs_pptr)));
>
> static inline struct xfs_pptr_info *
> xfs_pptr_alloc(
> 	size_t			nr_ptrs)
> {
> 	struct xfs_pptr_info	*ppi;
>
> 	ppi = malloc(XFS_PPTR_INFO_SIZEOF(nr_ptrs));
> 	if (!ppi)
> 		return NULL;
> 	memset(ppi, 0, XFS_PPTR_INFO_SIZEOF(nr_ptrs));
> 	ppi->pi_ptrs_size = nr_ptrs;
> 	return ppi;
> }
>
> With the following example userspace program (that does no checking
> whatsoever):
>
> int main(int argc, char *argv[])
> {
> 	struct xfs_pptr_info	*ppi;
> 	struct xfs_pptr		*pp;
> 	int			fd;
>
> 	fd = open(argv[1], O_RDONLY);
> 	ppi = xfs_pptr_alloc(32);
>
> 	while (ioctl(fd, XFS_IOC_GETPPOINTER, ppi) == 0 && ppi->pi_ptrs_used) {
> 		for (i = 0; i < ppi->pi_ptrs_used; i++) {
> 			printf("%llu:%u -> %s\n",
> 					ppi->pi_ptrs[i].pp_ino,
> 					ppi->pi_ptrs[i].pp_gen,
> 					ppi->pi_ptrs[i].pp_name);
> 		}
> 	}
> }
>
> Notice here how we the userspace structure contains an opaque attribute
> list cursor, so we can keep coming back for more parent pointers until
> we run out of xattrs (and pi_ptrs_used == 0).  The kernel will copy its
> internal cursor out to the userspace buffer as an opaque cookie prior to
> returning.
>
>  From this simple implementation it shouldn't be difficult to finish the
> parents_by_handle/parentpaths_by_handle functions in libhandle, though
> given that they've never been implemented in Linux and we no longer care
> about Irix, you've some flexibility to change those library functions if
> that is convenient for setting up xfstests.
Wow, ok that makes a lot of sense. I will follow your model here and get 
it fleshed out.  Thank you!
> Speaking of xfstests... what are the initial test cases?  I figured at
> least the following:
>
> 0) mkfs with protofile, make sure the parent records get created
> 1) create file, check parent records
> 2) hardlink file, check both parent records
> 3) delete one link of a hardlinked file, check parent records
> 4) hardlink a file a few thousand times, check that the iteration
>     scheme laid out above actually works
> 5) rename a file within a directory, check the parent records
> 6) rename a file across directories, check the parent records
> 7) some sort of testing where we run out of space while updating pptrs
> 8) add some error injection knobs to make sure that pptr replay actually
>     works correctly
>
> Can you think of other test cases?
I think that is a good start.  This looks similar to what I've been 
doing by hand to stabilize things as I go along.  I'll have to work on 
developing an inject knob for the last one.
> For xfs_scrub, we want to be able to query the parents of any (damaged)
> inode we find in the filesystem.  If the inode is so damaged we can't
> open it (or it's a special file) then scrub has to construct a file
> handle and pass that in via pi_handle.
Alrighty, I will take a look at those routines and see if I can put 
together something that reconstructs the parent pointers with out 
opening the inode
> I /also/ wonder if there's any interest in having a fallback for
> non-pptr filesystems that walks the dentry->d_parent links (like
> d_paths() does) back to the root.  Such a fallback will only work on an
> opened dir or a file opened by path (i.e. not a handle), however, which
> limits its appeal.
>
> --D
You mean a way to get the parent pointer even if they chose not to 
enable the feature flag?  I think its something we could investigate, 
but I think you're right in that the limitations might not make it quite 
as valuable.  IMHO I think maybe getting the full version working first 
might give people a chance to appreciate what it can do, and if it turns 
out to be something that people end up using a lot, then it might 
generate more demand for the "light" version. :-)
>>   /*
>>    * ioctl commands that replace IRIX syssgi()'s
>> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
>> index 0829687..0ec3458 100644
>> --- a/fs/xfs/xfs_attr.h
>> +++ b/fs/xfs/xfs_attr.h
>> @@ -172,6 +172,8 @@ int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
>>   		int flags);
>>   int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
>>   		size_t namelen, unsigned char *value, int valuelen, int flags);
>> +int xfs_attr_get_parent_pointer(struct xfs_inode *ip,
>> +				struct xfs_parent_name_irec *xpnir);
>>   int xfs_attr_set_args(struct xfs_da_args *args, int flags, bool roll_trans);
>>   int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
>>   		size_t namelen, int flags);
>> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
>> index 7740c8a..78fc477 100644
>> --- a/fs/xfs/xfs_attr_list.c
>> +++ b/fs/xfs/xfs_attr_list.c
>> @@ -534,6 +534,9 @@ xfs_attr_put_listent(
>>   	if (((context->flags & ATTR_ROOT) == 0) !=
>>   	    ((flags & XFS_ATTR_ROOT) == 0))
>>   		return;
>> +	if (((context->flags & ATTR_PARENT) == 0) !=
>> +	    ((flags & XFS_ATTR_PARENT) == 0))
>> +		return;
>>   
>>   	arraytop = sizeof(*alist) +
>>   			context->count * sizeof(alist->al_offset[0]);
>> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
>> index 4664314..5492607 100644
>> --- a/fs/xfs/xfs_ioctl.c
>> +++ b/fs/xfs/xfs_ioctl.c
>> @@ -44,6 +44,7 @@
>>   #include "xfs_btree.h"
>>   #include <linux/fsmap.h>
>>   #include "xfs_fsmap.h"
>> +#include "xfs_attr.h"
>>   
>>   #include <linux/capability.h>
>>   #include <linux/cred.h>
>> @@ -1710,6 +1711,50 @@ xfs_ioc_getfsmap(
>>   	return 0;
>>   }
>>   
>> +/*
>> + * IOCTL routine to get the parent pointer of an inode and return it to user
>> + * space.  Caller must pass an struct xfs_parent_name_irec with a name buffer
>> + * large enough to hold the file name.  Returns 0 on success or non-zero on
>> + * failure
>> + */
>> +STATIC int
>> +xfs_ioc_get_parent_pointer(
>> +	struct file			*filp,
>> +	void				__user *arg)
>> +{
>> +	struct inode			*inode = file_inode(filp);
>> +	struct xfs_inode		*ip = XFS_I(inode);
>> +	struct xfs_parent_name_irec	xpnir;
>> +	char				*uname;
>> +	char				*kname;
>> +	int				error = 0;
>> +
>> +	copy_from_user(&xpnir, arg, sizeof(struct xfs_parent_name_irec));
>> +	uname = (char *)xpnir.p_name;
>> +
>> +	/*
>> +	 * Use kernel space memory to get the parent pointer name.
>> +	 * We'll copy it to the user space name back when we're done
>> +	 */
>> +	kname = kmem_zalloc_large(xpnir.p_namelen, KM_SLEEP);
> Please sanity-check the amount of memory we try to allocate.
>
>> +	if (!kname)
>> +		return -ENOMEM;
>> +
>> +	xpnir.p_name = kname;
>> +	error = xfs_attr_get_parent_pointer(ip, &xpnir);
>> +
>> +	if (error)
>> +		goto out;
>> +
>> +	copy_to_user(uname, xpnir.p_name, xpnir.p_namelen);
>> +	xpnir.p_name = uname;
>> +	copy_to_user(arg, &xpnir, sizeof(struct xfs_parent_name_irec));
>> +
>> +out:
>> +	kmem_free(kname);
>> +	return error;
>> +}
>> +
>>   int
>>   xfs_ioc_swapext(
>>   	xfs_swapext_t	*sxp)
>> @@ -1866,7 +1911,8 @@ xfs_file_ioctl(
>>   		return xfs_ioc_getxflags(ip, arg);
>>   	case XFS_IOC_SETXFLAGS:
>>   		return xfs_ioc_setxflags(ip, filp, arg);
>> -
>> +	case XFS_IOC_GETPPOINTER:
>> +		return xfs_ioc_get_parent_pointer(filp, arg);
>>   	case XFS_IOC_FSSETDM: {
>>   		struct fsdmidata	dmi;
>>   
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message tomajordomo@vger.kernel.org
>> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=4f7DOEYDfWf_ZRdBfE0cU7L0QfDJjKolv1tc2HeLeck&s=6K6iOFwNgQv30L_9mpWjoAPsnvxojOglPp6hADhWRb8&e=
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message tomajordomo@vger.kernel.org
> More majordomo info athttps://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=4f7DOEYDfWf_ZRdBfE0cU7L0QfDJjKolv1tc2HeLeck&s=6K6iOFwNgQv30L_9mpWjoAPsnvxojOglPp6hADhWRb8&e=


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

* Re: [PATCH v3 02/17] Set up infastructure for deferred attribute operations
  2017-11-29  1:19     ` Dave Chinner
@ 2017-11-29 18:52       ` Allison Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 18:52 UTC (permalink / raw)
  To: Dave Chinner, Darrick J. Wong; +Cc: linux-xfs

On 11/28/2017 06:19 PM, Dave Chinner wrote:

> On Tue, Nov 28, 2017 at 11:45:47AM -0800, Darrick J. Wong wrote:
>> On Fri, Nov 17, 2017 at 11:21:30AM -0700, Allison Henderson wrote:
>>> +/*
>>> + * This is the structure used to lay out an attr log item in the
>>> + * log.
>>> + */
>>> +struct xfs_attr_log_format {
>>> +	uint64_t	alf_id;		/* attri identifier */
>>> +	xfs_ino_t       alf_ino;	/* the inode for this attr operation */
>>> +	uint32_t        alf_op_flags;	/* marks the op as a set or remove */
>>> +	uint32_t        alf_name_len;	/* attr name length */
>>> +	uint32_t        alf_value_len;	/* attr value length */
>>> +	uint32_t        alf_attr_flags;	/* attr flags */
>>> +	uint16_t	alf_type;	/* attri log item type */
>>> +	uint16_t	alf_size;	/* size of this item */
>> Type and size should go first so that the self-identification
>> information ends up at the same byte offsets as the other log formats.
>> This makes it much easier to dissect dirty log contents by hand if
>> things get messy.
> I'll point out this is not a "nice to have" feature but a
> requirement of the on-disk log format structures.
>
> That is, log recovery assumes that every log format item it finds in
> the log has it's type and size as the first two 16 bit fields in the
> log format item so it can validate that a) it's a known log format
> type, and b) knows how big the log format structure it is about to
> decode is supposed to be.
>
>  From fs/xfs/xfs_log_recovery.c:
>
> /*
>   * The next region to add is the start of a new region.  It could be
>   * a whole region or it could be the first part of a new region.  Because
>   * of this, the assumption here is that the type and size fields of all
>   * format structures fit into the first 32 bits of the structure.
>   *
>   * This works because all regions must be 32 bit aligned.  Therefore, we
>   * either have both fields or we have neither field.  In the case we have
>   * neither field, the data part of the region is zero length.  We only have
>   * a log_op_header and can throw away the header since a new one will appear
>   * later.  If we have at least 4 bytes, then we can determine how many regions
>   * will appear in the current log item.
>   */
> STATIC int
> xlog_recover_add_to_trans(
> .....
>
> Also, see the use of the ITEM_TYPE() macro in
> fs/xfs/xfs_log_recovery.c as another example of assuming the type
> field is the first 16 bits of the log format structures....
>
>
> Cheers,
>
> Dave.
Alrighty, thank you for pointing that out, I will be sure to get it 
corrected in the next version.  And thanks everyone for the very 
thorough review!!

Allison


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

* Re: [PATCH v3 11/17] Add the extra space requirements for parent pointer attributes when calculating the minimum log size during mkfs
  2017-11-29 18:47     ` Allison Henderson
@ 2017-11-29 20:18       ` Darrick J. Wong
  0 siblings, 0 replies; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-29 20:18 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

On Wed, Nov 29, 2017 at 11:47:27AM -0700, Allison Henderson wrote:
> On 11/28/2017 11:51 AM, Darrick J. Wong wrote:
> 
> >On Fri, Nov 17, 2017 at 11:21:39AM -0700, Allison Henderson wrote:
> >>Signed-off-by: Allison Henderson<allison.henderson@oracle.com>
> >>---
> >>  fs/xfs/libxfs/xfs_log_rlimit.c | 34 ++++++++++++++++++++++++++++++++++
> >>  1 file changed, 34 insertions(+)
> >>
> >>diff --git a/fs/xfs/libxfs/xfs_log_rlimit.c b/fs/xfs/libxfs/xfs_log_rlimit.c
> >>index c105979..beec9bf 100644
> >>--- a/fs/xfs/libxfs/xfs_log_rlimit.c
> >>+++ b/fs/xfs/libxfs/xfs_log_rlimit.c
> >>@@ -39,6 +39,40 @@ xfs_log_calc_max_attrsetm_res(
> >>  {
> >>  	int			size;
> >>  	int			nblks;
> >>+	struct xfs_trans_resv   *resp = M_RES(mp);
> >>+
> >>+	/* Calculate extra space needed for parent pointer attributes */
> >>+	if (!xfs_sb_version_hasparent(&mp->m_sb)) {
> >if (xfs_sb_version_hasparent()) ?
> >
> >--D
> yeah I think you're right.   This means there's something wrong with the
> check then, because it appears to succeed.  I will debug that, it's probably
> the command line flag i added to mkfs.xfs to exercise it.

Keep in mind that the log reservation calculations represent worst case
space requirements, so if we screw this up we won't always immediately
see things blow up... until some time later when a heavily fragmented fs
actually needs the worst case space, overruns, and bombs. :(

Also mkfs probably formats a larger log than the minimum requirements,
unless you have a bunch of 500M disks lying around for testing.

--D

> >>+
> >>+		/* 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;
> >>+	}
> >>+
> >>  	size = xfs_attr_leaf_entsize_local_max(mp->m_attr_geo->blksize) -
> >>  	       MAXNAMELEN - 1;
> >>-- 
> >>2.7.4
> >>
> >>--
> >>To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> >>the body of a message tomajordomo@vger.kernel.org
> >>More majordomo info athttp://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] 69+ messages in thread

* Re: [PATCH v3 17/17] Add parent pointer ioctl
  2017-11-28 20:35   ` Darrick J. Wong
  2017-11-29 18:52     ` Allison Henderson
@ 2017-11-29 21:37     ` Dave Chinner
  2017-11-29 22:48       ` Allison Henderson
  1 sibling, 1 reply; 69+ messages in thread
From: Dave Chinner @ 2017-11-29 21:37 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: Allison Henderson, linux-xfs

On Tue, Nov 28, 2017 at 12:35:37PM -0800, Darrick J. Wong wrote:
> On Fri, Nov 17, 2017 at 11:21:45AM -0700, Allison Henderson wrote:
> > This patch adds a new file ioctl to retrieve the parent
> > pointer of a given inode
> 
> (Yes, it's time to start talking about actual use cases...)
> 
> At a bare minimum, this is what I pictured for the "return parents of
> the open file" ioctl:
> 
> #define XFS_PPTR_MAXNAMELEN		255
> 
> struct xfs_pptr {
> 	u64				pp_ino;
> 	u32				pp_gen;
> 	u8				pp_namelen;
> 	u8				pp_name[XFS_PPTR_MAXNAMELEN];
> };

That's going to be a different size on 32bit and 64 bit platforms
as the structure size is a multiple of 4 bytes, not 8 bytes.
That will cause problems and need complex comapt ioctl translation.
Better to make pp_namelen a u32 and that will make the structure
64 bit aligned and sized on all platforms.

I'd allow more than u8 for the namelen. Yes, while we currently
allow on 255 bytes for a name, it would make more sense to
use a u32 here so that the structure size is a multiple of it's
alignment rather than having a 4 byte hole in the array we don't
fill out....

> 
> /* return parents of the handle, instead of the open fd */
> #define XFS_PPTR_FLAG_HANDLE		(1u << 0)
> 
> struct xfs_pptr_info {
> 	struct xfs_fsop_handlereq	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];
> 	struct xfs_pptr			pi_ptrs[0];
> };

I thought gcc had started doing weird things with variable size
array declarations like this (i.e. pi_ptrs[0]) because the exact
behaviour is not defined in the C standard. i.e. we need to avoid
adding new declarations that do this...


> #define XFS_PPTR_INFO_SIZEOF(ptrs)	(sizeof(struct xfs_pptr_info) + \
> 					((ptrs) * sizeof(struct xfs_pptr)));
> static inline struct xfs_pptr_info *
> xfs_pptr_alloc(
> 	size_t			nr_ptrs)
> {
> 	struct xfs_pptr_info	*ppi;
> 
> 	ppi = malloc(XFS_PPTR_INFO_SIZEOF(nr_ptrs));
> 	if (!ppi)
> 		return NULL;
> 	memset(ppi, 0, XFS_PPTR_INFO_SIZEOF(nr_ptrs));
> 	ppi->pi_ptrs_size = nr_ptrs;
> 	return ppi;
> }
> 
> With the following example userspace program (that does no checking
> whatsoever):
> 
> int main(int argc, char *argv[])
> {
> 	struct xfs_pptr_info	*ppi;
> 	struct xfs_pptr		*pp;
> 	int			fd;
> 
> 	fd = open(argv[1], O_RDONLY);
> 	ppi = xfs_pptr_alloc(32);
> 
> 	while (ioctl(fd, XFS_IOC_GETPPOINTER, ppi) == 0 && ppi->pi_ptrs_used) {
> 		for (i = 0; i < ppi->pi_ptrs_used; i++) {
> 			printf("%llu:%u -> %s\n",
> 					ppi->pi_ptrs[i].pp_ino,
> 					ppi->pi_ptrs[i].pp_gen,
> 					ppi->pi_ptrs[i].pp_name);
> 		}
> 	}
> }

Seems like a reasonable model to me.

> I /also/ wonder if there's any interest in having a fallback for
> non-pptr filesystems that walks the dentry->d_parent links (like
> d_paths() does) back to the root.  Such a fallback will only work on an
> opened dir or a file opened by path (i.e. not a handle), however, which
> limits its appeal.

I wouldn't bother complicating anything by trying to support
filesytems that don't have parent pointer info. Just have
non-parent-ptr filesystems return EOPNOTSUPP for the ioctl and be
done with it...

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v3 01/17] Add helper functions xfs_attr_set_args and xfs_attr_remove_args
  2017-11-29 18:52     ` Allison Henderson
@ 2017-11-29 22:34       ` Allison Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 22:34 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 11/29/2017 11:52 AM, Allison Henderson wrote:
> On 11/28/2017 12:54 PM, Darrick J. Wong wrote:
> 
>> On Fri, Nov 17, 2017 at 11:21:29AM -0700, Allison Henderson wrote:
>>> These sub-routines set or remove 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>
>>> ---
>>>   fs/xfs/libxfs/xfs_attr.c | 335 
>>> ++++++++++++++++++++++++++++-------------------
>>>   fs/xfs/libxfs/xfs_bmap.c |  55 ++++----
>>>   fs/xfs/libxfs/xfs_bmap.h |   1 +
>>>   fs/xfs/xfs_attr.h        |   2 +
>>>   4 files changed, 236 insertions(+), 157 deletions(-)
>>>
>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>> index 6249c92..e5f2960 100644
>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>> @@ -168,6 +168,195 @@ 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.
>> We have sufficient space in the single transaction case to do both, 
>> right?
> I will double check.  You mean modifying the directory and then setting 
> the parent pointer?
>>> + */
>>> +int
>>> +xfs_attr_set_args(
>>> +    struct xfs_da_args    *args,
>>> +    int            flags,
>>> +    bool            roll_trans)
>>> +{
>>> +    struct xfs_inode    *dp = args->dp;
>>> +    struct xfs_mount        *mp = dp->i_mount;
>>> +    struct xfs_trans_res    tres;
>>> +    int            rsvd = 0;
>>> +    int            error = 0;
>>> +    int            sf_size;
>>> +
> 
> This is the code (below) I had referenced earlier that was folded in 
> from xfs_set_first_parent in the last version of the set.
>>> +    /*
>>> +     * 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;
>>> +    }
>>> +
>>> +    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;
>> /me raises eyebrows about declaring our own tres here, though it came
>> from the original code so I gues I can't complain too loudly.
>>
>> (Primarily because we use the transaction reservations to calculate the
>> minimum log size, so I would think we'd want this one included in those
>> calculations...)
> I believe that is done in patch 10 right?  We add one more transaction 
> to the create operation for the parent pointer?  Should this one count 
> for another?
>>> +    /*
>>> +     * 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;
>>> +
>>> +    error = xfs_trans_reserve_quota_nblks(args->trans, dp, 
>>> args->total, 0,
>>> +                          rsvd ? XFS_QMOPT_RES_REGBLKS |
>>> +                             XFS_QMOPT_FORCE_RES :
>>> +                             XFS_QMOPT_RES_REGBLKS);
>>> +    if (error)
>>> +        goto out;
>>> +
>>> +    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);
>>> +        if (error != -ENOSPC) {
>>> +            ASSERT(args->trans);
>>> +            if (!error && (flags & ATTR_KERNOTIME) == 0)
>>> +                xfs_trans_ichgtime(args->trans, dp,
>>> +                           XFS_ICHGTIME_CHG);
>>> +            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);
>>> +        if (error)
>>> +            goto out;
>>> +        xfs_defer_ijoin(args->dfops, dp);
>>> +        if (roll_trans) {
>>> +            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;
>>> +        }
>>> +    }
>>> +
>>> +    if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
>>> +        error = xfs_attr_leaf_addname(args);
>>> +    else
>>> +        error = xfs_attr_node_addname(args);
>>> +    if (error)
>>> +        goto out;
>>> +
>>> +    if ((flags & ATTR_KERNOTIME) == 0)
>>> +        xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
>>> +
>>> +    xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
>>> +out:
>>> +    return error;
>>> +}
>>> +
>>> +/*
>>> + * Remove the attribute specified in @args.
>>> + */
>>> +int
>>> +xfs_attr_remove_args(
>>> +    struct xfs_da_args      *args,
>>> +    int            flags)
>>> +{
>>> +    struct xfs_inode    *dp = args->dp;
>>> +    struct xfs_mount    *mp = dp->i_mount;
>>> +    int            error;
>>> +    int                     rsvd = 0;
>>> +
>>> +    /*
>>> +     * Root fork attributes can use reserved data blocks for this
>>> +     * operation if necessary
>>> +     */
>>> +    if (flags & ATTR_ROOT)
>>> +        rsvd = XFS_TRANS_RESERVE;
>> Insert a blank line to separate these two...
>>
>>> +    error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
>>> +        XFS_ATTRRM_SPACE_RES(mp), 0, rsvd, &args->trans);
>>> +
>> ...and remove this one since they're directly related.
> ok, will do
>>> +    if (error)
>>> +        goto out;
>>> +
>>> +    /*
>>> +     * No need to make quota reservations here. We expect to release 
>>> some
>>> +     * blocks not allocate in the common case.
>>> +     */
>>> +    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);
>>> +    } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>> +        error = xfs_attr_leaf_removename(args);
>>> +    } else {
>>> +        error = xfs_attr_node_removename(args);
>>> +    }
>>> +
>>> +    if (error)
>>> +        goto out;
>>> +
>>> +    /*
>>> +     * 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 ((flags & ATTR_KERNOTIME) == 0)
>>> +        xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
>>> +
>>> +    xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
>>> +
>>> +    return error;
>>> +
>>> +out:
>>> +    if (args->trans)
>>> +        xfs_trans_cancel(args->trans);
>>> +
>>> +    return error;
>>> +}
>>> +
>>> +/*
>>>    * Calculate how many blocks we need for the new attribute,
>>>    */
>>>   STATIC int
>>> @@ -214,10 +403,9 @@ xfs_attr_set(
>>>       struct xfs_mount    *mp = dp->i_mount;
>>>       struct xfs_da_args    args;
>>>       struct xfs_defer_ops    dfops;
>>> -    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);
>>> @@ -252,106 +440,11 @@ xfs_attr_set(
>>>               return error;
>>>       }
>>> -    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)
>>> -        return error;
>>> -
>>>       xfs_ilock(dp, XFS_ILOCK_EXCL);
>>> -    error = xfs_trans_reserve_quota_nblks(args.trans, dp, 
>>> args.total, 0,
>>> -                rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
>>> -                       XFS_QMOPT_RES_REGBLKS);
>>> -    if (error) {
>>> -        xfs_iunlock(dp, XFS_ILOCK_EXCL);
>>> -        xfs_trans_cancel(args.trans);
>>> -        return error;
>>> -    }
>>> -
>>> -    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);
>>> -        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);
>>> -        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 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;
>>> -
>>> -    }
>>> -
>>> -    if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
>>> -        error = xfs_attr_leaf_addname(&args);
>>> -    else
>>> -        error = xfs_attr_node_addname(&args);
>>> +    xfs_defer_init(args.dfops, args.firstblock);
>>> +    error = xfs_attr_set_args(&args, flags, true);
>>>       if (error)
>>> -        goto out;
>>> +        goto out_defer_cancel;
>>>       /*
>>>        * If this is a synchronous mount, make sure that the
>>> @@ -360,9 +453,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.
>>>        */
>>> @@ -374,10 +464,6 @@ xfs_attr_set(
>>>   out_defer_cancel:
>>>       xfs_defer_cancel(&dfops);
>>> -    args.trans = NULL;
>>> -out:
>>> -    if (args.trans)
>>> -        xfs_trans_cancel(args.trans);
>>>       xfs_iunlock(dp, XFS_ILOCK_EXCL);
>>>       return error;
>>>   }
>>> @@ -417,38 +503,18 @@ xfs_attr_remove(
>>>        */
>>>       args.op_flags = XFS_DA_OP_OKNOENT;
>>> -    error = xfs_qm_dqattach(dp, 0);
>>> -    if (error)
>>> -        return error;
>>> -
>>> -    /*
>>> -     * Root fork attributes can use reserved data blocks for this
>>> -     * operation if necessary
>>> -     */
>>> -    error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
>>> -            XFS_ATTRRM_SPACE_RES(mp), 0,
>>> -            (flags & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
>>> -            &args.trans);
>>> -    if (error)
>>> -        return error;
>>> -
>>>       xfs_ilock(dp, XFS_ILOCK_EXCL);
>>>       /*
>>>        * No need to make quota reservations here. We expect to 
>>> release some
>>>        * blocks not allocate in the common case.
>>>        */
>>>       xfs_trans_ijoin(args.trans, dp, 0);
>>> +    xfs_defer_init(args.dfops, args.firstblock);
>>> +    error = xfs_qm_dqattach_locked(dp, 0);
>>> +    if (error)
>>> +        return error;
>>> -    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);
>>> -    } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>> -        error = xfs_attr_leaf_removename(&args);
>>> -    } else {
>>> -        error = xfs_attr_node_removename(&args);
>>> -    }
>>> +    error = xfs_attr_remove_args(&args, flags);
>>>       if (error)
>>>           goto out;
>>> @@ -460,9 +526,6 @@ xfs_attr_remove(
>>>       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.
>>>        */
>>> @@ -473,6 +536,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/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
>>> index 8926379..7fa58fa 100644
>>> --- a/fs/xfs/libxfs/xfs_bmap.c
>>> +++ b/fs/xfs/libxfs/xfs_bmap.c
>>> @@ -1066,6 +1066,37 @@ 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_UUID:
>>> +        ip->i_d.di_forkoff = roundup(sizeof(uuid_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.
>>> @@ -1119,29 +1150,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_UUID:
>>> -        ip->i_d.di_forkoff = roundup(sizeof(uuid_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/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
>>> index 502e0d8..5ca4a73 100644
>>> --- a/fs/xfs/libxfs/xfs_bmap.h
>>> +++ b/fs/xfs/libxfs/xfs_bmap.h
>>> @@ -210,6 +210,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,
>>> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
>>> index 5d5a5e2..8542606 100644
>>> --- a/fs/xfs/xfs_attr.h
>>> +++ b/fs/xfs/xfs_attr.h
>>> @@ -149,7 +149,9 @@ 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, 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);
>> libxfs functions should be declared in a libxfs header, not here.
> Alrighty, will move.  Thx!

Should I make a new fs/xfs/libfs/xfs_attr.h for these two?  Or do people 
generally just move the whole header from fs/xfs/ to fs/xfs/libfs?  I'm 
a little puzzled as to why it's not there already.  Thanks!

Allison

>> --D
>>
>>>   int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>>>             int flags, struct attrlist_cursor_kern *cursor);
>>> -- 
>>> 2.7.4
>>>
>>> -- 
>>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>>> the body of a message tomajordomo@vger.kernel.org
>>> More majordomo info athttp://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  
> https://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIDaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=Vw7DNKdrW801vH0asmDs05cz9GwhOBOP8D9IR0lCzMM&s=yHqomezvPJ_awB8f62O1IQjOdvzALvuP_noYoGPFA3Y&e= 
> 

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

* Re: [PATCH v3 17/17] Add parent pointer ioctl
  2017-11-29 21:37     ` Dave Chinner
@ 2017-11-29 22:48       ` Allison Henderson
  2017-11-30  0:02         ` Dave Chinner
  0 siblings, 1 reply; 69+ messages in thread
From: Allison Henderson @ 2017-11-29 22:48 UTC (permalink / raw)
  To: Dave Chinner, Darrick J. Wong; +Cc: linux-xfs



On 11/29/2017 02:37 PM, Dave Chinner wrote:
> On Tue, Nov 28, 2017 at 12:35:37PM -0800, Darrick J. Wong wrote:
>> On Fri, Nov 17, 2017 at 11:21:45AM -0700, Allison Henderson wrote:
>>> This patch adds a new file ioctl to retrieve the parent
>>> pointer of a given inode
>>
>> (Yes, it's time to start talking about actual use cases...)
>>
>> At a bare minimum, this is what I pictured for the "return parents of
>> the open file" ioctl:
>>
>> #define XFS_PPTR_MAXNAMELEN		255
>>
>> struct xfs_pptr {
>> 	u64				pp_ino;
>> 	u32				pp_gen;
>> 	u8				pp_namelen;
>> 	u8				pp_name[XFS_PPTR_MAXNAMELEN];
>> };
> 
> That's going to be a different size on 32bit and 64 bit platforms
> as the structure size is a multiple of 4 bytes, not 8 bytes.
> That will cause problems and need complex comapt ioctl translation.
> Better to make pp_namelen a u32 and that will make the structure
> 64 bit aligned and sized on all platforms.
> 
> I'd allow more than u8 for the namelen. Yes, while we currently
> allow on 255 bytes for a name, it would make more sense to
> use a u32 here so that the structure size is a multiple of it's
> alignment rather than having a 4 byte hole in the array we don't
> fill out....
> 
>>
>> /* return parents of the handle, instead of the open fd */
>> #define XFS_PPTR_FLAG_HANDLE		(1u << 0)
>>
>> struct xfs_pptr_info {
>> 	struct xfs_fsop_handlereq	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];
>> 	struct xfs_pptr			pi_ptrs[0];
>> };
> 
> I thought gcc had started doing weird things with variable size
> array declarations like this (i.e. pi_ptrs[0]) because the exact
> behaviour is not defined in the C standard. i.e. we need to avoid
> adding new declarations that do this...

Oh, I think there's a few places in the set where I have declarations 
like that.  Should they be some_array[1]; instead?

> 
> 
>> #define XFS_PPTR_INFO_SIZEOF(ptrs)	(sizeof(struct xfs_pptr_info) + \
>> 					((ptrs) * sizeof(struct xfs_pptr)));
>> static inline struct xfs_pptr_info *
>> xfs_pptr_alloc(
>> 	size_t			nr_ptrs)
>> {
>> 	struct xfs_pptr_info	*ppi;
>>
>> 	ppi = malloc(XFS_PPTR_INFO_SIZEOF(nr_ptrs));
>> 	if (!ppi)
>> 		return NULL;
>> 	memset(ppi, 0, XFS_PPTR_INFO_SIZEOF(nr_ptrs));
>> 	ppi->pi_ptrs_size = nr_ptrs;
>> 	return ppi;
>> }
>>
>> With the following example userspace program (that does no checking
>> whatsoever):
>>
>> int main(int argc, char *argv[])
>> {
>> 	struct xfs_pptr_info	*ppi;
>> 	struct xfs_pptr		*pp;
>> 	int			fd;
>>
>> 	fd = open(argv[1], O_RDONLY);
>> 	ppi = xfs_pptr_alloc(32);
>>
>> 	while (ioctl(fd, XFS_IOC_GETPPOINTER, ppi) == 0 && ppi->pi_ptrs_used) {
>> 		for (i = 0; i < ppi->pi_ptrs_used; i++) {
>> 			printf("%llu:%u -> %s\n",
>> 					ppi->pi_ptrs[i].pp_ino,
>> 					ppi->pi_ptrs[i].pp_gen,
>> 					ppi->pi_ptrs[i].pp_name);
>> 		}
>> 	}
>> }
> 
> Seems like a reasonable model to me.
> 
>> I /also/ wonder if there's any interest in having a fallback for
>> non-pptr filesystems that walks the dentry->d_parent links (like
>> d_paths() does) back to the root.  Such a fallback will only work on an
>> opened dir or a file opened by path (i.e. not a handle), however, which
>> limits its appeal.
> 
> I wouldn't bother complicating anything by trying to support
> filesytems that don't have parent pointer info. Just have
> non-parent-ptr filesystems return EOPNOTSUPP for the ioctl and be
> done with it...
> 
> Cheers,
> 
> Dave.
> 

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

* Re: [PATCH v3 17/17] Add parent pointer ioctl
  2017-11-29 22:48       ` Allison Henderson
@ 2017-11-30  0:02         ` Dave Chinner
  2017-11-30  1:52           ` Allison Henderson
  2017-11-30 21:11           ` Darrick J. Wong
  0 siblings, 2 replies; 69+ messages in thread
From: Dave Chinner @ 2017-11-30  0:02 UTC (permalink / raw)
  To: Allison Henderson; +Cc: Darrick J. Wong, linux-xfs

On Wed, Nov 29, 2017 at 03:48:50PM -0700, Allison Henderson wrote:
> 
> 
> On 11/29/2017 02:37 PM, Dave Chinner wrote:
> >On Tue, Nov 28, 2017 at 12:35:37PM -0800, Darrick J. Wong wrote:
> >>On Fri, Nov 17, 2017 at 11:21:45AM -0700, Allison Henderson wrote:
> >>>This patch adds a new file ioctl to retrieve the parent
> >>>pointer of a given inode
> >>
> >>(Yes, it's time to start talking about actual use cases...)
> >>
> >>At a bare minimum, this is what I pictured for the "return parents of
> >>the open file" ioctl:
> >>
> >>#define XFS_PPTR_MAXNAMELEN		255
> >>
> >>struct xfs_pptr {
> >>	u64				pp_ino;
> >>	u32				pp_gen;
> >>	u8				pp_namelen;
> >>	u8				pp_name[XFS_PPTR_MAXNAMELEN];
> >>};
> >
> >That's going to be a different size on 32bit and 64 bit platforms
> >as the structure size is a multiple of 4 bytes, not 8 bytes.
> >That will cause problems and need complex comapt ioctl translation.
> >Better to make pp_namelen a u32 and that will make the structure
> >64 bit aligned and sized on all platforms.
> >
> >I'd allow more than u8 for the namelen. Yes, while we currently
> >allow on 255 bytes for a name, it would make more sense to
> >use a u32 here so that the structure size is a multiple of it's
> >alignment rather than having a 4 byte hole in the array we don't
> >fill out....
> >
> >>
> >>/* return parents of the handle, instead of the open fd */
> >>#define XFS_PPTR_FLAG_HANDLE		(1u << 0)
> >>
> >>struct xfs_pptr_info {
> >>	struct xfs_fsop_handlereq	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];
> >>	struct xfs_pptr			pi_ptrs[0];
> >>};
> >
> >I thought gcc had started doing weird things with variable size
> >array declarations like this (i.e. pi_ptrs[0]) because the exact
> >behaviour is not defined in the C standard. i.e. we need to avoid
> >adding new declarations that do this...
> 
> Oh, I think there's a few places in the set where I have
> declarations like that.

Yup, there are quite a few, but IIRC we can't rely on them working
as they do right now in future compilers. So I'm pretty sure we need
to avoid these sorts of constructs if we can. Doing something like
this:

struct xfs_pptr_info {
	struct xfs_fsop_handlereq	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.
	 */
};

And providing an accessor function:

#define XFS_PPINFO_TO_PP(info, idx)	\
	(&(((struct xfs_pptr *)((char *)(info) + sizeof(*(info))))[(idx)]))

Will solve the problem.

> Should they be some_array[1]; instead?

That has problems, too. See, for example, commit ffeecc521302 ("xfs:
Fix xfs_attr_leafblock definition"), where gcc completely mangled
the code because it thought it could optimise away bits of the
structure and code that "weren't used".

> >>#define XFS_PPTR_INFO_SIZEOF(ptrs)	(sizeof(struct xfs_pptr_info) + \
> >>					((ptrs) * sizeof(struct xfs_pptr)));
> >>static inline struct xfs_pptr_info *
> >>xfs_pptr_alloc(
> >>	size_t			nr_ptrs)
> >>{
> >>	struct xfs_pptr_info	*ppi;
> >>
> >>	ppi = malloc(XFS_PPTR_INFO_SIZEOF(nr_ptrs));
> >>	if (!ppi)
> >>		return NULL;
> >>	memset(ppi, 0, XFS_PPTR_INFO_SIZEOF(nr_ptrs));
> >>	ppi->pi_ptrs_size = nr_ptrs;
> >>	return ppi;
> >>}
> >>
> >>With the following example userspace program (that does no checking
> >>whatsoever):
> >>
> >>int main(int argc, char *argv[])
> >>{
> >>	struct xfs_pptr_info	*ppi;
> >>	struct xfs_pptr		*pp;
> >>	int			fd;
> >>
> >>	fd = open(argv[1], O_RDONLY);
> >>	ppi = xfs_pptr_alloc(32);
> >>
> >>	while (ioctl(fd, XFS_IOC_GETPPOINTER, ppi) == 0 && ppi->pi_ptrs_used) {
> >>		for (i = 0; i < ppi->pi_ptrs_used; i++) {
> >>			printf("%llu:%u -> %s\n",
> >>					ppi->pi_ptrs[i].pp_ino,
> >>					ppi->pi_ptrs[i].pp_gen,
> >>					ppi->pi_ptrs[i].pp_name);

And this becomes:

		for (i = 0; i < ppi->pi_ptrs_used; i++) {
			pp = XFS_PPINFO_TO_PP(ppi, i);
			printf("%llu:%u -> %s\n", pp->pp_ino, pp->pp_gen,
						  pp->pp_name);
		}

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH v3 17/17] Add parent pointer ioctl
  2017-11-30  0:02         ` Dave Chinner
@ 2017-11-30  1:52           ` Allison Henderson
  2017-11-30 21:11           ` Darrick J. Wong
  1 sibling, 0 replies; 69+ messages in thread
From: Allison Henderson @ 2017-11-30  1:52 UTC (permalink / raw)
  To: Dave Chinner; +Cc: Darrick J. Wong, linux-xfs



On 11/29/2017 05:02 PM, Dave Chinner wrote:
> On Wed, Nov 29, 2017 at 03:48:50PM -0700, Allison Henderson wrote:
>>
>>
>> On 11/29/2017 02:37 PM, Dave Chinner wrote:
>>> On Tue, Nov 28, 2017 at 12:35:37PM -0800, Darrick J. Wong wrote:
>>>> On Fri, Nov 17, 2017 at 11:21:45AM -0700, Allison Henderson wrote:
>>>>> This patch adds a new file ioctl to retrieve the parent
>>>>> pointer of a given inode
>>>>
>>>> (Yes, it's time to start talking about actual use cases...)
>>>>
>>>> At a bare minimum, this is what I pictured for the "return parents of
>>>> the open file" ioctl:
>>>>
>>>> #define XFS_PPTR_MAXNAMELEN		255
>>>>
>>>> struct xfs_pptr {
>>>> 	u64				pp_ino;
>>>> 	u32				pp_gen;
>>>> 	u8				pp_namelen;
>>>> 	u8				pp_name[XFS_PPTR_MAXNAMELEN];
>>>> };
>>>
>>> That's going to be a different size on 32bit and 64 bit platforms
>>> as the structure size is a multiple of 4 bytes, not 8 bytes.
>>> That will cause problems and need complex comapt ioctl translation.
>>> Better to make pp_namelen a u32 and that will make the structure
>>> 64 bit aligned and sized on all platforms.
>>>
>>> I'd allow more than u8 for the namelen. Yes, while we currently
>>> allow on 255 bytes for a name, it would make more sense to
>>> use a u32 here so that the structure size is a multiple of it's
>>> alignment rather than having a 4 byte hole in the array we don't
>>> fill out....
>>>
>>>>
>>>> /* return parents of the handle, instead of the open fd */
>>>> #define XFS_PPTR_FLAG_HANDLE		(1u << 0)
>>>>
>>>> struct xfs_pptr_info {
>>>> 	struct xfs_fsop_handlereq	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];
>>>> 	struct xfs_pptr			pi_ptrs[0];
>>>> };
>>>
>>> I thought gcc had started doing weird things with variable size
>>> array declarations like this (i.e. pi_ptrs[0]) because the exact
>>> behaviour is not defined in the C standard. i.e. we need to avoid
>>> adding new declarations that do this...
>>
>> Oh, I think there's a few places in the set where I have
>> declarations like that.
> 
> Yup, there are quite a few, but IIRC we can't rely on them working
> as they do right now in future compilers. So I'm pretty sure we need
> to avoid these sorts of constructs if we can. Doing something like
> this:
> 
> struct xfs_pptr_info {
> 	struct xfs_fsop_handlereq	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.
> 	 */
> };
> 
> And providing an accessor function:
> 
> #define XFS_PPINFO_TO_PP(info, idx)	\
> 	(&(((struct xfs_pptr *)((char *)(info) + sizeof(*(info))))[(idx)]))
> 
> Will solve the problem.
> 
>> Should they be some_array[1]; instead?
> 
> That has problems, too. See, for example, commit ffeecc521302 ("xfs:
> Fix xfs_attr_leafblock definition"), where gcc completely mangled
> the code because it thought it could optimise away bits of the
> structure and code that "weren't used".
> 
>>>> #define XFS_PPTR_INFO_SIZEOF(ptrs)	(sizeof(struct xfs_pptr_info) + \
>>>> 					((ptrs) * sizeof(struct xfs_pptr)));
>>>> static inline struct xfs_pptr_info *
>>>> xfs_pptr_alloc(
>>>> 	size_t			nr_ptrs)
>>>> {
>>>> 	struct xfs_pptr_info	*ppi;
>>>>
>>>> 	ppi = malloc(XFS_PPTR_INFO_SIZEOF(nr_ptrs));
>>>> 	if (!ppi)
>>>> 		return NULL;
>>>> 	memset(ppi, 0, XFS_PPTR_INFO_SIZEOF(nr_ptrs));
>>>> 	ppi->pi_ptrs_size = nr_ptrs;
>>>> 	return ppi;
>>>> }
>>>>
>>>> With the following example userspace program (that does no checking
>>>> whatsoever):
>>>>
>>>> int main(int argc, char *argv[])
>>>> {
>>>> 	struct xfs_pptr_info	*ppi;
>>>> 	struct xfs_pptr		*pp;
>>>> 	int			fd;
>>>>
>>>> 	fd = open(argv[1], O_RDONLY);
>>>> 	ppi = xfs_pptr_alloc(32);
>>>>
>>>> 	while (ioctl(fd, XFS_IOC_GETPPOINTER, ppi) == 0 && ppi->pi_ptrs_used) {
>>>> 		for (i = 0; i < ppi->pi_ptrs_used; i++) {
>>>> 			printf("%llu:%u -> %s\n",
>>>> 					ppi->pi_ptrs[i].pp_ino,
>>>> 					ppi->pi_ptrs[i].pp_gen,
>>>> 					ppi->pi_ptrs[i].pp_name);
> 
> And this becomes:
> 
> 		for (i = 0; i < ppi->pi_ptrs_used; i++) {
> 			pp = XFS_PPINFO_TO_PP(ppi, i);
> 			printf("%llu:%u -> %s\n", pp->pp_ino, pp->pp_gen,
> 						  pp->pp_name);
> 		}
> 
> Cheers,
> 
> Dave.
> 
Alrighty then, thank you!

Allison

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

* Re: [PATCH v3 17/17] Add parent pointer ioctl
  2017-11-30  0:02         ` Dave Chinner
  2017-11-30  1:52           ` Allison Henderson
@ 2017-11-30 21:11           ` Darrick J. Wong
  2017-12-01  2:58             ` Dave Chinner
  1 sibling, 1 reply; 69+ messages in thread
From: Darrick J. Wong @ 2017-11-30 21:11 UTC (permalink / raw)
  To: Dave Chinner; +Cc: Allison Henderson, linux-xfs

On Thu, Nov 30, 2017 at 11:02:51AM +1100, Dave Chinner wrote:
> On Wed, Nov 29, 2017 at 03:48:50PM -0700, Allison Henderson wrote:
> > 
> > 
> > On 11/29/2017 02:37 PM, Dave Chinner wrote:
> > >On Tue, Nov 28, 2017 at 12:35:37PM -0800, Darrick J. Wong wrote:
> > >>On Fri, Nov 17, 2017 at 11:21:45AM -0700, Allison Henderson wrote:
> > >>>This patch adds a new file ioctl to retrieve the parent
> > >>>pointer of a given inode
> > >>
> > >>(Yes, it's time to start talking about actual use cases...)
> > >>
> > >>At a bare minimum, this is what I pictured for the "return parents of
> > >>the open file" ioctl:
> > >>
> > >>#define XFS_PPTR_MAXNAMELEN		255
> > >>
> > >>struct xfs_pptr {
> > >>	u64				pp_ino;
> > >>	u32				pp_gen;
> > >>	u8				pp_namelen;
> > >>	u8				pp_name[XFS_PPTR_MAXNAMELEN];
> > >>};
> > >
> > >That's going to be a different size on 32bit and 64 bit platforms
> > >as the structure size is a multiple of 4 bytes, not 8 bytes.
> > >That will cause problems and need complex comapt ioctl translation.
> > >Better to make pp_namelen a u32 and that will make the structure
> > >64 bit aligned and sized on all platforms.
> > >
> > >I'd allow more than u8 for the namelen. Yes, while we currently
> > >allow on 255 bytes for a name, it would make more sense to
> > >use a u32 here so that the structure size is a multiple of it's
> > >alignment rather than having a 4 byte hole in the array we don't
> > >fill out....

Maybe this ought to get padded up to the nearest 8-byte boundary too.

> > >
> > >>
> > >>/* return parents of the handle, instead of the open fd */
> > >>#define XFS_PPTR_FLAG_HANDLE		(1u << 0)
> > >>
> > >>struct xfs_pptr_info {
> > >>	struct xfs_fsop_handlereq	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];
> > >>	struct xfs_pptr			pi_ptrs[0];
> > >>};
> > >
> > >I thought gcc had started doing weird things with variable size
> > >array declarations like this (i.e. pi_ptrs[0]) because the exact
> > >behaviour is not defined in the C standard. i.e. we need to avoid
> > >adding new declarations that do this...
> > 
> > Oh, I think there's a few places in the set where I have
> > declarations like that.
> 
> Yup, there are quite a few, but IIRC we can't rely on them working
> as they do right now in future compilers. So I'm pretty sure we need
> to avoid these sorts of constructs if we can. Doing something like
> this:

If gcc starts bungling them, there's going to be a lot of stuff in
include/uapi/ that breaks.  FIEMAP, FSMAP, the weird vfs dedupe ioctl...

I think it'll be fine so long as we keep an eye on the structure size
in xfs_ondisk.h.  If the structure size mutates we'll know because the
ioctl will stop working with old userspace and/or we fail the build.

Oh but we don't keep an eye on that stuff.  Sigh.

> struct xfs_pptr_info {
> 	struct xfs_fsop_handlereq	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.
> 	 */
> };
> 
> And providing an accessor function:
> 
> #define XFS_PPINFO_TO_PP(info, idx)	\
> 	(&(((struct xfs_pptr *)((char *)(info) + sizeof(*(info))))[(idx)]))

Eww, macros. :)

static inline struct xfs_pptr *
xfs_ppinfo_to_pp(
	struct xfs_pptr_info	*info,
	unsigned int		idx)
{
	return (struct xfs_pptr *)((char *)(info + 1)) + (idx * sizeof(struct xfs_pptr));
}

> Will solve the problem.
> 
> > Should they be some_array[1]; instead?
> 
> That has problems, too. See, for example, commit ffeecc521302 ("xfs:
> Fix xfs_attr_leafblock definition"), where gcc completely mangled
> the code because it thought it could optimise away bits of the
> structure and code that "weren't used".

Especially no on the some_array[1], that bit us with the v5 AGFL...

> > >>#define XFS_PPTR_INFO_SIZEOF(ptrs)	(sizeof(struct xfs_pptr_info) + \
> > >>					((ptrs) * sizeof(struct xfs_pptr)));
> > >>static inline struct xfs_pptr_info *
> > >>xfs_pptr_alloc(
> > >>	size_t			nr_ptrs)
> > >>{
> > >>	struct xfs_pptr_info	*ppi;
> > >>
> > >>	ppi = malloc(XFS_PPTR_INFO_SIZEOF(nr_ptrs));
> > >>	if (!ppi)
> > >>		return NULL;
> > >>	memset(ppi, 0, XFS_PPTR_INFO_SIZEOF(nr_ptrs));
> > >>	ppi->pi_ptrs_size = nr_ptrs;
> > >>	return ppi;
> > >>}
> > >>
> > >>With the following example userspace program (that does no checking
> > >>whatsoever):
> > >>
> > >>int main(int argc, char *argv[])
> > >>{
> > >>	struct xfs_pptr_info	*ppi;
> > >>	struct xfs_pptr		*pp;
> > >>	int			fd;
> > >>
> > >>	fd = open(argv[1], O_RDONLY);
> > >>	ppi = xfs_pptr_alloc(32);
> > >>
> > >>	while (ioctl(fd, XFS_IOC_GETPPOINTER, ppi) == 0 && ppi->pi_ptrs_used) {
> > >>		for (i = 0; i < ppi->pi_ptrs_used; i++) {
> > >>			printf("%llu:%u -> %s\n",
> > >>					ppi->pi_ptrs[i].pp_ino,
> > >>					ppi->pi_ptrs[i].pp_gen,
> > >>					ppi->pi_ptrs[i].pp_name);
> 
> And this becomes:
> 
> 		for (i = 0; i < ppi->pi_ptrs_used; i++) {
> 			pp = XFS_PPINFO_TO_PP(ppi, i);
> 			printf("%llu:%u -> %s\n", pp->pp_ino, pp->pp_gen,
> 						  pp->pp_name);
> 		}

Funnily enough I've added more bits to this, maybe I should just send a
real RFC patch to the list.

--D

> 
> Cheers,
> 
> Dave.
> -- 
> Dave Chinner
> david@fromorbit.com
> --
> 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] 69+ messages in thread

* Re: [PATCH v3 17/17] Add parent pointer ioctl
  2017-11-30 21:11           ` Darrick J. Wong
@ 2017-12-01  2:58             ` Dave Chinner
  0 siblings, 0 replies; 69+ messages in thread
From: Dave Chinner @ 2017-12-01  2:58 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: Allison Henderson, linux-xfs

On Thu, Nov 30, 2017 at 01:11:34PM -0800, Darrick J. Wong wrote:
> On Thu, Nov 30, 2017 at 11:02:51AM +1100, Dave Chinner wrote:
> > On Wed, Nov 29, 2017 at 03:48:50PM -0700, Allison Henderson wrote:
> > > 
> > > 
> > > On 11/29/2017 02:37 PM, Dave Chinner wrote:
> > > >On Tue, Nov 28, 2017 at 12:35:37PM -0800, Darrick J. Wong wrote:
> > > >>On Fri, Nov 17, 2017 at 11:21:45AM -0700, Allison Henderson wrote:
> > > >>>This patch adds a new file ioctl to retrieve the parent
> > > >>>pointer of a given inode
> > > >>
> > > >>(Yes, it's time to start talking about actual use cases...)
> > > >>
> > > >>At a bare minimum, this is what I pictured for the "return parents of
> > > >>the open file" ioctl:
> > > >>
> > > >>#define XFS_PPTR_MAXNAMELEN		255
> > > >>
> > > >>struct xfs_pptr {
> > > >>	u64				pp_ino;
> > > >>	u32				pp_gen;
> > > >>	u8				pp_namelen;
> > > >>	u8				pp_name[XFS_PPTR_MAXNAMELEN];
> > > >>};
> > > >
> > > >That's going to be a different size on 32bit and 64 bit platforms
> > > >as the structure size is a multiple of 4 bytes, not 8 bytes.
> > > >That will cause problems and need complex comapt ioctl translation.
> > > >Better to make pp_namelen a u32 and that will make the structure
> > > >64 bit aligned and sized on all platforms.
> > > >
> > > >I'd allow more than u8 for the namelen. Yes, while we currently
> > > >allow on 255 bytes for a name, it would make more sense to
> > > >use a u32 here so that the structure size is a multiple of it's
> > > >alignment rather than having a 4 byte hole in the array we don't
> > > >fill out....
> 
> Maybe this ought to get padded up to the nearest 8-byte boundary too.
> 
> > > >
> > > >>
> > > >>/* return parents of the handle, instead of the open fd */
> > > >>#define XFS_PPTR_FLAG_HANDLE		(1u << 0)
> > > >>
> > > >>struct xfs_pptr_info {
> > > >>	struct xfs_fsop_handlereq	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];
> > > >>	struct xfs_pptr			pi_ptrs[0];
> > > >>};
> > > >
> > > >I thought gcc had started doing weird things with variable size
> > > >array declarations like this (i.e. pi_ptrs[0]) because the exact
> > > >behaviour is not defined in the C standard. i.e. we need to avoid
> > > >adding new declarations that do this...
> > > 
> > > Oh, I think there's a few places in the set where I have
> > > declarations like that.
> > 
> > Yup, there are quite a few, but IIRC we can't rely on them working
> > as they do right now in future compilers. So I'm pretty sure we need
> > to avoid these sorts of constructs if we can. Doing something like
> > this:
> 
> If gcc starts bungling them, there's going to be a lot of stuff in
> include/uapi/ that breaks.  FIEMAP, FSMAP, the weird vfs dedupe ioctl...

Yup, that'd kick up a shit storm. But when it's just XFS code that
triggers the problem, the compiler developers don't care that it's
worked for 20 years, they just quote chapter and verse: "code that
relies on undefined language constructs can be broken at any time by
the compiler and we don't care. Fix your code!"

So regardless of whatever happens elsewhere, we need to avoid adding
no potential problems to persistent structures such as on-disk and
ioctl interfaces....

> I think it'll be fine so long as we keep an eye on the structure size
> in xfs_ondisk.h.  If the structure size mutates we'll know because the
> ioctl will stop working with old userspace and/or we fail the build.
> 
> Oh but we don't keep an eye on that stuff.  Sigh.

Because who would expect entire structure members to be optimised
away by the compiler? :/

> > struct xfs_pptr_info {
> > 	struct xfs_fsop_handlereq	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.
> > 	 */
> > };
> > 
> > And providing an accessor function:
> > 
> > #define XFS_PPINFO_TO_PP(info, idx)	\
> > 	(&(((struct xfs_pptr *)((char *)(info) + sizeof(*(info))))[(idx)]))
> 
> Eww, macros. :)

You did it first with XFS_PPTR_INFO_SIZEOF() :P

> > > >>With the following example userspace program (that does no checking
> > > >>whatsoever):
> > > >>
> > > >>int main(int argc, char *argv[])
> > > >>{
> > > >>	struct xfs_pptr_info	*ppi;
> > > >>	struct xfs_pptr		*pp;
> > > >>	int			fd;
> > > >>
> > > >>	fd = open(argv[1], O_RDONLY);
> > > >>	ppi = xfs_pptr_alloc(32);
> > > >>
> > > >>	while (ioctl(fd, XFS_IOC_GETPPOINTER, ppi) == 0 && ppi->pi_ptrs_used) {
> > > >>		for (i = 0; i < ppi->pi_ptrs_used; i++) {
> > > >>			printf("%llu:%u -> %s\n",
> > > >>					ppi->pi_ptrs[i].pp_ino,
> > > >>					ppi->pi_ptrs[i].pp_gen,
> > > >>					ppi->pi_ptrs[i].pp_name);
> > 
> > And this becomes:
> > 
> > 		for (i = 0; i < ppi->pi_ptrs_used; i++) {
> > 			pp = XFS_PPINFO_TO_PP(ppi, i);
> > 			printf("%llu:%u -> %s\n", pp->pp_ino, pp->pp_gen,
> > 						  pp->pp_name);
> > 		}
> 
> Funnily enough I've added more bits to this, maybe I should just send a
> real RFC patch to the list.

Sounds like a plan :P

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

end of thread, other threads:[~2017-12-01  2:58 UTC | newest]

Thread overview: 69+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-17 18:21 [PATCH v3 00/17] Parent Pointers v4 Allison Henderson
2017-11-17 18:21 ` [PATCH v3 01/17] Add helper functions xfs_attr_set_args and xfs_attr_remove_args Allison Henderson
2017-11-28 19:54   ` Darrick J. Wong
2017-11-29  1:02     ` Dave Chinner
2017-11-29 18:52     ` Allison Henderson
2017-11-29 22:34       ` Allison Henderson
2017-11-17 18:21 ` [PATCH v3 02/17] Set up infastructure for deferred attribute operations Allison Henderson
2017-11-28 19:45   ` Darrick J. Wong
2017-11-29  1:19     ` Dave Chinner
2017-11-29 18:52       ` Allison Henderson
2017-11-29 18:51     ` Allison Henderson
2017-11-17 18:21 ` [PATCH v3 03/17] Add xfs_attr_set_defered and xfs_attr_remove_defered Allison Henderson
2017-11-28 19:19   ` Darrick J. Wong
2017-11-29 18:50     ` Allison Henderson
2017-11-17 18:21 ` [PATCH v3 04/17] Remove all strlen calls in all xfs_attr_* functions for attr names Allison Henderson
2017-11-28 19:10   ` Darrick J. Wong
2017-11-29 18:50     ` Allison Henderson
2017-11-17 18:21 ` [PATCH v3 05/17] xfs: get directory offset when adding directory name Allison Henderson
2017-11-28 19:07   ` Darrick J. Wong
2017-11-29 18:50     ` Allison Henderson
2017-11-17 18:21 ` [PATCH v3 06/17] xfs: get directory offset when removing " Allison Henderson
2017-11-28 19:05   ` Darrick J. Wong
2017-11-29 18:49     ` Allison Henderson
2017-11-17 18:21 ` [PATCH v3 07/17] xfs: get directory offset when replacing a " Allison Henderson
2017-11-28 19:04   ` Darrick J. Wong
2017-11-29 18:49     ` Allison Henderson
2017-11-17 18:21 ` [PATCH v3 08/17] xfs: add parent pointer support to attribute code Allison Henderson
2017-11-28 19:01   ` Darrick J. Wong
2017-11-29 18:48     ` Allison Henderson
2017-11-17 18:21 ` [PATCH v3 09/17] xfs: define parent pointer xattr format Allison Henderson
2017-11-28 18:59   ` Darrick J. Wong
2017-11-29 18:48     ` Allison Henderson
2017-11-17 18:21 ` [PATCH v3 10/17] xfs: extent transaction reservations for parent attributes Allison Henderson
2017-11-28 18:58   ` Darrick J. Wong
2017-11-29 18:48     ` Allison Henderson
2017-11-17 18:21 ` [PATCH v3 11/17] Add the extra space requirements for parent pointer attributes when calculating the minimum log size during mkfs Allison Henderson
2017-11-28 18:51   ` Darrick J. Wong
2017-11-29 18:47     ` Allison Henderson
2017-11-29 20:18       ` Darrick J. Wong
2017-11-17 18:21 ` [PATCH v3 12/17] xfs: parent pointer attribute creation Allison Henderson
2017-11-28 18:49   ` Darrick J. Wong
2017-11-28 18:54     ` Darrick J. Wong
2017-11-29 18:46       ` Allison Henderson
2017-11-17 18:21 ` [PATCH v3 13/17] xfs: add parent attributes to link Allison Henderson
2017-11-28 18:37   ` Darrick J. Wong
2017-11-29 18:45     ` Allison Henderson
2017-11-17 18:21 ` [PATCH v3 14/17] xfs: remove parent pointers in unlink Allison Henderson
2017-11-28 18:24   ` Darrick J. Wong
2017-11-29 18:44     ` Allison Henderson
2017-11-17 18:21 ` [PATCH v3 15/17] Add parent pointers to rename Allison Henderson
2017-11-28 18:20   ` Darrick J. Wong
2017-11-29 18:43     ` Allison Henderson
2017-11-17 18:21 ` [PATCH v3 16/17] Add the parent pointer support to the superblock version 5 Allison Henderson
2017-11-28 18:08   ` Darrick J. Wong
2017-11-29 18:41     ` Allison Henderson
2017-11-17 18:21 ` [PATCH v3 17/17] Add parent pointer ioctl Allison Henderson
2017-11-22 19:54   ` Allison Henderson
2017-11-22 21:07     ` Dave Chinner
2017-11-22 22:49       ` Allison Henderson
2017-11-22 21:13     ` Darrick J. Wong
2017-11-22 22:49       ` Allison Henderson
2017-11-28 20:35   ` Darrick J. Wong
2017-11-29 18:52     ` Allison Henderson
2017-11-29 21:37     ` Dave Chinner
2017-11-29 22:48       ` Allison Henderson
2017-11-30  0:02         ` Dave Chinner
2017-11-30  1:52           ` Allison Henderson
2017-11-30 21:11           ` Darrick J. Wong
2017-12-01  2:58             ` Dave Chinner

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.