All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/27] Parent Pointers
@ 2022-10-21 22:29 allison.henderson
  2022-10-21 22:29 ` [PATCH v4 01/27] xfs: Add new name to attri/d allison.henderson
                   ` (26 more replies)
  0 siblings, 27 replies; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

Hi all,

This is the latest 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 can be viewed on github here
https://github.com/allisonhenderson/xfs/tree/xfs_new_pptrsv4_r3

And the corresponding xfsprogs code is here
https://github.com/allisonhenderson/xfsprogs/tree/xfsprogs_new_pptrs_v4_r1

This set has been tested with the below parent pointers tests
https://lore.kernel.org/fstests/20221012013812.82161-1-catherine.hoang@oracle.com/T/#t

Updates since v3:

xfs: Add new name to attri/d
   Added check for new name length in xfs_attri_validate

xfs: Increase XFS_DEFER_OPS_NR_INODES to 5
   Typo fix

xfs: Hold inode locks in xfs_rename
   Added helper xfs_iunlock_after_rename

xfs: Expose init_xattrs in xfs_create_tmpfile
   only expose new param through xfs_create_tmpfile

xfs: Increase rename inode reservation
   NEW

xfs: extend transaction reservations for parent attributes
  Added xfs_*_log_count helpers
  Refactored xfs_calc_*_reservation helpers
    Added iovec payloads to overhead calculations
  Removed xfs_calc_parent_ptr_reservations

xfs: parent pointer attribute creation
   Added xfs_pptr_calc_space_res
   Added xfs_create_space_res
   Added xfs_mkdir_space_res
   Typedef fix

xfs: add parent attributes to link
   Added xfs_link_space_res

xfs: add parent attributes to symlink
   Added xfs_symlink_space_res
   
xfs: remove parent pointers in unlink
   Added xfs_remove_space_res
   
xfs: Add parent pointers to xfs_cross_rename
   White space adjust

xfs: Add parent pointers to rename
   Added xfs_rename_space_res
   rebase updates

xfs: Filter XFS_ATTR_PARENT for getfattr
  Redone (new)

xfs: Add parent pointer ioctl
   Removed XFS_IOC_ATTR_PARENT
   Commented xfs_pptr_info
   Whitespace adjustments
      
Questions comments and feedback appreciated!

Thanks all!
Allison 

Allison Henderson (27):
  xfs: Add new name to attri/d
  xfs: Increase XFS_DEFER_OPS_NR_INODES to 5
  xfs: Hold inode locks in xfs_ialloc
  xfs: Hold inode locks in xfs_trans_alloc_dir
  xfs: Hold inode locks in xfs_rename
  xfs: Expose init_xattrs in xfs_create_tmpfile
  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
  xfs: define parent pointer xattr format
  xfs: Add xfs_verify_pptr
  xfs: Increase rename inode reservation
  xfs: extend transaction reservations for parent attributes
  xfs: parent pointer attribute creation
  xfs: add parent attributes to link
  xfs: add parent attributes to symlink
  xfs: remove parent pointers in unlink
  xfs: Add parent pointers to xfs_cross_rename
  xfs: Indent xfs_rename
  xfs: Add parent pointers to rename
  xfs: Add the parent pointer support to the  superblock version 5.
  xfs: Add helper function xfs_attr_list_context_init
  xfs: Filter XFS_ATTR_PARENT for getfattr
  xfs: Add parent pointer ioctl
  xfs: fix unit conversion error in xfs_log_calc_max_attrsetm_res
  xfs: drop compatibility minimum log size computations for reflink

 fs/xfs/Makefile                |   2 +
 fs/xfs/libxfs/xfs_attr.c       |  71 ++++-
 fs/xfs/libxfs/xfs_attr.h       |  13 +-
 fs/xfs/libxfs/xfs_da_btree.h   |   3 +
 fs/xfs/libxfs/xfs_da_format.h  |  30 ++-
 fs/xfs/libxfs/xfs_defer.c      |  28 +-
 fs/xfs/libxfs/xfs_defer.h      |   8 +-
 fs/xfs/libxfs/xfs_dir2.c       |  21 +-
 fs/xfs/libxfs/xfs_dir2.h       |   7 +-
 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     |   4 +-
 fs/xfs/libxfs/xfs_fs.h         |  75 ++++++
 fs/xfs/libxfs/xfs_log_format.h |   7 +-
 fs/xfs/libxfs/xfs_log_rlimit.c |  53 ++++
 fs/xfs/libxfs/xfs_parent.c     | 207 +++++++++++++++
 fs/xfs/libxfs/xfs_parent.h     |  47 ++++
 fs/xfs/libxfs/xfs_sb.c         |   4 +
 fs/xfs/libxfs/xfs_trans_resv.c | 305 ++++++++++++++++++----
 fs/xfs/scrub/attr.c            |   2 +-
 fs/xfs/xfs_attr_item.c         | 115 +++++++--
 fs/xfs/xfs_attr_item.h         |   1 +
 fs/xfs/xfs_attr_list.c         |  17 +-
 fs/xfs/xfs_file.c              |   1 +
 fs/xfs/xfs_inode.c             | 456 ++++++++++++++++++++++++++-------
 fs/xfs/xfs_inode.h             |   3 +-
 fs/xfs/xfs_ioctl.c             | 148 +++++++++--
 fs/xfs/xfs_ioctl.h             |   2 +
 fs/xfs/xfs_iops.c              |   3 +-
 fs/xfs/xfs_ondisk.h            |   4 +
 fs/xfs/xfs_parent_utils.c      | 124 +++++++++
 fs/xfs/xfs_parent_utils.h      |  11 +
 fs/xfs/xfs_qm.c                |   4 +-
 fs/xfs/xfs_super.c             |   4 +
 fs/xfs/xfs_symlink.c           |  54 +++-
 fs/xfs/xfs_trans.c             |   6 +-
 fs/xfs/xfs_xattr.c             |   5 +-
 fs/xfs/xfs_xattr.h             |   1 +
 40 files changed, 1651 insertions(+), 226 deletions(-)
 create mode 100644 fs/xfs/libxfs/xfs_parent.c
 create mode 100644 fs/xfs/libxfs/xfs_parent.h
 create mode 100644 fs/xfs/xfs_parent_utils.c
 create mode 100644 fs/xfs/xfs_parent_utils.h

-- 
2.25.1


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

* [PATCH v4 01/27] xfs: Add new name to attri/d
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-25 19:09   ` Darrick J. Wong
  2022-10-21 22:29 ` [PATCH v4 02/27] xfs: Increase XFS_DEFER_OPS_NR_INODES to 5 allison.henderson
                   ` (25 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

This patch adds two new fields to the atti/d.  They are nname and
nnamelen.  This will be used for parent pointer updates since a
rename operation may cause the parent pointer to update both the
name and value.  So we need to carry both the new name as well as
the target name in the attri/d.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c       |  12 +++-
 fs/xfs/libxfs/xfs_attr.h       |   4 +-
 fs/xfs/libxfs/xfs_da_btree.h   |   2 +
 fs/xfs/libxfs/xfs_log_format.h |   6 +-
 fs/xfs/xfs_attr_item.c         | 108 +++++++++++++++++++++++++++++----
 fs/xfs/xfs_attr_item.h         |   1 +
 6 files changed, 115 insertions(+), 18 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index e28d93d232de..b1dbed7655e8 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -423,6 +423,12 @@ xfs_attr_complete_op(
 	args->op_flags &= ~XFS_DA_OP_REPLACE;
 	if (do_replace) {
 		args->attr_filter &= ~XFS_ATTR_INCOMPLETE;
+		if (args->new_namelen > 0) {
+			args->name = args->new_name;
+			args->namelen = args->new_namelen;
+			args->hashval = xfs_da_hashname(args->name,
+							args->namelen);
+		}
 		return replace_state;
 	}
 	return XFS_DAS_DONE;
@@ -922,9 +928,13 @@ xfs_attr_defer_replace(
 	struct xfs_da_args	*args)
 {
 	struct xfs_attr_intent	*new;
+	int			op_flag;
 	int			error = 0;
 
-	error = xfs_attr_intent_init(args, XFS_ATTRI_OP_FLAGS_REPLACE, &new);
+	op_flag = args->new_namelen == 0 ? XFS_ATTRI_OP_FLAGS_REPLACE :
+		  XFS_ATTRI_OP_FLAGS_NVREPLACE;
+
+	error = xfs_attr_intent_init(args, op_flag, &new);
 	if (error)
 		return error;
 
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 81be9b3e4004..3e81f3f48560 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -510,8 +510,8 @@ struct xfs_attr_intent {
 	struct xfs_da_args		*xattri_da_args;
 
 	/*
-	 * Shared buffer containing the attr name and value so that the logging
-	 * code can share large memory buffers between log items.
+	 * Shared buffer containing the attr name, new name, and value so that
+	 * the logging code can share large memory buffers between log items.
 	 */
 	struct xfs_attri_log_nameval	*xattri_nameval;
 
diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
index ffa3df5b2893..a4b29827603f 100644
--- a/fs/xfs/libxfs/xfs_da_btree.h
+++ b/fs/xfs/libxfs/xfs_da_btree.h
@@ -55,7 +55,9 @@ enum xfs_dacmp {
 typedef struct xfs_da_args {
 	struct xfs_da_geometry *geo;	/* da block geometry */
 	const uint8_t		*name;		/* string (maybe not NULL terminated) */
+	const uint8_t	*new_name;	/* new attr name */
 	int		namelen;	/* length of string (maybe no NULL) */
+	int		new_namelen;	/* new attr name len */
 	uint8_t		filetype;	/* filetype of inode for directories */
 	void		*value;		/* set of bytes (maybe contain NULLs) */
 	int		valuelen;	/* length of value */
diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
index b351b9dc6561..62f40e6353c2 100644
--- a/fs/xfs/libxfs/xfs_log_format.h
+++ b/fs/xfs/libxfs/xfs_log_format.h
@@ -117,7 +117,8 @@ struct xfs_unmount_log_format {
 #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		30
+#define XLOG_REG_TYPE_ATTR_NNAME	31
+#define XLOG_REG_TYPE_MAX		31
 
 
 /*
@@ -909,6 +910,7 @@ struct xfs_icreate_log {
 #define XFS_ATTRI_OP_FLAGS_SET		1	/* Set the attribute */
 #define XFS_ATTRI_OP_FLAGS_REMOVE	2	/* Remove the attribute */
 #define XFS_ATTRI_OP_FLAGS_REPLACE	3	/* Replace the attribute */
+#define XFS_ATTRI_OP_FLAGS_NVREPLACE	4	/* Replace attr name and val */
 #define XFS_ATTRI_OP_FLAGS_TYPE_MASK	0xFF	/* Flags type mask */
 
 /*
@@ -926,7 +928,7 @@ struct xfs_icreate_log {
 struct xfs_attri_log_format {
 	uint16_t	alfi_type;	/* attri log item type */
 	uint16_t	alfi_size;	/* size of this item */
-	uint32_t	__pad;		/* pad to 64 bit aligned */
+	uint32_t	alfi_nname_len;	/* attr new name length */
 	uint64_t	alfi_id;	/* attri identifier */
 	uint64_t	alfi_ino;	/* the inode for this attr operation */
 	uint32_t	alfi_op_flags;	/* marks the op as a set or remove */
diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
index cf5ce607dc05..0c449fb606ed 100644
--- a/fs/xfs/xfs_attr_item.c
+++ b/fs/xfs/xfs_attr_item.c
@@ -75,6 +75,8 @@ static inline struct xfs_attri_log_nameval *
 xfs_attri_log_nameval_alloc(
 	const void			*name,
 	unsigned int			name_len,
+	const void			*nname,
+	unsigned int			nname_len,
 	const void			*value,
 	unsigned int			value_len)
 {
@@ -85,15 +87,25 @@ xfs_attri_log_nameval_alloc(
 	 * this. But kvmalloc() utterly sucks, so we use our own version.
 	 */
 	nv = xlog_kvmalloc(sizeof(struct xfs_attri_log_nameval) +
-					name_len + value_len);
+					name_len + nname_len + value_len);
 
 	nv->name.i_addr = nv + 1;
 	nv->name.i_len = name_len;
 	nv->name.i_type = XLOG_REG_TYPE_ATTR_NAME;
 	memcpy(nv->name.i_addr, name, name_len);
 
+	if (nname_len) {
+		nv->nname.i_addr = nv->name.i_addr + name_len;
+		nv->nname.i_len = nname_len;
+		memcpy(nv->nname.i_addr, nname, nname_len);
+	} else {
+		nv->nname.i_addr = NULL;
+		nv->nname.i_len = 0;
+	}
+	nv->nname.i_type = XLOG_REG_TYPE_ATTR_NNAME;
+
 	if (value_len) {
-		nv->value.i_addr = nv->name.i_addr + name_len;
+		nv->value.i_addr = nv->name.i_addr + nname_len + name_len;
 		nv->value.i_len = value_len;
 		memcpy(nv->value.i_addr, value, value_len);
 	} else {
@@ -147,11 +159,15 @@ xfs_attri_item_size(
 	*nbytes += sizeof(struct xfs_attri_log_format) +
 			xlog_calc_iovec_len(nv->name.i_len);
 
-	if (!nv->value.i_len)
-		return;
+	if (nv->nname.i_len) {
+		*nvecs += 1;
+		*nbytes += xlog_calc_iovec_len(nv->nname.i_len);
+	}
 
-	*nvecs += 1;
-	*nbytes += xlog_calc_iovec_len(nv->value.i_len);
+	if (nv->value.i_len) {
+		*nvecs += 1;
+		*nbytes += xlog_calc_iovec_len(nv->value.i_len);
+	}
 }
 
 /*
@@ -181,6 +197,9 @@ xfs_attri_item_format(
 	ASSERT(nv->name.i_len > 0);
 	attrip->attri_format.alfi_size++;
 
+	if (nv->nname.i_len > 0)
+		attrip->attri_format.alfi_size++;
+
 	if (nv->value.i_len > 0)
 		attrip->attri_format.alfi_size++;
 
@@ -188,6 +207,10 @@ xfs_attri_item_format(
 			&attrip->attri_format,
 			sizeof(struct xfs_attri_log_format));
 	xlog_copy_from_iovec(lv, &vecp, &nv->name);
+
+	if (nv->nname.i_len > 0)
+		xlog_copy_from_iovec(lv, &vecp, &nv->nname);
+
 	if (nv->value.i_len > 0)
 		xlog_copy_from_iovec(lv, &vecp, &nv->value);
 }
@@ -396,6 +419,7 @@ xfs_attr_log_item(
 	attrp->alfi_op_flags = attr->xattri_op_flags;
 	attrp->alfi_value_len = attr->xattri_nameval->value.i_len;
 	attrp->alfi_name_len = attr->xattri_nameval->name.i_len;
+	attrp->alfi_nname_len = attr->xattri_nameval->nname.i_len;
 	ASSERT(!(attr->xattri_da_args->attr_filter & ~XFS_ATTRI_FILTER_MASK));
 	attrp->alfi_attr_filter = attr->xattri_da_args->attr_filter;
 }
@@ -437,7 +461,8 @@ xfs_attr_create_intent(
 		 * deferred work state structure.
 		 */
 		attr->xattri_nameval = xfs_attri_log_nameval_alloc(args->name,
-				args->namelen, args->value, args->valuelen);
+				args->namelen, args->new_name,
+				args->new_namelen, args->value, args->valuelen);
 	}
 
 	attrip = xfs_attri_init(mp, attr->xattri_nameval);
@@ -525,7 +550,8 @@ xfs_attri_validate(
 	unsigned int			op = attrp->alfi_op_flags &
 					     XFS_ATTRI_OP_FLAGS_TYPE_MASK;
 
-	if (attrp->__pad != 0)
+	if (attrp->alfi_op_flags != XFS_ATTRI_OP_FLAGS_NVREPLACE &&
+	    attrp->alfi_nname_len != 0)
 		return false;
 
 	if (attrp->alfi_op_flags & ~XFS_ATTRI_OP_FLAGS_TYPE_MASK)
@@ -539,6 +565,7 @@ xfs_attri_validate(
 	case XFS_ATTRI_OP_FLAGS_SET:
 	case XFS_ATTRI_OP_FLAGS_REPLACE:
 	case XFS_ATTRI_OP_FLAGS_REMOVE:
+	case XFS_ATTRI_OP_FLAGS_NVREPLACE:
 		break;
 	default:
 		return false;
@@ -548,9 +575,14 @@ xfs_attri_validate(
 		return false;
 
 	if ((attrp->alfi_name_len > XATTR_NAME_MAX) ||
+	    (attrp->alfi_nname_len > XATTR_NAME_MAX) ||
 	    (attrp->alfi_name_len == 0))
 		return false;
 
+	if (op == XFS_ATTRI_OP_FLAGS_REMOVE &&
+	    attrp->alfi_value_len != 0)
+		return false;
+
 	return xfs_verify_ino(mp, attrp->alfi_ino);
 }
 
@@ -611,6 +643,8 @@ xfs_attri_item_recover(
 	args->whichfork = XFS_ATTR_FORK;
 	args->name = nv->name.i_addr;
 	args->namelen = nv->name.i_len;
+	args->new_name = nv->nname.i_addr;
+	args->new_namelen = nv->nname.i_len;
 	args->hashval = xfs_da_hashname(args->name, args->namelen);
 	args->attr_filter = attrp->alfi_attr_filter & XFS_ATTRI_FILTER_MASK;
 	args->op_flags = XFS_DA_OP_RECOVERY | XFS_DA_OP_OKNOENT |
@@ -621,6 +655,7 @@ xfs_attri_item_recover(
 	switch (attr->xattri_op_flags) {
 	case XFS_ATTRI_OP_FLAGS_SET:
 	case XFS_ATTRI_OP_FLAGS_REPLACE:
+	case XFS_ATTRI_OP_FLAGS_NVREPLACE:
 		args->value = nv->value.i_addr;
 		args->valuelen = nv->value.i_len;
 		args->total = xfs_attr_calc_size(args, &local);
@@ -710,6 +745,7 @@ xfs_attri_item_relog(
 	new_attrp->alfi_op_flags = old_attrp->alfi_op_flags;
 	new_attrp->alfi_value_len = old_attrp->alfi_value_len;
 	new_attrp->alfi_name_len = old_attrp->alfi_name_len;
+	new_attrp->alfi_nname_len = old_attrp->alfi_nname_len;
 	new_attrp->alfi_attr_filter = old_attrp->alfi_attr_filter;
 
 	xfs_trans_add_item(tp, &new_attrip->attri_item);
@@ -731,10 +767,41 @@ xlog_recover_attri_commit_pass2(
 	struct xfs_attri_log_nameval	*nv;
 	const void			*attr_value = NULL;
 	const void			*attr_name;
-	int                             error;
+	const void			*attr_nname = NULL;
+	int				i = 0;
+	int                             op, error = 0;
 
-	attri_formatp = item->ri_buf[0].i_addr;
-	attr_name = item->ri_buf[1].i_addr;
+	if (item->ri_total == 0) {
+		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
+		return -EFSCORRUPTED;
+	}
+
+	attri_formatp = item->ri_buf[i].i_addr;
+	i++;
+
+	op = attri_formatp->alfi_op_flags & XFS_ATTRI_OP_FLAGS_TYPE_MASK;
+	switch (op) {
+	case XFS_ATTRI_OP_FLAGS_SET:
+	case XFS_ATTRI_OP_FLAGS_REPLACE:
+		if (item->ri_total != 3)
+			error = -EFSCORRUPTED;
+		break;
+	case XFS_ATTRI_OP_FLAGS_REMOVE:
+		if (item->ri_total != 2)
+			error = -EFSCORRUPTED;
+		break;
+	case XFS_ATTRI_OP_FLAGS_NVREPLACE:
+		if (item->ri_total != 4)
+			error = -EFSCORRUPTED;
+		break;
+	default:
+		error = -EFSCORRUPTED;
+	}
+
+	if (error) {
+		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
+		return error;
+	}
 
 	/* Validate xfs_attri_log_format before the large memory allocation */
 	if (!xfs_attri_validate(mp, attri_formatp)) {
@@ -742,13 +809,27 @@ xlog_recover_attri_commit_pass2(
 		return -EFSCORRUPTED;
 	}
 
+	attr_name = item->ri_buf[i].i_addr;
+	i++;
+
 	if (!xfs_attr_namecheck(attr_name, attri_formatp->alfi_name_len)) {
 		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
 		return -EFSCORRUPTED;
 	}
 
+	if (attri_formatp->alfi_nname_len) {
+		attr_nname = item->ri_buf[i].i_addr;
+		i++;
+
+		if (!xfs_attr_namecheck(attr_nname,
+				attri_formatp->alfi_nname_len)) {
+			XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
+			return -EFSCORRUPTED;
+		}
+	}
+
 	if (attri_formatp->alfi_value_len)
-		attr_value = item->ri_buf[2].i_addr;
+		attr_value = item->ri_buf[i].i_addr;
 
 	/*
 	 * Memory alloc failure will cause replay to abort.  We attach the
@@ -756,7 +837,8 @@ xlog_recover_attri_commit_pass2(
 	 * reference.
 	 */
 	nv = xfs_attri_log_nameval_alloc(attr_name,
-			attri_formatp->alfi_name_len, attr_value,
+			attri_formatp->alfi_name_len, attr_nname,
+			attri_formatp->alfi_nname_len, attr_value,
 			attri_formatp->alfi_value_len);
 
 	attrip = xfs_attri_init(mp, nv);
diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h
index 3280a7930287..24d4968dd6cc 100644
--- a/fs/xfs/xfs_attr_item.h
+++ b/fs/xfs/xfs_attr_item.h
@@ -13,6 +13,7 @@ struct kmem_zone;
 
 struct xfs_attri_log_nameval {
 	struct xfs_log_iovec	name;
+	struct xfs_log_iovec	nname;
 	struct xfs_log_iovec	value;
 	refcount_t		refcount;
 
-- 
2.25.1


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

* [PATCH v4 02/27] xfs: Increase XFS_DEFER_OPS_NR_INODES to 5
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
  2022-10-21 22:29 ` [PATCH v4 01/27] xfs: Add new name to attri/d allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-28  1:52   ` Catherine Hoang
  2022-10-21 22:29 ` [PATCH v4 03/27] xfs: Hold inode locks in xfs_ialloc allison.henderson
                   ` (24 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

Renames that generate parent pointer updates can join up to 5
inodes locked in sorted order.  So we need to increase the
number of defer ops inodes and relock them in the same way.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/libxfs/xfs_defer.c | 28 ++++++++++++++++++++++++++--
 fs/xfs/libxfs/xfs_defer.h |  8 +++++++-
 fs/xfs/xfs_inode.c        |  2 +-
 fs/xfs/xfs_inode.h        |  1 +
 4 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c
index 5a321b783398..c0279b57e51d 100644
--- a/fs/xfs/libxfs/xfs_defer.c
+++ b/fs/xfs/libxfs/xfs_defer.c
@@ -820,13 +820,37 @@ xfs_defer_ops_continue(
 	struct xfs_trans		*tp,
 	struct xfs_defer_resources	*dres)
 {
-	unsigned int			i;
+	unsigned int			i, j;
+	struct xfs_inode		*sips[XFS_DEFER_OPS_NR_INODES];
+	struct xfs_inode		*temp;
 
 	ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
 	ASSERT(!(tp->t_flags & XFS_TRANS_DIRTY));
 
 	/* Lock the captured resources to the new transaction. */
-	if (dfc->dfc_held.dr_inos == 2)
+	if (dfc->dfc_held.dr_inos > 2) {
+		/*
+		 * Renames with parent pointer updates can lock up to 5 inodes,
+		 * sorted by their inode number.  So we need to make sure they
+		 * are relocked in the same way.
+		 */
+		memset(sips, 0, sizeof(sips));
+		for (i = 0; i < dfc->dfc_held.dr_inos; i++)
+			sips[i] = dfc->dfc_held.dr_ip[i];
+
+		/* Bubble sort of at most 5 inodes */
+		for (i = 0; i < dfc->dfc_held.dr_inos; i++) {
+			for (j = 1; j < dfc->dfc_held.dr_inos; j++) {
+				if (sips[j]->i_ino < sips[j-1]->i_ino) {
+					temp = sips[j];
+					sips[j] = sips[j-1];
+					sips[j-1] = temp;
+				}
+			}
+		}
+
+		xfs_lock_inodes(sips, dfc->dfc_held.dr_inos, XFS_ILOCK_EXCL);
+	} else if (dfc->dfc_held.dr_inos == 2)
 		xfs_lock_two_inodes(dfc->dfc_held.dr_ip[0], XFS_ILOCK_EXCL,
 				    dfc->dfc_held.dr_ip[1], XFS_ILOCK_EXCL);
 	else if (dfc->dfc_held.dr_inos == 1)
diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h
index 114a3a4930a3..fdf6941f8f4d 100644
--- a/fs/xfs/libxfs/xfs_defer.h
+++ b/fs/xfs/libxfs/xfs_defer.h
@@ -70,7 +70,13 @@ extern const struct xfs_defer_op_type xfs_attr_defer_type;
 /*
  * Deferred operation item relogging limits.
  */
-#define XFS_DEFER_OPS_NR_INODES	2	/* join up to two inodes */
+
+/*
+ * Rename w/ parent pointers can require up to 5 inodes with deferred ops to
+ * be joined to the transaction: src_dp, target_dp, src_ip, target_ip, and wip.
+ * These inodes are locked in sorted order by their inode numbers
+ */
+#define XFS_DEFER_OPS_NR_INODES	5
 #define XFS_DEFER_OPS_NR_BUFS	2	/* join up to two buffers */
 
 /* Resources that must be held across a transaction roll. */
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index c000b74dd203..5ebbfceb1ada 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -447,7 +447,7 @@ xfs_lock_inumorder(
  * lock more than one at a time, lockdep will report false positives saying we
  * have violated locking orders.
  */
-static void
+void
 xfs_lock_inodes(
 	struct xfs_inode	**ips,
 	int			inodes,
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index fa780f08dc89..2eaed98af814 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -574,5 +574,6 @@ void xfs_end_io(struct work_struct *work);
 
 int xfs_ilock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
 void xfs_iunlock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
+void xfs_lock_inodes(struct xfs_inode **ips, int inodes, uint lock_mode);
 
 #endif	/* __XFS_INODE_H__ */
-- 
2.25.1


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

* [PATCH v4 03/27] xfs: Hold inode locks in xfs_ialloc
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
  2022-10-21 22:29 ` [PATCH v4 01/27] xfs: Add new name to attri/d allison.henderson
  2022-10-21 22:29 ` [PATCH v4 02/27] xfs: Increase XFS_DEFER_OPS_NR_INODES to 5 allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-28  1:54   ` Catherine Hoang
  2022-10-21 22:29 ` [PATCH v4 04/27] xfs: Hold inode locks in xfs_trans_alloc_dir allison.henderson
                   ` (23 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

Modify xfs_ialloc to hold locks after return.  Caller will be
responsible for manual unlock.  We will need this later to hold locks
across parent pointer operations

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/xfs_inode.c   | 6 +++++-
 fs/xfs/xfs_qm.c      | 4 +++-
 fs/xfs/xfs_symlink.c | 3 +++
 3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 5ebbfceb1ada..f21f625b428e 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -774,6 +774,8 @@ xfs_inode_inherit_flags2(
 /*
  * Initialise a newly allocated inode and return the in-core inode to the
  * caller locked exclusively.
+ *
+ * Caller is responsible for unlocking the inode manually upon return
  */
 int
 xfs_init_new_inode(
@@ -899,7 +901,7 @@ xfs_init_new_inode(
 	/*
 	 * Log the new values stuffed into the inode.
 	 */
-	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+	xfs_trans_ijoin(tp, ip, 0);
 	xfs_trans_log_inode(tp, ip, flags);
 
 	/* now that we have an i_mode we can setup the inode structure */
@@ -1076,6 +1078,7 @@ xfs_create(
 	xfs_qm_dqrele(pdqp);
 
 	*ipp = ip;
+	xfs_iunlock(ip, XFS_ILOCK_EXCL);
 	return 0;
 
  out_trans_cancel:
@@ -1172,6 +1175,7 @@ xfs_create_tmpfile(
 	xfs_qm_dqrele(pdqp);
 
 	*ipp = ip;
+	xfs_iunlock(ip, XFS_ILOCK_EXCL);
 	return 0;
 
  out_trans_cancel:
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 18bb4ec4d7c9..96e7b4959721 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -818,8 +818,10 @@ xfs_qm_qino_alloc(
 		ASSERT(xfs_is_shutdown(mp));
 		xfs_alert(mp, "%s failed (error %d)!", __func__, error);
 	}
-	if (need_alloc)
+	if (need_alloc) {
 		xfs_finish_inode_setup(*ipp);
+		xfs_iunlock(*ipp, XFS_ILOCK_EXCL);
+	}
 	return error;
 }
 
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
index 8389f3ef88ef..d8e120913036 100644
--- a/fs/xfs/xfs_symlink.c
+++ b/fs/xfs/xfs_symlink.c
@@ -337,6 +337,7 @@ xfs_symlink(
 	xfs_qm_dqrele(pdqp);
 
 	*ipp = ip;
+	xfs_iunlock(ip, XFS_ILOCK_EXCL);
 	return 0;
 
 out_trans_cancel:
@@ -358,6 +359,8 @@ xfs_symlink(
 
 	if (unlock_dp_on_error)
 		xfs_iunlock(dp, XFS_ILOCK_EXCL);
+	if (ip)
+		xfs_iunlock(ip, XFS_ILOCK_EXCL);
 	return error;
 }
 
-- 
2.25.1


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

* [PATCH v4 04/27] xfs: Hold inode locks in xfs_trans_alloc_dir
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (2 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 03/27] xfs: Hold inode locks in xfs_ialloc allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-28  1:56   ` Catherine Hoang
  2022-10-21 22:29 ` [PATCH v4 05/27] xfs: Hold inode locks in xfs_rename allison.henderson
                   ` (22 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

Modify xfs_trans_alloc_dir to hold locks after return.  Caller will be
responsible for manual unlock.  We will need this later to hold locks
across parent pointer operations

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/xfs_inode.c | 14 ++++++++++++--
 fs/xfs/xfs_trans.c |  6 ++++--
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index f21f625b428e..9a3174a8f895 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1277,10 +1277,15 @@ xfs_link(
 	if (xfs_has_wsync(mp) || xfs_has_dirsync(mp))
 		xfs_trans_set_sync(tp);
 
-	return xfs_trans_commit(tp);
+	error = xfs_trans_commit(tp);
+	xfs_iunlock(tdp, XFS_ILOCK_EXCL);
+	xfs_iunlock(sip, XFS_ILOCK_EXCL);
+	return error;
 
  error_return:
 	xfs_trans_cancel(tp);
+	xfs_iunlock(tdp, XFS_ILOCK_EXCL);
+	xfs_iunlock(sip, XFS_ILOCK_EXCL);
  std_return:
 	if (error == -ENOSPC && nospace_error)
 		error = nospace_error;
@@ -2516,15 +2521,20 @@ xfs_remove(
 
 	error = xfs_trans_commit(tp);
 	if (error)
-		goto std_return;
+		goto out_unlock;
 
 	if (is_dir && xfs_inode_is_filestream(ip))
 		xfs_filestream_deassociate(ip);
 
+	xfs_iunlock(ip, XFS_ILOCK_EXCL);
+	xfs_iunlock(dp, XFS_ILOCK_EXCL);
 	return 0;
 
  out_trans_cancel:
 	xfs_trans_cancel(tp);
+ out_unlock:
+	xfs_iunlock(ip, XFS_ILOCK_EXCL);
+	xfs_iunlock(dp, XFS_ILOCK_EXCL);
  std_return:
 	return error;
 }
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 7bd16fbff534..ac98ff416e54 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -1356,6 +1356,8 @@ xfs_trans_alloc_ichange(
  * The caller must ensure that the on-disk dquots attached to this inode have
  * already been allocated and initialized.  The ILOCKs will be dropped when the
  * transaction is committed or cancelled.
+ *
+ * Caller is responsible for unlocking the inodes manually upon return
  */
 int
 xfs_trans_alloc_dir(
@@ -1386,8 +1388,8 @@ xfs_trans_alloc_dir(
 
 	xfs_lock_two_inodes(dp, XFS_ILOCK_EXCL, ip, XFS_ILOCK_EXCL);
 
-	xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
-	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+	xfs_trans_ijoin(tp, dp, 0);
+	xfs_trans_ijoin(tp, ip, 0);
 
 	error = xfs_qm_dqattach_locked(dp, false);
 	if (error) {
-- 
2.25.1


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

* [PATCH v4 05/27] xfs: Hold inode locks in xfs_rename
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (3 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 04/27] xfs: Hold inode locks in xfs_trans_alloc_dir allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-28  1:59   ` Catherine Hoang
  2022-10-21 22:29 ` [PATCH v4 06/27] xfs: Expose init_xattrs in xfs_create_tmpfile allison.henderson
                   ` (21 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

Modify xfs_rename to hold all inode locks across a rename operation
We will need this later when we add parent pointers

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/xfs_inode.c | 42 +++++++++++++++++++++++++++++-------------
 1 file changed, 29 insertions(+), 13 deletions(-)

diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 9a3174a8f895..44b68fa53a72 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2539,6 +2539,21 @@ xfs_remove(
 	return error;
 }
 
+static inline void
+xfs_iunlock_after_rename(
+	struct xfs_inode	**i_tab,
+	int			num_inodes)
+{
+	int			i;
+
+	for (i = num_inodes - 1; i >= 0; i--) {
+		/* Skip duplicate inodes if src and target dps are the same */
+		if (!i_tab[i] || (i > 0 && i_tab[i] == i_tab[i - 1]))
+			continue;
+		xfs_iunlock(i_tab[i], XFS_ILOCK_EXCL);
+	}
+}
+
 /*
  * Enter all inodes for a rename transaction into a sorted array.
  */
@@ -2837,18 +2852,16 @@ xfs_rename(
 	xfs_lock_inodes(inodes, num_inodes, XFS_ILOCK_EXCL);
 
 	/*
-	 * Join all the inodes to the transaction. From this point on,
-	 * we can rely on either trans_commit or trans_cancel to unlock
-	 * them.
+	 * Join all the inodes to the transaction.
 	 */
-	xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL);
+	xfs_trans_ijoin(tp, src_dp, 0);
 	if (new_parent)
-		xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL);
-	xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
+		xfs_trans_ijoin(tp, target_dp, 0);
+	xfs_trans_ijoin(tp, src_ip, 0);
 	if (target_ip)
-		xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
+		xfs_trans_ijoin(tp, target_ip, 0);
 	if (wip)
-		xfs_trans_ijoin(tp, wip, XFS_ILOCK_EXCL);
+		xfs_trans_ijoin(tp, wip, 0);
 
 	/*
 	 * If we are using project inheritance, we only allow renames
@@ -2862,10 +2875,12 @@ xfs_rename(
 	}
 
 	/* RENAME_EXCHANGE is unique from here on. */
-	if (flags & RENAME_EXCHANGE)
-		return xfs_cross_rename(tp, src_dp, src_name, src_ip,
+	if (flags & RENAME_EXCHANGE) {
+		error = xfs_cross_rename(tp, src_dp, src_name, src_ip,
 					target_dp, target_name, target_ip,
 					spaceres);
+		goto out_unlock;
+	}
 
 	/*
 	 * Try to reserve quota to handle an expansion of the target directory.
@@ -3090,12 +3105,13 @@ xfs_rename(
 		xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE);
 
 	error = xfs_finish_rename(tp);
-	if (wip)
-		xfs_irele(wip);
-	return error;
+
+	goto out_unlock;
 
 out_trans_cancel:
 	xfs_trans_cancel(tp);
+out_unlock:
+	xfs_iunlock_after_rename(inodes, num_inodes);
 out_release_wip:
 	if (wip)
 		xfs_irele(wip);
-- 
2.25.1


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

* [PATCH v4 06/27] xfs: Expose init_xattrs in xfs_create_tmpfile
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (4 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 05/27] xfs: Hold inode locks in xfs_rename allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-25 19:13   ` Darrick J. Wong
  2022-10-21 22:29 ` [PATCH v4 07/27] xfs: get directory offset when adding directory name allison.henderson
                   ` (20 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

Tmp files are used as part of rename operations and will need attr forks
initialized for parent pointers.  Expose the init_xattrs parameter to
the calling function to initialize the fork.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/xfs_inode.c | 5 +++--
 fs/xfs/xfs_inode.h | 2 +-
 fs/xfs/xfs_iops.c  | 3 ++-
 3 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 44b68fa53a72..8b3aefd146a2 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1108,6 +1108,7 @@ xfs_create_tmpfile(
 	struct user_namespace	*mnt_userns,
 	struct xfs_inode	*dp,
 	umode_t			mode,
+	bool			init_xattrs,
 	struct xfs_inode	**ipp)
 {
 	struct xfs_mount	*mp = dp->i_mount;
@@ -1148,7 +1149,7 @@ xfs_create_tmpfile(
 	error = xfs_dialloc(&tp, dp->i_ino, mode, &ino);
 	if (!error)
 		error = xfs_init_new_inode(mnt_userns, tp, dp, ino, mode,
-				0, 0, prid, false, &ip);
+				0, 0, prid, init_xattrs, &ip);
 	if (error)
 		goto out_trans_cancel;
 
@@ -2748,7 +2749,7 @@ xfs_rename_alloc_whiteout(
 	int			error;
 
 	error = xfs_create_tmpfile(mnt_userns, dp, S_IFCHR | WHITEOUT_MODE,
-				   &tmpfile);
+				   false, &tmpfile);
 	if (error)
 		return error;
 
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 2eaed98af814..5735de32beeb 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -478,7 +478,7 @@ int		xfs_create(struct user_namespace *mnt_userns,
 			   umode_t mode, dev_t rdev, bool need_xattr,
 			   struct xfs_inode **ipp);
 int		xfs_create_tmpfile(struct user_namespace *mnt_userns,
-			   struct xfs_inode *dp, umode_t mode,
+			   struct xfs_inode *dp, umode_t mode, bool init_xattrs,
 			   struct xfs_inode **ipp);
 int		xfs_remove(struct xfs_inode *dp, struct xfs_name *name,
 			   struct xfs_inode *ip);
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 2e10e1c66ad6..10a5e85f2a70 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -200,7 +200,8 @@ xfs_generic_create(
 				xfs_create_need_xattr(dir, default_acl, acl),
 				&ip);
 	} else {
-		error = xfs_create_tmpfile(mnt_userns, XFS_I(dir), mode, &ip);
+		error = xfs_create_tmpfile(mnt_userns, XFS_I(dir), mode, false,
+					   &ip);
 	}
 	if (unlikely(error))
 		goto out_free_acl;
-- 
2.25.1


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

* [PATCH v4 07/27] xfs: get directory offset when adding directory name
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (5 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 06/27] xfs: Expose init_xattrs in xfs_create_tmpfile allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-28  2:02   ` Catherine Hoang
  2022-10-21 22:29 ` [PATCH v4 08/27] xfs: get directory offset when removing " allison.henderson
                   ` (19 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.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.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/libxfs/xfs_da_btree.h   | 1 +
 fs/xfs/libxfs/xfs_dir2.c       | 9 +++++++--
 fs/xfs/libxfs/xfs_dir2.h       | 2 +-
 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             | 6 +++---
 fs/xfs/xfs_symlink.c           | 3 ++-
 9 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
index a4b29827603f..90b86d00258f 100644
--- a/fs/xfs/libxfs/xfs_da_btree.h
+++ b/fs/xfs/libxfs/xfs_da_btree.h
@@ -81,6 +81,7 @@ typedef struct xfs_da_args {
 	int		rmtvaluelen2;	/* remote attr value length in bytes */
 	uint32_t	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 92bac3373f1f..69a6561c22cc 100644
--- a/fs/xfs/libxfs/xfs_dir2.c
+++ b/fs/xfs/libxfs/xfs_dir2.c
@@ -257,7 +257,8 @@ xfs_dir_createname(
 	struct xfs_inode	*dp,
 	const struct xfs_name	*name,
 	xfs_ino_t		inum,		/* new entry inode number */
-	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;
@@ -312,6 +313,10 @@ xfs_dir_createname(
 		rval = xfs_dir2_node_addname(args);
 
 out_free:
+	/* return the location that this entry was place in the parent inode */
+	if (offset)
+		*offset = args->offset;
+
 	kmem_free(args);
 	return rval;
 }
@@ -550,7 +555,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, 0);
+	return xfs_dir_createname(tp, dp, name, 0, 0, NULL);
 }
 
 /*
diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
index dd39f17dd9a9..d96954478696 100644
--- a/fs/xfs/libxfs/xfs_dir2.h
+++ b/fs/xfs/libxfs/xfs_dir2.h
@@ -40,7 +40,7 @@ extern int xfs_dir_init(struct xfs_trans *tp, struct xfs_inode *dp,
 				struct xfs_inode *pdp);
 extern int xfs_dir_createname(struct xfs_trans *tp, struct xfs_inode *dp,
 				const struct xfs_name *name, xfs_ino_t inum,
-				xfs_extlen_t tot);
+				xfs_extlen_t tot, xfs_dir2_dataptr_t *offset);
 extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
 				const 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 00f960a703b2..70aeab9d2a12 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -573,6 +573,7 @@ xfs_dir2_block_addname(
 	xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
 	tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, 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 cb9e950a911d..9ab520b66547 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -870,6 +870,8 @@ xfs_dir2_leaf_addname(
 	xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
 	tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, 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 7a03aeb9f4c9..5a9513c036b8 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -1974,6 +1974,8 @@ xfs_dir2_node_addname_int(
 	xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
 	tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, 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 freespace and log the data block if needed. */
diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
index 8cd37e6e9d38..44bc4ba3da8a 100644
--- a/fs/xfs/libxfs/xfs_dir2_sf.c
+++ b/fs/xfs/libxfs/xfs_dir2_sf.c
@@ -485,6 +485,7 @@ xfs_dir2_sf_addname_easy(
 	memcpy(sfep->name, args->name, sfep->namelen);
 	xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
 	xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
+	args->offset = xfs_dir2_byte_to_dataptr(offset);
 
 	/*
 	 * Update the header and inode.
@@ -575,6 +576,7 @@ xfs_dir2_sf_addname_hard(
 	memcpy(sfep->name, args->name, sfep->namelen);
 	xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
 	xfs_dir2_sf_put_ftype(mp, 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 8b3aefd146a2..229bc126b7c8 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1038,7 +1038,7 @@ xfs_create(
 	unlock_dp_on_error = false;
 
 	error = xfs_dir_createname(tp, dp, name, ip->i_ino,
-					resblks - XFS_IALLOC_SPACE_RES(mp));
+				   resblks - XFS_IALLOC_SPACE_RES(mp), NULL);
 	if (error) {
 		ASSERT(error != -ENOSPC);
 		goto out_trans_cancel;
@@ -1262,7 +1262,7 @@ xfs_link(
 	}
 
 	error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
-				   resblks);
+				   resblks, NULL);
 	if (error)
 		goto error_return;
 	xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
@@ -2998,7 +2998,7 @@ xfs_rename(
 		 * to account for the ".." reference from the new entry.
 		 */
 		error = xfs_dir_createname(tp, target_dp, target_name,
-					   src_ip->i_ino, spaceres);
+					   src_ip->i_ino, spaceres, NULL);
 		if (error)
 			goto out_trans_cancel;
 
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
index d8e120913036..27a7d7c57015 100644
--- a/fs/xfs/xfs_symlink.c
+++ b/fs/xfs/xfs_symlink.c
@@ -314,7 +314,8 @@ xfs_symlink(
 	/*
 	 * Create the directory entry for the symlink.
 	 */
-	error = xfs_dir_createname(tp, dp, link_name, ip->i_ino, resblks);
+	error = xfs_dir_createname(tp, dp, link_name,
+			ip->i_ino, resblks, NULL);
 	if (error)
 		goto out_trans_cancel;
 	xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-- 
2.25.1


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

* [PATCH v4 08/27] xfs: get directory offset when removing directory name
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (6 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 07/27] xfs: get directory offset when adding directory name allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-28  2:06   ` Catherine Hoang
  2022-10-21 22:29 ` [PATCH v4 09/27] xfs: get directory offset when replacing a " allison.henderson
                   ` (18 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.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.

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>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/libxfs/xfs_dir2.c       | 6 +++++-
 fs/xfs/libxfs/xfs_dir2.h       | 3 ++-
 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             | 4 ++--
 7 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
index 69a6561c22cc..891c1f701f53 100644
--- a/fs/xfs/libxfs/xfs_dir2.c
+++ b/fs/xfs/libxfs/xfs_dir2.c
@@ -436,7 +436,8 @@ xfs_dir_removename(
 	struct xfs_inode	*dp,
 	struct xfs_name		*name,
 	xfs_ino_t		ino,
-	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;
@@ -481,6 +482,9 @@ xfs_dir_removename(
 	else
 		rval = xfs_dir2_node_removename(args);
 out_free:
+	if (offset)
+		*offset = args->offset;
+
 	kmem_free(args);
 	return rval;
 }
diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
index d96954478696..0c2d7c0af78f 100644
--- a/fs/xfs/libxfs/xfs_dir2.h
+++ b/fs/xfs/libxfs/xfs_dir2.h
@@ -46,7 +46,8 @@ extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
 				struct xfs_name *ci_name);
 extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
 				struct xfs_name *name, xfs_ino_t ino,
-				xfs_extlen_t tot);
+				xfs_extlen_t tot,
+				xfs_dir2_dataptr_t *offset);
 extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
 				const struct xfs_name *name, xfs_ino_t inum,
 				xfs_extlen_t tot);
diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
index 70aeab9d2a12..d36f3f1491da 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -810,9 +810,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 9ab520b66547..b4a066259d97 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -1386,9 +1386,10 @@ xfs_dir2_leaf_removename(
 	 * Point to the leaf entry, use that to point to the data entry.
 	 */
 	lep = &leafhdr.ents[index];
-	db = xfs_dir2_dataptr_to_db(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(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(geo, leaf);
diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
index 5a9513c036b8..39cbdeafa0f6 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -1296,9 +1296,10 @@ xfs_dir2_leafn_remove(
 	/*
 	 * Extract the data block and offset from the entry.
 	 */
-	db = xfs_dir2_dataptr_to_db(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(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 44bc4ba3da8a..b49578a547b3 100644
--- a/fs/xfs/libxfs/xfs_dir2_sf.c
+++ b/fs/xfs/libxfs/xfs_dir2_sf.c
@@ -969,6 +969,8 @@ xfs_dir2_sf_removename(
 								XFS_CMP_EXACT) {
 			ASSERT(xfs_dir2_sf_get_ino(mp, 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 229bc126b7c8..a0d5761e1fee 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2506,7 +2506,7 @@ xfs_remove(
 	if (error)
 		goto out_trans_cancel;
 
-	error = xfs_dir_removename(tp, dp, name, ip->i_ino, resblks);
+	error = xfs_dir_removename(tp, dp, name, ip->i_ino, resblks, NULL);
 	if (error) {
 		ASSERT(error != -ENOENT);
 		goto out_trans_cancel;
@@ -3095,7 +3095,7 @@ xfs_rename(
 					spaceres);
 	else
 		error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
-					   spaceres);
+					   spaceres, NULL);
 
 	if (error)
 		goto out_trans_cancel;
-- 
2.25.1


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

* [PATCH v4 09/27] xfs: get directory offset when replacing a directory name
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (7 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 08/27] xfs: get directory offset when removing " allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-21 22:29 ` [PATCH v4 10/27] xfs: add parent pointer support to attribute code allison.henderson
                   ` (17 subsequent siblings)
  26 siblings, 0 replies; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.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.

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>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/libxfs/xfs_dir2.c       |  8 ++++++--
 fs/xfs/libxfs/xfs_dir2.h       |  2 +-
 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             | 16 ++++++++--------
 7 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
index 891c1f701f53..c1a9394d7478 100644
--- a/fs/xfs/libxfs/xfs_dir2.c
+++ b/fs/xfs/libxfs/xfs_dir2.c
@@ -482,7 +482,7 @@ xfs_dir_removename(
 	else
 		rval = xfs_dir2_node_removename(args);
 out_free:
-	if (offset)
+	if (!rval && offset)
 		*offset = args->offset;
 
 	kmem_free(args);
@@ -498,7 +498,8 @@ xfs_dir_replace(
 	struct xfs_inode	*dp,
 	const struct xfs_name	*name,		/* name of entry to replace */
 	xfs_ino_t		inum,		/* new inode number */
-	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;
@@ -546,6 +547,9 @@ xfs_dir_replace(
 	else
 		rval = xfs_dir2_node_replace(args);
 out_free:
+	if (offset)
+		*offset = args->offset;
+
 	kmem_free(args);
 	return rval;
 }
diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
index 0c2d7c0af78f..ff59f009d1fd 100644
--- a/fs/xfs/libxfs/xfs_dir2.h
+++ b/fs/xfs/libxfs/xfs_dir2.h
@@ -50,7 +50,7 @@ extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
 				xfs_dir2_dataptr_t *offset);
 extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
 				const struct xfs_name *name, xfs_ino_t inum,
-				xfs_extlen_t tot);
+				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 d36f3f1491da..0f3a03e87278 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -885,9 +885,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 b4a066259d97..fe75ffadace9 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -1523,6 +1523,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 39cbdeafa0f6..53cd0d5d94f7 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -2242,6 +2242,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(leafhdr.ents[blk->index].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 b49578a547b3..032c65804610 100644
--- a/fs/xfs/libxfs/xfs_dir2_sf.c
+++ b/fs/xfs/libxfs/xfs_dir2_sf.c
@@ -1107,6 +1107,8 @@ xfs_dir2_sf_replace(
 				xfs_dir2_sf_put_ino(mp, sfp, sfep,
 						args->inumber);
 				xfs_dir2_sf_put_ftype(mp, 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 a0d5761e1fee..71d60885000e 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2487,7 +2487,7 @@ xfs_remove(
 		 */
 		if (dp->i_ino != tp->t_mountp->m_sb.sb_rootino) {
 			error = xfs_dir_replace(tp, ip, &xfs_name_dotdot,
-					tp->t_mountp->m_sb.sb_rootino, 0);
+					tp->t_mountp->m_sb.sb_rootino, 0, NULL);
 			if (error)
 				return error;
 		}
@@ -2642,12 +2642,12 @@ 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, spaceres);
+	error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, 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, spaceres);
+	error = xfs_dir_replace(tp, dp2, name2, ip1->i_ino, spaceres, NULL);
 	if (error)
 		goto out_trans_abort;
 
@@ -2661,7 +2661,7 @@ xfs_cross_rename(
 
 		if (S_ISDIR(VFS_I(ip2)->i_mode)) {
 			error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot,
-						dp1->i_ino, spaceres);
+						dp1->i_ino, spaceres, NULL);
 			if (error)
 				goto out_trans_abort;
 
@@ -2685,7 +2685,7 @@ xfs_cross_rename(
 
 		if (S_ISDIR(VFS_I(ip1)->i_mode)) {
 			error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot,
-						dp2->i_ino, spaceres);
+						dp2->i_ino, spaceres, NULL);
 			if (error)
 				goto out_trans_abort;
 
@@ -3019,7 +3019,7 @@ xfs_rename(
 		 * name at the destination directory, remove it first.
 		 */
 		error = xfs_dir_replace(tp, target_dp, target_name,
-					src_ip->i_ino, spaceres);
+					src_ip->i_ino, spaceres, NULL);
 		if (error)
 			goto out_trans_cancel;
 
@@ -3053,7 +3053,7 @@ xfs_rename(
 		 * directory.
 		 */
 		error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,
-					target_dp->i_ino, spaceres);
+					target_dp->i_ino, spaceres, NULL);
 		ASSERT(error != -EEXIST);
 		if (error)
 			goto out_trans_cancel;
@@ -3092,7 +3092,7 @@ xfs_rename(
 	 */
 	if (wip)
 		error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino,
-					spaceres);
+					spaceres, NULL);
 	else
 		error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
 					   spaceres, NULL);
-- 
2.25.1


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

* [PATCH v4 10/27] xfs: add parent pointer support to attribute code
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (8 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 09/27] xfs: get directory offset when replacing a " allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-21 22:29 ` [PATCH v4 11/27] xfs: define parent pointer xattr format allison.henderson
                   ` (16 subsequent siblings)
  26 siblings, 0 replies; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.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.

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>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/libxfs/xfs_attr.c       | 4 +++-
 fs/xfs/libxfs/xfs_da_format.h  | 5 ++++-
 fs/xfs/libxfs/xfs_log_format.h | 1 +
 3 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index b1dbed7655e8..101823772bf9 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -976,11 +976,13 @@ xfs_attr_set(
 	struct xfs_inode	*dp = args->dp;
 	struct xfs_mount	*mp = dp->i_mount;
 	struct xfs_trans_res	tres;
-	bool			rsvd = (args->attr_filter & XFS_ATTR_ROOT);
+	bool			rsvd;
 	int			error, local;
 	int			rmt_blks = 0;
 	unsigned int		total;
 
+	rsvd = (args->attr_filter & (XFS_ATTR_ROOT | XFS_ATTR_PARENT)) != 0;
+
 	if (xfs_is_shutdown(dp->i_mount))
 		return -EIO;
 
diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h
index 25e2841084e1..3dc03968bba6 100644
--- a/fs/xfs/libxfs/xfs_da_format.h
+++ b/fs/xfs/libxfs/xfs_da_format.h
@@ -688,12 +688,15 @@ struct xfs_attr3_leafblock {
 #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 attrs */
 #define	XFS_ATTR_INCOMPLETE_BIT	7	/* attr in middle of create/delete */
 #define XFS_ATTR_LOCAL		(1u << XFS_ATTR_LOCAL_BIT)
 #define XFS_ATTR_ROOT		(1u << XFS_ATTR_ROOT_BIT)
 #define XFS_ATTR_SECURE		(1u << XFS_ATTR_SECURE_BIT)
+#define XFS_ATTR_PARENT		(1u << XFS_ATTR_PARENT_BIT)
 #define XFS_ATTR_INCOMPLETE	(1u << XFS_ATTR_INCOMPLETE_BIT)
-#define XFS_ATTR_NSP_ONDISK_MASK	(XFS_ATTR_ROOT | XFS_ATTR_SECURE)
+#define XFS_ATTR_NSP_ONDISK_MASK \
+			(XFS_ATTR_ROOT | XFS_ATTR_SECURE | XFS_ATTR_PARENT)
 
 /*
  * Alignment for namelist and valuelist entries (since they are mixed
diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
index 62f40e6353c2..57814057934d 100644
--- a/fs/xfs/libxfs/xfs_log_format.h
+++ b/fs/xfs/libxfs/xfs_log_format.h
@@ -919,6 +919,7 @@ struct xfs_icreate_log {
  */
 #define XFS_ATTRI_FILTER_MASK		(XFS_ATTR_ROOT | \
 					 XFS_ATTR_SECURE | \
+					 XFS_ATTR_PARENT | \
 					 XFS_ATTR_INCOMPLETE)
 
 /*
-- 
2.25.1


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

* [PATCH v4 11/27] xfs: define parent pointer xattr format
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (9 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 10/27] xfs: add parent pointer support to attribute code allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-21 22:29 ` [PATCH v4 12/27] xfs: Add xfs_verify_pptr allison.henderson
                   ` (15 subsequent siblings)
  26 siblings, 0 replies; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.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.

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

diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h
index 3dc03968bba6..b02b67f1999e 100644
--- a/fs/xfs/libxfs/xfs_da_format.h
+++ b/fs/xfs/libxfs/xfs_da_format.h
@@ -805,4 +805,29 @@ static inline unsigned int xfs_dir2_dirblock_bytes(struct xfs_sb *sbp)
 xfs_failaddr_t xfs_da3_blkinfo_verify(struct xfs_buf *bp,
 				      struct xfs_da3_blkinfo *hdr3);
 
+/*
+ * Parent pointer attribute format definition
+ *
+ * EA name encodes the parent inode number, generation and the offset of
+ * the dirent that points to the child inode. The EA value contains the
+ * same name as the dirent in the parent directory.
+ */
+struct xfs_parent_name_rec {
+	__be64  p_ino;
+	__be32  p_gen;
+	__be32  p_diroffset;
+};
+
+/*
+ * incore version of the above, also contains name pointers so callers
+ * can pass/obtain all the parent pointer information in a single structure
+ */
+struct xfs_parent_name_irec {
+	xfs_ino_t		p_ino;
+	uint32_t		p_gen;
+	xfs_dir2_dataptr_t	p_diroffset;
+	const char		*p_name;
+	uint8_t			p_namelen;
+};
+
 #endif /* __XFS_DA_FORMAT_H__ */
-- 
2.25.1


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

* [PATCH v4 12/27] xfs: Add xfs_verify_pptr
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (10 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 11/27] xfs: define parent pointer xattr format allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-21 22:29 ` [PATCH v4 13/27] xfs: Increase rename inode reservation allison.henderson
                   ` (14 subsequent siblings)
  26 siblings, 0 replies; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

Attribute names of parent pointers are not strings.  So we need to modify
attr_namecheck to verify parent pointer records when the XFS_ATTR_PARENT flag is
set.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/libxfs/xfs_attr.c | 47 +++++++++++++++++++++++++++++++++++++---
 fs/xfs/libxfs/xfs_attr.h |  3 ++-
 fs/xfs/scrub/attr.c      |  2 +-
 fs/xfs/xfs_attr_item.c   | 11 ++++++----
 fs/xfs/xfs_attr_list.c   | 17 ++++++++++-----
 5 files changed, 66 insertions(+), 14 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 101823772bf9..0c9589261990 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -1577,9 +1577,33 @@ xfs_attr_node_get(
 	return error;
 }
 
-/* Returns true if the attribute entry name is valid. */
-bool
-xfs_attr_namecheck(
+/*
+ * Verify parent pointer attribute is valid.
+ * Return true on success or false on failure
+ */
+STATIC bool
+xfs_verify_pptr(
+	struct xfs_mount		*mp,
+	struct xfs_parent_name_rec	*rec)
+{
+	xfs_ino_t			p_ino;
+	xfs_dir2_dataptr_t		p_diroffset;
+
+	p_ino = be64_to_cpu(rec->p_ino);
+	p_diroffset = be32_to_cpu(rec->p_diroffset);
+
+	if (!xfs_verify_ino(mp, p_ino))
+		return false;
+
+	if (p_diroffset > XFS_DIR2_MAX_DATAPTR)
+		return false;
+
+	return true;
+}
+
+/* Returns true if the string attribute entry name is valid. */
+static bool
+xfs_str_attr_namecheck(
 	const void	*name,
 	size_t		length)
 {
@@ -1594,6 +1618,23 @@ xfs_attr_namecheck(
 	return !memchr(name, 0, length);
 }
 
+/* Returns true if the attribute entry name is valid. */
+bool
+xfs_attr_namecheck(
+	struct xfs_mount	*mp,
+	const void		*name,
+	size_t			length,
+	int			flags)
+{
+	if (flags & XFS_ATTR_PARENT) {
+		if (length != sizeof(struct xfs_parent_name_rec))
+			return false;
+		return xfs_verify_pptr(mp, (struct xfs_parent_name_rec *)name);
+	}
+
+	return xfs_str_attr_namecheck(name, length);
+}
+
 int __init
 xfs_attr_intent_init_cache(void)
 {
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 3e81f3f48560..b79dae788cfb 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -547,7 +547,8 @@ int xfs_attr_get(struct xfs_da_args *args);
 int xfs_attr_set(struct xfs_da_args *args);
 int xfs_attr_set_iter(struct xfs_attr_intent *attr);
 int xfs_attr_remove_iter(struct xfs_attr_intent *attr);
-bool xfs_attr_namecheck(const void *name, size_t length);
+bool xfs_attr_namecheck(struct xfs_mount *mp, const void *name, size_t length,
+			int flags);
 int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
 void xfs_init_attr_trans(struct xfs_da_args *args, struct xfs_trans_res *tres,
 			 unsigned int *total);
diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c
index b6f0c9f3f124..d3e75c077fab 100644
--- a/fs/xfs/scrub/attr.c
+++ b/fs/xfs/scrub/attr.c
@@ -128,7 +128,7 @@ xchk_xattr_listent(
 	}
 
 	/* Does this name make sense? */
-	if (!xfs_attr_namecheck(name, namelen)) {
+	if (!xfs_attr_namecheck(sx->sc->mp, name, namelen, flags)) {
 		xchk_fblock_set_corrupt(sx->sc, XFS_ATTR_FORK, args.blkno);
 		return;
 	}
diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
index 0c449fb606ed..67eac5cc63dd 100644
--- a/fs/xfs/xfs_attr_item.c
+++ b/fs/xfs/xfs_attr_item.c
@@ -615,7 +615,8 @@ xfs_attri_item_recover(
 	 */
 	attrp = &attrip->attri_format;
 	if (!xfs_attri_validate(mp, attrp) ||
-	    !xfs_attr_namecheck(nv->name.i_addr, nv->name.i_len))
+	    !xfs_attr_namecheck(mp, nv->name.i_addr, nv->name.i_len,
+				attrp->alfi_attr_filter))
 		return -EFSCORRUPTED;
 
 	error = xlog_recover_iget(mp,  attrp->alfi_ino, &ip);
@@ -812,7 +813,8 @@ xlog_recover_attri_commit_pass2(
 	attr_name = item->ri_buf[i].i_addr;
 	i++;
 
-	if (!xfs_attr_namecheck(attr_name, attri_formatp->alfi_name_len)) {
+	if (!xfs_attr_namecheck(mp, attr_name, attri_formatp->alfi_name_len,
+				attri_formatp->alfi_attr_filter)) {
 		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
 		return -EFSCORRUPTED;
 	}
@@ -821,8 +823,9 @@ xlog_recover_attri_commit_pass2(
 		attr_nname = item->ri_buf[i].i_addr;
 		i++;
 
-		if (!xfs_attr_namecheck(attr_nname,
-				attri_formatp->alfi_nname_len)) {
+		if (!xfs_attr_namecheck(mp, attr_nname,
+				attri_formatp->alfi_nname_len,
+				attri_formatp->alfi_attr_filter)) {
 			XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
 			return -EFSCORRUPTED;
 		}
diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
index 99bbbe1a0e44..a51f7f13a352 100644
--- a/fs/xfs/xfs_attr_list.c
+++ b/fs/xfs/xfs_attr_list.c
@@ -58,9 +58,13 @@ xfs_attr_shortform_list(
 	struct xfs_attr_sf_sort		*sbuf, *sbp;
 	struct xfs_attr_shortform	*sf;
 	struct xfs_attr_sf_entry	*sfe;
+	struct xfs_mount		*mp;
 	int				sbsize, nsbuf, count, i;
 	int				error = 0;
 
+	ASSERT(context != NULL);
+	ASSERT(dp != NULL);
+	mp = dp->i_mount;
 	sf = (struct xfs_attr_shortform *)dp->i_af.if_u1.if_data;
 	ASSERT(sf != NULL);
 	if (!sf->hdr.count)
@@ -82,8 +86,9 @@ xfs_attr_shortform_list(
 	     (dp->i_af.if_bytes + sf->hdr.count * 16) < context->bufsize)) {
 		for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
 			if (XFS_IS_CORRUPT(context->dp->i_mount,
-					   !xfs_attr_namecheck(sfe->nameval,
-							       sfe->namelen)))
+					   !xfs_attr_namecheck(mp, sfe->nameval,
+							       sfe->namelen,
+							       sfe->flags)))
 				return -EFSCORRUPTED;
 			context->put_listent(context,
 					     sfe->flags,
@@ -174,8 +179,9 @@ xfs_attr_shortform_list(
 			cursor->offset = 0;
 		}
 		if (XFS_IS_CORRUPT(context->dp->i_mount,
-				   !xfs_attr_namecheck(sbp->name,
-						       sbp->namelen))) {
+				   !xfs_attr_namecheck(mp, sbp->name,
+						       sbp->namelen,
+						       sbp->flags))) {
 			error = -EFSCORRUPTED;
 			goto out;
 		}
@@ -465,7 +471,8 @@ xfs_attr3_leaf_list_int(
 		}
 
 		if (XFS_IS_CORRUPT(context->dp->i_mount,
-				   !xfs_attr_namecheck(name, namelen)))
+				   !xfs_attr_namecheck(mp, name, namelen,
+						       entry->flags)))
 			return -EFSCORRUPTED;
 		context->put_listent(context, entry->flags,
 					      name, namelen, valuelen);
-- 
2.25.1


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

* [PATCH v4 13/27] xfs: Increase rename inode reservation
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (11 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 12/27] xfs: Add xfs_verify_pptr allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-25 19:15   ` Darrick J. Wong
  2022-10-21 22:29 ` [PATCH v4 14/27] xfs: extend transaction reservations for parent attributes allison.henderson
                   ` (13 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

xfs_rename can lock up to 5 inodes: src_dp, target_dp, src_ip, target_ip
and wip.  So we need to increase the inode reservation to match.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_trans_resv.c | 4 ++--
 fs/xfs/xfs_inode.c             | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_trans_resv.c b/fs/xfs/libxfs/xfs_trans_resv.c
index 2c4ad6e4bb14..5b2f27cbdb80 100644
--- a/fs/xfs/libxfs/xfs_trans_resv.c
+++ b/fs/xfs/libxfs/xfs_trans_resv.c
@@ -422,7 +422,7 @@ xfs_calc_itruncate_reservation_minlogsize(
 
 /*
  * In renaming a files we can modify:
- *    the four inodes involved: 4 * inode size
+ *    the five inodes involved: 5 * inode size
  *    the two directory btrees: 2 * (max depth + v2) * dir block size
  *    the two directory bmap btrees: 2 * max depth * block size
  * And the bmap_finish transaction can free dir and bmap blocks (two sets
@@ -437,7 +437,7 @@ xfs_calc_rename_reservation(
 	struct xfs_mount	*mp)
 {
 	return XFS_DQUOT_LOGRES(mp) +
-		max((xfs_calc_inode_res(mp, 4) +
+		max((xfs_calc_inode_res(mp, 5) +
 		     xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp),
 				      XFS_FSB_TO_B(mp, 1))),
 		    (xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) +
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 71d60885000e..ea7aeab839c2 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2848,7 +2848,7 @@ xfs_rename(
 	 * Lock all the participating inodes. Depending upon whether
 	 * the target_name exists in the target directory, and
 	 * whether the target directory is the same as the source
-	 * directory, we can lock from 2 to 4 inodes.
+	 * directory, we can lock from 2 to 5 inodes.
 	 */
 	xfs_lock_inodes(inodes, num_inodes, XFS_ILOCK_EXCL);
 
-- 
2.25.1


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

* [PATCH v4 14/27] xfs: extend transaction reservations for parent attributes
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (12 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 13/27] xfs: Increase rename inode reservation allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-25 20:55   ` Darrick J. Wong
  2022-10-21 22:29 ` [PATCH v4 15/27] xfs: parent pointer attribute creation allison.henderson
                   ` (12 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.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.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_trans_resv.c | 303 +++++++++++++++++++++++++++------
 1 file changed, 249 insertions(+), 54 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_trans_resv.c b/fs/xfs/libxfs/xfs_trans_resv.c
index 5b2f27cbdb80..756b6f38c385 100644
--- a/fs/xfs/libxfs/xfs_trans_resv.c
+++ b/fs/xfs/libxfs/xfs_trans_resv.c
@@ -19,6 +19,9 @@
 #include "xfs_trans.h"
 #include "xfs_qm.h"
 #include "xfs_trans_space.h"
+#include "xfs_attr_item.h"
+#include "xfs_log.h"
+#include "xfs_da_format.h"
 
 #define _ALLOC	true
 #define _FREE	false
@@ -426,23 +429,62 @@ xfs_calc_itruncate_reservation_minlogsize(
  *    the two directory btrees: 2 * (max depth + v2) * dir block size
  *    the two directory bmap btrees: 2 * max depth * block size
  * And the bmap_finish transaction can free dir and bmap blocks (two sets
- *	of bmap blocks) giving:
+ *	of bmap blocks) giving (t2):
  *    the agf for the ags in which the blocks live: 3 * sector size
  *    the agfl for the ags in which the blocks live: 3 * sector size
  *    the superblock for the free block count: sector size
  *    the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size
+ * If parent pointers are enabled (t3), then each transaction in the chain
+ *    must be capable of setting or removing the extended attribute
+ *    containing the parent information.  It must also be able to handle
+ *    the three xattr intent items that track the progress of the parent
+ *    pointer update.
  */
 STATIC uint
 xfs_calc_rename_reservation(
 	struct xfs_mount	*mp)
 {
-	return XFS_DQUOT_LOGRES(mp) +
-		max((xfs_calc_inode_res(mp, 5) +
-		     xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp),
-				      XFS_FSB_TO_B(mp, 1))),
-		    (xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) +
-		     xfs_calc_buf_res(xfs_allocfree_block_count(mp, 3),
-				      XFS_FSB_TO_B(mp, 1))));
+	unsigned int		overhead = XFS_DQUOT_LOGRES(mp);
+	struct xfs_trans_resv	*resp = M_RES(mp);
+	unsigned int		t1, t2, t3 = 0;
+
+	t1 = xfs_calc_inode_res(mp, 5) +
+	     xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp),
+			XFS_FSB_TO_B(mp, 1));
+
+	t2 = xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) +
+	     xfs_calc_buf_res(xfs_allocfree_block_count(mp, 3),
+			XFS_FSB_TO_B(mp, 1));
+
+	if (xfs_has_parent(mp)) {
+		t3 = max(resp->tr_attrsetm.tr_logres,
+				resp->tr_attrrm.tr_logres);
+		overhead += 4 * (sizeof(struct xfs_attri_log_item) +
+				 (2 * xlog_calc_iovec_len(XATTR_NAME_MAX)) +
+				 xlog_calc_iovec_len(
+					sizeof(struct xfs_parent_name_rec)));
+	}
+
+	return overhead + max3(t1, t2, t3);
+}
+
+static inline unsigned int
+xfs_rename_log_count(
+	struct xfs_mount	*mp,
+	struct xfs_trans_resv	*resp)
+{
+	/* One for the rename, one more for freeing blocks */
+	unsigned int		ret = XFS_RENAME_LOG_COUNT;
+
+	/*
+	 * Pre-reserve enough log reservation to handle the transaction
+	 * rolling needed to remove or add one parent pointer.
+	 */
+	if (xfs_has_parent(mp))
+		ret += max(resp->tr_attrsetm.tr_logcount,
+			   resp->tr_attrrm.tr_logcount);
+
+	return ret;
 }
 
 /*
@@ -459,6 +501,23 @@ xfs_calc_iunlink_remove_reservation(
 	       2 * M_IGEO(mp)->inode_cluster_size;
 }
 
+static inline unsigned int
+xfs_link_log_count(
+	struct xfs_mount	*mp,
+	struct xfs_trans_resv	*resp)
+{
+	unsigned int		ret = XFS_LINK_LOG_COUNT;
+
+	/*
+	 * Pre-reserve enough log reservation to handle the transaction
+	 * rolling needed to add one parent pointer.
+	 */
+	if (xfs_has_parent(mp))
+		ret += resp->tr_attrsetm.tr_logcount;
+
+	return ret;
+}
+
 /*
  * For creating a link to an inode:
  *    the parent directory inode: inode size
@@ -475,14 +534,27 @@ STATIC uint
 xfs_calc_link_reservation(
 	struct xfs_mount	*mp)
 {
-	return XFS_DQUOT_LOGRES(mp) +
-		xfs_calc_iunlink_remove_reservation(mp) +
-		max((xfs_calc_inode_res(mp, 2) +
-		     xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
-				      XFS_FSB_TO_B(mp, 1))),
-		    (xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
-		     xfs_calc_buf_res(xfs_allocfree_block_count(mp, 1),
-				      XFS_FSB_TO_B(mp, 1))));
+	unsigned int            overhead = XFS_DQUOT_LOGRES(mp);
+	struct xfs_trans_resv   *resp = M_RES(mp);
+	unsigned int            t1, t2, t2_1, t2_2, t3 = 0;
+
+	t1 = xfs_calc_iunlink_remove_reservation(mp);
+	t2_1 = xfs_calc_inode_res(mp, 2) +
+	       xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1));
+	t2_2 = xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
+	       xfs_calc_buf_res(xfs_allocfree_block_count(mp, 1),
+				XFS_FSB_TO_B(mp, 1));
+	t2 = max(t2_1, t2_2);
+
+	if (xfs_has_parent(mp)) {
+		t3 = resp->tr_attrsetm.tr_logres;
+		overhead += sizeof(struct xfs_attri_log_item) +
+			    xlog_calc_iovec_len(XATTR_NAME_MAX) +
+			    xlog_calc_iovec_len(
+					sizeof(struct xfs_parent_name_rec));
+	}
+
+	return overhead + t1 + t2 + t3;
 }
 
 /*
@@ -497,6 +569,23 @@ xfs_calc_iunlink_add_reservation(xfs_mount_t *mp)
 			M_IGEO(mp)->inode_cluster_size;
 }
 
+static inline unsigned int
+xfs_remove_log_count(
+	struct xfs_mount	*mp,
+	struct xfs_trans_resv	*resp)
+{
+	unsigned int		ret = XFS_REMOVE_LOG_COUNT;
+
+	/*
+	 * Pre-reserve enough log reservation to handle the transaction
+	 * rolling needed to add one parent pointer.
+	 */
+	if (xfs_has_parent(mp))
+		ret += resp->tr_attrrm.tr_logcount;
+
+	return ret;
+}
+
 /*
  * For removing a directory entry we can modify:
  *    the parent directory inode: inode size
@@ -513,14 +602,27 @@ STATIC uint
 xfs_calc_remove_reservation(
 	struct xfs_mount	*mp)
 {
-	return XFS_DQUOT_LOGRES(mp) +
-		xfs_calc_iunlink_add_reservation(mp) +
-		max((xfs_calc_inode_res(mp, 2) +
-		     xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
-				      XFS_FSB_TO_B(mp, 1))),
-		    (xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) +
-		     xfs_calc_buf_res(xfs_allocfree_block_count(mp, 2),
-				      XFS_FSB_TO_B(mp, 1))));
+	unsigned int            overhead = XFS_DQUOT_LOGRES(mp);
+	struct xfs_trans_resv   *resp = M_RES(mp);
+	unsigned int            t1, t2, t2_1, t2_2, t3 = 0;
+
+	t1 = xfs_calc_iunlink_add_reservation(mp);
+
+	t2_1 = xfs_calc_inode_res(mp, 2) +
+	       xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1));
+	t2_2 = xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) +
+	       xfs_calc_buf_res(xfs_allocfree_block_count(mp, 2),
+				XFS_FSB_TO_B(mp, 1));
+	t2 = max(t2_1, t2_2);
+
+	if (xfs_has_parent(mp)) {
+		t3 = resp->tr_attrrm.tr_logres;
+		overhead += sizeof(struct xfs_attri_log_item) +
+			    xlog_calc_iovec_len(
+					sizeof(struct xfs_parent_name_rec));
+	}
+
+	return overhead + t1 + t2 + t3;
 }
 
 /*
@@ -569,12 +671,39 @@ xfs_calc_icreate_resv_alloc(
 		xfs_calc_finobt_res(mp);
 }
 
+static inline unsigned int
+xfs_icreate_log_count(
+	struct xfs_mount	*mp,
+	struct xfs_trans_resv	*resp)
+{
+	unsigned int		ret = XFS_CREATE_LOG_COUNT;
+
+	/*
+	 * Pre-reserve enough log reservation to handle the transaction
+	 * rolling needed to add one parent pointer.
+	 */
+	if (xfs_has_parent(mp))
+		ret += resp->tr_attrsetm.tr_logcount;
+
+	return ret;
+}
+
 STATIC uint
-xfs_calc_icreate_reservation(xfs_mount_t *mp)
+xfs_calc_icreate_reservation(
+	struct xfs_mount	*mp)
 {
-	return XFS_DQUOT_LOGRES(mp) +
-		max(xfs_calc_icreate_resv_alloc(mp),
-		    xfs_calc_create_resv_modify(mp));
+	struct xfs_trans_resv   *resp = M_RES(mp);
+	unsigned int		ret = XFS_DQUOT_LOGRES(mp) +
+				      max(xfs_calc_icreate_resv_alloc(mp),
+				      xfs_calc_create_resv_modify(mp));
+
+	if (xfs_has_parent(mp))
+		ret += resp->tr_attrsetm.tr_logres +
+		       sizeof(struct xfs_attri_log_item) +
+		       xlog_calc_iovec_len(XATTR_NAME_MAX) +
+		       xlog_calc_iovec_len(
+					sizeof(struct xfs_parent_name_rec));
+	return ret;
 }
 
 STATIC uint
@@ -587,6 +716,23 @@ xfs_calc_create_tmpfile_reservation(
 	return res + xfs_calc_iunlink_add_reservation(mp);
 }
 
+static inline unsigned int
+xfs_mkdir_log_count(
+	struct xfs_mount	*mp,
+	struct xfs_trans_resv	*resp)
+{
+	unsigned int		ret = XFS_MKDIR_LOG_COUNT;
+
+	/*
+	 * Pre-reserve enough log reservation to handle the transaction
+	 * rolling needed to add one parent pointer.
+	 */
+	if (xfs_has_parent(mp))
+		ret += resp->tr_attrsetm.tr_logcount;
+
+	return ret;
+}
+
 /*
  * Making a new directory is the same as creating a new file.
  */
@@ -597,6 +743,22 @@ xfs_calc_mkdir_reservation(
 	return xfs_calc_icreate_reservation(mp);
 }
 
+static inline unsigned int
+xfs_symlink_log_count(
+	struct xfs_mount	*mp,
+	struct xfs_trans_resv	*resp)
+{
+	unsigned int		ret = XFS_SYMLINK_LOG_COUNT;
+
+	/*
+	 * Pre-reserve enough log reservation to handle the transaction
+	 * rolling needed to add one parent pointer.
+	 */
+	if (xfs_has_parent(mp))
+		ret += resp->tr_attrsetm.tr_logcount;
+
+	return ret;
+}
 
 /*
  * Making a new symplink is the same as creating a new file, but
@@ -607,8 +769,17 @@ STATIC uint
 xfs_calc_symlink_reservation(
 	struct xfs_mount	*mp)
 {
-	return xfs_calc_icreate_reservation(mp) +
-	       xfs_calc_buf_res(1, XFS_SYMLINK_MAXLEN);
+	struct xfs_trans_resv   *resp = M_RES(mp);
+	unsigned int		ret = xfs_calc_icreate_reservation(mp) +
+				      xfs_calc_buf_res(1, XFS_SYMLINK_MAXLEN);
+
+	if (xfs_has_parent(mp))
+		ret += resp->tr_attrsetm.tr_logres +
+		       sizeof(struct xfs_attri_log_item) +
+		       xlog_calc_iovec_len(XATTR_NAME_MAX) +
+		       xlog_calc_iovec_len(
+					sizeof(struct xfs_parent_name_rec));
+	return ret;
 }
 
 /*
@@ -909,54 +1080,76 @@ xfs_calc_sb_reservation(
 	return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize);
 }
 
-void
-xfs_trans_resv_calc(
+/*
+ * 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.
+ */
+STATIC void
+xfs_calc_namespace_reservations(
 	struct xfs_mount	*mp,
 	struct xfs_trans_resv	*resp)
 {
-	int			logcount_adj = 0;
-
-	/*
-	 * 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, false);
-	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, false);
-	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;
+	resp->tr_rename.tr_logcount = xfs_rename_log_count(mp, resp);
 	resp->tr_rename.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
 
 	resp->tr_link.tr_logres = xfs_calc_link_reservation(mp);
-	resp->tr_link.tr_logcount = XFS_LINK_LOG_COUNT;
+	resp->tr_link.tr_logcount = xfs_link_log_count(mp, resp);
 	resp->tr_link.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
 
 	resp->tr_remove.tr_logres = xfs_calc_remove_reservation(mp);
-	resp->tr_remove.tr_logcount = XFS_REMOVE_LOG_COUNT;
+	resp->tr_remove.tr_logcount = xfs_remove_log_count(mp, resp);
 	resp->tr_remove.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
 
 	resp->tr_symlink.tr_logres = xfs_calc_symlink_reservation(mp);
-	resp->tr_symlink.tr_logcount = XFS_SYMLINK_LOG_COUNT;
+	resp->tr_symlink.tr_logcount = xfs_symlink_log_count(mp, resp);
 	resp->tr_symlink.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
 
 	resp->tr_create.tr_logres = xfs_calc_icreate_reservation(mp);
-	resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT;
+	resp->tr_create.tr_logcount = xfs_icreate_log_count(mp, resp);
 	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(mp, resp);
+	resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+}
+
+void
+xfs_trans_resv_calc(
+	struct xfs_mount	*mp,
+	struct xfs_trans_resv	*resp)
+{
+	int			logcount_adj = 0;
+
+	/*
+	 * 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, false);
+	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, false);
+	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;
@@ -986,6 +1179,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.25.1


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

* [PATCH v4 15/27] xfs: parent pointer attribute creation
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (13 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 14/27] xfs: extend transaction reservations for parent attributes allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-25 21:11   ` Darrick J. Wong
  2022-10-21 22:29 ` [PATCH v4 16/27] xfs: add parent attributes to link allison.henderson
                   ` (11 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

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

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/Makefile            |   1 +
 fs/xfs/libxfs/xfs_attr.c   |   4 +-
 fs/xfs/libxfs/xfs_attr.h   |   4 +-
 fs/xfs/libxfs/xfs_parent.c | 149 +++++++++++++++++++++++++++++++++++++
 fs/xfs/libxfs/xfs_parent.h |  34 +++++++++
 fs/xfs/xfs_inode.c         |  63 ++++++++++++++--
 fs/xfs/xfs_xattr.c         |   2 +-
 fs/xfs/xfs_xattr.h         |   1 +
 8 files changed, 247 insertions(+), 11 deletions(-)

diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index 03135a1c31b6..e2b2cf50ffcf 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -40,6 +40,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_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 0c9589261990..805aaa5639d2 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -886,7 +886,7 @@ xfs_attr_lookup(
 	return error;
 }
 
-static int
+int
 xfs_attr_intent_init(
 	struct xfs_da_args	*args,
 	unsigned int		op_flags,	/* op flag (set or remove) */
@@ -904,7 +904,7 @@ xfs_attr_intent_init(
 }
 
 /* Sets an attribute for an inode as a deferred operation */
-static int
+int
 xfs_attr_defer_add(
 	struct xfs_da_args	*args)
 {
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index b79dae788cfb..0cf23f5117ad 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -544,6 +544,7 @@ int xfs_inode_hasattr(struct xfs_inode *ip);
 bool xfs_attr_is_leaf(struct xfs_inode *ip);
 int xfs_attr_get_ilocked(struct xfs_da_args *args);
 int xfs_attr_get(struct xfs_da_args *args);
+int xfs_attr_defer_add(struct xfs_da_args *args);
 int xfs_attr_set(struct xfs_da_args *args);
 int xfs_attr_set_iter(struct xfs_attr_intent *attr);
 int xfs_attr_remove_iter(struct xfs_attr_intent *attr);
@@ -552,7 +553,8 @@ bool xfs_attr_namecheck(struct xfs_mount *mp, const void *name, size_t length,
 int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
 void xfs_init_attr_trans(struct xfs_da_args *args, struct xfs_trans_res *tres,
 			 unsigned int *total);
-
+int xfs_attr_intent_init(struct xfs_da_args *args, unsigned int op_flags,
+			 struct xfs_attr_intent  **attr);
 /*
  * Check to see if the attr should be upgraded from non-existent or shortform to
  * single-leaf-block attribute list.
diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
new file mode 100644
index 000000000000..cf5ea8ce8bd3
--- /dev/null
+++ b/fs/xfs/libxfs/xfs_parent.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Oracle, Inc.
+ * All rights reserved.
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_format.h"
+#include "xfs_da_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_da_btree.h"
+#include "xfs_attr.h"
+#include "xfs_da_btree.h"
+#include "xfs_attr_sf.h"
+#include "xfs_bmap.h"
+#include "xfs_defer.h"
+#include "xfs_log.h"
+#include "xfs_xattr.h"
+#include "xfs_parent.h"
+#include "xfs_trans_space.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 behavior 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,
+	struct xfs_inode		*ip,
+	uint32_t			p_diroffset)
+{
+	xfs_ino_t			p_ino = ip->i_ino;
+	uint32_t			p_gen = VFS_I(ip)->i_generation;
+
+	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);
+}
+
+int
+xfs_parent_init(
+	struct xfs_mount		*mp,
+	struct xfs_parent_defer		**parentp)
+{
+	struct xfs_parent_defer		*parent;
+	int				error;
+
+	if (!xfs_has_parent(mp))
+		return 0;
+
+	error = xfs_attr_grab_log_assist(mp);
+	if (error)
+		return error;
+
+	parent = kzalloc(sizeof(*parent), GFP_KERNEL);
+	if (!parent)
+		return -ENOMEM;
+
+	/* init parent da_args */
+	parent->args.geo = mp->m_attr_geo;
+	parent->args.whichfork = XFS_ATTR_FORK;
+	parent->args.attr_filter = XFS_ATTR_PARENT;
+	parent->args.op_flags = XFS_DA_OP_OKNOENT | XFS_DA_OP_LOGGED;
+	parent->args.name = (const uint8_t *)&parent->rec;
+	parent->args.namelen = sizeof(struct xfs_parent_name_rec);
+
+	*parentp = parent;
+	return 0;
+}
+
+int
+xfs_parent_defer_add(
+	struct xfs_trans	*tp,
+	struct xfs_parent_defer	*parent,
+	struct xfs_inode	*dp,
+	struct xfs_name		*parent_name,
+	xfs_dir2_dataptr_t	diroffset,
+	struct xfs_inode	*child)
+{
+	struct xfs_da_args	*args = &parent->args;
+
+	xfs_init_parent_name_rec(&parent->rec, dp, diroffset);
+	args->hashval = xfs_da_hashname(args->name, args->namelen);
+
+	args->trans = tp;
+	args->dp = child;
+	if (parent_name) {
+		parent->args.value = (void *)parent_name->name;
+		parent->args.valuelen = parent_name->len;
+	}
+
+	return xfs_attr_defer_add(args);
+}
+
+void
+xfs_parent_cancel(
+	xfs_mount_t		*mp,
+	struct xfs_parent_defer *parent)
+{
+	xlog_drop_incompat_feat(mp->m_log);
+	kfree(parent);
+}
+
+unsigned int
+xfs_pptr_calc_space_res(
+	struct xfs_mount	*mp,
+	unsigned int		namelen)
+{
+	/*
+	 * Pptrs are always the first attr in an attr tree, and never larger
+	 * than a block
+	 */
+	return XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) +
+	       XFS_NEXTENTADD_SPACE_RES(mp, namelen, XFS_ATTR_FORK);
+}
+
diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h
new file mode 100644
index 000000000000..9b8d0764aad6
--- /dev/null
+++ b/fs/xfs/libxfs/xfs_parent.h
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Oracle, Inc.
+ * All Rights Reserved.
+ */
+#ifndef	__XFS_PARENT_H__
+#define	__XFS_PARENT_H__
+
+/*
+ * Dynamically allocd structure used to wrap the needed data to pass around
+ * the defer ops machinery
+ */
+struct xfs_parent_defer {
+	struct xfs_parent_name_rec	rec;
+	struct xfs_da_args		args;
+};
+
+/*
+ * Parent pointer attribute prototypes
+ */
+void xfs_init_parent_name_rec(struct xfs_parent_name_rec *rec,
+			      struct xfs_inode *ip,
+			      uint32_t p_diroffset);
+void xfs_init_parent_name_irec(struct xfs_parent_name_irec *irec,
+			       struct xfs_parent_name_rec *rec);
+int xfs_parent_init(xfs_mount_t *mp, struct xfs_parent_defer **parentp);
+int xfs_parent_defer_add(struct xfs_trans *tp, struct xfs_parent_defer *parent,
+			 struct xfs_inode *dp, struct xfs_name *parent_name,
+			 xfs_dir2_dataptr_t diroffset, struct xfs_inode *child);
+void xfs_parent_cancel(xfs_mount_t *mp, struct xfs_parent_defer *parent);
+unsigned int xfs_pptr_calc_space_res(struct xfs_mount *mp,
+				     unsigned int namelen);
+
+#endif	/* __XFS_PARENT_H__ */
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index ea7aeab839c2..ae6604f51ce8 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -37,6 +37,8 @@
 #include "xfs_reflink.h"
 #include "xfs_ag.h"
 #include "xfs_log_priv.h"
+#include "xfs_parent.h"
+#include "xfs_xattr.h"
 
 struct kmem_cache *xfs_inode_cache;
 
@@ -946,10 +948,32 @@ xfs_bumplink(
 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 }
 
+unsigned int
+xfs_create_space_res(
+	struct xfs_mount	*mp,
+	unsigned int		namelen)
+{
+	unsigned int		ret;
+
+	ret = XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp, namelen);
+	if (xfs_has_parent(mp))
+		ret += xfs_pptr_calc_space_res(mp, namelen);
+
+	return ret;
+}
+
+unsigned int
+xfs_mkdir_space_res(
+	struct xfs_mount	*mp,
+	unsigned int		namelen)
+{
+	return xfs_create_space_res(mp, namelen);
+}
+
 int
 xfs_create(
 	struct user_namespace	*mnt_userns,
-	xfs_inode_t		*dp,
+	struct xfs_inode	*dp,
 	struct xfs_name		*name,
 	umode_t			mode,
 	dev_t			rdev,
@@ -961,7 +985,7 @@ xfs_create(
 	struct xfs_inode	*ip = NULL;
 	struct xfs_trans	*tp = NULL;
 	int			error;
-	bool                    unlock_dp_on_error = false;
+	bool			unlock_dp_on_error = false;
 	prid_t			prid;
 	struct xfs_dquot	*udqp = NULL;
 	struct xfs_dquot	*gdqp = NULL;
@@ -969,6 +993,8 @@ xfs_create(
 	struct xfs_trans_res	*tres;
 	uint			resblks;
 	xfs_ino_t		ino;
+	xfs_dir2_dataptr_t	diroffset;
+	struct xfs_parent_defer	*parent = NULL;
 
 	trace_xfs_create(dp, name);
 
@@ -988,13 +1014,19 @@ xfs_create(
 		return error;
 
 	if (is_dir) {
-		resblks = XFS_MKDIR_SPACE_RES(mp, name->len);
+		resblks = xfs_mkdir_space_res(mp, name->len);
 		tres = &M_RES(mp)->tr_mkdir;
 	} else {
-		resblks = XFS_CREATE_SPACE_RES(mp, name->len);
+		resblks = xfs_create_space_res(mp, name->len);
 		tres = &M_RES(mp)->tr_create;
 	}
 
+	if (xfs_has_parent(mp)) {
+		error = xfs_parent_init(mp, &parent);
+		if (error)
+			goto out_release_dquots;
+	}
+
 	/*
 	 * Initially assume that the file does not exist and
 	 * reserve the resources for that case.  If that is not
@@ -1010,7 +1042,7 @@ xfs_create(
 				resblks, &tp);
 	}
 	if (error)
-		goto out_release_dquots;
+		goto drop_incompat;
 
 	xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
 	unlock_dp_on_error = true;
@@ -1020,6 +1052,7 @@ xfs_create(
 	 * entry pointing to them, but a directory also the "." entry
 	 * pointing to itself.
 	 */
+	init_xattrs = init_xattrs || xfs_has_parent(mp);
 	error = xfs_dialloc(&tp, dp->i_ino, mode, &ino);
 	if (!error)
 		error = xfs_init_new_inode(mnt_userns, tp, dp, ino, mode,
@@ -1034,11 +1067,12 @@ xfs_create(
 	 * the transaction cancel unlocking dp so don't do it explicitly in the
 	 * error path.
 	 */
-	xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
+	xfs_trans_ijoin(tp, dp, 0);
 	unlock_dp_on_error = false;
 
 	error = xfs_dir_createname(tp, dp, name, ip->i_ino,
-				   resblks - XFS_IALLOC_SPACE_RES(mp), NULL);
+				   resblks - XFS_IALLOC_SPACE_RES(mp),
+				   &diroffset);
 	if (error) {
 		ASSERT(error != -ENOSPC);
 		goto out_trans_cancel;
@@ -1054,6 +1088,17 @@ xfs_create(
 		xfs_bumplink(tp, dp);
 	}
 
+	/*
+	 * If we have parent pointers, we need to add the attribute containing
+	 * the parent information now.
+	 */
+	if (parent) {
+		error = xfs_parent_defer_add(tp, parent, dp, name, diroffset,
+					     ip);
+		if (error)
+			goto out_trans_cancel;
+	}
+
 	/*
 	 * If this is a synchronous mount, make sure that the
 	 * create transaction goes to disk before returning to
@@ -1079,6 +1124,7 @@ xfs_create(
 
 	*ipp = ip;
 	xfs_iunlock(ip, XFS_ILOCK_EXCL);
+	xfs_iunlock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
 	return 0;
 
  out_trans_cancel:
@@ -1093,6 +1139,9 @@ xfs_create(
 		xfs_finish_inode_setup(ip);
 		xfs_irele(ip);
 	}
+ drop_incompat:
+	if (parent)
+		xfs_parent_cancel(mp, parent);
  out_release_dquots:
 	xfs_qm_dqrele(udqp);
 	xfs_qm_dqrele(gdqp);
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index c325a28b89a8..d9067c5f6bd6 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -27,7 +27,7 @@
  * they must release the permission by calling xlog_drop_incompat_feat
  * when they're done.
  */
-static inline int
+int
 xfs_attr_grab_log_assist(
 	struct xfs_mount	*mp)
 {
diff --git a/fs/xfs/xfs_xattr.h b/fs/xfs/xfs_xattr.h
index 2b09133b1b9b..3fd6520a4d69 100644
--- a/fs/xfs/xfs_xattr.h
+++ b/fs/xfs/xfs_xattr.h
@@ -7,6 +7,7 @@
 #define __XFS_XATTR_H__
 
 int xfs_attr_change(struct xfs_da_args *args);
+int xfs_attr_grab_log_assist(struct xfs_mount *mp);
 
 extern const struct xattr_handler *xfs_xattr_handlers[];
 
-- 
2.25.1


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

* [PATCH v4 16/27] xfs: add parent attributes to link
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (14 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 15/27] xfs: parent pointer attribute creation allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-25 20:58   ` Darrick J. Wong
  2022-10-21 22:29 ` [PATCH v4 17/27] xfs: add parent attributes to symlink allison.henderson
                   ` (10 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

This patch modifies xfs_link to add a parent pointer to the inode.

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

diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index ae6604f51ce8..f2e7da1befa4 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1248,16 +1248,32 @@ xfs_create_tmpfile(
 	return error;
 }
 
+unsigned int
+xfs_link_space_res(
+	struct xfs_mount	*mp,
+	unsigned int		namelen)
+{
+	unsigned int		ret;
+
+	ret = XFS_DIRENTER_SPACE_RES(mp, namelen);
+	if (xfs_has_parent(mp))
+		ret += xfs_pptr_calc_space_res(mp, namelen);
+
+	return ret;
+}
+
 int
 xfs_link(
-	xfs_inode_t		*tdp,
-	xfs_inode_t		*sip,
+	struct xfs_inode	*tdp,
+	struct xfs_inode	*sip,
 	struct xfs_name		*target_name)
 {
-	xfs_mount_t		*mp = tdp->i_mount;
-	xfs_trans_t		*tp;
+	struct xfs_mount	*mp = tdp->i_mount;
+	struct xfs_trans	*tp;
 	int			error, nospace_error = 0;
 	int			resblks;
+	xfs_dir2_dataptr_t	diroffset;
+	struct xfs_parent_defer	*parent = NULL;
 
 	trace_xfs_link(tdp, target_name);
 
@@ -1274,11 +1290,17 @@ xfs_link(
 	if (error)
 		goto std_return;
 
-	resblks = XFS_LINK_SPACE_RES(mp, target_name->len);
+	if (xfs_has_parent(mp)) {
+		error = xfs_parent_init(mp, &parent);
+		if (error)
+			goto std_return;
+	}
+
+	resblks = xfs_link_space_res(mp, target_name->len);
 	error = xfs_trans_alloc_dir(tdp, &M_RES(mp)->tr_link, sip, &resblks,
 			&tp, &nospace_error);
 	if (error)
-		goto std_return;
+		goto drop_incompat;
 
 	/*
 	 * If we are using project inheritance, we only allow hard link
@@ -1311,14 +1333,27 @@ xfs_link(
 	}
 
 	error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
-				   resblks, NULL);
+				   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);
 
 	xfs_bumplink(tp, sip);
 
+	/*
+	 * 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
+	 * attribute, we need to create it correctly, otherwise we can just add
+	 * the parent to the inode.
+	 */
+	if (parent) {
+		error = xfs_parent_defer_add(tp, parent, tdp, target_name,
+					     diroffset, sip);
+		if (error)
+			goto out_defer_cancel;
+	}
+
 	/*
 	 * If this is a synchronous mount, make sure that the
 	 * link transaction goes to disk before returning to
@@ -1332,11 +1367,16 @@ xfs_link(
 	xfs_iunlock(sip, XFS_ILOCK_EXCL);
 	return error;
 
- error_return:
+out_defer_cancel:
+	xfs_defer_cancel(tp);
+error_return:
 	xfs_trans_cancel(tp);
 	xfs_iunlock(tdp, XFS_ILOCK_EXCL);
 	xfs_iunlock(sip, XFS_ILOCK_EXCL);
- std_return:
+drop_incompat:
+	if (parent)
+		xfs_parent_cancel(mp, parent);
+std_return:
 	if (error == -ENOSPC && nospace_error)
 		error = nospace_error;
 	return error;
-- 
2.25.1


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

* [PATCH v4 17/27] xfs: add parent attributes to symlink
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (15 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 16/27] xfs: add parent attributes to link allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-25 21:06   ` Darrick J. Wong
  2022-10-21 22:29 ` [PATCH v4 18/27] xfs: remove parent pointers in unlink allison.henderson
                   ` (9 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

This patch modifies xfs_symlink to add a parent pointer to the inode.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/xfs_symlink.c | 50 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 45 insertions(+), 5 deletions(-)

diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
index 27a7d7c57015..968ca257cd82 100644
--- a/fs/xfs/xfs_symlink.c
+++ b/fs/xfs/xfs_symlink.c
@@ -23,6 +23,8 @@
 #include "xfs_trans.h"
 #include "xfs_ialloc.h"
 #include "xfs_error.h"
+#include "xfs_parent.h"
+#include "xfs_defer.h"
 
 /* ----- Kernel only functions below ----- */
 int
@@ -142,6 +144,23 @@ xfs_readlink(
 	return error;
 }
 
+unsigned int
+xfs_symlink_space_res(
+	struct xfs_mount	*mp,
+	unsigned int		namelen,
+	unsigned int		fsblocks)
+{
+	unsigned int		ret;
+
+	ret = XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp, namelen) +
+	      fsblocks;
+
+	if (xfs_has_parent(mp))
+		ret += xfs_pptr_calc_space_res(mp, namelen);
+
+	return ret;
+}
+
 int
 xfs_symlink(
 	struct user_namespace	*mnt_userns,
@@ -172,6 +191,8 @@ xfs_symlink(
 	struct xfs_dquot	*pdqp = NULL;
 	uint			resblks;
 	xfs_ino_t		ino;
+	xfs_dir2_dataptr_t      diroffset;
+	struct xfs_parent_defer *parent = NULL;
 
 	*ipp = NULL;
 
@@ -179,10 +200,10 @@ xfs_symlink(
 
 	if (xfs_is_shutdown(mp))
 		return -EIO;
-
 	/*
 	 * Check component lengths of the target path name.
 	 */
+
 	pathlen = strlen(target_path);
 	if (pathlen >= XFS_SYMLINK_MAXLEN)      /* total string too long */
 		return -ENAMETOOLONG;
@@ -204,11 +225,17 @@ xfs_symlink(
 	 * The symlink will fit into the inode data fork?
 	 * There can't be any attributes so we get the whole variable part.
 	 */
-	if (pathlen <= XFS_LITINO(mp))
+	if (pathlen <= XFS_LITINO(mp) && !xfs_has_parent(mp))
 		fs_blocks = 0;
 	else
 		fs_blocks = xfs_symlink_blocks(mp, pathlen);
-	resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks);
+	resblks = xfs_symlink_space_res(mp, link_name->len, fs_blocks);
+
+	if (xfs_has_parent(mp)) {
+		error = xfs_parent_init(mp, &parent);
+		if (error)
+			return error;
+	}
 
 	error = xfs_trans_alloc_icreate(mp, &M_RES(mp)->tr_symlink, udqp, gdqp,
 			pdqp, resblks, &tp);
@@ -233,7 +260,7 @@ xfs_symlink(
 	if (!error)
 		error = xfs_init_new_inode(mnt_userns, tp, dp, ino,
 				S_IFLNK | (mode & ~S_IFMT), 1, 0, prid,
-				false, &ip);
+				xfs_has_parent(mp), &ip);
 	if (error)
 		goto out_trans_cancel;
 
@@ -315,12 +342,20 @@ xfs_symlink(
 	 * Create the directory entry for the symlink.
 	 */
 	error = xfs_dir_createname(tp, dp, link_name,
-			ip->i_ino, resblks, NULL);
+			ip->i_ino, resblks, &diroffset);
 	if (error)
 		goto out_trans_cancel;
 	xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 	xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
 
+	if (parent) {
+		error = xfs_parent_defer_add(tp, parent, dp, link_name,
+					     diroffset, ip);
+		if (error)
+			goto out_trans_cancel;
+	}
+
+
 	/*
 	 * If this is a synchronous mount, make sure that the
 	 * symlink transaction goes to disk before returning to
@@ -344,6 +379,8 @@ xfs_symlink(
 out_trans_cancel:
 	xfs_trans_cancel(tp);
 out_release_inode:
+	xfs_defer_cancel(tp);
+
 	/*
 	 * Wait until after the current transaction is aborted to finish the
 	 * setup of the inode and release the inode.  This prevents recursive
@@ -362,6 +399,9 @@ xfs_symlink(
 		xfs_iunlock(dp, XFS_ILOCK_EXCL);
 	if (ip)
 		xfs_iunlock(ip, XFS_ILOCK_EXCL);
+	if (parent)
+		xfs_parent_cancel(mp, parent);
+
 	return error;
 }
 
-- 
2.25.1


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

* [PATCH v4 18/27] xfs: remove parent pointers in unlink
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (16 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 17/27] xfs: add parent attributes to symlink allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-25 21:14   ` Darrick J. Wong
  2022-10-21 22:29 ` [PATCH v4 19/27] xfs: Add parent pointers to xfs_cross_rename allison.henderson
                   ` (8 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

This patch removes the parent pointer attribute during unlink

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_attr.h   |  1 +
 fs/xfs/libxfs/xfs_parent.c | 17 +++++++++++++++
 fs/xfs/libxfs/xfs_parent.h |  4 ++++
 fs/xfs/xfs_inode.c         | 44 ++++++++++++++++++++++++++++++++------
 5 files changed, 60 insertions(+), 8 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 805aaa5639d2..e967728d1ee7 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -946,7 +946,7 @@ xfs_attr_defer_replace(
 }
 
 /* Removes an attribute for an inode as a deferred operation */
-static int
+int
 xfs_attr_defer_remove(
 	struct xfs_da_args	*args)
 {
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 0cf23f5117ad..033005542b9e 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -545,6 +545,7 @@ bool xfs_attr_is_leaf(struct xfs_inode *ip);
 int xfs_attr_get_ilocked(struct xfs_da_args *args);
 int xfs_attr_get(struct xfs_da_args *args);
 int xfs_attr_defer_add(struct xfs_da_args *args);
+int xfs_attr_defer_remove(struct xfs_da_args *args);
 int xfs_attr_set(struct xfs_da_args *args);
 int xfs_attr_set_iter(struct xfs_attr_intent *attr);
 int xfs_attr_remove_iter(struct xfs_attr_intent *attr);
diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
index cf5ea8ce8bd3..c09f49b7c241 100644
--- a/fs/xfs/libxfs/xfs_parent.c
+++ b/fs/xfs/libxfs/xfs_parent.c
@@ -125,6 +125,23 @@ xfs_parent_defer_add(
 	return xfs_attr_defer_add(args);
 }
 
+int
+xfs_parent_defer_remove(
+	struct xfs_trans	*tp,
+	struct xfs_inode	*dp,
+	struct xfs_parent_defer	*parent,
+	xfs_dir2_dataptr_t	diroffset,
+	struct xfs_inode	*child)
+{
+	struct xfs_da_args	*args = &parent->args;
+
+	xfs_init_parent_name_rec(&parent->rec, dp, diroffset);
+	args->trans = tp;
+	args->dp = child;
+	args->hashval = xfs_da_hashname(args->name, args->namelen);
+	return xfs_attr_defer_remove(args);
+}
+
 void
 xfs_parent_cancel(
 	xfs_mount_t		*mp,
diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h
index 9b8d0764aad6..1c506532c624 100644
--- a/fs/xfs/libxfs/xfs_parent.h
+++ b/fs/xfs/libxfs/xfs_parent.h
@@ -27,6 +27,10 @@ int xfs_parent_init(xfs_mount_t *mp, struct xfs_parent_defer **parentp);
 int xfs_parent_defer_add(struct xfs_trans *tp, struct xfs_parent_defer *parent,
 			 struct xfs_inode *dp, struct xfs_name *parent_name,
 			 xfs_dir2_dataptr_t diroffset, struct xfs_inode *child);
+int xfs_parent_defer_remove(struct xfs_trans *tp, struct xfs_inode *dp,
+			    struct xfs_parent_defer *parent,
+			    xfs_dir2_dataptr_t diroffset,
+			    struct xfs_inode *child);
 void xfs_parent_cancel(xfs_mount_t *mp, struct xfs_parent_defer *parent);
 unsigned int xfs_pptr_calc_space_res(struct xfs_mount *mp,
 				     unsigned int namelen);
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index f2e7da1befa4..83cc52c2bcf1 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2472,6 +2472,19 @@ xfs_iunpin_wait(
 		__xfs_iunpin_wait(ip);
 }
 
+unsigned int
+xfs_remove_space_res(
+	struct xfs_mount	*mp,
+	unsigned int		namelen)
+{
+	unsigned int		ret = XFS_DIRREMOVE_SPACE_RES(mp);
+
+	if (xfs_has_parent(mp))
+		ret += xfs_pptr_calc_space_res(mp, namelen);
+
+	return ret;
+}
+
 /*
  * Removing an inode from the namespace involves removing the directory entry
  * and dropping the link count on the inode. Removing the directory entry can
@@ -2501,16 +2514,18 @@ xfs_iunpin_wait(
  */
 int
 xfs_remove(
-	xfs_inode_t             *dp,
+	struct xfs_inode	*dp,
 	struct xfs_name		*name,
-	xfs_inode_t		*ip)
+	struct xfs_inode	*ip)
 {
-	xfs_mount_t		*mp = dp->i_mount;
-	xfs_trans_t             *tp = NULL;
+	struct xfs_mount	*mp = dp->i_mount;
+	struct xfs_trans	*tp = NULL;
 	int			is_dir = S_ISDIR(VFS_I(ip)->i_mode);
 	int			dontcare;
 	int                     error = 0;
 	uint			resblks;
+	xfs_dir2_dataptr_t	dir_offset;
+	struct xfs_parent_defer	*parent = NULL;
 
 	trace_xfs_remove(dp, name);
 
@@ -2525,6 +2540,12 @@ xfs_remove(
 	if (error)
 		goto std_return;
 
+	if (xfs_has_parent(mp)) {
+		error = xfs_parent_init(mp, &parent);
+		if (error)
+			goto std_return;
+	}
+
 	/*
 	 * We try to get the real space reservation first, allowing for
 	 * directory btree deletion(s) implying possible bmap insert(s).  If we
@@ -2536,12 +2557,12 @@ xfs_remove(
 	 * the directory code can handle a reservationless update and we don't
 	 * want to prevent a user from trying to free space by deleting things.
 	 */
-	resblks = XFS_REMOVE_SPACE_RES(mp);
+	resblks = xfs_remove_space_res(mp, name->len);
 	error = xfs_trans_alloc_dir(dp, &M_RES(mp)->tr_remove, ip, &resblks,
 			&tp, &dontcare);
 	if (error) {
 		ASSERT(error != -ENOSPC);
-		goto std_return;
+		goto drop_incompat;
 	}
 
 	/*
@@ -2595,12 +2616,18 @@ xfs_remove(
 	if (error)
 		goto out_trans_cancel;
 
-	error = xfs_dir_removename(tp, dp, name, ip->i_ino, resblks, NULL);
+	error = xfs_dir_removename(tp, dp, name, ip->i_ino, resblks, &dir_offset);
 	if (error) {
 		ASSERT(error != -ENOENT);
 		goto out_trans_cancel;
 	}
 
+	if (parent) {
+		error = xfs_parent_defer_remove(tp, dp, parent, dir_offset, ip);
+		if (error)
+			goto out_trans_cancel;
+	}
+
 	/*
 	 * If this is a synchronous mount, make sure that the
 	 * remove transaction goes to disk before returning to
@@ -2625,6 +2652,9 @@ xfs_remove(
  out_unlock:
 	xfs_iunlock(ip, XFS_ILOCK_EXCL);
 	xfs_iunlock(dp, XFS_ILOCK_EXCL);
+ drop_incompat:
+	if (parent)
+		xfs_parent_cancel(mp, parent);
  std_return:
 	return error;
 }
-- 
2.25.1


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

* [PATCH v4 19/27] xfs: Add parent pointers to xfs_cross_rename
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (17 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 18/27] xfs: remove parent pointers in unlink allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-25 21:32   ` Darrick J. Wong
  2022-10-21 22:29 ` [PATCH v4 20/27] xfs: Indent xfs_rename allison.henderson
                   ` (7 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

Cross renames are handled separately from standard renames, and
need different handling to update the parent attributes correctly.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/xfs_inode.c | 79 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 63 insertions(+), 16 deletions(-)

diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 83cc52c2bcf1..c79d1047d118 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2746,27 +2746,49 @@ xfs_finish_rename(
  */
 STATIC int
 xfs_cross_rename(
-	struct xfs_trans	*tp,
-	struct xfs_inode	*dp1,
-	struct xfs_name		*name1,
-	struct xfs_inode	*ip1,
-	struct xfs_inode	*dp2,
-	struct xfs_name		*name2,
-	struct xfs_inode	*ip2,
-	int			spaceres)
-{
-	int		error = 0;
-	int		ip1_flags = 0;
-	int		ip2_flags = 0;
-	int		dp2_flags = 0;
+	struct xfs_trans		*tp,
+	struct xfs_inode		*dp1,
+	struct xfs_name			*name1,
+	struct xfs_inode		*ip1,
+	struct xfs_inode		*dp2,
+	struct xfs_name			*name2,
+	struct xfs_inode		*ip2,
+	int				spaceres)
+{
+	struct xfs_mount		*mp = dp1->i_mount;
+	int				error = 0;
+	int				ip1_flags = 0;
+	int				ip2_flags = 0;
+	int				dp2_flags = 0;
+	int				new_diroffset, old_diroffset;
+	struct xfs_parent_defer		*old_parent_ptr = NULL;
+	struct xfs_parent_defer		*new_parent_ptr = NULL;
+	struct xfs_parent_defer		*old_parent_ptr2 = NULL;
+	struct xfs_parent_defer		*new_parent_ptr2 = NULL;
+
+
+	if (xfs_has_parent(mp)) {
+		error = xfs_parent_init(mp, &old_parent_ptr);
+		if (error)
+			goto out_trans_abort;
+		error = xfs_parent_init(mp, &new_parent_ptr);
+		if (error)
+			goto out_trans_abort;
+		error = xfs_parent_init(mp, &old_parent_ptr2);
+		if (error)
+			goto out_trans_abort;
+		error = xfs_parent_init(mp, &new_parent_ptr2);
+		if (error)
+			goto out_trans_abort;
+	}
 
 	/* Swap inode number for dirent in first parent */
-	error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, spaceres, NULL);
+	error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, spaceres, &old_diroffset);
 	if (error)
 		goto out_trans_abort;
 
 	/* Swap inode number for dirent in second parent */
-	error = xfs_dir_replace(tp, dp2, name2, ip1->i_ino, spaceres, NULL);
+	error = xfs_dir_replace(tp, dp2, name2, ip1->i_ino, spaceres, &new_diroffset);
 	if (error)
 		goto out_trans_abort;
 
@@ -2827,6 +2849,20 @@ xfs_cross_rename(
 		}
 	}
 
+	if (xfs_has_parent(mp)) {
+		error = xfs_parent_defer_replace(tp, dp1,
+				old_parent_ptr, old_diroffset, name2, dp2,
+				new_parent_ptr, new_diroffset, ip1);
+		if (error)
+			goto out_trans_abort;
+
+		error = xfs_parent_defer_replace(tp, dp2, new_parent_ptr2,
+				new_diroffset, name1, dp1, old_parent_ptr2,
+				old_diroffset, ip2);
+		if (error)
+			goto out_trans_abort;
+	}
+
 	if (ip1_flags) {
 		xfs_trans_ichgtime(tp, ip1, ip1_flags);
 		xfs_trans_log_inode(tp, ip1, XFS_ILOG_CORE);
@@ -2841,10 +2877,21 @@ xfs_cross_rename(
 	}
 	xfs_trans_ichgtime(tp, dp1, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 	xfs_trans_log_inode(tp, dp1, XFS_ILOG_CORE);
-	return xfs_finish_rename(tp);
 
+	error = xfs_finish_rename(tp);
+	goto out;
 out_trans_abort:
 	xfs_trans_cancel(tp);
+out:
+	if (new_parent_ptr)
+		xfs_parent_cancel(mp, new_parent_ptr);
+	if (old_parent_ptr)
+		xfs_parent_cancel(mp, old_parent_ptr);
+	if (new_parent_ptr2)
+		xfs_parent_cancel(mp, new_parent_ptr2);
+	if (old_parent_ptr2)
+		xfs_parent_cancel(mp, old_parent_ptr2);
+
 	return error;
 }
 
-- 
2.25.1


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

* [PATCH v4 20/27] xfs: Indent xfs_rename
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (18 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 19/27] xfs: Add parent pointers to xfs_cross_rename allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-21 22:29 ` [PATCH v4 21/27] xfs: Add parent pointers to rename allison.henderson
                   ` (6 subsequent siblings)
  26 siblings, 0 replies; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

Indent variables and parameters in xfs_rename in preparation for
parent pointer modifications.  White space only, no functional
changes.  This will make reviewing new code easier on reviewers.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/xfs_inode.c | 41 +++++++++++++++++++++--------------------
 1 file changed, 21 insertions(+), 20 deletions(-)

diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index c79d1047d118..b6b805ea30e5 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2946,26 +2946,27 @@ xfs_rename_alloc_whiteout(
  */
 int
 xfs_rename(
-	struct user_namespace	*mnt_userns,
-	struct xfs_inode	*src_dp,
-	struct xfs_name		*src_name,
-	struct xfs_inode	*src_ip,
-	struct xfs_inode	*target_dp,
-	struct xfs_name		*target_name,
-	struct xfs_inode	*target_ip,
-	unsigned int		flags)
-{
-	struct xfs_mount	*mp = src_dp->i_mount;
-	struct xfs_trans	*tp;
-	struct xfs_inode	*wip = NULL;		/* whiteout inode */
-	struct xfs_inode	*inodes[__XFS_SORT_INODES];
-	int			i;
-	int			num_inodes = __XFS_SORT_INODES;
-	bool			new_parent = (src_dp != target_dp);
-	bool			src_is_directory = S_ISDIR(VFS_I(src_ip)->i_mode);
-	int			spaceres;
-	bool			retried = false;
-	int			error, nospace_error = 0;
+	struct user_namespace		*mnt_userns,
+	struct xfs_inode		*src_dp,
+	struct xfs_name			*src_name,
+	struct xfs_inode		*src_ip,
+	struct xfs_inode		*target_dp,
+	struct xfs_name			*target_name,
+	struct xfs_inode		*target_ip,
+	unsigned int			flags)
+{
+	struct xfs_mount		*mp = src_dp->i_mount;
+	struct xfs_trans		*tp;
+	struct xfs_inode		*wip = NULL;	/* whiteout inode */
+	struct xfs_inode		*inodes[__XFS_SORT_INODES];
+	int				i;
+	int				num_inodes = __XFS_SORT_INODES;
+	bool				new_parent = (src_dp != target_dp);
+	bool				src_is_directory =
+						S_ISDIR(VFS_I(src_ip)->i_mode);
+	int				spaceres;
+	bool				retried = false;
+	int				error, nospace_error = 0;
 
 	trace_xfs_rename(src_dp, target_dp, src_name, target_name);
 
-- 
2.25.1


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

* [PATCH v4 21/27] xfs: Add parent pointers to rename
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (19 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 20/27] xfs: Indent xfs_rename allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-25 21:28   ` Darrick J. Wong
  2022-10-21 22:29 ` [PATCH v4 22/27] xfs: Add the parent pointer support to the superblock version 5 allison.henderson
                   ` (5 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

This patch removes the old parent pointer attribute during the rename
operation, and re-adds the updated parent pointer.  In the case of
xfs_cross_rename, we modify the routine not to roll the transaction just
yet.  We will do this after the parent pointer is added in the calling
xfs_rename function.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c   |  2 +-
 fs/xfs/libxfs/xfs_attr.h   |  1 +
 fs/xfs/libxfs/xfs_parent.c | 31 ++++++++++++
 fs/xfs/libxfs/xfs_parent.h |  7 +++
 fs/xfs/xfs_inode.c         | 96 +++++++++++++++++++++++++++++++++++---
 5 files changed, 130 insertions(+), 7 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index e967728d1ee7..3f9bd8401f33 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -923,7 +923,7 @@ xfs_attr_defer_add(
 }
 
 /* Sets an attribute for an inode as a deferred operation */
-static int
+int
 xfs_attr_defer_replace(
 	struct xfs_da_args	*args)
 {
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 033005542b9e..985761264d1f 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -546,6 +546,7 @@ int xfs_attr_get_ilocked(struct xfs_da_args *args);
 int xfs_attr_get(struct xfs_da_args *args);
 int xfs_attr_defer_add(struct xfs_da_args *args);
 int xfs_attr_defer_remove(struct xfs_da_args *args);
+int xfs_attr_defer_replace(struct xfs_da_args *args);
 int xfs_attr_set(struct xfs_da_args *args);
 int xfs_attr_set_iter(struct xfs_attr_intent *attr);
 int xfs_attr_remove_iter(struct xfs_attr_intent *attr);
diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
index c09f49b7c241..49ac95a301c4 100644
--- a/fs/xfs/libxfs/xfs_parent.c
+++ b/fs/xfs/libxfs/xfs_parent.c
@@ -142,6 +142,37 @@ xfs_parent_defer_remove(
 	return xfs_attr_defer_remove(args);
 }
 
+
+int
+xfs_parent_defer_replace(
+	struct xfs_trans	*tp,
+	struct xfs_inode	*old_ip,
+	struct xfs_parent_defer	*old_parent,
+	xfs_dir2_dataptr_t	old_diroffset,
+	struct xfs_name		*parent_name,
+	struct xfs_inode	*new_ip,
+	struct xfs_parent_defer	*new_parent,
+	xfs_dir2_dataptr_t	new_diroffset,
+	struct xfs_inode	*child)
+{
+	struct xfs_da_args	*args = &new_parent->args;
+
+	xfs_init_parent_name_rec(&old_parent->rec, old_ip, old_diroffset);
+	xfs_init_parent_name_rec(&new_parent->rec, new_ip, new_diroffset);
+	new_parent->args.name = (const uint8_t *)&old_parent->rec;
+	new_parent->args.namelen = sizeof(struct xfs_parent_name_rec);
+	new_parent->args.new_name = (const uint8_t *)&new_parent->rec;
+	new_parent->args.new_namelen = sizeof(struct xfs_parent_name_rec);
+	args->trans = tp;
+	args->dp = child;
+	if (parent_name) {
+		new_parent->args.value = (void *)parent_name->name;
+		new_parent->args.valuelen = parent_name->len;
+	}
+	args->hashval = xfs_da_hashname(args->name, args->namelen);
+	return xfs_attr_defer_replace(args);
+}
+
 void
 xfs_parent_cancel(
 	xfs_mount_t		*mp,
diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h
index 1c506532c624..5d8966a12084 100644
--- a/fs/xfs/libxfs/xfs_parent.h
+++ b/fs/xfs/libxfs/xfs_parent.h
@@ -27,6 +27,13 @@ int xfs_parent_init(xfs_mount_t *mp, struct xfs_parent_defer **parentp);
 int xfs_parent_defer_add(struct xfs_trans *tp, struct xfs_parent_defer *parent,
 			 struct xfs_inode *dp, struct xfs_name *parent_name,
 			 xfs_dir2_dataptr_t diroffset, struct xfs_inode *child);
+int xfs_parent_defer_replace(struct xfs_trans *tp, struct xfs_inode *old_ip,
+			 struct xfs_parent_defer *old_parent,
+			 xfs_dir2_dataptr_t old_diroffset,
+			 struct xfs_name *parent_name, struct xfs_inode *new_ip,
+			 struct xfs_parent_defer *new_parent,
+			 xfs_dir2_dataptr_t new_diroffset,
+			 struct xfs_inode *child);
 int xfs_parent_defer_remove(struct xfs_trans *tp, struct xfs_inode *dp,
 			    struct xfs_parent_defer *parent,
 			    xfs_dir2_dataptr_t diroffset,
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index b6b805ea30e5..a882daaeaf63 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2915,7 +2915,7 @@ xfs_rename_alloc_whiteout(
 	int			error;
 
 	error = xfs_create_tmpfile(mnt_userns, dp, S_IFCHR | WHITEOUT_MODE,
-				   false, &tmpfile);
+				   xfs_has_parent(dp->i_mount), &tmpfile);
 	if (error)
 		return error;
 
@@ -2941,6 +2941,31 @@ xfs_rename_alloc_whiteout(
 	return 0;
 }
 
+unsigned int
+xfs_rename_space_res(
+	struct xfs_mount	*mp,
+	struct xfs_name		*src_name,
+	struct xfs_parent_defer	*target_parent_ptr,
+	struct xfs_name		*target_name,
+	struct xfs_parent_defer	*new_parent_ptr,
+	struct xfs_inode	*wip)
+{
+	unsigned int		ret;
+
+	ret = XFS_DIRREMOVE_SPACE_RES(mp) +
+			XFS_DIRENTER_SPACE_RES(mp, target_name->len);
+
+	if (new_parent_ptr) {
+		if (wip)
+			ret += xfs_pptr_calc_space_res(mp, src_name->len);
+		ret += 2 * xfs_pptr_calc_space_res(mp, target_name->len);
+	}
+	if (target_parent_ptr)
+		ret += xfs_pptr_calc_space_res(mp, target_name->len);
+
+	return ret;
+}
+
 /*
  * xfs_rename
  */
@@ -2967,6 +2992,12 @@ xfs_rename(
 	int				spaceres;
 	bool				retried = false;
 	int				error, nospace_error = 0;
+	xfs_dir2_dataptr_t		new_diroffset;
+	xfs_dir2_dataptr_t		old_diroffset;
+	struct xfs_parent_defer		*old_parent_ptr = NULL;
+	struct xfs_parent_defer		*new_parent_ptr = NULL;
+	struct xfs_parent_defer		*target_parent_ptr = NULL;
+	struct xfs_parent_defer		*wip_parent_ptr = NULL;
 
 	trace_xfs_rename(src_dp, target_dp, src_name, target_name);
 
@@ -2990,10 +3021,29 @@ xfs_rename(
 
 	xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip, wip,
 				inodes, &num_inodes);
+	if (xfs_has_parent(mp)) {
+		error = xfs_parent_init(mp, &old_parent_ptr);
+		if (error)
+			goto out_release_wip;
+		error = xfs_parent_init(mp, &new_parent_ptr);
+		if (error)
+			goto out_release_wip;
+		if (wip) {
+			error = xfs_parent_init(mp, &wip_parent_ptr);
+			if (error)
+				goto out_release_wip;
+		}
+		if (target_ip != NULL) {
+			error = xfs_parent_init(mp, &target_parent_ptr);
+			if (error)
+				goto out_release_wip;
+		}
+	}
 
 retry:
 	nospace_error = 0;
-	spaceres = XFS_RENAME_SPACE_RES(mp, target_name->len);
+	spaceres = xfs_rename_space_res(mp, src_name, target_parent_ptr,
+			target_name, new_parent_ptr, wip);
 	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_rename, spaceres, 0, 0, &tp);
 	if (error == -ENOSPC) {
 		nospace_error = error;
@@ -3165,7 +3215,7 @@ xfs_rename(
 		 * to account for the ".." reference from the new entry.
 		 */
 		error = xfs_dir_createname(tp, target_dp, target_name,
-					   src_ip->i_ino, spaceres, NULL);
+					   src_ip->i_ino, spaceres, &new_diroffset);
 		if (error)
 			goto out_trans_cancel;
 
@@ -3186,7 +3236,7 @@ xfs_rename(
 		 * name at the destination directory, remove it first.
 		 */
 		error = xfs_dir_replace(tp, target_dp, target_name,
-					src_ip->i_ino, spaceres, NULL);
+					src_ip->i_ino, spaceres, &new_diroffset);
 		if (error)
 			goto out_trans_cancel;
 
@@ -3259,14 +3309,39 @@ xfs_rename(
 	 */
 	if (wip)
 		error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino,
-					spaceres, NULL);
+					spaceres, &old_diroffset);
 	else
 		error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
-					   spaceres, NULL);
+					   spaceres, &old_diroffset);
 
 	if (error)
 		goto out_trans_cancel;
 
+	if (new_parent_ptr) {
+		if (wip) {
+			error = xfs_parent_defer_add(tp, wip_parent_ptr,
+						     src_dp, src_name,
+						     old_diroffset, wip);
+			if (error)
+				goto out_trans_cancel;
+		}
+
+		error = xfs_parent_defer_replace(tp, src_dp, old_parent_ptr,
+						 old_diroffset, target_name,
+						 target_dp, new_parent_ptr,
+						 new_diroffset, src_ip);
+		if (error)
+			goto out_trans_cancel;
+	}
+
+	if (target_parent_ptr) {
+		error = xfs_parent_defer_remove(tp, target_dp,
+						target_parent_ptr,
+						new_diroffset, target_ip);
+		if (error)
+			goto out_trans_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)
@@ -3281,6 +3356,15 @@ xfs_rename(
 out_unlock:
 	xfs_iunlock_after_rename(inodes, num_inodes);
 out_release_wip:
+	if (new_parent_ptr)
+		xfs_parent_cancel(mp, new_parent_ptr);
+	if (old_parent_ptr)
+		xfs_parent_cancel(mp, old_parent_ptr);
+	if (target_parent_ptr)
+		xfs_parent_cancel(mp, target_parent_ptr);
+	if (wip_parent_ptr)
+		xfs_parent_cancel(mp, wip_parent_ptr);
+
 	if (wip)
 		xfs_irele(wip);
 	if (error == -ENOSPC && nospace_error)
-- 
2.25.1


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

* [PATCH v4 22/27] xfs: Add the parent pointer support to the  superblock version 5.
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (20 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 21/27] xfs: Add parent pointers to rename allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-21 22:29 ` [PATCH v4 23/27] xfs: Add helper function xfs_attr_list_context_init allison.henderson
                   ` (4 subsequent siblings)
  26 siblings, 0 replies; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

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>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/libxfs/xfs_format.h | 4 +++-
 fs/xfs/libxfs/xfs_fs.h     | 1 +
 fs/xfs/libxfs/xfs_sb.c     | 4 ++++
 fs/xfs/xfs_super.c         | 4 ++++
 4 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index b55bdfa9c8a8..0343f8586be3 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -373,13 +373,15 @@ xfs_sb_has_ro_compat_feature(
 #define XFS_SB_FEAT_INCOMPAT_BIGTIME	(1 << 3)	/* large timestamps */
 #define XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR (1 << 4)	/* needs xfs_repair */
 #define XFS_SB_FEAT_INCOMPAT_NREXT64	(1 << 5)	/* large extent counters */
+#define XFS_SB_FEAT_INCOMPAT_PARENT	(1 << 6)	/* parent pointers */
 #define XFS_SB_FEAT_INCOMPAT_ALL \
 		(XFS_SB_FEAT_INCOMPAT_FTYPE|	\
 		 XFS_SB_FEAT_INCOMPAT_SPINODES|	\
 		 XFS_SB_FEAT_INCOMPAT_META_UUID| \
 		 XFS_SB_FEAT_INCOMPAT_BIGTIME| \
 		 XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR| \
-		 XFS_SB_FEAT_INCOMPAT_NREXT64)
+		 XFS_SB_FEAT_INCOMPAT_NREXT64| \
+		 XFS_SB_FEAT_INCOMPAT_PARENT)
 
 #define XFS_SB_FEAT_INCOMPAT_UNKNOWN	~XFS_SB_FEAT_INCOMPAT_ALL
 static inline bool
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index 1cfd5bc6520a..b0b4d7a3aa15 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -237,6 +237,7 @@ typedef struct xfs_fsop_resblks {
 #define XFS_FSOP_GEOM_FLAGS_BIGTIME	(1 << 21) /* 64-bit nsec timestamps */
 #define XFS_FSOP_GEOM_FLAGS_INOBTCNT	(1 << 22) /* inobt btree counter */
 #define XFS_FSOP_GEOM_FLAGS_NREXT64	(1 << 23) /* large extent counters */
+#define XFS_FSOP_GEOM_FLAGS_PARENT	(1 << 24) /* parent pointers 	    */
 
 /*
  * Minimum and maximum sizes need for growth checks.
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index a20cade590e9..75e893e93629 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -173,6 +173,8 @@ xfs_sb_version_to_features(
 		features |= XFS_FEAT_NEEDSREPAIR;
 	if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_NREXT64)
 		features |= XFS_FEAT_NREXT64;
+	if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_PARENT)
+		features |= XFS_FEAT_PARENT;
 
 	return features;
 }
@@ -1187,6 +1189,8 @@ xfs_fs_geometry(
 		geo->flags |= XFS_FSOP_GEOM_FLAGS_BIGTIME;
 	if (xfs_has_inobtcounts(mp))
 		geo->flags |= XFS_FSOP_GEOM_FLAGS_INOBTCNT;
+	if (xfs_has_parent(mp))
+		geo->flags |= XFS_FSOP_GEOM_FLAGS_PARENT;
 	if (xfs_has_sector(mp)) {
 		geo->flags |= XFS_FSOP_GEOM_FLAGS_SECTOR;
 		geo->logsectsize = sbp->sb_logsectsize;
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index f029c6702dda..0305698cd5b0 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1663,6 +1663,10 @@ xfs_fs_fill_super(
 		xfs_warn(mp,
 	"EXPERIMENTAL Large extent counts feature in use. Use at your own risk!");
 
+	if (xfs_has_parent(mp))
+		xfs_alert(mp,
+	"EXPERIMENTAL parent pointer feature enabled. Use at your own risk!");
+
 	error = xfs_mountfs(mp);
 	if (error)
 		goto out_filestream_unmount;
-- 
2.25.1


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

* [PATCH v4 23/27] xfs: Add helper function xfs_attr_list_context_init
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (21 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 22/27] xfs: Add the parent pointer support to the superblock version 5 allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-21 22:29 ` [PATCH v4 24/27] xfs: Filter XFS_ATTR_PARENT for getfattr allison.henderson
                   ` (3 subsequent siblings)
  26 siblings, 0 replies; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

This patch adds a helper function xfs_attr_list_context_init used by
xfs_attr_list. This function initializes the xfs_attr_list_context
structure passed to xfs_attr_list_int. We will need this later to call
xfs_attr_list_int_ilocked when the node is already locked.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/xfs_file.c  |  1 +
 fs/xfs/xfs_ioctl.c | 54 ++++++++++++++++++++++++++++++++--------------
 fs/xfs/xfs_ioctl.h |  2 ++
 3 files changed, 41 insertions(+), 16 deletions(-)

diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index c6c80265c0b2..cb456fd92b72 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -17,6 +17,7 @@
 #include "xfs_bmap_util.h"
 #include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
+#include "xfs_attr.h"
 #include "xfs_ioctl.h"
 #include "xfs_trace.h"
 #include "xfs_log.h"
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 1f783e979629..5b600d3f7981 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -369,6 +369,40 @@ xfs_attr_flags(
 	return 0;
 }
 
+/*
+ * Initializes an xfs_attr_list_context suitable for
+ * use by xfs_attr_list
+ */
+int
+xfs_ioc_attr_list_context_init(
+	struct xfs_inode		*dp,
+	char				*buffer,
+	int				bufsize,
+	int				flags,
+	struct xfs_attr_list_context	*context)
+{
+	struct xfs_attrlist		*alist;
+
+	/*
+	 * Initialize the output buffer.
+	 */
+	context->dp = dp;
+	context->resynch = 1;
+	context->attr_filter = xfs_attr_filter(flags);
+	context->buffer = buffer;
+	context->bufsize = round_down(bufsize, sizeof(uint32_t));
+	context->firstu = context->bufsize;
+	context->put_listent = xfs_ioc_attr_put_listent;
+
+	alist = context->buffer;
+	alist->al_count = 0;
+	alist->al_more = 0;
+	alist->al_offset[0] = context->bufsize;
+
+	return 0;
+}
+
+
 int
 xfs_ioc_attr_list(
 	struct xfs_inode		*dp,
@@ -378,7 +412,6 @@ xfs_ioc_attr_list(
 	struct xfs_attrlist_cursor __user *ucursor)
 {
 	struct xfs_attr_list_context	context = { };
-	struct xfs_attrlist		*alist;
 	void				*buffer;
 	int				error;
 
@@ -410,21 +443,10 @@ xfs_ioc_attr_list(
 	if (!buffer)
 		return -ENOMEM;
 
-	/*
-	 * Initialize the output buffer.
-	 */
-	context.dp = dp;
-	context.resynch = 1;
-	context.attr_filter = xfs_attr_filter(flags);
-	context.buffer = buffer;
-	context.bufsize = round_down(bufsize, sizeof(uint32_t));
-	context.firstu = context.bufsize;
-	context.put_listent = xfs_ioc_attr_put_listent;
-
-	alist = context.buffer;
-	alist->al_count = 0;
-	alist->al_more = 0;
-	alist->al_offset[0] = context.bufsize;
+	error = xfs_ioc_attr_list_context_init(dp, buffer, bufsize, flags,
+			&context);
+	if (error)
+		return error;
 
 	error = xfs_attr_list(&context);
 	if (error)
diff --git a/fs/xfs/xfs_ioctl.h b/fs/xfs/xfs_ioctl.h
index d4abba2c13c1..ca60e1c427a3 100644
--- a/fs/xfs/xfs_ioctl.h
+++ b/fs/xfs/xfs_ioctl.h
@@ -35,6 +35,8 @@ int xfs_ioc_attrmulti_one(struct file *parfilp, struct inode *inode,
 int xfs_ioc_attr_list(struct xfs_inode *dp, void __user *ubuf,
 		      size_t bufsize, int flags,
 		      struct xfs_attrlist_cursor __user *ucursor);
+int xfs_ioc_attr_list_context_init(struct xfs_inode *dp, char *buffer,
+		int bufsize, int flags, struct xfs_attr_list_context *context);
 
 extern struct dentry *
 xfs_handle_to_dentry(
-- 
2.25.1


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

* [PATCH v4 24/27] xfs: Filter XFS_ATTR_PARENT for getfattr
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (22 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 23/27] xfs: Add helper function xfs_attr_list_context_init allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-25 21:34   ` Darrick J. Wong
  2022-10-21 22:29 ` [PATCH v4 25/27] xfs: Add parent pointer ioctl allison.henderson
                   ` (2 subsequent siblings)
  26 siblings, 1 reply; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

Parent pointers returned to the get_fattr tool cause errors since
the tool cannot parse parent pointers.  Fix this by filtering parent
parent pointers from xfs_xattr_put_listent.

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

diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index d9067c5f6bd6..5b57f6348d63 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -234,6 +234,9 @@ xfs_xattr_put_listent(
 
 	ASSERT(context->count >= 0);
 
+	if (flags & XFS_ATTR_PARENT)
+		return;
+
 	if (flags & XFS_ATTR_ROOT) {
 #ifdef CONFIG_XFS_POSIX_ACL
 		if (namelen == SGI_ACL_FILE_SIZE &&
-- 
2.25.1


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

* [PATCH v4 25/27] xfs: Add parent pointer ioctl
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (23 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 24/27] xfs: Filter XFS_ATTR_PARENT for getfattr allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-21 22:29 ` [PATCH v4 26/27] xfs: fix unit conversion error in xfs_log_calc_max_attrsetm_res allison.henderson
  2022-10-21 22:29 ` [PATCH v4 27/27] xfs: drop compatibility minimum log size computations for reflink allison.henderson
  26 siblings, 0 replies; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

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/Makefile            |   1 +
 fs/xfs/libxfs/xfs_fs.h     |  74 ++++++++++++++++++++++
 fs/xfs/libxfs/xfs_parent.c |  10 +++
 fs/xfs/libxfs/xfs_parent.h |   2 +
 fs/xfs/xfs_ioctl.c         |  94 +++++++++++++++++++++++++++-
 fs/xfs/xfs_ondisk.h        |   4 ++
 fs/xfs/xfs_parent_utils.c  | 124 +++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_parent_utils.h  |  11 ++++
 8 files changed, 319 insertions(+), 1 deletion(-)

diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index e2b2cf50ffcf..42d0496fdad7 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -86,6 +86,7 @@ xfs-y				+= xfs_aops.o \
 				   xfs_mount.o \
 				   xfs_mru_cache.o \
 				   xfs_pwork.o \
+				   xfs_parent_utils.o \
 				   xfs_reflink.o \
 				   xfs_stats.o \
 				   xfs_super.o \
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index b0b4d7a3aa15..9e59a1fdfb0c 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -752,6 +752,79 @@ struct xfs_scrub_metadata {
 				 XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED)
 #define XFS_SCRUB_FLAGS_ALL	(XFS_SCRUB_FLAGS_IN | XFS_SCRUB_FLAGS_OUT)
 
+#define XFS_PPTR_MAXNAMELEN				256
+
+/* return parents of the handle, not the open fd */
+#define XFS_PPTR_IFLAG_HANDLE  (1U << 0)
+
+/* target was the root directory */
+#define XFS_PPTR_OFLAG_ROOT    (1U << 1)
+
+/* Cursor is done iterating pptrs */
+#define XFS_PPTR_OFLAG_DONE    (1U << 2)
+
+ #define XFS_PPTR_FLAG_ALL     (XFS_PPTR_IFLAG_HANDLE | XFS_PPTR_OFLAG_ROOT | \
+				XFS_PPTR_OFLAG_DONE)
+
+/* Get an inode parent pointer through ioctl */
+struct xfs_parent_ptr {
+	__u64		xpp_ino;			/* Inode */
+	__u32		xpp_gen;			/* Inode generation */
+	__u32		xpp_diroffset;			/* Directory offset */
+	__u64		xpp_rsvd;			/* Reserved */
+	__u8		xpp_name[XFS_PPTR_MAXNAMELEN];	/* File name */
+};
+
+/* Iterate through an inodes parent pointers */
+struct xfs_pptr_info {
+	/* File handle, if XFS_PPTR_IFLAG_HANDLE is set */
+	struct xfs_handle		pi_handle;
+
+	/*
+	 * Structure to track progress in iterating the parent pointers.
+	 * Must be initialized to zeroes before the first ioctl call, and
+	 * not touched by callers after that.
+	 */
+	struct xfs_attrlist_cursor	pi_cursor;
+
+	/* Operational flags: XFS_PPTR_*FLAG* */
+	__u32				pi_flags;
+
+	/* Must be set to zero */
+	__u32				pi_reserved;
+
+	/* # of entries in array */
+	__u32				pi_ptrs_size;
+
+	/* # of entries filled in (output) */
+	__u32				pi_ptrs_used;
+
+	/* Must be set to zero */
+	__u64				pi_reserved2[6];
+
+	/*
+	 * An array of struct xfs_parent_ptr follows the header
+	 * information. Use xfs_ppinfo_to_pp() to access the
+	 * parent pointer array entries.
+	 */
+	struct xfs_parent_ptr		pi_parents[];
+};
+
+static inline size_t
+xfs_pptr_info_sizeof(int nr_ptrs)
+{
+	return sizeof(struct xfs_pptr_info) +
+	       (nr_ptrs * sizeof(struct xfs_parent_ptr));
+}
+
+static inline struct xfs_parent_ptr*
+xfs_ppinfo_to_pp(
+	struct xfs_pptr_info	*info,
+	int			idx)
+{
+	return &info->pi_parents[idx];
+}
+
 /*
  * ioctl limits
  */
@@ -797,6 +870,7 @@ struct xfs_scrub_metadata {
 /*	XFS_IOC_GETFSMAP ------ hoisted 59         */
 #define XFS_IOC_SCRUB_METADATA	_IOWR('X', 60, struct xfs_scrub_metadata)
 #define XFS_IOC_AG_GEOMETRY	_IOWR('X', 61, struct xfs_ag_geometry)
+#define XFS_IOC_GETPARENTS	_IOWR('X', 62, struct xfs_parent_ptr)
 
 /*
  * ioctl commands that replace IRIX syssgi()'s
diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
index 49ac95a301c4..ae883d6aaf40 100644
--- a/fs/xfs/libxfs/xfs_parent.c
+++ b/fs/xfs/libxfs/xfs_parent.c
@@ -27,6 +27,16 @@
 #include "xfs_parent.h"
 #include "xfs_trans_space.h"
 
+/* Initializes a xfs_parent_ptr from an xfs_parent_name_rec */
+void
+xfs_init_parent_ptr(struct xfs_parent_ptr		*xpp,
+		    const struct xfs_parent_name_rec	*rec)
+{
+	xpp->xpp_ino = be64_to_cpu(rec->p_ino);
+	xpp->xpp_gen = be32_to_cpu(rec->p_gen);
+	xpp->xpp_diroffset = be32_to_cpu(rec->p_diroffset);
+}
+
 /*
  * Parent pointer attribute handling.
  *
diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h
index 5d8966a12084..d03e64d74b31 100644
--- a/fs/xfs/libxfs/xfs_parent.h
+++ b/fs/xfs/libxfs/xfs_parent.h
@@ -23,6 +23,8 @@ void xfs_init_parent_name_rec(struct xfs_parent_name_rec *rec,
 			      uint32_t p_diroffset);
 void xfs_init_parent_name_irec(struct xfs_parent_name_irec *irec,
 			       struct xfs_parent_name_rec *rec);
+void xfs_init_parent_ptr(struct xfs_parent_ptr *xpp,
+			 const struct xfs_parent_name_rec *rec);
 int xfs_parent_init(xfs_mount_t *mp, struct xfs_parent_defer **parentp);
 int xfs_parent_defer_add(struct xfs_trans *tp, struct xfs_parent_defer *parent,
 			 struct xfs_inode *dp, struct xfs_name *parent_name,
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 5b600d3f7981..3cd46d030ccd 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -37,6 +37,7 @@
 #include "xfs_health.h"
 #include "xfs_reflink.h"
 #include "xfs_ioctl.h"
+#include "xfs_parent_utils.h"
 #include "xfs_xattr.h"
 
 #include <linux/mount.h>
@@ -1679,6 +1680,96 @@ xfs_ioc_scrub_metadata(
 	return 0;
 }
 
+/*
+ * IOCTL routine to get the parent pointers of an inode and return it to user
+ * space.  Caller must pass a buffer space containing a struct xfs_pptr_info,
+ * followed by a region large enough to contain an array of struct
+ * xfs_parent_ptr of a size specified in pi_ptrs_size.  If the inode contains
+ * more parent pointers than can fit in the buffer space, caller may re-call
+ * the function using the returned pi_cursor to resume iteration.  The
+ * number of xfs_parent_ptr returned will be stored in pi_ptrs_used.
+ *
+ * Returns 0 on success or non-zero on failure
+ */
+STATIC int
+xfs_ioc_get_parent_pointer(
+	struct file			*filp,
+	void				__user *arg)
+{
+	struct xfs_pptr_info		*ppi = NULL;
+	int				error = 0;
+	struct xfs_inode		*ip = XFS_I(file_inode(filp));
+	struct xfs_mount		*mp = ip->i_mount;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	/* Allocate an xfs_pptr_info to put the user data */
+	ppi = kmalloc(sizeof(struct xfs_pptr_info), 0);
+	if (!ppi)
+		return -ENOMEM;
+
+	/* Copy the data from the user */
+	error = copy_from_user(ppi, arg, sizeof(struct xfs_pptr_info));
+	if (error) {
+		error = -EFAULT;
+		goto out;
+	}
+
+	/* Check size of buffer requested by user */
+	if (xfs_pptr_info_sizeof(ppi->pi_ptrs_size) > XFS_XATTR_LIST_MAX) {
+		error = -ENOMEM;
+		goto out;
+	}
+
+	if (ppi->pi_flags & ~XFS_PPTR_FLAG_ALL) {
+		error = -EINVAL;
+		goto out;
+	}
+	ppi->pi_flags &= ~(XFS_PPTR_OFLAG_ROOT | XFS_PPTR_OFLAG_DONE);
+
+	/*
+	 * Now that we know how big the trailing buffer is, expand
+	 * our kernel xfs_pptr_info to be the same size
+	 */
+	ppi = krealloc(ppi, xfs_pptr_info_sizeof(ppi->pi_ptrs_size), 0);
+	if (!ppi)
+		return -ENOMEM;
+
+	if (ppi->pi_flags & XFS_PPTR_IFLAG_HANDLE) {
+		error = xfs_iget(mp, NULL, ppi->pi_handle.ha_fid.fid_ino,
+				0, 0, &ip);
+		if (error)
+			goto out;
+
+		if (VFS_I(ip)->i_generation != ppi->pi_handle.ha_fid.fid_gen) {
+			error = -EINVAL;
+			goto out;
+		}
+	}
+
+	if (ip->i_ino == mp->m_sb.sb_rootino)
+		ppi->pi_flags |= XFS_PPTR_OFLAG_ROOT;
+
+	/* Get the parent pointers */
+	error = xfs_attr_get_parent_pointer(ip, ppi);
+
+	if (error)
+		goto out;
+
+	/* Copy the parent pointers back to the user */
+	error = copy_to_user(arg, ppi,
+			xfs_pptr_info_sizeof(ppi->pi_ptrs_size));
+	if (error) {
+		error = -EFAULT;
+		goto out;
+	}
+
+out:
+	kmem_free(ppi);
+	return error;
+}
+
 int
 xfs_ioc_swapext(
 	xfs_swapext_t	*sxp)
@@ -1968,7 +2059,8 @@ xfs_file_ioctl(
 
 	case XFS_IOC_FSGETXATTRA:
 		return xfs_ioc_fsgetxattra(ip, arg);
-
+	case XFS_IOC_GETPARENTS:
+		return xfs_ioc_get_parent_pointer(filp, arg);
 	case XFS_IOC_GETBMAP:
 	case XFS_IOC_GETBMAPA:
 	case XFS_IOC_GETBMAPX:
diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h
index 758702b9495f..765eb514a917 100644
--- a/fs/xfs/xfs_ondisk.h
+++ b/fs/xfs/xfs_ondisk.h
@@ -135,6 +135,10 @@ xfs_check_ondisk_structs(void)
 	XFS_CHECK_STRUCT_SIZE(struct xfs_attri_log_format,	40);
 	XFS_CHECK_STRUCT_SIZE(struct xfs_attrd_log_format,	16);
 
+	/* parent pointer ioctls */
+	XFS_CHECK_STRUCT_SIZE(struct xfs_parent_ptr,            280);
+	XFS_CHECK_STRUCT_SIZE(struct xfs_pptr_info,             104);
+
 	/*
 	 * The v5 superblock format extended several v4 header structures with
 	 * additional data. While new fields are only accessible on v5
diff --git a/fs/xfs/xfs_parent_utils.c b/fs/xfs/xfs_parent_utils.c
new file mode 100644
index 000000000000..ea7890bd119a
--- /dev/null
+++ b/fs/xfs/xfs_parent_utils.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Oracle, Inc.
+ * All rights reserved.
+ */
+#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_da_format.h"
+#include "xfs_da_btree.h"
+#include "xfs_attr.h"
+#include "xfs_ioctl.h"
+#include "xfs_parent.h"
+#include "xfs_da_btree.h"
+
+/*
+ * Get the parent pointers for a given inode
+ *
+ * Returns 0 on success and non zero on error
+ */
+int
+xfs_attr_get_parent_pointer(
+	struct xfs_inode		*ip,
+	struct xfs_pptr_info		*ppi)
+{
+
+	struct xfs_attrlist		*alist;
+	struct xfs_attrlist_ent		*aent;
+	struct xfs_parent_ptr		*xpp;
+	struct xfs_parent_name_rec	*xpnr;
+	char				*namebuf;
+	unsigned int			namebuf_size;
+	int				name_len, i, error = 0;
+	unsigned int			lock_mode, flags = XFS_ATTR_PARENT;
+	struct xfs_attr_list_context	context;
+
+	/* Allocate a buffer to store the attribute names */
+	namebuf_size = sizeof(struct xfs_attrlist) +
+		       (ppi->pi_ptrs_size) * sizeof(struct xfs_attrlist_ent);
+	namebuf = kvzalloc(namebuf_size, GFP_KERNEL);
+	if (!namebuf)
+		return -ENOMEM;
+
+	memset(&context, 0, sizeof(struct xfs_attr_list_context));
+	error = xfs_ioc_attr_list_context_init(ip, namebuf, namebuf_size, 0,
+			&context);
+	if (error)
+		goto out_kfree;
+
+	/* Copy the cursor provided by caller */
+	memcpy(&context.cursor, &ppi->pi_cursor,
+		sizeof(struct xfs_attrlist_cursor));
+	context.attr_filter = XFS_ATTR_PARENT;
+
+	lock_mode = xfs_ilock_attr_map_shared(ip);
+
+	error = xfs_attr_list_ilocked(&context);
+	if (error)
+		goto out_kfree;
+
+	alist = (struct xfs_attrlist *)namebuf;
+	for (i = 0; i < alist->al_count; i++) {
+		struct xfs_da_args args = {
+			.geo = ip->i_mount->m_attr_geo,
+			.whichfork = XFS_ATTR_FORK,
+			.dp = ip,
+			.namelen = sizeof(struct xfs_parent_name_rec),
+			.attr_filter = flags,
+		};
+
+		xpp = xfs_ppinfo_to_pp(ppi, i);
+		memset(xpp, 0, sizeof(struct xfs_parent_ptr));
+		aent = (struct xfs_attrlist_ent *)
+			&namebuf[alist->al_offset[i]];
+		xpnr = (struct xfs_parent_name_rec *)(aent->a_name);
+
+		if (aent->a_valuelen > XFS_PPTR_MAXNAMELEN) {
+			error = -EFSCORRUPTED;
+			goto out_kfree;
+		}
+		name_len = aent->a_valuelen;
+
+		args.name = (char *)xpnr;
+		args.hashval = xfs_da_hashname(args.name, args.namelen),
+		args.value = (unsigned char *)(xpp->xpp_name);
+		args.valuelen = name_len;
+
+		error = xfs_attr_get_ilocked(&args);
+		error = (error == -EEXIST ? 0 : error);
+		if (error) {
+			error = -EFSCORRUPTED;
+			goto out_kfree;
+		}
+
+		xfs_init_parent_ptr(xpp, xpnr);
+		if (!xfs_verify_ino(args.dp->i_mount, xpp->xpp_ino)) {
+			error = -EFSCORRUPTED;
+			goto out_kfree;
+		}
+	}
+	ppi->pi_ptrs_used = alist->al_count;
+	if (!alist->al_more)
+		ppi->pi_flags |= XFS_PPTR_OFLAG_DONE;
+
+	/* Update the caller with the current cursor position */
+	memcpy(&ppi->pi_cursor, &context.cursor,
+			sizeof(struct xfs_attrlist_cursor));
+
+out_kfree:
+	xfs_iunlock(ip, lock_mode);
+	kvfree(namebuf);
+
+	return error;
+}
+
diff --git a/fs/xfs/xfs_parent_utils.h b/fs/xfs/xfs_parent_utils.h
new file mode 100644
index 000000000000..ad60baee8b2a
--- /dev/null
+++ b/fs/xfs/xfs_parent_utils.h
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Oracle, Inc.
+ * All rights reserved.
+ */
+#ifndef	__XFS_PARENT_UTILS_H__
+#define	__XFS_PARENT_UTILS_H__
+
+int xfs_attr_get_parent_pointer(struct xfs_inode *ip,
+				struct xfs_pptr_info *ppi);
+#endif	/* __XFS_PARENT_UTILS_H__ */
-- 
2.25.1


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

* [PATCH v4 26/27] xfs: fix unit conversion error in xfs_log_calc_max_attrsetm_res
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (24 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 25/27] xfs: Add parent pointer ioctl allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  2022-10-21 22:29 ` [PATCH v4 27/27] xfs: drop compatibility minimum log size computations for reflink allison.henderson
  26 siblings, 0 replies; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

Dave and I were discussing some recent test regressions as a result of
me turning on nrext64=1 on realtime filesystems, when we noticed that
the minimum log size of a 32M filesystem jumped from 954 blocks to 4287
blocks.

Digging through xfs_log_calc_max_attrsetm_res, Dave noticed that @size
contains the maximum estimated amount of space needed for a local format
xattr, in bytes, but we feed this quantity to XFS_NEXTENTADD_SPACE_RES,
which requires units of blocks.  This has resulted in an overestimation
of the minimum log size over the years.

We should nominally correct this, but there's a backwards compatibility
problem -- if we enable it now, the minimum log size will decrease.  If
a corrected mkfs formats a filesystem with this new smaller log size, a
user will encounter mount failures on an uncorrected kernel due to the
larger minimum log size computations there.

However, the large extent counters feature is still EXPERIMENTAL, so we
can gate the correction on that feature (or any features that get added
after that) being enabled.  Any filesystem with nrext64 or any of the
as-yet-undefined feature bits turned on will be rejected by old
uncorrected kernels, so this should be safe even in the upgrade case.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_log_rlimit.c | 43 ++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/fs/xfs/libxfs/xfs_log_rlimit.c b/fs/xfs/libxfs/xfs_log_rlimit.c
index 9975b93a7412..e5c606fb7a6a 100644
--- a/fs/xfs/libxfs/xfs_log_rlimit.c
+++ b/fs/xfs/libxfs/xfs_log_rlimit.c
@@ -16,6 +16,39 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_trace.h"
 
+/*
+ * Decide if the filesystem has the parent pointer feature or any feature
+ * added after that.
+ */
+static inline bool
+xfs_has_parent_or_newer_feature(
+	struct xfs_mount	*mp)
+{
+	if (!xfs_sb_is_v5(&mp->m_sb))
+		return false;
+
+	if (xfs_sb_has_compat_feature(&mp->m_sb, ~0))
+		return true;
+
+	if (xfs_sb_has_ro_compat_feature(&mp->m_sb,
+				~(XFS_SB_FEAT_RO_COMPAT_FINOBT |
+				 XFS_SB_FEAT_RO_COMPAT_RMAPBT |
+				 XFS_SB_FEAT_RO_COMPAT_REFLINK |
+				 XFS_SB_FEAT_RO_COMPAT_INOBTCNT)))
+		return true;
+
+	if (xfs_sb_has_incompat_feature(&mp->m_sb,
+				~(XFS_SB_FEAT_INCOMPAT_FTYPE |
+				 XFS_SB_FEAT_INCOMPAT_SPINODES |
+				 XFS_SB_FEAT_INCOMPAT_META_UUID |
+				 XFS_SB_FEAT_INCOMPAT_BIGTIME |
+				 XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR |
+				 XFS_SB_FEAT_INCOMPAT_NREXT64)))
+		return true;
+
+	return false;
+}
+
 /*
  * Calculate the maximum length in bytes that would be required for a local
  * attribute value as large attributes out of line are not logged.
@@ -31,6 +64,16 @@ xfs_log_calc_max_attrsetm_res(
 	       MAXNAMELEN - 1;
 	nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
 	nblks += XFS_B_TO_FSB(mp, size);
+
+	/*
+	 * Starting with the parent pointer feature, every new fs feature
+	 * corrects a unit conversion error in the xattr transaction
+	 * reservation code that resulted in oversized minimum log size
+	 * computations.
+	 */
+	if (xfs_has_parent_or_newer_feature(mp))
+		size = XFS_B_TO_FSB(mp, size);
+
 	nblks += XFS_NEXTENTADD_SPACE_RES(mp, size, XFS_ATTR_FORK);
 
 	return  M_RES(mp)->tr_attrsetm.tr_logres +
-- 
2.25.1


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

* [PATCH v4 27/27] xfs: drop compatibility minimum log size computations for reflink
  2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
                   ` (25 preceding siblings ...)
  2022-10-21 22:29 ` [PATCH v4 26/27] xfs: fix unit conversion error in xfs_log_calc_max_attrsetm_res allison.henderson
@ 2022-10-21 22:29 ` allison.henderson
  26 siblings, 0 replies; 55+ messages in thread
From: allison.henderson @ 2022-10-21 22:29 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

Having established that we can reduce the minimum log size computation
for filesystems with parent pointers or any newer feature, we should
also drop the compat minlogsize code that we added when we reduced the
transaction reservation size for rmap and reflink.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_log_rlimit.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/fs/xfs/libxfs/xfs_log_rlimit.c b/fs/xfs/libxfs/xfs_log_rlimit.c
index e5c606fb7a6a..74821c7fd0cc 100644
--- a/fs/xfs/libxfs/xfs_log_rlimit.c
+++ b/fs/xfs/libxfs/xfs_log_rlimit.c
@@ -91,6 +91,16 @@ xfs_log_calc_trans_resv_for_minlogblocks(
 {
 	unsigned int		rmap_maxlevels = mp->m_rmap_maxlevels;
 
+	/*
+	 * Starting with the parent pointer feature, every new fs feature
+	 * drops the oversized minimum log size computation introduced by the
+	 * original reflink code.
+	 */
+	if (xfs_has_parent_or_newer_feature(mp)) {
+		xfs_trans_resv_calc(mp, resv);
+		return;
+	}
+
 	/*
 	 * In the early days of rmap+reflink, we always set the rmap maxlevels
 	 * to 9 even if the AG was small enough that it would never grow to
-- 
2.25.1


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

* Re: [PATCH v4 01/27] xfs: Add new name to attri/d
  2022-10-21 22:29 ` [PATCH v4 01/27] xfs: Add new name to attri/d allison.henderson
@ 2022-10-25 19:09   ` Darrick J. Wong
  2022-10-26  7:40     ` Allison Henderson
  0 siblings, 1 reply; 55+ messages in thread
From: Darrick J. Wong @ 2022-10-25 19:09 UTC (permalink / raw)
  To: allison.henderson; +Cc: linux-xfs

On Fri, Oct 21, 2022 at 03:29:10PM -0700, allison.henderson@oracle.com wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> This patch adds two new fields to the atti/d.  They are nname and
> nnamelen.  This will be used for parent pointer updates since a
> rename operation may cause the parent pointer to update both the
> name and value.  So we need to carry both the new name as well as
> the target name in the attri/d.
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c       |  12 +++-
>  fs/xfs/libxfs/xfs_attr.h       |   4 +-
>  fs/xfs/libxfs/xfs_da_btree.h   |   2 +
>  fs/xfs/libxfs/xfs_log_format.h |   6 +-
>  fs/xfs/xfs_attr_item.c         | 108 +++++++++++++++++++++++++++++----
>  fs/xfs/xfs_attr_item.h         |   1 +
>  6 files changed, 115 insertions(+), 18 deletions(-)

<snip all the way to the one thing I noticed>

> diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
> index cf5ce607dc05..0c449fb606ed 100644
> --- a/fs/xfs/xfs_attr_item.c
> +++ b/fs/xfs/xfs_attr_item.c
> @@ -731,10 +767,41 @@ xlog_recover_attri_commit_pass2(

Ahahaha this function.  Could you review this patch that strengthens the
length checking on the incoming recovery item buffers, please?

https://lore.kernel.org/linux-xfs/166664715731.2688790.9836328662603103847.stgit@magnolia/

>  	struct xfs_attri_log_nameval	*nv;
>  	const void			*attr_value = NULL;
>  	const void			*attr_name;
> -	int                             error;
> +	const void			*attr_nname = NULL;
> +	int				i = 0;
> +	int                             op, error = 0;
>  
> -	attri_formatp = item->ri_buf[0].i_addr;
> -	attr_name = item->ri_buf[1].i_addr;
> +	if (item->ri_total == 0) {

Do all the log intent item types need to check for a nonzero number of
recovery item buffers too?  I /think/ this is unnecessary because
xlog_recover_add_to_trans will abort recovery if ilf_size == 0, and
ri_total is assigned to ilf_size:

	if (item->ri_total == 0) {	/* first region to be added */
		if (in_f->ilf_size == 0 ||
		    in_f->ilf_size > XLOG_MAX_REGIONS_IN_ITEM) {
			xfs_warn(log->l_mp,
		"bad number of regions (%d) in inode log format",
				  in_f->ilf_size);
			ASSERT(0);
			kmem_free(ptr);
			return -EFSCORRUPTED;
		}

		item->ri_total = in_f->ilf_size;

Hm?

> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
> +		return -EFSCORRUPTED;
> +	}
> +
> +	attri_formatp = item->ri_buf[i].i_addr;
> +	i++;
> +
> +	op = attri_formatp->alfi_op_flags & XFS_ATTRI_OP_FLAGS_TYPE_MASK;
> +	switch (op) {
> +	case XFS_ATTRI_OP_FLAGS_SET:
> +	case XFS_ATTRI_OP_FLAGS_REPLACE:
> +		if (item->ri_total != 3)
> +			error = -EFSCORRUPTED;
> +		break;
> +	case XFS_ATTRI_OP_FLAGS_REMOVE:
> +		if (item->ri_total != 2)
> +			error = -EFSCORRUPTED;
> +		break;
> +	case XFS_ATTRI_OP_FLAGS_NVREPLACE:
> +		if (item->ri_total != 4)
> +			error = -EFSCORRUPTED;
> +		break;
> +	default:
> +		error = -EFSCORRUPTED;
> +	}
> +
> +	if (error) {
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);

XFS_ERROR_REPORT is a macro encodes the exact instruction pointer
location in the error report that it emits.  I know it'll make the code
more verbose, but the macros should be embedded in that switch statement
above.

> +		return error;
> +	}
>  
>  	/* Validate xfs_attri_log_format before the large memory allocation */
>  	if (!xfs_attri_validate(mp, attri_formatp)) {
> @@ -742,13 +809,27 @@ xlog_recover_attri_commit_pass2(
>  		return -EFSCORRUPTED;
>  	}
>  
> +	attr_name = item->ri_buf[i].i_addr;
> +	i++;
> +
>  	if (!xfs_attr_namecheck(attr_name, attri_formatp->alfi_name_len)) {
>  		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
>  		return -EFSCORRUPTED;
>  	}
>  
> +	if (attri_formatp->alfi_nname_len) {

This needs to check that the length of the new name iovec buffer is what
we're expecting:

	if (item->ri_buf[i].i_len !=
			xlog_calc_iovec_len(attri_formatp->alfi_nname_len)) {
		/* complain... */
	}

--D

> +		attr_nname = item->ri_buf[i].i_addr;
> +		i++;
> +
> +		if (!xfs_attr_namecheck(attr_nname,
> +				attri_formatp->alfi_nname_len)) {
> +			XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
> +			return -EFSCORRUPTED;
> +		}
> +	}
> +
>  	if (attri_formatp->alfi_value_len)
> -		attr_value = item->ri_buf[2].i_addr;
> +		attr_value = item->ri_buf[i].i_addr;
>  
>  	/*
>  	 * Memory alloc failure will cause replay to abort.  We attach the
> @@ -756,7 +837,8 @@ xlog_recover_attri_commit_pass2(
>  	 * reference.
>  	 */
>  	nv = xfs_attri_log_nameval_alloc(attr_name,
> -			attri_formatp->alfi_name_len, attr_value,
> +			attri_formatp->alfi_name_len, attr_nname,
> +			attri_formatp->alfi_nname_len, attr_value,
>  			attri_formatp->alfi_value_len);
>  
>  	attrip = xfs_attri_init(mp, nv);
> diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h
> index 3280a7930287..24d4968dd6cc 100644
> --- a/fs/xfs/xfs_attr_item.h
> +++ b/fs/xfs/xfs_attr_item.h
> @@ -13,6 +13,7 @@ struct kmem_zone;
>  
>  struct xfs_attri_log_nameval {
>  	struct xfs_log_iovec	name;
> +	struct xfs_log_iovec	nname;
>  	struct xfs_log_iovec	value;
>  	refcount_t		refcount;
>  
> -- 
> 2.25.1
> 

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

* Re: [PATCH v4 06/27] xfs: Expose init_xattrs in xfs_create_tmpfile
  2022-10-21 22:29 ` [PATCH v4 06/27] xfs: Expose init_xattrs in xfs_create_tmpfile allison.henderson
@ 2022-10-25 19:13   ` Darrick J. Wong
  2022-10-25 21:33     ` Darrick J. Wong
  0 siblings, 1 reply; 55+ messages in thread
From: Darrick J. Wong @ 2022-10-25 19:13 UTC (permalink / raw)
  To: allison.henderson; +Cc: linux-xfs

On Fri, Oct 21, 2022 at 03:29:15PM -0700, allison.henderson@oracle.com wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> Tmp files are used as part of rename operations and will need attr forks
> initialized for parent pointers.  Expose the init_xattrs parameter to
> the calling function to initialize the fork.
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  fs/xfs/xfs_inode.c | 5 +++--
>  fs/xfs/xfs_inode.h | 2 +-
>  fs/xfs/xfs_iops.c  | 3 ++-
>  3 files changed, 6 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 44b68fa53a72..8b3aefd146a2 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -1108,6 +1108,7 @@ xfs_create_tmpfile(
>  	struct user_namespace	*mnt_userns,
>  	struct xfs_inode	*dp,
>  	umode_t			mode,
> +	bool			init_xattrs,
>  	struct xfs_inode	**ipp)
>  {
>  	struct xfs_mount	*mp = dp->i_mount;
> @@ -1148,7 +1149,7 @@ xfs_create_tmpfile(
>  	error = xfs_dialloc(&tp, dp->i_ino, mode, &ino);
>  	if (!error)
>  		error = xfs_init_new_inode(mnt_userns, tp, dp, ino, mode,
> -				0, 0, prid, false, &ip);
> +				0, 0, prid, init_xattrs, &ip);
>  	if (error)
>  		goto out_trans_cancel;
>  
> @@ -2748,7 +2749,7 @@ xfs_rename_alloc_whiteout(
>  	int			error;
>  
>  	error = xfs_create_tmpfile(mnt_userns, dp, S_IFCHR | WHITEOUT_MODE,
> -				   &tmpfile);
> +				   false, &tmpfile);

Similar question to last time -- shouldn't we initialize the attr fork
at whiteout creation time if we know that we're about to add the new
file to a directory?  IOWs, s/false/xfs_has_parent(mp)/ here?

--D

>  	if (error)
>  		return error;
>  
> diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
> index 2eaed98af814..5735de32beeb 100644
> --- a/fs/xfs/xfs_inode.h
> +++ b/fs/xfs/xfs_inode.h
> @@ -478,7 +478,7 @@ int		xfs_create(struct user_namespace *mnt_userns,
>  			   umode_t mode, dev_t rdev, bool need_xattr,
>  			   struct xfs_inode **ipp);
>  int		xfs_create_tmpfile(struct user_namespace *mnt_userns,
> -			   struct xfs_inode *dp, umode_t mode,
> +			   struct xfs_inode *dp, umode_t mode, bool init_xattrs,
>  			   struct xfs_inode **ipp);
>  int		xfs_remove(struct xfs_inode *dp, struct xfs_name *name,
>  			   struct xfs_inode *ip);
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index 2e10e1c66ad6..10a5e85f2a70 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -200,7 +200,8 @@ xfs_generic_create(
>  				xfs_create_need_xattr(dir, default_acl, acl),
>  				&ip);
>  	} else {
> -		error = xfs_create_tmpfile(mnt_userns, XFS_I(dir), mode, &ip);
> +		error = xfs_create_tmpfile(mnt_userns, XFS_I(dir), mode, false,
> +					   &ip);
>  	}
>  	if (unlikely(error))
>  		goto out_free_acl;
> -- 
> 2.25.1
> 

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

* Re: [PATCH v4 13/27] xfs: Increase rename inode reservation
  2022-10-21 22:29 ` [PATCH v4 13/27] xfs: Increase rename inode reservation allison.henderson
@ 2022-10-25 19:15   ` Darrick J. Wong
  2022-10-26  7:40     ` Allison Henderson
  0 siblings, 1 reply; 55+ messages in thread
From: Darrick J. Wong @ 2022-10-25 19:15 UTC (permalink / raw)
  To: allison.henderson; +Cc: linux-xfs

On Fri, Oct 21, 2022 at 03:29:22PM -0700, allison.henderson@oracle.com wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> xfs_rename can lock up to 5 inodes: src_dp, target_dp, src_ip, target_ip
> and wip.  So we need to increase the inode reservation to match.
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>

Looks good, I'll add this to the 6.1 fixes.
Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> ---
>  fs/xfs/libxfs/xfs_trans_resv.c | 4 ++--
>  fs/xfs/xfs_inode.c             | 2 +-
>  2 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_trans_resv.c b/fs/xfs/libxfs/xfs_trans_resv.c
> index 2c4ad6e4bb14..5b2f27cbdb80 100644
> --- a/fs/xfs/libxfs/xfs_trans_resv.c
> +++ b/fs/xfs/libxfs/xfs_trans_resv.c
> @@ -422,7 +422,7 @@ xfs_calc_itruncate_reservation_minlogsize(
>  
>  /*
>   * In renaming a files we can modify:
> - *    the four inodes involved: 4 * inode size
> + *    the five inodes involved: 5 * inode size
>   *    the two directory btrees: 2 * (max depth + v2) * dir block size
>   *    the two directory bmap btrees: 2 * max depth * block size
>   * And the bmap_finish transaction can free dir and bmap blocks (two sets
> @@ -437,7 +437,7 @@ xfs_calc_rename_reservation(
>  	struct xfs_mount	*mp)
>  {
>  	return XFS_DQUOT_LOGRES(mp) +
> -		max((xfs_calc_inode_res(mp, 4) +
> +		max((xfs_calc_inode_res(mp, 5) +
>  		     xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp),
>  				      XFS_FSB_TO_B(mp, 1))),
>  		    (xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) +
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 71d60885000e..ea7aeab839c2 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -2848,7 +2848,7 @@ xfs_rename(
>  	 * Lock all the participating inodes. Depending upon whether
>  	 * the target_name exists in the target directory, and
>  	 * whether the target directory is the same as the source
> -	 * directory, we can lock from 2 to 4 inodes.
> +	 * directory, we can lock from 2 to 5 inodes.
>  	 */
>  	xfs_lock_inodes(inodes, num_inodes, XFS_ILOCK_EXCL);
>  
> -- 
> 2.25.1
> 

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

* Re: [PATCH v4 14/27] xfs: extend transaction reservations for parent attributes
  2022-10-21 22:29 ` [PATCH v4 14/27] xfs: extend transaction reservations for parent attributes allison.henderson
@ 2022-10-25 20:55   ` Darrick J. Wong
  2022-10-26  7:40     ` Allison Henderson
  0 siblings, 1 reply; 55+ messages in thread
From: Darrick J. Wong @ 2022-10-25 20:55 UTC (permalink / raw)
  To: allison.henderson; +Cc: linux-xfs

On Fri, Oct 21, 2022 at 03:29:23PM -0700, allison.henderson@oracle.com wrote:
> From: Allison Henderson <allison.henderson@oracle.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.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_trans_resv.c | 303 +++++++++++++++++++++++++++------
>  1 file changed, 249 insertions(+), 54 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_trans_resv.c b/fs/xfs/libxfs/xfs_trans_resv.c
> index 5b2f27cbdb80..756b6f38c385 100644
> --- a/fs/xfs/libxfs/xfs_trans_resv.c
> +++ b/fs/xfs/libxfs/xfs_trans_resv.c
> @@ -19,6 +19,9 @@
>  #include "xfs_trans.h"
>  #include "xfs_qm.h"
>  #include "xfs_trans_space.h"
> +#include "xfs_attr_item.h"
> +#include "xfs_log.h"
> +#include "xfs_da_format.h"
>  
>  #define _ALLOC	true
>  #define _FREE	false
> @@ -426,23 +429,62 @@ xfs_calc_itruncate_reservation_minlogsize(
>   *    the two directory btrees: 2 * (max depth + v2) * dir block size
>   *    the two directory bmap btrees: 2 * max depth * block size
>   * And the bmap_finish transaction can free dir and bmap blocks (two sets
> - *	of bmap blocks) giving:
> + *	of bmap blocks) giving (t2):
>   *    the agf for the ags in which the blocks live: 3 * sector size
>   *    the agfl for the ags in which the blocks live: 3 * sector size
>   *    the superblock for the free block count: sector size
>   *    the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size
> + * If parent pointers are enabled (t3), then each transaction in the chain
> + *    must be capable of setting or removing the extended attribute
> + *    containing the parent information.  It must also be able to handle
> + *    the three xattr intent items that track the progress of the parent
> + *    pointer update.

To check my assumptions here: For a standard rename, the three xattr
intent items are (1) replacing the pptr for the source file; (2)
removing the pptr on the dest file; and (3) adding a pptr for the
whiteout file in the src dir?

For an RENAME_EXCHANGE, there are two xattr intent items to replace the
pptr for both src and dest files.  Link counts don't change and there is
no whiteout, correct?

>   */
>  STATIC uint
>  xfs_calc_rename_reservation(
>  	struct xfs_mount	*mp)
>  {
> -	return XFS_DQUOT_LOGRES(mp) +
> -		max((xfs_calc_inode_res(mp, 5) +
> -		     xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp),
> -				      XFS_FSB_TO_B(mp, 1))),
> -		    (xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) +
> -		     xfs_calc_buf_res(xfs_allocfree_block_count(mp, 3),
> -				      XFS_FSB_TO_B(mp, 1))));
> +	unsigned int		overhead = XFS_DQUOT_LOGRES(mp);
> +	struct xfs_trans_resv	*resp = M_RES(mp);
> +	unsigned int		t1, t2, t3 = 0;
> +
> +	t1 = xfs_calc_inode_res(mp, 5) +
> +	     xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp),
> +			XFS_FSB_TO_B(mp, 1));
> +
> +	t2 = xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) +
> +	     xfs_calc_buf_res(xfs_allocfree_block_count(mp, 3),
> +			XFS_FSB_TO_B(mp, 1));
> +
> +	if (xfs_has_parent(mp)) {
> +		t3 = max(resp->tr_attrsetm.tr_logres,
> +				resp->tr_attrrm.tr_logres);
> +		overhead += 4 * (sizeof(struct xfs_attri_log_item) +

I'm not sure why this multiplies by four then?

The log reservation is for the ondisk structures, so the sizeof should
be for xfs_attri_log_format, not xfs_attri_log_item.

> +				 (2 * xlog_calc_iovec_len(XATTR_NAME_MAX)) +

I guess the 2 * XATTR_NAME_MAX is to log replacing the old name with
the new name?

> +				 xlog_calc_iovec_len(
> +					sizeof(struct xfs_parent_name_rec)));

And this last one is for the xattr "name", which is just the (parent,
gen, diroffset) structure?

I'm concerned about the overhead becoming unnecessarily large here,
since that all comes out to:

	4 * (48 +
	     (2 * 256) +
	     16)

	= 2304 bytes?  Or 1728 bytes if we only multiply by 3?

Ok, maybe I'm not so concerned after all; 2.3k isn't that large as
compared to logging entire fsblock buffers.  These namespace
transactions are 300-400KB in size.  Could this be reduced further,
though?

For a regular rename, we're doing a replace, a link, and an unlink.

	(48 + (2 * 256)) +
	(48 + 256) +
	(48)

	= 912 bytes

For a RENAME_EXCHANGE, we're doing two replaces:

	(48 + (2 * 256)) +
	(48 + (2 * 256))

	= 1120 bytes

I'm glad that 1728 is larger than both of those. :)

Looking forward in this patch, I see the same open-coded overhead
calculations and wonder what you think of the following refactoring:

static inline unsigned int xfs_calc_pptr_link_overhead(void)
{
	return sizeof(struct xfs_attri_log_format) +
			xlog_calc_iovec_len(XATTR_NAME_MAX) +
			xlog_calc_iovec_len(sizeof(struct xfs_parent_name_rec));
}
static inline unsigned int xfs_calc_pptr_unlink_overhead(void)
{
	return sizeof(struct xfs_attri_log_format) +
			xlog_calc_iovec_len(sizeof(struct xfs_parent_name_rec));
}
static inline unsigned int xfs_calc_pptr_replace_overhead(void)
{
	return sizeof(struct xfs_attri_log_format) +
			xlog_calc_iovec_len(XATTR_NAME_MAX) +
			xlog_calc_iovec_len(XATTR_NAME_MAX) +
			xlog_calc_iovec_len(sizeof(struct xfs_parent_name_rec));
}

And then the above becomes:

	if (xfs_has_parent(mp)) {
		unsigned int	rename_overhead, exchange_overhead;

		t3 = max(resp->tr_attrsetm.tr_logres,
			 resp->tr_attrrm.tr_logres);

		/*
		 * For a standard rename, the three xattr intent log items
		 * are (1) replacing the pptr for the source file; (2)
		 * removing the pptr on the dest file; and (3) adding a
		 * pptr for the whiteout file in the src dir.
		 *
		 * For an RENAME_EXCHANGE, there are two xattr intent
		 * items to replace the pptr for both src and dest
		 * files.  Link counts don't change and there is no
		 * whiteout.
		 *
		 * In the worst case we can end up relogging all log
		 * intent items to allow the log tail to move ahead, so
		 * they become overhead added to each transaction in a
		 * processing chain.
		 */
		rename_overhead = xfs_calc_pptr_replace_overhead() +
				  xfs_calc_pptr_unlink_overhead() +
				  xfs_calc_pptr_link_overhead();
		exchange_overhead = 2 * xfs_calc_pptr_replace_overhead();

		overhead += max(rename_overhead, exchange_overhead);
	}

You might want to come up with better names though.

> +	}
> +
> +	return overhead + max3(t1, t2, t3);
> +}
> +
> +static inline unsigned int
> +xfs_rename_log_count(
> +	struct xfs_mount	*mp,
> +	struct xfs_trans_resv	*resp)
> +{
> +	/* One for the rename, one more for freeing blocks */
> +	unsigned int		ret = XFS_RENAME_LOG_COUNT;
> +
> +	/*
> +	 * Pre-reserve enough log reservation to handle the transaction
> +	 * rolling needed to remove or add one parent pointer.
> +	 */
> +	if (xfs_has_parent(mp))
> +		ret += max(resp->tr_attrsetm.tr_logcount,
> +			   resp->tr_attrrm.tr_logcount);
> +
> +	return ret;
>  }
>  
>  /*
> @@ -459,6 +501,23 @@ xfs_calc_iunlink_remove_reservation(
>  	       2 * M_IGEO(mp)->inode_cluster_size;
>  }
>  
> +static inline unsigned int
> +xfs_link_log_count(
> +	struct xfs_mount	*mp,
> +	struct xfs_trans_resv	*resp)
> +{
> +	unsigned int		ret = XFS_LINK_LOG_COUNT;
> +
> +	/*
> +	 * Pre-reserve enough log reservation to handle the transaction
> +	 * rolling needed to add one parent pointer.
> +	 */
> +	if (xfs_has_parent(mp))
> +		ret += resp->tr_attrsetm.tr_logcount;
> +
> +	return ret;
> +}
> +
>  /*
>   * For creating a link to an inode:
>   *    the parent directory inode: inode size
> @@ -475,14 +534,27 @@ STATIC uint
>  xfs_calc_link_reservation(
>  	struct xfs_mount	*mp)
>  {
> -	return XFS_DQUOT_LOGRES(mp) +
> -		xfs_calc_iunlink_remove_reservation(mp) +
> -		max((xfs_calc_inode_res(mp, 2) +
> -		     xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
> -				      XFS_FSB_TO_B(mp, 1))),
> -		    (xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
> -		     xfs_calc_buf_res(xfs_allocfree_block_count(mp, 1),
> -				      XFS_FSB_TO_B(mp, 1))));
> +	unsigned int            overhead = XFS_DQUOT_LOGRES(mp);
> +	struct xfs_trans_resv   *resp = M_RES(mp);
> +	unsigned int            t1, t2, t2_1, t2_2, t3 = 0;
> +
> +	t1 = xfs_calc_iunlink_remove_reservation(mp);
> +	t2_1 = xfs_calc_inode_res(mp, 2) +
> +	       xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1));
> +	t2_2 = xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
> +	       xfs_calc_buf_res(xfs_allocfree_block_count(mp, 1),
> +				XFS_FSB_TO_B(mp, 1));
> +	t2 = max(t2_1, t2_2);

Add xfs_calc_iunlink_remove_reservation to overhead, rename t2_1 to t1
and t2_2 to t2, and the return statement can become:

	return overhead + max3(t1, t2, t3);

> +
> +	if (xfs_has_parent(mp)) {
> +		t3 = resp->tr_attrsetm.tr_logres;
> +		overhead += sizeof(struct xfs_attri_log_item) +
> +			    xlog_calc_iovec_len(XATTR_NAME_MAX) +
> +			    xlog_calc_iovec_len(
> +					sizeof(struct xfs_parent_name_rec));

		overhead += xfs_calc_pptr_link_overhead();
> +	}
> +
> +	return overhead + t1 + t2 + t3;
>  }
>  
>  /*
> @@ -497,6 +569,23 @@ xfs_calc_iunlink_add_reservation(xfs_mount_t *mp)
>  			M_IGEO(mp)->inode_cluster_size;
>  }
>  
> +static inline unsigned int
> +xfs_remove_log_count(
> +	struct xfs_mount	*mp,
> +	struct xfs_trans_resv	*resp)
> +{
> +	unsigned int		ret = XFS_REMOVE_LOG_COUNT;
> +
> +	/*
> +	 * Pre-reserve enough log reservation to handle the transaction
> +	 * rolling needed to add one parent pointer.
> +	 */
> +	if (xfs_has_parent(mp))
> +		ret += resp->tr_attrrm.tr_logcount;
> +
> +	return ret;
> +}
> +
>  /*
>   * For removing a directory entry we can modify:
>   *    the parent directory inode: inode size
> @@ -513,14 +602,27 @@ STATIC uint
>  xfs_calc_remove_reservation(
>  	struct xfs_mount	*mp)
>  {
> -	return XFS_DQUOT_LOGRES(mp) +
> -		xfs_calc_iunlink_add_reservation(mp) +
> -		max((xfs_calc_inode_res(mp, 2) +
> -		     xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
> -				      XFS_FSB_TO_B(mp, 1))),
> -		    (xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) +
> -		     xfs_calc_buf_res(xfs_allocfree_block_count(mp, 2),
> -				      XFS_FSB_TO_B(mp, 1))));
> +	unsigned int            overhead = XFS_DQUOT_LOGRES(mp);
> +	struct xfs_trans_resv   *resp = M_RES(mp);
> +	unsigned int            t1, t2, t2_1, t2_2, t3 = 0;
> +
> +	t1 = xfs_calc_iunlink_add_reservation(mp);
> +
> +	t2_1 = xfs_calc_inode_res(mp, 2) +
> +	       xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1));
> +	t2_2 = xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) +
> +	       xfs_calc_buf_res(xfs_allocfree_block_count(mp, 2),
> +				XFS_FSB_TO_B(mp, 1));
> +	t2 = max(t2_1, t2_2);

Similar to the last _reservation function -- add
xfs_calc_iunlink_add_reservation to overhead, rename t2_1 to t1 and t2_2
to t2 and the return statement becomes:

	return overhead + max3(t1, t2, t3);

> +	if (xfs_has_parent(mp)) {
> +		t3 = resp->tr_attrrm.tr_logres;
> +		overhead += sizeof(struct xfs_attri_log_item) +
> +			    xlog_calc_iovec_len(
> +					sizeof(struct xfs_parent_name_rec));

		overhead += xfs_calc_pptr_unlink_overhead();

> +	}
> +
> +	return overhead + t1 + t2 + t3;
>  }
>  
>  /*
> @@ -569,12 +671,39 @@ xfs_calc_icreate_resv_alloc(
>  		xfs_calc_finobt_res(mp);
>  }
>  
> +static inline unsigned int
> +xfs_icreate_log_count(
> +	struct xfs_mount	*mp,
> +	struct xfs_trans_resv	*resp)
> +{
> +	unsigned int		ret = XFS_CREATE_LOG_COUNT;
> +
> +	/*
> +	 * Pre-reserve enough log reservation to handle the transaction
> +	 * rolling needed to add one parent pointer.
> +	 */
> +	if (xfs_has_parent(mp))
> +		ret += resp->tr_attrsetm.tr_logcount;
> +
> +	return ret;
> +}
> +
>  STATIC uint
> -xfs_calc_icreate_reservation(xfs_mount_t *mp)
> +xfs_calc_icreate_reservation(
> +	struct xfs_mount	*mp)
>  {
> -	return XFS_DQUOT_LOGRES(mp) +
> -		max(xfs_calc_icreate_resv_alloc(mp),
> -		    xfs_calc_create_resv_modify(mp));
> +	struct xfs_trans_resv   *resp = M_RES(mp);
> +	unsigned int		ret = XFS_DQUOT_LOGRES(mp) +
> +				      max(xfs_calc_icreate_resv_alloc(mp),
> +				      xfs_calc_create_resv_modify(mp));

Stylistic complaint: Please follow the same format as the other _calc
functions:

	unsigned int		overhead = XFS_DQUOT_LOGRES(mp);
	unsigned int		t1, t2, t3 = 0;

	t1 = xfs_calc_icreate_resv_alloc(mp);
	t2 = xfs_calc_create_resv_modify(mp);

	if (xfs_has_parent(mp)) {
		t3 = resp->tr_attrsetm.tr_logres;
		overhead += xfs_calc_pptr_link_overhead();
	}

	return overhead + max3(t1, t2, t3);

> +
> +	if (xfs_has_parent(mp))
> +		ret += resp->tr_attrsetm.tr_logres +
> +		       sizeof(struct xfs_attri_log_item) +
> +		       xlog_calc_iovec_len(XATTR_NAME_MAX) +
> +		       xlog_calc_iovec_len(
> +					sizeof(struct xfs_parent_name_rec));
> +	return ret;
>  }
>  
>  STATIC uint
> @@ -587,6 +716,23 @@ xfs_calc_create_tmpfile_reservation(
>  	return res + xfs_calc_iunlink_add_reservation(mp);
>  }
>  
> +static inline unsigned int
> +xfs_mkdir_log_count(
> +	struct xfs_mount	*mp,
> +	struct xfs_trans_resv	*resp)
> +{
> +	unsigned int		ret = XFS_MKDIR_LOG_COUNT;
> +
> +	/*
> +	 * Pre-reserve enough log reservation to handle the transaction
> +	 * rolling needed to add one parent pointer.
> +	 */
> +	if (xfs_has_parent(mp))
> +		ret += resp->tr_attrsetm.tr_logcount;
> +
> +	return ret;
> +}
> +
>  /*
>   * Making a new directory is the same as creating a new file.
>   */
> @@ -597,6 +743,22 @@ xfs_calc_mkdir_reservation(
>  	return xfs_calc_icreate_reservation(mp);
>  }
>  
> +static inline unsigned int
> +xfs_symlink_log_count(
> +	struct xfs_mount	*mp,
> +	struct xfs_trans_resv	*resp)
> +{
> +	unsigned int		ret = XFS_SYMLINK_LOG_COUNT;
> +
> +	/*
> +	 * Pre-reserve enough log reservation to handle the transaction
> +	 * rolling needed to add one parent pointer.
> +	 */
> +	if (xfs_has_parent(mp))
> +		ret += resp->tr_attrsetm.tr_logcount;
> +
> +	return ret;
> +}
>  
>  /*
>   * Making a new symplink is the same as creating a new file, but
> @@ -607,8 +769,17 @@ STATIC uint
>  xfs_calc_symlink_reservation(
>  	struct xfs_mount	*mp)
>  {
> -	return xfs_calc_icreate_reservation(mp) +
> -	       xfs_calc_buf_res(1, XFS_SYMLINK_MAXLEN);
> +	struct xfs_trans_resv   *resp = M_RES(mp);
> +	unsigned int		ret = xfs_calc_icreate_reservation(mp) +
> +				      xfs_calc_buf_res(1, XFS_SYMLINK_MAXLEN);
> +
> +	if (xfs_has_parent(mp))
> +		ret += resp->tr_attrsetm.tr_logres +
> +		       sizeof(struct xfs_attri_log_item) +
> +		       xlog_calc_iovec_len(XATTR_NAME_MAX) +
> +		       xlog_calc_iovec_len(
> +					sizeof(struct xfs_parent_name_rec));

Didn't we already account for the pptr log item overhead in
xfs_calc_icreate_reservation?

> +	return ret;
>  }
>  
>  /*
> @@ -909,54 +1080,76 @@ xfs_calc_sb_reservation(
>  	return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize);
>  }
>  
> -void
> -xfs_trans_resv_calc(
> +/*
> + * 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

s/assumes/requires/ since you put in ASSERTs :)

--D

> + * 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.
> + */
> +STATIC void
> +xfs_calc_namespace_reservations(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans_resv	*resp)
>  {
> -	int			logcount_adj = 0;
> -
> -	/*
> -	 * 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, false);
> -	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, false);
> -	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;
> +	resp->tr_rename.tr_logcount = xfs_rename_log_count(mp, resp);
>  	resp->tr_rename.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
>  
>  	resp->tr_link.tr_logres = xfs_calc_link_reservation(mp);
> -	resp->tr_link.tr_logcount = XFS_LINK_LOG_COUNT;
> +	resp->tr_link.tr_logcount = xfs_link_log_count(mp, resp);
>  	resp->tr_link.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
>  
>  	resp->tr_remove.tr_logres = xfs_calc_remove_reservation(mp);
> -	resp->tr_remove.tr_logcount = XFS_REMOVE_LOG_COUNT;
> +	resp->tr_remove.tr_logcount = xfs_remove_log_count(mp, resp);
>  	resp->tr_remove.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
>  
>  	resp->tr_symlink.tr_logres = xfs_calc_symlink_reservation(mp);
> -	resp->tr_symlink.tr_logcount = XFS_SYMLINK_LOG_COUNT;
> +	resp->tr_symlink.tr_logcount = xfs_symlink_log_count(mp, resp);
>  	resp->tr_symlink.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
>  
>  	resp->tr_create.tr_logres = xfs_calc_icreate_reservation(mp);
> -	resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT;
> +	resp->tr_create.tr_logcount = xfs_icreate_log_count(mp, resp);
>  	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(mp, resp);
> +	resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
> +}
> +
> +void
> +xfs_trans_resv_calc(
> +	struct xfs_mount	*mp,
> +	struct xfs_trans_resv	*resp)
> +{
> +	int			logcount_adj = 0;
> +
> +	/*
> +	 * 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, false);
> +	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, false);
> +	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;
> @@ -986,6 +1179,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.25.1
> 

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

* Re: [PATCH v4 16/27] xfs: add parent attributes to link
  2022-10-21 22:29 ` [PATCH v4 16/27] xfs: add parent attributes to link allison.henderson
@ 2022-10-25 20:58   ` Darrick J. Wong
  0 siblings, 0 replies; 55+ messages in thread
From: Darrick J. Wong @ 2022-10-25 20:58 UTC (permalink / raw)
  To: allison.henderson; +Cc: linux-xfs

On Fri, Oct 21, 2022 at 03:29:25PM -0700, allison.henderson@oracle.com wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> This patch modifies xfs_link to add a parent pointer to the inode.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  fs/xfs/xfs_inode.c | 60 ++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 50 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index ae6604f51ce8..f2e7da1befa4 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -1248,16 +1248,32 @@ xfs_create_tmpfile(
>  	return error;
>  }
>  
> +unsigned int
> +xfs_link_space_res(
> +	struct xfs_mount	*mp,
> +	unsigned int		namelen)
> +{
> +	unsigned int		ret;
> +
> +	ret = XFS_DIRENTER_SPACE_RES(mp, namelen);
> +	if (xfs_has_parent(mp))
> +		ret += xfs_pptr_calc_space_res(mp, namelen);
> +
> +	return ret;
> +}
> +
>  int
>  xfs_link(
> -	xfs_inode_t		*tdp,
> -	xfs_inode_t		*sip,
> +	struct xfs_inode	*tdp,
> +	struct xfs_inode	*sip,
>  	struct xfs_name		*target_name)
>  {
> -	xfs_mount_t		*mp = tdp->i_mount;
> -	xfs_trans_t		*tp;
> +	struct xfs_mount	*mp = tdp->i_mount;
> +	struct xfs_trans	*tp;
>  	int			error, nospace_error = 0;
>  	int			resblks;
> +	xfs_dir2_dataptr_t	diroffset;
> +	struct xfs_parent_defer	*parent = NULL;
>  
>  	trace_xfs_link(tdp, target_name);
>  
> @@ -1274,11 +1290,17 @@ xfs_link(
>  	if (error)
>  		goto std_return;
>  
> -	resblks = XFS_LINK_SPACE_RES(mp, target_name->len);
> +	if (xfs_has_parent(mp)) {
> +		error = xfs_parent_init(mp, &parent);
> +		if (error)
> +			goto std_return;
> +	}
> +
> +	resblks = xfs_link_space_res(mp, target_name->len);
>  	error = xfs_trans_alloc_dir(tdp, &M_RES(mp)->tr_link, sip, &resblks,
>  			&tp, &nospace_error);
>  	if (error)
> -		goto std_return;
> +		goto drop_incompat;
>  
>  	/*
>  	 * If we are using project inheritance, we only allow hard link
> @@ -1311,14 +1333,27 @@ xfs_link(
>  	}
>  
>  	error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
> -				   resblks, NULL);
> +				   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);
>  
>  	xfs_bumplink(tp, sip);
>  
> +	/*
> +	 * 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
> +	 * attribute, we need to create it correctly, otherwise we can just add
> +	 * the parent to the inode.
> +	 */
> +	if (parent) {
> +		error = xfs_parent_defer_add(tp, parent, tdp, target_name,
> +					     diroffset, sip);
> +		if (error)
> +			goto out_defer_cancel;
> +	}
> +
>  	/*
>  	 * If this is a synchronous mount, make sure that the
>  	 * link transaction goes to disk before returning to
> @@ -1332,11 +1367,16 @@ xfs_link(
>  	xfs_iunlock(sip, XFS_ILOCK_EXCL);
>  	return error;
>  
> - error_return:
> +out_defer_cancel:
> +	xfs_defer_cancel(tp);
> +error_return:
>  	xfs_trans_cancel(tp);

It's no longer necessary to call xfs_defer_cancel before
xfs_trans_cancel, so you can eliminate this cleanup code.

With that fixed,
Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D


>  	xfs_iunlock(tdp, XFS_ILOCK_EXCL);
>  	xfs_iunlock(sip, XFS_ILOCK_EXCL);
> - std_return:
> +drop_incompat:
> +	if (parent)
> +		xfs_parent_cancel(mp, parent);
> +std_return:
>  	if (error == -ENOSPC && nospace_error)
>  		error = nospace_error;
>  	return error;
> -- 
> 2.25.1
> 

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

* Re: [PATCH v4 17/27] xfs: add parent attributes to symlink
  2022-10-21 22:29 ` [PATCH v4 17/27] xfs: add parent attributes to symlink allison.henderson
@ 2022-10-25 21:06   ` Darrick J. Wong
  0 siblings, 0 replies; 55+ messages in thread
From: Darrick J. Wong @ 2022-10-25 21:06 UTC (permalink / raw)
  To: allison.henderson; +Cc: linux-xfs

On Fri, Oct 21, 2022 at 03:29:26PM -0700, allison.henderson@oracle.com wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> This patch modifies xfs_symlink to add a parent pointer to the inode.
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  fs/xfs/xfs_symlink.c | 50 +++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 45 insertions(+), 5 deletions(-)
> 
> diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
> index 27a7d7c57015..968ca257cd82 100644
> --- a/fs/xfs/xfs_symlink.c
> +++ b/fs/xfs/xfs_symlink.c
> @@ -23,6 +23,8 @@
>  #include "xfs_trans.h"
>  #include "xfs_ialloc.h"
>  #include "xfs_error.h"
> +#include "xfs_parent.h"
> +#include "xfs_defer.h"
>  
>  /* ----- Kernel only functions below ----- */
>  int
> @@ -142,6 +144,23 @@ xfs_readlink(
>  	return error;
>  }
>  
> +unsigned int
> +xfs_symlink_space_res(

Should the XFS_SYMLINK_SPACE_RES macro be removed from
xfs_trans_space.h?

Come to think of it, the same question applies to the previous patch.

> +	struct xfs_mount	*mp,
> +	unsigned int		namelen,
> +	unsigned int		fsblocks)
> +{
> +	unsigned int		ret;
> +
> +	ret = XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp, namelen) +
> +	      fsblocks;

Nit: This should probably be indented two tabs.

> +
> +	if (xfs_has_parent(mp))
> +		ret += xfs_pptr_calc_space_res(mp, namelen);
> +
> +	return ret;
> +}
> +
>  int
>  xfs_symlink(
>  	struct user_namespace	*mnt_userns,
> @@ -172,6 +191,8 @@ xfs_symlink(
>  	struct xfs_dquot	*pdqp = NULL;
>  	uint			resblks;
>  	xfs_ino_t		ino;
> +	xfs_dir2_dataptr_t      diroffset;
> +	struct xfs_parent_defer *parent = NULL;
>  
>  	*ipp = NULL;
>  
> @@ -179,10 +200,10 @@ xfs_symlink(
>  
>  	if (xfs_is_shutdown(mp))
>  		return -EIO;
> -
>  	/*
>  	 * Check component lengths of the target path name.
>  	 */
> +

Unnecessary whitespace changes (while we're on nits...)

>  	pathlen = strlen(target_path);
>  	if (pathlen >= XFS_SYMLINK_MAXLEN)      /* total string too long */
>  		return -ENAMETOOLONG;
> @@ -204,11 +225,17 @@ xfs_symlink(
>  	 * The symlink will fit into the inode data fork?
>  	 * There can't be any attributes so we get the whole variable part.
>  	 */
> -	if (pathlen <= XFS_LITINO(mp))
> +	if (pathlen <= XFS_LITINO(mp) && !xfs_has_parent(mp))

Why do we require !xfs_has_parent here?  fs_blocks are the blocks needed
to reserve space for the remote symlink target blocks.  Link targets are
not recorded in pptrs, so I am surprised to see this here.

>  		fs_blocks = 0;
>  	else
>  		fs_blocks = xfs_symlink_blocks(mp, pathlen);
> -	resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks);
> +	resblks = xfs_symlink_space_res(mp, link_name->len, fs_blocks);
> +
> +	if (xfs_has_parent(mp)) {
> +		error = xfs_parent_init(mp, &parent);
> +		if (error)
> +			return error;
> +	}
>  
>  	error = xfs_trans_alloc_icreate(mp, &M_RES(mp)->tr_symlink, udqp, gdqp,
>  			pdqp, resblks, &tp);
> @@ -233,7 +260,7 @@ xfs_symlink(
>  	if (!error)
>  		error = xfs_init_new_inode(mnt_userns, tp, dp, ino,
>  				S_IFLNK | (mode & ~S_IFMT), 1, 0, prid,
> -				false, &ip);
> +				xfs_has_parent(mp), &ip);

Ahaaaaa, some of these init_xattrs = false occurrences from earlier
patches get replaced by xfs_has_parent calls later.  I'll go back and
revise my earlier comments then.

>  	if (error)
>  		goto out_trans_cancel;
>  
> @@ -315,12 +342,20 @@ xfs_symlink(
>  	 * Create the directory entry for the symlink.
>  	 */
>  	error = xfs_dir_createname(tp, dp, link_name,
> -			ip->i_ino, resblks, NULL);
> +			ip->i_ino, resblks, &diroffset);
>  	if (error)
>  		goto out_trans_cancel;
>  	xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
>  	xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
>  
> +	if (parent) {
> +		error = xfs_parent_defer_add(tp, parent, dp, link_name,
> +					     diroffset, ip);
> +		if (error)
> +			goto out_trans_cancel;
> +	}
> +
> +
>  	/*
>  	 * If this is a synchronous mount, make sure that the
>  	 * symlink transaction goes to disk before returning to
> @@ -344,6 +379,8 @@ xfs_symlink(
>  out_trans_cancel:
>  	xfs_trans_cancel(tp);
>  out_release_inode:
> +	xfs_defer_cancel(tp);

Two complaints: xfs_trans_cancel frees @tp so the xfs_defer_cancel call
is a UAF error.

Second, xfs_trans_cancel calls xfs_defer_cancel so it's not necessary.

--D

> +
>  	/*
>  	 * Wait until after the current transaction is aborted to finish the
>  	 * setup of the inode and release the inode.  This prevents recursive
> @@ -362,6 +399,9 @@ xfs_symlink(
>  		xfs_iunlock(dp, XFS_ILOCK_EXCL);
>  	if (ip)
>  		xfs_iunlock(ip, XFS_ILOCK_EXCL);
> +	if (parent)
> +		xfs_parent_cancel(mp, parent);
> +
>  	return error;
>  }
>  
> -- 
> 2.25.1
> 

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

* Re: [PATCH v4 15/27] xfs: parent pointer attribute creation
  2022-10-21 22:29 ` [PATCH v4 15/27] xfs: parent pointer attribute creation allison.henderson
@ 2022-10-25 21:11   ` Darrick J. Wong
  2022-10-26  7:40     ` Allison Henderson
  0 siblings, 1 reply; 55+ messages in thread
From: Darrick J. Wong @ 2022-10-25 21:11 UTC (permalink / raw)
  To: allison.henderson; +Cc: linux-xfs

On Fri, Oct 21, 2022 at 03:29:24PM -0700, allison.henderson@oracle.com wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> Add parent pointer attribute during xfs_create, and subroutines to
> initialize attributes
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  fs/xfs/Makefile            |   1 +
>  fs/xfs/libxfs/xfs_attr.c   |   4 +-
>  fs/xfs/libxfs/xfs_attr.h   |   4 +-
>  fs/xfs/libxfs/xfs_parent.c | 149 +++++++++++++++++++++++++++++++++++++
>  fs/xfs/libxfs/xfs_parent.h |  34 +++++++++
>  fs/xfs/xfs_inode.c         |  63 ++++++++++++++--
>  fs/xfs/xfs_xattr.c         |   2 +-
>  fs/xfs/xfs_xattr.h         |   1 +
>  8 files changed, 247 insertions(+), 11 deletions(-)
> 
> diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
> index 03135a1c31b6..e2b2cf50ffcf 100644
> --- a/fs/xfs/Makefile
> +++ b/fs/xfs/Makefile
> @@ -40,6 +40,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_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 0c9589261990..805aaa5639d2 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -886,7 +886,7 @@ xfs_attr_lookup(
>  	return error;
>  }
>  
> -static int
> +int
>  xfs_attr_intent_init(
>  	struct xfs_da_args	*args,
>  	unsigned int		op_flags,	/* op flag (set or remove) */
> @@ -904,7 +904,7 @@ xfs_attr_intent_init(
>  }
>  
>  /* Sets an attribute for an inode as a deferred operation */
> -static int
> +int
>  xfs_attr_defer_add(
>  	struct xfs_da_args	*args)
>  {
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index b79dae788cfb..0cf23f5117ad 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -544,6 +544,7 @@ int xfs_inode_hasattr(struct xfs_inode *ip);
>  bool xfs_attr_is_leaf(struct xfs_inode *ip);
>  int xfs_attr_get_ilocked(struct xfs_da_args *args);
>  int xfs_attr_get(struct xfs_da_args *args);
> +int xfs_attr_defer_add(struct xfs_da_args *args);
>  int xfs_attr_set(struct xfs_da_args *args);
>  int xfs_attr_set_iter(struct xfs_attr_intent *attr);
>  int xfs_attr_remove_iter(struct xfs_attr_intent *attr);
> @@ -552,7 +553,8 @@ bool xfs_attr_namecheck(struct xfs_mount *mp, const void *name, size_t length,
>  int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
>  void xfs_init_attr_trans(struct xfs_da_args *args, struct xfs_trans_res *tres,
>  			 unsigned int *total);
> -
> +int xfs_attr_intent_init(struct xfs_da_args *args, unsigned int op_flags,
> +			 struct xfs_attr_intent  **attr);
>  /*
>   * Check to see if the attr should be upgraded from non-existent or shortform to
>   * single-leaf-block attribute list.
> diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
> new file mode 100644
> index 000000000000..cf5ea8ce8bd3
> --- /dev/null
> +++ b/fs/xfs/libxfs/xfs_parent.c
> @@ -0,0 +1,149 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2022 Oracle, Inc.
> + * All rights reserved.
> + */
> +#include "xfs.h"
> +#include "xfs_fs.h"
> +#include "xfs_format.h"
> +#include "xfs_da_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_da_btree.h"
> +#include "xfs_attr.h"
> +#include "xfs_da_btree.h"
> +#include "xfs_attr_sf.h"
> +#include "xfs_bmap.h"
> +#include "xfs_defer.h"
> +#include "xfs_log.h"
> +#include "xfs_xattr.h"
> +#include "xfs_parent.h"
> +#include "xfs_trans_space.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 behavior 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,
> +	struct xfs_inode		*ip,
> +	uint32_t			p_diroffset)
> +{
> +	xfs_ino_t			p_ino = ip->i_ino;
> +	uint32_t			p_gen = VFS_I(ip)->i_generation;
> +
> +	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);
> +}
> +
> +int
> +xfs_parent_init(
> +	struct xfs_mount		*mp,
> +	struct xfs_parent_defer		**parentp)
> +{
> +	struct xfs_parent_defer		*parent;
> +	int				error;
> +
> +	if (!xfs_has_parent(mp))
> +		return 0;
> +
> +	error = xfs_attr_grab_log_assist(mp);
> +	if (error)
> +		return error;
> +
> +	parent = kzalloc(sizeof(*parent), GFP_KERNEL);

I suspect we're still going to want to use a dedicated slab for greater
memory efficiency, but for now this is all right.

Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> +	if (!parent)
> +		return -ENOMEM;
> +
> +	/* init parent da_args */
> +	parent->args.geo = mp->m_attr_geo;
> +	parent->args.whichfork = XFS_ATTR_FORK;
> +	parent->args.attr_filter = XFS_ATTR_PARENT;
> +	parent->args.op_flags = XFS_DA_OP_OKNOENT | XFS_DA_OP_LOGGED;
> +	parent->args.name = (const uint8_t *)&parent->rec;
> +	parent->args.namelen = sizeof(struct xfs_parent_name_rec);
> +
> +	*parentp = parent;
> +	return 0;
> +}
> +
> +int
> +xfs_parent_defer_add(
> +	struct xfs_trans	*tp,
> +	struct xfs_parent_defer	*parent,
> +	struct xfs_inode	*dp,
> +	struct xfs_name		*parent_name,
> +	xfs_dir2_dataptr_t	diroffset,
> +	struct xfs_inode	*child)
> +{
> +	struct xfs_da_args	*args = &parent->args;
> +
> +	xfs_init_parent_name_rec(&parent->rec, dp, diroffset);
> +	args->hashval = xfs_da_hashname(args->name, args->namelen);
> +
> +	args->trans = tp;
> +	args->dp = child;
> +	if (parent_name) {
> +		parent->args.value = (void *)parent_name->name;
> +		parent->args.valuelen = parent_name->len;
> +	}
> +
> +	return xfs_attr_defer_add(args);
> +}
> +
> +void
> +xfs_parent_cancel(
> +	xfs_mount_t		*mp,
> +	struct xfs_parent_defer *parent)
> +{
> +	xlog_drop_incompat_feat(mp->m_log);
> +	kfree(parent);
> +}
> +
> +unsigned int
> +xfs_pptr_calc_space_res(
> +	struct xfs_mount	*mp,
> +	unsigned int		namelen)
> +{
> +	/*
> +	 * Pptrs are always the first attr in an attr tree, and never larger
> +	 * than a block
> +	 */
> +	return XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) +
> +	       XFS_NEXTENTADD_SPACE_RES(mp, namelen, XFS_ATTR_FORK);
> +}
> +
> diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h
> new file mode 100644
> index 000000000000..9b8d0764aad6
> --- /dev/null
> +++ b/fs/xfs/libxfs/xfs_parent.h
> @@ -0,0 +1,34 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2022 Oracle, Inc.
> + * All Rights Reserved.
> + */
> +#ifndef	__XFS_PARENT_H__
> +#define	__XFS_PARENT_H__
> +
> +/*
> + * Dynamically allocd structure used to wrap the needed data to pass around
> + * the defer ops machinery
> + */
> +struct xfs_parent_defer {
> +	struct xfs_parent_name_rec	rec;
> +	struct xfs_da_args		args;
> +};
> +
> +/*
> + * Parent pointer attribute prototypes
> + */
> +void xfs_init_parent_name_rec(struct xfs_parent_name_rec *rec,
> +			      struct xfs_inode *ip,
> +			      uint32_t p_diroffset);
> +void xfs_init_parent_name_irec(struct xfs_parent_name_irec *irec,
> +			       struct xfs_parent_name_rec *rec);
> +int xfs_parent_init(xfs_mount_t *mp, struct xfs_parent_defer **parentp);
> +int xfs_parent_defer_add(struct xfs_trans *tp, struct xfs_parent_defer *parent,
> +			 struct xfs_inode *dp, struct xfs_name *parent_name,
> +			 xfs_dir2_dataptr_t diroffset, struct xfs_inode *child);
> +void xfs_parent_cancel(xfs_mount_t *mp, struct xfs_parent_defer *parent);
> +unsigned int xfs_pptr_calc_space_res(struct xfs_mount *mp,
> +				     unsigned int namelen);
> +
> +#endif	/* __XFS_PARENT_H__ */
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index ea7aeab839c2..ae6604f51ce8 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -37,6 +37,8 @@
>  #include "xfs_reflink.h"
>  #include "xfs_ag.h"
>  #include "xfs_log_priv.h"
> +#include "xfs_parent.h"
> +#include "xfs_xattr.h"
>  
>  struct kmem_cache *xfs_inode_cache;
>  
> @@ -946,10 +948,32 @@ xfs_bumplink(
>  	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
>  }
>  
> +unsigned int
> +xfs_create_space_res(
> +	struct xfs_mount	*mp,
> +	unsigned int		namelen)
> +{
> +	unsigned int		ret;
> +
> +	ret = XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp, namelen);
> +	if (xfs_has_parent(mp))
> +		ret += xfs_pptr_calc_space_res(mp, namelen);
> +
> +	return ret;
> +}
> +
> +unsigned int
> +xfs_mkdir_space_res(
> +	struct xfs_mount	*mp,
> +	unsigned int		namelen)
> +{
> +	return xfs_create_space_res(mp, namelen);
> +}
> +
>  int
>  xfs_create(
>  	struct user_namespace	*mnt_userns,
> -	xfs_inode_t		*dp,
> +	struct xfs_inode	*dp,
>  	struct xfs_name		*name,
>  	umode_t			mode,
>  	dev_t			rdev,
> @@ -961,7 +985,7 @@ xfs_create(
>  	struct xfs_inode	*ip = NULL;
>  	struct xfs_trans	*tp = NULL;
>  	int			error;
> -	bool                    unlock_dp_on_error = false;
> +	bool			unlock_dp_on_error = false;
>  	prid_t			prid;
>  	struct xfs_dquot	*udqp = NULL;
>  	struct xfs_dquot	*gdqp = NULL;
> @@ -969,6 +993,8 @@ xfs_create(
>  	struct xfs_trans_res	*tres;
>  	uint			resblks;
>  	xfs_ino_t		ino;
> +	xfs_dir2_dataptr_t	diroffset;
> +	struct xfs_parent_defer	*parent = NULL;
>  
>  	trace_xfs_create(dp, name);
>  
> @@ -988,13 +1014,19 @@ xfs_create(
>  		return error;
>  
>  	if (is_dir) {
> -		resblks = XFS_MKDIR_SPACE_RES(mp, name->len);
> +		resblks = xfs_mkdir_space_res(mp, name->len);
>  		tres = &M_RES(mp)->tr_mkdir;
>  	} else {
> -		resblks = XFS_CREATE_SPACE_RES(mp, name->len);
> +		resblks = xfs_create_space_res(mp, name->len);
>  		tres = &M_RES(mp)->tr_create;
>  	}
>  
> +	if (xfs_has_parent(mp)) {
> +		error = xfs_parent_init(mp, &parent);
> +		if (error)
> +			goto out_release_dquots;
> +	}
> +
>  	/*
>  	 * Initially assume that the file does not exist and
>  	 * reserve the resources for that case.  If that is not
> @@ -1010,7 +1042,7 @@ xfs_create(
>  				resblks, &tp);
>  	}
>  	if (error)
> -		goto out_release_dquots;
> +		goto drop_incompat;
>  
>  	xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
>  	unlock_dp_on_error = true;
> @@ -1020,6 +1052,7 @@ xfs_create(
>  	 * entry pointing to them, but a directory also the "." entry
>  	 * pointing to itself.
>  	 */
> +	init_xattrs = init_xattrs || xfs_has_parent(mp);
>  	error = xfs_dialloc(&tp, dp->i_ino, mode, &ino);
>  	if (!error)
>  		error = xfs_init_new_inode(mnt_userns, tp, dp, ino, mode,
> @@ -1034,11 +1067,12 @@ xfs_create(
>  	 * the transaction cancel unlocking dp so don't do it explicitly in the
>  	 * error path.
>  	 */
> -	xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
> +	xfs_trans_ijoin(tp, dp, 0);
>  	unlock_dp_on_error = false;
>  
>  	error = xfs_dir_createname(tp, dp, name, ip->i_ino,
> -				   resblks - XFS_IALLOC_SPACE_RES(mp), NULL);
> +				   resblks - XFS_IALLOC_SPACE_RES(mp),
> +				   &diroffset);
>  	if (error) {
>  		ASSERT(error != -ENOSPC);
>  		goto out_trans_cancel;
> @@ -1054,6 +1088,17 @@ xfs_create(
>  		xfs_bumplink(tp, dp);
>  	}
>  
> +	/*
> +	 * If we have parent pointers, we need to add the attribute containing
> +	 * the parent information now.
> +	 */
> +	if (parent) {
> +		error = xfs_parent_defer_add(tp, parent, dp, name, diroffset,
> +					     ip);
> +		if (error)
> +			goto out_trans_cancel;
> +	}
> +
>  	/*
>  	 * If this is a synchronous mount, make sure that the
>  	 * create transaction goes to disk before returning to
> @@ -1079,6 +1124,7 @@ xfs_create(
>  
>  	*ipp = ip;
>  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
> +	xfs_iunlock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
>  	return 0;
>  
>   out_trans_cancel:
> @@ -1093,6 +1139,9 @@ xfs_create(
>  		xfs_finish_inode_setup(ip);
>  		xfs_irele(ip);
>  	}
> + drop_incompat:
> +	if (parent)
> +		xfs_parent_cancel(mp, parent);
>   out_release_dquots:
>  	xfs_qm_dqrele(udqp);
>  	xfs_qm_dqrele(gdqp);
> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
> index c325a28b89a8..d9067c5f6bd6 100644
> --- a/fs/xfs/xfs_xattr.c
> +++ b/fs/xfs/xfs_xattr.c
> @@ -27,7 +27,7 @@
>   * they must release the permission by calling xlog_drop_incompat_feat
>   * when they're done.
>   */
> -static inline int
> +int
>  xfs_attr_grab_log_assist(
>  	struct xfs_mount	*mp)
>  {
> diff --git a/fs/xfs/xfs_xattr.h b/fs/xfs/xfs_xattr.h
> index 2b09133b1b9b..3fd6520a4d69 100644
> --- a/fs/xfs/xfs_xattr.h
> +++ b/fs/xfs/xfs_xattr.h
> @@ -7,6 +7,7 @@
>  #define __XFS_XATTR_H__
>  
>  int xfs_attr_change(struct xfs_da_args *args);
> +int xfs_attr_grab_log_assist(struct xfs_mount *mp);
>  
>  extern const struct xattr_handler *xfs_xattr_handlers[];
>  
> -- 
> 2.25.1
> 

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

* Re: [PATCH v4 18/27] xfs: remove parent pointers in unlink
  2022-10-21 22:29 ` [PATCH v4 18/27] xfs: remove parent pointers in unlink allison.henderson
@ 2022-10-25 21:14   ` Darrick J. Wong
  2022-10-26  7:40     ` Allison Henderson
  0 siblings, 1 reply; 55+ messages in thread
From: Darrick J. Wong @ 2022-10-25 21:14 UTC (permalink / raw)
  To: allison.henderson; +Cc: linux-xfs

On Fri, Oct 21, 2022 at 03:29:27PM -0700, allison.henderson@oracle.com wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> This patch removes the parent pointer attribute during unlink
> 
> 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_attr.h   |  1 +
>  fs/xfs/libxfs/xfs_parent.c | 17 +++++++++++++++
>  fs/xfs/libxfs/xfs_parent.h |  4 ++++
>  fs/xfs/xfs_inode.c         | 44 ++++++++++++++++++++++++++++++++------
>  5 files changed, 60 insertions(+), 8 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 805aaa5639d2..e967728d1ee7 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -946,7 +946,7 @@ xfs_attr_defer_replace(
>  }
>  
>  /* Removes an attribute for an inode as a deferred operation */
> -static int
> +int
>  xfs_attr_defer_remove(
>  	struct xfs_da_args	*args)
>  {
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index 0cf23f5117ad..033005542b9e 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -545,6 +545,7 @@ bool xfs_attr_is_leaf(struct xfs_inode *ip);
>  int xfs_attr_get_ilocked(struct xfs_da_args *args);
>  int xfs_attr_get(struct xfs_da_args *args);
>  int xfs_attr_defer_add(struct xfs_da_args *args);
> +int xfs_attr_defer_remove(struct xfs_da_args *args);
>  int xfs_attr_set(struct xfs_da_args *args);
>  int xfs_attr_set_iter(struct xfs_attr_intent *attr);
>  int xfs_attr_remove_iter(struct xfs_attr_intent *attr);
> diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
> index cf5ea8ce8bd3..c09f49b7c241 100644
> --- a/fs/xfs/libxfs/xfs_parent.c
> +++ b/fs/xfs/libxfs/xfs_parent.c
> @@ -125,6 +125,23 @@ xfs_parent_defer_add(
>  	return xfs_attr_defer_add(args);
>  }
>  
> +int
> +xfs_parent_defer_remove(
> +	struct xfs_trans	*tp,
> +	struct xfs_inode	*dp,
> +	struct xfs_parent_defer	*parent,
> +	xfs_dir2_dataptr_t	diroffset,
> +	struct xfs_inode	*child)
> +{
> +	struct xfs_da_args	*args = &parent->args;
> +
> +	xfs_init_parent_name_rec(&parent->rec, dp, diroffset);
> +	args->trans = tp;
> +	args->dp = child;
> +	args->hashval = xfs_da_hashname(args->name, args->namelen);
> +	return xfs_attr_defer_remove(args);
> +}
> +
>  void
>  xfs_parent_cancel(
>  	xfs_mount_t		*mp,
> diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h
> index 9b8d0764aad6..1c506532c624 100644
> --- a/fs/xfs/libxfs/xfs_parent.h
> +++ b/fs/xfs/libxfs/xfs_parent.h
> @@ -27,6 +27,10 @@ int xfs_parent_init(xfs_mount_t *mp, struct xfs_parent_defer **parentp);
>  int xfs_parent_defer_add(struct xfs_trans *tp, struct xfs_parent_defer *parent,
>  			 struct xfs_inode *dp, struct xfs_name *parent_name,
>  			 xfs_dir2_dataptr_t diroffset, struct xfs_inode *child);
> +int xfs_parent_defer_remove(struct xfs_trans *tp, struct xfs_inode *dp,
> +			    struct xfs_parent_defer *parent,
> +			    xfs_dir2_dataptr_t diroffset,
> +			    struct xfs_inode *child);
>  void xfs_parent_cancel(xfs_mount_t *mp, struct xfs_parent_defer *parent);
>  unsigned int xfs_pptr_calc_space_res(struct xfs_mount *mp,
>  				     unsigned int namelen);
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index f2e7da1befa4..83cc52c2bcf1 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -2472,6 +2472,19 @@ xfs_iunpin_wait(
>  		__xfs_iunpin_wait(ip);
>  }
>  
> +unsigned int
> +xfs_remove_space_res(

This probably needs to remove XFS_REMOVE_SPACE_RES (the macro) right?

With that fixed,
Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> +	struct xfs_mount	*mp,
> +	unsigned int		namelen)
> +{
> +	unsigned int		ret = XFS_DIRREMOVE_SPACE_RES(mp);
> +
> +	if (xfs_has_parent(mp))
> +		ret += xfs_pptr_calc_space_res(mp, namelen);
> +
> +	return ret;
> +}
> +
>  /*
>   * Removing an inode from the namespace involves removing the directory entry
>   * and dropping the link count on the inode. Removing the directory entry can
> @@ -2501,16 +2514,18 @@ xfs_iunpin_wait(
>   */
>  int
>  xfs_remove(
> -	xfs_inode_t             *dp,
> +	struct xfs_inode	*dp,
>  	struct xfs_name		*name,
> -	xfs_inode_t		*ip)
> +	struct xfs_inode	*ip)
>  {
> -	xfs_mount_t		*mp = dp->i_mount;
> -	xfs_trans_t             *tp = NULL;
> +	struct xfs_mount	*mp = dp->i_mount;
> +	struct xfs_trans	*tp = NULL;
>  	int			is_dir = S_ISDIR(VFS_I(ip)->i_mode);
>  	int			dontcare;
>  	int                     error = 0;
>  	uint			resblks;
> +	xfs_dir2_dataptr_t	dir_offset;
> +	struct xfs_parent_defer	*parent = NULL;
>  
>  	trace_xfs_remove(dp, name);
>  
> @@ -2525,6 +2540,12 @@ xfs_remove(
>  	if (error)
>  		goto std_return;
>  
> +	if (xfs_has_parent(mp)) {
> +		error = xfs_parent_init(mp, &parent);
> +		if (error)
> +			goto std_return;
> +	}
> +
>  	/*
>  	 * We try to get the real space reservation first, allowing for
>  	 * directory btree deletion(s) implying possible bmap insert(s).  If we
> @@ -2536,12 +2557,12 @@ xfs_remove(
>  	 * the directory code can handle a reservationless update and we don't
>  	 * want to prevent a user from trying to free space by deleting things.
>  	 */
> -	resblks = XFS_REMOVE_SPACE_RES(mp);
> +	resblks = xfs_remove_space_res(mp, name->len);
>  	error = xfs_trans_alloc_dir(dp, &M_RES(mp)->tr_remove, ip, &resblks,
>  			&tp, &dontcare);
>  	if (error) {
>  		ASSERT(error != -ENOSPC);
> -		goto std_return;
> +		goto drop_incompat;
>  	}
>  
>  	/*
> @@ -2595,12 +2616,18 @@ xfs_remove(
>  	if (error)
>  		goto out_trans_cancel;
>  
> -	error = xfs_dir_removename(tp, dp, name, ip->i_ino, resblks, NULL);
> +	error = xfs_dir_removename(tp, dp, name, ip->i_ino, resblks, &dir_offset);
>  	if (error) {
>  		ASSERT(error != -ENOENT);
>  		goto out_trans_cancel;
>  	}
>  
> +	if (parent) {
> +		error = xfs_parent_defer_remove(tp, dp, parent, dir_offset, ip);
> +		if (error)
> +			goto out_trans_cancel;
> +	}
> +
>  	/*
>  	 * If this is a synchronous mount, make sure that the
>  	 * remove transaction goes to disk before returning to
> @@ -2625,6 +2652,9 @@ xfs_remove(
>   out_unlock:
>  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
>  	xfs_iunlock(dp, XFS_ILOCK_EXCL);
> + drop_incompat:
> +	if (parent)
> +		xfs_parent_cancel(mp, parent);
>   std_return:
>  	return error;
>  }
> -- 
> 2.25.1
> 

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

* Re: [PATCH v4 21/27] xfs: Add parent pointers to rename
  2022-10-21 22:29 ` [PATCH v4 21/27] xfs: Add parent pointers to rename allison.henderson
@ 2022-10-25 21:28   ` Darrick J. Wong
  2022-10-26  7:40     ` Allison Henderson
  0 siblings, 1 reply; 55+ messages in thread
From: Darrick J. Wong @ 2022-10-25 21:28 UTC (permalink / raw)
  To: allison.henderson; +Cc: linux-xfs

On Fri, Oct 21, 2022 at 03:29:30PM -0700, allison.henderson@oracle.com wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> This patch removes the old parent pointer attribute during the rename
> operation, and re-adds the updated parent pointer.  In the case of
> xfs_cross_rename, we modify the routine not to roll the transaction just
> yet.  We will do this after the parent pointer is added in the calling
> xfs_rename function.
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c   |  2 +-
>  fs/xfs/libxfs/xfs_attr.h   |  1 +
>  fs/xfs/libxfs/xfs_parent.c | 31 ++++++++++++
>  fs/xfs/libxfs/xfs_parent.h |  7 +++
>  fs/xfs/xfs_inode.c         | 96 +++++++++++++++++++++++++++++++++++---
>  5 files changed, 130 insertions(+), 7 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index e967728d1ee7..3f9bd8401f33 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -923,7 +923,7 @@ xfs_attr_defer_add(
>  }
>  
>  /* Sets an attribute for an inode as a deferred operation */
> -static int
> +int
>  xfs_attr_defer_replace(
>  	struct xfs_da_args	*args)
>  {
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index 033005542b9e..985761264d1f 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -546,6 +546,7 @@ int xfs_attr_get_ilocked(struct xfs_da_args *args);
>  int xfs_attr_get(struct xfs_da_args *args);
>  int xfs_attr_defer_add(struct xfs_da_args *args);
>  int xfs_attr_defer_remove(struct xfs_da_args *args);
> +int xfs_attr_defer_replace(struct xfs_da_args *args);
>  int xfs_attr_set(struct xfs_da_args *args);
>  int xfs_attr_set_iter(struct xfs_attr_intent *attr);
>  int xfs_attr_remove_iter(struct xfs_attr_intent *attr);
> diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
> index c09f49b7c241..49ac95a301c4 100644
> --- a/fs/xfs/libxfs/xfs_parent.c
> +++ b/fs/xfs/libxfs/xfs_parent.c
> @@ -142,6 +142,37 @@ xfs_parent_defer_remove(
>  	return xfs_attr_defer_remove(args);
>  }
>  
> +
> +int
> +xfs_parent_defer_replace(
> +	struct xfs_trans	*tp,
> +	struct xfs_inode	*old_ip,

old_dp -- we've been (slowly and poorly) trying to name directory inode
pointer variables "dp" instead of "ip".

> +	struct xfs_parent_defer	*old_parent,
> +	xfs_dir2_dataptr_t	old_diroffset,
> +	struct xfs_name		*parent_name,
> +	struct xfs_inode	*new_ip,
> +	struct xfs_parent_defer	*new_parent,
> +	xfs_dir2_dataptr_t	new_diroffset,
> +	struct xfs_inode	*child)
> +{
> +	struct xfs_da_args	*args = &new_parent->args;
> +
> +	xfs_init_parent_name_rec(&old_parent->rec, old_ip, old_diroffset);

Does old_parent get used for anything other than its embedded
xfs_parent_name_rec?

The xfs_da_args structure is already 136 bytes (and probably more with
the additions needed for pptrs) but the parent_name_rec is only 16.  If
old_parent->args is unused, then I think we ought to make
xfs_parent_defer slightly larger instead of going for a second memory
allocation:

struct xfs_parent_defer {
	struct xfs_parent_name_rec	rec;
	struct xfs_parent_name_rec	old_rec;
	struct xfs_da_args		args;
};

	xfs_init_parent_name_rec(&new_parent->old_rec, old_dp,
			old_diroffset);

> +	xfs_init_parent_name_rec(&new_parent->rec, new_ip, new_diroffset);
> +	new_parent->args.name = (const uint8_t *)&old_parent->rec;
> +	new_parent->args.namelen = sizeof(struct xfs_parent_name_rec);
> +	new_parent->args.new_name = (const uint8_t *)&new_parent->rec;
> +	new_parent->args.new_namelen = sizeof(struct xfs_parent_name_rec);
> +	args->trans = tp;
> +	args->dp = child;
> +	if (parent_name) {

Is parent_name ever non-null for a replacement?

> +		new_parent->args.value = (void *)parent_name->name;
> +		new_parent->args.valuelen = parent_name->len;
> +	}
> +	args->hashval = xfs_da_hashname(args->name, args->namelen);
> +	return xfs_attr_defer_replace(args);
> +}
> +
>  void
>  xfs_parent_cancel(
>  	xfs_mount_t		*mp,
> diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h
> index 1c506532c624..5d8966a12084 100644
> --- a/fs/xfs/libxfs/xfs_parent.h
> +++ b/fs/xfs/libxfs/xfs_parent.h
> @@ -27,6 +27,13 @@ int xfs_parent_init(xfs_mount_t *mp, struct xfs_parent_defer **parentp);
>  int xfs_parent_defer_add(struct xfs_trans *tp, struct xfs_parent_defer *parent,
>  			 struct xfs_inode *dp, struct xfs_name *parent_name,
>  			 xfs_dir2_dataptr_t diroffset, struct xfs_inode *child);
> +int xfs_parent_defer_replace(struct xfs_trans *tp, struct xfs_inode *old_ip,
> +			 struct xfs_parent_defer *old_parent,
> +			 xfs_dir2_dataptr_t old_diroffset,
> +			 struct xfs_name *parent_name, struct xfs_inode *new_ip,
> +			 struct xfs_parent_defer *new_parent,
> +			 xfs_dir2_dataptr_t new_diroffset,
> +			 struct xfs_inode *child);
>  int xfs_parent_defer_remove(struct xfs_trans *tp, struct xfs_inode *dp,
>  			    struct xfs_parent_defer *parent,
>  			    xfs_dir2_dataptr_t diroffset,
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index b6b805ea30e5..a882daaeaf63 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -2915,7 +2915,7 @@ xfs_rename_alloc_whiteout(
>  	int			error;
>  
>  	error = xfs_create_tmpfile(mnt_userns, dp, S_IFCHR | WHITEOUT_MODE,
> -				   false, &tmpfile);
> +				   xfs_has_parent(dp->i_mount), &tmpfile);
>  	if (error)
>  		return error;
>  
> @@ -2941,6 +2941,31 @@ xfs_rename_alloc_whiteout(
>  	return 0;
>  }
>  
> +unsigned int
> +xfs_rename_space_res(

XFS_RENAME_SPACE_RES probably can go away now?

--D

> +	struct xfs_mount	*mp,
> +	struct xfs_name		*src_name,
> +	struct xfs_parent_defer	*target_parent_ptr,
> +	struct xfs_name		*target_name,
> +	struct xfs_parent_defer	*new_parent_ptr,
> +	struct xfs_inode	*wip)
> +{
> +	unsigned int		ret;
> +
> +	ret = XFS_DIRREMOVE_SPACE_RES(mp) +
> +			XFS_DIRENTER_SPACE_RES(mp, target_name->len);
> +
> +	if (new_parent_ptr) {
> +		if (wip)
> +			ret += xfs_pptr_calc_space_res(mp, src_name->len);
> +		ret += 2 * xfs_pptr_calc_space_res(mp, target_name->len);
> +	}
> +	if (target_parent_ptr)
> +		ret += xfs_pptr_calc_space_res(mp, target_name->len);
> +
> +	return ret;
> +}
> +
>  /*
>   * xfs_rename
>   */
> @@ -2967,6 +2992,12 @@ xfs_rename(
>  	int				spaceres;
>  	bool				retried = false;
>  	int				error, nospace_error = 0;
> +	xfs_dir2_dataptr_t		new_diroffset;
> +	xfs_dir2_dataptr_t		old_diroffset;
> +	struct xfs_parent_defer		*old_parent_ptr = NULL;
> +	struct xfs_parent_defer		*new_parent_ptr = NULL;
> +	struct xfs_parent_defer		*target_parent_ptr = NULL;
> +	struct xfs_parent_defer		*wip_parent_ptr = NULL;
>  
>  	trace_xfs_rename(src_dp, target_dp, src_name, target_name);
>  
> @@ -2990,10 +3021,29 @@ xfs_rename(
>  
>  	xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip, wip,
>  				inodes, &num_inodes);
> +	if (xfs_has_parent(mp)) {
> +		error = xfs_parent_init(mp, &old_parent_ptr);
> +		if (error)
> +			goto out_release_wip;
> +		error = xfs_parent_init(mp, &new_parent_ptr);
> +		if (error)
> +			goto out_release_wip;
> +		if (wip) {
> +			error = xfs_parent_init(mp, &wip_parent_ptr);
> +			if (error)
> +				goto out_release_wip;
> +		}
> +		if (target_ip != NULL) {
> +			error = xfs_parent_init(mp, &target_parent_ptr);
> +			if (error)
> +				goto out_release_wip;
> +		}
> +	}
>  
>  retry:
>  	nospace_error = 0;
> -	spaceres = XFS_RENAME_SPACE_RES(mp, target_name->len);
> +	spaceres = xfs_rename_space_res(mp, src_name, target_parent_ptr,
> +			target_name, new_parent_ptr, wip);
>  	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_rename, spaceres, 0, 0, &tp);
>  	if (error == -ENOSPC) {
>  		nospace_error = error;
> @@ -3165,7 +3215,7 @@ xfs_rename(
>  		 * to account for the ".." reference from the new entry.
>  		 */
>  		error = xfs_dir_createname(tp, target_dp, target_name,
> -					   src_ip->i_ino, spaceres, NULL);
> +					   src_ip->i_ino, spaceres, &new_diroffset);
>  		if (error)
>  			goto out_trans_cancel;
>  
> @@ -3186,7 +3236,7 @@ xfs_rename(
>  		 * name at the destination directory, remove it first.
>  		 */
>  		error = xfs_dir_replace(tp, target_dp, target_name,
> -					src_ip->i_ino, spaceres, NULL);
> +					src_ip->i_ino, spaceres, &new_diroffset);
>  		if (error)
>  			goto out_trans_cancel;
>  
> @@ -3259,14 +3309,39 @@ xfs_rename(
>  	 */
>  	if (wip)
>  		error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino,
> -					spaceres, NULL);
> +					spaceres, &old_diroffset);
>  	else
>  		error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
> -					   spaceres, NULL);
> +					   spaceres, &old_diroffset);
>  
>  	if (error)
>  		goto out_trans_cancel;
>  
> +	if (new_parent_ptr) {
> +		if (wip) {
> +			error = xfs_parent_defer_add(tp, wip_parent_ptr,
> +						     src_dp, src_name,
> +						     old_diroffset, wip);
> +			if (error)
> +				goto out_trans_cancel;
> +		}
> +
> +		error = xfs_parent_defer_replace(tp, src_dp, old_parent_ptr,
> +						 old_diroffset, target_name,
> +						 target_dp, new_parent_ptr,
> +						 new_diroffset, src_ip);
> +		if (error)
> +			goto out_trans_cancel;
> +	}
> +
> +	if (target_parent_ptr) {
> +		error = xfs_parent_defer_remove(tp, target_dp,
> +						target_parent_ptr,
> +						new_diroffset, target_ip);
> +		if (error)
> +			goto out_trans_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)
> @@ -3281,6 +3356,15 @@ xfs_rename(
>  out_unlock:
>  	xfs_iunlock_after_rename(inodes, num_inodes);
>  out_release_wip:
> +	if (new_parent_ptr)
> +		xfs_parent_cancel(mp, new_parent_ptr);
> +	if (old_parent_ptr)
> +		xfs_parent_cancel(mp, old_parent_ptr);
> +	if (target_parent_ptr)
> +		xfs_parent_cancel(mp, target_parent_ptr);
> +	if (wip_parent_ptr)
> +		xfs_parent_cancel(mp, wip_parent_ptr);
> +
>  	if (wip)
>  		xfs_irele(wip);
>  	if (error == -ENOSPC && nospace_error)
> -- 
> 2.25.1
> 

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

* Re: [PATCH v4 19/27] xfs: Add parent pointers to xfs_cross_rename
  2022-10-21 22:29 ` [PATCH v4 19/27] xfs: Add parent pointers to xfs_cross_rename allison.henderson
@ 2022-10-25 21:32   ` Darrick J. Wong
  2022-10-26  7:40     ` Allison Henderson
  0 siblings, 1 reply; 55+ messages in thread
From: Darrick J. Wong @ 2022-10-25 21:32 UTC (permalink / raw)
  To: allison.henderson; +Cc: linux-xfs

On Fri, Oct 21, 2022 at 03:29:28PM -0700, allison.henderson@oracle.com wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> Cross renames are handled separately from standard renames, and
> need different handling to update the parent attributes correctly.
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
>  fs/xfs/xfs_inode.c | 79 ++++++++++++++++++++++++++++++++++++----------
>  1 file changed, 63 insertions(+), 16 deletions(-)
> 
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 83cc52c2bcf1..c79d1047d118 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -2746,27 +2746,49 @@ xfs_finish_rename(
>   */
>  STATIC int
>  xfs_cross_rename(
> -	struct xfs_trans	*tp,
> -	struct xfs_inode	*dp1,
> -	struct xfs_name		*name1,
> -	struct xfs_inode	*ip1,
> -	struct xfs_inode	*dp2,
> -	struct xfs_name		*name2,
> -	struct xfs_inode	*ip2,
> -	int			spaceres)
> -{
> -	int		error = 0;
> -	int		ip1_flags = 0;
> -	int		ip2_flags = 0;
> -	int		dp2_flags = 0;
> +	struct xfs_trans		*tp,
> +	struct xfs_inode		*dp1,
> +	struct xfs_name			*name1,
> +	struct xfs_inode		*ip1,
> +	struct xfs_inode		*dp2,
> +	struct xfs_name			*name2,
> +	struct xfs_inode		*ip2,
> +	int				spaceres)
> +{
> +	struct xfs_mount		*mp = dp1->i_mount;
> +	int				error = 0;
> +	int				ip1_flags = 0;
> +	int				ip2_flags = 0;
> +	int				dp2_flags = 0;
> +	int				new_diroffset, old_diroffset;
> +	struct xfs_parent_defer		*old_parent_ptr = NULL;
> +	struct xfs_parent_defer		*new_parent_ptr = NULL;
> +	struct xfs_parent_defer		*old_parent_ptr2 = NULL;
> +	struct xfs_parent_defer		*new_parent_ptr2 = NULL;
> +
> +

Nit: extra blank line

> +	if (xfs_has_parent(mp)) {
> +		error = xfs_parent_init(mp, &old_parent_ptr);
> +		if (error)
> +			goto out_trans_abort;
> +		error = xfs_parent_init(mp, &new_parent_ptr);
> +		if (error)
> +			goto out_trans_abort;
> +		error = xfs_parent_init(mp, &old_parent_ptr2);
> +		if (error)
> +			goto out_trans_abort;
> +		error = xfs_parent_init(mp, &new_parent_ptr2);
> +		if (error)
> +			goto out_trans_abort;
> +	}
>  
>  	/* Swap inode number for dirent in first parent */
> -	error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, spaceres, NULL);
> +	error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, spaceres, &old_diroffset);
>  	if (error)
>  		goto out_trans_abort;
>  
>  	/* Swap inode number for dirent in second parent */
> -	error = xfs_dir_replace(tp, dp2, name2, ip1->i_ino, spaceres, NULL);
> +	error = xfs_dir_replace(tp, dp2, name2, ip1->i_ino, spaceres, &new_diroffset);
>  	if (error)
>  		goto out_trans_abort;
>  
> @@ -2827,6 +2849,20 @@ xfs_cross_rename(
>  		}
>  	}
>  
> +	if (xfs_has_parent(mp)) {
> +		error = xfs_parent_defer_replace(tp, dp1,

Isn't xfs_parent_defer_replace() added in the next patch?

> +				old_parent_ptr, old_diroffset, name2, dp2,
> +				new_parent_ptr, new_diroffset, ip1);

The changes to xfs_parent_defer_replace that I mention in the next patch
notwithstanding, this looks good now.

--D

> +		if (error)
> +			goto out_trans_abort;
> +
> +		error = xfs_parent_defer_replace(tp, dp2, new_parent_ptr2,
> +				new_diroffset, name1, dp1, old_parent_ptr2,
> +				old_diroffset, ip2);
> +		if (error)
> +			goto out_trans_abort;
> +	}
> +
>  	if (ip1_flags) {
>  		xfs_trans_ichgtime(tp, ip1, ip1_flags);
>  		xfs_trans_log_inode(tp, ip1, XFS_ILOG_CORE);
> @@ -2841,10 +2877,21 @@ xfs_cross_rename(
>  	}
>  	xfs_trans_ichgtime(tp, dp1, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
>  	xfs_trans_log_inode(tp, dp1, XFS_ILOG_CORE);
> -	return xfs_finish_rename(tp);
>  
> +	error = xfs_finish_rename(tp);
> +	goto out;
>  out_trans_abort:
>  	xfs_trans_cancel(tp);
> +out:
> +	if (new_parent_ptr)
> +		xfs_parent_cancel(mp, new_parent_ptr);
> +	if (old_parent_ptr)
> +		xfs_parent_cancel(mp, old_parent_ptr);
> +	if (new_parent_ptr2)
> +		xfs_parent_cancel(mp, new_parent_ptr2);
> +	if (old_parent_ptr2)
> +		xfs_parent_cancel(mp, old_parent_ptr2);
> +
>  	return error;
>  }
>  
> -- 
> 2.25.1
> 

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

* Re: [PATCH v4 06/27] xfs: Expose init_xattrs in xfs_create_tmpfile
  2022-10-25 19:13   ` Darrick J. Wong
@ 2022-10-25 21:33     ` Darrick J. Wong
  2022-10-26  7:40       ` Allison Henderson
  0 siblings, 1 reply; 55+ messages in thread
From: Darrick J. Wong @ 2022-10-25 21:33 UTC (permalink / raw)
  To: allison.henderson; +Cc: linux-xfs

On Tue, Oct 25, 2022 at 12:13:47PM -0700, Darrick J. Wong wrote:
> On Fri, Oct 21, 2022 at 03:29:15PM -0700, allison.henderson@oracle.com wrote:
> > From: Allison Henderson <allison.henderson@oracle.com>
> > 
> > Tmp files are used as part of rename operations and will need attr forks
> > initialized for parent pointers.  Expose the init_xattrs parameter to
> > the calling function to initialize the fork.
> > 
> > Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> > ---
> >  fs/xfs/xfs_inode.c | 5 +++--
> >  fs/xfs/xfs_inode.h | 2 +-
> >  fs/xfs/xfs_iops.c  | 3 ++-
> >  3 files changed, 6 insertions(+), 4 deletions(-)
> > 
> > diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> > index 44b68fa53a72..8b3aefd146a2 100644
> > --- a/fs/xfs/xfs_inode.c
> > +++ b/fs/xfs/xfs_inode.c
> > @@ -1108,6 +1108,7 @@ xfs_create_tmpfile(
> >  	struct user_namespace	*mnt_userns,
> >  	struct xfs_inode	*dp,
> >  	umode_t			mode,
> > +	bool			init_xattrs,
> >  	struct xfs_inode	**ipp)
> >  {
> >  	struct xfs_mount	*mp = dp->i_mount;
> > @@ -1148,7 +1149,7 @@ xfs_create_tmpfile(
> >  	error = xfs_dialloc(&tp, dp->i_ino, mode, &ino);
> >  	if (!error)
> >  		error = xfs_init_new_inode(mnt_userns, tp, dp, ino, mode,
> > -				0, 0, prid, false, &ip);
> > +				0, 0, prid, init_xattrs, &ip);
> >  	if (error)
> >  		goto out_trans_cancel;
> >  
> > @@ -2748,7 +2749,7 @@ xfs_rename_alloc_whiteout(
> >  	int			error;
> >  
> >  	error = xfs_create_tmpfile(mnt_userns, dp, S_IFCHR | WHITEOUT_MODE,
> > -				   &tmpfile);
> > +				   false, &tmpfile);
> 
> Similar question to last time -- shouldn't we initialize the attr fork
> at whiteout creation time if we know that we're about to add the new
> file to a directory?  IOWs, s/false/xfs_has_parent(mp)/ here?

Aha, you *do* do that later.

Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D


> --D
> 
> >  	if (error)
> >  		return error;
> >  
> > diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
> > index 2eaed98af814..5735de32beeb 100644
> > --- a/fs/xfs/xfs_inode.h
> > +++ b/fs/xfs/xfs_inode.h
> > @@ -478,7 +478,7 @@ int		xfs_create(struct user_namespace *mnt_userns,
> >  			   umode_t mode, dev_t rdev, bool need_xattr,
> >  			   struct xfs_inode **ipp);
> >  int		xfs_create_tmpfile(struct user_namespace *mnt_userns,
> > -			   struct xfs_inode *dp, umode_t mode,
> > +			   struct xfs_inode *dp, umode_t mode, bool init_xattrs,
> >  			   struct xfs_inode **ipp);
> >  int		xfs_remove(struct xfs_inode *dp, struct xfs_name *name,
> >  			   struct xfs_inode *ip);
> > diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> > index 2e10e1c66ad6..10a5e85f2a70 100644
> > --- a/fs/xfs/xfs_iops.c
> > +++ b/fs/xfs/xfs_iops.c
> > @@ -200,7 +200,8 @@ xfs_generic_create(
> >  				xfs_create_need_xattr(dir, default_acl, acl),
> >  				&ip);
> >  	} else {
> > -		error = xfs_create_tmpfile(mnt_userns, XFS_I(dir), mode, &ip);
> > +		error = xfs_create_tmpfile(mnt_userns, XFS_I(dir), mode, false,
> > +					   &ip);
> >  	}
> >  	if (unlikely(error))
> >  		goto out_free_acl;
> > -- 
> > 2.25.1
> > 

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

* Re: [PATCH v4 24/27] xfs: Filter XFS_ATTR_PARENT for getfattr
  2022-10-21 22:29 ` [PATCH v4 24/27] xfs: Filter XFS_ATTR_PARENT for getfattr allison.henderson
@ 2022-10-25 21:34   ` Darrick J. Wong
  2022-10-26  7:40     ` Allison Henderson
  0 siblings, 1 reply; 55+ messages in thread
From: Darrick J. Wong @ 2022-10-25 21:34 UTC (permalink / raw)
  To: allison.henderson; +Cc: linux-xfs

On Fri, Oct 21, 2022 at 03:29:33PM -0700, allison.henderson@oracle.com wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> Parent pointers returned to the get_fattr tool cause errors since
> the tool cannot parse parent pointers.  Fix this by filtering parent
> parent pointers from xfs_xattr_put_listent.
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>

Looks good,
Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> ---
>  fs/xfs/xfs_xattr.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
> index d9067c5f6bd6..5b57f6348d63 100644
> --- a/fs/xfs/xfs_xattr.c
> +++ b/fs/xfs/xfs_xattr.c
> @@ -234,6 +234,9 @@ xfs_xattr_put_listent(
>  
>  	ASSERT(context->count >= 0);
>  
> +	if (flags & XFS_ATTR_PARENT)
> +		return;
> +
>  	if (flags & XFS_ATTR_ROOT) {
>  #ifdef CONFIG_XFS_POSIX_ACL
>  		if (namelen == SGI_ACL_FILE_SIZE &&
> -- 
> 2.25.1
> 

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

* Re: [PATCH v4 24/27] xfs: Filter XFS_ATTR_PARENT for getfattr
  2022-10-25 21:34   ` Darrick J. Wong
@ 2022-10-26  7:40     ` Allison Henderson
  0 siblings, 0 replies; 55+ messages in thread
From: Allison Henderson @ 2022-10-26  7:40 UTC (permalink / raw)
  To: djwong; +Cc: linux-xfs

On Tue, 2022-10-25 at 14:34 -0700, Darrick J. Wong wrote:
> On Fri, Oct 21, 2022 at 03:29:33PM -0700,
> allison.henderson@oracle.com wrote:
> > From: Allison Henderson <allison.henderson@oracle.com>
> > 
> > Parent pointers returned to the get_fattr tool cause errors since
> > the tool cannot parse parent pointers.  Fix this by filtering
> > parent
> > parent pointers from xfs_xattr_put_listent.
> > 
> > Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> 
> Looks good,
> Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Thank you!
Allison
> 
> --D
> 
> > ---
> >  fs/xfs/xfs_xattr.c | 3 +++
> >  1 file changed, 3 insertions(+)
> > 
> > diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
> > index d9067c5f6bd6..5b57f6348d63 100644
> > --- a/fs/xfs/xfs_xattr.c
> > +++ b/fs/xfs/xfs_xattr.c
> > @@ -234,6 +234,9 @@ xfs_xattr_put_listent(
> >  
> >         ASSERT(context->count >= 0);
> >  
> > +       if (flags & XFS_ATTR_PARENT)
> > +               return;
> > +
> >         if (flags & XFS_ATTR_ROOT) {
> >  #ifdef CONFIG_XFS_POSIX_ACL
> >                 if (namelen == SGI_ACL_FILE_SIZE &&
> > -- 
> > 2.25.1
> > 


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

* Re: [PATCH v4 06/27] xfs: Expose init_xattrs in xfs_create_tmpfile
  2022-10-25 21:33     ` Darrick J. Wong
@ 2022-10-26  7:40       ` Allison Henderson
  0 siblings, 0 replies; 55+ messages in thread
From: Allison Henderson @ 2022-10-26  7:40 UTC (permalink / raw)
  To: djwong; +Cc: linux-xfs

On Tue, 2022-10-25 at 14:33 -0700, Darrick J. Wong wrote:
> On Tue, Oct 25, 2022 at 12:13:47PM -0700, Darrick J. Wong wrote:
> > On Fri, Oct 21, 2022 at 03:29:15PM -0700,
> > allison.henderson@oracle.com wrote:
> > > From: Allison Henderson <allison.henderson@oracle.com>
> > > 
> > > Tmp files are used as part of rename operations and will need
> > > attr forks
> > > initialized for parent pointers.  Expose the init_xattrs
> > > parameter to
> > > the calling function to initialize the fork.
> > > 
> > > Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> > > ---
> > >  fs/xfs/xfs_inode.c | 5 +++--
> > >  fs/xfs/xfs_inode.h | 2 +-
> > >  fs/xfs/xfs_iops.c  | 3 ++-
> > >  3 files changed, 6 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> > > index 44b68fa53a72..8b3aefd146a2 100644
> > > --- a/fs/xfs/xfs_inode.c
> > > +++ b/fs/xfs/xfs_inode.c
> > > @@ -1108,6 +1108,7 @@ xfs_create_tmpfile(
> > >         struct user_namespace   *mnt_userns,
> > >         struct xfs_inode        *dp,
> > >         umode_t                 mode,
> > > +       bool                    init_xattrs,
> > >         struct xfs_inode        **ipp)
> > >  {
> > >         struct xfs_mount        *mp = dp->i_mount;
> > > @@ -1148,7 +1149,7 @@ xfs_create_tmpfile(
> > >         error = xfs_dialloc(&tp, dp->i_ino, mode, &ino);
> > >         if (!error)
> > >                 error = xfs_init_new_inode(mnt_userns, tp, dp,
> > > ino, mode,
> > > -                               0, 0, prid, false, &ip);
> > > +                               0, 0, prid, init_xattrs, &ip);
> > >         if (error)
> > >                 goto out_trans_cancel;
> > >  
> > > @@ -2748,7 +2749,7 @@ xfs_rename_alloc_whiteout(
> > >         int                     error;
> > >  
> > >         error = xfs_create_tmpfile(mnt_userns, dp, S_IFCHR |
> > > WHITEOUT_MODE,
> > > -                                  &tmpfile);
> > > +                                  false, &tmpfile);
> > 
> > Similar question to last time -- shouldn't we initialize the attr
> > fork
> > at whiteout creation time if we know that we're about to add the
> > new
> > file to a directory?  IOWs, s/false/xfs_has_parent(mp)/ here?
> 
> Aha, you *do* do that later.
> 
> Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Great!  Thanks!
Allison
> 
> --D
> 
> 
> > --D
> > 
> > >         if (error)
> > >                 return error;
> > >  
> > > diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
> > > index 2eaed98af814..5735de32beeb 100644
> > > --- a/fs/xfs/xfs_inode.h
> > > +++ b/fs/xfs/xfs_inode.h
> > > @@ -478,7 +478,7 @@ int         xfs_create(struct user_namespace
> > > *mnt_userns,
> > >                            umode_t mode, dev_t rdev, bool
> > > need_xattr,
> > >                            struct xfs_inode **ipp);
> > >  int            xfs_create_tmpfile(struct user_namespace
> > > *mnt_userns,
> > > -                          struct xfs_inode *dp, umode_t mode,
> > > +                          struct xfs_inode *dp, umode_t mode,
> > > bool init_xattrs,
> > >                            struct xfs_inode **ipp);
> > >  int            xfs_remove(struct xfs_inode *dp, struct xfs_name
> > > *name,
> > >                            struct xfs_inode *ip);
> > > diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> > > index 2e10e1c66ad6..10a5e85f2a70 100644
> > > --- a/fs/xfs/xfs_iops.c
> > > +++ b/fs/xfs/xfs_iops.c
> > > @@ -200,7 +200,8 @@ xfs_generic_create(
> > >                                 xfs_create_need_xattr(dir,
> > > default_acl, acl),
> > >                                 &ip);
> > >         } else {
> > > -               error = xfs_create_tmpfile(mnt_userns,
> > > XFS_I(dir), mode, &ip);
> > > +               error = xfs_create_tmpfile(mnt_userns,
> > > XFS_I(dir), mode, false,
> > > +                                          &ip);
> > >         }
> > >         if (unlikely(error))
> > >                 goto out_free_acl;
> > > -- 
> > > 2.25.1
> > > 


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

* Re: [PATCH v4 18/27] xfs: remove parent pointers in unlink
  2022-10-25 21:14   ` Darrick J. Wong
@ 2022-10-26  7:40     ` Allison Henderson
  0 siblings, 0 replies; 55+ messages in thread
From: Allison Henderson @ 2022-10-26  7:40 UTC (permalink / raw)
  To: djwong; +Cc: linux-xfs

On Tue, 2022-10-25 at 14:14 -0700, Darrick J. Wong wrote:
> On Fri, Oct 21, 2022 at 03:29:27PM -0700,
> allison.henderson@oracle.com wrote:
> > From: Allison Henderson <allison.henderson@oracle.com>
> > 
> > This patch removes the parent pointer attribute during unlink
> > 
> > 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_attr.h   |  1 +
> >  fs/xfs/libxfs/xfs_parent.c | 17 +++++++++++++++
> >  fs/xfs/libxfs/xfs_parent.h |  4 ++++
> >  fs/xfs/xfs_inode.c         | 44 ++++++++++++++++++++++++++++++++--
> > ----
> >  5 files changed, 60 insertions(+), 8 deletions(-)
> > 
> > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > index 805aaa5639d2..e967728d1ee7 100644
> > --- a/fs/xfs/libxfs/xfs_attr.c
> > +++ b/fs/xfs/libxfs/xfs_attr.c
> > @@ -946,7 +946,7 @@ xfs_attr_defer_replace(
> >  }
> >  
> >  /* Removes an attribute for an inode as a deferred operation */
> > -static int
> > +int
> >  xfs_attr_defer_remove(
> >         struct xfs_da_args      *args)
> >  {
> > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> > index 0cf23f5117ad..033005542b9e 100644
> > --- a/fs/xfs/libxfs/xfs_attr.h
> > +++ b/fs/xfs/libxfs/xfs_attr.h
> > @@ -545,6 +545,7 @@ bool xfs_attr_is_leaf(struct xfs_inode *ip);
> >  int xfs_attr_get_ilocked(struct xfs_da_args *args);
> >  int xfs_attr_get(struct xfs_da_args *args);
> >  int xfs_attr_defer_add(struct xfs_da_args *args);
> > +int xfs_attr_defer_remove(struct xfs_da_args *args);
> >  int xfs_attr_set(struct xfs_da_args *args);
> >  int xfs_attr_set_iter(struct xfs_attr_intent *attr);
> >  int xfs_attr_remove_iter(struct xfs_attr_intent *attr);
> > diff --git a/fs/xfs/libxfs/xfs_parent.c
> > b/fs/xfs/libxfs/xfs_parent.c
> > index cf5ea8ce8bd3..c09f49b7c241 100644
> > --- a/fs/xfs/libxfs/xfs_parent.c
> > +++ b/fs/xfs/libxfs/xfs_parent.c
> > @@ -125,6 +125,23 @@ xfs_parent_defer_add(
> >         return xfs_attr_defer_add(args);
> >  }
> >  
> > +int
> > +xfs_parent_defer_remove(
> > +       struct xfs_trans        *tp,
> > +       struct xfs_inode        *dp,
> > +       struct xfs_parent_defer *parent,
> > +       xfs_dir2_dataptr_t      diroffset,
> > +       struct xfs_inode        *child)
> > +{
> > +       struct xfs_da_args      *args = &parent->args;
> > +
> > +       xfs_init_parent_name_rec(&parent->rec, dp, diroffset);
> > +       args->trans = tp;
> > +       args->dp = child;
> > +       args->hashval = xfs_da_hashname(args->name, args->namelen);
> > +       return xfs_attr_defer_remove(args);
> > +}
> > +
> >  void
> >  xfs_parent_cancel(
> >         xfs_mount_t             *mp,
> > diff --git a/fs/xfs/libxfs/xfs_parent.h
> > b/fs/xfs/libxfs/xfs_parent.h
> > index 9b8d0764aad6..1c506532c624 100644
> > --- a/fs/xfs/libxfs/xfs_parent.h
> > +++ b/fs/xfs/libxfs/xfs_parent.h
> > @@ -27,6 +27,10 @@ int xfs_parent_init(xfs_mount_t *mp, struct
> > xfs_parent_defer **parentp);
> >  int xfs_parent_defer_add(struct xfs_trans *tp, struct
> > xfs_parent_defer *parent,
> >                          struct xfs_inode *dp, struct xfs_name
> > *parent_name,
> >                          xfs_dir2_dataptr_t diroffset, struct
> > xfs_inode *child);
> > +int xfs_parent_defer_remove(struct xfs_trans *tp, struct xfs_inode
> > *dp,
> > +                           struct xfs_parent_defer *parent,
> > +                           xfs_dir2_dataptr_t diroffset,
> > +                           struct xfs_inode *child);
> >  void xfs_parent_cancel(xfs_mount_t *mp, struct xfs_parent_defer
> > *parent);
> >  unsigned int xfs_pptr_calc_space_res(struct xfs_mount *mp,
> >                                      unsigned int namelen);
> > diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> > index f2e7da1befa4..83cc52c2bcf1 100644
> > --- a/fs/xfs/xfs_inode.c
> > +++ b/fs/xfs/xfs_inode.c
> > @@ -2472,6 +2472,19 @@ xfs_iunpin_wait(
> >                 __xfs_iunpin_wait(ip);
> >  }
> >  
> > +unsigned int
> > +xfs_remove_space_res(
> 
> This probably needs to remove XFS_REMOVE_SPACE_RES (the macro) right?
Yes, I think that's ok to remove now.

> 
> With that fixed,
> Reviewed-by: Darrick J. Wong <djwong@kernel.org>
> 
Great, thanks for the reviews!
Allison

> --D
> 
> > +       struct xfs_mount        *mp,
> > +       unsigned int            namelen)
> > +{
> > +       unsigned int            ret = XFS_DIRREMOVE_SPACE_RES(mp);
> > +
> > +       if (xfs_has_parent(mp))
> > +               ret += xfs_pptr_calc_space_res(mp, namelen);
> > +
> > +       return ret;
> > +}
> > +
> >  /*
> >   * Removing an inode from the namespace involves removing the
> > directory entry
> >   * and dropping the link count on the inode. Removing the
> > directory entry can
> > @@ -2501,16 +2514,18 @@ xfs_iunpin_wait(
> >   */
> >  int
> >  xfs_remove(
> > -       xfs_inode_t             *dp,
> > +       struct xfs_inode        *dp,
> >         struct xfs_name         *name,
> > -       xfs_inode_t             *ip)
> > +       struct xfs_inode        *ip)
> >  {
> > -       xfs_mount_t             *mp = dp->i_mount;
> > -       xfs_trans_t             *tp = NULL;
> > +       struct xfs_mount        *mp = dp->i_mount;
> > +       struct xfs_trans        *tp = NULL;
> >         int                     is_dir = S_ISDIR(VFS_I(ip)-
> > >i_mode);
> >         int                     dontcare;
> >         int                     error = 0;
> >         uint                    resblks;
> > +       xfs_dir2_dataptr_t      dir_offset;
> > +       struct xfs_parent_defer *parent = NULL;
> >  
> >         trace_xfs_remove(dp, name);
> >  
> > @@ -2525,6 +2540,12 @@ xfs_remove(
> >         if (error)
> >                 goto std_return;
> >  
> > +       if (xfs_has_parent(mp)) {
> > +               error = xfs_parent_init(mp, &parent);
> > +               if (error)
> > +                       goto std_return;
> > +       }
> > +
> >         /*
> >          * We try to get the real space reservation first, allowing
> > for
> >          * directory btree deletion(s) implying possible bmap
> > insert(s).  If we
> > @@ -2536,12 +2557,12 @@ xfs_remove(
> >          * the directory code can handle a reservationless update
> > and we don't
> >          * want to prevent a user from trying to free space by
> > deleting things.
> >          */
> > -       resblks = XFS_REMOVE_SPACE_RES(mp);
> > +       resblks = xfs_remove_space_res(mp, name->len);
> >         error = xfs_trans_alloc_dir(dp, &M_RES(mp)->tr_remove, ip,
> > &resblks,
> >                         &tp, &dontcare);
> >         if (error) {
> >                 ASSERT(error != -ENOSPC);
> > -               goto std_return;
> > +               goto drop_incompat;
> >         }
> >  
> >         /*
> > @@ -2595,12 +2616,18 @@ xfs_remove(
> >         if (error)
> >                 goto out_trans_cancel;
> >  
> > -       error = xfs_dir_removename(tp, dp, name, ip->i_ino,
> > resblks, NULL);
> > +       error = xfs_dir_removename(tp, dp, name, ip->i_ino,
> > resblks, &dir_offset);
> >         if (error) {
> >                 ASSERT(error != -ENOENT);
> >                 goto out_trans_cancel;
> >         }
> >  
> > +       if (parent) {
> > +               error = xfs_parent_defer_remove(tp, dp, parent,
> > dir_offset, ip);
> > +               if (error)
> > +                       goto out_trans_cancel;
> > +       }
> > +
> >         /*
> >          * If this is a synchronous mount, make sure that the
> >          * remove transaction goes to disk before returning to
> > @@ -2625,6 +2652,9 @@ xfs_remove(
> >   out_unlock:
> >         xfs_iunlock(ip, XFS_ILOCK_EXCL);
> >         xfs_iunlock(dp, XFS_ILOCK_EXCL);
> > + drop_incompat:
> > +       if (parent)
> > +               xfs_parent_cancel(mp, parent);
> >   std_return:
> >         return error;
> >  }
> > -- 
> > 2.25.1
> > 


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

* Re: [PATCH v4 15/27] xfs: parent pointer attribute creation
  2022-10-25 21:11   ` Darrick J. Wong
@ 2022-10-26  7:40     ` Allison Henderson
  0 siblings, 0 replies; 55+ messages in thread
From: Allison Henderson @ 2022-10-26  7:40 UTC (permalink / raw)
  To: djwong; +Cc: linux-xfs

On Tue, 2022-10-25 at 14:11 -0700, Darrick J. Wong wrote:
> On Fri, Oct 21, 2022 at 03:29:24PM -0700,
> allison.henderson@oracle.com wrote:
> > From: Allison Henderson <allison.henderson@oracle.com>
> > 
> > Add parent pointer attribute during xfs_create, and subroutines to
> > initialize attributes
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> > ---
> >  fs/xfs/Makefile            |   1 +
> >  fs/xfs/libxfs/xfs_attr.c   |   4 +-
> >  fs/xfs/libxfs/xfs_attr.h   |   4 +-
> >  fs/xfs/libxfs/xfs_parent.c | 149
> > +++++++++++++++++++++++++++++++++++++
> >  fs/xfs/libxfs/xfs_parent.h |  34 +++++++++
> >  fs/xfs/xfs_inode.c         |  63 ++++++++++++++--
> >  fs/xfs/xfs_xattr.c         |   2 +-
> >  fs/xfs/xfs_xattr.h         |   1 +
> >  8 files changed, 247 insertions(+), 11 deletions(-)
> > 
> > diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
> > index 03135a1c31b6..e2b2cf50ffcf 100644
> > --- a/fs/xfs/Makefile
> > +++ b/fs/xfs/Makefile
> > @@ -40,6 +40,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_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > index 0c9589261990..805aaa5639d2 100644
> > --- a/fs/xfs/libxfs/xfs_attr.c
> > +++ b/fs/xfs/libxfs/xfs_attr.c
> > @@ -886,7 +886,7 @@ xfs_attr_lookup(
> >         return error;
> >  }
> >  
> > -static int
> > +int
> >  xfs_attr_intent_init(
> >         struct xfs_da_args      *args,
> >         unsigned int            op_flags,       /* op flag (set or
> > remove) */
> > @@ -904,7 +904,7 @@ xfs_attr_intent_init(
> >  }
> >  
> >  /* Sets an attribute for an inode as a deferred operation */
> > -static int
> > +int
> >  xfs_attr_defer_add(
> >         struct xfs_da_args      *args)
> >  {
> > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> > index b79dae788cfb..0cf23f5117ad 100644
> > --- a/fs/xfs/libxfs/xfs_attr.h
> > +++ b/fs/xfs/libxfs/xfs_attr.h
> > @@ -544,6 +544,7 @@ int xfs_inode_hasattr(struct xfs_inode *ip);
> >  bool xfs_attr_is_leaf(struct xfs_inode *ip);
> >  int xfs_attr_get_ilocked(struct xfs_da_args *args);
> >  int xfs_attr_get(struct xfs_da_args *args);
> > +int xfs_attr_defer_add(struct xfs_da_args *args);
> >  int xfs_attr_set(struct xfs_da_args *args);
> >  int xfs_attr_set_iter(struct xfs_attr_intent *attr);
> >  int xfs_attr_remove_iter(struct xfs_attr_intent *attr);
> > @@ -552,7 +553,8 @@ bool xfs_attr_namecheck(struct xfs_mount *mp,
> > const void *name, size_t length,
> >  int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
> >  void xfs_init_attr_trans(struct xfs_da_args *args, struct
> > xfs_trans_res *tres,
> >                          unsigned int *total);
> > -
> > +int xfs_attr_intent_init(struct xfs_da_args *args, unsigned int
> > op_flags,
> > +                        struct xfs_attr_intent  **attr);
> >  /*
> >   * Check to see if the attr should be upgraded from non-existent
> > or shortform to
> >   * single-leaf-block attribute list.
> > diff --git a/fs/xfs/libxfs/xfs_parent.c
> > b/fs/xfs/libxfs/xfs_parent.c
> > new file mode 100644
> > index 000000000000..cf5ea8ce8bd3
> > --- /dev/null
> > +++ b/fs/xfs/libxfs/xfs_parent.c
> > @@ -0,0 +1,149 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (c) 2022 Oracle, Inc.
> > + * All rights reserved.
> > + */
> > +#include "xfs.h"
> > +#include "xfs_fs.h"
> > +#include "xfs_format.h"
> > +#include "xfs_da_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_da_btree.h"
> > +#include "xfs_attr.h"
> > +#include "xfs_da_btree.h"
> > +#include "xfs_attr_sf.h"
> > +#include "xfs_bmap.h"
> > +#include "xfs_defer.h"
> > +#include "xfs_log.h"
> > +#include "xfs_xattr.h"
> > +#include "xfs_parent.h"
> > +#include "xfs_trans_space.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 behavior 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,
> > +       struct xfs_inode                *ip,
> > +       uint32_t                        p_diroffset)
> > +{
> > +       xfs_ino_t                       p_ino = ip->i_ino;
> > +       uint32_t                        p_gen = VFS_I(ip)-
> > >i_generation;
> > +
> > +       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);
> > +}
> > +
> > +int
> > +xfs_parent_init(
> > +       struct xfs_mount                *mp,
> > +       struct xfs_parent_defer         **parentp)
> > +{
> > +       struct xfs_parent_defer         *parent;
> > +       int                             error;
> > +
> > +       if (!xfs_has_parent(mp))
> > +               return 0;
> > +
> > +       error = xfs_attr_grab_log_assist(mp);
> > +       if (error)
> > +               return error;
> > +
> > +       parent = kzalloc(sizeof(*parent), GFP_KERNEL);
> 
> I suspect we're still going to want to use a dedicated slab for
> greater
> memory efficiency, but for now this is all right.
> 
> Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Alrighty then, thx for the reviews!
Allison

> 
> --D
> 
> > +       if (!parent)
> > +               return -ENOMEM;
> > +
> > +       /* init parent da_args */
> > +       parent->args.geo = mp->m_attr_geo;
> > +       parent->args.whichfork = XFS_ATTR_FORK;
> > +       parent->args.attr_filter = XFS_ATTR_PARENT;
> > +       parent->args.op_flags = XFS_DA_OP_OKNOENT |
> > XFS_DA_OP_LOGGED;
> > +       parent->args.name = (const uint8_t *)&parent->rec;
> > +       parent->args.namelen = sizeof(struct xfs_parent_name_rec);
> > +
> > +       *parentp = parent;
> > +       return 0;
> > +}
> > +
> > +int
> > +xfs_parent_defer_add(
> > +       struct xfs_trans        *tp,
> > +       struct xfs_parent_defer *parent,
> > +       struct xfs_inode        *dp,
> > +       struct xfs_name         *parent_name,
> > +       xfs_dir2_dataptr_t      diroffset,
> > +       struct xfs_inode        *child)
> > +{
> > +       struct xfs_da_args      *args = &parent->args;
> > +
> > +       xfs_init_parent_name_rec(&parent->rec, dp, diroffset);
> > +       args->hashval = xfs_da_hashname(args->name, args->namelen);
> > +
> > +       args->trans = tp;
> > +       args->dp = child;
> > +       if (parent_name) {
> > +               parent->args.value = (void *)parent_name->name;
> > +               parent->args.valuelen = parent_name->len;
> > +       }
> > +
> > +       return xfs_attr_defer_add(args);
> > +}
> > +
> > +void
> > +xfs_parent_cancel(
> > +       xfs_mount_t             *mp,
> > +       struct xfs_parent_defer *parent)
> > +{
> > +       xlog_drop_incompat_feat(mp->m_log);
> > +       kfree(parent);
> > +}
> > +
> > +unsigned int
> > +xfs_pptr_calc_space_res(
> > +       struct xfs_mount        *mp,
> > +       unsigned int            namelen)
> > +{
> > +       /*
> > +        * Pptrs are always the first attr in an attr tree, and
> > never larger
> > +        * than a block
> > +        */
> > +       return XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) +
> > +              XFS_NEXTENTADD_SPACE_RES(mp, namelen,
> > XFS_ATTR_FORK);
> > +}
> > +
> > diff --git a/fs/xfs/libxfs/xfs_parent.h
> > b/fs/xfs/libxfs/xfs_parent.h
> > new file mode 100644
> > index 000000000000..9b8d0764aad6
> > --- /dev/null
> > +++ b/fs/xfs/libxfs/xfs_parent.h
> > @@ -0,0 +1,34 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (c) 2022 Oracle, Inc.
> > + * All Rights Reserved.
> > + */
> > +#ifndef        __XFS_PARENT_H__
> > +#define        __XFS_PARENT_H__
> > +
> > +/*
> > + * Dynamically allocd structure used to wrap the needed data to
> > pass around
> > + * the defer ops machinery
> > + */
> > +struct xfs_parent_defer {
> > +       struct xfs_parent_name_rec      rec;
> > +       struct xfs_da_args              args;
> > +};
> > +
> > +/*
> > + * Parent pointer attribute prototypes
> > + */
> > +void xfs_init_parent_name_rec(struct xfs_parent_name_rec *rec,
> > +                             struct xfs_inode *ip,
> > +                             uint32_t p_diroffset);
> > +void xfs_init_parent_name_irec(struct xfs_parent_name_irec *irec,
> > +                              struct xfs_parent_name_rec *rec);
> > +int xfs_parent_init(xfs_mount_t *mp, struct xfs_parent_defer
> > **parentp);
> > +int xfs_parent_defer_add(struct xfs_trans *tp, struct
> > xfs_parent_defer *parent,
> > +                        struct xfs_inode *dp, struct xfs_name
> > *parent_name,
> > +                        xfs_dir2_dataptr_t diroffset, struct
> > xfs_inode *child);
> > +void xfs_parent_cancel(xfs_mount_t *mp, struct xfs_parent_defer
> > *parent);
> > +unsigned int xfs_pptr_calc_space_res(struct xfs_mount *mp,
> > +                                    unsigned int namelen);
> > +
> > +#endif /* __XFS_PARENT_H__ */
> > diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> > index ea7aeab839c2..ae6604f51ce8 100644
> > --- a/fs/xfs/xfs_inode.c
> > +++ b/fs/xfs/xfs_inode.c
> > @@ -37,6 +37,8 @@
> >  #include "xfs_reflink.h"
> >  #include "xfs_ag.h"
> >  #include "xfs_log_priv.h"
> > +#include "xfs_parent.h"
> > +#include "xfs_xattr.h"
> >  
> >  struct kmem_cache *xfs_inode_cache;
> >  
> > @@ -946,10 +948,32 @@ xfs_bumplink(
> >         xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
> >  }
> >  
> > +unsigned int
> > +xfs_create_space_res(
> > +       struct xfs_mount        *mp,
> > +       unsigned int            namelen)
> > +{
> > +       unsigned int            ret;
> > +
> > +       ret = XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,
> > namelen);
> > +       if (xfs_has_parent(mp))
> > +               ret += xfs_pptr_calc_space_res(mp, namelen);
> > +
> > +       return ret;
> > +}
> > +
> > +unsigned int
> > +xfs_mkdir_space_res(
> > +       struct xfs_mount        *mp,
> > +       unsigned int            namelen)
> > +{
> > +       return xfs_create_space_res(mp, namelen);
> > +}
> > +
> >  int
> >  xfs_create(
> >         struct user_namespace   *mnt_userns,
> > -       xfs_inode_t             *dp,
> > +       struct xfs_inode        *dp,
> >         struct xfs_name         *name,
> >         umode_t                 mode,
> >         dev_t                   rdev,
> > @@ -961,7 +985,7 @@ xfs_create(
> >         struct xfs_inode        *ip = NULL;
> >         struct xfs_trans        *tp = NULL;
> >         int                     error;
> > -       bool                    unlock_dp_on_error = false;
> > +       bool                    unlock_dp_on_error = false;
> >         prid_t                  prid;
> >         struct xfs_dquot        *udqp = NULL;
> >         struct xfs_dquot        *gdqp = NULL;
> > @@ -969,6 +993,8 @@ xfs_create(
> >         struct xfs_trans_res    *tres;
> >         uint                    resblks;
> >         xfs_ino_t               ino;
> > +       xfs_dir2_dataptr_t      diroffset;
> > +       struct xfs_parent_defer *parent = NULL;
> >  
> >         trace_xfs_create(dp, name);
> >  
> > @@ -988,13 +1014,19 @@ xfs_create(
> >                 return error;
> >  
> >         if (is_dir) {
> > -               resblks = XFS_MKDIR_SPACE_RES(mp, name->len);
> > +               resblks = xfs_mkdir_space_res(mp, name->len);
> >                 tres = &M_RES(mp)->tr_mkdir;
> >         } else {
> > -               resblks = XFS_CREATE_SPACE_RES(mp, name->len);
> > +               resblks = xfs_create_space_res(mp, name->len);
> >                 tres = &M_RES(mp)->tr_create;
> >         }
> >  
> > +       if (xfs_has_parent(mp)) {
> > +               error = xfs_parent_init(mp, &parent);
> > +               if (error)
> > +                       goto out_release_dquots;
> > +       }
> > +
> >         /*
> >          * Initially assume that the file does not exist and
> >          * reserve the resources for that case.  If that is not
> > @@ -1010,7 +1042,7 @@ xfs_create(
> >                                 resblks, &tp);
> >         }
> >         if (error)
> > -               goto out_release_dquots;
> > +               goto drop_incompat;
> >  
> >         xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
> >         unlock_dp_on_error = true;
> > @@ -1020,6 +1052,7 @@ xfs_create(
> >          * entry pointing to them, but a directory also the "."
> > entry
> >          * pointing to itself.
> >          */
> > +       init_xattrs = init_xattrs || xfs_has_parent(mp);
> >         error = xfs_dialloc(&tp, dp->i_ino, mode, &ino);
> >         if (!error)
> >                 error = xfs_init_new_inode(mnt_userns, tp, dp, ino,
> > mode,
> > @@ -1034,11 +1067,12 @@ xfs_create(
> >          * the transaction cancel unlocking dp so don't do it
> > explicitly in the
> >          * error path.
> >          */
> > -       xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
> > +       xfs_trans_ijoin(tp, dp, 0);
> >         unlock_dp_on_error = false;
> >  
> >         error = xfs_dir_createname(tp, dp, name, ip->i_ino,
> > -                                  resblks -
> > XFS_IALLOC_SPACE_RES(mp), NULL);
> > +                                  resblks -
> > XFS_IALLOC_SPACE_RES(mp),
> > +                                  &diroffset);
> >         if (error) {
> >                 ASSERT(error != -ENOSPC);
> >                 goto out_trans_cancel;
> > @@ -1054,6 +1088,17 @@ xfs_create(
> >                 xfs_bumplink(tp, dp);
> >         }
> >  
> > +       /*
> > +        * If we have parent pointers, we need to add the attribute
> > containing
> > +        * the parent information now.
> > +        */
> > +       if (parent) {
> > +               error = xfs_parent_defer_add(tp, parent, dp, name,
> > diroffset,
> > +                                            ip);
> > +               if (error)
> > +                       goto out_trans_cancel;
> > +       }
> > +
> >         /*
> >          * If this is a synchronous mount, make sure that the
> >          * create transaction goes to disk before returning to
> > @@ -1079,6 +1124,7 @@ xfs_create(
> >  
> >         *ipp = ip;
> >         xfs_iunlock(ip, XFS_ILOCK_EXCL);
> > +       xfs_iunlock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
> >         return 0;
> >  
> >   out_trans_cancel:
> > @@ -1093,6 +1139,9 @@ xfs_create(
> >                 xfs_finish_inode_setup(ip);
> >                 xfs_irele(ip);
> >         }
> > + drop_incompat:
> > +       if (parent)
> > +               xfs_parent_cancel(mp, parent);
> >   out_release_dquots:
> >         xfs_qm_dqrele(udqp);
> >         xfs_qm_dqrele(gdqp);
> > diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
> > index c325a28b89a8..d9067c5f6bd6 100644
> > --- a/fs/xfs/xfs_xattr.c
> > +++ b/fs/xfs/xfs_xattr.c
> > @@ -27,7 +27,7 @@
> >   * they must release the permission by calling
> > xlog_drop_incompat_feat
> >   * when they're done.
> >   */
> > -static inline int
> > +int
> >  xfs_attr_grab_log_assist(
> >         struct xfs_mount        *mp)
> >  {
> > diff --git a/fs/xfs/xfs_xattr.h b/fs/xfs/xfs_xattr.h
> > index 2b09133b1b9b..3fd6520a4d69 100644
> > --- a/fs/xfs/xfs_xattr.h
> > +++ b/fs/xfs/xfs_xattr.h
> > @@ -7,6 +7,7 @@
> >  #define __XFS_XATTR_H__
> >  
> >  int xfs_attr_change(struct xfs_da_args *args);
> > +int xfs_attr_grab_log_assist(struct xfs_mount *mp);
> >  
> >  extern const struct xattr_handler *xfs_xattr_handlers[];
> >  
> > -- 
> > 2.25.1
> > 


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

* Re: [PATCH v4 14/27] xfs: extend transaction reservations for parent attributes
  2022-10-25 20:55   ` Darrick J. Wong
@ 2022-10-26  7:40     ` Allison Henderson
  0 siblings, 0 replies; 55+ messages in thread
From: Allison Henderson @ 2022-10-26  7:40 UTC (permalink / raw)
  To: djwong; +Cc: linux-xfs

On Tue, 2022-10-25 at 13:55 -0700, Darrick J. Wong wrote:
> On Fri, Oct 21, 2022 at 03:29:23PM -0700,
> allison.henderson@oracle.com wrote:
> > From: Allison Henderson <allison.henderson@oracle.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.
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> > ---
> >  fs/xfs/libxfs/xfs_trans_resv.c | 303 +++++++++++++++++++++++++++--
> > ----
> >  1 file changed, 249 insertions(+), 54 deletions(-)
> > 
> > diff --git a/fs/xfs/libxfs/xfs_trans_resv.c
> > b/fs/xfs/libxfs/xfs_trans_resv.c
> > index 5b2f27cbdb80..756b6f38c385 100644
> > --- a/fs/xfs/libxfs/xfs_trans_resv.c
> > +++ b/fs/xfs/libxfs/xfs_trans_resv.c
> > @@ -19,6 +19,9 @@
> >  #include "xfs_trans.h"
> >  #include "xfs_qm.h"
> >  #include "xfs_trans_space.h"
> > +#include "xfs_attr_item.h"
> > +#include "xfs_log.h"
> > +#include "xfs_da_format.h"
> >  
> >  #define _ALLOC true
> >  #define _FREE  false
> > @@ -426,23 +429,62 @@ xfs_calc_itruncate_reservation_minlogsize(
> >   *    the two directory btrees: 2 * (max depth + v2) * dir block
> > size
> >   *    the two directory bmap btrees: 2 * max depth * block size
> >   * And the bmap_finish transaction can free dir and bmap blocks
> > (two sets
> > - *     of bmap blocks) giving:
> > + *     of bmap blocks) giving (t2):
> >   *    the agf for the ags in which the blocks live: 3 * sector
> > size
> >   *    the agfl for the ags in which the blocks live: 3 * sector
> > size
> >   *    the superblock for the free block count: sector size
> >   *    the allocation btrees: 3 exts * 2 trees * (2 * max depth -
> > 1) * block size
> > + * If parent pointers are enabled (t3), then each transaction in
> > the chain
> > + *    must be capable of setting or removing the extended
> > attribute
> > + *    containing the parent information.  It must also be able to
> > handle
> > + *    the three xattr intent items that track the progress of the
> > parent
> > + *    pointer update.
> 
> To check my assumptions here: For a standard rename, the three xattr
> intent items are (1) replacing the pptr for the source file; (2)
> removing the pptr on the dest file; and (3) adding a pptr for the
> whiteout file in the src dir?
> 
> For an RENAME_EXCHANGE, there are two xattr intent items to replace
> the
> pptr for both src and dest files.  Link counts don't change and there
> is
> no whiteout, correct?
> 
> >   */
> >  STATIC uint
> >  xfs_calc_rename_reservation(
> >         struct xfs_mount        *mp)
> >  {
> > -       return XFS_DQUOT_LOGRES(mp) +
> > -               max((xfs_calc_inode_res(mp, 5) +
> > -                    xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp),
> > -                                     XFS_FSB_TO_B(mp, 1))),
> > -                   (xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) +
> > -                    xfs_calc_buf_res(xfs_allocfree_block_count(mp,
> > 3),
> > -                                     XFS_FSB_TO_B(mp, 1))));
> > +       unsigned int            overhead = XFS_DQUOT_LOGRES(mp);
> > +       struct xfs_trans_resv   *resp = M_RES(mp);
> > +       unsigned int            t1, t2, t3 = 0;
> > +
> > +       t1 = xfs_calc_inode_res(mp, 5) +
> > +            xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp),
> > +                       XFS_FSB_TO_B(mp, 1));
> > +
> > +       t2 = xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) +
> > +            xfs_calc_buf_res(xfs_allocfree_block_count(mp, 3),
> > +                       XFS_FSB_TO_B(mp, 1));
> > +
> > +       if (xfs_has_parent(mp)) {
> > +               t3 = max(resp->tr_attrsetm.tr_logres,
> > +                               resp->tr_attrrm.tr_logres);
> > +               overhead += 4 * (sizeof(struct xfs_attri_log_item)
> > +
> 
> I'm not sure why this multiplies by four then?
> 
> The log reservation is for the ondisk structures, so the sizeof
> should
> be for xfs_attri_log_format, not xfs_attri_log_item.
> 
> > +                                (2 *
> > xlog_calc_iovec_len(XATTR_NAME_MAX)) +
> 
> I guess the 2 * XATTR_NAME_MAX is to log replacing the old name with
> the new name?
> 
> > +                                xlog_calc_iovec_len(
> > +                                       sizeof(struct
> > xfs_parent_name_rec)));
> 
> And this last one is for the xattr "name", which is just the (parent,
> gen, diroffset) structure?
> 
> I'm concerned about the overhead becoming unnecessarily large here,
> since that all comes out to:
> 
>         4 * (48 +
>              (2 * 256) +
>              16)
> 
>         = 2304 bytes?  Or 1728 bytes if we only multiply by 3?
I think it's 3, I dug back through the revisions and I think I must
have mistakenly switched inode count and pptrs

> 
> Ok, maybe I'm not so concerned after all; 2.3k isn't that large as
> compared to logging entire fsblock buffers.  These namespace
> transactions are 300-400KB in size.  Could this be reduced further,
> though?
> 
> For a regular rename, we're doing a replace, a link, and an unlink.
> 
>         (48 + (2 * 256)) +
>         (48 + 256) +
>         (48)
> 
>         = 912 bytes
> 
> For a RENAME_EXCHANGE, we're doing two replaces:
> 
>         (48 + (2 * 256)) +
>         (48 + (2 * 256))
> 
>         = 1120 bytes
> 
> I'm glad that 1728 is larger than both of those. :)
> 
> Looking forward in this patch, I see the same open-coded overhead
> calculations and wonder what you think of the following refactoring:
> 
> static inline unsigned int xfs_calc_pptr_link_overhead(void)
> {
>         return sizeof(struct xfs_attri_log_format) +
>                         xlog_calc_iovec_len(XATTR_NAME_MAX) +
>                         xlog_calc_iovec_len(sizeof(struct
> xfs_parent_name_rec));
> }
> static inline unsigned int xfs_calc_pptr_unlink_overhead(void)
> {
>         return sizeof(struct xfs_attri_log_format) +
>                         xlog_calc_iovec_len(sizeof(struct
> xfs_parent_name_rec));
> }
> static inline unsigned int xfs_calc_pptr_replace_overhead(void)
> {
>         return sizeof(struct xfs_attri_log_format) +
>                         xlog_calc_iovec_len(XATTR_NAME_MAX) +
>                         xlog_calc_iovec_len(XATTR_NAME_MAX) +
>                         xlog_calc_iovec_len(sizeof(struct
> xfs_parent_name_rec));
> }
I think that's a descent clean up, I'll see if I can work those in

> 
> And then the above becomes:
> 
>         if (xfs_has_parent(mp)) {
>                 unsigned int    rename_overhead, exchange_overhead;
> 
>                 t3 = max(resp->tr_attrsetm.tr_logres,
>                          resp->tr_attrrm.tr_logres);
> 
>                 /*
>                  * For a standard rename, the three xattr intent log
> items
>                  * are (1) replacing the pptr for the source file;
> (2)
>                  * removing the pptr on the dest file; and (3) adding
> a
>                  * pptr for the whiteout file in the src dir.
>                  *
>                  * For an RENAME_EXCHANGE, there are two xattr intent
>                  * items to replace the pptr for both src and dest
>                  * files.  Link counts don't change and there is no
>                  * whiteout.
>                  *
>                  * In the worst case we can end up relogging all log
>                  * intent items to allow the log tail to move ahead,
> so
>                  * they become overhead added to each transaction in
> a
>                  * processing chain.
>                  */
>                 rename_overhead = xfs_calc_pptr_replace_overhead() +
>                                   xfs_calc_pptr_unlink_overhead() +
>                                   xfs_calc_pptr_link_overhead();
>                 exchange_overhead = 2 *
> xfs_calc_pptr_replace_overhead();
> 
>                 overhead += max(rename_overhead, exchange_overhead);
>         }
> 
> You might want to come up with better names though.

xfs_calc_*_parent_overhead?  I'm not super picky with names, so if
there's something folks prefer let me know.

> 
> > +       }
> > +
> > +       return overhead + max3(t1, t2, t3);
> > +}
> > +
> > +static inline unsigned int
> > +xfs_rename_log_count(
> > +       struct xfs_mount        *mp,
> > +       struct xfs_trans_resv   *resp)
> > +{
> > +       /* One for the rename, one more for freeing blocks */
> > +       unsigned int            ret = XFS_RENAME_LOG_COUNT;
> > +
> > +       /*
> > +        * Pre-reserve enough log reservation to handle the
> > transaction
> > +        * rolling needed to remove or add one parent pointer.
> > +        */
> > +       if (xfs_has_parent(mp))
> > +               ret += max(resp->tr_attrsetm.tr_logcount,
> > +                          resp->tr_attrrm.tr_logcount);
> > +
> > +       return ret;
> >  }
> >  
> >  /*
> > @@ -459,6 +501,23 @@ xfs_calc_iunlink_remove_reservation(
> >                2 * M_IGEO(mp)->inode_cluster_size;
> >  }
> >  
> > +static inline unsigned int
> > +xfs_link_log_count(
> > +       struct xfs_mount        *mp,
> > +       struct xfs_trans_resv   *resp)
> > +{
> > +       unsigned int            ret = XFS_LINK_LOG_COUNT;
> > +
> > +       /*
> > +        * Pre-reserve enough log reservation to handle the
> > transaction
> > +        * rolling needed to add one parent pointer.
> > +        */
> > +       if (xfs_has_parent(mp))
> > +               ret += resp->tr_attrsetm.tr_logcount;
> > +
> > +       return ret;
> > +}
> > +
> >  /*
> >   * For creating a link to an inode:
> >   *    the parent directory inode: inode size
> > @@ -475,14 +534,27 @@ STATIC uint
> >  xfs_calc_link_reservation(
> >         struct xfs_mount        *mp)
> >  {
> > -       return XFS_DQUOT_LOGRES(mp) +
> > -               xfs_calc_iunlink_remove_reservation(mp) +
> > -               max((xfs_calc_inode_res(mp, 2) +
> > -                    xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
> > -                                     XFS_FSB_TO_B(mp, 1))),
> > -                   (xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
> > -                    xfs_calc_buf_res(xfs_allocfree_block_count(mp,
> > 1),
> > -                                     XFS_FSB_TO_B(mp, 1))));
> > +       unsigned int            overhead = XFS_DQUOT_LOGRES(mp);
> > +       struct xfs_trans_resv   *resp = M_RES(mp);
> > +       unsigned int            t1, t2, t2_1, t2_2, t3 = 0;
> > +
> > +       t1 = xfs_calc_iunlink_remove_reservation(mp);
> > +       t2_1 = xfs_calc_inode_res(mp, 2) +
> > +              xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
> > XFS_FSB_TO_B(mp, 1));
> > +       t2_2 = xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
> > +              xfs_calc_buf_res(xfs_allocfree_block_count(mp, 1),
> > +                               XFS_FSB_TO_B(mp, 1));
> > +       t2 = max(t2_1, t2_2);
> 
> Add xfs_calc_iunlink_remove_reservation to overhead, rename t2_1 to
> t1
> and t2_2 to t2, and the return statement can become:
> 
>         return overhead + max3(t1, t2, t3);
Ok, will update

> 
> > +
> > +       if (xfs_has_parent(mp)) {
> > +               t3 = resp->tr_attrsetm.tr_logres;
> > +               overhead += sizeof(struct xfs_attri_log_item) +
> > +                           xlog_calc_iovec_len(XATTR_NAME_MAX) +
> > +                           xlog_calc_iovec_len(
> > +                                       sizeof(struct
> > xfs_parent_name_rec));
> 
>                 overhead += xfs_calc_pptr_link_overhead();
Ok, will add
> > +       }
> > +
> > +       return overhead + t1 + t2 + t3;
> >  }
> >  
> >  /*
> > @@ -497,6 +569,23 @@ xfs_calc_iunlink_add_reservation(xfs_mount_t
> > *mp)
> >                         M_IGEO(mp)->inode_cluster_size;
> >  }
> >  
> > +static inline unsigned int
> > +xfs_remove_log_count(
> > +       struct xfs_mount        *mp,
> > +       struct xfs_trans_resv   *resp)
> > +{
> > +       unsigned int            ret = XFS_REMOVE_LOG_COUNT;
> > +
> > +       /*
> > +        * Pre-reserve enough log reservation to handle the
> > transaction
> > +        * rolling needed to add one parent pointer.
> > +        */
> > +       if (xfs_has_parent(mp))
> > +               ret += resp->tr_attrrm.tr_logcount;
> > +
> > +       return ret;
> > +}
> > +
> >  /*
> >   * For removing a directory entry we can modify:
> >   *    the parent directory inode: inode size
> > @@ -513,14 +602,27 @@ STATIC uint
> >  xfs_calc_remove_reservation(
> >         struct xfs_mount        *mp)
> >  {
> > -       return XFS_DQUOT_LOGRES(mp) +
> > -               xfs_calc_iunlink_add_reservation(mp) +
> > -               max((xfs_calc_inode_res(mp, 2) +
> > -                    xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
> > -                                     XFS_FSB_TO_B(mp, 1))),
> > -                   (xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) +
> > -                    xfs_calc_buf_res(xfs_allocfree_block_count(mp,
> > 2),
> > -                                     XFS_FSB_TO_B(mp, 1))));
> > +       unsigned int            overhead = XFS_DQUOT_LOGRES(mp);
> > +       struct xfs_trans_resv   *resp = M_RES(mp);
> > +       unsigned int            t1, t2, t2_1, t2_2, t3 = 0;
> > +
> > +       t1 = xfs_calc_iunlink_add_reservation(mp);
> > +
> > +       t2_1 = xfs_calc_inode_res(mp, 2) +
> > +              xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
> > XFS_FSB_TO_B(mp, 1));
> > +       t2_2 = xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) +
> > +              xfs_calc_buf_res(xfs_allocfree_block_count(mp, 2),
> > +                               XFS_FSB_TO_B(mp, 1));
> > +       t2 = max(t2_1, t2_2);
> 
> Similar to the last _reservation function -- add
> xfs_calc_iunlink_add_reservation to overhead, rename t2_1 to t1 and
> t2_2
> to t2 and the return statement becomes:
> 
>         return overhead + max3(t1, t2, t3);
> 
Right, same thing here

> > +       if (xfs_has_parent(mp)) {
> > +               t3 = resp->tr_attrrm.tr_logres;
> > +               overhead += sizeof(struct xfs_attri_log_item) +
> > +                           xlog_calc_iovec_len(
> > +                                       sizeof(struct
> > xfs_parent_name_rec));
> 
>                 overhead += xfs_calc_pptr_unlink_overhead();
> 
Will update
> > +       }
> > +
> > +       return overhead + t1 + t2 + t3;
> >  }
> >  
> >  /*
> > @@ -569,12 +671,39 @@ xfs_calc_icreate_resv_alloc(
> >                 xfs_calc_finobt_res(mp);
> >  }
> >  
> > +static inline unsigned int
> > +xfs_icreate_log_count(
> > +       struct xfs_mount        *mp,
> > +       struct xfs_trans_resv   *resp)
> > +{
> > +       unsigned int            ret = XFS_CREATE_LOG_COUNT;
> > +
> > +       /*
> > +        * Pre-reserve enough log reservation to handle the
> > transaction
> > +        * rolling needed to add one parent pointer.
> > +        */
> > +       if (xfs_has_parent(mp))
> > +               ret += resp->tr_attrsetm.tr_logcount;
> > +
> > +       return ret;
> > +}
> > +
> >  STATIC uint
> > -xfs_calc_icreate_reservation(xfs_mount_t *mp)
> > +xfs_calc_icreate_reservation(
> > +       struct xfs_mount        *mp)
> >  {
> > -       return XFS_DQUOT_LOGRES(mp) +
> > -               max(xfs_calc_icreate_resv_alloc(mp),
> > -                   xfs_calc_create_resv_modify(mp));
> > +       struct xfs_trans_resv   *resp = M_RES(mp);
> > +       unsigned int            ret = XFS_DQUOT_LOGRES(mp) +
> > +                                    
> > max(xfs_calc_icreate_resv_alloc(mp),
> > +                                    
> > xfs_calc_create_resv_modify(mp));
> 
> Stylistic complaint: Please follow the same format as the other _calc
> functions:
> 
>         unsigned int            overhead = XFS_DQUOT_LOGRES(mp);
>         unsigned int            t1, t2, t3 = 0;
> 
>         t1 = xfs_calc_icreate_resv_alloc(mp);
>         t2 = xfs_calc_create_resv_modify(mp);
> 
>         if (xfs_has_parent(mp)) {
>                 t3 = resp->tr_attrsetm.tr_logres;
>                 overhead += xfs_calc_pptr_link_overhead();
>         }
> 
>         return overhead + max3(t1, t2, t3);
> 
Sure, will update
> > +
> > +       if (xfs_has_parent(mp))
> > +               ret += resp->tr_attrsetm.tr_logres +
> > +                      sizeof(struct xfs_attri_log_item) +
> > +                      xlog_calc_iovec_len(XATTR_NAME_MAX) +
> > +                      xlog_calc_iovec_len(
> > +                                       sizeof(struct
> > xfs_parent_name_rec));
> > +       return ret;
> >  }
> >  
> >  STATIC uint
> > @@ -587,6 +716,23 @@ xfs_calc_create_tmpfile_reservation(
> >         return res + xfs_calc_iunlink_add_reservation(mp);
> >  }
> >  
> > +static inline unsigned int
> > +xfs_mkdir_log_count(
> > +       struct xfs_mount        *mp,
> > +       struct xfs_trans_resv   *resp)
> > +{
> > +       unsigned int            ret = XFS_MKDIR_LOG_COUNT;
> > +
> > +       /*
> > +        * Pre-reserve enough log reservation to handle the
> > transaction
> > +        * rolling needed to add one parent pointer.
> > +        */
> > +       if (xfs_has_parent(mp))
> > +               ret += resp->tr_attrsetm.tr_logcount;
> > +
> > +       return ret;
> > +}
> > +
> >  /*
> >   * Making a new directory is the same as creating a new file.
> >   */
> > @@ -597,6 +743,22 @@ xfs_calc_mkdir_reservation(
> >         return xfs_calc_icreate_reservation(mp);
> >  }
> >  
> > +static inline unsigned int
> > +xfs_symlink_log_count(
> > +       struct xfs_mount        *mp,
> > +       struct xfs_trans_resv   *resp)
> > +{
> > +       unsigned int            ret = XFS_SYMLINK_LOG_COUNT;
> > +
> > +       /*
> > +        * Pre-reserve enough log reservation to handle the
> > transaction
> > +        * rolling needed to add one parent pointer.
> > +        */
> > +       if (xfs_has_parent(mp))
> > +               ret += resp->tr_attrsetm.tr_logcount;
> > +
> > +       return ret;
> > +}
> >  
> >  /*
> >   * Making a new symplink is the same as creating a new file, but
> > @@ -607,8 +769,17 @@ STATIC uint
> >  xfs_calc_symlink_reservation(
> >         struct xfs_mount        *mp)
> >  {
> > -       return xfs_calc_icreate_reservation(mp) +
> > -              xfs_calc_buf_res(1, XFS_SYMLINK_MAXLEN);
> > +       struct xfs_trans_resv   *resp = M_RES(mp);
> > +       unsigned int            ret =
> > xfs_calc_icreate_reservation(mp) +
> > +                                     xfs_calc_buf_res(1,
> > XFS_SYMLINK_MAXLEN);
> > +
> > +       if (xfs_has_parent(mp))
> > +               ret += resp->tr_attrsetm.tr_logres +
> > +                      sizeof(struct xfs_attri_log_item) +
> > +                      xlog_calc_iovec_len(XATTR_NAME_MAX) +
> > +                      xlog_calc_iovec_len(
> > +                                       sizeof(struct
> > xfs_parent_name_rec));
> 
> Didn't we already account for the pptr log item overhead in
> xfs_calc_icreate_reservation?
> 
Oh, I think youre right, so this one can go away.

> > +       return ret;
> >  }
> >  
> >  /*
> > @@ -909,54 +1080,76 @@ xfs_calc_sb_reservation(
> >         return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize);
> >  }
> >  
> > -void
> > -xfs_trans_resv_calc(
> > +/*
> > + * 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
> 
> s/assumes/requires/ since you put in ASSERTs :)
> 
Sure, will update.  Thanks for the reviews!
Allison

> --D
> 
> > + * 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.
> > + */
> > +STATIC void
> > +xfs_calc_namespace_reservations(
> >         struct xfs_mount        *mp,
> >         struct xfs_trans_resv   *resp)
> >  {
> > -       int                     logcount_adj = 0;
> > -
> > -       /*
> > -        * 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,
> > false);
> > -       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, false);
> > -       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;
> > +       resp->tr_rename.tr_logcount = xfs_rename_log_count(mp,
> > resp);
> >         resp->tr_rename.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
> >  
> >         resp->tr_link.tr_logres = xfs_calc_link_reservation(mp);
> > -       resp->tr_link.tr_logcount = XFS_LINK_LOG_COUNT;
> > +       resp->tr_link.tr_logcount = xfs_link_log_count(mp, resp);
> >         resp->tr_link.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
> >  
> >         resp->tr_remove.tr_logres =
> > xfs_calc_remove_reservation(mp);
> > -       resp->tr_remove.tr_logcount = XFS_REMOVE_LOG_COUNT;
> > +       resp->tr_remove.tr_logcount = xfs_remove_log_count(mp,
> > resp);
> >         resp->tr_remove.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
> >  
> >         resp->tr_symlink.tr_logres =
> > xfs_calc_symlink_reservation(mp);
> > -       resp->tr_symlink.tr_logcount = XFS_SYMLINK_LOG_COUNT;
> > +       resp->tr_symlink.tr_logcount = xfs_symlink_log_count(mp,
> > resp);
> >         resp->tr_symlink.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
> >  
> >         resp->tr_create.tr_logres =
> > xfs_calc_icreate_reservation(mp);
> > -       resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT;
> > +       resp->tr_create.tr_logcount = xfs_icreate_log_count(mp,
> > resp);
> >         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(mp, resp);
> > +       resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
> > +}
> > +
> > +void
> > +xfs_trans_resv_calc(
> > +       struct xfs_mount        *mp,
> > +       struct xfs_trans_resv   *resp)
> > +{
> > +       int                     logcount_adj = 0;
> > +
> > +       /*
> > +        * 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,
> > false);
> > +       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, false);
> > +       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;
> > @@ -986,6 +1179,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.25.1
> > 


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

* Re: [PATCH v4 13/27] xfs: Increase rename inode reservation
  2022-10-25 19:15   ` Darrick J. Wong
@ 2022-10-26  7:40     ` Allison Henderson
  0 siblings, 0 replies; 55+ messages in thread
From: Allison Henderson @ 2022-10-26  7:40 UTC (permalink / raw)
  To: djwong; +Cc: linux-xfs

On Tue, 2022-10-25 at 12:15 -0700, Darrick J. Wong wrote:
> On Fri, Oct 21, 2022 at 03:29:22PM -0700,
> allison.henderson@oracle.com wrote:
> > From: Allison Henderson <allison.henderson@oracle.com>
> > 
> > xfs_rename can lock up to 5 inodes: src_dp, target_dp, src_ip,
> > target_ip
> > and wip.  So we need to increase the inode reservation to match.
> > 
> > Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> 
> Looks good, I'll add this to the 6.1 fixes.
> Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Great, thanks!
Allison
> 
> --D
> 
> > ---
> >  fs/xfs/libxfs/xfs_trans_resv.c | 4 ++--
> >  fs/xfs/xfs_inode.c             | 2 +-
> >  2 files changed, 3 insertions(+), 3 deletions(-)
> > 
> > diff --git a/fs/xfs/libxfs/xfs_trans_resv.c
> > b/fs/xfs/libxfs/xfs_trans_resv.c
> > index 2c4ad6e4bb14..5b2f27cbdb80 100644
> > --- a/fs/xfs/libxfs/xfs_trans_resv.c
> > +++ b/fs/xfs/libxfs/xfs_trans_resv.c
> > @@ -422,7 +422,7 @@ xfs_calc_itruncate_reservation_minlogsize(
> >  
> >  /*
> >   * In renaming a files we can modify:
> > - *    the four inodes involved: 4 * inode size
> > + *    the five inodes involved: 5 * inode size
> >   *    the two directory btrees: 2 * (max depth + v2) * dir block
> > size
> >   *    the two directory bmap btrees: 2 * max depth * block size
> >   * And the bmap_finish transaction can free dir and bmap blocks
> > (two sets
> > @@ -437,7 +437,7 @@ xfs_calc_rename_reservation(
> >         struct xfs_mount        *mp)
> >  {
> >         return XFS_DQUOT_LOGRES(mp) +
> > -               max((xfs_calc_inode_res(mp, 4) +
> > +               max((xfs_calc_inode_res(mp, 5) +
> >                      xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp),
> >                                       XFS_FSB_TO_B(mp, 1))),
> >                     (xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) +
> > diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> > index 71d60885000e..ea7aeab839c2 100644
> > --- a/fs/xfs/xfs_inode.c
> > +++ b/fs/xfs/xfs_inode.c
> > @@ -2848,7 +2848,7 @@ xfs_rename(
> >          * Lock all the participating inodes. Depending upon
> > whether
> >          * the target_name exists in the target directory, and
> >          * whether the target directory is the same as the source
> > -        * directory, we can lock from 2 to 4 inodes.
> > +        * directory, we can lock from 2 to 5 inodes.
> >          */
> >         xfs_lock_inodes(inodes, num_inodes, XFS_ILOCK_EXCL);
> >  
> > -- 
> > 2.25.1
> > 


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

* Re: [PATCH v4 01/27] xfs: Add new name to attri/d
  2022-10-25 19:09   ` Darrick J. Wong
@ 2022-10-26  7:40     ` Allison Henderson
  0 siblings, 0 replies; 55+ messages in thread
From: Allison Henderson @ 2022-10-26  7:40 UTC (permalink / raw)
  To: djwong; +Cc: linux-xfs

On Tue, 2022-10-25 at 12:09 -0700, Darrick J. Wong wrote:
> On Fri, Oct 21, 2022 at 03:29:10PM -0700,
> allison.henderson@oracle.com wrote:
> > From: Allison Henderson <allison.henderson@oracle.com>
> > 
> > This patch adds two new fields to the atti/d.  They are nname and
> > nnamelen.  This will be used for parent pointer updates since a
> > rename operation may cause the parent pointer to update both the
> > name and value.  So we need to carry both the new name as well as
> > the target name in the attri/d.
> > 
> > Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> > ---
> >  fs/xfs/libxfs/xfs_attr.c       |  12 +++-
> >  fs/xfs/libxfs/xfs_attr.h       |   4 +-
> >  fs/xfs/libxfs/xfs_da_btree.h   |   2 +
> >  fs/xfs/libxfs/xfs_log_format.h |   6 +-
> >  fs/xfs/xfs_attr_item.c         | 108
> > +++++++++++++++++++++++++++++----
> >  fs/xfs/xfs_attr_item.h         |   1 +
> >  6 files changed, 115 insertions(+), 18 deletions(-)
> 
> <snip all the way to the one thing I noticed>
> 
> > diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
> > index cf5ce607dc05..0c449fb606ed 100644
> > --- a/fs/xfs/xfs_attr_item.c
> > +++ b/fs/xfs/xfs_attr_item.c
> > @@ -731,10 +767,41 @@ xlog_recover_attri_commit_pass2(
> 
> Ahahaha this function.  Could you review this patch that strengthens
> the
> length checking on the incoming recovery item buffers, please?
> 
> https://urldefense.com/v3/__https://lore.kernel.org/linux-xfs/166664715731.2688790.9836328662603103847.stgit@magnolia/__;!!ACWV5N9M2RV99hQ!OutjRUqHArhrP2siuYlLuBIq4FlzRPXu0GgSDtBCK8gD6D1EJYIUzqyyksrA6hreO_duiNUCpFuDCtUTTQEP$
>  
Yes, I saw that, I'll see if I can rebase ontop of it
> 
> >         struct xfs_attri_log_nameval    *nv;
> >         const void                      *attr_value = NULL;
> >         const void                      *attr_name;
> > -       int                             error;
> > +       const void                      *attr_nname = NULL;
> > +       int                             i = 0;
> > +       int                             op, error = 0;
> >  
> > -       attri_formatp = item->ri_buf[0].i_addr;
> > -       attr_name = item->ri_buf[1].i_addr;
> > +       if (item->ri_total == 0) {
> 
> Do all the log intent item types need to check for a nonzero number
> of
> recovery item buffers too?  I /think/ this is unnecessary because
> xlog_recover_add_to_trans will abort recovery if ilf_size == 0, and
> ri_total is assigned to ilf_size:
I think I had modeled this function off of other
xlog_recover_*_commit_pass2 I had observed at the time, so I suspect at
one point they did.  Maybe they dont anymore, I'll see if I can take it
out.

> 
>         if (item->ri_total == 0) {      /* first region to be added
> */
>                 if (in_f->ilf_size == 0 ||
>                     in_f->ilf_size > XLOG_MAX_REGIONS_IN_ITEM) {
>                         xfs_warn(log->l_mp,
>                 "bad number of regions (%d) in inode log format",
>                                   in_f->ilf_size);
>                         ASSERT(0);
>                         kmem_free(ptr);
>                         return -EFSCORRUPTED;
>                 }
> 
>                 item->ri_total = in_f->ilf_size;
> 
> Hm?
> 
> > +               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
> > +               return -EFSCORRUPTED;
> > +       }
> > +
> > +       attri_formatp = item->ri_buf[i].i_addr;
> > +       i++;
> > +
> > +       op = attri_formatp->alfi_op_flags &
> > XFS_ATTRI_OP_FLAGS_TYPE_MASK;
> > +       switch (op) {
> > +       case XFS_ATTRI_OP_FLAGS_SET:
> > +       case XFS_ATTRI_OP_FLAGS_REPLACE:
> > +               if (item->ri_total != 3)
> > +                       error = -EFSCORRUPTED;
> > +               break;
> > +       case XFS_ATTRI_OP_FLAGS_REMOVE:
> > +               if (item->ri_total != 2)
> > +                       error = -EFSCORRUPTED;
> > +               break;
> > +       case XFS_ATTRI_OP_FLAGS_NVREPLACE:
> > +               if (item->ri_total != 4)
> > +                       error = -EFSCORRUPTED;
> > +               break;
> > +       default:
> > +               error = -EFSCORRUPTED;
> > +       }
> > +
> > +       if (error) {
> > +               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
> 
> XFS_ERROR_REPORT is a macro encodes the exact instruction pointer
> location in the error report that it emits.  I know it'll make the
> code
> more verbose, but the macros should be embedded in that switch
> statement
> above.
Ok, will add the individual error reports

> 
> > +               return error;
> > +       }
> >  
> >         /* Validate xfs_attri_log_format before the large memory
> > allocation */
> >         if (!xfs_attri_validate(mp, attri_formatp)) {
> > @@ -742,13 +809,27 @@ xlog_recover_attri_commit_pass2(
> >                 return -EFSCORRUPTED;
> >         }
> >  
> > +       attr_name = item->ri_buf[i].i_addr;
> > +       i++;
> > +
> >         if (!xfs_attr_namecheck(attr_name, attri_formatp-
> > >alfi_name_len)) {
> >                 XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
> >                 return -EFSCORRUPTED;
> >         }
> >  
> > +       if (attri_formatp->alfi_nname_len) {
> 
> This needs to check that the length of the new name iovec buffer is
> what
> we're expecting:
> 
>         if (item->ri_buf[i].i_len !=
>                         xlog_calc_iovec_len(attri_formatp-
> >alfi_nname_len)) {
>                 /* complain... */
>         }
> 
Ok, I will add that check too.

Thanks for the reviews!
Allison

> --D
> 
> > +               attr_nname = item->ri_buf[i].i_addr;
> > +               i++;
> > +
> > +               if (!xfs_attr_namecheck(attr_nname,
> > +                               attri_formatp->alfi_nname_len)) {
> > +                       XFS_ERROR_REPORT(__func__,
> > XFS_ERRLEVEL_LOW, mp);
> > +                       return -EFSCORRUPTED;
> > +               }
> > +       }
> > +
> >         if (attri_formatp->alfi_value_len)
> > -               attr_value = item->ri_buf[2].i_addr;
> > +               attr_value = item->ri_buf[i].i_addr;
> >  
> >         /*
> >          * Memory alloc failure will cause replay to abort.  We
> > attach the
> > @@ -756,7 +837,8 @@ xlog_recover_attri_commit_pass2(
> >          * reference.
> >          */
> >         nv = xfs_attri_log_nameval_alloc(attr_name,
> > -                       attri_formatp->alfi_name_len, attr_value,
> > +                       attri_formatp->alfi_name_len, attr_nname,
> > +                       attri_formatp->alfi_nname_len, attr_value,
> >                         attri_formatp->alfi_value_len);
> >  
> >         attrip = xfs_attri_init(mp, nv);
> > diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h
> > index 3280a7930287..24d4968dd6cc 100644
> > --- a/fs/xfs/xfs_attr_item.h
> > +++ b/fs/xfs/xfs_attr_item.h
> > @@ -13,6 +13,7 @@ struct kmem_zone;
> >  
> >  struct xfs_attri_log_nameval {
> >         struct xfs_log_iovec    name;
> > +       struct xfs_log_iovec    nname;
> >         struct xfs_log_iovec    value;
> >         refcount_t              refcount;
> >  
> > -- 
> > 2.25.1
> > 


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

* Re: [PATCH v4 19/27] xfs: Add parent pointers to xfs_cross_rename
  2022-10-25 21:32   ` Darrick J. Wong
@ 2022-10-26  7:40     ` Allison Henderson
  0 siblings, 0 replies; 55+ messages in thread
From: Allison Henderson @ 2022-10-26  7:40 UTC (permalink / raw)
  To: djwong; +Cc: linux-xfs

On Tue, 2022-10-25 at 14:32 -0700, Darrick J. Wong wrote:
> On Fri, Oct 21, 2022 at 03:29:28PM -0700,
> allison.henderson@oracle.com wrote:
> > From: Allison Henderson <allison.henderson@oracle.com>
> > 
> > Cross renames are handled separately from standard renames, and
> > need different handling to update the parent attributes correctly.
> > 
> > Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> > ---
> >  fs/xfs/xfs_inode.c | 79 ++++++++++++++++++++++++++++++++++++------
> > ----
> >  1 file changed, 63 insertions(+), 16 deletions(-)
> > 
> > diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> > index 83cc52c2bcf1..c79d1047d118 100644
> > --- a/fs/xfs/xfs_inode.c
> > +++ b/fs/xfs/xfs_inode.c
> > @@ -2746,27 +2746,49 @@ xfs_finish_rename(
> >   */
> >  STATIC int
> >  xfs_cross_rename(
> > -       struct xfs_trans        *tp,
> > -       struct xfs_inode        *dp1,
> > -       struct xfs_name         *name1,
> > -       struct xfs_inode        *ip1,
> > -       struct xfs_inode        *dp2,
> > -       struct xfs_name         *name2,
> > -       struct xfs_inode        *ip2,
> > -       int                     spaceres)
> > -{
> > -       int             error = 0;
> > -       int             ip1_flags = 0;
> > -       int             ip2_flags = 0;
> > -       int             dp2_flags = 0;
> > +       struct xfs_trans                *tp,
> > +       struct xfs_inode                *dp1,
> > +       struct xfs_name                 *name1,
> > +       struct xfs_inode                *ip1,
> > +       struct xfs_inode                *dp2,
> > +       struct xfs_name                 *name2,
> > +       struct xfs_inode                *ip2,
> > +       int                             spaceres)
> > +{
> > +       struct xfs_mount                *mp = dp1->i_mount;
> > +       int                             error = 0;
> > +       int                             ip1_flags = 0;
> > +       int                             ip2_flags = 0;
> > +       int                             dp2_flags = 0;
> > +       int                             new_diroffset,
> > old_diroffset;
> > +       struct xfs_parent_defer         *old_parent_ptr = NULL;
> > +       struct xfs_parent_defer         *new_parent_ptr = NULL;
> > +       struct xfs_parent_defer         *old_parent_ptr2 = NULL;
> > +       struct xfs_parent_defer         *new_parent_ptr2 = NULL;
> > +
> > +
> 
> Nit: extra blank line
Ok, will fix

> 
> > +       if (xfs_has_parent(mp)) {
> > +               error = xfs_parent_init(mp, &old_parent_ptr);
> > +               if (error)
> > +                       goto out_trans_abort;
> > +               error = xfs_parent_init(mp, &new_parent_ptr);
> > +               if (error)
> > +                       goto out_trans_abort;
> > +               error = xfs_parent_init(mp, &old_parent_ptr2);
> > +               if (error)
> > +                       goto out_trans_abort;
> > +               error = xfs_parent_init(mp, &new_parent_ptr2);
> > +               if (error)
> > +                       goto out_trans_abort;
> > +       }
> >  
> >         /* Swap inode number for dirent in first parent */
> > -       error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino,
> > spaceres, NULL);
> > +       error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino,
> > spaceres, &old_diroffset);
> >         if (error)
> >                 goto out_trans_abort;
> >  
> >         /* Swap inode number for dirent in second parent */
> > -       error = xfs_dir_replace(tp, dp2, name2, ip1->i_ino,
> > spaceres, NULL);
> > +       error = xfs_dir_replace(tp, dp2, name2, ip1->i_ino,
> > spaceres, &new_diroffset);
> >         if (error)
> >                 goto out_trans_abort;
> >  
> > @@ -2827,6 +2849,20 @@ xfs_cross_rename(
> >                 }
> >         }
> >  
> > +       if (xfs_has_parent(mp)) {
> > +               error = xfs_parent_defer_replace(tp, dp1,
> 
> Isn't xfs_parent_defer_replace() added in the next patch?
> 
> > +                               old_parent_ptr, old_diroffset,
> > name2, dp2,
> > +                               new_parent_ptr, new_diroffset,
> > ip1);
> 
> The changes to xfs_parent_defer_replace that I mention in the next
> patch
> notwithstanding, this looks good now.
> 
Oh I think youre right.  I think probably I can just swap these two
patches and it should be ok.  Thanks!

Allison

> --D
> 
> > +               if (error)
> > +                       goto out_trans_abort;
> > +
> > +               error = xfs_parent_defer_replace(tp, dp2,
> > new_parent_ptr2,
> > +                               new_diroffset, name1, dp1,
> > old_parent_ptr2,
> > +                               old_diroffset, ip2);
> > +               if (error)
> > +                       goto out_trans_abort;
> > +       }
> > +
> >         if (ip1_flags) {
> >                 xfs_trans_ichgtime(tp, ip1, ip1_flags);
> >                 xfs_trans_log_inode(tp, ip1, XFS_ILOG_CORE);
> > @@ -2841,10 +2877,21 @@ xfs_cross_rename(
> >         }
> >         xfs_trans_ichgtime(tp, dp1, XFS_ICHGTIME_MOD |
> > XFS_ICHGTIME_CHG);
> >         xfs_trans_log_inode(tp, dp1, XFS_ILOG_CORE);
> > -       return xfs_finish_rename(tp);
> >  
> > +       error = xfs_finish_rename(tp);
> > +       goto out;
> >  out_trans_abort:
> >         xfs_trans_cancel(tp);
> > +out:
> > +       if (new_parent_ptr)
> > +               xfs_parent_cancel(mp, new_parent_ptr);
> > +       if (old_parent_ptr)
> > +               xfs_parent_cancel(mp, old_parent_ptr);
> > +       if (new_parent_ptr2)
> > +               xfs_parent_cancel(mp, new_parent_ptr2);
> > +       if (old_parent_ptr2)
> > +               xfs_parent_cancel(mp, old_parent_ptr2);
> > +
> >         return error;
> >  }
> >  
> > -- 
> > 2.25.1
> > 


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

* Re: [PATCH v4 21/27] xfs: Add parent pointers to rename
  2022-10-25 21:28   ` Darrick J. Wong
@ 2022-10-26  7:40     ` Allison Henderson
  0 siblings, 0 replies; 55+ messages in thread
From: Allison Henderson @ 2022-10-26  7:40 UTC (permalink / raw)
  To: djwong; +Cc: linux-xfs

On Tue, 2022-10-25 at 14:28 -0700, Darrick J. Wong wrote:
> On Fri, Oct 21, 2022 at 03:29:30PM -0700,
> allison.henderson@oracle.com wrote:
> > From: Allison Henderson <allison.henderson@oracle.com>
> > 
> > This patch removes the old parent pointer attribute during the
> > rename
> > operation, and re-adds the updated parent pointer.  In the case of
> > xfs_cross_rename, we modify the routine not to roll the transaction
> > just
> > yet.  We will do this after the parent pointer is added in the
> > calling
> > xfs_rename function.
> > 
> > Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> > ---
> >  fs/xfs/libxfs/xfs_attr.c   |  2 +-
> >  fs/xfs/libxfs/xfs_attr.h   |  1 +
> >  fs/xfs/libxfs/xfs_parent.c | 31 ++++++++++++
> >  fs/xfs/libxfs/xfs_parent.h |  7 +++
> >  fs/xfs/xfs_inode.c         | 96
> > +++++++++++++++++++++++++++++++++++---
> >  5 files changed, 130 insertions(+), 7 deletions(-)
> > 
> > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > index e967728d1ee7..3f9bd8401f33 100644
> > --- a/fs/xfs/libxfs/xfs_attr.c
> > +++ b/fs/xfs/libxfs/xfs_attr.c
> > @@ -923,7 +923,7 @@ xfs_attr_defer_add(
> >  }
> >  
> >  /* Sets an attribute for an inode as a deferred operation */
> > -static int
> > +int
> >  xfs_attr_defer_replace(
> >         struct xfs_da_args      *args)
> >  {
> > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> > index 033005542b9e..985761264d1f 100644
> > --- a/fs/xfs/libxfs/xfs_attr.h
> > +++ b/fs/xfs/libxfs/xfs_attr.h
> > @@ -546,6 +546,7 @@ int xfs_attr_get_ilocked(struct xfs_da_args
> > *args);
> >  int xfs_attr_get(struct xfs_da_args *args);
> >  int xfs_attr_defer_add(struct xfs_da_args *args);
> >  int xfs_attr_defer_remove(struct xfs_da_args *args);
> > +int xfs_attr_defer_replace(struct xfs_da_args *args);
> >  int xfs_attr_set(struct xfs_da_args *args);
> >  int xfs_attr_set_iter(struct xfs_attr_intent *attr);
> >  int xfs_attr_remove_iter(struct xfs_attr_intent *attr);
> > diff --git a/fs/xfs/libxfs/xfs_parent.c
> > b/fs/xfs/libxfs/xfs_parent.c
> > index c09f49b7c241..49ac95a301c4 100644
> > --- a/fs/xfs/libxfs/xfs_parent.c
> > +++ b/fs/xfs/libxfs/xfs_parent.c
> > @@ -142,6 +142,37 @@ xfs_parent_defer_remove(
> >         return xfs_attr_defer_remove(args);
> >  }
> >  
> > +
> > +int
> > +xfs_parent_defer_replace(
> > +       struct xfs_trans        *tp,
> > +       struct xfs_inode        *old_ip,
> 
> old_dp -- we've been (slowly and poorly) trying to name directory
> inode
> pointer variables "dp" instead of "ip".
Ok, will update name

> 
> > +       struct xfs_parent_defer *old_parent,
> > +       xfs_dir2_dataptr_t      old_diroffset,
> > +       struct xfs_name         *parent_name,
> > +       struct xfs_inode        *new_ip,
> > +       struct xfs_parent_defer *new_parent,
> > +       xfs_dir2_dataptr_t      new_diroffset,
> > +       struct xfs_inode        *child)
> > +{
> > +       struct xfs_da_args      *args = &new_parent->args;
> > +
> > +       xfs_init_parent_name_rec(&old_parent->rec, old_ip,
> > old_diroffset);
> 
> Does old_parent get used for anything other than its embedded
> xfs_parent_name_rec?
> 
I dont think so, so the below change should work.  Will add

> The xfs_da_args structure is already 136 bytes (and probably more
> with
> the additions needed for pptrs) but the parent_name_rec is only 16. 
> If
> old_parent->args is unused, then I think we ought to make
> xfs_parent_defer slightly larger instead of going for a second memory
> allocation:
> 
> struct xfs_parent_defer {
>         struct xfs_parent_name_rec      rec;
>         struct xfs_parent_name_rec      old_rec;
>         struct xfs_da_args              args;
> };
> 
>         xfs_init_parent_name_rec(&new_parent->old_rec, old_dp,
>                         old_diroffset);
> 
> > +       xfs_init_parent_name_rec(&new_parent->rec, new_ip,
> > new_diroffset);
> > +       new_parent->args.name = (const uint8_t *)&old_parent->rec;
> > +       new_parent->args.namelen = sizeof(struct
> > xfs_parent_name_rec);
> > +       new_parent->args.new_name = (const uint8_t *)&new_parent-
> > >rec;
> > +       new_parent->args.new_namelen = sizeof(struct
> > xfs_parent_name_rec);
> > +       args->trans = tp;
> > +       args->dp = child;
> > +       if (parent_name) {
> 
> Is parent_name ever non-null for a replacement?
> 
I dont think so, I will see if I can take the check out

> > +               new_parent->args.value = (void *)parent_name->name;
> > +               new_parent->args.valuelen = parent_name->len;
> > +       }
> > +       args->hashval = xfs_da_hashname(args->name, args->namelen);
> > +       return xfs_attr_defer_replace(args);
> > +}
> > +
> >  void
> >  xfs_parent_cancel(
> >         xfs_mount_t             *mp,
> > diff --git a/fs/xfs/libxfs/xfs_parent.h
> > b/fs/xfs/libxfs/xfs_parent.h
> > index 1c506532c624..5d8966a12084 100644
> > --- a/fs/xfs/libxfs/xfs_parent.h
> > +++ b/fs/xfs/libxfs/xfs_parent.h
> > @@ -27,6 +27,13 @@ int xfs_parent_init(xfs_mount_t *mp, struct
> > xfs_parent_defer **parentp);
> >  int xfs_parent_defer_add(struct xfs_trans *tp, struct
> > xfs_parent_defer *parent,
> >                          struct xfs_inode *dp, struct xfs_name
> > *parent_name,
> >                          xfs_dir2_dataptr_t diroffset, struct
> > xfs_inode *child);
> > +int xfs_parent_defer_replace(struct xfs_trans *tp, struct
> > xfs_inode *old_ip,
> > +                        struct xfs_parent_defer *old_parent,
> > +                        xfs_dir2_dataptr_t old_diroffset,
> > +                        struct xfs_name *parent_name, struct
> > xfs_inode *new_ip,
> > +                        struct xfs_parent_defer *new_parent,
> > +                        xfs_dir2_dataptr_t new_diroffset,
> > +                        struct xfs_inode *child);
> >  int xfs_parent_defer_remove(struct xfs_trans *tp, struct xfs_inode
> > *dp,
> >                             struct xfs_parent_defer *parent,
> >                             xfs_dir2_dataptr_t diroffset,
> > diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> > index b6b805ea30e5..a882daaeaf63 100644
> > --- a/fs/xfs/xfs_inode.c
> > +++ b/fs/xfs/xfs_inode.c
> > @@ -2915,7 +2915,7 @@ xfs_rename_alloc_whiteout(
> >         int                     error;
> >  
> >         error = xfs_create_tmpfile(mnt_userns, dp, S_IFCHR |
> > WHITEOUT_MODE,
> > -                                  false, &tmpfile);
> > +                                  xfs_has_parent(dp->i_mount),
> > &tmpfile);
> >         if (error)
> >                 return error;
> >  
> > @@ -2941,6 +2941,31 @@ xfs_rename_alloc_whiteout(
> >         return 0;
> >  }
> >  
> > +unsigned int
> > +xfs_rename_space_res(
> 
> XFS_RENAME_SPACE_RES probably can go away now?
> 
Yes, will clean out.  Thanks for the reviews!
Allison

> --D
> 
> > +       struct xfs_mount        *mp,
> > +       struct xfs_name         *src_name,
> > +       struct xfs_parent_defer *target_parent_ptr,
> > +       struct xfs_name         *target_name,
> > +       struct xfs_parent_defer *new_parent_ptr,
> > +       struct xfs_inode        *wip)
> > +{
> > +       unsigned int            ret;
> > +
> > +       ret = XFS_DIRREMOVE_SPACE_RES(mp) +
> > +                       XFS_DIRENTER_SPACE_RES(mp, target_name-
> > >len);
> > +
> > +       if (new_parent_ptr) {
> > +               if (wip)
> > +                       ret += xfs_pptr_calc_space_res(mp,
> > src_name->len);
> > +               ret += 2 * xfs_pptr_calc_space_res(mp, target_name-
> > >len);
> > +       }
> > +       if (target_parent_ptr)
> > +               ret += xfs_pptr_calc_space_res(mp, target_name-
> > >len);
> > +
> > +       return ret;
> > +}
> > +
> >  /*
> >   * xfs_rename
> >   */
> > @@ -2967,6 +2992,12 @@ xfs_rename(
> >         int                             spaceres;
> >         bool                            retried = false;
> >         int                             error, nospace_error = 0;
> > +       xfs_dir2_dataptr_t              new_diroffset;
> > +       xfs_dir2_dataptr_t              old_diroffset;
> > +       struct xfs_parent_defer         *old_parent_ptr = NULL;
> > +       struct xfs_parent_defer         *new_parent_ptr = NULL;
> > +       struct xfs_parent_defer         *target_parent_ptr = NULL;
> > +       struct xfs_parent_defer         *wip_parent_ptr = NULL;
> >  
> >         trace_xfs_rename(src_dp, target_dp, src_name, target_name);
> >  
> > @@ -2990,10 +3021,29 @@ xfs_rename(
> >  
> >         xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip,
> > wip,
> >                                 inodes, &num_inodes);
> > +       if (xfs_has_parent(mp)) {
> > +               error = xfs_parent_init(mp, &old_parent_ptr);
> > +               if (error)
> > +                       goto out_release_wip;
> > +               error = xfs_parent_init(mp, &new_parent_ptr);
> > +               if (error)
> > +                       goto out_release_wip;
> > +               if (wip) {
> > +                       error = xfs_parent_init(mp,
> > &wip_parent_ptr);
> > +                       if (error)
> > +                               goto out_release_wip;
> > +               }
> > +               if (target_ip != NULL) {
> > +                       error = xfs_parent_init(mp,
> > &target_parent_ptr);
> > +                       if (error)
> > +                               goto out_release_wip;
> > +               }
> > +       }
> >  
> >  retry:
> >         nospace_error = 0;
> > -       spaceres = XFS_RENAME_SPACE_RES(mp, target_name->len);
> > +       spaceres = xfs_rename_space_res(mp, src_name,
> > target_parent_ptr,
> > +                       target_name, new_parent_ptr, wip);
> >         error = xfs_trans_alloc(mp, &M_RES(mp)->tr_rename,
> > spaceres, 0, 0, &tp);
> >         if (error == -ENOSPC) {
> >                 nospace_error = error;
> > @@ -3165,7 +3215,7 @@ xfs_rename(
> >                  * to account for the ".." reference from the new
> > entry.
> >                  */
> >                 error = xfs_dir_createname(tp, target_dp,
> > target_name,
> > -                                          src_ip->i_ino, spaceres,
> > NULL);
> > +                                          src_ip->i_ino, spaceres,
> > &new_diroffset);
> >                 if (error)
> >                         goto out_trans_cancel;
> >  
> > @@ -3186,7 +3236,7 @@ xfs_rename(
> >                  * name at the destination directory, remove it
> > first.
> >                  */
> >                 error = xfs_dir_replace(tp, target_dp, target_name,
> > -                                       src_ip->i_ino, spaceres,
> > NULL);
> > +                                       src_ip->i_ino, spaceres,
> > &new_diroffset);
> >                 if (error)
> >                         goto out_trans_cancel;
> >  
> > @@ -3259,14 +3309,39 @@ xfs_rename(
> >          */
> >         if (wip)
> >                 error = xfs_dir_replace(tp, src_dp, src_name, wip-
> > >i_ino,
> > -                                       spaceres, NULL);
> > +                                       spaceres, &old_diroffset);
> >         else
> >                 error = xfs_dir_removename(tp, src_dp, src_name,
> > src_ip->i_ino,
> > -                                          spaceres, NULL);
> > +                                          spaceres,
> > &old_diroffset);
> >  
> >         if (error)
> >                 goto out_trans_cancel;
> >  
> > +       if (new_parent_ptr) {
> > +               if (wip) {
> > +                       error = xfs_parent_defer_add(tp,
> > wip_parent_ptr,
> > +                                                    src_dp,
> > src_name,
> > +                                                    old_diroffset,
> > wip);
> > +                       if (error)
> > +                               goto out_trans_cancel;
> > +               }
> > +
> > +               error = xfs_parent_defer_replace(tp, src_dp,
> > old_parent_ptr,
> > +                                                old_diroffset,
> > target_name,
> > +                                                target_dp,
> > new_parent_ptr,
> > +                                                new_diroffset,
> > src_ip);
> > +               if (error)
> > +                       goto out_trans_cancel;
> > +       }
> > +
> > +       if (target_parent_ptr) {
> > +               error = xfs_parent_defer_remove(tp, target_dp,
> > +                                               target_parent_ptr,
> > +                                               new_diroffset,
> > target_ip);
> > +               if (error)
> > +                       goto out_trans_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)
> > @@ -3281,6 +3356,15 @@ xfs_rename(
> >  out_unlock:
> >         xfs_iunlock_after_rename(inodes, num_inodes);
> >  out_release_wip:
> > +       if (new_parent_ptr)
> > +               xfs_parent_cancel(mp, new_parent_ptr);
> > +       if (old_parent_ptr)
> > +               xfs_parent_cancel(mp, old_parent_ptr);
> > +       if (target_parent_ptr)
> > +               xfs_parent_cancel(mp, target_parent_ptr);
> > +       if (wip_parent_ptr)
> > +               xfs_parent_cancel(mp, wip_parent_ptr);
> > +
> >         if (wip)
> >                 xfs_irele(wip);
> >         if (error == -ENOSPC && nospace_error)
> > -- 
> > 2.25.1
> > 


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

* Re: [PATCH v4 02/27] xfs: Increase XFS_DEFER_OPS_NR_INODES to 5
  2022-10-21 22:29 ` [PATCH v4 02/27] xfs: Increase XFS_DEFER_OPS_NR_INODES to 5 allison.henderson
@ 2022-10-28  1:52   ` Catherine Hoang
  0 siblings, 0 replies; 55+ messages in thread
From: Catherine Hoang @ 2022-10-28  1:52 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

> On Oct 21, 2022, at 3:29 PM, allison.henderson@oracle.com wrote:
> 
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> Renames that generate parent pointer updates can join up to 5
> inodes locked in sorted order.  So we need to increase the
> number of defer ops inodes and relock them in the same way.
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> Reviewed-by: Darrick J. Wong <djwong@kernel.org>

Looks good
Reviewed-by: Catherine Hoang <catherine.hoang@oracle.com>
> ---
> fs/xfs/libxfs/xfs_defer.c | 28 ++++++++++++++++++++++++++--
> fs/xfs/libxfs/xfs_defer.h |  8 +++++++-
> fs/xfs/xfs_inode.c        |  2 +-
> fs/xfs/xfs_inode.h        |  1 +
> 4 files changed, 35 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c
> index 5a321b783398..c0279b57e51d 100644
> --- a/fs/xfs/libxfs/xfs_defer.c
> +++ b/fs/xfs/libxfs/xfs_defer.c
> @@ -820,13 +820,37 @@ xfs_defer_ops_continue(
> 	struct xfs_trans		*tp,
> 	struct xfs_defer_resources	*dres)
> {
> -	unsigned int			i;
> +	unsigned int			i, j;
> +	struct xfs_inode		*sips[XFS_DEFER_OPS_NR_INODES];
> +	struct xfs_inode		*temp;
> 
> 	ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
> 	ASSERT(!(tp->t_flags & XFS_TRANS_DIRTY));
> 
> 	/* Lock the captured resources to the new transaction. */
> -	if (dfc->dfc_held.dr_inos == 2)
> +	if (dfc->dfc_held.dr_inos > 2) {
> +		/*
> +		 * Renames with parent pointer updates can lock up to 5 inodes,
> +		 * sorted by their inode number.  So we need to make sure they
> +		 * are relocked in the same way.
> +		 */
> +		memset(sips, 0, sizeof(sips));
> +		for (i = 0; i < dfc->dfc_held.dr_inos; i++)
> +			sips[i] = dfc->dfc_held.dr_ip[i];
> +
> +		/* Bubble sort of at most 5 inodes */
> +		for (i = 0; i < dfc->dfc_held.dr_inos; i++) {
> +			for (j = 1; j < dfc->dfc_held.dr_inos; j++) {
> +				if (sips[j]->i_ino < sips[j-1]->i_ino) {
> +					temp = sips[j];
> +					sips[j] = sips[j-1];
> +					sips[j-1] = temp;
> +				}
> +			}
> +		}
> +
> +		xfs_lock_inodes(sips, dfc->dfc_held.dr_inos, XFS_ILOCK_EXCL);
> +	} else if (dfc->dfc_held.dr_inos == 2)
> 		xfs_lock_two_inodes(dfc->dfc_held.dr_ip[0], XFS_ILOCK_EXCL,
> 				    dfc->dfc_held.dr_ip[1], XFS_ILOCK_EXCL);
> 	else if (dfc->dfc_held.dr_inos == 1)
> diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h
> index 114a3a4930a3..fdf6941f8f4d 100644
> --- a/fs/xfs/libxfs/xfs_defer.h
> +++ b/fs/xfs/libxfs/xfs_defer.h
> @@ -70,7 +70,13 @@ extern const struct xfs_defer_op_type xfs_attr_defer_type;
> /*
>  * Deferred operation item relogging limits.
>  */
> -#define XFS_DEFER_OPS_NR_INODES	2	/* join up to two inodes */
> +
> +/*
> + * Rename w/ parent pointers can require up to 5 inodes with deferred ops to
> + * be joined to the transaction: src_dp, target_dp, src_ip, target_ip, and wip.
> + * These inodes are locked in sorted order by their inode numbers
> + */
> +#define XFS_DEFER_OPS_NR_INODES	5
> #define XFS_DEFER_OPS_NR_BUFS	2	/* join up to two buffers */
> 
> /* Resources that must be held across a transaction roll. */
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index c000b74dd203..5ebbfceb1ada 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -447,7 +447,7 @@ xfs_lock_inumorder(
>  * lock more than one at a time, lockdep will report false positives saying we
>  * have violated locking orders.
>  */
> -static void
> +void
> xfs_lock_inodes(
> 	struct xfs_inode	**ips,
> 	int			inodes,
> diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
> index fa780f08dc89..2eaed98af814 100644
> --- a/fs/xfs/xfs_inode.h
> +++ b/fs/xfs/xfs_inode.h
> @@ -574,5 +574,6 @@ void xfs_end_io(struct work_struct *work);
> 
> int xfs_ilock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
> void xfs_iunlock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
> +void xfs_lock_inodes(struct xfs_inode **ips, int inodes, uint lock_mode);
> 
> #endif	/* __XFS_INODE_H__ */
> -- 
> 2.25.1
> 


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

* Re: [PATCH v4 03/27] xfs: Hold inode locks in xfs_ialloc
  2022-10-21 22:29 ` [PATCH v4 03/27] xfs: Hold inode locks in xfs_ialloc allison.henderson
@ 2022-10-28  1:54   ` Catherine Hoang
  0 siblings, 0 replies; 55+ messages in thread
From: Catherine Hoang @ 2022-10-28  1:54 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

> On Oct 21, 2022, at 3:29 PM, allison.henderson@oracle.com wrote:
> 
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> Modify xfs_ialloc to hold locks after return.  Caller will be
> responsible for manual unlock.  We will need this later to hold locks
> across parent pointer operations
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> Reviewed-by: Darrick J. Wong <djwong@kernel.org>

Looks good
Reviewed-by: Catherine Hoang <catherine.hoang@oracle.com>
> ---
> fs/xfs/xfs_inode.c   | 6 +++++-
> fs/xfs/xfs_qm.c      | 4 +++-
> fs/xfs/xfs_symlink.c | 3 +++
> 3 files changed, 11 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 5ebbfceb1ada..f21f625b428e 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -774,6 +774,8 @@ xfs_inode_inherit_flags2(
> /*
>  * Initialise a newly allocated inode and return the in-core inode to the
>  * caller locked exclusively.
> + *
> + * Caller is responsible for unlocking the inode manually upon return
>  */
> int
> xfs_init_new_inode(
> @@ -899,7 +901,7 @@ xfs_init_new_inode(
> 	/*
> 	 * Log the new values stuffed into the inode.
> 	 */
> -	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
> +	xfs_trans_ijoin(tp, ip, 0);
> 	xfs_trans_log_inode(tp, ip, flags);
> 
> 	/* now that we have an i_mode we can setup the inode structure */
> @@ -1076,6 +1078,7 @@ xfs_create(
> 	xfs_qm_dqrele(pdqp);
> 
> 	*ipp = ip;
> +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
> 	return 0;
> 
>  out_trans_cancel:
> @@ -1172,6 +1175,7 @@ xfs_create_tmpfile(
> 	xfs_qm_dqrele(pdqp);
> 
> 	*ipp = ip;
> +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
> 	return 0;
> 
>  out_trans_cancel:
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index 18bb4ec4d7c9..96e7b4959721 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -818,8 +818,10 @@ xfs_qm_qino_alloc(
> 		ASSERT(xfs_is_shutdown(mp));
> 		xfs_alert(mp, "%s failed (error %d)!", __func__, error);
> 	}
> -	if (need_alloc)
> +	if (need_alloc) {
> 		xfs_finish_inode_setup(*ipp);
> +		xfs_iunlock(*ipp, XFS_ILOCK_EXCL);
> +	}
> 	return error;
> }
> 
> diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
> index 8389f3ef88ef..d8e120913036 100644
> --- a/fs/xfs/xfs_symlink.c
> +++ b/fs/xfs/xfs_symlink.c
> @@ -337,6 +337,7 @@ xfs_symlink(
> 	xfs_qm_dqrele(pdqp);
> 
> 	*ipp = ip;
> +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
> 	return 0;
> 
> out_trans_cancel:
> @@ -358,6 +359,8 @@ xfs_symlink(
> 
> 	if (unlock_dp_on_error)
> 		xfs_iunlock(dp, XFS_ILOCK_EXCL);
> +	if (ip)
> +		xfs_iunlock(ip, XFS_ILOCK_EXCL);
> 	return error;
> }
> 
> -- 
> 2.25.1
> 


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

* Re: [PATCH v4 04/27] xfs: Hold inode locks in xfs_trans_alloc_dir
  2022-10-21 22:29 ` [PATCH v4 04/27] xfs: Hold inode locks in xfs_trans_alloc_dir allison.henderson
@ 2022-10-28  1:56   ` Catherine Hoang
  0 siblings, 0 replies; 55+ messages in thread
From: Catherine Hoang @ 2022-10-28  1:56 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

> On Oct 21, 2022, at 3:29 PM, allison.henderson@oracle.com wrote:
> 
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> Modify xfs_trans_alloc_dir to hold locks after return.  Caller will be
> responsible for manual unlock.  We will need this later to hold locks
> across parent pointer operations
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> Reviewed-by: Darrick J. Wong <djwong@kernel.org>

Looks good
Reviewed-by: Catherine Hoang <catherine.hoang@oracle.com>
> ---
> fs/xfs/xfs_inode.c | 14 ++++++++++++--
> fs/xfs/xfs_trans.c |  6 ++++--
> 2 files changed, 16 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index f21f625b428e..9a3174a8f895 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -1277,10 +1277,15 @@ xfs_link(
> 	if (xfs_has_wsync(mp) || xfs_has_dirsync(mp))
> 		xfs_trans_set_sync(tp);
> 
> -	return xfs_trans_commit(tp);
> +	error = xfs_trans_commit(tp);
> +	xfs_iunlock(tdp, XFS_ILOCK_EXCL);
> +	xfs_iunlock(sip, XFS_ILOCK_EXCL);
> +	return error;
> 
>  error_return:
> 	xfs_trans_cancel(tp);
> +	xfs_iunlock(tdp, XFS_ILOCK_EXCL);
> +	xfs_iunlock(sip, XFS_ILOCK_EXCL);
>  std_return:
> 	if (error == -ENOSPC && nospace_error)
> 		error = nospace_error;
> @@ -2516,15 +2521,20 @@ xfs_remove(
> 
> 	error = xfs_trans_commit(tp);
> 	if (error)
> -		goto std_return;
> +		goto out_unlock;
> 
> 	if (is_dir && xfs_inode_is_filestream(ip))
> 		xfs_filestream_deassociate(ip);
> 
> +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
> +	xfs_iunlock(dp, XFS_ILOCK_EXCL);
> 	return 0;
> 
>  out_trans_cancel:
> 	xfs_trans_cancel(tp);
> + out_unlock:
> +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
> +	xfs_iunlock(dp, XFS_ILOCK_EXCL);
>  std_return:
> 	return error;
> }
> diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
> index 7bd16fbff534..ac98ff416e54 100644
> --- a/fs/xfs/xfs_trans.c
> +++ b/fs/xfs/xfs_trans.c
> @@ -1356,6 +1356,8 @@ xfs_trans_alloc_ichange(
>  * The caller must ensure that the on-disk dquots attached to this inode have
>  * already been allocated and initialized.  The ILOCKs will be dropped when the
>  * transaction is committed or cancelled.
> + *
> + * Caller is responsible for unlocking the inodes manually upon return
>  */
> int
> xfs_trans_alloc_dir(
> @@ -1386,8 +1388,8 @@ xfs_trans_alloc_dir(
> 
> 	xfs_lock_two_inodes(dp, XFS_ILOCK_EXCL, ip, XFS_ILOCK_EXCL);
> 
> -	xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
> -	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
> +	xfs_trans_ijoin(tp, dp, 0);
> +	xfs_trans_ijoin(tp, ip, 0);
> 
> 	error = xfs_qm_dqattach_locked(dp, false);
> 	if (error) {
> -- 
> 2.25.1
> 


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

* Re: [PATCH v4 05/27] xfs: Hold inode locks in xfs_rename
  2022-10-21 22:29 ` [PATCH v4 05/27] xfs: Hold inode locks in xfs_rename allison.henderson
@ 2022-10-28  1:59   ` Catherine Hoang
  0 siblings, 0 replies; 55+ messages in thread
From: Catherine Hoang @ 2022-10-28  1:59 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

> On Oct 21, 2022, at 3:29 PM, allison.henderson@oracle.com wrote:
> 
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> Modify xfs_rename to hold all inode locks across a rename operation
> We will need this later when we add parent pointers
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> Reviewed-by: Darrick J. Wong <djwong@kernel.org>

Looks good
Reviewed-by: Catherine Hoang <catherine.hoang@oracle.com>
> ---
> fs/xfs/xfs_inode.c | 42 +++++++++++++++++++++++++++++-------------
> 1 file changed, 29 insertions(+), 13 deletions(-)
> 
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 9a3174a8f895..44b68fa53a72 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -2539,6 +2539,21 @@ xfs_remove(
> 	return error;
> }
> 
> +static inline void
> +xfs_iunlock_after_rename(
> +	struct xfs_inode	**i_tab,
> +	int			num_inodes)
> +{
> +	int			i;
> +
> +	for (i = num_inodes - 1; i >= 0; i--) {
> +		/* Skip duplicate inodes if src and target dps are the same */
> +		if (!i_tab[i] || (i > 0 && i_tab[i] == i_tab[i - 1]))
> +			continue;
> +		xfs_iunlock(i_tab[i], XFS_ILOCK_EXCL);
> +	}
> +}
> +
> /*
>  * Enter all inodes for a rename transaction into a sorted array.
>  */
> @@ -2837,18 +2852,16 @@ xfs_rename(
> 	xfs_lock_inodes(inodes, num_inodes, XFS_ILOCK_EXCL);
> 
> 	/*
> -	 * Join all the inodes to the transaction. From this point on,
> -	 * we can rely on either trans_commit or trans_cancel to unlock
> -	 * them.
> +	 * Join all the inodes to the transaction.
> 	 */
> -	xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL);
> +	xfs_trans_ijoin(tp, src_dp, 0);
> 	if (new_parent)
> -		xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL);
> -	xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
> +		xfs_trans_ijoin(tp, target_dp, 0);
> +	xfs_trans_ijoin(tp, src_ip, 0);
> 	if (target_ip)
> -		xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
> +		xfs_trans_ijoin(tp, target_ip, 0);
> 	if (wip)
> -		xfs_trans_ijoin(tp, wip, XFS_ILOCK_EXCL);
> +		xfs_trans_ijoin(tp, wip, 0);
> 
> 	/*
> 	 * If we are using project inheritance, we only allow renames
> @@ -2862,10 +2875,12 @@ xfs_rename(
> 	}
> 
> 	/* RENAME_EXCHANGE is unique from here on. */
> -	if (flags & RENAME_EXCHANGE)
> -		return xfs_cross_rename(tp, src_dp, src_name, src_ip,
> +	if (flags & RENAME_EXCHANGE) {
> +		error = xfs_cross_rename(tp, src_dp, src_name, src_ip,
> 					target_dp, target_name, target_ip,
> 					spaceres);
> +		goto out_unlock;
> +	}
> 
> 	/*
> 	 * Try to reserve quota to handle an expansion of the target directory.
> @@ -3090,12 +3105,13 @@ xfs_rename(
> 		xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE);
> 
> 	error = xfs_finish_rename(tp);
> -	if (wip)
> -		xfs_irele(wip);
> -	return error;
> +
> +	goto out_unlock;
> 
> out_trans_cancel:
> 	xfs_trans_cancel(tp);
> +out_unlock:
> +	xfs_iunlock_after_rename(inodes, num_inodes);
> out_release_wip:
> 	if (wip)
> 		xfs_irele(wip);
> -- 
> 2.25.1
> 


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

* Re: [PATCH v4 07/27] xfs: get directory offset when adding directory name
  2022-10-21 22:29 ` [PATCH v4 07/27] xfs: get directory offset when adding directory name allison.henderson
@ 2022-10-28  2:02   ` Catherine Hoang
  0 siblings, 0 replies; 55+ messages in thread
From: Catherine Hoang @ 2022-10-28  2:02 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

> On Oct 21, 2022, at 3:29 PM, allison.henderson@oracle.com wrote:
> 
> From: Allison Henderson <allison.henderson@oracle.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.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> Reviewed-by: Darrick J. Wong <djwong@kernel.org>

Looks good
Reviewed-by: Catherine Hoang <catherine.hoang@oracle.com>
> ---
> fs/xfs/libxfs/xfs_da_btree.h   | 1 +
> fs/xfs/libxfs/xfs_dir2.c       | 9 +++++++--
> fs/xfs/libxfs/xfs_dir2.h       | 2 +-
> 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             | 6 +++---
> fs/xfs/xfs_symlink.c           | 3 ++-
> 9 files changed, 21 insertions(+), 7 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
> index a4b29827603f..90b86d00258f 100644
> --- a/fs/xfs/libxfs/xfs_da_btree.h
> +++ b/fs/xfs/libxfs/xfs_da_btree.h
> @@ -81,6 +81,7 @@ typedef struct xfs_da_args {
> 	int		rmtvaluelen2;	/* remote attr value length in bytes */
> 	uint32_t	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 92bac3373f1f..69a6561c22cc 100644
> --- a/fs/xfs/libxfs/xfs_dir2.c
> +++ b/fs/xfs/libxfs/xfs_dir2.c
> @@ -257,7 +257,8 @@ xfs_dir_createname(
> 	struct xfs_inode	*dp,
> 	const struct xfs_name	*name,
> 	xfs_ino_t		inum,		/* new entry inode number */
> -	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;
> @@ -312,6 +313,10 @@ xfs_dir_createname(
> 		rval = xfs_dir2_node_addname(args);
> 
> out_free:
> +	/* return the location that this entry was place in the parent inode */
> +	if (offset)
> +		*offset = args->offset;
> +
> 	kmem_free(args);
> 	return rval;
> }
> @@ -550,7 +555,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, 0);
> +	return xfs_dir_createname(tp, dp, name, 0, 0, NULL);
> }
> 
> /*
> diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
> index dd39f17dd9a9..d96954478696 100644
> --- a/fs/xfs/libxfs/xfs_dir2.h
> +++ b/fs/xfs/libxfs/xfs_dir2.h
> @@ -40,7 +40,7 @@ extern int xfs_dir_init(struct xfs_trans *tp, struct xfs_inode *dp,
> 				struct xfs_inode *pdp);
> extern int xfs_dir_createname(struct xfs_trans *tp, struct xfs_inode *dp,
> 				const struct xfs_name *name, xfs_ino_t inum,
> -				xfs_extlen_t tot);
> +				xfs_extlen_t tot, xfs_dir2_dataptr_t *offset);
> extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
> 				const 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 00f960a703b2..70aeab9d2a12 100644
> --- a/fs/xfs/libxfs/xfs_dir2_block.c
> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
> @@ -573,6 +573,7 @@ xfs_dir2_block_addname(
> 	xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
> 	tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, 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 cb9e950a911d..9ab520b66547 100644
> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
> @@ -870,6 +870,8 @@ xfs_dir2_leaf_addname(
> 	xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
> 	tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, 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 7a03aeb9f4c9..5a9513c036b8 100644
> --- a/fs/xfs/libxfs/xfs_dir2_node.c
> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
> @@ -1974,6 +1974,8 @@ xfs_dir2_node_addname_int(
> 	xfs_dir2_data_put_ftype(dp->i_mount, dep, args->filetype);
> 	tagp = xfs_dir2_data_entry_tag_p(dp->i_mount, 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 freespace and log the data block if needed. */
> diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
> index 8cd37e6e9d38..44bc4ba3da8a 100644
> --- a/fs/xfs/libxfs/xfs_dir2_sf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_sf.c
> @@ -485,6 +485,7 @@ xfs_dir2_sf_addname_easy(
> 	memcpy(sfep->name, args->name, sfep->namelen);
> 	xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
> 	xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
> +	args->offset = xfs_dir2_byte_to_dataptr(offset);
> 
> 	/*
> 	 * Update the header and inode.
> @@ -575,6 +576,7 @@ xfs_dir2_sf_addname_hard(
> 	memcpy(sfep->name, args->name, sfep->namelen);
> 	xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
> 	xfs_dir2_sf_put_ftype(mp, 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 8b3aefd146a2..229bc126b7c8 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -1038,7 +1038,7 @@ xfs_create(
> 	unlock_dp_on_error = false;
> 
> 	error = xfs_dir_createname(tp, dp, name, ip->i_ino,
> -					resblks - XFS_IALLOC_SPACE_RES(mp));
> +				   resblks - XFS_IALLOC_SPACE_RES(mp), NULL);
> 	if (error) {
> 		ASSERT(error != -ENOSPC);
> 		goto out_trans_cancel;
> @@ -1262,7 +1262,7 @@ xfs_link(
> 	}
> 
> 	error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
> -				   resblks);
> +				   resblks, NULL);
> 	if (error)
> 		goto error_return;
> 	xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
> @@ -2998,7 +2998,7 @@ xfs_rename(
> 		 * to account for the ".." reference from the new entry.
> 		 */
> 		error = xfs_dir_createname(tp, target_dp, target_name,
> -					   src_ip->i_ino, spaceres);
> +					   src_ip->i_ino, spaceres, NULL);
> 		if (error)
> 			goto out_trans_cancel;
> 
> diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
> index d8e120913036..27a7d7c57015 100644
> --- a/fs/xfs/xfs_symlink.c
> +++ b/fs/xfs/xfs_symlink.c
> @@ -314,7 +314,8 @@ xfs_symlink(
> 	/*
> 	 * Create the directory entry for the symlink.
> 	 */
> -	error = xfs_dir_createname(tp, dp, link_name, ip->i_ino, resblks);
> +	error = xfs_dir_createname(tp, dp, link_name,
> +			ip->i_ino, resblks, NULL);
> 	if (error)
> 		goto out_trans_cancel;
> 	xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
> -- 
> 2.25.1
> 


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

* Re: [PATCH v4 08/27] xfs: get directory offset when removing directory name
  2022-10-21 22:29 ` [PATCH v4 08/27] xfs: get directory offset when removing " allison.henderson
@ 2022-10-28  2:06   ` Catherine Hoang
  0 siblings, 0 replies; 55+ messages in thread
From: Catherine Hoang @ 2022-10-28  2:06 UTC (permalink / raw)
  To: Allison Henderson; +Cc: linux-xfs

> On Oct 21, 2022, at 3:29 PM, allison.henderson@oracle.com wrote:
> 
> From: Allison Henderson <allison.henderson@oracle.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.
> 
> 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>
> Reviewed-by: Darrick J. Wong <djwong@kernel.org>

Looks good
Reviewed-by: Catherine Hoang <catherine.hoang@oracle.com>
> ---
> fs/xfs/libxfs/xfs_dir2.c       | 6 +++++-
> fs/xfs/libxfs/xfs_dir2.h       | 3 ++-
> 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             | 4 ++--
> 7 files changed, 19 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
> index 69a6561c22cc..891c1f701f53 100644
> --- a/fs/xfs/libxfs/xfs_dir2.c
> +++ b/fs/xfs/libxfs/xfs_dir2.c
> @@ -436,7 +436,8 @@ xfs_dir_removename(
> 	struct xfs_inode	*dp,
> 	struct xfs_name		*name,
> 	xfs_ino_t		ino,
> -	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;
> @@ -481,6 +482,9 @@ xfs_dir_removename(
> 	else
> 		rval = xfs_dir2_node_removename(args);
> out_free:
> +	if (offset)
> +		*offset = args->offset;
> +
> 	kmem_free(args);
> 	return rval;
> }
> diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
> index d96954478696..0c2d7c0af78f 100644
> --- a/fs/xfs/libxfs/xfs_dir2.h
> +++ b/fs/xfs/libxfs/xfs_dir2.h
> @@ -46,7 +46,8 @@ extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
> 				struct xfs_name *ci_name);
> extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
> 				struct xfs_name *name, xfs_ino_t ino,
> -				xfs_extlen_t tot);
> +				xfs_extlen_t tot,
> +				xfs_dir2_dataptr_t *offset);
> extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
> 				const struct xfs_name *name, xfs_ino_t inum,
> 				xfs_extlen_t tot);
> diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
> index 70aeab9d2a12..d36f3f1491da 100644
> --- a/fs/xfs/libxfs/xfs_dir2_block.c
> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
> @@ -810,9 +810,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 9ab520b66547..b4a066259d97 100644
> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
> @@ -1386,9 +1386,10 @@ xfs_dir2_leaf_removename(
> 	 * Point to the leaf entry, use that to point to the data entry.
> 	 */
> 	lep = &leafhdr.ents[index];
> -	db = xfs_dir2_dataptr_to_db(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(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(geo, leaf);
> diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
> index 5a9513c036b8..39cbdeafa0f6 100644
> --- a/fs/xfs/libxfs/xfs_dir2_node.c
> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
> @@ -1296,9 +1296,10 @@ xfs_dir2_leafn_remove(
> 	/*
> 	 * Extract the data block and offset from the entry.
> 	 */
> -	db = xfs_dir2_dataptr_to_db(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(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 44bc4ba3da8a..b49578a547b3 100644
> --- a/fs/xfs/libxfs/xfs_dir2_sf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_sf.c
> @@ -969,6 +969,8 @@ xfs_dir2_sf_removename(
> 								XFS_CMP_EXACT) {
> 			ASSERT(xfs_dir2_sf_get_ino(mp, 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 229bc126b7c8..a0d5761e1fee 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -2506,7 +2506,7 @@ xfs_remove(
> 	if (error)
> 		goto out_trans_cancel;
> 
> -	error = xfs_dir_removename(tp, dp, name, ip->i_ino, resblks);
> +	error = xfs_dir_removename(tp, dp, name, ip->i_ino, resblks, NULL);
> 	if (error) {
> 		ASSERT(error != -ENOENT);
> 		goto out_trans_cancel;
> @@ -3095,7 +3095,7 @@ xfs_rename(
> 					spaceres);
> 	else
> 		error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
> -					   spaceres);
> +					   spaceres, NULL);
> 
> 	if (error)
> 		goto out_trans_cancel;
> -- 
> 2.25.1
> 


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

end of thread, other threads:[~2022-10-28  2:06 UTC | newest]

Thread overview: 55+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-21 22:29 [PATCH v4 00/27] Parent Pointers allison.henderson
2022-10-21 22:29 ` [PATCH v4 01/27] xfs: Add new name to attri/d allison.henderson
2022-10-25 19:09   ` Darrick J. Wong
2022-10-26  7:40     ` Allison Henderson
2022-10-21 22:29 ` [PATCH v4 02/27] xfs: Increase XFS_DEFER_OPS_NR_INODES to 5 allison.henderson
2022-10-28  1:52   ` Catherine Hoang
2022-10-21 22:29 ` [PATCH v4 03/27] xfs: Hold inode locks in xfs_ialloc allison.henderson
2022-10-28  1:54   ` Catherine Hoang
2022-10-21 22:29 ` [PATCH v4 04/27] xfs: Hold inode locks in xfs_trans_alloc_dir allison.henderson
2022-10-28  1:56   ` Catherine Hoang
2022-10-21 22:29 ` [PATCH v4 05/27] xfs: Hold inode locks in xfs_rename allison.henderson
2022-10-28  1:59   ` Catherine Hoang
2022-10-21 22:29 ` [PATCH v4 06/27] xfs: Expose init_xattrs in xfs_create_tmpfile allison.henderson
2022-10-25 19:13   ` Darrick J. Wong
2022-10-25 21:33     ` Darrick J. Wong
2022-10-26  7:40       ` Allison Henderson
2022-10-21 22:29 ` [PATCH v4 07/27] xfs: get directory offset when adding directory name allison.henderson
2022-10-28  2:02   ` Catherine Hoang
2022-10-21 22:29 ` [PATCH v4 08/27] xfs: get directory offset when removing " allison.henderson
2022-10-28  2:06   ` Catherine Hoang
2022-10-21 22:29 ` [PATCH v4 09/27] xfs: get directory offset when replacing a " allison.henderson
2022-10-21 22:29 ` [PATCH v4 10/27] xfs: add parent pointer support to attribute code allison.henderson
2022-10-21 22:29 ` [PATCH v4 11/27] xfs: define parent pointer xattr format allison.henderson
2022-10-21 22:29 ` [PATCH v4 12/27] xfs: Add xfs_verify_pptr allison.henderson
2022-10-21 22:29 ` [PATCH v4 13/27] xfs: Increase rename inode reservation allison.henderson
2022-10-25 19:15   ` Darrick J. Wong
2022-10-26  7:40     ` Allison Henderson
2022-10-21 22:29 ` [PATCH v4 14/27] xfs: extend transaction reservations for parent attributes allison.henderson
2022-10-25 20:55   ` Darrick J. Wong
2022-10-26  7:40     ` Allison Henderson
2022-10-21 22:29 ` [PATCH v4 15/27] xfs: parent pointer attribute creation allison.henderson
2022-10-25 21:11   ` Darrick J. Wong
2022-10-26  7:40     ` Allison Henderson
2022-10-21 22:29 ` [PATCH v4 16/27] xfs: add parent attributes to link allison.henderson
2022-10-25 20:58   ` Darrick J. Wong
2022-10-21 22:29 ` [PATCH v4 17/27] xfs: add parent attributes to symlink allison.henderson
2022-10-25 21:06   ` Darrick J. Wong
2022-10-21 22:29 ` [PATCH v4 18/27] xfs: remove parent pointers in unlink allison.henderson
2022-10-25 21:14   ` Darrick J. Wong
2022-10-26  7:40     ` Allison Henderson
2022-10-21 22:29 ` [PATCH v4 19/27] xfs: Add parent pointers to xfs_cross_rename allison.henderson
2022-10-25 21:32   ` Darrick J. Wong
2022-10-26  7:40     ` Allison Henderson
2022-10-21 22:29 ` [PATCH v4 20/27] xfs: Indent xfs_rename allison.henderson
2022-10-21 22:29 ` [PATCH v4 21/27] xfs: Add parent pointers to rename allison.henderson
2022-10-25 21:28   ` Darrick J. Wong
2022-10-26  7:40     ` Allison Henderson
2022-10-21 22:29 ` [PATCH v4 22/27] xfs: Add the parent pointer support to the superblock version 5 allison.henderson
2022-10-21 22:29 ` [PATCH v4 23/27] xfs: Add helper function xfs_attr_list_context_init allison.henderson
2022-10-21 22:29 ` [PATCH v4 24/27] xfs: Filter XFS_ATTR_PARENT for getfattr allison.henderson
2022-10-25 21:34   ` Darrick J. Wong
2022-10-26  7:40     ` Allison Henderson
2022-10-21 22:29 ` [PATCH v4 25/27] xfs: Add parent pointer ioctl allison.henderson
2022-10-21 22:29 ` [PATCH v4 26/27] xfs: fix unit conversion error in xfs_log_calc_max_attrsetm_res allison.henderson
2022-10-21 22:29 ` [PATCH v4 27/27] xfs: drop compatibility minimum log size computations for reflink allison.henderson

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