All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/18] Delayed Attributes
@ 2019-08-09 21:37 Allison Collins
  2019-08-09 21:37 ` [PATCH v2 01/18] xfs: Remove all strlen in all xfs_attr_* functions for attr names Allison Collins
                   ` (18 more replies)
  0 siblings, 19 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

Hi all,

This set is a subset of a larger series for parent pointers. 
Delayed attributes allow attribute operations (set and remove) to be 
logged and committed in the same way that other delayed operations do.
This will help break up more complex operations when we later introduce
parent pointers which can be used in a number of optimizations.  Since
delayed attributes can be implemented as a stand alone feature, I've
decided to subdivide the set to help make it more manageable.

Changes since v2:
Patches 6 through 17 are new and focus mostly on refactoring the
attribute set and remove operations.  Since delayed operations can
not be handling transactions, to goal of the refactoring is to
factor up the transaction specific code as much as possible while
modularizing the remaining code into helper functions that we can
reuse for our new delayed attr routines.

Patch 15 then adds a new set of xfs_attr_da* routines that
return EAGAIN when a new transaction is needed.  Patch 14 adds
a new struct xfs_delay_context which these new routine will use
to stash local variables or other information they need to more
or less pickup where they left off. 

I've also made the corresponding updates to the user space side, and
added a new test case to xfstests as well.  I'm still getting an
error about busy inodes after the journal replay, but I figure
theres plenty here to people to review while I work on that.

Question, comment and feedback appreciated! 

Thanks all!
Allison

Allison Collins (13):
  xfs: Replace attribute parameters with struct xfs_name
  xfs: Factor out new helper functions xfs_attr_rmtval_set
  xfs: Factor up trans handling in xfs_attr3_leaf_flipflags
  xfs: Factor out xfs_attr_leaf_addname helper
  xfs: Factor up commit from xfs_attr_try_sf_addname
  xfs: Factor up trans roll from xfs_attr3_leaf_setflag
  xfs: Add xfs_attr3_leaf helper functions
  xfs: Factor out xfs_attr_rmtval_remove_value
  xfs: Factor up trans roll in xfs_attr3_leaf_clearflag
  xfs: Add delay context to xfs_da_args
  xfs: Add delayed attribute routines
  xfs: Roll delayed attr operations by returning EAGAIN
  xfs: Enable delayed attributes

Allison Henderson (5):
  xfs: Remove all strlen in all xfs_attr_* functions for attr names.
  xfs: Set up infastructure for deferred attribute operations
  xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
  xfs: Add xfs_has_attr and subroutines
  xfs: Add delayed attributes error tag

 fs/xfs/Makefile                 |    2 +-
 fs/xfs/libxfs/xfs_attr.c        | 1145 ++++++++++++++++++++++++++++++++++-----
 fs/xfs/libxfs/xfs_attr.h        |   49 +-
 fs/xfs/libxfs/xfs_attr_leaf.c   |  167 ++++--
 fs/xfs/libxfs/xfs_attr_leaf.h   |    4 +
 fs/xfs/libxfs/xfs_attr_remote.c |   98 +++-
 fs/xfs/libxfs/xfs_attr_remote.h |    5 +-
 fs/xfs/libxfs/xfs_da_btree.h    |   23 +
 fs/xfs/libxfs/xfs_defer.c       |    1 +
 fs/xfs/libxfs/xfs_defer.h       |    3 +
 fs/xfs/libxfs/xfs_errortag.h    |    4 +-
 fs/xfs/libxfs/xfs_log_format.h  |   44 +-
 fs/xfs/libxfs/xfs_types.h       |    1 +
 fs/xfs/scrub/common.c           |    2 +
 fs/xfs/xfs_acl.c                |   26 +-
 fs/xfs/xfs_attr_item.c          |  804 +++++++++++++++++++++++++++
 fs/xfs/xfs_attr_item.h          |  102 ++++
 fs/xfs/xfs_attr_list.c          |    1 +
 fs/xfs/xfs_error.c              |    3 +
 fs/xfs/xfs_ioctl.c              |   21 +-
 fs/xfs/xfs_ioctl32.c            |    2 +
 fs/xfs/xfs_iops.c               |   10 +-
 fs/xfs/xfs_log.c                |    4 +
 fs/xfs/xfs_log_recover.c        |  174 ++++++
 fs/xfs/xfs_ondisk.h             |    2 +
 fs/xfs/xfs_trans.h              |    4 +-
 fs/xfs/xfs_xattr.c              |   20 +-
 27 files changed, 2504 insertions(+), 217 deletions(-)
 create mode 100644 fs/xfs/xfs_attr_item.c
 create mode 100644 fs/xfs/xfs_attr_item.h

-- 
2.7.4

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

* [PATCH v2 01/18] xfs: Remove all strlen in all xfs_attr_* functions for attr names.
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-09 21:37 ` [PATCH v2 02/18] xfs: Replace attribute parameters with struct xfs_name Allison Collins
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

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

This helps to pre-simplify the extra handling of the null terminator in
delayed operations which use memcpy rather than strlen.  Later
when we introduce parent pointers, attribute names will become binary,
so strlen will not work at all.  Removing uses of strlen now will
help reduce complexities later

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/libxfs/xfs_attr.c | 12 ++++++++----
 fs/xfs/libxfs/xfs_attr.h |  8 +++++---
 fs/xfs/xfs_acl.c         | 12 +++++++-----
 fs/xfs/xfs_ioctl.c       | 13 ++++++++++---
 fs/xfs/xfs_iops.c        |  6 ++++--
 fs/xfs/xfs_xattr.c       | 10 ++++++----
 6 files changed, 40 insertions(+), 21 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index d48fcf1..7761925 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -62,6 +62,7 @@ xfs_attr_args_init(
 	struct xfs_da_args	*args,
 	struct xfs_inode	*dp,
 	const unsigned char	*name,
+	size_t			namelen,
 	int			flags)
 {
 
@@ -74,7 +75,7 @@ xfs_attr_args_init(
 	args->dp = dp;
 	args->flags = flags;
 	args->name = name;
-	args->namelen = strlen((const char *)name);
+	args->namelen = namelen;
 	if (args->namelen >= MAXNAMELEN)
 		return -EFAULT;		/* match IRIX behaviour */
 
@@ -120,6 +121,7 @@ int
 xfs_attr_get(
 	struct xfs_inode	*ip,
 	const unsigned char	*name,
+	size_t			namelen,
 	unsigned char		*value,
 	int			*valuelenp,
 	int			flags)
@@ -133,7 +135,7 @@ xfs_attr_get(
 	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, ip, name, flags);
+	error = xfs_attr_args_init(&args, ip, name, namelen, flags);
 	if (error)
 		return error;
 
@@ -305,6 +307,7 @@ int
 xfs_attr_set(
 	struct xfs_inode	*dp,
 	const unsigned char	*name,
+	size_t			namelen,
 	unsigned char		*value,
 	int			valuelen,
 	int			flags)
@@ -320,7 +323,7 @@ xfs_attr_set(
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, dp, name, flags);
+	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
 	if (error)
 		return error;
 
@@ -409,6 +412,7 @@ int
 xfs_attr_remove(
 	struct xfs_inode	*dp,
 	const unsigned char	*name,
+	size_t			namelen,
 	int			flags)
 {
 	struct xfs_mount	*mp = dp->i_mount;
@@ -420,7 +424,7 @@ xfs_attr_remove(
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, dp, name, flags);
+	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
 	if (error)
 		return error;
 
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index ff28ebf..69493b5 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -143,11 +143,13 @@ int xfs_attr_list_int(struct xfs_attr_list_context *);
 int xfs_inode_hasattr(struct xfs_inode *ip);
 int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
 int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
-		 unsigned char *value, int *valuelenp, int flags);
+		 size_t namelen, unsigned char *value, int *valuelenp,
+		 int flags);
 int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
-		 unsigned char *value, int valuelen, int flags);
+		 size_t namelen, unsigned char *value, int valuelen, int flags);
 int xfs_attr_set_args(struct xfs_da_args *args);
-int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
+int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
+		    size_t namelen, int flags);
 int xfs_attr_remove_args(struct xfs_da_args *args);
 int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
 		  int flags, struct attrlist_cursor_kern *cursor);
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index cbda40d..abb17a7 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -139,8 +139,8 @@ xfs_get_acl(struct inode *inode, int type)
 	if (!xfs_acl)
 		return ERR_PTR(-ENOMEM);
 
-	error = xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl,
-							&len, ATTR_ROOT);
+	error = xfs_attr_get(ip, ea_name, strlen(ea_name),
+			     (unsigned char *)xfs_acl, &len, ATTR_ROOT);
 	if (error) {
 		/*
 		 * If the attribute doesn't exist make sure we have a negative
@@ -190,15 +190,17 @@ __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 		len -= sizeof(struct xfs_acl_entry) *
 			 (XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count);
 
-		error = xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
-				len, ATTR_ROOT);
+		error = xfs_attr_set(ip, ea_name, strlen(ea_name),
+				     (unsigned char *)xfs_acl, len, ATTR_ROOT);
 
 		kmem_free(xfs_acl);
 	} else {
 		/*
 		 * A NULL ACL argument means we want to remove the ACL.
 		 */
-		error = xfs_attr_remove(ip, ea_name, ATTR_ROOT);
+		error = xfs_attr_remove(ip, ea_name,
+					strlen(ea_name),
+					ATTR_ROOT);
 
 		/*
 		 * If the attribute didn't exist to start with that's fine.
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 6f7848c..f3c7ba5 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -431,6 +431,7 @@ xfs_attrmulti_attr_get(
 {
 	unsigned char		*kbuf;
 	int			error = -EFAULT;
+	size_t			namelen;
 
 	if (*len > XFS_XATTR_SIZE_MAX)
 		return -EINVAL;
@@ -438,7 +439,9 @@ xfs_attrmulti_attr_get(
 	if (!kbuf)
 		return -ENOMEM;
 
-	error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags);
+	namelen = strlen(name);
+	error = xfs_attr_get(XFS_I(inode), name, namelen,
+			     kbuf, (int *)len, flags);
 	if (error)
 		goto out_kfree;
 
@@ -460,6 +463,7 @@ xfs_attrmulti_attr_set(
 {
 	unsigned char		*kbuf;
 	int			error;
+	size_t			namelen;
 
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		return -EPERM;
@@ -470,7 +474,8 @@ xfs_attrmulti_attr_set(
 	if (IS_ERR(kbuf))
 		return PTR_ERR(kbuf);
 
-	error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags);
+	namelen = strlen(name);
+	error = xfs_attr_set(XFS_I(inode), name, namelen, kbuf, len, flags);
 	if (!error)
 		xfs_forget_acl(inode, name, flags);
 	kfree(kbuf);
@@ -484,10 +489,12 @@ xfs_attrmulti_attr_remove(
 	uint32_t		flags)
 {
 	int			error;
+	size_t			namelen;
 
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		return -EPERM;
-	error = xfs_attr_remove(XFS_I(inode), name, flags);
+	namelen = strlen(name);
+	error = xfs_attr_remove(XFS_I(inode), name, namelen, flags);
 	if (!error)
 		xfs_forget_acl(inode, name, flags);
 	return error;
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index ff3c1fa..b1b7b1b 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -49,8 +49,10 @@ xfs_initxattrs(
 	int			error = 0;
 
 	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
-		error = xfs_attr_set(ip, xattr->name, xattr->value,
-				      xattr->value_len, ATTR_SECURE);
+		error = xfs_attr_set(ip, xattr->name,
+				     strlen(xattr->name),
+				     xattr->value, xattr->value_len,
+				     ATTR_SECURE);
 		if (error < 0)
 			break;
 	}
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index 3123b5a..fe12d11 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -23,6 +23,7 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
 	int xflags = handler->flags;
 	struct xfs_inode *ip = XFS_I(inode);
 	int error, asize = size;
+	size_t namelen = strlen(name);
 
 	/* Convert Linux syscall to XFS internal ATTR flags */
 	if (!size) {
@@ -30,7 +31,7 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
 		value = NULL;
 	}
 
-	error = xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags);
+	error = xfs_attr_get(ip, name, namelen, value, &asize, xflags);
 	if (error)
 		return error;
 	return asize;
@@ -66,6 +67,7 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
 	int			xflags = handler->flags;
 	struct xfs_inode	*ip = XFS_I(inode);
 	int			error;
+	size_t			namelen = strlen(name);
 
 	/* Convert Linux syscall to XFS internal ATTR flags */
 	if (flags & XATTR_CREATE)
@@ -74,9 +76,9 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
 		xflags |= ATTR_REPLACE;
 
 	if (!value)
-		return xfs_attr_remove(ip, (unsigned char *)name, xflags);
-	error = xfs_attr_set(ip, (unsigned char *)name,
-				(void *)value, size, xflags);
+		return xfs_attr_remove(ip, name,
+				       namelen, xflags);
+	error = xfs_attr_set(ip, name, namelen, (void *)value, size, xflags);
 	if (!error)
 		xfs_forget_acl(inode, name, xflags);
 
-- 
2.7.4

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

* [PATCH v2 02/18] xfs: Replace attribute parameters with struct xfs_name
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
  2019-08-09 21:37 ` [PATCH v2 01/18] xfs: Remove all strlen in all xfs_attr_* functions for attr names Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-12 15:13   ` Darrick J. Wong
  2019-08-09 21:37 ` [PATCH v2 03/18] xfs: Set up infastructure for deferred attribute operations Allison Collins
                   ` (16 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

This patch replaces the attribute name, length and flags parameters with a
single struct xfs_name parameter.  This helps to clean up the numbers of
parameters being passed around and pre-simplifies the code some.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c | 40 ++++++++++++++++------------------------
 fs/xfs/libxfs/xfs_attr.h | 12 +++++-------
 fs/xfs/xfs_acl.c         | 26 +++++++++++++-------------
 fs/xfs/xfs_ioctl.c       | 26 ++++++++++++++++----------
 fs/xfs/xfs_iops.c        | 10 ++++++----
 fs/xfs/xfs_xattr.c       | 21 +++++++++------------
 6 files changed, 65 insertions(+), 70 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 7761925..0c91116 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -61,9 +61,7 @@ STATIC int
 xfs_attr_args_init(
 	struct xfs_da_args	*args,
 	struct xfs_inode	*dp,
-	const unsigned char	*name,
-	size_t			namelen,
-	int			flags)
+	struct xfs_name		*name)
 {
 
 	if (!name)
@@ -73,9 +71,9 @@ xfs_attr_args_init(
 	args->geo = dp->i_mount->m_attr_geo;
 	args->whichfork = XFS_ATTR_FORK;
 	args->dp = dp;
-	args->flags = flags;
-	args->name = name;
-	args->namelen = namelen;
+	args->flags = name->type;
+	args->name = name->name;
+	args->namelen = name->len;
 	if (args->namelen >= MAXNAMELEN)
 		return -EFAULT;		/* match IRIX behaviour */
 
@@ -120,11 +118,9 @@ xfs_attr_get_ilocked(
 int
 xfs_attr_get(
 	struct xfs_inode	*ip,
-	const unsigned char	*name,
-	size_t			namelen,
+	struct xfs_name		*name,
 	unsigned char		*value,
-	int			*valuelenp,
-	int			flags)
+	int			*valuelenp)
 {
 	struct xfs_da_args	args;
 	uint			lock_mode;
@@ -135,7 +131,7 @@ xfs_attr_get(
 	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, ip, name, namelen, flags);
+	error = xfs_attr_args_init(&args, ip, name);
 	if (error)
 		return error;
 
@@ -306,16 +302,14 @@ xfs_attr_remove_args(
 int
 xfs_attr_set(
 	struct xfs_inode	*dp,
-	const unsigned char	*name,
-	size_t			namelen,
+	struct xfs_name		*name,
 	unsigned char		*value,
-	int			valuelen,
-	int			flags)
+	int			valuelen)
 {
 	struct xfs_mount	*mp = dp->i_mount;
 	struct xfs_da_args	args;
 	struct xfs_trans_res	tres;
-	int			rsvd = (flags & ATTR_ROOT) != 0;
+	int			rsvd = (name->type & ATTR_ROOT) != 0;
 	int			error, local;
 
 	XFS_STATS_INC(mp, xs_attr_set);
@@ -323,7 +317,7 @@ xfs_attr_set(
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
+	error = xfs_attr_args_init(&args, dp, name);
 	if (error)
 		return error;
 
@@ -386,7 +380,7 @@ xfs_attr_set(
 	if (mp->m_flags & XFS_MOUNT_WSYNC)
 		xfs_trans_set_sync(args.trans);
 
-	if ((flags & ATTR_KERNOTIME) == 0)
+	if ((name->type & ATTR_KERNOTIME) == 0)
 		xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
 
 	/*
@@ -411,9 +405,7 @@ xfs_attr_set(
 int
 xfs_attr_remove(
 	struct xfs_inode	*dp,
-	const unsigned char	*name,
-	size_t			namelen,
-	int			flags)
+	struct xfs_name		*name)
 {
 	struct xfs_mount	*mp = dp->i_mount;
 	struct xfs_da_args	args;
@@ -424,7 +416,7 @@ xfs_attr_remove(
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
+	error = xfs_attr_args_init(&args, dp, name);
 	if (error)
 		return error;
 
@@ -445,7 +437,7 @@ xfs_attr_remove(
 	 */
 	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
 			XFS_ATTRRM_SPACE_RES(mp), 0,
-			(flags & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
+			(name->type & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
 			&args.trans);
 	if (error)
 		return error;
@@ -468,7 +460,7 @@ xfs_attr_remove(
 	if (mp->m_flags & XFS_MOUNT_WSYNC)
 		xfs_trans_set_sync(args.trans);
 
-	if ((flags & ATTR_KERNOTIME) == 0)
+	if ((name->type & ATTR_KERNOTIME) == 0)
 		xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
 
 	/*
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 69493b5..aa7261a 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -142,14 +142,12 @@ int xfs_attr_list_int_ilocked(struct xfs_attr_list_context *);
 int xfs_attr_list_int(struct xfs_attr_list_context *);
 int xfs_inode_hasattr(struct xfs_inode *ip);
 int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
-int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
-		 size_t namelen, unsigned char *value, int *valuelenp,
-		 int flags);
-int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
-		 size_t namelen, unsigned char *value, int valuelen, int flags);
+int xfs_attr_get(struct xfs_inode *ip, struct xfs_name *name,
+		 unsigned char *value, int *valuelenp);
+int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
+		 unsigned char *value, int valuelen);
 int xfs_attr_set_args(struct xfs_da_args *args);
-int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
-		    size_t namelen, int flags);
+int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name);
 int xfs_attr_remove_args(struct xfs_da_args *args);
 int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
 		  int flags, struct attrlist_cursor_kern *cursor);
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index abb17a7..3da2568 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -113,7 +113,7 @@ xfs_get_acl(struct inode *inode, int type)
 	struct xfs_inode *ip = XFS_I(inode);
 	struct posix_acl *acl = NULL;
 	struct xfs_acl *xfs_acl;
-	unsigned char *ea_name;
+	struct xfs_name name;
 	int error;
 	int len;
 
@@ -121,10 +121,10 @@ xfs_get_acl(struct inode *inode, int type)
 
 	switch (type) {
 	case ACL_TYPE_ACCESS:
-		ea_name = SGI_ACL_FILE;
+		name.name = SGI_ACL_FILE;
 		break;
 	case ACL_TYPE_DEFAULT:
-		ea_name = SGI_ACL_DEFAULT;
+		name.name = SGI_ACL_DEFAULT;
 		break;
 	default:
 		BUG();
@@ -139,8 +139,9 @@ xfs_get_acl(struct inode *inode, int type)
 	if (!xfs_acl)
 		return ERR_PTR(-ENOMEM);
 
-	error = xfs_attr_get(ip, ea_name, strlen(ea_name),
-			     (unsigned char *)xfs_acl, &len, ATTR_ROOT);
+	name.len = strlen(name.name);
+	name.type = ATTR_ROOT;
+	error = xfs_attr_get(ip, &name, (unsigned char *)xfs_acl, &len);
 	if (error) {
 		/*
 		 * If the attribute doesn't exist make sure we have a negative
@@ -160,17 +161,17 @@ int
 __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
 	struct xfs_inode *ip = XFS_I(inode);
-	unsigned char *ea_name;
+	struct xfs_name name;
 	int error;
 
 	switch (type) {
 	case ACL_TYPE_ACCESS:
-		ea_name = SGI_ACL_FILE;
+		name.name = SGI_ACL_FILE;
 		break;
 	case ACL_TYPE_DEFAULT:
 		if (!S_ISDIR(inode->i_mode))
 			return acl ? -EACCES : 0;
-		ea_name = SGI_ACL_DEFAULT;
+		name.name = SGI_ACL_DEFAULT;
 		break;
 	default:
 		return -EINVAL;
@@ -190,17 +191,16 @@ __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 		len -= sizeof(struct xfs_acl_entry) *
 			 (XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count);
 
-		error = xfs_attr_set(ip, ea_name, strlen(ea_name),
-				     (unsigned char *)xfs_acl, len, ATTR_ROOT);
+		name.len = strlen(name.name);
+		name.type = ATTR_ROOT;
+		error = xfs_attr_set(ip, &name, (unsigned char *)xfs_acl, len);
 
 		kmem_free(xfs_acl);
 	} else {
 		/*
 		 * A NULL ACL argument means we want to remove the ACL.
 		 */
-		error = xfs_attr_remove(ip, ea_name,
-					strlen(ea_name),
-					ATTR_ROOT);
+		error = xfs_attr_remove(ip, &name);
 
 		/*
 		 * If the attribute didn't exist to start with that's fine.
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index f3c7ba5..b6a7220 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -431,7 +431,7 @@ xfs_attrmulti_attr_get(
 {
 	unsigned char		*kbuf;
 	int			error = -EFAULT;
-	size_t			namelen;
+	struct xfs_name		xname;
 
 	if (*len > XFS_XATTR_SIZE_MAX)
 		return -EINVAL;
@@ -439,9 +439,10 @@ xfs_attrmulti_attr_get(
 	if (!kbuf)
 		return -ENOMEM;
 
-	namelen = strlen(name);
-	error = xfs_attr_get(XFS_I(inode), name, namelen,
-			     kbuf, (int *)len, flags);
+	xname.name = name;
+	xname.len = strlen(name);
+	xname.type = flags;
+	error = xfs_attr_get(XFS_I(inode), &xname, kbuf, (int *)len);
 	if (error)
 		goto out_kfree;
 
@@ -463,7 +464,7 @@ xfs_attrmulti_attr_set(
 {
 	unsigned char		*kbuf;
 	int			error;
-	size_t			namelen;
+	struct xfs_name		xname;
 
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		return -EPERM;
@@ -474,8 +475,10 @@ xfs_attrmulti_attr_set(
 	if (IS_ERR(kbuf))
 		return PTR_ERR(kbuf);
 
-	namelen = strlen(name);
-	error = xfs_attr_set(XFS_I(inode), name, namelen, kbuf, len, flags);
+	xname.name = name;
+	xname.len = strlen(name);
+	xname.type = flags;
+	error = xfs_attr_set(XFS_I(inode), &xname, kbuf, len);
 	if (!error)
 		xfs_forget_acl(inode, name, flags);
 	kfree(kbuf);
@@ -489,12 +492,15 @@ xfs_attrmulti_attr_remove(
 	uint32_t		flags)
 {
 	int			error;
-	size_t			namelen;
+	struct xfs_name		xname;
 
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		return -EPERM;
-	namelen = strlen(name);
-	error = xfs_attr_remove(XFS_I(inode), name, namelen, flags);
+
+	xname.name = name;
+	xname.len = strlen(name);
+	xname.type = flags;
+	error = xfs_attr_remove(XFS_I(inode), &xname);
 	if (!error)
 		xfs_forget_acl(inode, name, flags);
 	return error;
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index b1b7b1b..bdf925c 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -46,13 +46,15 @@ xfs_initxattrs(
 {
 	const struct xattr	*xattr;
 	struct xfs_inode	*ip = XFS_I(inode);
+	struct xfs_name		name;
 	int			error = 0;
 
 	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
-		error = xfs_attr_set(ip, xattr->name,
-				     strlen(xattr->name),
-				     xattr->value, xattr->value_len,
-				     ATTR_SECURE);
+		name.name = xattr->name;
+		name.len = strlen(xattr->name);
+		name.type = ATTR_SECURE;
+		error = xfs_attr_set(ip, &name,
+				     xattr->value, xattr->value_len);
 		if (error < 0)
 			break;
 	}
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index fe12d11..3c63930 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -20,18 +20,17 @@ static int
 xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
 		struct inode *inode, const char *name, void *value, size_t size)
 {
-	int xflags = handler->flags;
 	struct xfs_inode *ip = XFS_I(inode);
 	int error, asize = size;
-	size_t namelen = strlen(name);
+	struct xfs_name xname = {name, strlen(name), handler->flags};
 
 	/* Convert Linux syscall to XFS internal ATTR flags */
 	if (!size) {
-		xflags |= ATTR_KERNOVAL;
+		xname.type |= ATTR_KERNOVAL;
 		value = NULL;
 	}
 
-	error = xfs_attr_get(ip, name, namelen, value, &asize, xflags);
+	error = xfs_attr_get(ip, &xname, value, &asize);
 	if (error)
 		return error;
 	return asize;
@@ -64,23 +63,21 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
 		struct inode *inode, const char *name, const void *value,
 		size_t size, int flags)
 {
-	int			xflags = handler->flags;
 	struct xfs_inode	*ip = XFS_I(inode);
 	int			error;
-	size_t			namelen = strlen(name);
+	struct xfs_name		xname = {name, strlen(name), handler->flags};
 
 	/* Convert Linux syscall to XFS internal ATTR flags */
 	if (flags & XATTR_CREATE)
-		xflags |= ATTR_CREATE;
+		xname.type |= ATTR_CREATE;
 	if (flags & XATTR_REPLACE)
-		xflags |= ATTR_REPLACE;
+		xname.type |= ATTR_REPLACE;
 
 	if (!value)
-		return xfs_attr_remove(ip, name,
-				       namelen, xflags);
-	error = xfs_attr_set(ip, name, namelen, (void *)value, size, xflags);
+		return xfs_attr_remove(ip, &xname);
+	error = xfs_attr_set(ip, &xname, (void *)value, size);
 	if (!error)
-		xfs_forget_acl(inode, name, xflags);
+		xfs_forget_acl(inode, name, xname.type);
 
 	return error;
 }
-- 
2.7.4

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

* [PATCH v2 03/18] xfs: Set up infastructure for deferred attribute operations
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
  2019-08-09 21:37 ` [PATCH v2 01/18] xfs: Remove all strlen in all xfs_attr_* functions for attr names Allison Collins
  2019-08-09 21:37 ` [PATCH v2 02/18] xfs: Replace attribute parameters with struct xfs_name Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-12 15:40   ` Darrick J. Wong
  2019-08-12 19:28   ` Brian Foster
  2019-08-09 21:37 ` [PATCH v2 04/18] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred Allison Collins
                   ` (15 subsequent siblings)
  18 siblings, 2 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

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

Currently attributes are modified directly across one or more
transactions.  But they are not logged or replayed in the event of
an error. The goal of delayed attributes is to enable logging and
replaying of attribute operations using the existing delayed
operations infrastructure.  This will later enable the attributes
to become part of larger multi part operations that also must first
be recorded to the log.  This is mostly of interest in the scheme of
parent pointers which would need to maintain an attribute containing
parent inode information any time an inode is moved, created, or
removed.  Parent pointers would then be of interest to any feature
that would need to quickly derive an inode path from the mount
point.  Online scrub, nfs lookups and fs grow or shrink operations
are all features that could take advantage of this.

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

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/Makefile                |   2 +-
 fs/xfs/libxfs/xfs_attr.c       |   5 +-
 fs/xfs/libxfs/xfs_attr.h       |  25 ++
 fs/xfs/libxfs/xfs_defer.c      |   1 +
 fs/xfs/libxfs/xfs_defer.h      |   3 +
 fs/xfs/libxfs/xfs_log_format.h |  44 ++-
 fs/xfs/libxfs/xfs_types.h      |   1 +
 fs/xfs/xfs_attr_item.c         | 755 +++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_attr_item.h         | 102 ++++++
 fs/xfs/xfs_log.c               |   4 +
 fs/xfs/xfs_log_recover.c       | 174 ++++++++++
 fs/xfs/xfs_ondisk.h            |   2 +
 fs/xfs/xfs_trans.h             |   4 +-
 13 files changed, 1116 insertions(+), 6 deletions(-)

diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index 06b68b6..70b4716 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -102,6 +102,7 @@ xfs-y				+= xfs_log.o \
 				   xfs_bmap_item.o \
 				   xfs_buf_item.o \
 				   xfs_extfree_item.o \
+				   xfs_attr_item.o \
 				   xfs_icreate_item.o \
 				   xfs_inode_item.o \
 				   xfs_refcount_item.o \
@@ -109,7 +110,6 @@ xfs-y				+= xfs_log.o \
 				   xfs_log_recover.o \
 				   xfs_trans_ail.o \
 				   xfs_trans_buf.o
-
 # optional features
 xfs-$(CONFIG_XFS_QUOTA)		+= xfs_dquot.o \
 				   xfs_dquot_item.o \
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 0c91116..1f76618 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -24,6 +24,7 @@
 #include "xfs_quota.h"
 #include "xfs_trans_space.h"
 #include "xfs_trace.h"
+#include "xfs_attr_item.h"
 
 /*
  * xfs_attr.c
@@ -57,7 +58,7 @@ STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
 STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
 
 
-STATIC int
+int
 xfs_attr_args_init(
 	struct xfs_da_args	*args,
 	struct xfs_inode	*dp,
@@ -151,7 +152,7 @@ xfs_attr_get(
 /*
  * Calculate how many blocks we need for the new attribute,
  */
-STATIC int
+int
 xfs_attr_calc_size(
 	struct xfs_da_args	*args,
 	int			*local)
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index aa7261a..9132d4f 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -78,6 +78,28 @@ typedef struct attrlist_ent {	/* data from attr_list() */
 } attrlist_ent_t;
 
 /*
+ * List of attrs to commit later.
+ */
+struct xfs_attr_item {
+	struct xfs_inode  *xattri_ip;
+	uint32_t	  xattri_op_flags;
+	void		  *xattri_value;      /* attr value */
+	uint32_t	  xattri_value_len;   /* length of value */
+	void		  *xattri_name;	      /* attr name */
+	uint32_t	  xattri_name_len;    /* length of name */
+	uint32_t	  xattri_flags;       /* attr flags */
+	struct list_head  xattri_list;
+
+	/*
+	 * A byte array follows the header containing the file name and
+	 * attribute value.
+	 */
+};
+
+#define XFS_ATTR_ITEM_SIZEOF(namelen, valuelen)	\
+	(sizeof(struct xfs_attr_item) + (namelen) + (valuelen))
+
+/*
  * Given a pointer to the (char*) buffer containing the attr_list() result,
  * and an index, return a pointer to the indicated attribute in the buffer.
  */
@@ -152,5 +174,8 @@ int xfs_attr_remove_args(struct xfs_da_args *args);
 int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
 		  int flags, struct attrlist_cursor_kern *cursor);
 bool xfs_attr_namecheck(const void *name, size_t length);
+int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
+		       struct xfs_name *name);
+int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
 
 #endif	/* __XFS_ATTR_H__ */
diff --git a/fs/xfs/libxfs/xfs_defer.c b/fs/xfs/libxfs/xfs_defer.c
index eb2be2a..ae9b52c 100644
--- a/fs/xfs/libxfs/xfs_defer.c
+++ b/fs/xfs/libxfs/xfs_defer.c
@@ -176,6 +176,7 @@ static const struct xfs_defer_op_type *defer_op_types[] = {
 	[XFS_DEFER_OPS_TYPE_RMAP]	= &xfs_rmap_update_defer_type,
 	[XFS_DEFER_OPS_TYPE_FREE]	= &xfs_extent_free_defer_type,
 	[XFS_DEFER_OPS_TYPE_AGFL_FREE]	= &xfs_agfl_free_defer_type,
+	[XFS_DEFER_OPS_TYPE_ATTR]	= &xfs_attr_defer_type,
 };
 
 /*
diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h
index 7c28d76..b9ff7b9 100644
--- a/fs/xfs/libxfs/xfs_defer.h
+++ b/fs/xfs/libxfs/xfs_defer.h
@@ -17,6 +17,7 @@ enum xfs_defer_ops_type {
 	XFS_DEFER_OPS_TYPE_RMAP,
 	XFS_DEFER_OPS_TYPE_FREE,
 	XFS_DEFER_OPS_TYPE_AGFL_FREE,
+	XFS_DEFER_OPS_TYPE_ATTR,
 	XFS_DEFER_OPS_TYPE_MAX,
 };
 
@@ -60,5 +61,7 @@ extern const struct xfs_defer_op_type xfs_refcount_update_defer_type;
 extern const struct xfs_defer_op_type xfs_rmap_update_defer_type;
 extern const struct xfs_defer_op_type xfs_extent_free_defer_type;
 extern const struct xfs_defer_op_type xfs_agfl_free_defer_type;
+extern const struct xfs_defer_op_type xfs_attr_defer_type;
+
 
 #endif /* __XFS_DEFER_H__ */
diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
index e5f97c6..acdb8ad 100644
--- a/fs/xfs/libxfs/xfs_log_format.h
+++ b/fs/xfs/libxfs/xfs_log_format.h
@@ -117,7 +117,12 @@ struct xfs_unmount_log_format {
 #define XLOG_REG_TYPE_CUD_FORMAT	24
 #define XLOG_REG_TYPE_BUI_FORMAT	25
 #define XLOG_REG_TYPE_BUD_FORMAT	26
-#define XLOG_REG_TYPE_MAX		26
+#define XLOG_REG_TYPE_ATTRI_FORMAT	27
+#define XLOG_REG_TYPE_ATTRD_FORMAT	28
+#define XLOG_REG_TYPE_ATTR_NAME	29
+#define XLOG_REG_TYPE_ATTR_VALUE	30
+#define XLOG_REG_TYPE_MAX		30
+
 
 /*
  * Flags to log operation header
@@ -240,6 +245,8 @@ typedef struct xfs_trans_header {
 #define	XFS_LI_CUD		0x1243
 #define	XFS_LI_BUI		0x1244	/* bmbt update intent */
 #define	XFS_LI_BUD		0x1245
+#define	XFS_LI_ATTRI		0x1246  /* attr set/remove intent*/
+#define	XFS_LI_ATTRD		0x1247  /* attr set/remove done */
 
 #define XFS_LI_TYPE_DESC \
 	{ XFS_LI_EFI,		"XFS_LI_EFI" }, \
@@ -255,7 +262,9 @@ typedef struct xfs_trans_header {
 	{ XFS_LI_CUI,		"XFS_LI_CUI" }, \
 	{ XFS_LI_CUD,		"XFS_LI_CUD" }, \
 	{ XFS_LI_BUI,		"XFS_LI_BUI" }, \
-	{ XFS_LI_BUD,		"XFS_LI_BUD" }
+	{ XFS_LI_BUD,		"XFS_LI_BUD" }, \
+	{ XFS_LI_ATTRI,		"XFS_LI_ATTRI" }, \
+	{ XFS_LI_ATTRD,		"XFS_LI_ATTRD" }
 
 /*
  * Inode Log Item Format definitions.
@@ -853,4 +862,35 @@ struct xfs_icreate_log {
 	__be32		icl_gen;	/* inode generation number to use */
 };
 
+/*
+ * Flags for deferred attribute operations.
+ * Upper bits are flags, lower byte is type code
+ */
+#define XFS_ATTR_OP_FLAGS_SET		1	/* Set the attribute */
+#define XFS_ATTR_OP_FLAGS_REMOVE	2	/* Remove the attribute */
+#define XFS_ATTR_OP_FLAGS_TYPE_MASK	0x0FF	/* Flags type mask */
+
+/*
+ * This is the structure used to lay out an attr log item in the
+ * log.
+ */
+struct xfs_attri_log_format {
+	uint16_t	alfi_type;	/* attri log item type */
+	uint16_t	alfi_size;	/* size of this item */
+	uint32_t	__pad;		/* pad to 64 bit aligned */
+	uint64_t	alfi_id;	/* attri identifier */
+	xfs_ino_t       alfi_ino;	/* the inode for this attr operation */
+	uint32_t        alfi_op_flags;	/* marks the op as a set or remove */
+	uint32_t        alfi_name_len;	/* attr name length */
+	uint32_t        alfi_value_len;	/* attr value length */
+	uint32_t        alfi_attr_flags;/* attr flags */
+};
+
+struct xfs_attrd_log_format {
+	uint16_t	alfd_type;	/* attrd log item type */
+	uint16_t	alfd_size;	/* size of this item */
+	uint32_t	__pad;		/* pad to 64 bit aligned */
+	uint64_t	alfd_alf_id;	/* id of corresponding attrd */
+};
+
 #endif /* __XFS_LOG_FORMAT_H__ */
diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
index 802b34c..5e1dce5 100644
--- a/fs/xfs/libxfs/xfs_types.h
+++ b/fs/xfs/libxfs/xfs_types.h
@@ -11,6 +11,7 @@ typedef uint32_t	prid_t;		/* project ID */
 typedef uint32_t	xfs_agblock_t;	/* blockno in alloc. group */
 typedef uint32_t	xfs_agino_t;	/* inode # within allocation grp */
 typedef uint32_t	xfs_extlen_t;	/* extent length in blocks */
+typedef uint32_t	xfs_attrlen_t;	/* attr length */
 typedef uint32_t	xfs_agnumber_t;	/* allocation group number */
 typedef int32_t		xfs_extnum_t;	/* # of extents in a file */
 typedef int16_t		xfs_aextnum_t;	/* # extents in an attribute fork */
diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
new file mode 100644
index 0000000..2340589
--- /dev/null
+++ b/fs/xfs/xfs_attr_item.c
@@ -0,0 +1,755 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Oracle.  All Rights Reserved.
+ * Author: Allison Henderson <allison.henderson@oracle.com>
+ */
+
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_bit.h"
+#include "xfs_shared.h"
+#include "xfs_mount.h"
+#include "xfs_defer.h"
+#include "xfs_trans.h"
+#include "xfs_trans_priv.h"
+#include "xfs_buf_item.h"
+#include "xfs_attr_item.h"
+#include "xfs_log.h"
+#include "xfs_btree.h"
+#include "xfs_rmap.h"
+#include "xfs_inode.h"
+#include "xfs_icache.h"
+#include "xfs_attr.h"
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
+#include "xfs_shared.h"
+#include "xfs_attr_item.h"
+#include "xfs_alloc.h"
+#include "xfs_bmap.h"
+#include "xfs_trace.h"
+#include "libxfs/xfs_da_format.h"
+#include "xfs_inode.h"
+#include "xfs_quota.h"
+
+
+/*
+ * This routine is called to allocate an "attr free done" log item.
+ */
+struct xfs_attrd_log_item *
+xfs_trans_get_attrd(struct xfs_trans		*tp,
+		  struct xfs_attri_log_item	*attrip)
+{
+	struct xfs_attrd_log_item		*attrdp;
+
+	ASSERT(tp != NULL);
+
+	attrdp = xfs_attrd_init(tp->t_mountp, attrip);
+	ASSERT(attrdp != NULL);
+
+	/*
+	 * Get a log_item_desc to point at the new item.
+	 */
+	xfs_trans_add_item(tp, &attrdp->attrd_item);
+	return attrdp;
+}
+
+/*
+ * Delete an attr and log it to the ATTRD. Note that the transaction is marked
+ * dirty regardless of whether the attr delete succeeds or fails to support the
+ * ATTRI/ATTRD lifecycle rules.
+ */
+int
+xfs_trans_attr(
+	struct xfs_da_args		*args,
+	struct xfs_attrd_log_item	*attrdp,
+	uint32_t			op_flags)
+{
+	int				error;
+
+	error = xfs_qm_dqattach_locked(args->dp, 0);
+	if (error)
+		return error;
+
+	switch (op_flags) {
+	case XFS_ATTR_OP_FLAGS_SET:
+		args->op_flags |= XFS_DA_OP_ADDNAME;
+		error = xfs_attr_set_args(args);
+		break;
+	case XFS_ATTR_OP_FLAGS_REMOVE:
+		ASSERT(XFS_IFORK_Q((args->dp)));
+		error = xfs_attr_remove_args(args);
+		break;
+	default:
+		error = -EFSCORRUPTED;
+	}
+
+	/*
+	 * Mark the transaction dirty, even on error. This ensures the
+	 * transaction is aborted, which:
+	 *
+	 * 1.) releases the ATTRI and frees the ATTRD
+	 * 2.) shuts down the filesystem
+	 */
+	args->trans->t_flags |= XFS_TRANS_DIRTY;
+	set_bit(XFS_LI_DIRTY, &attrdp->attrd_item.li_flags);
+
+	return error;
+}
+
+static int
+xfs_attr_diff_items(
+	void				*priv,
+	struct list_head		*a,
+	struct list_head		*b)
+{
+	return 0;
+}
+
+/* Get an ATTRI. */
+STATIC void *
+xfs_attr_create_intent(
+	struct xfs_trans		*tp,
+	unsigned int			count)
+{
+	struct xfs_attri_log_item	*attrip;
+
+	ASSERT(tp != NULL);
+	ASSERT(count == 1);
+
+	attrip = xfs_attri_init(tp->t_mountp);
+	ASSERT(attrip != NULL);
+
+	/*
+	 * Get a log_item_desc to point at the new item.
+	 */
+	xfs_trans_add_item(tp, &attrip->attri_item);
+	return attrip;
+}
+
+/* Log an attr to the intent item. */
+STATIC void
+xfs_attr_log_item(
+	struct xfs_trans		*tp,
+	void				*intent,
+	struct list_head		*item)
+{
+	struct xfs_attri_log_item	*attrip = intent;
+	struct xfs_attr_item		*attr;
+	struct xfs_attri_log_format	*attrp;
+	char				*name_value;
+
+	attr = container_of(item, struct xfs_attr_item, xattri_list);
+	name_value = ((char *)attr) + sizeof(struct xfs_attr_item);
+
+	tp->t_flags |= XFS_TRANS_DIRTY;
+	set_bit(XFS_LI_DIRTY, &attrip->attri_item.li_flags);
+
+	/*
+	 * At this point the xfs_attr_item has been constructed, and we've
+	 * created the log intent. Fill in the attri log item and log format
+	 * structure with fields from this xfs_attr_item
+	 */
+	attrp = &attrip->attri_format;
+	attrp->alfi_ino = attr->xattri_ip->i_ino;
+	attrp->alfi_op_flags = attr->xattri_op_flags;
+	attrp->alfi_value_len = attr->xattri_value_len;
+	attrp->alfi_name_len = attr->xattri_name_len;
+	attrp->alfi_attr_flags = attr->xattri_flags;
+
+	attrip->attri_name = name_value;
+	attrip->attri_value = &name_value[attr->xattri_name_len];
+	attrip->attri_name_len = attr->xattri_name_len;
+	attrip->attri_value_len = attr->xattri_value_len;
+}
+
+/* Get an ATTRD so we can process all the attrs. */
+STATIC void *
+xfs_attr_create_done(
+	struct xfs_trans		*tp,
+	void				*intent,
+	unsigned int			count)
+{
+	return xfs_trans_get_attrd(tp, intent);
+}
+
+/* Process an attr. */
+STATIC int
+xfs_attr_finish_item(
+	struct xfs_trans		*tp,
+	struct list_head		*item,
+	void				*done_item,
+	void				**state)
+{
+	struct xfs_attr_item		*attr;
+	char				*name_value;
+	int				error;
+	int				local;
+	struct xfs_da_args		args;
+	struct xfs_name			name;
+	struct xfs_attrd_log_item	*attrdp;
+	struct xfs_attri_log_item	*attrip;
+
+	attr = container_of(item, struct xfs_attr_item, xattri_list);
+	name_value = ((char *)attr) + sizeof(struct xfs_attr_item);
+
+	name.name = name_value;
+	name.len = attr->xattri_name_len;
+	name.type = attr->xattri_flags;
+	error = xfs_attr_args_init(&args, attr->xattri_ip, &name);
+	if (error)
+		goto out;
+
+	args.hashval = xfs_da_hashname(args.name, args.namelen);
+	args.value = &name_value[attr->xattri_name_len];
+	args.valuelen = attr->xattri_value_len;
+	args.op_flags = XFS_DA_OP_OKNOENT;
+	args.total = xfs_attr_calc_size(&args, &local);
+	args.trans = tp;
+
+	error = xfs_trans_attr(&args, done_item,
+			attr->xattri_op_flags);
+out:
+	/*
+	 * We are about to free the xfs_attr_item, so we need to remove any
+	 * refrences that are currently pointing at its members
+	 */
+	attrdp = (struct xfs_attrd_log_item *)done_item;
+	attrip = attrdp->attrd_attrip;
+	attrip->attri_name = NULL;
+	attrip->attri_value = NULL;
+	attrip->attri_name_len = 0;
+	attrip->attri_value_len = 0;
+
+	kmem_free(attr);
+	return error;
+}
+
+/* Abort all pending ATTRs. */
+STATIC void
+xfs_attr_abort_intent(
+	void				*intent)
+{
+	xfs_attri_release(intent);
+}
+
+/* Cancel an attr */
+STATIC void
+xfs_attr_cancel_item(
+	struct list_head		*item)
+{
+	struct xfs_attr_item	*attr;
+
+	attr = container_of(item, struct xfs_attr_item, xattri_list);
+	kmem_free(attr);
+}
+
+const struct xfs_defer_op_type xfs_attr_defer_type = {
+	.max_items	= XFS_ATTRI_MAX_FAST_ATTRS,
+	.diff_items	= xfs_attr_diff_items,
+	.create_intent	= xfs_attr_create_intent,
+	.abort_intent	= xfs_attr_abort_intent,
+	.log_item	= xfs_attr_log_item,
+	.create_done	= xfs_attr_create_done,
+	.finish_item	= xfs_attr_finish_item,
+	.cancel_item	= xfs_attr_cancel_item,
+};
+
+static inline struct xfs_attri_log_item *ATTRI_ITEM(struct xfs_log_item *lip)
+{
+	return container_of(lip, struct xfs_attri_log_item, attri_item);
+}
+
+void
+xfs_attri_item_free(
+	struct xfs_attri_log_item	*attrip)
+{
+	kmem_free(attrip->attri_item.li_lv_shadow);
+	kmem_free(attrip);
+}
+
+/*
+ * This returns the number of iovecs needed to log the given attri item. We
+ * only need 1 iovec for an attri item.  It just logs the attr_log_format
+ * structure.
+ */
+static inline int
+xfs_attri_item_sizeof(
+	struct xfs_attri_log_item *attrip)
+{
+	return sizeof(struct xfs_attri_log_format);
+}
+
+STATIC void
+xfs_attri_item_size(
+	struct xfs_log_item	*lip,
+	int			*nvecs,
+	int			*nbytes)
+{
+	struct xfs_attri_log_item       *attrip = ATTRI_ITEM(lip);
+
+	*nvecs += 1;
+	*nbytes += xfs_attri_item_sizeof(attrip);
+
+	if (attrip->attri_name_len > 0) {
+		*nvecs += 1;
+		*nbytes += ATTR_NVEC_SIZE(attrip->attri_name_len);
+	}
+
+	if (attrip->attri_value_len > 0) {
+		*nvecs += 1;
+		*nbytes += ATTR_NVEC_SIZE(attrip->attri_value_len);
+	}
+}
+
+/*
+ * This is called to fill in the vector of log iovecs for the given attri log
+ * item. We use only 1 iovec, and we point that at the attri_log_format
+ * structure embedded in the attri item. It is at this point that we assert
+ * that all of the attr slots in the attri item have been filled.
+ */
+STATIC void
+xfs_attri_item_format(
+	struct xfs_log_item	*lip,
+	struct xfs_log_vec	*lv)
+{
+	struct xfs_attri_log_item	*attrip = ATTRI_ITEM(lip);
+	struct xfs_log_iovec	*vecp = NULL;
+
+	attrip->attri_format.alfi_type = XFS_LI_ATTRI;
+	attrip->attri_format.alfi_size = 1;
+
+	/*
+	 * This size accounting must be done before copying the attrip into the
+	 * iovec.  If we do it after, the wrong size will be recorded to the log
+	 * and we trip across assertion checks for bad region sizes later during
+	 * the log recovery.
+	 */
+	if (attrip->attri_name_len > 0)
+		attrip->attri_format.alfi_size++;
+	if (attrip->attri_value_len > 0)
+		attrip->attri_format.alfi_size++;
+
+	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRI_FORMAT,
+			&attrip->attri_format,
+			xfs_attri_item_sizeof(attrip));
+	if (attrip->attri_name_len > 0)
+		xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_NAME,
+				attrip->attri_name,
+				ATTR_NVEC_SIZE(attrip->attri_name_len));
+
+	if (attrip->attri_value_len > 0)
+		xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_VALUE,
+				attrip->attri_value,
+				ATTR_NVEC_SIZE(attrip->attri_value_len));
+}
+
+
+/*
+ * Pinning has no meaning for an attri item, so just return.
+ */
+STATIC void
+xfs_attri_item_pin(
+	struct xfs_log_item	*lip)
+{
+}
+
+/*
+ * The unpin operation is the last place an ATTRI is manipulated in the log. It
+ * is either inserted in the AIL or aborted in the event of a log I/O error. In
+ * either case, the ATTRI transaction has been successfully committed to make
+ * it this far. Therefore, we expect whoever committed the ATTRI to either
+ * construct and commit the ATTRD or drop the ATTRD's reference in the event of
+ * error. Simply drop the log's ATTRI reference now that the log is done with
+ * it.
+ */
+STATIC void
+xfs_attri_item_unpin(
+	struct xfs_log_item	*lip,
+	int			remove)
+{
+	struct xfs_attri_log_item	*attrip = ATTRI_ITEM(lip);
+
+	xfs_attri_release(attrip);
+}
+
+/*
+ * attri items have no locking or pushing.  However, since ATTRIs are pulled
+ * from the AIL when their corresponding ATTRDs are committed to disk, their
+ * situation is very similar to being pinned.  Return XFS_ITEM_PINNED so that
+ * the caller will eventually flush the log.  This should help in getting the
+ * ATTRI out of the AIL.
+ */
+STATIC uint
+xfs_attri_item_push(
+	struct xfs_log_item	*lip,
+	struct list_head	*buffer_list)
+{
+	return XFS_ITEM_PINNED;
+}
+
+/*
+ * The ATTRI is logged only once and cannot be moved in the log, so simply
+ * return the lsn at which it's been logged.
+ */
+STATIC xfs_lsn_t
+xfs_attri_item_committed(
+	struct xfs_log_item	*lip,
+	xfs_lsn_t		lsn)
+{
+	return lsn;
+}
+
+STATIC void
+xfs_attri_item_committing(
+	struct xfs_log_item	*lip,
+	xfs_lsn_t		lsn)
+{
+}
+
+STATIC void
+xfs_attri_item_release(
+	struct xfs_log_item	*lip)
+{
+	xfs_attri_release(ATTRI_ITEM(lip));
+}
+
+/*
+ * This is the ops vector shared by all attri log items.
+ */
+static const struct xfs_item_ops xfs_attri_item_ops = {
+	.iop_size	= xfs_attri_item_size,
+	.iop_format	= xfs_attri_item_format,
+	.iop_pin	= xfs_attri_item_pin,
+	.iop_unpin	= xfs_attri_item_unpin,
+	.iop_committed	= xfs_attri_item_committed,
+	.iop_push	= xfs_attri_item_push,
+	.iop_committing = xfs_attri_item_committing,
+	.iop_release    = xfs_attri_item_release,
+};
+
+
+/*
+ * Allocate and initialize an attri item
+ */
+struct xfs_attri_log_item *
+xfs_attri_init(
+	struct xfs_mount	*mp)
+
+{
+	struct xfs_attri_log_item	*attrip;
+	uint				size;
+
+	size = (uint)(sizeof(struct xfs_attri_log_item));
+	attrip = kmem_zalloc(size, KM_SLEEP);
+
+	xfs_log_item_init(mp, &attrip->attri_item, XFS_LI_ATTRI,
+			  &xfs_attri_item_ops);
+	attrip->attri_format.alfi_id = (uintptr_t)(void *)attrip;
+	atomic_set(&attrip->attri_refcount, 2);
+
+	return attrip;
+}
+
+/*
+ * Copy an attr format buffer from the given buf, and into the destination attr
+ * format structure.
+ */
+int
+xfs_attri_copy_format(struct xfs_log_iovec *buf,
+		      struct xfs_attri_log_format *dst_attr_fmt)
+{
+	struct xfs_attri_log_format *src_attr_fmt = buf->i_addr;
+	uint len = sizeof(struct xfs_attri_log_format);
+
+	if (buf->i_len != len)
+		return -EFSCORRUPTED;
+
+	memcpy((char *)dst_attr_fmt, (char *)src_attr_fmt, len);
+	return 0;
+}
+
+/*
+ * Freeing the attrip requires that we remove it from the AIL if it has already
+ * been placed there. However, the ATTRI may not yet have been placed in the
+ * AIL when called by xfs_attri_release() from ATTRD processing due to the
+ * ordering of committed vs unpin operations in bulk insert operations. Hence
+ * the reference count to ensure only the last caller frees the ATTRI.
+ */
+void
+xfs_attri_release(
+	struct xfs_attri_log_item	*attrip)
+{
+	ASSERT(atomic_read(&attrip->attri_refcount) > 0);
+	if (atomic_dec_and_test(&attrip->attri_refcount)) {
+		xfs_trans_ail_remove(&attrip->attri_item,
+				     SHUTDOWN_LOG_IO_ERROR);
+		xfs_attri_item_free(attrip);
+	}
+}
+
+static inline struct xfs_attrd_log_item *ATTRD_ITEM(struct xfs_log_item *lip)
+{
+	return container_of(lip, struct xfs_attrd_log_item, attrd_item);
+}
+
+STATIC void
+xfs_attrd_item_free(struct xfs_attrd_log_item *attrdp)
+{
+	kmem_free(attrdp->attrd_item.li_lv_shadow);
+	kmem_free(attrdp);
+}
+
+/*
+ * This returns the number of iovecs needed to log the given attrd item.
+ * We only need 1 iovec for an attrd item.  It just logs the attr_log_format
+ * structure.
+ */
+static inline int
+xfs_attrd_item_sizeof(
+	struct xfs_attrd_log_item *attrdp)
+{
+	return sizeof(struct xfs_attrd_log_format);
+}
+
+STATIC void
+xfs_attrd_item_size(
+	struct xfs_log_item	*lip,
+	int			*nvecs,
+	int			*nbytes)
+{
+	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
+	*nvecs += 1;
+	*nbytes += xfs_attrd_item_sizeof(attrdp);
+}
+
+/*
+ * This is called to fill in the vector of log iovecs for the
+ * given attrd log item. We use only 1 iovec, and we point that
+ * at the attr_log_format structure embedded in the attrd item.
+ * It is at this point that we assert that all of the attr
+ * slots in the attrd item have been filled.
+ */
+STATIC void
+xfs_attrd_item_format(
+	struct xfs_log_item	*lip,
+	struct xfs_log_vec	*lv)
+{
+	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
+	struct xfs_log_iovec	*vecp = NULL;
+
+	attrdp->attrd_format.alfd_type = XFS_LI_ATTRD;
+	attrdp->attrd_format.alfd_size = 1;
+
+	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRD_FORMAT,
+			&attrdp->attrd_format, xfs_attrd_item_sizeof(attrdp));
+}
+
+/*
+ * Pinning has no meaning for an attrd item, so just return.
+ */
+STATIC void
+xfs_attrd_item_pin(
+	struct xfs_log_item	*lip)
+{
+}
+
+/*
+ * Since pinning has no meaning for an attrd item, unpinning does
+ * not either.
+ */
+STATIC void
+xfs_attrd_item_unpin(
+	struct xfs_log_item	*lip,
+	int			remove)
+{
+}
+
+/*
+ * There isn't much you can do to push on an attrd item.  It is simply stuck
+ * waiting for the log to be flushed to disk.
+ */
+STATIC uint
+xfs_attrd_item_push(
+	struct xfs_log_item	*lip,
+	struct list_head	*buffer_list)
+{
+	return XFS_ITEM_PINNED;
+}
+
+/*
+ * When the attrd item is committed to disk, all we need to do is delete our
+ * reference to our partner attri item and then free ourselves. Since we're
+ * freeing ourselves we must return -1 to keep the transaction code from
+ * further referencing this item.
+ */
+STATIC xfs_lsn_t
+xfs_attrd_item_committed(
+	struct xfs_log_item	*lip,
+	xfs_lsn_t		lsn)
+{
+	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
+
+	/*
+	 * Drop the ATTRI reference regardless of whether the ATTRD has been
+	 * aborted. Once the ATTRD transaction is constructed, it is the sole
+	 * responsibility of the ATTRD to release the ATTRI (even if the ATTRI
+	 * is aborted due to log I/O error).
+	 */
+	xfs_attri_release(attrdp->attrd_attrip);
+	xfs_attrd_item_free(attrdp);
+
+	return (xfs_lsn_t)-1;
+}
+
+STATIC void
+xfs_attrd_item_committing(
+	struct xfs_log_item	*lip,
+	xfs_lsn_t		lsn)
+{
+}
+
+/*
+ * The ATTRD is either committed or aborted if the transaction is cancelled. If
+ * the transaction is cancelled, drop our reference to the ATTRI and free the
+ * ATTRD.
+ */
+STATIC void
+xfs_attrd_item_release(
+	struct xfs_log_item     *lip)
+{
+	struct xfs_attrd_log_item *attrdp = ATTRD_ITEM(lip);
+
+	xfs_attri_release(attrdp->attrd_attrip);
+	xfs_attrd_item_free(attrdp);
+}
+
+/*
+ * This is the ops vector shared by all attrd log items.
+ */
+static const struct xfs_item_ops xfs_attrd_item_ops = {
+	.iop_size	= xfs_attrd_item_size,
+	.iop_format	= xfs_attrd_item_format,
+	.iop_pin	= xfs_attrd_item_pin,
+	.iop_unpin	= xfs_attrd_item_unpin,
+	.iop_committed	= xfs_attrd_item_committed,
+	.iop_push	= xfs_attrd_item_push,
+	.iop_committing = xfs_attrd_item_committing,
+	.iop_release    = xfs_attrd_item_release,
+};
+
+/*
+ * Allocate and initialize an attrd item
+ */
+struct xfs_attrd_log_item *
+xfs_attrd_init(
+	struct xfs_mount		*mp,
+	struct xfs_attri_log_item	*attrip)
+
+{
+	struct xfs_attrd_log_item	*attrdp;
+	uint				size;
+
+	size = (uint)(sizeof(struct xfs_attrd_log_item));
+	attrdp = kmem_zalloc(size, KM_SLEEP);
+
+	xfs_log_item_init(mp, &attrdp->attrd_item, XFS_LI_ATTRD,
+			  &xfs_attrd_item_ops);
+	attrdp->attrd_attrip = attrip;
+	attrdp->attrd_format.alfd_alf_id = attrip->attri_format.alfi_id;
+
+	return attrdp;
+}
+
+/*
+ * Process an attr intent item that was recovered from the log.  We need to
+ * delete the attr that it describes.
+ */
+int
+xfs_attri_recover(
+	struct xfs_mount		*mp,
+	struct xfs_attri_log_item	*attrip)
+{
+	struct xfs_inode		*ip;
+	struct xfs_attrd_log_item	*attrdp;
+	struct xfs_da_args		args;
+	struct xfs_attri_log_format	*attrp;
+	struct xfs_trans_res		tres;
+	int				local;
+	int				error = 0;
+	int				rsvd = 0;
+	struct xfs_name			name;
+
+	ASSERT(!test_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags));
+
+	/*
+	 * First check the validity of the attr described by the ATTRI.  If any
+	 * are bad, then assume that all are bad and just toss the ATTRI.
+	 */
+	attrp = &attrip->attri_format;
+	if (
+	    !(attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_SET ||
+		attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_REMOVE) ||
+	      (attrp->alfi_value_len > XATTR_SIZE_MAX) ||
+	      (attrp->alfi_name_len > XATTR_NAME_MAX) ||
+	      (attrp->alfi_name_len == 0)
+	) {
+		/*
+		 * This will pull the ATTRI from the AIL and free the memory
+		 * associated with it.
+		 */
+		set_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags);
+		xfs_attri_release(attrip);
+		return -EIO;
+	}
+
+	attrp = &attrip->attri_format;
+	error = xfs_iget(mp, 0, attrp->alfi_ino, 0, 0, &ip);
+	if (error)
+		return error;
+
+	name.name = attrip->attri_name;
+	name.len = attrp->alfi_name_len;
+	name.type = attrp->alfi_attr_flags;
+	error = xfs_attr_args_init(&args, ip, &name);
+	if (error)
+		return error;
+
+	args.hashval = xfs_da_hashname(args.name, args.namelen);
+	args.value = attrip->attri_value;
+	args.valuelen = attrp->alfi_value_len;
+	args.op_flags = XFS_DA_OP_OKNOENT;
+	args.total = xfs_attr_calc_size(&args, &local);
+
+	tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
+			M_RES(mp)->tr_attrsetrt.tr_logres * args.total;
+	tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
+	tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
+
+	error = xfs_trans_alloc(mp, &tres, args.total,  0,
+				rsvd ? XFS_TRANS_RESERVE : 0, &args.trans);
+	if (error)
+		return error;
+	attrdp = xfs_trans_get_attrd(args.trans, attrip);
+
+	xfs_ilock(ip, XFS_ILOCK_EXCL);
+
+	xfs_trans_ijoin(args.trans, ip, 0);
+	error = xfs_trans_attr(&args, attrdp, attrp->alfi_op_flags);
+	if (error)
+		goto abort_error;
+
+
+	set_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags);
+	xfs_trans_log_inode(args.trans, ip, XFS_ILOG_CORE | XFS_ILOG_ADATA);
+	error = xfs_trans_commit(args.trans);
+	xfs_iunlock(ip, XFS_ILOCK_EXCL);
+	return error;
+
+abort_error:
+	xfs_trans_cancel(args.trans);
+	xfs_iunlock(ip, XFS_ILOCK_EXCL);
+	return error;
+}
diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h
new file mode 100644
index 0000000..aad32ed
--- /dev/null
+++ b/fs/xfs/xfs_attr_item.h
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Oracle.  All Rights Reserved.
+ * Author: Allison Henderson <allison.henderson@oracle.com>
+ */
+#ifndef	__XFS_ATTR_ITEM_H__
+#define	__XFS_ATTR_ITEM_H__
+
+/* kernel only ATTRI/ATTRD definitions */
+
+struct xfs_mount;
+struct kmem_zone;
+
+/*
+ * Max number of attrs in fast allocation path.
+ */
+#define XFS_ATTRI_MAX_FAST_ATTRS        1
+
+
+/*
+ * Define ATTR flag bits. Manipulated by set/clear/test_bit operators.
+ */
+#define	XFS_ATTRI_RECOVERED	1
+
+
+/* iovec length must be 32-bit aligned */
+#define ATTR_NVEC_SIZE(size) (size == sizeof(int32_t) ? sizeof(int32_t) : \
+				size + sizeof(int32_t) - \
+				(size % sizeof(int32_t)))
+
+/*
+ * This is the "attr intention" log item.  It is used to log the fact that some
+ * need to be processed.  It is used in conjunction with the "attr done" log
+ * item described below.
+ *
+ * The ATTRI is reference counted so that it is not freed prior to both the
+ * ATTRI and ATTRD being committed and unpinned. This ensures the ATTRI is
+ * inserted into the AIL even in the event of out of order ATTRI/ATTRD
+ * processing. In other words, an ATTRI is born with two references:
+ *
+ *      1.) an ATTRI held reference to track ATTRI AIL insertion
+ *      2.) an ATTRD held reference to track ATTRD commit
+ *
+ * On allocation, both references are the responsibility of the caller. Once the
+ * ATTRI is added to and dirtied in a transaction, ownership of reference one
+ * transfers to the transaction. The reference is dropped once the ATTRI is
+ * inserted to the AIL or in the event of failure along the way (e.g., commit
+ * failure, log I/O error, etc.). Note that the caller remains responsible for
+ * the ATTRD reference under all circumstances to this point. The caller has no
+ * means to detect failure once the transaction is committed, however.
+ * Therefore, an ATTRD is required after this point, even in the event of
+ * unrelated failure.
+ *
+ * Once an ATTRD is allocated and dirtied in a transaction, reference two
+ * transfers to the transaction. The ATTRD reference is dropped once it reaches
+ * the unpin handler. Similar to the ATTRI, the reference also drops in the
+ * event of commit failure or log I/O errors. Note that the ATTRD is not
+ * inserted in the AIL, so at this point both the ATTI and ATTRD are freed.
+ */
+struct xfs_attri_log_item {
+	struct xfs_log_item		attri_item;
+	atomic_t			attri_refcount;
+	unsigned long			attri_flags;	/* misc flags */
+	int				attri_name_len;
+	void				*attri_name;
+	int				attri_value_len;
+	void				*attri_value;
+	struct xfs_attri_log_format	attri_format;
+};
+
+/*
+ * This is the "attr done" log item.  It is used to log the fact that some attrs
+ * earlier mentioned in an attri item have been freed.
+ */
+struct xfs_attrd_log_item {
+	struct xfs_log_item		attrd_item;
+	struct xfs_attri_log_item	*attrd_attrip;
+	struct xfs_attrd_log_format	attrd_format;
+};
+
+/*
+ * Max number of attrs in fast allocation path.
+ */
+#define	XFS_ATTRD_MAX_FAST_ATTRS	1
+
+extern struct kmem_zone	*xfs_attri_zone;
+extern struct kmem_zone	*xfs_attrd_zone;
+
+struct xfs_attri_log_item	*xfs_attri_init(struct xfs_mount *mp);
+struct xfs_attrd_log_item	*xfs_attrd_init(struct xfs_mount *mp,
+					struct xfs_attri_log_item *attrip);
+int xfs_attri_copy_format(struct xfs_log_iovec *buf,
+			   struct xfs_attri_log_format *dst_attri_fmt);
+int xfs_attrd_copy_format(struct xfs_log_iovec *buf,
+			   struct xfs_attrd_log_format *dst_attrd_fmt);
+void			xfs_attri_item_free(struct xfs_attri_log_item *attrip);
+void			xfs_attri_release(struct xfs_attri_log_item *attrip);
+
+int			xfs_attri_recover(struct xfs_mount *mp,
+					struct xfs_attri_log_item *attrip);
+
+#endif	/* __XFS_ATTR_ITEM_H__ */
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 00e9f5c..2fbd180 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -2005,6 +2005,10 @@ xlog_print_tic_res(
 	    REG_TYPE_STR(CUD_FORMAT, "cud_format"),
 	    REG_TYPE_STR(BUI_FORMAT, "bui_format"),
 	    REG_TYPE_STR(BUD_FORMAT, "bud_format"),
+	    REG_TYPE_STR(ATTRI_FORMAT, "attri_format"),
+	    REG_TYPE_STR(ATTRD_FORMAT, "attrd_format"),
+	    REG_TYPE_STR(ATTR_NAME, "attr_name"),
+	    REG_TYPE_STR(ATTR_VALUE, "attr_value"),
 	};
 	BUILD_BUG_ON(ARRAY_SIZE(res_type_str) != XLOG_REG_TYPE_MAX + 1);
 #undef REG_TYPE_STR
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 13d1d3e..233efdb3 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -20,6 +20,7 @@
 #include "xfs_log_recover.h"
 #include "xfs_inode_item.h"
 #include "xfs_extfree_item.h"
+#include "xfs_attr_item.h"
 #include "xfs_trans_priv.h"
 #include "xfs_alloc.h"
 #include "xfs_ialloc.h"
@@ -1885,6 +1886,8 @@ xlog_recover_reorder_trans(
 		case XFS_LI_CUD:
 		case XFS_LI_BUI:
 		case XFS_LI_BUD:
+		case XFS_LI_ATTRI:
+		case XFS_LI_ATTRD:
 			trace_xfs_log_recover_item_reorder_tail(log,
 							trans, item, pass);
 			list_move_tail(&item->ri_list, &inode_list);
@@ -3422,6 +3425,119 @@ xlog_recover_efd_pass2(
 	return 0;
 }
 
+STATIC int
+xlog_recover_attri_pass2(
+	struct xlog                     *log,
+	struct xlog_recover_item        *item,
+	xfs_lsn_t                       lsn)
+{
+	int                             error;
+	struct xfs_mount                *mp = log->l_mp;
+	struct xfs_attri_log_item       *attrip;
+	struct xfs_attri_log_format     *attri_formatp;
+	char				*name = NULL;
+	char				*value = NULL;
+	int				region = 0;
+
+	attri_formatp = item->ri_buf[region].i_addr;
+
+	attrip = xfs_attri_init(mp);
+	error = xfs_attri_copy_format(&item->ri_buf[region],
+				      &attrip->attri_format);
+	if (error) {
+		xfs_attri_item_free(attrip);
+		return error;
+	}
+
+	attrip->attri_name_len = attri_formatp->alfi_name_len;
+	attrip->attri_value_len = attri_formatp->alfi_value_len;
+	attrip = kmem_realloc(attrip, sizeof(struct xfs_attri_log_item) +
+			      attrip->attri_name_len + attrip->attri_value_len,
+			      KM_SLEEP);
+
+	if (attrip->attri_name_len > 0) {
+		region++;
+		name = ((char *)attrip) + sizeof(struct xfs_attri_log_item);
+		memcpy(name, item->ri_buf[region].i_addr,
+		       attrip->attri_name_len);
+		attrip->attri_name = name;
+	}
+
+	if (attrip->attri_value_len > 0) {
+		region++;
+		value = ((char *)attrip) + sizeof(struct xfs_attri_log_item) +
+			attrip->attri_name_len;
+		memcpy(value, item->ri_buf[region].i_addr,
+			attrip->attri_value_len);
+		attrip->attri_value = value;
+	}
+
+	spin_lock(&log->l_ailp->ail_lock);
+	/*
+	 * The ATTRI has two references. One for the ATTRD and one for ATTRI to
+	 * ensure it makes it into the AIL. Insert the ATTRI into the AIL
+	 * directly and drop the ATTRI reference. Note that
+	 * xfs_trans_ail_update() drops the AIL lock.
+	 */
+	xfs_trans_ail_update(log->l_ailp, &attrip->attri_item, lsn);
+	xfs_attri_release(attrip);
+	return 0;
+}
+
+
+/*
+ * This routine is called when an ATTRD format structure is found in a committed
+ * transaction in the log. Its purpose is to cancel the corresponding ATTRI if
+ * it was still in the log. To do this it searches the AIL for the ATTRI with
+ * an id equal to that in the ATTRD format structure. If we find it we drop
+ * the ATTRD reference, which removes the ATTRI from the AIL and frees it.
+ */
+STATIC int
+xlog_recover_attrd_pass2(
+	struct xlog                     *log,
+	struct xlog_recover_item        *item)
+{
+	struct xfs_attrd_log_format	*attrd_formatp;
+	struct xfs_attri_log_item	*attrip = NULL;
+	struct xfs_log_item		*lip;
+	uint64_t			attri_id;
+	struct xfs_ail_cursor		cur;
+	struct xfs_ail			*ailp = log->l_ailp;
+
+	attrd_formatp = item->ri_buf[0].i_addr;
+	ASSERT((item->ri_buf[0].i_len ==
+				(sizeof(struct xfs_attrd_log_format))));
+	attri_id = attrd_formatp->alfd_alf_id;
+
+	/*
+	 * Search for the ATTRI with the id in the ATTRD format structure in the
+	 * AIL.
+	 */
+	spin_lock(&ailp->ail_lock);
+	lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
+	while (lip != NULL) {
+		if (lip->li_type == XFS_LI_ATTRI) {
+			attrip = (struct xfs_attri_log_item *)lip;
+			if (attrip->attri_format.alfi_id == attri_id) {
+				/*
+				 * Drop the ATTRD reference to the ATTRI. This
+				 * removes the ATTRI from the AIL and frees it.
+				 */
+				spin_unlock(&ailp->ail_lock);
+				xfs_attri_release(attrip);
+				spin_lock(&ailp->ail_lock);
+				break;
+			}
+		}
+		lip = xfs_trans_ail_cursor_next(ailp, &cur);
+	}
+
+	xfs_trans_ail_cursor_done(&cur);
+	spin_unlock(&ailp->ail_lock);
+
+	return 0;
+}
+
 /*
  * This routine is called to create an in-core extent rmap update
  * item from the rui format structure which was logged on disk.
@@ -3974,6 +4090,8 @@ xlog_recover_ra_pass2(
 		break;
 	case XFS_LI_EFI:
 	case XFS_LI_EFD:
+	case XFS_LI_ATTRI:
+	case XFS_LI_ATTRD:
 	case XFS_LI_QUOTAOFF:
 	case XFS_LI_RUI:
 	case XFS_LI_RUD:
@@ -4002,6 +4120,8 @@ xlog_recover_commit_pass1(
 	case XFS_LI_INODE:
 	case XFS_LI_EFI:
 	case XFS_LI_EFD:
+	case XFS_LI_ATTRI:
+	case XFS_LI_ATTRD:
 	case XFS_LI_DQUOT:
 	case XFS_LI_ICREATE:
 	case XFS_LI_RUI:
@@ -4040,6 +4160,10 @@ xlog_recover_commit_pass2(
 		return xlog_recover_efi_pass2(log, item, trans->r_lsn);
 	case XFS_LI_EFD:
 		return xlog_recover_efd_pass2(log, item);
+	case XFS_LI_ATTRI:
+		return xlog_recover_attri_pass2(log, item, trans->r_lsn);
+	case XFS_LI_ATTRD:
+		return xlog_recover_attrd_pass2(log, item);
 	case XFS_LI_RUI:
 		return xlog_recover_rui_pass2(log, item, trans->r_lsn);
 	case XFS_LI_RUD:
@@ -4601,6 +4725,48 @@ xlog_recover_cancel_efi(
 	spin_lock(&ailp->ail_lock);
 }
 
+/* Release the ATTRI since we're cancelling everything. */
+STATIC void
+xlog_recover_cancel_attri(
+	struct xfs_mount                *mp,
+	struct xfs_ail                  *ailp,
+	struct xfs_log_item             *lip)
+{
+	struct xfs_attri_log_item         *attrip;
+
+	attrip = container_of(lip, struct xfs_attri_log_item, attri_item);
+
+	spin_unlock(&ailp->ail_lock);
+	xfs_attri_release(attrip);
+	spin_lock(&ailp->ail_lock);
+}
+
+
+/* Recover the ATTRI if necessary. */
+STATIC int
+xlog_recover_process_attri(
+	struct xfs_mount                *mp,
+	struct xfs_ail                  *ailp,
+	struct xfs_log_item             *lip)
+{
+	struct xfs_attri_log_item       *attrip;
+	int                             error;
+
+	/*
+	 * Skip ATTRIs that we've already processed.
+	 */
+	attrip = container_of(lip, struct xfs_attri_log_item, attri_item);
+	if (test_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags))
+		return 0;
+
+	spin_unlock(&ailp->ail_lock);
+	error = xfs_attri_recover(mp, attrip);
+	spin_lock(&ailp->ail_lock);
+
+	return error;
+}
+
+
 /* Recover the RUI if necessary. */
 STATIC int
 xlog_recover_process_rui(
@@ -4729,6 +4895,7 @@ static inline bool xlog_item_is_intent(struct xfs_log_item *lip)
 	case XFS_LI_RUI:
 	case XFS_LI_CUI:
 	case XFS_LI_BUI:
+	case XFS_LI_ATTRI:
 		return true;
 	default:
 		return false;
@@ -4847,6 +5014,10 @@ xlog_recover_process_intents(
 		case XFS_LI_EFI:
 			error = xlog_recover_process_efi(log->l_mp, ailp, lip);
 			break;
+		case XFS_LI_ATTRI:
+			error = xlog_recover_process_attri(log->l_mp,
+							   ailp, lip);
+			break;
 		case XFS_LI_RUI:
 			error = xlog_recover_process_rui(log->l_mp, ailp, lip);
 			break;
@@ -4912,6 +5083,9 @@ xlog_recover_cancel_intents(
 		case XFS_LI_BUI:
 			xlog_recover_cancel_bui(log->l_mp, ailp, lip);
 			break;
+		case XFS_LI_ATTRI:
+			xlog_recover_cancel_attri(log->l_mp, ailp, lip);
+			break;
 		}
 
 		lip = xfs_trans_ail_cursor_next(ailp, &cur);
diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h
index b6701b4..120fb0c 100644
--- a/fs/xfs/xfs_ondisk.h
+++ b/fs/xfs/xfs_ondisk.h
@@ -125,6 +125,8 @@ xfs_check_ondisk_structs(void)
 	XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format,	56);
 	XFS_CHECK_STRUCT_SIZE(struct xfs_qoff_logformat,	20);
 	XFS_CHECK_STRUCT_SIZE(struct xfs_trans_header,		16);
+	XFS_CHECK_STRUCT_SIZE(struct xfs_attri_log_format,	40);
+	XFS_CHECK_STRUCT_SIZE(struct xfs_attrd_log_format,	16);
 
 	/*
 	 * The v5 superblock format extended several v4 header structures with
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 64d7f17..95924dc 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -26,6 +26,9 @@ struct xfs_cui_log_item;
 struct xfs_cud_log_item;
 struct xfs_bui_log_item;
 struct xfs_bud_log_item;
+struct xfs_attrd_log_item;
+struct xfs_attri_log_item;
+struct xfs_da_args;
 
 struct xfs_log_item {
 	struct list_head		li_ail;		/* AIL pointers */
@@ -229,7 +232,6 @@ void		xfs_trans_log_buf(struct xfs_trans *, struct xfs_buf *, uint,
 void		xfs_trans_dirty_buf(struct xfs_trans *, struct xfs_buf *);
 bool		xfs_trans_buf_is_dirty(struct xfs_buf *bp);
 void		xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
-
 int		xfs_trans_commit(struct xfs_trans *);
 int		xfs_trans_roll(struct xfs_trans **);
 int		xfs_trans_roll_inode(struct xfs_trans **, struct xfs_inode *);
-- 
2.7.4

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

* [PATCH v2 04/18] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
                   ` (2 preceding siblings ...)
  2019-08-09 21:37 ` [PATCH v2 03/18] xfs: Set up infastructure for deferred attribute operations Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-12 15:44   ` Darrick J. Wong
  2019-08-09 21:37 ` [PATCH v2 05/18] xfs: Add xfs_has_attr and subroutines Allison Collins
                   ` (14 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

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

These routines set up set and start a new deferred attribute
operation.  These functions are meant to be called by other
code needing to initiate a deferred attribute operation.

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

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 1f76618..a2fba0c 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -25,6 +25,7 @@
 #include "xfs_trans_space.h"
 #include "xfs_trace.h"
 #include "xfs_attr_item.h"
+#include "xfs_attr.h"
 
 /*
  * xfs_attr.c
@@ -399,6 +400,48 @@ xfs_attr_set(
 	goto out_unlock;
 }
 
+/* Sets an attribute for an inode as a deferred operation */
+int
+xfs_attr_set_deferred(
+	struct xfs_inode	*dp,
+	struct xfs_trans	*tp,
+	struct xfs_name		*name,
+	const unsigned char	*value,
+	unsigned int		valuelen)
+{
+
+	struct xfs_attr_item	*new;
+	char			*name_value;
+
+	/*
+	 * All set operations must have a name but not necessarily a value.
+	 */
+	if (!name->len) {
+		ASSERT(0);
+		return -EINVAL;
+	}
+
+	new = kmem_alloc_large(XFS_ATTR_ITEM_SIZEOF(name->len, valuelen),
+			 KM_SLEEP|KM_NOFS);
+	name_value = ((char *)new) + sizeof(struct xfs_attr_item);
+	memset(new, 0, XFS_ATTR_ITEM_SIZEOF(name->len, valuelen));
+	new->xattri_ip = dp;
+	new->xattri_op_flags = XFS_ATTR_OP_FLAGS_SET;
+	new->xattri_name_len = name->len;
+	new->xattri_value_len = valuelen;
+	new->xattri_flags = name->type;
+	memcpy(&name_value[0], name->name, name->len);
+	new->xattri_name = name_value;
+	new->xattri_value = name_value + name->len;
+
+	if (valuelen > 0)
+		memcpy(&name_value[name->len], value, valuelen);
+
+	xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
+
+	return 0;
+}
+
 /*
  * Generic handler routine to remove a name from an attribute list.
  * Transitions attribute list from Btree to shortform as necessary.
@@ -480,6 +523,37 @@ xfs_attr_remove(
 	return error;
 }
 
+/* Removes an attribute for an inode as a deferred operation */
+int
+xfs_attr_remove_deferred(
+	struct xfs_inode        *dp,
+	struct xfs_trans	*tp,
+	struct xfs_name		*name)
+{
+
+	struct xfs_attr_item	*new;
+	char			*name_value;
+
+	if (!name->len) {
+		ASSERT(0);
+		return -EINVAL;
+	}
+
+	new = kmem_alloc(XFS_ATTR_ITEM_SIZEOF(name->len, 0), KM_SLEEP|KM_NOFS);
+	name_value = ((char *)new) + sizeof(struct xfs_attr_item);
+	memset(new, 0, XFS_ATTR_ITEM_SIZEOF(name->len, 0));
+	new->xattri_ip = dp;
+	new->xattri_op_flags = XFS_ATTR_OP_FLAGS_REMOVE;
+	new->xattri_name_len = name->len;
+	new->xattri_value_len = 0;
+	new->xattri_flags = name->type;
+	memcpy(name_value, name->name, name->len);
+
+	xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
+
+	return 0;
+}
+
 /*========================================================================
  * External routines when attribute list is inside the inode
  *========================================================================*/
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 9132d4f..0bade83 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -177,5 +177,10 @@ bool xfs_attr_namecheck(const void *name, size_t length);
 int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
 		       struct xfs_name *name);
 int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
+int xfs_attr_set_deferred(struct xfs_inode *dp, struct xfs_trans *tp,
+			  struct xfs_name *name, const unsigned char *value,
+			  unsigned int valuelen);
+int xfs_attr_remove_deferred(struct xfs_inode *dp, struct xfs_trans *tp,
+			    struct xfs_name *name);
 
 #endif	/* __XFS_ATTR_H__ */
-- 
2.7.4

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

* [PATCH v2 05/18] xfs: Add xfs_has_attr and subroutines
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
                   ` (3 preceding siblings ...)
  2019-08-09 21:37 ` [PATCH v2 04/18] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-12 15:56   ` Darrick J. Wong
  2019-08-09 21:37 ` [PATCH v2 06/18] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

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

This patch adds a new functions to check for the existence of
an attribute.  Subroutines are also added to handle the cases
of leaf blocks, nodes or shortform.  Common code that appears
in existing attr add and remove functions have been factored
out to help reduce the appearence of duplicated code.  We will
need these routines later for delayed attributes since delayed
operations cannot return error codes.

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c      | 151 +++++++++++++++++++++++++++---------------
 fs/xfs/libxfs/xfs_attr.h      |   1 +
 fs/xfs/libxfs/xfs_attr_leaf.c |  82 +++++++++++++++--------
 fs/xfs/libxfs/xfs_attr_leaf.h |   2 +
 4 files changed, 158 insertions(+), 78 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index a2fba0c..72af8e2 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -48,6 +48,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
+STATIC int xfs_leaf_has_attr(xfs_da_args_t *args, struct xfs_buf **bp);         
 
 /*
  * Internal routines when attribute list is more than one block.
@@ -55,6 +56,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
 STATIC int xfs_attr_node_get(xfs_da_args_t *args);
 STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
 STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
+STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
+				 struct xfs_da_state **state);
 STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
 STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
 
@@ -278,6 +281,32 @@ xfs_attr_set_args(
 }
 
 /*
+ * Return EEXIST if attr is found, or ENOATTR if not
+ */
+int
+xfs_has_attr(
+	struct xfs_da_args      *args)
+{
+	struct xfs_inode        *dp = args->dp;
+	struct xfs_buf		*bp;
+	int                     error;
+
+	if (!xfs_inode_hasattr(dp)) {
+		error = -ENOATTR;
+	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
+		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
+		error = xfs_shortform_has_attr(args, NULL, NULL);
+	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+		error = xfs_leaf_has_attr(args, &bp);
+		xfs_trans_brelse(args->trans, bp);
+	} else {
+		error = xfs_attr_node_hasname(args, NULL);
+	}
+
+	return error;
+}
+
+/*
  * Remove the attribute specified in @args.
  */
 int
@@ -616,26 +645,17 @@ STATIC int
 xfs_attr_leaf_addname(
 	struct xfs_da_args	*args)
 {
-	struct xfs_inode	*dp;
 	struct xfs_buf		*bp;
 	int			retval, error, forkoff;
+	struct xfs_inode	*dp = args->dp;
 
 	trace_xfs_attr_leaf_addname(args);
 
 	/*
-	 * Read the (only) block in the attribute list in.
-	 */
-	dp = args->dp;
-	args->blkno = 0;
-	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
-	if (error)
-		return error;
-
-	/*
 	 * Look up the given attribute in the leaf block.  Figure out if
 	 * the given flags produce an error or call for an atomic rename.
 	 */
-	retval = xfs_attr3_leaf_lookup_int(bp, args);
+	retval = xfs_leaf_has_attr(args, &bp);
 	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
 		xfs_trans_brelse(args->trans, bp);
 		return retval;
@@ -787,6 +807,26 @@ xfs_attr_leaf_addname(
 }
 
 /*
+ * Return EEXIST if attr is found, or ENOATTR if not
+ */
+STATIC int
+xfs_leaf_has_attr(
+	struct xfs_da_args      *args,
+	struct xfs_buf		**bp)
+{
+	int                     error = 0;
+
+	args->blkno = 0;
+	error = xfs_attr3_leaf_read(args->trans, args->dp,
+			args->blkno, -1, bp);
+	if (error)
+		return error;
+
+	error = xfs_attr3_leaf_lookup_int(*bp, args);
+	return error;
+}
+
+/*
  * Remove a name from the leaf attribute list structure
  *
  * This leaf block cannot have a "remote" value, we only call this routine
@@ -806,12 +846,8 @@ xfs_attr_leaf_removename(
 	 * Remove the attribute.
 	 */
 	dp = args->dp;
-	args->blkno = 0;
-	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
-	if (error)
-		return error;
 
-	error = xfs_attr3_leaf_lookup_int(bp, args);
+	error = xfs_leaf_has_attr(args, &bp);
 	if (error == -ENOATTR) {
 		xfs_trans_brelse(args->trans, bp);
 		return error;
@@ -848,12 +884,7 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
 
 	trace_xfs_attr_leaf_get(args);
 
-	args->blkno = 0;
-	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
-	if (error)
-		return error;
-
-	error = xfs_attr3_leaf_lookup_int(bp, args);
+	error = xfs_leaf_has_attr(args, &bp);
 	if (error != -EEXIST)  {
 		xfs_trans_brelse(args->trans, bp);
 		return error;
@@ -866,6 +897,43 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
 	return error;
 }
 
+/*
+ * Return EEXIST if attr is found, or ENOATTR if not
+ * statep: If not null is set to point at the found state.  Caller will
+ * 	   be responsible for freeing the state in this case.
+ */
+STATIC int
+xfs_attr_node_hasname(
+	struct xfs_da_args	*args,
+	struct xfs_da_state	**statep)
+{
+	struct xfs_da_state	*state;
+	struct xfs_inode	*dp;
+	int			retval, error;
+
+	/*
+	 * Tie a string around our finger to remind us where we are.
+	 */
+	dp = args->dp;
+	state = xfs_da_state_alloc();
+	state->args = args;
+	state->mp = dp->i_mount;
+
+	/*
+	 * Search to see if name exists, and get back a pointer to it.
+	 */
+	error = xfs_da3_node_lookup_int(state, &retval);
+	if (error == 0)
+		error = retval;
+
+	if (statep != NULL)
+		*statep = state;
+	else
+		xfs_da_state_free(state);
+
+	return error;
+}
+
 /*========================================================================
  * External routines when attribute list size > geo->blksize
  *========================================================================*/
@@ -898,17 +966,14 @@ xfs_attr_node_addname(
 	dp = args->dp;
 	mp = dp->i_mount;
 restart:
-	state = xfs_da_state_alloc();
-	state->args = args;
-	state->mp = mp;
-
 	/*
 	 * Search to see if name already exists, and get back a pointer
 	 * to where it should go.
 	 */
-	error = xfs_da3_node_lookup_int(state, &retval);
-	if (error)
+	error = xfs_attr_node_hasname(args, &state);
+	if (error == -EEXIST)
 		goto out;
+
 	blk = &state->path.blk[ state->path.active-1 ];
 	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
 	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
@@ -1113,29 +1178,15 @@ xfs_attr_node_removename(
 {
 	struct xfs_da_state	*state;
 	struct xfs_da_state_blk	*blk;
-	struct xfs_inode	*dp;
 	struct xfs_buf		*bp;
 	int			retval, error, forkoff;
+	struct xfs_inode	*dp = args->dp;
 
 	trace_xfs_attr_node_removename(args);
 
-	/*
-	 * Tie a string around our finger to remind us where we are.
-	 */
-	dp = args->dp;
-	state = xfs_da_state_alloc();
-	state->args = args;
-	state->mp = dp->i_mount;
-
-	/*
-	 * Search to see if name exists, and get back a pointer to it.
-	 */
-	error = xfs_da3_node_lookup_int(state, &retval);
-	if (error || (retval != -EEXIST)) {
-		if (error == 0)
-			error = retval;
+	error = xfs_attr_node_hasname(args, &state);
+	if (error != -EEXIST)
 		goto out;
-	}
 
 	/*
 	 * If there is an out-of-line value, de-allocate the blocks.
@@ -1355,17 +1406,13 @@ xfs_attr_node_get(xfs_da_args_t *args)
 
 	trace_xfs_attr_node_get(args);
 
-	state = xfs_da_state_alloc();
-	state->args = args;
-	state->mp = args->dp->i_mount;
-
 	/*
 	 * Search to see if name exists, and get back a pointer to it.
 	 */
-	error = xfs_da3_node_lookup_int(state, &retval);
-	if (error) {
+	error = xfs_attr_node_hasname(args, &state);
+	if (error != -EEXIST) {
 		retval = error;
-	} else if (retval == -EEXIST) {
+	} else {
 		blk = &state->path.blk[ state->path.active-1 ];
 		ASSERT(blk->bp != NULL);
 		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 0bade83..c082d34 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -170,6 +170,7 @@ int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
 		 unsigned char *value, int valuelen);
 int xfs_attr_set_args(struct xfs_da_args *args);
 int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name);
+int xfs_has_attr(struct xfs_da_args *args);
 int xfs_attr_remove_args(struct xfs_da_args *args);
 int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
 		  int flags, struct attrlist_cursor_kern *cursor);
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 70eb941..8d2e11f 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -546,6 +546,53 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
 }
 
 /*
+ * Return EEXIST if attr is found, or ENOATTR if not
+ * args:  args containing attribute name and namelen
+ * sfep:  If not null, pointer will be set to the last attr entry found
+ * basep: If not null, pointer is set to the byte offset of the entry in the
+ *	  list
+ */
+int
+xfs_shortform_has_attr(
+	struct xfs_da_args	 *args,
+	struct xfs_attr_sf_entry **sfep,
+	int			 *basep)
+{
+	struct xfs_attr_shortform *sf;
+	struct xfs_attr_sf_entry *sfe;
+	int			base = sizeof(struct xfs_attr_sf_hdr);
+	int			size = 0;
+	int			end;
+	int			i;
+
+	base = sizeof(struct xfs_attr_sf_hdr);
+	sf = (struct xfs_attr_shortform *)args->dp->i_afp->if_u1.if_data;
+	sfe = &sf->list[0];
+	end = sf->hdr.count;
+	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
+			base += size, i++) {
+		size = XFS_ATTR_SF_ENTSIZE(sfe);
+		if (sfe->namelen != args->namelen)
+			continue;
+		if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
+			continue;
+		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
+			continue;
+		break;
+	}
+
+	if (sfep != NULL)
+		*sfep = sfe;
+
+	if (basep != NULL)
+		*basep = base;
+
+	if (i == end)
+		return -ENOATTR;
+	return -EEXIST;
+}
+
+/*
  * Add a name/value pair to the shortform attribute list.
  * Overflow from the inode has already been checked for.
  */
@@ -554,7 +601,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
 {
 	xfs_attr_shortform_t *sf;
 	xfs_attr_sf_entry_t *sfe;
-	int i, offset, size;
+	int offset, size, error;
 	xfs_mount_t *mp;
 	xfs_inode_t *dp;
 	struct xfs_ifork *ifp;
@@ -568,18 +615,11 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
 	ifp = dp->i_afp;
 	ASSERT(ifp->if_flags & XFS_IFINLINE);
 	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
-	sfe = &sf->list[0];
-	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
+	error = xfs_shortform_has_attr(args, &sfe, NULL);
 #ifdef DEBUG
-		if (sfe->namelen != args->namelen)
-			continue;
-		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
-			continue;
-		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
-			continue;
+	if (error == -EEXIST)
 		ASSERT(0);
 #endif
-	}
 
 	offset = (char *)sfe - (char *)sf;
 	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
@@ -626,7 +666,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
 {
 	xfs_attr_shortform_t *sf;
 	xfs_attr_sf_entry_t *sfe;
-	int base, size=0, end, totsize, i;
+	int base, size = 0, end, totsize, error;
 	xfs_mount_t *mp;
 	xfs_inode_t *dp;
 
@@ -634,23 +674,13 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
 
 	dp = args->dp;
 	mp = dp->i_mount;
-	base = sizeof(xfs_attr_sf_hdr_t);
 	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
-	sfe = &sf->list[0];
 	end = sf->hdr.count;
-	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
-					base += size, i++) {
-		size = XFS_ATTR_SF_ENTSIZE(sfe);
-		if (sfe->namelen != args->namelen)
-			continue;
-		if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
-			continue;
-		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
-			continue;
-		break;
-	}
-	if (i == end)
-		return -ENOATTR;
+
+	error = xfs_shortform_has_attr(args, &sfe, &base);
+	if (error == -ENOATTR)
+		return error;
+	size = XFS_ATTR_SF_ENTSIZE(sfe);
 
 	/*
 	 * Fix up the attribute fork data, covering the hole
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
index 7b74e18..be1f636 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.h
+++ b/fs/xfs/libxfs/xfs_attr_leaf.h
@@ -39,6 +39,8 @@ int	xfs_attr_shortform_getvalue(struct xfs_da_args *args);
 int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
 			struct xfs_buf **leaf_bp);
 int	xfs_attr_shortform_remove(struct xfs_da_args *args);
+int	xfs_shortform_has_attr(struct xfs_da_args *args,
+			       struct xfs_attr_sf_entry **sfep, int *basep);
 int	xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
 int	xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes);
 xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_inode *ip);
-- 
2.7.4

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

* [PATCH v2 06/18] xfs: Factor out new helper functions xfs_attr_rmtval_set
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
                   ` (4 preceding siblings ...)
  2019-08-09 21:37 ` [PATCH v2 05/18] xfs: Add xfs_has_attr and subroutines Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-12 16:01   ` Darrick J. Wong
  2019-08-09 21:37 ` [PATCH v2 07/18] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags Allison Collins
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

Break xfs_attr_rmtval_set into two helper functions
xfs_attr_rmt_find_hole and xfs_attr_rmtval_set_value.
xfs_attr_rmtval_set rolls the transaction between the
helpers, but delayed operations cannot.  We will use
the helpers later when constructing new delayed
attribute routines.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr_remote.c | 73 +++++++++++++++++++++++++++++++----------
 fs/xfs/libxfs/xfs_attr_remote.h |  4 ++-
 2 files changed, 58 insertions(+), 19 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index 4eb30d3..c421412 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -21,6 +21,7 @@
 #include "xfs_attr.h"
 #include "xfs_trace.h"
 #include "xfs_error.h"
+#include "xfs_attr_remote.h"
 
 #define ATTR_RMTVALUE_MAPSIZE	1	/* # of map entries at once */
 
@@ -430,34 +431,18 @@ xfs_attr_rmtval_set(
 	struct xfs_da_args	*args)
 {
 	struct xfs_inode	*dp = args->dp;
-	struct xfs_mount	*mp = dp->i_mount;
 	struct xfs_bmbt_irec	map;
 	xfs_dablk_t		lblkno;
 	xfs_fileoff_t		lfileoff = 0;
-	uint8_t			*src = args->value;
 	int			blkcnt;
-	int			valuelen;
 	int			nmap;
 	int			error;
-	int			offset = 0;
 
-	trace_xfs_attr_rmtval_set(args);
-
-	/*
-	 * Find a "hole" in the attribute address space large enough for
-	 * us to drop the new attribute's value into. Because CRC enable
-	 * attributes have headers, we can't just do a straight byte to FSB
-	 * conversion and have to take the header space into account.
-	 */
-	blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
-	error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
-						   XFS_ATTR_FORK);
+	error = xfs_attr_rmt_find_hole(args, &blkcnt, &lfileoff);
 	if (error)
 		return error;
 
-	args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
-	args->rmtblkcnt = blkcnt;
-
+	lblkno = (xfs_dablk_t)lfileoff;
 	/*
 	 * Roll through the "value", allocating blocks on disk as required.
 	 */
@@ -498,6 +483,58 @@ xfs_attr_rmtval_set(
 			return error;
 	}
 
+	error = xfs_attr_rmtval_set_value(args);
+	return error;
+}
+
+
+
+int
+xfs_attr_rmt_find_hole(
+	struct xfs_da_args	*args,
+	int			*blkcnt,
+	xfs_fileoff_t		*lfileoff)
+{
+	struct xfs_inode        *dp = args->dp;
+	struct xfs_mount	*mp = dp->i_mount;
+	int			error;
+
+	trace_xfs_attr_rmtval_set(args);
+
+	/*
+	 * Find a "hole" in the attribute address space large enough for
+	 * us to drop the new attribute's value into. Because CRC enable
+	 * attributes have headers, we can't just do a straight byte to FSB
+	 * conversion and have to take the header space into account.
+	 */
+	*blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
+	error = xfs_bmap_first_unused(args->trans, args->dp, *blkcnt, lfileoff,
+						   XFS_ATTR_FORK);
+	if (error)
+		return error;
+
+	args->rmtblkno = (xfs_dablk_t)*lfileoff;
+	args->rmtblkcnt = *blkcnt;
+
+	return 0;
+}
+
+int
+xfs_attr_rmtval_set_value(
+	struct xfs_da_args	*args)
+{
+	struct xfs_inode	*dp = args->dp;
+	struct xfs_mount	*mp = dp->i_mount;
+	struct xfs_bmbt_irec	map;
+	xfs_dablk_t		lblkno;
+	uint8_t			*src = args->value;
+	int			blkcnt;
+	int			valuelen;
+	int			nmap;
+	int			error;
+	int			offset = 0;
+
+
 	/*
 	 * Roll through the "value", copying the attribute value to the
 	 * already-allocated blocks.  Blocks are written synchronously
diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
index 9d20b66..2a73cd9 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.h
+++ b/fs/xfs/libxfs/xfs_attr_remote.h
@@ -11,5 +11,7 @@ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen);
 int xfs_attr_rmtval_get(struct xfs_da_args *args);
 int xfs_attr_rmtval_set(struct xfs_da_args *args);
 int xfs_attr_rmtval_remove(struct xfs_da_args *args);
-
+int xfs_attr_rmtval_set_value(struct xfs_da_args *args);
+int xfs_attr_rmt_find_hole(struct xfs_da_args *args, int *blkcnt,
+			   xfs_fileoff_t *lfileoff);
 #endif /* __XFS_ATTR_REMOTE_H__ */
-- 
2.7.4

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

* [PATCH v2 07/18] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
                   ` (5 preceding siblings ...)
  2019-08-09 21:37 ` [PATCH v2 06/18] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-12 16:02   ` Darrick J. Wong
  2019-08-09 21:37 ` [PATCH v2 08/18] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
                   ` (11 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

Since delayed operations cannot roll transactions, factor
up the transaction handling into the calling function

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c      | 10 ++++++++++
 fs/xfs/libxfs/xfs_attr_leaf.c |  5 -----
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 72af8e2..f36c792 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -752,6 +752,11 @@ xfs_attr_leaf_addname(
 		error = xfs_attr3_leaf_flipflags(args);
 		if (error)
 			return error;
+		/*
+		 * Commit the flag value change and start the next trans in
+		 * series.
+		 */
+		error = xfs_trans_roll_inode(&args->trans, args->dp);
 
 		/*
 		 * Dismantle the "old" attribute/value pair by removing
@@ -1090,6 +1095,11 @@ xfs_attr_node_addname(
 		error = xfs_attr3_leaf_flipflags(args);
 		if (error)
 			goto out;
+		/*
+		 * Commit the flag value change and start the next trans in
+		 * series
+		 */
+		error = xfs_trans_roll_inode(&args->trans, args->dp);
 
 		/*
 		 * Dismantle the "old" attribute/value pair by removing
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 8d2e11f..8a6f5df 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2891,10 +2891,5 @@ xfs_attr3_leaf_flipflags(
 			 XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt)));
 	}
 
-	/*
-	 * Commit the flag value change and start the next trans in series.
-	 */
-	error = xfs_trans_roll_inode(&args->trans, args->dp);
-
 	return error;
 }
-- 
2.7.4

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

* [PATCH v2 08/18] xfs: Factor out xfs_attr_leaf_addname helper
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
                   ` (6 preceding siblings ...)
  2019-08-09 21:37 ` [PATCH v2 07/18] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-12 16:06   ` Darrick J. Wong
  2019-08-09 21:37 ` [PATCH v2 09/18] xfs: Factor up commit from xfs_attr_try_sf_addname Allison Collins
                   ` (10 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

Factor out new helper function xfs_attr_leaf_try_add.
Because new delayed attribute routines cannot roll
transactions, we carve off the parts of
xfs_attr_leaf_addname that we can use.  This will help
to reduce repetitive code later when we introduce
delayed attributes.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c | 43 +++++++++++++++++++++++++++++--------------
 1 file changed, 29 insertions(+), 14 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index f36c792..f9d5e28 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -635,19 +635,12 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
  * External routines when attribute list is one block
  *========================================================================*/
 
-/*
- * Add a name to the leaf attribute list structure
- *
- * This leaf block cannot have a "remote" value, we only call this routine
- * if bmap_one_block() says there is only one block (ie: no remote blks).
- */
 STATIC int
-xfs_attr_leaf_addname(
-	struct xfs_da_args	*args)
+xfs_attr_leaf_try_add(
+	struct xfs_da_args	*args,
+	struct xfs_buf		*bp)
 {
-	struct xfs_buf		*bp;
-	int			retval, error, forkoff;
-	struct xfs_inode	*dp = args->dp;
+	int			retval, error;
 
 	trace_xfs_attr_leaf_addname(args);
 
@@ -692,13 +685,35 @@ xfs_attr_leaf_addname(
 	retval = xfs_attr3_leaf_add(bp, args);
 	if (retval == -ENOSPC) {
 		/*
-		 * Promote the attribute list to the Btree format, then
-		 * Commit that transaction so that the node_addname() call
-		 * can manage its own transactions.
+		 * Promote the attribute list to the Btree format,
 		 */
 		error = xfs_attr3_leaf_to_node(args);
 		if (error)
 			return error;
+	}
+	return retval;
+}
+
+
+/*
+ * Add a name to the leaf attribute list structure
+ *
+ * This leaf block cannot have a "remote" value, we only call this routine
+ * if bmap_one_block() says there is only one block (ie: no remote blks).
+ */
+STATIC int
+xfs_attr_leaf_addname(struct xfs_da_args	*args)
+{
+	int retval, error, forkoff;
+	struct xfs_buf		*bp = NULL;
+	struct xfs_inode	*dp = args->dp;
+
+	retval = xfs_attr_leaf_try_add(args, bp);
+	if (retval == -ENOSPC) {
+		/*
+		 * Commit that transaction so that the node_addname() call
+		 * can manage its own transactions.
+		 */
 		error = xfs_defer_finish(&args->trans);
 		if (error)
 			return error;
-- 
2.7.4

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

* [PATCH v2 09/18] xfs: Factor up commit from xfs_attr_try_sf_addname
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
                   ` (7 preceding siblings ...)
  2019-08-09 21:37 ` [PATCH v2 08/18] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-12 16:14   ` Darrick J. Wong
  2019-08-09 21:37 ` [PATCH v2 10/18] xfs: Factor up trans roll from xfs_attr3_leaf_setflag Allison Collins
                   ` (9 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

New delayed attribute routines cannot handle transactions,
so factor this up to the calling function.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index f9d5e28..6bd87e6 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -196,7 +196,7 @@ xfs_attr_try_sf_addname(
 {
 
 	struct xfs_mount	*mp = dp->i_mount;
-	int			error, error2;
+	int			error;
 
 	error = xfs_attr_shortform_addname(args);
 	if (error == -ENOSPC)
@@ -212,9 +212,7 @@ xfs_attr_try_sf_addname(
 	if (mp->m_flags & XFS_MOUNT_WSYNC)
 		xfs_trans_set_sync(args->trans);
 
-	error2 = xfs_trans_commit(args->trans);
-	args->trans = NULL;
-	return error ? error : error2;
+	return error;
 }
 
 /*
@@ -226,7 +224,7 @@ xfs_attr_set_args(
 {
 	struct xfs_inode	*dp = args->dp;
 	struct xfs_buf          *leaf_bp = NULL;
-	int			error;
+	int			error, error2 = 0;;
 
 	/*
 	 * If the attribute list is non-existent or a shortform list,
@@ -246,8 +244,11 @@ xfs_attr_set_args(
 		 * Try to add the attr to the attribute list in the inode.
 		 */
 		error = xfs_attr_try_sf_addname(dp, args);
-		if (error != -ENOSPC)
-			return error;
+		if (error != -ENOSPC) {
+			error2 = xfs_trans_commit(args->trans);
+			args->trans = NULL;
+			return error ? error : error2;
+		}
 
 		/*
 		 * It won't fit in the shortform, transform to a leaf block.
-- 
2.7.4

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

* [PATCH v2 10/18] xfs: Factor up trans roll from xfs_attr3_leaf_setflag
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
                   ` (8 preceding siblings ...)
  2019-08-09 21:37 ` [PATCH v2 09/18] xfs: Factor up commit from xfs_attr_try_sf_addname Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-12 16:14   ` Darrick J. Wong
  2019-08-09 21:37 ` [PATCH v2 11/18] xfs: Add xfs_attr3_leaf helper functions Allison Collins
                   ` (8 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

New delayed allocation routines cannot be handling
transactions so factor them up into the calling functions

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c      | 5 +++++
 fs/xfs/libxfs/xfs_attr_leaf.c | 5 +----
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 6bd87e6..7648ceb 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -1239,6 +1239,11 @@ xfs_attr_node_removename(
 		error = xfs_attr3_leaf_setflag(args);
 		if (error)
 			goto out;
+
+		error = xfs_trans_roll_inode(&args->trans, args->dp);
+		if (error)
+			goto out;
+
 		error = xfs_attr_rmtval_remove(args);
 		if (error)
 			goto out;
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 8a6f5df..4a22ced 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2773,10 +2773,7 @@ xfs_attr3_leaf_setflag(
 			 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
 	}
 
-	/*
-	 * Commit the flag value change and start the next trans in series.
-	 */
-	return xfs_trans_roll_inode(&args->trans, args->dp);
+	return error;
 }
 
 /*
-- 
2.7.4

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

* [PATCH v2 11/18] xfs: Add xfs_attr3_leaf helper functions
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
                   ` (9 preceding siblings ...)
  2019-08-09 21:37 ` [PATCH v2 10/18] xfs: Factor up trans roll from xfs_attr3_leaf_setflag Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-12 16:22   ` Darrick J. Wong
  2019-08-09 21:37 ` [PATCH v2 12/18] xfs: Factor out xfs_attr_rmtval_remove_value Allison Collins
                   ` (7 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

And new helper functions xfs_attr3_leaf_flag_is_set and
xfs_attr3_leaf_flagsflipped.  These routines check to see
if xfs_attr3_leaf_setflag or xfs_attr3_leaf_flipflags have
already been run.  We will need this later for delayed
attributes since routines may be recalled several times
when -EAGAIN is returned.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr_leaf.c | 78 +++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/libxfs/xfs_attr_leaf.h |  2 ++
 2 files changed, 80 insertions(+)

diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 4a22ced..b2d5f62 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2729,6 +2729,34 @@ xfs_attr3_leaf_clearflag(
 }
 
 /*
+ * Check if the INCOMPLETE flag on an entry in a leaf block is set.
+ */
+int
+xfs_attr3_leaf_flag_is_set(
+	struct xfs_da_args		*args)
+{
+	struct xfs_attr_leafblock	*leaf;
+	struct xfs_attr_leaf_entry	*entry;
+	struct xfs_buf			*bp;
+	struct xfs_inode		*dp = args->dp;
+	int				error = 0;
+
+	trace_xfs_attr_leaf_setflag(args);
+
+	/*
+	 * Set up the operation.
+	 */
+	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno, -1, &bp);
+	if (error)
+		return error;
+
+	leaf = bp->b_addr;
+	entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
+
+	return ((entry->flags & XFS_ATTR_INCOMPLETE) != 0);
+}
+
+/*
  * Set the INCOMPLETE flag on an entry in a leaf block.
  */
 int
@@ -2890,3 +2918,53 @@ xfs_attr3_leaf_flipflags(
 
 	return error;
 }
+
+/*
+ * On a leaf entry, check to see if the INCOMPLETE flag is cleared
+ * in args->blkno/index and set in args->blkno2/index2.
+ *
+ * Note that they could be in different blocks, or in the same block.
+ */
+int
+xfs_attr3_leaf_flagsflipped(
+	struct xfs_da_args		*args)
+{
+	struct xfs_attr_leafblock	*leaf1;
+	struct xfs_attr_leafblock	*leaf2;
+	struct xfs_attr_leaf_entry	*entry1;
+	struct xfs_attr_leaf_entry	*entry2;
+	struct xfs_buf			*bp1;
+	struct xfs_buf			*bp2;
+	struct xfs_inode		*dp = args->dp;
+	int				error = 0;
+
+	trace_xfs_attr_leaf_flipflags(args);
+
+	/*
+	 * Read the block containing the "old" attr
+	 */
+	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno, -1, &bp1);
+	if (error)
+		return error;
+
+	/*
+	 * Read the block containing the "new" attr, if it is different
+	 */
+	if (args->blkno2 != args->blkno) {
+		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno2,
+					   -1, &bp2);
+		if (error)
+			return error;
+	} else {
+		bp2 = bp1;
+	}
+
+	leaf1 = bp1->b_addr;
+	entry1 = &xfs_attr3_leaf_entryp(leaf1)[args->index];
+
+	leaf2 = bp2->b_addr;
+	entry2 = &xfs_attr3_leaf_entryp(leaf2)[args->index2];
+
+	return (((entry1->flags & XFS_ATTR_INCOMPLETE) == 0) &&
+		 (entry2->flags & XFS_ATTR_INCOMPLETE));
+}
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
index be1f636..d6afe23 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.h
+++ b/fs/xfs/libxfs/xfs_attr_leaf.h
@@ -54,7 +54,9 @@ int	xfs_attr3_leaf_to_shortform(struct xfs_buf *bp,
 				   struct xfs_da_args *args, int forkoff);
 int	xfs_attr3_leaf_clearflag(struct xfs_da_args *args);
 int	xfs_attr3_leaf_setflag(struct xfs_da_args *args);
+int	xfs_attr3_leaf_flag_is_set(struct xfs_da_args *args);
 int	xfs_attr3_leaf_flipflags(struct xfs_da_args *args);
+int	xfs_attr3_leaf_flagsflipped(struct xfs_da_args *args);
 
 /*
  * Routines used for growing the Btree.
-- 
2.7.4

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

* [PATCH v2 12/18] xfs: Factor out xfs_attr_rmtval_remove_value
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
                   ` (10 preceding siblings ...)
  2019-08-09 21:37 ` [PATCH v2 11/18] xfs: Add xfs_attr3_leaf helper functions Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-12 16:27   ` Darrick J. Wong
  2019-08-09 21:37 ` [PATCH v2 13/18] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag Allison Collins
                   ` (6 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

Because new delayed attribute routines cannot roll
transactions, we carve off the parts of
xfs_attr_rmtval_remove that we can use.  This will help to
reduce repetitive code later when we introduce delayed
attributes.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr_remote.c | 25 +++++++++++++++++++------
 fs/xfs/libxfs/xfs_attr_remote.h |  1 +
 2 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index c421412..f030365 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -586,19 +586,14 @@ xfs_attr_rmtval_set_value(
 	return 0;
 }
 
-/*
- * Remove the value associated with an attribute by deleting the
- * out-of-line buffer that it is stored on.
- */
 int
-xfs_attr_rmtval_remove(
+xfs_attr_rmtval_remove_value(
 	struct xfs_da_args	*args)
 {
 	struct xfs_mount	*mp = args->dp->i_mount;
 	xfs_dablk_t		lblkno;
 	int			blkcnt;
 	int			error;
-	int			done;
 
 	trace_xfs_attr_rmtval_remove(args);
 
@@ -642,7 +637,25 @@ xfs_attr_rmtval_remove(
 		lblkno += map.br_blockcount;
 		blkcnt -= map.br_blockcount;
 	}
+	return 0;
+}
 
+/*
+ * Remove the value associated with an attribute by deleting the
+ * out-of-line buffer that it is stored on.
+ */
+int
+xfs_attr_rmtval_remove(
+	struct xfs_da_args      *args)
+{
+	xfs_dablk_t		lblkno;
+	int			blkcnt;
+	int			error = 0;
+	int			done = 0;
+
+	error = xfs_attr_rmtval_remove_value(args);
+	if (error)
+		return error;
 	/*
 	 * Keep de-allocating extents until the remote-value region is gone.
 	 */
diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
index 2a73cd9..9a58a23 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.h
+++ b/fs/xfs/libxfs/xfs_attr_remote.h
@@ -11,6 +11,7 @@ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen);
 int xfs_attr_rmtval_get(struct xfs_da_args *args);
 int xfs_attr_rmtval_set(struct xfs_da_args *args);
 int xfs_attr_rmtval_remove(struct xfs_da_args *args);
+int xfs_attr_rmtval_remove_value(struct xfs_da_args *args);
 int xfs_attr_rmtval_set_value(struct xfs_da_args *args);
 int xfs_attr_rmt_find_hole(struct xfs_da_args *args, int *blkcnt,
 			   xfs_fileoff_t *lfileoff);
-- 
2.7.4

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

* [PATCH v2 13/18] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
                   ` (11 preceding siblings ...)
  2019-08-09 21:37 ` [PATCH v2 12/18] xfs: Factor out xfs_attr_rmtval_remove_value Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-12 16:28   ` Darrick J. Wong
  2019-08-09 21:37 ` [PATCH v2 14/18] xfs: Add delay context to xfs_da_args Allison Collins
                   ` (5 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

New delayed allocation routines cannot be handling
transactions so factor them up into the calling functions

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c      | 12 ++++++++++++
 fs/xfs/libxfs/xfs_attr_leaf.c |  5 +----
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 7648ceb..ca57202 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -823,6 +823,12 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
 		 * Added a "remote" value, just clear the incomplete flag.
 		 */
 		error = xfs_attr3_leaf_clearflag(args);
+
+		/*
+		 * Commit the flag value change and start the next trans in
+		 * series.
+		 */
+		error = xfs_trans_roll_inode(&args->trans, args->dp);
 	}
 	return error;
 }
@@ -1180,6 +1186,12 @@ xfs_attr_node_addname(
 		error = xfs_attr3_leaf_clearflag(args);
 		if (error)
 			goto out;
+
+		 /*
+		  * Commit the flag value change and start the next trans in
+		  * series.
+		  */
+		error = xfs_trans_roll_inode(&args->trans, args->dp);
 	}
 	retval = error = 0;
 
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index b2d5f62..e3604b9 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2722,10 +2722,7 @@ xfs_attr3_leaf_clearflag(
 			 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
 	}
 
-	/*
-	 * Commit the flag value change and start the next trans in series.
-	 */
-	return xfs_trans_roll_inode(&args->trans, args->dp);
+	return error;
 }
 
 /*
-- 
2.7.4

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

* [PATCH v2 14/18] xfs: Add delay context to xfs_da_args
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
                   ` (12 preceding siblings ...)
  2019-08-09 21:37 ` [PATCH v2 13/18] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-09 21:37 ` [PATCH v2 15/18] xfs: Add delayed attribute routines Allison Collins
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

This patch adds a new struct xfs_delay_context, which we
will use to keep track of the current state of a delayed
attribute operation.

The flags member is used to track various operations that
are in progress so that we know not to repeat them, and
resume where we left off before EAGAIN was returned to
cycle out the transaction.  Other members take the place
of local variables that need to retain their values
across multiple function recalls.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.h     |  6 ++++++
 fs/xfs/libxfs/xfs_da_btree.h | 23 +++++++++++++++++++++++
 fs/xfs/scrub/common.c        |  2 ++
 fs/xfs/xfs_acl.c             |  2 ++
 fs/xfs/xfs_attr_item.c       |  2 +-
 fs/xfs/xfs_attr_list.c       |  1 +
 fs/xfs/xfs_ioctl.c           |  2 ++
 fs/xfs/xfs_ioctl32.c         |  2 ++
 fs/xfs/xfs_iops.c            |  2 ++
 fs/xfs/xfs_xattr.c           |  1 +
 10 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index c082d34..b1172fd 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -91,6 +91,12 @@ struct xfs_attr_item {
 	struct list_head  xattri_list;
 
 	/*
+	 * xfs_da_args needs to remain instantiated across transaction rolls
+	 * during the defer finish, so store it here
+	 */
+	struct xfs_da_args	xattri_args;
+
+	/*
 	 * A byte array follows the header containing the file name and
 	 * attribute value.
 	 */
diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
index 84dd865..b4607ad 100644
--- a/fs/xfs/libxfs/xfs_da_btree.h
+++ b/fs/xfs/libxfs/xfs_da_btree.h
@@ -42,6 +42,28 @@ enum xfs_dacmp {
 	XFS_CMP_CASE		/* names are same but differ in case */
 };
 
+#define		XFS_DC_INIT		0x01 /* Init delay info */
+#define		XFS_DC_FOUND_LBLK	0x02 /* We found leaf blk for attr */
+#define		XFS_DC_FOUND_NBLK	0x04 /* We found node blk for attr */
+#define		XFS_DC_ALLOC_LEAF	0x08 /* We are allocating leaf blocks */
+#define		XFS_DC_ALLOC_NODE	0x10 /* We are allocating node blocks */
+#define		XFS_DC_RM_LEAF_BLKS	0x20 /* We are removing leaf blocks */
+#define		XFS_DC_RM_NODE_BLKS	0x40 /* We are removing node blocks */
+
+/*
+ * Context used for keeping track of delayed attribute operations
+ */
+struct xfs_delay_context {
+	unsigned int		flags;
+	struct xfs_buf		*leaf_bp;
+	struct xfs_bmbt_irec	map;
+	xfs_dablk_t		lblkno;
+	xfs_fileoff_t		lfileoff;
+	int			blkcnt;
+	struct xfs_da_state	*state;
+	struct xfs_da_state_blk *blk;
+};
+
 /*
  * Structure to ease passing around component names.
  */
@@ -71,6 +93,7 @@ typedef struct xfs_da_args {
 	int		rmtvaluelen2;	/* remote attr value length in bytes */
 	int		op_flags;	/* operation flags */
 	enum xfs_dacmp	cmpresult;	/* name compare result for lookups */
+	struct xfs_delay_context  dc;	/* context used for delay attr ops */
 } xfs_da_args_t;
 
 /*
diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
index 1887605..9a649d1 100644
--- a/fs/xfs/scrub/common.c
+++ b/fs/xfs/scrub/common.c
@@ -24,6 +24,8 @@
 #include "xfs_rmap_btree.h"
 #include "xfs_log.h"
 #include "xfs_trans_priv.h"
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
 #include "xfs_attr.h"
 #include "xfs_reflink.h"
 #include "scrub/scrub.h"
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 3da2568..74a62d2 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -10,6 +10,8 @@
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
 #include "xfs_inode.h"
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
 #include "xfs_attr.h"
 #include "xfs_trace.h"
 #include <linux/posix_acl_xattr.h>
diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
index 2340589..88efaf9 100644
--- a/fs/xfs/xfs_attr_item.c
+++ b/fs/xfs/xfs_attr_item.c
@@ -22,9 +22,9 @@
 #include "xfs_rmap.h"
 #include "xfs_inode.h"
 #include "xfs_icache.h"
-#include "xfs_attr.h"
 #include "xfs_da_format.h"
 #include "xfs_da_btree.h"
+#include "xfs_attr.h"
 #include "xfs_shared.h"
 #include "xfs_attr_item.h"
 #include "xfs_alloc.h"
diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
index 58fc820..a62a4be 100644
--- a/fs/xfs/xfs_attr_list.c
+++ b/fs/xfs/xfs_attr_list.c
@@ -12,6 +12,7 @@
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
 #include "xfs_da_format.h"
+#include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
 #include "xfs_bmap.h"
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index b6a7220..a754116 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -15,6 +15,8 @@
 #include "xfs_iwalk.h"
 #include "xfs_itable.h"
 #include "xfs_error.h"
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
 #include "xfs_attr.h"
 #include "xfs_bmap.h"
 #include "xfs_bmap_util.h"
diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
index 7fcf756..e48ccee 100644
--- a/fs/xfs/xfs_ioctl32.c
+++ b/fs/xfs/xfs_ioctl32.c
@@ -17,6 +17,8 @@
 #include "xfs_itable.h"
 #include "xfs_fsops.h"
 #include "xfs_rtalloc.h"
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
 #include "xfs_attr.h"
 #include "xfs_ioctl.h"
 #include "xfs_ioctl32.h"
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index bdf925c..2cc6b84 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -13,6 +13,8 @@
 #include "xfs_inode.h"
 #include "xfs_acl.h"
 #include "xfs_quota.h"
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
 #include "xfs_attr.h"
 #include "xfs_trans.h"
 #include "xfs_trace.h"
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index 3c63930..df4b1c8 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -10,6 +10,7 @@
 #include "xfs_log_format.h"
 #include "xfs_da_format.h"
 #include "xfs_inode.h"
+#include "xfs_da_btree.h"
 #include "xfs_attr.h"
 
 #include <linux/posix_acl_xattr.h>
-- 
2.7.4

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

* [PATCH v2 15/18] xfs: Add delayed attribute routines
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
                   ` (13 preceding siblings ...)
  2019-08-09 21:37 ` [PATCH v2 14/18] xfs: Add delay context to xfs_da_args Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-12 17:29   ` Darrick J. Wong
  2019-08-09 21:37 ` [PATCH v2 16/18] xfs: Roll delayed attr operations by returning EAGAIN Allison Collins
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

This patch adds new delayed attribute routines:

xfs_attr_da_set_args
xfs_attr_da_remove_args
xfs_attr_da_leaf_addname
xfs_attr_da_node_addname
xfs_attr_da_node_removename

These routines are similar to their existing counter parts,
but they do not roll or commit transactions.  They instead
return -EGAIN to allow the calling function to roll the
transaction and recall the function.  This allows the
attribute operations to be logged in multiple smaller
transactions.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c | 720 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/libxfs/xfs_attr.h |   2 +
 2 files changed, 722 insertions(+)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index ca57202..9931e50 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -47,6 +47,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
  */
 STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
+STATIC int xfs_attr_da_leaf_addname(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
 STATIC int xfs_leaf_has_attr(xfs_da_args_t *args, struct xfs_buf **bp);         
 
@@ -55,12 +56,16 @@ STATIC int xfs_leaf_has_attr(xfs_da_args_t *args, struct xfs_buf **bp);
  */
 STATIC int xfs_attr_node_get(xfs_da_args_t *args);
 STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
+STATIC int xfs_attr_da_node_addname(xfs_da_args_t *args);
 STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
+STATIC int xfs_attr_da_node_removename(xfs_da_args_t *args);
 STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
 				 struct xfs_da_state **state);
 STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
 STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
 
+STATIC int
+xfs_attr_leaf_try_add(struct xfs_da_args *args, struct xfs_buf *bp);
 
 int
 xfs_attr_args_init(
@@ -282,6 +287,117 @@ xfs_attr_set_args(
 }
 
 /*
+ * Set the attribute specified in @args.
+ * This routine is meant to function as a delayed operation, and may return
+ * -EGAIN when the transaction needs to be rolled.  Calling functions will need
+ * to handle this, and recall the function until a successful error code is
+ * returned.
+ */
+int
+xfs_attr_da_set_args(
+	struct xfs_da_args	*args,
+	struct xfs_buf          **leaf_bp)
+{
+	struct xfs_inode	*dp = args->dp;
+	int			error = 0;
+	int			sf_size;
+	struct xfs_buf          *bp;
+	struct xfs_buf_log_item *bip;
+
+	/*
+	 * New inodes may not have an attribute fork yet. So set the attribute
+	 * fork appropriately
+	 */
+	if (XFS_IFORK_Q((args->dp)) == 0) {
+		sf_size = sizeof(struct xfs_attr_sf_hdr) +
+		     XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
+		xfs_bmap_set_attrforkoff(args->dp, sf_size, NULL);
+		args->dp->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
+		args->dp->i_afp->if_flags = XFS_IFEXTENTS;
+	}
+
+	/*
+	 * If the attribute list is non-existent or a shortform list,
+	 * upgrade it to a single-leaf-block attribute list.
+	 */
+	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
+	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
+	     dp->i_d.di_anextents == 0)) {
+		/*
+		 * Build initial attribute list (if required).
+		 */
+		if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
+			xfs_attr_shortform_create(args);
+
+		/*
+		 * Try to add the attr to the attribute list in the inode.
+		 */
+		error = xfs_attr_try_sf_addname(dp, args);
+		if (error != -ENOSPC)
+			return error;
+
+		/*
+		 * It won't fit in the shortform, transform to a leaf block.
+		 * GROT: another possible req'mt for a double-split btree op.
+		 */
+		error = xfs_attr_shortform_to_leaf(args, leaf_bp);
+		if (error)
+			return error;
+
+		/*
+		 * Prevent the leaf buffer from being unlocked so that a
+		 * concurrent AIL push cannot grab the half-baked leaf
+		 * buffer and run into problems with the write verifier.
+		 */
+
+		xfs_trans_bhold(args->trans, *leaf_bp);
+		return -EAGAIN;
+	}
+
+	/*
+	 * After a shortform to leaf conversion, we need to hold the leaf and
+	 * cylce out the transaction.  When we get back, we need to release
+	 * the leaf.
+	 */
+	if (*leaf_bp != NULL) {
+		bp = *leaf_bp;
+		bip = (struct xfs_buf_log_item *)(bp->b_log_item);
+		if (bp->b_transp == args->trans)
+			xfs_trans_brelse(args->trans, *leaf_bp);
+		*leaf_bp = NULL;
+	}
+
+	/*
+	 * If we fit in a block, or we are in the middle of adding a leaf name.
+	 * xfs_attr_da_leaf_addname will set the XFS_DC_ALLOC_LEAF to indicate
+	 * that it is not done yet, and need to be recalled to finish up from
+	 * the last EAGAIN it returned
+	 */
+	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) ||
+	    args->dc.flags & XFS_DC_ALLOC_LEAF) {
+		if (!(args->dc.flags & XFS_DC_FOUND_LBLK)) {
+			error = xfs_attr_leaf_try_add(args, *leaf_bp);
+			args->dc.flags |= XFS_DC_FOUND_LBLK;
+
+			if (error && error != -ENOSPC)
+				return error;
+
+			return -EAGAIN;
+		}
+
+		error = xfs_attr_da_leaf_addname(args);
+		if (error && error != -ENOSPC)
+			return error;
+	} else {
+		error = xfs_attr_da_node_addname(args);
+	}
+
+	return error;
+}
+
+
+
+/*
  * Return EEXIST if attr is found, or ENOATTR if not
  */
 int
@@ -331,6 +447,57 @@ xfs_attr_remove_args(
 	return error;
 }
 
+/*
+ * Remove the attribute specified in @args.
+ * This routine is meant to function as a delayed operation, and may return
+ * -EGAIN when the transaction needs to be rolled.  Calling functions will need
+ * to handle this, and recall the function until a successful error code is
+ * returned.
+ */
+int
+xfs_attr_da_remove_args(
+	struct xfs_da_args      *args)
+{
+	struct xfs_inode	*dp = args->dp;
+	struct xfs_buf		*bp;
+	int			forkoff, error = 0;
+
+	if (!xfs_inode_hasattr(dp)) {
+		error = -ENOATTR;
+	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
+		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
+		error = xfs_attr_shortform_remove(args);
+	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK) &&
+		   !(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
+		/*
+		 * If we fit in a block AND we are not in the middle of
+		 * removing node blocks, remove the leaf attribute.
+		 * xfs_attr_da_node_removename will set XFS_DC_RM_NODE_BLKS to
+		 * signal that it is not done yet, and needs to be recalled to
+		 * to finish up from the last -EAGAIN
+		 */
+		error = xfs_leaf_has_attr(args, &bp);
+		if (error == -ENOATTR) {
+			xfs_trans_brelse(args->trans, bp);
+			return error;
+		}
+		error = 0;
+
+		xfs_attr3_leaf_remove(bp, args);
+
+		/* If the result is small enough, shrink it into the inode.*/
+		forkoff = xfs_attr_shortform_allfit(bp, dp);
+		if (forkoff)
+			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
+	} else {
+		error = xfs_attr_da_node_removename(args);
+	}
+
+	return error;
+}
+
+
+
 int
 xfs_attr_set(
 	struct xfs_inode	*dp,
@@ -834,6 +1001,150 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
 }
 
 /*
+ * Add a name to the leaf attribute list structure
+ *
+ * This leaf block cannot have a "remote" value, we only call this routine
+ * if bmap_one_block() says there is only one block (ie: no remote blks).
+ *
+ * This routine is meant to function as a delayed operation, and may return
+ * -EGAIN when the transaction needs to be rolled.  Calling functions will need
+ * to handle this, and recall the function until a successful error code is
+ * returned.
+ */
+STATIC int
+xfs_attr_da_leaf_addname(
+	struct xfs_da_args	*args)
+{
+	int			error, forkoff, nmap;
+	struct xfs_buf		*bp = NULL;
+	struct xfs_inode	*dp = args->dp;
+	struct xfs_bmbt_irec	*map = &args->dc.map;
+
+	/*
+	 * If there was an out-of-line value, allocate the blocks we
+	 * identified for its storage and copy the value.  This is done
+	 * after we create the attribute so that we don't overflow the
+	 * maximum size of a transaction and/or hit a deadlock.
+	 */
+	if (args->rmtblkno > 0) {
+		if (!(args->dc.flags & XFS_DC_ALLOC_LEAF)) {
+			args->dc.lfileoff = 0;
+			args->dc.lblkno = 0;
+			args->dc.blkcnt = 0;
+			memset(map, 0, sizeof(struct xfs_bmbt_irec));
+
+			error = xfs_attr_rmt_find_hole(args, &args->dc.blkcnt,
+						       &args->dc.lfileoff);
+			if (error)
+				return error;
+
+			args->dc.lblkno = (xfs_dablk_t)args->dc.lfileoff;
+			args->dc.flags |= XFS_DC_ALLOC_LEAF;
+		}
+
+		/*
+		 * Roll through the "value", allocating blocks on disk as
+		 * required.
+		 */
+		while (args->dc.blkcnt > 0) {
+			nmap = 1;
+			error = xfs_bmapi_write(args->trans, dp,
+				  (xfs_fileoff_t)args->dc.lblkno,
+				  args->dc.blkcnt, XFS_BMAPI_ATTRFORK,
+				  args->total, map, &nmap);
+			if (error)
+				return error;
+			ASSERT(nmap == 1);
+			ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
+			       (map->br_startblock != HOLESTARTBLOCK));
+
+			/* roll attribute extent map forwards */
+			args->dc.lblkno += map->br_blockcount;
+			args->dc.blkcnt -= map->br_blockcount;
+
+			return -EAGAIN;
+		}
+
+		error = xfs_attr_rmtval_set_value(args);
+		if (error)
+			return error;
+	}
+
+	/*
+	 * If this is an atomic rename operation, we must "flip" the
+	 * incomplete flags on the "new" and "old" attribute/value pairs
+	 * so that one disappears and one appears atomically.  Then we
+	 * must remove the "old" attribute/value pair.
+	 */
+	if (args->op_flags & XFS_DA_OP_RENAME) {
+		/*
+		 * In a separate transaction, set the incomplete flag on the
+		 * "old" attr and clear the incomplete flag on the "new" attr.
+		 */
+		if (!xfs_attr3_leaf_flagsflipped(args)) {
+			error = xfs_attr3_leaf_flipflags(args);
+			if (error)
+				return error;
+			return -EAGAIN;
+		}
+		/*
+		 * Dismantle the "old" attribute/value pair by removing
+		 * a "remote" value (if it exists).
+		 */
+		args->index = args->index2;
+		args->blkno = args->blkno2;
+		args->rmtblkno = args->rmtblkno2;
+		args->rmtblkcnt = args->rmtblkcnt2;
+		args->rmtvaluelen = args->rmtvaluelen2;
+		if (args->rmtblkno) {
+			int done = 0;
+
+			error = xfs_attr_rmtval_remove_value(args);
+			if (error)
+				return error;
+
+			while (!done && !error)
+				error = xfs_bunmapi(args->trans,
+				    args->dp, args->rmtblkno,
+				    args->rmtblkcnt, XFS_BMAPI_ATTRFORK,
+				    1, &done);
+
+			if (error)
+				return error;
+		}
+
+		/*
+		 * Read in the block containing the "old" attr, then
+		 * remove the "old" attr from that block (neat, huh!)
+		 */
+		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
+					   -1, &bp);
+		if (error)
+			return error;
+
+		xfs_attr3_leaf_remove(bp, args);
+
+		/*
+		 * If the result is small enough, shrink it all into the inode.
+		 */
+		forkoff = xfs_attr_shortform_allfit(bp, dp);
+		if (forkoff) {
+			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
+			/* bp is gone due to xfs_da_shrink_inode */
+			if (error)
+				return error;
+		}
+	} else if (args->rmtblkno > 0) {
+		/*
+		 * Added a "remote" value, just clear the incomplete flag.
+		 */
+		error = xfs_attr3_leaf_clearflag(args);
+	}
+	args->dc.flags &= ~XFS_DC_ALLOC_LEAF;
+	return error;
+}
+
+/*
  * Return EEXIST if attr is found, or ENOATTR if not
  */
 STATIC int
@@ -1329,6 +1640,415 @@ xfs_attr_node_removename(
 }
 
 /*
+ * Remove a name from a B-tree attribute list.
+ *
+ * This will involve walking down the Btree, and may involve joining
+ * leaf nodes and even joining intermediate nodes up to and including
+ * the root node (a special case of an intermediate node).
+ *
+ * This routine is meant to function as a delayed operation, and may return
+ * -EGAIN when the transaction needs to be rolled.  Calling functions
+ * will need to handle this, and recall the function until a successful error
+ * code is returned.
+ */
+STATIC int
+xfs_attr_da_node_removename(
+	struct xfs_da_args	*args)
+{
+	struct xfs_da_state	*state = NULL;
+	struct xfs_da_state_blk	*blk;
+	struct xfs_buf		*bp;
+	int			error, forkoff, retval = 0;
+	struct xfs_inode	*dp = args->dp;
+	int			done = 0;
+
+	trace_xfs_attr_node_removename(args);
+
+	if (args->dc.state == NULL) {
+		error = xfs_attr_node_hasname(args, &args->dc.state);
+		if (error != -EEXIST)
+			goto out;
+		else
+			error = 0;
+
+		/*
+		 * If there is an out-of-line value, de-allocate the blocks.
+		 * This is done before we remove the attribute so that we don't
+		 * overflow the maximum size of a transaction and/or hit a
+		 * deadlock.
+		 */
+		state = args->dc.state;
+		args->dc.blk = &state->path.blk[state->path.active - 1];
+		ASSERT(args->dc.blk->bp != NULL);
+		ASSERT(args->dc.blk->magic == XFS_ATTR_LEAF_MAGIC);
+	}
+	state = args->dc.state;
+	blk = args->dc.blk;
+
+	if (args->rmtblkno > 0 && !(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
+		if (!xfs_attr3_leaf_flag_is_set(args)) {
+			/*
+			 * Fill in disk block numbers in the state structure
+			 * so that we can get the buffers back after we commit
+			 * several transactions in the following calls.
+			 */
+			error = xfs_attr_fillstate(state);
+			if (error)
+				goto out;
+
+			/*
+			 * Mark the attribute as INCOMPLETE, then bunmapi() the
+			 * remote value.
+			 */
+			error = xfs_attr3_leaf_setflag(args);
+			if (error)
+				goto out;
+
+			return -EAGAIN;
+		}
+
+		if (!(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
+			error = xfs_attr_rmtval_remove_value(args);
+			if (error)
+				goto out;
+		}
+
+		args->dc.flags |= XFS_DC_RM_NODE_BLKS;
+		while (!done && !error) {
+			error = xfs_bunmapi(args->trans, args->dp,
+				    args->rmtblkno, args->rmtblkcnt,
+				    XFS_BMAPI_ATTRFORK, 1, &done);
+			if (error)
+				return error;
+
+			if (!done)
+				return -EAGAIN;
+		}
+
+		if (error)
+			goto out;
+
+		/*
+		 * Refill the state structure with buffers, the prior calls
+		 * released our buffers.
+		 */
+		error = xfs_attr_refillstate(state);
+		if (error)
+			goto out;
+	}
+
+	/*
+	 * Remove the name and update the hashvals in the tree.
+	 */
+	if (!(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
+		blk = &state->path.blk[state->path.active - 1];
+		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
+		retval = xfs_attr3_leaf_remove(blk->bp, args);
+		xfs_da3_fixhashpath(state, &state->path);
+
+		args->dc.flags |= XFS_DC_RM_LEAF_BLKS;
+	}
+
+	/*
+	 * Check to see if the tree needs to be collapsed.
+	 */
+	if (retval && (state->path.active > 1)) {
+		args->dc.flags |= XFS_DC_RM_NODE_BLKS;
+		error = xfs_da3_join(state);
+		if (error)
+			goto out;
+
+		return -EAGAIN;
+	}
+
+	/*
+	 * If the result is small enough, push it all into the inode.
+	 */
+	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+		/*
+		 * Have to get rid of the copy of this dabuf in the state.
+		 */
+		ASSERT(state->path.active == 1);
+		ASSERT(state->path.blk[0].bp);
+		state->path.blk[0].bp = NULL;
+
+		error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
+		if (error)
+			goto out;
+
+		forkoff = xfs_attr_shortform_allfit(bp, dp);
+		if (forkoff) {
+			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
+			/* bp is gone due to xfs_da_shrink_inode */
+			if (error)
+				goto out;
+		} else
+			xfs_trans_brelse(args->trans, bp);
+	}
+out:
+	if (state != NULL)
+		xfs_da_state_free(state);
+
+	return error;
+}
+
+/*
+ * Add a name to a Btree-format attribute list.
+ *
+ * This will involve walking down the Btree, and may involve splitting
+ * leaf nodes and even splitting intermediate nodes up to and including
+ * the root node (a special case of an intermediate node).
+ *
+ * "Remote" attribute values confuse the issue and atomic rename operations
+ * add a whole extra layer of confusion on top of that.
+ *
+ * This routine is meant to function as a delayed operation, and may return
+ * -EGAIN when the transaction needs to be rolled.  Calling functions will need
+ * to handle this, and recall the function until a successful error code is
+ *returned.
+ */
+STATIC int
+xfs_attr_da_node_addname(
+	struct xfs_da_args	*args)
+{
+	struct xfs_da_state	*state = NULL;
+	struct xfs_da_state_blk	*blk;
+	struct xfs_inode	*dp;
+	struct xfs_mount	*mp;
+	int			retval, error = 0;
+	int			nmap;
+	int			done = 0;
+	struct xfs_bmbt_irec    *map = &args->dc.map;
+
+	trace_xfs_attr_node_addname(args);
+
+	/*
+	 * Fill in bucket of arguments/results/context to carry around.
+	 */
+	dp = args->dp;
+	mp = dp->i_mount;
+
+	if (args->dc.flags & XFS_DC_FOUND_NBLK)
+		goto found_blk;
+
+	/*
+	 * Search to see if name already exists, and get back a pointer
+	 * to where it should go.
+	 */
+	retval = xfs_attr_node_hasname(args, &state);
+	blk = &state->path.blk[state->path.active-1];
+	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
+	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
+		goto out;
+	} else if (retval == -EEXIST) {
+		if (args->flags & ATTR_CREATE)
+			goto out;
+
+		trace_xfs_attr_node_replace(args);
+
+		/* save the attribute state for later removal*/
+		args->op_flags |= XFS_DA_OP_RENAME;	/* atomic rename op */
+		args->blkno2 = args->blkno;		/* set 2nd entry info*/
+		args->index2 = args->index;
+		args->rmtblkno2 = args->rmtblkno;
+		args->rmtblkcnt2 = args->rmtblkcnt;
+		args->rmtvaluelen2 = args->rmtvaluelen;
+
+		/*
+		 * clear the remote attr state now that it is saved so that the
+		 * values reflect the state of the attribute we are about to
+		 * add, not the attribute we just found and will remove later.
+		 */
+		args->rmtblkno = 0;
+		args->rmtblkcnt = 0;
+		args->rmtvaluelen = 0;
+	}
+
+	retval = xfs_attr3_leaf_add(blk->bp, state->args);
+	if (retval == -ENOSPC) {
+		if (state->path.active == 1) {
+			/*
+			 * Its really a single leaf node, but it had
+			 * out-of-line values so it looked like it *might*
+			 * have been a b-tree.
+			 */
+			xfs_da_state_free(state);
+			state = NULL;
+			error = xfs_attr3_leaf_to_node(args);
+			if (error)
+				goto out;
+
+			return -EAGAIN;
+		}
+
+		/*
+		 * Split as many Btree elements as required.
+		 * This code tracks the new and old attr's location
+		 * in the index/blkno/rmtblkno/rmtblkcnt fields and
+		 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
+		 */
+		error = xfs_da3_split(state);
+		if (error)
+			goto out;
+	} else {
+		/*
+		 * Addition succeeded, update Btree hashvals.
+		 */
+		xfs_da3_fixhashpath(state, &state->path);
+	}
+
+	/*
+	 * Kill the state structure, we're done with it and need to
+	 * allow the buffers to come back later.
+	 */
+	xfs_da_state_free(state);
+	state = NULL;
+
+	args->dc.flags |= XFS_DC_FOUND_NBLK;
+	return -EAGAIN;
+found_blk:
+
+	/*
+	 * If there was an out-of-line value, allocate the blocks we
+	 * identified for its storage and copy the value.  This is done
+	 * after we create the attribute so that we don't overflow the
+	 * maximum size of a transaction and/or hit a deadlock.
+	 */
+	if (args->rmtblkno > 0) {
+		if (!(args->dc.flags & XFS_DC_ALLOC_NODE)) {
+			args->dc.flags |= XFS_DC_ALLOC_NODE;
+			args->dc.lblkno = 0;
+			args->dc.lfileoff = 0;
+			args->dc.blkcnt = 0;
+			memset(map, 0, sizeof(struct xfs_bmbt_irec));
+
+			error = xfs_attr_rmt_find_hole(args, &args->dc.blkcnt,
+						       &args->dc.lfileoff);
+			if (error)
+				return error;
+
+			args->dc.lblkno = (xfs_dablk_t)args->dc.lfileoff;
+		}
+		/*
+		 * Roll through the "value", allocating blocks on disk as
+		 * required.
+		 */
+		while (args->dc.blkcnt > 0) {
+			nmap = 1;
+			error = xfs_bmapi_write(args->trans, dp,
+				(xfs_fileoff_t)args->dc.lblkno, args->dc.blkcnt,
+				XFS_BMAPI_ATTRFORK, args->total, map, &nmap);
+			if (error)
+				return error;
+
+			ASSERT(nmap == 1);
+			ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
+			       (map->br_startblock != HOLESTARTBLOCK));
+
+			/* roll attribute extent map forwards */
+			args->dc.lblkno += map->br_blockcount;
+			args->dc.blkcnt -= map->br_blockcount;
+
+			return -EAGAIN;
+		}
+
+		error = xfs_attr_rmtval_set_value(args);
+		if (error)
+			return error;
+	}
+
+	/*
+	 * If this is an atomic rename operation, we must "flip" the
+	 * incomplete flags on the "new" and "old" attribute/value pairs
+	 * so that one disappears and one appears atomically.  Then we
+	 * must remove the "old" attribute/value pair.
+	 */
+	if (args->op_flags & XFS_DA_OP_RENAME) {
+		/*
+		 * In a separate transaction, set the incomplete flag on the
+		 * "old" attr and clear the incomplete flag on the "new" attr.
+		 */
+		if (!xfs_attr3_leaf_flagsflipped(args)) {
+			error = xfs_attr3_leaf_flipflags(args);
+			if (error)
+				goto out;
+			return -EAGAIN;
+		}
+		/*
+		 * Dismantle the "old" attribute/value pair by removing
+		 * a "remote" value (if it exists).
+		 */
+		args->index = args->index2;
+		args->blkno = args->blkno2;
+		args->rmtblkno = args->rmtblkno2;
+		args->rmtblkcnt = args->rmtblkcnt2;
+		args->rmtvaluelen = args->rmtvaluelen2;
+		if (args->rmtblkno) {
+			error = xfs_attr_rmtval_remove_value(args);
+			if (error)
+				return error;
+
+			while (!done && !error)
+				error = xfs_bunmapi(args->trans,
+				    args->dp, args->rmtblkno,
+				    args->rmtblkcnt, XFS_BMAPI_ATTRFORK,
+				    1, &done);
+			if (error)
+				return error;
+		}
+
+		/*
+		 * Re-find the "old" attribute entry after any split ops.
+		 * The INCOMPLETE flag means that we will find the "old"
+		 * attr, not the "new" one.
+		 */
+		args->flags |= XFS_ATTR_INCOMPLETE;
+		state = xfs_da_state_alloc();
+		state->args = args;
+		state->mp = mp;
+		state->inleaf = 0;
+		error = xfs_da3_node_lookup_int(state, &retval);
+		if (error)
+			goto out;
+
+		/*
+		 * Remove the name and update the hashvals in the tree.
+		 */
+		blk = &state->path.blk[state->path.active - 1];
+		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
+		error = xfs_attr3_leaf_remove(blk->bp, args);
+		xfs_da3_fixhashpath(state, &state->path);
+
+		/*
+		 * Check to see if the tree needs to be collapsed.
+		 */
+		if (retval && (state->path.active > 1)) {
+			error = xfs_da3_join(state);
+			if (error)
+				goto out;
+		}
+	} else if (args->rmtblkno > 0) {
+		/*
+		 * Added a "remote" value, just clear the incomplete flag.
+		 */
+		error = xfs_attr3_leaf_clearflag(args);
+		if (error)
+			goto out;
+	}
+	retval = error = 0;
+
+out:
+	if (state)
+		xfs_da_state_free(state);
+	if (error)
+		return error;
+
+	return retval;
+}
+
+
+
+/*
  * Fill in the disk block numbers in the state structure for the buffers
  * that are attached to the state structure.
  * This is done so that we can quickly reattach ourselves to those buffers
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index b1172fd..d05749e 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -175,9 +175,11 @@ int xfs_attr_get(struct xfs_inode *ip, struct xfs_name *name,
 int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
 		 unsigned char *value, int valuelen);
 int xfs_attr_set_args(struct xfs_da_args *args);
+int xfs_attr_da_set_args(struct xfs_da_args *args, struct xfs_buf **leaf_bp);
 int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name);
 int xfs_has_attr(struct xfs_da_args *args);
 int xfs_attr_remove_args(struct xfs_da_args *args);
+int xfs_attr_da_remove_args(struct xfs_da_args *args);
 int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
 		  int flags, struct attrlist_cursor_kern *cursor);
 bool xfs_attr_namecheck(const void *name, size_t length);
-- 
2.7.4

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

* [PATCH v2 16/18] xfs: Roll delayed attr operations by returning EAGAIN
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
                   ` (14 preceding siblings ...)
  2019-08-09 21:37 ` [PATCH v2 15/18] xfs: Add delayed attribute routines Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-09 21:37 ` [PATCH v2 17/18] xfs: Enable delayed attributes Allison Collins
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

Modify delayed operations to use the new xfs_attr_da*
routines

In this patch, xfs_trans_attr is modified to use the new
xfs_attr_da_* scheme, and pass the -EAGAIN back to the
calling function.  The leaf_bp is also factored up to
be released after the transactions are handled.

xfs_attri_recover will need to handle the -EAGAIN by
logging and committing the transaction before recalling
xfs_trans_attr.

xfs_attr_finish_item does not need to handle the -EAGAIN
since it is handled by its calling function.  But it
does need to plumb in xfs_da_args from the log item since
it cant keep args instantiated in its own function context.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/xfs_attr_item.c | 83 +++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 62 insertions(+), 21 deletions(-)

diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
index 88efaf9..6693880 100644
--- a/fs/xfs/xfs_attr_item.c
+++ b/fs/xfs/xfs_attr_item.c
@@ -65,6 +65,7 @@ int
 xfs_trans_attr(
 	struct xfs_da_args		*args,
 	struct xfs_attrd_log_item	*attrdp,
+	struct xfs_buf			**leaf_bp,
 	uint32_t			op_flags)
 {
 	int				error;
@@ -76,11 +77,11 @@ xfs_trans_attr(
 	switch (op_flags) {
 	case XFS_ATTR_OP_FLAGS_SET:
 		args->op_flags |= XFS_DA_OP_ADDNAME;
-		error = xfs_attr_set_args(args);
+		error = xfs_attr_da_set_args(args, leaf_bp);
 		break;
 	case XFS_ATTR_OP_FLAGS_REMOVE:
 		ASSERT(XFS_IFORK_Q((args->dp)));
-		error = xfs_attr_remove_args(args);
+		error = xfs_attr_da_remove_args(args);
 		break;
 	default:
 		error = -EFSCORRUPTED;
@@ -187,29 +188,40 @@ xfs_attr_finish_item(
 	char				*name_value;
 	int				error;
 	int				local;
-	struct xfs_da_args		args;
+	struct xfs_da_args		*args;
 	struct xfs_name			name;
 	struct xfs_attrd_log_item	*attrdp;
 	struct xfs_attri_log_item	*attrip;
 
 	attr = container_of(item, struct xfs_attr_item, xattri_list);
-	name_value = ((char *)attr) + sizeof(struct xfs_attr_item);
+	args = &attr->xattri_args;
 
+	name_value = ((char *)attr) + sizeof(struct xfs_attr_item);
 	name.name = name_value;
 	name.len = attr->xattri_name_len;
 	name.type = attr->xattri_flags;
-	error = xfs_attr_args_init(&args, attr->xattri_ip, &name);
-	if (error)
-		goto out;
 
-	args.hashval = xfs_da_hashname(args.name, args.namelen);
-	args.value = &name_value[attr->xattri_name_len];
-	args.valuelen = attr->xattri_value_len;
-	args.op_flags = XFS_DA_OP_OKNOENT;
-	args.total = xfs_attr_calc_size(&args, &local);
-	args.trans = tp;
+	if (!(args->dc.flags & XFS_DC_INIT)) {
+		/* Only need to initialize args context once */
+		error = xfs_attr_args_init(args, attr->xattri_ip, &name);
+		if (error)
+			goto out;
+
+		args->hashval = xfs_da_hashname(args->name, args->namelen);
+		args->value = &name_value[attr->xattri_name_len];
+		args->valuelen = attr->xattri_value_len;
+		args->op_flags = XFS_DA_OP_OKNOENT;
+		args->total = xfs_attr_calc_size(args, &local);
+		args->dc.flags |= XFS_DC_INIT;
+	}
+
+	/*
+	 * Always reset trans after EAGAIN cycle
+	 * since the transaction is new
+	 */
+	args->trans = tp;
 
-	error = xfs_trans_attr(&args, done_item,
+	error = xfs_trans_attr(args, done_item, &args->dc.leaf_bp,
 			attr->xattri_op_flags);
 out:
 	/*
@@ -223,7 +235,9 @@ xfs_attr_finish_item(
 	attrip->attri_name_len = 0;
 	attrip->attri_value_len = 0;
 
-	kmem_free(attr);
+	if (error != -EAGAIN)
+		kmem_free(attr);
+
 	return error;
 }
 
@@ -678,9 +692,10 @@ xfs_attri_recover(
 	struct xfs_attri_log_format	*attrp;
 	struct xfs_trans_res		tres;
 	int				local;
-	int				error = 0;
+	int				error, err2 = 0;
 	int				rsvd = 0;
 	struct xfs_name			name;
+	struct xfs_buf			*leaf_bp = NULL;
 
 	ASSERT(!test_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags));
 
@@ -737,14 +752,40 @@ xfs_attri_recover(
 	xfs_ilock(ip, XFS_ILOCK_EXCL);
 
 	xfs_trans_ijoin(args.trans, ip, 0);
-	error = xfs_trans_attr(&args, attrdp, attrp->alfi_op_flags);
-	if (error)
-		goto abort_error;
 
+	do {
+		leaf_bp = NULL;
+
+		error = xfs_trans_attr(&args, attrdp, &leaf_bp,
+				       attrp->alfi_op_flags);
+		if (error && error != -EAGAIN)
+			goto abort_error;
+
+		xfs_trans_log_inode(args.trans, ip,
+				XFS_ILOG_CORE | XFS_ILOG_ADATA);
+
+		err2 = xfs_trans_commit(args.trans);
+		if (err2) {
+			error = err2;
+			goto abort_error;
+		}
+
+		if (error == -EAGAIN) {
+			err2 = xfs_trans_alloc(mp, &tres, args.total, 0,
+				XFS_TRANS_PERM_LOG_RES, &args.trans);
+			if (err2) {
+				error = err2;
+				goto abort_error;
+			}
+			xfs_trans_ijoin(args.trans, ip, 0);
+		}
+
+	} while (error == -EAGAIN);
+
+	if (leaf_bp)
+		xfs_trans_brelse(args.trans, leaf_bp);
 
 	set_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags);
-	xfs_trans_log_inode(args.trans, ip, XFS_ILOG_CORE | XFS_ILOG_ADATA);
-	error = xfs_trans_commit(args.trans);
 	xfs_iunlock(ip, XFS_ILOCK_EXCL);
 	return error;
 
-- 
2.7.4

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

* [PATCH v2 17/18] xfs: Enable delayed attributes
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
                   ` (15 preceding siblings ...)
  2019-08-09 21:37 ` [PATCH v2 16/18] xfs: Roll delayed attr operations by returning EAGAIN Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-12 16:42   ` Darrick J. Wong
  2019-08-09 21:37 ` [PATCH v2 18/18] xfs: Add delayed attributes error tag Allison Collins
  2019-08-12  8:19 ` [PATCH v2 00/18] Delayed Attributes Christoph Hellwig
  18 siblings, 1 reply; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

Finally enable delayed attributes in xfs_attr_set and
xfs_attr_remove.  We only do this for v4 and up since we
cant add new log entries to old fs versions

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 9931e50..7023734 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -506,6 +506,7 @@ xfs_attr_set(
 	int			valuelen)
 {
 	struct xfs_mount	*mp = dp->i_mount;
+	struct xfs_sb		*sbp = &mp->m_sb;
 	struct xfs_da_args	args;
 	struct xfs_trans_res	tres;
 	int			rsvd = (name->type & ATTR_ROOT) != 0;
@@ -564,7 +565,20 @@ xfs_attr_set(
 		goto out_trans_cancel;
 
 	xfs_trans_ijoin(args.trans, dp, 0);
-	error = xfs_attr_set_args(&args);
+	if (XFS_SB_VERSION_NUM(sbp) < XFS_SB_VERSION_4)
+		error = xfs_attr_set_args(&args);
+	else {
+		error = xfs_has_attr(&args);
+
+		if (error == -EEXIST && (name->type & ATTR_CREATE))
+			goto out_trans_cancel;
+
+		if (error == -ENOATTR && (name->type & ATTR_REPLACE))
+			goto out_trans_cancel;
+
+		error = xfs_attr_set_deferred(dp, args.trans, name, value,
+					      valuelen);
+	}
 	if (error)
 		goto out_trans_cancel;
 	if (!args.trans) {
@@ -649,6 +663,7 @@ xfs_attr_remove(
 	struct xfs_name		*name)
 {
 	struct xfs_mount	*mp = dp->i_mount;
+	struct xfs_sb		*sbp = &mp->m_sb;
 	struct xfs_da_args	args;
 	int			error;
 
@@ -690,7 +705,14 @@ xfs_attr_remove(
 	 */
 	xfs_trans_ijoin(args.trans, dp, 0);
 
-	error = xfs_attr_remove_args(&args);
+	error = xfs_has_attr(&args);
+	if (error == -ENOATTR)
+		goto out;
+
+	if (XFS_SB_VERSION_NUM(sbp) < XFS_SB_VERSION_4)
+		error = xfs_attr_remove_args(&args);
+	else
+		error = xfs_attr_remove_deferred(dp, args.trans, name);
 	if (error)
 		goto out;
 
-- 
2.7.4

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

* [PATCH v2 18/18] xfs: Add delayed attributes error tag
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
                   ` (16 preceding siblings ...)
  2019-08-09 21:37 ` [PATCH v2 17/18] xfs: Enable delayed attributes Allison Collins
@ 2019-08-09 21:37 ` Allison Collins
  2019-08-12 16:51   ` Darrick J. Wong
  2019-08-12  8:19 ` [PATCH v2 00/18] Delayed Attributes Christoph Hellwig
  18 siblings, 1 reply; 56+ messages in thread
From: Allison Collins @ 2019-08-09 21:37 UTC (permalink / raw)
  To: linux-xfs

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

This patch adds an error tag that we can use to test
delayed attribute recovery and replay

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_errortag.h | 4 +++-
 fs/xfs/xfs_attr_item.c       | 8 ++++++++
 fs/xfs/xfs_error.c           | 3 +++
 3 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/fs/xfs/libxfs/xfs_errortag.h b/fs/xfs/libxfs/xfs_errortag.h
index 79e6c4f..85d5850 100644
--- a/fs/xfs/libxfs/xfs_errortag.h
+++ b/fs/xfs/libxfs/xfs_errortag.h
@@ -55,7 +55,8 @@
 #define XFS_ERRTAG_FORCE_SCRUB_REPAIR			32
 #define XFS_ERRTAG_FORCE_SUMMARY_RECALC			33
 #define XFS_ERRTAG_IUNLINK_FALLBACK			34
-#define XFS_ERRTAG_MAX					35
+#define XFS_ERRTAG_DELAYED_ATTR				35
+#define XFS_ERRTAG_MAX					36
 
 /*
  * Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
@@ -95,5 +96,6 @@
 #define XFS_RANDOM_FORCE_SCRUB_REPAIR			1
 #define XFS_RANDOM_FORCE_SUMMARY_RECALC			1
 #define XFS_RANDOM_IUNLINK_FALLBACK			(XFS_RANDOM_DEFAULT/10)
+#define XFS_RANDOM_DELAYED_ATTR				1
 
 #endif /* __XFS_ERRORTAG_H_ */
diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
index 6693880..045d23a 100644
--- a/fs/xfs/xfs_attr_item.c
+++ b/fs/xfs/xfs_attr_item.c
@@ -33,6 +33,8 @@
 #include "libxfs/xfs_da_format.h"
 #include "xfs_inode.h"
 #include "xfs_quota.h"
+#include "xfs_error.h"
+#include "xfs_errortag.h"
 
 
 /*
@@ -74,6 +76,11 @@ xfs_trans_attr(
 	if (error)
 		return error;
 
+	if (XFS_TEST_ERROR(false, args->dp->i_mount, XFS_ERRTAG_DELAYED_ATTR)) {
+		error = -EIO;
+		goto out;
+	}
+
 	switch (op_flags) {
 	case XFS_ATTR_OP_FLAGS_SET:
 		args->op_flags |= XFS_DA_OP_ADDNAME;
@@ -87,6 +94,7 @@ xfs_trans_attr(
 		error = -EFSCORRUPTED;
 	}
 
+out:
 	/*
 	 * Mark the transaction dirty, even on error. This ensures the
 	 * transaction is aborted, which:
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
index 544c948..9b2de63 100644
--- a/fs/xfs/xfs_error.c
+++ b/fs/xfs/xfs_error.c
@@ -53,6 +53,7 @@ static unsigned int xfs_errortag_random_default[] = {
 	XFS_RANDOM_FORCE_SCRUB_REPAIR,
 	XFS_RANDOM_FORCE_SUMMARY_RECALC,
 	XFS_RANDOM_IUNLINK_FALLBACK,
+	XFS_RANDOM_DELAYED_ATTR,
 };
 
 struct xfs_errortag_attr {
@@ -162,6 +163,7 @@ XFS_ERRORTAG_ATTR_RW(buf_lru_ref,	XFS_ERRTAG_BUF_LRU_REF);
 XFS_ERRORTAG_ATTR_RW(force_repair,	XFS_ERRTAG_FORCE_SCRUB_REPAIR);
 XFS_ERRORTAG_ATTR_RW(bad_summary,	XFS_ERRTAG_FORCE_SUMMARY_RECALC);
 XFS_ERRORTAG_ATTR_RW(iunlink_fallback,	XFS_ERRTAG_IUNLINK_FALLBACK);
+XFS_ERRORTAG_ATTR_RW(delayed_attr,	XFS_ERRTAG_DELAYED_ATTR);
 
 static struct attribute *xfs_errortag_attrs[] = {
 	XFS_ERRORTAG_ATTR_LIST(noerror),
@@ -199,6 +201,7 @@ static struct attribute *xfs_errortag_attrs[] = {
 	XFS_ERRORTAG_ATTR_LIST(force_repair),
 	XFS_ERRORTAG_ATTR_LIST(bad_summary),
 	XFS_ERRORTAG_ATTR_LIST(iunlink_fallback),
+	XFS_ERRORTAG_ATTR_LIST(delayed_attr),
 	NULL,
 };
 
-- 
2.7.4

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

* Re: [PATCH v2 00/18] Delayed Attributes
  2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
                   ` (17 preceding siblings ...)
  2019-08-09 21:37 ` [PATCH v2 18/18] xfs: Add delayed attributes error tag Allison Collins
@ 2019-08-12  8:19 ` Christoph Hellwig
  2019-08-12 19:26   ` Allison Collins
  18 siblings, 1 reply; 56+ messages in thread
From: Christoph Hellwig @ 2019-08-12  8:19 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

Btw, this seems like the right series to also look into our problem
that large attributes are not updated transactionally.  We just do
a synchronous write (xfs_bwrite) for them but don't include them
in the transaction.  With the deferred operations and rolled
transactions that should be fairly easy to fix.

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

* Re: [PATCH v2 02/18] xfs: Replace attribute parameters with struct xfs_name
  2019-08-09 21:37 ` [PATCH v2 02/18] xfs: Replace attribute parameters with struct xfs_name Allison Collins
@ 2019-08-12 15:13   ` Darrick J. Wong
  2019-08-12 19:27     ` Allison Collins
  0 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2019-08-12 15:13 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Aug 09, 2019 at 02:37:10PM -0700, Allison Collins wrote:
> This patch replaces the attribute name, length and flags parameters with a
> single struct xfs_name parameter.  This helps to clean up the numbers of
> parameters being passed around and pre-simplifies the code some.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 40 ++++++++++++++++------------------------
>  fs/xfs/libxfs/xfs_attr.h | 12 +++++-------
>  fs/xfs/xfs_acl.c         | 26 +++++++++++++-------------
>  fs/xfs/xfs_ioctl.c       | 26 ++++++++++++++++----------
>  fs/xfs/xfs_iops.c        | 10 ++++++----
>  fs/xfs/xfs_xattr.c       | 21 +++++++++------------
>  6 files changed, 65 insertions(+), 70 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 7761925..0c91116 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -61,9 +61,7 @@ STATIC int
>  xfs_attr_args_init(
>  	struct xfs_da_args	*args,
>  	struct xfs_inode	*dp,
> -	const unsigned char	*name,
> -	size_t			namelen,
> -	int			flags)
> +	struct xfs_name		*name)
>  {
>  
>  	if (!name)
> @@ -73,9 +71,9 @@ xfs_attr_args_init(
>  	args->geo = dp->i_mount->m_attr_geo;
>  	args->whichfork = XFS_ATTR_FORK;
>  	args->dp = dp;
> -	args->flags = flags;
> -	args->name = name;
> -	args->namelen = namelen;
> +	args->flags = name->type;
> +	args->name = name->name;
> +	args->namelen = name->len;

/me wonders if you ought to just have an xfs_name embedded in the
xfs_da_args struct, seeing as the directory code uses it too.

>  	if (args->namelen >= MAXNAMELEN)
>  		return -EFAULT;		/* match IRIX behaviour */
>  

<skipping a bunch of changes that look fine to me>

> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index b1b7b1b..bdf925c 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -46,13 +46,15 @@ xfs_initxattrs(
>  {
>  	const struct xattr	*xattr;
>  	struct xfs_inode	*ip = XFS_I(inode);
> +	struct xfs_name		name;
>  	int			error = 0;
>  
>  	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
> -		error = xfs_attr_set(ip, xattr->name,
> -				     strlen(xattr->name),
> -				     xattr->value, xattr->value_len,
> -				     ATTR_SECURE);
> +		name.name = xattr->name;
> +		name.len = strlen(xattr->name);
> +		name.type = ATTR_SECURE;

You might as well declare and initialize name in the loop body.

> +		error = xfs_attr_set(ip, &name,
> +				     xattr->value, xattr->value_len);

Does the attr value need a similar structure encapsulation too?

>  		if (error < 0)
>  			break;
>  	}
> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
> index fe12d11..3c63930 100644
> --- a/fs/xfs/xfs_xattr.c
> +++ b/fs/xfs/xfs_xattr.c
> @@ -20,18 +20,17 @@ static int
>  xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>  		struct inode *inode, const char *name, void *value, size_t size)
>  {
> -	int xflags = handler->flags;
>  	struct xfs_inode *ip = XFS_I(inode);
>  	int error, asize = size;
> -	size_t namelen = strlen(name);
> +	struct xfs_name xname = {name, strlen(name), handler->flags};

I think the preferred format for this is to use the structure field
names explicity during assignment...

	struct xfs_name		xname = {
		.name		= name,
		.namelen	= strlen(name),
		.type		= handler->flags,
	};

Also, please fix the variable/argument declaration indentation style of
this function to match the rest of xfs. :)

--D

>  
>  	/* Convert Linux syscall to XFS internal ATTR flags */
>  	if (!size) {
> -		xflags |= ATTR_KERNOVAL;
> +		xname.type |= ATTR_KERNOVAL;
>  		value = NULL;
>  	}
>  
> -	error = xfs_attr_get(ip, name, namelen, value, &asize, xflags);
> +	error = xfs_attr_get(ip, &xname, value, &asize);
>  	if (error)
>  		return error;
>  	return asize;
> @@ -64,23 +63,21 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>  		struct inode *inode, const char *name, const void *value,
>  		size_t size, int flags)
>  {
> -	int			xflags = handler->flags;
>  	struct xfs_inode	*ip = XFS_I(inode);
>  	int			error;
> -	size_t			namelen = strlen(name);
> +	struct xfs_name		xname = {name, strlen(name), handler->flags};
>  
>  	/* Convert Linux syscall to XFS internal ATTR flags */
>  	if (flags & XATTR_CREATE)
> -		xflags |= ATTR_CREATE;
> +		xname.type |= ATTR_CREATE;
>  	if (flags & XATTR_REPLACE)
> -		xflags |= ATTR_REPLACE;
> +		xname.type |= ATTR_REPLACE;
>  
>  	if (!value)
> -		return xfs_attr_remove(ip, name,
> -				       namelen, xflags);
> -	error = xfs_attr_set(ip, name, namelen, (void *)value, size, xflags);
> +		return xfs_attr_remove(ip, &xname);
> +	error = xfs_attr_set(ip, &xname, (void *)value, size);
>  	if (!error)
> -		xfs_forget_acl(inode, name, xflags);
> +		xfs_forget_acl(inode, name, xname.type);
>  
>  	return error;
>  }
> -- 
> 2.7.4
> 

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

* Re: [PATCH v2 03/18] xfs: Set up infastructure for deferred attribute operations
  2019-08-09 21:37 ` [PATCH v2 03/18] xfs: Set up infastructure for deferred attribute operations Allison Collins
@ 2019-08-12 15:40   ` Darrick J. Wong
  2019-08-12 19:28     ` Allison Collins
  2019-08-12 19:28   ` Brian Foster
  1 sibling, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2019-08-12 15:40 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Aug 09, 2019 at 02:37:11PM -0700, Allison Collins wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> Currently attributes are modified directly across one or more
> transactions.  But they are not logged or replayed in the event of
> an error. The goal of delayed attributes is to enable logging and
> replaying of attribute operations using the existing delayed
> operations infrastructure.  This will later enable the attributes
> to become part of larger multi part operations that also must first
> be recorded to the log.  This is mostly of interest in the scheme of
> parent pointers which would need to maintain an attribute containing
> parent inode information any time an inode is moved, created, or
> removed.  Parent pointers would then be of interest to any feature
> that would need to quickly derive an inode path from the mount
> point.  Online scrub, nfs lookups and fs grow or shrink operations
> are all features that could take advantage of this.
> 
> This patch adds two new log item types for setting or removing
> attributes as deferred operations.  The xfs_attri_log_item logs an
> intent to set or remove an attribute.  The corresponding
> xfs_attrd_log_item holds a reference to the xfs_attri_log_item and
> is freed once the transaction is done.  Both log items use a generic
> xfs_attr_log_format structure that contains the attribute name,
> value, flags, inode, and an op_flag that indicates if the operations
> is a set or remove.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/Makefile                |   2 +-
>  fs/xfs/libxfs/xfs_attr.c       |   5 +-
>  fs/xfs/libxfs/xfs_attr.h       |  25 ++
>  fs/xfs/libxfs/xfs_defer.c      |   1 +
>  fs/xfs/libxfs/xfs_defer.h      |   3 +
>  fs/xfs/libxfs/xfs_log_format.h |  44 ++-
>  fs/xfs/libxfs/xfs_types.h      |   1 +
>  fs/xfs/xfs_attr_item.c         | 755 +++++++++++++++++++++++++++++++++++++++++
>  fs/xfs/xfs_attr_item.h         | 102 ++++++
>  fs/xfs/xfs_log.c               |   4 +
>  fs/xfs/xfs_log_recover.c       | 174 ++++++++++
>  fs/xfs/xfs_ondisk.h            |   2 +
>  fs/xfs/xfs_trans.h             |   4 +-
>  13 files changed, 1116 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
> index 06b68b6..70b4716 100644
> --- a/fs/xfs/Makefile
> +++ b/fs/xfs/Makefile
> @@ -102,6 +102,7 @@ xfs-y				+= xfs_log.o \
>  				   xfs_bmap_item.o \
>  				   xfs_buf_item.o \
>  				   xfs_extfree_item.o \
> +				   xfs_attr_item.o \
>  				   xfs_icreate_item.o \
>  				   xfs_inode_item.o \
>  				   xfs_refcount_item.o \
> @@ -109,7 +110,6 @@ xfs-y				+= xfs_log.o \
>  				   xfs_log_recover.o \
>  				   xfs_trans_ail.o \
>  				   xfs_trans_buf.o
> -
>  # optional features
>  xfs-$(CONFIG_XFS_QUOTA)		+= xfs_dquot.o \
>  				   xfs_dquot_item.o \
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 0c91116..1f76618 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -24,6 +24,7 @@
>  #include "xfs_quota.h"
>  #include "xfs_trans_space.h"
>  #include "xfs_trace.h"
> +#include "xfs_attr_item.h"
>  
>  /*
>   * xfs_attr.c
> @@ -57,7 +58,7 @@ STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>  STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>  
>  
> -STATIC int
> +int
>  xfs_attr_args_init(
>  	struct xfs_da_args	*args,
>  	struct xfs_inode	*dp,
> @@ -151,7 +152,7 @@ xfs_attr_get(
>  /*
>   * Calculate how many blocks we need for the new attribute,
>   */
> -STATIC int
> +int
>  xfs_attr_calc_size(
>  	struct xfs_da_args	*args,
>  	int			*local)
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index aa7261a..9132d4f 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -78,6 +78,28 @@ typedef struct attrlist_ent {	/* data from attr_list() */
>  } attrlist_ent_t;
>  
>  /*
> + * List of attrs to commit later.
> + */
> +struct xfs_attr_item {
> +	struct xfs_inode  *xattri_ip;
> +	uint32_t	  xattri_op_flags;
> +	void		  *xattri_value;      /* attr value */
> +	uint32_t	  xattri_value_len;   /* length of value */
> +	void		  *xattri_name;	      /* attr name */
> +	uint32_t	  xattri_name_len;    /* length of name */
> +	uint32_t	  xattri_flags;       /* attr flags */
> +	struct list_head  xattri_list;

pahole says you could reduce the size of this header from 64 to 56 bytes
by grouping all the pointers together and all the uin32_t together.

> +
> +	/*
> +	 * A byte array follows the header containing the file name and
> +	 * attribute value.
> +	 */
> +};
> +
> +#define XFS_ATTR_ITEM_SIZEOF(namelen, valuelen)	\
> +	(sizeof(struct xfs_attr_item) + (namelen) + (valuelen))
> +
> +/*
>   * Given a pointer to the (char*) buffer containing the attr_list() result,
>   * and an index, return a pointer to the indicated attribute in the buffer.
>   */

<skip past things that look ok>

> diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
> new file mode 100644
> index 0000000..2340589
> --- /dev/null
> +++ b/fs/xfs/xfs_attr_item.c
> @@ -0,0 +1,755 @@
> +// SPDX-License-Identifier: GPL-2.0+

Sooooo... [redact idiotic spdx drama that I don't care to rehash]

This means that "GPL-2.0+" is not correct here, it's supposed to be
"GPL-2.0-or-later" as defined in LICENSES/preferred/GPL-2.0, and Greg KH
can go fix all the breakage he pushed in the kernel with insufficient
review.

> +/*
> + * Copyright (C) 2019 Oracle.  All Rights Reserved.
> + * Author: Allison Henderson <allison.henderson@oracle.com>
> + */
> +
> +#include "xfs.h"
> +#include "xfs_fs.h"
> +#include "xfs_format.h"
> +#include "xfs_log_format.h"
> +#include "xfs_trans_resv.h"
> +#include "xfs_bit.h"
> +#include "xfs_shared.h"
> +#include "xfs_mount.h"
> +#include "xfs_defer.h"
> +#include "xfs_trans.h"
> +#include "xfs_trans_priv.h"
> +#include "xfs_buf_item.h"
> +#include "xfs_attr_item.h"
> +#include "xfs_log.h"
> +#include "xfs_btree.h"
> +#include "xfs_rmap.h"
> +#include "xfs_inode.h"
> +#include "xfs_icache.h"
> +#include "xfs_attr.h"
> +#include "xfs_da_format.h"
> +#include "xfs_da_btree.h"
> +#include "xfs_shared.h"
> +#include "xfs_attr_item.h"
> +#include "xfs_alloc.h"
> +#include "xfs_bmap.h"
> +#include "xfs_trace.h"
> +#include "libxfs/xfs_da_format.h"
> +#include "xfs_inode.h"
> +#include "xfs_quota.h"
> +
> +
> +/*
> + * This routine is called to allocate an "attr free done" log item.
> + */
> +struct xfs_attrd_log_item *
> +xfs_trans_get_attrd(struct xfs_trans		*tp,
> +		  struct xfs_attri_log_item	*attrip)
> +{
> +	struct xfs_attrd_log_item		*attrdp;
> +
> +	ASSERT(tp != NULL);
> +
> +	attrdp = xfs_attrd_init(tp->t_mountp, attrip);
> +	ASSERT(attrdp != NULL);
> +
> +	/*
> +	 * Get a log_item_desc to point at the new item.
> +	 */
> +	xfs_trans_add_item(tp, &attrdp->attrd_item);
> +	return attrdp;
> +}
> +
> +/*
> + * Delete an attr and log it to the ATTRD. Note that the transaction is marked
> + * dirty regardless of whether the attr delete succeeds or fails to support the
> + * ATTRI/ATTRD lifecycle rules.
> + */
> +int
> +xfs_trans_attr(
> +	struct xfs_da_args		*args,
> +	struct xfs_attrd_log_item	*attrdp,
> +	uint32_t			op_flags)
> +{
> +	int				error;
> +
> +	error = xfs_qm_dqattach_locked(args->dp, 0);
> +	if (error)
> +		return error;
> +
> +	switch (op_flags) {
> +	case XFS_ATTR_OP_FLAGS_SET:
> +		args->op_flags |= XFS_DA_OP_ADDNAME;
> +		error = xfs_attr_set_args(args);
> +		break;
> +	case XFS_ATTR_OP_FLAGS_REMOVE:
> +		ASSERT(XFS_IFORK_Q((args->dp)));
> +		error = xfs_attr_remove_args(args);
> +		break;
> +	default:
> +		error = -EFSCORRUPTED;

The default clause needs a break; here.

> +	}
> +
> +	/*
> +	 * Mark the transaction dirty, even on error. This ensures the
> +	 * transaction is aborted, which:
> +	 *
> +	 * 1.) releases the ATTRI and frees the ATTRD
> +	 * 2.) shuts down the filesystem
> +	 */
> +	args->trans->t_flags |= XFS_TRANS_DIRTY;
> +	set_bit(XFS_LI_DIRTY, &attrdp->attrd_item.li_flags);
> +
> +	return error;
> +}
> +

<skip stuff that looks ok>

> +/*
> + * This is the ops vector shared by all attri log items.
> + */

We just got rid of this comment above all the other log item ops
structure definitions, so you can clip these out.

> +static const struct xfs_item_ops xfs_attri_item_ops = {
> +	.iop_size	= xfs_attri_item_size,
> +	.iop_format	= xfs_attri_item_format,
> +	.iop_pin	= xfs_attri_item_pin,
> +	.iop_unpin	= xfs_attri_item_unpin,
> +	.iop_committed	= xfs_attri_item_committed,
> +	.iop_push	= xfs_attri_item_push,
> +	.iop_committing = xfs_attri_item_committing,
> +	.iop_release    = xfs_attri_item_release,
> +};
> +
> +
> +/*
> + * Allocate and initialize an attri item
> + */
> +struct xfs_attri_log_item *
> +xfs_attri_init(
> +	struct xfs_mount	*mp)
> +
> +{
> +	struct xfs_attri_log_item	*attrip;
> +	uint				size;
> +
> +	size = (uint)(sizeof(struct xfs_attri_log_item));
> +	attrip = kmem_zalloc(size, KM_SLEEP);
> +
> +	xfs_log_item_init(mp, &attrip->attri_item, XFS_LI_ATTRI,
> +			  &xfs_attri_item_ops);
> +	attrip->attri_format.alfi_id = (uintptr_t)(void *)attrip;

/me wonders if we ought to clean up all these *[id]_id types so that we
don't have to employ all these annoying casts, but that's not relevant
to this series.

> +	atomic_set(&attrip->attri_refcount, 2);
> +
> +	return attrip;
> +}
> +

<skip more stuff that looked ok>

> +/*
> + * Pinning has no meaning for an attrd item, so just return.
> + */
> +STATIC void
> +xfs_attrd_item_pin(
> +	struct xfs_log_item	*lip)
> +{
> +}

Hmm, didn't Christoph refactor the log code in 5.3 so that log items
don't need all these empty unlock/committing/pin functions?

> +
> +/*
> + * Since pinning has no meaning for an attrd item, unpinning does
> + * not either.
> + */
> +STATIC void
> +xfs_attrd_item_unpin(
> +	struct xfs_log_item	*lip,
> +	int			remove)
> +{
> +}
> +
> +/*
> + * There isn't much you can do to push on an attrd item.  It is simply stuck
> + * waiting for the log to be flushed to disk.
> + */
> +STATIC uint
> +xfs_attrd_item_push(
> +	struct xfs_log_item	*lip,
> +	struct list_head	*buffer_list)
> +{
> +	return XFS_ITEM_PINNED;
> +}
> +
> +/*
> + * When the attrd item is committed to disk, all we need to do is delete our
> + * reference to our partner attri item and then free ourselves. Since we're
> + * freeing ourselves we must return -1 to keep the transaction code from
> + * further referencing this item.
> + */
> +STATIC xfs_lsn_t
> +xfs_attrd_item_committed(
> +	struct xfs_log_item	*lip,
> +	xfs_lsn_t		lsn)
> +{
> +	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
> +
> +	/*
> +	 * Drop the ATTRI reference regardless of whether the ATTRD has been
> +	 * aborted. Once the ATTRD transaction is constructed, it is the sole
> +	 * responsibility of the ATTRD to release the ATTRI (even if the ATTRI
> +	 * is aborted due to log I/O error).
> +	 */
> +	xfs_attri_release(attrdp->attrd_attrip);
> +	xfs_attrd_item_free(attrdp);
> +
> +	return (xfs_lsn_t)-1;

NULLCOMMITLSN?

<skip more>

> +/*
> + * Process an attr intent item that was recovered from the log.  We need to
> + * delete the attr that it describes.
> + */
> +int
> +xfs_attri_recover(
> +	struct xfs_mount		*mp,
> +	struct xfs_attri_log_item	*attrip)
> +{
> +	struct xfs_inode		*ip;
> +	struct xfs_attrd_log_item	*attrdp;
> +	struct xfs_da_args		args;
> +	struct xfs_attri_log_format	*attrp;
> +	struct xfs_trans_res		tres;
> +	int				local;
> +	int				error = 0;
> +	int				rsvd = 0;
> +	struct xfs_name			name;
> +
> +	ASSERT(!test_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags));
> +
> +	/*
> +	 * First check the validity of the attr described by the ATTRI.  If any
> +	 * are bad, then assume that all are bad and just toss the ATTRI.
> +	 */
> +	attrp = &attrip->attri_format;
> +	if (
> +	    !(attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_SET ||
> +		attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_REMOVE) ||
> +	      (attrp->alfi_value_len > XATTR_SIZE_MAX) ||
> +	      (attrp->alfi_name_len > XATTR_NAME_MAX) ||
> +	      (attrp->alfi_name_len == 0)
> +	) {
> +		/*
> +		 * This will pull the ATTRI from the AIL and free the memory
> +		 * associated with it.
> +		 */
> +		set_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags);
> +		xfs_attri_release(attrip);
> +		return -EIO;

This is probably more EFSCORRUPTED than EIO here, right?

> +	}
> +
> +	attrp = &attrip->attri_format;
> +	error = xfs_iget(mp, 0, attrp->alfi_ino, 0, 0, &ip);
> +	if (error)
> +		return error;
> +
> +	name.name = attrip->attri_name;
> +	name.len = attrp->alfi_name_len;
> +	name.type = attrp->alfi_attr_flags;
> +	error = xfs_attr_args_init(&args, ip, &name);
> +	if (error)
> +		return error;
> +
> +	args.hashval = xfs_da_hashname(args.name, args.namelen);
> +	args.value = attrip->attri_value;
> +	args.valuelen = attrp->alfi_value_len;
> +	args.op_flags = XFS_DA_OP_OKNOENT;
> +	args.total = xfs_attr_calc_size(&args, &local);
> +
> +	tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
> +			M_RES(mp)->tr_attrsetrt.tr_logres * args.total;
> +	tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
> +	tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
> +
> +	error = xfs_trans_alloc(mp, &tres, args.total,  0,
> +				rsvd ? XFS_TRANS_RESERVE : 0, &args.trans);
> +	if (error)
> +		return error;
> +	attrdp = xfs_trans_get_attrd(args.trans, attrip);
> +
> +	xfs_ilock(ip, XFS_ILOCK_EXCL);
> +
> +	xfs_trans_ijoin(args.trans, ip, 0);
> +	error = xfs_trans_attr(&args, attrdp, attrp->alfi_op_flags);
> +	if (error)
> +		goto abort_error;
> +
> +
> +	set_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags);
> +	xfs_trans_log_inode(args.trans, ip, XFS_ILOG_CORE | XFS_ILOG_ADATA);
> +	error = xfs_trans_commit(args.trans);
> +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
> +	return error;
> +
> +abort_error:
> +	xfs_trans_cancel(args.trans);
> +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
> +	return error;
> +}
> diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h
> new file mode 100644
> index 0000000..aad32ed
> --- /dev/null
> +++ b/fs/xfs/xfs_attr_item.h
> @@ -0,0 +1,102 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2019 Oracle.  All Rights Reserved.
> + * Author: Allison Henderson <allison.henderson@oracle.com>
> + */
> +#ifndef	__XFS_ATTR_ITEM_H__
> +#define	__XFS_ATTR_ITEM_H__
> +
> +/* kernel only ATTRI/ATTRD definitions */
> +
> +struct xfs_mount;
> +struct kmem_zone;
> +
> +/*
> + * Max number of attrs in fast allocation path.
> + */
> +#define XFS_ATTRI_MAX_FAST_ATTRS        1
> +
> +
> +/*
> + * Define ATTR flag bits. Manipulated by set/clear/test_bit operators.
> + */
> +#define	XFS_ATTRI_RECOVERED	1
> +
> +
> +/* iovec length must be 32-bit aligned */
> +#define ATTR_NVEC_SIZE(size) (size == sizeof(int32_t) ? sizeof(int32_t) : \
> +				size + sizeof(int32_t) - \
> +				(size % sizeof(int32_t)))
> +
> +/*
> + * This is the "attr intention" log item.  It is used to log the fact that some
> + * need to be processed.  It is used in conjunction with the "attr done" log
> + * item described below.
> + *
> + * The ATTRI is reference counted so that it is not freed prior to both the
> + * ATTRI and ATTRD being committed and unpinned. This ensures the ATTRI is
> + * inserted into the AIL even in the event of out of order ATTRI/ATTRD
> + * processing. In other words, an ATTRI is born with two references:
> + *
> + *      1.) an ATTRI held reference to track ATTRI AIL insertion
> + *      2.) an ATTRD held reference to track ATTRD commit
> + *
> + * On allocation, both references are the responsibility of the caller. Once the
> + * ATTRI is added to and dirtied in a transaction, ownership of reference one
> + * transfers to the transaction. The reference is dropped once the ATTRI is
> + * inserted to the AIL or in the event of failure along the way (e.g., commit
> + * failure, log I/O error, etc.). Note that the caller remains responsible for
> + * the ATTRD reference under all circumstances to this point. The caller has no
> + * means to detect failure once the transaction is committed, however.
> + * Therefore, an ATTRD is required after this point, even in the event of
> + * unrelated failure.
> + *
> + * Once an ATTRD is allocated and dirtied in a transaction, reference two
> + * transfers to the transaction. The ATTRD reference is dropped once it reaches
> + * the unpin handler. Similar to the ATTRI, the reference also drops in the
> + * event of commit failure or log I/O errors. Note that the ATTRD is not
> + * inserted in the AIL, so at this point both the ATTI and ATTRD are freed.

"...the ATTRI and ATTRD are freed." ?

> + */
> +struct xfs_attri_log_item {
> +	struct xfs_log_item		attri_item;
> +	atomic_t			attri_refcount;
> +	unsigned long			attri_flags;	/* misc flags */
> +	int				attri_name_len;
> +	void				*attri_name;
> +	int				attri_value_len;
> +	void				*attri_value;
> +	struct xfs_attri_log_format	attri_format;
> +};
> +
> +/*
> + * This is the "attr done" log item.  It is used to log the fact that some attrs
> + * earlier mentioned in an attri item have been freed.
> + */
> +struct xfs_attrd_log_item {
> +	struct xfs_log_item		attrd_item;
> +	struct xfs_attri_log_item	*attrd_attrip;
> +	struct xfs_attrd_log_format	attrd_format;
> +};

Can these be rearranged to use less memory?

Everything else after this looks ok to me.

--D

> +
> +/*
> + * Max number of attrs in fast allocation path.
> + */
> +#define	XFS_ATTRD_MAX_FAST_ATTRS	1
> +
> +extern struct kmem_zone	*xfs_attri_zone;
> +extern struct kmem_zone	*xfs_attrd_zone;
> +
> +struct xfs_attri_log_item	*xfs_attri_init(struct xfs_mount *mp);
> +struct xfs_attrd_log_item	*xfs_attrd_init(struct xfs_mount *mp,
> +					struct xfs_attri_log_item *attrip);
> +int xfs_attri_copy_format(struct xfs_log_iovec *buf,
> +			   struct xfs_attri_log_format *dst_attri_fmt);
> +int xfs_attrd_copy_format(struct xfs_log_iovec *buf,
> +			   struct xfs_attrd_log_format *dst_attrd_fmt);
> +void			xfs_attri_item_free(struct xfs_attri_log_item *attrip);
> +void			xfs_attri_release(struct xfs_attri_log_item *attrip);
> +
> +int			xfs_attri_recover(struct xfs_mount *mp,
> +					struct xfs_attri_log_item *attrip);
> +
> +#endif	/* __XFS_ATTR_ITEM_H__ */
> diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
> index 00e9f5c..2fbd180 100644
> --- a/fs/xfs/xfs_log.c
> +++ b/fs/xfs/xfs_log.c
> @@ -2005,6 +2005,10 @@ xlog_print_tic_res(
>  	    REG_TYPE_STR(CUD_FORMAT, "cud_format"),
>  	    REG_TYPE_STR(BUI_FORMAT, "bui_format"),
>  	    REG_TYPE_STR(BUD_FORMAT, "bud_format"),
> +	    REG_TYPE_STR(ATTRI_FORMAT, "attri_format"),
> +	    REG_TYPE_STR(ATTRD_FORMAT, "attrd_format"),
> +	    REG_TYPE_STR(ATTR_NAME, "attr_name"),
> +	    REG_TYPE_STR(ATTR_VALUE, "attr_value"),
>  	};
>  	BUILD_BUG_ON(ARRAY_SIZE(res_type_str) != XLOG_REG_TYPE_MAX + 1);
>  #undef REG_TYPE_STR
> diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
> index 13d1d3e..233efdb3 100644
> --- a/fs/xfs/xfs_log_recover.c
> +++ b/fs/xfs/xfs_log_recover.c
> @@ -20,6 +20,7 @@
>  #include "xfs_log_recover.h"
>  #include "xfs_inode_item.h"
>  #include "xfs_extfree_item.h"
> +#include "xfs_attr_item.h"
>  #include "xfs_trans_priv.h"
>  #include "xfs_alloc.h"
>  #include "xfs_ialloc.h"
> @@ -1885,6 +1886,8 @@ xlog_recover_reorder_trans(
>  		case XFS_LI_CUD:
>  		case XFS_LI_BUI:
>  		case XFS_LI_BUD:
> +		case XFS_LI_ATTRI:
> +		case XFS_LI_ATTRD:
>  			trace_xfs_log_recover_item_reorder_tail(log,
>  							trans, item, pass);
>  			list_move_tail(&item->ri_list, &inode_list);
> @@ -3422,6 +3425,119 @@ xlog_recover_efd_pass2(
>  	return 0;
>  }
>  
> +STATIC int
> +xlog_recover_attri_pass2(
> +	struct xlog                     *log,
> +	struct xlog_recover_item        *item,
> +	xfs_lsn_t                       lsn)
> +{
> +	int                             error;
> +	struct xfs_mount                *mp = log->l_mp;
> +	struct xfs_attri_log_item       *attrip;
> +	struct xfs_attri_log_format     *attri_formatp;
> +	char				*name = NULL;
> +	char				*value = NULL;
> +	int				region = 0;
> +
> +	attri_formatp = item->ri_buf[region].i_addr;
> +
> +	attrip = xfs_attri_init(mp);
> +	error = xfs_attri_copy_format(&item->ri_buf[region],
> +				      &attrip->attri_format);
> +	if (error) {
> +		xfs_attri_item_free(attrip);
> +		return error;
> +	}
> +
> +	attrip->attri_name_len = attri_formatp->alfi_name_len;
> +	attrip->attri_value_len = attri_formatp->alfi_value_len;
> +	attrip = kmem_realloc(attrip, sizeof(struct xfs_attri_log_item) +
> +			      attrip->attri_name_len + attrip->attri_value_len,
> +			      KM_SLEEP);
> +
> +	if (attrip->attri_name_len > 0) {
> +		region++;
> +		name = ((char *)attrip) + sizeof(struct xfs_attri_log_item);
> +		memcpy(name, item->ri_buf[region].i_addr,
> +		       attrip->attri_name_len);
> +		attrip->attri_name = name;
> +	}
> +
> +	if (attrip->attri_value_len > 0) {
> +		region++;
> +		value = ((char *)attrip) + sizeof(struct xfs_attri_log_item) +
> +			attrip->attri_name_len;
> +		memcpy(value, item->ri_buf[region].i_addr,
> +			attrip->attri_value_len);
> +		attrip->attri_value = value;
> +	}
> +
> +	spin_lock(&log->l_ailp->ail_lock);
> +	/*
> +	 * The ATTRI has two references. One for the ATTRD and one for ATTRI to
> +	 * ensure it makes it into the AIL. Insert the ATTRI into the AIL
> +	 * directly and drop the ATTRI reference. Note that
> +	 * xfs_trans_ail_update() drops the AIL lock.
> +	 */
> +	xfs_trans_ail_update(log->l_ailp, &attrip->attri_item, lsn);
> +	xfs_attri_release(attrip);
> +	return 0;
> +}
> +
> +
> +/*
> + * This routine is called when an ATTRD format structure is found in a committed
> + * transaction in the log. Its purpose is to cancel the corresponding ATTRI if
> + * it was still in the log. To do this it searches the AIL for the ATTRI with
> + * an id equal to that in the ATTRD format structure. If we find it we drop
> + * the ATTRD reference, which removes the ATTRI from the AIL and frees it.
> + */
> +STATIC int
> +xlog_recover_attrd_pass2(
> +	struct xlog                     *log,
> +	struct xlog_recover_item        *item)
> +{
> +	struct xfs_attrd_log_format	*attrd_formatp;
> +	struct xfs_attri_log_item	*attrip = NULL;
> +	struct xfs_log_item		*lip;
> +	uint64_t			attri_id;
> +	struct xfs_ail_cursor		cur;
> +	struct xfs_ail			*ailp = log->l_ailp;
> +
> +	attrd_formatp = item->ri_buf[0].i_addr;
> +	ASSERT((item->ri_buf[0].i_len ==
> +				(sizeof(struct xfs_attrd_log_format))));
> +	attri_id = attrd_formatp->alfd_alf_id;
> +
> +	/*
> +	 * Search for the ATTRI with the id in the ATTRD format structure in the
> +	 * AIL.
> +	 */
> +	spin_lock(&ailp->ail_lock);
> +	lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
> +	while (lip != NULL) {
> +		if (lip->li_type == XFS_LI_ATTRI) {
> +			attrip = (struct xfs_attri_log_item *)lip;
> +			if (attrip->attri_format.alfi_id == attri_id) {
> +				/*
> +				 * Drop the ATTRD reference to the ATTRI. This
> +				 * removes the ATTRI from the AIL and frees it.
> +				 */
> +				spin_unlock(&ailp->ail_lock);
> +				xfs_attri_release(attrip);
> +				spin_lock(&ailp->ail_lock);
> +				break;
> +			}
> +		}
> +		lip = xfs_trans_ail_cursor_next(ailp, &cur);
> +	}
> +
> +	xfs_trans_ail_cursor_done(&cur);
> +	spin_unlock(&ailp->ail_lock);
> +
> +	return 0;
> +}
> +
>  /*
>   * This routine is called to create an in-core extent rmap update
>   * item from the rui format structure which was logged on disk.
> @@ -3974,6 +4090,8 @@ xlog_recover_ra_pass2(
>  		break;
>  	case XFS_LI_EFI:
>  	case XFS_LI_EFD:
> +	case XFS_LI_ATTRI:
> +	case XFS_LI_ATTRD:
>  	case XFS_LI_QUOTAOFF:
>  	case XFS_LI_RUI:
>  	case XFS_LI_RUD:
> @@ -4002,6 +4120,8 @@ xlog_recover_commit_pass1(
>  	case XFS_LI_INODE:
>  	case XFS_LI_EFI:
>  	case XFS_LI_EFD:
> +	case XFS_LI_ATTRI:
> +	case XFS_LI_ATTRD:
>  	case XFS_LI_DQUOT:
>  	case XFS_LI_ICREATE:
>  	case XFS_LI_RUI:
> @@ -4040,6 +4160,10 @@ xlog_recover_commit_pass2(
>  		return xlog_recover_efi_pass2(log, item, trans->r_lsn);
>  	case XFS_LI_EFD:
>  		return xlog_recover_efd_pass2(log, item);
> +	case XFS_LI_ATTRI:
> +		return xlog_recover_attri_pass2(log, item, trans->r_lsn);
> +	case XFS_LI_ATTRD:
> +		return xlog_recover_attrd_pass2(log, item);
>  	case XFS_LI_RUI:
>  		return xlog_recover_rui_pass2(log, item, trans->r_lsn);
>  	case XFS_LI_RUD:
> @@ -4601,6 +4725,48 @@ xlog_recover_cancel_efi(
>  	spin_lock(&ailp->ail_lock);
>  }
>  
> +/* Release the ATTRI since we're cancelling everything. */
> +STATIC void
> +xlog_recover_cancel_attri(
> +	struct xfs_mount                *mp,
> +	struct xfs_ail                  *ailp,
> +	struct xfs_log_item             *lip)
> +{
> +	struct xfs_attri_log_item         *attrip;
> +
> +	attrip = container_of(lip, struct xfs_attri_log_item, attri_item);
> +
> +	spin_unlock(&ailp->ail_lock);
> +	xfs_attri_release(attrip);
> +	spin_lock(&ailp->ail_lock);
> +}
> +
> +
> +/* Recover the ATTRI if necessary. */
> +STATIC int
> +xlog_recover_process_attri(
> +	struct xfs_mount                *mp,
> +	struct xfs_ail                  *ailp,
> +	struct xfs_log_item             *lip)
> +{
> +	struct xfs_attri_log_item       *attrip;
> +	int                             error;
> +
> +	/*
> +	 * Skip ATTRIs that we've already processed.
> +	 */
> +	attrip = container_of(lip, struct xfs_attri_log_item, attri_item);
> +	if (test_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags))
> +		return 0;
> +
> +	spin_unlock(&ailp->ail_lock);
> +	error = xfs_attri_recover(mp, attrip);
> +	spin_lock(&ailp->ail_lock);
> +
> +	return error;
> +}
> +
> +
>  /* Recover the RUI if necessary. */
>  STATIC int
>  xlog_recover_process_rui(
> @@ -4729,6 +4895,7 @@ static inline bool xlog_item_is_intent(struct xfs_log_item *lip)
>  	case XFS_LI_RUI:
>  	case XFS_LI_CUI:
>  	case XFS_LI_BUI:
> +	case XFS_LI_ATTRI:
>  		return true;
>  	default:
>  		return false;
> @@ -4847,6 +5014,10 @@ xlog_recover_process_intents(
>  		case XFS_LI_EFI:
>  			error = xlog_recover_process_efi(log->l_mp, ailp, lip);
>  			break;
> +		case XFS_LI_ATTRI:
> +			error = xlog_recover_process_attri(log->l_mp,
> +							   ailp, lip);
> +			break;
>  		case XFS_LI_RUI:
>  			error = xlog_recover_process_rui(log->l_mp, ailp, lip);
>  			break;
> @@ -4912,6 +5083,9 @@ xlog_recover_cancel_intents(
>  		case XFS_LI_BUI:
>  			xlog_recover_cancel_bui(log->l_mp, ailp, lip);
>  			break;
> +		case XFS_LI_ATTRI:
> +			xlog_recover_cancel_attri(log->l_mp, ailp, lip);
> +			break;
>  		}
>  
>  		lip = xfs_trans_ail_cursor_next(ailp, &cur);
> diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h
> index b6701b4..120fb0c 100644
> --- a/fs/xfs/xfs_ondisk.h
> +++ b/fs/xfs/xfs_ondisk.h
> @@ -125,6 +125,8 @@ xfs_check_ondisk_structs(void)
>  	XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format,	56);
>  	XFS_CHECK_STRUCT_SIZE(struct xfs_qoff_logformat,	20);
>  	XFS_CHECK_STRUCT_SIZE(struct xfs_trans_header,		16);
> +	XFS_CHECK_STRUCT_SIZE(struct xfs_attri_log_format,	40);
> +	XFS_CHECK_STRUCT_SIZE(struct xfs_attrd_log_format,	16);
>  
>  	/*
>  	 * The v5 superblock format extended several v4 header structures with
> diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
> index 64d7f17..95924dc 100644
> --- a/fs/xfs/xfs_trans.h
> +++ b/fs/xfs/xfs_trans.h
> @@ -26,6 +26,9 @@ struct xfs_cui_log_item;
>  struct xfs_cud_log_item;
>  struct xfs_bui_log_item;
>  struct xfs_bud_log_item;
> +struct xfs_attrd_log_item;
> +struct xfs_attri_log_item;
> +struct xfs_da_args;
>  
>  struct xfs_log_item {
>  	struct list_head		li_ail;		/* AIL pointers */
> @@ -229,7 +232,6 @@ void		xfs_trans_log_buf(struct xfs_trans *, struct xfs_buf *, uint,
>  void		xfs_trans_dirty_buf(struct xfs_trans *, struct xfs_buf *);
>  bool		xfs_trans_buf_is_dirty(struct xfs_buf *bp);
>  void		xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
> -
>  int		xfs_trans_commit(struct xfs_trans *);
>  int		xfs_trans_roll(struct xfs_trans **);
>  int		xfs_trans_roll_inode(struct xfs_trans **, struct xfs_inode *);
> -- 
> 2.7.4
> 

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

* Re: [PATCH v2 04/18] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
  2019-08-09 21:37 ` [PATCH v2 04/18] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred Allison Collins
@ 2019-08-12 15:44   ` Darrick J. Wong
  2019-08-12 19:28     ` Allison Collins
  0 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2019-08-12 15:44 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Aug 09, 2019 at 02:37:12PM -0700, Allison Collins wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> These routines set up set and start a new deferred attribute
> operation.  These functions are meant to be called by other
> code needing to initiate a deferred attribute operation.
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++
>  fs/xfs/libxfs/xfs_attr.h |  5 ++++
>  2 files changed, 79 insertions(+)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 1f76618..a2fba0c 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -25,6 +25,7 @@
>  #include "xfs_trans_space.h"
>  #include "xfs_trace.h"
>  #include "xfs_attr_item.h"
> +#include "xfs_attr.h"
>  
>  /*
>   * xfs_attr.c
> @@ -399,6 +400,48 @@ xfs_attr_set(
>  	goto out_unlock;
>  }
>  
> +/* Sets an attribute for an inode as a deferred operation */
> +int
> +xfs_attr_set_deferred(
> +	struct xfs_inode	*dp,
> +	struct xfs_trans	*tp,
> +	struct xfs_name		*name,
> +	const unsigned char	*value,
> +	unsigned int		valuelen)
> +{
> +
> +	struct xfs_attr_item	*new;
> +	char			*name_value;
> +
> +	/*
> +	 * All set operations must have a name but not necessarily a value.
> +	 */
> +	if (!name->len) {
> +		ASSERT(0);
> +		return -EINVAL;
> +	}
> +
> +	new = kmem_alloc_large(XFS_ATTR_ITEM_SIZEOF(name->len, valuelen),
> +			 KM_SLEEP|KM_NOFS);
> +	name_value = ((char *)new) + sizeof(struct xfs_attr_item);
> +	memset(new, 0, XFS_ATTR_ITEM_SIZEOF(name->len, valuelen));
> +	new->xattri_ip = dp;
> +	new->xattri_op_flags = XFS_ATTR_OP_FLAGS_SET;
> +	new->xattri_name_len = name->len;
> +	new->xattri_value_len = valuelen;
> +	new->xattri_flags = name->type;
> +	memcpy(&name_value[0], name->name, name->len);
> +	new->xattri_name = name_value;
> +	new->xattri_value = name_value + name->len;
> +
> +	if (valuelen > 0)
> +		memcpy(&name_value[name->len], value, valuelen);
> +
> +	xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
> +
> +	return 0;
> +}
> +
>  /*
>   * Generic handler routine to remove a name from an attribute list.
>   * Transitions attribute list from Btree to shortform as necessary.
> @@ -480,6 +523,37 @@ xfs_attr_remove(
>  	return error;
>  }
>  
> +/* Removes an attribute for an inode as a deferred operation */
> +int
> +xfs_attr_remove_deferred(
> +	struct xfs_inode        *dp,
> +	struct xfs_trans	*tp,
> +	struct xfs_name		*name)
> +{
> +
> +	struct xfs_attr_item	*new;
> +	char			*name_value;
> +
> +	if (!name->len) {
> +		ASSERT(0);
> +		return -EINVAL;
> +	}
> +
> +	new = kmem_alloc(XFS_ATTR_ITEM_SIZEOF(name->len, 0), KM_SLEEP|KM_NOFS);
> +	name_value = ((char *)new) + sizeof(struct xfs_attr_item);
> +	memset(new, 0, XFS_ATTR_ITEM_SIZEOF(name->len, 0));
> +	new->xattri_ip = dp;
> +	new->xattri_op_flags = XFS_ATTR_OP_FLAGS_REMOVE;
> +	new->xattri_name_len = name->len;
> +	new->xattri_value_len = 0;
> +	new->xattri_flags = name->type;
> +	memcpy(name_value, name->name, name->len);
> +
> +	xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);

Can the common parts of these two functions be refactored into a single
initialization function called from xfs_attr_{set,remove}_deferred,
similar to what xfs_rmap.c does for all the various deferred rmap calls?

--D

> +
> +	return 0;
> +}
> +
>  /*========================================================================
>   * External routines when attribute list is inside the inode
>   *========================================================================*/
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index 9132d4f..0bade83 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -177,5 +177,10 @@ bool xfs_attr_namecheck(const void *name, size_t length);
>  int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
>  		       struct xfs_name *name);
>  int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
> +int xfs_attr_set_deferred(struct xfs_inode *dp, struct xfs_trans *tp,
> +			  struct xfs_name *name, const unsigned char *value,
> +			  unsigned int valuelen);
> +int xfs_attr_remove_deferred(struct xfs_inode *dp, struct xfs_trans *tp,
> +			    struct xfs_name *name);
>  
>  #endif	/* __XFS_ATTR_H__ */
> -- 
> 2.7.4
> 

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

* Re: [PATCH v2 05/18] xfs: Add xfs_has_attr and subroutines
  2019-08-09 21:37 ` [PATCH v2 05/18] xfs: Add xfs_has_attr and subroutines Allison Collins
@ 2019-08-12 15:56   ` Darrick J. Wong
  2019-08-12 19:29     ` Allison Collins
  0 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2019-08-12 15:56 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Aug 09, 2019 at 02:37:13PM -0700, Allison Collins wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> This patch adds a new functions to check for the existence of
> an attribute.  Subroutines are also added to handle the cases
> of leaf blocks, nodes or shortform.  Common code that appears
> in existing attr add and remove functions have been factored
> out to help reduce the appearence of duplicated code.  We will
> need these routines later for delayed attributes since delayed
> operations cannot return error codes.
> 
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c      | 151 +++++++++++++++++++++++++++---------------
>  fs/xfs/libxfs/xfs_attr.h      |   1 +
>  fs/xfs/libxfs/xfs_attr_leaf.c |  82 +++++++++++++++--------
>  fs/xfs/libxfs/xfs_attr_leaf.h |   2 +
>  4 files changed, 158 insertions(+), 78 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index a2fba0c..72af8e2 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -48,6 +48,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>  STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
>  STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
>  STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
> +STATIC int xfs_leaf_has_attr(xfs_da_args_t *args, struct xfs_buf **bp);         

Trailing whitespace, and please use "struct xfs_da_args", not the
typedef...

>  
>  /*
>   * Internal routines when attribute list is more than one block.
> @@ -55,6 +56,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>  STATIC int xfs_attr_node_get(xfs_da_args_t *args);
>  STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
>  STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
> +STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
> +				 struct xfs_da_state **state);
>  STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>  STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>  
> @@ -278,6 +281,32 @@ xfs_attr_set_args(
>  }
>  
>  /*
> + * Return EEXIST if attr is found, or ENOATTR if not
> + */
> +int
> +xfs_has_attr(
> +	struct xfs_da_args      *args)
> +{
> +	struct xfs_inode        *dp = args->dp;
> +	struct xfs_buf		*bp;
> +	int                     error;
> +
> +	if (!xfs_inode_hasattr(dp)) {
> +		error = -ENOATTR;
> +	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
> +		error = xfs_shortform_has_attr(args, NULL, NULL);
> +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> +		error = xfs_leaf_has_attr(args, &bp);
> +		xfs_trans_brelse(args->trans, bp);
> +	} else {
> +		error = xfs_attr_node_hasname(args, NULL);
> +	}
> +
> +	return error;
> +}
> +
> +/*
>   * Remove the attribute specified in @args.
>   */
>  int
> @@ -616,26 +645,17 @@ STATIC int
>  xfs_attr_leaf_addname(
>  	struct xfs_da_args	*args)
>  {
> -	struct xfs_inode	*dp;
>  	struct xfs_buf		*bp;
>  	int			retval, error, forkoff;
> +	struct xfs_inode	*dp = args->dp;
>  
>  	trace_xfs_attr_leaf_addname(args);
>  
>  	/*
> -	 * Read the (only) block in the attribute list in.
> -	 */
> -	dp = args->dp;
> -	args->blkno = 0;
> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
> -	if (error)
> -		return error;
> -
> -	/*
>  	 * Look up the given attribute in the leaf block.  Figure out if
>  	 * the given flags produce an error or call for an atomic rename.
>  	 */
> -	retval = xfs_attr3_leaf_lookup_int(bp, args);
> +	retval = xfs_leaf_has_attr(args, &bp);
>  	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
>  		xfs_trans_brelse(args->trans, bp);
>  		return retval;
> @@ -787,6 +807,26 @@ xfs_attr_leaf_addname(
>  }
>  
>  /*
> + * Return EEXIST if attr is found, or ENOATTR if not
> + */
> +STATIC int
> +xfs_leaf_has_attr(
> +	struct xfs_da_args      *args,
> +	struct xfs_buf		**bp)
> +{
> +	int                     error = 0;
> +
> +	args->blkno = 0;
> +	error = xfs_attr3_leaf_read(args->trans, args->dp,
> +			args->blkno, -1, bp);

Can we please get rid of these -1 and -2 magic values that eventually
become the mappedbno argument to xfs_dabuf_map?

> +	if (error)
> +		return error;
> +
> +	error = xfs_attr3_leaf_lookup_int(*bp, args);
> +	return error;

"return xfs_attr3_leaf_lookup_int..." ?

> +}
> +
> +/*
>   * Remove a name from the leaf attribute list structure
>   *
>   * This leaf block cannot have a "remote" value, we only call this routine
> @@ -806,12 +846,8 @@ xfs_attr_leaf_removename(
>  	 * Remove the attribute.
>  	 */
>  	dp = args->dp;
> -	args->blkno = 0;
> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
> -	if (error)
> -		return error;
>  
> -	error = xfs_attr3_leaf_lookup_int(bp, args);
> +	error = xfs_leaf_has_attr(args, &bp);
>  	if (error == -ENOATTR) {
>  		xfs_trans_brelse(args->trans, bp);
>  		return error;
> @@ -848,12 +884,7 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>  
>  	trace_xfs_attr_leaf_get(args);
>  
> -	args->blkno = 0;
> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
> -	if (error)
> -		return error;
> -
> -	error = xfs_attr3_leaf_lookup_int(bp, args);
> +	error = xfs_leaf_has_attr(args, &bp);
>  	if (error != -EEXIST)  {
>  		xfs_trans_brelse(args->trans, bp);
>  		return error;
> @@ -866,6 +897,43 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>  	return error;
>  }
>  
> +/*
> + * Return EEXIST if attr is found, or ENOATTR if not
> + * statep: If not null is set to point at the found state.  Caller will
> + * 	   be responsible for freeing the state in this case.
> + */
> +STATIC int
> +xfs_attr_node_hasname(
> +	struct xfs_da_args	*args,
> +	struct xfs_da_state	**statep)
> +{
> +	struct xfs_da_state	*state;
> +	struct xfs_inode	*dp;
> +	int			retval, error;
> +
> +	/*
> +	 * Tie a string around our finger to remind us where we are.
> +	 */
> +	dp = args->dp;
> +	state = xfs_da_state_alloc();
> +	state->args = args;
> +	state->mp = dp->i_mount;
> +
> +	/*
> +	 * Search to see if name exists, and get back a pointer to it.
> +	 */
> +	error = xfs_da3_node_lookup_int(state, &retval);
> +	if (error == 0)
> +		error = retval;
> +
> +	if (statep != NULL)
> +		*statep = state;
> +	else
> +		xfs_da_state_free(state);
> +
> +	return error;
> +}
> +
>  /*========================================================================
>   * External routines when attribute list size > geo->blksize
>   *========================================================================*/
> @@ -898,17 +966,14 @@ xfs_attr_node_addname(
>  	dp = args->dp;
>  	mp = dp->i_mount;
>  restart:
> -	state = xfs_da_state_alloc();
> -	state->args = args;
> -	state->mp = mp;
> -
>  	/*
>  	 * Search to see if name already exists, and get back a pointer
>  	 * to where it should go.
>  	 */
> -	error = xfs_da3_node_lookup_int(state, &retval);
> -	if (error)
> +	error = xfs_attr_node_hasname(args, &state);
> +	if (error == -EEXIST)
>  		goto out;
> +
>  	blk = &state->path.blk[ state->path.active-1 ];
>  	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>  	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
> @@ -1113,29 +1178,15 @@ xfs_attr_node_removename(
>  {
>  	struct xfs_da_state	*state;
>  	struct xfs_da_state_blk	*blk;
> -	struct xfs_inode	*dp;
>  	struct xfs_buf		*bp;
>  	int			retval, error, forkoff;
> +	struct xfs_inode	*dp = args->dp;
>  
>  	trace_xfs_attr_node_removename(args);
>  
> -	/*
> -	 * Tie a string around our finger to remind us where we are.
> -	 */
> -	dp = args->dp;
> -	state = xfs_da_state_alloc();
> -	state->args = args;
> -	state->mp = dp->i_mount;
> -
> -	/*
> -	 * Search to see if name exists, and get back a pointer to it.
> -	 */
> -	error = xfs_da3_node_lookup_int(state, &retval);
> -	if (error || (retval != -EEXIST)) {
> -		if (error == 0)
> -			error = retval;
> +	error = xfs_attr_node_hasname(args, &state);
> +	if (error != -EEXIST)
>  		goto out;
> -	}
>  
>  	/*
>  	 * If there is an out-of-line value, de-allocate the blocks.
> @@ -1355,17 +1406,13 @@ xfs_attr_node_get(xfs_da_args_t *args)
>  
>  	trace_xfs_attr_node_get(args);
>  
> -	state = xfs_da_state_alloc();
> -	state->args = args;
> -	state->mp = args->dp->i_mount;
> -
>  	/*
>  	 * Search to see if name exists, and get back a pointer to it.
>  	 */
> -	error = xfs_da3_node_lookup_int(state, &retval);
> -	if (error) {
> +	error = xfs_attr_node_hasname(args, &state);
> +	if (error != -EEXIST) {
>  		retval = error;
> -	} else if (retval == -EEXIST) {
> +	} else {
>  		blk = &state->path.blk[ state->path.active-1 ];
>  		ASSERT(blk->bp != NULL);
>  		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index 0bade83..c082d34 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -170,6 +170,7 @@ int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
>  		 unsigned char *value, int valuelen);
>  int xfs_attr_set_args(struct xfs_da_args *args);
>  int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name);
> +int xfs_has_attr(struct xfs_da_args *args);
>  int xfs_attr_remove_args(struct xfs_da_args *args);
>  int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>  		  int flags, struct attrlist_cursor_kern *cursor);
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index 70eb941..8d2e11f 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -546,6 +546,53 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
>  }
>  
>  /*
> + * Return EEXIST if attr is found, or ENOATTR if not
> + * args:  args containing attribute name and namelen
> + * sfep:  If not null, pointer will be set to the last attr entry found
> + * basep: If not null, pointer is set to the byte offset of the entry in the
> + *	  list
> + */
> +int
> +xfs_shortform_has_attr(
> +	struct xfs_da_args	 *args,
> +	struct xfs_attr_sf_entry **sfep,
> +	int			 *basep)
> +{
> +	struct xfs_attr_shortform *sf;
> +	struct xfs_attr_sf_entry *sfe;
> +	int			base = sizeof(struct xfs_attr_sf_hdr);
> +	int			size = 0;
> +	int			end;
> +	int			i;
> +
> +	base = sizeof(struct xfs_attr_sf_hdr);
> +	sf = (struct xfs_attr_shortform *)args->dp->i_afp->if_u1.if_data;
> +	sfe = &sf->list[0];
> +	end = sf->hdr.count;
> +	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
> +			base += size, i++) {
> +		size = XFS_ATTR_SF_ENTSIZE(sfe);
> +		if (sfe->namelen != args->namelen)
> +			continue;
> +		if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
> +			continue;
> +		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
> +			continue;
> +		break;
> +	}
> +
> +	if (sfep != NULL)
> +		*sfep = sfe;
> +
> +	if (basep != NULL)
> +		*basep = base;
> +
> +	if (i == end)
> +		return -ENOATTR;
> +	return -EEXIST;
> +}
> +
> +/*
>   * Add a name/value pair to the shortform attribute list.
>   * Overflow from the inode has already been checked for.
>   */
> @@ -554,7 +601,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>  {
>  	xfs_attr_shortform_t *sf;
>  	xfs_attr_sf_entry_t *sfe;
> -	int i, offset, size;
> +	int offset, size, error;
>  	xfs_mount_t *mp;
>  	xfs_inode_t *dp;
>  	struct xfs_ifork *ifp;
> @@ -568,18 +615,11 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>  	ifp = dp->i_afp;
>  	ASSERT(ifp->if_flags & XFS_IFINLINE);
>  	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
> -	sfe = &sf->list[0];
> -	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
> +	error = xfs_shortform_has_attr(args, &sfe, NULL);
>  #ifdef DEBUG
> -		if (sfe->namelen != args->namelen)
> -			continue;
> -		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
> -			continue;
> -		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
> -			continue;
> +	if (error == -EEXIST)
>  		ASSERT(0);

ASSERT(error != -EEXIST); ?  Without the #ifdef DEBUG since ASSERT does
nothing if DEBUG isn't defined...

>  #endif
> -	}
>  
>  	offset = (char *)sfe - (char *)sf;
>  	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
> @@ -626,7 +666,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
>  {
>  	xfs_attr_shortform_t *sf;
>  	xfs_attr_sf_entry_t *sfe;
> -	int base, size=0, end, totsize, i;
> +	int base, size = 0, end, totsize, error;
>  	xfs_mount_t *mp;
>  	xfs_inode_t *dp;

Please fix the typedef and indentation here while you're changing this
(and all the other attr) functions.

Otherwise, I very much like this cleanup. :)

--D

>  
> @@ -634,23 +674,13 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
>  
>  	dp = args->dp;
>  	mp = dp->i_mount;
> -	base = sizeof(xfs_attr_sf_hdr_t);
>  	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
> -	sfe = &sf->list[0];
>  	end = sf->hdr.count;
> -	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
> -					base += size, i++) {
> -		size = XFS_ATTR_SF_ENTSIZE(sfe);
> -		if (sfe->namelen != args->namelen)
> -			continue;
> -		if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
> -			continue;
> -		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
> -			continue;
> -		break;
> -	}
> -	if (i == end)
> -		return -ENOATTR;
> +
> +	error = xfs_shortform_has_attr(args, &sfe, &base);
> +	if (error == -ENOATTR)
> +		return error;
> +	size = XFS_ATTR_SF_ENTSIZE(sfe);
>  
>  	/*
>  	 * Fix up the attribute fork data, covering the hole
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
> index 7b74e18..be1f636 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
> @@ -39,6 +39,8 @@ int	xfs_attr_shortform_getvalue(struct xfs_da_args *args);
>  int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
>  			struct xfs_buf **leaf_bp);
>  int	xfs_attr_shortform_remove(struct xfs_da_args *args);
> +int	xfs_shortform_has_attr(struct xfs_da_args *args,
> +			       struct xfs_attr_sf_entry **sfep, int *basep);
>  int	xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
>  int	xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes);
>  xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_inode *ip);
> -- 
> 2.7.4
> 

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

* Re: [PATCH v2 06/18] xfs: Factor out new helper functions xfs_attr_rmtval_set
  2019-08-09 21:37 ` [PATCH v2 06/18] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
@ 2019-08-12 16:01   ` Darrick J. Wong
  2019-08-12 19:29     ` Allison Collins
  0 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2019-08-12 16:01 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Aug 09, 2019 at 02:37:14PM -0700, Allison Collins wrote:
> Break xfs_attr_rmtval_set into two helper functions
> xfs_attr_rmt_find_hole and xfs_attr_rmtval_set_value.
> xfs_attr_rmtval_set rolls the transaction between the
> helpers, but delayed operations cannot.  We will use
> the helpers later when constructing new delayed
> attribute routines.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr_remote.c | 73 +++++++++++++++++++++++++++++++----------
>  fs/xfs/libxfs/xfs_attr_remote.h |  4 ++-
>  2 files changed, 58 insertions(+), 19 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index 4eb30d3..c421412 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -21,6 +21,7 @@
>  #include "xfs_attr.h"
>  #include "xfs_trace.h"
>  #include "xfs_error.h"
> +#include "xfs_attr_remote.h"
>  
>  #define ATTR_RMTVALUE_MAPSIZE	1	/* # of map entries at once */
>  
> @@ -430,34 +431,18 @@ xfs_attr_rmtval_set(
>  	struct xfs_da_args	*args)
>  {
>  	struct xfs_inode	*dp = args->dp;
> -	struct xfs_mount	*mp = dp->i_mount;
>  	struct xfs_bmbt_irec	map;
>  	xfs_dablk_t		lblkno;
>  	xfs_fileoff_t		lfileoff = 0;
> -	uint8_t			*src = args->value;
>  	int			blkcnt;
> -	int			valuelen;
>  	int			nmap;
>  	int			error;
> -	int			offset = 0;
>  
> -	trace_xfs_attr_rmtval_set(args);
> -
> -	/*
> -	 * Find a "hole" in the attribute address space large enough for
> -	 * us to drop the new attribute's value into. Because CRC enable
> -	 * attributes have headers, we can't just do a straight byte to FSB
> -	 * conversion and have to take the header space into account.
> -	 */
> -	blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
> -	error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
> -						   XFS_ATTR_FORK);
> +	error = xfs_attr_rmt_find_hole(args, &blkcnt, &lfileoff);
>  	if (error)
>  		return error;
>  
> -	args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
> -	args->rmtblkcnt = blkcnt;
> -
> +	lblkno = (xfs_dablk_t)lfileoff;
>  	/*
>  	 * Roll through the "value", allocating blocks on disk as required.
>  	 */
> @@ -498,6 +483,58 @@ xfs_attr_rmtval_set(
>  			return error;
>  	}
>  
> +	error = xfs_attr_rmtval_set_value(args);
> +	return error;
> +}
> +
> +
> +

Only need one blank line between functions.

> +int
> +xfs_attr_rmt_find_hole(
> +	struct xfs_da_args	*args,
> +	int			*blkcnt,
> +	xfs_fileoff_t		*lfileoff)
> +{
> +	struct xfs_inode        *dp = args->dp;
> +	struct xfs_mount	*mp = dp->i_mount;
> +	int			error;
> +
> +	trace_xfs_attr_rmtval_set(args);

Shouldn't this be in the xfs_attr_rmtval_set_value function?
We're not actually setting anything here, we're just looking for holes.

> +
> +	/*
> +	 * Find a "hole" in the attribute address space large enough for
> +	 * us to drop the new attribute's value into. Because CRC enable

This first sentence would make a lovely comment above this function
telling us what it does.

> +	 * attributes have headers, we can't just do a straight byte to FSB
> +	 * conversion and have to take the header space into account.
> +	 */
> +	*blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);

Can the callers be refactored to use args->rmtblkcnt to eliminate the
@blkcnt parameter?

--D

> +	error = xfs_bmap_first_unused(args->trans, args->dp, *blkcnt, lfileoff,
> +						   XFS_ATTR_FORK);
> +	if (error)
> +		return error;
> +
> +	args->rmtblkno = (xfs_dablk_t)*lfileoff;
> +	args->rmtblkcnt = *blkcnt;
> +
> +	return 0;
> +}
> +
> +int
> +xfs_attr_rmtval_set_value(
> +	struct xfs_da_args	*args)
> +{
> +	struct xfs_inode	*dp = args->dp;
> +	struct xfs_mount	*mp = dp->i_mount;
> +	struct xfs_bmbt_irec	map;
> +	xfs_dablk_t		lblkno;
> +	uint8_t			*src = args->value;
> +	int			blkcnt;
> +	int			valuelen;
> +	int			nmap;
> +	int			error;
> +	int			offset = 0;
> +
> +
>  	/*
>  	 * Roll through the "value", copying the attribute value to the
>  	 * already-allocated blocks.  Blocks are written synchronously
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> index 9d20b66..2a73cd9 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.h
> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
> @@ -11,5 +11,7 @@ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen);
>  int xfs_attr_rmtval_get(struct xfs_da_args *args);
>  int xfs_attr_rmtval_set(struct xfs_da_args *args);
>  int xfs_attr_rmtval_remove(struct xfs_da_args *args);
> -
> +int xfs_attr_rmtval_set_value(struct xfs_da_args *args);
> +int xfs_attr_rmt_find_hole(struct xfs_da_args *args, int *blkcnt,
> +			   xfs_fileoff_t *lfileoff);
>  #endif /* __XFS_ATTR_REMOTE_H__ */
> -- 
> 2.7.4
> 

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

* Re: [PATCH v2 07/18] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags
  2019-08-09 21:37 ` [PATCH v2 07/18] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags Allison Collins
@ 2019-08-12 16:02   ` Darrick J. Wong
  2019-08-12 16:30     ` Darrick J. Wong
  0 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2019-08-12 16:02 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Aug 09, 2019 at 02:37:15PM -0700, Allison Collins wrote:
> Since delayed operations cannot roll transactions, factor
> up the transaction handling into the calling function
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>

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

--D

> ---
>  fs/xfs/libxfs/xfs_attr.c      | 10 ++++++++++
>  fs/xfs/libxfs/xfs_attr_leaf.c |  5 -----
>  2 files changed, 10 insertions(+), 5 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 72af8e2..f36c792 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -752,6 +752,11 @@ xfs_attr_leaf_addname(
>  		error = xfs_attr3_leaf_flipflags(args);
>  		if (error)
>  			return error;
> +		/*
> +		 * Commit the flag value change and start the next trans in
> +		 * series.
> +		 */
> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>  
>  		/*
>  		 * Dismantle the "old" attribute/value pair by removing
> @@ -1090,6 +1095,11 @@ xfs_attr_node_addname(
>  		error = xfs_attr3_leaf_flipflags(args);
>  		if (error)
>  			goto out;
> +		/*
> +		 * Commit the flag value change and start the next trans in
> +		 * series
> +		 */
> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>  
>  		/*
>  		 * Dismantle the "old" attribute/value pair by removing
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index 8d2e11f..8a6f5df 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -2891,10 +2891,5 @@ xfs_attr3_leaf_flipflags(
>  			 XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt)));
>  	}
>  
> -	/*
> -	 * Commit the flag value change and start the next trans in series.
> -	 */
> -	error = xfs_trans_roll_inode(&args->trans, args->dp);
> -
>  	return error;
>  }
> -- 
> 2.7.4
> 

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

* Re: [PATCH v2 08/18] xfs: Factor out xfs_attr_leaf_addname helper
  2019-08-09 21:37 ` [PATCH v2 08/18] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
@ 2019-08-12 16:06   ` Darrick J. Wong
  2019-08-12 19:37     ` Allison Collins
  0 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2019-08-12 16:06 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Aug 09, 2019 at 02:37:16PM -0700, Allison Collins wrote:
> Factor out new helper function xfs_attr_leaf_try_add.
> Because new delayed attribute routines cannot roll
> transactions, we carve off the parts of
> xfs_attr_leaf_addname that we can use.  This will help
> to reduce repetitive code later when we introduce
> delayed attributes.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 43 +++++++++++++++++++++++++++++--------------
>  1 file changed, 29 insertions(+), 14 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index f36c792..f9d5e28 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -635,19 +635,12 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>   * External routines when attribute list is one block
>   *========================================================================*/
>  
> -/*
> - * Add a name to the leaf attribute list structure
> - *
> - * This leaf block cannot have a "remote" value, we only call this routine
> - * if bmap_one_block() says there is only one block (ie: no remote blks).
> - */
>  STATIC int
> -xfs_attr_leaf_addname(
> -	struct xfs_da_args	*args)
> +xfs_attr_leaf_try_add(
> +	struct xfs_da_args	*args,
> +	struct xfs_buf		*bp)
>  {
> -	struct xfs_buf		*bp;
> -	int			retval, error, forkoff;
> -	struct xfs_inode	*dp = args->dp;
> +	int			retval, error;
>  
>  	trace_xfs_attr_leaf_addname(args);
>  
> @@ -692,13 +685,35 @@ xfs_attr_leaf_addname(
>  	retval = xfs_attr3_leaf_add(bp, args);
>  	if (retval == -ENOSPC) {
>  		/*
> -		 * Promote the attribute list to the Btree format, then
> -		 * Commit that transaction so that the node_addname() call
> -		 * can manage its own transactions.
> +		 * Promote the attribute list to the Btree format,

Why does the sentence end with a comma?

>  		 */
>  		error = xfs_attr3_leaf_to_node(args);
>  		if (error)
>  			return error;
> +	}
> +	return retval;
> +}
> +
> +
> +/*
> + * Add a name to the leaf attribute list structure
> + *
> + * This leaf block cannot have a "remote" value, we only call this routine
> + * if bmap_one_block() says there is only one block (ie: no remote blks).
> + */
> +STATIC int
> +xfs_attr_leaf_addname(struct xfs_da_args	*args)
> +{
> +	int retval, error, forkoff;

Indentation problem here.

--D

> +	struct xfs_buf		*bp = NULL;
> +	struct xfs_inode	*dp = args->dp;
> +
> +	retval = xfs_attr_leaf_try_add(args, bp);
> +	if (retval == -ENOSPC) {
> +		/*
> +		 * Commit that transaction so that the node_addname() call
> +		 * can manage its own transactions.
> +		 */
>  		error = xfs_defer_finish(&args->trans);
>  		if (error)
>  			return error;
> -- 
> 2.7.4
> 

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

* Re: [PATCH v2 09/18] xfs: Factor up commit from xfs_attr_try_sf_addname
  2019-08-09 21:37 ` [PATCH v2 09/18] xfs: Factor up commit from xfs_attr_try_sf_addname Allison Collins
@ 2019-08-12 16:14   ` Darrick J. Wong
  2019-08-12 22:38     ` Allison Collins
  0 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2019-08-12 16:14 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Aug 09, 2019 at 02:37:17PM -0700, Allison Collins wrote:
> New delayed attribute routines cannot handle transactions,
> so factor this up to the calling function.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 15 ++++++++-------
>  1 file changed, 8 insertions(+), 7 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index f9d5e28..6bd87e6 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -196,7 +196,7 @@ xfs_attr_try_sf_addname(
>  {
>  
>  	struct xfs_mount	*mp = dp->i_mount;
> -	int			error, error2;
> +	int			error;
>  
>  	error = xfs_attr_shortform_addname(args);
>  	if (error == -ENOSPC)
> @@ -212,9 +212,7 @@ xfs_attr_try_sf_addname(
>  	if (mp->m_flags & XFS_MOUNT_WSYNC)
>  		xfs_trans_set_sync(args->trans);
>  
> -	error2 = xfs_trans_commit(args->trans);
> -	args->trans = NULL;
> -	return error ? error : error2;
> +	return error;
>  }
>  
>  /*
> @@ -226,7 +224,7 @@ xfs_attr_set_args(
>  {
>  	struct xfs_inode	*dp = args->dp;
>  	struct xfs_buf          *leaf_bp = NULL;
> -	int			error;
> +	int			error, error2 = 0;;
>  
>  	/*
>  	 * If the attribute list is non-existent or a shortform list,
> @@ -246,8 +244,11 @@ xfs_attr_set_args(
>  		 * Try to add the attr to the attribute list in the inode.
>  		 */
>  		error = xfs_attr_try_sf_addname(dp, args);
> -		if (error != -ENOSPC)
> -			return error;
> +		if (error != -ENOSPC) {
> +			error2 = xfs_trans_commit(args->trans);

I've wondered about this weird logic... if xfs_attr_shortform_addname
returns an error code other than ENOSPC, why would we commit the
transaction?  Usually we let the error code bounce up to whomever
allocated the transaction and let them cancel it.

Hmm, looking around some more, I guess xfs_attr_shortform_remove can
return ENOATTR to _addname and _shortform_lookup can return EEXIST, but
with either of those error codes, the transaction isn't dirty so it's
not like we're committing garbage state into the filesystem...?

--D

> +			args->trans = NULL;
> +			return error ? error : error2;
> +		}
>  
>  		/*
>  		 * It won't fit in the shortform, transform to a leaf block.
> -- 
> 2.7.4
> 

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

* Re: [PATCH v2 10/18] xfs: Factor up trans roll from xfs_attr3_leaf_setflag
  2019-08-09 21:37 ` [PATCH v2 10/18] xfs: Factor up trans roll from xfs_attr3_leaf_setflag Allison Collins
@ 2019-08-12 16:14   ` Darrick J. Wong
  2019-08-12 22:38     ` Allison Collins
  0 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2019-08-12 16:14 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Aug 09, 2019 at 02:37:18PM -0700, Allison Collins wrote:
> New delayed allocation routines cannot be handling
> transactions so factor them up into the calling functions
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>

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

--D

> ---
>  fs/xfs/libxfs/xfs_attr.c      | 5 +++++
>  fs/xfs/libxfs/xfs_attr_leaf.c | 5 +----
>  2 files changed, 6 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 6bd87e6..7648ceb 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -1239,6 +1239,11 @@ xfs_attr_node_removename(
>  		error = xfs_attr3_leaf_setflag(args);
>  		if (error)
>  			goto out;
> +
> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
> +		if (error)
> +			goto out;
> +
>  		error = xfs_attr_rmtval_remove(args);
>  		if (error)
>  			goto out;
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index 8a6f5df..4a22ced 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -2773,10 +2773,7 @@ xfs_attr3_leaf_setflag(
>  			 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
>  	}
>  
> -	/*
> -	 * Commit the flag value change and start the next trans in series.
> -	 */
> -	return xfs_trans_roll_inode(&args->trans, args->dp);
> +	return error;
>  }
>  
>  /*
> -- 
> 2.7.4
> 

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

* Re: [PATCH v2 11/18] xfs: Add xfs_attr3_leaf helper functions
  2019-08-09 21:37 ` [PATCH v2 11/18] xfs: Add xfs_attr3_leaf helper functions Allison Collins
@ 2019-08-12 16:22   ` Darrick J. Wong
  2019-08-12 22:38     ` Allison Collins
  0 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2019-08-12 16:22 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Aug 09, 2019 at 02:37:19PM -0700, Allison Collins wrote:
> And new helper functions xfs_attr3_leaf_flag_is_set and
> xfs_attr3_leaf_flagsflipped.  These routines check to see
> if xfs_attr3_leaf_setflag or xfs_attr3_leaf_flipflags have
> already been run.  We will need this later for delayed
> attributes since routines may be recalled several times
> when -EAGAIN is returned.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr_leaf.c | 78 +++++++++++++++++++++++++++++++++++++++++++
>  fs/xfs/libxfs/xfs_attr_leaf.h |  2 ++
>  2 files changed, 80 insertions(+)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index 4a22ced..b2d5f62 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -2729,6 +2729,34 @@ xfs_attr3_leaf_clearflag(
>  }
>  
>  /*
> + * Check if the INCOMPLETE flag on an entry in a leaf block is set.
> + */
> +int
> +xfs_attr3_leaf_flag_is_set(
> +	struct xfs_da_args		*args)

<urk> Please don't conflate error codes and a boolean predicate.  It
would be way too easy to do:

if (xfs_attr3_leaf_flag_is_set(&args)) {
	/* launch the nuculur missiles */
}

because there was a disk error and xfs_attr3_leaf_read fed us -EIO.
Either make the callers do the _read and pass the bp to this predicate,
or add a "bool *isset" outparam.

Second potential failure case:

error = xfs_attr3_leaf_flag_is_set(&args);
if (error) {
	/* bury all the whatever */
}

Wherein everything was actually fine, but instead someone incorrectly
freaked out and that's why my neighbors were running chainsaws at 11pm
last night.

> +{
> +	struct xfs_attr_leafblock	*leaf;
> +	struct xfs_attr_leaf_entry	*entry;
> +	struct xfs_buf			*bp;
> +	struct xfs_inode		*dp = args->dp;
> +	int				error = 0;
> +
> +	trace_xfs_attr_leaf_setflag(args);
> +
> +	/*
> +	 * Set up the operation.
> +	 */
> +	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno, -1, &bp);
> +	if (error)
> +		return error;
> +
> +	leaf = bp->b_addr;
> +	entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
> +
> +	return ((entry->flags & XFS_ATTR_INCOMPLETE) != 0);
> +}
> +
> +/*
>   * Set the INCOMPLETE flag on an entry in a leaf block.
>   */
>  int
> @@ -2890,3 +2918,53 @@ xfs_attr3_leaf_flipflags(
>  
>  	return error;
>  }
> +
> +/*
> + * On a leaf entry, check to see if the INCOMPLETE flag is cleared
> + * in args->blkno/index and set in args->blkno2/index2.
> + *
> + * Note that they could be in different blocks, or in the same block.
> + */
> +int
> +xfs_attr3_leaf_flagsflipped(
> +	struct xfs_da_args		*args)
> +{
> +	struct xfs_attr_leafblock	*leaf1;
> +	struct xfs_attr_leafblock	*leaf2;
> +	struct xfs_attr_leaf_entry	*entry1;
> +	struct xfs_attr_leaf_entry	*entry2;
> +	struct xfs_buf			*bp1;
> +	struct xfs_buf			*bp2;
> +	struct xfs_inode		*dp = args->dp;
> +	int				error = 0;
> +
> +	trace_xfs_attr_leaf_flipflags(args);
> +
> +	/*
> +	 * Read the block containing the "old" attr
> +	 */
> +	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno, -1, &bp1);
> +	if (error)
> +		return error;
> +
> +	/*
> +	 * Read the block containing the "new" attr, if it is different
> +	 */
> +	if (args->blkno2 != args->blkno) {
> +		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno2,
> +					   -1, &bp2);
> +		if (error)
> +			return error;
> +	} else {
> +		bp2 = bp1;
> +	}
> +
> +	leaf1 = bp1->b_addr;
> +	entry1 = &xfs_attr3_leaf_entryp(leaf1)[args->index];
> +
> +	leaf2 = bp2->b_addr;
> +	entry2 = &xfs_attr3_leaf_entryp(leaf2)[args->index2];
> +
> +	return (((entry1->flags & XFS_ATTR_INCOMPLETE) == 0) &&
> +		 (entry2->flags & XFS_ATTR_INCOMPLETE));

Same complaint here.

--D

> +}
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
> index be1f636..d6afe23 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
> @@ -54,7 +54,9 @@ int	xfs_attr3_leaf_to_shortform(struct xfs_buf *bp,
>  				   struct xfs_da_args *args, int forkoff);
>  int	xfs_attr3_leaf_clearflag(struct xfs_da_args *args);
>  int	xfs_attr3_leaf_setflag(struct xfs_da_args *args);
> +int	xfs_attr3_leaf_flag_is_set(struct xfs_da_args *args);
>  int	xfs_attr3_leaf_flipflags(struct xfs_da_args *args);
> +int	xfs_attr3_leaf_flagsflipped(struct xfs_da_args *args);
>  
>  /*
>   * Routines used for growing the Btree.
> -- 
> 2.7.4
> 

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

* Re: [PATCH v2 12/18] xfs: Factor out xfs_attr_rmtval_remove_value
  2019-08-09 21:37 ` [PATCH v2 12/18] xfs: Factor out xfs_attr_rmtval_remove_value Allison Collins
@ 2019-08-12 16:27   ` Darrick J. Wong
  2019-08-12 22:39     ` Allison Collins
  0 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2019-08-12 16:27 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Aug 09, 2019 at 02:37:20PM -0700, Allison Collins wrote:
> Because new delayed attribute routines cannot roll
> transactions, we carve off the parts of
> xfs_attr_rmtval_remove that we can use.  This will help to
> reduce repetitive code later when we introduce delayed
> attributes.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr_remote.c | 25 +++++++++++++++++++------
>  fs/xfs/libxfs/xfs_attr_remote.h |  1 +
>  2 files changed, 20 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index c421412..f030365 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -586,19 +586,14 @@ xfs_attr_rmtval_set_value(
>  	return 0;
>  }
>  
> -/*
> - * Remove the value associated with an attribute by deleting the
> - * out-of-line buffer that it is stored on.
> - */
>  int
> -xfs_attr_rmtval_remove(
> +xfs_attr_rmtval_remove_value(

This function invalidates the incore buffers, right?  Since _remove
below still does the actual bunmapi work to unmap blocks from the attr
fork?  Would this be better named xfs_attr_rmtval_invalidate()?

>  	struct xfs_da_args	*args)
>  {
>  	struct xfs_mount	*mp = args->dp->i_mount;
>  	xfs_dablk_t		lblkno;
>  	int			blkcnt;
>  	int			error;
> -	int			done;
>  
>  	trace_xfs_attr_rmtval_remove(args);

Leave this in xfs_attr_rmtval_remove.

--D

>  
> @@ -642,7 +637,25 @@ xfs_attr_rmtval_remove(
>  		lblkno += map.br_blockcount;
>  		blkcnt -= map.br_blockcount;
>  	}
> +	return 0;
> +}
>  
> +/*
> + * Remove the value associated with an attribute by deleting the
> + * out-of-line buffer that it is stored on.
> + */
> +int
> +xfs_attr_rmtval_remove(
> +	struct xfs_da_args      *args)
> +{
> +	xfs_dablk_t		lblkno;
> +	int			blkcnt;
> +	int			error = 0;
> +	int			done = 0;
> +
> +	error = xfs_attr_rmtval_remove_value(args);
> +	if (error)
> +		return error;
>  	/*
>  	 * Keep de-allocating extents until the remote-value region is gone.
>  	 */
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> index 2a73cd9..9a58a23 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.h
> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
> @@ -11,6 +11,7 @@ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen);
>  int xfs_attr_rmtval_get(struct xfs_da_args *args);
>  int xfs_attr_rmtval_set(struct xfs_da_args *args);
>  int xfs_attr_rmtval_remove(struct xfs_da_args *args);
> +int xfs_attr_rmtval_remove_value(struct xfs_da_args *args);
>  int xfs_attr_rmtval_set_value(struct xfs_da_args *args);
>  int xfs_attr_rmt_find_hole(struct xfs_da_args *args, int *blkcnt,
>  			   xfs_fileoff_t *lfileoff);
> -- 
> 2.7.4
> 

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

* Re: [PATCH v2 13/18] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag
  2019-08-09 21:37 ` [PATCH v2 13/18] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag Allison Collins
@ 2019-08-12 16:28   ` Darrick J. Wong
  2019-08-12 22:39     ` Allison Collins
  0 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2019-08-12 16:28 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Aug 09, 2019 at 02:37:21PM -0700, Allison Collins wrote:
> New delayed allocation routines cannot be handling
> transactions so factor them up into the calling functions
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c      | 12 ++++++++++++
>  fs/xfs/libxfs/xfs_attr_leaf.c |  5 +----
>  2 files changed, 13 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 7648ceb..ca57202 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -823,6 +823,12 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
>  		 * Added a "remote" value, just clear the incomplete flag.
>  		 */
>  		error = xfs_attr3_leaf_clearflag(args);
> +
> +		/*
> +		 * Commit the flag value change and start the next trans in
> +		 * series.
> +		 */
> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>  	}
>  	return error;
>  }
> @@ -1180,6 +1186,12 @@ xfs_attr_node_addname(
>  		error = xfs_attr3_leaf_clearflag(args);
>  		if (error)
>  			goto out;
> +
> +		 /*
> +		  * Commit the flag value change and start the next trans in
> +		  * series.
> +		  */
> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>  	}
>  	retval = error = 0;

Doesn't this cause us to lose the error code from the roll_inode above?

--D

>  
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index b2d5f62..e3604b9 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -2722,10 +2722,7 @@ xfs_attr3_leaf_clearflag(
>  			 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
>  	}
>  
> -	/*
> -	 * Commit the flag value change and start the next trans in series.
> -	 */
> -	return xfs_trans_roll_inode(&args->trans, args->dp);
> +	return error;
>  }
>  
>  /*
> -- 
> 2.7.4
> 

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

* Re: [PATCH v2 07/18] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags
  2019-08-12 16:02   ` Darrick J. Wong
@ 2019-08-12 16:30     ` Darrick J. Wong
  2019-08-12 19:31       ` Allison Collins
  0 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2019-08-12 16:30 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Mon, Aug 12, 2019 at 09:02:52AM -0700, Darrick J. Wong wrote:
> On Fri, Aug 09, 2019 at 02:37:15PM -0700, Allison Collins wrote:
> > Since delayed operations cannot roll transactions, factor
> > up the transaction handling into the calling function
> > 
> > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> 
> Looks ok,
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

No, not ok!

> > ---
> >  fs/xfs/libxfs/xfs_attr.c      | 10 ++++++++++
> >  fs/xfs/libxfs/xfs_attr_leaf.c |  5 -----
> >  2 files changed, 10 insertions(+), 5 deletions(-)
> > 
> > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > index 72af8e2..f36c792 100644
> > --- a/fs/xfs/libxfs/xfs_attr.c
> > +++ b/fs/xfs/libxfs/xfs_attr.c
> > @@ -752,6 +752,11 @@ xfs_attr_leaf_addname(
> >  		error = xfs_attr3_leaf_flipflags(args);
> >  		if (error)
> >  			return error;
> > +		/*
> > +		 * Commit the flag value change and start the next trans in
> > +		 * series.
> > +		 */
> > +		error = xfs_trans_roll_inode(&args->trans, args->dp);

Lost error value here!

> >  
> >  		/*
> >  		 * Dismantle the "old" attribute/value pair by removing
> > @@ -1090,6 +1095,11 @@ xfs_attr_node_addname(
> >  		error = xfs_attr3_leaf_flipflags(args);
> >  		if (error)
> >  			goto out;
> > +		/*
> > +		 * Commit the flag value change and start the next trans in
> > +		 * series
> > +		 */
> > +		error = xfs_trans_roll_inode(&args->trans, args->dp);

And here!

--D

> >  
> >  		/*
> >  		 * Dismantle the "old" attribute/value pair by removing
> > diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> > index 8d2e11f..8a6f5df 100644
> > --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> > +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> > @@ -2891,10 +2891,5 @@ xfs_attr3_leaf_flipflags(
> >  			 XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt)));
> >  	}
> >  
> > -	/*
> > -	 * Commit the flag value change and start the next trans in series.
> > -	 */
> > -	error = xfs_trans_roll_inode(&args->trans, args->dp);
> > -
> >  	return error;
> >  }
> > -- 
> > 2.7.4
> > 

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

* Re: [PATCH v2 17/18] xfs: Enable delayed attributes
  2019-08-09 21:37 ` [PATCH v2 17/18] xfs: Enable delayed attributes Allison Collins
@ 2019-08-12 16:42   ` Darrick J. Wong
  2019-08-12 22:39     ` Allison Collins
  0 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2019-08-12 16:42 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Aug 09, 2019 at 02:37:25PM -0700, Allison Collins wrote:
> Finally enable delayed attributes in xfs_attr_set and
> xfs_attr_remove.  We only do this for v4 and up since we
> cant add new log entries to old fs versions

...you can't add new log item types to *existing* fs versions, which
includes everything through present-day v5.

This needs a separate feature bit somewhere to prevent existing xfs
drivers from crashing and burning on attri/attrd items.  Most of this
deferred attr code could exist independently from the parent pointer
feature, so I guess you could be the first person to use one of the log
incompat feature bits?  That would be one way to get wider testing of
deferred attrs while we work on parent pointers.

--D

> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 26 ++++++++++++++++++++++++--
>  1 file changed, 24 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 9931e50..7023734 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -506,6 +506,7 @@ xfs_attr_set(
>  	int			valuelen)
>  {
>  	struct xfs_mount	*mp = dp->i_mount;
> +	struct xfs_sb		*sbp = &mp->m_sb;
>  	struct xfs_da_args	args;
>  	struct xfs_trans_res	tres;
>  	int			rsvd = (name->type & ATTR_ROOT) != 0;
> @@ -564,7 +565,20 @@ xfs_attr_set(
>  		goto out_trans_cancel;
>  
>  	xfs_trans_ijoin(args.trans, dp, 0);
> -	error = xfs_attr_set_args(&args);
> +	if (XFS_SB_VERSION_NUM(sbp) < XFS_SB_VERSION_4)
> +		error = xfs_attr_set_args(&args);
> +	else {
> +		error = xfs_has_attr(&args);
> +
> +		if (error == -EEXIST && (name->type & ATTR_CREATE))
> +			goto out_trans_cancel;
> +
> +		if (error == -ENOATTR && (name->type & ATTR_REPLACE))
> +			goto out_trans_cancel;
> +
> +		error = xfs_attr_set_deferred(dp, args.trans, name, value,
> +					      valuelen);
> +	}
>  	if (error)
>  		goto out_trans_cancel;
>  	if (!args.trans) {
> @@ -649,6 +663,7 @@ xfs_attr_remove(
>  	struct xfs_name		*name)
>  {
>  	struct xfs_mount	*mp = dp->i_mount;
> +	struct xfs_sb		*sbp = &mp->m_sb;
>  	struct xfs_da_args	args;
>  	int			error;
>  
> @@ -690,7 +705,14 @@ xfs_attr_remove(
>  	 */
>  	xfs_trans_ijoin(args.trans, dp, 0);
>  
> -	error = xfs_attr_remove_args(&args);
> +	error = xfs_has_attr(&args);
> +	if (error == -ENOATTR)
> +		goto out;
> +
> +	if (XFS_SB_VERSION_NUM(sbp) < XFS_SB_VERSION_4)
> +		error = xfs_attr_remove_args(&args);
> +	else
> +		error = xfs_attr_remove_deferred(dp, args.trans, name);
>  	if (error)
>  		goto out;
>  
> -- 
> 2.7.4
> 

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

* Re: [PATCH v2 18/18] xfs: Add delayed attributes error tag
  2019-08-09 21:37 ` [PATCH v2 18/18] xfs: Add delayed attributes error tag Allison Collins
@ 2019-08-12 16:51   ` Darrick J. Wong
  0 siblings, 0 replies; 56+ messages in thread
From: Darrick J. Wong @ 2019-08-12 16:51 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Aug 09, 2019 at 02:37:26PM -0700, Allison Collins wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> This patch adds an error tag that we can use to test
> delayed attribute recovery and replay
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>

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

--D

> ---
>  fs/xfs/libxfs/xfs_errortag.h | 4 +++-
>  fs/xfs/xfs_attr_item.c       | 8 ++++++++
>  fs/xfs/xfs_error.c           | 3 +++
>  3 files changed, 14 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_errortag.h b/fs/xfs/libxfs/xfs_errortag.h
> index 79e6c4f..85d5850 100644
> --- a/fs/xfs/libxfs/xfs_errortag.h
> +++ b/fs/xfs/libxfs/xfs_errortag.h
> @@ -55,7 +55,8 @@
>  #define XFS_ERRTAG_FORCE_SCRUB_REPAIR			32
>  #define XFS_ERRTAG_FORCE_SUMMARY_RECALC			33
>  #define XFS_ERRTAG_IUNLINK_FALLBACK			34
> -#define XFS_ERRTAG_MAX					35
> +#define XFS_ERRTAG_DELAYED_ATTR				35
> +#define XFS_ERRTAG_MAX					36
>  
>  /*
>   * Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
> @@ -95,5 +96,6 @@
>  #define XFS_RANDOM_FORCE_SCRUB_REPAIR			1
>  #define XFS_RANDOM_FORCE_SUMMARY_RECALC			1
>  #define XFS_RANDOM_IUNLINK_FALLBACK			(XFS_RANDOM_DEFAULT/10)
> +#define XFS_RANDOM_DELAYED_ATTR				1
>  
>  #endif /* __XFS_ERRORTAG_H_ */
> diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
> index 6693880..045d23a 100644
> --- a/fs/xfs/xfs_attr_item.c
> +++ b/fs/xfs/xfs_attr_item.c
> @@ -33,6 +33,8 @@
>  #include "libxfs/xfs_da_format.h"
>  #include "xfs_inode.h"
>  #include "xfs_quota.h"
> +#include "xfs_error.h"
> +#include "xfs_errortag.h"
>  
>  
>  /*
> @@ -74,6 +76,11 @@ xfs_trans_attr(
>  	if (error)
>  		return error;
>  
> +	if (XFS_TEST_ERROR(false, args->dp->i_mount, XFS_ERRTAG_DELAYED_ATTR)) {
> +		error = -EIO;
> +		goto out;
> +	}
> +
>  	switch (op_flags) {
>  	case XFS_ATTR_OP_FLAGS_SET:
>  		args->op_flags |= XFS_DA_OP_ADDNAME;
> @@ -87,6 +94,7 @@ xfs_trans_attr(
>  		error = -EFSCORRUPTED;
>  	}
>  
> +out:
>  	/*
>  	 * Mark the transaction dirty, even on error. This ensures the
>  	 * transaction is aborted, which:
> diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
> index 544c948..9b2de63 100644
> --- a/fs/xfs/xfs_error.c
> +++ b/fs/xfs/xfs_error.c
> @@ -53,6 +53,7 @@ static unsigned int xfs_errortag_random_default[] = {
>  	XFS_RANDOM_FORCE_SCRUB_REPAIR,
>  	XFS_RANDOM_FORCE_SUMMARY_RECALC,
>  	XFS_RANDOM_IUNLINK_FALLBACK,
> +	XFS_RANDOM_DELAYED_ATTR,
>  };
>  
>  struct xfs_errortag_attr {
> @@ -162,6 +163,7 @@ XFS_ERRORTAG_ATTR_RW(buf_lru_ref,	XFS_ERRTAG_BUF_LRU_REF);
>  XFS_ERRORTAG_ATTR_RW(force_repair,	XFS_ERRTAG_FORCE_SCRUB_REPAIR);
>  XFS_ERRORTAG_ATTR_RW(bad_summary,	XFS_ERRTAG_FORCE_SUMMARY_RECALC);
>  XFS_ERRORTAG_ATTR_RW(iunlink_fallback,	XFS_ERRTAG_IUNLINK_FALLBACK);
> +XFS_ERRORTAG_ATTR_RW(delayed_attr,	XFS_ERRTAG_DELAYED_ATTR);
>  
>  static struct attribute *xfs_errortag_attrs[] = {
>  	XFS_ERRORTAG_ATTR_LIST(noerror),
> @@ -199,6 +201,7 @@ static struct attribute *xfs_errortag_attrs[] = {
>  	XFS_ERRORTAG_ATTR_LIST(force_repair),
>  	XFS_ERRORTAG_ATTR_LIST(bad_summary),
>  	XFS_ERRORTAG_ATTR_LIST(iunlink_fallback),
> +	XFS_ERRORTAG_ATTR_LIST(delayed_attr),
>  	NULL,
>  };
>  
> -- 
> 2.7.4
> 

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

* Re: [PATCH v2 15/18] xfs: Add delayed attribute routines
  2019-08-09 21:37 ` [PATCH v2 15/18] xfs: Add delayed attribute routines Allison Collins
@ 2019-08-12 17:29   ` Darrick J. Wong
  2019-08-13  2:19     ` Allison Collins
  0 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2019-08-12 17:29 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Aug 09, 2019 at 02:37:23PM -0700, Allison Collins wrote:
> This patch adds new delayed attribute routines:
> 
> xfs_attr_da_set_args
> xfs_attr_da_remove_args
> xfs_attr_da_leaf_addname
> xfs_attr_da_node_addname
> xfs_attr_da_node_removename

I think the "_da_" thing is shorthand for "deferred attr", right?

If so, it's way too close to the other "_da_" (which is shorthand for
"directory/attr") for my taste.

xfs_attr_set_later()
xfs_attr_remove_later()
xfs_leaf_addname_later()
xfs_node_addname_later()
xfs_node_remove_later() ?

> These routines are similar to their existing counter parts,
> but they do not roll or commit transactions.  They instead
> return -EGAIN to allow the calling function to roll the

EAGAIN...

> transaction and recall the function.  This allows the
> attribute operations to be logged in multiple smaller
> transactions.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 720 +++++++++++++++++++++++++++++++++++++++++++++++
>  fs/xfs/libxfs/xfs_attr.h |   2 +
>  2 files changed, 722 insertions(+)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index ca57202..9931e50 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -47,6 +47,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>   */
>  STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
>  STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
> +STATIC int xfs_attr_da_leaf_addname(xfs_da_args_t *args);
>  STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>  STATIC int xfs_leaf_has_attr(xfs_da_args_t *args, struct xfs_buf **bp);         
>  
> @@ -55,12 +56,16 @@ STATIC int xfs_leaf_has_attr(xfs_da_args_t *args, struct xfs_buf **bp);
>   */
>  STATIC int xfs_attr_node_get(xfs_da_args_t *args);
>  STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
> +STATIC int xfs_attr_da_node_addname(xfs_da_args_t *args);
>  STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
> +STATIC int xfs_attr_da_node_removename(xfs_da_args_t *args);
>  STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
>  				 struct xfs_da_state **state);
>  STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>  STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>  
> +STATIC int
> +xfs_attr_leaf_try_add(struct xfs_da_args *args, struct xfs_buf *bp);

STATIC int xfs_attr_leaf_try_add(...)

(no newline between the return type and the function name)

>  
>  int
>  xfs_attr_args_init(

<snip>

> +STATIC int
> +xfs_attr_da_leaf_addname(
> +	struct xfs_da_args	*args)
> +{
> +	int			error, forkoff, nmap;
> +	struct xfs_buf		*bp = NULL;
> +	struct xfs_inode	*dp = args->dp;
> +	struct xfs_bmbt_irec	*map = &args->dc.map;

<snip>

> +	/*
> +	 * If this is an atomic rename operation, we must "flip" the
> +	 * incomplete flags on the "new" and "old" attribute/value pairs
> +	 * so that one disappears and one appears atomically.  Then we
> +	 * must remove the "old" attribute/value pair.
> +	 */
> +	if (args->op_flags & XFS_DA_OP_RENAME) {
> +		/*
> +		 * In a separate transaction, set the incomplete flag on the
> +		 * "old" attr and clear the incomplete flag on the "new" attr.

Echoing Christoph, can this new attr implementation set the attr value
through the log so we can get rid of the INCOMPLETE flag switcheroo
business?  I see a lot of nearly duplicated code and if we're going to
have to support having two paths through the attr set/remove code, we
could at least avoid the weird warts of the old path when designing the
new one.

<snip more>

> +STATIC int
> +xfs_attr_da_node_removename(
> +	struct xfs_da_args	*args)
> +{
> +	struct xfs_da_state	*state = NULL;
> +	struct xfs_da_state_blk	*blk;
> +	struct xfs_buf		*bp;
> +	int			error, forkoff, retval = 0;
> +	struct xfs_inode	*dp = args->dp;
> +	int			done = 0;
> +
> +	trace_xfs_attr_node_removename(args);
> +
> +	if (args->dc.state == NULL) {
> +		error = xfs_attr_node_hasname(args, &args->dc.state);
> +		if (error != -EEXIST)
> +			goto out;
> +		else
> +			error = 0;
> +
> +		/*
> +		 * If there is an out-of-line value, de-allocate the blocks.
> +		 * This is done before we remove the attribute so that we don't
> +		 * overflow the maximum size of a transaction and/or hit a
> +		 * deadlock.
> +		 */
> +		state = args->dc.state;
> +		args->dc.blk = &state->path.blk[state->path.active - 1];
> +		ASSERT(args->dc.blk->bp != NULL);
> +		ASSERT(args->dc.blk->magic == XFS_ATTR_LEAF_MAGIC);
> +	}
> +	state = args->dc.state;
> +	blk = args->dc.blk;
> +
> +	if (args->rmtblkno > 0 && !(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
> +		if (!xfs_attr3_leaf_flag_is_set(args)) {
> +			/*
> +			 * Fill in disk block numbers in the state structure
> +			 * so that we can get the buffers back after we commit
> +			 * several transactions in the following calls.
> +			 */
> +			error = xfs_attr_fillstate(state);
> +			if (error)
> +				goto out;
> +
> +			/*
> +			 * Mark the attribute as INCOMPLETE, then bunmapi() the
> +			 * remote value.
> +			 */
> +			error = xfs_attr3_leaf_setflag(args);
> +			if (error)
> +				goto out;
> +
> +			return -EAGAIN;
> +		}
> +
> +		if (!(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
> +			error = xfs_attr_rmtval_remove_value(args);
> +			if (error)
> +				goto out;
> +		}
> +
> +		args->dc.flags |= XFS_DC_RM_NODE_BLKS;

This ought to be set in the if clause above...

> +		while (!done && !error) {
> +			error = xfs_bunmapi(args->trans, args->dp,
> +				    args->rmtblkno, args->rmtblkcnt,
> +				    XFS_BMAPI_ATTRFORK, 1, &done);
> +			if (error)
> +				return error;
> +
> +			if (!done)
> +				return -EAGAIN;
> +		}

Probably worth a comment to make it a little clearer that this is the
bottom part of xfs_attr_rmtval_remove but open-coded for this case.

I wish this new attr path could share more code with the old one,
though I dunno, probably you've already done that analysis and decided
that cutting this up into ~30 tiny functions isn't worth it...?

(Yeah, snip all the way to the end because I need to go rest my eyes for
a bit but didn't want to delay this reply further.)

--D

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

* Re: [PATCH v2 00/18] Delayed Attributes
  2019-08-12  8:19 ` [PATCH v2 00/18] Delayed Attributes Christoph Hellwig
@ 2019-08-12 19:26   ` Allison Collins
  0 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-12 19:26 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: linux-xfs

On 8/12/19 1:19 AM, Christoph Hellwig wrote:
> Btw, this seems like the right series to also look into our problem
> that large attributes are not updated transactionally.  We just do
> a synchronous write (xfs_bwrite) for them but don't include them
> in the transaction.  With the deferred operations and rolled
> transactions that should be fairly easy to fix.
> 
Ah, alrighty then.  I will add that into the cover letter next time as
another possible use case for it.  :-)

Thx!
Allison

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

* Re: [PATCH v2 02/18] xfs: Replace attribute parameters with struct xfs_name
  2019-08-12 15:13   ` Darrick J. Wong
@ 2019-08-12 19:27     ` Allison Collins
  0 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-12 19:27 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 8/12/19 8:13 AM, Darrick J. Wong wrote:
> On Fri, Aug 09, 2019 at 02:37:10PM -0700, Allison Collins wrote:
>> This patch replaces the attribute name, length and flags parameters with a
>> single struct xfs_name parameter.  This helps to clean up the numbers of
>> parameters being passed around and pre-simplifies the code some.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 40 ++++++++++++++++------------------------
>>   fs/xfs/libxfs/xfs_attr.h | 12 +++++-------
>>   fs/xfs/xfs_acl.c         | 26 +++++++++++++-------------
>>   fs/xfs/xfs_ioctl.c       | 26 ++++++++++++++++----------
>>   fs/xfs/xfs_iops.c        | 10 ++++++----
>>   fs/xfs/xfs_xattr.c       | 21 +++++++++------------
>>   6 files changed, 65 insertions(+), 70 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 7761925..0c91116 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -61,9 +61,7 @@ STATIC int
>>   xfs_attr_args_init(
>>   	struct xfs_da_args	*args,
>>   	struct xfs_inode	*dp,
>> -	const unsigned char	*name,
>> -	size_t			namelen,
>> -	int			flags)
>> +	struct xfs_name		*name)
>>   {
>>   
>>   	if (!name)
>> @@ -73,9 +71,9 @@ xfs_attr_args_init(
>>   	args->geo = dp->i_mount->m_attr_geo;
>>   	args->whichfork = XFS_ATTR_FORK;
>>   	args->dp = dp;
>> -	args->flags = flags;
>> -	args->name = name;
>> -	args->namelen = namelen;
>> +	args->flags = name->type;
>> +	args->name = name->name;
>> +	args->namelen = name->len;
> 
> /me wonders if you ought to just have an xfs_name embedded in the
> xfs_da_args struct, seeing as the directory code uses it too.
> 
Sure, that seems reasonable

>>   	if (args->namelen >= MAXNAMELEN)
>>   		return -EFAULT;		/* match IRIX behaviour */
>>   
> 
> <skipping a bunch of changes that look fine to me>
> 
>> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
>> index b1b7b1b..bdf925c 100644
>> --- a/fs/xfs/xfs_iops.c
>> +++ b/fs/xfs/xfs_iops.c
>> @@ -46,13 +46,15 @@ xfs_initxattrs(
>>   {
>>   	const struct xattr	*xattr;
>>   	struct xfs_inode	*ip = XFS_I(inode);
>> +	struct xfs_name		name;
>>   	int			error = 0;
>>   
>>   	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
>> -		error = xfs_attr_set(ip, xattr->name,
>> -				     strlen(xattr->name),
>> -				     xattr->value, xattr->value_len,
>> -				     ATTR_SECURE);
>> +		name.name = xattr->name;
>> +		name.len = strlen(xattr->name);
>> +		name.type = ATTR_SECURE;
> 
> You might as well declare and initialize name in the loop body.
Ok, I will pull that down in the loop.

> 
>> +		error = xfs_attr_set(ip, &name,
>> +				     xattr->value, xattr->value_len);
> 
> Does the attr value need a similar structure encapsulation too?

We can add one, though it's not particularly needed.  I had raised a 
similar question in the last review when this was proposed, but value 
isnt a const like name is, and I think people thought the abstraction 
was getting to be a little too much.  I think Dave had suggested using 
the struct xfs_name because it was already here and sort of documents 
what we're passing around, so it was an easy way of cleaning up some of 
the arguments.

> 
>>   		if (error < 0)
>>   			break;
>>   	}
>> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
>> index fe12d11..3c63930 100644
>> --- a/fs/xfs/xfs_xattr.c
>> +++ b/fs/xfs/xfs_xattr.c
>> @@ -20,18 +20,17 @@ static int
>>   xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>>   		struct inode *inode, const char *name, void *value, size_t size)
>>   {
>> -	int xflags = handler->flags;
>>   	struct xfs_inode *ip = XFS_I(inode);
>>   	int error, asize = size;
>> -	size_t namelen = strlen(name);
>> +	struct xfs_name xname = {name, strlen(name), handler->flags};
> 
> I think the preferred format for this is to use the structure field
> names explicity during assignment...
> 
> 	struct xfs_name		xname = {
> 		.name		= name,
> 		.namelen	= strlen(name),
> 		.type		= handler->flags,
> 	};
> 
> Also, please fix the variable/argument declaration indentation style of
> this function to match the rest of xfs. :)
> 
Sure, will do.

Allison

> --D
> 
>>   
>>   	/* Convert Linux syscall to XFS internal ATTR flags */
>>   	if (!size) {
>> -		xflags |= ATTR_KERNOVAL;
>> +		xname.type |= ATTR_KERNOVAL;
>>   		value = NULL;
>>   	}
>>   
>> -	error = xfs_attr_get(ip, name, namelen, value, &asize, xflags);
>> +	error = xfs_attr_get(ip, &xname, value, &asize);
>>   	if (error)
>>   		return error;
>>   	return asize;
>> @@ -64,23 +63,21 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>>   		struct inode *inode, const char *name, const void *value,
>>   		size_t size, int flags)
>>   {
>> -	int			xflags = handler->flags;
>>   	struct xfs_inode	*ip = XFS_I(inode);
>>   	int			error;
>> -	size_t			namelen = strlen(name);
>> +	struct xfs_name		xname = {name, strlen(name), handler->flags};
>>   
>>   	/* Convert Linux syscall to XFS internal ATTR flags */
>>   	if (flags & XATTR_CREATE)
>> -		xflags |= ATTR_CREATE;
>> +		xname.type |= ATTR_CREATE;
>>   	if (flags & XATTR_REPLACE)
>> -		xflags |= ATTR_REPLACE;
>> +		xname.type |= ATTR_REPLACE;
>>   
>>   	if (!value)
>> -		return xfs_attr_remove(ip, name,
>> -				       namelen, xflags);
>> -	error = xfs_attr_set(ip, name, namelen, (void *)value, size, xflags);
>> +		return xfs_attr_remove(ip, &xname);
>> +	error = xfs_attr_set(ip, &xname, (void *)value, size);
>>   	if (!error)
>> -		xfs_forget_acl(inode, name, xflags);
>> +		xfs_forget_acl(inode, name, xname.type);
>>   
>>   	return error;
>>   }
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v2 03/18] xfs: Set up infastructure for deferred attribute operations
  2019-08-12 15:40   ` Darrick J. Wong
@ 2019-08-12 19:28     ` Allison Collins
  0 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-12 19:28 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 8/12/19 8:40 AM, Darrick J. Wong wrote:
> On Fri, Aug 09, 2019 at 02:37:11PM -0700, Allison Collins wrote:
>> From: Allison Henderson <allison.henderson@oracle.com>
>>
>> Currently attributes are modified directly across one or more
>> transactions.  But they are not logged or replayed in the event of
>> an error. The goal of delayed attributes is to enable logging and
>> replaying of attribute operations using the existing delayed
>> operations infrastructure.  This will later enable the attributes
>> to become part of larger multi part operations that also must first
>> be recorded to the log.  This is mostly of interest in the scheme of
>> parent pointers which would need to maintain an attribute containing
>> parent inode information any time an inode is moved, created, or
>> removed.  Parent pointers would then be of interest to any feature
>> that would need to quickly derive an inode path from the mount
>> point.  Online scrub, nfs lookups and fs grow or shrink operations
>> are all features that could take advantage of this.
>>
>> This patch adds two new log item types for setting or removing
>> attributes as deferred operations.  The xfs_attri_log_item logs an
>> intent to set or remove an attribute.  The corresponding
>> xfs_attrd_log_item holds a reference to the xfs_attri_log_item and
>> is freed once the transaction is done.  Both log items use a generic
>> xfs_attr_log_format structure that contains the attribute name,
>> value, flags, inode, and an op_flag that indicates if the operations
>> is a set or remove.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/Makefile                |   2 +-
>>   fs/xfs/libxfs/xfs_attr.c       |   5 +-
>>   fs/xfs/libxfs/xfs_attr.h       |  25 ++
>>   fs/xfs/libxfs/xfs_defer.c      |   1 +
>>   fs/xfs/libxfs/xfs_defer.h      |   3 +
>>   fs/xfs/libxfs/xfs_log_format.h |  44 ++-
>>   fs/xfs/libxfs/xfs_types.h      |   1 +
>>   fs/xfs/xfs_attr_item.c         | 755 +++++++++++++++++++++++++++++++++++++++++
>>   fs/xfs/xfs_attr_item.h         | 102 ++++++
>>   fs/xfs/xfs_log.c               |   4 +
>>   fs/xfs/xfs_log_recover.c       | 174 ++++++++++
>>   fs/xfs/xfs_ondisk.h            |   2 +
>>   fs/xfs/xfs_trans.h             |   4 +-
>>   13 files changed, 1116 insertions(+), 6 deletions(-)
>>
>> diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
>> index 06b68b6..70b4716 100644
>> --- a/fs/xfs/Makefile
>> +++ b/fs/xfs/Makefile
>> @@ -102,6 +102,7 @@ xfs-y				+= xfs_log.o \
>>   				   xfs_bmap_item.o \
>>   				   xfs_buf_item.o \
>>   				   xfs_extfree_item.o \
>> +				   xfs_attr_item.o \
>>   				   xfs_icreate_item.o \
>>   				   xfs_inode_item.o \
>>   				   xfs_refcount_item.o \
>> @@ -109,7 +110,6 @@ xfs-y				+= xfs_log.o \
>>   				   xfs_log_recover.o \
>>   				   xfs_trans_ail.o \
>>   				   xfs_trans_buf.o
>> -
>>   # optional features
>>   xfs-$(CONFIG_XFS_QUOTA)		+= xfs_dquot.o \
>>   				   xfs_dquot_item.o \
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 0c91116..1f76618 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -24,6 +24,7 @@
>>   #include "xfs_quota.h"
>>   #include "xfs_trans_space.h"
>>   #include "xfs_trace.h"
>> +#include "xfs_attr_item.h"
>>   
>>   /*
>>    * xfs_attr.c
>> @@ -57,7 +58,7 @@ STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>>   STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>>   
>>   
>> -STATIC int
>> +int
>>   xfs_attr_args_init(
>>   	struct xfs_da_args	*args,
>>   	struct xfs_inode	*dp,
>> @@ -151,7 +152,7 @@ xfs_attr_get(
>>   /*
>>    * Calculate how many blocks we need for the new attribute,
>>    */
>> -STATIC int
>> +int
>>   xfs_attr_calc_size(
>>   	struct xfs_da_args	*args,
>>   	int			*local)
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index aa7261a..9132d4f 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -78,6 +78,28 @@ typedef struct attrlist_ent {	/* data from attr_list() */
>>   } attrlist_ent_t;
>>   
>>   /*
>> + * List of attrs to commit later.
>> + */
>> +struct xfs_attr_item {
>> +	struct xfs_inode  *xattri_ip;
>> +	uint32_t	  xattri_op_flags;
>> +	void		  *xattri_value;      /* attr value */
>> +	uint32_t	  xattri_value_len;   /* length of value */
>> +	void		  *xattri_name;	      /* attr name */
>> +	uint32_t	  xattri_name_len;    /* length of name */
>> +	uint32_t	  xattri_flags;       /* attr flags */
>> +	struct list_head  xattri_list;
> 
> pahole says you could reduce the size of this header from 64 to 56 bytes
> by grouping all the pointers together and all the uin32_t together.
Alrighty, will do

> 
>> +
>> +	/*
>> +	 * A byte array follows the header containing the file name and
>> +	 * attribute value.
>> +	 */
>> +};
>> +
>> +#define XFS_ATTR_ITEM_SIZEOF(namelen, valuelen)	\
>> +	(sizeof(struct xfs_attr_item) + (namelen) + (valuelen))
>> +
>> +/*
>>    * Given a pointer to the (char*) buffer containing the attr_list() result,
>>    * and an index, return a pointer to the indicated attribute in the buffer.
>>    */
> 
> <skip past things that look ok>
> 
>> diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
>> new file mode 100644
>> index 0000000..2340589
>> --- /dev/null
>> +++ b/fs/xfs/xfs_attr_item.c
>> @@ -0,0 +1,755 @@
>> +// SPDX-License-Identifier: GPL-2.0+
> 
> Sooooo... [redact idiotic spdx drama that I don't care to rehash]
> 
> This means that "GPL-2.0+" is not correct here, it's supposed to be
> "GPL-2.0-or-later" as defined in LICENSES/preferred/GPL-2.0, and Greg KH
> can go fix all the breakage he pushed in the kernel with insufficient
> review.
Oh dear.  Ok then, I'll get that updated

> 
>> +/*
>> + * Copyright (C) 2019 Oracle.  All Rights Reserved.
>> + * Author: Allison Henderson <allison.henderson@oracle.com>
>> + */
>> +
>> +#include "xfs.h"
>> +#include "xfs_fs.h"
>> +#include "xfs_format.h"
>> +#include "xfs_log_format.h"
>> +#include "xfs_trans_resv.h"
>> +#include "xfs_bit.h"
>> +#include "xfs_shared.h"
>> +#include "xfs_mount.h"
>> +#include "xfs_defer.h"
>> +#include "xfs_trans.h"
>> +#include "xfs_trans_priv.h"
>> +#include "xfs_buf_item.h"
>> +#include "xfs_attr_item.h"
>> +#include "xfs_log.h"
>> +#include "xfs_btree.h"
>> +#include "xfs_rmap.h"
>> +#include "xfs_inode.h"
>> +#include "xfs_icache.h"
>> +#include "xfs_attr.h"
>> +#include "xfs_da_format.h"
>> +#include "xfs_da_btree.h"
>> +#include "xfs_shared.h"
>> +#include "xfs_attr_item.h"
>> +#include "xfs_alloc.h"
>> +#include "xfs_bmap.h"
>> +#include "xfs_trace.h"
>> +#include "libxfs/xfs_da_format.h"
>> +#include "xfs_inode.h"
>> +#include "xfs_quota.h"
>> +
>> +
>> +/*
>> + * This routine is called to allocate an "attr free done" log item.
>> + */
>> +struct xfs_attrd_log_item *
>> +xfs_trans_get_attrd(struct xfs_trans		*tp,
>> +		  struct xfs_attri_log_item	*attrip)
>> +{
>> +	struct xfs_attrd_log_item		*attrdp;
>> +
>> +	ASSERT(tp != NULL);
>> +
>> +	attrdp = xfs_attrd_init(tp->t_mountp, attrip);
>> +	ASSERT(attrdp != NULL);
>> +
>> +	/*
>> +	 * Get a log_item_desc to point at the new item.
>> +	 */
>> +	xfs_trans_add_item(tp, &attrdp->attrd_item);
>> +	return attrdp;
>> +}
>> +
>> +/*
>> + * Delete an attr and log it to the ATTRD. Note that the transaction is marked
>> + * dirty regardless of whether the attr delete succeeds or fails to support the
>> + * ATTRI/ATTRD lifecycle rules.
>> + */
>> +int
>> +xfs_trans_attr(
>> +	struct xfs_da_args		*args,
>> +	struct xfs_attrd_log_item	*attrdp,
>> +	uint32_t			op_flags)
>> +{
>> +	int				error;
>> +
>> +	error = xfs_qm_dqattach_locked(args->dp, 0);
>> +	if (error)
>> +		return error;
>> +
>> +	switch (op_flags) {
>> +	case XFS_ATTR_OP_FLAGS_SET:
>> +		args->op_flags |= XFS_DA_OP_ADDNAME;
>> +		error = xfs_attr_set_args(args);
>> +		break;
>> +	case XFS_ATTR_OP_FLAGS_REMOVE:
>> +		ASSERT(XFS_IFORK_Q((args->dp)));
>> +		error = xfs_attr_remove_args(args);
>> +		break;
>> +	default:
>> +		error = -EFSCORRUPTED;
> 
> The default clause needs a break; here.
Ok, will add the break.

> 
>> +	}
>> +
>> +	/*
>> +	 * Mark the transaction dirty, even on error. This ensures the
>> +	 * transaction is aborted, which:
>> +	 *
>> +	 * 1.) releases the ATTRI and frees the ATTRD
>> +	 * 2.) shuts down the filesystem
>> +	 */
>> +	args->trans->t_flags |= XFS_TRANS_DIRTY;
>> +	set_bit(XFS_LI_DIRTY, &attrdp->attrd_item.li_flags);
>> +
>> +	return error;
>> +}
>> +
> 
> <skip stuff that looks ok>
> 
>> +/*
>> + * This is the ops vector shared by all attri log items.
>> + */
> 
> We just got rid of this comment above all the other log item ops
> structure definitions, so you can clip these out.
> 
Sure, I will go back and clean those out then

>> +static const struct xfs_item_ops xfs_attri_item_ops = {
>> +	.iop_size	= xfs_attri_item_size,
>> +	.iop_format	= xfs_attri_item_format,
>> +	.iop_pin	= xfs_attri_item_pin,
>> +	.iop_unpin	= xfs_attri_item_unpin,
>> +	.iop_committed	= xfs_attri_item_committed,
>> +	.iop_push	= xfs_attri_item_push,
>> +	.iop_committing = xfs_attri_item_committing,
>> +	.iop_release    = xfs_attri_item_release,
>> +};
>> +
>> +
>> +/*
>> + * Allocate and initialize an attri item
>> + */
>> +struct xfs_attri_log_item *
>> +xfs_attri_init(
>> +	struct xfs_mount	*mp)
>> +
>> +{
>> +	struct xfs_attri_log_item	*attrip;
>> +	uint				size;
>> +
>> +	size = (uint)(sizeof(struct xfs_attri_log_item));
>> +	attrip = kmem_zalloc(size, KM_SLEEP);
>> +
>> +	xfs_log_item_init(mp, &attrip->attri_item, XFS_LI_ATTRI,
>> +			  &xfs_attri_item_ops);
>> +	attrip->attri_format.alfi_id = (uintptr_t)(void *)attrip;
> 
> /me wonders if we ought to clean up all these *[id]_id types so that we
> don't have to employ all these annoying casts, but that's not relevant
> to this series.
Yeah, I may wait and see what the trend is by the time v3 goes back 
around, or add another patch for that.

> 
>> +	atomic_set(&attrip->attri_refcount, 2);
>> +
>> +	return attrip;
>> +}
>> +
> 
> <skip more stuff that looked ok>
> 
>> +/*
>> + * Pinning has no meaning for an attrd item, so just return.
>> + */
>> +STATIC void
>> +xfs_attrd_item_pin(
>> +	struct xfs_log_item	*lip)
>> +{
>> +}
> 
> Hmm, didn't Christoph refactor the log code in 5.3 so that log items
> don't need all these empty unlock/committing/pin functions?
I may have missed it.  Most of this code used the efi code as a model 
but that was some time ago, and I've been trying to keep it up to date 
as things move forward.  I'll go back and clean out the empty stubs

> 
>> +
>> +/*
>> + * Since pinning has no meaning for an attrd item, unpinning does
>> + * not either.
>> + */
>> +STATIC void
>> +xfs_attrd_item_unpin(
>> +	struct xfs_log_item	*lip,
>> +	int			remove)
>> +{
>> +}
>> +
>> +/*
>> + * There isn't much you can do to push on an attrd item.  It is simply stuck
>> + * waiting for the log to be flushed to disk.
>> + */
>> +STATIC uint
>> +xfs_attrd_item_push(
>> +	struct xfs_log_item	*lip,
>> +	struct list_head	*buffer_list)
>> +{
>> +	return XFS_ITEM_PINNED;
>> +}
>> +
>> +/*
>> + * When the attrd item is committed to disk, all we need to do is delete our
>> + * reference to our partner attri item and then free ourselves. Since we're
>> + * freeing ourselves we must return -1 to keep the transaction code from
>> + * further referencing this item.
>> + */
>> +STATIC xfs_lsn_t
>> +xfs_attrd_item_committed(
>> +	struct xfs_log_item	*lip,
>> +	xfs_lsn_t		lsn)
>> +{
>> +	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
>> +
>> +	/*
>> +	 * Drop the ATTRI reference regardless of whether the ATTRD has been
>> +	 * aborted. Once the ATTRD transaction is constructed, it is the sole
>> +	 * responsibility of the ATTRD to release the ATTRI (even if the ATTRI
>> +	 * is aborted due to log I/O error).
>> +	 */
>> +	xfs_attri_release(attrdp->attrd_attrip);
>> +	xfs_attrd_item_free(attrdp);
>> +
>> +	return (xfs_lsn_t)-1;
> 
> NULLCOMMITLSN?
Sure, will update.

> 
> <skip more>
> 
>> +/*
>> + * Process an attr intent item that was recovered from the log.  We need to
>> + * delete the attr that it describes.
>> + */
>> +int
>> +xfs_attri_recover(
>> +	struct xfs_mount		*mp,
>> +	struct xfs_attri_log_item	*attrip)
>> +{
>> +	struct xfs_inode		*ip;
>> +	struct xfs_attrd_log_item	*attrdp;
>> +	struct xfs_da_args		args;
>> +	struct xfs_attri_log_format	*attrp;
>> +	struct xfs_trans_res		tres;
>> +	int				local;
>> +	int				error = 0;
>> +	int				rsvd = 0;
>> +	struct xfs_name			name;
>> +
>> +	ASSERT(!test_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags));
>> +
>> +	/*
>> +	 * First check the validity of the attr described by the ATTRI.  If any
>> +	 * are bad, then assume that all are bad and just toss the ATTRI.
>> +	 */
>> +	attrp = &attrip->attri_format;
>> +	if (
>> +	    !(attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_SET ||
>> +		attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_REMOVE) ||
>> +	      (attrp->alfi_value_len > XATTR_SIZE_MAX) ||
>> +	      (attrp->alfi_name_len > XATTR_NAME_MAX) ||
>> +	      (attrp->alfi_name_len == 0)
>> +	) {
>> +		/*
>> +		 * This will pull the ATTRI from the AIL and free the memory
>> +		 * associated with it.
>> +		 */
>> +		set_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags);
>> +		xfs_attri_release(attrip);
>> +		return -EIO;
> 
> This is probably more EFSCORRUPTED than EIO here, right?
Yes, I think you're right.  Will update.

> 
>> +	}
>> +
>> +	attrp = &attrip->attri_format;
>> +	error = xfs_iget(mp, 0, attrp->alfi_ino, 0, 0, &ip);
>> +	if (error)
>> +		return error;
>> +
>> +	name.name = attrip->attri_name;
>> +	name.len = attrp->alfi_name_len;
>> +	name.type = attrp->alfi_attr_flags;
>> +	error = xfs_attr_args_init(&args, ip, &name);
>> +	if (error)
>> +		return error;
>> +
>> +	args.hashval = xfs_da_hashname(args.name, args.namelen);
>> +	args.value = attrip->attri_value;
>> +	args.valuelen = attrp->alfi_value_len;
>> +	args.op_flags = XFS_DA_OP_OKNOENT;
>> +	args.total = xfs_attr_calc_size(&args, &local);
>> +
>> +	tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
>> +			M_RES(mp)->tr_attrsetrt.tr_logres * args.total;
>> +	tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
>> +	tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
>> +
>> +	error = xfs_trans_alloc(mp, &tres, args.total,  0,
>> +				rsvd ? XFS_TRANS_RESERVE : 0, &args.trans);
>> +	if (error)
>> +		return error;
>> +	attrdp = xfs_trans_get_attrd(args.trans, attrip);
>> +
>> +	xfs_ilock(ip, XFS_ILOCK_EXCL);
>> +
>> +	xfs_trans_ijoin(args.trans, ip, 0);
>> +	error = xfs_trans_attr(&args, attrdp, attrp->alfi_op_flags);
>> +	if (error)
>> +		goto abort_error;
>> +
>> +
>> +	set_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags);
>> +	xfs_trans_log_inode(args.trans, ip, XFS_ILOG_CORE | XFS_ILOG_ADATA);
>> +	error = xfs_trans_commit(args.trans);
>> +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
>> +	return error;
>> +
>> +abort_error:
>> +	xfs_trans_cancel(args.trans);
>> +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
>> +	return error;
>> +}
>> diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h
>> new file mode 100644
>> index 0000000..aad32ed
>> --- /dev/null
>> +++ b/fs/xfs/xfs_attr_item.h
>> @@ -0,0 +1,102 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Copyright (C) 2019 Oracle.  All Rights Reserved.
>> + * Author: Allison Henderson <allison.henderson@oracle.com>
>> + */
>> +#ifndef	__XFS_ATTR_ITEM_H__
>> +#define	__XFS_ATTR_ITEM_H__
>> +
>> +/* kernel only ATTRI/ATTRD definitions */
>> +
>> +struct xfs_mount;
>> +struct kmem_zone;
>> +
>> +/*
>> + * Max number of attrs in fast allocation path.
>> + */
>> +#define XFS_ATTRI_MAX_FAST_ATTRS        1
>> +
>> +
>> +/*
>> + * Define ATTR flag bits. Manipulated by set/clear/test_bit operators.
>> + */
>> +#define	XFS_ATTRI_RECOVERED	1
>> +
>> +
>> +/* iovec length must be 32-bit aligned */
>> +#define ATTR_NVEC_SIZE(size) (size == sizeof(int32_t) ? sizeof(int32_t) : \
>> +				size + sizeof(int32_t) - \
>> +				(size % sizeof(int32_t)))
>> +
>> +/*
>> + * This is the "attr intention" log item.  It is used to log the fact that some
>> + * need to be processed.  It is used in conjunction with the "attr done" log
>> + * item described below.
>> + *
>> + * The ATTRI is reference counted so that it is not freed prior to both the
>> + * ATTRI and ATTRD being committed and unpinned. This ensures the ATTRI is
>> + * inserted into the AIL even in the event of out of order ATTRI/ATTRD
>> + * processing. In other words, an ATTRI is born with two references:
>> + *
>> + *      1.) an ATTRI held reference to track ATTRI AIL insertion
>> + *      2.) an ATTRD held reference to track ATTRD commit
>> + *
>> + * On allocation, both references are the responsibility of the caller. Once the
>> + * ATTRI is added to and dirtied in a transaction, ownership of reference one
>> + * transfers to the transaction. The reference is dropped once the ATTRI is
>> + * inserted to the AIL or in the event of failure along the way (e.g., commit
>> + * failure, log I/O error, etc.). Note that the caller remains responsible for
>> + * the ATTRD reference under all circumstances to this point. The caller has no
>> + * means to detect failure once the transaction is committed, however.
>> + * Therefore, an ATTRD is required after this point, even in the event of
>> + * unrelated failure.
>> + *
>> + * Once an ATTRD is allocated and dirtied in a transaction, reference two
>> + * transfers to the transaction. The ATTRD reference is dropped once it reaches
>> + * the unpin handler. Similar to the ATTRI, the reference also drops in the
>> + * event of commit failure or log I/O errors. Note that the ATTRD is not
>> + * inserted in the AIL, so at this point both the ATTI and ATTRD are freed.
> 
> "...the ATTRI and ATTRD are freed." ?
Ok, will fix typo :-)

> 
>> + */
>> +struct xfs_attri_log_item {
>> +	struct xfs_log_item		attri_item;
>> +	atomic_t			attri_refcount;
>> +	unsigned long			attri_flags;	/* misc flags */
>> +	int				attri_name_len;
>> +	void				*attri_name;
>> +	int				attri_value_len;
>> +	void				*attri_value;
>> +	struct xfs_attri_log_format	attri_format;
>> +};
>> +
>> +/*
>> + * This is the "attr done" log item.  It is used to log the fact that some attrs
>> + * earlier mentioned in an attri item have been freed.
>> + */
>> +struct xfs_attrd_log_item {
>> +	struct xfs_log_item		attrd_item;
>> +	struct xfs_attri_log_item	*attrd_attrip;
>> +	struct xfs_attrd_log_format	attrd_format;
>> +};
> 
> Can these be rearranged to use less memory?
> 
> Everything else after this looks ok to me.
> 
Ok, I'll play with it and see if I can shrink it down some.  Thx for the 
review!

Allison

> --D
> 
>> +
>> +/*
>> + * Max number of attrs in fast allocation path.
>> + */
>> +#define	XFS_ATTRD_MAX_FAST_ATTRS	1
>> +
>> +extern struct kmem_zone	*xfs_attri_zone;
>> +extern struct kmem_zone	*xfs_attrd_zone;
>> +
>> +struct xfs_attri_log_item	*xfs_attri_init(struct xfs_mount *mp);
>> +struct xfs_attrd_log_item	*xfs_attrd_init(struct xfs_mount *mp,
>> +					struct xfs_attri_log_item *attrip);
>> +int xfs_attri_copy_format(struct xfs_log_iovec *buf,
>> +			   struct xfs_attri_log_format *dst_attri_fmt);
>> +int xfs_attrd_copy_format(struct xfs_log_iovec *buf,
>> +			   struct xfs_attrd_log_format *dst_attrd_fmt);
>> +void			xfs_attri_item_free(struct xfs_attri_log_item *attrip);
>> +void			xfs_attri_release(struct xfs_attri_log_item *attrip);
>> +
>> +int			xfs_attri_recover(struct xfs_mount *mp,
>> +					struct xfs_attri_log_item *attrip);
>> +
>> +#endif	/* __XFS_ATTR_ITEM_H__ */
>> diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
>> index 00e9f5c..2fbd180 100644
>> --- a/fs/xfs/xfs_log.c
>> +++ b/fs/xfs/xfs_log.c
>> @@ -2005,6 +2005,10 @@ xlog_print_tic_res(
>>   	    REG_TYPE_STR(CUD_FORMAT, "cud_format"),
>>   	    REG_TYPE_STR(BUI_FORMAT, "bui_format"),
>>   	    REG_TYPE_STR(BUD_FORMAT, "bud_format"),
>> +	    REG_TYPE_STR(ATTRI_FORMAT, "attri_format"),
>> +	    REG_TYPE_STR(ATTRD_FORMAT, "attrd_format"),
>> +	    REG_TYPE_STR(ATTR_NAME, "attr_name"),
>> +	    REG_TYPE_STR(ATTR_VALUE, "attr_value"),
>>   	};
>>   	BUILD_BUG_ON(ARRAY_SIZE(res_type_str) != XLOG_REG_TYPE_MAX + 1);
>>   #undef REG_TYPE_STR
>> diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
>> index 13d1d3e..233efdb3 100644
>> --- a/fs/xfs/xfs_log_recover.c
>> +++ b/fs/xfs/xfs_log_recover.c
>> @@ -20,6 +20,7 @@
>>   #include "xfs_log_recover.h"
>>   #include "xfs_inode_item.h"
>>   #include "xfs_extfree_item.h"
>> +#include "xfs_attr_item.h"
>>   #include "xfs_trans_priv.h"
>>   #include "xfs_alloc.h"
>>   #include "xfs_ialloc.h"
>> @@ -1885,6 +1886,8 @@ xlog_recover_reorder_trans(
>>   		case XFS_LI_CUD:
>>   		case XFS_LI_BUI:
>>   		case XFS_LI_BUD:
>> +		case XFS_LI_ATTRI:
>> +		case XFS_LI_ATTRD:
>>   			trace_xfs_log_recover_item_reorder_tail(log,
>>   							trans, item, pass);
>>   			list_move_tail(&item->ri_list, &inode_list);
>> @@ -3422,6 +3425,119 @@ xlog_recover_efd_pass2(
>>   	return 0;
>>   }
>>   
>> +STATIC int
>> +xlog_recover_attri_pass2(
>> +	struct xlog                     *log,
>> +	struct xlog_recover_item        *item,
>> +	xfs_lsn_t                       lsn)
>> +{
>> +	int                             error;
>> +	struct xfs_mount                *mp = log->l_mp;
>> +	struct xfs_attri_log_item       *attrip;
>> +	struct xfs_attri_log_format     *attri_formatp;
>> +	char				*name = NULL;
>> +	char				*value = NULL;
>> +	int				region = 0;
>> +
>> +	attri_formatp = item->ri_buf[region].i_addr;
>> +
>> +	attrip = xfs_attri_init(mp);
>> +	error = xfs_attri_copy_format(&item->ri_buf[region],
>> +				      &attrip->attri_format);
>> +	if (error) {
>> +		xfs_attri_item_free(attrip);
>> +		return error;
>> +	}
>> +
>> +	attrip->attri_name_len = attri_formatp->alfi_name_len;
>> +	attrip->attri_value_len = attri_formatp->alfi_value_len;
>> +	attrip = kmem_realloc(attrip, sizeof(struct xfs_attri_log_item) +
>> +			      attrip->attri_name_len + attrip->attri_value_len,
>> +			      KM_SLEEP);
>> +
>> +	if (attrip->attri_name_len > 0) {
>> +		region++;
>> +		name = ((char *)attrip) + sizeof(struct xfs_attri_log_item);
>> +		memcpy(name, item->ri_buf[region].i_addr,
>> +		       attrip->attri_name_len);
>> +		attrip->attri_name = name;
>> +	}
>> +
>> +	if (attrip->attri_value_len > 0) {
>> +		region++;
>> +		value = ((char *)attrip) + sizeof(struct xfs_attri_log_item) +
>> +			attrip->attri_name_len;
>> +		memcpy(value, item->ri_buf[region].i_addr,
>> +			attrip->attri_value_len);
>> +		attrip->attri_value = value;
>> +	}
>> +
>> +	spin_lock(&log->l_ailp->ail_lock);
>> +	/*
>> +	 * The ATTRI has two references. One for the ATTRD and one for ATTRI to
>> +	 * ensure it makes it into the AIL. Insert the ATTRI into the AIL
>> +	 * directly and drop the ATTRI reference. Note that
>> +	 * xfs_trans_ail_update() drops the AIL lock.
>> +	 */
>> +	xfs_trans_ail_update(log->l_ailp, &attrip->attri_item, lsn);
>> +	xfs_attri_release(attrip);
>> +	return 0;
>> +}
>> +
>> +
>> +/*
>> + * This routine is called when an ATTRD format structure is found in a committed
>> + * transaction in the log. Its purpose is to cancel the corresponding ATTRI if
>> + * it was still in the log. To do this it searches the AIL for the ATTRI with
>> + * an id equal to that in the ATTRD format structure. If we find it we drop
>> + * the ATTRD reference, which removes the ATTRI from the AIL and frees it.
>> + */
>> +STATIC int
>> +xlog_recover_attrd_pass2(
>> +	struct xlog                     *log,
>> +	struct xlog_recover_item        *item)
>> +{
>> +	struct xfs_attrd_log_format	*attrd_formatp;
>> +	struct xfs_attri_log_item	*attrip = NULL;
>> +	struct xfs_log_item		*lip;
>> +	uint64_t			attri_id;
>> +	struct xfs_ail_cursor		cur;
>> +	struct xfs_ail			*ailp = log->l_ailp;
>> +
>> +	attrd_formatp = item->ri_buf[0].i_addr;
>> +	ASSERT((item->ri_buf[0].i_len ==
>> +				(sizeof(struct xfs_attrd_log_format))));
>> +	attri_id = attrd_formatp->alfd_alf_id;
>> +
>> +	/*
>> +	 * Search for the ATTRI with the id in the ATTRD format structure in the
>> +	 * AIL.
>> +	 */
>> +	spin_lock(&ailp->ail_lock);
>> +	lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
>> +	while (lip != NULL) {
>> +		if (lip->li_type == XFS_LI_ATTRI) {
>> +			attrip = (struct xfs_attri_log_item *)lip;
>> +			if (attrip->attri_format.alfi_id == attri_id) {
>> +				/*
>> +				 * Drop the ATTRD reference to the ATTRI. This
>> +				 * removes the ATTRI from the AIL and frees it.
>> +				 */
>> +				spin_unlock(&ailp->ail_lock);
>> +				xfs_attri_release(attrip);
>> +				spin_lock(&ailp->ail_lock);
>> +				break;
>> +			}
>> +		}
>> +		lip = xfs_trans_ail_cursor_next(ailp, &cur);
>> +	}
>> +
>> +	xfs_trans_ail_cursor_done(&cur);
>> +	spin_unlock(&ailp->ail_lock);
>> +
>> +	return 0;
>> +}
>> +
>>   /*
>>    * This routine is called to create an in-core extent rmap update
>>    * item from the rui format structure which was logged on disk.
>> @@ -3974,6 +4090,8 @@ xlog_recover_ra_pass2(
>>   		break;
>>   	case XFS_LI_EFI:
>>   	case XFS_LI_EFD:
>> +	case XFS_LI_ATTRI:
>> +	case XFS_LI_ATTRD:
>>   	case XFS_LI_QUOTAOFF:
>>   	case XFS_LI_RUI:
>>   	case XFS_LI_RUD:
>> @@ -4002,6 +4120,8 @@ xlog_recover_commit_pass1(
>>   	case XFS_LI_INODE:
>>   	case XFS_LI_EFI:
>>   	case XFS_LI_EFD:
>> +	case XFS_LI_ATTRI:
>> +	case XFS_LI_ATTRD:
>>   	case XFS_LI_DQUOT:
>>   	case XFS_LI_ICREATE:
>>   	case XFS_LI_RUI:
>> @@ -4040,6 +4160,10 @@ xlog_recover_commit_pass2(
>>   		return xlog_recover_efi_pass2(log, item, trans->r_lsn);
>>   	case XFS_LI_EFD:
>>   		return xlog_recover_efd_pass2(log, item);
>> +	case XFS_LI_ATTRI:
>> +		return xlog_recover_attri_pass2(log, item, trans->r_lsn);
>> +	case XFS_LI_ATTRD:
>> +		return xlog_recover_attrd_pass2(log, item);
>>   	case XFS_LI_RUI:
>>   		return xlog_recover_rui_pass2(log, item, trans->r_lsn);
>>   	case XFS_LI_RUD:
>> @@ -4601,6 +4725,48 @@ xlog_recover_cancel_efi(
>>   	spin_lock(&ailp->ail_lock);
>>   }
>>   
>> +/* Release the ATTRI since we're cancelling everything. */
>> +STATIC void
>> +xlog_recover_cancel_attri(
>> +	struct xfs_mount                *mp,
>> +	struct xfs_ail                  *ailp,
>> +	struct xfs_log_item             *lip)
>> +{
>> +	struct xfs_attri_log_item         *attrip;
>> +
>> +	attrip = container_of(lip, struct xfs_attri_log_item, attri_item);
>> +
>> +	spin_unlock(&ailp->ail_lock);
>> +	xfs_attri_release(attrip);
>> +	spin_lock(&ailp->ail_lock);
>> +}
>> +
>> +
>> +/* Recover the ATTRI if necessary. */
>> +STATIC int
>> +xlog_recover_process_attri(
>> +	struct xfs_mount                *mp,
>> +	struct xfs_ail                  *ailp,
>> +	struct xfs_log_item             *lip)
>> +{
>> +	struct xfs_attri_log_item       *attrip;
>> +	int                             error;
>> +
>> +	/*
>> +	 * Skip ATTRIs that we've already processed.
>> +	 */
>> +	attrip = container_of(lip, struct xfs_attri_log_item, attri_item);
>> +	if (test_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags))
>> +		return 0;
>> +
>> +	spin_unlock(&ailp->ail_lock);
>> +	error = xfs_attri_recover(mp, attrip);
>> +	spin_lock(&ailp->ail_lock);
>> +
>> +	return error;
>> +}
>> +
>> +
>>   /* Recover the RUI if necessary. */
>>   STATIC int
>>   xlog_recover_process_rui(
>> @@ -4729,6 +4895,7 @@ static inline bool xlog_item_is_intent(struct xfs_log_item *lip)
>>   	case XFS_LI_RUI:
>>   	case XFS_LI_CUI:
>>   	case XFS_LI_BUI:
>> +	case XFS_LI_ATTRI:
>>   		return true;
>>   	default:
>>   		return false;
>> @@ -4847,6 +5014,10 @@ xlog_recover_process_intents(
>>   		case XFS_LI_EFI:
>>   			error = xlog_recover_process_efi(log->l_mp, ailp, lip);
>>   			break;
>> +		case XFS_LI_ATTRI:
>> +			error = xlog_recover_process_attri(log->l_mp,
>> +							   ailp, lip);
>> +			break;
>>   		case XFS_LI_RUI:
>>   			error = xlog_recover_process_rui(log->l_mp, ailp, lip);
>>   			break;
>> @@ -4912,6 +5083,9 @@ xlog_recover_cancel_intents(
>>   		case XFS_LI_BUI:
>>   			xlog_recover_cancel_bui(log->l_mp, ailp, lip);
>>   			break;
>> +		case XFS_LI_ATTRI:
>> +			xlog_recover_cancel_attri(log->l_mp, ailp, lip);
>> +			break;
>>   		}
>>   
>>   		lip = xfs_trans_ail_cursor_next(ailp, &cur);
>> diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h
>> index b6701b4..120fb0c 100644
>> --- a/fs/xfs/xfs_ondisk.h
>> +++ b/fs/xfs/xfs_ondisk.h
>> @@ -125,6 +125,8 @@ xfs_check_ondisk_structs(void)
>>   	XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format,	56);
>>   	XFS_CHECK_STRUCT_SIZE(struct xfs_qoff_logformat,	20);
>>   	XFS_CHECK_STRUCT_SIZE(struct xfs_trans_header,		16);
>> +	XFS_CHECK_STRUCT_SIZE(struct xfs_attri_log_format,	40);
>> +	XFS_CHECK_STRUCT_SIZE(struct xfs_attrd_log_format,	16);
>>   
>>   	/*
>>   	 * The v5 superblock format extended several v4 header structures with
>> diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
>> index 64d7f17..95924dc 100644
>> --- a/fs/xfs/xfs_trans.h
>> +++ b/fs/xfs/xfs_trans.h
>> @@ -26,6 +26,9 @@ struct xfs_cui_log_item;
>>   struct xfs_cud_log_item;
>>   struct xfs_bui_log_item;
>>   struct xfs_bud_log_item;
>> +struct xfs_attrd_log_item;
>> +struct xfs_attri_log_item;
>> +struct xfs_da_args;
>>   
>>   struct xfs_log_item {
>>   	struct list_head		li_ail;		/* AIL pointers */
>> @@ -229,7 +232,6 @@ void		xfs_trans_log_buf(struct xfs_trans *, struct xfs_buf *, uint,
>>   void		xfs_trans_dirty_buf(struct xfs_trans *, struct xfs_buf *);
>>   bool		xfs_trans_buf_is_dirty(struct xfs_buf *bp);
>>   void		xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
>> -
>>   int		xfs_trans_commit(struct xfs_trans *);
>>   int		xfs_trans_roll(struct xfs_trans **);
>>   int		xfs_trans_roll_inode(struct xfs_trans **, struct xfs_inode *);
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v2 04/18] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
  2019-08-12 15:44   ` Darrick J. Wong
@ 2019-08-12 19:28     ` Allison Collins
  0 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-12 19:28 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 8/12/19 8:44 AM, Darrick J. Wong wrote:
> On Fri, Aug 09, 2019 at 02:37:12PM -0700, Allison Collins wrote:
>> From: Allison Henderson <allison.henderson@oracle.com>
>>
>> These routines set up set and start a new deferred attribute
>> operation.  These functions are meant to be called by other
>> code needing to initiate a deferred attribute operation.
>>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++
>>   fs/xfs/libxfs/xfs_attr.h |  5 ++++
>>   2 files changed, 79 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 1f76618..a2fba0c 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -25,6 +25,7 @@
>>   #include "xfs_trans_space.h"
>>   #include "xfs_trace.h"
>>   #include "xfs_attr_item.h"
>> +#include "xfs_attr.h"
>>   
>>   /*
>>    * xfs_attr.c
>> @@ -399,6 +400,48 @@ xfs_attr_set(
>>   	goto out_unlock;
>>   }
>>   
>> +/* Sets an attribute for an inode as a deferred operation */
>> +int
>> +xfs_attr_set_deferred(
>> +	struct xfs_inode	*dp,
>> +	struct xfs_trans	*tp,
>> +	struct xfs_name		*name,
>> +	const unsigned char	*value,
>> +	unsigned int		valuelen)
>> +{
>> +
>> +	struct xfs_attr_item	*new;
>> +	char			*name_value;
>> +
>> +	/*
>> +	 * All set operations must have a name but not necessarily a value.
>> +	 */
>> +	if (!name->len) {
>> +		ASSERT(0);
>> +		return -EINVAL;
>> +	}
>> +
>> +	new = kmem_alloc_large(XFS_ATTR_ITEM_SIZEOF(name->len, valuelen),
>> +			 KM_SLEEP|KM_NOFS);
>> +	name_value = ((char *)new) + sizeof(struct xfs_attr_item);
>> +	memset(new, 0, XFS_ATTR_ITEM_SIZEOF(name->len, valuelen));
>> +	new->xattri_ip = dp;
>> +	new->xattri_op_flags = XFS_ATTR_OP_FLAGS_SET;
>> +	new->xattri_name_len = name->len;
>> +	new->xattri_value_len = valuelen;
>> +	new->xattri_flags = name->type;
>> +	memcpy(&name_value[0], name->name, name->len);
>> +	new->xattri_name = name_value;
>> +	new->xattri_value = name_value + name->len;
>> +
>> +	if (valuelen > 0)
>> +		memcpy(&name_value[name->len], value, valuelen);
>> +
>> +	xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
>> +
>> +	return 0;
>> +}
>> +
>>   /*
>>    * Generic handler routine to remove a name from an attribute list.
>>    * Transitions attribute list from Btree to shortform as necessary.
>> @@ -480,6 +523,37 @@ xfs_attr_remove(
>>   	return error;
>>   }
>>   
>> +/* Removes an attribute for an inode as a deferred operation */
>> +int
>> +xfs_attr_remove_deferred(
>> +	struct xfs_inode        *dp,
>> +	struct xfs_trans	*tp,
>> +	struct xfs_name		*name)
>> +{
>> +
>> +	struct xfs_attr_item	*new;
>> +	char			*name_value;
>> +
>> +	if (!name->len) {
>> +		ASSERT(0);
>> +		return -EINVAL;
>> +	}
>> +
>> +	new = kmem_alloc(XFS_ATTR_ITEM_SIZEOF(name->len, 0), KM_SLEEP|KM_NOFS);
>> +	name_value = ((char *)new) + sizeof(struct xfs_attr_item);
>> +	memset(new, 0, XFS_ATTR_ITEM_SIZEOF(name->len, 0));
>> +	new->xattri_ip = dp;
>> +	new->xattri_op_flags = XFS_ATTR_OP_FLAGS_REMOVE;
>> +	new->xattri_name_len = name->len;
>> +	new->xattri_value_len = 0;
>> +	new->xattri_flags = name->type;
>> +	memcpy(name_value, name->name, name->len);
>> +
>> +	xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
> 
> Can the common parts of these two functions be refactored into a single
> initialization function called from xfs_attr_{set,remove}_deferred,
> similar to what xfs_rmap.c does for all the various deferred rmap calls?
> 
> --D

Sure, I can add a quick init routine.

Thx!
Allison

> 
>> +
>> +	return 0;
>> +}
>> +
>>   /*========================================================================
>>    * External routines when attribute list is inside the inode
>>    *========================================================================*/
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index 9132d4f..0bade83 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -177,5 +177,10 @@ bool xfs_attr_namecheck(const void *name, size_t length);
>>   int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
>>   		       struct xfs_name *name);
>>   int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
>> +int xfs_attr_set_deferred(struct xfs_inode *dp, struct xfs_trans *tp,
>> +			  struct xfs_name *name, const unsigned char *value,
>> +			  unsigned int valuelen);
>> +int xfs_attr_remove_deferred(struct xfs_inode *dp, struct xfs_trans *tp,
>> +			    struct xfs_name *name);
>>   
>>   #endif	/* __XFS_ATTR_H__ */
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v2 03/18] xfs: Set up infastructure for deferred attribute operations
  2019-08-09 21:37 ` [PATCH v2 03/18] xfs: Set up infastructure for deferred attribute operations Allison Collins
  2019-08-12 15:40   ` Darrick J. Wong
@ 2019-08-12 19:28   ` Brian Foster
  2019-08-13 18:43     ` Allison Collins
  1 sibling, 1 reply; 56+ messages in thread
From: Brian Foster @ 2019-08-12 19:28 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Aug 09, 2019 at 02:37:11PM -0700, Allison Collins wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> Currently attributes are modified directly across one or more
> transactions.  But they are not logged or replayed in the event of
> an error. The goal of delayed attributes is to enable logging and
> replaying of attribute operations using the existing delayed
> operations infrastructure.  This will later enable the attributes
> to become part of larger multi part operations that also must first
> be recorded to the log.  This is mostly of interest in the scheme of
> parent pointers which would need to maintain an attribute containing
> parent inode information any time an inode is moved, created, or
> removed.  Parent pointers would then be of interest to any feature
> that would need to quickly derive an inode path from the mount
> point.  Online scrub, nfs lookups and fs grow or shrink operations
> are all features that could take advantage of this.
> 
> This patch adds two new log item types for setting or removing
> attributes as deferred operations.  The xfs_attri_log_item logs an
> intent to set or remove an attribute.  The corresponding
> xfs_attrd_log_item holds a reference to the xfs_attri_log_item and
> is freed once the transaction is done.  Both log items use a generic
> xfs_attr_log_format structure that contains the attribute name,
> value, flags, inode, and an op_flag that indicates if the operations
> is a set or remove.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---

Mostly small stuff, some of which may overlap with Darrick's comments...

>  fs/xfs/Makefile                |   2 +-
>  fs/xfs/libxfs/xfs_attr.c       |   5 +-
>  fs/xfs/libxfs/xfs_attr.h       |  25 ++
>  fs/xfs/libxfs/xfs_defer.c      |   1 +
>  fs/xfs/libxfs/xfs_defer.h      |   3 +
>  fs/xfs/libxfs/xfs_log_format.h |  44 ++-
>  fs/xfs/libxfs/xfs_types.h      |   1 +
>  fs/xfs/xfs_attr_item.c         | 755 +++++++++++++++++++++++++++++++++++++++++
>  fs/xfs/xfs_attr_item.h         | 102 ++++++
>  fs/xfs/xfs_log.c               |   4 +
>  fs/xfs/xfs_log_recover.c       | 174 ++++++++++
>  fs/xfs/xfs_ondisk.h            |   2 +
>  fs/xfs/xfs_trans.h             |   4 +-
>  13 files changed, 1116 insertions(+), 6 deletions(-)
> 
...
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index aa7261a..9132d4f 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -78,6 +78,28 @@ typedef struct attrlist_ent {	/* data from attr_list() */
>  } attrlist_ent_t;
>  
>  /*
> + * List of attrs to commit later.
> + */
> +struct xfs_attr_item {
> +	struct xfs_inode  *xattri_ip;
> +	uint32_t	  xattri_op_flags;
> +	void		  *xattri_value;      /* attr value */
> +	uint32_t	  xattri_value_len;   /* length of value */
> +	void		  *xattri_name;	      /* attr name */
> +	uint32_t	  xattri_name_len;    /* length of name */
> +	uint32_t	  xattri_flags;       /* attr flags */
> +	struct list_head  xattri_list;

Could use a comment on the xattri_list line as well.

> +
> +	/*
> +	 * A byte array follows the header containing the file name and
> +	 * attribute value.
> +	 */
> +};
> +
> +#define XFS_ATTR_ITEM_SIZEOF(namelen, valuelen)	\
> +	(sizeof(struct xfs_attr_item) + (namelen) + (valuelen))
> +
> +/*
>   * Given a pointer to the (char*) buffer containing the attr_list() result,
>   * and an index, return a pointer to the indicated attribute in the buffer.
>   */
> @@ -152,5 +174,8 @@ int xfs_attr_remove_args(struct xfs_da_args *args);
>  int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>  		  int flags, struct attrlist_cursor_kern *cursor);
>  bool xfs_attr_namecheck(const void *name, size_t length);
> +int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
> +		       struct xfs_name *name);
> +int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
>  
>  #endif	/* __XFS_ATTR_H__ */
...
> diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
> new file mode 100644
> index 0000000..2340589
> --- /dev/null
> +++ b/fs/xfs/xfs_attr_item.c
> @@ -0,0 +1,755 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2019 Oracle.  All Rights Reserved.
> + * Author: Allison Henderson <allison.henderson@oracle.com>
> + */
> +
...
> +
> +
> +/*
> + * This routine is called to allocate an "attr free done" log item.
> + */
> +struct xfs_attrd_log_item *
> +xfs_trans_get_attrd(struct xfs_trans		*tp,
> +		  struct xfs_attri_log_item	*attrip)
> +{
> +	struct xfs_attrd_log_item		*attrdp;
> +
> +	ASSERT(tp != NULL);
> +
> +	attrdp = xfs_attrd_init(tp->t_mountp, attrip);
> +	ASSERT(attrdp != NULL);
> +
> +	/*
> +	 * Get a log_item_desc to point at the new item.
> +	 */

No such thing as a log_item_desc any more. :)

> +	xfs_trans_add_item(tp, &attrdp->attrd_item);
> +	return attrdp;
> +}
> +
> +/*
> + * Delete an attr and log it to the ATTRD. Note that the transaction is marked
> + * dirty regardless of whether the attr delete succeeds or fails to support the
> + * ATTRI/ATTRD lifecycle rules.
> + */

Looks like the comment needs an update. This function doesn't just
handle deletes.

> +int
> +xfs_trans_attr(
> +	struct xfs_da_args		*args,
> +	struct xfs_attrd_log_item	*attrdp,
> +	uint32_t			op_flags)
> +{
> +	int				error;
> +
> +	error = xfs_qm_dqattach_locked(args->dp, 0);
> +	if (error)
> +		return error;
> +
> +	switch (op_flags) {
> +	case XFS_ATTR_OP_FLAGS_SET:
> +		args->op_flags |= XFS_DA_OP_ADDNAME;
> +		error = xfs_attr_set_args(args);
> +		break;
> +	case XFS_ATTR_OP_FLAGS_REMOVE:
> +		ASSERT(XFS_IFORK_Q((args->dp)));
> +		error = xfs_attr_remove_args(args);
> +		break;
> +	default:
> +		error = -EFSCORRUPTED;
> +	}
> +
> +	/*
> +	 * Mark the transaction dirty, even on error. This ensures the
> +	 * transaction is aborted, which:
> +	 *
> +	 * 1.) releases the ATTRI and frees the ATTRD
> +	 * 2.) shuts down the filesystem
> +	 */
> +	args->trans->t_flags |= XFS_TRANS_DIRTY;
> +	set_bit(XFS_LI_DIRTY, &attrdp->attrd_item.li_flags);
> +
> +	return error;
> +}
> +
> +static int
> +xfs_attr_diff_items(
> +	void				*priv,
> +	struct list_head		*a,
> +	struct list_head		*b)
> +{
> +	return 0;
> +}
> +
> +/* Get an ATTRI. */
> +STATIC void *
> +xfs_attr_create_intent(
> +	struct xfs_trans		*tp,
> +	unsigned int			count)
> +{
> +	struct xfs_attri_log_item	*attrip;
> +
> +	ASSERT(tp != NULL);
> +	ASSERT(count == 1);
> +
> +	attrip = xfs_attri_init(tp->t_mountp);
> +	ASSERT(attrip != NULL);
> +
> +	/*
> +	 * Get a log_item_desc to point at the new item.
> +	 */

Same deal here.

> +	xfs_trans_add_item(tp, &attrip->attri_item);
> +	return attrip;
> +}
> +
> +/* Log an attr to the intent item. */
> +STATIC void
> +xfs_attr_log_item(
> +	struct xfs_trans		*tp,
> +	void				*intent,
> +	struct list_head		*item)
> +{
> +	struct xfs_attri_log_item	*attrip = intent;
> +	struct xfs_attr_item		*attr;
> +	struct xfs_attri_log_format	*attrp;
> +	char				*name_value;
> +
> +	attr = container_of(item, struct xfs_attr_item, xattri_list);
> +	name_value = ((char *)attr) + sizeof(struct xfs_attr_item);
> +
> +	tp->t_flags |= XFS_TRANS_DIRTY;
> +	set_bit(XFS_LI_DIRTY, &attrip->attri_item.li_flags);
> +
> +	/*
> +	 * At this point the xfs_attr_item has been constructed, and we've
> +	 * created the log intent. Fill in the attri log item and log format
> +	 * structure with fields from this xfs_attr_item
> +	 */
> +	attrp = &attrip->attri_format;
> +	attrp->alfi_ino = attr->xattri_ip->i_ino;
> +	attrp->alfi_op_flags = attr->xattri_op_flags;
> +	attrp->alfi_value_len = attr->xattri_value_len;
> +	attrp->alfi_name_len = attr->xattri_name_len;
> +	attrp->alfi_attr_flags = attr->xattri_flags;
> +
> +	attrip->attri_name = name_value;
> +	attrip->attri_value = &name_value[attr->xattri_name_len];
> +	attrip->attri_name_len = attr->xattri_name_len;
> +	attrip->attri_value_len = attr->xattri_value_len;
> +}
> +
> +/* Get an ATTRD so we can process all the attrs. */
> +STATIC void *
> +xfs_attr_create_done(
> +	struct xfs_trans		*tp,
> +	void				*intent,
> +	unsigned int			count)
> +{
> +	return xfs_trans_get_attrd(tp, intent);
> +}
> +
> +/* Process an attr. */
> +STATIC int
> +xfs_attr_finish_item(
> +	struct xfs_trans		*tp,
> +	struct list_head		*item,
> +	void				*done_item,
> +	void				**state)
> +{
> +	struct xfs_attr_item		*attr;
> +	char				*name_value;
> +	int				error;
> +	int				local;
> +	struct xfs_da_args		args;
> +	struct xfs_name			name;
> +	struct xfs_attrd_log_item	*attrdp;
> +	struct xfs_attri_log_item	*attrip;
> +
> +	attr = container_of(item, struct xfs_attr_item, xattri_list);
> +	name_value = ((char *)attr) + sizeof(struct xfs_attr_item);
> +
> +	name.name = name_value;
> +	name.len = attr->xattri_name_len;
> +	name.type = attr->xattri_flags;
> +	error = xfs_attr_args_init(&args, attr->xattri_ip, &name);
> +	if (error)
> +		goto out;
> +
> +	args.hashval = xfs_da_hashname(args.name, args.namelen);
> +	args.value = &name_value[attr->xattri_name_len];
> +	args.valuelen = attr->xattri_value_len;
> +	args.op_flags = XFS_DA_OP_OKNOENT;
> +	args.total = xfs_attr_calc_size(&args, &local);

It feels a little strange to calculate this here since it should be part
of the transaction reservation that already occurred. The interface
requires it however, so maybe it's something we can clean up later. For
now, a one liner comment would be useful:

	/* must match existing transaction block res */
	args.total = xfs_attr_calc_size(&args, &local);
	...

> +	args.trans = tp;
> +
> +	error = xfs_trans_attr(&args, done_item,
> +			attr->xattri_op_flags);

This fits on one 80 column line.

> +out:
> +	/*
> +	 * We are about to free the xfs_attr_item, so we need to remove any
> +	 * refrences that are currently pointing at its members
> +	 */

A little more context would help. I.e.:

"The attrip refers to xfs_attr_item memory to log the name and value
with the intent item. This already occurred when the intent was
committed so these fields are no longer accessed. Clear them out of
caution since we're about to free the xfs_attr_item."

> +	attrdp = (struct xfs_attrd_log_item *)done_item;
> +	attrip = attrdp->attrd_attrip;
> +	attrip->attri_name = NULL;
> +	attrip->attri_value = NULL;
> +	attrip->attri_name_len = 0;
> +	attrip->attri_value_len = 0;
> +

Probably no need to clear the length fields either. It kind of confuses
things IMO.

BTW, I know I suggested this and I don't want to churn this patch to
death, but seeing it now along with the above ->total hack makes me
wonder if we could still more elegantly carry things from the high level
xfs_attr_item to the intent log item. It's not immediately clear to me
what the best option is. Perhaps a separate structure to hold things
like the name, value, tx block res, etc..? I'm ultimately fine with this
for now. Just something to think more about for a follow on cleanup I
suppose..

> +	kmem_free(attr);
> +	return error;
> +}
> +
> +/* Abort all pending ATTRs. */
> +STATIC void
> +xfs_attr_abort_intent(
> +	void				*intent)
> +{
> +	xfs_attri_release(intent);
> +}
> +
> +/* Cancel an attr */
> +STATIC void
> +xfs_attr_cancel_item(
> +	struct list_head		*item)
> +{
> +	struct xfs_attr_item	*attr;
> +
> +	attr = container_of(item, struct xfs_attr_item, xattri_list);
> +	kmem_free(attr);
> +}
> +
> +const struct xfs_defer_op_type xfs_attr_defer_type = {
> +	.max_items	= XFS_ATTRI_MAX_FAST_ATTRS,
> +	.diff_items	= xfs_attr_diff_items,
> +	.create_intent	= xfs_attr_create_intent,
> +	.abort_intent	= xfs_attr_abort_intent,
> +	.log_item	= xfs_attr_log_item,
> +	.create_done	= xfs_attr_create_done,
> +	.finish_item	= xfs_attr_finish_item,
> +	.cancel_item	= xfs_attr_cancel_item,
> +};
> +
> +static inline struct xfs_attri_log_item *ATTRI_ITEM(struct xfs_log_item *lip)
> +{
> +	return container_of(lip, struct xfs_attri_log_item, attri_item);
> +}
> +
> +void
> +xfs_attri_item_free(
> +	struct xfs_attri_log_item	*attrip)
> +{
> +	kmem_free(attrip->attri_item.li_lv_shadow);
> +	kmem_free(attrip);
> +}
> +
> +/*
> + * This returns the number of iovecs needed to log the given attri item. We
> + * only need 1 iovec for an attri item.  It just logs the attr_log_format
> + * structure.
> + */
> +static inline int
> +xfs_attri_item_sizeof(
> +	struct xfs_attri_log_item *attrip)
> +{
> +	return sizeof(struct xfs_attri_log_format);
> +}
> +
> +STATIC void
> +xfs_attri_item_size(
> +	struct xfs_log_item	*lip,
> +	int			*nvecs,
> +	int			*nbytes)
> +{
> +	struct xfs_attri_log_item       *attrip = ATTRI_ITEM(lip);
> +
> +	*nvecs += 1;
> +	*nbytes += xfs_attri_item_sizeof(attrip);
> +
> +	if (attrip->attri_name_len > 0) {
> +		*nvecs += 1;
> +		*nbytes += ATTR_NVEC_SIZE(attrip->attri_name_len);
> +	}

We always need an attr name, right? Perhaps this branch should be
replaced with an assert on ->attri_name_len.

> +
> +	if (attrip->attri_value_len > 0) {
> +		*nvecs += 1;
> +		*nbytes += ATTR_NVEC_SIZE(attrip->attri_value_len);
> +	}
> +}
> +
> +/*
> + * This is called to fill in the vector of log iovecs for the given attri log
> + * item. We use only 1 iovec, and we point that at the attri_log_format
> + * structure embedded in the attri item. It is at this point that we assert
> + * that all of the attr slots in the attri item have been filled.
> + */

Looks like a stale comment. We use up to three iovecs here. I also don't
see any assertion related to attr slots. Irrelevant bit from a different
intent item perhaps?

> +STATIC void
> +xfs_attri_item_format(
> +	struct xfs_log_item	*lip,
> +	struct xfs_log_vec	*lv)
> +{
> +	struct xfs_attri_log_item	*attrip = ATTRI_ITEM(lip);
> +	struct xfs_log_iovec	*vecp = NULL;
> +
> +	attrip->attri_format.alfi_type = XFS_LI_ATTRI;
> +	attrip->attri_format.alfi_size = 1;
> +
> +	/*
> +	 * This size accounting must be done before copying the attrip into the
> +	 * iovec.  If we do it after, the wrong size will be recorded to the log
> +	 * and we trip across assertion checks for bad region sizes later during
> +	 * the log recovery.
> +	 */
> +	if (attrip->attri_name_len > 0)
> +		attrip->attri_format.alfi_size++;

Similar comment as before wrt to a required name.

> +	if (attrip->attri_value_len > 0)
> +		attrip->attri_format.alfi_size++;
> +
> +	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRI_FORMAT,
> +			&attrip->attri_format,
> +			xfs_attri_item_sizeof(attrip));
> +	if (attrip->attri_name_len > 0)
> +		xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_NAME,
> +				attrip->attri_name,
> +				ATTR_NVEC_SIZE(attrip->attri_name_len));
> +
> +	if (attrip->attri_value_len > 0)
> +		xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_VALUE,
> +				attrip->attri_value,
> +				ATTR_NVEC_SIZE(attrip->attri_value_len));
> +}
> +
> +
...
> +
> +/*
> + * This is called to fill in the vector of log iovecs for the
> + * given attrd log item. We use only 1 iovec, and we point that
> + * at the attr_log_format structure embedded in the attrd item.
> + * It is at this point that we assert that all of the attr
> + * slots in the attrd item have been filled.
> + */

Comment can be widened to 80 cols and another reference to an assertion
that doesn't exist.

> +STATIC void
> +xfs_attrd_item_format(
> +	struct xfs_log_item	*lip,
> +	struct xfs_log_vec	*lv)
> +{
> +	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
> +	struct xfs_log_iovec	*vecp = NULL;
> +
> +	attrdp->attrd_format.alfd_type = XFS_LI_ATTRD;
> +	attrdp->attrd_format.alfd_size = 1;
> +
> +	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRD_FORMAT,
> +			&attrdp->attrd_format, xfs_attrd_item_sizeof(attrdp));
> +}
> +
...
> +/*
> + * Process an attr intent item that was recovered from the log.  We need to
> + * delete the attr that it describes.
> + */
> +int
> +xfs_attri_recover(
> +	struct xfs_mount		*mp,
> +	struct xfs_attri_log_item	*attrip)
> +{
> +	struct xfs_inode		*ip;
> +	struct xfs_attrd_log_item	*attrdp;
> +	struct xfs_da_args		args;
> +	struct xfs_attri_log_format	*attrp;
> +	struct xfs_trans_res		tres;
> +	int				local;
> +	int				error = 0;
> +	int				rsvd = 0;
> +	struct xfs_name			name;
> +
> +	ASSERT(!test_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags));
> +
> +	/*
> +	 * First check the validity of the attr described by the ATTRI.  If any
> +	 * are bad, then assume that all are bad and just toss the ATTRI.
> +	 */
> +	attrp = &attrip->attri_format;
> +	if (
> +	    !(attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_SET ||
> +		attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_REMOVE) ||
> +	      (attrp->alfi_value_len > XATTR_SIZE_MAX) ||
> +	      (attrp->alfi_name_len > XATTR_NAME_MAX) ||
> +	      (attrp->alfi_name_len == 0)
> +	) {

Can we fix the brace usage here?

> +		/*
> +		 * This will pull the ATTRI from the AIL and free the memory
> +		 * associated with it.
> +		 */
> +		set_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags);
> +		xfs_attri_release(attrip);
> +		return -EIO;
> +	}
> +
> +	attrp = &attrip->attri_format;

Just assigned attrp above.

> +	error = xfs_iget(mp, 0, attrp->alfi_ino, 0, 0, &ip);
> +	if (error)
> +		return error;
> +

I don't see any corresponding xfs_irele() in this function.

> +	name.name = attrip->attri_name;
> +	name.len = attrp->alfi_name_len;
> +	name.type = attrp->alfi_attr_flags;
> +	error = xfs_attr_args_init(&args, ip, &name);
> +	if (error)
> +		return error;
> +
> +	args.hashval = xfs_da_hashname(args.name, args.namelen);
> +	args.value = attrip->attri_value;
> +	args.valuelen = attrp->alfi_value_len;
> +	args.op_flags = XFS_DA_OP_OKNOENT;
> +	args.total = xfs_attr_calc_size(&args, &local);
> +
> +	tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
> +			M_RES(mp)->tr_attrsetrt.tr_logres * args.total;
> +	tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
> +	tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
> +
> +	error = xfs_trans_alloc(mp, &tres, args.total,  0,
> +				rsvd ? XFS_TRANS_RESERVE : 0, &args.trans);
> +	if (error)
> +		return error;
> +	attrdp = xfs_trans_get_attrd(args.trans, attrip);
> +
> +	xfs_ilock(ip, XFS_ILOCK_EXCL);
> +
> +	xfs_trans_ijoin(args.trans, ip, 0);
> +	error = xfs_trans_attr(&args, attrdp, attrp->alfi_op_flags);
> +	if (error)
> +		goto abort_error;
> +
> +
> +	set_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags);
> +	xfs_trans_log_inode(args.trans, ip, XFS_ILOG_CORE | XFS_ILOG_ADATA);
> +	error = xfs_trans_commit(args.trans);
> +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
> +	return error;
> +
> +abort_error:
> +	xfs_trans_cancel(args.trans);
> +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
> +	return error;
> +}
> diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h
> new file mode 100644
> index 0000000..aad32ed
> --- /dev/null
> +++ b/fs/xfs/xfs_attr_item.h
> @@ -0,0 +1,102 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2019 Oracle.  All Rights Reserved.
> + * Author: Allison Henderson <allison.henderson@oracle.com>
> + */
> +#ifndef	__XFS_ATTR_ITEM_H__
> +#define	__XFS_ATTR_ITEM_H__
> +
> +/* kernel only ATTRI/ATTRD definitions */
> +
> +struct xfs_mount;
> +struct kmem_zone;
> +
> +/*
> + * Max number of attrs in fast allocation path.
> + */
> +#define XFS_ATTRI_MAX_FAST_ATTRS        1
> +

I don't think we really need a macro for this given there is no concept
of a fast path. I'd just hardcode the 1 in the dfops structure.

> +
> +/*
> + * Define ATTR flag bits. Manipulated by set/clear/test_bit operators.
> + */
> +#define	XFS_ATTRI_RECOVERED	1
> +
> +
> +/* iovec length must be 32-bit aligned */
> +#define ATTR_NVEC_SIZE(size) (size == sizeof(int32_t) ? sizeof(int32_t) : \
> +				size + sizeof(int32_t) - \
> +				(size % sizeof(int32_t)))
> +
> +/*
> + * This is the "attr intention" log item.  It is used to log the fact that some
> + * need to be processed.  It is used in conjunction with the "attr done" log

Some what need to be processed?

> + * item described below.
> + *
> + * The ATTRI is reference counted so that it is not freed prior to both the
> + * ATTRI and ATTRD being committed and unpinned. This ensures the ATTRI is
> + * inserted into the AIL even in the event of out of order ATTRI/ATTRD
> + * processing. In other words, an ATTRI is born with two references:
> + *
> + *      1.) an ATTRI held reference to track ATTRI AIL insertion
> + *      2.) an ATTRD held reference to track ATTRD commit
> + *
> + * On allocation, both references are the responsibility of the caller. Once the
> + * ATTRI is added to and dirtied in a transaction, ownership of reference one
> + * transfers to the transaction. The reference is dropped once the ATTRI is
> + * inserted to the AIL or in the event of failure along the way (e.g., commit
> + * failure, log I/O error, etc.). Note that the caller remains responsible for
> + * the ATTRD reference under all circumstances to this point. The caller has no
> + * means to detect failure once the transaction is committed, however.
> + * Therefore, an ATTRD is required after this point, even in the event of
> + * unrelated failure.
> + *
> + * Once an ATTRD is allocated and dirtied in a transaction, reference two
> + * transfers to the transaction. The ATTRD reference is dropped once it reaches
> + * the unpin handler. Similar to the ATTRI, the reference also drops in the
> + * event of commit failure or log I/O errors. Note that the ATTRD is not
> + * inserted in the AIL, so at this point both the ATTI and ATTRD are freed.
> + */
> +struct xfs_attri_log_item {
> +	struct xfs_log_item		attri_item;
> +	atomic_t			attri_refcount;
> +	unsigned long			attri_flags;	/* misc flags */
> +	int				attri_name_len;
> +	void				*attri_name;
> +	int				attri_value_len;
> +	void				*attri_value;
> +	struct xfs_attri_log_format	attri_format;
> +};
> +
> +/*
> + * This is the "attr done" log item.  It is used to log the fact that some attrs
> + * earlier mentioned in an attri item have been freed.
> + */
> +struct xfs_attrd_log_item {
> +	struct xfs_log_item		attrd_item;
> +	struct xfs_attri_log_item	*attrd_attrip;
> +	struct xfs_attrd_log_format	attrd_format;
> +};
> +
> +/*
> + * Max number of attrs in fast allocation path.
> + */
> +#define	XFS_ATTRD_MAX_FAST_ATTRS	1
> +

This define is unused.

> +extern struct kmem_zone	*xfs_attri_zone;
> +extern struct kmem_zone	*xfs_attrd_zone;
> +

The above zones don't exist either.

> +struct xfs_attri_log_item	*xfs_attri_init(struct xfs_mount *mp);
> +struct xfs_attrd_log_item	*xfs_attrd_init(struct xfs_mount *mp,
> +					struct xfs_attri_log_item *attrip);
> +int xfs_attri_copy_format(struct xfs_log_iovec *buf,
> +			   struct xfs_attri_log_format *dst_attri_fmt);
> +int xfs_attrd_copy_format(struct xfs_log_iovec *buf,
> +			   struct xfs_attrd_log_format *dst_attrd_fmt);

Function doesn't exist.

> +void			xfs_attri_item_free(struct xfs_attri_log_item *attrip);
> +void			xfs_attri_release(struct xfs_attri_log_item *attrip);
> +
> +int			xfs_attri_recover(struct xfs_mount *mp,
> +					struct xfs_attri_log_item *attrip);
> +
> +#endif	/* __XFS_ATTR_ITEM_H__ */
> diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
> index 00e9f5c..2fbd180 100644
> --- a/fs/xfs/xfs_log.c
> +++ b/fs/xfs/xfs_log.c
> @@ -2005,6 +2005,10 @@ xlog_print_tic_res(
>  	    REG_TYPE_STR(CUD_FORMAT, "cud_format"),
>  	    REG_TYPE_STR(BUI_FORMAT, "bui_format"),
>  	    REG_TYPE_STR(BUD_FORMAT, "bud_format"),
> +	    REG_TYPE_STR(ATTRI_FORMAT, "attri_format"),
> +	    REG_TYPE_STR(ATTRD_FORMAT, "attrd_format"),
> +	    REG_TYPE_STR(ATTR_NAME, "attr_name"),
> +	    REG_TYPE_STR(ATTR_VALUE, "attr_value"),
>  	};
>  	BUILD_BUG_ON(ARRAY_SIZE(res_type_str) != XLOG_REG_TYPE_MAX + 1);
>  #undef REG_TYPE_STR
> diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
> index 13d1d3e..233efdb3 100644
> --- a/fs/xfs/xfs_log_recover.c
> +++ b/fs/xfs/xfs_log_recover.c
...
> @@ -3422,6 +3425,119 @@ xlog_recover_efd_pass2(
>  	return 0;
>  }
>  
> +STATIC int
> +xlog_recover_attri_pass2(
> +	struct xlog                     *log,
> +	struct xlog_recover_item        *item,
> +	xfs_lsn_t                       lsn)
> +{
> +	int                             error;
> +	struct xfs_mount                *mp = log->l_mp;
> +	struct xfs_attri_log_item       *attrip;
> +	struct xfs_attri_log_format     *attri_formatp;
> +	char				*name = NULL;
> +	char				*value = NULL;
> +	int				region = 0;
> +
> +	attri_formatp = item->ri_buf[region].i_addr;
> +
> +	attrip = xfs_attri_init(mp);
> +	error = xfs_attri_copy_format(&item->ri_buf[region],
> +				      &attrip->attri_format);
> +	if (error) {
> +		xfs_attri_item_free(attrip);
> +		return error;
> +	}
> +
> +	attrip->attri_name_len = attri_formatp->alfi_name_len;
> +	attrip->attri_value_len = attri_formatp->alfi_value_len;
> +	attrip = kmem_realloc(attrip, sizeof(struct xfs_attri_log_item) +
> +			      attrip->attri_name_len + attrip->attri_value_len,
> +			      KM_SLEEP);
> +
> +	if (attrip->attri_name_len > 0) {
> +		region++;
> +		name = ((char *)attrip) + sizeof(struct xfs_attri_log_item);
> +		memcpy(name, item->ri_buf[region].i_addr,
> +		       attrip->attri_name_len);
> +		attrip->attri_name = name;
> +	}

Same comment wrt to a required name.

> +
> +	if (attrip->attri_value_len > 0) {
> +		region++;
> +		value = ((char *)attrip) + sizeof(struct xfs_attri_log_item) +
> +			attrip->attri_name_len;
> +		memcpy(value, item->ri_buf[region].i_addr,
> +			attrip->attri_value_len);
> +		attrip->attri_value = value;
> +	}
> +
> +	spin_lock(&log->l_ailp->ail_lock);
> +	/*
> +	 * The ATTRI has two references. One for the ATTRD and one for ATTRI to
> +	 * ensure it makes it into the AIL. Insert the ATTRI into the AIL
> +	 * directly and drop the ATTRI reference. Note that
> +	 * xfs_trans_ail_update() drops the AIL lock.
> +	 */
> +	xfs_trans_ail_update(log->l_ailp, &attrip->attri_item, lsn);
> +	xfs_attri_release(attrip);
> +	return 0;
> +}
> +
> +
...
> diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
> index 64d7f17..95924dc 100644
> --- a/fs/xfs/xfs_trans.h
> +++ b/fs/xfs/xfs_trans.h
> @@ -26,6 +26,9 @@ struct xfs_cui_log_item;
>  struct xfs_cud_log_item;
>  struct xfs_bui_log_item;
>  struct xfs_bud_log_item;
> +struct xfs_attrd_log_item;
> +struct xfs_attri_log_item;
> +struct xfs_da_args;
>  

What are the xfs_trans.h changes for?

Brian

>  struct xfs_log_item {
>  	struct list_head		li_ail;		/* AIL pointers */
> @@ -229,7 +232,6 @@ void		xfs_trans_log_buf(struct xfs_trans *, struct xfs_buf *, uint,
>  void		xfs_trans_dirty_buf(struct xfs_trans *, struct xfs_buf *);
>  bool		xfs_trans_buf_is_dirty(struct xfs_buf *bp);
>  void		xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
> -
>  int		xfs_trans_commit(struct xfs_trans *);
>  int		xfs_trans_roll(struct xfs_trans **);
>  int		xfs_trans_roll_inode(struct xfs_trans **, struct xfs_inode *);
> -- 
> 2.7.4
> 

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

* Re: [PATCH v2 05/18] xfs: Add xfs_has_attr and subroutines
  2019-08-12 15:56   ` Darrick J. Wong
@ 2019-08-12 19:29     ` Allison Collins
  2019-08-12 20:00       ` Darrick J. Wong
  0 siblings, 1 reply; 56+ messages in thread
From: Allison Collins @ 2019-08-12 19:29 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 8/12/19 8:56 AM, Darrick J. Wong wrote:
> On Fri, Aug 09, 2019 at 02:37:13PM -0700, Allison Collins wrote:
>> From: Allison Henderson <allison.henderson@oracle.com>
>>
>> This patch adds a new functions to check for the existence of
>> an attribute.  Subroutines are also added to handle the cases
>> of leaf blocks, nodes or shortform.  Common code that appears
>> in existing attr add and remove functions have been factored
>> out to help reduce the appearence of duplicated code.  We will
>> need these routines later for delayed attributes since delayed
>> operations cannot return error codes.
>>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c      | 151 +++++++++++++++++++++++++++---------------
>>   fs/xfs/libxfs/xfs_attr.h      |   1 +
>>   fs/xfs/libxfs/xfs_attr_leaf.c |  82 +++++++++++++++--------
>>   fs/xfs/libxfs/xfs_attr_leaf.h |   2 +
>>   4 files changed, 158 insertions(+), 78 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index a2fba0c..72af8e2 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -48,6 +48,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>>   STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
>>   STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
>>   STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>> +STATIC int xfs_leaf_has_attr(xfs_da_args_t *args, struct xfs_buf **bp);
> 
> Trailing whitespace, and please use "struct xfs_da_args", not the
> typedef...
Ok, will that clean up.

> 
>>   
>>   /*
>>    * Internal routines when attribute list is more than one block.
>> @@ -55,6 +56,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>>   STATIC int xfs_attr_node_get(xfs_da_args_t *args);
>>   STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
>>   STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
>> +STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
>> +				 struct xfs_da_state **state);
>>   STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>>   STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>>   
>> @@ -278,6 +281,32 @@ xfs_attr_set_args(
>>   }
>>   
>>   /*
>> + * Return EEXIST if attr is found, or ENOATTR if not
>> + */
>> +int
>> +xfs_has_attr(
>> +	struct xfs_da_args      *args)
>> +{
>> +	struct xfs_inode        *dp = args->dp;
>> +	struct xfs_buf		*bp;
>> +	int                     error;
>> +
>> +	if (!xfs_inode_hasattr(dp)) {
>> +		error = -ENOATTR;
>> +	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>> +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
>> +		error = xfs_shortform_has_attr(args, NULL, NULL);
>> +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> +		error = xfs_leaf_has_attr(args, &bp);
>> +		xfs_trans_brelse(args->trans, bp);
>> +	} else {
>> +		error = xfs_attr_node_hasname(args, NULL);
>> +	}
>> +
>> +	return error;
>> +}
>> +
>> +/*
>>    * Remove the attribute specified in @args.
>>    */
>>   int
>> @@ -616,26 +645,17 @@ STATIC int
>>   xfs_attr_leaf_addname(
>>   	struct xfs_da_args	*args)
>>   {
>> -	struct xfs_inode	*dp;
>>   	struct xfs_buf		*bp;
>>   	int			retval, error, forkoff;
>> +	struct xfs_inode	*dp = args->dp;
>>   
>>   	trace_xfs_attr_leaf_addname(args);
>>   
>>   	/*
>> -	 * Read the (only) block in the attribute list in.
>> -	 */
>> -	dp = args->dp;
>> -	args->blkno = 0;
>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
>> -	if (error)
>> -		return error;
>> -
>> -	/*
>>   	 * Look up the given attribute in the leaf block.  Figure out if
>>   	 * the given flags produce an error or call for an atomic rename.
>>   	 */
>> -	retval = xfs_attr3_leaf_lookup_int(bp, args);
>> +	retval = xfs_leaf_has_attr(args, &bp);
>>   	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
>>   		xfs_trans_brelse(args->trans, bp);
>>   		return retval;
>> @@ -787,6 +807,26 @@ xfs_attr_leaf_addname(
>>   }
>>   
>>   /*
>> + * Return EEXIST if attr is found, or ENOATTR if not
>> + */
>> +STATIC int
>> +xfs_leaf_has_attr(
>> +	struct xfs_da_args      *args,
>> +	struct xfs_buf		**bp)
>> +{
>> +	int                     error = 0;
>> +
>> +	args->blkno = 0;
>> +	error = xfs_attr3_leaf_read(args->trans, args->dp,
>> +			args->blkno, -1, bp);
> 
> Can we please get rid of these -1 and -2 magic values that eventually
> become the mappedbno argument to xfs_dabuf_map?
Sure, maybe we can add some constants here.  I took a quick peek at 
xfs_dabuf_map.  Maybe we can add something like this:

#define MBNO_NOMAP	-1
#define MBNO_HOLE_OK	-2


> 
>> +	if (error)
>> +		return error;
>> +
>> +	error = xfs_attr3_leaf_lookup_int(*bp, args);
>> +	return error;
> 
> "return xfs_attr3_leaf_lookup_int..." ?
> 
>> +}
>> +
>> +/*
>>    * Remove a name from the leaf attribute list structure
>>    *
>>    * This leaf block cannot have a "remote" value, we only call this routine
>> @@ -806,12 +846,8 @@ xfs_attr_leaf_removename(
>>   	 * Remove the attribute.
>>   	 */
>>   	dp = args->dp;
>> -	args->blkno = 0;
>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
>> -	if (error)
>> -		return error;
>>   
>> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>> +	error = xfs_leaf_has_attr(args, &bp);
>>   	if (error == -ENOATTR) {
>>   		xfs_trans_brelse(args->trans, bp);
>>   		return error;
>> @@ -848,12 +884,7 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>>   
>>   	trace_xfs_attr_leaf_get(args);
>>   
>> -	args->blkno = 0;
>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
>> -	if (error)
>> -		return error;
>> -
>> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>> +	error = xfs_leaf_has_attr(args, &bp);
>>   	if (error != -EEXIST)  {
>>   		xfs_trans_brelse(args->trans, bp);
>>   		return error;
>> @@ -866,6 +897,43 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>>   	return error;
>>   }
>>   
>> +/*
>> + * Return EEXIST if attr is found, or ENOATTR if not
>> + * statep: If not null is set to point at the found state.  Caller will
>> + * 	   be responsible for freeing the state in this case.
>> + */
>> +STATIC int
>> +xfs_attr_node_hasname(
>> +	struct xfs_da_args	*args,
>> +	struct xfs_da_state	**statep)
>> +{
>> +	struct xfs_da_state	*state;
>> +	struct xfs_inode	*dp;
>> +	int			retval, error;
>> +
>> +	/*
>> +	 * Tie a string around our finger to remind us where we are.
>> +	 */
>> +	dp = args->dp;
>> +	state = xfs_da_state_alloc();
>> +	state->args = args;
>> +	state->mp = dp->i_mount;
>> +
>> +	/*
>> +	 * Search to see if name exists, and get back a pointer to it.
>> +	 */
>> +	error = xfs_da3_node_lookup_int(state, &retval);
>> +	if (error == 0)
>> +		error = retval;
>> +
>> +	if (statep != NULL)
>> +		*statep = state;
>> +	else
>> +		xfs_da_state_free(state);
>> +
>> +	return error;
>> +}
>> +
>>   /*========================================================================
>>    * External routines when attribute list size > geo->blksize
>>    *========================================================================*/
>> @@ -898,17 +966,14 @@ xfs_attr_node_addname(
>>   	dp = args->dp;
>>   	mp = dp->i_mount;
>>   restart:
>> -	state = xfs_da_state_alloc();
>> -	state->args = args;
>> -	state->mp = mp;
>> -
>>   	/*
>>   	 * Search to see if name already exists, and get back a pointer
>>   	 * to where it should go.
>>   	 */
>> -	error = xfs_da3_node_lookup_int(state, &retval);
>> -	if (error)
>> +	error = xfs_attr_node_hasname(args, &state);
>> +	if (error == -EEXIST)
>>   		goto out;
>> +
>>   	blk = &state->path.blk[ state->path.active-1 ];
>>   	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>>   	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
>> @@ -1113,29 +1178,15 @@ xfs_attr_node_removename(
>>   {
>>   	struct xfs_da_state	*state;
>>   	struct xfs_da_state_blk	*blk;
>> -	struct xfs_inode	*dp;
>>   	struct xfs_buf		*bp;
>>   	int			retval, error, forkoff;
>> +	struct xfs_inode	*dp = args->dp;
>>   
>>   	trace_xfs_attr_node_removename(args);
>>   
>> -	/*
>> -	 * Tie a string around our finger to remind us where we are.
>> -	 */
>> -	dp = args->dp;
>> -	state = xfs_da_state_alloc();
>> -	state->args = args;
>> -	state->mp = dp->i_mount;
>> -
>> -	/*
>> -	 * Search to see if name exists, and get back a pointer to it.
>> -	 */
>> -	error = xfs_da3_node_lookup_int(state, &retval);
>> -	if (error || (retval != -EEXIST)) {
>> -		if (error == 0)
>> -			error = retval;
>> +	error = xfs_attr_node_hasname(args, &state);
>> +	if (error != -EEXIST)
>>   		goto out;
>> -	}
>>   
>>   	/*
>>   	 * If there is an out-of-line value, de-allocate the blocks.
>> @@ -1355,17 +1406,13 @@ xfs_attr_node_get(xfs_da_args_t *args)
>>   
>>   	trace_xfs_attr_node_get(args);
>>   
>> -	state = xfs_da_state_alloc();
>> -	state->args = args;
>> -	state->mp = args->dp->i_mount;
>> -
>>   	/*
>>   	 * Search to see if name exists, and get back a pointer to it.
>>   	 */
>> -	error = xfs_da3_node_lookup_int(state, &retval);
>> -	if (error) {
>> +	error = xfs_attr_node_hasname(args, &state);
>> +	if (error != -EEXIST) {
>>   		retval = error;
>> -	} else if (retval == -EEXIST) {
>> +	} else {
>>   		blk = &state->path.blk[ state->path.active-1 ];
>>   		ASSERT(blk->bp != NULL);
>>   		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index 0bade83..c082d34 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -170,6 +170,7 @@ int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
>>   		 unsigned char *value, int valuelen);
>>   int xfs_attr_set_args(struct xfs_da_args *args);
>>   int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name);
>> +int xfs_has_attr(struct xfs_da_args *args);
>>   int xfs_attr_remove_args(struct xfs_da_args *args);
>>   int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>>   		  int flags, struct attrlist_cursor_kern *cursor);
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>> index 70eb941..8d2e11f 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -546,6 +546,53 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
>>   }
>>   
>>   /*
>> + * Return EEXIST if attr is found, or ENOATTR if not
>> + * args:  args containing attribute name and namelen
>> + * sfep:  If not null, pointer will be set to the last attr entry found
>> + * basep: If not null, pointer is set to the byte offset of the entry in the
>> + *	  list
>> + */
>> +int
>> +xfs_shortform_has_attr(
>> +	struct xfs_da_args	 *args,
>> +	struct xfs_attr_sf_entry **sfep,
>> +	int			 *basep)
>> +{
>> +	struct xfs_attr_shortform *sf;
>> +	struct xfs_attr_sf_entry *sfe;
>> +	int			base = sizeof(struct xfs_attr_sf_hdr);
>> +	int			size = 0;
>> +	int			end;
>> +	int			i;
>> +
>> +	base = sizeof(struct xfs_attr_sf_hdr);
>> +	sf = (struct xfs_attr_shortform *)args->dp->i_afp->if_u1.if_data;
>> +	sfe = &sf->list[0];
>> +	end = sf->hdr.count;
>> +	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
>> +			base += size, i++) {
>> +		size = XFS_ATTR_SF_ENTSIZE(sfe);
>> +		if (sfe->namelen != args->namelen)
>> +			continue;
>> +		if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
>> +			continue;
>> +		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
>> +			continue;
>> +		break;
>> +	}
>> +
>> +	if (sfep != NULL)
>> +		*sfep = sfe;
>> +
>> +	if (basep != NULL)
>> +		*basep = base;
>> +
>> +	if (i == end)
>> +		return -ENOATTR;
>> +	return -EEXIST;
>> +}
>> +
>> +/*
>>    * Add a name/value pair to the shortform attribute list.
>>    * Overflow from the inode has already been checked for.
>>    */
>> @@ -554,7 +601,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>>   {
>>   	xfs_attr_shortform_t *sf;
>>   	xfs_attr_sf_entry_t *sfe;
>> -	int i, offset, size;
>> +	int offset, size, error;
>>   	xfs_mount_t *mp;
>>   	xfs_inode_t *dp;
>>   	struct xfs_ifork *ifp;
>> @@ -568,18 +615,11 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>>   	ifp = dp->i_afp;
>>   	ASSERT(ifp->if_flags & XFS_IFINLINE);
>>   	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
>> -	sfe = &sf->list[0];
>> -	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
>> +	error = xfs_shortform_has_attr(args, &sfe, NULL);
>>   #ifdef DEBUG
>> -		if (sfe->namelen != args->namelen)
>> -			continue;
>> -		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
>> -			continue;
>> -		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
>> -			continue;
>> +	if (error == -EEXIST)
>>   		ASSERT(0);
> 
> ASSERT(error != -EEXIST); ?  Without the #ifdef DEBUG since ASSERT does
> nothing if DEBUG isn't defined...
> 
>>   #endif
>> -	}
>>   
>>   	offset = (char *)sfe - (char *)sf;
>>   	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
>> @@ -626,7 +666,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
>>   {
>>   	xfs_attr_shortform_t *sf;
>>   	xfs_attr_sf_entry_t *sfe;
>> -	int base, size=0, end, totsize, i;
>> +	int base, size = 0, end, totsize, error;
>>   	xfs_mount_t *mp;
>>   	xfs_inode_t *dp;
> 
> Please fix the typedef and indentation here while you're changing this
> (and all the other attr) functions.
> 
> Otherwise, I very much like this cleanup. :)
Great!  I'll tidy these up then.  Thx for the review!

Allison

> 
> --D
> 
>>   
>> @@ -634,23 +674,13 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
>>   
>>   	dp = args->dp;
>>   	mp = dp->i_mount;
>> -	base = sizeof(xfs_attr_sf_hdr_t);
>>   	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
>> -	sfe = &sf->list[0];
>>   	end = sf->hdr.count;
>> -	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
>> -					base += size, i++) {
>> -		size = XFS_ATTR_SF_ENTSIZE(sfe);
>> -		if (sfe->namelen != args->namelen)
>> -			continue;
>> -		if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
>> -			continue;
>> -		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
>> -			continue;
>> -		break;
>> -	}
>> -	if (i == end)
>> -		return -ENOATTR;
>> +
>> +	error = xfs_shortform_has_attr(args, &sfe, &base);
>> +	if (error == -ENOATTR)
>> +		return error;
>> +	size = XFS_ATTR_SF_ENTSIZE(sfe);
>>   
>>   	/*
>>   	 * Fix up the attribute fork data, covering the hole
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
>> index 7b74e18..be1f636 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
>> @@ -39,6 +39,8 @@ int	xfs_attr_shortform_getvalue(struct xfs_da_args *args);
>>   int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
>>   			struct xfs_buf **leaf_bp);
>>   int	xfs_attr_shortform_remove(struct xfs_da_args *args);
>> +int	xfs_shortform_has_attr(struct xfs_da_args *args,
>> +			       struct xfs_attr_sf_entry **sfep, int *basep);
>>   int	xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
>>   int	xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes);
>>   xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_inode *ip);
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v2 06/18] xfs: Factor out new helper functions xfs_attr_rmtval_set
  2019-08-12 16:01   ` Darrick J. Wong
@ 2019-08-12 19:29     ` Allison Collins
  0 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-12 19:29 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 8/12/19 9:01 AM, Darrick J. Wong wrote:
> On Fri, Aug 09, 2019 at 02:37:14PM -0700, Allison Collins wrote:
>> Break xfs_attr_rmtval_set into two helper functions
>> xfs_attr_rmt_find_hole and xfs_attr_rmtval_set_value.
>> xfs_attr_rmtval_set rolls the transaction between the
>> helpers, but delayed operations cannot.  We will use
>> the helpers later when constructing new delayed
>> attribute routines.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr_remote.c | 73 +++++++++++++++++++++++++++++++----------
>>   fs/xfs/libxfs/xfs_attr_remote.h |  4 ++-
>>   2 files changed, 58 insertions(+), 19 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index 4eb30d3..c421412 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>> @@ -21,6 +21,7 @@
>>   #include "xfs_attr.h"
>>   #include "xfs_trace.h"
>>   #include "xfs_error.h"
>> +#include "xfs_attr_remote.h"
>>   
>>   #define ATTR_RMTVALUE_MAPSIZE	1	/* # of map entries at once */
>>   
>> @@ -430,34 +431,18 @@ xfs_attr_rmtval_set(
>>   	struct xfs_da_args	*args)
>>   {
>>   	struct xfs_inode	*dp = args->dp;
>> -	struct xfs_mount	*mp = dp->i_mount;
>>   	struct xfs_bmbt_irec	map;
>>   	xfs_dablk_t		lblkno;
>>   	xfs_fileoff_t		lfileoff = 0;
>> -	uint8_t			*src = args->value;
>>   	int			blkcnt;
>> -	int			valuelen;
>>   	int			nmap;
>>   	int			error;
>> -	int			offset = 0;
>>   
>> -	trace_xfs_attr_rmtval_set(args);
>> -
>> -	/*
>> -	 * Find a "hole" in the attribute address space large enough for
>> -	 * us to drop the new attribute's value into. Because CRC enable
>> -	 * attributes have headers, we can't just do a straight byte to FSB
>> -	 * conversion and have to take the header space into account.
>> -	 */
>> -	blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
>> -	error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
>> -						   XFS_ATTR_FORK);
>> +	error = xfs_attr_rmt_find_hole(args, &blkcnt, &lfileoff);
>>   	if (error)
>>   		return error;
>>   
>> -	args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
>> -	args->rmtblkcnt = blkcnt;
>> -
>> +	lblkno = (xfs_dablk_t)lfileoff;
>>   	/*
>>   	 * Roll through the "value", allocating blocks on disk as required.
>>   	 */
>> @@ -498,6 +483,58 @@ xfs_attr_rmtval_set(
>>   			return error;
>>   	}
>>   
>> +	error = xfs_attr_rmtval_set_value(args);
>> +	return error;
>> +}
>> +
>> +
>> +
> 
> Only need one blank line between functions.
Ok, will trim out

> 
>> +int
>> +xfs_attr_rmt_find_hole(
>> +	struct xfs_da_args	*args,
>> +	int			*blkcnt,
>> +	xfs_fileoff_t		*lfileoff)
>> +{
>> +	struct xfs_inode        *dp = args->dp;
>> +	struct xfs_mount	*mp = dp->i_mount;
>> +	int			error;
>> +
>> +	trace_xfs_attr_rmtval_set(args);
> 
> Shouldn't this be in the xfs_attr_rmtval_set_value function?
> We're not actually setting anything here, we're just looking for holes.
Yes, that would probably make more sense there.  :-)

> 
>> +
>> +	/*
>> +	 * Find a "hole" in the attribute address space large enough for
>> +	 * us to drop the new attribute's value into. Because CRC enable
> 
> This first sentence would make a lovely comment above this function
> telling us what it does.
Ok, that sounds good, I will move that up

> 
>> +	 * attributes have headers, we can't just do a straight byte to FSB
>> +	 * conversion and have to take the header space into account.
>> +	 */
>> +	*blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
> 
> Can the callers be refactored to use args->rmtblkcnt to eliminate the
> @blkcnt parameter?

Sure, I think that would be ok.  I'll see if I can clean that out.
Thanks!

Allison

> 
> --D
> 
>> +	error = xfs_bmap_first_unused(args->trans, args->dp, *blkcnt, lfileoff,
>> +						   XFS_ATTR_FORK);
>> +	if (error)
>> +		return error;
>> +
>> +	args->rmtblkno = (xfs_dablk_t)*lfileoff;
>> +	args->rmtblkcnt = *blkcnt;
>> +
>> +	return 0;
>> +}
>> +
>> +int
>> +xfs_attr_rmtval_set_value(
>> +	struct xfs_da_args	*args)
>> +{
>> +	struct xfs_inode	*dp = args->dp;
>> +	struct xfs_mount	*mp = dp->i_mount;
>> +	struct xfs_bmbt_irec	map;
>> +	xfs_dablk_t		lblkno;
>> +	uint8_t			*src = args->value;
>> +	int			blkcnt;
>> +	int			valuelen;
>> +	int			nmap;
>> +	int			error;
>> +	int			offset = 0;
>> +
>> +
>>   	/*
>>   	 * Roll through the "value", copying the attribute value to the
>>   	 * already-allocated blocks.  Blocks are written synchronously
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
>> index 9d20b66..2a73cd9 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.h
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
>> @@ -11,5 +11,7 @@ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen);
>>   int xfs_attr_rmtval_get(struct xfs_da_args *args);
>>   int xfs_attr_rmtval_set(struct xfs_da_args *args);
>>   int xfs_attr_rmtval_remove(struct xfs_da_args *args);
>> -
>> +int xfs_attr_rmtval_set_value(struct xfs_da_args *args);
>> +int xfs_attr_rmt_find_hole(struct xfs_da_args *args, int *blkcnt,
>> +			   xfs_fileoff_t *lfileoff);
>>   #endif /* __XFS_ATTR_REMOTE_H__ */
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v2 07/18] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags
  2019-08-12 16:30     ` Darrick J. Wong
@ 2019-08-12 19:31       ` Allison Collins
  0 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-12 19:31 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 8/12/19 9:30 AM, Darrick J. Wong wrote:
> On Mon, Aug 12, 2019 at 09:02:52AM -0700, Darrick J. Wong wrote:
>> On Fri, Aug 09, 2019 at 02:37:15PM -0700, Allison Collins wrote:
>>> Since delayed operations cannot roll transactions, factor
>>> up the transaction handling into the calling function
>>>
>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>>
>> Looks ok,
>> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> 
> No, not ok!
> 
>>> ---
>>>   fs/xfs/libxfs/xfs_attr.c      | 10 ++++++++++
>>>   fs/xfs/libxfs/xfs_attr_leaf.c |  5 -----
>>>   2 files changed, 10 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>> index 72af8e2..f36c792 100644
>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>> @@ -752,6 +752,11 @@ xfs_attr_leaf_addname(
>>>   		error = xfs_attr3_leaf_flipflags(args);
>>>   		if (error)
>>>   			return error;
>>> +		/*
>>> +		 * Commit the flag value change and start the next trans in
>>> +		 * series.
>>> +		 */
>>> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
> 
> Lost error value here!
> 
>>>   
>>>   		/*
>>>   		 * Dismantle the "old" attribute/value pair by removing
>>> @@ -1090,6 +1095,11 @@ xfs_attr_node_addname(
>>>   		error = xfs_attr3_leaf_flipflags(args);
>>>   		if (error)
>>>   			goto out;
>>> +		/*
>>> +		 * Commit the flag value change and start the next trans in
>>> +		 * series
>>> +		 */
>>> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
> 
> And here!
> 
> --D
Sorry about that!  Thanks for the catch!  Will add in the error code 
handlers.

Allison

> 
>>>   
>>>   		/*
>>>   		 * Dismantle the "old" attribute/value pair by removing
>>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>>> index 8d2e11f..8a6f5df 100644
>>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>>> @@ -2891,10 +2891,5 @@ xfs_attr3_leaf_flipflags(
>>>   			 XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt)));
>>>   	}
>>>   
>>> -	/*
>>> -	 * Commit the flag value change and start the next trans in series.
>>> -	 */
>>> -	error = xfs_trans_roll_inode(&args->trans, args->dp);
>>> -
>>>   	return error;
>>>   }
>>> -- 
>>> 2.7.4
>>>

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

* Re: [PATCH v2 08/18] xfs: Factor out xfs_attr_leaf_addname helper
  2019-08-12 16:06   ` Darrick J. Wong
@ 2019-08-12 19:37     ` Allison Collins
  0 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-12 19:37 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 8/12/19 9:06 AM, Darrick J. Wong wrote:
> On Fri, Aug 09, 2019 at 02:37:16PM -0700, Allison Collins wrote:
>> Factor out new helper function xfs_attr_leaf_try_add.
>> Because new delayed attribute routines cannot roll
>> transactions, we carve off the parts of
>> xfs_attr_leaf_addname that we can use.  This will help
>> to reduce repetitive code later when we introduce
>> delayed attributes.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 43 +++++++++++++++++++++++++++++--------------
>>   1 file changed, 29 insertions(+), 14 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index f36c792..f9d5e28 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -635,19 +635,12 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>>    * External routines when attribute list is one block
>>    *========================================================================*/
>>   
>> -/*
>> - * Add a name to the leaf attribute list structure
>> - *
>> - * This leaf block cannot have a "remote" value, we only call this routine
>> - * if bmap_one_block() says there is only one block (ie: no remote blks).
>> - */
>>   STATIC int
>> -xfs_attr_leaf_addname(
>> -	struct xfs_da_args	*args)
>> +xfs_attr_leaf_try_add(
>> +	struct xfs_da_args	*args,
>> +	struct xfs_buf		*bp)
>>   {
>> -	struct xfs_buf		*bp;
>> -	int			retval, error, forkoff;
>> -	struct xfs_inode	*dp = args->dp;
>> +	int			retval, error;
>>   
>>   	trace_xfs_attr_leaf_addname(args);
>>   
>> @@ -692,13 +685,35 @@ xfs_attr_leaf_addname(
>>   	retval = xfs_attr3_leaf_add(bp, args);
>>   	if (retval == -ENOSPC) {
>>   		/*
>> -		 * Promote the attribute list to the Btree format, then
>> -		 * Commit that transaction so that the node_addname() call
>> -		 * can manage its own transactions.
>> +		 * Promote the attribute list to the Btree format,
> 
> Why does the sentence end with a comma?
I think there came a point when they all started looking the same!  Lol, 
will clean up.  :-)

> 
>>   		 */
>>   		error = xfs_attr3_leaf_to_node(args);
>>   		if (error)
>>   			return error;
>> +	}
>> +	return retval;
>> +}
>> +
>> +
>> +/*
>> + * Add a name to the leaf attribute list structure
>> + *
>> + * This leaf block cannot have a "remote" value, we only call this routine
>> + * if bmap_one_block() says there is only one block (ie: no remote blks).
>> + */
>> +STATIC int
>> +xfs_attr_leaf_addname(struct xfs_da_args	*args)
>> +{
>> +	int retval, error, forkoff;
> 
> Indentation problem here.
Alrighty, will catch.  Thanks!

Allison

> 
> --D
> 
>> +	struct xfs_buf		*bp = NULL;
>> +	struct xfs_inode	*dp = args->dp;
>> +
>> +	retval = xfs_attr_leaf_try_add(args, bp);
>> +	if (retval == -ENOSPC) {
>> +		/*
>> +		 * Commit that transaction so that the node_addname() call
>> +		 * can manage its own transactions.
>> +		 */
>>   		error = xfs_defer_finish(&args->trans);
>>   		if (error)
>>   			return error;
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v2 05/18] xfs: Add xfs_has_attr and subroutines
  2019-08-12 19:29     ` Allison Collins
@ 2019-08-12 20:00       ` Darrick J. Wong
  2019-08-12 22:38         ` Allison Collins
  0 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2019-08-12 20:00 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Mon, Aug 12, 2019 at 12:29:03PM -0700, Allison Collins wrote:
> On 8/12/19 8:56 AM, Darrick J. Wong wrote:
> > On Fri, Aug 09, 2019 at 02:37:13PM -0700, Allison Collins wrote:
> > > From: Allison Henderson <allison.henderson@oracle.com>
> > > 
> > > This patch adds a new functions to check for the existence of
> > > an attribute.  Subroutines are also added to handle the cases
> > > of leaf blocks, nodes or shortform.  Common code that appears
> > > in existing attr add and remove functions have been factored
> > > out to help reduce the appearence of duplicated code.  We will
> > > need these routines later for delayed attributes since delayed
> > > operations cannot return error codes.
> > > 
> > > Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > ---
> > >   fs/xfs/libxfs/xfs_attr.c      | 151 +++++++++++++++++++++++++++---------------
> > >   fs/xfs/libxfs/xfs_attr.h      |   1 +
> > >   fs/xfs/libxfs/xfs_attr_leaf.c |  82 +++++++++++++++--------
> > >   fs/xfs/libxfs/xfs_attr_leaf.h |   2 +
> > >   4 files changed, 158 insertions(+), 78 deletions(-)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > index a2fba0c..72af8e2 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > @@ -48,6 +48,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
> > >   STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
> > >   STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
> > >   STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
> > > +STATIC int xfs_leaf_has_attr(xfs_da_args_t *args, struct xfs_buf **bp);
> > 
> > Trailing whitespace, and please use "struct xfs_da_args", not the
> > typedef...
> Ok, will that clean up.
> 
> > 
> > >   /*
> > >    * Internal routines when attribute list is more than one block.
> > > @@ -55,6 +56,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
> > >   STATIC int xfs_attr_node_get(xfs_da_args_t *args);
> > >   STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
> > >   STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
> > > +STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
> > > +				 struct xfs_da_state **state);
> > >   STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
> > >   STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
> > > @@ -278,6 +281,32 @@ xfs_attr_set_args(
> > >   }
> > >   /*
> > > + * Return EEXIST if attr is found, or ENOATTR if not
> > > + */
> > > +int
> > > +xfs_has_attr(
> > > +	struct xfs_da_args      *args)
> > > +{
> > > +	struct xfs_inode        *dp = args->dp;
> > > +	struct xfs_buf		*bp;
> > > +	int                     error;
> > > +
> > > +	if (!xfs_inode_hasattr(dp)) {
> > > +		error = -ENOATTR;
> > > +	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> > > +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
> > > +		error = xfs_shortform_has_attr(args, NULL, NULL);
> > > +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> > > +		error = xfs_leaf_has_attr(args, &bp);
> > > +		xfs_trans_brelse(args->trans, bp);
> > > +	} else {
> > > +		error = xfs_attr_node_hasname(args, NULL);
> > > +	}
> > > +
> > > +	return error;
> > > +}
> > > +
> > > +/*
> > >    * Remove the attribute specified in @args.
> > >    */
> > >   int
> > > @@ -616,26 +645,17 @@ STATIC int
> > >   xfs_attr_leaf_addname(
> > >   	struct xfs_da_args	*args)
> > >   {
> > > -	struct xfs_inode	*dp;
> > >   	struct xfs_buf		*bp;
> > >   	int			retval, error, forkoff;
> > > +	struct xfs_inode	*dp = args->dp;
> > >   	trace_xfs_attr_leaf_addname(args);
> > >   	/*
> > > -	 * Read the (only) block in the attribute list in.
> > > -	 */
> > > -	dp = args->dp;
> > > -	args->blkno = 0;
> > > -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
> > > -	if (error)
> > > -		return error;
> > > -
> > > -	/*
> > >   	 * Look up the given attribute in the leaf block.  Figure out if
> > >   	 * the given flags produce an error or call for an atomic rename.
> > >   	 */
> > > -	retval = xfs_attr3_leaf_lookup_int(bp, args);
> > > +	retval = xfs_leaf_has_attr(args, &bp);
> > >   	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
> > >   		xfs_trans_brelse(args->trans, bp);
> > >   		return retval;
> > > @@ -787,6 +807,26 @@ xfs_attr_leaf_addname(
> > >   }
> > >   /*
> > > + * Return EEXIST if attr is found, or ENOATTR if not
> > > + */
> > > +STATIC int
> > > +xfs_leaf_has_attr(
> > > +	struct xfs_da_args      *args,
> > > +	struct xfs_buf		**bp)
> > > +{
> > > +	int                     error = 0;
> > > +
> > > +	args->blkno = 0;
> > > +	error = xfs_attr3_leaf_read(args->trans, args->dp,
> > > +			args->blkno, -1, bp);
> > 
> > Can we please get rid of these -1 and -2 magic values that eventually
> > become the mappedbno argument to xfs_dabuf_map?
> Sure, maybe we can add some constants here.  I took a quick peek at
> xfs_dabuf_map.  Maybe we can add something like this:
> 
> #define MBNO_NOMAP	-1
> #define MBNO_HOLE_OK	-2

#define XFS_DABUF_MAP_NOMAPPING	(-1)
#define XFS_DABUF_MAP_HOLE_OK	(-2)

Function flags should be named for the function that consumes them,
but otoh these values sink through multiple levels of call stack.

Macros should have parentheses around them to avoid unexpected fun with
the preprocessor, since:

printf("%d\n", XFS_DABUF_MAP_NOMAPPING XFS_DABUF_MAP_NOMAPPING);

Should produce a compile error, not a program that prints -2.

--D

> 
> 
> > 
> > > +	if (error)
> > > +		return error;
> > > +
> > > +	error = xfs_attr3_leaf_lookup_int(*bp, args);
> > > +	return error;
> > 
> > "return xfs_attr3_leaf_lookup_int..." ?
> > 
> > > +}
> > > +
> > > +/*
> > >    * Remove a name from the leaf attribute list structure
> > >    *
> > >    * This leaf block cannot have a "remote" value, we only call this routine
> > > @@ -806,12 +846,8 @@ xfs_attr_leaf_removename(
> > >   	 * Remove the attribute.
> > >   	 */
> > >   	dp = args->dp;
> > > -	args->blkno = 0;
> > > -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
> > > -	if (error)
> > > -		return error;
> > > -	error = xfs_attr3_leaf_lookup_int(bp, args);
> > > +	error = xfs_leaf_has_attr(args, &bp);
> > >   	if (error == -ENOATTR) {
> > >   		xfs_trans_brelse(args->trans, bp);
> > >   		return error;
> > > @@ -848,12 +884,7 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
> > >   	trace_xfs_attr_leaf_get(args);
> > > -	args->blkno = 0;
> > > -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
> > > -	if (error)
> > > -		return error;
> > > -
> > > -	error = xfs_attr3_leaf_lookup_int(bp, args);
> > > +	error = xfs_leaf_has_attr(args, &bp);
> > >   	if (error != -EEXIST)  {
> > >   		xfs_trans_brelse(args->trans, bp);
> > >   		return error;
> > > @@ -866,6 +897,43 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
> > >   	return error;
> > >   }
> > > +/*
> > > + * Return EEXIST if attr is found, or ENOATTR if not
> > > + * statep: If not null is set to point at the found state.  Caller will
> > > + * 	   be responsible for freeing the state in this case.
> > > + */
> > > +STATIC int
> > > +xfs_attr_node_hasname(
> > > +	struct xfs_da_args	*args,
> > > +	struct xfs_da_state	**statep)
> > > +{
> > > +	struct xfs_da_state	*state;
> > > +	struct xfs_inode	*dp;
> > > +	int			retval, error;
> > > +
> > > +	/*
> > > +	 * Tie a string around our finger to remind us where we are.
> > > +	 */
> > > +	dp = args->dp;
> > > +	state = xfs_da_state_alloc();
> > > +	state->args = args;
> > > +	state->mp = dp->i_mount;
> > > +
> > > +	/*
> > > +	 * Search to see if name exists, and get back a pointer to it.
> > > +	 */
> > > +	error = xfs_da3_node_lookup_int(state, &retval);
> > > +	if (error == 0)
> > > +		error = retval;
> > > +
> > > +	if (statep != NULL)
> > > +		*statep = state;
> > > +	else
> > > +		xfs_da_state_free(state);
> > > +
> > > +	return error;
> > > +}
> > > +
> > >   /*========================================================================
> > >    * External routines when attribute list size > geo->blksize
> > >    *========================================================================*/
> > > @@ -898,17 +966,14 @@ xfs_attr_node_addname(
> > >   	dp = args->dp;
> > >   	mp = dp->i_mount;
> > >   restart:
> > > -	state = xfs_da_state_alloc();
> > > -	state->args = args;
> > > -	state->mp = mp;
> > > -
> > >   	/*
> > >   	 * Search to see if name already exists, and get back a pointer
> > >   	 * to where it should go.
> > >   	 */
> > > -	error = xfs_da3_node_lookup_int(state, &retval);
> > > -	if (error)
> > > +	error = xfs_attr_node_hasname(args, &state);
> > > +	if (error == -EEXIST)
> > >   		goto out;
> > > +
> > >   	blk = &state->path.blk[ state->path.active-1 ];
> > >   	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> > >   	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
> > > @@ -1113,29 +1178,15 @@ xfs_attr_node_removename(
> > >   {
> > >   	struct xfs_da_state	*state;
> > >   	struct xfs_da_state_blk	*blk;
> > > -	struct xfs_inode	*dp;
> > >   	struct xfs_buf		*bp;
> > >   	int			retval, error, forkoff;
> > > +	struct xfs_inode	*dp = args->dp;
> > >   	trace_xfs_attr_node_removename(args);
> > > -	/*
> > > -	 * Tie a string around our finger to remind us where we are.
> > > -	 */
> > > -	dp = args->dp;
> > > -	state = xfs_da_state_alloc();
> > > -	state->args = args;
> > > -	state->mp = dp->i_mount;
> > > -
> > > -	/*
> > > -	 * Search to see if name exists, and get back a pointer to it.
> > > -	 */
> > > -	error = xfs_da3_node_lookup_int(state, &retval);
> > > -	if (error || (retval != -EEXIST)) {
> > > -		if (error == 0)
> > > -			error = retval;
> > > +	error = xfs_attr_node_hasname(args, &state);
> > > +	if (error != -EEXIST)
> > >   		goto out;
> > > -	}
> > >   	/*
> > >   	 * If there is an out-of-line value, de-allocate the blocks.
> > > @@ -1355,17 +1406,13 @@ xfs_attr_node_get(xfs_da_args_t *args)
> > >   	trace_xfs_attr_node_get(args);
> > > -	state = xfs_da_state_alloc();
> > > -	state->args = args;
> > > -	state->mp = args->dp->i_mount;
> > > -
> > >   	/*
> > >   	 * Search to see if name exists, and get back a pointer to it.
> > >   	 */
> > > -	error = xfs_da3_node_lookup_int(state, &retval);
> > > -	if (error) {
> > > +	error = xfs_attr_node_hasname(args, &state);
> > > +	if (error != -EEXIST) {
> > >   		retval = error;
> > > -	} else if (retval == -EEXIST) {
> > > +	} else {
> > >   		blk = &state->path.blk[ state->path.active-1 ];
> > >   		ASSERT(blk->bp != NULL);
> > >   		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> > > index 0bade83..c082d34 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.h
> > > +++ b/fs/xfs/libxfs/xfs_attr.h
> > > @@ -170,6 +170,7 @@ int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
> > >   		 unsigned char *value, int valuelen);
> > >   int xfs_attr_set_args(struct xfs_da_args *args);
> > >   int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name);
> > > +int xfs_has_attr(struct xfs_da_args *args);
> > >   int xfs_attr_remove_args(struct xfs_da_args *args);
> > >   int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
> > >   		  int flags, struct attrlist_cursor_kern *cursor);
> > > diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> > > index 70eb941..8d2e11f 100644
> > > --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> > > +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> > > @@ -546,6 +546,53 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
> > >   }
> > >   /*
> > > + * Return EEXIST if attr is found, or ENOATTR if not
> > > + * args:  args containing attribute name and namelen
> > > + * sfep:  If not null, pointer will be set to the last attr entry found
> > > + * basep: If not null, pointer is set to the byte offset of the entry in the
> > > + *	  list
> > > + */
> > > +int
> > > +xfs_shortform_has_attr(
> > > +	struct xfs_da_args	 *args,
> > > +	struct xfs_attr_sf_entry **sfep,
> > > +	int			 *basep)
> > > +{
> > > +	struct xfs_attr_shortform *sf;
> > > +	struct xfs_attr_sf_entry *sfe;
> > > +	int			base = sizeof(struct xfs_attr_sf_hdr);
> > > +	int			size = 0;
> > > +	int			end;
> > > +	int			i;
> > > +
> > > +	base = sizeof(struct xfs_attr_sf_hdr);
> > > +	sf = (struct xfs_attr_shortform *)args->dp->i_afp->if_u1.if_data;
> > > +	sfe = &sf->list[0];
> > > +	end = sf->hdr.count;
> > > +	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
> > > +			base += size, i++) {
> > > +		size = XFS_ATTR_SF_ENTSIZE(sfe);
> > > +		if (sfe->namelen != args->namelen)
> > > +			continue;
> > > +		if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
> > > +			continue;
> > > +		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
> > > +			continue;
> > > +		break;
> > > +	}
> > > +
> > > +	if (sfep != NULL)
> > > +		*sfep = sfe;
> > > +
> > > +	if (basep != NULL)
> > > +		*basep = base;
> > > +
> > > +	if (i == end)
> > > +		return -ENOATTR;
> > > +	return -EEXIST;
> > > +}
> > > +
> > > +/*
> > >    * Add a name/value pair to the shortform attribute list.
> > >    * Overflow from the inode has already been checked for.
> > >    */
> > > @@ -554,7 +601,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
> > >   {
> > >   	xfs_attr_shortform_t *sf;
> > >   	xfs_attr_sf_entry_t *sfe;
> > > -	int i, offset, size;
> > > +	int offset, size, error;
> > >   	xfs_mount_t *mp;
> > >   	xfs_inode_t *dp;
> > >   	struct xfs_ifork *ifp;
> > > @@ -568,18 +615,11 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
> > >   	ifp = dp->i_afp;
> > >   	ASSERT(ifp->if_flags & XFS_IFINLINE);
> > >   	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
> > > -	sfe = &sf->list[0];
> > > -	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
> > > +	error = xfs_shortform_has_attr(args, &sfe, NULL);
> > >   #ifdef DEBUG
> > > -		if (sfe->namelen != args->namelen)
> > > -			continue;
> > > -		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
> > > -			continue;
> > > -		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
> > > -			continue;
> > > +	if (error == -EEXIST)
> > >   		ASSERT(0);
> > 
> > ASSERT(error != -EEXIST); ?  Without the #ifdef DEBUG since ASSERT does
> > nothing if DEBUG isn't defined...
> > 
> > >   #endif
> > > -	}
> > >   	offset = (char *)sfe - (char *)sf;
> > >   	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
> > > @@ -626,7 +666,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
> > >   {
> > >   	xfs_attr_shortform_t *sf;
> > >   	xfs_attr_sf_entry_t *sfe;
> > > -	int base, size=0, end, totsize, i;
> > > +	int base, size = 0, end, totsize, error;
> > >   	xfs_mount_t *mp;
> > >   	xfs_inode_t *dp;
> > 
> > Please fix the typedef and indentation here while you're changing this
> > (and all the other attr) functions.
> > 
> > Otherwise, I very much like this cleanup. :)
> Great!  I'll tidy these up then.  Thx for the review!
> 
> Allison
> 
> > 
> > --D
> > 
> > > @@ -634,23 +674,13 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
> > >   	dp = args->dp;
> > >   	mp = dp->i_mount;
> > > -	base = sizeof(xfs_attr_sf_hdr_t);
> > >   	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
> > > -	sfe = &sf->list[0];
> > >   	end = sf->hdr.count;
> > > -	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
> > > -					base += size, i++) {
> > > -		size = XFS_ATTR_SF_ENTSIZE(sfe);
> > > -		if (sfe->namelen != args->namelen)
> > > -			continue;
> > > -		if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
> > > -			continue;
> > > -		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
> > > -			continue;
> > > -		break;
> > > -	}
> > > -	if (i == end)
> > > -		return -ENOATTR;
> > > +
> > > +	error = xfs_shortform_has_attr(args, &sfe, &base);
> > > +	if (error == -ENOATTR)
> > > +		return error;
> > > +	size = XFS_ATTR_SF_ENTSIZE(sfe);
> > >   	/*
> > >   	 * Fix up the attribute fork data, covering the hole
> > > diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
> > > index 7b74e18..be1f636 100644
> > > --- a/fs/xfs/libxfs/xfs_attr_leaf.h
> > > +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
> > > @@ -39,6 +39,8 @@ int	xfs_attr_shortform_getvalue(struct xfs_da_args *args);
> > >   int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
> > >   			struct xfs_buf **leaf_bp);
> > >   int	xfs_attr_shortform_remove(struct xfs_da_args *args);
> > > +int	xfs_shortform_has_attr(struct xfs_da_args *args,
> > > +			       struct xfs_attr_sf_entry **sfep, int *basep);
> > >   int	xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
> > >   int	xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes);
> > >   xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_inode *ip);
> > > -- 
> > > 2.7.4
> > > 

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

* Re: [PATCH v2 05/18] xfs: Add xfs_has_attr and subroutines
  2019-08-12 20:00       ` Darrick J. Wong
@ 2019-08-12 22:38         ` Allison Collins
  0 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-12 22:38 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 8/12/19 1:00 PM, Darrick J. Wong wrote:
> On Mon, Aug 12, 2019 at 12:29:03PM -0700, Allison Collins wrote:
>> On 8/12/19 8:56 AM, Darrick J. Wong wrote:
>>> On Fri, Aug 09, 2019 at 02:37:13PM -0700, Allison Collins wrote:
>>>> From: Allison Henderson <allison.henderson@oracle.com>
>>>>
>>>> This patch adds a new functions to check for the existence of
>>>> an attribute.  Subroutines are also added to handle the cases
>>>> of leaf blocks, nodes or shortform.  Common code that appears
>>>> in existing attr add and remove functions have been factored
>>>> out to help reduce the appearence of duplicated code.  We will
>>>> need these routines later for delayed attributes since delayed
>>>> operations cannot return error codes.
>>>>
>>>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>>>> ---
>>>>    fs/xfs/libxfs/xfs_attr.c      | 151 +++++++++++++++++++++++++++---------------
>>>>    fs/xfs/libxfs/xfs_attr.h      |   1 +
>>>>    fs/xfs/libxfs/xfs_attr_leaf.c |  82 +++++++++++++++--------
>>>>    fs/xfs/libxfs/xfs_attr_leaf.h |   2 +
>>>>    4 files changed, 158 insertions(+), 78 deletions(-)
>>>>
>>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>>> index a2fba0c..72af8e2 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>>> @@ -48,6 +48,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>>>>    STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
>>>>    STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
>>>>    STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>>>> +STATIC int xfs_leaf_has_attr(xfs_da_args_t *args, struct xfs_buf **bp);
>>>
>>> Trailing whitespace, and please use "struct xfs_da_args", not the
>>> typedef...
>> Ok, will that clean up.
>>
>>>
>>>>    /*
>>>>     * Internal routines when attribute list is more than one block.
>>>> @@ -55,6 +56,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>>>>    STATIC int xfs_attr_node_get(xfs_da_args_t *args);
>>>>    STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
>>>>    STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
>>>> +STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
>>>> +				 struct xfs_da_state **state);
>>>>    STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>>>>    STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>>>> @@ -278,6 +281,32 @@ xfs_attr_set_args(
>>>>    }
>>>>    /*
>>>> + * Return EEXIST if attr is found, or ENOATTR if not
>>>> + */
>>>> +int
>>>> +xfs_has_attr(
>>>> +	struct xfs_da_args      *args)
>>>> +{
>>>> +	struct xfs_inode        *dp = args->dp;
>>>> +	struct xfs_buf		*bp;
>>>> +	int                     error;
>>>> +
>>>> +	if (!xfs_inode_hasattr(dp)) {
>>>> +		error = -ENOATTR;
>>>> +	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>>>> +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
>>>> +		error = xfs_shortform_has_attr(args, NULL, NULL);
>>>> +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>>> +		error = xfs_leaf_has_attr(args, &bp);
>>>> +		xfs_trans_brelse(args->trans, bp);
>>>> +	} else {
>>>> +		error = xfs_attr_node_hasname(args, NULL);
>>>> +	}
>>>> +
>>>> +	return error;
>>>> +}
>>>> +
>>>> +/*
>>>>     * Remove the attribute specified in @args.
>>>>     */
>>>>    int
>>>> @@ -616,26 +645,17 @@ STATIC int
>>>>    xfs_attr_leaf_addname(
>>>>    	struct xfs_da_args	*args)
>>>>    {
>>>> -	struct xfs_inode	*dp;
>>>>    	struct xfs_buf		*bp;
>>>>    	int			retval, error, forkoff;
>>>> +	struct xfs_inode	*dp = args->dp;
>>>>    	trace_xfs_attr_leaf_addname(args);
>>>>    	/*
>>>> -	 * Read the (only) block in the attribute list in.
>>>> -	 */
>>>> -	dp = args->dp;
>>>> -	args->blkno = 0;
>>>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
>>>> -	if (error)
>>>> -		return error;
>>>> -
>>>> -	/*
>>>>    	 * Look up the given attribute in the leaf block.  Figure out if
>>>>    	 * the given flags produce an error or call for an atomic rename.
>>>>    	 */
>>>> -	retval = xfs_attr3_leaf_lookup_int(bp, args);
>>>> +	retval = xfs_leaf_has_attr(args, &bp);
>>>>    	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
>>>>    		xfs_trans_brelse(args->trans, bp);
>>>>    		return retval;
>>>> @@ -787,6 +807,26 @@ xfs_attr_leaf_addname(
>>>>    }
>>>>    /*
>>>> + * Return EEXIST if attr is found, or ENOATTR if not
>>>> + */
>>>> +STATIC int
>>>> +xfs_leaf_has_attr(
>>>> +	struct xfs_da_args      *args,
>>>> +	struct xfs_buf		**bp)
>>>> +{
>>>> +	int                     error = 0;
>>>> +
>>>> +	args->blkno = 0;
>>>> +	error = xfs_attr3_leaf_read(args->trans, args->dp,
>>>> +			args->blkno, -1, bp);
>>>
>>> Can we please get rid of these -1 and -2 magic values that eventually
>>> become the mappedbno argument to xfs_dabuf_map?
>> Sure, maybe we can add some constants here.  I took a quick peek at
>> xfs_dabuf_map.  Maybe we can add something like this:
>>
>> #define MBNO_NOMAP	-1
>> #define MBNO_HOLE_OK	-2
> 
> #define XFS_DABUF_MAP_NOMAPPING	(-1)
> #define XFS_DABUF_MAP_HOLE_OK	(-2)
> 
> Function flags should be named for the function that consumes them,
> but otoh these values sink through multiple levels of call stack.
> 
> Macros should have parentheses around them to avoid unexpected fun with
> the preprocessor, since:
> 
> printf("%d\n", XFS_DABUF_MAP_NOMAPPING XFS_DABUF_MAP_NOMAPPING);
> 
> Should produce a compile error, not a program that prints -2.
> 
> --D

Ok, sounds good.  I'll add another patch for this in v3

Allison
> 
>>
>>
>>>
>>>> +	if (error)
>>>> +		return error;
>>>> +
>>>> +	error = xfs_attr3_leaf_lookup_int(*bp, args);
>>>> +	return error;
>>>
>>> "return xfs_attr3_leaf_lookup_int..." ?
>>>
>>>> +}
>>>> +
>>>> +/*
>>>>     * Remove a name from the leaf attribute list structure
>>>>     *
>>>>     * This leaf block cannot have a "remote" value, we only call this routine
>>>> @@ -806,12 +846,8 @@ xfs_attr_leaf_removename(
>>>>    	 * Remove the attribute.
>>>>    	 */
>>>>    	dp = args->dp;
>>>> -	args->blkno = 0;
>>>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
>>>> -	if (error)
>>>> -		return error;
>>>> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>>>> +	error = xfs_leaf_has_attr(args, &bp);
>>>>    	if (error == -ENOATTR) {
>>>>    		xfs_trans_brelse(args->trans, bp);
>>>>    		return error;
>>>> @@ -848,12 +884,7 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>>>>    	trace_xfs_attr_leaf_get(args);
>>>> -	args->blkno = 0;
>>>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
>>>> -	if (error)
>>>> -		return error;
>>>> -
>>>> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>>>> +	error = xfs_leaf_has_attr(args, &bp);
>>>>    	if (error != -EEXIST)  {
>>>>    		xfs_trans_brelse(args->trans, bp);
>>>>    		return error;
>>>> @@ -866,6 +897,43 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>>>>    	return error;
>>>>    }
>>>> +/*
>>>> + * Return EEXIST if attr is found, or ENOATTR if not
>>>> + * statep: If not null is set to point at the found state.  Caller will
>>>> + * 	   be responsible for freeing the state in this case.
>>>> + */
>>>> +STATIC int
>>>> +xfs_attr_node_hasname(
>>>> +	struct xfs_da_args	*args,
>>>> +	struct xfs_da_state	**statep)
>>>> +{
>>>> +	struct xfs_da_state	*state;
>>>> +	struct xfs_inode	*dp;
>>>> +	int			retval, error;
>>>> +
>>>> +	/*
>>>> +	 * Tie a string around our finger to remind us where we are.
>>>> +	 */
>>>> +	dp = args->dp;
>>>> +	state = xfs_da_state_alloc();
>>>> +	state->args = args;
>>>> +	state->mp = dp->i_mount;
>>>> +
>>>> +	/*
>>>> +	 * Search to see if name exists, and get back a pointer to it.
>>>> +	 */
>>>> +	error = xfs_da3_node_lookup_int(state, &retval);
>>>> +	if (error == 0)
>>>> +		error = retval;
>>>> +
>>>> +	if (statep != NULL)
>>>> +		*statep = state;
>>>> +	else
>>>> +		xfs_da_state_free(state);
>>>> +
>>>> +	return error;
>>>> +}
>>>> +
>>>>    /*========================================================================
>>>>     * External routines when attribute list size > geo->blksize
>>>>     *========================================================================*/
>>>> @@ -898,17 +966,14 @@ xfs_attr_node_addname(
>>>>    	dp = args->dp;
>>>>    	mp = dp->i_mount;
>>>>    restart:
>>>> -	state = xfs_da_state_alloc();
>>>> -	state->args = args;
>>>> -	state->mp = mp;
>>>> -
>>>>    	/*
>>>>    	 * Search to see if name already exists, and get back a pointer
>>>>    	 * to where it should go.
>>>>    	 */
>>>> -	error = xfs_da3_node_lookup_int(state, &retval);
>>>> -	if (error)
>>>> +	error = xfs_attr_node_hasname(args, &state);
>>>> +	if (error == -EEXIST)
>>>>    		goto out;
>>>> +
>>>>    	blk = &state->path.blk[ state->path.active-1 ];
>>>>    	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>>>>    	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
>>>> @@ -1113,29 +1178,15 @@ xfs_attr_node_removename(
>>>>    {
>>>>    	struct xfs_da_state	*state;
>>>>    	struct xfs_da_state_blk	*blk;
>>>> -	struct xfs_inode	*dp;
>>>>    	struct xfs_buf		*bp;
>>>>    	int			retval, error, forkoff;
>>>> +	struct xfs_inode	*dp = args->dp;
>>>>    	trace_xfs_attr_node_removename(args);
>>>> -	/*
>>>> -	 * Tie a string around our finger to remind us where we are.
>>>> -	 */
>>>> -	dp = args->dp;
>>>> -	state = xfs_da_state_alloc();
>>>> -	state->args = args;
>>>> -	state->mp = dp->i_mount;
>>>> -
>>>> -	/*
>>>> -	 * Search to see if name exists, and get back a pointer to it.
>>>> -	 */
>>>> -	error = xfs_da3_node_lookup_int(state, &retval);
>>>> -	if (error || (retval != -EEXIST)) {
>>>> -		if (error == 0)
>>>> -			error = retval;
>>>> +	error = xfs_attr_node_hasname(args, &state);
>>>> +	if (error != -EEXIST)
>>>>    		goto out;
>>>> -	}
>>>>    	/*
>>>>    	 * If there is an out-of-line value, de-allocate the blocks.
>>>> @@ -1355,17 +1406,13 @@ xfs_attr_node_get(xfs_da_args_t *args)
>>>>    	trace_xfs_attr_node_get(args);
>>>> -	state = xfs_da_state_alloc();
>>>> -	state->args = args;
>>>> -	state->mp = args->dp->i_mount;
>>>> -
>>>>    	/*
>>>>    	 * Search to see if name exists, and get back a pointer to it.
>>>>    	 */
>>>> -	error = xfs_da3_node_lookup_int(state, &retval);
>>>> -	if (error) {
>>>> +	error = xfs_attr_node_hasname(args, &state);
>>>> +	if (error != -EEXIST) {
>>>>    		retval = error;
>>>> -	} else if (retval == -EEXIST) {
>>>> +	} else {
>>>>    		blk = &state->path.blk[ state->path.active-1 ];
>>>>    		ASSERT(blk->bp != NULL);
>>>>    		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>>>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>>>> index 0bade83..c082d34 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr.h
>>>> +++ b/fs/xfs/libxfs/xfs_attr.h
>>>> @@ -170,6 +170,7 @@ int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
>>>>    		 unsigned char *value, int valuelen);
>>>>    int xfs_attr_set_args(struct xfs_da_args *args);
>>>>    int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name);
>>>> +int xfs_has_attr(struct xfs_da_args *args);
>>>>    int xfs_attr_remove_args(struct xfs_da_args *args);
>>>>    int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>>>>    		  int flags, struct attrlist_cursor_kern *cursor);
>>>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>>>> index 70eb941..8d2e11f 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>>>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>>>> @@ -546,6 +546,53 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
>>>>    }
>>>>    /*
>>>> + * Return EEXIST if attr is found, or ENOATTR if not
>>>> + * args:  args containing attribute name and namelen
>>>> + * sfep:  If not null, pointer will be set to the last attr entry found
>>>> + * basep: If not null, pointer is set to the byte offset of the entry in the
>>>> + *	  list
>>>> + */
>>>> +int
>>>> +xfs_shortform_has_attr(
>>>> +	struct xfs_da_args	 *args,
>>>> +	struct xfs_attr_sf_entry **sfep,
>>>> +	int			 *basep)
>>>> +{
>>>> +	struct xfs_attr_shortform *sf;
>>>> +	struct xfs_attr_sf_entry *sfe;
>>>> +	int			base = sizeof(struct xfs_attr_sf_hdr);
>>>> +	int			size = 0;
>>>> +	int			end;
>>>> +	int			i;
>>>> +
>>>> +	base = sizeof(struct xfs_attr_sf_hdr);
>>>> +	sf = (struct xfs_attr_shortform *)args->dp->i_afp->if_u1.if_data;
>>>> +	sfe = &sf->list[0];
>>>> +	end = sf->hdr.count;
>>>> +	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
>>>> +			base += size, i++) {
>>>> +		size = XFS_ATTR_SF_ENTSIZE(sfe);
>>>> +		if (sfe->namelen != args->namelen)
>>>> +			continue;
>>>> +		if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
>>>> +			continue;
>>>> +		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
>>>> +			continue;
>>>> +		break;
>>>> +	}
>>>> +
>>>> +	if (sfep != NULL)
>>>> +		*sfep = sfe;
>>>> +
>>>> +	if (basep != NULL)
>>>> +		*basep = base;
>>>> +
>>>> +	if (i == end)
>>>> +		return -ENOATTR;
>>>> +	return -EEXIST;
>>>> +}
>>>> +
>>>> +/*
>>>>     * Add a name/value pair to the shortform attribute list.
>>>>     * Overflow from the inode has already been checked for.
>>>>     */
>>>> @@ -554,7 +601,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>>>>    {
>>>>    	xfs_attr_shortform_t *sf;
>>>>    	xfs_attr_sf_entry_t *sfe;
>>>> -	int i, offset, size;
>>>> +	int offset, size, error;
>>>>    	xfs_mount_t *mp;
>>>>    	xfs_inode_t *dp;
>>>>    	struct xfs_ifork *ifp;
>>>> @@ -568,18 +615,11 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>>>>    	ifp = dp->i_afp;
>>>>    	ASSERT(ifp->if_flags & XFS_IFINLINE);
>>>>    	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
>>>> -	sfe = &sf->list[0];
>>>> -	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
>>>> +	error = xfs_shortform_has_attr(args, &sfe, NULL);
>>>>    #ifdef DEBUG
>>>> -		if (sfe->namelen != args->namelen)
>>>> -			continue;
>>>> -		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
>>>> -			continue;
>>>> -		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
>>>> -			continue;
>>>> +	if (error == -EEXIST)
>>>>    		ASSERT(0);
>>>
>>> ASSERT(error != -EEXIST); ?  Without the #ifdef DEBUG since ASSERT does
>>> nothing if DEBUG isn't defined...
>>>
>>>>    #endif
>>>> -	}
>>>>    	offset = (char *)sfe - (char *)sf;
>>>>    	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
>>>> @@ -626,7 +666,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
>>>>    {
>>>>    	xfs_attr_shortform_t *sf;
>>>>    	xfs_attr_sf_entry_t *sfe;
>>>> -	int base, size=0, end, totsize, i;
>>>> +	int base, size = 0, end, totsize, error;
>>>>    	xfs_mount_t *mp;
>>>>    	xfs_inode_t *dp;
>>>
>>> Please fix the typedef and indentation here while you're changing this
>>> (and all the other attr) functions.
>>>
>>> Otherwise, I very much like this cleanup. :)
>> Great!  I'll tidy these up then.  Thx for the review!
>>
>> Allison
>>
>>>
>>> --D
>>>
>>>> @@ -634,23 +674,13 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
>>>>    	dp = args->dp;
>>>>    	mp = dp->i_mount;
>>>> -	base = sizeof(xfs_attr_sf_hdr_t);
>>>>    	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
>>>> -	sfe = &sf->list[0];
>>>>    	end = sf->hdr.count;
>>>> -	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
>>>> -					base += size, i++) {
>>>> -		size = XFS_ATTR_SF_ENTSIZE(sfe);
>>>> -		if (sfe->namelen != args->namelen)
>>>> -			continue;
>>>> -		if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
>>>> -			continue;
>>>> -		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
>>>> -			continue;
>>>> -		break;
>>>> -	}
>>>> -	if (i == end)
>>>> -		return -ENOATTR;
>>>> +
>>>> +	error = xfs_shortform_has_attr(args, &sfe, &base);
>>>> +	if (error == -ENOATTR)
>>>> +		return error;
>>>> +	size = XFS_ATTR_SF_ENTSIZE(sfe);
>>>>    	/*
>>>>    	 * Fix up the attribute fork data, covering the hole
>>>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
>>>> index 7b74e18..be1f636 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
>>>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
>>>> @@ -39,6 +39,8 @@ int	xfs_attr_shortform_getvalue(struct xfs_da_args *args);
>>>>    int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
>>>>    			struct xfs_buf **leaf_bp);
>>>>    int	xfs_attr_shortform_remove(struct xfs_da_args *args);
>>>> +int	xfs_shortform_has_attr(struct xfs_da_args *args,
>>>> +			       struct xfs_attr_sf_entry **sfep, int *basep);
>>>>    int	xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
>>>>    int	xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes);
>>>>    xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_inode *ip);
>>>> -- 
>>>> 2.7.4
>>>>

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

* Re: [PATCH v2 09/18] xfs: Factor up commit from xfs_attr_try_sf_addname
  2019-08-12 16:14   ` Darrick J. Wong
@ 2019-08-12 22:38     ` Allison Collins
  0 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-12 22:38 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 8/12/19 9:14 AM, Darrick J. Wong wrote:
> On Fri, Aug 09, 2019 at 02:37:17PM -0700, Allison Collins wrote:
>> New delayed attribute routines cannot handle transactions,
>> so factor this up to the calling function.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 15 ++++++++-------
>>   1 file changed, 8 insertions(+), 7 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index f9d5e28..6bd87e6 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -196,7 +196,7 @@ xfs_attr_try_sf_addname(
>>   {
>>   
>>   	struct xfs_mount	*mp = dp->i_mount;
>> -	int			error, error2;
>> +	int			error;
>>   
>>   	error = xfs_attr_shortform_addname(args);
>>   	if (error == -ENOSPC)
>> @@ -212,9 +212,7 @@ xfs_attr_try_sf_addname(
>>   	if (mp->m_flags & XFS_MOUNT_WSYNC)
>>   		xfs_trans_set_sync(args->trans);
>>   
>> -	error2 = xfs_trans_commit(args->trans);
>> -	args->trans = NULL;
>> -	return error ? error : error2;
>> +	return error;
>>   }
>>   
>>   /*
>> @@ -226,7 +224,7 @@ xfs_attr_set_args(
>>   {
>>   	struct xfs_inode	*dp = args->dp;
>>   	struct xfs_buf          *leaf_bp = NULL;
>> -	int			error;
>> +	int			error, error2 = 0;;
>>   
>>   	/*
>>   	 * If the attribute list is non-existent or a shortform list,
>> @@ -246,8 +244,11 @@ xfs_attr_set_args(
>>   		 * Try to add the attr to the attribute list in the inode.
>>   		 */
>>   		error = xfs_attr_try_sf_addname(dp, args);
>> -		if (error != -ENOSPC)
>> -			return error;
>> +		if (error != -ENOSPC) {
>> +			error2 = xfs_trans_commit(args->trans);
> 
> I've wondered about this weird logic... if xfs_attr_shortform_addname
> returns an error code other than ENOSPC, why would we commit the
> transaction?  Usually we let the error code bounce up to whomever
> allocated the transaction and let them cancel it.
> 
> Hmm, looking around some more, I guess xfs_attr_shortform_remove can
> return ENOATTR to _addname and _shortform_lookup can return EEXIST, but
> with either of those error codes, the transaction isn't dirty so it's
> not like we're committing garbage state into the filesystem...?
> 
> --D

It does seem a little weird.  If I make the adjustment to only commit
on success, it seems to be ok.  I can add that as an optimization in v3.

Allison

> 
>> +			args->trans = NULL;
>> +			return error ? error : error2;
>> +		}
>>   
>>   		/*
>>   		 * It won't fit in the shortform, transform to a leaf block.
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v2 10/18] xfs: Factor up trans roll from xfs_attr3_leaf_setflag
  2019-08-12 16:14   ` Darrick J. Wong
@ 2019-08-12 22:38     ` Allison Collins
  0 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-12 22:38 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 8/12/19 9:14 AM, Darrick J. Wong wrote:
> On Fri, Aug 09, 2019 at 02:37:18PM -0700, Allison Collins wrote:
>> New delayed allocation routines cannot be handling
>> transactions so factor them up into the calling functions
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> 
> Looks ok,
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

Great!  Thanks!
Allison

> 
> --D
> 
>> ---
>>   fs/xfs/libxfs/xfs_attr.c      | 5 +++++
>>   fs/xfs/libxfs/xfs_attr_leaf.c | 5 +----
>>   2 files changed, 6 insertions(+), 4 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 6bd87e6..7648ceb 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -1239,6 +1239,11 @@ xfs_attr_node_removename(
>>   		error = xfs_attr3_leaf_setflag(args);
>>   		if (error)
>>   			goto out;
>> +
>> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		if (error)
>> +			goto out;
>> +
>>   		error = xfs_attr_rmtval_remove(args);
>>   		if (error)
>>   			goto out;
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>> index 8a6f5df..4a22ced 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -2773,10 +2773,7 @@ xfs_attr3_leaf_setflag(
>>   			 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
>>   	}
>>   
>> -	/*
>> -	 * Commit the flag value change and start the next trans in series.
>> -	 */
>> -	return xfs_trans_roll_inode(&args->trans, args->dp);
>> +	return error;
>>   }
>>   
>>   /*
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v2 11/18] xfs: Add xfs_attr3_leaf helper functions
  2019-08-12 16:22   ` Darrick J. Wong
@ 2019-08-12 22:38     ` Allison Collins
  0 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-12 22:38 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 8/12/19 9:22 AM, Darrick J. Wong wrote:
> On Fri, Aug 09, 2019 at 02:37:19PM -0700, Allison Collins wrote:
>> And new helper functions xfs_attr3_leaf_flag_is_set and
>> xfs_attr3_leaf_flagsflipped.  These routines check to see
>> if xfs_attr3_leaf_setflag or xfs_attr3_leaf_flipflags have
>> already been run.  We will need this later for delayed
>> attributes since routines may be recalled several times
>> when -EAGAIN is returned.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr_leaf.c | 78 +++++++++++++++++++++++++++++++++++++++++++
>>   fs/xfs/libxfs/xfs_attr_leaf.h |  2 ++
>>   2 files changed, 80 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>> index 4a22ced..b2d5f62 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -2729,6 +2729,34 @@ xfs_attr3_leaf_clearflag(
>>   }
>>   
>>   /*
>> + * Check if the INCOMPLETE flag on an entry in a leaf block is set.
>> + */
>> +int
>> +xfs_attr3_leaf_flag_is_set(
>> +	struct xfs_da_args		*args)
> 
> <urk> Please don't conflate error codes and a boolean predicate.  It
> would be way too easy to do:
> 
> if (xfs_attr3_leaf_flag_is_set(&args)) {
> 	/* launch the nuculur missiles */
> }
> 
> because there was a disk error and xfs_attr3_leaf_read fed us -EIO.
> Either make the callers do the _read and pass the bp to this predicate,
> or add a "bool *isset" outparam.
> 
> Second potential failure case:
> 
> error = xfs_attr3_leaf_flag_is_set(&args);
> if (error) {
> 	/* bury all the whatever */
> }
> 
> Wherein everything was actually fine, but instead someone incorrectly
> freaked out and that's why my neighbors were running chainsaws at 11pm
> last night.

Lol, I see.  Sure, I'll add in an isset param here.

> 
>> +{
>> +	struct xfs_attr_leafblock	*leaf;
>> +	struct xfs_attr_leaf_entry	*entry;
>> +	struct xfs_buf			*bp;
>> +	struct xfs_inode		*dp = args->dp;
>> +	int				error = 0;
>> +
>> +	trace_xfs_attr_leaf_setflag(args);
>> +
>> +	/*
>> +	 * Set up the operation.
>> +	 */
>> +	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno, -1, &bp);
>> +	if (error)
>> +		return error;
>> +
>> +	leaf = bp->b_addr;
>> +	entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
>> +
>> +	return ((entry->flags & XFS_ATTR_INCOMPLETE) != 0);
>> +}
>> +
>> +/*
>>    * Set the INCOMPLETE flag on an entry in a leaf block.
>>    */
>>   int
>> @@ -2890,3 +2918,53 @@ xfs_attr3_leaf_flipflags(
>>   
>>   	return error;
>>   }
>> +
>> +/*
>> + * On a leaf entry, check to see if the INCOMPLETE flag is cleared
>> + * in args->blkno/index and set in args->blkno2/index2.
>> + *
>> + * Note that they could be in different blocks, or in the same block.
>> + */
>> +int
>> +xfs_attr3_leaf_flagsflipped(
>> +	struct xfs_da_args		*args)
>> +{
>> +	struct xfs_attr_leafblock	*leaf1;
>> +	struct xfs_attr_leafblock	*leaf2;
>> +	struct xfs_attr_leaf_entry	*entry1;
>> +	struct xfs_attr_leaf_entry	*entry2;
>> +	struct xfs_buf			*bp1;
>> +	struct xfs_buf			*bp2;
>> +	struct xfs_inode		*dp = args->dp;
>> +	int				error = 0;
>> +
>> +	trace_xfs_attr_leaf_flipflags(args);
>> +
>> +	/*
>> +	 * Read the block containing the "old" attr
>> +	 */
>> +	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno, -1, &bp1);
>> +	if (error)
>> +		return error;
>> +
>> +	/*
>> +	 * Read the block containing the "new" attr, if it is different
>> +	 */
>> +	if (args->blkno2 != args->blkno) {
>> +		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno2,
>> +					   -1, &bp2);
>> +		if (error)
>> +			return error;
>> +	} else {
>> +		bp2 = bp1;
>> +	}
>> +
>> +	leaf1 = bp1->b_addr;
>> +	entry1 = &xfs_attr3_leaf_entryp(leaf1)[args->index];
>> +
>> +	leaf2 = bp2->b_addr;
>> +	entry2 = &xfs_attr3_leaf_entryp(leaf2)[args->index2];
>> +
>> +	return (((entry1->flags & XFS_ATTR_INCOMPLETE) == 0) &&
>> +		 (entry2->flags & XFS_ATTR_INCOMPLETE));
> 
> Same complaint here.

Ok, will fix.  Thx!

Allison

> 
> --D
> 
>> +}
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
>> index be1f636..d6afe23 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
>> @@ -54,7 +54,9 @@ int	xfs_attr3_leaf_to_shortform(struct xfs_buf *bp,
>>   				   struct xfs_da_args *args, int forkoff);
>>   int	xfs_attr3_leaf_clearflag(struct xfs_da_args *args);
>>   int	xfs_attr3_leaf_setflag(struct xfs_da_args *args);
>> +int	xfs_attr3_leaf_flag_is_set(struct xfs_da_args *args);
>>   int	xfs_attr3_leaf_flipflags(struct xfs_da_args *args);
>> +int	xfs_attr3_leaf_flagsflipped(struct xfs_da_args *args);
>>   
>>   /*
>>    * Routines used for growing the Btree.
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v2 12/18] xfs: Factor out xfs_attr_rmtval_remove_value
  2019-08-12 16:27   ` Darrick J. Wong
@ 2019-08-12 22:39     ` Allison Collins
  0 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-12 22:39 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 8/12/19 9:27 AM, Darrick J. Wong wrote:
> On Fri, Aug 09, 2019 at 02:37:20PM -0700, Allison Collins wrote:
>> Because new delayed attribute routines cannot roll
>> transactions, we carve off the parts of
>> xfs_attr_rmtval_remove that we can use.  This will help to
>> reduce repetitive code later when we introduce delayed
>> attributes.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr_remote.c | 25 +++++++++++++++++++------
>>   fs/xfs/libxfs/xfs_attr_remote.h |  1 +
>>   2 files changed, 20 insertions(+), 6 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index c421412..f030365 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>> @@ -586,19 +586,14 @@ xfs_attr_rmtval_set_value(
>>   	return 0;
>>   }
>>   
>> -/*
>> - * Remove the value associated with an attribute by deleting the
>> - * out-of-line buffer that it is stored on.
>> - */
>>   int
>> -xfs_attr_rmtval_remove(
>> +xfs_attr_rmtval_remove_value(
> 
> This function invalidates the incore buffers, right?  Since _remove
> below still does the actual bunmapi work to unmap blocks from the attr
> fork?  Would this be better named xfs_attr_rmtval_invalidate()?

Yeah, I struggled with what to call some of these other than "yet one 
more helper function" that doesn't roll or commit something. 
xfs_attr_rmtval_invalidate sounds good, I will add that into v3.

> 
>>   	struct xfs_da_args	*args)
>>   {
>>   	struct xfs_mount	*mp = args->dp->i_mount;
>>   	xfs_dablk_t		lblkno;
>>   	int			blkcnt;
>>   	int			error;
>> -	int			done;
>>   
>>   	trace_xfs_attr_rmtval_remove(args);
> 
> Leave this in xfs_attr_rmtval_remove.
> 

Ok, will move.  Thanks!

Allison

> --D
> 
>>   
>> @@ -642,7 +637,25 @@ xfs_attr_rmtval_remove(
>>   		lblkno += map.br_blockcount;
>>   		blkcnt -= map.br_blockcount;
>>   	}
>> +	return 0;
>> +}
>>   
>> +/*
>> + * Remove the value associated with an attribute by deleting the
>> + * out-of-line buffer that it is stored on.
>> + */
>> +int
>> +xfs_attr_rmtval_remove(
>> +	struct xfs_da_args      *args)
>> +{
>> +	xfs_dablk_t		lblkno;
>> +	int			blkcnt;
>> +	int			error = 0;
>> +	int			done = 0;
>> +
>> +	error = xfs_attr_rmtval_remove_value(args);
>> +	if (error)
>> +		return error;
>>   	/*
>>   	 * Keep de-allocating extents until the remote-value region is gone.
>>   	 */
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
>> index 2a73cd9..9a58a23 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.h
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
>> @@ -11,6 +11,7 @@ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen);
>>   int xfs_attr_rmtval_get(struct xfs_da_args *args);
>>   int xfs_attr_rmtval_set(struct xfs_da_args *args);
>>   int xfs_attr_rmtval_remove(struct xfs_da_args *args);
>> +int xfs_attr_rmtval_remove_value(struct xfs_da_args *args);
>>   int xfs_attr_rmtval_set_value(struct xfs_da_args *args);
>>   int xfs_attr_rmt_find_hole(struct xfs_da_args *args, int *blkcnt,
>>   			   xfs_fileoff_t *lfileoff);
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v2 13/18] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag
  2019-08-12 16:28   ` Darrick J. Wong
@ 2019-08-12 22:39     ` Allison Collins
  0 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-12 22:39 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 8/12/19 9:28 AM, Darrick J. Wong wrote:
> On Fri, Aug 09, 2019 at 02:37:21PM -0700, Allison Collins wrote:
>> New delayed allocation routines cannot be handling
>> transactions so factor them up into the calling functions
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c      | 12 ++++++++++++
>>   fs/xfs/libxfs/xfs_attr_leaf.c |  5 +----
>>   2 files changed, 13 insertions(+), 4 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 7648ceb..ca57202 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -823,6 +823,12 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
>>   		 * Added a "remote" value, just clear the incomplete flag.
>>   		 */
>>   		error = xfs_attr3_leaf_clearflag(args);
>> +
>> +		/*
>> +		 * Commit the flag value change and start the next trans in
>> +		 * series.
>> +		 */
>> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>>   	}
>>   	return error;
>>   }
>> @@ -1180,6 +1186,12 @@ xfs_attr_node_addname(
>>   		error = xfs_attr3_leaf_clearflag(args);
>>   		if (error)
>>   			goto out;
>> +
>> +		 /*
>> +		  * Commit the flag value change and start the next trans in
>> +		  * series.
>> +		  */
>> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>>   	}
>>   	retval = error = 0;
> 
> Doesn't this cause us to lose the error code from the roll_inode above?
> 
> --D

Yes, I overlooked weird assignment in this case.  I will add a extra 
handler.  THx!

Allison

> 
>>   
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>> index b2d5f62..e3604b9 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -2722,10 +2722,7 @@ xfs_attr3_leaf_clearflag(
>>   			 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
>>   	}
>>   
>> -	/*
>> -	 * Commit the flag value change and start the next trans in series.
>> -	 */
>> -	return xfs_trans_roll_inode(&args->trans, args->dp);
>> +	return error;
>>   }
>>   
>>   /*
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v2 17/18] xfs: Enable delayed attributes
  2019-08-12 16:42   ` Darrick J. Wong
@ 2019-08-12 22:39     ` Allison Collins
  0 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-12 22:39 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 8/12/19 9:42 AM, Darrick J. Wong wrote:
> On Fri, Aug 09, 2019 at 02:37:25PM -0700, Allison Collins wrote:
>> Finally enable delayed attributes in xfs_attr_set and
>> xfs_attr_remove.  We only do this for v4 and up since we
>> cant add new log entries to old fs versions
> 
> ...you can't add new log item types to *existing* fs versions, which
> includes everything through present-day v5.
> 
> This needs a separate feature bit somewhere to prevent existing xfs
> drivers from crashing and burning on attri/attrd items.  Most of this
> deferred attr code could exist independently from the parent pointer
> feature, so I guess you could be the first person to use one of the log
> incompat feature bits?  That would be one way to get wider testing of
> deferred attrs while we work on parent pointers.

Ok, that sounds good then, I will look into plumbing in a feature bit 
for it.  Thx!

Allison

> 
> --D
> 
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 26 ++++++++++++++++++++++++--
>>   1 file changed, 24 insertions(+), 2 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 9931e50..7023734 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -506,6 +506,7 @@ xfs_attr_set(
>>   	int			valuelen)
>>   {
>>   	struct xfs_mount	*mp = dp->i_mount;
>> +	struct xfs_sb		*sbp = &mp->m_sb;
>>   	struct xfs_da_args	args;
>>   	struct xfs_trans_res	tres;
>>   	int			rsvd = (name->type & ATTR_ROOT) != 0;
>> @@ -564,7 +565,20 @@ xfs_attr_set(
>>   		goto out_trans_cancel;
>>   
>>   	xfs_trans_ijoin(args.trans, dp, 0);
>> -	error = xfs_attr_set_args(&args);
>> +	if (XFS_SB_VERSION_NUM(sbp) < XFS_SB_VERSION_4)
>> +		error = xfs_attr_set_args(&args);
>> +	else {
>> +		error = xfs_has_attr(&args);
>> +
>> +		if (error == -EEXIST && (name->type & ATTR_CREATE))
>> +			goto out_trans_cancel;
>> +
>> +		if (error == -ENOATTR && (name->type & ATTR_REPLACE))
>> +			goto out_trans_cancel;
>> +
>> +		error = xfs_attr_set_deferred(dp, args.trans, name, value,
>> +					      valuelen);
>> +	}
>>   	if (error)
>>   		goto out_trans_cancel;
>>   	if (!args.trans) {
>> @@ -649,6 +663,7 @@ xfs_attr_remove(
>>   	struct xfs_name		*name)
>>   {
>>   	struct xfs_mount	*mp = dp->i_mount;
>> +	struct xfs_sb		*sbp = &mp->m_sb;
>>   	struct xfs_da_args	args;
>>   	int			error;
>>   
>> @@ -690,7 +705,14 @@ xfs_attr_remove(
>>   	 */
>>   	xfs_trans_ijoin(args.trans, dp, 0);
>>   
>> -	error = xfs_attr_remove_args(&args);
>> +	error = xfs_has_attr(&args);
>> +	if (error == -ENOATTR)
>> +		goto out;
>> +
>> +	if (XFS_SB_VERSION_NUM(sbp) < XFS_SB_VERSION_4)
>> +		error = xfs_attr_remove_args(&args);
>> +	else
>> +		error = xfs_attr_remove_deferred(dp, args.trans, name);
>>   	if (error)
>>   		goto out;
>>   
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v2 15/18] xfs: Add delayed attribute routines
  2019-08-12 17:29   ` Darrick J. Wong
@ 2019-08-13  2:19     ` Allison Collins
  0 siblings, 0 replies; 56+ messages in thread
From: Allison Collins @ 2019-08-13  2:19 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 8/12/19 10:29 AM, Darrick J. Wong wrote:
> On Fri, Aug 09, 2019 at 02:37:23PM -0700, Allison Collins wrote:
>> This patch adds new delayed attribute routines:
>>
>> xfs_attr_da_set_args
>> xfs_attr_da_remove_args
>> xfs_attr_da_leaf_addname
>> xfs_attr_da_node_addname
>> xfs_attr_da_node_removename
> 
> I think the "_da_" thing is shorthand for "deferred attr", right?
> 
> If so, it's way too close to the other "_da_" (which is shorthand for
> "directory/attr") for my taste.
> 
> xfs_attr_set_later()
> xfs_attr_remove_later()
> xfs_leaf_addname_later()
> xfs_node_addname_later()
> xfs_node_remove_later() ?

Sure, I'm not very particular about the names, I think the later scheme 
is fine.

> 
>> These routines are similar to their existing counter parts,
>> but they do not roll or commit transactions.  They instead
>> return -EGAIN to allow the calling function to roll the
> 
> EAGAIN...
> 
>> transaction and recall the function.  This allows the
>> attribute operations to be logged in multiple smaller
>> transactions.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 720 +++++++++++++++++++++++++++++++++++++++++++++++
>>   fs/xfs/libxfs/xfs_attr.h |   2 +
>>   2 files changed, 722 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index ca57202..9931e50 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -47,6 +47,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>>    */
>>   STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
>>   STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
>> +STATIC int xfs_attr_da_leaf_addname(xfs_da_args_t *args);
>>   STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>>   STATIC int xfs_leaf_has_attr(xfs_da_args_t *args, struct xfs_buf **bp);
>>   
>> @@ -55,12 +56,16 @@ STATIC int xfs_leaf_has_attr(xfs_da_args_t *args, struct xfs_buf **bp);
>>    */
>>   STATIC int xfs_attr_node_get(xfs_da_args_t *args);
>>   STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
>> +STATIC int xfs_attr_da_node_addname(xfs_da_args_t *args);
>>   STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
>> +STATIC int xfs_attr_da_node_removename(xfs_da_args_t *args);
>>   STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
>>   				 struct xfs_da_state **state);
>>   STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>>   STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>>   
>> +STATIC int
>> +xfs_attr_leaf_try_add(struct xfs_da_args *args, struct xfs_buf *bp);
> 
> STATIC int xfs_attr_leaf_try_add(...)
> 
> (no newline between the return type and the function name)
Ok, will clean out

> 
>>   
>>   int
>>   xfs_attr_args_init(
> 
> <snip>
> 
>> +STATIC int
>> +xfs_attr_da_leaf_addname(
>> +	struct xfs_da_args	*args)
>> +{
>> +	int			error, forkoff, nmap;
>> +	struct xfs_buf		*bp = NULL;
>> +	struct xfs_inode	*dp = args->dp;
>> +	struct xfs_bmbt_irec	*map = &args->dc.map;
> 
> <snip>
> 
>> +	/*
>> +	 * If this is an atomic rename operation, we must "flip" the
>> +	 * incomplete flags on the "new" and "old" attribute/value pairs
>> +	 * so that one disappears and one appears atomically.  Then we
>> +	 * must remove the "old" attribute/value pair.
>> +	 */
>> +	if (args->op_flags & XFS_DA_OP_RENAME) {
>> +		/*
>> +		 * In a separate transaction, set the incomplete flag on the
>> +		 * "old" attr and clear the incomplete flag on the "new" attr.
> 
> Echoing Christoph, can this new attr implementation set the attr value
> through the log so we can get rid of the INCOMPLETE flag switcheroo
> business?  I see a lot of nearly duplicated code and if we're going to
> have to support having two paths through the attr set/remove code, we
> could at least avoid the weird warts of the old path when designing the
> new one.

Hmm, Ok, I will see what I can do. I dont know that we could completely 
remove it since the old code path will still need it but maybe we can 
get away from it in the delayed code path here.

> 
> <snip more>
> 
>> +STATIC int
>> +xfs_attr_da_node_removename(
>> +	struct xfs_da_args	*args)
>> +{
>> +	struct xfs_da_state	*state = NULL;
>> +	struct xfs_da_state_blk	*blk;
>> +	struct xfs_buf		*bp;
>> +	int			error, forkoff, retval = 0;
>> +	struct xfs_inode	*dp = args->dp;
>> +	int			done = 0;
>> +
>> +	trace_xfs_attr_node_removename(args);
>> +
>> +	if (args->dc.state == NULL) {
>> +		error = xfs_attr_node_hasname(args, &args->dc.state);
>> +		if (error != -EEXIST)
>> +			goto out;
>> +		else
>> +			error = 0;
>> +
>> +		/*
>> +		 * If there is an out-of-line value, de-allocate the blocks.
>> +		 * This is done before we remove the attribute so that we don't
>> +		 * overflow the maximum size of a transaction and/or hit a
>> +		 * deadlock.
>> +		 */
>> +		state = args->dc.state;
>> +		args->dc.blk = &state->path.blk[state->path.active - 1];
>> +		ASSERT(args->dc.blk->bp != NULL);
>> +		ASSERT(args->dc.blk->magic == XFS_ATTR_LEAF_MAGIC);
>> +	}
>> +	state = args->dc.state;
>> +	blk = args->dc.blk;
>> +
>> +	if (args->rmtblkno > 0 && !(args->dc.flags & XFS_DC_RM_LEAF_BLKS)) {
>> +		if (!xfs_attr3_leaf_flag_is_set(args)) {
>> +			/*
>> +			 * Fill in disk block numbers in the state structure
>> +			 * so that we can get the buffers back after we commit
>> +			 * several transactions in the following calls.
>> +			 */
>> +			error = xfs_attr_fillstate(state);
>> +			if (error)
>> +				goto out;
>> +
>> +			/*
>> +			 * Mark the attribute as INCOMPLETE, then bunmapi() the
>> +			 * remote value.
>> +			 */
>> +			error = xfs_attr3_leaf_setflag(args);
>> +			if (error)
>> +				goto out;
>> +
>> +			return -EAGAIN;
>> +		}
>> +
>> +		if (!(args->dc.flags & XFS_DC_RM_NODE_BLKS)) {
>> +			error = xfs_attr_rmtval_remove_value(args);
>> +			if (error)
>> +				goto out;
>> +		}
>> +
>> +		args->dc.flags |= XFS_DC_RM_NODE_BLKS;
> 
> This ought to be set in the if clause above...
Ok, will tuck that in

> 
>> +		while (!done && !error) {
>> +			error = xfs_bunmapi(args->trans, args->dp,
>> +				    args->rmtblkno, args->rmtblkcnt,
>> +				    XFS_BMAPI_ATTRFORK, 1, &done);
>> +			if (error)
>> +				return error;
>> +
>> +			if (!done)
>> +				return -EAGAIN;
>> +		}
> 
> Probably worth a comment to make it a little clearer that this is the
> bottom part of xfs_attr_rmtval_remove but open-coded for this case.
> 
> I wish this new attr path could share more code with the old one,
> though I dunno, probably you've already done that analysis and decided
> that cutting this up into ~30 tiny functions isn't worth it...?

Ok, I will work in some comments.  Yes, at one point I finally decided 
that further modularizing every little bit was starting to make things 
more complicated than not.

> 
> (Yeah, snip all the way to the end because I need to go rest my eyes for
> a bit but didn't want to delay this reply further.)
> 
> --D
> 

Yes, it is convoluted to follow.  Truth be told, I do think the set is a 
bit complex, but also good illustration of what the -EAGAIN solution 
looks like in practice.  I'm not really sure if there are better 
approaches, but I'm certainly open to ideas or optimizations!  :-)

Thanks!
Allison

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

* Re: [PATCH v2 03/18] xfs: Set up infastructure for deferred attribute operations
  2019-08-12 19:28   ` Brian Foster
@ 2019-08-13 18:43     ` Allison Collins
  2019-08-13 19:17       ` Brian Foster
  0 siblings, 1 reply; 56+ messages in thread
From: Allison Collins @ 2019-08-13 18:43 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs


On 8/12/19 12:28 PM, Brian Foster wrote:
> On Fri, Aug 09, 2019 at 02:37:11PM -0700, Allison Collins wrote:
>> From: Allison Henderson <allison.henderson@oracle.com>
>>
>> Currently attributes are modified directly across one or more
>> transactions.  But they are not logged or replayed in the event of
>> an error. The goal of delayed attributes is to enable logging and
>> replaying of attribute operations using the existing delayed
>> operations infrastructure.  This will later enable the attributes
>> to become part of larger multi part operations that also must first
>> be recorded to the log.  This is mostly of interest in the scheme of
>> parent pointers which would need to maintain an attribute containing
>> parent inode information any time an inode is moved, created, or
>> removed.  Parent pointers would then be of interest to any feature
>> that would need to quickly derive an inode path from the mount
>> point.  Online scrub, nfs lookups and fs grow or shrink operations
>> are all features that could take advantage of this.
>>
>> This patch adds two new log item types for setting or removing
>> attributes as deferred operations.  The xfs_attri_log_item logs an
>> intent to set or remove an attribute.  The corresponding
>> xfs_attrd_log_item holds a reference to the xfs_attri_log_item and
>> is freed once the transaction is done.  Both log items use a generic
>> xfs_attr_log_format structure that contains the attribute name,
>> value, flags, inode, and an op_flag that indicates if the operations
>> is a set or remove.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
> 
> Mostly small stuff, some of which may overlap with Darrick's comments...
> 
>>   fs/xfs/Makefile                |   2 +-
>>   fs/xfs/libxfs/xfs_attr.c       |   5 +-
>>   fs/xfs/libxfs/xfs_attr.h       |  25 ++
>>   fs/xfs/libxfs/xfs_defer.c      |   1 +
>>   fs/xfs/libxfs/xfs_defer.h      |   3 +
>>   fs/xfs/libxfs/xfs_log_format.h |  44 ++-
>>   fs/xfs/libxfs/xfs_types.h      |   1 +
>>   fs/xfs/xfs_attr_item.c         | 755 +++++++++++++++++++++++++++++++++++++++++
>>   fs/xfs/xfs_attr_item.h         | 102 ++++++
>>   fs/xfs/xfs_log.c               |   4 +
>>   fs/xfs/xfs_log_recover.c       | 174 ++++++++++
>>   fs/xfs/xfs_ondisk.h            |   2 +
>>   fs/xfs/xfs_trans.h             |   4 +-
>>   13 files changed, 1116 insertions(+), 6 deletions(-)
>>
> ...
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index aa7261a..9132d4f 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -78,6 +78,28 @@ typedef struct attrlist_ent {	/* data from attr_list() */
>>   } attrlist_ent_t;
>>   
>>   /*
>> + * List of attrs to commit later.
>> + */
>> +struct xfs_attr_item {
>> +	struct xfs_inode  *xattri_ip;
>> +	uint32_t	  xattri_op_flags;
>> +	void		  *xattri_value;      /* attr value */
>> +	uint32_t	  xattri_value_len;   /* length of value */
>> +	void		  *xattri_name;	      /* attr name */
>> +	uint32_t	  xattri_name_len;    /* length of name */
>> +	uint32_t	  xattri_flags;       /* attr flags */
>> +	struct list_head  xattri_list;
> 
> Could use a comment on the xattri_list line as well.
Sure, will do

> 
>> +
>> +	/*
>> +	 * A byte array follows the header containing the file name and
>> +	 * attribute value.
>> +	 */
>> +};
>> +
>> +#define XFS_ATTR_ITEM_SIZEOF(namelen, valuelen)	\
>> +	(sizeof(struct xfs_attr_item) + (namelen) + (valuelen))
>> +
>> +/*
>>    * Given a pointer to the (char*) buffer containing the attr_list() result,
>>    * and an index, return a pointer to the indicated attribute in the buffer.
>>    */
>> @@ -152,5 +174,8 @@ int xfs_attr_remove_args(struct xfs_da_args *args);
>>   int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>>   		  int flags, struct attrlist_cursor_kern *cursor);
>>   bool xfs_attr_namecheck(const void *name, size_t length);
>> +int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
>> +		       struct xfs_name *name);
>> +int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
>>   
>>   #endif	/* __XFS_ATTR_H__ */
> ...
>> diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
>> new file mode 100644
>> index 0000000..2340589
>> --- /dev/null
>> +++ b/fs/xfs/xfs_attr_item.c
>> @@ -0,0 +1,755 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Copyright (C) 2019 Oracle.  All Rights Reserved.
>> + * Author: Allison Henderson <allison.henderson@oracle.com>
>> + */
>> +
> ...
>> +
>> +
>> +/*
>> + * This routine is called to allocate an "attr free done" log item.
>> + */
>> +struct xfs_attrd_log_item *
>> +xfs_trans_get_attrd(struct xfs_trans		*tp,
>> +		  struct xfs_attri_log_item	*attrip)
>> +{
>> +	struct xfs_attrd_log_item		*attrdp;
>> +
>> +	ASSERT(tp != NULL);
>> +
>> +	attrdp = xfs_attrd_init(tp->t_mountp, attrip);
>> +	ASSERT(attrdp != NULL);
>> +
>> +	/*
>> +	 * Get a log_item_desc to point at the new item.
>> +	 */
> 
> No such thing as a log_item_desc any more. :)
Alrighty, will clean out

> 
>> +	xfs_trans_add_item(tp, &attrdp->attrd_item);
>> +	return attrdp;
>> +}
>> +
>> +/*
>> + * Delete an attr and log it to the ATTRD. Note that the transaction is marked
>> + * dirty regardless of whether the attr delete succeeds or fails to support the
>> + * ATTRI/ATTRD lifecycle rules.
>> + */
> 
> Looks like the comment needs an update. This function doesn't just
> handle deletes.
I think I meant "Delete attri", though maybe it's better to say it's 
been "Released". It will expand this a little to talk about the set and 
remove logic too.

> 
>> +int
>> +xfs_trans_attr(
>> +	struct xfs_da_args		*args,
>> +	struct xfs_attrd_log_item	*attrdp,
>> +	uint32_t			op_flags)
>> +{
>> +	int				error;
>> +
>> +	error = xfs_qm_dqattach_locked(args->dp, 0);
>> +	if (error)
>> +		return error;
>> +
>> +	switch (op_flags) {
>> +	case XFS_ATTR_OP_FLAGS_SET:
>> +		args->op_flags |= XFS_DA_OP_ADDNAME;
>> +		error = xfs_attr_set_args(args);
>> +		break;
>> +	case XFS_ATTR_OP_FLAGS_REMOVE:
>> +		ASSERT(XFS_IFORK_Q((args->dp)));
>> +		error = xfs_attr_remove_args(args);
>> +		break;
>> +	default:
>> +		error = -EFSCORRUPTED;
>> +	}
>> +
>> +	/*
>> +	 * Mark the transaction dirty, even on error. This ensures the
>> +	 * transaction is aborted, which:
>> +	 *
>> +	 * 1.) releases the ATTRI and frees the ATTRD
>> +	 * 2.) shuts down the filesystem
>> +	 */
>> +	args->trans->t_flags |= XFS_TRANS_DIRTY;
>> +	set_bit(XFS_LI_DIRTY, &attrdp->attrd_item.li_flags);
>> +
>> +	return error;
>> +}
>> +
>> +static int
>> +xfs_attr_diff_items(
>> +	void				*priv,
>> +	struct list_head		*a,
>> +	struct list_head		*b)
>> +{
>> +	return 0;
>> +}
>> +
>> +/* Get an ATTRI. */
>> +STATIC void *
>> +xfs_attr_create_intent(
>> +	struct xfs_trans		*tp,
>> +	unsigned int			count)
>> +{
>> +	struct xfs_attri_log_item	*attrip;
>> +
>> +	ASSERT(tp != NULL);
>> +	ASSERT(count == 1);
>> +
>> +	attrip = xfs_attri_init(tp->t_mountp);
>> +	ASSERT(attrip != NULL);
>> +
>> +	/*
>> +	 * Get a log_item_desc to point at the new item.
>> +	 */
> 
> Same deal here.
Alrighty, will clean out

> 
>> +	xfs_trans_add_item(tp, &attrip->attri_item);
>> +	return attrip;
>> +}
>> +
>> +/* Log an attr to the intent item. */
>> +STATIC void
>> +xfs_attr_log_item(
>> +	struct xfs_trans		*tp,
>> +	void				*intent,
>> +	struct list_head		*item)
>> +{
>> +	struct xfs_attri_log_item	*attrip = intent;
>> +	struct xfs_attr_item		*attr;
>> +	struct xfs_attri_log_format	*attrp;
>> +	char				*name_value;
>> +
>> +	attr = container_of(item, struct xfs_attr_item, xattri_list);
>> +	name_value = ((char *)attr) + sizeof(struct xfs_attr_item);
>> +
>> +	tp->t_flags |= XFS_TRANS_DIRTY;
>> +	set_bit(XFS_LI_DIRTY, &attrip->attri_item.li_flags);
>> +
>> +	/*
>> +	 * At this point the xfs_attr_item has been constructed, and we've
>> +	 * created the log intent. Fill in the attri log item and log format
>> +	 * structure with fields from this xfs_attr_item
>> +	 */
>> +	attrp = &attrip->attri_format;
>> +	attrp->alfi_ino = attr->xattri_ip->i_ino;
>> +	attrp->alfi_op_flags = attr->xattri_op_flags;
>> +	attrp->alfi_value_len = attr->xattri_value_len;
>> +	attrp->alfi_name_len = attr->xattri_name_len;
>> +	attrp->alfi_attr_flags = attr->xattri_flags;
>> +
>> +	attrip->attri_name = name_value;
>> +	attrip->attri_value = &name_value[attr->xattri_name_len];
>> +	attrip->attri_name_len = attr->xattri_name_len;
>> +	attrip->attri_value_len = attr->xattri_value_len;
>> +}
>> +
>> +/* Get an ATTRD so we can process all the attrs. */
>> +STATIC void *
>> +xfs_attr_create_done(
>> +	struct xfs_trans		*tp,
>> +	void				*intent,
>> +	unsigned int			count)
>> +{
>> +	return xfs_trans_get_attrd(tp, intent);
>> +}
>> +
>> +/* Process an attr. */
>> +STATIC int
>> +xfs_attr_finish_item(
>> +	struct xfs_trans		*tp,
>> +	struct list_head		*item,
>> +	void				*done_item,
>> +	void				**state)
>> +{
>> +	struct xfs_attr_item		*attr;
>> +	char				*name_value;
>> +	int				error;
>> +	int				local;
>> +	struct xfs_da_args		args;
>> +	struct xfs_name			name;
>> +	struct xfs_attrd_log_item	*attrdp;
>> +	struct xfs_attri_log_item	*attrip;
>> +
>> +	attr = container_of(item, struct xfs_attr_item, xattri_list);
>> +	name_value = ((char *)attr) + sizeof(struct xfs_attr_item);
>> +
>> +	name.name = name_value;
>> +	name.len = attr->xattri_name_len;
>> +	name.type = attr->xattri_flags;
>> +	error = xfs_attr_args_init(&args, attr->xattri_ip, &name);
>> +	if (error)
>> +		goto out;
>> +
>> +	args.hashval = xfs_da_hashname(args.name, args.namelen);
>> +	args.value = &name_value[attr->xattri_name_len];
>> +	args.valuelen = attr->xattri_value_len;
>> +	args.op_flags = XFS_DA_OP_OKNOENT;
>> +	args.total = xfs_attr_calc_size(&args, &local);
> 
> It feels a little strange to calculate this here since it should be part
> of the transaction reservation that already occurred. The interface
> requires it however, so maybe it's something we can clean up later. For
> now, a one liner comment would be useful:
> 
> 	/* must match existing transaction block res */
> 	args.total = xfs_attr_calc_size(&args, &local);
Yes, the logic did end up feeling weird for that reason.  I will add the 
comment to help clarify

> 	...
> 
>> +	args.trans = tp;
>> +
>> +	error = xfs_trans_attr(&args, done_item,
>> +			attr->xattri_op_flags);
> 
> This fits on one 80 column line.
> 
>> +out:
>> +	/*
>> +	 * We are about to free the xfs_attr_item, so we need to remove any
>> +	 * refrences that are currently pointing at its members
>> +	 */
> 
> A little more context would help. I.e.:
> 
> "The attrip refers to xfs_attr_item memory to log the name and value
> with the intent item. This already occurred when the intent was
> committed so these fields are no longer accessed. Clear them out of
> caution since we're about to free the xfs_attr_item."
> 
Sure, will add

>> +	attrdp = (struct xfs_attrd_log_item *)done_item;
>> +	attrip = attrdp->attrd_attrip;
>> +	attrip->attri_name = NULL;
>> +	attrip->attri_value = NULL;
>> +	attrip->attri_name_len = 0;
>> +	attrip->attri_value_len = 0;
>> +
> 
> Probably no need to clear the length fields either. It kind of confuses
> things IMO.
> 
> BTW, I know I suggested this and I don't want to churn this patch to
> death, but seeing it now along with the above ->total hack makes me
> wonder if we could still more elegantly carry things from the high level
> xfs_attr_item to the intent log item. It's not immediately clear to me
> what the best option is. Perhaps a separate structure to hold things
> like the name, value, tx block res, etc..? I'm ultimately fine with this
> for now. Just something to think more about for a follow on cleanup I
> suppose..
> 
>> +	kmem_free(attr);
>> +	return error;
>> +}
>> +
>> +/* Abort all pending ATTRs. */
>> +STATIC void
>> +xfs_attr_abort_intent(
>> +	void				*intent)
>> +{
>> +	xfs_attri_release(intent);
>> +}
>> +
>> +/* Cancel an attr */
>> +STATIC void
>> +xfs_attr_cancel_item(
>> +	struct list_head		*item)
>> +{
>> +	struct xfs_attr_item	*attr;
>> +
>> +	attr = container_of(item, struct xfs_attr_item, xattri_list);
>> +	kmem_free(attr);
>> +}
>> +
>> +const struct xfs_defer_op_type xfs_attr_defer_type = {
>> +	.max_items	= XFS_ATTRI_MAX_FAST_ATTRS,
>> +	.diff_items	= xfs_attr_diff_items,
>> +	.create_intent	= xfs_attr_create_intent,
>> +	.abort_intent	= xfs_attr_abort_intent,
>> +	.log_item	= xfs_attr_log_item,
>> +	.create_done	= xfs_attr_create_done,
>> +	.finish_item	= xfs_attr_finish_item,
>> +	.cancel_item	= xfs_attr_cancel_item,
>> +};
>> +
>> +static inline struct xfs_attri_log_item *ATTRI_ITEM(struct xfs_log_item *lip)
>> +{
>> +	return container_of(lip, struct xfs_attri_log_item, attri_item);
>> +}
>> +
>> +void
>> +xfs_attri_item_free(
>> +	struct xfs_attri_log_item	*attrip)
>> +{
>> +	kmem_free(attrip->attri_item.li_lv_shadow);
>> +	kmem_free(attrip);
>> +}
>> +
>> +/*
>> + * This returns the number of iovecs needed to log the given attri item. We
>> + * only need 1 iovec for an attri item.  It just logs the attr_log_format
>> + * structure.
>> + */
>> +static inline int
>> +xfs_attri_item_sizeof(
>> +	struct xfs_attri_log_item *attrip)
>> +{
>> +	return sizeof(struct xfs_attri_log_format);
>> +}
>> +
>> +STATIC void
>> +xfs_attri_item_size(
>> +	struct xfs_log_item	*lip,
>> +	int			*nvecs,
>> +	int			*nbytes)
>> +{
>> +	struct xfs_attri_log_item       *attrip = ATTRI_ITEM(lip);
>> +
>> +	*nvecs += 1;
>> +	*nbytes += xfs_attri_item_sizeof(attrip);
>> +
>> +	if (attrip->attri_name_len > 0) {
>> +		*nvecs += 1;
>> +		*nbytes += ATTR_NVEC_SIZE(attrip->attri_name_len);
>> +	}
> 
> We always need an attr name, right? Perhaps this branch should be
> replaced with an assert on ->attri_name_len.
Yes, name is a must, value is not.  Will add the assert

> 
>> +
>> +	if (attrip->attri_value_len > 0) {
>> +		*nvecs += 1;
>> +		*nbytes += ATTR_NVEC_SIZE(attrip->attri_value_len);
>> +	}
>> +}
>> +
>> +/*
>> + * This is called to fill in the vector of log iovecs for the given attri log
>> + * item. We use only 1 iovec, and we point that at the attri_log_format
>> + * structure embedded in the attri item. It is at this point that we assert
>> + * that all of the attr slots in the attri item have been filled.
>> + */
> 
> Looks like a stale comment. We use up to three iovecs here. I also don't
> see any assertion related to attr slots. Irrelevant bit from a different
> intent item perhaps?
Yes, I think the efis had then slots, so that verbage should come out.  Thx!

> 
>> +STATIC void
>> +xfs_attri_item_format(
>> +	struct xfs_log_item	*lip,
>> +	struct xfs_log_vec	*lv)
>> +{
>> +	struct xfs_attri_log_item	*attrip = ATTRI_ITEM(lip);
>> +	struct xfs_log_iovec	*vecp = NULL;
>> +
>> +	attrip->attri_format.alfi_type = XFS_LI_ATTRI;
>> +	attrip->attri_format.alfi_size = 1;
>> +
>> +	/*
>> +	 * This size accounting must be done before copying the attrip into the
>> +	 * iovec.  If we do it after, the wrong size will be recorded to the log
>> +	 * and we trip across assertion checks for bad region sizes later during
>> +	 * the log recovery.
>> +	 */
>> +	if (attrip->attri_name_len > 0)
>> +		attrip->attri_format.alfi_size++;
> 
> Similar comment as before wrt to a required name.
Ok, will do

> 
>> +	if (attrip->attri_value_len > 0)
>> +		attrip->attri_format.alfi_size++;
>> +
>> +	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRI_FORMAT,
>> +			&attrip->attri_format,
>> +			xfs_attri_item_sizeof(attrip));
>> +	if (attrip->attri_name_len > 0)
>> +		xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_NAME,
>> +				attrip->attri_name,
>> +				ATTR_NVEC_SIZE(attrip->attri_name_len));
>> +
>> +	if (attrip->attri_value_len > 0)
>> +		xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_VALUE,
>> +				attrip->attri_value,
>> +				ATTR_NVEC_SIZE(attrip->attri_value_len));
>> +}
>> +
>> +
> ...
>> +
>> +/*
>> + * This is called to fill in the vector of log iovecs for the
>> + * given attrd log item. We use only 1 iovec, and we point that
>> + * at the attr_log_format structure embedded in the attrd item.
>> + * It is at this point that we assert that all of the attr
>> + * slots in the attrd item have been filled.
>> + */
> 
> Comment can be widened to 80 cols and another reference to an assertion
> that doesn't exist.Sure, I will widen out the line wrapping here
> 
>> +STATIC void
>> +xfs_attrd_item_format(
>> +	struct xfs_log_item	*lip,
>> +	struct xfs_log_vec	*lv)
>> +{
>> +	struct xfs_attrd_log_item	*attrdp = ATTRD_ITEM(lip);
>> +	struct xfs_log_iovec	*vecp = NULL;
>> +
>> +	attrdp->attrd_format.alfd_type = XFS_LI_ATTRD;
>> +	attrdp->attrd_format.alfd_size = 1;
>> +
>> +	xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRD_FORMAT,
>> +			&attrdp->attrd_format, xfs_attrd_item_sizeof(attrdp));
>> +}
>> +
> ...
>> +/*
>> + * Process an attr intent item that was recovered from the log.  We need to
>> + * delete the attr that it describes.
>> + */
>> +int
>> +xfs_attri_recover(
>> +	struct xfs_mount		*mp,
>> +	struct xfs_attri_log_item	*attrip)
>> +{
>> +	struct xfs_inode		*ip;
>> +	struct xfs_attrd_log_item	*attrdp;
>> +	struct xfs_da_args		args;
>> +	struct xfs_attri_log_format	*attrp;
>> +	struct xfs_trans_res		tres;
>> +	int				local;
>> +	int				error = 0;
>> +	int				rsvd = 0;
>> +	struct xfs_name			name;
>> +
>> +	ASSERT(!test_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags));
>> +
>> +	/*
>> +	 * First check the validity of the attr described by the ATTRI.  If any
>> +	 * are bad, then assume that all are bad and just toss the ATTRI.
>> +	 */
>> +	attrp = &attrip->attri_format;
>> +	if (
>> +	    !(attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_SET ||
>> +		attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_REMOVE) ||
>> +	      (attrp->alfi_value_len > XATTR_SIZE_MAX) ||
>> +	      (attrp->alfi_name_len > XATTR_NAME_MAX) ||
>> +	      (attrp->alfi_name_len == 0)
>> +	) {
> 
> Can we fix the brace usage here?
Sure, it's got a lot of logic going on here, so I was trying to make it 
easier to look at.  You prefer the parens not to be on separate lines?

> 
>> +		/*
>> +		 * This will pull the ATTRI from the AIL and free the memory
>> +		 * associated with it.
>> +		 */
>> +		set_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags);
>> +		xfs_attri_release(attrip);
>> +		return -EIO;
>> +	}
>> +
>> +	attrp = &attrip->attri_format;
> 
> Just assigned attrp above.
> 
>> +	error = xfs_iget(mp, 0, attrp->alfi_ino, 0, 0, &ip);
>> +	if (error)
>> +		return error;
>> +
> 
> I don't see any corresponding xfs_irele() in this function.
You fixed the busy inode bug I was chasing!  Thank you!

> 
>> +	name.name = attrip->attri_name;
>> +	name.len = attrp->alfi_name_len;
>> +	name.type = attrp->alfi_attr_flags;
>> +	error = xfs_attr_args_init(&args, ip, &name);
>> +	if (error)
>> +		return error;
>> +
>> +	args.hashval = xfs_da_hashname(args.name, args.namelen);
>> +	args.value = attrip->attri_value;
>> +	args.valuelen = attrp->alfi_value_len;
>> +	args.op_flags = XFS_DA_OP_OKNOENT;
>> +	args.total = xfs_attr_calc_size(&args, &local);
>> +
>> +	tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
>> +			M_RES(mp)->tr_attrsetrt.tr_logres * args.total;
>> +	tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
>> +	tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
>> +
>> +	error = xfs_trans_alloc(mp, &tres, args.total,  0,
>> +				rsvd ? XFS_TRANS_RESERVE : 0, &args.trans);
>> +	if (error)
>> +		return error;
>> +	attrdp = xfs_trans_get_attrd(args.trans, attrip);
>> +
>> +	xfs_ilock(ip, XFS_ILOCK_EXCL);
>> +
>> +	xfs_trans_ijoin(args.trans, ip, 0);
>> +	error = xfs_trans_attr(&args, attrdp, attrp->alfi_op_flags);
>> +	if (error)
>> +		goto abort_error;
>> +
>> +
>> +	set_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags);
>> +	xfs_trans_log_inode(args.trans, ip, XFS_ILOG_CORE | XFS_ILOG_ADATA);
>> +	error = xfs_trans_commit(args.trans);
>> +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
>> +	return error;
>> +
>> +abort_error:
>> +	xfs_trans_cancel(args.trans);
>> +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
>> +	return error;
>> +}
>> diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h
>> new file mode 100644
>> index 0000000..aad32ed
>> --- /dev/null
>> +++ b/fs/xfs/xfs_attr_item.h
>> @@ -0,0 +1,102 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Copyright (C) 2019 Oracle.  All Rights Reserved.
>> + * Author: Allison Henderson <allison.henderson@oracle.com>
>> + */
>> +#ifndef	__XFS_ATTR_ITEM_H__
>> +#define	__XFS_ATTR_ITEM_H__
>> +
>> +/* kernel only ATTRI/ATTRD definitions */
>> +
>> +struct xfs_mount;
>> +struct kmem_zone;
>> +
>> +/*
>> + * Max number of attrs in fast allocation path.
>> + */
>> +#define XFS_ATTRI_MAX_FAST_ATTRS        1
>> +
> 
> I don't think we really need a macro for this given there is no concept
> of a fast path. I'd just hardcode the 1 in the dfops structure.
Alrighty, will clean that out too.

> 
>> +
>> +/*
>> + * Define ATTR flag bits. Manipulated by set/clear/test_bit operators.
>> + */
>> +#define	XFS_ATTRI_RECOVERED	1
>> +
>> +
>> +/* iovec length must be 32-bit aligned */
>> +#define ATTR_NVEC_SIZE(size) (size == sizeof(int32_t) ? sizeof(int32_t) : \
>> +				size + sizeof(int32_t) - \
>> +				(size % sizeof(int32_t)))
>> +
>> +/*
>> + * This is the "attr intention" log item.  It is used to log the fact that some
>> + * need to be processed.  It is used in conjunction with the "attr done" log
> 
> Some what need to be processed?
The attribute operation in general (set or remove).  I will add a little 
extra commentary to help clarify

> 
>> + * item described below.
>> + *
>> + * The ATTRI is reference counted so that it is not freed prior to both the
>> + * ATTRI and ATTRD being committed and unpinned. This ensures the ATTRI is
>> + * inserted into the AIL even in the event of out of order ATTRI/ATTRD
>> + * processing. In other words, an ATTRI is born with two references:
>> + *
>> + *      1.) an ATTRI held reference to track ATTRI AIL insertion
>> + *      2.) an ATTRD held reference to track ATTRD commit
>> + *
>> + * On allocation, both references are the responsibility of the caller. Once the
>> + * ATTRI is added to and dirtied in a transaction, ownership of reference one
>> + * transfers to the transaction. The reference is dropped once the ATTRI is
>> + * inserted to the AIL or in the event of failure along the way (e.g., commit
>> + * failure, log I/O error, etc.). Note that the caller remains responsible for
>> + * the ATTRD reference under all circumstances to this point. The caller has no
>> + * means to detect failure once the transaction is committed, however.
>> + * Therefore, an ATTRD is required after this point, even in the event of
>> + * unrelated failure.
>> + *
>> + * Once an ATTRD is allocated and dirtied in a transaction, reference two
>> + * transfers to the transaction. The ATTRD reference is dropped once it reaches
>> + * the unpin handler. Similar to the ATTRI, the reference also drops in the
>> + * event of commit failure or log I/O errors. Note that the ATTRD is not
>> + * inserted in the AIL, so at this point both the ATTI and ATTRD are freed.
>> + */
>> +struct xfs_attri_log_item {
>> +	struct xfs_log_item		attri_item;
>> +	atomic_t			attri_refcount;
>> +	unsigned long			attri_flags;	/* misc flags */
>> +	int				attri_name_len;
>> +	void				*attri_name;
>> +	int				attri_value_len;
>> +	void				*attri_value;
>> +	struct xfs_attri_log_format	attri_format;
>> +};
>> +
>> +/*
>> + * This is the "attr done" log item.  It is used to log the fact that some attrs
>> + * earlier mentioned in an attri item have been freed.
>> + */
>> +struct xfs_attrd_log_item {
>> +	struct xfs_log_item		attrd_item;
>> +	struct xfs_attri_log_item	*attrd_attrip;
>> +	struct xfs_attrd_log_format	attrd_format;
>> +};
>> +
>> +/*
>> + * Max number of attrs in fast allocation path.
>> + */
>> +#define	XFS_ATTRD_MAX_FAST_ATTRS	1
>> +
> 
> This define is unused.
> 
>> +extern struct kmem_zone	*xfs_attri_zone;
>> +extern struct kmem_zone	*xfs_attrd_zone;
>> +
> 
> The above zones don't exist either.
Ok, will remove these then

> 
>> +struct xfs_attri_log_item	*xfs_attri_init(struct xfs_mount *mp);
>> +struct xfs_attrd_log_item	*xfs_attrd_init(struct xfs_mount *mp,
>> +					struct xfs_attri_log_item *attrip);
>> +int xfs_attri_copy_format(struct xfs_log_iovec *buf,
>> +			   struct xfs_attri_log_format *dst_attri_fmt);
>> +int xfs_attrd_copy_format(struct xfs_log_iovec *buf,
>> +			   struct xfs_attrd_log_format *dst_attrd_fmt);
> 
> Function doesn't exist.
> 
>> +void			xfs_attri_item_free(struct xfs_attri_log_item *attrip);
>> +void			xfs_attri_release(struct xfs_attri_log_item *attrip);
>> +
>> +int			xfs_attri_recover(struct xfs_mount *mp,
>> +					struct xfs_attri_log_item *attrip);
>> +
>> +#endif	/* __XFS_ATTR_ITEM_H__ */
>> diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
>> index 00e9f5c..2fbd180 100644
>> --- a/fs/xfs/xfs_log.c
>> +++ b/fs/xfs/xfs_log.c
>> @@ -2005,6 +2005,10 @@ xlog_print_tic_res(
>>   	    REG_TYPE_STR(CUD_FORMAT, "cud_format"),
>>   	    REG_TYPE_STR(BUI_FORMAT, "bui_format"),
>>   	    REG_TYPE_STR(BUD_FORMAT, "bud_format"),
>> +	    REG_TYPE_STR(ATTRI_FORMAT, "attri_format"),
>> +	    REG_TYPE_STR(ATTRD_FORMAT, "attrd_format"),
>> +	    REG_TYPE_STR(ATTR_NAME, "attr_name"),
>> +	    REG_TYPE_STR(ATTR_VALUE, "attr_value"),
>>   	};
>>   	BUILD_BUG_ON(ARRAY_SIZE(res_type_str) != XLOG_REG_TYPE_MAX + 1);
>>   #undef REG_TYPE_STR
>> diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
>> index 13d1d3e..233efdb3 100644
>> --- a/fs/xfs/xfs_log_recover.c
>> +++ b/fs/xfs/xfs_log_recover.c
> ...
>> @@ -3422,6 +3425,119 @@ xlog_recover_efd_pass2(
>>   	return 0;
>>   }
>>   
>> +STATIC int
>> +xlog_recover_attri_pass2(
>> +	struct xlog                     *log,
>> +	struct xlog_recover_item        *item,
>> +	xfs_lsn_t                       lsn)
>> +{
>> +	int                             error;
>> +	struct xfs_mount                *mp = log->l_mp;
>> +	struct xfs_attri_log_item       *attrip;
>> +	struct xfs_attri_log_format     *attri_formatp;
>> +	char				*name = NULL;
>> +	char				*value = NULL;
>> +	int				region = 0;
>> +
>> +	attri_formatp = item->ri_buf[region].i_addr;
>> +
>> +	attrip = xfs_attri_init(mp);
>> +	error = xfs_attri_copy_format(&item->ri_buf[region],
>> +				      &attrip->attri_format);
>> +	if (error) {
>> +		xfs_attri_item_free(attrip);
>> +		return error;
>> +	}
>> +
>> +	attrip->attri_name_len = attri_formatp->alfi_name_len;
>> +	attrip->attri_value_len = attri_formatp->alfi_value_len;
>> +	attrip = kmem_realloc(attrip, sizeof(struct xfs_attri_log_item) +
>> +			      attrip->attri_name_len + attrip->attri_value_len,
>> +			      KM_SLEEP);
>> +
>> +	if (attrip->attri_name_len > 0) {
>> +		region++;
>> +		name = ((char *)attrip) + sizeof(struct xfs_attri_log_item);
>> +		memcpy(name, item->ri_buf[region].i_addr,
>> +		       attrip->attri_name_len);
>> +		attrip->attri_name = name;
>> +	}
> 
> Same comment wrt to a required name.
> 
>> +
>> +	if (attrip->attri_value_len > 0) {
>> +		region++;
>> +		value = ((char *)attrip) + sizeof(struct xfs_attri_log_item) +
>> +			attrip->attri_name_len;
>> +		memcpy(value, item->ri_buf[region].i_addr,
>> +			attrip->attri_value_len);
>> +		attrip->attri_value = value;
>> +	}
>> +
>> +	spin_lock(&log->l_ailp->ail_lock);
>> +	/*
>> +	 * The ATTRI has two references. One for the ATTRD and one for ATTRI to
>> +	 * ensure it makes it into the AIL. Insert the ATTRI into the AIL
>> +	 * directly and drop the ATTRI reference. Note that
>> +	 * xfs_trans_ail_update() drops the AIL lock.
>> +	 */
>> +	xfs_trans_ail_update(log->l_ailp, &attrip->attri_item, lsn);
>> +	xfs_attri_release(attrip);
>> +	return 0;
>> +}
>> +
>> +
> ...
>> diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
>> index 64d7f17..95924dc 100644
>> --- a/fs/xfs/xfs_trans.h
>> +++ b/fs/xfs/xfs_trans.h
>> @@ -26,6 +26,9 @@ struct xfs_cui_log_item;
>>   struct xfs_cud_log_item;
>>   struct xfs_bui_log_item;
>>   struct xfs_bud_log_item;
>> +struct xfs_attrd_log_item;
>> +struct xfs_attri_log_item;
>> +struct xfs_da_args;
>>   
> 
> What are the xfs_trans.h changes for?

Oh, they used to be for xfs_trans_attr and friends in v1.  I noticed a 
recent change moved this family of routines into their corresponding 
*_item.c files, so I followed suit.  Will clean these out.

Thanks for the review!  I know it's a lot!
Allison

> 
> Brian
> 
>>   struct xfs_log_item {
>>   	struct list_head		li_ail;		/* AIL pointers */
>> @@ -229,7 +232,6 @@ void		xfs_trans_log_buf(struct xfs_trans *, struct xfs_buf *, uint,
>>   void		xfs_trans_dirty_buf(struct xfs_trans *, struct xfs_buf *);
>>   bool		xfs_trans_buf_is_dirty(struct xfs_buf *bp);
>>   void		xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
>> -
>>   int		xfs_trans_commit(struct xfs_trans *);
>>   int		xfs_trans_roll(struct xfs_trans **);
>>   int		xfs_trans_roll_inode(struct xfs_trans **, struct xfs_inode *);
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v2 03/18] xfs: Set up infastructure for deferred attribute operations
  2019-08-13 18:43     ` Allison Collins
@ 2019-08-13 19:17       ` Brian Foster
  0 siblings, 0 replies; 56+ messages in thread
From: Brian Foster @ 2019-08-13 19:17 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Tue, Aug 13, 2019 at 11:43:51AM -0700, Allison Collins wrote:
> 
> On 8/12/19 12:28 PM, Brian Foster wrote:
> > On Fri, Aug 09, 2019 at 02:37:11PM -0700, Allison Collins wrote:
> > > From: Allison Henderson <allison.henderson@oracle.com>
> > > 
> > > Currently attributes are modified directly across one or more
> > > transactions.  But they are not logged or replayed in the event of
> > > an error. The goal of delayed attributes is to enable logging and
> > > replaying of attribute operations using the existing delayed
> > > operations infrastructure.  This will later enable the attributes
> > > to become part of larger multi part operations that also must first
> > > be recorded to the log.  This is mostly of interest in the scheme of
> > > parent pointers which would need to maintain an attribute containing
> > > parent inode information any time an inode is moved, created, or
> > > removed.  Parent pointers would then be of interest to any feature
> > > that would need to quickly derive an inode path from the mount
> > > point.  Online scrub, nfs lookups and fs grow or shrink operations
> > > are all features that could take advantage of this.
> > > 
> > > This patch adds two new log item types for setting or removing
> > > attributes as deferred operations.  The xfs_attri_log_item logs an
> > > intent to set or remove an attribute.  The corresponding
> > > xfs_attrd_log_item holds a reference to the xfs_attri_log_item and
> > > is freed once the transaction is done.  Both log items use a generic
> > > xfs_attr_log_format structure that contains the attribute name,
> > > value, flags, inode, and an op_flag that indicates if the operations
> > > is a set or remove.
> > > 
> > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > ---
...
> > > +/*
> > > + * Process an attr intent item that was recovered from the log.  We need to
> > > + * delete the attr that it describes.
> > > + */
> > > +int
> > > +xfs_attri_recover(
> > > +	struct xfs_mount		*mp,
> > > +	struct xfs_attri_log_item	*attrip)
> > > +{
> > > +	struct xfs_inode		*ip;
> > > +	struct xfs_attrd_log_item	*attrdp;
> > > +	struct xfs_da_args		args;
> > > +	struct xfs_attri_log_format	*attrp;
> > > +	struct xfs_trans_res		tres;
> > > +	int				local;
> > > +	int				error = 0;
> > > +	int				rsvd = 0;
> > > +	struct xfs_name			name;
> > > +
> > > +	ASSERT(!test_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags));
> > > +
> > > +	/*
> > > +	 * First check the validity of the attr described by the ATTRI.  If any
> > > +	 * are bad, then assume that all are bad and just toss the ATTRI.
> > > +	 */
> > > +	attrp = &attrip->attri_format;
> > > +	if (
> > > +	    !(attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_SET ||
> > > +		attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_REMOVE) ||
> > > +	      (attrp->alfi_value_len > XATTR_SIZE_MAX) ||
> > > +	      (attrp->alfi_name_len > XATTR_NAME_MAX) ||
> > > +	      (attrp->alfi_name_len == 0)
> > > +	) {
> > 
> > Can we fix the brace usage here?
> Sure, it's got a lot of logic going on here, so I was trying to make it
> easier to look at.  You prefer the parens not to be on separate lines?
> 

Yeah, and just align the checks that go together to be consistent with
the rest of the code:

	if (!(attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_SET ||
	      attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_REMOVE) ||
	    (attrp->alfi_value_len > XATTR_SIZE_MAX) ||
	    (attrp->alfi_name_len > XATTR_NAME_MAX) ||
	    (attrp->alfi_name_len == 0)) {
		...
	}

Thanks!

Brian

> > 
> > > +		/*
> > > +		 * This will pull the ATTRI from the AIL and free the memory
> > > +		 * associated with it.
> > > +		 */
> > > +		set_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags);
> > > +		xfs_attri_release(attrip);
> > > +		return -EIO;
> > > +	}
> > > +
> > > +	attrp = &attrip->attri_format;
> > 
> > Just assigned attrp above.
> > 
> > > +	error = xfs_iget(mp, 0, attrp->alfi_ino, 0, 0, &ip);
> > > +	if (error)
> > > +		return error;
> > > +
> > 
> > I don't see any corresponding xfs_irele() in this function.
> You fixed the busy inode bug I was chasing!  Thank you!
> 
> > 
> > > +	name.name = attrip->attri_name;
> > > +	name.len = attrp->alfi_name_len;
> > > +	name.type = attrp->alfi_attr_flags;
> > > +	error = xfs_attr_args_init(&args, ip, &name);
> > > +	if (error)
> > > +		return error;
> > > +
> > > +	args.hashval = xfs_da_hashname(args.name, args.namelen);
> > > +	args.value = attrip->attri_value;
> > > +	args.valuelen = attrp->alfi_value_len;
> > > +	args.op_flags = XFS_DA_OP_OKNOENT;
> > > +	args.total = xfs_attr_calc_size(&args, &local);
> > > +
> > > +	tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
> > > +			M_RES(mp)->tr_attrsetrt.tr_logres * args.total;
> > > +	tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
> > > +	tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
> > > +
> > > +	error = xfs_trans_alloc(mp, &tres, args.total,  0,
> > > +				rsvd ? XFS_TRANS_RESERVE : 0, &args.trans);
> > > +	if (error)
> > > +		return error;
> > > +	attrdp = xfs_trans_get_attrd(args.trans, attrip);
> > > +
> > > +	xfs_ilock(ip, XFS_ILOCK_EXCL);
> > > +
> > > +	xfs_trans_ijoin(args.trans, ip, 0);
> > > +	error = xfs_trans_attr(&args, attrdp, attrp->alfi_op_flags);
> > > +	if (error)
> > > +		goto abort_error;
> > > +
> > > +
> > > +	set_bit(XFS_ATTRI_RECOVERED, &attrip->attri_flags);
> > > +	xfs_trans_log_inode(args.trans, ip, XFS_ILOG_CORE | XFS_ILOG_ADATA);
> > > +	error = xfs_trans_commit(args.trans);
> > > +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
> > > +	return error;
> > > +
> > > +abort_error:
> > > +	xfs_trans_cancel(args.trans);
> > > +	xfs_iunlock(ip, XFS_ILOCK_EXCL);
> > > +	return error;
> > > +}
> > > diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h
> > > new file mode 100644
> > > index 0000000..aad32ed
> > > --- /dev/null
> > > +++ b/fs/xfs/xfs_attr_item.h
> > > @@ -0,0 +1,102 @@
> > > +// SPDX-License-Identifier: GPL-2.0+
> > > +/*
> > > + * Copyright (C) 2019 Oracle.  All Rights Reserved.
> > > + * Author: Allison Henderson <allison.henderson@oracle.com>
> > > + */
> > > +#ifndef	__XFS_ATTR_ITEM_H__
> > > +#define	__XFS_ATTR_ITEM_H__
> > > +
> > > +/* kernel only ATTRI/ATTRD definitions */
> > > +
> > > +struct xfs_mount;
> > > +struct kmem_zone;
> > > +
> > > +/*
> > > + * Max number of attrs in fast allocation path.
> > > + */
> > > +#define XFS_ATTRI_MAX_FAST_ATTRS        1
> > > +
> > 
> > I don't think we really need a macro for this given there is no concept
> > of a fast path. I'd just hardcode the 1 in the dfops structure.
> Alrighty, will clean that out too.
> 
> > 
> > > +
> > > +/*
> > > + * Define ATTR flag bits. Manipulated by set/clear/test_bit operators.
> > > + */
> > > +#define	XFS_ATTRI_RECOVERED	1
> > > +
> > > +
> > > +/* iovec length must be 32-bit aligned */
> > > +#define ATTR_NVEC_SIZE(size) (size == sizeof(int32_t) ? sizeof(int32_t) : \
> > > +				size + sizeof(int32_t) - \
> > > +				(size % sizeof(int32_t)))
> > > +
> > > +/*
> > > + * This is the "attr intention" log item.  It is used to log the fact that some
> > > + * need to be processed.  It is used in conjunction with the "attr done" log
> > 
> > Some what need to be processed?
> The attribute operation in general (set or remove).  I will add a little
> extra commentary to help clarify
> 
> > 
> > > + * item described below.
> > > + *
> > > + * The ATTRI is reference counted so that it is not freed prior to both the
> > > + * ATTRI and ATTRD being committed and unpinned. This ensures the ATTRI is
> > > + * inserted into the AIL even in the event of out of order ATTRI/ATTRD
> > > + * processing. In other words, an ATTRI is born with two references:
> > > + *
> > > + *      1.) an ATTRI held reference to track ATTRI AIL insertion
> > > + *      2.) an ATTRD held reference to track ATTRD commit
> > > + *
> > > + * On allocation, both references are the responsibility of the caller. Once the
> > > + * ATTRI is added to and dirtied in a transaction, ownership of reference one
> > > + * transfers to the transaction. The reference is dropped once the ATTRI is
> > > + * inserted to the AIL or in the event of failure along the way (e.g., commit
> > > + * failure, log I/O error, etc.). Note that the caller remains responsible for
> > > + * the ATTRD reference under all circumstances to this point. The caller has no
> > > + * means to detect failure once the transaction is committed, however.
> > > + * Therefore, an ATTRD is required after this point, even in the event of
> > > + * unrelated failure.
> > > + *
> > > + * Once an ATTRD is allocated and dirtied in a transaction, reference two
> > > + * transfers to the transaction. The ATTRD reference is dropped once it reaches
> > > + * the unpin handler. Similar to the ATTRI, the reference also drops in the
> > > + * event of commit failure or log I/O errors. Note that the ATTRD is not
> > > + * inserted in the AIL, so at this point both the ATTI and ATTRD are freed.
> > > + */
> > > +struct xfs_attri_log_item {
> > > +	struct xfs_log_item		attri_item;
> > > +	atomic_t			attri_refcount;
> > > +	unsigned long			attri_flags;	/* misc flags */
> > > +	int				attri_name_len;
> > > +	void				*attri_name;
> > > +	int				attri_value_len;
> > > +	void				*attri_value;
> > > +	struct xfs_attri_log_format	attri_format;
> > > +};
> > > +
> > > +/*
> > > + * This is the "attr done" log item.  It is used to log the fact that some attrs
> > > + * earlier mentioned in an attri item have been freed.
> > > + */
> > > +struct xfs_attrd_log_item {
> > > +	struct xfs_log_item		attrd_item;
> > > +	struct xfs_attri_log_item	*attrd_attrip;
> > > +	struct xfs_attrd_log_format	attrd_format;
> > > +};
> > > +
> > > +/*
> > > + * Max number of attrs in fast allocation path.
> > > + */
> > > +#define	XFS_ATTRD_MAX_FAST_ATTRS	1
> > > +
> > 
> > This define is unused.
> > 
> > > +extern struct kmem_zone	*xfs_attri_zone;
> > > +extern struct kmem_zone	*xfs_attrd_zone;
> > > +
> > 
> > The above zones don't exist either.
> Ok, will remove these then
> 
> > 
> > > +struct xfs_attri_log_item	*xfs_attri_init(struct xfs_mount *mp);
> > > +struct xfs_attrd_log_item	*xfs_attrd_init(struct xfs_mount *mp,
> > > +					struct xfs_attri_log_item *attrip);
> > > +int xfs_attri_copy_format(struct xfs_log_iovec *buf,
> > > +			   struct xfs_attri_log_format *dst_attri_fmt);
> > > +int xfs_attrd_copy_format(struct xfs_log_iovec *buf,
> > > +			   struct xfs_attrd_log_format *dst_attrd_fmt);
> > 
> > Function doesn't exist.
> > 
> > > +void			xfs_attri_item_free(struct xfs_attri_log_item *attrip);
> > > +void			xfs_attri_release(struct xfs_attri_log_item *attrip);
> > > +
> > > +int			xfs_attri_recover(struct xfs_mount *mp,
> > > +					struct xfs_attri_log_item *attrip);
> > > +
> > > +#endif	/* __XFS_ATTR_ITEM_H__ */
> > > diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
> > > index 00e9f5c..2fbd180 100644
> > > --- a/fs/xfs/xfs_log.c
> > > +++ b/fs/xfs/xfs_log.c
> > > @@ -2005,6 +2005,10 @@ xlog_print_tic_res(
> > >   	    REG_TYPE_STR(CUD_FORMAT, "cud_format"),
> > >   	    REG_TYPE_STR(BUI_FORMAT, "bui_format"),
> > >   	    REG_TYPE_STR(BUD_FORMAT, "bud_format"),
> > > +	    REG_TYPE_STR(ATTRI_FORMAT, "attri_format"),
> > > +	    REG_TYPE_STR(ATTRD_FORMAT, "attrd_format"),
> > > +	    REG_TYPE_STR(ATTR_NAME, "attr_name"),
> > > +	    REG_TYPE_STR(ATTR_VALUE, "attr_value"),
> > >   	};
> > >   	BUILD_BUG_ON(ARRAY_SIZE(res_type_str) != XLOG_REG_TYPE_MAX + 1);
> > >   #undef REG_TYPE_STR
> > > diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
> > > index 13d1d3e..233efdb3 100644
> > > --- a/fs/xfs/xfs_log_recover.c
> > > +++ b/fs/xfs/xfs_log_recover.c
> > ...
> > > @@ -3422,6 +3425,119 @@ xlog_recover_efd_pass2(
> > >   	return 0;
> > >   }
> > > +STATIC int
> > > +xlog_recover_attri_pass2(
> > > +	struct xlog                     *log,
> > > +	struct xlog_recover_item        *item,
> > > +	xfs_lsn_t                       lsn)
> > > +{
> > > +	int                             error;
> > > +	struct xfs_mount                *mp = log->l_mp;
> > > +	struct xfs_attri_log_item       *attrip;
> > > +	struct xfs_attri_log_format     *attri_formatp;
> > > +	char				*name = NULL;
> > > +	char				*value = NULL;
> > > +	int				region = 0;
> > > +
> > > +	attri_formatp = item->ri_buf[region].i_addr;
> > > +
> > > +	attrip = xfs_attri_init(mp);
> > > +	error = xfs_attri_copy_format(&item->ri_buf[region],
> > > +				      &attrip->attri_format);
> > > +	if (error) {
> > > +		xfs_attri_item_free(attrip);
> > > +		return error;
> > > +	}
> > > +
> > > +	attrip->attri_name_len = attri_formatp->alfi_name_len;
> > > +	attrip->attri_value_len = attri_formatp->alfi_value_len;
> > > +	attrip = kmem_realloc(attrip, sizeof(struct xfs_attri_log_item) +
> > > +			      attrip->attri_name_len + attrip->attri_value_len,
> > > +			      KM_SLEEP);
> > > +
> > > +	if (attrip->attri_name_len > 0) {
> > > +		region++;
> > > +		name = ((char *)attrip) + sizeof(struct xfs_attri_log_item);
> > > +		memcpy(name, item->ri_buf[region].i_addr,
> > > +		       attrip->attri_name_len);
> > > +		attrip->attri_name = name;
> > > +	}
> > 
> > Same comment wrt to a required name.
> > 
> > > +
> > > +	if (attrip->attri_value_len > 0) {
> > > +		region++;
> > > +		value = ((char *)attrip) + sizeof(struct xfs_attri_log_item) +
> > > +			attrip->attri_name_len;
> > > +		memcpy(value, item->ri_buf[region].i_addr,
> > > +			attrip->attri_value_len);
> > > +		attrip->attri_value = value;
> > > +	}
> > > +
> > > +	spin_lock(&log->l_ailp->ail_lock);
> > > +	/*
> > > +	 * The ATTRI has two references. One for the ATTRD and one for ATTRI to
> > > +	 * ensure it makes it into the AIL. Insert the ATTRI into the AIL
> > > +	 * directly and drop the ATTRI reference. Note that
> > > +	 * xfs_trans_ail_update() drops the AIL lock.
> > > +	 */
> > > +	xfs_trans_ail_update(log->l_ailp, &attrip->attri_item, lsn);
> > > +	xfs_attri_release(attrip);
> > > +	return 0;
> > > +}
> > > +
> > > +
> > ...
> > > diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
> > > index 64d7f17..95924dc 100644
> > > --- a/fs/xfs/xfs_trans.h
> > > +++ b/fs/xfs/xfs_trans.h
> > > @@ -26,6 +26,9 @@ struct xfs_cui_log_item;
> > >   struct xfs_cud_log_item;
> > >   struct xfs_bui_log_item;
> > >   struct xfs_bud_log_item;
> > > +struct xfs_attrd_log_item;
> > > +struct xfs_attri_log_item;
> > > +struct xfs_da_args;
> > 
> > What are the xfs_trans.h changes for?
> 
> Oh, they used to be for xfs_trans_attr and friends in v1.  I noticed a
> recent change moved this family of routines into their corresponding
> *_item.c files, so I followed suit.  Will clean these out.
> 
> Thanks for the review!  I know it's a lot!
> Allison
> 
> > 
> > Brian
> > 
> > >   struct xfs_log_item {
> > >   	struct list_head		li_ail;		/* AIL pointers */
> > > @@ -229,7 +232,6 @@ void		xfs_trans_log_buf(struct xfs_trans *, struct xfs_buf *, uint,
> > >   void		xfs_trans_dirty_buf(struct xfs_trans *, struct xfs_buf *);
> > >   bool		xfs_trans_buf_is_dirty(struct xfs_buf *bp);
> > >   void		xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
> > > -
> > >   int		xfs_trans_commit(struct xfs_trans *);
> > >   int		xfs_trans_roll(struct xfs_trans **);
> > >   int		xfs_trans_roll_inode(struct xfs_trans **, struct xfs_inode *);
> > > -- 
> > > 2.7.4
> > > 

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

end of thread, other threads:[~2019-08-13 19:17 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-09 21:37 [PATCH v2 00/18] Delayed Attributes Allison Collins
2019-08-09 21:37 ` [PATCH v2 01/18] xfs: Remove all strlen in all xfs_attr_* functions for attr names Allison Collins
2019-08-09 21:37 ` [PATCH v2 02/18] xfs: Replace attribute parameters with struct xfs_name Allison Collins
2019-08-12 15:13   ` Darrick J. Wong
2019-08-12 19:27     ` Allison Collins
2019-08-09 21:37 ` [PATCH v2 03/18] xfs: Set up infastructure for deferred attribute operations Allison Collins
2019-08-12 15:40   ` Darrick J. Wong
2019-08-12 19:28     ` Allison Collins
2019-08-12 19:28   ` Brian Foster
2019-08-13 18:43     ` Allison Collins
2019-08-13 19:17       ` Brian Foster
2019-08-09 21:37 ` [PATCH v2 04/18] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred Allison Collins
2019-08-12 15:44   ` Darrick J. Wong
2019-08-12 19:28     ` Allison Collins
2019-08-09 21:37 ` [PATCH v2 05/18] xfs: Add xfs_has_attr and subroutines Allison Collins
2019-08-12 15:56   ` Darrick J. Wong
2019-08-12 19:29     ` Allison Collins
2019-08-12 20:00       ` Darrick J. Wong
2019-08-12 22:38         ` Allison Collins
2019-08-09 21:37 ` [PATCH v2 06/18] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
2019-08-12 16:01   ` Darrick J. Wong
2019-08-12 19:29     ` Allison Collins
2019-08-09 21:37 ` [PATCH v2 07/18] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags Allison Collins
2019-08-12 16:02   ` Darrick J. Wong
2019-08-12 16:30     ` Darrick J. Wong
2019-08-12 19:31       ` Allison Collins
2019-08-09 21:37 ` [PATCH v2 08/18] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
2019-08-12 16:06   ` Darrick J. Wong
2019-08-12 19:37     ` Allison Collins
2019-08-09 21:37 ` [PATCH v2 09/18] xfs: Factor up commit from xfs_attr_try_sf_addname Allison Collins
2019-08-12 16:14   ` Darrick J. Wong
2019-08-12 22:38     ` Allison Collins
2019-08-09 21:37 ` [PATCH v2 10/18] xfs: Factor up trans roll from xfs_attr3_leaf_setflag Allison Collins
2019-08-12 16:14   ` Darrick J. Wong
2019-08-12 22:38     ` Allison Collins
2019-08-09 21:37 ` [PATCH v2 11/18] xfs: Add xfs_attr3_leaf helper functions Allison Collins
2019-08-12 16:22   ` Darrick J. Wong
2019-08-12 22:38     ` Allison Collins
2019-08-09 21:37 ` [PATCH v2 12/18] xfs: Factor out xfs_attr_rmtval_remove_value Allison Collins
2019-08-12 16:27   ` Darrick J. Wong
2019-08-12 22:39     ` Allison Collins
2019-08-09 21:37 ` [PATCH v2 13/18] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag Allison Collins
2019-08-12 16:28   ` Darrick J. Wong
2019-08-12 22:39     ` Allison Collins
2019-08-09 21:37 ` [PATCH v2 14/18] xfs: Add delay context to xfs_da_args Allison Collins
2019-08-09 21:37 ` [PATCH v2 15/18] xfs: Add delayed attribute routines Allison Collins
2019-08-12 17:29   ` Darrick J. Wong
2019-08-13  2:19     ` Allison Collins
2019-08-09 21:37 ` [PATCH v2 16/18] xfs: Roll delayed attr operations by returning EAGAIN Allison Collins
2019-08-09 21:37 ` [PATCH v2 17/18] xfs: Enable delayed attributes Allison Collins
2019-08-12 16:42   ` Darrick J. Wong
2019-08-12 22:39     ` Allison Collins
2019-08-09 21:37 ` [PATCH v2 18/18] xfs: Add delayed attributes error tag Allison Collins
2019-08-12 16:51   ` Darrick J. Wong
2019-08-12  8:19 ` [PATCH v2 00/18] Delayed Attributes Christoph Hellwig
2019-08-12 19:26   ` Allison Collins

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.