* [PATCH 00/21] Parent Pointers v6
@ 2018-05-06 17:24 Allison Henderson
2018-05-06 17:24 ` [PATCH 01/21] xfs: Move fs/xfs/xfs_attr.h to fs/xfs/libxfs/xfs_attr.h Allison Henderson
` (21 more replies)
0 siblings, 22 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
Hi all,
This is the 6th version of parent pointer attributes for xfs. The goal of
this patch set is to add a parent pointer attribute to each inode. The
attribute name containing the parent inode, generation, and directory offset,
while the attribute value contains the file name. This feature will enable
future optimizations for online scrub, or any other feature that could make
use of quickly deriving an inodes path from the mount point. This set also
introduces deferred attribute operations, though it is currently only used by
the new parent pointer code.
Some points of interest since v5:
Patches 2 and 14 are new, so I would appreciate some focus on those.
They lay the ground work for delaying transaction rolls until
the entire operation is finished. Patches 15 through 18 have been
adjusted to hold locks across create, link, remove and rename operations.
Corresponding userspace and test cases are enroute.
As always, comments and feedback are appreciated. Thank you!
Allison Henderson (12):
xfs: Move fs/xfs/xfs_attr.h to fs/xfs/libxfs/xfs_attr.h
Add trans toggle to attr routines
xfs: Add attibute set and helper functions
xfs: Add attibute remove and helper functions
xfs: Set up infastructure for deferred attribute operations
xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
xfs: Remove all strlen calls in all xfs_attr_* functions for attr
names.
Add lock_flags to xfs_ialloc and xfs_dir_ialloc
xfs: Add parent pointers to rename
xfs: Add the parent pointer support to the superblock version 5.
xfs: Add parent pointer ioctl
xfs: Add delayed attributes error tag
Dave Chinner (5):
xfs: define parent pointer xattr format
xfs: extent transaction reservations for parent attributes
xfs: parent pointer attribute creation
xfs: add parent attributes to link
xfs: remove parent pointers in unlink
Mark Tinguely (4):
xfs: get directory offset when adding directory name
xfs: get directory offset when removing directory name
xfs: get directory offset when replacing a directory name
xfs: add parent pointer support to attribute code
fs/xfs/Makefile | 4 +
fs/xfs/libxfs/xfs_attr.c | 480 ++++++++++++++++++++++++-------------
fs/xfs/libxfs/xfs_attr.h | 196 +++++++++++++++
fs/xfs/libxfs/xfs_attr_leaf.c | 12 +-
fs/xfs/libxfs/xfs_attr_leaf.h | 8 +-
fs/xfs/libxfs/xfs_bmap.c | 49 ++--
fs/xfs/libxfs/xfs_bmap.h | 1 +
fs/xfs/libxfs/xfs_da_btree.h | 1 +
fs/xfs/libxfs/xfs_da_format.h | 38 ++-
fs/xfs/libxfs/xfs_defer.h | 1 +
fs/xfs/libxfs/xfs_dir2.c | 41 ++--
fs/xfs/libxfs/xfs_dir2.h | 10 +-
fs/xfs/libxfs/xfs_dir2_block.c | 9 +-
fs/xfs/libxfs/xfs_dir2_leaf.c | 8 +-
fs/xfs/libxfs/xfs_dir2_node.c | 8 +-
fs/xfs/libxfs/xfs_dir2_sf.c | 6 +
fs/xfs/libxfs/xfs_errortag.h | 5 +-
fs/xfs/libxfs/xfs_format.h | 10 +-
fs/xfs/libxfs/xfs_fs.h | 39 +++
fs/xfs/libxfs/xfs_log_format.h | 44 +++-
fs/xfs/libxfs/xfs_parent.c | 168 +++++++++++++
fs/xfs/libxfs/xfs_parent.h | 38 +++
fs/xfs/libxfs/xfs_sb.c | 2 +
fs/xfs/libxfs/xfs_trans_resv.c | 111 +++++++--
fs/xfs/libxfs/xfs_trans_resv.h | 1 +
fs/xfs/libxfs/xfs_types.h | 1 +
fs/xfs/xfs_acl.c | 12 +-
fs/xfs/xfs_attr.h | 160 -------------
fs/xfs/xfs_attr_item.c | 530 +++++++++++++++++++++++++++++++++++++++++
fs/xfs/xfs_attr_item.h | 119 +++++++++
fs/xfs/xfs_attr_list.c | 3 +
fs/xfs/xfs_error.c | 3 +
fs/xfs/xfs_inode.c | 220 ++++++++++++-----
fs/xfs/xfs_inode.h | 2 +-
fs/xfs/xfs_ioctl.c | 74 +++++-
fs/xfs/xfs_iops.c | 6 +-
fs/xfs/xfs_log_recover.c | 122 ++++++++++
fs/xfs/xfs_parent_utils.c | 136 +++++++++++
fs/xfs/xfs_parent_utils.h | 32 +++
fs/xfs/xfs_qm.c | 2 +-
fs/xfs/xfs_super.c | 5 +
fs/xfs/xfs_symlink.c | 4 +-
fs/xfs/xfs_trans.h | 13 +
fs/xfs/xfs_trans_attr.c | 291 ++++++++++++++++++++++
fs/xfs/xfs_xattr.c | 10 +-
45 files changed, 2552 insertions(+), 483 deletions(-)
create mode 100644 fs/xfs/libxfs/xfs_attr.h
create mode 100644 fs/xfs/libxfs/xfs_parent.c
create mode 100644 fs/xfs/libxfs/xfs_parent.h
delete mode 100644 fs/xfs/xfs_attr.h
create mode 100644 fs/xfs/xfs_attr_item.c
create mode 100644 fs/xfs/xfs_attr_item.h
create mode 100644 fs/xfs/xfs_parent_utils.c
create mode 100644 fs/xfs/xfs_parent_utils.h
create mode 100644 fs/xfs/xfs_trans_attr.c
--
2.7.4
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH 01/21] xfs: Move fs/xfs/xfs_attr.h to fs/xfs/libxfs/xfs_attr.h
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 23:39 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 02/21] Add trans toggle to attr routines Allison Henderson
` (20 subsequent siblings)
21 siblings, 1 reply; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
This patch moves fs/xfs/xfs_attr.h to fs/xfs/libxfs/xfs_attr.h
since xfs_attr.c is in libxfs. We will need these later in
xfsprogs.
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/libxfs/xfs_attr.h | 160 +++++++++++++++++++++++++++++++++++++++++++++++
fs/xfs/xfs_attr.h | 160 -----------------------------------------------
2 files changed, 160 insertions(+), 160 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
new file mode 100644
index 0000000..d07bf27
--- /dev/null
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2000,2002-2003,2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __XFS_ATTR_H__
+#define __XFS_ATTR_H__
+
+struct xfs_inode;
+struct xfs_da_args;
+struct xfs_attr_list_context;
+
+/*
+ * Large attribute lists are structured around Btrees where all the data
+ * elements are in the leaf nodes. Attribute names are hashed into an int,
+ * then that int is used as the index into the Btree. Since the hashval
+ * of an attribute name may not be unique, we may have duplicate keys.
+ * The internal links in the Btree are logical block offsets into the file.
+ *
+ * Small attribute lists use a different format and are packed as tightly
+ * as possible so as to fit into the literal area of the inode.
+ */
+
+/*========================================================================
+ * External interfaces
+ *========================================================================*/
+
+
+#define ATTR_DONTFOLLOW 0x0001 /* -- unused, from IRIX -- */
+#define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */
+#define ATTR_TRUST 0x0004 /* -- unused, from IRIX -- */
+#define ATTR_SECURE 0x0008 /* use attrs in security namespace */
+#define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */
+#define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */
+
+#define ATTR_KERNOTIME 0x1000 /* [kernel] don't update inode timestamps */
+#define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */
+
+#define ATTR_INCOMPLETE 0x4000 /* [kernel] return INCOMPLETE attr keys */
+
+#define XFS_ATTR_FLAGS \
+ { ATTR_DONTFOLLOW, "DONTFOLLOW" }, \
+ { ATTR_ROOT, "ROOT" }, \
+ { ATTR_TRUST, "TRUST" }, \
+ { ATTR_SECURE, "SECURE" }, \
+ { ATTR_CREATE, "CREATE" }, \
+ { ATTR_REPLACE, "REPLACE" }, \
+ { ATTR_KERNOTIME, "KERNOTIME" }, \
+ { ATTR_KERNOVAL, "KERNOVAL" }, \
+ { ATTR_INCOMPLETE, "INCOMPLETE" }
+
+/*
+ * The maximum size (into the kernel or returned from the kernel) of an
+ * attribute value or the buffer used for an attr_list() call. Larger
+ * sizes will result in an ERANGE return code.
+ */
+#define ATTR_MAX_VALUELEN (64*1024) /* max length of a value */
+
+/*
+ * Define how lists of attribute names are returned to the user from
+ * the attr_list() call. A large, 32bit aligned, buffer is passed in
+ * along with its size. We put an array of offsets at the top that each
+ * reference an attrlist_ent_t and pack the attrlist_ent_t's at the bottom.
+ */
+typedef struct attrlist {
+ __s32 al_count; /* number of entries in attrlist */
+ __s32 al_more; /* T/F: more attrs (do call again) */
+ __s32 al_offset[1]; /* byte offsets of attrs [var-sized] */
+} attrlist_t;
+
+/*
+ * Show the interesting info about one attribute. This is what the
+ * al_offset[i] entry points to.
+ */
+typedef struct attrlist_ent { /* data from attr_list() */
+ __u32 a_valuelen; /* number bytes in value of attr */
+ char a_name[1]; /* attr name (NULL terminated) */
+} attrlist_ent_t;
+
+/*
+ * Given a pointer to the (char*) buffer containing the attr_list() result,
+ * and an index, return a pointer to the indicated attribute in the buffer.
+ */
+#define ATTR_ENTRY(buffer, index) \
+ ((attrlist_ent_t *) \
+ &((char *)buffer)[ ((attrlist_t *)(buffer))->al_offset[index] ])
+
+/*
+ * Kernel-internal version of the attrlist cursor.
+ */
+typedef struct attrlist_cursor_kern {
+ __u32 hashval; /* hash value of next entry to add */
+ __u32 blkno; /* block containing entry (suggestion) */
+ __u32 offset; /* offset in list of equal-hashvals */
+ __u16 pad1; /* padding to match user-level */
+ __u8 pad2; /* padding to match user-level */
+ __u8 initted; /* T/F: cursor has been initialized */
+} attrlist_cursor_kern_t;
+
+
+/*========================================================================
+ * Structure used to pass context around among the routines.
+ *========================================================================*/
+
+
+/* void; state communicated via *context */
+typedef void (*put_listent_func_t)(struct xfs_attr_list_context *, int,
+ unsigned char *, int, int);
+
+typedef struct xfs_attr_list_context {
+ struct xfs_trans *tp;
+ struct xfs_inode *dp; /* inode */
+ struct attrlist_cursor_kern *cursor; /* position in list */
+ char *alist; /* output buffer */
+ int seen_enough; /* T/F: seen enough of list? */
+ ssize_t count; /* num used entries */
+ int dupcnt; /* count dup hashvals seen */
+ int bufsize; /* total buffer size */
+ int firstu; /* first used byte in buffer */
+ int flags; /* from VOP call */
+ int resynch; /* T/F: resynch with cursor */
+ put_listent_func_t put_listent; /* list output fmt function */
+ int index; /* index into output buffer */
+} xfs_attr_list_context_t;
+
+
+/*========================================================================
+ * Function prototypes for the kernel.
+ *========================================================================*/
+
+/*
+ * Overall external interface routines.
+ */
+int xfs_attr_inactive(struct xfs_inode *dp);
+int xfs_attr_list_int_ilocked(struct xfs_attr_list_context *);
+int xfs_attr_list_int(struct xfs_attr_list_context *);
+int xfs_inode_hasattr(struct xfs_inode *ip);
+int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
+int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
+ unsigned char *value, int *valuelenp, int flags);
+int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
+ unsigned char *value, int valuelen, int flags);
+int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
+int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
+ int flags, struct attrlist_cursor_kern *cursor);
+
+
+#endif /* __XFS_ATTR_H__ */
diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
deleted file mode 100644
index d07bf27..0000000
--- a/fs/xfs/xfs_attr.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (c) 2000,2002-2003,2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#ifndef __XFS_ATTR_H__
-#define __XFS_ATTR_H__
-
-struct xfs_inode;
-struct xfs_da_args;
-struct xfs_attr_list_context;
-
-/*
- * Large attribute lists are structured around Btrees where all the data
- * elements are in the leaf nodes. Attribute names are hashed into an int,
- * then that int is used as the index into the Btree. Since the hashval
- * of an attribute name may not be unique, we may have duplicate keys.
- * The internal links in the Btree are logical block offsets into the file.
- *
- * Small attribute lists use a different format and are packed as tightly
- * as possible so as to fit into the literal area of the inode.
- */
-
-/*========================================================================
- * External interfaces
- *========================================================================*/
-
-
-#define ATTR_DONTFOLLOW 0x0001 /* -- unused, from IRIX -- */
-#define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */
-#define ATTR_TRUST 0x0004 /* -- unused, from IRIX -- */
-#define ATTR_SECURE 0x0008 /* use attrs in security namespace */
-#define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */
-#define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */
-
-#define ATTR_KERNOTIME 0x1000 /* [kernel] don't update inode timestamps */
-#define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */
-
-#define ATTR_INCOMPLETE 0x4000 /* [kernel] return INCOMPLETE attr keys */
-
-#define XFS_ATTR_FLAGS \
- { ATTR_DONTFOLLOW, "DONTFOLLOW" }, \
- { ATTR_ROOT, "ROOT" }, \
- { ATTR_TRUST, "TRUST" }, \
- { ATTR_SECURE, "SECURE" }, \
- { ATTR_CREATE, "CREATE" }, \
- { ATTR_REPLACE, "REPLACE" }, \
- { ATTR_KERNOTIME, "KERNOTIME" }, \
- { ATTR_KERNOVAL, "KERNOVAL" }, \
- { ATTR_INCOMPLETE, "INCOMPLETE" }
-
-/*
- * The maximum size (into the kernel or returned from the kernel) of an
- * attribute value or the buffer used for an attr_list() call. Larger
- * sizes will result in an ERANGE return code.
- */
-#define ATTR_MAX_VALUELEN (64*1024) /* max length of a value */
-
-/*
- * Define how lists of attribute names are returned to the user from
- * the attr_list() call. A large, 32bit aligned, buffer is passed in
- * along with its size. We put an array of offsets at the top that each
- * reference an attrlist_ent_t and pack the attrlist_ent_t's at the bottom.
- */
-typedef struct attrlist {
- __s32 al_count; /* number of entries in attrlist */
- __s32 al_more; /* T/F: more attrs (do call again) */
- __s32 al_offset[1]; /* byte offsets of attrs [var-sized] */
-} attrlist_t;
-
-/*
- * Show the interesting info about one attribute. This is what the
- * al_offset[i] entry points to.
- */
-typedef struct attrlist_ent { /* data from attr_list() */
- __u32 a_valuelen; /* number bytes in value of attr */
- char a_name[1]; /* attr name (NULL terminated) */
-} attrlist_ent_t;
-
-/*
- * Given a pointer to the (char*) buffer containing the attr_list() result,
- * and an index, return a pointer to the indicated attribute in the buffer.
- */
-#define ATTR_ENTRY(buffer, index) \
- ((attrlist_ent_t *) \
- &((char *)buffer)[ ((attrlist_t *)(buffer))->al_offset[index] ])
-
-/*
- * Kernel-internal version of the attrlist cursor.
- */
-typedef struct attrlist_cursor_kern {
- __u32 hashval; /* hash value of next entry to add */
- __u32 blkno; /* block containing entry (suggestion) */
- __u32 offset; /* offset in list of equal-hashvals */
- __u16 pad1; /* padding to match user-level */
- __u8 pad2; /* padding to match user-level */
- __u8 initted; /* T/F: cursor has been initialized */
-} attrlist_cursor_kern_t;
-
-
-/*========================================================================
- * Structure used to pass context around among the routines.
- *========================================================================*/
-
-
-/* void; state communicated via *context */
-typedef void (*put_listent_func_t)(struct xfs_attr_list_context *, int,
- unsigned char *, int, int);
-
-typedef struct xfs_attr_list_context {
- struct xfs_trans *tp;
- struct xfs_inode *dp; /* inode */
- struct attrlist_cursor_kern *cursor; /* position in list */
- char *alist; /* output buffer */
- int seen_enough; /* T/F: seen enough of list? */
- ssize_t count; /* num used entries */
- int dupcnt; /* count dup hashvals seen */
- int bufsize; /* total buffer size */
- int firstu; /* first used byte in buffer */
- int flags; /* from VOP call */
- int resynch; /* T/F: resynch with cursor */
- put_listent_func_t put_listent; /* list output fmt function */
- int index; /* index into output buffer */
-} xfs_attr_list_context_t;
-
-
-/*========================================================================
- * Function prototypes for the kernel.
- *========================================================================*/
-
-/*
- * Overall external interface routines.
- */
-int xfs_attr_inactive(struct xfs_inode *dp);
-int xfs_attr_list_int_ilocked(struct xfs_attr_list_context *);
-int xfs_attr_list_int(struct xfs_attr_list_context *);
-int xfs_inode_hasattr(struct xfs_inode *ip);
-int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
-int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
- unsigned char *value, int *valuelenp, int flags);
-int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
- unsigned char *value, int valuelen, int flags);
-int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
-int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
- int flags, struct attrlist_cursor_kern *cursor);
-
-
-#endif /* __XFS_ATTR_H__ */
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 02/21] Add trans toggle to attr routines
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
2018-05-06 17:24 ` [PATCH 01/21] xfs: Move fs/xfs/xfs_attr.h to fs/xfs/libxfs/xfs_attr.h Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 23:52 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 03/21] xfs: Add attibute set and helper functions Allison Henderson
` (19 subsequent siblings)
21 siblings, 1 reply; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
This patch adds a roll_trans parameter to all attribute routines.
Calling functions may pass true to roll transactions as normal,
or false to hold them. We will need this later for delayed
attribute operations.
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/libxfs/xfs_attr.c | 144 +++++++++++++++++++++++-------------------
fs/xfs/libxfs/xfs_attr_leaf.c | 12 ++--
fs/xfs/libxfs/xfs_attr_leaf.h | 8 +--
3 files changed, 90 insertions(+), 74 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index ce4a34a..0ade22b 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -55,21 +55,21 @@
/*
* Internal routines when attribute list fits inside the inode.
*/
-STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
+STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args, bool roll_trans);
/*
* Internal routines when attribute list is one block.
*/
STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
-STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
-STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
+STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args, bool roll_trans);
+STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args, bool roll_trans);
/*
* Internal routines when attribute list is more than one block.
*/
STATIC int xfs_attr_node_get(xfs_da_args_t *args);
-STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
-STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
+STATIC int xfs_attr_node_addname(xfs_da_args_t *args, bool roll_trans);
+STATIC int xfs_attr_node_removename(xfs_da_args_t *args, bool roll_trans);
STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
@@ -297,7 +297,7 @@ xfs_attr_set(
* Try to add the attr to the attribute list in
* the inode.
*/
- error = xfs_attr_shortform_addname(&args);
+ error = xfs_attr_shortform_addname(&args, true);
if (error != -ENOSPC) {
/*
* Commit the shortform mods, and we're done.
@@ -356,9 +356,9 @@ xfs_attr_set(
}
if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
- error = xfs_attr_leaf_addname(&args);
+ error = xfs_attr_leaf_addname(&args, true);
else
- error = xfs_attr_node_addname(&args);
+ error = xfs_attr_node_addname(&args, true);
if (error)
goto out;
@@ -453,11 +453,11 @@ xfs_attr_remove(
error = -ENOATTR;
} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
- error = xfs_attr_shortform_remove(&args);
+ error = xfs_attr_shortform_remove(&args, true);
} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
- error = xfs_attr_leaf_removename(&args);
+ error = xfs_attr_leaf_removename(&args, true);
} else {
- error = xfs_attr_node_removename(&args);
+ error = xfs_attr_node_removename(&args, true);
}
if (error)
@@ -498,7 +498,7 @@ xfs_attr_remove(
* This is the external routine.
*/
STATIC int
-xfs_attr_shortform_addname(xfs_da_args_t *args)
+xfs_attr_shortform_addname(xfs_da_args_t *args, bool roll_trans)
{
int newsize, forkoff, retval;
@@ -510,7 +510,7 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
} else if (retval == -EEXIST) {
if (args->flags & ATTR_CREATE)
return retval;
- retval = xfs_attr_shortform_remove(args);
+ retval = xfs_attr_shortform_remove(args, roll_trans);
ASSERT(retval == 0);
}
@@ -525,7 +525,7 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
if (!forkoff)
return -ENOSPC;
- xfs_attr_shortform_add(args, forkoff);
+ xfs_attr_shortform_add(args, forkoff, roll_trans);
return 0;
}
@@ -541,7 +541,7 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
* if bmap_one_block() says there is only one block (ie: no remote blks).
*/
STATIC int
-xfs_attr_leaf_addname(xfs_da_args_t *args)
+xfs_attr_leaf_addname(xfs_da_args_t *args, bool roll_trans)
{
xfs_inode_t *dp;
struct xfs_buf *bp;
@@ -604,36 +604,42 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
* can manage its own transactions.
*/
xfs_defer_init(args->dfops, args->firstblock);
- error = xfs_attr3_leaf_to_node(args);
- if (error)
- goto out_defer_cancel;
- xfs_defer_ijoin(args->dfops, dp);
- error = xfs_defer_finish(&args->trans, args->dfops);
+ error = xfs_attr3_leaf_to_node(args, roll_trans);
if (error)
goto out_defer_cancel;
+ if (roll_trans) {
+ xfs_defer_ijoin(args->dfops, dp);
+ error = xfs_defer_finish(&args->trans, args->dfops);
+ if (error)
+ goto out_defer_cancel;
- /*
- * Commit the current trans (including the inode) and start
- * a new one.
- */
- error = xfs_trans_roll_inode(&args->trans, dp);
- if (error)
- return error;
+ /*
+ * Commit the current trans (including the inode) and start
+ * a new one.
+ */
+ error = xfs_trans_roll_inode(&args->trans, dp);
+ if (error)
+ return error;
+ }
/*
* Fob the whole rest of the problem off on the Btree code.
*/
- error = xfs_attr_node_addname(args);
+ error = xfs_attr_node_addname(args, roll_trans);
+
return error;
}
- /*
- * Commit the transaction that added the attr name so that
- * later routines can manage their own transactions.
- */
- error = xfs_trans_roll_inode(&args->trans, dp);
- if (error)
- return error;
+
+ if (roll_trans) {
+ /*
+ * Commit the transaction that added the attr name so that
+ * later routines can manage their own transactions.
+ */
+ error = xfs_trans_roll_inode(&args->trans, dp);
+ if (error)
+ return error;
+ }
/*
* If there was an out-of-line value, allocate the blocks we
@@ -691,9 +697,9 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
/*
* If the result is small enough, shrink it all into the inode.
*/
- if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
+ if ((forkoff = xfs_attr_shortform_allfit(bp, dp)) && roll_trans) {
xfs_defer_init(args->dfops, args->firstblock);
- error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
+ error = xfs_attr3_leaf_to_shortform(bp, args, forkoff, roll_trans);
/* bp is gone due to xfs_da_shrink_inode */
if (error)
goto out_defer_cancel;
@@ -727,7 +733,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
* if bmap_one_block() says there is only one block (ie: no remote blks).
*/
STATIC int
-xfs_attr_leaf_removename(xfs_da_args_t *args)
+xfs_attr_leaf_removename(xfs_da_args_t *args, bool roll_trans)
{
xfs_inode_t *dp;
struct xfs_buf *bp;
@@ -755,9 +761,9 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
/*
* If the result is small enough, shrink it all into the inode.
*/
- if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
+ if ((forkoff = xfs_attr_shortform_allfit(bp, dp)) && roll_trans) {
xfs_defer_init(args->dfops, args->firstblock);
- error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
+ error = xfs_attr3_leaf_to_shortform(bp, args, forkoff, roll_trans);
/* bp is gone due to xfs_da_shrink_inode */
if (error)
goto out_defer_cancel;
@@ -819,7 +825,7 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
* add a whole extra layer of confusion on top of that.
*/
STATIC int
-xfs_attr_node_addname(xfs_da_args_t *args)
+xfs_attr_node_addname(xfs_da_args_t *args, bool roll_trans)
{
xfs_da_state_t *state;
xfs_da_state_blk_t *blk;
@@ -885,21 +891,23 @@ xfs_attr_node_addname(xfs_da_args_t *args)
xfs_da_state_free(state);
state = NULL;
xfs_defer_init(args->dfops, args->firstblock);
- error = xfs_attr3_leaf_to_node(args);
+ error = xfs_attr3_leaf_to_node(args, roll_trans);
if (error)
goto out_defer_cancel;
xfs_defer_ijoin(args->dfops, dp);
- error = xfs_defer_finish(&args->trans, args->dfops);
- if (error)
- goto out_defer_cancel;
-
- /*
- * Commit the node conversion and start the next
- * trans in the chain.
- */
- error = xfs_trans_roll_inode(&args->trans, dp);
- if (error)
- goto out;
+ if (roll_trans) {
+ error = xfs_defer_finish(&args->trans, args->dfops);
+ if (error)
+ goto out_defer_cancel;
+
+ /*
+ * Commit the node conversion and start the next
+ * trans in the chain.
+ */
+ error = xfs_trans_roll_inode(&args->trans, dp);
+ if (error)
+ goto out;
+ }
goto restart;
}
@@ -915,9 +923,11 @@ xfs_attr_node_addname(xfs_da_args_t *args)
if (error)
goto out_defer_cancel;
xfs_defer_ijoin(args->dfops, dp);
- error = xfs_defer_finish(&args->trans, args->dfops);
- if (error)
- goto out_defer_cancel;
+ if (roll_trans) {
+ error = xfs_defer_finish(&args->trans, args->dfops);
+ if (error)
+ goto out_defer_cancel;
+ }
} else {
/*
* Addition succeeded, update Btree hashvals.
@@ -936,9 +946,11 @@ xfs_attr_node_addname(xfs_da_args_t *args)
* Commit the leaf addition or btree split and start the next
* trans in the chain.
*/
- error = xfs_trans_roll_inode(&args->trans, dp);
- if (error)
- goto out;
+ if (roll_trans) {
+ error = xfs_trans_roll_inode(&args->trans, dp);
+ if (error)
+ goto out;
+ }
/*
* If there was an out-of-line value, allocate the blocks we
@@ -1013,9 +1025,11 @@ xfs_attr_node_addname(xfs_da_args_t *args)
if (error)
goto out_defer_cancel;
xfs_defer_ijoin(args->dfops, dp);
- error = xfs_defer_finish(&args->trans, args->dfops);
- if (error)
- goto out_defer_cancel;
+ if (roll_trans) {
+ error = xfs_defer_finish(&args->trans, args->dfops);
+ if (error)
+ goto out_defer_cancel;
+ }
}
/*
@@ -1054,7 +1068,7 @@ xfs_attr_node_addname(xfs_da_args_t *args)
* the root node (a special case of an intermediate node).
*/
STATIC int
-xfs_attr_node_removename(xfs_da_args_t *args)
+xfs_attr_node_removename(xfs_da_args_t *args, bool roll_trans)
{
xfs_da_state_t *state;
xfs_da_state_blk_t *blk;
@@ -1163,9 +1177,9 @@ xfs_attr_node_removename(xfs_da_args_t *args)
if (error)
goto out;
- if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
+ if ((forkoff = xfs_attr_shortform_allfit(bp, dp)) && roll_trans) {
xfs_defer_init(args->dfops, args->firstblock);
- error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
+ error = xfs_attr3_leaf_to_shortform(bp, args, forkoff, roll_trans);
/* bp is gone due to xfs_da_shrink_inode */
if (error)
goto out_defer_cancel;
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 2135b8e..01935fe 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -546,7 +546,7 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
* Overflow from the inode has already been checked for.
*/
void
-xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
+xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff, bool roll_trans)
{
xfs_attr_shortform_t *sf;
xfs_attr_sf_entry_t *sfe;
@@ -618,7 +618,7 @@ xfs_attr_fork_remove(
* Remove an attribute from the shortform attribute list structure.
*/
int
-xfs_attr_shortform_remove(xfs_da_args_t *args)
+xfs_attr_shortform_remove(xfs_da_args_t *args, bool roll_trans)
{
xfs_attr_shortform_t *sf;
xfs_attr_sf_entry_t *sfe;
@@ -970,7 +970,8 @@ int
xfs_attr3_leaf_to_shortform(
struct xfs_buf *bp,
struct xfs_da_args *args,
- int forkoff)
+ int forkoff,
+ bool roll_trans)
{
struct xfs_attr_leafblock *leaf;
struct xfs_attr3_icleaf_hdr ichdr;
@@ -1039,7 +1040,7 @@ xfs_attr3_leaf_to_shortform(
nargs.valuelen = be16_to_cpu(name_loc->valuelen);
nargs.hashval = be32_to_cpu(entry->hashval);
nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags);
- xfs_attr_shortform_add(&nargs, forkoff);
+ xfs_attr_shortform_add(&nargs, forkoff, roll_trans);
}
error = 0;
@@ -1053,7 +1054,8 @@ xfs_attr3_leaf_to_shortform(
*/
int
xfs_attr3_leaf_to_node(
- struct xfs_da_args *args)
+ struct xfs_da_args *args,
+ bool roll_trans)
{
struct xfs_attr_leafblock *leaf;
struct xfs_attr3_icleaf_hdr icleafhdr;
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
index 4da08af..b5dea0e 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.h
+++ b/fs/xfs/libxfs/xfs_attr_leaf.h
@@ -45,12 +45,12 @@ typedef struct xfs_attr_inactive_list {
* Internal routines when attribute fork size < XFS_LITINO(mp).
*/
void xfs_attr_shortform_create(struct xfs_da_args *args);
-void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff);
+void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff, bool roll_trans);
int xfs_attr_shortform_lookup(struct xfs_da_args *args);
int xfs_attr_shortform_getvalue(struct xfs_da_args *args);
int xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
struct xfs_buf **leaf_bp);
-int xfs_attr_shortform_remove(struct xfs_da_args *args);
+int xfs_attr_shortform_remove(struct xfs_da_args *args, bool roll_trans);
int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
int xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes);
xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_inode *ip);
@@ -59,9 +59,9 @@ void xfs_attr_fork_remove(struct xfs_inode *ip, struct xfs_trans *tp);
/*
* Internal routines when attribute fork size == XFS_LBSIZE(mp).
*/
-int xfs_attr3_leaf_to_node(struct xfs_da_args *args);
+int xfs_attr3_leaf_to_node(struct xfs_da_args *args, bool roll_trans);
int xfs_attr3_leaf_to_shortform(struct xfs_buf *bp,
- struct xfs_da_args *args, int forkoff);
+ struct xfs_da_args *args, int forkoff, bool roll_trans);
int xfs_attr3_leaf_clearflag(struct xfs_da_args *args);
int xfs_attr3_leaf_setflag(struct xfs_da_args *args);
int xfs_attr3_leaf_flipflags(struct xfs_da_args *args);
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 03/21] xfs: Add attibute set and helper functions
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
2018-05-06 17:24 ` [PATCH 01/21] xfs: Move fs/xfs/xfs_attr.h to fs/xfs/libxfs/xfs_attr.h Allison Henderson
2018-05-06 17:24 ` [PATCH 02/21] Add trans toggle to attr routines Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 23:36 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 04/21] xfs: Add attibute remove " Allison Henderson
` (18 subsequent siblings)
21 siblings, 1 reply; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
This patch adds xfs_attr_set_args and xfs_bmap_set_attrforkoff.
These sub-routines set the attributes specified in @args.
We will use this later for setting parent pointers as a deferred
attribute operation.
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/libxfs/xfs_attr.c | 217 ++++++++++++++++++++++++++++-------------------
fs/xfs/libxfs/xfs_attr.h | 2 +
fs/xfs/libxfs/xfs_bmap.c | 49 ++++++-----
fs/xfs/libxfs/xfs_bmap.h | 1 +
4 files changed, 165 insertions(+), 104 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 0ade22b..99c4a31 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -168,6 +168,134 @@ xfs_attr_get(
}
/*
+ * Set the attribute specified in @args. In the case of the parent attribute
+ * being set, we do not want to roll the transaction on shortform-to-leaf
+ * conversion, as the attribute must be added in the same transaction as the
+ * parent directory modifications. Hence @roll_trans needs to be set
+ * appropriately to control whether the transaction is committed during this
+ * function.
+ */
+int
+xfs_attr_set_args(
+ struct xfs_da_args *args,
+ int flags,
+ struct xfs_buf *leaf_bp,
+ bool roll_trans)
+{
+ struct xfs_inode *dp = args->dp;
+ struct xfs_mount *mp = dp->i_mount;
+ int error = 0;
+ int err2 = 0;
+ int sf_size;
+
+ /*
+ * New inodes setting the parent pointer attr will
+ * not have an attribute fork yet. So set the attribute
+ * fork appropriately
+ */
+ if (XFS_IFORK_Q((args->dp)) == 0) {
+ sf_size = sizeof(struct xfs_attr_sf_hdr) +
+ XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
+ xfs_bmap_set_attrforkoff(args->dp, sf_size, NULL);
+ args->dp->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
+ args->dp->i_afp->if_flags = XFS_IFEXTENTS;
+ }
+
+ xfs_trans_ijoin(args->trans, dp, 0);
+ /*
+ * If the attribute list is non-existent or a shortform list,
+ * upgrade it to a single-leaf-block attribute list.
+ */
+ if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
+ (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
+ dp->i_d.di_anextents == 0)) {
+
+ /*
+ * Build initial attribute list (if required).
+ */
+ if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
+ xfs_attr_shortform_create(args);
+
+ /*
+ * Try to add the attr to the attribute list in the inode.
+ */
+ error = xfs_attr_shortform_addname(args, roll_trans);
+ if (error != -ENOSPC) {
+ if (roll_trans) {
+ /*
+ * Commit the shortform mods, and we're done.
+ * NOTE: this is also the error path (EEXIST, etc).
+ */
+ ASSERT(args->trans != NULL);
+
+ /*
+ * If this is a synchronous mount, make sure that
+ * the transaction goes to disk before returning
+ * to the user.
+ */
+ if (mp->m_flags & XFS_MOUNT_WSYNC)
+ xfs_trans_set_sync(args->trans);
+
+ if (!error && (flags & ATTR_KERNOTIME) == 0)
+ xfs_trans_ichgtime(args->trans, dp,
+ XFS_ICHGTIME_CHG);
+
+ err2 = xfs_trans_commit(args->trans);
+ error = error ? error : err2;
+ }
+ goto out;
+ }
+
+ /*
+ * It won't fit in the shortform, transform to a leaf block.
+ * GROT: another possible req'mt for a double-split btree op.
+ */
+ error = xfs_attr_shortform_to_leaf(args, &leaf_bp);
+ if (error)
+ goto out;
+
+ xfs_defer_bjoin(args->dfops, leaf_bp);
+ xfs_defer_ijoin(args->dfops, dp);
+ if (roll_trans) {
+ /*
+ * Prevent the leaf buffer from being unlocked so that a
+ * concurrent AIL push cannot grab the half-baked leaf
+ * buffer and run into problems with the write verifier.
+ */
+ xfs_trans_bhold(args->trans, leaf_bp);
+
+ error = xfs_defer_finish(&args->trans, args->dfops);
+ if (error) {
+ args->trans = NULL;
+ goto out;
+ }
+
+ /*
+ * Commit the leaf transformation. We'll need another
+ * (linked) transaction to add the new attribute to the
+ * leaf.
+ */
+ error = xfs_trans_roll_inode(&args->trans, dp);
+ if (error)
+ goto out;
+ xfs_defer_ijoin(args->dfops, dp);
+ xfs_trans_bjoin(args->trans, leaf_bp);
+ leaf_bp = NULL;
+ }
+ }
+
+ if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
+ error = xfs_attr_leaf_addname(args, roll_trans);
+ else
+ error = xfs_attr_node_addname(args, roll_trans);
+ if (error)
+ goto out;
+
+out:
+ return error;
+}
+
+/*
* Calculate how many blocks we need for the new attribute,
*/
STATIC int
@@ -218,7 +346,7 @@ xfs_attr_set(
struct xfs_trans_res tres;
xfs_fsblock_t firstblock;
int rsvd = (flags & ATTR_ROOT) != 0;
- int error, err2, local;
+ int error, local;
XFS_STATS_INC(mp, xs_attr_set);
@@ -279,88 +407,11 @@ xfs_attr_set(
xfs_trans_ijoin(args.trans, dp, 0);
- /*
- * If the attribute list is non-existent or a shortform list,
- * upgrade it to a single-leaf-block attribute list.
- */
- if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
- (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
- dp->i_d.di_anextents == 0)) {
-
- /*
- * Build initial attribute list (if required).
- */
- if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
- xfs_attr_shortform_create(&args);
-
- /*
- * Try to add the attr to the attribute list in
- * the inode.
- */
- error = xfs_attr_shortform_addname(&args, true);
- if (error != -ENOSPC) {
- /*
- * Commit the shortform mods, and we're done.
- * NOTE: this is also the error path (EEXIST, etc).
- */
- ASSERT(args.trans != NULL);
-
- /*
- * If this is a synchronous mount, make sure that
- * the transaction goes to disk before returning
- * to the user.
- */
- if (mp->m_flags & XFS_MOUNT_WSYNC)
- xfs_trans_set_sync(args.trans);
-
- if (!error && (flags & ATTR_KERNOTIME) == 0) {
- xfs_trans_ichgtime(args.trans, dp,
- XFS_ICHGTIME_CHG);
- }
- err2 = xfs_trans_commit(args.trans);
- xfs_iunlock(dp, XFS_ILOCK_EXCL);
-
- return error ? error : err2;
- }
-
- /*
- * It won't fit in the shortform, transform to a leaf block.
- * GROT: another possible req'mt for a double-split btree op.
- */
- xfs_defer_init(args.dfops, args.firstblock);
- error = xfs_attr_shortform_to_leaf(&args, &leaf_bp);
- if (error)
- goto out_defer_cancel;
- /*
- * Prevent the leaf buffer from being unlocked so that a
- * concurrent AIL push cannot grab the half-baked leaf
- * buffer and run into problems with the write verifier.
- */
- xfs_trans_bhold(args.trans, leaf_bp);
- xfs_defer_bjoin(args.dfops, leaf_bp);
- xfs_defer_ijoin(args.dfops, dp);
- error = xfs_defer_finish(&args.trans, args.dfops);
- if (error)
- goto out_defer_cancel;
-
- /*
- * Commit the leaf transformation. We'll need another (linked)
- * transaction to add the new attribute to the leaf, which
- * means that we have to hold & join the leaf buffer here too.
- */
- error = xfs_trans_roll_inode(&args.trans, dp);
- if (error)
- goto out;
- xfs_trans_bjoin(args.trans, leaf_bp);
- leaf_bp = NULL;
- }
+ xfs_defer_init(args.dfops, args.firstblock);
+ error = xfs_attr_set_args(&args, flags, leaf_bp, true);
- if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
- error = xfs_attr_leaf_addname(&args, true);
- else
- error = xfs_attr_node_addname(&args, true);
if (error)
- goto out;
+ goto out_defer_cancel;
/*
* If this is a synchronous mount, make sure that the
@@ -369,9 +420,6 @@ xfs_attr_set(
if (mp->m_flags & XFS_MOUNT_WSYNC)
xfs_trans_set_sync(args.trans);
- if ((flags & ATTR_KERNOTIME) == 0)
- xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
-
/*
* Commit the last in the sequence of transactions.
*/
@@ -383,7 +431,6 @@ xfs_attr_set(
out_defer_cancel:
xfs_defer_cancel(&dfops);
-out:
if (leaf_bp)
xfs_trans_brelse(args.trans, leaf_bp);
if (args.trans)
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index d07bf27..b5dc02c 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -152,6 +152,8 @@ int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
unsigned char *value, int *valuelenp, int flags);
int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
unsigned char *value, int valuelen, int flags);
+int xfs_attr_set_args(struct xfs_da_args *args, int flags,
+ struct xfs_buf *leaf_bp, bool roll_trans);
int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
int flags, struct attrlist_cursor_kern *cursor);
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 6a7c2f0..4e16a5d 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -1031,6 +1031,34 @@ xfs_bmap_add_attrfork_local(
return -EFSCORRUPTED;
}
+/* Set an inode attr fork off based on the format */
+int
+xfs_bmap_set_attrforkoff(
+ struct xfs_inode *ip,
+ int size,
+ int *version)
+{
+ switch (ip->i_d.di_format) {
+ case XFS_DINODE_FMT_DEV:
+ ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3;
+ break;
+ case XFS_DINODE_FMT_LOCAL:
+ case XFS_DINODE_FMT_EXTENTS:
+ case XFS_DINODE_FMT_BTREE:
+ ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size);
+ if (!ip->i_d.di_forkoff)
+ ip->i_d.di_forkoff = xfs_default_attroffset(ip) >> 3;
+ else if ((ip->i_mount->m_flags & XFS_MOUNT_ATTR2) && version)
+ *version = 2;
+ break;
+ default:
+ ASSERT(0);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/*
* Convert inode from non-attributed to attributed.
* Must not be in a transaction, ip must not be locked.
@@ -1084,26 +1112,9 @@ xfs_bmap_add_attrfork(
xfs_trans_ijoin(tp, ip, 0);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-
- switch (ip->i_d.di_format) {
- case XFS_DINODE_FMT_DEV:
- ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3;
- break;
- case XFS_DINODE_FMT_LOCAL:
- case XFS_DINODE_FMT_EXTENTS:
- case XFS_DINODE_FMT_BTREE:
- ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size);
- if (!ip->i_d.di_forkoff)
- ip->i_d.di_forkoff = xfs_default_attroffset(ip) >> 3;
- else if (mp->m_flags & XFS_MOUNT_ATTR2)
- version = 2;
- break;
- default:
- ASSERT(0);
- error = -EINVAL;
+ error = xfs_bmap_set_attrforkoff(ip, size, &version);
+ if (error)
goto trans_cancel;
- }
-
ASSERT(ip->i_afp == NULL);
ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
ip->i_afp->if_flags = XFS_IFEXTENTS;
diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
index 2b766b3..50e9115 100644
--- a/fs/xfs/libxfs/xfs_bmap.h
+++ b/fs/xfs/libxfs/xfs_bmap.h
@@ -191,6 +191,7 @@ void xfs_trim_extent(struct xfs_bmbt_irec *irec, xfs_fileoff_t bno,
xfs_filblks_t len);
void xfs_trim_extent_eof(struct xfs_bmbt_irec *, struct xfs_inode *);
int xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd);
+int xfs_bmap_set_attrforkoff(struct xfs_inode *ip, int size, int *version);
void xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork);
void xfs_bmap_add_free(struct xfs_mount *mp, struct xfs_defer_ops *dfops,
xfs_fsblock_t bno, xfs_filblks_t len,
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 04/21] xfs: Add attibute remove and helper functions
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (2 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 03/21] xfs: Add attibute set and helper functions Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 23:21 ` Darrick J. Wong
2018-05-08 7:33 ` Amir Goldstein
2018-05-06 17:24 ` [PATCH 05/21] xfs: Set up infastructure for deferred attribute operations Allison Henderson
` (17 subsequent siblings)
21 siblings, 2 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
This patch adds xfs_attr_remove_args. These sub-routines remove
the attributes specified in @args. We will use this later for setting
parent pointers as a deferred attribute operation.
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/libxfs/xfs_attr.c | 43 +++++++++++++++++++++++++++++++++----------
fs/xfs/libxfs/xfs_attr.h | 1 +
2 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 99c4a31..514f4f8 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -296,6 +296,34 @@ xfs_attr_set_args(
}
/*
+ * Remove the attribute specified in @args.
+ */
+int
+xfs_attr_remove_args(
+ struct xfs_da_args *args,
+ int flags,
+ bool roll_trans)
+{
+ struct xfs_inode *dp = args->dp;
+ int error;
+
+ xfs_trans_ijoin(args->trans, dp, 0);
+
+ if (!xfs_inode_hasattr(dp)) {
+ error = -ENOATTR;
+ } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
+ ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
+ error = xfs_attr_shortform_remove(args, roll_trans);
+ } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+ error = xfs_attr_leaf_removename(args, roll_trans);
+ } else {
+ error = xfs_attr_node_removename(args, roll_trans);
+ }
+
+ return error;
+}
+
+/*
* Calculate how many blocks we need for the new attribute,
*/
STATIC int
@@ -439,6 +467,7 @@ xfs_attr_set(
return error;
}
+
/*
* Generic handler routine to remove a name from an attribute list.
* Transitions attribute list from Btree to shortform as necessary.
@@ -495,17 +524,9 @@ xfs_attr_remove(
* blocks not allocate in the common case.
*/
xfs_trans_ijoin(args.trans, dp, 0);
+ xfs_defer_init(args.dfops, args.firstblock);
- if (!xfs_inode_hasattr(dp)) {
- error = -ENOATTR;
- } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
- ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
- error = xfs_attr_shortform_remove(&args, true);
- } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
- error = xfs_attr_leaf_removename(&args, true);
- } else {
- error = xfs_attr_node_removename(&args, true);
- }
+ error = xfs_attr_remove_args(&args, flags, true);
if (error)
goto out;
@@ -530,6 +551,8 @@ xfs_attr_remove(
return error;
out:
+ xfs_defer_cancel(&dfops);
+
if (args.trans)
xfs_trans_cancel(args.trans);
xfs_iunlock(dp, XFS_ILOCK_EXCL);
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index b5dc02c..ef6b47e 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -155,6 +155,7 @@ int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
int xfs_attr_set_args(struct xfs_da_args *args, int flags,
struct xfs_buf *leaf_bp, bool roll_trans);
int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
+int xfs_attr_remove_args(struct xfs_da_args *args, int flags, bool roll_trans);
int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
int flags, struct attrlist_cursor_kern *cursor);
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 05/21] xfs: Set up infastructure for deferred attribute operations
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (3 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 04/21] xfs: Add attibute remove " Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 23:19 ` Darrick J. Wong
2018-05-08 9:55 ` Amir Goldstein
2018-05-06 17:24 ` [PATCH 06/21] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred Allison Henderson
` (16 subsequent siblings)
21 siblings, 2 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
This patch adds two new log item types for setting or
removing attributes as deferred operations. The
xfs_attri_log_item logs an intent to set or remove an
attribute. The corresponding xfs_attrd_log_item holds
a reference to the xfs_attri_log_item and is freed once
the transaction is done. Both log items use a generic
xfs_attr_log_format structure that contains the attribute
name, value, flags, inode, and an op_flag that indicates
if the operations is a set or remove.
At the moment, this feature will only be used by the parent
pointer patch set which uses attributes to store information
about an inodes parent.
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/Makefile | 2 +
fs/xfs/libxfs/xfs_attr.c | 5 +-
fs/xfs/libxfs/xfs_attr.h | 26 +-
fs/xfs/libxfs/xfs_defer.h | 1 +
fs/xfs/libxfs/xfs_log_format.h | 44 +++-
fs/xfs/libxfs/xfs_types.h | 1 +
fs/xfs/xfs_attr_item.c | 530 +++++++++++++++++++++++++++++++++++++++++
fs/xfs/xfs_attr_item.h | 119 +++++++++
fs/xfs/xfs_log_recover.c | 122 ++++++++++
fs/xfs/xfs_super.c | 1 +
fs/xfs/xfs_trans.h | 13 +
fs/xfs/xfs_trans_attr.c | 283 ++++++++++++++++++++++
12 files changed, 1142 insertions(+), 5 deletions(-)
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index 7ceb41a..d3c0004 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -107,6 +107,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 \
@@ -116,6 +117,7 @@ xfs-y += xfs_log.o \
xfs_trans_bmap.o \
xfs_trans_buf.o \
xfs_trans_extfree.o \
+ xfs_trans_attr.o \
xfs_trans_inode.o \
xfs_trans_refcount.o \
xfs_trans_rmap.o \
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 514f4f8..2f295ca 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -41,6 +41,7 @@
#include "xfs_quota.h"
#include "xfs_trans_space.h"
#include "xfs_trace.h"
+#include "xfs_attr_item.h"
/*
* xfs_attr.c
@@ -74,7 +75,7 @@ STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
-STATIC int
+int
xfs_attr_args_init(
struct xfs_da_args *args,
struct xfs_inode *dp,
@@ -326,7 +327,7 @@ xfs_attr_remove_args(
/*
* Calculate how many blocks we need for the new attribute,
*/
-STATIC int
+int
xfs_attr_calc_size(
struct xfs_da_args *args,
int *local)
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index ef6b47e..33b33d3 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -18,6 +18,8 @@
#ifndef __XFS_ATTR_H__
#define __XFS_ATTR_H__
+#include "libxfs/xfs_defer.h"
+
struct xfs_inode;
struct xfs_da_args;
struct xfs_attr_list_context;
@@ -90,6 +92,26 @@ typedef struct attrlist_ent { /* data from attr_list() */
} attrlist_ent_t;
/*
+ * List of attrs to commit later.
+ */
+struct xfs_attr_item {
+ struct xfs_inode *xattri_ip;
+ uint32_t xattri_op_flags;
+ uint32_t xattri_value_len; /* length of value */
+ uint32_t xattri_name_len; /* length of name */
+ uint32_t xattri_flags; /* attr flags */
+ struct list_head xattri_list;
+
+ /*
+ * A byte array follows the header containing the file name and
+ * attribute value.
+ */
+};
+
+#define XFS_ATTR_ITEM_SIZEOF(namelen, valuelen) \
+ (sizeof(struct xfs_attr_item) + (namelen) + (valuelen))
+
+/*
* Given a pointer to the (char*) buffer containing the attr_list() result,
* and an index, return a pointer to the indicated attribute in the buffer.
*/
@@ -158,6 +180,8 @@ int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
int xfs_attr_remove_args(struct xfs_da_args *args, int flags, bool roll_trans);
int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
int flags, struct attrlist_cursor_kern *cursor);
-
+int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
+ const unsigned char *name, int flags);
+int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
#endif /* __XFS_ATTR_H__ */
diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h
index 045beac..11e1690 100644
--- a/fs/xfs/libxfs/xfs_defer.h
+++ b/fs/xfs/libxfs/xfs_defer.h
@@ -55,6 +55,7 @@ enum xfs_defer_ops_type {
XFS_DEFER_OPS_TYPE_REFCOUNT,
XFS_DEFER_OPS_TYPE_RMAP,
XFS_DEFER_OPS_TYPE_FREE,
+ XFS_DEFER_OPS_TYPE_ATTR,
XFS_DEFER_OPS_TYPE_MAX,
};
diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
index 349d9f8..291e5ff 100644
--- a/fs/xfs/libxfs/xfs_log_format.h
+++ b/fs/xfs/libxfs/xfs_log_format.h
@@ -116,7 +116,12 @@ static inline uint xlog_get_cycle(char *ptr)
#define XLOG_REG_TYPE_CUD_FORMAT 24
#define XLOG_REG_TYPE_BUI_FORMAT 25
#define XLOG_REG_TYPE_BUD_FORMAT 26
-#define XLOG_REG_TYPE_MAX 26
+#define XLOG_REG_TYPE_ATTRI_FORMAT 27
+#define XLOG_REG_TYPE_ATTRD_FORMAT 28
+#define XLOG_REG_TYPE_ATTR_NAME 29
+#define XLOG_REG_TYPE_ATTR_VALUE 30
+#define XLOG_REG_TYPE_MAX 31
+
/*
* Flags to log operation header
@@ -239,6 +244,8 @@ typedef struct xfs_trans_header {
#define XFS_LI_CUD 0x1243
#define XFS_LI_BUI 0x1244 /* bmbt update intent */
#define XFS_LI_BUD 0x1245
+#define XFS_LI_ATTRI 0x1246 /* attr set/remove intent*/
+#define XFS_LI_ATTRD 0x1247 /* attr set/remove done */
#define XFS_LI_TYPE_DESC \
{ XFS_LI_EFI, "XFS_LI_EFI" }, \
@@ -254,7 +261,9 @@ typedef struct xfs_trans_header {
{ XFS_LI_CUI, "XFS_LI_CUI" }, \
{ XFS_LI_CUD, "XFS_LI_CUD" }, \
{ XFS_LI_BUI, "XFS_LI_BUI" }, \
- { XFS_LI_BUD, "XFS_LI_BUD" }
+ { XFS_LI_BUD, "XFS_LI_BUD" }, \
+ { XFS_LI_ATTRI, "XFS_LI_ATTRI" }, \
+ { XFS_LI_ATTRD, "XFS_LI_ATTRD" }
/*
* Inode Log Item Format definitions.
@@ -852,4 +861,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 3c56069..2905ce3 100644
--- a/fs/xfs/libxfs/xfs_types.h
+++ b/fs/xfs/libxfs/xfs_types.h
@@ -23,6 +23,7 @@ typedef uint32_t prid_t; /* project ID */
typedef uint32_t xfs_agblock_t; /* blockno in alloc. group */
typedef uint32_t xfs_agino_t; /* inode # within allocation grp */
typedef uint32_t xfs_extlen_t; /* extent length in blocks */
+typedef uint32_t xfs_attrlen_t; /* attr length */
typedef uint32_t xfs_agnumber_t; /* allocation group number */
typedef int32_t xfs_extnum_t; /* # of extents in a file */
typedef int16_t xfs_aextnum_t; /* # extents in an attribute fork */
diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
new file mode 100644
index 0000000..7e986e8
--- /dev/null
+++ b/fs/xfs/xfs_attr_item.c
@@ -0,0 +1,530 @@
+/*
+ * Copyright (c) 2017 Oracle, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation Inc.
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_bit.h"
+#include "xfs_mount.h"
+#include "xfs_trans.h"
+#include "xfs_trans_priv.h"
+#include "xfs_buf_item.h"
+#include "xfs_attr_item.h"
+#include "xfs_log.h"
+#include "xfs_btree.h"
+#include "xfs_rmap.h"
+#include "xfs_inode.h"
+#include "xfs_icache.h"
+
+static inline struct xfs_attri_log_item *ATTRI_ITEM(struct xfs_log_item *lip)
+{
+ return container_of(lip, struct xfs_attri_log_item, item);
+}
+
+void
+xfs_attri_item_free(
+ struct xfs_attri_log_item *attrip)
+{
+ kmem_free(attrip->item.li_lv_shadow);
+ kmem_free(attrip);
+}
+
+/*
+ * This returns the number of iovecs needed to log the given attri item.
+ * We only need 1 iovec for an attri item. It just logs the attr_log_format
+ * structure.
+ */
+static inline int
+xfs_attri_item_sizeof(
+ struct xfs_attri_log_item *attrip)
+{
+ return sizeof(struct xfs_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->name_len > 0) {
+ *nvecs += 1;
+ nbytes += ATTR_NVEC_SIZE(attrip->name_len);
+ }
+
+ if (attrip->value_len > 0) {
+ *nvecs += 1;
+ nbytes += ATTR_NVEC_SIZE(attrip->value_len);
+ }
+}
+
+/*
+ * This is called to fill in the vector of log iovecs for the
+ * given attri log item. We use only 1 iovec, and we point that
+ * at the attri_log_format structure embedded in the attri item.
+ * It is at this point that we assert that all of the attr
+ * slots in the attri item have been filled.
+ */
+STATIC void
+xfs_attri_item_format(
+ struct xfs_log_item *lip,
+ struct xfs_log_vec *lv)
+{
+ struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip);
+ struct xfs_log_iovec *vecp = NULL;
+
+ attrip->format.alfi_type = XFS_LI_ATTRI;
+ attrip->format.alfi_size = 1;
+
+ xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRI_FORMAT,
+ &attrip->format,
+ xfs_attri_item_sizeof(attrip));
+ if (attrip->name_len > 0)
+ xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_NAME,
+ attrip->name, ATTR_NVEC_SIZE(attrip->name_len));
+
+ if (attrip->value_len > 0)
+ xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_VALUE,
+ attrip->value,
+ ATTR_NVEC_SIZE(attrip->value_len));
+}
+
+
+/*
+ * Pinning has no meaning for an attri item, so just return.
+ */
+STATIC void
+xfs_attri_item_pin(
+ struct xfs_log_item *lip)
+{
+}
+
+/*
+ * The unpin operation is the last place an ATTRI is manipulated in the log. It
+ * is either inserted in the AIL or aborted in the event of a log I/O error. In
+ * either case, the ATTRI transaction has been successfully committed to make it
+ * this far. Therefore, we expect whoever committed the ATTRI to either
+ * construct and commit the ATTRD or drop the ATTRD's reference in the event of
+ * error. Simply drop the log's ATTRI reference now that the log is done with
+ * it.
+ */
+STATIC void
+xfs_attri_item_unpin(
+ struct xfs_log_item *lip,
+ int remove)
+{
+ struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip);
+
+ xfs_attri_release(attrip);
+}
+
+/*
+ * attri items have no locking or pushing. However, since ATTRIs are pulled
+ * from the AIL when their corresponding ATTRDs are committed to disk, their
+ * situation is very similar to being pinned. Return XFS_ITEM_PINNED so that
+ * the caller will eventually flush the log. This should help in getting the
+ * ATTRI out of the AIL.
+ */
+STATIC uint
+xfs_attri_item_push(
+ struct xfs_log_item *lip,
+ struct list_head *buffer_list)
+{
+ return XFS_ITEM_PINNED;
+}
+
+/*
+ * The ATTRI has been either committed or aborted if the transaction has been
+ * cancelled. If the transaction was cancelled, an ATTRD isn't going to be
+ * constructed and thus we free the ATTRI here directly.
+ */
+STATIC void
+xfs_attri_item_unlock(
+ struct xfs_log_item *lip)
+{
+ if (lip->li_flags & XFS_LI_ABORTED)
+ xfs_attri_release(ATTRI_ITEM(lip));
+}
+
+/*
+ * The ATTRI is logged only once and cannot be moved in the log, so simply
+ * return the lsn at which it's been logged.
+ */
+STATIC xfs_lsn_t
+xfs_attri_item_committed(
+ struct xfs_log_item *lip,
+ xfs_lsn_t lsn)
+{
+ return lsn;
+}
+
+STATIC void
+xfs_attri_item_committing(
+ struct xfs_log_item *lip,
+ xfs_lsn_t lsn)
+{
+}
+
+/*
+ * This is the ops vector shared by all attri log items.
+ */
+static const struct xfs_item_ops xfs_attri_item_ops = {
+ .iop_size = xfs_attri_item_size,
+ .iop_format = xfs_attri_item_format,
+ .iop_pin = xfs_attri_item_pin,
+ .iop_unpin = xfs_attri_item_unpin,
+ .iop_unlock = xfs_attri_item_unlock,
+ .iop_committed = xfs_attri_item_committed,
+ .iop_push = xfs_attri_item_push,
+ .iop_committing = xfs_attri_item_committing
+};
+
+
+/*
+ * Allocate and initialize an attri item
+ */
+struct xfs_attri_log_item *
+xfs_attri_init(
+ struct xfs_mount *mp)
+
+{
+ struct xfs_attri_log_item *attrip;
+ uint size;
+
+ size = (uint)(sizeof(struct xfs_attri_log_item));
+ attrip = kmem_zalloc(size, KM_SLEEP);
+
+ xfs_log_item_init(mp, &(attrip->item), XFS_LI_ATTRI,
+ &xfs_attri_item_ops);
+ attrip->format.alfi_id = (uintptr_t)(void *)attrip;
+ atomic_set(&attrip->refcount, 2);
+
+ return attrip;
+}
+
+/*
+ * Copy an attr format buffer from the given buf, and into the destination
+ * attr format structure.
+ */
+int
+xfs_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) {
+ memcpy((char *)dst_attr_fmt, (char *)src_attr_fmt, len);
+ return 0;
+ }
+ return -EFSCORRUPTED;
+}
+
+/*
+ * Copy an attr format buffer from the given buf, and into the destination
+ * attr format structure.
+ */
+int
+xfs_attrd_copy_format(struct xfs_log_iovec *buf,
+ struct xfs_attrd_log_format *dst_attr_fmt)
+{
+ struct xfs_attrd_log_format *src_attr_fmt = buf->i_addr;
+ uint len = sizeof(struct xfs_attrd_log_format);
+
+ if (buf->i_len == len) {
+ memcpy((char *)dst_attr_fmt, (char *)src_attr_fmt, len);
+ return 0;
+ }
+ return -EFSCORRUPTED;
+}
+
+/*
+ * 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->refcount) > 0);
+ if (atomic_dec_and_test(&attrip->refcount)) {
+ xfs_trans_ail_remove(&attrip->item, SHUTDOWN_LOG_IO_ERROR);
+ xfs_attri_item_free(attrip);
+ }
+}
+
+static inline struct xfs_attrd_log_item *ATTRD_ITEM(struct xfs_log_item *lip)
+{
+ return container_of(lip, struct xfs_attrd_log_item, item);
+}
+
+STATIC void
+xfs_attrd_item_free(struct xfs_attrd_log_item *attrdp)
+{
+ kmem_free(attrdp->item.li_lv_shadow);
+ kmem_free(attrdp);
+}
+
+/*
+ * This returns the number of iovecs needed to log the given attrd item.
+ * We only need 1 iovec for an attrd item. It just logs the attr_log_format
+ * structure.
+ */
+static inline int
+xfs_attrd_item_sizeof(
+ struct xfs_attrd_log_item *attrdp)
+{
+ return sizeof(struct xfs_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);
+
+ if (attrdp->name_len > 0) {
+ *nvecs += 1;
+ nbytes += attrdp->name_len;
+ }
+
+ if (attrdp->value_len > 0) {
+ *nvecs += 1;
+ nbytes += attrdp->value_len;
+ }
+}
+
+/*
+ * This is called to fill in the vector of log iovecs for the
+ * given attrd log item. We use only 1 iovec, and we point that
+ * at the attr_log_format structure embedded in the attrd item.
+ * It is at this point that we assert that all of the attr
+ * slots in the attrd item have been filled.
+ */
+STATIC void
+xfs_attrd_item_format(
+ struct xfs_log_item *lip,
+ struct xfs_log_vec *lv)
+{
+ struct xfs_attrd_log_item *attrdp = ATTRD_ITEM(lip);
+ struct xfs_log_iovec *vecp = NULL;
+
+ attrdp->format.alfd_type = XFS_LI_ATTRD;
+ attrdp->format.alfd_size = 1;
+
+ xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRD_FORMAT,
+ &attrdp->format,
+ xfs_attrd_item_sizeof(attrdp));
+}
+
+/*
+ * Pinning has no meaning for an attrd item, so just return.
+ */
+STATIC void
+xfs_attrd_item_pin(
+ struct xfs_log_item *lip)
+{
+}
+
+/*
+ * Since pinning has no meaning for an attrd item, unpinning does
+ * not either.
+ */
+STATIC void
+xfs_attrd_item_unpin(
+ struct xfs_log_item *lip,
+ int remove)
+{
+}
+
+/*
+ * There isn't much you can do to push on an attrd item. It is simply stuck
+ * waiting for the log to be flushed to disk.
+ */
+STATIC uint
+xfs_attrd_item_push(
+ struct xfs_log_item *lip,
+ struct list_head *buffer_list)
+{
+ return XFS_ITEM_PINNED;
+}
+
+/*
+ * The ATTRD is either committed or aborted if the transaction is cancelled. If
+ * the transaction is cancelled, drop our reference to the ATTRI and free the
+ * ATTRD.
+ */
+STATIC void
+xfs_attrd_item_unlock(
+ struct xfs_log_item *lip)
+{
+ struct xfs_attrd_log_item *attrdp = ATTRD_ITEM(lip);
+
+ if (lip->li_flags & XFS_LI_ABORTED) {
+ xfs_attri_release(attrdp->attrip);
+ xfs_attrd_item_free(attrdp);
+ }
+}
+
+/*
+ * When the attrd item is committed to disk, all we need to do is delete our
+ * reference to our partner attri item and then free ourselves. Since we're
+ * freeing ourselves we must return -1 to keep the transaction code from
+ * further referencing this item.
+ */
+STATIC xfs_lsn_t
+xfs_attrd_item_committed(
+ struct xfs_log_item *lip,
+ xfs_lsn_t lsn)
+{
+ struct xfs_attrd_log_item *attrdp = ATTRD_ITEM(lip);
+
+ /*
+ * Drop the ATTRI reference regardless of whether the ATTRD has been
+ * aborted. Once the ATTRD transaction is constructed, it is the sole
+ * responsibility of the ATTRD to release the ATTRI (even if the ATTRI
+ * is aborted due to log I/O error).
+ */
+ xfs_attri_release(attrdp->attrip);
+ xfs_attrd_item_free(attrdp);
+
+ return (xfs_lsn_t)-1;
+}
+
+STATIC void
+xfs_attrd_item_committing(
+ struct xfs_log_item *lip,
+ xfs_lsn_t lsn)
+{
+}
+
+/*
+ * This is the ops vector shared by all attrd log items.
+ */
+static const struct xfs_item_ops xfs_attrd_item_ops = {
+ .iop_size = xfs_attrd_item_size,
+ .iop_format = xfs_attrd_item_format,
+ .iop_pin = xfs_attrd_item_pin,
+ .iop_unpin = xfs_attrd_item_unpin,
+ .iop_unlock = xfs_attrd_item_unlock,
+ .iop_committed = xfs_attrd_item_committed,
+ .iop_push = xfs_attrd_item_push,
+ .iop_committing = xfs_attrd_item_committing
+};
+
+/*
+ * Allocate and initialize an attrd item
+ */
+struct xfs_attrd_log_item *
+xfs_attrd_init(
+ struct xfs_mount *mp,
+ struct xfs_attri_log_item *attrip)
+
+{
+ struct xfs_attrd_log_item *attrdp;
+ uint size;
+
+ size = (uint)(sizeof(struct xfs_attrd_log_item));
+ attrdp = kmem_zalloc(size, KM_SLEEP);
+
+ xfs_log_item_init(mp, &attrdp->item, XFS_LI_ATTRD,
+ &xfs_attrd_item_ops);
+ attrdp->attrip = attrip;
+ attrdp->format.alfd_alf_id = attrip->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_trans *tp;
+ int error = 0;
+ struct xfs_attri_log_format *attrp;
+
+ ASSERT(!test_bit(XFS_ATTRI_RECOVERED, &attrip->flags));
+
+ /*
+ * First check the validity of the attr described by the
+ * ATTRI. If any are bad, then assume that all are bad and
+ * just toss the ATTRI. A valid attr must have a name length,
+ * a value length, and either a "set" or "remove" op flag
+ */
+ attrp = &attrip->format;
+ if (attrp->alfi_value_len == 0 ||
+ attrp->alfi_name_len == 0 ||
+ !(attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_SET ||
+ attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_REMOVE) ) {
+ /*
+ * This will pull the ATTRI from the AIL and
+ * free the memory associated with it.
+ */
+ set_bit(XFS_ATTRI_RECOVERED, &attrip->flags);
+ xfs_attri_release(attrip);
+ return -EIO;
+ }
+
+ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
+ if (error)
+ return error;
+ attrdp = xfs_trans_get_attrd(tp, attrip);
+ attrp = &attrip->format;
+
+ error = xfs_iget(mp, tp, attrp->alfi_ino, 0, 0, &ip);
+ if (error)
+ return error;
+
+ error = xfs_trans_attr(tp, attrdp, ip,
+ attrp->alfi_op_flags,
+ attrp->alfi_attr_flags,
+ attrp->alfi_name_len,
+ attrp->alfi_value_len,
+ attrip->name,
+ attrip->value);
+ if (error)
+ goto abort_error;
+
+
+ set_bit(XFS_ATTRI_RECOVERED, &attrip->flags);
+ error = xfs_trans_commit(tp);
+ return error;
+
+abort_error:
+ xfs_trans_cancel(tp);
+ return error;
+}
diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h
new file mode 100644
index 0000000..6ff07cc
--- /dev/null
+++ b/fs/xfs/xfs_attr_item.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2017 Oracle, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation Inc.
+ */
+#ifndef __XFS_ATTR_ITEM_H__
+#define __XFS_ATTR_ITEM_H__
+
+/* kernel only ATTRI/ATTRD definitions */
+
+struct xfs_mount;
+struct kmem_zone;
+
+/*
+ * Max number of attrs in fast allocation path.
+ */
+#define XFS_ATTRI_MAX_FAST_ATTRS 1
+
+
+/*
+ * Define ATTR flag bits. Manipulated by set/clear/test_bit operators.
+ */
+#define XFS_ATTRI_RECOVERED 1
+
+
+/* nvecs must be in multiples of 4 */
+#define ATTR_NVEC_SIZE(size) (size == sizeof(int32_t) ? sizeof(int32_t) : \
+ size + sizeof(int32_t) - \
+ (size % sizeof(int32_t)))
+
+/*
+ * This is the "attr intention" log item. It is used to log the fact
+ * that some attrs need to be processed. It is used in conjunction with the
+ * "attr done" log item described below.
+ *
+ * The ATTRI is reference counted so that it is not freed prior to both the
+ * ATTRI and ATTRD being committed and unpinned. This ensures the ATTRI is
+ * inserted into the AIL even in the event of out of order ATTRI/ATTRD
+ * processing. In other words, an ATTRI is born with two references:
+ *
+ * 1.) an ATTRI held reference to track ATTRI AIL insertion
+ * 2.) an ATTRD held reference to track ATTRD commit
+ *
+ * On allocation, both references are the responsibility of the caller. Once
+ * the ATTRI is added to and dirtied in a transaction, ownership of reference
+ * one transfers to the transaction. The reference is dropped once the ATTRI is
+ * inserted to the AIL or in the event of failure along the way (e.g., commit
+ * failure, log I/O error, etc.). Note that the caller remains responsible for
+ * the ATTRD reference under all circumstances to this point. The caller has no
+ * means to detect failure once the transaction is committed, however.
+ * Therefore, an ATTRD is required after this point, even in the event of
+ * unrelated failure.
+ *
+ * Once an ATTRD is allocated and dirtied in a transaction, reference two
+ * transfers to the transaction. The ATTRD reference is dropped once it reaches
+ * the unpin handler. Similar to the ATTRI, the reference also drops in the
+ * event of commit failure or log I/O errors. Note that the ATTRD is not
+ * inserted in the AIL, so at this point both the ATTI and ATTRD are freed.
+ */
+struct xfs_attri_log_item {
+ xfs_log_item_t item;
+ atomic_t refcount;
+ unsigned long flags; /* misc flags */
+ int name_len;
+ void *name;
+ int value_len;
+ void *value;
+ struct xfs_attri_log_format format;
+};
+
+/*
+ * This is the "attr done" log item. It is used to log
+ * the fact that some attrs earlier mentioned in an attri item
+ * have been freed.
+ */
+struct xfs_attrd_log_item {
+ struct xfs_log_item item;
+ struct xfs_attri_log_item *attrip;
+ uint next_attr;
+ int name_len;
+ void *name;
+ int value_len;
+ void *value;
+ struct xfs_attrd_log_format format;
+};
+
+/*
+ * Max number of attrs in fast allocation path.
+ */
+#define XFS_ATTRD_MAX_FAST_ATTRS 1
+
+extern struct kmem_zone *xfs_attri_zone;
+extern struct kmem_zone *xfs_attrd_zone;
+
+struct xfs_attri_log_item *xfs_attri_init(struct xfs_mount *mp);
+struct xfs_attrd_log_item *xfs_attrd_init(struct xfs_mount *mp,
+ struct xfs_attri_log_item *attrip);
+int xfs_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_recover.c b/fs/xfs/xfs_log_recover.c
index 2b2383f..696b6ff 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -34,6 +34,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"
@@ -1967,6 +1968,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);
@@ -3497,6 +3500,92 @@ xlog_recover_efd_pass2(
return 0;
}
+STATIC int
+xlog_recover_attri_pass2(
+ struct xlog *log,
+ struct xlog_recover_item *item,
+ xfs_lsn_t lsn)
+{
+ int error;
+ struct xfs_mount *mp = log->l_mp;
+ struct xfs_attri_log_item *attrip;
+ struct xfs_attr_log_format *attri_formatp;
+
+ attri_formatp = item->ri_buf[0].i_addr;
+
+ attrip = xfs_attri_init(mp);
+ error = xfs_attri_copy_format(&item->ri_buf[0], &attrip->format);
+ if (error) {
+ xfs_attri_item_free(attrip);
+ return error;
+ }
+
+ 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->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->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.
@@ -4116,6 +4205,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:
@@ -4677,6 +4770,31 @@ xlog_recover_cancel_efi(
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, item);
+ if (test_bit(XFS_ATTRI_RECOVERED, &attrip->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(
@@ -4920,6 +5038,10 @@ xlog_recover_process_intents(
case XFS_LI_EFI:
error = xlog_recover_process_efi(log->l_mp, ailp, lip);
break;
+ case XFS_LI_ATTRI:
+ error = xlog_recover_process_attri(log->l_mp,
+ ailp, lip);
+ break;
case XFS_LI_RUI:
error = xlog_recover_process_rui(log->l_mp, ailp, lip);
break;
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index d714240..dce3baf 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -2077,6 +2077,7 @@ init_xfs_fs(void)
xfs_rmap_update_init_defer_op();
xfs_refcount_update_init_defer_op();
xfs_bmap_update_init_defer_op();
+ xfs_attr_init_defer_op();
xfs_dir_startup();
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 9d542df..abd0a46 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -40,6 +40,9 @@ struct xfs_cud_log_item;
struct xfs_defer_ops;
struct xfs_bui_log_item;
struct xfs_bud_log_item;
+struct xfs_attrd_log_item;
+struct xfs_attri_log_item;
+
typedef struct xfs_log_item {
struct list_head li_ail; /* AIL pointers */
@@ -223,12 +226,22 @@ void xfs_trans_dirty_buf(struct xfs_trans *, struct xfs_buf *);
void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
void xfs_extent_free_init_defer_op(void);
+void xfs_attr_init_defer_op(void);
+
struct xfs_efd_log_item *xfs_trans_get_efd(struct xfs_trans *,
struct xfs_efi_log_item *,
uint);
int xfs_trans_free_extent(struct xfs_trans *,
struct xfs_efd_log_item *, xfs_fsblock_t,
xfs_extlen_t, struct xfs_owner_info *);
+struct xfs_attrd_log_item *
+xfs_trans_get_attrd(struct xfs_trans *tp,
+ struct xfs_attri_log_item *attrip);
+int xfs_trans_attr(struct xfs_trans *tp, struct xfs_attrd_log_item *attrdp,
+ struct xfs_inode *ip, uint32_t attr_op_flags,
+ uint32_t flags, uint32_t name_len, uint32_t value_len,
+ char *name, char *value);
+
int xfs_trans_commit(struct xfs_trans *);
int xfs_trans_roll(struct xfs_trans **);
int xfs_trans_roll_inode(struct xfs_trans **, struct xfs_inode *);
diff --git a/fs/xfs/xfs_trans_attr.c b/fs/xfs/xfs_trans_attr.c
new file mode 100644
index 0000000..8e3a0a0
--- /dev/null
+++ b/fs/xfs/xfs_trans_attr.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2017, Oracle Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation Inc.
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_bit.h"
+#include "xfs_mount.h"
+#include "xfs_defer.h"
+#include "xfs_trans.h"
+#include "xfs_trans_priv.h"
+#include "xfs_attr_item.h"
+#include "xfs_alloc.h"
+#include "xfs_bmap.h"
+#include "xfs_trace.h"
+#include "libxfs/xfs_da_format.h"
+#include "xfs_da_btree.h"
+#include "xfs_attr.h"
+#include "xfs_inode.h"
+#include "xfs_icache.h"
+#include "xfs_quota.h"
+
+/*
+ * This routine is called to allocate an "extent free done"
+ * log item that will hold nextents worth of extents. The
+ * caller must use all nextents extents, because we are not
+ * flexible about this at all.
+ */
+struct xfs_attrd_log_item *
+xfs_trans_get_attrd(struct xfs_trans *tp,
+ struct xfs_attri_log_item *attrip)
+{
+ struct xfs_attrd_log_item *attrdp;
+
+ ASSERT(tp != NULL);
+
+ attrdp = xfs_attrd_init(tp->t_mountp, attrip);
+ ASSERT(attrdp != NULL);
+
+ /*
+ * Get a log_item_desc to point at the new item.
+ */
+ xfs_trans_add_item(tp, &attrdp->item);
+ return attrdp;
+}
+
+/*
+ * Delete an attr and log it to the ATTRD. Note that the transaction is marked
+ * dirty regardless of whether the attr delete succeeds or fails to support the
+ * ATTRI/ATTRD lifecycle rules.
+ */
+int
+xfs_trans_attr(
+ struct xfs_trans *tp,
+ struct xfs_attrd_log_item *attrdp,
+ struct xfs_inode *ip,
+ uint32_t op_flags,
+ uint32_t flags,
+ uint32_t name_len,
+ uint32_t value_len,
+ char *name,
+ char *value)
+{
+ int error;
+ int local;
+ struct xfs_da_args args;
+ struct xfs_defer_ops dfops;
+ xfs_fsblock_t firstblock = NULLFSBLOCK;
+ struct xfs_buf *leaf_bp = NULL;
+
+ tp->t_flags |= XFS_TRANS_RESERVE;
+
+ error = xfs_attr_args_init(&args, ip, name, flags);
+ if (error)
+ return error;
+
+ xfs_defer_init(&dfops, &firstblock);
+
+ args.name = name;
+ args.namelen = name_len;
+ args.hashval = xfs_da_hashname(args.name, args.namelen);
+ args.value = value;
+ args.valuelen = value_len;
+ args.dfops = &dfops;
+ args.firstblock = &firstblock;
+ args.op_flags = XFS_DA_OP_OKNOENT;
+ args.total = xfs_attr_calc_size(&args, &local);
+ args.trans = tp;
+ ASSERT(local);
+
+ error = xfs_qm_dqattach_locked(ip, 0);
+ if (error)
+ return error;
+
+ switch (op_flags) {
+ case XFS_ATTR_OP_FLAGS_SET:
+ args.op_flags |= XFS_DA_OP_ADDNAME;
+ error = xfs_attr_set_args(&args, flags,
+ leaf_bp, false);
+ break;
+ case XFS_ATTR_OP_FLAGS_REMOVE:
+ ASSERT(XFS_IFORK_Q((ip)));
+ error = xfs_attr_remove_args(&args, flags, false);
+ break;
+ default:
+ error = -EFSCORRUPTED;
+ }
+
+ if (error) {
+ xfs_defer_cancel(&dfops);
+ if (leaf_bp)
+ xfs_trans_brelse(args.trans, leaf_bp);
+ }
+
+ /*
+ * Mark the transaction dirty, even on error. This ensures the
+ * transaction is aborted, which:
+ *
+ * 1.) releases the ATTRI and frees the ATTRD
+ * 2.) shuts down the filesystem
+ */
+ tp->t_flags |= XFS_TRANS_DIRTY;
+ attrdp->item.li_desc->lid_flags |= XFS_LID_DIRTY;
+ attrdp->name = name;
+ attrdp->value = value;
+ attrdp->name_len = name_len;
+ attrdp->value_len = value_len;
+ attrdp->next_attr++;
+
+ return error;
+}
+
+static int
+xfs_attr_diff_items(
+ void *priv,
+ struct list_head *a,
+ struct list_head *b)
+{
+ return 0;
+}
+
+/* Get an ATTRI. */
+STATIC void *
+xfs_attr_create_intent(
+ struct xfs_trans *tp,
+ unsigned int count)
+{
+ struct xfs_attri_log_item *attrip;
+
+ ASSERT(tp != NULL);
+ ASSERT(count == 1);
+
+ attrip = xfs_attri_init(tp->t_mountp);
+ ASSERT(attrip != NULL);
+
+ /*
+ * Get a log_item_desc to point at the new item.
+ */
+ xfs_trans_add_item(tp, &attrip->item);
+ return attrip;
+}
+
+/* Log an attr to the intent item. */
+STATIC void
+xfs_attr_log_item(
+ struct xfs_trans *tp,
+ void *intent,
+ struct list_head *item)
+{
+ struct xfs_attri_log_item *attrip = intent;
+ struct xfs_attr_item *free;
+ struct xfs_attri_log_format *attrp;
+ char *name_value;
+
+ free = container_of(item, struct xfs_attr_item, xattri_list);
+ name_value = ((char *)free) + sizeof(struct xfs_attr_item);
+
+ tp->t_flags |= XFS_TRANS_DIRTY;
+ attrip->item.li_desc->lid_flags |= XFS_LID_DIRTY;
+
+ attrp = &attrip->format;
+ attrp->alfi_ino = free->xattri_ip->i_ino;
+ attrp->alfi_op_flags = free->xattri_op_flags;
+ attrp->alfi_value_len = free->xattri_value_len;
+ attrp->alfi_name_len = free->xattri_name_len;
+ attrp->alfi_attr_flags = free->xattri_flags;
+
+ attrip->name = name_value;
+ attrip->value = &name_value[free->xattri_name_len];
+ attrip->name_len = free->xattri_name_len;
+ attrip->value_len = free->xattri_value_len;
+}
+
+/* Get an ATTRD so we can process all the attrs. */
+STATIC void *
+xfs_attr_create_done(
+ struct xfs_trans *tp,
+ void *intent,
+ unsigned int count)
+{
+ return xfs_trans_get_attrd(tp, intent);
+}
+
+/* Process an attr. */
+STATIC int
+xfs_attr_finish_item(
+ struct xfs_trans *tp,
+ struct xfs_defer_ops *dop,
+ struct list_head *item,
+ void *done_item,
+ void **state)
+{
+ struct xfs_attr_item *free;
+ char *name_value;
+ int error;
+
+ free = container_of(item, struct xfs_attr_item, xattri_list);
+ name_value = ((char *)free) + sizeof(struct xfs_attr_item);
+ error = xfs_trans_attr(tp, done_item,
+ free->xattri_ip,
+ free->xattri_op_flags,
+ free->xattri_flags,
+ free->xattri_name_len,
+ free->xattri_value_len,
+ name_value,
+ &name_value[free->xattri_name_len]);
+ kmem_free(free);
+ return error;
+}
+
+/* Abort all pending ATTRs. */
+STATIC void
+xfs_attr_abort_intent(
+ void *intent)
+{
+ xfs_attri_release(intent);
+}
+
+/* Cancel an attr */
+STATIC void
+xfs_attr_cancel_item(
+ struct list_head *item)
+{
+ struct xfs_attr_item *free;
+
+ free = container_of(item, struct xfs_attr_item, xattri_list);
+ kmem_free(free);
+}
+
+static const struct xfs_defer_op_type xfs_attr_defer_type = {
+ .type = XFS_DEFER_OPS_TYPE_ATTR,
+ .max_items = XFS_ATTRI_MAX_FAST_ATTRS,
+ .diff_items = xfs_attr_diff_items,
+ .create_intent = xfs_attr_create_intent,
+ .abort_intent = xfs_attr_abort_intent,
+ .log_item = xfs_attr_log_item,
+ .create_done = xfs_attr_create_done,
+ .finish_item = xfs_attr_finish_item,
+ .cancel_item = xfs_attr_cancel_item,
+};
+
+/* Register the deferred op type. */
+void
+xfs_attr_init_defer_op(void)
+{
+ xfs_defer_init_op_type(&xfs_attr_defer_type);
+}
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 06/21] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (4 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 05/21] xfs: Set up infastructure for deferred attribute operations Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 22:59 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 07/21] xfs: Remove all strlen calls in all xfs_attr_* functions for attr names Allison Henderson
` (15 subsequent siblings)
21 siblings, 1 reply; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
These routines set up set and start a new deferred attribute
operation. These functions are meant to be called by other
code needing to initiate a deferred attribute operation. We
will use these routines later in the parent pointer patches.
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/libxfs/xfs_attr.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++
fs/xfs/libxfs/xfs_attr.h | 5 ++++
2 files changed, 74 insertions(+)
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 2f295ca..adbcef2 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -468,6 +468,42 @@ xfs_attr_set(
return error;
}
+/* Sets an attribute for an inode as a deferred operation */
+int
+xfs_attr_set_deferred(
+ struct xfs_inode *dp,
+ struct xfs_defer_ops *dfops,
+ void *name,
+ unsigned int namelen,
+ void *value,
+ unsigned int valuelen,
+ int flags)
+{
+
+ struct xfs_attr_item *new;
+ char *name_value;
+
+ if (!namelen || !valuelen) {
+ ASSERT(0);
+ return -EFSCORRUPTED;
+ }
+
+ new = kmem_alloc(XFS_ATTR_ITEM_SIZEOF(namelen, valuelen),
+ KM_SLEEP|KM_NOFS);
+ name_value = ((char *)new) + sizeof(struct xfs_attr_item);
+ memset(new, 0, XFS_ATTR_ITEM_SIZEOF(namelen, valuelen));
+ new->xattri_ip = dp;
+ new->xattri_op_flags = XFS_ATTR_OP_FLAGS_SET;
+ new->xattri_name_len = namelen;
+ new->xattri_value_len = valuelen;
+ new->xattri_flags = flags;
+ memcpy(&name_value[0], name, namelen);
+ memcpy(&name_value[namelen], value, valuelen);
+
+ xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
+
+ return 0;
+}
/*
* Generic handler routine to remove a name from an attribute list.
@@ -560,6 +596,39 @@ xfs_attr_remove(
return error;
}
+/* Removes an attribute for an inode as a deferred operation */
+int
+xfs_attr_remove_deferred(
+ struct xfs_inode *dp,
+ struct xfs_defer_ops *dfops,
+ void *name,
+ unsigned int namelen,
+ int flags)
+{
+
+ struct xfs_attr_item *new;
+ char *name_value;
+
+ if (!namelen) {
+ ASSERT(0);
+ return -EFSCORRUPTED;
+ }
+
+ new = kmem_alloc(XFS_ATTR_ITEM_SIZEOF(namelen, 0), KM_SLEEP|KM_NOFS);
+ name_value = ((char *)new) + sizeof(struct xfs_attr_item);
+ memset(new, 0, XFS_ATTR_ITEM_SIZEOF(namelen, 0));
+ new->xattri_ip = dp;
+ new->xattri_op_flags = XFS_ATTR_OP_FLAGS_REMOVE;
+ new->xattri_name_len = namelen;
+ new->xattri_value_len = 0;
+ new->xattri_flags = flags;
+ memcpy(name_value, name, namelen);
+
+ xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
+
+ return 0;
+}
+
/*========================================================================
* External routines when attribute list is inside the inode
*========================================================================*/
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 33b33d3..ec26565 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -183,5 +183,10 @@ int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
const unsigned char *name, int flags);
int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
+int xfs_attr_set_deferred(struct xfs_inode *dp, struct xfs_defer_ops *dfops,
+ void *name, unsigned int name_len, void *value,
+ unsigned int valuelen, int flags);
+int xfs_attr_remove_deferred(struct xfs_inode *dp, struct xfs_defer_ops *dfops,
+ void *name, unsigned int namelen, int flags);
#endif /* __XFS_ATTR_H__ */
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 07/21] xfs: Remove all strlen calls in all xfs_attr_* functions for attr names.
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (5 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 06/21] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 22:54 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 08/21] xfs: get directory offset when adding directory name Allison Henderson
` (14 subsequent siblings)
21 siblings, 1 reply; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
Parent pointer attributes use a binary name, so strlen will not work.
Calling functions will need to pass in the name length
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/libxfs/xfs_attr.c | 12 ++++++++----
fs/xfs/libxfs/xfs_attr.h | 10 ++++++----
fs/xfs/xfs_acl.c | 12 +++++++-----
fs/xfs/xfs_ioctl.c | 13 ++++++++++---
fs/xfs/xfs_iops.c | 6 ++++--
fs/xfs/xfs_trans_attr.c | 2 +-
fs/xfs/xfs_xattr.c | 10 +++++++---
7 files changed, 43 insertions(+), 22 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index adbcef2..484fa86 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -80,6 +80,7 @@ xfs_attr_args_init(
struct xfs_da_args *args,
struct xfs_inode *dp,
const unsigned char *name,
+ size_t namelen,
int flags)
{
@@ -92,7 +93,7 @@ xfs_attr_args_init(
args->dp = dp;
args->flags = flags;
args->name = name;
- args->namelen = strlen((const char *)name);
+ args->namelen = namelen;
if (args->namelen >= MAXNAMELEN)
return -EFAULT; /* match IRIX behaviour */
@@ -138,6 +139,7 @@ int
xfs_attr_get(
struct xfs_inode *ip,
const unsigned char *name,
+ size_t namelen,
unsigned char *value,
int *valuelenp,
int flags)
@@ -151,7 +153,7 @@ xfs_attr_get(
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return -EIO;
- error = xfs_attr_args_init(&args, ip, name, flags);
+ error = xfs_attr_args_init(&args, ip, name, namelen, flags);
if (error)
return error;
@@ -364,6 +366,7 @@ int
xfs_attr_set(
struct xfs_inode *dp,
const unsigned char *name,
+ size_t namelen,
unsigned char *value,
int valuelen,
int flags)
@@ -382,7 +385,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;
@@ -513,6 +516,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;
@@ -526,7 +530,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 ec26565..308a93e 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -171,17 +171,19 @@ int xfs_attr_list_int(struct xfs_attr_list_context *);
int xfs_inode_hasattr(struct xfs_inode *ip);
int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
- unsigned char *value, int *valuelenp, int flags);
+ size_t namelen, unsigned char *value, int *valuelenp,
+ int flags);
int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
- unsigned char *value, int valuelen, int flags);
+ size_t namelen, unsigned char *value, int valuelen, int flags);
int xfs_attr_set_args(struct xfs_da_args *args, int flags,
struct xfs_buf *leaf_bp, bool roll_trans);
-int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
+int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
+ size_t namelen, int flags);
int xfs_attr_remove_args(struct xfs_da_args *args, int flags, bool roll_trans);
int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
int flags, struct attrlist_cursor_kern *cursor);
int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
- const unsigned char *name, int flags);
+ const unsigned char *name, size_t namelen, int flags);
int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
int xfs_attr_set_deferred(struct xfs_inode *dp, struct xfs_defer_ops *dfops,
void *name, unsigned int name_len, void *value,
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 3354140..e59b26d 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -153,8 +153,8 @@ xfs_get_acl(struct inode *inode, int type)
if (!xfs_acl)
return ERR_PTR(-ENOMEM);
- error = xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl,
- &len, ATTR_ROOT);
+ error = xfs_attr_get(ip, ea_name, strlen(ea_name),
+ (unsigned char *)xfs_acl, &len, ATTR_ROOT);
if (error) {
/*
* If the attribute doesn't exist make sure we have a negative
@@ -204,15 +204,17 @@ __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
len -= sizeof(struct xfs_acl_entry) *
(XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count);
- error = xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
- len, ATTR_ROOT);
+ error = xfs_attr_set(ip, ea_name, strlen(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 89fb1eb..844480a 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -450,6 +450,7 @@ xfs_attrmulti_attr_get(
{
unsigned char *kbuf;
int error = -EFAULT;
+ size_t namelen;
if (*len > XFS_XATTR_SIZE_MAX)
return -EINVAL;
@@ -457,7 +458,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;
@@ -479,6 +482,7 @@ xfs_attrmulti_attr_set(
{
unsigned char *kbuf;
int error;
+ size_t namelen;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM;
@@ -489,7 +493,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);
@@ -503,10 +508,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 c45acf0..7920f19 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -71,8 +71,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_trans_attr.c b/fs/xfs/xfs_trans_attr.c
index 8e3a0a0..d1d75bb 100644
--- a/fs/xfs/xfs_trans_attr.c
+++ b/fs/xfs/xfs_trans_attr.c
@@ -86,7 +86,7 @@ xfs_trans_attr(
tp->t_flags |= XFS_TRANS_RESERVE;
- error = xfs_attr_args_init(&args, ip, name, flags);
+ error = xfs_attr_args_init(&args, ip, name, name_len, flags);
if (error)
return error;
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index 0594db4..6cf30ae 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -38,6 +38,7 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
int xflags = handler->flags;
struct xfs_inode *ip = XFS_I(inode);
int error, asize = size;
+ size_t namelen = strlen(name);
/* Convert Linux syscall to XFS internal ATTR flags */
if (!size) {
@@ -45,7 +46,8 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
value = NULL;
}
- error = xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags);
+ error = xfs_attr_get(ip, name, namelen, value,
+ &asize, xflags);
if (error)
return error;
return asize;
@@ -81,6 +83,7 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
int xflags = handler->flags;
struct xfs_inode *ip = XFS_I(inode);
int error;
+ size_t namelen = strlen(name);
/* Convert Linux syscall to XFS internal ATTR flags */
if (flags & XATTR_CREATE)
@@ -89,8 +92,9 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
xflags |= ATTR_REPLACE;
if (!value)
- return xfs_attr_remove(ip, (unsigned char *)name, xflags);
- error = xfs_attr_set(ip, (unsigned char *)name,
+ return xfs_attr_remove(ip, 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] 72+ messages in thread
* [PATCH 08/21] xfs: get directory offset when adding directory name
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (6 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 07/21] xfs: Remove all strlen calls in all xfs_attr_* functions for attr names Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 22:50 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 09/21] xfs: get directory offset when removing " Allison Henderson
` (13 subsequent siblings)
21 siblings, 1 reply; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
From: Mark Tinguely <tinguely@sgi.com>
Return the directory offset information when adding an entry to the
directory.
This offset will be used as the parent pointer offset in xfs_create,
xfs_symlink, xfs_link and xfs_rename.
[dchinner: forward ported and cleaned up]
[dchinner: no s-o-b from Mark]
[bfoster: rebased, use args->geo in dir code]
[achender: rebased, chaged __uint32_t to xfs_dir2_dataptr_t]
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/libxfs/xfs_da_btree.h | 1 +
fs/xfs/libxfs/xfs_dir2.c | 9 +++++++--
fs/xfs/libxfs/xfs_dir2.h | 3 ++-
fs/xfs/libxfs/xfs_dir2_block.c | 1 +
fs/xfs/libxfs/xfs_dir2_leaf.c | 2 ++
fs/xfs/libxfs/xfs_dir2_node.c | 2 ++
fs/xfs/libxfs/xfs_dir2_sf.c | 2 ++
fs/xfs/xfs_inode.c | 9 +++++----
fs/xfs/xfs_symlink.c | 2 +-
9 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
index ae6de17..bce96d6 100644
--- a/fs/xfs/libxfs/xfs_da_btree.h
+++ b/fs/xfs/libxfs/xfs_da_btree.h
@@ -86,6 +86,7 @@ typedef struct xfs_da_args {
int rmtvaluelen2; /* remote attr value length in bytes */
int op_flags; /* operation flags */
enum xfs_dacmp cmpresult; /* name compare result for lookups */
+ xfs_dir2_dataptr_t offset; /* OUT: offset in directory */
} xfs_da_args_t;
/*
diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
index 92f94e1..409a1e7 100644
--- a/fs/xfs/libxfs/xfs_dir2.c
+++ b/fs/xfs/libxfs/xfs_dir2.c
@@ -257,7 +257,8 @@ xfs_dir_createname(
xfs_ino_t inum, /* new entry inode number */
xfs_fsblock_t *first, /* bmap's firstblock */
struct xfs_defer_ops *dfops, /* bmap's freeblock list */
- xfs_extlen_t total) /* bmap's total block count */
+ xfs_extlen_t total, /* bmap's total block count */
+ xfs_dir2_dataptr_t *offset) /* OUT entry's dir offset */
{
struct xfs_da_args *args;
int rval;
@@ -313,6 +314,10 @@ xfs_dir_createname(
rval = xfs_dir2_node_addname(args);
out_free:
+ /* return the location that this entry was place in the parent inode */
+ if (offset)
+ *offset = args->offset;
+
kmem_free(args);
return rval;
}
@@ -559,7 +564,7 @@ xfs_dir_canenter(
xfs_inode_t *dp,
struct xfs_name *name) /* name of entry to add */
{
- return xfs_dir_createname(tp, dp, name, 0, NULL, NULL, 0);
+ return xfs_dir_createname(tp, dp, name, 0, NULL, NULL, 0, NULL);
}
/*
diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
index 989e95a..c98a3ca 100644
--- a/fs/xfs/libxfs/xfs_dir2.h
+++ b/fs/xfs/libxfs/xfs_dir2.h
@@ -131,7 +131,8 @@ extern int xfs_dir_init(struct xfs_trans *tp, struct xfs_inode *dp,
extern int xfs_dir_createname(struct xfs_trans *tp, struct xfs_inode *dp,
struct xfs_name *name, xfs_ino_t inum,
xfs_fsblock_t *first,
- struct xfs_defer_ops *dfops, xfs_extlen_t tot);
+ struct xfs_defer_ops *dfops, xfs_extlen_t tot,
+ xfs_dir2_dataptr_t *offset);
extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
struct xfs_name *name, xfs_ino_t *inum,
struct xfs_name *ci_name);
diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
index 875893d..9b7f173 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -559,6 +559,7 @@ xfs_dir2_block_addname(
dp->d_ops->data_put_ftype(dep, args->filetype);
tagp = dp->d_ops->data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)hdr);
+ args->offset = xfs_dir2_byte_to_dataptr((char *)dep - (char *)hdr);
/*
* Clean up the bestfree array and log the header, tail, and entry.
*/
diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
index 50fc9c0..8ae2953 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -894,6 +894,8 @@ xfs_dir2_leaf_addname(
dp->d_ops->data_put_ftype(dep, args->filetype);
tagp = dp->d_ops->data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)hdr);
+ args->offset = xfs_dir2_db_off_to_dataptr(args->geo, use_block,
+ (char *)dep - (char *)hdr);
/*
* Need to scan fix up the bestfree table.
*/
diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
index 9df096c..4e544f7 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -2041,6 +2041,8 @@ xfs_dir2_node_addname_int(
dp->d_ops->data_put_ftype(dep, args->filetype);
tagp = dp->d_ops->data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)hdr);
+ args->offset = xfs_dir2_db_off_to_dataptr(args->geo, dbno,
+ (char *)dep - (char *)hdr);
xfs_dir2_data_log_entry(args, dbp, dep);
/*
* Rescan the block for bestfree if needed.
diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
index 0c75a7f..222ccf5 100644
--- a/fs/xfs/libxfs/xfs_dir2_sf.c
+++ b/fs/xfs/libxfs/xfs_dir2_sf.c
@@ -405,6 +405,7 @@ xfs_dir2_sf_addname_easy(
memcpy(sfep->name, args->name, sfep->namelen);
dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
dp->d_ops->sf_put_ftype(sfep, args->filetype);
+ args->offset = xfs_dir2_byte_to_dataptr(offset);
/*
* Update the header and inode.
@@ -496,6 +497,7 @@ xfs_dir2_sf_addname_hard(
memcpy(sfep->name, args->name, sfep->namelen);
dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
dp->d_ops->sf_put_ftype(sfep, args->filetype);
+ args->offset = xfs_dir2_byte_to_dataptr(offset);
sfp->count++;
if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)
sfp->i8count++;
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 2b70c8b..fc07b4f 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1226,7 +1226,8 @@ xfs_create(
error = xfs_dir_createname(tp, dp, name, ip->i_ino,
&first_block, &dfops, resblks ?
- resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
+ resblks - XFS_IALLOC_SPACE_RES(mp) : 0,
+ NULL);
if (error) {
ASSERT(error != -ENOSPC);
goto out_trans_cancel;
@@ -1462,7 +1463,7 @@ xfs_link(
}
error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
- &first_block, &dfops, resblks);
+ &first_block, &dfops, resblks, NULL);
if (error)
goto error_return;
xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
@@ -3040,8 +3041,8 @@ xfs_rename(
* to account for the ".." reference from the new entry.
*/
error = xfs_dir_createname(tp, target_dp, target_name,
- src_ip->i_ino, &first_block,
- &dfops, spaceres);
+ src_ip->i_ino, &first_block, &dfops,
+ spaceres, NULL);
if (error)
goto out_bmap_cancel;
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
index 5b66ac1..b1d3301 100644
--- a/fs/xfs/xfs_symlink.c
+++ b/fs/xfs/xfs_symlink.c
@@ -350,7 +350,7 @@ xfs_symlink(
* Create the directory entry for the symlink.
*/
error = xfs_dir_createname(tp, dp, link_name, ip->i_ino,
- &first_block, &dfops, resblks);
+ &first_block, &dfops, resblks, NULL);
if (error)
goto out_bmap_cancel;
xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 09/21] xfs: get directory offset when removing directory name
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (7 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 08/21] xfs: get directory offset when adding directory name Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 22:48 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 10/21] xfs: get directory offset when replacing a " Allison Henderson
` (12 subsequent siblings)
21 siblings, 1 reply; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
From: Mark Tinguely <tinguely@sgi.com>
Return the directory offset information when removing an entry to the
directory.
This offset will be used as the parent pointer offset in xfs_remove.
[dchinner: forward ported and cleaned up]
[achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
Changed typedefs to raw struct types]
Signed-off-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/libxfs/xfs_dir2.c | 16 ++++++++++------
fs/xfs/libxfs/xfs_dir2.h | 4 +++-
fs/xfs/libxfs/xfs_dir2_block.c | 4 ++--
fs/xfs/libxfs/xfs_dir2_leaf.c | 5 +++--
fs/xfs/libxfs/xfs_dir2_node.c | 5 +++--
fs/xfs/libxfs/xfs_dir2_sf.c | 2 ++
fs/xfs/xfs_inode.c | 7 ++++---
7 files changed, 27 insertions(+), 16 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
index 409a1e7..090ab0e 100644
--- a/fs/xfs/libxfs/xfs_dir2.c
+++ b/fs/xfs/libxfs/xfs_dir2.c
@@ -433,13 +433,14 @@ xfs_dir_lookup(
*/
int
xfs_dir_removename(
- xfs_trans_t *tp,
- xfs_inode_t *dp,
- struct xfs_name *name,
- xfs_ino_t ino,
- xfs_fsblock_t *first, /* bmap's firstblock */
+ struct xfs_trans *tp,
+ struct xfs_inode *dp,
+ struct xfs_name *name,
+ xfs_ino_t ino,
+ xfs_fsblock_t *first, /* bmap's firstblock */
struct xfs_defer_ops *dfops, /* bmap's freeblock list */
- xfs_extlen_t total) /* bmap's total block count */
+ xfs_extlen_t total, /* bmap's total block count */
+ xfs_dir2_dataptr_t *offset) /* OUT: offset in directory */
{
struct xfs_da_args *args;
int rval;
@@ -486,6 +487,9 @@ xfs_dir_removename(
else
rval = xfs_dir2_node_removename(args);
out_free:
+ if (offset)
+ *offset = args->offset;
+
kmem_free(args);
return rval;
}
diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
index c98a3ca..b73bdcb 100644
--- a/fs/xfs/libxfs/xfs_dir2.h
+++ b/fs/xfs/libxfs/xfs_dir2.h
@@ -139,7 +139,9 @@ extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
struct xfs_name *name, xfs_ino_t ino,
xfs_fsblock_t *first,
- struct xfs_defer_ops *dfops, xfs_extlen_t tot);
+ struct xfs_defer_ops *dfops,
+ xfs_extlen_t tot,
+ xfs_dir2_dataptr_t *offset);
extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
struct xfs_name *name, xfs_ino_t inum,
xfs_fsblock_t *first,
diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
index 9b7f173..9c1e485 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -798,9 +798,9 @@ xfs_dir2_block_removename(
/*
* Point to the data entry using the leaf entry.
*/
+ args->offset = be32_to_cpu(blp[ent].address);
dep = (xfs_dir2_data_entry_t *)((char *)hdr +
- xfs_dir2_dataptr_to_off(args->geo,
- be32_to_cpu(blp[ent].address)));
+ xfs_dir2_dataptr_to_off(args->geo, args->offset));
/*
* Mark the data entry's space free.
*/
diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
index 8ae2953..c5595c1 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -1414,9 +1414,10 @@ xfs_dir2_leaf_removename(
* Point to the leaf entry, use that to point to the data entry.
*/
lep = &ents[index];
- db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address));
+ args->offset = be32_to_cpu(lep->address);
+ db = xfs_dir2_dataptr_to_db(args->geo, args->offset);
dep = (xfs_dir2_data_entry_t *)((char *)hdr +
- xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address)));
+ xfs_dir2_dataptr_to_off(args->geo, args->offset));
needscan = needlog = 0;
oldbest = be16_to_cpu(bf[0].length);
ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
index 4e544f7..eb8b240 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -1252,9 +1252,10 @@ xfs_dir2_leafn_remove(
/*
* Extract the data block and offset from the entry.
*/
- db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address));
+ args->offset = be32_to_cpu(lep->address);
+ db = xfs_dir2_dataptr_to_db(args->geo, args->offset);
ASSERT(dblk->blkno == db);
- off = xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address));
+ off = xfs_dir2_dataptr_to_off(args->geo, args->offset);
ASSERT(dblk->index == off);
/*
diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
index 222ccf5..1d0957c 100644
--- a/fs/xfs/libxfs/xfs_dir2_sf.c
+++ b/fs/xfs/libxfs/xfs_dir2_sf.c
@@ -917,6 +917,8 @@ xfs_dir2_sf_removename(
XFS_CMP_EXACT) {
ASSERT(dp->d_ops->sf_get_ino(sfp, sfep) ==
args->inumber);
+ args->offset = xfs_dir2_byte_to_dataptr(
+ xfs_dir2_sf_get_offset(sfep));
break;
}
}
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index fc07b4f..3054e9a 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2648,8 +2648,8 @@ xfs_remove(
goto out_trans_cancel;
xfs_defer_init(&dfops, &first_block);
- error = xfs_dir_removename(tp, dp, name, ip->i_ino,
- &first_block, &dfops, resblks);
+ error = xfs_dir_removename(tp, dp, name, ip->i_ino, &first_block,
+ &dfops, resblks, NULL);
if (error) {
ASSERT(error != -ENOENT);
goto out_bmap_cancel;
@@ -3159,7 +3159,8 @@ xfs_rename(
&first_block, &dfops, spaceres);
} else
error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
- &first_block, &dfops, spaceres);
+ &first_block, &dfops, spaceres,
+ NULL);
if (error)
goto out_bmap_cancel;
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 10/21] xfs: get directory offset when replacing a directory name
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (8 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 09/21] xfs: get directory offset when removing " Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 22:45 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 11/21] xfs: add parent pointer support to attribute code Allison Henderson
` (11 subsequent siblings)
21 siblings, 1 reply; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
From: Mark Tinguely <tinguely@sgi.com>
Return the directory offset information when replacing an entry to the
directory.
This offset will be used as the parent pointer offset in xfs_rename.
[dchinner: forward ported and cleaned up]
[achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
Changed typedefs to raw struct types]
Signed-off-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/libxfs/xfs_dir2.c | 16 ++++++++++------
fs/xfs/libxfs/xfs_dir2.h | 3 ++-
fs/xfs/libxfs/xfs_dir2_block.c | 4 ++--
fs/xfs/libxfs/xfs_dir2_leaf.c | 1 +
fs/xfs/libxfs/xfs_dir2_node.c | 1 +
fs/xfs/libxfs/xfs_dir2_sf.c | 2 ++
fs/xfs/xfs_inode.c | 28 +++++++++++++---------------
7 files changed, 31 insertions(+), 24 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
index 090ab0e..a4f7bcd 100644
--- a/fs/xfs/libxfs/xfs_dir2.c
+++ b/fs/xfs/libxfs/xfs_dir2.c
@@ -499,13 +499,14 @@ xfs_dir_removename(
*/
int
xfs_dir_replace(
- xfs_trans_t *tp,
- xfs_inode_t *dp,
- struct xfs_name *name, /* name of entry to replace */
- xfs_ino_t inum, /* new inode number */
- xfs_fsblock_t *first, /* bmap's firstblock */
+ struct xfs_trans *tp,
+ struct xfs_inode *dp,
+ struct xfs_name *name, /* name of entry to replace */
+ xfs_ino_t inum, /* new inode number */
+ xfs_fsblock_t *first, /* bmap's firstblock */
struct xfs_defer_ops *dfops, /* bmap's freeblock list */
- xfs_extlen_t total) /* bmap's total block count */
+ xfs_extlen_t total, /* bmap's total block count */
+ xfs_dir2_dataptr_t *offset) /* OUT: offset in directory */
{
struct xfs_da_args *args;
int rval;
@@ -555,6 +556,9 @@ xfs_dir_replace(
else
rval = xfs_dir2_node_replace(args);
out_free:
+ if (offset)
+ *offset = args->offset;
+
kmem_free(args);
return rval;
}
diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
index b73bdcb..d361442 100644
--- a/fs/xfs/libxfs/xfs_dir2.h
+++ b/fs/xfs/libxfs/xfs_dir2.h
@@ -145,7 +145,8 @@ extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
struct xfs_name *name, xfs_ino_t inum,
xfs_fsblock_t *first,
- struct xfs_defer_ops *dfops, xfs_extlen_t tot);
+ struct xfs_defer_ops *dfops, xfs_extlen_t tot,
+ xfs_dir2_dataptr_t *offset);
extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp,
struct xfs_name *name);
diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
index 9c1e485..77744e5 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -872,9 +872,9 @@ xfs_dir2_block_replace(
/*
* Point to the data entry we need to change.
*/
+ args->offset = be32_to_cpu(blp[ent].address);
dep = (xfs_dir2_data_entry_t *)((char *)hdr +
- xfs_dir2_dataptr_to_off(args->geo,
- be32_to_cpu(blp[ent].address)));
+ xfs_dir2_dataptr_to_off(args->geo, args->offset));
ASSERT(be64_to_cpu(dep->inumber) != args->inumber);
/*
* Change the inode number to the new value.
diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
index c5595c1..6ad7741 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -1550,6 +1550,7 @@ xfs_dir2_leaf_replace(
/*
* Point to the data entry.
*/
+ args->offset = be32_to_cpu(lep->address);
dep = (xfs_dir2_data_entry_t *)
((char *)dbp->b_addr +
xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address)));
diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
index eb8b240..ccf220a 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -2256,6 +2256,7 @@ xfs_dir2_node_replace(
hdr = state->extrablk.bp->b_addr;
ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC));
+ args->offset = be32_to_cpu(lep->address);
dep = (xfs_dir2_data_entry_t *)
((char *)hdr +
xfs_dir2_dataptr_to_off(args->geo,
diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
index 1d0957c..73f1eef 100644
--- a/fs/xfs/libxfs/xfs_dir2_sf.c
+++ b/fs/xfs/libxfs/xfs_dir2_sf.c
@@ -1043,6 +1043,8 @@ xfs_dir2_sf_replace(
ASSERT(args->inumber != ino);
dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
dp->d_ops->sf_put_ftype(sfep, args->filetype);
+ args->offset = xfs_dir2_byte_to_dataptr(
+ xfs_dir2_sf_get_offset(sfep));
break;
}
}
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 3054e9a..5c291d2 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2783,16 +2783,14 @@ xfs_cross_rename(
int dp2_flags = 0;
/* Swap inode number for dirent in first parent */
- error = xfs_dir_replace(tp, dp1, name1,
- ip2->i_ino,
- first_block, dfops, spaceres);
+ error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, first_block, dfops,
+ spaceres, NULL);
if (error)
goto out_trans_abort;
/* Swap inode number for dirent in second parent */
- error = xfs_dir_replace(tp, dp2, name2,
- ip1->i_ino,
- first_block, dfops, spaceres);
+ error = xfs_dir_replace(tp, dp2, name2, ip1->i_ino, first_block, dfops,
+ spaceres, NULL);
if (error)
goto out_trans_abort;
@@ -2806,8 +2804,8 @@ xfs_cross_rename(
if (S_ISDIR(VFS_I(ip2)->i_mode)) {
error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot,
- dp1->i_ino, first_block,
- dfops, spaceres);
+ dp1->i_ino, first_block, dfops,
+ spaceres, NULL);
if (error)
goto out_trans_abort;
@@ -2833,8 +2831,8 @@ xfs_cross_rename(
if (S_ISDIR(VFS_I(ip1)->i_mode)) {
error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot,
- dp2->i_ino, first_block,
- dfops, spaceres);
+ dp2->i_ino, first_block, dfops,
+ spaceres, NULL);
if (error)
goto out_trans_abort;
@@ -3081,8 +3079,8 @@ xfs_rename(
* name at the destination directory, remove it first.
*/
error = xfs_dir_replace(tp, target_dp, target_name,
- src_ip->i_ino,
- &first_block, &dfops, spaceres);
+ src_ip->i_ino, &first_block, &dfops,
+ spaceres, NULL);
if (error)
goto out_bmap_cancel;
@@ -3116,8 +3114,8 @@ xfs_rename(
* directory.
*/
error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,
- target_dp->i_ino,
- &first_block, &dfops, spaceres);
+ target_dp->i_ino, &first_block, &dfops,
+ spaceres, NULL);
ASSERT(error != -EEXIST);
if (error)
goto out_bmap_cancel;
@@ -3156,7 +3154,7 @@ xfs_rename(
*/
if (wip) {
error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino,
- &first_block, &dfops, spaceres);
+ &first_block, &dfops, spaceres, NULL);
} else
error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
&first_block, &dfops, spaceres,
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 11/21] xfs: add parent pointer support to attribute code
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (9 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 10/21] xfs: get directory offset when replacing a " Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 22:36 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 12/21] xfs: define parent pointer xattr format Allison Henderson
` (10 subsequent siblings)
21 siblings, 1 reply; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
From: Mark Tinguely <tinguely@sgi.com>
Add the new parent attribute type. XFS_ATTR_PARENT is used only for
parent pointer entries; it uses reserved blocks like XFS_ATTR_ROOT.
[dchinner: forward ported and cleaned up]
[achender: rebased]
Signed-off-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/libxfs/xfs_attr.c | 2 +-
fs/xfs/libxfs/xfs_attr.h | 2 ++
fs/xfs/libxfs/xfs_da_format.h | 12 ++++++++----
3 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 484fa86..41b31dc 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -377,7 +377,7 @@ xfs_attr_set(
struct xfs_defer_ops dfops;
struct xfs_trans_res tres;
xfs_fsblock_t firstblock;
- int rsvd = (flags & ATTR_ROOT) != 0;
+ bool rsvd = (flags & (ATTR_ROOT | ATTR_PARENT)) != 0;
int error, local;
XFS_STATS_INC(mp, xs_attr_set);
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 308a93e..d041734 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -46,6 +46,7 @@ struct xfs_attr_list_context;
#define ATTR_SECURE 0x0008 /* use attrs in security namespace */
#define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */
#define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */
+#define ATTR_PARENT 0x0040 /* use attrs in parent namespace */
#define ATTR_KERNOTIME 0x1000 /* [kernel] don't update inode timestamps */
#define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */
@@ -59,6 +60,7 @@ struct xfs_attr_list_context;
{ ATTR_SECURE, "SECURE" }, \
{ ATTR_CREATE, "CREATE" }, \
{ ATTR_REPLACE, "REPLACE" }, \
+ { ATTR_PARENT, "PARENT" }, \
{ ATTR_KERNOTIME, "KERNOTIME" }, \
{ ATTR_KERNOVAL, "KERNOVAL" }, \
{ ATTR_INCOMPLETE, "INCOMPLETE" }
diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h
index 7e77299..9bd2e6b 100644
--- a/fs/xfs/libxfs/xfs_da_format.h
+++ b/fs/xfs/libxfs/xfs_da_format.h
@@ -758,24 +758,28 @@ struct xfs_attr3_icleaf_hdr {
#define XFS_ATTR_LOCAL_BIT 0 /* attr is stored locally */
#define XFS_ATTR_ROOT_BIT 1 /* limit access to trusted attrs */
#define XFS_ATTR_SECURE_BIT 2 /* limit access to secure attrs */
+#define XFS_ATTR_PARENT_BIT 3 /* parent pointer secure attrs */
#define XFS_ATTR_INCOMPLETE_BIT 7 /* attr in middle of create/delete */
#define XFS_ATTR_LOCAL (1 << XFS_ATTR_LOCAL_BIT)
#define XFS_ATTR_ROOT (1 << XFS_ATTR_ROOT_BIT)
#define XFS_ATTR_SECURE (1 << XFS_ATTR_SECURE_BIT)
+#define XFS_ATTR_PARENT (1 << XFS_ATTR_PARENT_BIT)
#define XFS_ATTR_INCOMPLETE (1 << XFS_ATTR_INCOMPLETE_BIT)
/*
* Conversion macros for converting namespace bits from argument flags
* to ondisk flags.
*/
-#define XFS_ATTR_NSP_ARGS_MASK (ATTR_ROOT | ATTR_SECURE)
-#define XFS_ATTR_NSP_ONDISK_MASK (XFS_ATTR_ROOT | XFS_ATTR_SECURE)
+#define XFS_ATTR_NSP_ARGS_MASK (ATTR_ROOT | ATTR_SECURE | XFS_ATTR_PARENT)
+#define XFS_ATTR_NSP_ONDISK_MASK (XFS_ATTR_ROOT | XFS_ATTR_SECURE | XFS_ATTR_PARENT)
#define XFS_ATTR_NSP_ONDISK(flags) ((flags) & XFS_ATTR_NSP_ONDISK_MASK)
#define XFS_ATTR_NSP_ARGS(flags) ((flags) & XFS_ATTR_NSP_ARGS_MASK)
#define XFS_ATTR_NSP_ARGS_TO_ONDISK(x) (((x) & ATTR_ROOT ? XFS_ATTR_ROOT : 0) |\
- ((x) & ATTR_SECURE ? XFS_ATTR_SECURE : 0))
+ ((x) & ATTR_SECURE ? XFS_ATTR_SECURE : 0) | \
+ ((x) & ATTR_PARENT ? XFS_ATTR_PARENT : 0))
#define XFS_ATTR_NSP_ONDISK_TO_ARGS(x) (((x) & XFS_ATTR_ROOT ? ATTR_ROOT : 0) |\
- ((x) & XFS_ATTR_SECURE ? ATTR_SECURE : 0))
+ ((x) & XFS_ATTR_SECURE ? ATTR_SECURE : 0) | \
+ ((x) & XFS_ATTR_PARENT ? ATTR_PARENT : 0))
/*
* Alignment for namelist and valuelist entries (since they are mixed
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 12/21] xfs: define parent pointer xattr format
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (10 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 11/21] xfs: add parent pointer support to attribute code Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 22:35 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 13/21] xfs: extent transaction reservations for parent attributes Allison Henderson
` (9 subsequent siblings)
21 siblings, 1 reply; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
From: Dave Chinner <dchinner@redhat.com>
We need to define the parent pointer attribute format before we
start adding support for it into all the code that needs to use it.
The EA format we will use encodes the following information:
name={parent inode #, parent inode generation, dirent offset}
value={dirent filename}
The inode/gen gives all the information we need to reliably identify
the parent without requiring child->parent lock ordering, and allows
userspace to do pathname component level reconstruction without the
kernel ever needing to verify the parent itself as part of ioctl
calls.
By using the dirent offset in the EA name, we have a method of
knowing the exact parent pointer EA we need to modify/remove in
rename/unlink without an unbound EA name search.
By keeping the dirent name in the value, we have enough information
to be able to validate and reconstruct damaged directory trees.
While the diroffset of a filename alone is not unique enough to
identify the child, the {diroffset,filename,child_inode} tuple is
sufficient. That is, if the diroffset gets reused and points to a
different filename, we can detect that from the contents of EA. If a
link of the same name is created, then we can check whether it
points at the same inode as the parent EA we current have.
[achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
changed p_ino to xfs_ino_t and p_namelen to uint8_t,
moved to xfs_da_format for xfs_dir2_dataptr_t]
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong<darrick.wong@oracle.com>
---
fs/xfs/libxfs/xfs_da_format.h | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h
index 9bd2e6b..d1c1221 100644
--- a/fs/xfs/libxfs/xfs_da_format.h
+++ b/fs/xfs/libxfs/xfs_da_format.h
@@ -878,11 +878,35 @@ struct xfs_attr3_rmt_hdr {
#define XFS_ATTR3_RMT_BUF_SPACE(mp, bufsize) \
((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \
sizeof(struct xfs_attr3_rmt_hdr) : 0))
-
/* Number of bytes in a directory block. */
static inline unsigned int xfs_dir2_dirblock_bytes(struct xfs_sb *sbp)
{
return 1 << (sbp->sb_blocklog + sbp->sb_dirblklog);
}
+/*
+ * Parent pointer attribute format definition
+ *
+ * EA name encodes the parent inode number, generation and the offset of
+ * the dirent that points to the child inode. The EA value contains the
+ * same name as the dirent in the parent directory.
+ */
+struct xfs_parent_name_rec {
+ __be64 p_ino;
+ __be32 p_gen;
+ __be32 p_diroffset;
+};
+
+/*
+ * incore version of the above, also contains name pointers so callers
+ * can pass/obtain all the parent pointer information in a single structure
+ */
+struct xfs_parent_name_irec {
+ xfs_ino_t p_ino;
+ uint32_t p_gen;
+ xfs_dir2_dataptr_t p_diroffset;
+ const char *p_name;
+ uint8_t p_namelen;
+};
+
#endif /* __XFS_DA_FORMAT_H__ */
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 13/21] xfs: extent transaction reservations for parent attributes
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (11 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 12/21] xfs: define parent pointer xattr format Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 22:34 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 14/21] Add lock_flags to xfs_ialloc and xfs_dir_ialloc Allison Henderson
` (8 subsequent siblings)
21 siblings, 1 reply; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
From: Dave Chinner <dchinner@redhat.com>
We need to add, remove or modify parent pointer attributes during
create/link/unlink/rename operations atomically with the dirents in the parent
directories being modified. This means they need to be modified in the same
transaction as the parent directories, and so we need to add the required
space for the attribute modifications to the transaction reservations.
[achender: rebased, added xfs_sb_version_hasparent stub]
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/libxfs/xfs_format.h | 5 ++
fs/xfs/libxfs/xfs_trans_resv.c | 111 ++++++++++++++++++++++++++++++++---------
fs/xfs/libxfs/xfs_trans_resv.h | 1 +
3 files changed, 94 insertions(+), 23 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 42956d8..5e946c8 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -559,6 +559,11 @@ static inline bool xfs_sb_version_hasreflink(struct xfs_sb *sbp)
(sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_REFLINK);
}
+static inline bool xfs_sb_version_hasparent(struct xfs_sb *sbp)
+{
+ return false; /* We'll enable this at the end of the set */
+}
+
/*
* end of superblock version macros
*/
diff --git a/fs/xfs/libxfs/xfs_trans_resv.c b/fs/xfs/libxfs/xfs_trans_resv.c
index 3bccdf7..76440fb 100644
--- a/fs/xfs/libxfs/xfs_trans_resv.c
+++ b/fs/xfs/libxfs/xfs_trans_resv.c
@@ -787,29 +787,30 @@ xfs_calc_sb_reservation(
return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize);
}
+/*
+ * Namespace reservations.
+ *
+ * These get tricky when parent pointers are enabled as we have attribute
+ * modifications occurring from within these transactions. Rather than confuse
+ * each of these reservation calculations with the conditional attribute
+ * reservations, add them here in a clear and concise manner. This assumes that
+ * the attribute reservations have already been calculated.
+ *
+ * Note that we only include the static attribute reservation here; the runtime
+ * reservation will have to be modified by the size of the attributes being
+ * added/removed/modified. See the comments on the attribute reservation
+ * calculations for more details.
+ *
+ * Note for rename: rename will vastly overestimate requirements. This will be
+ * addressed later when modifications are made to ensure parent attribute
+ * modifications can be done atomically with the rename operation.
+ */
void
-xfs_trans_resv_calc(
+xfs_calc_namespace_reservations(
struct xfs_mount *mp,
struct xfs_trans_resv *resp)
{
- /*
- * The following transactions are logged in physical format and
- * require a permanent reservation on space.
- */
- resp->tr_write.tr_logres = xfs_calc_write_reservation(mp);
- if (xfs_sb_version_hasreflink(&mp->m_sb))
- resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK;
- else
- resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT;
- resp->tr_write.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
-
- resp->tr_itruncate.tr_logres = xfs_calc_itruncate_reservation(mp);
- if (xfs_sb_version_hasreflink(&mp->m_sb))
- resp->tr_itruncate.tr_logcount =
- XFS_ITRUNCATE_LOG_COUNT_REFLINK;
- else
- resp->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT;
- resp->tr_itruncate.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+ ASSERT(resp->tr_attrsetm.tr_logres > 0);
resp->tr_rename.tr_logres = xfs_calc_rename_reservation(mp);
resp->tr_rename.tr_logcount = XFS_RENAME_LOG_COUNT;
@@ -831,15 +832,77 @@ xfs_trans_resv_calc(
resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT;
resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+ resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp);
+ resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT;
+ resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+ xfs_calc_parent_ptr_reservations(mp);
+}
+
+void xfs_calc_parent_ptr_reservations(struct xfs_mount *mp)
+{
+ struct xfs_trans_resv *resp = M_RES(mp);
+
+ /* Calculate extra space needed for parent pointer attributes */
+ if (!xfs_sb_version_hasparent(&mp->m_sb))
+ return;
+
+ /* rename can add/remove/modify 2 parent attributes */
+ resp->tr_rename.tr_logres += 2 * max(resp->tr_attrsetm.tr_logres,
+ resp->tr_attrrm.tr_logres);
+ resp->tr_rename.tr_logcount += 2 * max(resp->tr_attrsetm.tr_logcount,
+ resp->tr_attrrm.tr_logcount);
+
+ /* create will add 1 parent attribute */
+ resp->tr_create.tr_logres += resp->tr_attrsetm.tr_logres;
+ resp->tr_create.tr_logcount += resp->tr_attrsetm.tr_logcount;
+
+ /* mkdir will add 1 parent attribute */
+ resp->tr_mkdir.tr_logres += resp->tr_attrsetm.tr_logres;
+ resp->tr_mkdir.tr_logcount += resp->tr_attrsetm.tr_logcount;
+
+ /* link will add 1 parent attribute */
+ resp->tr_link.tr_logres += resp->tr_attrsetm.tr_logres;
+ resp->tr_link.tr_logcount += resp->tr_attrsetm.tr_logcount;
+
+ /* symlink will add 1 parent attribute */
+ resp->tr_symlink.tr_logres += resp->tr_attrsetm.tr_logres;
+ resp->tr_symlink.tr_logcount += resp->tr_attrsetm.tr_logcount;
+
+ /* remove will remove 1 parent attribute */
+ resp->tr_remove.tr_logres += resp->tr_attrrm.tr_logres;
+ resp->tr_remove.tr_logcount += resp->tr_attrrm.tr_logcount;
+}
+
+void
+xfs_trans_resv_calc(
+ struct xfs_mount *mp,
+ struct xfs_trans_resv *resp)
+{
+ /*
+ * The following transactions are logged in physical format and
+ * require a permanent reservation on space.
+ */
+ resp->tr_write.tr_logres = xfs_calc_write_reservation(mp);
+ if (xfs_sb_version_hasreflink(&mp->m_sb))
+ resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK;
+ else
+ resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT;
+ resp->tr_write.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+ resp->tr_itruncate.tr_logres = xfs_calc_itruncate_reservation(mp);
+ if (xfs_sb_version_hasreflink(&mp->m_sb))
+ resp->tr_itruncate.tr_logcount =
+ XFS_ITRUNCATE_LOG_COUNT_REFLINK;
+ else
+ resp->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT;
+ resp->tr_itruncate.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
resp->tr_create_tmpfile.tr_logres =
xfs_calc_create_tmpfile_reservation(mp);
resp->tr_create_tmpfile.tr_logcount = XFS_CREATE_TMPFILE_LOG_COUNT;
resp->tr_create_tmpfile.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
- resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp);
- resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT;
- resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
-
resp->tr_ifree.tr_logres = xfs_calc_ifree_reservation(mp);
resp->tr_ifree.tr_logcount = XFS_INACTIVE_LOG_COUNT;
resp->tr_ifree.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
@@ -871,6 +934,8 @@ xfs_trans_resv_calc(
resp->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT;
resp->tr_qm_dqalloc.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+ xfs_calc_namespace_reservations(mp, resp);
+
/*
* The following transactions are logged in logical format with
* a default log count.
diff --git a/fs/xfs/libxfs/xfs_trans_resv.h b/fs/xfs/libxfs/xfs_trans_resv.h
index b7e5357..c7190d6 100644
--- a/fs/xfs/libxfs/xfs_trans_resv.h
+++ b/fs/xfs/libxfs/xfs_trans_resv.h
@@ -105,5 +105,6 @@ struct xfs_trans_resv {
void xfs_trans_resv_calc(struct xfs_mount *mp, struct xfs_trans_resv *resp);
uint xfs_allocfree_log_count(struct xfs_mount *mp, uint num_ops);
+void xfs_calc_parent_ptr_reservations(struct xfs_mount *mp);
#endif /* __XFS_TRANS_RESV_H__ */
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 14/21] Add lock_flags to xfs_ialloc and xfs_dir_ialloc
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (12 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 13/21] xfs: extent transaction reservations for parent attributes Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 22:30 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 15/21] xfs: parent pointer attribute creation Allison Henderson
` (7 subsequent siblings)
21 siblings, 1 reply; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
Add lock_flags to xfs_ialloc and xfs_dir_ialloc to control
whick locks are released by xfs_trans_ijoin. We will need this
later in defered parent pointers
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/xfs_inode.c | 17 +++++++++--------
fs/xfs/xfs_inode.h | 2 +-
fs/xfs/xfs_qm.c | 2 +-
fs/xfs/xfs_symlink.c | 2 +-
4 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 5c291d2..2859a697 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -766,7 +766,8 @@ xfs_ialloc(
dev_t rdev,
prid_t prid,
xfs_buf_t **ialloc_context,
- xfs_inode_t **ipp)
+ xfs_inode_t **ipp,
+ int lock_flags)
{
struct xfs_mount *mp = tp->t_mountp;
xfs_ino_t ino;
@@ -942,7 +943,7 @@ xfs_ialloc(
/*
* Log the new values stuffed into the inode.
*/
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin(tp, ip, lock_flags);
xfs_trans_log_inode(tp, ip, flags);
/* now that we have an i_mode we can setup the inode structure */
@@ -972,8 +973,8 @@ xfs_dir_ialloc(
xfs_nlink_t nlink,
dev_t rdev,
prid_t prid, /* project id */
- xfs_inode_t **ipp) /* pointer to inode; it will be
- locked. */
+ xfs_inode_t **ipp, /* pointer to inode; it will be locked. */
+ int lock_flags)
{
xfs_trans_t *tp;
xfs_inode_t *ip;
@@ -1001,7 +1002,7 @@ xfs_dir_ialloc(
* the inode(s) that we've just allocated.
*/
code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, &ialloc_context,
- &ip);
+ &ip, lock_flags);
/*
* Return an error if we were unable to allocate a new inode.
@@ -1071,7 +1072,7 @@ xfs_dir_ialloc(
* this call should always succeed.
*/
code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid,
- &ialloc_context, &ip);
+ &ialloc_context, &ip, lock_flags);
/*
* If we get an error at this point, return to the caller
@@ -1210,7 +1211,7 @@ xfs_create(
* entry pointing to them, but a directory also the "." entry
* pointing to itself.
*/
- error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, prid, &ip);
+ error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, prid, &ip, XFS_ILOCK_EXCL);
if (error)
goto out_trans_cancel;
@@ -1343,7 +1344,7 @@ xfs_create_tmpfile(
if (error)
goto out_trans_cancel;
- error = xfs_dir_ialloc(&tp, dp, mode, 1, 0, prid, &ip);
+ error = xfs_dir_ialloc(&tp, dp, mode, 1, 0, prid, &ip, XFS_ILOCK_EXCL);
if (error)
goto out_trans_cancel;
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 1eebc53..466f252 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -431,7 +431,7 @@ xfs_extlen_t xfs_get_cowextsz_hint(struct xfs_inode *ip);
int xfs_dir_ialloc(struct xfs_trans **, struct xfs_inode *, umode_t,
xfs_nlink_t, dev_t, prid_t,
- struct xfs_inode **);
+ struct xfs_inode **, int lock_flags);
/* from xfs_file.c */
enum xfs_prealloc_flags {
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index ec39ae2..3e68a52 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -787,7 +787,7 @@ xfs_qm_qino_alloc(
return error;
if (need_alloc) {
- error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, ip);
+ error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, ip, XFS_ILOCK_EXCL);
if (error) {
xfs_trans_cancel(tp);
return error;
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
index b1d3301..ce8dbea 100644
--- a/fs/xfs/xfs_symlink.c
+++ b/fs/xfs/xfs_symlink.c
@@ -264,7 +264,7 @@ xfs_symlink(
* Allocate an inode for the symlink.
*/
error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT), 1, 0,
- prid, &ip);
+ prid, &ip, XFS_ILOCK_EXCL);
if (error)
goto out_trans_cancel;
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 15/21] xfs: parent pointer attribute creation
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (13 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 14/21] Add lock_flags to xfs_ialloc and xfs_dir_ialloc Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 22:19 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 16/21] xfs: add parent attributes to link Allison Henderson
` (6 subsequent siblings)
21 siblings, 1 reply; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
From: Dave Chinner <dchinner@redhat.com>
Add parent pointer attribute during xfs_create, and
subroutines to initialize attributes
Kernel create routines take advantage of deferred attributes,
where as libxfs routines will add parent pointers directly.
[bfoster: rebase, use VFS inode generation]
[achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
fixed some null pointer bugs,
merged error handling patch,
added subroutines to handle attribute initialization,
remove unnecessary ENOSPC handling in xfs_attr_set_first_parent]
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/Makefile | 2 +
fs/xfs/libxfs/xfs_parent.c | 158 +++++++++++++++++++++++++++++++++++++++++++++
fs/xfs/libxfs/xfs_parent.h | 36 +++++++++++
fs/xfs/xfs_inode.c | 22 ++++++-
fs/xfs/xfs_parent_utils.c | 51 +++++++++++++++
fs/xfs/xfs_parent_utils.h | 26 ++++++++
6 files changed, 292 insertions(+), 3 deletions(-)
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index d3c0004..d092f72 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -53,6 +53,7 @@ xfs-y += $(addprefix libxfs/, \
xfs_inode_fork.o \
xfs_inode_buf.o \
xfs_log_rlimit.o \
+ xfs_parent.o \
xfs_ag_resv.o \
xfs_rmap.o \
xfs_rmap_btree.o \
@@ -92,6 +93,7 @@ xfs-y += xfs_aops.o \
xfs_message.o \
xfs_mount.o \
xfs_mru_cache.o \
+ xfs_parent_utils.o \
xfs_reflink.o \
xfs_stats.o \
xfs_super.o \
diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
new file mode 100644
index 0000000..e6de97c
--- /dev/null
+++ b/fs/xfs/libxfs/xfs_parent.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2015 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_format.h"
+#include "xfs_da_format.h"
+#include "xfs_log_format.h"
+#include "xfs_shared.h"
+#include "xfs_trans_resv.h"
+#include "xfs_mount.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_inode.h"
+#include "xfs_error.h"
+#include "xfs_trace.h"
+#include "xfs_trans.h"
+#include "xfs_attr.h"
+#include "xfs_da_btree.h"
+#include "xfs_attr_sf.h"
+#include "xfs_bmap.h"
+
+/*
+ * Parent pointer attribute handling.
+ *
+ * Because the attribute value is a filename component, it will never be longer
+ * than 255 bytes. This means the attribute will always be a local format
+ * attribute as it is xfs_attr_leaf_entsize_local_max() for v5 filesystems will
+ * always be larger than this (max is 75% of block size).
+ *
+ * Creating a new parent attribute will always create a new attribute - there
+ * should never, ever be an existing attribute in the tree for a new inode.
+ * ENOSPC behaviour is problematic - creating the inode without the parent
+ * pointer is effectively a corruption, so we allow parent attribute creation
+ * to dip into the reserve block pool to avoid unexpected ENOSPC errors from
+ * occurring.
+ */
+
+
+/* Initializes a xfs_parent_name_rec to be stored as an attribute name */
+void
+xfs_init_parent_name_rec(
+ struct xfs_parent_name_rec *rec,
+ xfs_ino_t p_ino,
+ uint32_t p_gen,
+ uint32_t p_diroffset)
+{
+ rec->p_ino = cpu_to_be64(p_ino);
+ rec->p_gen = cpu_to_be32(p_gen);
+ rec->p_diroffset = cpu_to_be32(p_diroffset);
+}
+
+/* Initializes a xfs_parent_name_irec from an xfs_parent_name_rec */
+void
+xfs_init_parent_name_irec(
+ struct xfs_parent_name_irec *irec,
+ struct xfs_parent_name_rec *rec)
+{
+ irec->p_ino = be64_to_cpu(rec->p_ino);
+ irec->p_gen = be32_to_cpu(rec->p_gen);
+ irec->p_diroffset = be32_to_cpu(rec->p_diroffset);
+}
+
+/*
+ * Directly add a parent pointer instead of as a deferred operation
+ * Currently only used during protofile creation
+ */
+int
+xfs_parent_add(
+ struct xfs_inode *parent,
+ struct xfs_inode *child,
+ struct xfs_name *child_name,
+ uint32_t diroffset,
+ xfs_fsblock_t *firstblock,
+ struct xfs_defer_ops *dfops)
+{
+ struct xfs_parent_name_rec rec;
+ int error;
+ struct xfs_da_args args;
+ int flags = ATTR_PARENT;
+ int local = 0;
+ int rsvd = 0;
+ struct xfs_buf *leaf_bp = NULL;
+ struct xfs_trans_res tres;
+ struct xfs_mount *mp = child->i_mount;
+
+ xfs_init_parent_name_rec(&rec, parent->i_ino,
+ VFS_I(parent)->i_generation, diroffset);
+
+ error = xfs_attr_args_init(&args, child, (const unsigned char *)&rec,
+ sizeof(rec), flags);
+ if (error)
+ return error;
+
+ args.hashval = xfs_da_hashname(args.name, args.namelen);
+ args.value = (char *)child_name->name;
+ args.valuelen = child_name->len;
+ args.dfops = dfops;
+ args.op_flags = XFS_DA_OP_OKNOENT | XFS_DA_OP_ADDNAME;
+ args.firstblock = firstblock;
+ args.total = xfs_attr_calc_size(&args, &local);
+ ASSERT(local);
+
+ tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
+ M_RES(mp)->tr_attrsetrt.tr_logres * args.total;
+ tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
+ tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
+
+ /*
+ * Root fork attributes can use reserved data blocks for this
+ * operation if necessary
+ */
+ error = xfs_trans_alloc(mp, &tres, args.total, 0,
+ rsvd ? XFS_TRANS_RESERVE : 0, &args.trans);
+ if (error)
+ goto out;
+
+ /*
+ * If the inode doesn't have an attribute fork, add one.
+ * (inode must not be locked when we call this routine)
+ */
+ if (XFS_IFORK_Q(child) == 0) {
+ int sf_size = sizeof(xfs_attr_sf_hdr_t) +
+ XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, args.valuelen);
+
+ error = xfs_bmap_add_attrfork(child, sf_size, rsvd);
+ if (error)
+ return error;
+ }
+
+ error = xfs_attr_set_args(&args, flags, leaf_bp, false);
+
+ if (error)
+ goto out;
+
+ xfs_trans_log_inode(args.trans, child, XFS_ILOG_CORE);
+
+ return error;
+
+out:
+ if (args.trans)
+ xfs_trans_cancel(args.trans);
+
+ return error;
+}
+
diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h
new file mode 100644
index 0000000..298562b
--- /dev/null
+++ b/fs/xfs/libxfs/xfs_parent.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Oracle, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation Inc.
+ */
+#ifndef __XFS_PARENT_H__
+#define __XFS_PARENT_H__
+
+#include "xfs_da_format.h"
+#include "xfs_format.h"
+
+/*
+ * Parent pointer attribute prototypes
+ */
+void xfs_init_parent_name_rec(struct xfs_parent_name_rec *rec,
+ xfs_ino_t p_ino, uint32_t p_gen,
+ uint32_t p_diroffset);
+void xfs_init_parent_name_irec(struct xfs_parent_name_irec *irec,
+ struct xfs_parent_name_rec *rec);
+
+int xfs_parent_add(struct xfs_trans *tp, struct xfs_inode *parent,
+ struct xfs_inode *child, struct xfs_name *child_name,
+ uint32_t diroffset, xfs_fsblock_t *firstblock,
+ struct xfs_defer_ops *dfops);
+#endif /* __XFS_PARENT_H__ */
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 2859a697..a515f11 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -53,6 +53,7 @@
#include "xfs_bmap_btree.h"
#include "xfs_reflink.h"
#include "xfs_dir2_priv.h"
+#include "xfs_parent_utils.h"
kmem_zone_t *xfs_inode_zone;
@@ -1152,6 +1153,7 @@ xfs_create(
struct xfs_dquot *pdqp = NULL;
struct xfs_trans_res *tres;
uint resblks;
+ xfs_dir2_dataptr_t diroffset;
trace_xfs_create(dp, name);
@@ -1211,7 +1213,7 @@ xfs_create(
* entry pointing to them, but a directory also the "." entry
* pointing to itself.
*/
- error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, prid, &ip, XFS_ILOCK_EXCL);
+ error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, prid, &ip, 0);
if (error)
goto out_trans_cancel;
@@ -1222,13 +1224,13 @@ xfs_create(
* the transaction cancel unlocking dp so don't do it explicitly in the
* error path.
*/
- xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin(tp, dp, 0);
unlock_dp_on_error = false;
error = xfs_dir_createname(tp, dp, name, ip->i_ino,
&first_block, &dfops, resblks ?
resblks - XFS_IALLOC_SPACE_RES(mp) : 0,
- NULL);
+ &diroffset);
if (error) {
ASSERT(error != -ENOSPC);
goto out_trans_cancel;
@@ -1247,6 +1249,17 @@ xfs_create(
}
/*
+ * If we have parent pointers, we need to add the attribute containing
+ * the parent information now.
+ */
+ if (xfs_sb_version_hasparent(&mp->m_sb)) {
+ error = xfs_parent_add_deferred(dp, ip, name, diroffset,
+ &dfops);
+ if (error)
+ goto out_bmap_cancel;
+ }
+
+ /*
* If this is a synchronous mount, make sure that the
* create transaction goes to disk before returning to
* the user.
@@ -1274,6 +1287,9 @@ xfs_create(
xfs_qm_dqrele(pdqp);
*ipp = ip;
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ xfs_iunlock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
+
return 0;
out_bmap_cancel:
diff --git a/fs/xfs/xfs_parent_utils.c b/fs/xfs/xfs_parent_utils.c
new file mode 100644
index 0000000..cf4a7e2
--- /dev/null
+++ b/fs/xfs/xfs_parent_utils.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_shared.h"
+#include "xfs_trans_resv.h"
+#include "xfs_mount.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_inode.h"
+#include "xfs_error.h"
+#include "xfs_trace.h"
+#include "xfs_trans.h"
+#include "xfs_attr.h"
+#include "xfs_parent.h"
+
+/*
+ * Add a parent record to an inode with existing parent records.
+ */
+int
+xfs_parent_add_deferred(
+ struct xfs_inode *parent,
+ struct xfs_inode *child,
+ struct xfs_name *child_name,
+ uint32_t diroffset,
+ struct xfs_defer_ops *dfops)
+{
+ struct xfs_parent_name_rec rec;
+
+ xfs_init_parent_name_rec(&rec, parent->i_ino,
+ VFS_I(parent)->i_generation, diroffset);
+
+ return xfs_attr_set_deferred(child, dfops, &rec, sizeof(rec),
+ (void *)child_name->name, child_name->len, ATTR_PARENT);
+}
+
diff --git a/fs/xfs/xfs_parent_utils.h b/fs/xfs/xfs_parent_utils.h
new file mode 100644
index 0000000..a667d1d
--- /dev/null
+++ b/fs/xfs/xfs_parent_utils.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017 Oracle, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation Inc.
+ */
+#ifndef __XFS_PARENT_UTILS_H__
+#define __XFS_PARENT_UTILS_H__
+
+/*
+ * Parent pointer attribute prototypes
+ */
+int xfs_parent_add_deferred(struct xfs_inode *parent, struct xfs_inode *child,
+ struct xfs_name *child_name, uint32_t diroffset,
+ struct xfs_defer_ops *dfops);
+#endif /* __XFS_PARENT_UTILS_H__ */
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 16/21] xfs: add parent attributes to link
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (14 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 15/21] xfs: parent pointer attribute creation Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 22:12 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 17/21] xfs: remove parent pointers in unlink Allison Henderson
` (5 subsequent siblings)
21 siblings, 1 reply; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
From: Dave Chinner <dchinner@redhat.com>
This patch modifies xfs_link to add a parent pointer to the inode.
xfs_link will also need to create an attribute fork if the inode does
not already have one.
[bfoster: rebase, use VFS inode fields, fix xfs_bmap_finish() usage]
[achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
fixed null pointer bugs]
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/xfs_inode.c | 66 ++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 52 insertions(+), 14 deletions(-)
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index a515f11..3a68e72 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1421,6 +1421,8 @@ xfs_link(
struct xfs_defer_ops dfops;
xfs_fsblock_t first_block;
int resblks;
+ xfs_dir2_dataptr_t diroffset;
+ bool first_parent = false;
trace_xfs_link(tdp, target_name);
@@ -1437,6 +1439,25 @@ xfs_link(
if (error)
goto std_return;
+ /*
+ * If we have parent pointers and there is no attribute fork (i.e. we
+ * are linking in a O_TMPFILE created inode) we need to add the
+ * attribute fork to the inode. Because we may have an existing data
+ * fork, we do this before we start the link transaction as adding an
+ * attribute fork requires it's own transaction.
+ */
+ if (xfs_sb_version_hasparent(&mp->m_sb) && !xfs_inode_hasattr(sip)) {
+ int sf_size = sizeof(struct xfs_attr_sf_hdr) +
+ XFS_ATTR_SF_ENTSIZE_BYNAME(
+ sizeof(struct xfs_parent_name_rec),
+ target_name->len);
+ ASSERT(VFS_I(sip)->i_nlink == 0);
+ error = xfs_bmap_add_attrfork(sip, sf_size, 0);
+ if (error)
+ goto std_return;
+ first_parent = true;
+ }
+
resblks = XFS_LINK_SPACE_RES(mp, target_name->len);
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, resblks, 0, 0, &tp);
if (error == -ENOSPC) {
@@ -1448,8 +1469,8 @@ xfs_link(
xfs_lock_two_inodes(sip, XFS_ILOCK_EXCL, tdp, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin(tp, sip, 0);
+ xfs_trans_ijoin(tp, tdp, 0);
/*
* If we are using project inheritance, we only allow hard link
@@ -1468,8 +1489,6 @@ xfs_link(
goto error_return;
}
- xfs_defer_init(&dfops, &first_block);
-
/*
* Handle initial link state of O_TMPFILE inode
*/
@@ -1479,16 +1498,30 @@ xfs_link(
goto error_return;
}
+ xfs_defer_init(&dfops, &first_block);
error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
- &first_block, &dfops, resblks, NULL);
+ &first_block, &dfops, resblks, &diroffset);
if (error)
- goto error_return;
+ goto out_defer_cancel;
xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
error = xfs_bumplink(tp, sip);
if (error)
- goto error_return;
+ goto out_defer_cancel;
+
+ /*
+ * If we have parent pointers, we now need to add the parent record to
+ * the attribute fork of the inode. If this is the initial parent
+ * attribute, we need to create it correctly, otherwise we can just add
+ * the parent to the inode.
+ */
+ if (xfs_sb_version_hasparent(&mp->m_sb)) {
+ error = xfs_parent_add_deferred(tdp, sip, target_name,
+ diroffset, &dfops);
+ if (error)
+ goto out_defer_cancel;
+ }
/*
* If this is a synchronous mount, make sure that the
@@ -1499,16 +1532,21 @@ xfs_link(
xfs_trans_set_sync(tp);
error = xfs_defer_finish(&tp, &dfops);
- if (error) {
- xfs_defer_cancel(&dfops);
- goto error_return;
- }
+ if (error)
+ goto out_defer_cancel;
- return xfs_trans_commit(tp);
+ error = xfs_trans_commit(tp);
+ xfs_iunlock(tdp, XFS_ILOCK_EXCL);
+ xfs_iunlock(sip, XFS_ILOCK_EXCL);
+ return error;
- error_return:
+out_defer_cancel:
+ xfs_defer_cancel(&dfops);
+error_return:
xfs_trans_cancel(tp);
- std_return:
+ xfs_iunlock(tdp, XFS_ILOCK_EXCL);
+ xfs_iunlock(sip, XFS_ILOCK_EXCL);
+std_return:
return error;
}
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 17/21] xfs: remove parent pointers in unlink
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (15 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 16/21] xfs: add parent attributes to link Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 21:59 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 18/21] xfs: Add parent pointers to rename Allison Henderson
` (4 subsequent siblings)
21 siblings, 1 reply; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
From: Dave Chinner <dchinner@redhat.com>
This patch removes the parent pointer attribute during unlink
[bfoster: rebase, use VFS inode generation]
[achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t
implemented xfs_attr_remove_parent]
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/xfs_inode.c | 21 ++++++++++++++++-----
fs/xfs/xfs_parent_utils.c | 19 +++++++++++++++++++
fs/xfs/xfs_parent_utils.h | 4 ++++
3 files changed, 39 insertions(+), 5 deletions(-)
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 3a68e72..b18b20c 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2624,6 +2624,7 @@ xfs_remove(
struct xfs_defer_ops dfops;
xfs_fsblock_t first_block;
uint resblks;
+ xfs_dir2_dataptr_t dir_offset;
trace_xfs_remove(dp, name);
@@ -2661,8 +2662,8 @@ xfs_remove(
xfs_lock_two_inodes(dp, XFS_ILOCK_EXCL, ip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin(tp, dp, 0);
+ xfs_trans_ijoin(tp, ip, 0);
/*
* If we're removing a directory perform some additional validation.
@@ -2704,12 +2705,18 @@ xfs_remove(
xfs_defer_init(&dfops, &first_block);
error = xfs_dir_removename(tp, dp, name, ip->i_ino, &first_block,
- &dfops, resblks, NULL);
+ &dfops, resblks, &dir_offset);
if (error) {
ASSERT(error != -ENOENT);
goto out_bmap_cancel;
}
+ if (xfs_sb_version_hasparent(&mp->m_sb)) {
+ error = xfs_parent_remove_deferred(dp, ip, dir_offset, &dfops);
+ if (error)
+ goto out_bmap_cancel;
+ }
+
/*
* If this is a synchronous mount, make sure that the
* remove transaction goes to disk before returning to
@@ -2724,17 +2731,21 @@ xfs_remove(
error = xfs_trans_commit(tp);
if (error)
- goto std_return;
+ goto out_unlock;
if (is_dir && xfs_inode_is_filestream(ip))
xfs_filestream_deassociate(ip);
- return 0;
+ error = 0;
+ goto out_unlock;
out_bmap_cancel:
xfs_defer_cancel(&dfops);
out_trans_cancel:
xfs_trans_cancel(tp);
+out_unlock:
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ xfs_iunlock(dp, XFS_ILOCK_EXCL);
std_return:
return error;
}
diff --git a/fs/xfs/xfs_parent_utils.c b/fs/xfs/xfs_parent_utils.c
index cf4a7e2..0fd48b8 100644
--- a/fs/xfs/xfs_parent_utils.c
+++ b/fs/xfs/xfs_parent_utils.c
@@ -49,3 +49,22 @@ xfs_parent_add_deferred(
(void *)child_name->name, child_name->len, ATTR_PARENT);
}
+/*
+ * Remove a parent record from a child inode.
+ */
+int
+xfs_parent_remove_deferred(
+ struct xfs_inode *parent,
+ struct xfs_inode *child,
+ xfs_dir2_dataptr_t diroffset,
+ struct xfs_defer_ops *dfops)
+{
+ struct xfs_parent_name_rec rec;
+
+ xfs_init_parent_name_rec(&rec, parent->i_ino,
+ VFS_I(parent)->i_generation, diroffset);
+
+ return xfs_attr_remove_deferred(child, dfops, &rec, sizeof(rec),
+ ATTR_PARENT);
+}
+
diff --git a/fs/xfs/xfs_parent_utils.h b/fs/xfs/xfs_parent_utils.h
index a667d1d..9e0ac13 100644
--- a/fs/xfs/xfs_parent_utils.h
+++ b/fs/xfs/xfs_parent_utils.h
@@ -23,4 +23,8 @@
int xfs_parent_add_deferred(struct xfs_inode *parent, struct xfs_inode *child,
struct xfs_name *child_name, uint32_t diroffset,
struct xfs_defer_ops *dfops);
+int xfs_parent_remove_deferred(struct xfs_inode *parent,
+ struct xfs_inode *child,
+ xfs_dir2_dataptr_t diroffset,
+ struct xfs_defer_ops *dfops);
#endif /* __XFS_PARENT_UTILS_H__ */
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 18/21] xfs: Add parent pointers to rename
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (16 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 17/21] xfs: remove parent pointers in unlink Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 21:52 ` Darrick J. Wong
2018-05-08 10:04 ` Amir Goldstein
2018-05-06 17:24 ` [PATCH 19/21] xfs: Add the parent pointer support to the superblock version 5 Allison Henderson
` (3 subsequent siblings)
21 siblings, 2 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
This patch removes the old parent pointer attribute during the
rename operation, and re-adds the updated parent pointer
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/xfs_inode.c | 68 +++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 52 insertions(+), 16 deletions(-)
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index b18b20c..7fd1479 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -3004,6 +3004,8 @@ xfs_rename(
bool src_is_directory = S_ISDIR(VFS_I(src_ip)->i_mode);
int spaceres;
int error;
+ xfs_dir2_dataptr_t new_diroffset;
+ xfs_dir2_dataptr_t old_diroffset;
trace_xfs_rename(src_dp, target_dp, src_name, target_name);
@@ -3058,14 +3060,14 @@ xfs_rename(
* we can rely on either trans_commit or trans_cancel to unlock
* them.
*/
- xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin(tp, src_dp, 0);
if (new_parent)
- xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin(tp, target_dp, 0);
+ xfs_trans_ijoin(tp, src_ip, 0);
if (target_ip)
- xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin(tp, target_ip, 0);
if (wip)
- xfs_trans_ijoin(tp, wip, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin(tp, wip, 0);
/*
* If we are using project inheritance, we only allow renames
@@ -3075,17 +3077,18 @@ xfs_rename(
if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
(xfs_get_projid(target_dp) != xfs_get_projid(src_ip)))) {
error = -EXDEV;
- goto out_trans_cancel;
+ goto out_unlock;
}
xfs_defer_init(&dfops, &first_block);
/* RENAME_EXCHANGE is unique from here on. */
- if (flags & RENAME_EXCHANGE)
- return xfs_cross_rename(tp, src_dp, src_name, src_ip,
+ if (flags & RENAME_EXCHANGE) {
+ error = xfs_cross_rename(tp, src_dp, src_name, src_ip,
target_dp, target_name, target_ip,
&dfops, &first_block, spaceres);
-
+ goto out;
+ }
/*
* Set up the target.
*/
@@ -3097,7 +3100,7 @@ xfs_rename(
if (!spaceres) {
error = xfs_dir_canenter(tp, target_dp, target_name);
if (error)
- goto out_trans_cancel;
+ goto out_unlock;
}
/*
* If target does not exist and the rename crosses
@@ -3106,7 +3109,7 @@ xfs_rename(
*/
error = xfs_dir_createname(tp, target_dp, target_name,
src_ip->i_ino, &first_block, &dfops,
- spaceres, NULL);
+ spaceres, &new_diroffset);
if (error)
goto out_bmap_cancel;
@@ -3131,7 +3134,7 @@ xfs_rename(
if (!(xfs_dir_isempty(target_ip)) ||
(VFS_I(target_ip)->i_nlink > 2)) {
error = -EEXIST;
- goto out_trans_cancel;
+ goto out_unlock;
}
}
@@ -3146,7 +3149,7 @@ xfs_rename(
*/
error = xfs_dir_replace(tp, target_dp, target_name,
src_ip->i_ino, &first_block, &dfops,
- spaceres, NULL);
+ spaceres, &new_diroffset);
if (error)
goto out_bmap_cancel;
@@ -3181,7 +3184,7 @@ xfs_rename(
*/
error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,
target_dp->i_ino, &first_block, &dfops,
- spaceres, NULL);
+ spaceres, &new_diroffset);
ASSERT(error != -EEXIST);
if (error)
goto out_bmap_cancel;
@@ -3220,11 +3223,12 @@ xfs_rename(
*/
if (wip) {
error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino,
- &first_block, &dfops, spaceres, NULL);
+ &first_block, &dfops, spaceres,
+ &old_diroffset);
} else
error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
&first_block, &dfops, spaceres,
- NULL);
+ &old_diroffset);
if (error)
goto out_bmap_cancel;
@@ -3254,6 +3258,18 @@ xfs_rename(
VFS_I(wip)->i_state &= ~I_LINKABLE;
}
+ if (xfs_sb_version_hasparent(&mp->m_sb)) {
+ error = xfs_parent_add_deferred(target_dp, src_ip, target_name,
+ new_diroffset, &dfops);
+ if (error)
+ goto out_bmap_cancel;
+
+ error = xfs_parent_remove_deferred(src_dp, src_ip,
+ old_diroffset, &dfops);
+ if (error)
+ goto out_bmap_cancel;
+ }
+
xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE);
if (new_parent)
@@ -3262,10 +3278,30 @@ xfs_rename(
error = xfs_finish_rename(tp, &dfops);
if (wip)
IRELE(wip);
+out:
+ if (wip)
+ xfs_iunlock(wip, XFS_ILOCK_EXCL);
+ if (target_ip)
+ xfs_iunlock(target_ip, XFS_ILOCK_EXCL);
+ xfs_iunlock(src_ip, XFS_ILOCK_EXCL);
+ if (new_parent)
+ xfs_iunlock(target_dp, XFS_ILOCK_EXCL);
+ xfs_iunlock(src_dp, XFS_ILOCK_EXCL);
+
return error;
out_bmap_cancel:
xfs_defer_cancel(&dfops);
+out_unlock:
+ if (wip)
+ xfs_iunlock(wip, XFS_ILOCK_EXCL);
+ if (target_ip)
+ xfs_iunlock(target_ip, XFS_ILOCK_EXCL);
+ xfs_iunlock(src_ip, XFS_ILOCK_EXCL);
+ if (new_parent)
+ xfs_iunlock(target_dp, XFS_ILOCK_EXCL);
+ xfs_iunlock(src_dp, XFS_ILOCK_EXCL);
+
out_trans_cancel:
xfs_trans_cancel(tp);
out_release_wip:
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 19/21] xfs: Add the parent pointer support to the superblock version 5.
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (17 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 18/21] xfs: Add parent pointers to rename Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 21:38 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 20/21] xfs: Add parent pointer ioctl Allison Henderson
` (2 subsequent siblings)
21 siblings, 1 reply; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
[dchinner: forward ported and cleaned up]
[achender: rebased and added parent pointer attribute to
compatible attributes mask]
Signed-off-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/libxfs/xfs_format.h | 7 +++++--
fs/xfs/libxfs/xfs_fs.h | 1 +
fs/xfs/libxfs/xfs_sb.c | 2 ++
fs/xfs/xfs_super.c | 4 ++++
4 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 5e946c8..d05ffc5 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -462,10 +462,12 @@ xfs_sb_has_compat_feature(
#define XFS_SB_FEAT_RO_COMPAT_FINOBT (1 << 0) /* free inode btree */
#define XFS_SB_FEAT_RO_COMPAT_RMAPBT (1 << 1) /* reverse map btree */
#define XFS_SB_FEAT_RO_COMPAT_REFLINK (1 << 2) /* reflinked files */
+#define XFS_SB_FEAT_RO_COMPAT_PARENT (1 << 3) /* parent inode ptr */
#define XFS_SB_FEAT_RO_COMPAT_ALL \
(XFS_SB_FEAT_RO_COMPAT_FINOBT | \
XFS_SB_FEAT_RO_COMPAT_RMAPBT | \
- XFS_SB_FEAT_RO_COMPAT_REFLINK)
+ XFS_SB_FEAT_RO_COMPAT_REFLINK| \
+ XFS_SB_FEAT_RO_COMPAT_PARENT)
#define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALL
static inline bool
xfs_sb_has_ro_compat_feature(
@@ -561,7 +563,8 @@ static inline bool xfs_sb_version_hasreflink(struct xfs_sb *sbp)
static inline bool xfs_sb_version_hasparent(struct xfs_sb *sbp)
{
- return false; /* We'll enable this at the end of the set */
+ return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 &&
+ (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_PARENT));
}
/*
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index faf1a4e..641e0af 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -222,6 +222,7 @@ typedef struct xfs_fsop_resblks {
#define XFS_FSOP_GEOM_FLAGS_SPINODES 0x40000 /* sparse inode chunks */
#define XFS_FSOP_GEOM_FLAGS_RMAPBT 0x80000 /* reverse mapping btree */
#define XFS_FSOP_GEOM_FLAGS_REFLINK 0x100000 /* files can share blocks */
+#define XFS_FSOP_GEOM_FLAGS_PARENT 0x200000 /* parent pointers */
/*
* Minimum and maximum sizes need for growth checks.
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index d9b94bd..e1f0ac1 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -955,6 +955,8 @@ xfs_fs_geometry(
geo->flags |= XFS_FSOP_GEOM_FLAGS_RMAPBT;
if (xfs_sb_version_hasreflink(sbp))
geo->flags |= XFS_FSOP_GEOM_FLAGS_REFLINK;
+ if(xfs_sb_version_hasparent(sbp))
+ geo->flags |= XFS_FSOP_GEOM_FLAGS_PARENT;
if (xfs_sb_version_hassector(sbp))
geo->logsectsize = sbp->sb_logsectsize;
else
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index dce3baf..366deee 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1731,6 +1731,10 @@ xfs_fs_fill_super(
goto out_filestream_unmount;
}
+ if (xfs_sb_version_hasparent(&mp->m_sb))
+ xfs_alert(mp,
+ "EXPERIMENTAL parent pointer feature enabled. Use at your own risk!");
+
error = xfs_mountfs(mp);
if (error)
goto out_filestream_unmount;
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 20/21] xfs: Add parent pointer ioctl
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (18 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 19/21] xfs: Add the parent pointer support to the superblock version 5 Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 21:36 ` Darrick J. Wong
2018-05-15 16:27 ` Catalin Iacob
2018-05-06 17:24 ` [PATCH 21/21] xfs: Add delayed attributes error tag Allison Henderson
2018-05-08 5:36 ` [PATCH 00/21] Parent Pointers v6 Amir Goldstein
21 siblings, 2 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
This patch adds a new file ioctl to retrieve the parent
pointer of a given inode
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/libxfs/xfs_fs.h | 38 ++++++++++++++++++++++++++
fs/xfs/libxfs/xfs_parent.c | 10 +++++++
fs/xfs/libxfs/xfs_parent.h | 2 ++
fs/xfs/xfs_attr_list.c | 3 +++
fs/xfs/xfs_ioctl.c | 61 +++++++++++++++++++++++++++++++++++++++++-
fs/xfs/xfs_parent_utils.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++
fs/xfs/xfs_parent_utils.h | 2 ++
7 files changed, 181 insertions(+), 1 deletion(-)
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index 641e0af..4e0ccdd 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -552,6 +552,43 @@ struct xfs_scrub_metadata {
XFS_SCRUB_OFLAG_WARNING)
#define XFS_SCRUB_FLAGS_ALL (XFS_SCRUB_FLAGS_IN | XFS_SCRUB_FLAGS_OUT)
+#define XFS_PPTR_MAXNAMELEN 255
+
+/* return parents of the handle, not the open fd */
+#define XFS_PPTR_IFLAG_HANDLE (1U << 0)
+
+/* Get an inode parent pointer through ioctl */
+struct xfs_parent_ptr {
+ __u64 xpp_ino; /* Inode */
+ __u32 xpp_gen; /* Inode generation */
+ __u32 xpp_diroffset; /* Directory offset */
+ __u32 xpp_namelen; /* File name length */
+ __u8 xpp_name[XFS_PPTR_MAXNAMELEN]; /* File name */
+};
+
+/* Iterate though an inodes parent pointers */
+struct xfs_pptr_info {
+ struct xfs_handle pi_handle;
+ struct xfs_attrlist_cursor pi_cursor;
+ __u32 pi_flags;
+ __u32 pi_reserved;
+ __u32 pi_ptrs_size;
+ __u32 pi_ptrs_used;
+ __u64 pi_reserved2[6];
+
+ /*
+ * An array of struct xfs_pptr follows the header
+ * information. Use XFS_PPINFO_TO_PP() to access the
+ * parent pointer array entries.
+ */
+};
+
+#define XFS_PPTR_INFO_SIZEOF(nr_ptrs) sizeof (struct xfs_pptr_info) + \
+ nr_ptrs * sizeof(struct xfs_parent_ptr)
+
+#define XFS_PPINFO_TO_PP(info, idx) \
+ (&(((struct xfs_parent_ptr *)((char *)(info) + sizeof(*(info))))[(idx)]))
+
/*
* ioctl limits
*/
@@ -596,6 +633,7 @@ struct xfs_scrub_metadata {
#define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_fs_eofblocks)
/* XFS_IOC_GETFSMAP ------ hoisted 59 */
#define XFS_IOC_SCRUB_METADATA _IOWR('X', 60, struct xfs_scrub_metadata)
+#define XFS_IOC_GETPPOINTER _IOR ('X', 61, struct xfs_parent_ptr)
/*
* ioctl commands that replace IRIX syssgi()'s
diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
index e6de97c..61f1961 100644
--- a/fs/xfs/libxfs/xfs_parent.c
+++ b/fs/xfs/libxfs/xfs_parent.c
@@ -32,6 +32,16 @@
#include "xfs_attr_sf.h"
#include "xfs_bmap.h"
+/* Initializes a xfs_parent_ptr from an xfs_parent_name_rec */
+void
+xfs_init_parent_ptr(struct xfs_parent_ptr *xpp,
+ struct xfs_parent_name_rec *rec)
+{
+ xpp->xpp_ino = be64_to_cpu(rec->p_ino);
+ xpp->xpp_gen = be32_to_cpu(rec->p_gen);
+ xpp->xpp_diroffset = be32_to_cpu(rec->p_diroffset);
+}
+
/*
* Parent pointer attribute handling.
*
diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h
index 298562b..1a321db 100644
--- a/fs/xfs/libxfs/xfs_parent.h
+++ b/fs/xfs/libxfs/xfs_parent.h
@@ -33,4 +33,6 @@ int xfs_parent_add(struct xfs_trans *tp, struct xfs_inode *parent,
struct xfs_inode *child, struct xfs_name *child_name,
uint32_t diroffset, xfs_fsblock_t *firstblock,
struct xfs_defer_ops *dfops);
+void xfs_init_parent_ptr(struct xfs_parent_ptr *xpp,
+ struct xfs_parent_name_rec *rec);
#endif /* __XFS_PARENT_H__ */
diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
index 3e59a34..bdbe9fb 100644
--- a/fs/xfs/xfs_attr_list.c
+++ b/fs/xfs/xfs_attr_list.c
@@ -581,6 +581,9 @@ xfs_attr_put_listent(
if (((context->flags & ATTR_ROOT) == 0) !=
((flags & XFS_ATTR_ROOT) == 0))
return;
+ if (((context->flags & ATTR_PARENT) == 0) !=
+ ((flags & XFS_ATTR_PARENT) == 0))
+ return;
arraytop = sizeof(*alist) +
context->count * sizeof(alist->al_offset[0]);
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 844480a..ee544f2 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -46,6 +46,8 @@
#include "xfs_fsmap.h"
#include "scrub/xfs_scrub.h"
#include "xfs_sb.h"
+#include "xfs_da_format.h"
+#include "xfs_parent_utils.h"
#include <linux/capability.h>
#include <linux/cred.h>
@@ -1738,6 +1740,62 @@ xfs_ioc_scrub_metadata(
return 0;
}
+/*
+ * IOCTL routine to get the parent pointer of an inode and return it to user
+ * space. Caller must pass an struct xfs_parent_name_irec with a name buffer
+ * large enough to hold the file name. Returns 0 on success or non-zero on
+ * failure
+ */
+STATIC int
+xfs_ioc_get_parent_pointer(
+ struct file *filp,
+ void __user *arg)
+{
+ struct xfs_inode *ip;
+ struct xfs_pptr_info *ppi;
+ struct dentry *dentry;
+ int error = 0;
+
+ /* Allocate an xfs_pptr_info to put the user data */
+ ppi = kmem_alloc(sizeof(struct xfs_pptr_info), KM_SLEEP);
+ if (!ppi)
+ return -ENOMEM;
+
+ /* Copy the data from the user */
+ copy_from_user(ppi, arg, sizeof(struct xfs_pptr_info));
+
+ /*
+ * Now that we know how big the trailing buffer is, expand
+ * our kernel xfs_pptr_info to be the same size
+ */
+ ppi = kmem_realloc(ppi, XFS_PPTR_INFO_SIZEOF(ppi->pi_ptrs_size),
+ KM_SLEEP);
+ if (!ppi)
+ return -ENOMEM;
+
+ if (ppi->pi_flags == XFS_PPTR_IFLAG_HANDLE) {
+ dentry = xfs_handle_to_dentry(filp, &ppi->pi_handle,
+ sizeof(struct xfs_handle));
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+ ip = XFS_I(d_inode(dentry));
+ } else
+ ip = XFS_I(file_inode(filp));
+
+ /* Get the parent pointers */
+ error = xfs_attr_get_parent_pointer(ip, ppi);
+
+ if (error)
+ goto out;
+
+ /* Copy the parent pointers back to the user */
+ copy_to_user(arg, ppi, XFS_PPTR_INFO_SIZEOF(ppi->pi_ptrs_size));
+
+out:
+ kmem_free(ppi);
+ return error;
+}
+
int
xfs_ioc_swapext(
xfs_swapext_t *sxp)
@@ -1894,7 +1952,8 @@ xfs_file_ioctl(
return xfs_ioc_getxflags(ip, arg);
case XFS_IOC_SETXFLAGS:
return xfs_ioc_setxflags(ip, filp, arg);
-
+ case XFS_IOC_GETPPOINTER:
+ return xfs_ioc_get_parent_pointer(filp, arg);
case XFS_IOC_FSSETDM: {
struct fsdmidata dmi;
diff --git a/fs/xfs/xfs_parent_utils.c b/fs/xfs/xfs_parent_utils.c
index 0fd48b8..1df003a 100644
--- a/fs/xfs/xfs_parent_utils.c
+++ b/fs/xfs/xfs_parent_utils.c
@@ -68,3 +68,69 @@ xfs_parent_remove_deferred(
ATTR_PARENT);
}
+/*
+ * Get the parent pointers for a given inode
+ *
+ * Returns 0 on success and non zero on error
+ */
+int
+xfs_attr_get_parent_pointer(struct xfs_inode *ip,
+ struct xfs_pptr_info *ppi)
+
+{
+
+ struct attrlist *alist;
+ struct attrlist_ent *aent;
+ struct xfs_parent_ptr *xpp;
+ struct xfs_parent_name_rec *xpnr;
+ char *namebuf;
+ unsigned int namebuf_size;
+ int name_len;
+ int error = 0;
+ unsigned int flags = ATTR_PARENT;
+ int i;
+
+ /* Allocate a buffer to store the attribute names */
+ namebuf_size = sizeof(struct attrlist) +
+ (ppi->pi_ptrs_size) * sizeof(struct attrlist_ent);
+ namebuf = kmem_zalloc_large(namebuf_size, KM_SLEEP);
+ if (!namebuf)
+ return -ENOMEM;
+
+ error = xfs_attr_list(ip, namebuf, namebuf_size, flags,
+ (attrlist_cursor_kern_t *)&ppi->pi_cursor);
+ if (error)
+ goto out_kfree;
+
+ alist = (struct attrlist *)namebuf;
+
+ for (i = 0; i < alist->al_count; i++) {
+ xpp = XFS_PPINFO_TO_PP(ppi, i);
+ memset(xpp, 0, sizeof(struct xfs_parent_ptr));
+ aent = (struct attrlist_ent *) &namebuf[alist->al_offset[i]];
+ xpnr = (struct xfs_parent_name_rec *)(aent->a_name);
+
+ if (aent->a_valuelen > XFS_PPTR_MAXNAMELEN) {
+ error = -ERANGE;
+ goto out_kfree;
+ }
+
+ name_len = aent->a_valuelen;
+ error = xfs_attr_get(ip, (char *)xpnr,
+ sizeof(struct xfs_parent_name_rec),
+ (unsigned char *)(xpp->xpp_name),
+ &name_len, flags);
+ if (error)
+ goto out_kfree;
+
+ xpp->xpp_namelen = name_len;
+ xfs_init_parent_ptr(xpp, xpnr);
+ }
+ ppi->pi_ptrs_used = alist->al_count;
+
+out_kfree:
+ kmem_free(namebuf);
+
+ return error;
+}
+
diff --git a/fs/xfs/xfs_parent_utils.h b/fs/xfs/xfs_parent_utils.h
index 9e0ac13..33e3b2c 100644
--- a/fs/xfs/xfs_parent_utils.h
+++ b/fs/xfs/xfs_parent_utils.h
@@ -27,4 +27,6 @@ int xfs_parent_remove_deferred(struct xfs_inode *parent,
struct xfs_inode *child,
xfs_dir2_dataptr_t diroffset,
struct xfs_defer_ops *dfops);
+int xfs_attr_get_parent_pointer(struct xfs_inode *ip,
+ struct xfs_pptr_info *ppi);
#endif /* __XFS_PARENT_UTILS_H__ */
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* [PATCH 21/21] xfs: Add delayed attributes error tag
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (19 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 20/21] xfs: Add parent pointer ioctl Allison Henderson
@ 2018-05-06 17:24 ` Allison Henderson
2018-05-07 20:57 ` Darrick J. Wong
2018-05-08 5:36 ` [PATCH 00/21] Parent Pointers v6 Amir Goldstein
21 siblings, 1 reply; 72+ messages in thread
From: Allison Henderson @ 2018-05-06 17:24 UTC (permalink / raw)
To: linux-xfs
This patch adds an error tag that we can use to test
delayed attribute recovery and replay
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
---
fs/xfs/libxfs/xfs_errortag.h | 5 ++++-
fs/xfs/xfs_error.c | 3 +++
fs/xfs/xfs_trans_attr.c | 8 ++++++++
3 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/fs/xfs/libxfs/xfs_errortag.h b/fs/xfs/libxfs/xfs_errortag.h
index bc1789d..f606ab6 100644
--- a/fs/xfs/libxfs/xfs_errortag.h
+++ b/fs/xfs/libxfs/xfs_errortag.h
@@ -65,7 +65,8 @@
#define XFS_ERRTAG_LOG_BAD_CRC 29
#define XFS_ERRTAG_LOG_ITEM_PIN 30
#define XFS_ERRTAG_BUF_LRU_REF 31
-#define XFS_ERRTAG_MAX 32
+#define XFS_ERRTAG_DELAYED_ATTR 32
+#define XFS_ERRTAG_MAX 33
/*
* Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
@@ -102,5 +103,7 @@
#define XFS_RANDOM_LOG_BAD_CRC 1
#define XFS_RANDOM_LOG_ITEM_PIN 1
#define XFS_RANDOM_BUF_LRU_REF 2
+#define XFS_RANDOM_DELAYED_ATTR 1
#endif /* __XFS_ERRORTAG_H_ */
+
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
index a63f508..0752f20 100644
--- a/fs/xfs/xfs_error.c
+++ b/fs/xfs/xfs_error.c
@@ -61,6 +61,7 @@ static unsigned int xfs_errortag_random_default[] = {
XFS_RANDOM_LOG_BAD_CRC,
XFS_RANDOM_LOG_ITEM_PIN,
XFS_RANDOM_BUF_LRU_REF,
+ XFS_RANDOM_DELAYED_ATTR,
};
struct xfs_errortag_attr {
@@ -167,6 +168,7 @@ XFS_ERRORTAG_ATTR_RW(drop_writes, XFS_ERRTAG_DROP_WRITES);
XFS_ERRORTAG_ATTR_RW(log_bad_crc, XFS_ERRTAG_LOG_BAD_CRC);
XFS_ERRORTAG_ATTR_RW(log_item_pin, XFS_ERRTAG_LOG_ITEM_PIN);
XFS_ERRORTAG_ATTR_RW(buf_lru_ref, XFS_ERRTAG_BUF_LRU_REF);
+XFS_ERRORTAG_ATTR_RW(delayed_attr, XFS_ERRTAG_DELAYED_ATTR);
static struct attribute *xfs_errortag_attrs[] = {
XFS_ERRORTAG_ATTR_LIST(noerror),
@@ -201,6 +203,7 @@ static struct attribute *xfs_errortag_attrs[] = {
XFS_ERRORTAG_ATTR_LIST(log_bad_crc),
XFS_ERRORTAG_ATTR_LIST(log_item_pin),
XFS_ERRORTAG_ATTR_LIST(buf_lru_ref),
+ XFS_ERRORTAG_ATTR_LIST(delayed_attr),
NULL,
};
diff --git a/fs/xfs/xfs_trans_attr.c b/fs/xfs/xfs_trans_attr.c
index d1d75bb..7ea0880 100644
--- a/fs/xfs/xfs_trans_attr.c
+++ b/fs/xfs/xfs_trans_attr.c
@@ -35,6 +35,8 @@
#include "xfs_inode.h"
#include "xfs_icache.h"
#include "xfs_quota.h"
+#include "xfs_errortag.h"
+#include "xfs_error.h"
/*
* This routine is called to allocate an "extent free done"
@@ -108,6 +110,11 @@ xfs_trans_attr(
if (error)
return error;
+ if (XFS_TEST_ERROR(false, ip->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;
@@ -122,6 +129,7 @@ xfs_trans_attr(
error = -EFSCORRUPTED;
}
+out:
if (error) {
xfs_defer_cancel(&dfops);
if (leaf_bp)
--
2.7.4
^ permalink raw reply related [flat|nested] 72+ messages in thread
* Re: [PATCH 21/21] xfs: Add delayed attributes error tag
2018-05-06 17:24 ` [PATCH 21/21] xfs: Add delayed attributes error tag Allison Henderson
@ 2018-05-07 20:57 ` Darrick J. Wong
0 siblings, 0 replies; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 20:57 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:54AM -0700, Allison Henderson wrote:
> This patch adds an error tag that we can use to test
> delayed attribute recovery and replay
>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
/me starts reviewing from the back (we'll see how this goes :P)
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
--D
> ---
> fs/xfs/libxfs/xfs_errortag.h | 5 ++++-
> fs/xfs/xfs_error.c | 3 +++
> fs/xfs/xfs_trans_attr.c | 8 ++++++++
> 3 files changed, 15 insertions(+), 1 deletion(-)
>
> diff --git a/fs/xfs/libxfs/xfs_errortag.h b/fs/xfs/libxfs/xfs_errortag.h
> index bc1789d..f606ab6 100644
> --- a/fs/xfs/libxfs/xfs_errortag.h
> +++ b/fs/xfs/libxfs/xfs_errortag.h
> @@ -65,7 +65,8 @@
> #define XFS_ERRTAG_LOG_BAD_CRC 29
> #define XFS_ERRTAG_LOG_ITEM_PIN 30
> #define XFS_ERRTAG_BUF_LRU_REF 31
> -#define XFS_ERRTAG_MAX 32
> +#define XFS_ERRTAG_DELAYED_ATTR 32
> +#define XFS_ERRTAG_MAX 33
>
> /*
> * Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
> @@ -102,5 +103,7 @@
> #define XFS_RANDOM_LOG_BAD_CRC 1
> #define XFS_RANDOM_LOG_ITEM_PIN 1
> #define XFS_RANDOM_BUF_LRU_REF 2
> +#define XFS_RANDOM_DELAYED_ATTR 1
>
> #endif /* __XFS_ERRORTAG_H_ */
> +
> diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
> index a63f508..0752f20 100644
> --- a/fs/xfs/xfs_error.c
> +++ b/fs/xfs/xfs_error.c
> @@ -61,6 +61,7 @@ static unsigned int xfs_errortag_random_default[] = {
> XFS_RANDOM_LOG_BAD_CRC,
> XFS_RANDOM_LOG_ITEM_PIN,
> XFS_RANDOM_BUF_LRU_REF,
> + XFS_RANDOM_DELAYED_ATTR,
> };
>
> struct xfs_errortag_attr {
> @@ -167,6 +168,7 @@ XFS_ERRORTAG_ATTR_RW(drop_writes, XFS_ERRTAG_DROP_WRITES);
> XFS_ERRORTAG_ATTR_RW(log_bad_crc, XFS_ERRTAG_LOG_BAD_CRC);
> XFS_ERRORTAG_ATTR_RW(log_item_pin, XFS_ERRTAG_LOG_ITEM_PIN);
> XFS_ERRORTAG_ATTR_RW(buf_lru_ref, XFS_ERRTAG_BUF_LRU_REF);
> +XFS_ERRORTAG_ATTR_RW(delayed_attr, XFS_ERRTAG_DELAYED_ATTR);
>
> static struct attribute *xfs_errortag_attrs[] = {
> XFS_ERRORTAG_ATTR_LIST(noerror),
> @@ -201,6 +203,7 @@ static struct attribute *xfs_errortag_attrs[] = {
> XFS_ERRORTAG_ATTR_LIST(log_bad_crc),
> XFS_ERRORTAG_ATTR_LIST(log_item_pin),
> XFS_ERRORTAG_ATTR_LIST(buf_lru_ref),
> + XFS_ERRORTAG_ATTR_LIST(delayed_attr),
> NULL,
> };
>
> diff --git a/fs/xfs/xfs_trans_attr.c b/fs/xfs/xfs_trans_attr.c
> index d1d75bb..7ea0880 100644
> --- a/fs/xfs/xfs_trans_attr.c
> +++ b/fs/xfs/xfs_trans_attr.c
> @@ -35,6 +35,8 @@
> #include "xfs_inode.h"
> #include "xfs_icache.h"
> #include "xfs_quota.h"
> +#include "xfs_errortag.h"
> +#include "xfs_error.h"
>
> /*
> * This routine is called to allocate an "extent free done"
> @@ -108,6 +110,11 @@ xfs_trans_attr(
> if (error)
> return error;
>
> + if (XFS_TEST_ERROR(false, ip->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;
> @@ -122,6 +129,7 @@ xfs_trans_attr(
> error = -EFSCORRUPTED;
> }
>
> +out:
> if (error) {
> xfs_defer_cancel(&dfops);
> if (leaf_bp)
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 20/21] xfs: Add parent pointer ioctl
2018-05-06 17:24 ` [PATCH 20/21] xfs: Add parent pointer ioctl Allison Henderson
@ 2018-05-07 21:36 ` Darrick J. Wong
2018-05-08 10:24 ` Amir Goldstein
2018-05-08 16:57 ` Allison Henderson
2018-05-15 16:27 ` Catalin Iacob
1 sibling, 2 replies; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 21:36 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:53AM -0700, Allison Henderson wrote:
> This patch adds a new file ioctl to retrieve the parent
> pointer of a given inode
>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
> fs/xfs/libxfs/xfs_fs.h | 38 ++++++++++++++++++++++++++
> fs/xfs/libxfs/xfs_parent.c | 10 +++++++
> fs/xfs/libxfs/xfs_parent.h | 2 ++
> fs/xfs/xfs_attr_list.c | 3 +++
> fs/xfs/xfs_ioctl.c | 61 +++++++++++++++++++++++++++++++++++++++++-
> fs/xfs/xfs_parent_utils.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++
> fs/xfs/xfs_parent_utils.h | 2 ++
> 7 files changed, 181 insertions(+), 1 deletion(-)
>
> diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
> index 641e0af..4e0ccdd 100644
> --- a/fs/xfs/libxfs/xfs_fs.h
> +++ b/fs/xfs/libxfs/xfs_fs.h
> @@ -552,6 +552,43 @@ struct xfs_scrub_metadata {
> XFS_SCRUB_OFLAG_WARNING)
> #define XFS_SCRUB_FLAGS_ALL (XFS_SCRUB_FLAGS_IN | XFS_SCRUB_FLAGS_OUT)
>
> +#define XFS_PPTR_MAXNAMELEN 255
> +
> +/* return parents of the handle, not the open fd */
> +#define XFS_PPTR_IFLAG_HANDLE (1U << 0)
> +
> +/* Get an inode parent pointer through ioctl */
> +struct xfs_parent_ptr {
> + __u64 xpp_ino; /* Inode */
> + __u32 xpp_gen; /* Inode generation */
> + __u32 xpp_diroffset; /* Directory offset */
> + __u32 xpp_namelen; /* File name length */
> + __u8 xpp_name[XFS_PPTR_MAXNAMELEN]; /* File name */
> +};
Hmm, this structure probably needs padding to round up the size up to an
even multiple of 8 bytes so that 32-bit userspace can call it without
problems(?)
(I suggest dumping the structure definitions into a plain C program and
calling pahole...)
> +
> +/* Iterate though an inodes parent pointers */
> +struct xfs_pptr_info {
> + struct xfs_handle pi_handle;
> + struct xfs_attrlist_cursor pi_cursor;
> + __u32 pi_flags;
> + __u32 pi_reserved;
> + __u32 pi_ptrs_size;
> + __u32 pi_ptrs_used;
> + __u64 pi_reserved2[6];
> +
> + /*
> + * An array of struct xfs_pptr follows the header
> + * information. Use XFS_PPINFO_TO_PP() to access the
> + * parent pointer array entries.
> + */
> +};
> +
> +#define XFS_PPTR_INFO_SIZEOF(nr_ptrs) sizeof (struct xfs_pptr_info) + \
> + nr_ptrs * sizeof(struct xfs_parent_ptr)
> +
> +#define XFS_PPINFO_TO_PP(info, idx) \
> + (&(((struct xfs_parent_ptr *)((char *)(info) + sizeof(*(info))))[(idx)]))
> +
> /*
> * ioctl limits
> */
> @@ -596,6 +633,7 @@ struct xfs_scrub_metadata {
> #define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_fs_eofblocks)
> /* XFS_IOC_GETFSMAP ------ hoisted 59 */
> #define XFS_IOC_SCRUB_METADATA _IOWR('X', 60, struct xfs_scrub_metadata)
> +#define XFS_IOC_GETPPOINTER _IOR ('X', 61, struct xfs_parent_ptr)
>
> /*
> * ioctl commands that replace IRIX syssgi()'s
> diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
> index e6de97c..61f1961 100644
> --- a/fs/xfs/libxfs/xfs_parent.c
> +++ b/fs/xfs/libxfs/xfs_parent.c
> @@ -32,6 +32,16 @@
> #include "xfs_attr_sf.h"
> #include "xfs_bmap.h"
>
> +/* Initializes a xfs_parent_ptr from an xfs_parent_name_rec */
> +void
> +xfs_init_parent_ptr(struct xfs_parent_ptr *xpp,
> + struct xfs_parent_name_rec *rec)
> +{
> + xpp->xpp_ino = be64_to_cpu(rec->p_ino);
> + xpp->xpp_gen = be32_to_cpu(rec->p_gen);
> + xpp->xpp_diroffset = be32_to_cpu(rec->p_diroffset);
> +}
> +
> /*
> * Parent pointer attribute handling.
> *
> diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h
> index 298562b..1a321db 100644
> --- a/fs/xfs/libxfs/xfs_parent.h
> +++ b/fs/xfs/libxfs/xfs_parent.h
> @@ -33,4 +33,6 @@ int xfs_parent_add(struct xfs_trans *tp, struct xfs_inode *parent,
> struct xfs_inode *child, struct xfs_name *child_name,
> uint32_t diroffset, xfs_fsblock_t *firstblock,
> struct xfs_defer_ops *dfops);
> +void xfs_init_parent_ptr(struct xfs_parent_ptr *xpp,
> + struct xfs_parent_name_rec *rec);
> #endif /* __XFS_PARENT_H__ */
> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
> index 3e59a34..bdbe9fb 100644
> --- a/fs/xfs/xfs_attr_list.c
> +++ b/fs/xfs/xfs_attr_list.c
> @@ -581,6 +581,9 @@ xfs_attr_put_listent(
> if (((context->flags & ATTR_ROOT) == 0) !=
> ((flags & XFS_ATTR_ROOT) == 0))
> return;
> + if (((context->flags & ATTR_PARENT) == 0) !=
> + ((flags & XFS_ATTR_PARENT) == 0))
> + return;
>
> arraytop = sizeof(*alist) +
> context->count * sizeof(alist->al_offset[0]);
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index 844480a..ee544f2 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -46,6 +46,8 @@
> #include "xfs_fsmap.h"
> #include "scrub/xfs_scrub.h"
> #include "xfs_sb.h"
> +#include "xfs_da_format.h"
> +#include "xfs_parent_utils.h"
>
> #include <linux/capability.h>
> #include <linux/cred.h>
> @@ -1738,6 +1740,62 @@ xfs_ioc_scrub_metadata(
> return 0;
> }
>
> +/*
> + * IOCTL routine to get the parent pointer of an inode and return it to user
> + * space. Caller must pass an struct xfs_parent_name_irec with a name buffer
> + * large enough to hold the file name. Returns 0 on success or non-zero on
> + * failure
> + */
> +STATIC int
> +xfs_ioc_get_parent_pointer(
> + struct file *filp,
> + void __user *arg)
> +{
> + struct xfs_inode *ip;
> + struct xfs_pptr_info *ppi;
> + struct dentry *dentry;
> + int error = 0;
At least initially this ought to be restricted by capabilities.
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
I'd be open to allowing a few other capabilities? Maybe the DAC
override one?
Also needs to check for invalid pi_flags and nonzero reserved fields.
> +
> + /* Allocate an xfs_pptr_info to put the user data */
> + ppi = kmem_alloc(sizeof(struct xfs_pptr_info), KM_SLEEP);
> + if (!ppi)
> + return -ENOMEM;
> +
> + /* Copy the data from the user */
> + copy_from_user(ppi, arg, sizeof(struct xfs_pptr_info));
Please do not throw away the return value.
> +
> + /*
> + * Now that we know how big the trailing buffer is, expand
> + * our kernel xfs_pptr_info to be the same size
> + */
> + ppi = kmem_realloc(ppi, XFS_PPTR_INFO_SIZEOF(ppi->pi_ptrs_size),
Hmm, pi_ptrs_size probably needs some kind of check so that userspace
can't ask for insane large allocations. 64k, perhaps? ~230 records per
call ought to be enough for anyone... :P
if (XFS_PPTR_INFO_SIZEOFI(...) > XFS_XATTR_LIST_MAX)
return -ENOMEM;
ppi = kmem_realloc(...);
> + KM_SLEEP);
> + if (!ppi)
> + return -ENOMEM;
> +
> + if (ppi->pi_flags == XFS_PPTR_IFLAG_HANDLE) {
> + dentry = xfs_handle_to_dentry(filp, &ppi->pi_handle,
> + sizeof(struct xfs_handle));
> + if (IS_ERR(dentry))
> + return PTR_ERR(dentry);
> + ip = XFS_I(d_inode(dentry));
I would've thought that between the dentry and the ip that at least one
of those would require a dput/iput, and that we'd need to do something
to prevent the dentry or the inode from disappearing from underneath us...
...but you could also extract the inode and generation numbers from the
handle information and call xfs_iget directly. The exportfs code tries
to reconnect dentry parent information up to the root, which will turn
out badly if some mid-level directory is corrupt and scrub is trying to
reconstruct the former path of a now inaccessible file.
That said, I could just fix this myself to satisfy the requirements of
the, uh, single consumer of this information. :)
(Particularly since my dorky rfc used this exact exportfs_decode_fh
mechanism. :p)
((You could also replace this hunk with 'return -EPERM' and let me sort
the whole thing out. :) ))
> + } else
> + ip = XFS_I(file_inode(filp));
> +
> + /* Get the parent pointers */
> + error = xfs_attr_get_parent_pointer(ip, ppi);
> +
> + if (error)
> + goto out;
> +
> + /* Copy the parent pointers back to the user */
> + copy_to_user(arg, ppi, XFS_PPTR_INFO_SIZEOF(ppi->pi_ptrs_size));
Need to check the return values here too.
> +
> +out:
> + kmem_free(ppi);
> + return error;
> +}
> +
> int
> xfs_ioc_swapext(
> xfs_swapext_t *sxp)
> @@ -1894,7 +1952,8 @@ xfs_file_ioctl(
> return xfs_ioc_getxflags(ip, arg);
> case XFS_IOC_SETXFLAGS:
> return xfs_ioc_setxflags(ip, filp, arg);
> -
> + case XFS_IOC_GETPPOINTER:
> + return xfs_ioc_get_parent_pointer(filp, arg);
> case XFS_IOC_FSSETDM: {
> struct fsdmidata dmi;
>
> diff --git a/fs/xfs/xfs_parent_utils.c b/fs/xfs/xfs_parent_utils.c
> index 0fd48b8..1df003a 100644
> --- a/fs/xfs/xfs_parent_utils.c
> +++ b/fs/xfs/xfs_parent_utils.c
> @@ -68,3 +68,69 @@ xfs_parent_remove_deferred(
> ATTR_PARENT);
> }
>
> +/*
> + * Get the parent pointers for a given inode
> + *
> + * Returns 0 on success and non zero on error
> + */
> +int
> +xfs_attr_get_parent_pointer(struct xfs_inode *ip,
> + struct xfs_pptr_info *ppi)
> +
> +{
> +
> + struct attrlist *alist;
> + struct attrlist_ent *aent;
> + struct xfs_parent_ptr *xpp;
> + struct xfs_parent_name_rec *xpnr;
> + char *namebuf;
> + unsigned int namebuf_size;
> + int name_len;
> + int error = 0;
> + unsigned int flags = ATTR_PARENT;
> + int i;
> +
> + /* Allocate a buffer to store the attribute names */
> + namebuf_size = sizeof(struct attrlist) +
> + (ppi->pi_ptrs_size) * sizeof(struct attrlist_ent);
> + namebuf = kmem_zalloc_large(namebuf_size, KM_SLEEP);
> + if (!namebuf)
> + return -ENOMEM;
> +
> + error = xfs_attr_list(ip, namebuf, namebuf_size, flags,
I suspect we need to hold the ILOCK across the xfs_attr_list call and
the xfs_attr_get loop so that we hold the attr list consistent while
extracting parent pointer information; see xfs_attr_list_int_ilocked and
xfs_attr_get_ilocked...
--D
> + (attrlist_cursor_kern_t *)&ppi->pi_cursor);
> + if (error)
> + goto out_kfree;
> +
> + alist = (struct attrlist *)namebuf;
> +
> + for (i = 0; i < alist->al_count; i++) {
> + xpp = XFS_PPINFO_TO_PP(ppi, i);
> + memset(xpp, 0, sizeof(struct xfs_parent_ptr));
> + aent = (struct attrlist_ent *) &namebuf[alist->al_offset[i]];
> + xpnr = (struct xfs_parent_name_rec *)(aent->a_name);
> +
> + if (aent->a_valuelen > XFS_PPTR_MAXNAMELEN) {
> + error = -ERANGE;
> + goto out_kfree;
> + }
> +
> + name_len = aent->a_valuelen;
> + error = xfs_attr_get(ip, (char *)xpnr,
> + sizeof(struct xfs_parent_name_rec),
> + (unsigned char *)(xpp->xpp_name),
> + &name_len, flags);
> + if (error)
> + goto out_kfree;
> +
> + xpp->xpp_namelen = name_len;
> + xfs_init_parent_ptr(xpp, xpnr);
> + }
> + ppi->pi_ptrs_used = alist->al_count;
> +
> +out_kfree:
> + kmem_free(namebuf);
> +
> + return error;
> +}
> +
> diff --git a/fs/xfs/xfs_parent_utils.h b/fs/xfs/xfs_parent_utils.h
> index 9e0ac13..33e3b2c 100644
> --- a/fs/xfs/xfs_parent_utils.h
> +++ b/fs/xfs/xfs_parent_utils.h
> @@ -27,4 +27,6 @@ int xfs_parent_remove_deferred(struct xfs_inode *parent,
> struct xfs_inode *child,
> xfs_dir2_dataptr_t diroffset,
> struct xfs_defer_ops *dfops);
> +int xfs_attr_get_parent_pointer(struct xfs_inode *ip,
> + struct xfs_pptr_info *ppi);
> #endif /* __XFS_PARENT_UTILS_H__ */
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 19/21] xfs: Add the parent pointer support to the superblock version 5.
2018-05-06 17:24 ` [PATCH 19/21] xfs: Add the parent pointer support to the superblock version 5 Allison Henderson
@ 2018-05-07 21:38 ` Darrick J. Wong
2018-05-08 16:58 ` Allison Henderson
0 siblings, 1 reply; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 21:38 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:52AM -0700, Allison Henderson wrote:
> [dchinner: forward ported and cleaned up]
> [achender: rebased and added parent pointer attribute to
> compatible attributes mask]
>
> Signed-off-by: Mark Tinguely <tinguely@sgi.com>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Old kernels can't accidentally start returning the ATTR_PARENT
attributes, right? I think the answer is yes.....?
If so,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
--D
> ---
> fs/xfs/libxfs/xfs_format.h | 7 +++++--
> fs/xfs/libxfs/xfs_fs.h | 1 +
> fs/xfs/libxfs/xfs_sb.c | 2 ++
> fs/xfs/xfs_super.c | 4 ++++
> 4 files changed, 12 insertions(+), 2 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index 5e946c8..d05ffc5 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -462,10 +462,12 @@ xfs_sb_has_compat_feature(
> #define XFS_SB_FEAT_RO_COMPAT_FINOBT (1 << 0) /* free inode btree */
> #define XFS_SB_FEAT_RO_COMPAT_RMAPBT (1 << 1) /* reverse map btree */
> #define XFS_SB_FEAT_RO_COMPAT_REFLINK (1 << 2) /* reflinked files */
> +#define XFS_SB_FEAT_RO_COMPAT_PARENT (1 << 3) /* parent inode ptr */
> #define XFS_SB_FEAT_RO_COMPAT_ALL \
> (XFS_SB_FEAT_RO_COMPAT_FINOBT | \
> XFS_SB_FEAT_RO_COMPAT_RMAPBT | \
> - XFS_SB_FEAT_RO_COMPAT_REFLINK)
> + XFS_SB_FEAT_RO_COMPAT_REFLINK| \
> + XFS_SB_FEAT_RO_COMPAT_PARENT)
> #define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALL
> static inline bool
> xfs_sb_has_ro_compat_feature(
> @@ -561,7 +563,8 @@ static inline bool xfs_sb_version_hasreflink(struct xfs_sb *sbp)
>
> static inline bool xfs_sb_version_hasparent(struct xfs_sb *sbp)
> {
> - return false; /* We'll enable this at the end of the set */
> + return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 &&
> + (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_PARENT));
> }
>
> /*
> diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
> index faf1a4e..641e0af 100644
> --- a/fs/xfs/libxfs/xfs_fs.h
> +++ b/fs/xfs/libxfs/xfs_fs.h
> @@ -222,6 +222,7 @@ typedef struct xfs_fsop_resblks {
> #define XFS_FSOP_GEOM_FLAGS_SPINODES 0x40000 /* sparse inode chunks */
> #define XFS_FSOP_GEOM_FLAGS_RMAPBT 0x80000 /* reverse mapping btree */
> #define XFS_FSOP_GEOM_FLAGS_REFLINK 0x100000 /* files can share blocks */
> +#define XFS_FSOP_GEOM_FLAGS_PARENT 0x200000 /* parent pointers */
>
> /*
> * Minimum and maximum sizes need for growth checks.
> diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
> index d9b94bd..e1f0ac1 100644
> --- a/fs/xfs/libxfs/xfs_sb.c
> +++ b/fs/xfs/libxfs/xfs_sb.c
> @@ -955,6 +955,8 @@ xfs_fs_geometry(
> geo->flags |= XFS_FSOP_GEOM_FLAGS_RMAPBT;
> if (xfs_sb_version_hasreflink(sbp))
> geo->flags |= XFS_FSOP_GEOM_FLAGS_REFLINK;
> + if(xfs_sb_version_hasparent(sbp))
> + geo->flags |= XFS_FSOP_GEOM_FLAGS_PARENT;
> if (xfs_sb_version_hassector(sbp))
> geo->logsectsize = sbp->sb_logsectsize;
> else
> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> index dce3baf..366deee 100644
> --- a/fs/xfs/xfs_super.c
> +++ b/fs/xfs/xfs_super.c
> @@ -1731,6 +1731,10 @@ xfs_fs_fill_super(
> goto out_filestream_unmount;
> }
>
> + if (xfs_sb_version_hasparent(&mp->m_sb))
> + xfs_alert(mp,
> + "EXPERIMENTAL parent pointer feature enabled. Use at your own risk!");
> +
> error = xfs_mountfs(mp);
> if (error)
> goto out_filestream_unmount;
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 18/21] xfs: Add parent pointers to rename
2018-05-06 17:24 ` [PATCH 18/21] xfs: Add parent pointers to rename Allison Henderson
@ 2018-05-07 21:52 ` Darrick J. Wong
2018-05-08 16:58 ` Allison Henderson
2018-05-08 10:04 ` Amir Goldstein
1 sibling, 1 reply; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 21:52 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:51AM -0700, Allison Henderson wrote:
> This patch removes the old parent pointer attribute during the
> rename operation, and re-adds the updated parent pointer
>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
> fs/xfs/xfs_inode.c | 68 +++++++++++++++++++++++++++++++++++++++++-------------
> 1 file changed, 52 insertions(+), 16 deletions(-)
>
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index b18b20c..7fd1479 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -3004,6 +3004,8 @@ xfs_rename(
> bool src_is_directory = S_ISDIR(VFS_I(src_ip)->i_mode);
> int spaceres;
> int error;
> + xfs_dir2_dataptr_t new_diroffset;
> + xfs_dir2_dataptr_t old_diroffset;
>
> trace_xfs_rename(src_dp, target_dp, src_name, target_name);
>
> @@ -3058,14 +3060,14 @@ xfs_rename(
> * we can rely on either trans_commit or trans_cancel to unlock
> * them.
> */
> - xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL);
> + xfs_trans_ijoin(tp, src_dp, 0);
> if (new_parent)
> - xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL);
> - xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
> + xfs_trans_ijoin(tp, target_dp, 0);
> + xfs_trans_ijoin(tp, src_ip, 0);
> if (target_ip)
> - xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
> + xfs_trans_ijoin(tp, target_ip, 0);
> if (wip)
> - xfs_trans_ijoin(tp, wip, XFS_ILOCK_EXCL);
> + xfs_trans_ijoin(tp, wip, 0);
>
> /*
> * If we are using project inheritance, we only allow renames
> @@ -3075,17 +3077,18 @@ xfs_rename(
> if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
> (xfs_get_projid(target_dp) != xfs_get_projid(src_ip)))) {
> error = -EXDEV;
> - goto out_trans_cancel;
> + goto out_unlock;
> }
>
> xfs_defer_init(&dfops, &first_block);
>
> /* RENAME_EXCHANGE is unique from here on. */
> - if (flags & RENAME_EXCHANGE)
> - return xfs_cross_rename(tp, src_dp, src_name, src_ip,
> + if (flags & RENAME_EXCHANGE) {
> + error = xfs_cross_rename(tp, src_dp, src_name, src_ip,
> target_dp, target_name, target_ip,
> &dfops, &first_block, spaceres);
> -
> + goto out;
> + }
> /*
> * Set up the target.
> */
> @@ -3097,7 +3100,7 @@ xfs_rename(
> if (!spaceres) {
> error = xfs_dir_canenter(tp, target_dp, target_name);
> if (error)
> - goto out_trans_cancel;
> + goto out_unlock;
> }
> /*
> * If target does not exist and the rename crosses
> @@ -3106,7 +3109,7 @@ xfs_rename(
> */
> error = xfs_dir_createname(tp, target_dp, target_name,
> src_ip->i_ino, &first_block, &dfops,
> - spaceres, NULL);
> + spaceres, &new_diroffset);
> if (error)
> goto out_bmap_cancel;
>
> @@ -3131,7 +3134,7 @@ xfs_rename(
> if (!(xfs_dir_isempty(target_ip)) ||
> (VFS_I(target_ip)->i_nlink > 2)) {
> error = -EEXIST;
> - goto out_trans_cancel;
> + goto out_unlock;
> }
> }
>
> @@ -3146,7 +3149,7 @@ xfs_rename(
> */
> error = xfs_dir_replace(tp, target_dp, target_name,
> src_ip->i_ino, &first_block, &dfops,
> - spaceres, NULL);
> + spaceres, &new_diroffset);
> if (error)
> goto out_bmap_cancel;
>
> @@ -3181,7 +3184,7 @@ xfs_rename(
> */
> error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,
> target_dp->i_ino, &first_block, &dfops,
> - spaceres, NULL);
> + spaceres, &new_diroffset);
> ASSERT(error != -EEXIST);
> if (error)
> goto out_bmap_cancel;
> @@ -3220,11 +3223,12 @@ xfs_rename(
> */
> if (wip) {
> error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino,
> - &first_block, &dfops, spaceres, NULL);
> + &first_block, &dfops, spaceres,
> + &old_diroffset);
> } else
> error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
> &first_block, &dfops, spaceres,
> - NULL);
> + &old_diroffset);
> if (error)
> goto out_bmap_cancel;
>
> @@ -3254,6 +3258,18 @@ xfs_rename(
> VFS_I(wip)->i_state &= ~I_LINKABLE;
> }
>
> + if (xfs_sb_version_hasparent(&mp->m_sb)) {
> + error = xfs_parent_add_deferred(target_dp, src_ip, target_name,
> + new_diroffset, &dfops);
Only two indents needed for the second line:
error = xfs_parent_add_deferred(target_dp, src_ip, target_name,
new_diroffset, &dfops);
if (error)
goto out_bmap_cancel;
> + if (error)
> + goto out_bmap_cancel;
> +
> + error = xfs_parent_remove_deferred(src_dp, src_ip,
> + old_diroffset, &dfops);
> + if (error)
> + goto out_bmap_cancel;
> + }
> +
> xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
> xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE);
> if (new_parent)
> @@ -3262,10 +3278,30 @@ xfs_rename(
> error = xfs_finish_rename(tp, &dfops);
> if (wip)
> IRELE(wip);
> +out:
> + if (wip)
> + xfs_iunlock(wip, XFS_ILOCK_EXCL);
IRELE = iput = release inode, which means that you have to unlock the
wip inode before you can release it.
--D
> + if (target_ip)
> + xfs_iunlock(target_ip, XFS_ILOCK_EXCL);
> + xfs_iunlock(src_ip, XFS_ILOCK_EXCL);
> + if (new_parent)
> + xfs_iunlock(target_dp, XFS_ILOCK_EXCL);
> + xfs_iunlock(src_dp, XFS_ILOCK_EXCL);
> +
> return error;
>
> out_bmap_cancel:
> xfs_defer_cancel(&dfops);
> +out_unlock:
> + if (wip)
> + xfs_iunlock(wip, XFS_ILOCK_EXCL);
> + if (target_ip)
> + xfs_iunlock(target_ip, XFS_ILOCK_EXCL);
> + xfs_iunlock(src_ip, XFS_ILOCK_EXCL);
> + if (new_parent)
> + xfs_iunlock(target_dp, XFS_ILOCK_EXCL);
> + xfs_iunlock(src_dp, XFS_ILOCK_EXCL);
> +
> out_trans_cancel:
> xfs_trans_cancel(tp);
> out_release_wip:
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 17/21] xfs: remove parent pointers in unlink
2018-05-06 17:24 ` [PATCH 17/21] xfs: remove parent pointers in unlink Allison Henderson
@ 2018-05-07 21:59 ` Darrick J. Wong
2018-05-08 16:58 ` Allison Henderson
0 siblings, 1 reply; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 21:59 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:50AM -0700, Allison Henderson wrote:
> From: Dave Chinner <dchinner@redhat.com>
>
> This patch removes the parent pointer attribute during unlink
>
> [bfoster: rebase, use VFS inode generation]
> [achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t
> implemented xfs_attr_remove_parent]
>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
> fs/xfs/xfs_inode.c | 21 ++++++++++++++++-----
> fs/xfs/xfs_parent_utils.c | 19 +++++++++++++++++++
> fs/xfs/xfs_parent_utils.h | 4 ++++
> 3 files changed, 39 insertions(+), 5 deletions(-)
>
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 3a68e72..b18b20c 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -2624,6 +2624,7 @@ xfs_remove(
> struct xfs_defer_ops dfops;
> xfs_fsblock_t first_block;
> uint resblks;
> + xfs_dir2_dataptr_t dir_offset;
>
> trace_xfs_remove(dp, name);
>
> @@ -2661,8 +2662,8 @@ xfs_remove(
>
> xfs_lock_two_inodes(dp, XFS_ILOCK_EXCL, ip, XFS_ILOCK_EXCL);
>
> - xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
> - xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
> + xfs_trans_ijoin(tp, dp, 0);
> + xfs_trans_ijoin(tp, ip, 0);
>
> /*
> * If we're removing a directory perform some additional validation.
> @@ -2704,12 +2705,18 @@ xfs_remove(
>
> xfs_defer_init(&dfops, &first_block);
> error = xfs_dir_removename(tp, dp, name, ip->i_ino, &first_block,
> - &dfops, resblks, NULL);
> + &dfops, resblks, &dir_offset);
> if (error) {
> ASSERT(error != -ENOENT);
> goto out_bmap_cancel;
> }
>
> + if (xfs_sb_version_hasparent(&mp->m_sb)) {
> + error = xfs_parent_remove_deferred(dp, ip, dir_offset, &dfops);
> + if (error)
> + goto out_bmap_cancel;
> + }
> +
> /*
> * If this is a synchronous mount, make sure that the
> * remove transaction goes to disk before returning to
> @@ -2724,17 +2731,21 @@ xfs_remove(
>
> error = xfs_trans_commit(tp);
> if (error)
> - goto std_return;
> + goto out_unlock;
>
> if (is_dir && xfs_inode_is_filestream(ip))
> xfs_filestream_deassociate(ip);
>
> - return 0;
> + error = 0;
> + goto out_unlock;
I'd unlock the two inodes directly here instead of mixing the sucess
return path with the error paths.
>
> out_bmap_cancel:
> xfs_defer_cancel(&dfops);
> out_trans_cancel:
> xfs_trans_cancel(tp);
> +out_unlock:
> + xfs_iunlock(ip, XFS_ILOCK_EXCL);
> + xfs_iunlock(dp, XFS_ILOCK_EXCL);
> std_return:
> return error;
> }
> diff --git a/fs/xfs/xfs_parent_utils.c b/fs/xfs/xfs_parent_utils.c
> index cf4a7e2..0fd48b8 100644
> --- a/fs/xfs/xfs_parent_utils.c
> +++ b/fs/xfs/xfs_parent_utils.c
> @@ -49,3 +49,22 @@ xfs_parent_add_deferred(
> (void *)child_name->name, child_name->len, ATTR_PARENT);
> }
>
> +/*
> + * Remove a parent record from a child inode.
> + */
> +int
> +xfs_parent_remove_deferred(
> + struct xfs_inode *parent,
> + struct xfs_inode *child,
> + xfs_dir2_dataptr_t diroffset,
> + struct xfs_defer_ops *dfops)
> +{
> + struct xfs_parent_name_rec rec;
> +
> + xfs_init_parent_name_rec(&rec, parent->i_ino,
> + VFS_I(parent)->i_generation, diroffset);
> +
> + return xfs_attr_remove_deferred(child, dfops, &rec, sizeof(rec),
> + ATTR_PARENT);
Two indents, no need to align these with the left paren.
--D
> +}
> +
> diff --git a/fs/xfs/xfs_parent_utils.h b/fs/xfs/xfs_parent_utils.h
> index a667d1d..9e0ac13 100644
> --- a/fs/xfs/xfs_parent_utils.h
> +++ b/fs/xfs/xfs_parent_utils.h
> @@ -23,4 +23,8 @@
> int xfs_parent_add_deferred(struct xfs_inode *parent, struct xfs_inode *child,
> struct xfs_name *child_name, uint32_t diroffset,
> struct xfs_defer_ops *dfops);
> +int xfs_parent_remove_deferred(struct xfs_inode *parent,
> + struct xfs_inode *child,
> + xfs_dir2_dataptr_t diroffset,
> + struct xfs_defer_ops *dfops);
> #endif /* __XFS_PARENT_UTILS_H__ */
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 16/21] xfs: add parent attributes to link
2018-05-06 17:24 ` [PATCH 16/21] xfs: add parent attributes to link Allison Henderson
@ 2018-05-07 22:12 ` Darrick J. Wong
2018-05-08 16:58 ` Allison Henderson
0 siblings, 1 reply; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 22:12 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:49AM -0700, Allison Henderson wrote:
> From: Dave Chinner <dchinner@redhat.com>
>
> This patch modifies xfs_link to add a parent pointer to the inode.
> xfs_link will also need to create an attribute fork if the inode does
> not already have one.
>
> [bfoster: rebase, use VFS inode fields, fix xfs_bmap_finish() usage]
> [achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
> fixed null pointer bugs]
>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
> fs/xfs/xfs_inode.c | 66 ++++++++++++++++++++++++++++++++++++++++++------------
> 1 file changed, 52 insertions(+), 14 deletions(-)
>
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index a515f11..3a68e72 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -1421,6 +1421,8 @@ xfs_link(
> struct xfs_defer_ops dfops;
> xfs_fsblock_t first_block;
> int resblks;
> + xfs_dir2_dataptr_t diroffset;
> + bool first_parent = false;
>
> trace_xfs_link(tdp, target_name);
>
> @@ -1437,6 +1439,25 @@ xfs_link(
> if (error)
> goto std_return;
>
> + /*
> + * If we have parent pointers and there is no attribute fork (i.e. we
> + * are linking in a O_TMPFILE created inode) we need to add the
> + * attribute fork to the inode. Because we may have an existing data
> + * fork, we do this before we start the link transaction as adding an
> + * attribute fork requires it's own transaction.
> + */
> + if (xfs_sb_version_hasparent(&mp->m_sb) && !xfs_inode_hasattr(sip)) {
> + int sf_size = sizeof(struct xfs_attr_sf_hdr) +
> + XFS_ATTR_SF_ENTSIZE_BYNAME(
> + sizeof(struct xfs_parent_name_rec),
> + target_name->len);
> + ASSERT(VFS_I(sip)->i_nlink == 0);
> + error = xfs_bmap_add_attrfork(sip, sf_size, 0);
> + if (error)
> + goto std_return;
> + first_parent = true;
Can adding the attribute fork ought to be made part of the finish step
for deferred xattr setting? xfs_attr_finish_item() could do something
like:
if (!xfs_inode_hasattr(ip)) {
sf_size = sizeof(...) + free->xattri_name_len;
error = xfs_bmap_add_attrfork(free->xattri_ip, sf_size, 0);
if (error)
goto out_free;
return -EAGAIN;
}
error = xfs_trans_attr(...existing stuff...);
kmem_free(free);
out_free:
return error;
The 'return -EAGAIN' tells the log item code that it needs to roll the
transaction and then call us back to add the attr.
--D
> + }
> +
> resblks = XFS_LINK_SPACE_RES(mp, target_name->len);
> error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, resblks, 0, 0, &tp);
> if (error == -ENOSPC) {
> @@ -1448,8 +1469,8 @@ xfs_link(
>
> xfs_lock_two_inodes(sip, XFS_ILOCK_EXCL, tdp, XFS_ILOCK_EXCL);
>
> - xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL);
> - xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL);
> + xfs_trans_ijoin(tp, sip, 0);
> + xfs_trans_ijoin(tp, tdp, 0);
>
> /*
> * If we are using project inheritance, we only allow hard link
> @@ -1468,8 +1489,6 @@ xfs_link(
> goto error_return;
> }
>
> - xfs_defer_init(&dfops, &first_block);
> -
> /*
> * Handle initial link state of O_TMPFILE inode
> */
> @@ -1479,16 +1498,30 @@ xfs_link(
> goto error_return;
> }
>
> + xfs_defer_init(&dfops, &first_block);
> error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
> - &first_block, &dfops, resblks, NULL);
> + &first_block, &dfops, resblks, &diroffset);
> if (error)
> - goto error_return;
> + goto out_defer_cancel;
> xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
> xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
>
> error = xfs_bumplink(tp, sip);
> if (error)
> - goto error_return;
> + goto out_defer_cancel;
> +
> + /*
> + * If we have parent pointers, we now need to add the parent record to
> + * the attribute fork of the inode. If this is the initial parent
> + * attribute, we need to create it correctly, otherwise we can just add
> + * the parent to the inode.
> + */
> + if (xfs_sb_version_hasparent(&mp->m_sb)) {
> + error = xfs_parent_add_deferred(tdp, sip, target_name,
> + diroffset, &dfops);
> + if (error)
> + goto out_defer_cancel;
> + }
>
> /*
> * If this is a synchronous mount, make sure that the
> @@ -1499,16 +1532,21 @@ xfs_link(
> xfs_trans_set_sync(tp);
>
> error = xfs_defer_finish(&tp, &dfops);
> - if (error) {
> - xfs_defer_cancel(&dfops);
> - goto error_return;
> - }
> + if (error)
> + goto out_defer_cancel;
>
> - return xfs_trans_commit(tp);
> + error = xfs_trans_commit(tp);
> + xfs_iunlock(tdp, XFS_ILOCK_EXCL);
> + xfs_iunlock(sip, XFS_ILOCK_EXCL);
> + return error;
>
> - error_return:
> +out_defer_cancel:
> + xfs_defer_cancel(&dfops);
> +error_return:
> xfs_trans_cancel(tp);
> - std_return:
> + xfs_iunlock(tdp, XFS_ILOCK_EXCL);
> + xfs_iunlock(sip, XFS_ILOCK_EXCL);
> +std_return:
> return error;
> }
>
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 15/21] xfs: parent pointer attribute creation
2018-05-06 17:24 ` [PATCH 15/21] xfs: parent pointer attribute creation Allison Henderson
@ 2018-05-07 22:19 ` Darrick J. Wong
2018-05-08 16:58 ` Allison Henderson
0 siblings, 1 reply; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 22:19 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:48AM -0700, Allison Henderson wrote:
> From: Dave Chinner <dchinner@redhat.com>
>
> Add parent pointer attribute during xfs_create, and
> subroutines to initialize attributes
>
> Kernel create routines take advantage of deferred attributes,
> where as libxfs routines will add parent pointers directly.
>
> [bfoster: rebase, use VFS inode generation]
> [achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
> fixed some null pointer bugs,
> merged error handling patch,
> added subroutines to handle attribute initialization,
> remove unnecessary ENOSPC handling in xfs_attr_set_first_parent]
>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
> fs/xfs/Makefile | 2 +
> fs/xfs/libxfs/xfs_parent.c | 158 +++++++++++++++++++++++++++++++++++++++++++++
> fs/xfs/libxfs/xfs_parent.h | 36 +++++++++++
> fs/xfs/xfs_inode.c | 22 ++++++-
> fs/xfs/xfs_parent_utils.c | 51 +++++++++++++++
> fs/xfs/xfs_parent_utils.h | 26 ++++++++
> 6 files changed, 292 insertions(+), 3 deletions(-)
>
> diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
> index d3c0004..d092f72 100644
> --- a/fs/xfs/Makefile
> +++ b/fs/xfs/Makefile
> @@ -53,6 +53,7 @@ xfs-y += $(addprefix libxfs/, \
> xfs_inode_fork.o \
> xfs_inode_buf.o \
> xfs_log_rlimit.o \
> + xfs_parent.o \
> xfs_ag_resv.o \
> xfs_rmap.o \
> xfs_rmap_btree.o \
> @@ -92,6 +93,7 @@ xfs-y += xfs_aops.o \
> xfs_message.o \
> xfs_mount.o \
> xfs_mru_cache.o \
> + xfs_parent_utils.o \
> xfs_reflink.o \
> xfs_stats.o \
> xfs_super.o \
> diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
> new file mode 100644
> index 0000000..e6de97c
> --- /dev/null
> +++ b/fs/xfs/libxfs/xfs_parent.c
> @@ -0,0 +1,158 @@
> +/*
> + * Copyright (c) 2015 Red Hat, Inc.
> + * All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write the Free Software Foundation
> + */
> +#include "xfs.h"
> +#include "xfs_fs.h"
> +#include "xfs_format.h"
> +#include "xfs_da_format.h"
> +#include "xfs_log_format.h"
> +#include "xfs_shared.h"
> +#include "xfs_trans_resv.h"
> +#include "xfs_mount.h"
> +#include "xfs_bmap_btree.h"
> +#include "xfs_inode.h"
> +#include "xfs_error.h"
> +#include "xfs_trace.h"
> +#include "xfs_trans.h"
> +#include "xfs_attr.h"
> +#include "xfs_da_btree.h"
> +#include "xfs_attr_sf.h"
> +#include "xfs_bmap.h"
> +
> +/*
> + * Parent pointer attribute handling.
> + *
> + * Because the attribute value is a filename component, it will never be longer
> + * than 255 bytes. This means the attribute will always be a local format
> + * attribute as it is xfs_attr_leaf_entsize_local_max() for v5 filesystems will
> + * always be larger than this (max is 75% of block size).
> + *
> + * Creating a new parent attribute will always create a new attribute - there
> + * should never, ever be an existing attribute in the tree for a new inode.
> + * ENOSPC behaviour is problematic - creating the inode without the parent
> + * pointer is effectively a corruption, so we allow parent attribute creation
> + * to dip into the reserve block pool to avoid unexpected ENOSPC errors from
> + * occurring.
> + */
> +
> +
> +/* Initializes a xfs_parent_name_rec to be stored as an attribute name */
> +void
> +xfs_init_parent_name_rec(
> + struct xfs_parent_name_rec *rec,
> + xfs_ino_t p_ino,
> + uint32_t p_gen,
Seeing as both parameters are always from the same inode, just pass in
the inode to extract the inode number & generation.
> + uint32_t p_diroffset)
Only one indent here and in the other function definitions.
uint32_t p_diroffset)
> +{
> + rec->p_ino = cpu_to_be64(p_ino);
> + rec->p_gen = cpu_to_be32(p_gen);
> + rec->p_diroffset = cpu_to_be32(p_diroffset);
> +}
> +
> +/* Initializes a xfs_parent_name_irec from an xfs_parent_name_rec */
> +void
> +xfs_init_parent_name_irec(
> + struct xfs_parent_name_irec *irec,
> + struct xfs_parent_name_rec *rec)
> +{
> + irec->p_ino = be64_to_cpu(rec->p_ino);
> + irec->p_gen = be32_to_cpu(rec->p_gen);
> + irec->p_diroffset = be32_to_cpu(rec->p_diroffset);
> +}
> +
> +/*
> + * Directly add a parent pointer instead of as a deferred operation
> + * Currently only used during protofile creation
> + */
> +int
> +xfs_parent_add(
> + struct xfs_inode *parent,
> + struct xfs_inode *child,
> + struct xfs_name *child_name,
> + uint32_t diroffset,
> + xfs_fsblock_t *firstblock,
> + struct xfs_defer_ops *dfops)
> +{
> + struct xfs_parent_name_rec rec;
Indentation between the variable type and name should be consistent
with the parameters. In other words, the parameters need an extra tab
before the name.
> + int error;
> + struct xfs_da_args args;
> + int flags = ATTR_PARENT;
> + int local = 0;
> + int rsvd = 0;
> + struct xfs_buf *leaf_bp = NULL;
> + struct xfs_trans_res tres;
> + struct xfs_mount *mp = child->i_mount;
> +
> + xfs_init_parent_name_rec(&rec, parent->i_ino,
> + VFS_I(parent)->i_generation, diroffset);
> +
> + error = xfs_attr_args_init(&args, child, (const unsigned char *)&rec,
> + sizeof(rec), flags);
> + if (error)
> + return error;
> +
> + args.hashval = xfs_da_hashname(args.name, args.namelen);
> + args.value = (char *)child_name->name;
> + args.valuelen = child_name->len;
> + args.dfops = dfops;
> + args.op_flags = XFS_DA_OP_OKNOENT | XFS_DA_OP_ADDNAME;
> + args.firstblock = firstblock;
> + args.total = xfs_attr_calc_size(&args, &local);
> + ASSERT(local);
> +
> + tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
> + M_RES(mp)->tr_attrsetrt.tr_logres * args.total;
> + tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
> + tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
> +
> + /*
> + * Root fork attributes can use reserved data blocks for this
> + * operation if necessary
> + */
> + error = xfs_trans_alloc(mp, &tres, args.total, 0,
> + rsvd ? XFS_TRANS_RESERVE : 0, &args.trans);
> + if (error)
> + goto out;
> +
> + /*
> + * If the inode doesn't have an attribute fork, add one.
> + * (inode must not be locked when we call this routine)
> + */
> + if (XFS_IFORK_Q(child) == 0) {
> + int sf_size = sizeof(xfs_attr_sf_hdr_t) +
> + XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, args.valuelen);
> +
> + error = xfs_bmap_add_attrfork(child, sf_size, rsvd);
> + if (error)
> + return error;
> + }
> +
> + error = xfs_attr_set_args(&args, flags, leaf_bp, false);
> +
> + if (error)
> + goto out;
> +
> + xfs_trans_log_inode(args.trans, child, XFS_ILOG_CORE);
> +
> + return error;
> +
> +out:
> + if (args.trans)
> + xfs_trans_cancel(args.trans);
> +
> + return error;
> +}
> +
> diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h
> new file mode 100644
> index 0000000..298562b
> --- /dev/null
> +++ b/fs/xfs/libxfs/xfs_parent.h
> @@ -0,0 +1,36 @@
> +/*
> + * Copyright (c) 2017 Oracle, Inc.
Please update the copyright year. :)
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write the Free Software Foundation Inc.
> + */
> +#ifndef __XFS_PARENT_H__
> +#define __XFS_PARENT_H__
> +
> +#include "xfs_da_format.h"
> +#include "xfs_format.h"
> +
> +/*
> + * Parent pointer attribute prototypes
> + */
> +void xfs_init_parent_name_rec(struct xfs_parent_name_rec *rec,
> + xfs_ino_t p_ino, uint32_t p_gen,
> + uint32_t p_diroffset);
> +void xfs_init_parent_name_irec(struct xfs_parent_name_irec *irec,
> + struct xfs_parent_name_rec *rec);
> +
> +int xfs_parent_add(struct xfs_trans *tp, struct xfs_inode *parent,
> + struct xfs_inode *child, struct xfs_name *child_name,
> + uint32_t diroffset, xfs_fsblock_t *firstblock,
> + struct xfs_defer_ops *dfops);
> +#endif /* __XFS_PARENT_H__ */
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 2859a697..a515f11 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -53,6 +53,7 @@
> #include "xfs_bmap_btree.h"
> #include "xfs_reflink.h"
> #include "xfs_dir2_priv.h"
> +#include "xfs_parent_utils.h"
>
> kmem_zone_t *xfs_inode_zone;
>
> @@ -1152,6 +1153,7 @@ xfs_create(
> struct xfs_dquot *pdqp = NULL;
> struct xfs_trans_res *tres;
> uint resblks;
> + xfs_dir2_dataptr_t diroffset;
>
> trace_xfs_create(dp, name);
>
> @@ -1211,7 +1213,7 @@ xfs_create(
> * entry pointing to them, but a directory also the "." entry
> * pointing to itself.
> */
> - error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, prid, &ip, XFS_ILOCK_EXCL);
> + error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, prid, &ip, 0);
> if (error)
> goto out_trans_cancel;
>
> @@ -1222,13 +1224,13 @@ xfs_create(
> * the transaction cancel unlocking dp so don't do it explicitly in the
> * error path.
> */
> - xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
> + xfs_trans_ijoin(tp, dp, 0);
> unlock_dp_on_error = false;
>
> error = xfs_dir_createname(tp, dp, name, ip->i_ino,
> &first_block, &dfops, resblks ?
> resblks - XFS_IALLOC_SPACE_RES(mp) : 0,
> - NULL);
> + &diroffset);
> if (error) {
> ASSERT(error != -ENOSPC);
> goto out_trans_cancel;
> @@ -1247,6 +1249,17 @@ xfs_create(
> }
>
> /*
> + * If we have parent pointers, we need to add the attribute containing
> + * the parent information now.
Trailing whitespace (see scripts/checkpatch.pl)
> + */
> + if (xfs_sb_version_hasparent(&mp->m_sb)) {
> + error = xfs_parent_add_deferred(dp, ip, name, diroffset,
> + &dfops);
> + if (error)
> + goto out_bmap_cancel;
> + }
> +
> + /*
> * If this is a synchronous mount, make sure that the
> * create transaction goes to disk before returning to
> * the user.
> @@ -1274,6 +1287,9 @@ xfs_create(
> xfs_qm_dqrele(pdqp);
>
> *ipp = ip;
> + xfs_iunlock(ip, XFS_ILOCK_EXCL);
> + xfs_iunlock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
> +
> return 0;
>
> out_bmap_cancel:
> diff --git a/fs/xfs/xfs_parent_utils.c b/fs/xfs/xfs_parent_utils.c
> new file mode 100644
> index 0000000..cf4a7e2
> --- /dev/null
> +++ b/fs/xfs/xfs_parent_utils.c
> @@ -0,0 +1,51 @@
> +/*
> + * Copyright (c) 2015 Red Hat, Inc.
> + * All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write the Free Software Foundation
> + */
> +#include "xfs.h"
> +#include "xfs_fs.h"
> +#include "xfs_format.h"
> +#include "xfs_log_format.h"
> +#include "xfs_shared.h"
> +#include "xfs_trans_resv.h"
> +#include "xfs_mount.h"
> +#include "xfs_bmap_btree.h"
> +#include "xfs_inode.h"
> +#include "xfs_error.h"
> +#include "xfs_trace.h"
> +#include "xfs_trans.h"
> +#include "xfs_attr.h"
> +#include "xfs_parent.h"
> +
> +/*
> + * Add a parent record to an inode with existing parent records.
> + */
> +int
> +xfs_parent_add_deferred(
> + struct xfs_inode *parent,
> + struct xfs_inode *child,
> + struct xfs_name *child_name,
> + uint32_t diroffset,
> + struct xfs_defer_ops *dfops)
> +{
> + struct xfs_parent_name_rec rec;
> +
> + xfs_init_parent_name_rec(&rec, parent->i_ino,
> + VFS_I(parent)->i_generation, diroffset);
> +
> + return xfs_attr_set_deferred(child, dfops, &rec, sizeof(rec),
> + (void *)child_name->name, child_name->len, ATTR_PARENT);
Needs two indents here.
return xfs_attr_set_deferred(child, dfops, &rec, sizeof(rec),
(void *)child_name->name, child_name->len, ATTR_PARENT);
Looks ok otherwise.
--D
> +}
> +
> diff --git a/fs/xfs/xfs_parent_utils.h b/fs/xfs/xfs_parent_utils.h
> new file mode 100644
> index 0000000..a667d1d
> --- /dev/null
> +++ b/fs/xfs/xfs_parent_utils.h
> @@ -0,0 +1,26 @@
> +/*
> + * Copyright (c) 2017 Oracle, Inc.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write the Free Software Foundation Inc.
> + */
> +#ifndef __XFS_PARENT_UTILS_H__
> +#define __XFS_PARENT_UTILS_H__
> +
> +/*
> + * Parent pointer attribute prototypes
> + */
> +int xfs_parent_add_deferred(struct xfs_inode *parent, struct xfs_inode *child,
> + struct xfs_name *child_name, uint32_t diroffset,
> + struct xfs_defer_ops *dfops);
> +#endif /* __XFS_PARENT_UTILS_H__ */
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 14/21] Add lock_flags to xfs_ialloc and xfs_dir_ialloc
2018-05-06 17:24 ` [PATCH 14/21] Add lock_flags to xfs_ialloc and xfs_dir_ialloc Allison Henderson
@ 2018-05-07 22:30 ` Darrick J. Wong
2018-05-08 16:59 ` Allison Henderson
0 siblings, 1 reply; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 22:30 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:47AM -0700, Allison Henderson wrote:
> Add lock_flags to xfs_ialloc and xfs_dir_ialloc to control
> whick locks are released by xfs_trans_ijoin. We will need this
> later in defered parent pointers
>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
> fs/xfs/xfs_inode.c | 17 +++++++++--------
> fs/xfs/xfs_inode.h | 2 +-
> fs/xfs/xfs_qm.c | 2 +-
> fs/xfs/xfs_symlink.c | 2 +-
> 4 files changed, 12 insertions(+), 11 deletions(-)
>
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 5c291d2..2859a697 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -766,7 +766,8 @@ xfs_ialloc(
> dev_t rdev,
> prid_t prid,
> xfs_buf_t **ialloc_context,
> - xfs_inode_t **ipp)
> + xfs_inode_t **ipp,
> + int lock_flags)
Wait, what?
Oh, these are the locks we want *dropped* at the first _trans_commit
after this call returns, and for xfs_create we need to retain the ilock
while we roll the transaction(s) during _defer_finish; and for
everything else (create temp file, create quota inode, and symlink??) we
want the ilock dropped as soon as the transaction commits.
I dislike having this oddly named parameter, can we amend the comment to
say that the caller is responsible for unlocking the inode manually
(i.e. we're going to xfs_trans_ijoin(tp, ip, 0)) , and then change all
the callers to do the iunlock explicitly if they need to?
--D
> {
> struct xfs_mount *mp = tp->t_mountp;
> xfs_ino_t ino;
> @@ -942,7 +943,7 @@ xfs_ialloc(
> /*
> * Log the new values stuffed into the inode.
> */
> - xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
> + xfs_trans_ijoin(tp, ip, lock_flags);
> xfs_trans_log_inode(tp, ip, flags);
>
> /* now that we have an i_mode we can setup the inode structure */
> @@ -972,8 +973,8 @@ xfs_dir_ialloc(
> xfs_nlink_t nlink,
> dev_t rdev,
> prid_t prid, /* project id */
> - xfs_inode_t **ipp) /* pointer to inode; it will be
> - locked. */
> + xfs_inode_t **ipp, /* pointer to inode; it will be locked. */
> + int lock_flags)
> {
> xfs_trans_t *tp;
> xfs_inode_t *ip;
> @@ -1001,7 +1002,7 @@ xfs_dir_ialloc(
> * the inode(s) that we've just allocated.
> */
> code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, &ialloc_context,
> - &ip);
> + &ip, lock_flags);
>
> /*
> * Return an error if we were unable to allocate a new inode.
> @@ -1071,7 +1072,7 @@ xfs_dir_ialloc(
> * this call should always succeed.
> */
> code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid,
> - &ialloc_context, &ip);
> + &ialloc_context, &ip, lock_flags);
>
> /*
> * If we get an error at this point, return to the caller
> @@ -1210,7 +1211,7 @@ xfs_create(
> * entry pointing to them, but a directory also the "." entry
> * pointing to itself.
> */
> - error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, prid, &ip);
> + error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, prid, &ip, XFS_ILOCK_EXCL);
> if (error)
> goto out_trans_cancel;
>
> @@ -1343,7 +1344,7 @@ xfs_create_tmpfile(
> if (error)
> goto out_trans_cancel;
>
> - error = xfs_dir_ialloc(&tp, dp, mode, 1, 0, prid, &ip);
> + error = xfs_dir_ialloc(&tp, dp, mode, 1, 0, prid, &ip, XFS_ILOCK_EXCL);
> if (error)
> goto out_trans_cancel;
>
> diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
> index 1eebc53..466f252 100644
> --- a/fs/xfs/xfs_inode.h
> +++ b/fs/xfs/xfs_inode.h
> @@ -431,7 +431,7 @@ xfs_extlen_t xfs_get_cowextsz_hint(struct xfs_inode *ip);
>
> int xfs_dir_ialloc(struct xfs_trans **, struct xfs_inode *, umode_t,
> xfs_nlink_t, dev_t, prid_t,
> - struct xfs_inode **);
> + struct xfs_inode **, int lock_flags);
>
> /* from xfs_file.c */
> enum xfs_prealloc_flags {
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index ec39ae2..3e68a52 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -787,7 +787,7 @@ xfs_qm_qino_alloc(
> return error;
>
> if (need_alloc) {
> - error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, ip);
> + error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, ip, XFS_ILOCK_EXCL);
> if (error) {
> xfs_trans_cancel(tp);
> return error;
> diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
> index b1d3301..ce8dbea 100644
> --- a/fs/xfs/xfs_symlink.c
> +++ b/fs/xfs/xfs_symlink.c
> @@ -264,7 +264,7 @@ xfs_symlink(
> * Allocate an inode for the symlink.
> */
> error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT), 1, 0,
> - prid, &ip);
> + prid, &ip, XFS_ILOCK_EXCL);
> if (error)
> goto out_trans_cancel;
>
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 13/21] xfs: extent transaction reservations for parent attributes
2018-05-06 17:24 ` [PATCH 13/21] xfs: extent transaction reservations for parent attributes Allison Henderson
@ 2018-05-07 22:34 ` Darrick J. Wong
2018-05-08 17:00 ` Allison Henderson
0 siblings, 1 reply; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 22:34 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:46AM -0700, Allison Henderson wrote:
> From: Dave Chinner <dchinner@redhat.com>
>
> We need to add, remove or modify parent pointer attributes during
> create/link/unlink/rename operations atomically with the dirents in the parent
> directories being modified. This means they need to be modified in the same
> transaction as the parent directories, and so we need to add the required
> space for the attribute modifications to the transaction reservations.
>
> [achender: rebased, added xfs_sb_version_hasparent stub]
>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
> fs/xfs/libxfs/xfs_format.h | 5 ++
> fs/xfs/libxfs/xfs_trans_resv.c | 111 ++++++++++++++++++++++++++++++++---------
> fs/xfs/libxfs/xfs_trans_resv.h | 1 +
> 3 files changed, 94 insertions(+), 23 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index 42956d8..5e946c8 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -559,6 +559,11 @@ static inline bool xfs_sb_version_hasreflink(struct xfs_sb *sbp)
> (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_REFLINK);
> }
>
> +static inline bool xfs_sb_version_hasparent(struct xfs_sb *sbp)
> +{
> + return false; /* We'll enable this at the end of the set */
> +}
> +
> /*
> * end of superblock version macros
> */
> diff --git a/fs/xfs/libxfs/xfs_trans_resv.c b/fs/xfs/libxfs/xfs_trans_resv.c
> index 3bccdf7..76440fb 100644
> --- a/fs/xfs/libxfs/xfs_trans_resv.c
> +++ b/fs/xfs/libxfs/xfs_trans_resv.c
> @@ -787,29 +787,30 @@ xfs_calc_sb_reservation(
> return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize);
> }
>
> +/*
> + * Namespace reservations.
> + *
> + * These get tricky when parent pointers are enabled as we have attribute
> + * modifications occurring from within these transactions. Rather than confuse
> + * each of these reservation calculations with the conditional attribute
> + * reservations, add them here in a clear and concise manner. This assumes that
> + * the attribute reservations have already been calculated.
> + *
> + * Note that we only include the static attribute reservation here; the runtime
> + * reservation will have to be modified by the size of the attributes being
> + * added/removed/modified. See the comments on the attribute reservation
> + * calculations for more details.
> + *
> + * Note for rename: rename will vastly overestimate requirements. This will be
> + * addressed later when modifications are made to ensure parent attribute
> + * modifications can be done atomically with the rename operation.
> + */
> void
> -xfs_trans_resv_calc(
> +xfs_calc_namespace_reservations(
> struct xfs_mount *mp,
> struct xfs_trans_resv *resp)
> {
> - /*
> - * The following transactions are logged in physical format and
> - * require a permanent reservation on space.
> - */
> - resp->tr_write.tr_logres = xfs_calc_write_reservation(mp);
> - if (xfs_sb_version_hasreflink(&mp->m_sb))
> - resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK;
> - else
> - resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT;
> - resp->tr_write.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
> -
> - resp->tr_itruncate.tr_logres = xfs_calc_itruncate_reservation(mp);
> - if (xfs_sb_version_hasreflink(&mp->m_sb))
> - resp->tr_itruncate.tr_logcount =
> - XFS_ITRUNCATE_LOG_COUNT_REFLINK;
> - else
> - resp->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT;
> - resp->tr_itruncate.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
> + ASSERT(resp->tr_attrsetm.tr_logres > 0);
>
> resp->tr_rename.tr_logres = xfs_calc_rename_reservation(mp);
> resp->tr_rename.tr_logcount = XFS_RENAME_LOG_COUNT;
> @@ -831,15 +832,77 @@ xfs_trans_resv_calc(
> resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT;
> resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
>
> + resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp);
> + resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT;
> + resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
> +
> + xfs_calc_parent_ptr_reservations(mp);
> +}
> +
> +void xfs_calc_parent_ptr_reservations(struct xfs_mount *mp)
Parameter goes on the next line, please.
> +{
> + struct xfs_trans_resv *resp = M_RES(mp);
> +
> + /* Calculate extra space needed for parent pointer attributes */
> + if (!xfs_sb_version_hasparent(&mp->m_sb))
> + return;
> +
> + /* rename can add/remove/modify 2 parent attributes */
> + resp->tr_rename.tr_logres += 2 * max(resp->tr_attrsetm.tr_logres,
> + resp->tr_attrrm.tr_logres);
> + resp->tr_rename.tr_logcount += 2 * max(resp->tr_attrsetm.tr_logcount,
> + resp->tr_attrrm.tr_logcount);
RENAME_EXCHANGE can perform four updates -- remove pptr from both
inodes, then add the (now swapped) to both inodes.
> +
> + /* create will add 1 parent attribute */
> + resp->tr_create.tr_logres += resp->tr_attrsetm.tr_logres;
> + resp->tr_create.tr_logcount += resp->tr_attrsetm.tr_logcount;
> +
> + /* mkdir will add 1 parent attribute */
> + resp->tr_mkdir.tr_logres += resp->tr_attrsetm.tr_logres;
> + resp->tr_mkdir.tr_logcount += resp->tr_attrsetm.tr_logcount;
> +
> + /* link will add 1 parent attribute */
> + resp->tr_link.tr_logres += resp->tr_attrsetm.tr_logres;
> + resp->tr_link.tr_logcount += resp->tr_attrsetm.tr_logcount;
> +
> + /* symlink will add 1 parent attribute */
> + resp->tr_symlink.tr_logres += resp->tr_attrsetm.tr_logres;
> + resp->tr_symlink.tr_logcount += resp->tr_attrsetm.tr_logcount;
> +
> + /* remove will remove 1 parent attribute */
> + resp->tr_remove.tr_logres += resp->tr_attrrm.tr_logres;
> + resp->tr_remove.tr_logcount += resp->tr_attrrm.tr_logcount;
> +}
> +
> +void
> +xfs_trans_resv_calc(
> + struct xfs_mount *mp,
> + struct xfs_trans_resv *resp)
> +{
> + /*
> + * The following transactions are logged in physical format and
> + * require a permanent reservation on space.
> + */
> + resp->tr_write.tr_logres = xfs_calc_write_reservation(mp);
> + if (xfs_sb_version_hasreflink(&mp->m_sb))
> + resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK;
> + else
> + resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT;
> + resp->tr_write.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
> +
> + resp->tr_itruncate.tr_logres = xfs_calc_itruncate_reservation(mp);
> + if (xfs_sb_version_hasreflink(&mp->m_sb))
> + resp->tr_itruncate.tr_logcount =
> + XFS_ITRUNCATE_LOG_COUNT_REFLINK;
> + else
> + resp->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT;
> + resp->tr_itruncate.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
> +
> resp->tr_create_tmpfile.tr_logres =
> xfs_calc_create_tmpfile_reservation(mp);
> resp->tr_create_tmpfile.tr_logcount = XFS_CREATE_TMPFILE_LOG_COUNT;
> resp->tr_create_tmpfile.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
>
> - resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp);
> - resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT;
> - resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
> -
> resp->tr_ifree.tr_logres = xfs_calc_ifree_reservation(mp);
> resp->tr_ifree.tr_logcount = XFS_INACTIVE_LOG_COUNT;
> resp->tr_ifree.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
> @@ -871,6 +934,8 @@ xfs_trans_resv_calc(
> resp->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT;
> resp->tr_qm_dqalloc.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
>
> + xfs_calc_namespace_reservations(mp, resp);
> +
> /*
> * The following transactions are logged in logical format with
> * a default log count.
> diff --git a/fs/xfs/libxfs/xfs_trans_resv.h b/fs/xfs/libxfs/xfs_trans_resv.h
> index b7e5357..c7190d6 100644
> --- a/fs/xfs/libxfs/xfs_trans_resv.h
> +++ b/fs/xfs/libxfs/xfs_trans_resv.h
> @@ -105,5 +105,6 @@ struct xfs_trans_resv {
>
> void xfs_trans_resv_calc(struct xfs_mount *mp, struct xfs_trans_resv *resp);
> uint xfs_allocfree_log_count(struct xfs_mount *mp, uint num_ops);
> +void xfs_calc_parent_ptr_reservations(struct xfs_mount *mp);
Are we going to need this outside xfs_trans_resv.c? If not, leave it private.
--D
>
> #endif /* __XFS_TRANS_RESV_H__ */
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 12/21] xfs: define parent pointer xattr format
2018-05-06 17:24 ` [PATCH 12/21] xfs: define parent pointer xattr format Allison Henderson
@ 2018-05-07 22:35 ` Darrick J. Wong
2018-05-08 17:00 ` Allison Henderson
0 siblings, 1 reply; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 22:35 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:45AM -0700, Allison Henderson wrote:
> From: Dave Chinner <dchinner@redhat.com>
>
> We need to define the parent pointer attribute format before we
> start adding support for it into all the code that needs to use it.
> The EA format we will use encodes the following information:
>
> name={parent inode #, parent inode generation, dirent offset}
> value={dirent filename}
>
> The inode/gen gives all the information we need to reliably identify
> the parent without requiring child->parent lock ordering, and allows
> userspace to do pathname component level reconstruction without the
> kernel ever needing to verify the parent itself as part of ioctl
> calls.
>
> By using the dirent offset in the EA name, we have a method of
> knowing the exact parent pointer EA we need to modify/remove in
> rename/unlink without an unbound EA name search.
>
> By keeping the dirent name in the value, we have enough information
> to be able to validate and reconstruct damaged directory trees.
> While the diroffset of a filename alone is not unique enough to
> identify the child, the {diroffset,filename,child_inode} tuple is
> sufficient. That is, if the diroffset gets reused and points to a
> different filename, we can detect that from the contents of EA. If a
> link of the same name is created, then we can check whether it
> points at the same inode as the parent EA we current have.
>
> [achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
> changed p_ino to xfs_ino_t and p_namelen to uint8_t,
> moved to xfs_da_format for xfs_dir2_dataptr_t]
>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> Reviewed-by: Darrick J. Wong<darrick.wong@oracle.com>
> ---
> fs/xfs/libxfs/xfs_da_format.h | 26 +++++++++++++++++++++++++-
> 1 file changed, 25 insertions(+), 1 deletion(-)
>
> diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h
> index 9bd2e6b..d1c1221 100644
> --- a/fs/xfs/libxfs/xfs_da_format.h
> +++ b/fs/xfs/libxfs/xfs_da_format.h
> @@ -878,11 +878,35 @@ struct xfs_attr3_rmt_hdr {
> #define XFS_ATTR3_RMT_BUF_SPACE(mp, bufsize) \
> ((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \
> sizeof(struct xfs_attr3_rmt_hdr) : 0))
> -
Unrelated/unnecessary whitespace removal? Otherwise this is still
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
--D
> /* Number of bytes in a directory block. */
> static inline unsigned int xfs_dir2_dirblock_bytes(struct xfs_sb *sbp)
> {
> return 1 << (sbp->sb_blocklog + sbp->sb_dirblklog);
> }
>
> +/*
> + * Parent pointer attribute format definition
> + *
> + * EA name encodes the parent inode number, generation and the offset of
> + * the dirent that points to the child inode. The EA value contains the
> + * same name as the dirent in the parent directory.
> + */
> +struct xfs_parent_name_rec {
> + __be64 p_ino;
> + __be32 p_gen;
> + __be32 p_diroffset;
> +};
> +
> +/*
> + * incore version of the above, also contains name pointers so callers
> + * can pass/obtain all the parent pointer information in a single structure
> + */
> +struct xfs_parent_name_irec {
> + xfs_ino_t p_ino;
> + uint32_t p_gen;
> + xfs_dir2_dataptr_t p_diroffset;
> + const char *p_name;
> + uint8_t p_namelen;
> +};
> +
> #endif /* __XFS_DA_FORMAT_H__ */
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 11/21] xfs: add parent pointer support to attribute code
2018-05-06 17:24 ` [PATCH 11/21] xfs: add parent pointer support to attribute code Allison Henderson
@ 2018-05-07 22:36 ` Darrick J. Wong
0 siblings, 0 replies; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 22:36 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:44AM -0700, Allison Henderson wrote:
> From: Mark Tinguely <tinguely@sgi.com>
>
> Add the new parent attribute type. XFS_ATTR_PARENT is used only for
> parent pointer entries; it uses reserved blocks like XFS_ATTR_ROOT.
>
> [dchinner: forward ported and cleaned up]
> [achender: rebased]
>
> Signed-off-by: Mark Tinguely <tinguely@sgi.com>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Looks ok,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
--D
> ---
> fs/xfs/libxfs/xfs_attr.c | 2 +-
> fs/xfs/libxfs/xfs_attr.h | 2 ++
> fs/xfs/libxfs/xfs_da_format.h | 12 ++++++++----
> 3 files changed, 11 insertions(+), 5 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 484fa86..41b31dc 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -377,7 +377,7 @@ xfs_attr_set(
> struct xfs_defer_ops dfops;
> struct xfs_trans_res tres;
> xfs_fsblock_t firstblock;
> - int rsvd = (flags & ATTR_ROOT) != 0;
> + bool rsvd = (flags & (ATTR_ROOT | ATTR_PARENT)) != 0;
> int error, local;
>
> XFS_STATS_INC(mp, xs_attr_set);
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index 308a93e..d041734 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -46,6 +46,7 @@ struct xfs_attr_list_context;
> #define ATTR_SECURE 0x0008 /* use attrs in security namespace */
> #define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */
> #define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */
> +#define ATTR_PARENT 0x0040 /* use attrs in parent namespace */
>
> #define ATTR_KERNOTIME 0x1000 /* [kernel] don't update inode timestamps */
> #define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */
> @@ -59,6 +60,7 @@ struct xfs_attr_list_context;
> { ATTR_SECURE, "SECURE" }, \
> { ATTR_CREATE, "CREATE" }, \
> { ATTR_REPLACE, "REPLACE" }, \
> + { ATTR_PARENT, "PARENT" }, \
> { ATTR_KERNOTIME, "KERNOTIME" }, \
> { ATTR_KERNOVAL, "KERNOVAL" }, \
> { ATTR_INCOMPLETE, "INCOMPLETE" }
> diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h
> index 7e77299..9bd2e6b 100644
> --- a/fs/xfs/libxfs/xfs_da_format.h
> +++ b/fs/xfs/libxfs/xfs_da_format.h
> @@ -758,24 +758,28 @@ struct xfs_attr3_icleaf_hdr {
> #define XFS_ATTR_LOCAL_BIT 0 /* attr is stored locally */
> #define XFS_ATTR_ROOT_BIT 1 /* limit access to trusted attrs */
> #define XFS_ATTR_SECURE_BIT 2 /* limit access to secure attrs */
> +#define XFS_ATTR_PARENT_BIT 3 /* parent pointer secure attrs */
> #define XFS_ATTR_INCOMPLETE_BIT 7 /* attr in middle of create/delete */
> #define XFS_ATTR_LOCAL (1 << XFS_ATTR_LOCAL_BIT)
> #define XFS_ATTR_ROOT (1 << XFS_ATTR_ROOT_BIT)
> #define XFS_ATTR_SECURE (1 << XFS_ATTR_SECURE_BIT)
> +#define XFS_ATTR_PARENT (1 << XFS_ATTR_PARENT_BIT)
> #define XFS_ATTR_INCOMPLETE (1 << XFS_ATTR_INCOMPLETE_BIT)
>
> /*
> * Conversion macros for converting namespace bits from argument flags
> * to ondisk flags.
> */
> -#define XFS_ATTR_NSP_ARGS_MASK (ATTR_ROOT | ATTR_SECURE)
> -#define XFS_ATTR_NSP_ONDISK_MASK (XFS_ATTR_ROOT | XFS_ATTR_SECURE)
> +#define XFS_ATTR_NSP_ARGS_MASK (ATTR_ROOT | ATTR_SECURE | XFS_ATTR_PARENT)
> +#define XFS_ATTR_NSP_ONDISK_MASK (XFS_ATTR_ROOT | XFS_ATTR_SECURE | XFS_ATTR_PARENT)
> #define XFS_ATTR_NSP_ONDISK(flags) ((flags) & XFS_ATTR_NSP_ONDISK_MASK)
> #define XFS_ATTR_NSP_ARGS(flags) ((flags) & XFS_ATTR_NSP_ARGS_MASK)
> #define XFS_ATTR_NSP_ARGS_TO_ONDISK(x) (((x) & ATTR_ROOT ? XFS_ATTR_ROOT : 0) |\
> - ((x) & ATTR_SECURE ? XFS_ATTR_SECURE : 0))
> + ((x) & ATTR_SECURE ? XFS_ATTR_SECURE : 0) | \
> + ((x) & ATTR_PARENT ? XFS_ATTR_PARENT : 0))
> #define XFS_ATTR_NSP_ONDISK_TO_ARGS(x) (((x) & XFS_ATTR_ROOT ? ATTR_ROOT : 0) |\
> - ((x) & XFS_ATTR_SECURE ? ATTR_SECURE : 0))
> + ((x) & XFS_ATTR_SECURE ? ATTR_SECURE : 0) | \
> + ((x) & XFS_ATTR_PARENT ? ATTR_PARENT : 0))
>
> /*
> * Alignment for namelist and valuelist entries (since they are mixed
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 10/21] xfs: get directory offset when replacing a directory name
2018-05-06 17:24 ` [PATCH 10/21] xfs: get directory offset when replacing a " Allison Henderson
@ 2018-05-07 22:45 ` Darrick J. Wong
2018-05-08 17:00 ` Allison Henderson
0 siblings, 1 reply; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 22:45 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:43AM -0700, Allison Henderson wrote:
> From: Mark Tinguely <tinguely@sgi.com>
>
> Return the directory offset information when replacing an entry to the
> directory.
>
> This offset will be used as the parent pointer offset in xfs_rename.
>
> [dchinner: forward ported and cleaned up]
> [achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
> Changed typedefs to raw struct types]
>
> Signed-off-by: Mark Tinguely <tinguely@sgi.com>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
> fs/xfs/libxfs/xfs_dir2.c | 16 ++++++++++------
> fs/xfs/libxfs/xfs_dir2.h | 3 ++-
> fs/xfs/libxfs/xfs_dir2_block.c | 4 ++--
> fs/xfs/libxfs/xfs_dir2_leaf.c | 1 +
> fs/xfs/libxfs/xfs_dir2_node.c | 1 +
> fs/xfs/libxfs/xfs_dir2_sf.c | 2 ++
> fs/xfs/xfs_inode.c | 28 +++++++++++++---------------
> 7 files changed, 31 insertions(+), 24 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
> index 090ab0e..a4f7bcd 100644
> --- a/fs/xfs/libxfs/xfs_dir2.c
> +++ b/fs/xfs/libxfs/xfs_dir2.c
> @@ -499,13 +499,14 @@ xfs_dir_removename(
> */
> int
> xfs_dir_replace(
> - xfs_trans_t *tp,
> - xfs_inode_t *dp,
> - struct xfs_name *name, /* name of entry to replace */
> - xfs_ino_t inum, /* new inode number */
> - xfs_fsblock_t *first, /* bmap's firstblock */
> + struct xfs_trans *tp,
> + struct xfs_inode *dp,
> + struct xfs_name *name, /* name of entry to replace */
> + xfs_ino_t inum, /* new inode number */
> + xfs_fsblock_t *first, /* bmap's firstblock */
> struct xfs_defer_ops *dfops, /* bmap's freeblock list */
> - xfs_extlen_t total) /* bmap's total block count */
> + xfs_extlen_t total, /* bmap's total block count */
> + xfs_dir2_dataptr_t *offset) /* OUT: offset in directory */
> {
> struct xfs_da_args *args;
> int rval;
> @@ -555,6 +556,9 @@ xfs_dir_replace(
> else
> rval = xfs_dir2_node_replace(args);
> out_free:
> + if (offset)
> + *offset = args->offset;
Just from a outvar purity point of view, we should only set *offset if
we're not also returning an error. AFAICT there's no practical
consequence for setting *offset and returning a negative number, just a
nit to pick. :P
The rest looks ok, so:
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
--D
> +
> kmem_free(args);
> return rval;
> }
> diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
> index b73bdcb..d361442 100644
> --- a/fs/xfs/libxfs/xfs_dir2.h
> +++ b/fs/xfs/libxfs/xfs_dir2.h
> @@ -145,7 +145,8 @@ extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
> extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
> struct xfs_name *name, xfs_ino_t inum,
> xfs_fsblock_t *first,
> - struct xfs_defer_ops *dfops, xfs_extlen_t tot);
> + struct xfs_defer_ops *dfops, xfs_extlen_t tot,
> + xfs_dir2_dataptr_t *offset);
> extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp,
> struct xfs_name *name);
>
> diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
> index 9c1e485..77744e5 100644
> --- a/fs/xfs/libxfs/xfs_dir2_block.c
> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
> @@ -872,9 +872,9 @@ xfs_dir2_block_replace(
> /*
> * Point to the data entry we need to change.
> */
> + args->offset = be32_to_cpu(blp[ent].address);
> dep = (xfs_dir2_data_entry_t *)((char *)hdr +
> - xfs_dir2_dataptr_to_off(args->geo,
> - be32_to_cpu(blp[ent].address)));
> + xfs_dir2_dataptr_to_off(args->geo, args->offset));
> ASSERT(be64_to_cpu(dep->inumber) != args->inumber);
> /*
> * Change the inode number to the new value.
> diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
> index c5595c1..6ad7741 100644
> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
> @@ -1550,6 +1550,7 @@ xfs_dir2_leaf_replace(
> /*
> * Point to the data entry.
> */
> + args->offset = be32_to_cpu(lep->address);
> dep = (xfs_dir2_data_entry_t *)
> ((char *)dbp->b_addr +
> xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address)));
> diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
> index eb8b240..ccf220a 100644
> --- a/fs/xfs/libxfs/xfs_dir2_node.c
> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
> @@ -2256,6 +2256,7 @@ xfs_dir2_node_replace(
> hdr = state->extrablk.bp->b_addr;
> ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
> hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC));
> + args->offset = be32_to_cpu(lep->address);
> dep = (xfs_dir2_data_entry_t *)
> ((char *)hdr +
> xfs_dir2_dataptr_to_off(args->geo,
> diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
> index 1d0957c..73f1eef 100644
> --- a/fs/xfs/libxfs/xfs_dir2_sf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_sf.c
> @@ -1043,6 +1043,8 @@ xfs_dir2_sf_replace(
> ASSERT(args->inumber != ino);
> dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
> dp->d_ops->sf_put_ftype(sfep, args->filetype);
> + args->offset = xfs_dir2_byte_to_dataptr(
> + xfs_dir2_sf_get_offset(sfep));
> break;
> }
> }
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 3054e9a..5c291d2 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -2783,16 +2783,14 @@ xfs_cross_rename(
> int dp2_flags = 0;
>
> /* Swap inode number for dirent in first parent */
> - error = xfs_dir_replace(tp, dp1, name1,
> - ip2->i_ino,
> - first_block, dfops, spaceres);
> + error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, first_block, dfops,
> + spaceres, NULL);
> if (error)
> goto out_trans_abort;
>
> /* Swap inode number for dirent in second parent */
> - error = xfs_dir_replace(tp, dp2, name2,
> - ip1->i_ino,
> - first_block, dfops, spaceres);
> + error = xfs_dir_replace(tp, dp2, name2, ip1->i_ino, first_block, dfops,
> + spaceres, NULL);
> if (error)
> goto out_trans_abort;
>
> @@ -2806,8 +2804,8 @@ xfs_cross_rename(
>
> if (S_ISDIR(VFS_I(ip2)->i_mode)) {
> error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot,
> - dp1->i_ino, first_block,
> - dfops, spaceres);
> + dp1->i_ino, first_block, dfops,
> + spaceres, NULL);
> if (error)
> goto out_trans_abort;
>
> @@ -2833,8 +2831,8 @@ xfs_cross_rename(
>
> if (S_ISDIR(VFS_I(ip1)->i_mode)) {
> error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot,
> - dp2->i_ino, first_block,
> - dfops, spaceres);
> + dp2->i_ino, first_block, dfops,
> + spaceres, NULL);
> if (error)
> goto out_trans_abort;
>
> @@ -3081,8 +3079,8 @@ xfs_rename(
> * name at the destination directory, remove it first.
> */
> error = xfs_dir_replace(tp, target_dp, target_name,
> - src_ip->i_ino,
> - &first_block, &dfops, spaceres);
> + src_ip->i_ino, &first_block, &dfops,
> + spaceres, NULL);
> if (error)
> goto out_bmap_cancel;
>
> @@ -3116,8 +3114,8 @@ xfs_rename(
> * directory.
> */
> error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,
> - target_dp->i_ino,
> - &first_block, &dfops, spaceres);
> + target_dp->i_ino, &first_block, &dfops,
> + spaceres, NULL);
> ASSERT(error != -EEXIST);
> if (error)
> goto out_bmap_cancel;
> @@ -3156,7 +3154,7 @@ xfs_rename(
> */
> if (wip) {
> error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino,
> - &first_block, &dfops, spaceres);
> + &first_block, &dfops, spaceres, NULL);
> } else
> error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
> &first_block, &dfops, spaceres,
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 09/21] xfs: get directory offset when removing directory name
2018-05-06 17:24 ` [PATCH 09/21] xfs: get directory offset when removing " Allison Henderson
@ 2018-05-07 22:48 ` Darrick J. Wong
2018-05-08 17:00 ` Allison Henderson
0 siblings, 1 reply; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 22:48 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:42AM -0700, Allison Henderson wrote:
> From: Mark Tinguely <tinguely@sgi.com>
>
> Return the directory offset information when removing an entry to the
> directory.
>
> This offset will be used as the parent pointer offset in xfs_remove.
>
> [dchinner: forward ported and cleaned up]
> [achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
> Changed typedefs to raw struct types]
>
> Signed-off-by: Mark Tinguely <tinguely@sgi.com>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
> fs/xfs/libxfs/xfs_dir2.c | 16 ++++++++++------
> fs/xfs/libxfs/xfs_dir2.h | 4 +++-
> fs/xfs/libxfs/xfs_dir2_block.c | 4 ++--
> fs/xfs/libxfs/xfs_dir2_leaf.c | 5 +++--
> fs/xfs/libxfs/xfs_dir2_node.c | 5 +++--
> fs/xfs/libxfs/xfs_dir2_sf.c | 2 ++
> fs/xfs/xfs_inode.c | 7 ++++---
> 7 files changed, 27 insertions(+), 16 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
> index 409a1e7..090ab0e 100644
> --- a/fs/xfs/libxfs/xfs_dir2.c
> +++ b/fs/xfs/libxfs/xfs_dir2.c
> @@ -433,13 +433,14 @@ xfs_dir_lookup(
> */
> int
> xfs_dir_removename(
> - xfs_trans_t *tp,
> - xfs_inode_t *dp,
> - struct xfs_name *name,
> - xfs_ino_t ino,
> - xfs_fsblock_t *first, /* bmap's firstblock */
> + struct xfs_trans *tp,
> + struct xfs_inode *dp,
> + struct xfs_name *name,
> + xfs_ino_t ino,
> + xfs_fsblock_t *first, /* bmap's firstblock */
> struct xfs_defer_ops *dfops, /* bmap's freeblock list */
> - xfs_extlen_t total) /* bmap's total block count */
> + xfs_extlen_t total, /* bmap's total block count */
> + xfs_dir2_dataptr_t *offset) /* OUT: offset in directory */
> {
> struct xfs_da_args *args;
> int rval;
> @@ -486,6 +487,9 @@ xfs_dir_removename(
> else
> rval = xfs_dir2_node_removename(args);
> out_free:
> + if (offset)
> + *offset = args->offset;
> +
> kmem_free(args);
> return rval;
> }
> diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
> index c98a3ca..b73bdcb 100644
> --- a/fs/xfs/libxfs/xfs_dir2.h
> +++ b/fs/xfs/libxfs/xfs_dir2.h
> @@ -139,7 +139,9 @@ extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
> extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
> struct xfs_name *name, xfs_ino_t ino,
> xfs_fsblock_t *first,
> - struct xfs_defer_ops *dfops, xfs_extlen_t tot);
> + struct xfs_defer_ops *dfops,
> + xfs_extlen_t tot,
> + xfs_dir2_dataptr_t *offset);
> extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
> struct xfs_name *name, xfs_ino_t inum,
> xfs_fsblock_t *first,
> diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
> index 9b7f173..9c1e485 100644
> --- a/fs/xfs/libxfs/xfs_dir2_block.c
> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
> @@ -798,9 +798,9 @@ xfs_dir2_block_removename(
> /*
> * Point to the data entry using the leaf entry.
> */
> + args->offset = be32_to_cpu(blp[ent].address);
> dep = (xfs_dir2_data_entry_t *)((char *)hdr +
> - xfs_dir2_dataptr_to_off(args->geo,
> - be32_to_cpu(blp[ent].address)));
> + xfs_dir2_dataptr_to_off(args->geo, args->offset));
> /*
> * Mark the data entry's space free.
> */
> diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
> index 8ae2953..c5595c1 100644
> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
> @@ -1414,9 +1414,10 @@ xfs_dir2_leaf_removename(
> * Point to the leaf entry, use that to point to the data entry.
> */
> lep = &ents[index];
> - db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address));
> + args->offset = be32_to_cpu(lep->address);
> + db = xfs_dir2_dataptr_to_db(args->geo, args->offset);
> dep = (xfs_dir2_data_entry_t *)((char *)hdr +
> - xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address)));
> + xfs_dir2_dataptr_to_off(args->geo, args->offset));
> needscan = needlog = 0;
> oldbest = be16_to_cpu(bf[0].length);
> ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
> diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
> index 4e544f7..eb8b240 100644
> --- a/fs/xfs/libxfs/xfs_dir2_node.c
> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
> @@ -1252,9 +1252,10 @@ xfs_dir2_leafn_remove(
> /*
> * Extract the data block and offset from the entry.
> */
> - db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address));
> + args->offset = be32_to_cpu(lep->address);
> + db = xfs_dir2_dataptr_to_db(args->geo, args->offset);
> ASSERT(dblk->blkno == db);
> - off = xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address));
> + off = xfs_dir2_dataptr_to_off(args->geo, args->offset);
> ASSERT(dblk->index == off);
>
> /*
> diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
> index 222ccf5..1d0957c 100644
> --- a/fs/xfs/libxfs/xfs_dir2_sf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_sf.c
> @@ -917,6 +917,8 @@ xfs_dir2_sf_removename(
> XFS_CMP_EXACT) {
> ASSERT(dp->d_ops->sf_get_ino(sfp, sfep) ==
> args->inumber);
> + args->offset = xfs_dir2_byte_to_dataptr(
> + xfs_dir2_sf_get_offset(sfep));
> break;
> }
> }
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index fc07b4f..3054e9a 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -2648,8 +2648,8 @@ xfs_remove(
> goto out_trans_cancel;
>
> xfs_defer_init(&dfops, &first_block);
> - error = xfs_dir_removename(tp, dp, name, ip->i_ino,
> - &first_block, &dfops, resblks);
> + error = xfs_dir_removename(tp, dp, name, ip->i_ino, &first_block,
> + &dfops, resblks, NULL);
> if (error) {
> ASSERT(error != -ENOENT);
> goto out_bmap_cancel;
> @@ -3159,7 +3159,8 @@ xfs_rename(
> &first_block, &dfops, spaceres);
> } else
> error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
> - &first_block, &dfops, spaceres);
> + &first_block, &dfops, spaceres,
> + NULL);
Two indents for the second & third lines, please.
Otherwise looks ok,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
--D
> if (error)
> goto out_bmap_cancel;
>
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 08/21] xfs: get directory offset when adding directory name
2018-05-06 17:24 ` [PATCH 08/21] xfs: get directory offset when adding directory name Allison Henderson
@ 2018-05-07 22:50 ` Darrick J. Wong
0 siblings, 0 replies; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 22:50 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:41AM -0700, Allison Henderson wrote:
> From: Mark Tinguely <tinguely@sgi.com>
>
> Return the directory offset information when adding an entry to the
> directory.
>
> This offset will be used as the parent pointer offset in xfs_create,
> xfs_symlink, xfs_link and xfs_rename.
>
> [dchinner: forward ported and cleaned up]
> [dchinner: no s-o-b from Mark]
> [bfoster: rebased, use args->geo in dir code]
> [achender: rebased, chaged __uint32_t to xfs_dir2_dataptr_t]
>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Looks ok,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
--D
> ---
> fs/xfs/libxfs/xfs_da_btree.h | 1 +
> fs/xfs/libxfs/xfs_dir2.c | 9 +++++++--
> fs/xfs/libxfs/xfs_dir2.h | 3 ++-
> fs/xfs/libxfs/xfs_dir2_block.c | 1 +
> fs/xfs/libxfs/xfs_dir2_leaf.c | 2 ++
> fs/xfs/libxfs/xfs_dir2_node.c | 2 ++
> fs/xfs/libxfs/xfs_dir2_sf.c | 2 ++
> fs/xfs/xfs_inode.c | 9 +++++----
> fs/xfs/xfs_symlink.c | 2 +-
> 9 files changed, 23 insertions(+), 8 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
> index ae6de17..bce96d6 100644
> --- a/fs/xfs/libxfs/xfs_da_btree.h
> +++ b/fs/xfs/libxfs/xfs_da_btree.h
> @@ -86,6 +86,7 @@ typedef struct xfs_da_args {
> int rmtvaluelen2; /* remote attr value length in bytes */
> int op_flags; /* operation flags */
> enum xfs_dacmp cmpresult; /* name compare result for lookups */
> + xfs_dir2_dataptr_t offset; /* OUT: offset in directory */
> } xfs_da_args_t;
>
> /*
> diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
> index 92f94e1..409a1e7 100644
> --- a/fs/xfs/libxfs/xfs_dir2.c
> +++ b/fs/xfs/libxfs/xfs_dir2.c
> @@ -257,7 +257,8 @@ xfs_dir_createname(
> xfs_ino_t inum, /* new entry inode number */
> xfs_fsblock_t *first, /* bmap's firstblock */
> struct xfs_defer_ops *dfops, /* bmap's freeblock list */
> - xfs_extlen_t total) /* bmap's total block count */
> + xfs_extlen_t total, /* bmap's total block count */
> + xfs_dir2_dataptr_t *offset) /* OUT entry's dir offset */
> {
> struct xfs_da_args *args;
> int rval;
> @@ -313,6 +314,10 @@ xfs_dir_createname(
> rval = xfs_dir2_node_addname(args);
>
> out_free:
> + /* return the location that this entry was place in the parent inode */
> + if (offset)
> + *offset = args->offset;
> +
> kmem_free(args);
> return rval;
> }
> @@ -559,7 +564,7 @@ xfs_dir_canenter(
> xfs_inode_t *dp,
> struct xfs_name *name) /* name of entry to add */
> {
> - return xfs_dir_createname(tp, dp, name, 0, NULL, NULL, 0);
> + return xfs_dir_createname(tp, dp, name, 0, NULL, NULL, 0, NULL);
> }
>
> /*
> diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
> index 989e95a..c98a3ca 100644
> --- a/fs/xfs/libxfs/xfs_dir2.h
> +++ b/fs/xfs/libxfs/xfs_dir2.h
> @@ -131,7 +131,8 @@ extern int xfs_dir_init(struct xfs_trans *tp, struct xfs_inode *dp,
> extern int xfs_dir_createname(struct xfs_trans *tp, struct xfs_inode *dp,
> struct xfs_name *name, xfs_ino_t inum,
> xfs_fsblock_t *first,
> - struct xfs_defer_ops *dfops, xfs_extlen_t tot);
> + struct xfs_defer_ops *dfops, xfs_extlen_t tot,
> + xfs_dir2_dataptr_t *offset);
> extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
> struct xfs_name *name, xfs_ino_t *inum,
> struct xfs_name *ci_name);
> diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
> index 875893d..9b7f173 100644
> --- a/fs/xfs/libxfs/xfs_dir2_block.c
> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
> @@ -559,6 +559,7 @@ xfs_dir2_block_addname(
> dp->d_ops->data_put_ftype(dep, args->filetype);
> tagp = dp->d_ops->data_entry_tag_p(dep);
> *tagp = cpu_to_be16((char *)dep - (char *)hdr);
> + args->offset = xfs_dir2_byte_to_dataptr((char *)dep - (char *)hdr);
> /*
> * Clean up the bestfree array and log the header, tail, and entry.
> */
> diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
> index 50fc9c0..8ae2953 100644
> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
> @@ -894,6 +894,8 @@ xfs_dir2_leaf_addname(
> dp->d_ops->data_put_ftype(dep, args->filetype);
> tagp = dp->d_ops->data_entry_tag_p(dep);
> *tagp = cpu_to_be16((char *)dep - (char *)hdr);
> + args->offset = xfs_dir2_db_off_to_dataptr(args->geo, use_block,
> + (char *)dep - (char *)hdr);
> /*
> * Need to scan fix up the bestfree table.
> */
> diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
> index 9df096c..4e544f7 100644
> --- a/fs/xfs/libxfs/xfs_dir2_node.c
> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
> @@ -2041,6 +2041,8 @@ xfs_dir2_node_addname_int(
> dp->d_ops->data_put_ftype(dep, args->filetype);
> tagp = dp->d_ops->data_entry_tag_p(dep);
> *tagp = cpu_to_be16((char *)dep - (char *)hdr);
> + args->offset = xfs_dir2_db_off_to_dataptr(args->geo, dbno,
> + (char *)dep - (char *)hdr);
> xfs_dir2_data_log_entry(args, dbp, dep);
> /*
> * Rescan the block for bestfree if needed.
> diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
> index 0c75a7f..222ccf5 100644
> --- a/fs/xfs/libxfs/xfs_dir2_sf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_sf.c
> @@ -405,6 +405,7 @@ xfs_dir2_sf_addname_easy(
> memcpy(sfep->name, args->name, sfep->namelen);
> dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
> dp->d_ops->sf_put_ftype(sfep, args->filetype);
> + args->offset = xfs_dir2_byte_to_dataptr(offset);
>
> /*
> * Update the header and inode.
> @@ -496,6 +497,7 @@ xfs_dir2_sf_addname_hard(
> memcpy(sfep->name, args->name, sfep->namelen);
> dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
> dp->d_ops->sf_put_ftype(sfep, args->filetype);
> + args->offset = xfs_dir2_byte_to_dataptr(offset);
> sfp->count++;
> if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)
> sfp->i8count++;
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 2b70c8b..fc07b4f 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -1226,7 +1226,8 @@ xfs_create(
>
> error = xfs_dir_createname(tp, dp, name, ip->i_ino,
> &first_block, &dfops, resblks ?
> - resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
> + resblks - XFS_IALLOC_SPACE_RES(mp) : 0,
> + NULL);
> if (error) {
> ASSERT(error != -ENOSPC);
> goto out_trans_cancel;
> @@ -1462,7 +1463,7 @@ xfs_link(
> }
>
> error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
> - &first_block, &dfops, resblks);
> + &first_block, &dfops, resblks, NULL);
> if (error)
> goto error_return;
> xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
> @@ -3040,8 +3041,8 @@ xfs_rename(
> * to account for the ".." reference from the new entry.
> */
> error = xfs_dir_createname(tp, target_dp, target_name,
> - src_ip->i_ino, &first_block,
> - &dfops, spaceres);
> + src_ip->i_ino, &first_block, &dfops,
> + spaceres, NULL);
> if (error)
> goto out_bmap_cancel;
>
> diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
> index 5b66ac1..b1d3301 100644
> --- a/fs/xfs/xfs_symlink.c
> +++ b/fs/xfs/xfs_symlink.c
> @@ -350,7 +350,7 @@ xfs_symlink(
> * Create the directory entry for the symlink.
> */
> error = xfs_dir_createname(tp, dp, link_name, ip->i_ino,
> - &first_block, &dfops, resblks);
> + &first_block, &dfops, resblks, NULL);
> if (error)
> goto out_bmap_cancel;
> xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 07/21] xfs: Remove all strlen calls in all xfs_attr_* functions for attr names.
2018-05-06 17:24 ` [PATCH 07/21] xfs: Remove all strlen calls in all xfs_attr_* functions for attr names Allison Henderson
@ 2018-05-07 22:54 ` Darrick J. Wong
2018-05-08 17:00 ` Allison Henderson
0 siblings, 1 reply; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 22:54 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:40AM -0700, Allison Henderson wrote:
> Parent pointer attributes use a binary name, so strlen will not work.
> Calling functions will need to pass in the name length
>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
> fs/xfs/libxfs/xfs_attr.c | 12 ++++++++----
> fs/xfs/libxfs/xfs_attr.h | 10 ++++++----
> fs/xfs/xfs_acl.c | 12 +++++++-----
> fs/xfs/xfs_ioctl.c | 13 ++++++++++---
> fs/xfs/xfs_iops.c | 6 ++++--
> fs/xfs/xfs_trans_attr.c | 2 +-
> fs/xfs/xfs_xattr.c | 10 +++++++---
> 7 files changed, 43 insertions(+), 22 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index adbcef2..484fa86 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -80,6 +80,7 @@ xfs_attr_args_init(
> struct xfs_da_args *args,
> struct xfs_inode *dp,
> const unsigned char *name,
> + size_t namelen,
> int flags)
> {
>
> @@ -92,7 +93,7 @@ xfs_attr_args_init(
> args->dp = dp;
> args->flags = flags;
> args->name = name;
> - args->namelen = strlen((const char *)name);
> + args->namelen = namelen;
> if (args->namelen >= MAXNAMELEN)
> return -EFAULT; /* match IRIX behaviour */
>
> @@ -138,6 +139,7 @@ int
> xfs_attr_get(
> struct xfs_inode *ip,
> const unsigned char *name,
> + size_t namelen,
> unsigned char *value,
> int *valuelenp,
> int flags)
> @@ -151,7 +153,7 @@ xfs_attr_get(
> if (XFS_FORCED_SHUTDOWN(ip->i_mount))
> return -EIO;
>
> - error = xfs_attr_args_init(&args, ip, name, flags);
> + error = xfs_attr_args_init(&args, ip, name, namelen, flags);
> if (error)
> return error;
>
> @@ -364,6 +366,7 @@ int
> xfs_attr_set(
> struct xfs_inode *dp,
> const unsigned char *name,
> + size_t namelen,
> unsigned char *value,
> int valuelen,
> int flags)
> @@ -382,7 +385,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;
>
> @@ -513,6 +516,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;
> @@ -526,7 +530,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 ec26565..308a93e 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -171,17 +171,19 @@ int xfs_attr_list_int(struct xfs_attr_list_context *);
> int xfs_inode_hasattr(struct xfs_inode *ip);
> int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
> int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
> - unsigned char *value, int *valuelenp, int flags);
> + size_t namelen, unsigned char *value, int *valuelenp,
> + int flags);
> int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
> - unsigned char *value, int valuelen, int flags);
> + size_t namelen, unsigned char *value, int valuelen, int flags);
> int xfs_attr_set_args(struct xfs_da_args *args, int flags,
> struct xfs_buf *leaf_bp, bool roll_trans);
> -int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
> +int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
> + size_t namelen, int flags);
> int xfs_attr_remove_args(struct xfs_da_args *args, int flags, bool roll_trans);
> int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
> int flags, struct attrlist_cursor_kern *cursor);
> int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
> - const unsigned char *name, int flags);
> + const unsigned char *name, size_t namelen, int flags);
> int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
> int xfs_attr_set_deferred(struct xfs_inode *dp, struct xfs_defer_ops *dfops,
> void *name, unsigned int name_len, void *value,
> diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
> index 3354140..e59b26d 100644
> --- a/fs/xfs/xfs_acl.c
> +++ b/fs/xfs/xfs_acl.c
> @@ -153,8 +153,8 @@ xfs_get_acl(struct inode *inode, int type)
> if (!xfs_acl)
> return ERR_PTR(-ENOMEM);
>
> - error = xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl,
> - &len, ATTR_ROOT);
> + error = xfs_attr_get(ip, ea_name, strlen(ea_name),
> + (unsigned char *)xfs_acl, &len, ATTR_ROOT);
> if (error) {
> /*
> * If the attribute doesn't exist make sure we have a negative
> @@ -204,15 +204,17 @@ __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
> len -= sizeof(struct xfs_acl_entry) *
> (XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count);
>
> - error = xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
> - len, ATTR_ROOT);
> + error = xfs_attr_set(ip, ea_name, strlen(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 89fb1eb..844480a 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -450,6 +450,7 @@ xfs_attrmulti_attr_get(
> {
> unsigned char *kbuf;
> int error = -EFAULT;
> + size_t namelen;
>
> if (*len > XFS_XATTR_SIZE_MAX)
> return -EINVAL;
> @@ -457,7 +458,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;
>
> @@ -479,6 +482,7 @@ xfs_attrmulti_attr_set(
> {
> unsigned char *kbuf;
> int error;
> + size_t namelen;
>
> if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
> return -EPERM;
> @@ -489,7 +493,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);
> @@ -503,10 +508,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 c45acf0..7920f19 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -71,8 +71,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_trans_attr.c b/fs/xfs/xfs_trans_attr.c
> index 8e3a0a0..d1d75bb 100644
> --- a/fs/xfs/xfs_trans_attr.c
> +++ b/fs/xfs/xfs_trans_attr.c
> @@ -86,7 +86,7 @@ xfs_trans_attr(
>
> tp->t_flags |= XFS_TRANS_RESERVE;
>
> - error = xfs_attr_args_init(&args, ip, name, flags);
> + error = xfs_attr_args_init(&args, ip, name, name_len, flags);
> if (error)
> return error;
>
> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
> index 0594db4..6cf30ae 100644
> --- a/fs/xfs/xfs_xattr.c
> +++ b/fs/xfs/xfs_xattr.c
> @@ -38,6 +38,7 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
> int xflags = handler->flags;
> struct xfs_inode *ip = XFS_I(inode);
> int error, asize = size;
> + size_t namelen = strlen(name);
>
> /* Convert Linux syscall to XFS internal ATTR flags */
> if (!size) {
> @@ -45,7 +46,8 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
> value = NULL;
> }
>
> - error = xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags);
> + error = xfs_attr_get(ip, name, namelen, value,
> + &asize, xflags);
/methinks these could all stll be on one line?
> if (error)
> return error;
> return asize;
> @@ -81,6 +83,7 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
> int xflags = handler->flags;
> struct xfs_inode *ip = XFS_I(inode);
> int error;
> + size_t namelen = strlen(name);
>
> /* Convert Linux syscall to XFS internal ATTR flags */
> if (flags & XATTR_CREATE)
> @@ -89,8 +92,9 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
> xflags |= ATTR_REPLACE;
>
> if (!value)
> - return xfs_attr_remove(ip, (unsigned char *)name, xflags);
> - error = xfs_attr_set(ip, (unsigned char *)name,
> + return xfs_attr_remove(ip, name,
> + namelen, xflags);
> + error = xfs_attr_set(ip, name, namelen,
> (void *)value, size, xflags);
Same here?
Looks ok with those fixed up,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
--D
> if (!error)
> xfs_forget_acl(inode, name, xflags);
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 06/21] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
2018-05-06 17:24 ` [PATCH 06/21] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred Allison Henderson
@ 2018-05-07 22:59 ` Darrick J. Wong
2018-05-08 17:01 ` Allison Henderson
0 siblings, 1 reply; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 22:59 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:39AM -0700, Allison Henderson wrote:
> These routines set up set and start a new deferred attribute
> operation. These functions are meant to be called by other
> code needing to initiate a deferred attribute operation. We
> will use these routines later in the parent pointer patches.
>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
> fs/xfs/libxfs/xfs_attr.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++
> fs/xfs/libxfs/xfs_attr.h | 5 ++++
> 2 files changed, 74 insertions(+)
>
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 2f295ca..adbcef2 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -468,6 +468,42 @@ xfs_attr_set(
> return error;
> }
>
> +/* Sets an attribute for an inode as a deferred operation */
> +int
> +xfs_attr_set_deferred(
> + struct xfs_inode *dp,
> + struct xfs_defer_ops *dfops,
> + void *name,
> + unsigned int namelen,
> + void *value,
> + unsigned int valuelen,
> + int flags)
> +{
> +
> + struct xfs_attr_item *new;
> + char *name_value;
> +
> + if (!namelen || !valuelen) {
> + ASSERT(0);
> + return -EFSCORRUPTED;
> + }
> +
> + new = kmem_alloc(XFS_ATTR_ITEM_SIZEOF(namelen, valuelen),
> + KM_SLEEP|KM_NOFS);
> + name_value = ((char *)new) + sizeof(struct xfs_attr_item);
> + memset(new, 0, XFS_ATTR_ITEM_SIZEOF(namelen, valuelen));
> + new->xattri_ip = dp;
> + new->xattri_op_flags = XFS_ATTR_OP_FLAGS_SET;
> + new->xattri_name_len = namelen;
> + new->xattri_value_len = valuelen;
> + new->xattri_flags = flags;
> + memcpy(&name_value[0], name, namelen);
> + memcpy(&name_value[namelen], value, valuelen);
If we're going to keep the inode locked across _defer_finish rolls then
we need to xfs_defer_ijoin the inode to the dfops so that the inode is
relogged in each transaction, which prevents the log tail from being
pinned unnecessarily. xfs_bmap.c does a similar thing with the deferred
map/unmap intents.
> +
> + xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
> +
> + return 0;
> +}
>
> /*
> * Generic handler routine to remove a name from an attribute list.
> @@ -560,6 +596,39 @@ xfs_attr_remove(
> return error;
> }
>
> +/* Removes an attribute for an inode as a deferred operation */
> +int
> +xfs_attr_remove_deferred(
> + struct xfs_inode *dp,
> + struct xfs_defer_ops *dfops,
> + void *name,
> + unsigned int namelen,
> + int flags)
> +{
> +
> + struct xfs_attr_item *new;
> + char *name_value;
> +
> + if (!namelen) {
> + ASSERT(0);
> + return -EFSCORRUPTED;
> + }
> +
> + new = kmem_alloc(XFS_ATTR_ITEM_SIZEOF(namelen, 0), KM_SLEEP|KM_NOFS);
> + name_value = ((char *)new) + sizeof(struct xfs_attr_item);
> + memset(new, 0, XFS_ATTR_ITEM_SIZEOF(namelen, 0));
> + new->xattri_ip = dp;
> + new->xattri_op_flags = XFS_ATTR_OP_FLAGS_REMOVE;
> + new->xattri_name_len = namelen;
> + new->xattri_value_len = 0;
> + new->xattri_flags = flags;
> + memcpy(name_value, name, namelen);
Same here.
--D
> + xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
> +
> + return 0;
> +}
> +
> /*========================================================================
> * External routines when attribute list is inside the inode
> *========================================================================*/
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index 33b33d3..ec26565 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -183,5 +183,10 @@ int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
> int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
> const unsigned char *name, int flags);
> int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
> +int xfs_attr_set_deferred(struct xfs_inode *dp, struct xfs_defer_ops *dfops,
> + void *name, unsigned int name_len, void *value,
> + unsigned int valuelen, int flags);
> +int xfs_attr_remove_deferred(struct xfs_inode *dp, struct xfs_defer_ops *dfops,
> + void *name, unsigned int namelen, int flags);
>
> #endif /* __XFS_ATTR_H__ */
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 05/21] xfs: Set up infastructure for deferred attribute operations
2018-05-06 17:24 ` [PATCH 05/21] xfs: Set up infastructure for deferred attribute operations Allison Henderson
@ 2018-05-07 23:19 ` Darrick J. Wong
2018-05-08 17:01 ` Allison Henderson
2018-05-08 9:55 ` Amir Goldstein
1 sibling, 1 reply; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 23:19 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:38AM -0700, Allison Henderson wrote:
> This patch adds two new log item types for setting or
> removing attributes as deferred operations. The
> xfs_attri_log_item logs an intent to set or remove an
> attribute. The corresponding xfs_attrd_log_item holds
> a reference to the xfs_attri_log_item and is freed once
> the transaction is done. Both log items use a generic
> xfs_attr_log_format structure that contains the attribute
> name, value, flags, inode, and an op_flag that indicates
> if the operations is a set or remove.
>
> At the moment, this feature will only be used by the parent
> pointer patch set which uses attributes to store information
> about an inodes parent.
>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
> fs/xfs/Makefile | 2 +
> fs/xfs/libxfs/xfs_attr.c | 5 +-
> fs/xfs/libxfs/xfs_attr.h | 26 +-
> fs/xfs/libxfs/xfs_defer.h | 1 +
> fs/xfs/libxfs/xfs_log_format.h | 44 +++-
> fs/xfs/libxfs/xfs_types.h | 1 +
> fs/xfs/xfs_attr_item.c | 530 +++++++++++++++++++++++++++++++++++++++++
> fs/xfs/xfs_attr_item.h | 119 +++++++++
> fs/xfs/xfs_log_recover.c | 122 ++++++++++
> fs/xfs/xfs_super.c | 1 +
> fs/xfs/xfs_trans.h | 13 +
> fs/xfs/xfs_trans_attr.c | 283 ++++++++++++++++++++++
> 12 files changed, 1142 insertions(+), 5 deletions(-)
>
> diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
> index 7ceb41a..d3c0004 100644
> --- a/fs/xfs/Makefile
> +++ b/fs/xfs/Makefile
> @@ -107,6 +107,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 \
> @@ -116,6 +117,7 @@ xfs-y += xfs_log.o \
> xfs_trans_bmap.o \
> xfs_trans_buf.o \
> xfs_trans_extfree.o \
> + xfs_trans_attr.o \
> xfs_trans_inode.o \
> xfs_trans_refcount.o \
> xfs_trans_rmap.o \
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 514f4f8..2f295ca 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -41,6 +41,7 @@
> #include "xfs_quota.h"
> #include "xfs_trans_space.h"
> #include "xfs_trace.h"
> +#include "xfs_attr_item.h"
>
> /*
> * xfs_attr.c
> @@ -74,7 +75,7 @@ STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
> STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>
>
> -STATIC int
> +int
> xfs_attr_args_init(
> struct xfs_da_args *args,
> struct xfs_inode *dp,
> @@ -326,7 +327,7 @@ xfs_attr_remove_args(
> /*
> * Calculate how many blocks we need for the new attribute,
> */
> -STATIC int
> +int
> xfs_attr_calc_size(
> struct xfs_da_args *args,
> int *local)
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index ef6b47e..33b33d3 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -18,6 +18,8 @@
> #ifndef __XFS_ATTR_H__
> #define __XFS_ATTR_H__
>
> +#include "libxfs/xfs_defer.h"
> +
> struct xfs_inode;
> struct xfs_da_args;
> struct xfs_attr_list_context;
> @@ -90,6 +92,26 @@ typedef struct attrlist_ent { /* data from attr_list() */
> } attrlist_ent_t;
>
> /*
> + * List of attrs to commit later.
> + */
> +struct xfs_attr_item {
> + struct xfs_inode *xattri_ip;
> + uint32_t xattri_op_flags;
> + uint32_t xattri_value_len; /* length of value */
> + uint32_t xattri_name_len; /* length of name */
> + uint32_t xattri_flags; /* attr flags */
> + struct list_head xattri_list;
You could shave four bytes off this structure's size by sorting the
fields in decreasing size order (e.g. put the xattri_list first).
> +
> + /*
> + * 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.
> */
> @@ -158,6 +180,8 @@ int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
> int xfs_attr_remove_args(struct xfs_da_args *args, int flags, bool roll_trans);
> int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
> int flags, struct attrlist_cursor_kern *cursor);
> -
> +int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
> + const unsigned char *name, int flags);
> +int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
>
> #endif /* __XFS_ATTR_H__ */
> diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h
> index 045beac..11e1690 100644
> --- a/fs/xfs/libxfs/xfs_defer.h
> +++ b/fs/xfs/libxfs/xfs_defer.h
> @@ -55,6 +55,7 @@ enum xfs_defer_ops_type {
> XFS_DEFER_OPS_TYPE_REFCOUNT,
> XFS_DEFER_OPS_TYPE_RMAP,
> XFS_DEFER_OPS_TYPE_FREE,
> + XFS_DEFER_OPS_TYPE_ATTR,
> XFS_DEFER_OPS_TYPE_MAX,
> };
>
> diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
> index 349d9f8..291e5ff 100644
> --- a/fs/xfs/libxfs/xfs_log_format.h
> +++ b/fs/xfs/libxfs/xfs_log_format.h
> @@ -116,7 +116,12 @@ static inline uint xlog_get_cycle(char *ptr)
> #define XLOG_REG_TYPE_CUD_FORMAT 24
> #define XLOG_REG_TYPE_BUI_FORMAT 25
> #define XLOG_REG_TYPE_BUD_FORMAT 26
> -#define XLOG_REG_TYPE_MAX 26
> +#define XLOG_REG_TYPE_ATTRI_FORMAT 27
> +#define XLOG_REG_TYPE_ATTRD_FORMAT 28
> +#define XLOG_REG_TYPE_ATTR_NAME 29
> +#define XLOG_REG_TYPE_ATTR_VALUE 30
> +#define XLOG_REG_TYPE_MAX 31
> +
>
> /*
> * Flags to log operation header
> @@ -239,6 +244,8 @@ typedef struct xfs_trans_header {
> #define XFS_LI_CUD 0x1243
> #define XFS_LI_BUI 0x1244 /* bmbt update intent */
> #define XFS_LI_BUD 0x1245
> +#define XFS_LI_ATTRI 0x1246 /* attr set/remove intent*/
> +#define XFS_LI_ATTRD 0x1247 /* attr set/remove done */
>
> #define XFS_LI_TYPE_DESC \
> { XFS_LI_EFI, "XFS_LI_EFI" }, \
> @@ -254,7 +261,9 @@ typedef struct xfs_trans_header {
> { XFS_LI_CUI, "XFS_LI_CUI" }, \
> { XFS_LI_CUD, "XFS_LI_CUD" }, \
> { XFS_LI_BUI, "XFS_LI_BUI" }, \
> - { XFS_LI_BUD, "XFS_LI_BUD" }
> + { XFS_LI_BUD, "XFS_LI_BUD" }, \
> + { XFS_LI_ATTRI, "XFS_LI_ATTRI" }, \
> + { XFS_LI_ATTRD, "XFS_LI_ATTRD" }
>
> /*
> * Inode Log Item Format definitions.
> @@ -852,4 +861,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 */
> +};
The size of these log structures, all the other on-disk metadata
structures, and possibly the ioctl structures needs to be checked in
xfs_ondisk.h so that we don't repeat the AGFL padding mess.
> +
> #endif /* __XFS_LOG_FORMAT_H__ */
> diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
> index 3c56069..2905ce3 100644
> --- a/fs/xfs/libxfs/xfs_types.h
> +++ b/fs/xfs/libxfs/xfs_types.h
> @@ -23,6 +23,7 @@ typedef uint32_t prid_t; /* project ID */
> typedef uint32_t xfs_agblock_t; /* blockno in alloc. group */
> typedef uint32_t xfs_agino_t; /* inode # within allocation grp */
> typedef uint32_t xfs_extlen_t; /* extent length in blocks */
> +typedef uint32_t xfs_attrlen_t; /* attr length */
> typedef uint32_t xfs_agnumber_t; /* allocation group number */
> typedef int32_t xfs_extnum_t; /* # of extents in a file */
> typedef int16_t xfs_aextnum_t; /* # extents in an attribute fork */
> diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
> new file mode 100644
> index 0000000..7e986e8
> --- /dev/null
> +++ b/fs/xfs/xfs_attr_item.c
> @@ -0,0 +1,530 @@
> +/*
> + * Copyright (c) 2017 Oracle, Inc.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write the Free Software Foundation Inc.
> + */
> +#include "xfs.h"
> +#include "xfs_fs.h"
> +#include "xfs_format.h"
> +#include "xfs_log_format.h"
> +#include "xfs_trans_resv.h"
> +#include "xfs_bit.h"
> +#include "xfs_mount.h"
> +#include "xfs_trans.h"
> +#include "xfs_trans_priv.h"
> +#include "xfs_buf_item.h"
> +#include "xfs_attr_item.h"
> +#include "xfs_log.h"
> +#include "xfs_btree.h"
> +#include "xfs_rmap.h"
> +#include "xfs_inode.h"
> +#include "xfs_icache.h"
> +
> +static inline struct xfs_attri_log_item *ATTRI_ITEM(struct xfs_log_item *lip)
> +{
> + return container_of(lip, struct xfs_attri_log_item, item);
> +}
> +
> +void
> +xfs_attri_item_free(
> + struct xfs_attri_log_item *attrip)
> +{
> + kmem_free(attrip->item.li_lv_shadow);
> + kmem_free(attrip);
> +}
> +
> +/*
> + * This returns the number of iovecs needed to log the given attri item.
> + * We only need 1 iovec for an attri item. It just logs the attr_log_format
> + * structure.
> + */
> +static inline int
> +xfs_attri_item_sizeof(
> + struct xfs_attri_log_item *attrip)
> +{
> + return sizeof(struct xfs_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->name_len > 0) {
> + *nvecs += 1;
> + nbytes += ATTR_NVEC_SIZE(attrip->name_len);
> + }
> +
> + if (attrip->value_len > 0) {
> + *nvecs += 1;
> + nbytes += ATTR_NVEC_SIZE(attrip->value_len);
> + }
> +}
> +
> +/*
> + * This is called to fill in the vector of log iovecs for the
> + * given attri log item. We use only 1 iovec, and we point that
> + * at the attri_log_format structure embedded in the attri item.
> + * It is at this point that we assert that all of the attr
> + * slots in the attri item have been filled.
> + */
> +STATIC void
> +xfs_attri_item_format(
> + struct xfs_log_item *lip,
> + struct xfs_log_vec *lv)
> +{
> + struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip);
> + struct xfs_log_iovec *vecp = NULL;
> +
> + attrip->format.alfi_type = XFS_LI_ATTRI;
> + attrip->format.alfi_size = 1;
> +
> + xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRI_FORMAT,
> + &attrip->format,
> + xfs_attri_item_sizeof(attrip));
> + if (attrip->name_len > 0)
> + xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_NAME,
> + attrip->name, ATTR_NVEC_SIZE(attrip->name_len));
> +
> + if (attrip->value_len > 0)
> + xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_VALUE,
> + attrip->value,
> + ATTR_NVEC_SIZE(attrip->value_len));
> +}
> +
> +
> +/*
> + * Pinning has no meaning for an attri item, so just return.
> + */
> +STATIC void
> +xfs_attri_item_pin(
> + struct xfs_log_item *lip)
> +{
> +}
> +
> +/*
> + * The unpin operation is the last place an ATTRI is manipulated in the log. It
> + * is either inserted in the AIL or aborted in the event of a log I/O error. In
> + * either case, the ATTRI transaction has been successfully committed to make it
> + * this far. Therefore, we expect whoever committed the ATTRI to either
> + * construct and commit the ATTRD or drop the ATTRD's reference in the event of
> + * error. Simply drop the log's ATTRI reference now that the log is done with
> + * it.
> + */
> +STATIC void
> +xfs_attri_item_unpin(
> + struct xfs_log_item *lip,
> + int remove)
> +{
> + struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip);
> +
> + xfs_attri_release(attrip);
> +}
> +
> +/*
> + * attri items have no locking or pushing. However, since ATTRIs are pulled
> + * from the AIL when their corresponding ATTRDs are committed to disk, their
> + * situation is very similar to being pinned. Return XFS_ITEM_PINNED so that
> + * the caller will eventually flush the log. This should help in getting the
> + * ATTRI out of the AIL.
> + */
> +STATIC uint
> +xfs_attri_item_push(
> + struct xfs_log_item *lip,
> + struct list_head *buffer_list)
> +{
> + return XFS_ITEM_PINNED;
> +}
> +
> +/*
> + * The ATTRI has been either committed or aborted if the transaction has been
> + * cancelled. If the transaction was cancelled, an ATTRD isn't going to be
> + * constructed and thus we free the ATTRI here directly.
> + */
> +STATIC void
> +xfs_attri_item_unlock(
> + struct xfs_log_item *lip)
> +{
> + if (lip->li_flags & XFS_LI_ABORTED)
> + xfs_attri_release(ATTRI_ITEM(lip));
> +}
> +
> +/*
> + * The ATTRI is logged only once and cannot be moved in the log, so simply
> + * return the lsn at which it's been logged.
> + */
> +STATIC xfs_lsn_t
> +xfs_attri_item_committed(
> + struct xfs_log_item *lip,
> + xfs_lsn_t lsn)
> +{
> + return lsn;
> +}
> +
> +STATIC void
> +xfs_attri_item_committing(
> + struct xfs_log_item *lip,
> + xfs_lsn_t lsn)
> +{
> +}
> +
> +/*
> + * This is the ops vector shared by all attri log items.
> + */
> +static const struct xfs_item_ops xfs_attri_item_ops = {
> + .iop_size = xfs_attri_item_size,
> + .iop_format = xfs_attri_item_format,
> + .iop_pin = xfs_attri_item_pin,
> + .iop_unpin = xfs_attri_item_unpin,
> + .iop_unlock = xfs_attri_item_unlock,
> + .iop_committed = xfs_attri_item_committed,
> + .iop_push = xfs_attri_item_push,
> + .iop_committing = xfs_attri_item_committing
> +};
> +
> +
> +/*
> + * Allocate and initialize an attri item
> + */
> +struct xfs_attri_log_item *
> +xfs_attri_init(
> + struct xfs_mount *mp)
> +
> +{
> + struct xfs_attri_log_item *attrip;
> + uint size;
> +
> + size = (uint)(sizeof(struct xfs_attri_log_item));
> + attrip = kmem_zalloc(size, KM_SLEEP);
> +
> + xfs_log_item_init(mp, &(attrip->item), XFS_LI_ATTRI,
> + &xfs_attri_item_ops);
> + attrip->format.alfi_id = (uintptr_t)(void *)attrip;
> + atomic_set(&attrip->refcount, 2);
> +
> + return attrip;
> +}
> +
> +/*
> + * Copy an attr format buffer from the given buf, and into the destination
> + * attr format structure.
> + */
> +int
> +xfs_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) {
> + memcpy((char *)dst_attr_fmt, (char *)src_attr_fmt, len);
> + return 0;
> + }
> + return -EFSCORRUPTED;
> +}
> +
> +/*
> + * Copy an attr format buffer from the given buf, and into the destination
> + * attr format structure.
> + */
> +int
> +xfs_attrd_copy_format(struct xfs_log_iovec *buf,
> + struct xfs_attrd_log_format *dst_attr_fmt)
> +{
> + struct xfs_attrd_log_format *src_attr_fmt = buf->i_addr;
> + uint len = sizeof(struct xfs_attrd_log_format);
> +
> + if (buf->i_len == len) {
> + memcpy((char *)dst_attr_fmt, (char *)src_attr_fmt, len);
> + return 0;
> + }
> + return -EFSCORRUPTED;
> +}
> +
> +/*
> + * 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->refcount) > 0);
> + if (atomic_dec_and_test(&attrip->refcount)) {
> + xfs_trans_ail_remove(&attrip->item, SHUTDOWN_LOG_IO_ERROR);
> + xfs_attri_item_free(attrip);
> + }
> +}
> +
> +static inline struct xfs_attrd_log_item *ATTRD_ITEM(struct xfs_log_item *lip)
> +{
> + return container_of(lip, struct xfs_attrd_log_item, item);
> +}
> +
> +STATIC void
> +xfs_attrd_item_free(struct xfs_attrd_log_item *attrdp)
> +{
> + kmem_free(attrdp->item.li_lv_shadow);
> + kmem_free(attrdp);
> +}
> +
> +/*
> + * This returns the number of iovecs needed to log the given attrd item.
> + * We only need 1 iovec for an attrd item. It just logs the attr_log_format
> + * structure.
> + */
> +static inline int
> +xfs_attrd_item_sizeof(
> + struct xfs_attrd_log_item *attrdp)
> +{
> + return sizeof(struct xfs_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);
> +
> + if (attrdp->name_len > 0) {
> + *nvecs += 1;
> + nbytes += attrdp->name_len;
> + }
> +
> + if (attrdp->value_len > 0) {
> + *nvecs += 1;
> + nbytes += attrdp->value_len;
> + }
> +}
> +
> +/*
> + * This is called to fill in the vector of log iovecs for the
> + * given attrd log item. We use only 1 iovec, and we point that
> + * at the attr_log_format structure embedded in the attrd item.
> + * It is at this point that we assert that all of the attr
> + * slots in the attrd item have been filled.
> + */
> +STATIC void
> +xfs_attrd_item_format(
> + struct xfs_log_item *lip,
> + struct xfs_log_vec *lv)
> +{
> + struct xfs_attrd_log_item *attrdp = ATTRD_ITEM(lip);
> + struct xfs_log_iovec *vecp = NULL;
> +
> + attrdp->format.alfd_type = XFS_LI_ATTRD;
> + attrdp->format.alfd_size = 1;
> +
> + xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRD_FORMAT,
> + &attrdp->format,
> + xfs_attrd_item_sizeof(attrdp));
> +}
> +
> +/*
> + * Pinning has no meaning for an attrd item, so just return.
> + */
> +STATIC void
> +xfs_attrd_item_pin(
> + struct xfs_log_item *lip)
> +{
> +}
> +
> +/*
> + * Since pinning has no meaning for an attrd item, unpinning does
> + * not either.
> + */
> +STATIC void
> +xfs_attrd_item_unpin(
> + struct xfs_log_item *lip,
> + int remove)
> +{
> +}
> +
> +/*
> + * There isn't much you can do to push on an attrd item. It is simply stuck
> + * waiting for the log to be flushed to disk.
> + */
> +STATIC uint
> +xfs_attrd_item_push(
> + struct xfs_log_item *lip,
> + struct list_head *buffer_list)
> +{
> + return XFS_ITEM_PINNED;
> +}
> +
> +/*
> + * The ATTRD is either committed or aborted if the transaction is cancelled. If
> + * the transaction is cancelled, drop our reference to the ATTRI and free the
> + * ATTRD.
> + */
> +STATIC void
> +xfs_attrd_item_unlock(
> + struct xfs_log_item *lip)
> +{
> + struct xfs_attrd_log_item *attrdp = ATTRD_ITEM(lip);
> +
> + if (lip->li_flags & XFS_LI_ABORTED) {
> + xfs_attri_release(attrdp->attrip);
> + xfs_attrd_item_free(attrdp);
> + }
> +}
> +
> +/*
> + * When the attrd item is committed to disk, all we need to do is delete our
> + * reference to our partner attri item and then free ourselves. Since we're
> + * freeing ourselves we must return -1 to keep the transaction code from
> + * further referencing this item.
> + */
> +STATIC xfs_lsn_t
> +xfs_attrd_item_committed(
> + struct xfs_log_item *lip,
> + xfs_lsn_t lsn)
> +{
> + struct xfs_attrd_log_item *attrdp = ATTRD_ITEM(lip);
> +
> + /*
> + * Drop the ATTRI reference regardless of whether the ATTRD has been
> + * aborted. Once the ATTRD transaction is constructed, it is the sole
> + * responsibility of the ATTRD to release the ATTRI (even if the ATTRI
> + * is aborted due to log I/O error).
> + */
> + xfs_attri_release(attrdp->attrip);
> + xfs_attrd_item_free(attrdp);
> +
> + return (xfs_lsn_t)-1;
> +}
> +
> +STATIC void
> +xfs_attrd_item_committing(
> + struct xfs_log_item *lip,
> + xfs_lsn_t lsn)
> +{
> +}
> +
> +/*
> + * This is the ops vector shared by all attrd log items.
> + */
> +static const struct xfs_item_ops xfs_attrd_item_ops = {
> + .iop_size = xfs_attrd_item_size,
> + .iop_format = xfs_attrd_item_format,
> + .iop_pin = xfs_attrd_item_pin,
> + .iop_unpin = xfs_attrd_item_unpin,
> + .iop_unlock = xfs_attrd_item_unlock,
> + .iop_committed = xfs_attrd_item_committed,
> + .iop_push = xfs_attrd_item_push,
> + .iop_committing = xfs_attrd_item_committing
> +};
> +
> +/*
> + * Allocate and initialize an attrd item
> + */
> +struct xfs_attrd_log_item *
> +xfs_attrd_init(
> + struct xfs_mount *mp,
> + struct xfs_attri_log_item *attrip)
> +
> +{
> + struct xfs_attrd_log_item *attrdp;
> + uint size;
> +
> + size = (uint)(sizeof(struct xfs_attrd_log_item));
> + attrdp = kmem_zalloc(size, KM_SLEEP);
> +
> + xfs_log_item_init(mp, &attrdp->item, XFS_LI_ATTRD,
> + &xfs_attrd_item_ops);
> + attrdp->attrip = attrip;
> + attrdp->format.alfd_alf_id = attrip->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_trans *tp;
> + int error = 0;
> + struct xfs_attri_log_format *attrp;
> +
> + ASSERT(!test_bit(XFS_ATTRI_RECOVERED, &attrip->flags));
> +
> + /*
> + * First check the validity of the attr described by the
> + * ATTRI. If any are bad, then assume that all are bad and
> + * just toss the ATTRI. A valid attr must have a name length,
> + * a value length, and either a "set" or "remove" op flag
> + */
> + attrp = &attrip->format;
> + if (attrp->alfi_value_len == 0 ||
> + attrp->alfi_name_len == 0 ||
> + !(attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_SET ||
> + attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_REMOVE) ) {
The name/value len should be checked to ensure it isn't too long.
> + /*
> + * This will pull the ATTRI from the AIL and
> + * free the memory associated with it.
> + */
> + set_bit(XFS_ATTRI_RECOVERED, &attrip->flags);
> + xfs_attri_release(attrip);
> + return -EIO;
> + }
> +
> + error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
> + if (error)
> + return error;
> + attrdp = xfs_trans_get_attrd(tp, attrip);
> + attrp = &attrip->format;
> +
> + error = xfs_iget(mp, tp, attrp->alfi_ino, 0, 0, &ip);
> + if (error)
> + return error;
> +
> + error = xfs_trans_attr(tp, attrdp, ip,
> + attrp->alfi_op_flags,
> + attrp->alfi_attr_flags,
> + attrp->alfi_name_len,
> + attrp->alfi_value_len,
> + attrip->name,
> + attrip->value);
> + if (error)
> + goto abort_error;
> +
> +
> + set_bit(XFS_ATTRI_RECOVERED, &attrip->flags);
> + error = xfs_trans_commit(tp);
> + return error;
> +
> +abort_error:
> + xfs_trans_cancel(tp);
> + return error;
> +}
> diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h
> new file mode 100644
> index 0000000..6ff07cc
> --- /dev/null
> +++ b/fs/xfs/xfs_attr_item.h
> @@ -0,0 +1,119 @@
> +/*
> + * Copyright (c) 2017 Oracle, Inc.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write the Free Software Foundation Inc.
> + */
> +#ifndef __XFS_ATTR_ITEM_H__
> +#define __XFS_ATTR_ITEM_H__
> +
> +/* kernel only ATTRI/ATTRD definitions */
> +
> +struct xfs_mount;
> +struct kmem_zone;
> +
> +/*
> + * Max number of attrs in fast allocation path.
> + */
> +#define XFS_ATTRI_MAX_FAST_ATTRS 1
> +
> +
> +/*
> + * Define ATTR flag bits. Manipulated by set/clear/test_bit operators.
> + */
> +#define XFS_ATTRI_RECOVERED 1
> +
> +
> +/* nvecs must be in multiples of 4 */
> +#define ATTR_NVEC_SIZE(size) (size == sizeof(int32_t) ? sizeof(int32_t) : \
> + size + sizeof(int32_t) - \
> + (size % sizeof(int32_t)))
> +
> +/*
> + * This is the "attr intention" log item. It is used to log the fact
> + * that some attrs need to be processed. It is used in conjunction with the
> + * "attr done" log item described below.
> + *
> + * The ATTRI is reference counted so that it is not freed prior to both the
> + * ATTRI and ATTRD being committed and unpinned. This ensures the ATTRI is
> + * inserted into the AIL even in the event of out of order ATTRI/ATTRD
> + * processing. In other words, an ATTRI is born with two references:
> + *
> + * 1.) an ATTRI held reference to track ATTRI AIL insertion
> + * 2.) an ATTRD held reference to track ATTRD commit
> + *
> + * On allocation, both references are the responsibility of the caller. Once
> + * the ATTRI is added to and dirtied in a transaction, ownership of reference
> + * one transfers to the transaction. The reference is dropped once the ATTRI is
> + * inserted to the AIL or in the event of failure along the way (e.g., commit
> + * failure, log I/O error, etc.). Note that the caller remains responsible for
> + * the ATTRD reference under all circumstances to this point. The caller has no
> + * means to detect failure once the transaction is committed, however.
> + * Therefore, an ATTRD is required after this point, even in the event of
> + * unrelated failure.
> + *
> + * Once an ATTRD is allocated and dirtied in a transaction, reference two
> + * transfers to the transaction. The ATTRD reference is dropped once it reaches
> + * the unpin handler. Similar to the ATTRI, the reference also drops in the
> + * event of commit failure or log I/O errors. Note that the ATTRD is not
> + * inserted in the AIL, so at this point both the ATTI and ATTRD are freed.
> + */
> +struct xfs_attri_log_item {
> + xfs_log_item_t item;
> + atomic_t refcount;
> + unsigned long flags; /* misc flags */
> + int name_len;
> + void *name;
> + int value_len;
> + void *value;
> + struct xfs_attri_log_format format;
> +};
> +
> +/*
> + * This is the "attr done" log item. It is used to log
> + * the fact that some attrs earlier mentioned in an attri item
> + * have been freed.
> + */
> +struct xfs_attrd_log_item {
> + struct xfs_log_item item;
> + struct xfs_attri_log_item *attrip;
> + uint next_attr;
> + int name_len;
> + void *name;
> + int value_len;
> + void *value;
> + struct xfs_attrd_log_format format;
> +};
> +
> +/*
> + * Max number of attrs in fast allocation path.
> + */
> +#define XFS_ATTRD_MAX_FAST_ATTRS 1
> +
> +extern struct kmem_zone *xfs_attri_zone;
> +extern struct kmem_zone *xfs_attrd_zone;
> +
> +struct xfs_attri_log_item *xfs_attri_init(struct xfs_mount *mp);
> +struct xfs_attrd_log_item *xfs_attrd_init(struct xfs_mount *mp,
> + struct xfs_attri_log_item *attrip);
> +int xfs_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_recover.c b/fs/xfs/xfs_log_recover.c
> index 2b2383f..696b6ff 100644
> --- a/fs/xfs/xfs_log_recover.c
> +++ b/fs/xfs/xfs_log_recover.c
> @@ -34,6 +34,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"
> @@ -1967,6 +1968,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);
> @@ -3497,6 +3500,92 @@ xlog_recover_efd_pass2(
> return 0;
> }
>
> +STATIC int
> +xlog_recover_attri_pass2(
> + struct xlog *log,
> + struct xlog_recover_item *item,
> + xfs_lsn_t lsn)
> +{
> + int error;
> + struct xfs_mount *mp = log->l_mp;
> + struct xfs_attri_log_item *attrip;
> + struct xfs_attr_log_format *attri_formatp;
> +
> + attri_formatp = item->ri_buf[0].i_addr;
> +
> + attrip = xfs_attri_init(mp);
> + error = xfs_attri_copy_format(&item->ri_buf[0], &attrip->format);
> + if (error) {
> + xfs_attri_item_free(attrip);
> + return error;
> + }
> +
> + 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->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->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.
> @@ -4116,6 +4205,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:
> @@ -4677,6 +4770,31 @@ xlog_recover_cancel_efi(
> 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, item);
> + if (test_bit(XFS_ATTRI_RECOVERED, &attrip->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(
> @@ -4920,6 +5038,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);
Pass the &dfops into xlog_recover_process_attri -> xfs_attri_recover ->
xfs_trans_attr so that deferred items generated during recovery of other
deferred items are finished in the correct order. More information is
in commit 509955823cc9 ("xfs: log recovery should replay deferred ops in
order").
> + break;
> case XFS_LI_RUI:
> error = xlog_recover_process_rui(log->l_mp, ailp, lip);
> break;
> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> index d714240..dce3baf 100644
> --- a/fs/xfs/xfs_super.c
> +++ b/fs/xfs/xfs_super.c
> @@ -2077,6 +2077,7 @@ init_xfs_fs(void)
> xfs_rmap_update_init_defer_op();
> xfs_refcount_update_init_defer_op();
> xfs_bmap_update_init_defer_op();
> + xfs_attr_init_defer_op();
>
> xfs_dir_startup();
>
> diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
> index 9d542df..abd0a46 100644
> --- a/fs/xfs/xfs_trans.h
> +++ b/fs/xfs/xfs_trans.h
> @@ -40,6 +40,9 @@ struct xfs_cud_log_item;
> struct xfs_defer_ops;
> struct xfs_bui_log_item;
> struct xfs_bud_log_item;
> +struct xfs_attrd_log_item;
> +struct xfs_attri_log_item;
> +
>
> typedef struct xfs_log_item {
> struct list_head li_ail; /* AIL pointers */
> @@ -223,12 +226,22 @@ void xfs_trans_dirty_buf(struct xfs_trans *, struct xfs_buf *);
> void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
>
> void xfs_extent_free_init_defer_op(void);
> +void xfs_attr_init_defer_op(void);
> +
> struct xfs_efd_log_item *xfs_trans_get_efd(struct xfs_trans *,
> struct xfs_efi_log_item *,
> uint);
> int xfs_trans_free_extent(struct xfs_trans *,
> struct xfs_efd_log_item *, xfs_fsblock_t,
> xfs_extlen_t, struct xfs_owner_info *);
> +struct xfs_attrd_log_item *
> +xfs_trans_get_attrd(struct xfs_trans *tp,
> + struct xfs_attri_log_item *attrip);
> +int xfs_trans_attr(struct xfs_trans *tp, struct xfs_attrd_log_item *attrdp,
> + struct xfs_inode *ip, uint32_t attr_op_flags,
> + uint32_t flags, uint32_t name_len, uint32_t value_len,
> + char *name, char *value);
> +
> int xfs_trans_commit(struct xfs_trans *);
> int xfs_trans_roll(struct xfs_trans **);
> int xfs_trans_roll_inode(struct xfs_trans **, struct xfs_inode *);
> diff --git a/fs/xfs/xfs_trans_attr.c b/fs/xfs/xfs_trans_attr.c
> new file mode 100644
> index 0000000..8e3a0a0
> --- /dev/null
> +++ b/fs/xfs/xfs_trans_attr.c
> @@ -0,0 +1,283 @@
> +/*
> + * Copyright (c) 2017, Oracle Inc.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write the Free Software Foundation Inc.
> + */
> +#include "xfs.h"
> +#include "xfs_fs.h"
> +#include "xfs_shared.h"
> +#include "xfs_format.h"
> +#include "xfs_log_format.h"
> +#include "xfs_trans_resv.h"
> +#include "xfs_bit.h"
> +#include "xfs_mount.h"
> +#include "xfs_defer.h"
> +#include "xfs_trans.h"
> +#include "xfs_trans_priv.h"
> +#include "xfs_attr_item.h"
> +#include "xfs_alloc.h"
> +#include "xfs_bmap.h"
> +#include "xfs_trace.h"
> +#include "libxfs/xfs_da_format.h"
> +#include "xfs_da_btree.h"
> +#include "xfs_attr.h"
> +#include "xfs_inode.h"
> +#include "xfs_icache.h"
> +#include "xfs_quota.h"
> +
> +/*
> + * This routine is called to allocate an "extent free done"
> + * log item that will hold nextents worth of extents. The
> + * caller must use all nextents extents, because we are not
> + * flexible about this at all.
> + */
> +struct xfs_attrd_log_item *
> +xfs_trans_get_attrd(struct xfs_trans *tp,
> + struct xfs_attri_log_item *attrip)
> +{
> + struct xfs_attrd_log_item *attrdp;
> +
> + ASSERT(tp != NULL);
> +
> + attrdp = xfs_attrd_init(tp->t_mountp, attrip);
> + ASSERT(attrdp != NULL);
> +
> + /*
> + * Get a log_item_desc to point at the new item.
> + */
> + xfs_trans_add_item(tp, &attrdp->item);
> + return attrdp;
> +}
> +
> +/*
> + * Delete an attr and log it to the ATTRD. Note that the transaction is marked
> + * dirty regardless of whether the attr delete succeeds or fails to support the
> + * ATTRI/ATTRD lifecycle rules.
> + */
> +int
> +xfs_trans_attr(
> + struct xfs_trans *tp,
> + struct xfs_attrd_log_item *attrdp,
> + struct xfs_inode *ip,
> + uint32_t op_flags,
> + uint32_t flags,
> + uint32_t name_len,
> + uint32_t value_len,
> + char *name,
> + char *value)
> +{
> + int error;
> + int local;
> + struct xfs_da_args args;
> + struct xfs_defer_ops dfops;
Whitespace problems between type and name (the three lines leading up to
this)?
> + xfs_fsblock_t firstblock = NULLFSBLOCK;
> + struct xfs_buf *leaf_bp = NULL;
> +
> + tp->t_flags |= XFS_TRANS_RESERVE;
Why was this necessary? Usually the creator of the transaction knows if
it's ok to dip into the free space reserves.
> +
> + error = xfs_attr_args_init(&args, ip, name, flags);
> + if (error)
> + return error;
> +
> + xfs_defer_init(&dfops, &firstblock);
See above comment about passing a dfops into this function to preserve
correct finishing order of intents created by intent recovery.
> + args.name = name;
> + args.namelen = name_len;
> + args.hashval = xfs_da_hashname(args.name, args.namelen);
> + args.value = value;
> + args.valuelen = value_len;
> + args.dfops = &dfops;
> + args.firstblock = &firstblock;
> + args.op_flags = XFS_DA_OP_OKNOENT;
> + args.total = xfs_attr_calc_size(&args, &local);
> + args.trans = tp;
> + ASSERT(local);
> +
> + error = xfs_qm_dqattach_locked(ip, 0);
> + if (error)
> + return error;
> +
> + switch (op_flags) {
> + case XFS_ATTR_OP_FLAGS_SET:
> + args.op_flags |= XFS_DA_OP_ADDNAME;
> + error = xfs_attr_set_args(&args, flags,
> + leaf_bp, false);
> + break;
> + case XFS_ATTR_OP_FLAGS_REMOVE:
> + ASSERT(XFS_IFORK_Q((ip)));
> + error = xfs_attr_remove_args(&args, flags, false);
> + break;
> + default:
> + error = -EFSCORRUPTED;
> + }
> +
> + if (error) {
> + xfs_defer_cancel(&dfops);
> + if (leaf_bp)
> + xfs_trans_brelse(args.trans, leaf_bp);
Leading whitespace problem (tabs not spacs)...
> + }
> +
> + /*
> + * Mark the transaction dirty, even on error. This ensures the
> + * transaction is aborted, which:
> + *
> + * 1.) releases the ATTRI and frees the ATTRD
> + * 2.) shuts down the filesystem
> + */
> + tp->t_flags |= XFS_TRANS_DIRTY;
> + attrdp->item.li_desc->lid_flags |= XFS_LID_DIRTY;
> + attrdp->name = name;
> + attrdp->value = value;
> + attrdp->name_len = name_len;
> + attrdp->value_len = value_len;
> + attrdp->next_attr++;
> +
> + return error;
> +}
> +
> +static int
> +xfs_attr_diff_items(
> + void *priv,
> + struct list_head *a,
> + struct list_head *b)
> +{
> + return 0;
> +}
> +
> +/* Get an ATTRI. */
> +STATIC void *
> +xfs_attr_create_intent(
> + struct xfs_trans *tp,
> + unsigned int count)
> +{
> + struct xfs_attri_log_item *attrip;
> +
> + ASSERT(tp != NULL);
> + ASSERT(count == 1);
> +
> + attrip = xfs_attri_init(tp->t_mountp);
> + ASSERT(attrip != NULL);
> +
> + /*
> + * Get a log_item_desc to point at the new item.
> + */
> + xfs_trans_add_item(tp, &attrip->item);
> + return attrip;
> +}
> +
> +/* Log an attr to the intent item. */
> +STATIC void
> +xfs_attr_log_item(
> + struct xfs_trans *tp,
> + void *intent,
> + struct list_head *item)
> +{
> + struct xfs_attri_log_item *attrip = intent;
> + struct xfs_attr_item *free;
> + struct xfs_attri_log_format *attrp;
> + char *name_value;
> +
> + free = container_of(item, struct xfs_attr_item, xattri_list);
> + name_value = ((char *)free) + sizeof(struct xfs_attr_item);
> +
> + tp->t_flags |= XFS_TRANS_DIRTY;
> + attrip->item.li_desc->lid_flags |= XFS_LID_DIRTY;
> +
> + attrp = &attrip->format;
> + attrp->alfi_ino = free->xattri_ip->i_ino;
> + attrp->alfi_op_flags = free->xattri_op_flags;
> + attrp->alfi_value_len = free->xattri_value_len;
> + attrp->alfi_name_len = free->xattri_name_len;
> + attrp->alfi_attr_flags = free->xattri_flags;
> +
> + attrip->name = name_value;
> + attrip->value = &name_value[free->xattri_name_len];
> + attrip->name_len = free->xattri_name_len;
> + attrip->value_len = free->xattri_value_len;
> +}
> +
> +/* Get an ATTRD so we can process all the attrs. */
> +STATIC void *
> +xfs_attr_create_done(
> + struct xfs_trans *tp,
> + void *intent,
> + unsigned int count)
> +{
> + return xfs_trans_get_attrd(tp, intent);
> +}
> +
> +/* Process an attr. */
> +STATIC int
> +xfs_attr_finish_item(
> + struct xfs_trans *tp,
> + struct xfs_defer_ops *dop,
This dop really needs to be passed into xfs_trans_attr because any
deferred ops created as a side effect of finishing this deferred op
(e.g. if the attr set has to map a block into the attr fork and we have
rmapbt=1) then the deferred rmap update has to be done in the correct
order and in the same context as the original defer_ops.
In other words we don't support nested defer_ops just like we don't
support nested transactions because that's a mess to sort out.
--D
> + struct list_head *item,
> + void *done_item,
> + void **state)
> +{
> + struct xfs_attr_item *free;
> + char *name_value;
> + int error;
> +
> + free = container_of(item, struct xfs_attr_item, xattri_list);
> + name_value = ((char *)free) + sizeof(struct xfs_attr_item);
> + error = xfs_trans_attr(tp, done_item,
> + free->xattri_ip,
> + free->xattri_op_flags,
> + free->xattri_flags,
> + free->xattri_name_len,
> + free->xattri_value_len,
> + name_value,
> + &name_value[free->xattri_name_len]);
> + kmem_free(free);
> + return error;
> +}
> +
> +/* Abort all pending ATTRs. */
> +STATIC void
> +xfs_attr_abort_intent(
> + void *intent)
> +{
> + xfs_attri_release(intent);
> +}
> +
> +/* Cancel an attr */
> +STATIC void
> +xfs_attr_cancel_item(
> + struct list_head *item)
> +{
> + struct xfs_attr_item *free;
> +
> + free = container_of(item, struct xfs_attr_item, xattri_list);
> + kmem_free(free);
> +}
> +
> +static const struct xfs_defer_op_type xfs_attr_defer_type = {
> + .type = XFS_DEFER_OPS_TYPE_ATTR,
> + .max_items = XFS_ATTRI_MAX_FAST_ATTRS,
> + .diff_items = xfs_attr_diff_items,
> + .create_intent = xfs_attr_create_intent,
> + .abort_intent = xfs_attr_abort_intent,
> + .log_item = xfs_attr_log_item,
> + .create_done = xfs_attr_create_done,
> + .finish_item = xfs_attr_finish_item,
> + .cancel_item = xfs_attr_cancel_item,
> +};
> +
> +/* Register the deferred op type. */
> +void
> +xfs_attr_init_defer_op(void)
> +{
> + xfs_defer_init_op_type(&xfs_attr_defer_type);
> +}
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 04/21] xfs: Add attibute remove and helper functions
2018-05-06 17:24 ` [PATCH 04/21] xfs: Add attibute remove " Allison Henderson
@ 2018-05-07 23:21 ` Darrick J. Wong
2018-05-08 7:33 ` Amir Goldstein
1 sibling, 0 replies; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 23:21 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:37AM -0700, Allison Henderson wrote:
> This patch adds xfs_attr_remove_args. These sub-routines remove
> the attributes specified in @args. We will use this later for setting
> parent pointers as a deferred attribute operation.
>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Looks ok,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
--D
> ---
> fs/xfs/libxfs/xfs_attr.c | 43 +++++++++++++++++++++++++++++++++----------
> fs/xfs/libxfs/xfs_attr.h | 1 +
> 2 files changed, 34 insertions(+), 10 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 99c4a31..514f4f8 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -296,6 +296,34 @@ xfs_attr_set_args(
> }
>
> /*
> + * Remove the attribute specified in @args.
> + */
> +int
> +xfs_attr_remove_args(
> + struct xfs_da_args *args,
> + int flags,
> + bool roll_trans)
> +{
> + struct xfs_inode *dp = args->dp;
> + int error;
> +
> + xfs_trans_ijoin(args->trans, dp, 0);
> +
> + if (!xfs_inode_hasattr(dp)) {
> + error = -ENOATTR;
> + } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> + ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
> + error = xfs_attr_shortform_remove(args, roll_trans);
> + } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> + error = xfs_attr_leaf_removename(args, roll_trans);
> + } else {
> + error = xfs_attr_node_removename(args, roll_trans);
> + }
> +
> + return error;
> +}
> +
> +/*
> * Calculate how many blocks we need for the new attribute,
> */
> STATIC int
> @@ -439,6 +467,7 @@ xfs_attr_set(
> return error;
> }
>
> +
> /*
> * Generic handler routine to remove a name from an attribute list.
> * Transitions attribute list from Btree to shortform as necessary.
> @@ -495,17 +524,9 @@ xfs_attr_remove(
> * blocks not allocate in the common case.
> */
> xfs_trans_ijoin(args.trans, dp, 0);
> + xfs_defer_init(args.dfops, args.firstblock);
>
> - if (!xfs_inode_hasattr(dp)) {
> - error = -ENOATTR;
> - } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> - ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
> - error = xfs_attr_shortform_remove(&args, true);
> - } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> - error = xfs_attr_leaf_removename(&args, true);
> - } else {
> - error = xfs_attr_node_removename(&args, true);
> - }
> + error = xfs_attr_remove_args(&args, flags, true);
>
> if (error)
> goto out;
> @@ -530,6 +551,8 @@ xfs_attr_remove(
> return error;
>
> out:
> + xfs_defer_cancel(&dfops);
> +
> if (args.trans)
> xfs_trans_cancel(args.trans);
> xfs_iunlock(dp, XFS_ILOCK_EXCL);
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index b5dc02c..ef6b47e 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -155,6 +155,7 @@ int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
> int xfs_attr_set_args(struct xfs_da_args *args, int flags,
> struct xfs_buf *leaf_bp, bool roll_trans);
> int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
> +int xfs_attr_remove_args(struct xfs_da_args *args, int flags, bool roll_trans);
> int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
> int flags, struct attrlist_cursor_kern *cursor);
>
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 03/21] xfs: Add attibute set and helper functions
2018-05-06 17:24 ` [PATCH 03/21] xfs: Add attibute set and helper functions Allison Henderson
@ 2018-05-07 23:36 ` Darrick J. Wong
2018-05-08 7:25 ` Amir Goldstein
2018-05-08 17:01 ` Allison Henderson
0 siblings, 2 replies; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 23:36 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:36AM -0700, Allison Henderson wrote:
> This patch adds xfs_attr_set_args and xfs_bmap_set_attrforkoff.
> These sub-routines set the attributes specified in @args.
> We will use this later for setting parent pointers as a deferred
> attribute operation.
>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
> fs/xfs/libxfs/xfs_attr.c | 217 ++++++++++++++++++++++++++++-------------------
> fs/xfs/libxfs/xfs_attr.h | 2 +
> fs/xfs/libxfs/xfs_bmap.c | 49 ++++++-----
> fs/xfs/libxfs/xfs_bmap.h | 1 +
> 4 files changed, 165 insertions(+), 104 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 0ade22b..99c4a31 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -168,6 +168,134 @@ xfs_attr_get(
> }
>
> /*
> + * Set the attribute specified in @args. In the case of the parent attribute
> + * being set, we do not want to roll the transaction on shortform-to-leaf
> + * conversion, as the attribute must be added in the same transaction as the
> + * parent directory modifications. Hence @roll_trans needs to be set
> + * appropriately to control whether the transaction is committed during this
> + * function.
> + */
> +int
> +xfs_attr_set_args(
> + struct xfs_da_args *args,
> + int flags,
> + struct xfs_buf *leaf_bp,
> + bool roll_trans)
> +{
> + struct xfs_inode *dp = args->dp;
> + struct xfs_mount *mp = dp->i_mount;
> + int error = 0;
> + int err2 = 0;
> + int sf_size;
> +
> + /*
> + * New inodes setting the parent pointer attr will
> + * not have an attribute fork yet. So set the attribute
> + * fork appropriately
> + */
> + if (XFS_IFORK_Q((args->dp)) == 0) {
> + sf_size = sizeof(struct xfs_attr_sf_hdr) +
> + XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
> + xfs_bmap_set_attrforkoff(args->dp, sf_size, NULL);
> + args->dp->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
> + args->dp->i_afp->if_flags = XFS_IFEXTENTS;
> + }
> +
> + xfs_trans_ijoin(args->trans, dp, 0);
> + /*
> + * If the attribute list is non-existent or a shortform list,
> + * upgrade it to a single-leaf-block attribute list.
> + */
> + if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
> + (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
> + dp->i_d.di_anextents == 0)) {
> +
> + /*
> + * Build initial attribute list (if required).
> + */
> + if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
> + xfs_attr_shortform_create(args);
> +
> + /*
> + * Try to add the attr to the attribute list in the inode.
> + */
> + error = xfs_attr_shortform_addname(args, roll_trans);
> + if (error != -ENOSPC) {
> + if (roll_trans) {
I dislike this roll_trans parameter. Most other places in xfs when a
function is passed in a defer_ops or a transaction it's assumed that we
don't own the transaction or the defer_ops and so while it's ok to
attach dirty things to the dfops or the tp, we let the caller decide
when it's appropriate to start committing things.
This function is getting rather long and indenty, can it be broken up
into smaller pieces? That should make it easier to reuse the core
logic of "try to stuff it in the sfattr, if it doesn't fit then convert
to attr block and retry the add" without having to add extra parameters
to control whether or not we commit transactions.
This is more complex than in other parts of xfs because we're (for the
moment anyway) leaving both the deferred and non-deferred paths, but at
least the attr logic and the transaction management logic should be
split into separate functions to handle the unique situations of both
the deferred and non-deferred xattr setting code.
Also, please don't hoist code into a helper function /and/ change its
behavior & parameters in the same patch.
--D
> + /*
> + * Commit the shortform mods, and we're done.
> + * NOTE: this is also the error path (EEXIST, etc).
> + */
> + ASSERT(args->trans != NULL);
> +
> + /*
> + * If this is a synchronous mount, make sure that
> + * the transaction goes to disk before returning
> + * to the user.
> + */
> + if (mp->m_flags & XFS_MOUNT_WSYNC)
> + xfs_trans_set_sync(args->trans);
> +
> + if (!error && (flags & ATTR_KERNOTIME) == 0)
> + xfs_trans_ichgtime(args->trans, dp,
> + XFS_ICHGTIME_CHG);
> +
> + err2 = xfs_trans_commit(args->trans);
> + error = error ? error : err2;
> + }
> + goto out;
> + }
> +
> + /*
> + * It won't fit in the shortform, transform to a leaf block.
> + * GROT: another possible req'mt for a double-split btree op.
> + */
> + error = xfs_attr_shortform_to_leaf(args, &leaf_bp);
> + if (error)
> + goto out;
> +
> + xfs_defer_bjoin(args->dfops, leaf_bp);
> + xfs_defer_ijoin(args->dfops, dp);
> + if (roll_trans) {
> + /*
> + * Prevent the leaf buffer from being unlocked so that a
> + * concurrent AIL push cannot grab the half-baked leaf
> + * buffer and run into problems with the write verifier.
> + */
> + xfs_trans_bhold(args->trans, leaf_bp);
> +
> + error = xfs_defer_finish(&args->trans, args->dfops);
> + if (error) {
> + args->trans = NULL;
> + goto out;
> + }
> +
> + /*
> + * Commit the leaf transformation. We'll need another
> + * (linked) transaction to add the new attribute to the
> + * leaf.
> + */
> + error = xfs_trans_roll_inode(&args->trans, dp);
> + if (error)
> + goto out;
> + xfs_defer_ijoin(args->dfops, dp);
> + xfs_trans_bjoin(args->trans, leaf_bp);
> + leaf_bp = NULL;
> + }
> + }
> +
> + if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
> + error = xfs_attr_leaf_addname(args, roll_trans);
> + else
> + error = xfs_attr_node_addname(args, roll_trans);
> + if (error)
> + goto out;
> +
> +out:
> + return error;
> +}
> +
> +/*
> * Calculate how many blocks we need for the new attribute,
> */
> STATIC int
> @@ -218,7 +346,7 @@ xfs_attr_set(
> struct xfs_trans_res tres;
> xfs_fsblock_t firstblock;
> int rsvd = (flags & ATTR_ROOT) != 0;
> - int error, err2, local;
> + int error, local;
>
> XFS_STATS_INC(mp, xs_attr_set);
>
> @@ -279,88 +407,11 @@ xfs_attr_set(
>
> xfs_trans_ijoin(args.trans, dp, 0);
>
> - /*
> - * If the attribute list is non-existent or a shortform list,
> - * upgrade it to a single-leaf-block attribute list.
> - */
> - if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
> - (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
> - dp->i_d.di_anextents == 0)) {
> -
> - /*
> - * Build initial attribute list (if required).
> - */
> - if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
> - xfs_attr_shortform_create(&args);
> -
> - /*
> - * Try to add the attr to the attribute list in
> - * the inode.
> - */
> - error = xfs_attr_shortform_addname(&args, true);
> - if (error != -ENOSPC) {
> - /*
> - * Commit the shortform mods, and we're done.
> - * NOTE: this is also the error path (EEXIST, etc).
> - */
> - ASSERT(args.trans != NULL);
> -
> - /*
> - * If this is a synchronous mount, make sure that
> - * the transaction goes to disk before returning
> - * to the user.
> - */
> - if (mp->m_flags & XFS_MOUNT_WSYNC)
> - xfs_trans_set_sync(args.trans);
> -
> - if (!error && (flags & ATTR_KERNOTIME) == 0) {
> - xfs_trans_ichgtime(args.trans, dp,
> - XFS_ICHGTIME_CHG);
> - }
> - err2 = xfs_trans_commit(args.trans);
> - xfs_iunlock(dp, XFS_ILOCK_EXCL);
> -
> - return error ? error : err2;
> - }
> -
> - /*
> - * It won't fit in the shortform, transform to a leaf block.
> - * GROT: another possible req'mt for a double-split btree op.
> - */
> - xfs_defer_init(args.dfops, args.firstblock);
> - error = xfs_attr_shortform_to_leaf(&args, &leaf_bp);
> - if (error)
> - goto out_defer_cancel;
> - /*
> - * Prevent the leaf buffer from being unlocked so that a
> - * concurrent AIL push cannot grab the half-baked leaf
> - * buffer and run into problems with the write verifier.
> - */
> - xfs_trans_bhold(args.trans, leaf_bp);
> - xfs_defer_bjoin(args.dfops, leaf_bp);
> - xfs_defer_ijoin(args.dfops, dp);
> - error = xfs_defer_finish(&args.trans, args.dfops);
> - if (error)
> - goto out_defer_cancel;
> -
> - /*
> - * Commit the leaf transformation. We'll need another (linked)
> - * transaction to add the new attribute to the leaf, which
> - * means that we have to hold & join the leaf buffer here too.
> - */
> - error = xfs_trans_roll_inode(&args.trans, dp);
> - if (error)
> - goto out;
> - xfs_trans_bjoin(args.trans, leaf_bp);
> - leaf_bp = NULL;
> - }
> + xfs_defer_init(args.dfops, args.firstblock);
> + error = xfs_attr_set_args(&args, flags, leaf_bp, true);
>
> - if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
> - error = xfs_attr_leaf_addname(&args, true);
> - else
> - error = xfs_attr_node_addname(&args, true);
> if (error)
> - goto out;
> + goto out_defer_cancel;
>
> /*
> * If this is a synchronous mount, make sure that the
> @@ -369,9 +420,6 @@ xfs_attr_set(
> if (mp->m_flags & XFS_MOUNT_WSYNC)
> xfs_trans_set_sync(args.trans);
>
> - if ((flags & ATTR_KERNOTIME) == 0)
> - xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
> -
> /*
> * Commit the last in the sequence of transactions.
> */
> @@ -383,7 +431,6 @@ xfs_attr_set(
>
> out_defer_cancel:
> xfs_defer_cancel(&dfops);
> -out:
> if (leaf_bp)
> xfs_trans_brelse(args.trans, leaf_bp);
> if (args.trans)
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index d07bf27..b5dc02c 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -152,6 +152,8 @@ int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
> unsigned char *value, int *valuelenp, int flags);
> int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
> unsigned char *value, int valuelen, int flags);
> +int xfs_attr_set_args(struct xfs_da_args *args, int flags,
> + struct xfs_buf *leaf_bp, bool roll_trans);
> int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
> int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
> int flags, struct attrlist_cursor_kern *cursor);
> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
> index 6a7c2f0..4e16a5d 100644
> --- a/fs/xfs/libxfs/xfs_bmap.c
> +++ b/fs/xfs/libxfs/xfs_bmap.c
> @@ -1031,6 +1031,34 @@ xfs_bmap_add_attrfork_local(
> return -EFSCORRUPTED;
> }
>
> +/* Set an inode attr fork off based on the format */
> +int
> +xfs_bmap_set_attrforkoff(
> + struct xfs_inode *ip,
> + int size,
> + int *version)
> +{
> + switch (ip->i_d.di_format) {
> + case XFS_DINODE_FMT_DEV:
> + ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3;
> + break;
> + case XFS_DINODE_FMT_LOCAL:
> + case XFS_DINODE_FMT_EXTENTS:
> + case XFS_DINODE_FMT_BTREE:
> + ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size);
> + if (!ip->i_d.di_forkoff)
> + ip->i_d.di_forkoff = xfs_default_attroffset(ip) >> 3;
> + else if ((ip->i_mount->m_flags & XFS_MOUNT_ATTR2) && version)
> + *version = 2;
> + break;
> + default:
> + ASSERT(0);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> /*
> * Convert inode from non-attributed to attributed.
> * Must not be in a transaction, ip must not be locked.
> @@ -1084,26 +1112,9 @@ xfs_bmap_add_attrfork(
>
> xfs_trans_ijoin(tp, ip, 0);
> xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
> -
> - switch (ip->i_d.di_format) {
> - case XFS_DINODE_FMT_DEV:
> - ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3;
> - break;
> - case XFS_DINODE_FMT_LOCAL:
> - case XFS_DINODE_FMT_EXTENTS:
> - case XFS_DINODE_FMT_BTREE:
> - ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size);
> - if (!ip->i_d.di_forkoff)
> - ip->i_d.di_forkoff = xfs_default_attroffset(ip) >> 3;
> - else if (mp->m_flags & XFS_MOUNT_ATTR2)
> - version = 2;
> - break;
> - default:
> - ASSERT(0);
> - error = -EINVAL;
> + error = xfs_bmap_set_attrforkoff(ip, size, &version);
> + if (error)
> goto trans_cancel;
> - }
> -
> ASSERT(ip->i_afp == NULL);
> ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
> ip->i_afp->if_flags = XFS_IFEXTENTS;
> diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
> index 2b766b3..50e9115 100644
> --- a/fs/xfs/libxfs/xfs_bmap.h
> +++ b/fs/xfs/libxfs/xfs_bmap.h
> @@ -191,6 +191,7 @@ void xfs_trim_extent(struct xfs_bmbt_irec *irec, xfs_fileoff_t bno,
> xfs_filblks_t len);
> void xfs_trim_extent_eof(struct xfs_bmbt_irec *, struct xfs_inode *);
> int xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd);
> +int xfs_bmap_set_attrforkoff(struct xfs_inode *ip, int size, int *version);
> void xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork);
> void xfs_bmap_add_free(struct xfs_mount *mp, struct xfs_defer_ops *dfops,
> xfs_fsblock_t bno, xfs_filblks_t len,
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 01/21] xfs: Move fs/xfs/xfs_attr.h to fs/xfs/libxfs/xfs_attr.h
2018-05-06 17:24 ` [PATCH 01/21] xfs: Move fs/xfs/xfs_attr.h to fs/xfs/libxfs/xfs_attr.h Allison Henderson
@ 2018-05-07 23:39 ` Darrick J. Wong
0 siblings, 0 replies; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 23:39 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:34AM -0700, Allison Henderson wrote:
> This patch moves fs/xfs/xfs_attr.h to fs/xfs/libxfs/xfs_attr.h
> since xfs_attr.c is in libxfs. We will need these later in
> xfsprogs.
>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Looks ok,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
--D
> ---
> fs/xfs/libxfs/xfs_attr.h | 160 +++++++++++++++++++++++++++++++++++++++++++++++
> fs/xfs/xfs_attr.h | 160 -----------------------------------------------
> 2 files changed, 160 insertions(+), 160 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> new file mode 100644
> index 0000000..d07bf27
> --- /dev/null
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -0,0 +1,160 @@
> +/*
> + * Copyright (c) 2000,2002-2003,2005 Silicon Graphics, Inc.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write the Free Software Foundation,
> + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +#ifndef __XFS_ATTR_H__
> +#define __XFS_ATTR_H__
> +
> +struct xfs_inode;
> +struct xfs_da_args;
> +struct xfs_attr_list_context;
> +
> +/*
> + * Large attribute lists are structured around Btrees where all the data
> + * elements are in the leaf nodes. Attribute names are hashed into an int,
> + * then that int is used as the index into the Btree. Since the hashval
> + * of an attribute name may not be unique, we may have duplicate keys.
> + * The internal links in the Btree are logical block offsets into the file.
> + *
> + * Small attribute lists use a different format and are packed as tightly
> + * as possible so as to fit into the literal area of the inode.
> + */
> +
> +/*========================================================================
> + * External interfaces
> + *========================================================================*/
> +
> +
> +#define ATTR_DONTFOLLOW 0x0001 /* -- unused, from IRIX -- */
> +#define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */
> +#define ATTR_TRUST 0x0004 /* -- unused, from IRIX -- */
> +#define ATTR_SECURE 0x0008 /* use attrs in security namespace */
> +#define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */
> +#define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */
> +
> +#define ATTR_KERNOTIME 0x1000 /* [kernel] don't update inode timestamps */
> +#define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */
> +
> +#define ATTR_INCOMPLETE 0x4000 /* [kernel] return INCOMPLETE attr keys */
> +
> +#define XFS_ATTR_FLAGS \
> + { ATTR_DONTFOLLOW, "DONTFOLLOW" }, \
> + { ATTR_ROOT, "ROOT" }, \
> + { ATTR_TRUST, "TRUST" }, \
> + { ATTR_SECURE, "SECURE" }, \
> + { ATTR_CREATE, "CREATE" }, \
> + { ATTR_REPLACE, "REPLACE" }, \
> + { ATTR_KERNOTIME, "KERNOTIME" }, \
> + { ATTR_KERNOVAL, "KERNOVAL" }, \
> + { ATTR_INCOMPLETE, "INCOMPLETE" }
> +
> +/*
> + * The maximum size (into the kernel or returned from the kernel) of an
> + * attribute value or the buffer used for an attr_list() call. Larger
> + * sizes will result in an ERANGE return code.
> + */
> +#define ATTR_MAX_VALUELEN (64*1024) /* max length of a value */
> +
> +/*
> + * Define how lists of attribute names are returned to the user from
> + * the attr_list() call. A large, 32bit aligned, buffer is passed in
> + * along with its size. We put an array of offsets at the top that each
> + * reference an attrlist_ent_t and pack the attrlist_ent_t's at the bottom.
> + */
> +typedef struct attrlist {
> + __s32 al_count; /* number of entries in attrlist */
> + __s32 al_more; /* T/F: more attrs (do call again) */
> + __s32 al_offset[1]; /* byte offsets of attrs [var-sized] */
> +} attrlist_t;
> +
> +/*
> + * Show the interesting info about one attribute. This is what the
> + * al_offset[i] entry points to.
> + */
> +typedef struct attrlist_ent { /* data from attr_list() */
> + __u32 a_valuelen; /* number bytes in value of attr */
> + char a_name[1]; /* attr name (NULL terminated) */
> +} attrlist_ent_t;
> +
> +/*
> + * Given a pointer to the (char*) buffer containing the attr_list() result,
> + * and an index, return a pointer to the indicated attribute in the buffer.
> + */
> +#define ATTR_ENTRY(buffer, index) \
> + ((attrlist_ent_t *) \
> + &((char *)buffer)[ ((attrlist_t *)(buffer))->al_offset[index] ])
> +
> +/*
> + * Kernel-internal version of the attrlist cursor.
> + */
> +typedef struct attrlist_cursor_kern {
> + __u32 hashval; /* hash value of next entry to add */
> + __u32 blkno; /* block containing entry (suggestion) */
> + __u32 offset; /* offset in list of equal-hashvals */
> + __u16 pad1; /* padding to match user-level */
> + __u8 pad2; /* padding to match user-level */
> + __u8 initted; /* T/F: cursor has been initialized */
> +} attrlist_cursor_kern_t;
> +
> +
> +/*========================================================================
> + * Structure used to pass context around among the routines.
> + *========================================================================*/
> +
> +
> +/* void; state communicated via *context */
> +typedef void (*put_listent_func_t)(struct xfs_attr_list_context *, int,
> + unsigned char *, int, int);
> +
> +typedef struct xfs_attr_list_context {
> + struct xfs_trans *tp;
> + struct xfs_inode *dp; /* inode */
> + struct attrlist_cursor_kern *cursor; /* position in list */
> + char *alist; /* output buffer */
> + int seen_enough; /* T/F: seen enough of list? */
> + ssize_t count; /* num used entries */
> + int dupcnt; /* count dup hashvals seen */
> + int bufsize; /* total buffer size */
> + int firstu; /* first used byte in buffer */
> + int flags; /* from VOP call */
> + int resynch; /* T/F: resynch with cursor */
> + put_listent_func_t put_listent; /* list output fmt function */
> + int index; /* index into output buffer */
> +} xfs_attr_list_context_t;
> +
> +
> +/*========================================================================
> + * Function prototypes for the kernel.
> + *========================================================================*/
> +
> +/*
> + * Overall external interface routines.
> + */
> +int xfs_attr_inactive(struct xfs_inode *dp);
> +int xfs_attr_list_int_ilocked(struct xfs_attr_list_context *);
> +int xfs_attr_list_int(struct xfs_attr_list_context *);
> +int xfs_inode_hasattr(struct xfs_inode *ip);
> +int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
> +int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
> + unsigned char *value, int *valuelenp, int flags);
> +int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
> + unsigned char *value, int valuelen, int flags);
> +int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
> +int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
> + int flags, struct attrlist_cursor_kern *cursor);
> +
> +
> +#endif /* __XFS_ATTR_H__ */
> diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
> deleted file mode 100644
> index d07bf27..0000000
> --- a/fs/xfs/xfs_attr.h
> +++ /dev/null
> @@ -1,160 +0,0 @@
> -/*
> - * Copyright (c) 2000,2002-2003,2005 Silicon Graphics, Inc.
> - * All Rights Reserved.
> - *
> - * This program is free software; you can redistribute it and/or
> - * modify it under the terms of the GNU General Public License as
> - * published by the Free Software Foundation.
> - *
> - * This program is distributed in the hope that it would be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program; if not, write the Free Software Foundation,
> - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> - */
> -#ifndef __XFS_ATTR_H__
> -#define __XFS_ATTR_H__
> -
> -struct xfs_inode;
> -struct xfs_da_args;
> -struct xfs_attr_list_context;
> -
> -/*
> - * Large attribute lists are structured around Btrees where all the data
> - * elements are in the leaf nodes. Attribute names are hashed into an int,
> - * then that int is used as the index into the Btree. Since the hashval
> - * of an attribute name may not be unique, we may have duplicate keys.
> - * The internal links in the Btree are logical block offsets into the file.
> - *
> - * Small attribute lists use a different format and are packed as tightly
> - * as possible so as to fit into the literal area of the inode.
> - */
> -
> -/*========================================================================
> - * External interfaces
> - *========================================================================*/
> -
> -
> -#define ATTR_DONTFOLLOW 0x0001 /* -- unused, from IRIX -- */
> -#define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */
> -#define ATTR_TRUST 0x0004 /* -- unused, from IRIX -- */
> -#define ATTR_SECURE 0x0008 /* use attrs in security namespace */
> -#define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */
> -#define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */
> -
> -#define ATTR_KERNOTIME 0x1000 /* [kernel] don't update inode timestamps */
> -#define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */
> -
> -#define ATTR_INCOMPLETE 0x4000 /* [kernel] return INCOMPLETE attr keys */
> -
> -#define XFS_ATTR_FLAGS \
> - { ATTR_DONTFOLLOW, "DONTFOLLOW" }, \
> - { ATTR_ROOT, "ROOT" }, \
> - { ATTR_TRUST, "TRUST" }, \
> - { ATTR_SECURE, "SECURE" }, \
> - { ATTR_CREATE, "CREATE" }, \
> - { ATTR_REPLACE, "REPLACE" }, \
> - { ATTR_KERNOTIME, "KERNOTIME" }, \
> - { ATTR_KERNOVAL, "KERNOVAL" }, \
> - { ATTR_INCOMPLETE, "INCOMPLETE" }
> -
> -/*
> - * The maximum size (into the kernel or returned from the kernel) of an
> - * attribute value or the buffer used for an attr_list() call. Larger
> - * sizes will result in an ERANGE return code.
> - */
> -#define ATTR_MAX_VALUELEN (64*1024) /* max length of a value */
> -
> -/*
> - * Define how lists of attribute names are returned to the user from
> - * the attr_list() call. A large, 32bit aligned, buffer is passed in
> - * along with its size. We put an array of offsets at the top that each
> - * reference an attrlist_ent_t and pack the attrlist_ent_t's at the bottom.
> - */
> -typedef struct attrlist {
> - __s32 al_count; /* number of entries in attrlist */
> - __s32 al_more; /* T/F: more attrs (do call again) */
> - __s32 al_offset[1]; /* byte offsets of attrs [var-sized] */
> -} attrlist_t;
> -
> -/*
> - * Show the interesting info about one attribute. This is what the
> - * al_offset[i] entry points to.
> - */
> -typedef struct attrlist_ent { /* data from attr_list() */
> - __u32 a_valuelen; /* number bytes in value of attr */
> - char a_name[1]; /* attr name (NULL terminated) */
> -} attrlist_ent_t;
> -
> -/*
> - * Given a pointer to the (char*) buffer containing the attr_list() result,
> - * and an index, return a pointer to the indicated attribute in the buffer.
> - */
> -#define ATTR_ENTRY(buffer, index) \
> - ((attrlist_ent_t *) \
> - &((char *)buffer)[ ((attrlist_t *)(buffer))->al_offset[index] ])
> -
> -/*
> - * Kernel-internal version of the attrlist cursor.
> - */
> -typedef struct attrlist_cursor_kern {
> - __u32 hashval; /* hash value of next entry to add */
> - __u32 blkno; /* block containing entry (suggestion) */
> - __u32 offset; /* offset in list of equal-hashvals */
> - __u16 pad1; /* padding to match user-level */
> - __u8 pad2; /* padding to match user-level */
> - __u8 initted; /* T/F: cursor has been initialized */
> -} attrlist_cursor_kern_t;
> -
> -
> -/*========================================================================
> - * Structure used to pass context around among the routines.
> - *========================================================================*/
> -
> -
> -/* void; state communicated via *context */
> -typedef void (*put_listent_func_t)(struct xfs_attr_list_context *, int,
> - unsigned char *, int, int);
> -
> -typedef struct xfs_attr_list_context {
> - struct xfs_trans *tp;
> - struct xfs_inode *dp; /* inode */
> - struct attrlist_cursor_kern *cursor; /* position in list */
> - char *alist; /* output buffer */
> - int seen_enough; /* T/F: seen enough of list? */
> - ssize_t count; /* num used entries */
> - int dupcnt; /* count dup hashvals seen */
> - int bufsize; /* total buffer size */
> - int firstu; /* first used byte in buffer */
> - int flags; /* from VOP call */
> - int resynch; /* T/F: resynch with cursor */
> - put_listent_func_t put_listent; /* list output fmt function */
> - int index; /* index into output buffer */
> -} xfs_attr_list_context_t;
> -
> -
> -/*========================================================================
> - * Function prototypes for the kernel.
> - *========================================================================*/
> -
> -/*
> - * Overall external interface routines.
> - */
> -int xfs_attr_inactive(struct xfs_inode *dp);
> -int xfs_attr_list_int_ilocked(struct xfs_attr_list_context *);
> -int xfs_attr_list_int(struct xfs_attr_list_context *);
> -int xfs_inode_hasattr(struct xfs_inode *ip);
> -int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
> -int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
> - unsigned char *value, int *valuelenp, int flags);
> -int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
> - unsigned char *value, int valuelen, int flags);
> -int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
> -int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
> - int flags, struct attrlist_cursor_kern *cursor);
> -
> -
> -#endif /* __XFS_ATTR_H__ */
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 02/21] Add trans toggle to attr routines
2018-05-06 17:24 ` [PATCH 02/21] Add trans toggle to attr routines Allison Henderson
@ 2018-05-07 23:52 ` Darrick J. Wong
2018-05-08 17:04 ` Allison Henderson
0 siblings, 1 reply; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-07 23:52 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 06, 2018 at 10:24:35AM -0700, Allison Henderson wrote:
> This patch adds a roll_trans parameter to all attribute routines.
> Calling functions may pass true to roll transactions as normal,
> or false to hold them. We will need this later for delayed
> attribute operations.
/me kinda dislikes this, but I guess the reason for the roll_trans
parameter is that we can't call defer_finish from a defer ops finishing
function, right?
Under the existing attr code we do things like:
_trans_alloc
_defer_init
*dirty transaction, accumulate dfops*
_defer_finish
*finish items*
*dirty transaction again, accumulate more dfops*
_defer_finish
*finish_items*
_trans_commit
But since we /really/ can't have nested _defer_finish calls I guess we
have to do something like this?
_defer_finish
_attr_finish_item
*dirty transaction, accumulate dfops*
bail out with EAGAIN
_defer_roll
_attr_finish_item (again)
*dirty transaction again, accumulate more dfops*
_defer_roll
*finish items*
Thoughts?
--D
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
> fs/xfs/libxfs/xfs_attr.c | 144 +++++++++++++++++++++++-------------------
> fs/xfs/libxfs/xfs_attr_leaf.c | 12 ++--
> fs/xfs/libxfs/xfs_attr_leaf.h | 8 +--
> 3 files changed, 90 insertions(+), 74 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index ce4a34a..0ade22b 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -55,21 +55,21 @@
> /*
> * Internal routines when attribute list fits inside the inode.
> */
> -STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
> +STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args, bool roll_trans);
>
> /*
> * Internal routines when attribute list is one block.
> */
> STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
> -STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
> -STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
> +STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args, bool roll_trans);
> +STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args, bool roll_trans);
>
> /*
> * Internal routines when attribute list is more than one block.
> */
> STATIC int xfs_attr_node_get(xfs_da_args_t *args);
> -STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
> -STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
> +STATIC int xfs_attr_node_addname(xfs_da_args_t *args, bool roll_trans);
> +STATIC int xfs_attr_node_removename(xfs_da_args_t *args, bool roll_trans);
> STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
> STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>
> @@ -297,7 +297,7 @@ xfs_attr_set(
> * Try to add the attr to the attribute list in
> * the inode.
> */
> - error = xfs_attr_shortform_addname(&args);
> + error = xfs_attr_shortform_addname(&args, true);
> if (error != -ENOSPC) {
> /*
> * Commit the shortform mods, and we're done.
> @@ -356,9 +356,9 @@ xfs_attr_set(
> }
>
> if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
> - error = xfs_attr_leaf_addname(&args);
> + error = xfs_attr_leaf_addname(&args, true);
> else
> - error = xfs_attr_node_addname(&args);
> + error = xfs_attr_node_addname(&args, true);
> if (error)
> goto out;
>
> @@ -453,11 +453,11 @@ xfs_attr_remove(
> error = -ENOATTR;
> } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
> - error = xfs_attr_shortform_remove(&args);
> + error = xfs_attr_shortform_remove(&args, true);
> } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> - error = xfs_attr_leaf_removename(&args);
> + error = xfs_attr_leaf_removename(&args, true);
> } else {
> - error = xfs_attr_node_removename(&args);
> + error = xfs_attr_node_removename(&args, true);
> }
>
> if (error)
> @@ -498,7 +498,7 @@ xfs_attr_remove(
> * This is the external routine.
> */
> STATIC int
> -xfs_attr_shortform_addname(xfs_da_args_t *args)
> +xfs_attr_shortform_addname(xfs_da_args_t *args, bool roll_trans)
> {
> int newsize, forkoff, retval;
>
> @@ -510,7 +510,7 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
> } else if (retval == -EEXIST) {
> if (args->flags & ATTR_CREATE)
> return retval;
> - retval = xfs_attr_shortform_remove(args);
> + retval = xfs_attr_shortform_remove(args, roll_trans);
> ASSERT(retval == 0);
> }
>
> @@ -525,7 +525,7 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
> if (!forkoff)
> return -ENOSPC;
>
> - xfs_attr_shortform_add(args, forkoff);
> + xfs_attr_shortform_add(args, forkoff, roll_trans);
> return 0;
> }
>
> @@ -541,7 +541,7 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
> * if bmap_one_block() says there is only one block (ie: no remote blks).
> */
> STATIC int
> -xfs_attr_leaf_addname(xfs_da_args_t *args)
> +xfs_attr_leaf_addname(xfs_da_args_t *args, bool roll_trans)
> {
> xfs_inode_t *dp;
> struct xfs_buf *bp;
> @@ -604,36 +604,42 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
> * can manage its own transactions.
> */
> xfs_defer_init(args->dfops, args->firstblock);
> - error = xfs_attr3_leaf_to_node(args);
> - if (error)
> - goto out_defer_cancel;
> - xfs_defer_ijoin(args->dfops, dp);
> - error = xfs_defer_finish(&args->trans, args->dfops);
> + error = xfs_attr3_leaf_to_node(args, roll_trans);
> if (error)
> goto out_defer_cancel;
> + if (roll_trans) {
> + xfs_defer_ijoin(args->dfops, dp);
> + error = xfs_defer_finish(&args->trans, args->dfops);
> + if (error)
> + goto out_defer_cancel;
>
> - /*
> - * Commit the current trans (including the inode) and start
> - * a new one.
> - */
> - error = xfs_trans_roll_inode(&args->trans, dp);
> - if (error)
> - return error;
> + /*
> + * Commit the current trans (including the inode) and start
> + * a new one.
> + */
> + error = xfs_trans_roll_inode(&args->trans, dp);
> + if (error)
> + return error;
> + }
>
> /*
> * Fob the whole rest of the problem off on the Btree code.
> */
> - error = xfs_attr_node_addname(args);
> + error = xfs_attr_node_addname(args, roll_trans);
> +
> return error;
> }
>
> - /*
> - * Commit the transaction that added the attr name so that
> - * later routines can manage their own transactions.
> - */
> - error = xfs_trans_roll_inode(&args->trans, dp);
> - if (error)
> - return error;
> +
> + if (roll_trans) {
> + /*
> + * Commit the transaction that added the attr name so that
> + * later routines can manage their own transactions.
> + */
> + error = xfs_trans_roll_inode(&args->trans, dp);
> + if (error)
> + return error;
> + }
>
> /*
> * If there was an out-of-line value, allocate the blocks we
> @@ -691,9 +697,9 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
> /*
> * If the result is small enough, shrink it all into the inode.
> */
> - if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
> + if ((forkoff = xfs_attr_shortform_allfit(bp, dp)) && roll_trans) {
> xfs_defer_init(args->dfops, args->firstblock);
> - error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> + error = xfs_attr3_leaf_to_shortform(bp, args, forkoff, roll_trans);
> /* bp is gone due to xfs_da_shrink_inode */
> if (error)
> goto out_defer_cancel;
> @@ -727,7 +733,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
> * if bmap_one_block() says there is only one block (ie: no remote blks).
> */
> STATIC int
> -xfs_attr_leaf_removename(xfs_da_args_t *args)
> +xfs_attr_leaf_removename(xfs_da_args_t *args, bool roll_trans)
> {
> xfs_inode_t *dp;
> struct xfs_buf *bp;
> @@ -755,9 +761,9 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
> /*
> * If the result is small enough, shrink it all into the inode.
> */
> - if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
> + if ((forkoff = xfs_attr_shortform_allfit(bp, dp)) && roll_trans) {
> xfs_defer_init(args->dfops, args->firstblock);
> - error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> + error = xfs_attr3_leaf_to_shortform(bp, args, forkoff, roll_trans);
> /* bp is gone due to xfs_da_shrink_inode */
> if (error)
> goto out_defer_cancel;
> @@ -819,7 +825,7 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
> * add a whole extra layer of confusion on top of that.
> */
> STATIC int
> -xfs_attr_node_addname(xfs_da_args_t *args)
> +xfs_attr_node_addname(xfs_da_args_t *args, bool roll_trans)
> {
> xfs_da_state_t *state;
> xfs_da_state_blk_t *blk;
> @@ -885,21 +891,23 @@ xfs_attr_node_addname(xfs_da_args_t *args)
> xfs_da_state_free(state);
> state = NULL;
> xfs_defer_init(args->dfops, args->firstblock);
> - error = xfs_attr3_leaf_to_node(args);
> + error = xfs_attr3_leaf_to_node(args, roll_trans);
> if (error)
> goto out_defer_cancel;
> xfs_defer_ijoin(args->dfops, dp);
> - error = xfs_defer_finish(&args->trans, args->dfops);
> - if (error)
> - goto out_defer_cancel;
> -
> - /*
> - * Commit the node conversion and start the next
> - * trans in the chain.
> - */
> - error = xfs_trans_roll_inode(&args->trans, dp);
> - if (error)
> - goto out;
> + if (roll_trans) {
> + error = xfs_defer_finish(&args->trans, args->dfops);
> + if (error)
> + goto out_defer_cancel;
> +
> + /*
> + * Commit the node conversion and start the next
> + * trans in the chain.
> + */
> + error = xfs_trans_roll_inode(&args->trans, dp);
> + if (error)
> + goto out;
> + }
>
> goto restart;
> }
> @@ -915,9 +923,11 @@ xfs_attr_node_addname(xfs_da_args_t *args)
> if (error)
> goto out_defer_cancel;
> xfs_defer_ijoin(args->dfops, dp);
> - error = xfs_defer_finish(&args->trans, args->dfops);
> - if (error)
> - goto out_defer_cancel;
> + if (roll_trans) {
> + error = xfs_defer_finish(&args->trans, args->dfops);
> + if (error)
> + goto out_defer_cancel;
> + }
> } else {
> /*
> * Addition succeeded, update Btree hashvals.
> @@ -936,9 +946,11 @@ xfs_attr_node_addname(xfs_da_args_t *args)
> * Commit the leaf addition or btree split and start the next
> * trans in the chain.
> */
> - error = xfs_trans_roll_inode(&args->trans, dp);
> - if (error)
> - goto out;
> + if (roll_trans) {
> + error = xfs_trans_roll_inode(&args->trans, dp);
> + if (error)
> + goto out;
> + }
>
> /*
> * If there was an out-of-line value, allocate the blocks we
> @@ -1013,9 +1025,11 @@ xfs_attr_node_addname(xfs_da_args_t *args)
> if (error)
> goto out_defer_cancel;
> xfs_defer_ijoin(args->dfops, dp);
> - error = xfs_defer_finish(&args->trans, args->dfops);
> - if (error)
> - goto out_defer_cancel;
> + if (roll_trans) {
> + error = xfs_defer_finish(&args->trans, args->dfops);
> + if (error)
> + goto out_defer_cancel;
> + }
> }
>
> /*
> @@ -1054,7 +1068,7 @@ xfs_attr_node_addname(xfs_da_args_t *args)
> * the root node (a special case of an intermediate node).
> */
> STATIC int
> -xfs_attr_node_removename(xfs_da_args_t *args)
> +xfs_attr_node_removename(xfs_da_args_t *args, bool roll_trans)
> {
> xfs_da_state_t *state;
> xfs_da_state_blk_t *blk;
> @@ -1163,9 +1177,9 @@ xfs_attr_node_removename(xfs_da_args_t *args)
> if (error)
> goto out;
>
> - if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
> + if ((forkoff = xfs_attr_shortform_allfit(bp, dp)) && roll_trans) {
> xfs_defer_init(args->dfops, args->firstblock);
> - error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> + error = xfs_attr3_leaf_to_shortform(bp, args, forkoff, roll_trans);
> /* bp is gone due to xfs_da_shrink_inode */
> if (error)
> goto out_defer_cancel;
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index 2135b8e..01935fe 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -546,7 +546,7 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
> * Overflow from the inode has already been checked for.
> */
> void
> -xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
> +xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff, bool roll_trans)
> {
> xfs_attr_shortform_t *sf;
> xfs_attr_sf_entry_t *sfe;
> @@ -618,7 +618,7 @@ xfs_attr_fork_remove(
> * Remove an attribute from the shortform attribute list structure.
> */
> int
> -xfs_attr_shortform_remove(xfs_da_args_t *args)
> +xfs_attr_shortform_remove(xfs_da_args_t *args, bool roll_trans)
> {
> xfs_attr_shortform_t *sf;
> xfs_attr_sf_entry_t *sfe;
> @@ -970,7 +970,8 @@ int
> xfs_attr3_leaf_to_shortform(
> struct xfs_buf *bp,
> struct xfs_da_args *args,
> - int forkoff)
> + int forkoff,
> + bool roll_trans)
> {
> struct xfs_attr_leafblock *leaf;
> struct xfs_attr3_icleaf_hdr ichdr;
> @@ -1039,7 +1040,7 @@ xfs_attr3_leaf_to_shortform(
> nargs.valuelen = be16_to_cpu(name_loc->valuelen);
> nargs.hashval = be32_to_cpu(entry->hashval);
> nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags);
> - xfs_attr_shortform_add(&nargs, forkoff);
> + xfs_attr_shortform_add(&nargs, forkoff, roll_trans);
> }
> error = 0;
>
> @@ -1053,7 +1054,8 @@ xfs_attr3_leaf_to_shortform(
> */
> int
> xfs_attr3_leaf_to_node(
> - struct xfs_da_args *args)
> + struct xfs_da_args *args,
> + bool roll_trans)
> {
> struct xfs_attr_leafblock *leaf;
> struct xfs_attr3_icleaf_hdr icleafhdr;
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
> index 4da08af..b5dea0e 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
> @@ -45,12 +45,12 @@ typedef struct xfs_attr_inactive_list {
> * Internal routines when attribute fork size < XFS_LITINO(mp).
> */
> void xfs_attr_shortform_create(struct xfs_da_args *args);
> -void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff);
> +void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff, bool roll_trans);
> int xfs_attr_shortform_lookup(struct xfs_da_args *args);
> int xfs_attr_shortform_getvalue(struct xfs_da_args *args);
> int xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
> struct xfs_buf **leaf_bp);
> -int xfs_attr_shortform_remove(struct xfs_da_args *args);
> +int xfs_attr_shortform_remove(struct xfs_da_args *args, bool roll_trans);
> int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
> int xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes);
> xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_inode *ip);
> @@ -59,9 +59,9 @@ void xfs_attr_fork_remove(struct xfs_inode *ip, struct xfs_trans *tp);
> /*
> * Internal routines when attribute fork size == XFS_LBSIZE(mp).
> */
> -int xfs_attr3_leaf_to_node(struct xfs_da_args *args);
> +int xfs_attr3_leaf_to_node(struct xfs_da_args *args, bool roll_trans);
> int xfs_attr3_leaf_to_shortform(struct xfs_buf *bp,
> - struct xfs_da_args *args, int forkoff);
> + struct xfs_da_args *args, int forkoff, bool roll_trans);
> int xfs_attr3_leaf_clearflag(struct xfs_da_args *args);
> int xfs_attr3_leaf_setflag(struct xfs_da_args *args);
> int xfs_attr3_leaf_flipflags(struct xfs_da_args *args);
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 00/21] Parent Pointers v6
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
` (20 preceding siblings ...)
2018-05-06 17:24 ` [PATCH 21/21] xfs: Add delayed attributes error tag Allison Henderson
@ 2018-05-08 5:36 ` Amir Goldstein
2018-05-08 17:03 ` Allison Henderson
21 siblings, 1 reply; 72+ messages in thread
From: Amir Goldstein @ 2018-05-08 5:36 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs, Darrick J. Wong
On Sun, May 6, 2018 at 8:24 PM, Allison Henderson
<allison.henderson@oracle.com> wrote:
> Hi all,
>
> This is the 6th version of parent pointer attributes for xfs. The goal of
Please try to remember to use git format-patch -v $N as it makes it easier
to lookup old revisions of the patch in the mailbox.
Looking back, I see that Darrick doesn't seem to be tagging individual
patches with revision in his patch bombs as well...
Thanks,
Amir.
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 03/21] xfs: Add attibute set and helper functions
2018-05-07 23:36 ` Darrick J. Wong
@ 2018-05-08 7:25 ` Amir Goldstein
2018-05-08 17:02 ` Allison Henderson
2018-05-08 17:01 ` Allison Henderson
1 sibling, 1 reply; 72+ messages in thread
From: Amir Goldstein @ 2018-05-08 7:25 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: Allison Henderson, linux-xfs
On Tue, May 8, 2018 at 2:36 AM, Darrick J. Wong <darrick.wong@oracle.com> wrote:
> On Sun, May 06, 2018 at 10:24:36AM -0700, Allison Henderson wrote:
>> This patch adds xfs_attr_set_args and xfs_bmap_set_attrforkoff.
>> These sub-routines set the attributes specified in @args.
>> We will use this later for setting parent pointers as a deferred
>> attribute operation.
>>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
>> fs/xfs/libxfs/xfs_attr.c | 217 ++++++++++++++++++++++++++++-------------------
>> fs/xfs/libxfs/xfs_attr.h | 2 +
>> fs/xfs/libxfs/xfs_bmap.c | 49 ++++++-----
>> fs/xfs/libxfs/xfs_bmap.h | 1 +
>> 4 files changed, 165 insertions(+), 104 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 0ade22b..99c4a31 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -168,6 +168,134 @@ xfs_attr_get(
>> }
>>
>> /*
>> + * Set the attribute specified in @args. In the case of the parent attribute
>> + * being set, we do not want to roll the transaction on shortform-to-leaf
>> + * conversion, as the attribute must be added in the same transaction as the
>> + * parent directory modifications. Hence @roll_trans needs to be set
>> + * appropriately to control whether the transaction is committed during this
>> + * function.
>> + */
>> +int
>> +xfs_attr_set_args(
>> + struct xfs_da_args *args,
>> + int flags,
>> + struct xfs_buf *leaf_bp,
>> + bool roll_trans)
>> +{
>> + struct xfs_inode *dp = args->dp;
>> + struct xfs_mount *mp = dp->i_mount;
>> + int error = 0;
>> + int err2 = 0;
>> + int sf_size;
>> +
>> + /*
>> + * New inodes setting the parent pointer attr will
>> + * not have an attribute fork yet. So set the attribute
>> + * fork appropriately
>> + */
>> + if (XFS_IFORK_Q((args->dp)) == 0) {
>> + sf_size = sizeof(struct xfs_attr_sf_hdr) +
>> + XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
>> + xfs_bmap_set_attrforkoff(args->dp, sf_size, NULL);
>> + args->dp->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
>> + args->dp->i_afp->if_flags = XFS_IFEXTENTS;
>> + }
>> +
>> + xfs_trans_ijoin(args->trans, dp, 0);
>> + /*
>> + * If the attribute list is non-existent or a shortform list,
>> + * upgrade it to a single-leaf-block attribute list.
>> + */
>> + if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
>> + (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
>> + dp->i_d.di_anextents == 0)) {
>> +
>> + /*
>> + * Build initial attribute list (if required).
>> + */
>> + if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
>> + xfs_attr_shortform_create(args);
>> +
>> + /*
>> + * Try to add the attr to the attribute list in the inode.
>> + */
>> + error = xfs_attr_shortform_addname(args, roll_trans);
>> + if (error != -ENOSPC) {
>> + if (roll_trans) {
>
> I dislike this roll_trans parameter. Most other places in xfs when a
> function is passed in a defer_ops or a transaction it's assumed that we
> don't own the transaction or the defer_ops and so while it's ok to
> attach dirty things to the dfops or the tp, we let the caller decide
> when it's appropriate to start committing things.
>
> This function is getting rather long and indenty, can it be broken up
> into smaller pieces? That should make it easier to reuse the core
> logic of "try to stuff it in the sfattr, if it doesn't fit then convert
> to attr block and retry the add" without having to add extra parameters
> to control whether or not we commit transactions.
>
> This is more complex than in other parts of xfs because we're (for the
> moment anyway) leaving both the deferred and non-deferred paths, but at
> least the attr logic and the transaction management logic should be
> split into separate functions to handle the unique situations of both
> the deferred and non-deferred xattr setting code.
>
> Also, please don't hoist code into a helper function /and/ change its
> behavior & parameters in the same patch.
>
Indeed. I was going to comment that the description should say
"factor out helper" and "doesn't change logic" so reviewers can
review it properly, although now I am not sure if that is really the
case, so please make it the case.
Thanks,
Amir.
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 04/21] xfs: Add attibute remove and helper functions
2018-05-06 17:24 ` [PATCH 04/21] xfs: Add attibute remove " Allison Henderson
2018-05-07 23:21 ` Darrick J. Wong
@ 2018-05-08 7:33 ` Amir Goldstein
2018-05-08 17:02 ` Allison Henderson
2018-05-08 17:14 ` Darrick J. Wong
1 sibling, 2 replies; 72+ messages in thread
From: Amir Goldstein @ 2018-05-08 7:33 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 6, 2018 at 8:24 PM, Allison Henderson
<allison.henderson@oracle.com> wrote:
> This patch adds xfs_attr_remove_args. These sub-routines remove
> the attributes specified in @args. We will use this later for setting
> parent pointers as a deferred attribute operation.
>
But this patch also adds xfs_defer_init()+xfs_trans_ijoin()
so maybe I am not understanding how this work, but it seems
to be changing logic as well.
Please say something about this in commit message.
Thanks,
Amir.
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 05/21] xfs: Set up infastructure for deferred attribute operations
2018-05-06 17:24 ` [PATCH 05/21] xfs: Set up infastructure for deferred attribute operations Allison Henderson
2018-05-07 23:19 ` Darrick J. Wong
@ 2018-05-08 9:55 ` Amir Goldstein
1 sibling, 0 replies; 72+ messages in thread
From: Amir Goldstein @ 2018-05-08 9:55 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 6, 2018 at 8:24 PM, Allison Henderson
<allison.henderson@oracle.com> wrote:
> This patch adds two new log item types for setting or
> removing attributes as deferred operations. The
> xfs_attri_log_item logs an intent to set or remove an
> attribute. The corresponding xfs_attrd_log_item holds
> a reference to the xfs_attri_log_item and is freed once
> the transaction is done. Both log items use a generic
> xfs_attr_log_format structure that contains the attribute
> name, value, flags, inode, and an op_flag that indicates
> if the operations is a set or remove.
>
> At the moment, this feature will only be used by the parent
> pointer patch set which uses attributes to store information
> about an inodes parent.
>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
[...]
> +++ b/fs/xfs/xfs_trans_attr.c
> @@ -0,0 +1,283 @@
> +/*
> + * Copyright (c) 2017, Oracle Inc.
> + * All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it would be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write the Free Software Foundation Inc.
> + */
> +#include "xfs.h"
> +#include "xfs_fs.h"
> +#include "xfs_shared.h"
> +#include "xfs_format.h"
> +#include "xfs_log_format.h"
> +#include "xfs_trans_resv.h"
> +#include "xfs_bit.h"
> +#include "xfs_mount.h"
> +#include "xfs_defer.h"
> +#include "xfs_trans.h"
> +#include "xfs_trans_priv.h"
> +#include "xfs_attr_item.h"
> +#include "xfs_alloc.h"
> +#include "xfs_bmap.h"
> +#include "xfs_trace.h"
> +#include "libxfs/xfs_da_format.h"
> +#include "xfs_da_btree.h"
> +#include "xfs_attr.h"
> +#include "xfs_inode.h"
> +#include "xfs_icache.h"
> +#include "xfs_quota.h"
> +
> +/*
> + * This routine is called to allocate an "extent free done"
> + * log item that will hold nextents worth of extents. The
> + * caller must use all nextents extents, because we are not
> + * flexible about this at all.
> + */
Copy&paste error...
Thanks,
Amir.
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 18/21] xfs: Add parent pointers to rename
2018-05-06 17:24 ` [PATCH 18/21] xfs: Add parent pointers to rename Allison Henderson
2018-05-07 21:52 ` Darrick J. Wong
@ 2018-05-08 10:04 ` Amir Goldstein
1 sibling, 0 replies; 72+ messages in thread
From: Amir Goldstein @ 2018-05-08 10:04 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 6, 2018 at 8:24 PM, Allison Henderson
<allison.henderson@oracle.com> wrote:
> This patch removes the old parent pointer attribute during the
> rename operation, and re-adds the updated parent pointer
>
> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
> ---
> fs/xfs/xfs_inode.c | 68 +++++++++++++++++++++++++++++++++++++++++-------------
> 1 file changed, 52 insertions(+), 16 deletions(-)
>
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index b18b20c..7fd1479 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -3004,6 +3004,8 @@ xfs_rename(
> bool src_is_directory = S_ISDIR(VFS_I(src_ip)->i_mode);
> int spaceres;
> int error;
> + xfs_dir2_dataptr_t new_diroffset;
> + xfs_dir2_dataptr_t old_diroffset;
>
> trace_xfs_rename(src_dp, target_dp, src_name, target_name);
>
> @@ -3058,14 +3060,14 @@ xfs_rename(
> * we can rely on either trans_commit or trans_cancel to unlock
> * them.
> */
> - xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL);
> + xfs_trans_ijoin(tp, src_dp, 0);
> if (new_parent)
> - xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL);
> - xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
> + xfs_trans_ijoin(tp, target_dp, 0);
> + xfs_trans_ijoin(tp, src_ip, 0);
> if (target_ip)
> - xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
> + xfs_trans_ijoin(tp, target_ip, 0);
> if (wip)
> - xfs_trans_ijoin(tp, wip, XFS_ILOCK_EXCL);
> + xfs_trans_ijoin(tp, wip, 0);
>
> /*
> * If we are using project inheritance, we only allow renames
> @@ -3075,17 +3077,18 @@ xfs_rename(
> if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
> (xfs_get_projid(target_dp) != xfs_get_projid(src_ip)))) {
> error = -EXDEV;
> - goto out_trans_cancel;
> + goto out_unlock;
> }
>
> xfs_defer_init(&dfops, &first_block);
>
> /* RENAME_EXCHANGE is unique from here on. */
> - if (flags & RENAME_EXCHANGE)
> - return xfs_cross_rename(tp, src_dp, src_name, src_ip,
> + if (flags & RENAME_EXCHANGE) {
> + error = xfs_cross_rename(tp, src_dp, src_name, src_ip,
> target_dp, target_name, target_ip,
> &dfops, &first_block, spaceres);
> -
> + goto out;
What about updating parent pointers in xfs_cross_rename()?
Thanks,
Amir.
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 20/21] xfs: Add parent pointer ioctl
2018-05-07 21:36 ` Darrick J. Wong
@ 2018-05-08 10:24 ` Amir Goldstein
2018-05-08 10:25 ` Amir Goldstein
2018-05-08 16:57 ` Allison Henderson
1 sibling, 1 reply; 72+ messages in thread
From: Amir Goldstein @ 2018-05-08 10:24 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: Allison Henderson, linux-xfs
On Tue, May 8, 2018 at 12:36 AM, Darrick J. Wong
<darrick.wong@oracle.com> wrote:
> On Sun, May 06, 2018 at 10:24:53AM -0700, Allison Henderson wrote:
>> This patch adds a new file ioctl to retrieve the parent
>> pointer of a given inode
>>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
[...]
>> +
>> + /*
>> + * Now that we know how big the trailing buffer is, expand
>> + * our kernel xfs_pptr_info to be the same size
>> + */
>> + ppi = kmem_realloc(ppi, XFS_PPTR_INFO_SIZEOF(ppi->pi_ptrs_size),
>
> Hmm, pi_ptrs_size probably needs some kind of check so that userspace
> can't ask for insane large allocations. 64k, perhaps? ~230 records per
> call ought to be enough for anyone... :P
>
> if (XFS_PPTR_INFO_SIZEOFI(...) > XFS_XATTR_LIST_MAX)
> return -ENOMEM;
ERANGE feels more appropriate.
> ppi = kmem_realloc(...);
>
>> + KM_SLEEP);
>> + if (!ppi)
>> + return -ENOMEM;
>> +
>> + if (ppi->pi_flags == XFS_PPTR_IFLAG_HANDLE) {
>> + dentry = xfs_handle_to_dentry(filp, &ppi->pi_handle,
>> + sizeof(struct xfs_handle));
>> + if (IS_ERR(dentry))
>> + return PTR_ERR(dentry);
>> + ip = XFS_I(d_inode(dentry));
>
> I would've thought that between the dentry and the ip that at least one
> of those would require a dput/iput, and that we'd need to do something
> to prevent the dentry or the inode from disappearing from underneath us...
>
> ...but you could also extract the inode and generation numbers from the
> handle information and call xfs_iget directly. The exportfs code tries
> to reconnect dentry parent information up to the root, which will turn
> out badly if some mid-level directory is corrupt and scrub is trying to
> reconstruct the former path of a now inaccessible file.
>
Here is an easy code reuse solution for you.
It's a way to suppress reconnect and reuse of the conversions
done in xfs_handle_to_dentry().
Thanks,
Amir.
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 89fb1eb80aae..2312862dc34a 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -159,7 +159,8 @@ struct dentry *
xfs_handle_to_dentry(
struct file *parfilp,
void __user *uhandle,
- u32 hlen)
+ u32 hlen,
+ bool reconnect)
{
xfs_handle_t handle;
struct xfs_fid64 fid;
@@ -184,7 +185,7 @@ xfs_handle_to_dentry(
return exportfs_decode_fh(parfilp->f_path.mnt, (struct fid *)&fid, 3,
FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG,
- xfs_handle_acceptable, NULL);
+ reconnect ? xfs_handle_acceptable : NULL, NULL);
}
STATIC struct dentry *
@@ -192,7 +193,8 @@ xfs_handlereq_to_dentry(
struct file *parfilp,
xfs_fsop_handlereq_t *hreq)
{
- return xfs_handle_to_dentry(parfilp, hreq->ihandle, hreq->ihandlen);
+ return xfs_handle_to_dentry(parfilp, hreq->ihandle, hreq->ihandlen,
+ false);
}
^ permalink raw reply related [flat|nested] 72+ messages in thread
* Re: [PATCH 20/21] xfs: Add parent pointer ioctl
2018-05-08 10:24 ` Amir Goldstein
@ 2018-05-08 10:25 ` Amir Goldstein
0 siblings, 0 replies; 72+ messages in thread
From: Amir Goldstein @ 2018-05-08 10:25 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: Allison Henderson, linux-xfs
On Tue, May 8, 2018 at 1:24 PM, Amir Goldstein <amir73il@gmail.com> wrote:
> On Tue, May 8, 2018 at 12:36 AM, Darrick J. Wong
> <darrick.wong@oracle.com> wrote:
>> On Sun, May 06, 2018 at 10:24:53AM -0700, Allison Henderson wrote:
>>> This patch adds a new file ioctl to retrieve the parent
>>> pointer of a given inode
>>>
>>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>>> ---
> [...]
>>> +
>>> + /*
>>> + * Now that we know how big the trailing buffer is, expand
>>> + * our kernel xfs_pptr_info to be the same size
>>> + */
>>> + ppi = kmem_realloc(ppi, XFS_PPTR_INFO_SIZEOF(ppi->pi_ptrs_size),
>>
>> Hmm, pi_ptrs_size probably needs some kind of check so that userspace
>> can't ask for insane large allocations. 64k, perhaps? ~230 records per
>> call ought to be enough for anyone... :P
>>
>> if (XFS_PPTR_INFO_SIZEOFI(...) > XFS_XATTR_LIST_MAX)
>> return -ENOMEM;
>
> ERANGE feels more appropriate.
>
>> ppi = kmem_realloc(...);
>>
>>> + KM_SLEEP);
>>> + if (!ppi)
>>> + return -ENOMEM;
>>> +
>>> + if (ppi->pi_flags == XFS_PPTR_IFLAG_HANDLE) {
>>> + dentry = xfs_handle_to_dentry(filp, &ppi->pi_handle,
>>> + sizeof(struct xfs_handle));
>>> + if (IS_ERR(dentry))
>>> + return PTR_ERR(dentry);
>>> + ip = XFS_I(d_inode(dentry));
>>
>> I would've thought that between the dentry and the ip that at least one
>> of those would require a dput/iput, and that we'd need to do something
>> to prevent the dentry or the inode from disappearing from underneath us...
>>
>> ...but you could also extract the inode and generation numbers from the
>> handle information and call xfs_iget directly. The exportfs code tries
>> to reconnect dentry parent information up to the root, which will turn
>> out badly if some mid-level directory is corrupt and scrub is trying to
>> reconstruct the former path of a now inaccessible file.
>>
>
> Here is an easy code reuse solution for you.
> It's a way to suppress reconnect and reuse of the conversions
> done in xfs_handle_to_dentry().
>
> Thanks,
> Amir.
>
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index 89fb1eb80aae..2312862dc34a 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -159,7 +159,8 @@ struct dentry *
> xfs_handle_to_dentry(
> struct file *parfilp,
> void __user *uhandle,
> - u32 hlen)
> + u32 hlen,
> + bool reconnect)
> {
> xfs_handle_t handle;
> struct xfs_fid64 fid;
> @@ -184,7 +185,7 @@ xfs_handle_to_dentry(
>
> return exportfs_decode_fh(parfilp->f_path.mnt, (struct fid *)&fid, 3,
> FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG,
> - xfs_handle_acceptable, NULL);
> + reconnect ? xfs_handle_acceptable : NULL, NULL);
> }
>
> STATIC struct dentry *
> @@ -192,7 +193,8 @@ xfs_handlereq_to_dentry(
> struct file *parfilp,
> xfs_fsop_handlereq_t *hreq)
> {
> - return xfs_handle_to_dentry(parfilp, hreq->ihandle, hreq->ihandlen);
> + return xfs_handle_to_dentry(parfilp, hreq->ihandle, hreq->ihandlen,
> + false);
Sorry, that was meant to be true of course. false is what parent pointer ioctl
would use.
Thanks,
Amir.
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 20/21] xfs: Add parent pointer ioctl
2018-05-07 21:36 ` Darrick J. Wong
2018-05-08 10:24 ` Amir Goldstein
@ 2018-05-08 16:57 ` Allison Henderson
1 sibling, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 16:57 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 05/07/2018 02:36 PM, Darrick J. Wong wrote:
> On Sun, May 06, 2018 at 10:24:53AM -0700, Allison Henderson wrote:
>> This patch adds a new file ioctl to retrieve the parent
>> pointer of a given inode
>>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
>> fs/xfs/libxfs/xfs_fs.h | 38 ++++++++++++++++++++++++++
>> fs/xfs/libxfs/xfs_parent.c | 10 +++++++
>> fs/xfs/libxfs/xfs_parent.h | 2 ++
>> fs/xfs/xfs_attr_list.c | 3 +++
>> fs/xfs/xfs_ioctl.c | 61 +++++++++++++++++++++++++++++++++++++++++-
>> fs/xfs/xfs_parent_utils.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++
>> fs/xfs/xfs_parent_utils.h | 2 ++
>> 7 files changed, 181 insertions(+), 1 deletion(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
>> index 641e0af..4e0ccdd 100644
>> --- a/fs/xfs/libxfs/xfs_fs.h
>> +++ b/fs/xfs/libxfs/xfs_fs.h
>> @@ -552,6 +552,43 @@ struct xfs_scrub_metadata {
>> XFS_SCRUB_OFLAG_WARNING)
>> #define XFS_SCRUB_FLAGS_ALL (XFS_SCRUB_FLAGS_IN | XFS_SCRUB_FLAGS_OUT)
>>
>> +#define XFS_PPTR_MAXNAMELEN 255
>> +
>> +/* return parents of the handle, not the open fd */
>> +#define XFS_PPTR_IFLAG_HANDLE (1U << 0)
>> +
>> +/* Get an inode parent pointer through ioctl */
>> +struct xfs_parent_ptr {
>> + __u64 xpp_ino; /* Inode */
>> + __u32 xpp_gen; /* Inode generation */
>> + __u32 xpp_diroffset; /* Directory offset */
>> + __u32 xpp_namelen; /* File name length */
>> + __u8 xpp_name[XFS_PPTR_MAXNAMELEN]; /* File name */
>> +};
>
> Hmm, this structure probably needs padding to round up the size up to an
> even multiple of 8 bytes so that 32-bit userspace can call it without
> problems(?)
>
> (I suggest dumping the structure definitions into a plain C program and
> calling pahole...)
>
>> +
>> +/* Iterate though an inodes parent pointers */
>> +struct xfs_pptr_info {
>> + struct xfs_handle pi_handle;
>> + struct xfs_attrlist_cursor pi_cursor;
>> + __u32 pi_flags;
>> + __u32 pi_reserved;
>> + __u32 pi_ptrs_size;
>> + __u32 pi_ptrs_used;
>> + __u64 pi_reserved2[6];
>> +
>> + /*
>> + * An array of struct xfs_pptr follows the header
>> + * information. Use XFS_PPINFO_TO_PP() to access the
>> + * parent pointer array entries.
>> + */
>> +};
>> +
>> +#define XFS_PPTR_INFO_SIZEOF(nr_ptrs) sizeof (struct xfs_pptr_info) + \
>> + nr_ptrs * sizeof(struct xfs_parent_ptr)
>> +
>> +#define XFS_PPINFO_TO_PP(info, idx) \
>> + (&(((struct xfs_parent_ptr *)((char *)(info) + sizeof(*(info))))[(idx)]))
>> +
>> /*
>> * ioctl limits
>> */
>> @@ -596,6 +633,7 @@ struct xfs_scrub_metadata {
>> #define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_fs_eofblocks)
>> /* XFS_IOC_GETFSMAP ------ hoisted 59 */
>> #define XFS_IOC_SCRUB_METADATA _IOWR('X', 60, struct xfs_scrub_metadata)
>> +#define XFS_IOC_GETPPOINTER _IOR ('X', 61, struct xfs_parent_ptr)
>>
>> /*
>> * ioctl commands that replace IRIX syssgi()'s
>> diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
>> index e6de97c..61f1961 100644
>> --- a/fs/xfs/libxfs/xfs_parent.c
>> +++ b/fs/xfs/libxfs/xfs_parent.c
>> @@ -32,6 +32,16 @@
>> #include "xfs_attr_sf.h"
>> #include "xfs_bmap.h"
>>
>> +/* Initializes a xfs_parent_ptr from an xfs_parent_name_rec */
>> +void
>> +xfs_init_parent_ptr(struct xfs_parent_ptr *xpp,
>> + struct xfs_parent_name_rec *rec)
>> +{
>> + xpp->xpp_ino = be64_to_cpu(rec->p_ino);
>> + xpp->xpp_gen = be32_to_cpu(rec->p_gen);
>> + xpp->xpp_diroffset = be32_to_cpu(rec->p_diroffset);
>> +}
>> +
>> /*
>> * Parent pointer attribute handling.
>> *
>> diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h
>> index 298562b..1a321db 100644
>> --- a/fs/xfs/libxfs/xfs_parent.h
>> +++ b/fs/xfs/libxfs/xfs_parent.h
>> @@ -33,4 +33,6 @@ int xfs_parent_add(struct xfs_trans *tp, struct xfs_inode *parent,
>> struct xfs_inode *child, struct xfs_name *child_name,
>> uint32_t diroffset, xfs_fsblock_t *firstblock,
>> struct xfs_defer_ops *dfops);
>> +void xfs_init_parent_ptr(struct xfs_parent_ptr *xpp,
>> + struct xfs_parent_name_rec *rec);
>> #endif /* __XFS_PARENT_H__ */
>> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
>> index 3e59a34..bdbe9fb 100644
>> --- a/fs/xfs/xfs_attr_list.c
>> +++ b/fs/xfs/xfs_attr_list.c
>> @@ -581,6 +581,9 @@ xfs_attr_put_listent(
>> if (((context->flags & ATTR_ROOT) == 0) !=
>> ((flags & XFS_ATTR_ROOT) == 0))
>> return;
>> + if (((context->flags & ATTR_PARENT) == 0) !=
>> + ((flags & XFS_ATTR_PARENT) == 0))
>> + return;
>>
>> arraytop = sizeof(*alist) +
>> context->count * sizeof(alist->al_offset[0]);
>> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
>> index 844480a..ee544f2 100644
>> --- a/fs/xfs/xfs_ioctl.c
>> +++ b/fs/xfs/xfs_ioctl.c
>> @@ -46,6 +46,8 @@
>> #include "xfs_fsmap.h"
>> #include "scrub/xfs_scrub.h"
>> #include "xfs_sb.h"
>> +#include "xfs_da_format.h"
>> +#include "xfs_parent_utils.h"
>>
>> #include <linux/capability.h>
>> #include <linux/cred.h>
>> @@ -1738,6 +1740,62 @@ xfs_ioc_scrub_metadata(
>> return 0;
>> }
>>
>> +/*
>> + * IOCTL routine to get the parent pointer of an inode and return it to user
>> + * space. Caller must pass an struct xfs_parent_name_irec with a name buffer
>> + * large enough to hold the file name. Returns 0 on success or non-zero on
>> + * failure
>> + */
>> +STATIC int
>> +xfs_ioc_get_parent_pointer(
>> + struct file *filp,
>> + void __user *arg)
>> +{
>> + struct xfs_inode *ip;
>> + struct xfs_pptr_info *ppi;
>> + struct dentry *dentry;
>> + int error = 0;
>
> At least initially this ought to be restricted by capabilities.
>
> if (!capable(CAP_SYS_ADMIN))
> return -EPERM;
>
> I'd be open to allowing a few other capabilities? Maybe the DAC
> override one?
>
> Also needs to check for invalid pi_flags and nonzero reserved fields.
>
>> +
>> + /* Allocate an xfs_pptr_info to put the user data */
>> + ppi = kmem_alloc(sizeof(struct xfs_pptr_info), KM_SLEEP);
>> + if (!ppi)
>> + return -ENOMEM;
>> +
>> + /* Copy the data from the user */
>> + copy_from_user(ppi, arg, sizeof(struct xfs_pptr_info));
>
> Please do not throw away the return value.
>
>> +
>> + /*
>> + * Now that we know how big the trailing buffer is, expand
>> + * our kernel xfs_pptr_info to be the same size
>> + */
>> + ppi = kmem_realloc(ppi, XFS_PPTR_INFO_SIZEOF(ppi->pi_ptrs_size),
>
> Hmm, pi_ptrs_size probably needs some kind of check so that userspace
> can't ask for insane large allocations. 64k, perhaps? ~230 records per
> call ought to be enough for anyone... :P
>
> if (XFS_PPTR_INFO_SIZEOFI(...) > XFS_XATTR_LIST_MAX)
> return -ENOMEM;
> ppi = kmem_realloc(...);
>
>> + KM_SLEEP);
>> + if (!ppi)
>> + return -ENOMEM;
>> +
>> + if (ppi->pi_flags == XFS_PPTR_IFLAG_HANDLE) {
>> + dentry = xfs_handle_to_dentry(filp, &ppi->pi_handle,
>> + sizeof(struct xfs_handle));
>> + if (IS_ERR(dentry))
>> + return PTR_ERR(dentry);
>> + ip = XFS_I(d_inode(dentry));
>
> I would've thought that between the dentry and the ip that at least one
> of those would require a dput/iput, and that we'd need to do something
> to prevent the dentry or the inode from disappearing from underneath us...
>
> ...but you could also extract the inode and generation numbers from the
> handle information and call xfs_iget directly. The exportfs code tries
> to reconnect dentry parent information up to the root, which will turn
> out badly if some mid-level directory is corrupt and scrub is trying to
> reconstruct the former path of a now inaccessible file.
>
> That said, I could just fix this myself to satisfy the requirements of
> the, uh, single consumer of this information. :)
>
> (Particularly since my dorky rfc used this exact exportfs_decode_fh
> mechanism. :p)
>
> ((You could also replace this hunk with 'return -EPERM' and let me sort
> the whole thing out. :) ))
>
>> + } else
>> + ip = XFS_I(file_inode(filp));
>> +
>> + /* Get the parent pointers */
>> + error = xfs_attr_get_parent_pointer(ip, ppi);
>> +
>> + if (error)
>> + goto out;
>> +
>> + /* Copy the parent pointers back to the user */
>> + copy_to_user(arg, ppi, XFS_PPTR_INFO_SIZEOF(ppi->pi_ptrs_size));
>
> Need to check the return values here too.
>
>> +
>> +out:
>> + kmem_free(ppi);
>> + return error;
>> +}
>> +
>> int
>> xfs_ioc_swapext(
>> xfs_swapext_t *sxp)
>> @@ -1894,7 +1952,8 @@ xfs_file_ioctl(
>> return xfs_ioc_getxflags(ip, arg);
>> case XFS_IOC_SETXFLAGS:
>> return xfs_ioc_setxflags(ip, filp, arg);
>> -
>> + case XFS_IOC_GETPPOINTER:
>> + return xfs_ioc_get_parent_pointer(filp, arg);
>> case XFS_IOC_FSSETDM: {
>> struct fsdmidata dmi;
>>
>> diff --git a/fs/xfs/xfs_parent_utils.c b/fs/xfs/xfs_parent_utils.c
>> index 0fd48b8..1df003a 100644
>> --- a/fs/xfs/xfs_parent_utils.c
>> +++ b/fs/xfs/xfs_parent_utils.c
>> @@ -68,3 +68,69 @@ xfs_parent_remove_deferred(
>> ATTR_PARENT);
>> }
>>
>> +/*
>> + * Get the parent pointers for a given inode
>> + *
>> + * Returns 0 on success and non zero on error
>> + */
>> +int
>> +xfs_attr_get_parent_pointer(struct xfs_inode *ip,
>> + struct xfs_pptr_info *ppi)
>> +
>> +{
>> +
>> + struct attrlist *alist;
>> + struct attrlist_ent *aent;
>> + struct xfs_parent_ptr *xpp;
>> + struct xfs_parent_name_rec *xpnr;
>> + char *namebuf;
>> + unsigned int namebuf_size;
>> + int name_len;
>> + int error = 0;
>> + unsigned int flags = ATTR_PARENT;
>> + int i;
>> +
>> + /* Allocate a buffer to store the attribute names */
>> + namebuf_size = sizeof(struct attrlist) +
>> + (ppi->pi_ptrs_size) * sizeof(struct attrlist_ent);
>> + namebuf = kmem_zalloc_large(namebuf_size, KM_SLEEP);
>> + if (!namebuf)
>> + return -ENOMEM;
>> +
>> + error = xfs_attr_list(ip, namebuf, namebuf_size, flags,
>
> I suspect we need to hold the ILOCK across the xfs_attr_list call and
> the xfs_attr_get loop so that we hold the attr list consistent while
> extracting parent pointer information; see xfs_attr_list_int_ilocked and
> xfs_attr_get_ilocked...
>
> --D
>
Alrighty, I will get things updated. Thx for the review!
Allison
>> + (attrlist_cursor_kern_t *)&ppi->pi_cursor);
>> + if (error)
>> + goto out_kfree;
>> +
>> + alist = (struct attrlist *)namebuf;
>> +
>> + for (i = 0; i < alist->al_count; i++) {
>> + xpp = XFS_PPINFO_TO_PP(ppi, i);
>> + memset(xpp, 0, sizeof(struct xfs_parent_ptr));
>> + aent = (struct attrlist_ent *) &namebuf[alist->al_offset[i]];
>> + xpnr = (struct xfs_parent_name_rec *)(aent->a_name);
>> +
>> + if (aent->a_valuelen > XFS_PPTR_MAXNAMELEN) {
>> + error = -ERANGE;
>> + goto out_kfree;
>> + }
>> +
>> + name_len = aent->a_valuelen;
>> + error = xfs_attr_get(ip, (char *)xpnr,
>> + sizeof(struct xfs_parent_name_rec),
>> + (unsigned char *)(xpp->xpp_name),
>> + &name_len, flags);
>> + if (error)
>> + goto out_kfree;
>> +
>> + xpp->xpp_namelen = name_len;
>> + xfs_init_parent_ptr(xpp, xpnr);
>> + }
>> + ppi->pi_ptrs_used = alist->al_count;
>> +
>> +out_kfree:
>> + kmem_free(namebuf);
>> +
>> + return error;
>> +}
>> +
>> diff --git a/fs/xfs/xfs_parent_utils.h b/fs/xfs/xfs_parent_utils.h
>> index 9e0ac13..33e3b2c 100644
>> --- a/fs/xfs/xfs_parent_utils.h
>> +++ b/fs/xfs/xfs_parent_utils.h
>> @@ -27,4 +27,6 @@ int xfs_parent_remove_deferred(struct xfs_inode *parent,
>> struct xfs_inode *child,
>> xfs_dir2_dataptr_t diroffset,
>> struct xfs_defer_ops *dfops);
>> +int xfs_attr_get_parent_pointer(struct xfs_inode *ip,
>> + struct xfs_pptr_info *ppi);
>> #endif /* __XFS_PARENT_UTILS_H__ */
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 19/21] xfs: Add the parent pointer support to the superblock version 5.
2018-05-07 21:38 ` Darrick J. Wong
@ 2018-05-08 16:58 ` Allison Henderson
0 siblings, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 16:58 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 05/07/2018 02:38 PM, Darrick J. Wong wrote:
> On Sun, May 06, 2018 at 10:24:52AM -0700, Allison Henderson wrote:
>> [dchinner: forward ported and cleaned up]
>> [achender: rebased and added parent pointer attribute to
>> compatible attributes mask]
>>
>> Signed-off-by: Mark Tinguely <tinguely@sgi.com>
>> Signed-off-by: Dave Chinner <dchinner@redhat.com>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>
> Old kernels can't accidentally start returning the ATTR_PARENT
> attributes, right? I think the answer is yes.....?
>
> If so,
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
>
> --D
I suppose it's possible, though it wouldn't seem correct if they didn't
actually support the feature. Maybe I'm not understanding your concern?
You are concerned as to how we handle old file systems that may have
incorrectly set the attribute?
Allison
>
>> ---
>> fs/xfs/libxfs/xfs_format.h | 7 +++++--
>> fs/xfs/libxfs/xfs_fs.h | 1 +
>> fs/xfs/libxfs/xfs_sb.c | 2 ++
>> fs/xfs/xfs_super.c | 4 ++++
>> 4 files changed, 12 insertions(+), 2 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
>> index 5e946c8..d05ffc5 100644
>> --- a/fs/xfs/libxfs/xfs_format.h
>> +++ b/fs/xfs/libxfs/xfs_format.h
>> @@ -462,10 +462,12 @@ xfs_sb_has_compat_feature(
>> #define XFS_SB_FEAT_RO_COMPAT_FINOBT (1 << 0) /* free inode btree */
>> #define XFS_SB_FEAT_RO_COMPAT_RMAPBT (1 << 1) /* reverse map btree */
>> #define XFS_SB_FEAT_RO_COMPAT_REFLINK (1 << 2) /* reflinked files */
>> +#define XFS_SB_FEAT_RO_COMPAT_PARENT (1 << 3) /* parent inode ptr */
>> #define XFS_SB_FEAT_RO_COMPAT_ALL \
>> (XFS_SB_FEAT_RO_COMPAT_FINOBT | \
>> XFS_SB_FEAT_RO_COMPAT_RMAPBT | \
>> - XFS_SB_FEAT_RO_COMPAT_REFLINK)
>> + XFS_SB_FEAT_RO_COMPAT_REFLINK| \
>> + XFS_SB_FEAT_RO_COMPAT_PARENT)
>> #define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALL
>> static inline bool
>> xfs_sb_has_ro_compat_feature(
>> @@ -561,7 +563,8 @@ static inline bool xfs_sb_version_hasreflink(struct xfs_sb *sbp)
>>
>> static inline bool xfs_sb_version_hasparent(struct xfs_sb *sbp)
>> {
>> - return false; /* We'll enable this at the end of the set */
>> + return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 &&
>> + (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_PARENT));
>> }
>>
>> /*
>> diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
>> index faf1a4e..641e0af 100644
>> --- a/fs/xfs/libxfs/xfs_fs.h
>> +++ b/fs/xfs/libxfs/xfs_fs.h
>> @@ -222,6 +222,7 @@ typedef struct xfs_fsop_resblks {
>> #define XFS_FSOP_GEOM_FLAGS_SPINODES 0x40000 /* sparse inode chunks */
>> #define XFS_FSOP_GEOM_FLAGS_RMAPBT 0x80000 /* reverse mapping btree */
>> #define XFS_FSOP_GEOM_FLAGS_REFLINK 0x100000 /* files can share blocks */
>> +#define XFS_FSOP_GEOM_FLAGS_PARENT 0x200000 /* parent pointers */
>>
>> /*
>> * Minimum and maximum sizes need for growth checks.
>> diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
>> index d9b94bd..e1f0ac1 100644
>> --- a/fs/xfs/libxfs/xfs_sb.c
>> +++ b/fs/xfs/libxfs/xfs_sb.c
>> @@ -955,6 +955,8 @@ xfs_fs_geometry(
>> geo->flags |= XFS_FSOP_GEOM_FLAGS_RMAPBT;
>> if (xfs_sb_version_hasreflink(sbp))
>> geo->flags |= XFS_FSOP_GEOM_FLAGS_REFLINK;
>> + if(xfs_sb_version_hasparent(sbp))
>> + geo->flags |= XFS_FSOP_GEOM_FLAGS_PARENT;
>> if (xfs_sb_version_hassector(sbp))
>> geo->logsectsize = sbp->sb_logsectsize;
>> else
>> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
>> index dce3baf..366deee 100644
>> --- a/fs/xfs/xfs_super.c
>> +++ b/fs/xfs/xfs_super.c
>> @@ -1731,6 +1731,10 @@ xfs_fs_fill_super(
>> goto out_filestream_unmount;
>> }
>>
>> + if (xfs_sb_version_hasparent(&mp->m_sb))
>> + xfs_alert(mp,
>> + "EXPERIMENTAL parent pointer feature enabled. Use at your own risk!");
>> +
>> error = xfs_mountfs(mp);
>> if (error)
>> goto out_filestream_unmount;
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 18/21] xfs: Add parent pointers to rename
2018-05-07 21:52 ` Darrick J. Wong
@ 2018-05-08 16:58 ` Allison Henderson
0 siblings, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 16:58 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 05/07/2018 02:52 PM, Darrick J. Wong wrote:
> On Sun, May 06, 2018 at 10:24:51AM -0700, Allison Henderson wrote:
>> This patch removes the old parent pointer attribute during the
>> rename operation, and re-adds the updated parent pointer
>>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
>> fs/xfs/xfs_inode.c | 68 +++++++++++++++++++++++++++++++++++++++++-------------
>> 1 file changed, 52 insertions(+), 16 deletions(-)
>>
>> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
>> index b18b20c..7fd1479 100644
>> --- a/fs/xfs/xfs_inode.c
>> +++ b/fs/xfs/xfs_inode.c
>> @@ -3004,6 +3004,8 @@ xfs_rename(
>> bool src_is_directory = S_ISDIR(VFS_I(src_ip)->i_mode);
>> int spaceres;
>> int error;
>> + xfs_dir2_dataptr_t new_diroffset;
>> + xfs_dir2_dataptr_t old_diroffset;
>>
>> trace_xfs_rename(src_dp, target_dp, src_name, target_name);
>>
>> @@ -3058,14 +3060,14 @@ xfs_rename(
>> * we can rely on either trans_commit or trans_cancel to unlock
>> * them.
>> */
>> - xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL);
>> + xfs_trans_ijoin(tp, src_dp, 0);
>> if (new_parent)
>> - xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL);
>> - xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
>> + xfs_trans_ijoin(tp, target_dp, 0);
>> + xfs_trans_ijoin(tp, src_ip, 0);
>> if (target_ip)
>> - xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
>> + xfs_trans_ijoin(tp, target_ip, 0);
>> if (wip)
>> - xfs_trans_ijoin(tp, wip, XFS_ILOCK_EXCL);
>> + xfs_trans_ijoin(tp, wip, 0);
>>
>> /*
>> * If we are using project inheritance, we only allow renames
>> @@ -3075,17 +3077,18 @@ xfs_rename(
>> if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
>> (xfs_get_projid(target_dp) != xfs_get_projid(src_ip)))) {
>> error = -EXDEV;
>> - goto out_trans_cancel;
>> + goto out_unlock;
>> }
>>
>> xfs_defer_init(&dfops, &first_block);
>>
>> /* RENAME_EXCHANGE is unique from here on. */
>> - if (flags & RENAME_EXCHANGE)
>> - return xfs_cross_rename(tp, src_dp, src_name, src_ip,
>> + if (flags & RENAME_EXCHANGE) {
>> + error = xfs_cross_rename(tp, src_dp, src_name, src_ip,
>> target_dp, target_name, target_ip,
>> &dfops, &first_block, spaceres);
>> -
>> + goto out;
>> + }
>> /*
>> * Set up the target.
>> */
>> @@ -3097,7 +3100,7 @@ xfs_rename(
>> if (!spaceres) {
>> error = xfs_dir_canenter(tp, target_dp, target_name);
>> if (error)
>> - goto out_trans_cancel;
>> + goto out_unlock;
>> }
>> /*
>> * If target does not exist and the rename crosses
>> @@ -3106,7 +3109,7 @@ xfs_rename(
>> */
>> error = xfs_dir_createname(tp, target_dp, target_name,
>> src_ip->i_ino, &first_block, &dfops,
>> - spaceres, NULL);
>> + spaceres, &new_diroffset);
>> if (error)
>> goto out_bmap_cancel;
>>
>> @@ -3131,7 +3134,7 @@ xfs_rename(
>> if (!(xfs_dir_isempty(target_ip)) ||
>> (VFS_I(target_ip)->i_nlink > 2)) {
>> error = -EEXIST;
>> - goto out_trans_cancel;
>> + goto out_unlock;
>> }
>> }
>>
>> @@ -3146,7 +3149,7 @@ xfs_rename(
>> */
>> error = xfs_dir_replace(tp, target_dp, target_name,
>> src_ip->i_ino, &first_block, &dfops,
>> - spaceres, NULL);
>> + spaceres, &new_diroffset);
>> if (error)
>> goto out_bmap_cancel;
>>
>> @@ -3181,7 +3184,7 @@ xfs_rename(
>> */
>> error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,
>> target_dp->i_ino, &first_block, &dfops,
>> - spaceres, NULL);
>> + spaceres, &new_diroffset);
>> ASSERT(error != -EEXIST);
>> if (error)
>> goto out_bmap_cancel;
>> @@ -3220,11 +3223,12 @@ xfs_rename(
>> */
>> if (wip) {
>> error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino,
>> - &first_block, &dfops, spaceres, NULL);
>> + &first_block, &dfops, spaceres,
>> + &old_diroffset);
>> } else
>> error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
>> &first_block, &dfops, spaceres,
>> - NULL);
>> + &old_diroffset);
>> if (error)
>> goto out_bmap_cancel;
>>
>> @@ -3254,6 +3258,18 @@ xfs_rename(
>> VFS_I(wip)->i_state &= ~I_LINKABLE;
>> }
>>
>> + if (xfs_sb_version_hasparent(&mp->m_sb)) {
>> + error = xfs_parent_add_deferred(target_dp, src_ip, target_name,
>> + new_diroffset, &dfops);
>
> Only two indents needed for the second line:
>
> error = xfs_parent_add_deferred(target_dp, src_ip, target_name,
> new_diroffset, &dfops);
> if (error)
> goto out_bmap_cancel;
>
>> + if (error)
>> + goto out_bmap_cancel;
>> +
>> + error = xfs_parent_remove_deferred(src_dp, src_ip,
>> + old_diroffset, &dfops);
>> + if (error)
>> + goto out_bmap_cancel;
>> + }
>> +
>> xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
>> xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE);
>> if (new_parent)
>> @@ -3262,10 +3278,30 @@ xfs_rename(
>> error = xfs_finish_rename(tp, &dfops);
>> if (wip)
>> IRELE(wip);
>> +out:
>> + if (wip)
>> + xfs_iunlock(wip, XFS_ILOCK_EXCL);
>
> IRELE = iput = release inode, which means that you have to unlock the
> wip inode before you can release it.
>
> --D
>
Ok, I'll move that down and fix indents. Thx!
Allison
>> + if (target_ip)
>> + xfs_iunlock(target_ip, XFS_ILOCK_EXCL);
>> + xfs_iunlock(src_ip, XFS_ILOCK_EXCL);
>> + if (new_parent)
>> + xfs_iunlock(target_dp, XFS_ILOCK_EXCL);
>> + xfs_iunlock(src_dp, XFS_ILOCK_EXCL);
>> +
>> return error;
>>
>> out_bmap_cancel:
>> xfs_defer_cancel(&dfops);
>> +out_unlock:
>> + if (wip)
>> + xfs_iunlock(wip, XFS_ILOCK_EXCL);
>> + if (target_ip)
>> + xfs_iunlock(target_ip, XFS_ILOCK_EXCL);
>> + xfs_iunlock(src_ip, XFS_ILOCK_EXCL);
>> + if (new_parent)
>> + xfs_iunlock(target_dp, XFS_ILOCK_EXCL);
>> + xfs_iunlock(src_dp, XFS_ILOCK_EXCL);
>> +
>> out_trans_cancel:
>> xfs_trans_cancel(tp);
>> out_release_wip:
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 17/21] xfs: remove parent pointers in unlink
2018-05-07 21:59 ` Darrick J. Wong
@ 2018-05-08 16:58 ` Allison Henderson
0 siblings, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 16:58 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 05/07/2018 02:59 PM, Darrick J. Wong wrote:
> On Sun, May 06, 2018 at 10:24:50AM -0700, Allison Henderson wrote:
>> From: Dave Chinner <dchinner@redhat.com>
>>
>> This patch removes the parent pointer attribute during unlink
>>
>> [bfoster: rebase, use VFS inode generation]
>> [achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t
>> implemented xfs_attr_remove_parent]
>>
>> Signed-off-by: Dave Chinner <dchinner@redhat.com>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
>> fs/xfs/xfs_inode.c | 21 ++++++++++++++++-----
>> fs/xfs/xfs_parent_utils.c | 19 +++++++++++++++++++
>> fs/xfs/xfs_parent_utils.h | 4 ++++
>> 3 files changed, 39 insertions(+), 5 deletions(-)
>>
>> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
>> index 3a68e72..b18b20c 100644
>> --- a/fs/xfs/xfs_inode.c
>> +++ b/fs/xfs/xfs_inode.c
>> @@ -2624,6 +2624,7 @@ xfs_remove(
>> struct xfs_defer_ops dfops;
>> xfs_fsblock_t first_block;
>> uint resblks;
>> + xfs_dir2_dataptr_t dir_offset;
>>
>> trace_xfs_remove(dp, name);
>>
>> @@ -2661,8 +2662,8 @@ xfs_remove(
>>
>> xfs_lock_two_inodes(dp, XFS_ILOCK_EXCL, ip, XFS_ILOCK_EXCL);
>>
>> - xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
>> - xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
>> + xfs_trans_ijoin(tp, dp, 0);
>> + xfs_trans_ijoin(tp, ip, 0);
>>
>> /*
>> * If we're removing a directory perform some additional validation.
>> @@ -2704,12 +2705,18 @@ xfs_remove(
>>
>> xfs_defer_init(&dfops, &first_block);
>> error = xfs_dir_removename(tp, dp, name, ip->i_ino, &first_block,
>> - &dfops, resblks, NULL);
>> + &dfops, resblks, &dir_offset);
>> if (error) {
>> ASSERT(error != -ENOENT);
>> goto out_bmap_cancel;
>> }
>>
>> + if (xfs_sb_version_hasparent(&mp->m_sb)) {
>> + error = xfs_parent_remove_deferred(dp, ip, dir_offset, &dfops);
>> + if (error)
>> + goto out_bmap_cancel;
>> + }
>> +
>> /*
>> * If this is a synchronous mount, make sure that the
>> * remove transaction goes to disk before returning to
>> @@ -2724,17 +2731,21 @@ xfs_remove(
>>
>> error = xfs_trans_commit(tp);
>> if (error)
>> - goto std_return;
>> + goto out_unlock;
>>
>> if (is_dir && xfs_inode_is_filestream(ip))
>> xfs_filestream_deassociate(ip);
>>
>> - return 0;
>> + error = 0;
>> + goto out_unlock;
>
> I'd unlock the two inodes directly here instead of mixing the sucess
> return path with the error paths.
Sure, will fix. Thx!
Allison
>
>>
>> out_bmap_cancel:
>> xfs_defer_cancel(&dfops);
>> out_trans_cancel:
>> xfs_trans_cancel(tp);
>> +out_unlock:
>> + xfs_iunlock(ip, XFS_ILOCK_EXCL);
>> + xfs_iunlock(dp, XFS_ILOCK_EXCL);
>> std_return:
>> return error;
>> }
>> diff --git a/fs/xfs/xfs_parent_utils.c b/fs/xfs/xfs_parent_utils.c
>> index cf4a7e2..0fd48b8 100644
>> --- a/fs/xfs/xfs_parent_utils.c
>> +++ b/fs/xfs/xfs_parent_utils.c
>> @@ -49,3 +49,22 @@ xfs_parent_add_deferred(
>> (void *)child_name->name, child_name->len, ATTR_PARENT);
>> }
>>
>> +/*
>> + * Remove a parent record from a child inode.
>> + */
>> +int
>> +xfs_parent_remove_deferred(
>> + struct xfs_inode *parent,
>> + struct xfs_inode *child,
>> + xfs_dir2_dataptr_t diroffset,
>> + struct xfs_defer_ops *dfops)
>> +{
>> + struct xfs_parent_name_rec rec;
>> +
>> + xfs_init_parent_name_rec(&rec, parent->i_ino,
>> + VFS_I(parent)->i_generation, diroffset);
>> +
>> + return xfs_attr_remove_deferred(child, dfops, &rec, sizeof(rec),
>> + ATTR_PARENT);
>
> Two indents, no need to align these with the left paren.
>
> --D
>
>> +}
>> +
>> diff --git a/fs/xfs/xfs_parent_utils.h b/fs/xfs/xfs_parent_utils.h
>> index a667d1d..9e0ac13 100644
>> --- a/fs/xfs/xfs_parent_utils.h
>> +++ b/fs/xfs/xfs_parent_utils.h
>> @@ -23,4 +23,8 @@
>> int xfs_parent_add_deferred(struct xfs_inode *parent, struct xfs_inode *child,
>> struct xfs_name *child_name, uint32_t diroffset,
>> struct xfs_defer_ops *dfops);
>> +int xfs_parent_remove_deferred(struct xfs_inode *parent,
>> + struct xfs_inode *child,
>> + xfs_dir2_dataptr_t diroffset,
>> + struct xfs_defer_ops *dfops);
>> #endif /* __XFS_PARENT_UTILS_H__ */
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at https://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=KflT8_xtU5yMnGOwd0ZPCW2pBFzUSMyjcHn0gtvVEEs&s=KWZgWUtvv6RGSfjy5GjFPxiTq-ep3IqjgXLV5P52qX0&e=
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at https://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBAg&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=KflT8_xtU5yMnGOwd0ZPCW2pBFzUSMyjcHn0gtvVEEs&s=KWZgWUtvv6RGSfjy5GjFPxiTq-ep3IqjgXLV5P52qX0&e=
>
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 16/21] xfs: add parent attributes to link
2018-05-07 22:12 ` Darrick J. Wong
@ 2018-05-08 16:58 ` Allison Henderson
0 siblings, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 16:58 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 05/07/2018 03:12 PM, Darrick J. Wong wrote:
> On Sun, May 06, 2018 at 10:24:49AM -0700, Allison Henderson wrote:
>> From: Dave Chinner <dchinner@redhat.com>
>>
>> This patch modifies xfs_link to add a parent pointer to the inode.
>> xfs_link will also need to create an attribute fork if the inode does
>> not already have one.
>>
>> [bfoster: rebase, use VFS inode fields, fix xfs_bmap_finish() usage]
>> [achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
>> fixed null pointer bugs]
>>
>> Signed-off-by: Dave Chinner <dchinner@redhat.com>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
>> fs/xfs/xfs_inode.c | 66 ++++++++++++++++++++++++++++++++++++++++++------------
>> 1 file changed, 52 insertions(+), 14 deletions(-)
>>
>> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
>> index a515f11..3a68e72 100644
>> --- a/fs/xfs/xfs_inode.c
>> +++ b/fs/xfs/xfs_inode.c
>> @@ -1421,6 +1421,8 @@ xfs_link(
>> struct xfs_defer_ops dfops;
>> xfs_fsblock_t first_block;
>> int resblks;
>> + xfs_dir2_dataptr_t diroffset;
>> + bool first_parent = false;
>>
>> trace_xfs_link(tdp, target_name);
>>
>> @@ -1437,6 +1439,25 @@ xfs_link(
>> if (error)
>> goto std_return;
>>
>> + /*
>> + * If we have parent pointers and there is no attribute fork (i.e. we
>> + * are linking in a O_TMPFILE created inode) we need to add the
>> + * attribute fork to the inode. Because we may have an existing data
>> + * fork, we do this before we start the link transaction as adding an
>> + * attribute fork requires it's own transaction.
>> + */
>> + if (xfs_sb_version_hasparent(&mp->m_sb) && !xfs_inode_hasattr(sip)) {
>> + int sf_size = sizeof(struct xfs_attr_sf_hdr) +
>> + XFS_ATTR_SF_ENTSIZE_BYNAME(
>> + sizeof(struct xfs_parent_name_rec),
>> + target_name->len);
>> + ASSERT(VFS_I(sip)->i_nlink == 0);
>> + error = xfs_bmap_add_attrfork(sip, sf_size, 0);
>> + if (error)
>> + goto std_return;
>> + first_parent = true;
>
> Can adding the attribute fork ought to be made part of the finish step
> for deferred xattr setting? xfs_attr_finish_item() could do something
> like:
>
> if (!xfs_inode_hasattr(ip)) {
> sf_size = sizeof(...) + free->xattri_name_len;
> error = xfs_bmap_add_attrfork(free->xattri_ip, sf_size, 0);
> if (error)
> goto out_free;
> return -EAGAIN;
> }
>
> error = xfs_trans_attr(...existing stuff...);
> kmem_free(free);
> out_free:
> return error;
>
> The 'return -EAGAIN' tells the log item code that it needs to roll the
> transaction and then call us back to add the attr.
>
> --D
>
Sure, I will see if I can get it moved over there then. Thx!
Allison
>> + }
>> +
>> resblks = XFS_LINK_SPACE_RES(mp, target_name->len);
>> error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, resblks, 0, 0, &tp);
>> if (error == -ENOSPC) {
>> @@ -1448,8 +1469,8 @@ xfs_link(
>>
>> xfs_lock_two_inodes(sip, XFS_ILOCK_EXCL, tdp, XFS_ILOCK_EXCL);
>>
>> - xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL);
>> - xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL);
>> + xfs_trans_ijoin(tp, sip, 0);
>> + xfs_trans_ijoin(tp, tdp, 0);
>>
>> /*
>> * If we are using project inheritance, we only allow hard link
>> @@ -1468,8 +1489,6 @@ xfs_link(
>> goto error_return;
>> }
>>
>> - xfs_defer_init(&dfops, &first_block);
>> -
>> /*
>> * Handle initial link state of O_TMPFILE inode
>> */
>> @@ -1479,16 +1498,30 @@ xfs_link(
>> goto error_return;
>> }
>>
>> + xfs_defer_init(&dfops, &first_block);
>> error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
>> - &first_block, &dfops, resblks, NULL);
>> + &first_block, &dfops, resblks, &diroffset);
>> if (error)
>> - goto error_return;
>> + goto out_defer_cancel;
>> xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
>> xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
>>
>> error = xfs_bumplink(tp, sip);
>> if (error)
>> - goto error_return;
>> + goto out_defer_cancel;
>> +
>> + /*
>> + * If we have parent pointers, we now need to add the parent record to
>> + * the attribute fork of the inode. If this is the initial parent
>> + * attribute, we need to create it correctly, otherwise we can just add
>> + * the parent to the inode.
>> + */
>> + if (xfs_sb_version_hasparent(&mp->m_sb)) {
>> + error = xfs_parent_add_deferred(tdp, sip, target_name,
>> + diroffset, &dfops);
>> + if (error)
>> + goto out_defer_cancel;
>> + }
>>
>> /*
>> * If this is a synchronous mount, make sure that the
>> @@ -1499,16 +1532,21 @@ xfs_link(
>> xfs_trans_set_sync(tp);
>>
>> error = xfs_defer_finish(&tp, &dfops);
>> - if (error) {
>> - xfs_defer_cancel(&dfops);
>> - goto error_return;
>> - }
>> + if (error)
>> + goto out_defer_cancel;
>>
>> - return xfs_trans_commit(tp);
>> + error = xfs_trans_commit(tp);
>> + xfs_iunlock(tdp, XFS_ILOCK_EXCL);
>> + xfs_iunlock(sip, XFS_ILOCK_EXCL);
>> + return error;
>>
>> - error_return:
>> +out_defer_cancel:
>> + xfs_defer_cancel(&dfops);
>> +error_return:
>> xfs_trans_cancel(tp);
>> - std_return:
>> + xfs_iunlock(tdp, XFS_ILOCK_EXCL);
>> + xfs_iunlock(sip, XFS_ILOCK_EXCL);
>> +std_return:
>> return error;
>> }
>>
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 15/21] xfs: parent pointer attribute creation
2018-05-07 22:19 ` Darrick J. Wong
@ 2018-05-08 16:58 ` Allison Henderson
0 siblings, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 16:58 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 05/07/2018 03:19 PM, Darrick J. Wong wrote:
> On Sun, May 06, 2018 at 10:24:48AM -0700, Allison Henderson wrote:
>> From: Dave Chinner <dchinner@redhat.com>
>>
>> Add parent pointer attribute during xfs_create, and
>> subroutines to initialize attributes
>>
>> Kernel create routines take advantage of deferred attributes,
>> where as libxfs routines will add parent pointers directly.
>>
>> [bfoster: rebase, use VFS inode generation]
>> [achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
>> fixed some null pointer bugs,
>> merged error handling patch,
>> added subroutines to handle attribute initialization,
>> remove unnecessary ENOSPC handling in xfs_attr_set_first_parent]
>>
>> Signed-off-by: Dave Chinner <dchinner@redhat.com>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
>> fs/xfs/Makefile | 2 +
>> fs/xfs/libxfs/xfs_parent.c | 158 +++++++++++++++++++++++++++++++++++++++++++++
>> fs/xfs/libxfs/xfs_parent.h | 36 +++++++++++
>> fs/xfs/xfs_inode.c | 22 ++++++-
>> fs/xfs/xfs_parent_utils.c | 51 +++++++++++++++
>> fs/xfs/xfs_parent_utils.h | 26 ++++++++
>> 6 files changed, 292 insertions(+), 3 deletions(-)
>>
>> diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
>> index d3c0004..d092f72 100644
>> --- a/fs/xfs/Makefile
>> +++ b/fs/xfs/Makefile
>> @@ -53,6 +53,7 @@ xfs-y += $(addprefix libxfs/, \
>> xfs_inode_fork.o \
>> xfs_inode_buf.o \
>> xfs_log_rlimit.o \
>> + xfs_parent.o \
>> xfs_ag_resv.o \
>> xfs_rmap.o \
>> xfs_rmap_btree.o \
>> @@ -92,6 +93,7 @@ xfs-y += xfs_aops.o \
>> xfs_message.o \
>> xfs_mount.o \
>> xfs_mru_cache.o \
>> + xfs_parent_utils.o \
>> xfs_reflink.o \
>> xfs_stats.o \
>> xfs_super.o \
>> diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
>> new file mode 100644
>> index 0000000..e6de97c
>> --- /dev/null
>> +++ b/fs/xfs/libxfs/xfs_parent.c
>> @@ -0,0 +1,158 @@
>> +/*
>> + * Copyright (c) 2015 Red Hat, Inc.
>> + * All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it would be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write the Free Software Foundation
>> + */
>> +#include "xfs.h"
>> +#include "xfs_fs.h"
>> +#include "xfs_format.h"
>> +#include "xfs_da_format.h"
>> +#include "xfs_log_format.h"
>> +#include "xfs_shared.h"
>> +#include "xfs_trans_resv.h"
>> +#include "xfs_mount.h"
>> +#include "xfs_bmap_btree.h"
>> +#include "xfs_inode.h"
>> +#include "xfs_error.h"
>> +#include "xfs_trace.h"
>> +#include "xfs_trans.h"
>> +#include "xfs_attr.h"
>> +#include "xfs_da_btree.h"
>> +#include "xfs_attr_sf.h"
>> +#include "xfs_bmap.h"
>> +
>> +/*
>> + * Parent pointer attribute handling.
>> + *
>> + * Because the attribute value is a filename component, it will never be longer
>> + * than 255 bytes. This means the attribute will always be a local format
>> + * attribute as it is xfs_attr_leaf_entsize_local_max() for v5 filesystems will
>> + * always be larger than this (max is 75% of block size).
>> + *
>> + * Creating a new parent attribute will always create a new attribute - there
>> + * should never, ever be an existing attribute in the tree for a new inode.
>> + * ENOSPC behaviour is problematic - creating the inode without the parent
>> + * pointer is effectively a corruption, so we allow parent attribute creation
>> + * to dip into the reserve block pool to avoid unexpected ENOSPC errors from
>> + * occurring.
>> + */
>> +
>> +
>> +/* Initializes a xfs_parent_name_rec to be stored as an attribute name */
>> +void
>> +xfs_init_parent_name_rec(
>> + struct xfs_parent_name_rec *rec,
>> + xfs_ino_t p_ino,
>> + uint32_t p_gen,
>
> Seeing as both parameters are always from the same inode, just pass in
> the inode to extract the inode number & generation.
>
>> + uint32_t p_diroffset)
>
> Only one indent here and in the other function definitions.
>
> uint32_t p_diroffset)
>
>> +{
>> + rec->p_ino = cpu_to_be64(p_ino);
>> + rec->p_gen = cpu_to_be32(p_gen);
>> + rec->p_diroffset = cpu_to_be32(p_diroffset);
>> +}
>> +
>> +/* Initializes a xfs_parent_name_irec from an xfs_parent_name_rec */
>> +void
>> +xfs_init_parent_name_irec(
>> + struct xfs_parent_name_irec *irec,
>> + struct xfs_parent_name_rec *rec)
>> +{
>> + irec->p_ino = be64_to_cpu(rec->p_ino);
>> + irec->p_gen = be32_to_cpu(rec->p_gen);
>> + irec->p_diroffset = be32_to_cpu(rec->p_diroffset);
>> +}
>> +
>> +/*
>> + * Directly add a parent pointer instead of as a deferred operation
>> + * Currently only used during protofile creation
>> + */
>> +int
>> +xfs_parent_add(
>> + struct xfs_inode *parent,
>> + struct xfs_inode *child,
>> + struct xfs_name *child_name,
>> + uint32_t diroffset,
>> + xfs_fsblock_t *firstblock,
>> + struct xfs_defer_ops *dfops)
>> +{
>> + struct xfs_parent_name_rec rec;
>
> Indentation between the variable type and name should be consistent
> with the parameters. In other words, the parameters need an extra tab
> before the name.
>
>> + int error;
>> + struct xfs_da_args args;
>> + int flags = ATTR_PARENT;
>> + int local = 0;
>> + int rsvd = 0;
>> + struct xfs_buf *leaf_bp = NULL;
>> + struct xfs_trans_res tres;
>> + struct xfs_mount *mp = child->i_mount;
>> +
>> + xfs_init_parent_name_rec(&rec, parent->i_ino,
>> + VFS_I(parent)->i_generation, diroffset);
>> +
>> + error = xfs_attr_args_init(&args, child, (const unsigned char *)&rec,
>> + sizeof(rec), flags);
>> + if (error)
>> + return error;
>> +
>> + args.hashval = xfs_da_hashname(args.name, args.namelen);
>> + args.value = (char *)child_name->name;
>> + args.valuelen = child_name->len;
>> + args.dfops = dfops;
>> + args.op_flags = XFS_DA_OP_OKNOENT | XFS_DA_OP_ADDNAME;
>> + args.firstblock = firstblock;
>> + args.total = xfs_attr_calc_size(&args, &local);
>> + ASSERT(local);
>> +
>> + tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
>> + M_RES(mp)->tr_attrsetrt.tr_logres * args.total;
>> + tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
>> + tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
>> +
>> + /*
>> + * Root fork attributes can use reserved data blocks for this
>> + * operation if necessary
>> + */
>> + error = xfs_trans_alloc(mp, &tres, args.total, 0,
>> + rsvd ? XFS_TRANS_RESERVE : 0, &args.trans);
>> + if (error)
>> + goto out;
>> +
>> + /*
>> + * If the inode doesn't have an attribute fork, add one.
>> + * (inode must not be locked when we call this routine)
>> + */
>> + if (XFS_IFORK_Q(child) == 0) {
>> + int sf_size = sizeof(xfs_attr_sf_hdr_t) +
>> + XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, args.valuelen);
>> +
>> + error = xfs_bmap_add_attrfork(child, sf_size, rsvd);
>> + if (error)
>> + return error;
>> + }
>> +
>> + error = xfs_attr_set_args(&args, flags, leaf_bp, false);
>> +
>> + if (error)
>> + goto out;
>> +
>> + xfs_trans_log_inode(args.trans, child, XFS_ILOG_CORE);
>> +
>> + return error;
>> +
>> +out:
>> + if (args.trans)
>> + xfs_trans_cancel(args.trans);
>> +
>> + return error;
>> +}
>> +
>> diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h
>> new file mode 100644
>> index 0000000..298562b
>> --- /dev/null
>> +++ b/fs/xfs/libxfs/xfs_parent.h
>> @@ -0,0 +1,36 @@
>> +/*
>> + * Copyright (c) 2017 Oracle, Inc.
>
> Please update the copyright year. :)
>
>> + * All Rights Reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it would be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write the Free Software Foundation Inc.
>> + */
>> +#ifndef __XFS_PARENT_H__
>> +#define __XFS_PARENT_H__
>> +
>> +#include "xfs_da_format.h"
>> +#include "xfs_format.h"
>> +
>> +/*
>> + * Parent pointer attribute prototypes
>> + */
>> +void xfs_init_parent_name_rec(struct xfs_parent_name_rec *rec,
>> + xfs_ino_t p_ino, uint32_t p_gen,
>> + uint32_t p_diroffset);
>> +void xfs_init_parent_name_irec(struct xfs_parent_name_irec *irec,
>> + struct xfs_parent_name_rec *rec);
>> +
>> +int xfs_parent_add(struct xfs_trans *tp, struct xfs_inode *parent,
>> + struct xfs_inode *child, struct xfs_name *child_name,
>> + uint32_t diroffset, xfs_fsblock_t *firstblock,
>> + struct xfs_defer_ops *dfops);
>> +#endif /* __XFS_PARENT_H__ */
>> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
>> index 2859a697..a515f11 100644
>> --- a/fs/xfs/xfs_inode.c
>> +++ b/fs/xfs/xfs_inode.c
>> @@ -53,6 +53,7 @@
>> #include "xfs_bmap_btree.h"
>> #include "xfs_reflink.h"
>> #include "xfs_dir2_priv.h"
>> +#include "xfs_parent_utils.h"
>>
>> kmem_zone_t *xfs_inode_zone;
>>
>> @@ -1152,6 +1153,7 @@ xfs_create(
>> struct xfs_dquot *pdqp = NULL;
>> struct xfs_trans_res *tres;
>> uint resblks;
>> + xfs_dir2_dataptr_t diroffset;
>>
>> trace_xfs_create(dp, name);
>>
>> @@ -1211,7 +1213,7 @@ xfs_create(
>> * entry pointing to them, but a directory also the "." entry
>> * pointing to itself.
>> */
>> - error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, prid, &ip, XFS_ILOCK_EXCL);
>> + error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, prid, &ip, 0);
>> if (error)
>> goto out_trans_cancel;
>>
>> @@ -1222,13 +1224,13 @@ xfs_create(
>> * the transaction cancel unlocking dp so don't do it explicitly in the
>> * error path.
>> */
>> - xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
>> + xfs_trans_ijoin(tp, dp, 0);
>> unlock_dp_on_error = false;
>>
>> error = xfs_dir_createname(tp, dp, name, ip->i_ino,
>> &first_block, &dfops, resblks ?
>> resblks - XFS_IALLOC_SPACE_RES(mp) : 0,
>> - NULL);
>> + &diroffset);
>> if (error) {
>> ASSERT(error != -ENOSPC);
>> goto out_trans_cancel;
>> @@ -1247,6 +1249,17 @@ xfs_create(
>> }
>>
>> /*
>> + * If we have parent pointers, we need to add the attribute containing
>> + * the parent information now.
>
> Trailing whitespace (see scripts/checkpatch.pl)
>
>> + */
>> + if (xfs_sb_version_hasparent(&mp->m_sb)) {
>> + error = xfs_parent_add_deferred(dp, ip, name, diroffset,
>> + &dfops);
>> + if (error)
>> + goto out_bmap_cancel;
>> + }
>> +
>> + /*
>> * If this is a synchronous mount, make sure that the
>> * create transaction goes to disk before returning to
>> * the user.
>> @@ -1274,6 +1287,9 @@ xfs_create(
>> xfs_qm_dqrele(pdqp);
>>
>> *ipp = ip;
>> + xfs_iunlock(ip, XFS_ILOCK_EXCL);
>> + xfs_iunlock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
>> +
>> return 0;
>>
>> out_bmap_cancel:
>> diff --git a/fs/xfs/xfs_parent_utils.c b/fs/xfs/xfs_parent_utils.c
>> new file mode 100644
>> index 0000000..cf4a7e2
>> --- /dev/null
>> +++ b/fs/xfs/xfs_parent_utils.c
>> @@ -0,0 +1,51 @@
>> +/*
>> + * Copyright (c) 2015 Red Hat, Inc.
>> + * All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it would be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write the Free Software Foundation
>> + */
>> +#include "xfs.h"
>> +#include "xfs_fs.h"
>> +#include "xfs_format.h"
>> +#include "xfs_log_format.h"
>> +#include "xfs_shared.h"
>> +#include "xfs_trans_resv.h"
>> +#include "xfs_mount.h"
>> +#include "xfs_bmap_btree.h"
>> +#include "xfs_inode.h"
>> +#include "xfs_error.h"
>> +#include "xfs_trace.h"
>> +#include "xfs_trans.h"
>> +#include "xfs_attr.h"
>> +#include "xfs_parent.h"
>> +
>> +/*
>> + * Add a parent record to an inode with existing parent records.
>> + */
>> +int
>> +xfs_parent_add_deferred(
>> + struct xfs_inode *parent,
>> + struct xfs_inode *child,
>> + struct xfs_name *child_name,
>> + uint32_t diroffset,
>> + struct xfs_defer_ops *dfops)
>> +{
>> + struct xfs_parent_name_rec rec;
>> +
>> + xfs_init_parent_name_rec(&rec, parent->i_ino,
>> + VFS_I(parent)->i_generation, diroffset);
>> +
>> + return xfs_attr_set_deferred(child, dfops, &rec, sizeof(rec),
>> + (void *)child_name->name, child_name->len, ATTR_PARENT);
>
> Needs two indents here.
>
> return xfs_attr_set_deferred(child, dfops, &rec, sizeof(rec),
> (void *)child_name->name, child_name->len, ATTR_PARENT);
>
> Looks ok otherwise.
>
> --D
Sure, I'll get these things lined up. Thx!
Allison
>
>> +}
>> +
>> diff --git a/fs/xfs/xfs_parent_utils.h b/fs/xfs/xfs_parent_utils.h
>> new file mode 100644
>> index 0000000..a667d1d
>> --- /dev/null
>> +++ b/fs/xfs/xfs_parent_utils.h
>> @@ -0,0 +1,26 @@
>> +/*
>> + * Copyright (c) 2017 Oracle, Inc.
>> + * All Rights Reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it would be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write the Free Software Foundation Inc.
>> + */
>> +#ifndef __XFS_PARENT_UTILS_H__
>> +#define __XFS_PARENT_UTILS_H__
>> +
>> +/*
>> + * Parent pointer attribute prototypes
>> + */
>> +int xfs_parent_add_deferred(struct xfs_inode *parent, struct xfs_inode *child,
>> + struct xfs_name *child_name, uint32_t diroffset,
>> + struct xfs_defer_ops *dfops);
>> +#endif /* __XFS_PARENT_UTILS_H__ */
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 14/21] Add lock_flags to xfs_ialloc and xfs_dir_ialloc
2018-05-07 22:30 ` Darrick J. Wong
@ 2018-05-08 16:59 ` Allison Henderson
0 siblings, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 16:59 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 05/07/2018 03:30 PM, Darrick J. Wong wrote:
> On Sun, May 06, 2018 at 10:24:47AM -0700, Allison Henderson wrote:
>> Add lock_flags to xfs_ialloc and xfs_dir_ialloc to control
>> whick locks are released by xfs_trans_ijoin. We will need this
>> later in defered parent pointers
>>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
>> fs/xfs/xfs_inode.c | 17 +++++++++--------
>> fs/xfs/xfs_inode.h | 2 +-
>> fs/xfs/xfs_qm.c | 2 +-
>> fs/xfs/xfs_symlink.c | 2 +-
>> 4 files changed, 12 insertions(+), 11 deletions(-)
>>
>> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
>> index 5c291d2..2859a697 100644
>> --- a/fs/xfs/xfs_inode.c
>> +++ b/fs/xfs/xfs_inode.c
>> @@ -766,7 +766,8 @@ xfs_ialloc(
>> dev_t rdev,
>> prid_t prid,
>> xfs_buf_t **ialloc_context,
>> - xfs_inode_t **ipp)
>> + xfs_inode_t **ipp,
>> + int lock_flags)
>
> Wait, what?
>
> Oh, these are the locks we want *dropped* at the first _trans_commit
> after this call returns, and for xfs_create we need to retain the ilock
> while we roll the transaction(s) during _defer_finish; and for
> everything else (create temp file, create quota inode, and symlink??) we
> want the ilock dropped as soon as the transaction commits.
>
> I dislike having this oddly named parameter, can we amend the comment to
> say that the caller is responsible for unlocking the inode manually
> (i.e. we're going to xfs_trans_ijoin(tp, ip, 0)) , and then change all
> the callers to do the iunlock explicitly if they need to?
>
> --D
Sure, I can update the comment. Hmm, would an op_flag be a more
appropriate parameter in this case? Thx!
Allison
>
>> {
>> struct xfs_mount *mp = tp->t_mountp;
>> xfs_ino_t ino;
>> @@ -942,7 +943,7 @@ xfs_ialloc(
>> /*
>> * Log the new values stuffed into the inode.
>> */
>> - xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
>> + xfs_trans_ijoin(tp, ip, lock_flags);
>> xfs_trans_log_inode(tp, ip, flags);
>>
>> /* now that we have an i_mode we can setup the inode structure */
>> @@ -972,8 +973,8 @@ xfs_dir_ialloc(
>> xfs_nlink_t nlink,
>> dev_t rdev,
>> prid_t prid, /* project id */
>> - xfs_inode_t **ipp) /* pointer to inode; it will be
>> - locked. */
>> + xfs_inode_t **ipp, /* pointer to inode; it will be locked. */
>> + int lock_flags)
>> {
>> xfs_trans_t *tp;
>> xfs_inode_t *ip;
>> @@ -1001,7 +1002,7 @@ xfs_dir_ialloc(
>> * the inode(s) that we've just allocated.
>> */
>> code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, &ialloc_context,
>> - &ip);
>> + &ip, lock_flags);
>>
>> /*
>> * Return an error if we were unable to allocate a new inode.
>> @@ -1071,7 +1072,7 @@ xfs_dir_ialloc(
>> * this call should always succeed.
>> */
>> code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid,
>> - &ialloc_context, &ip);
>> + &ialloc_context, &ip, lock_flags);
>>
>> /*
>> * If we get an error at this point, return to the caller
>> @@ -1210,7 +1211,7 @@ xfs_create(
>> * entry pointing to them, but a directory also the "." entry
>> * pointing to itself.
>> */
>> - error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, prid, &ip);
>> + error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, prid, &ip, XFS_ILOCK_EXCL);
>> if (error)
>> goto out_trans_cancel;
>>
>> @@ -1343,7 +1344,7 @@ xfs_create_tmpfile(
>> if (error)
>> goto out_trans_cancel;
>>
>> - error = xfs_dir_ialloc(&tp, dp, mode, 1, 0, prid, &ip);
>> + error = xfs_dir_ialloc(&tp, dp, mode, 1, 0, prid, &ip, XFS_ILOCK_EXCL);
>> if (error)
>> goto out_trans_cancel;
>>
>> diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
>> index 1eebc53..466f252 100644
>> --- a/fs/xfs/xfs_inode.h
>> +++ b/fs/xfs/xfs_inode.h
>> @@ -431,7 +431,7 @@ xfs_extlen_t xfs_get_cowextsz_hint(struct xfs_inode *ip);
>>
>> int xfs_dir_ialloc(struct xfs_trans **, struct xfs_inode *, umode_t,
>> xfs_nlink_t, dev_t, prid_t,
>> - struct xfs_inode **);
>> + struct xfs_inode **, int lock_flags);
>>
>> /* from xfs_file.c */
>> enum xfs_prealloc_flags {
>> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
>> index ec39ae2..3e68a52 100644
>> --- a/fs/xfs/xfs_qm.c
>> +++ b/fs/xfs/xfs_qm.c
>> @@ -787,7 +787,7 @@ xfs_qm_qino_alloc(
>> return error;
>>
>> if (need_alloc) {
>> - error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, ip);
>> + error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, ip, XFS_ILOCK_EXCL);
>> if (error) {
>> xfs_trans_cancel(tp);
>> return error;
>> diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
>> index b1d3301..ce8dbea 100644
>> --- a/fs/xfs/xfs_symlink.c
>> +++ b/fs/xfs/xfs_symlink.c
>> @@ -264,7 +264,7 @@ xfs_symlink(
>> * Allocate an inode for the symlink.
>> */
>> error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT), 1, 0,
>> - prid, &ip);
>> + prid, &ip, XFS_ILOCK_EXCL);
>> if (error)
>> goto out_trans_cancel;
>>
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 13/21] xfs: extent transaction reservations for parent attributes
2018-05-07 22:34 ` Darrick J. Wong
@ 2018-05-08 17:00 ` Allison Henderson
0 siblings, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 17:00 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 05/07/2018 03:34 PM, Darrick J. Wong wrote:
> On Sun, May 06, 2018 at 10:24:46AM -0700, Allison Henderson wrote:
>> From: Dave Chinner <dchinner@redhat.com>
>>
>> We need to add, remove or modify parent pointer attributes during
>> create/link/unlink/rename operations atomically with the dirents in the parent
>> directories being modified. This means they need to be modified in the same
>> transaction as the parent directories, and so we need to add the required
>> space for the attribute modifications to the transaction reservations.
>>
>> [achender: rebased, added xfs_sb_version_hasparent stub]
>>
>> Signed-off-by: Dave Chinner <dchinner@redhat.com>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
>> fs/xfs/libxfs/xfs_format.h | 5 ++
>> fs/xfs/libxfs/xfs_trans_resv.c | 111 ++++++++++++++++++++++++++++++++---------
>> fs/xfs/libxfs/xfs_trans_resv.h | 1 +
>> 3 files changed, 94 insertions(+), 23 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
>> index 42956d8..5e946c8 100644
>> --- a/fs/xfs/libxfs/xfs_format.h
>> +++ b/fs/xfs/libxfs/xfs_format.h
>> @@ -559,6 +559,11 @@ static inline bool xfs_sb_version_hasreflink(struct xfs_sb *sbp)
>> (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_REFLINK);
>> }
>>
>> +static inline bool xfs_sb_version_hasparent(struct xfs_sb *sbp)
>> +{
>> + return false; /* We'll enable this at the end of the set */
>> +}
>> +
>> /*
>> * end of superblock version macros
>> */
>> diff --git a/fs/xfs/libxfs/xfs_trans_resv.c b/fs/xfs/libxfs/xfs_trans_resv.c
>> index 3bccdf7..76440fb 100644
>> --- a/fs/xfs/libxfs/xfs_trans_resv.c
>> +++ b/fs/xfs/libxfs/xfs_trans_resv.c
>> @@ -787,29 +787,30 @@ xfs_calc_sb_reservation(
>> return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize);
>> }
>>
>> +/*
>> + * Namespace reservations.
>> + *
>> + * These get tricky when parent pointers are enabled as we have attribute
>> + * modifications occurring from within these transactions. Rather than confuse
>> + * each of these reservation calculations with the conditional attribute
>> + * reservations, add them here in a clear and concise manner. This assumes that
>> + * the attribute reservations have already been calculated.
>> + *
>> + * Note that we only include the static attribute reservation here; the runtime
>> + * reservation will have to be modified by the size of the attributes being
>> + * added/removed/modified. See the comments on the attribute reservation
>> + * calculations for more details.
>> + *
>> + * Note for rename: rename will vastly overestimate requirements. This will be
>> + * addressed later when modifications are made to ensure parent attribute
>> + * modifications can be done atomically with the rename operation.
>> + */
>> void
>> -xfs_trans_resv_calc(
>> +xfs_calc_namespace_reservations(
>> struct xfs_mount *mp,
>> struct xfs_trans_resv *resp)
>> {
>> - /*
>> - * The following transactions are logged in physical format and
>> - * require a permanent reservation on space.
>> - */
>> - resp->tr_write.tr_logres = xfs_calc_write_reservation(mp);
>> - if (xfs_sb_version_hasreflink(&mp->m_sb))
>> - resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK;
>> - else
>> - resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT;
>> - resp->tr_write.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
>> -
>> - resp->tr_itruncate.tr_logres = xfs_calc_itruncate_reservation(mp);
>> - if (xfs_sb_version_hasreflink(&mp->m_sb))
>> - resp->tr_itruncate.tr_logcount =
>> - XFS_ITRUNCATE_LOG_COUNT_REFLINK;
>> - else
>> - resp->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT;
>> - resp->tr_itruncate.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
>> + ASSERT(resp->tr_attrsetm.tr_logres > 0);
>>
>> resp->tr_rename.tr_logres = xfs_calc_rename_reservation(mp);
>> resp->tr_rename.tr_logcount = XFS_RENAME_LOG_COUNT;
>> @@ -831,15 +832,77 @@ xfs_trans_resv_calc(
>> resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT;
>> resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
>>
>> + resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp);
>> + resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT;
>> + resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
>> +
>> + xfs_calc_parent_ptr_reservations(mp);
>> +}
>> +
>> +void xfs_calc_parent_ptr_reservations(struct xfs_mount *mp)
>
> Parameter goes on the next line, please.
>
>> +{
>> + struct xfs_trans_resv *resp = M_RES(mp);
>> +
>> + /* Calculate extra space needed for parent pointer attributes */
>> + if (!xfs_sb_version_hasparent(&mp->m_sb))
>> + return;
>> +
>> + /* rename can add/remove/modify 2 parent attributes */
>> + resp->tr_rename.tr_logres += 2 * max(resp->tr_attrsetm.tr_logres,
>> + resp->tr_attrrm.tr_logres);
>> + resp->tr_rename.tr_logcount += 2 * max(resp->tr_attrsetm.tr_logcount,
>> + resp->tr_attrrm.tr_logcount);
>
> RENAME_EXCHANGE can perform four updates -- remove pptr from both
> inodes, then add the (now swapped) to both inodes.
>
Ok, will update
>> +
>> + /* create will add 1 parent attribute */
>> + resp->tr_create.tr_logres += resp->tr_attrsetm.tr_logres;
>> + resp->tr_create.tr_logcount += resp->tr_attrsetm.tr_logcount;
>> +
>> + /* mkdir will add 1 parent attribute */
>> + resp->tr_mkdir.tr_logres += resp->tr_attrsetm.tr_logres;
>> + resp->tr_mkdir.tr_logcount += resp->tr_attrsetm.tr_logcount;
>> +
>> + /* link will add 1 parent attribute */
>> + resp->tr_link.tr_logres += resp->tr_attrsetm.tr_logres;
>> + resp->tr_link.tr_logcount += resp->tr_attrsetm.tr_logcount;
>> +
>> + /* symlink will add 1 parent attribute */
>> + resp->tr_symlink.tr_logres += resp->tr_attrsetm.tr_logres;
>> + resp->tr_symlink.tr_logcount += resp->tr_attrsetm.tr_logcount;
>> +
>> + /* remove will remove 1 parent attribute */
>> + resp->tr_remove.tr_logres += resp->tr_attrrm.tr_logres;
>> + resp->tr_remove.tr_logcount += resp->tr_attrrm.tr_logcount;
>> +}
>> +
>> +void
>> +xfs_trans_resv_calc(
>> + struct xfs_mount *mp,
>> + struct xfs_trans_resv *resp)
>> +{
>> + /*
>> + * The following transactions are logged in physical format and
>> + * require a permanent reservation on space.
>> + */
>> + resp->tr_write.tr_logres = xfs_calc_write_reservation(mp);
>> + if (xfs_sb_version_hasreflink(&mp->m_sb))
>> + resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK;
>> + else
>> + resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT;
>> + resp->tr_write.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
>> +
>> + resp->tr_itruncate.tr_logres = xfs_calc_itruncate_reservation(mp);
>> + if (xfs_sb_version_hasreflink(&mp->m_sb))
>> + resp->tr_itruncate.tr_logcount =
>> + XFS_ITRUNCATE_LOG_COUNT_REFLINK;
>> + else
>> + resp->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT;
>> + resp->tr_itruncate.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
>> +
>> resp->tr_create_tmpfile.tr_logres =
>> xfs_calc_create_tmpfile_reservation(mp);
>> resp->tr_create_tmpfile.tr_logcount = XFS_CREATE_TMPFILE_LOG_COUNT;
>> resp->tr_create_tmpfile.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
>>
>> - resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp);
>> - resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT;
>> - resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
>> -
>> resp->tr_ifree.tr_logres = xfs_calc_ifree_reservation(mp);
>> resp->tr_ifree.tr_logcount = XFS_INACTIVE_LOG_COUNT;
>> resp->tr_ifree.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
>> @@ -871,6 +934,8 @@ xfs_trans_resv_calc(
>> resp->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT;
>> resp->tr_qm_dqalloc.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
>>
>> + xfs_calc_namespace_reservations(mp, resp);
>> +
>> /*
>> * The following transactions are logged in logical format with
>> * a default log count.
>> diff --git a/fs/xfs/libxfs/xfs_trans_resv.h b/fs/xfs/libxfs/xfs_trans_resv.h
>> index b7e5357..c7190d6 100644
>> --- a/fs/xfs/libxfs/xfs_trans_resv.h
>> +++ b/fs/xfs/libxfs/xfs_trans_resv.h
>> @@ -105,5 +105,6 @@ struct xfs_trans_resv {
>>
>> void xfs_trans_resv_calc(struct xfs_mount *mp, struct xfs_trans_resv *resp);
>> uint xfs_allocfree_log_count(struct xfs_mount *mp, uint num_ops);
>> +void xfs_calc_parent_ptr_reservations(struct xfs_mount *mp);
>
> Are we going to need this outside xfs_trans_resv.c? If not, leave it private.
>
> --D
Ok, I dont think we do. I'll see if I can keep it private to
xfs_trans_resv.c
>
>>
>> #endif /* __XFS_TRANS_RESV_H__ */
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 12/21] xfs: define parent pointer xattr format
2018-05-07 22:35 ` Darrick J. Wong
@ 2018-05-08 17:00 ` Allison Henderson
0 siblings, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 17:00 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 05/07/2018 03:35 PM, Darrick J. Wong wrote:
> On Sun, May 06, 2018 at 10:24:45AM -0700, Allison Henderson wrote:
>> From: Dave Chinner <dchinner@redhat.com>
>>
>> We need to define the parent pointer attribute format before we
>> start adding support for it into all the code that needs to use it.
>> The EA format we will use encodes the following information:
>>
>> name={parent inode #, parent inode generation, dirent offset}
>> value={dirent filename}
>>
>> The inode/gen gives all the information we need to reliably identify
>> the parent without requiring child->parent lock ordering, and allows
>> userspace to do pathname component level reconstruction without the
>> kernel ever needing to verify the parent itself as part of ioctl
>> calls.
>>
>> By using the dirent offset in the EA name, we have a method of
>> knowing the exact parent pointer EA we need to modify/remove in
>> rename/unlink without an unbound EA name search.
>>
>> By keeping the dirent name in the value, we have enough information
>> to be able to validate and reconstruct damaged directory trees.
>> While the diroffset of a filename alone is not unique enough to
>> identify the child, the {diroffset,filename,child_inode} tuple is
>> sufficient. That is, if the diroffset gets reused and points to a
>> different filename, we can detect that from the contents of EA. If a
>> link of the same name is created, then we can check whether it
>> points at the same inode as the parent EA we current have.
>>
>> [achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
>> changed p_ino to xfs_ino_t and p_namelen to uint8_t,
>> moved to xfs_da_format for xfs_dir2_dataptr_t]
>>
>> Signed-off-by: Dave Chinner <dchinner@redhat.com>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> Reviewed-by: Darrick J. Wong<darrick.wong@oracle.com>
>> ---
>> fs/xfs/libxfs/xfs_da_format.h | 26 +++++++++++++++++++++++++-
>> 1 file changed, 25 insertions(+), 1 deletion(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h
>> index 9bd2e6b..d1c1221 100644
>> --- a/fs/xfs/libxfs/xfs_da_format.h
>> +++ b/fs/xfs/libxfs/xfs_da_format.h
>> @@ -878,11 +878,35 @@ struct xfs_attr3_rmt_hdr {
>> #define XFS_ATTR3_RMT_BUF_SPACE(mp, bufsize) \
>> ((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \
>> sizeof(struct xfs_attr3_rmt_hdr) : 0))
>> -
>
> Unrelated/unnecessary whitespace removal? Otherwise this is still
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
>
> --D
>
Sorry, not sure how that got in there. Will clean up. Thx!
Allison
>
>> /* Number of bytes in a directory block. */
>> static inline unsigned int xfs_dir2_dirblock_bytes(struct xfs_sb *sbp)
>> {
>> return 1 << (sbp->sb_blocklog + sbp->sb_dirblklog);
>> }
>>
>> +/*
>> + * Parent pointer attribute format definition
>> + *
>> + * EA name encodes the parent inode number, generation and the offset of
>> + * the dirent that points to the child inode. The EA value contains the
>> + * same name as the dirent in the parent directory.
>> + */
>> +struct xfs_parent_name_rec {
>> + __be64 p_ino;
>> + __be32 p_gen;
>> + __be32 p_diroffset;
>> +};
>> +
>> +/*
>> + * incore version of the above, also contains name pointers so callers
>> + * can pass/obtain all the parent pointer information in a single structure
>> + */
>> +struct xfs_parent_name_irec {
>> + xfs_ino_t p_ino;
>> + uint32_t p_gen;
>> + xfs_dir2_dataptr_t p_diroffset;
>> + const char *p_name;
>> + uint8_t p_namelen;
>> +};
>> +
>> #endif /* __XFS_DA_FORMAT_H__ */
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 10/21] xfs: get directory offset when replacing a directory name
2018-05-07 22:45 ` Darrick J. Wong
@ 2018-05-08 17:00 ` Allison Henderson
0 siblings, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 17:00 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 05/07/2018 03:45 PM, Darrick J. Wong wrote:
> On Sun, May 06, 2018 at 10:24:43AM -0700, Allison Henderson wrote:
>> From: Mark Tinguely <tinguely@sgi.com>
>>
>> Return the directory offset information when replacing an entry to the
>> directory.
>>
>> This offset will be used as the parent pointer offset in xfs_rename.
>>
>> [dchinner: forward ported and cleaned up]
>> [achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
>> Changed typedefs to raw struct types]
>>
>> Signed-off-by: Mark Tinguely <tinguely@sgi.com>
>> Signed-off-by: Dave Chinner <dchinner@redhat.com>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
>> fs/xfs/libxfs/xfs_dir2.c | 16 ++++++++++------
>> fs/xfs/libxfs/xfs_dir2.h | 3 ++-
>> fs/xfs/libxfs/xfs_dir2_block.c | 4 ++--
>> fs/xfs/libxfs/xfs_dir2_leaf.c | 1 +
>> fs/xfs/libxfs/xfs_dir2_node.c | 1 +
>> fs/xfs/libxfs/xfs_dir2_sf.c | 2 ++
>> fs/xfs/xfs_inode.c | 28 +++++++++++++---------------
>> 7 files changed, 31 insertions(+), 24 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
>> index 090ab0e..a4f7bcd 100644
>> --- a/fs/xfs/libxfs/xfs_dir2.c
>> +++ b/fs/xfs/libxfs/xfs_dir2.c
>> @@ -499,13 +499,14 @@ xfs_dir_removename(
>> */
>> int
>> xfs_dir_replace(
>> - xfs_trans_t *tp,
>> - xfs_inode_t *dp,
>> - struct xfs_name *name, /* name of entry to replace */
>> - xfs_ino_t inum, /* new inode number */
>> - xfs_fsblock_t *first, /* bmap's firstblock */
>> + struct xfs_trans *tp,
>> + struct xfs_inode *dp,
>> + struct xfs_name *name, /* name of entry to replace */
>> + xfs_ino_t inum, /* new inode number */
>> + xfs_fsblock_t *first, /* bmap's firstblock */
>> struct xfs_defer_ops *dfops, /* bmap's freeblock list */
>> - xfs_extlen_t total) /* bmap's total block count */
>> + xfs_extlen_t total, /* bmap's total block count */
>> + xfs_dir2_dataptr_t *offset) /* OUT: offset in directory */
>> {
>> struct xfs_da_args *args;
>> int rval;
>> @@ -555,6 +556,9 @@ xfs_dir_replace(
>> else
>> rval = xfs_dir2_node_replace(args);
>> out_free:
>> + if (offset)
>> + *offset = args->offset;
>
> Just from a outvar purity point of view, we should only set *offset if
> we're not also returning an error. AFAICT there's no practical
> consequence for setting *offset and returning a negative number, just a
> nit to pick. :P
>
> The rest looks ok, so:
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
>
> --D
Alrightly, will update. thx!
Allison
>
>> +
>> kmem_free(args);
>> return rval;
>> }
>> diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
>> index b73bdcb..d361442 100644
>> --- a/fs/xfs/libxfs/xfs_dir2.h
>> +++ b/fs/xfs/libxfs/xfs_dir2.h
>> @@ -145,7 +145,8 @@ extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
>> extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
>> struct xfs_name *name, xfs_ino_t inum,
>> xfs_fsblock_t *first,
>> - struct xfs_defer_ops *dfops, xfs_extlen_t tot);
>> + struct xfs_defer_ops *dfops, xfs_extlen_t tot,
>> + xfs_dir2_dataptr_t *offset);
>> extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp,
>> struct xfs_name *name);
>>
>> diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
>> index 9c1e485..77744e5 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_block.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
>> @@ -872,9 +872,9 @@ xfs_dir2_block_replace(
>> /*
>> * Point to the data entry we need to change.
>> */
>> + args->offset = be32_to_cpu(blp[ent].address);
>> dep = (xfs_dir2_data_entry_t *)((char *)hdr +
>> - xfs_dir2_dataptr_to_off(args->geo,
>> - be32_to_cpu(blp[ent].address)));
>> + xfs_dir2_dataptr_to_off(args->geo, args->offset));
>> ASSERT(be64_to_cpu(dep->inumber) != args->inumber);
>> /*
>> * Change the inode number to the new value.
>> diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
>> index c5595c1..6ad7741 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
>> @@ -1550,6 +1550,7 @@ xfs_dir2_leaf_replace(
>> /*
>> * Point to the data entry.
>> */
>> + args->offset = be32_to_cpu(lep->address);
>> dep = (xfs_dir2_data_entry_t *)
>> ((char *)dbp->b_addr +
>> xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address)));
>> diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
>> index eb8b240..ccf220a 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_node.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
>> @@ -2256,6 +2256,7 @@ xfs_dir2_node_replace(
>> hdr = state->extrablk.bp->b_addr;
>> ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
>> hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC));
>> + args->offset = be32_to_cpu(lep->address);
>> dep = (xfs_dir2_data_entry_t *)
>> ((char *)hdr +
>> xfs_dir2_dataptr_to_off(args->geo,
>> diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
>> index 1d0957c..73f1eef 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_sf.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_sf.c
>> @@ -1043,6 +1043,8 @@ xfs_dir2_sf_replace(
>> ASSERT(args->inumber != ino);
>> dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
>> dp->d_ops->sf_put_ftype(sfep, args->filetype);
>> + args->offset = xfs_dir2_byte_to_dataptr(
>> + xfs_dir2_sf_get_offset(sfep));
>> break;
>> }
>> }
>> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
>> index 3054e9a..5c291d2 100644
>> --- a/fs/xfs/xfs_inode.c
>> +++ b/fs/xfs/xfs_inode.c
>> @@ -2783,16 +2783,14 @@ xfs_cross_rename(
>> int dp2_flags = 0;
>>
>> /* Swap inode number for dirent in first parent */
>> - error = xfs_dir_replace(tp, dp1, name1,
>> - ip2->i_ino,
>> - first_block, dfops, spaceres);
>> + error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, first_block, dfops,
>> + spaceres, NULL);
>> if (error)
>> goto out_trans_abort;
>>
>> /* Swap inode number for dirent in second parent */
>> - error = xfs_dir_replace(tp, dp2, name2,
>> - ip1->i_ino,
>> - first_block, dfops, spaceres);
>> + error = xfs_dir_replace(tp, dp2, name2, ip1->i_ino, first_block, dfops,
>> + spaceres, NULL);
>> if (error)
>> goto out_trans_abort;
>>
>> @@ -2806,8 +2804,8 @@ xfs_cross_rename(
>>
>> if (S_ISDIR(VFS_I(ip2)->i_mode)) {
>> error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot,
>> - dp1->i_ino, first_block,
>> - dfops, spaceres);
>> + dp1->i_ino, first_block, dfops,
>> + spaceres, NULL);
>> if (error)
>> goto out_trans_abort;
>>
>> @@ -2833,8 +2831,8 @@ xfs_cross_rename(
>>
>> if (S_ISDIR(VFS_I(ip1)->i_mode)) {
>> error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot,
>> - dp2->i_ino, first_block,
>> - dfops, spaceres);
>> + dp2->i_ino, first_block, dfops,
>> + spaceres, NULL);
>> if (error)
>> goto out_trans_abort;
>>
>> @@ -3081,8 +3079,8 @@ xfs_rename(
>> * name at the destination directory, remove it first.
>> */
>> error = xfs_dir_replace(tp, target_dp, target_name,
>> - src_ip->i_ino,
>> - &first_block, &dfops, spaceres);
>> + src_ip->i_ino, &first_block, &dfops,
>> + spaceres, NULL);
>> if (error)
>> goto out_bmap_cancel;
>>
>> @@ -3116,8 +3114,8 @@ xfs_rename(
>> * directory.
>> */
>> error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,
>> - target_dp->i_ino,
>> - &first_block, &dfops, spaceres);
>> + target_dp->i_ino, &first_block, &dfops,
>> + spaceres, NULL);
>> ASSERT(error != -EEXIST);
>> if (error)
>> goto out_bmap_cancel;
>> @@ -3156,7 +3154,7 @@ xfs_rename(
>> */
>> if (wip) {
>> error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino,
>> - &first_block, &dfops, spaceres);
>> + &first_block, &dfops, spaceres, NULL);
>> } else
>> error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
>> &first_block, &dfops, spaceres,
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 09/21] xfs: get directory offset when removing directory name
2018-05-07 22:48 ` Darrick J. Wong
@ 2018-05-08 17:00 ` Allison Henderson
0 siblings, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 17:00 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 05/07/2018 03:48 PM, Darrick J. Wong wrote:
> On Sun, May 06, 2018 at 10:24:42AM -0700, Allison Henderson wrote:
>> From: Mark Tinguely <tinguely@sgi.com>
>>
>> Return the directory offset information when removing an entry to the
>> directory.
>>
>> This offset will be used as the parent pointer offset in xfs_remove.
>>
>> [dchinner: forward ported and cleaned up]
>> [achender: rebased, changed __unint32_t to xfs_dir2_dataptr_t,
>> Changed typedefs to raw struct types]
>>
>> Signed-off-by: Mark Tinguely <tinguely@sgi.com>
>> Signed-off-by: Dave Chinner <dchinner@redhat.com>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
>> fs/xfs/libxfs/xfs_dir2.c | 16 ++++++++++------
>> fs/xfs/libxfs/xfs_dir2.h | 4 +++-
>> fs/xfs/libxfs/xfs_dir2_block.c | 4 ++--
>> fs/xfs/libxfs/xfs_dir2_leaf.c | 5 +++--
>> fs/xfs/libxfs/xfs_dir2_node.c | 5 +++--
>> fs/xfs/libxfs/xfs_dir2_sf.c | 2 ++
>> fs/xfs/xfs_inode.c | 7 ++++---
>> 7 files changed, 27 insertions(+), 16 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
>> index 409a1e7..090ab0e 100644
>> --- a/fs/xfs/libxfs/xfs_dir2.c
>> +++ b/fs/xfs/libxfs/xfs_dir2.c
>> @@ -433,13 +433,14 @@ xfs_dir_lookup(
>> */
>> int
>> xfs_dir_removename(
>> - xfs_trans_t *tp,
>> - xfs_inode_t *dp,
>> - struct xfs_name *name,
>> - xfs_ino_t ino,
>> - xfs_fsblock_t *first, /* bmap's firstblock */
>> + struct xfs_trans *tp,
>> + struct xfs_inode *dp,
>> + struct xfs_name *name,
>> + xfs_ino_t ino,
>> + xfs_fsblock_t *first, /* bmap's firstblock */
>> struct xfs_defer_ops *dfops, /* bmap's freeblock list */
>> - xfs_extlen_t total) /* bmap's total block count */
>> + xfs_extlen_t total, /* bmap's total block count */
>> + xfs_dir2_dataptr_t *offset) /* OUT: offset in directory */
>> {
>> struct xfs_da_args *args;
>> int rval;
>> @@ -486,6 +487,9 @@ xfs_dir_removename(
>> else
>> rval = xfs_dir2_node_removename(args);
>> out_free:
>> + if (offset)
>> + *offset = args->offset;
>> +
>> kmem_free(args);
>> return rval;
>> }
>> diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
>> index c98a3ca..b73bdcb 100644
>> --- a/fs/xfs/libxfs/xfs_dir2.h
>> +++ b/fs/xfs/libxfs/xfs_dir2.h
>> @@ -139,7 +139,9 @@ extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp,
>> extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp,
>> struct xfs_name *name, xfs_ino_t ino,
>> xfs_fsblock_t *first,
>> - struct xfs_defer_ops *dfops, xfs_extlen_t tot);
>> + struct xfs_defer_ops *dfops,
>> + xfs_extlen_t tot,
>> + xfs_dir2_dataptr_t *offset);
>> extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
>> struct xfs_name *name, xfs_ino_t inum,
>> xfs_fsblock_t *first,
>> diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
>> index 9b7f173..9c1e485 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_block.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
>> @@ -798,9 +798,9 @@ xfs_dir2_block_removename(
>> /*
>> * Point to the data entry using the leaf entry.
>> */
>> + args->offset = be32_to_cpu(blp[ent].address);
>> dep = (xfs_dir2_data_entry_t *)((char *)hdr +
>> - xfs_dir2_dataptr_to_off(args->geo,
>> - be32_to_cpu(blp[ent].address)));
>> + xfs_dir2_dataptr_to_off(args->geo, args->offset));
>> /*
>> * Mark the data entry's space free.
>> */
>> diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
>> index 8ae2953..c5595c1 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
>> @@ -1414,9 +1414,10 @@ xfs_dir2_leaf_removename(
>> * Point to the leaf entry, use that to point to the data entry.
>> */
>> lep = &ents[index];
>> - db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address));
>> + args->offset = be32_to_cpu(lep->address);
>> + db = xfs_dir2_dataptr_to_db(args->geo, args->offset);
>> dep = (xfs_dir2_data_entry_t *)((char *)hdr +
>> - xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address)));
>> + xfs_dir2_dataptr_to_off(args->geo, args->offset));
>> needscan = needlog = 0;
>> oldbest = be16_to_cpu(bf[0].length);
>> ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
>> diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
>> index 4e544f7..eb8b240 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_node.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
>> @@ -1252,9 +1252,10 @@ xfs_dir2_leafn_remove(
>> /*
>> * Extract the data block and offset from the entry.
>> */
>> - db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address));
>> + args->offset = be32_to_cpu(lep->address);
>> + db = xfs_dir2_dataptr_to_db(args->geo, args->offset);
>> ASSERT(dblk->blkno == db);
>> - off = xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address));
>> + off = xfs_dir2_dataptr_to_off(args->geo, args->offset);
>> ASSERT(dblk->index == off);
>>
>> /*
>> diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
>> index 222ccf5..1d0957c 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_sf.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_sf.c
>> @@ -917,6 +917,8 @@ xfs_dir2_sf_removename(
>> XFS_CMP_EXACT) {
>> ASSERT(dp->d_ops->sf_get_ino(sfp, sfep) ==
>> args->inumber);
>> + args->offset = xfs_dir2_byte_to_dataptr(
>> + xfs_dir2_sf_get_offset(sfep));
>> break;
>> }
>> }
>> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
>> index fc07b4f..3054e9a 100644
>> --- a/fs/xfs/xfs_inode.c
>> +++ b/fs/xfs/xfs_inode.c
>> @@ -2648,8 +2648,8 @@ xfs_remove(
>> goto out_trans_cancel;
>>
>> xfs_defer_init(&dfops, &first_block);
>> - error = xfs_dir_removename(tp, dp, name, ip->i_ino,
>> - &first_block, &dfops, resblks);
>> + error = xfs_dir_removename(tp, dp, name, ip->i_ino, &first_block,
>> + &dfops, resblks, NULL);
>> if (error) {
>> ASSERT(error != -ENOENT);
>> goto out_bmap_cancel;
>> @@ -3159,7 +3159,8 @@ xfs_rename(
>> &first_block, &dfops, spaceres);
>> } else
>> error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
>> - &first_block, &dfops, spaceres);
>> + &first_block, &dfops, spaceres,
>> + NULL);
>
> Two indents for the second & third lines, please.
>
> Otherwise looks ok,
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
>
> --D
Alrighty, thx!
Allison
>
>> if (error)
>> goto out_bmap_cancel;
>>
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 07/21] xfs: Remove all strlen calls in all xfs_attr_* functions for attr names.
2018-05-07 22:54 ` Darrick J. Wong
@ 2018-05-08 17:00 ` Allison Henderson
0 siblings, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 17:00 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 05/07/2018 03:54 PM, Darrick J. Wong wrote:
> On Sun, May 06, 2018 at 10:24:40AM -0700, Allison Henderson wrote:
>> Parent pointer attributes use a binary name, so strlen will not work.
>> Calling functions will need to pass in the name length
>>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
>> fs/xfs/libxfs/xfs_attr.c | 12 ++++++++----
>> fs/xfs/libxfs/xfs_attr.h | 10 ++++++----
>> fs/xfs/xfs_acl.c | 12 +++++++-----
>> fs/xfs/xfs_ioctl.c | 13 ++++++++++---
>> fs/xfs/xfs_iops.c | 6 ++++--
>> fs/xfs/xfs_trans_attr.c | 2 +-
>> fs/xfs/xfs_xattr.c | 10 +++++++---
>> 7 files changed, 43 insertions(+), 22 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index adbcef2..484fa86 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -80,6 +80,7 @@ xfs_attr_args_init(
>> struct xfs_da_args *args,
>> struct xfs_inode *dp,
>> const unsigned char *name,
>> + size_t namelen,
>> int flags)
>> {
>>
>> @@ -92,7 +93,7 @@ xfs_attr_args_init(
>> args->dp = dp;
>> args->flags = flags;
>> args->name = name;
>> - args->namelen = strlen((const char *)name);
>> + args->namelen = namelen;
>> if (args->namelen >= MAXNAMELEN)
>> return -EFAULT; /* match IRIX behaviour */
>>
>> @@ -138,6 +139,7 @@ int
>> xfs_attr_get(
>> struct xfs_inode *ip,
>> const unsigned char *name,
>> + size_t namelen,
>> unsigned char *value,
>> int *valuelenp,
>> int flags)
>> @@ -151,7 +153,7 @@ xfs_attr_get(
>> if (XFS_FORCED_SHUTDOWN(ip->i_mount))
>> return -EIO;
>>
>> - error = xfs_attr_args_init(&args, ip, name, flags);
>> + error = xfs_attr_args_init(&args, ip, name, namelen, flags);
>> if (error)
>> return error;
>>
>> @@ -364,6 +366,7 @@ int
>> xfs_attr_set(
>> struct xfs_inode *dp,
>> const unsigned char *name,
>> + size_t namelen,
>> unsigned char *value,
>> int valuelen,
>> int flags)
>> @@ -382,7 +385,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;
>>
>> @@ -513,6 +516,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;
>> @@ -526,7 +530,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 ec26565..308a93e 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -171,17 +171,19 @@ int xfs_attr_list_int(struct xfs_attr_list_context *);
>> int xfs_inode_hasattr(struct xfs_inode *ip);
>> int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
>> int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
>> - unsigned char *value, int *valuelenp, int flags);
>> + size_t namelen, unsigned char *value, int *valuelenp,
>> + int flags);
>> int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
>> - unsigned char *value, int valuelen, int flags);
>> + size_t namelen, unsigned char *value, int valuelen, int flags);
>> int xfs_attr_set_args(struct xfs_da_args *args, int flags,
>> struct xfs_buf *leaf_bp, bool roll_trans);
>> -int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
>> +int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
>> + size_t namelen, int flags);
>> int xfs_attr_remove_args(struct xfs_da_args *args, int flags, bool roll_trans);
>> int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>> int flags, struct attrlist_cursor_kern *cursor);
>> int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
>> - const unsigned char *name, int flags);
>> + const unsigned char *name, size_t namelen, int flags);
>> int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
>> int xfs_attr_set_deferred(struct xfs_inode *dp, struct xfs_defer_ops *dfops,
>> void *name, unsigned int name_len, void *value,
>> diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
>> index 3354140..e59b26d 100644
>> --- a/fs/xfs/xfs_acl.c
>> +++ b/fs/xfs/xfs_acl.c
>> @@ -153,8 +153,8 @@ xfs_get_acl(struct inode *inode, int type)
>> if (!xfs_acl)
>> return ERR_PTR(-ENOMEM);
>>
>> - error = xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl,
>> - &len, ATTR_ROOT);
>> + error = xfs_attr_get(ip, ea_name, strlen(ea_name),
>> + (unsigned char *)xfs_acl, &len, ATTR_ROOT);
>> if (error) {
>> /*
>> * If the attribute doesn't exist make sure we have a negative
>> @@ -204,15 +204,17 @@ __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
>> len -= sizeof(struct xfs_acl_entry) *
>> (XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count);
>>
>> - error = xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
>> - len, ATTR_ROOT);
>> + error = xfs_attr_set(ip, ea_name, strlen(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 89fb1eb..844480a 100644
>> --- a/fs/xfs/xfs_ioctl.c
>> +++ b/fs/xfs/xfs_ioctl.c
>> @@ -450,6 +450,7 @@ xfs_attrmulti_attr_get(
>> {
>> unsigned char *kbuf;
>> int error = -EFAULT;
>> + size_t namelen;
>>
>> if (*len > XFS_XATTR_SIZE_MAX)
>> return -EINVAL;
>> @@ -457,7 +458,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;
>>
>> @@ -479,6 +482,7 @@ xfs_attrmulti_attr_set(
>> {
>> unsigned char *kbuf;
>> int error;
>> + size_t namelen;
>>
>> if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>> return -EPERM;
>> @@ -489,7 +493,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);
>> @@ -503,10 +508,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 c45acf0..7920f19 100644
>> --- a/fs/xfs/xfs_iops.c
>> +++ b/fs/xfs/xfs_iops.c
>> @@ -71,8 +71,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_trans_attr.c b/fs/xfs/xfs_trans_attr.c
>> index 8e3a0a0..d1d75bb 100644
>> --- a/fs/xfs/xfs_trans_attr.c
>> +++ b/fs/xfs/xfs_trans_attr.c
>> @@ -86,7 +86,7 @@ xfs_trans_attr(
>>
>> tp->t_flags |= XFS_TRANS_RESERVE;
>>
>> - error = xfs_attr_args_init(&args, ip, name, flags);
>> + error = xfs_attr_args_init(&args, ip, name, name_len, flags);
>> if (error)
>> return error;
>>
>> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
>> index 0594db4..6cf30ae 100644
>> --- a/fs/xfs/xfs_xattr.c
>> +++ b/fs/xfs/xfs_xattr.c
>> @@ -38,6 +38,7 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>> int xflags = handler->flags;
>> struct xfs_inode *ip = XFS_I(inode);
>> int error, asize = size;
>> + size_t namelen = strlen(name);
>>
>> /* Convert Linux syscall to XFS internal ATTR flags */
>> if (!size) {
>> @@ -45,7 +46,8 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>> value = NULL;
>> }
>>
>> - error = xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags);
>> + error = xfs_attr_get(ip, name, namelen, value,
>> + &asize, xflags);
>
> /methinks these could all stll be on one line?
>
>
>> if (error)
>> return error;
>> return asize;
>> @@ -81,6 +83,7 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>> int xflags = handler->flags;
>> struct xfs_inode *ip = XFS_I(inode);
>> int error;
>> + size_t namelen = strlen(name);
>>
>> /* Convert Linux syscall to XFS internal ATTR flags */
>> if (flags & XATTR_CREATE)
>> @@ -89,8 +92,9 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>> xflags |= ATTR_REPLACE;
>>
>> if (!value)
>> - return xfs_attr_remove(ip, (unsigned char *)name, xflags);
>> - error = xfs_attr_set(ip, (unsigned char *)name,
>> + return xfs_attr_remove(ip, name,
>> + namelen, xflags);
>> + error = xfs_attr_set(ip, name, namelen,
>> (void *)value, size, xflags);
>
> Same here?
>
> Looks ok with those fixed up,
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
>
> --D
Ok then, will fix. Thx!
Allison
>
>> if (!error)
>> xfs_forget_acl(inode, name, xflags);
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 06/21] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred
2018-05-07 22:59 ` Darrick J. Wong
@ 2018-05-08 17:01 ` Allison Henderson
0 siblings, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 17:01 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 05/07/2018 03:59 PM, Darrick J. Wong wrote:
> On Sun, May 06, 2018 at 10:24:39AM -0700, Allison Henderson wrote:
>> These routines set up set and start a new deferred attribute
>> operation. These functions are meant to be called by other
>> code needing to initiate a deferred attribute operation. We
>> will use these routines later in the parent pointer patches.
>>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
>> fs/xfs/libxfs/xfs_attr.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++
>> fs/xfs/libxfs/xfs_attr.h | 5 ++++
>> 2 files changed, 74 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 2f295ca..adbcef2 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -468,6 +468,42 @@ xfs_attr_set(
>> return error;
>> }
>>
>> +/* Sets an attribute for an inode as a deferred operation */
>> +int
>> +xfs_attr_set_deferred(
>> + struct xfs_inode *dp,
>> + struct xfs_defer_ops *dfops,
>> + void *name,
>> + unsigned int namelen,
>> + void *value,
>> + unsigned int valuelen,
>> + int flags)
>> +{
>> +
>> + struct xfs_attr_item *new;
>> + char *name_value;
>> +
>> + if (!namelen || !valuelen) {
>> + ASSERT(0);
>> + return -EFSCORRUPTED;
>> + }
>> +
>> + new = kmem_alloc(XFS_ATTR_ITEM_SIZEOF(namelen, valuelen),
>> + KM_SLEEP|KM_NOFS);
>> + name_value = ((char *)new) + sizeof(struct xfs_attr_item);
>> + memset(new, 0, XFS_ATTR_ITEM_SIZEOF(namelen, valuelen));
>> + new->xattri_ip = dp;
>> + new->xattri_op_flags = XFS_ATTR_OP_FLAGS_SET;
>> + new->xattri_name_len = namelen;
>> + new->xattri_value_len = valuelen;
>> + new->xattri_flags = flags;
>> + memcpy(&name_value[0], name, namelen);
>> + memcpy(&name_value[namelen], value, valuelen);
>
> If we're going to keep the inode locked across _defer_finish rolls then
> we need to xfs_defer_ijoin the inode to the dfops so that the inode is
> relogged in each transaction, which prevents the log tail from being
> pinned unnecessarily. xfs_bmap.c does a similar thing with the deferred
> map/unmap intents.
>
>> +
>> + xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
>> +
>> + return 0;
>> +}
>>
>> /*
>> * Generic handler routine to remove a name from an attribute list.
>> @@ -560,6 +596,39 @@ xfs_attr_remove(
>> return error;
>> }
>>
>> +/* Removes an attribute for an inode as a deferred operation */
>> +int
>> +xfs_attr_remove_deferred(
>> + struct xfs_inode *dp,
>> + struct xfs_defer_ops *dfops,
>> + void *name,
>> + unsigned int namelen,
>> + int flags)
>> +{
>> +
>> + struct xfs_attr_item *new;
>> + char *name_value;
>> +
>> + if (!namelen) {
>> + ASSERT(0);
>> + return -EFSCORRUPTED;
>> + }
>> +
>> + new = kmem_alloc(XFS_ATTR_ITEM_SIZEOF(namelen, 0), KM_SLEEP|KM_NOFS);
>> + name_value = ((char *)new) + sizeof(struct xfs_attr_item);
>> + memset(new, 0, XFS_ATTR_ITEM_SIZEOF(namelen, 0));
>> + new->xattri_ip = dp;
>> + new->xattri_op_flags = XFS_ATTR_OP_FLAGS_REMOVE;
>> + new->xattri_name_len = namelen;
>> + new->xattri_value_len = 0;
>> + new->xattri_flags = flags;
>> + memcpy(name_value, name, namelen);
>
> Same here.
>
> --D
Ok, I will add in the xfs_defer_ijoin's. Thx!
Allison
>
>> + xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
>> +
>> + return 0;
>> +}
>> +
>> /*========================================================================
>> * External routines when attribute list is inside the inode
>> *========================================================================*/
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index 33b33d3..ec26565 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -183,5 +183,10 @@ int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>> int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
>> const unsigned char *name, int flags);
>> int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
>> +int xfs_attr_set_deferred(struct xfs_inode *dp, struct xfs_defer_ops *dfops,
>> + void *name, unsigned int name_len, void *value,
>> + unsigned int valuelen, int flags);
>> +int xfs_attr_remove_deferred(struct xfs_inode *dp, struct xfs_defer_ops *dfops,
>> + void *name, unsigned int namelen, int flags);
>>
>> #endif /* __XFS_ATTR_H__ */
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 05/21] xfs: Set up infastructure for deferred attribute operations
2018-05-07 23:19 ` Darrick J. Wong
@ 2018-05-08 17:01 ` Allison Henderson
0 siblings, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 17:01 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 05/07/2018 04:19 PM, Darrick J. Wong wrote:
> On Sun, May 06, 2018 at 10:24:38AM -0700, Allison Henderson wrote:
>> This patch adds two new log item types for setting or
>> removing attributes as deferred operations. The
>> xfs_attri_log_item logs an intent to set or remove an
>> attribute. The corresponding xfs_attrd_log_item holds
>> a reference to the xfs_attri_log_item and is freed once
>> the transaction is done. Both log items use a generic
>> xfs_attr_log_format structure that contains the attribute
>> name, value, flags, inode, and an op_flag that indicates
>> if the operations is a set or remove.
>>
>> At the moment, this feature will only be used by the parent
>> pointer patch set which uses attributes to store information
>> about an inodes parent.
>>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
>> fs/xfs/Makefile | 2 +
>> fs/xfs/libxfs/xfs_attr.c | 5 +-
>> fs/xfs/libxfs/xfs_attr.h | 26 +-
>> fs/xfs/libxfs/xfs_defer.h | 1 +
>> fs/xfs/libxfs/xfs_log_format.h | 44 +++-
>> fs/xfs/libxfs/xfs_types.h | 1 +
>> fs/xfs/xfs_attr_item.c | 530 +++++++++++++++++++++++++++++++++++++++++
>> fs/xfs/xfs_attr_item.h | 119 +++++++++
>> fs/xfs/xfs_log_recover.c | 122 ++++++++++
>> fs/xfs/xfs_super.c | 1 +
>> fs/xfs/xfs_trans.h | 13 +
>> fs/xfs/xfs_trans_attr.c | 283 ++++++++++++++++++++++
>> 12 files changed, 1142 insertions(+), 5 deletions(-)
>>
>> diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
>> index 7ceb41a..d3c0004 100644
>> --- a/fs/xfs/Makefile
>> +++ b/fs/xfs/Makefile
>> @@ -107,6 +107,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 \
>> @@ -116,6 +117,7 @@ xfs-y += xfs_log.o \
>> xfs_trans_bmap.o \
>> xfs_trans_buf.o \
>> xfs_trans_extfree.o \
>> + xfs_trans_attr.o \
>> xfs_trans_inode.o \
>> xfs_trans_refcount.o \
>> xfs_trans_rmap.o \
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 514f4f8..2f295ca 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -41,6 +41,7 @@
>> #include "xfs_quota.h"
>> #include "xfs_trans_space.h"
>> #include "xfs_trace.h"
>> +#include "xfs_attr_item.h"
>>
>> /*
>> * xfs_attr.c
>> @@ -74,7 +75,7 @@ STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>> STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>>
>>
>> -STATIC int
>> +int
>> xfs_attr_args_init(
>> struct xfs_da_args *args,
>> struct xfs_inode *dp,
>> @@ -326,7 +327,7 @@ xfs_attr_remove_args(
>> /*
>> * Calculate how many blocks we need for the new attribute,
>> */
>> -STATIC int
>> +int
>> xfs_attr_calc_size(
>> struct xfs_da_args *args,
>> int *local)
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index ef6b47e..33b33d3 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -18,6 +18,8 @@
>> #ifndef __XFS_ATTR_H__
>> #define __XFS_ATTR_H__
>>
>> +#include "libxfs/xfs_defer.h"
>> +
>> struct xfs_inode;
>> struct xfs_da_args;
>> struct xfs_attr_list_context;
>> @@ -90,6 +92,26 @@ typedef struct attrlist_ent { /* data from attr_list() */
>> } attrlist_ent_t;
>>
>> /*
>> + * List of attrs to commit later.
>> + */
>> +struct xfs_attr_item {
>> + struct xfs_inode *xattri_ip;
>> + uint32_t xattri_op_flags;
>> + uint32_t xattri_value_len; /* length of value */
>> + uint32_t xattri_name_len; /* length of name */
>> + uint32_t xattri_flags; /* attr flags */
>> + struct list_head xattri_list;
>
> You could shave four bytes off this structure's size by sorting the
> fields in decreasing size order (e.g. put the xattri_list first).
>
>> +
>> + /*
>> + * 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.
>> */
>> @@ -158,6 +180,8 @@ int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
>> int xfs_attr_remove_args(struct xfs_da_args *args, int flags, bool roll_trans);
>> int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>> int flags, struct attrlist_cursor_kern *cursor);
>> -
>> +int xfs_attr_args_init(struct xfs_da_args *args, struct xfs_inode *dp,
>> + const unsigned char *name, int flags);
>> +int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
>>
>> #endif /* __XFS_ATTR_H__ */
>> diff --git a/fs/xfs/libxfs/xfs_defer.h b/fs/xfs/libxfs/xfs_defer.h
>> index 045beac..11e1690 100644
>> --- a/fs/xfs/libxfs/xfs_defer.h
>> +++ b/fs/xfs/libxfs/xfs_defer.h
>> @@ -55,6 +55,7 @@ enum xfs_defer_ops_type {
>> XFS_DEFER_OPS_TYPE_REFCOUNT,
>> XFS_DEFER_OPS_TYPE_RMAP,
>> XFS_DEFER_OPS_TYPE_FREE,
>> + XFS_DEFER_OPS_TYPE_ATTR,
>> XFS_DEFER_OPS_TYPE_MAX,
>> };
>>
>> diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
>> index 349d9f8..291e5ff 100644
>> --- a/fs/xfs/libxfs/xfs_log_format.h
>> +++ b/fs/xfs/libxfs/xfs_log_format.h
>> @@ -116,7 +116,12 @@ static inline uint xlog_get_cycle(char *ptr)
>> #define XLOG_REG_TYPE_CUD_FORMAT 24
>> #define XLOG_REG_TYPE_BUI_FORMAT 25
>> #define XLOG_REG_TYPE_BUD_FORMAT 26
>> -#define XLOG_REG_TYPE_MAX 26
>> +#define XLOG_REG_TYPE_ATTRI_FORMAT 27
>> +#define XLOG_REG_TYPE_ATTRD_FORMAT 28
>> +#define XLOG_REG_TYPE_ATTR_NAME 29
>> +#define XLOG_REG_TYPE_ATTR_VALUE 30
>> +#define XLOG_REG_TYPE_MAX 31
>> +
>>
>> /*
>> * Flags to log operation header
>> @@ -239,6 +244,8 @@ typedef struct xfs_trans_header {
>> #define XFS_LI_CUD 0x1243
>> #define XFS_LI_BUI 0x1244 /* bmbt update intent */
>> #define XFS_LI_BUD 0x1245
>> +#define XFS_LI_ATTRI 0x1246 /* attr set/remove intent*/
>> +#define XFS_LI_ATTRD 0x1247 /* attr set/remove done */
>>
>> #define XFS_LI_TYPE_DESC \
>> { XFS_LI_EFI, "XFS_LI_EFI" }, \
>> @@ -254,7 +261,9 @@ typedef struct xfs_trans_header {
>> { XFS_LI_CUI, "XFS_LI_CUI" }, \
>> { XFS_LI_CUD, "XFS_LI_CUD" }, \
>> { XFS_LI_BUI, "XFS_LI_BUI" }, \
>> - { XFS_LI_BUD, "XFS_LI_BUD" }
>> + { XFS_LI_BUD, "XFS_LI_BUD" }, \
>> + { XFS_LI_ATTRI, "XFS_LI_ATTRI" }, \
>> + { XFS_LI_ATTRD, "XFS_LI_ATTRD" }
>>
>> /*
>> * Inode Log Item Format definitions.
>> @@ -852,4 +861,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 */
>> +};
>
> The size of these log structures, all the other on-disk metadata
> structures, and possibly the ioctl structures needs to be checked in
> xfs_ondisk.h so that we don't repeat the AGFL padding mess.
>
>> +
>> #endif /* __XFS_LOG_FORMAT_H__ */
>> diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
>> index 3c56069..2905ce3 100644
>> --- a/fs/xfs/libxfs/xfs_types.h
>> +++ b/fs/xfs/libxfs/xfs_types.h
>> @@ -23,6 +23,7 @@ typedef uint32_t prid_t; /* project ID */
>> typedef uint32_t xfs_agblock_t; /* blockno in alloc. group */
>> typedef uint32_t xfs_agino_t; /* inode # within allocation grp */
>> typedef uint32_t xfs_extlen_t; /* extent length in blocks */
>> +typedef uint32_t xfs_attrlen_t; /* attr length */
>> typedef uint32_t xfs_agnumber_t; /* allocation group number */
>> typedef int32_t xfs_extnum_t; /* # of extents in a file */
>> typedef int16_t xfs_aextnum_t; /* # extents in an attribute fork */
>> diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
>> new file mode 100644
>> index 0000000..7e986e8
>> --- /dev/null
>> +++ b/fs/xfs/xfs_attr_item.c
>> @@ -0,0 +1,530 @@
>> +/*
>> + * Copyright (c) 2017 Oracle, Inc.
>> + * All Rights Reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it would be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write the Free Software Foundation Inc.
>> + */
>> +#include "xfs.h"
>> +#include "xfs_fs.h"
>> +#include "xfs_format.h"
>> +#include "xfs_log_format.h"
>> +#include "xfs_trans_resv.h"
>> +#include "xfs_bit.h"
>> +#include "xfs_mount.h"
>> +#include "xfs_trans.h"
>> +#include "xfs_trans_priv.h"
>> +#include "xfs_buf_item.h"
>> +#include "xfs_attr_item.h"
>> +#include "xfs_log.h"
>> +#include "xfs_btree.h"
>> +#include "xfs_rmap.h"
>> +#include "xfs_inode.h"
>> +#include "xfs_icache.h"
>> +
>> +static inline struct xfs_attri_log_item *ATTRI_ITEM(struct xfs_log_item *lip)
>> +{
>> + return container_of(lip, struct xfs_attri_log_item, item);
>> +}
>> +
>> +void
>> +xfs_attri_item_free(
>> + struct xfs_attri_log_item *attrip)
>> +{
>> + kmem_free(attrip->item.li_lv_shadow);
>> + kmem_free(attrip);
>> +}
>> +
>> +/*
>> + * This returns the number of iovecs needed to log the given attri item.
>> + * We only need 1 iovec for an attri item. It just logs the attr_log_format
>> + * structure.
>> + */
>> +static inline int
>> +xfs_attri_item_sizeof(
>> + struct xfs_attri_log_item *attrip)
>> +{
>> + return sizeof(struct xfs_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->name_len > 0) {
>> + *nvecs += 1;
>> + nbytes += ATTR_NVEC_SIZE(attrip->name_len);
>> + }
>> +
>> + if (attrip->value_len > 0) {
>> + *nvecs += 1;
>> + nbytes += ATTR_NVEC_SIZE(attrip->value_len);
>> + }
>> +}
>> +
>> +/*
>> + * This is called to fill in the vector of log iovecs for the
>> + * given attri log item. We use only 1 iovec, and we point that
>> + * at the attri_log_format structure embedded in the attri item.
>> + * It is at this point that we assert that all of the attr
>> + * slots in the attri item have been filled.
>> + */
>> +STATIC void
>> +xfs_attri_item_format(
>> + struct xfs_log_item *lip,
>> + struct xfs_log_vec *lv)
>> +{
>> + struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip);
>> + struct xfs_log_iovec *vecp = NULL;
>> +
>> + attrip->format.alfi_type = XFS_LI_ATTRI;
>> + attrip->format.alfi_size = 1;
>> +
>> + xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRI_FORMAT,
>> + &attrip->format,
>> + xfs_attri_item_sizeof(attrip));
>> + if (attrip->name_len > 0)
>> + xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_NAME,
>> + attrip->name, ATTR_NVEC_SIZE(attrip->name_len));
>> +
>> + if (attrip->value_len > 0)
>> + xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_VALUE,
>> + attrip->value,
>> + ATTR_NVEC_SIZE(attrip->value_len));
>> +}
>> +
>> +
>> +/*
>> + * Pinning has no meaning for an attri item, so just return.
>> + */
>> +STATIC void
>> +xfs_attri_item_pin(
>> + struct xfs_log_item *lip)
>> +{
>> +}
>> +
>> +/*
>> + * The unpin operation is the last place an ATTRI is manipulated in the log. It
>> + * is either inserted in the AIL or aborted in the event of a log I/O error. In
>> + * either case, the ATTRI transaction has been successfully committed to make it
>> + * this far. Therefore, we expect whoever committed the ATTRI to either
>> + * construct and commit the ATTRD or drop the ATTRD's reference in the event of
>> + * error. Simply drop the log's ATTRI reference now that the log is done with
>> + * it.
>> + */
>> +STATIC void
>> +xfs_attri_item_unpin(
>> + struct xfs_log_item *lip,
>> + int remove)
>> +{
>> + struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip);
>> +
>> + xfs_attri_release(attrip);
>> +}
>> +
>> +/*
>> + * attri items have no locking or pushing. However, since ATTRIs are pulled
>> + * from the AIL when their corresponding ATTRDs are committed to disk, their
>> + * situation is very similar to being pinned. Return XFS_ITEM_PINNED so that
>> + * the caller will eventually flush the log. This should help in getting the
>> + * ATTRI out of the AIL.
>> + */
>> +STATIC uint
>> +xfs_attri_item_push(
>> + struct xfs_log_item *lip,
>> + struct list_head *buffer_list)
>> +{
>> + return XFS_ITEM_PINNED;
>> +}
>> +
>> +/*
>> + * The ATTRI has been either committed or aborted if the transaction has been
>> + * cancelled. If the transaction was cancelled, an ATTRD isn't going to be
>> + * constructed and thus we free the ATTRI here directly.
>> + */
>> +STATIC void
>> +xfs_attri_item_unlock(
>> + struct xfs_log_item *lip)
>> +{
>> + if (lip->li_flags & XFS_LI_ABORTED)
>> + xfs_attri_release(ATTRI_ITEM(lip));
>> +}
>> +
>> +/*
>> + * The ATTRI is logged only once and cannot be moved in the log, so simply
>> + * return the lsn at which it's been logged.
>> + */
>> +STATIC xfs_lsn_t
>> +xfs_attri_item_committed(
>> + struct xfs_log_item *lip,
>> + xfs_lsn_t lsn)
>> +{
>> + return lsn;
>> +}
>> +
>> +STATIC void
>> +xfs_attri_item_committing(
>> + struct xfs_log_item *lip,
>> + xfs_lsn_t lsn)
>> +{
>> +}
>> +
>> +/*
>> + * This is the ops vector shared by all attri log items.
>> + */
>> +static const struct xfs_item_ops xfs_attri_item_ops = {
>> + .iop_size = xfs_attri_item_size,
>> + .iop_format = xfs_attri_item_format,
>> + .iop_pin = xfs_attri_item_pin,
>> + .iop_unpin = xfs_attri_item_unpin,
>> + .iop_unlock = xfs_attri_item_unlock,
>> + .iop_committed = xfs_attri_item_committed,
>> + .iop_push = xfs_attri_item_push,
>> + .iop_committing = xfs_attri_item_committing
>> +};
>> +
>> +
>> +/*
>> + * Allocate and initialize an attri item
>> + */
>> +struct xfs_attri_log_item *
>> +xfs_attri_init(
>> + struct xfs_mount *mp)
>> +
>> +{
>> + struct xfs_attri_log_item *attrip;
>> + uint size;
>> +
>> + size = (uint)(sizeof(struct xfs_attri_log_item));
>> + attrip = kmem_zalloc(size, KM_SLEEP);
>> +
>> + xfs_log_item_init(mp, &(attrip->item), XFS_LI_ATTRI,
>> + &xfs_attri_item_ops);
>> + attrip->format.alfi_id = (uintptr_t)(void *)attrip;
>> + atomic_set(&attrip->refcount, 2);
>> +
>> + return attrip;
>> +}
>> +
>> +/*
>> + * Copy an attr format buffer from the given buf, and into the destination
>> + * attr format structure.
>> + */
>> +int
>> +xfs_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) {
>> + memcpy((char *)dst_attr_fmt, (char *)src_attr_fmt, len);
>> + return 0;
>> + }
>> + return -EFSCORRUPTED;
>> +}
>> +
>> +/*
>> + * Copy an attr format buffer from the given buf, and into the destination
>> + * attr format structure.
>> + */
>> +int
>> +xfs_attrd_copy_format(struct xfs_log_iovec *buf,
>> + struct xfs_attrd_log_format *dst_attr_fmt)
>> +{
>> + struct xfs_attrd_log_format *src_attr_fmt = buf->i_addr;
>> + uint len = sizeof(struct xfs_attrd_log_format);
>> +
>> + if (buf->i_len == len) {
>> + memcpy((char *)dst_attr_fmt, (char *)src_attr_fmt, len);
>> + return 0;
>> + }
>> + return -EFSCORRUPTED;
>> +}
>> +
>> +/*
>> + * 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->refcount) > 0);
>> + if (atomic_dec_and_test(&attrip->refcount)) {
>> + xfs_trans_ail_remove(&attrip->item, SHUTDOWN_LOG_IO_ERROR);
>> + xfs_attri_item_free(attrip);
>> + }
>> +}
>> +
>> +static inline struct xfs_attrd_log_item *ATTRD_ITEM(struct xfs_log_item *lip)
>> +{
>> + return container_of(lip, struct xfs_attrd_log_item, item);
>> +}
>> +
>> +STATIC void
>> +xfs_attrd_item_free(struct xfs_attrd_log_item *attrdp)
>> +{
>> + kmem_free(attrdp->item.li_lv_shadow);
>> + kmem_free(attrdp);
>> +}
>> +
>> +/*
>> + * This returns the number of iovecs needed to log the given attrd item.
>> + * We only need 1 iovec for an attrd item. It just logs the attr_log_format
>> + * structure.
>> + */
>> +static inline int
>> +xfs_attrd_item_sizeof(
>> + struct xfs_attrd_log_item *attrdp)
>> +{
>> + return sizeof(struct xfs_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);
>> +
>> + if (attrdp->name_len > 0) {
>> + *nvecs += 1;
>> + nbytes += attrdp->name_len;
>> + }
>> +
>> + if (attrdp->value_len > 0) {
>> + *nvecs += 1;
>> + nbytes += attrdp->value_len;
>> + }
>> +}
>> +
>> +/*
>> + * This is called to fill in the vector of log iovecs for the
>> + * given attrd log item. We use only 1 iovec, and we point that
>> + * at the attr_log_format structure embedded in the attrd item.
>> + * It is at this point that we assert that all of the attr
>> + * slots in the attrd item have been filled.
>> + */
>> +STATIC void
>> +xfs_attrd_item_format(
>> + struct xfs_log_item *lip,
>> + struct xfs_log_vec *lv)
>> +{
>> + struct xfs_attrd_log_item *attrdp = ATTRD_ITEM(lip);
>> + struct xfs_log_iovec *vecp = NULL;
>> +
>> + attrdp->format.alfd_type = XFS_LI_ATTRD;
>> + attrdp->format.alfd_size = 1;
>> +
>> + xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRD_FORMAT,
>> + &attrdp->format,
>> + xfs_attrd_item_sizeof(attrdp));
>> +}
>> +
>> +/*
>> + * Pinning has no meaning for an attrd item, so just return.
>> + */
>> +STATIC void
>> +xfs_attrd_item_pin(
>> + struct xfs_log_item *lip)
>> +{
>> +}
>> +
>> +/*
>> + * Since pinning has no meaning for an attrd item, unpinning does
>> + * not either.
>> + */
>> +STATIC void
>> +xfs_attrd_item_unpin(
>> + struct xfs_log_item *lip,
>> + int remove)
>> +{
>> +}
>> +
>> +/*
>> + * There isn't much you can do to push on an attrd item. It is simply stuck
>> + * waiting for the log to be flushed to disk.
>> + */
>> +STATIC uint
>> +xfs_attrd_item_push(
>> + struct xfs_log_item *lip,
>> + struct list_head *buffer_list)
>> +{
>> + return XFS_ITEM_PINNED;
>> +}
>> +
>> +/*
>> + * The ATTRD is either committed or aborted if the transaction is cancelled. If
>> + * the transaction is cancelled, drop our reference to the ATTRI and free the
>> + * ATTRD.
>> + */
>> +STATIC void
>> +xfs_attrd_item_unlock(
>> + struct xfs_log_item *lip)
>> +{
>> + struct xfs_attrd_log_item *attrdp = ATTRD_ITEM(lip);
>> +
>> + if (lip->li_flags & XFS_LI_ABORTED) {
>> + xfs_attri_release(attrdp->attrip);
>> + xfs_attrd_item_free(attrdp);
>> + }
>> +}
>> +
>> +/*
>> + * When the attrd item is committed to disk, all we need to do is delete our
>> + * reference to our partner attri item and then free ourselves. Since we're
>> + * freeing ourselves we must return -1 to keep the transaction code from
>> + * further referencing this item.
>> + */
>> +STATIC xfs_lsn_t
>> +xfs_attrd_item_committed(
>> + struct xfs_log_item *lip,
>> + xfs_lsn_t lsn)
>> +{
>> + struct xfs_attrd_log_item *attrdp = ATTRD_ITEM(lip);
>> +
>> + /*
>> + * Drop the ATTRI reference regardless of whether the ATTRD has been
>> + * aborted. Once the ATTRD transaction is constructed, it is the sole
>> + * responsibility of the ATTRD to release the ATTRI (even if the ATTRI
>> + * is aborted due to log I/O error).
>> + */
>> + xfs_attri_release(attrdp->attrip);
>> + xfs_attrd_item_free(attrdp);
>> +
>> + return (xfs_lsn_t)-1;
>> +}
>> +
>> +STATIC void
>> +xfs_attrd_item_committing(
>> + struct xfs_log_item *lip,
>> + xfs_lsn_t lsn)
>> +{
>> +}
>> +
>> +/*
>> + * This is the ops vector shared by all attrd log items.
>> + */
>> +static const struct xfs_item_ops xfs_attrd_item_ops = {
>> + .iop_size = xfs_attrd_item_size,
>> + .iop_format = xfs_attrd_item_format,
>> + .iop_pin = xfs_attrd_item_pin,
>> + .iop_unpin = xfs_attrd_item_unpin,
>> + .iop_unlock = xfs_attrd_item_unlock,
>> + .iop_committed = xfs_attrd_item_committed,
>> + .iop_push = xfs_attrd_item_push,
>> + .iop_committing = xfs_attrd_item_committing
>> +};
>> +
>> +/*
>> + * Allocate and initialize an attrd item
>> + */
>> +struct xfs_attrd_log_item *
>> +xfs_attrd_init(
>> + struct xfs_mount *mp,
>> + struct xfs_attri_log_item *attrip)
>> +
>> +{
>> + struct xfs_attrd_log_item *attrdp;
>> + uint size;
>> +
>> + size = (uint)(sizeof(struct xfs_attrd_log_item));
>> + attrdp = kmem_zalloc(size, KM_SLEEP);
>> +
>> + xfs_log_item_init(mp, &attrdp->item, XFS_LI_ATTRD,
>> + &xfs_attrd_item_ops);
>> + attrdp->attrip = attrip;
>> + attrdp->format.alfd_alf_id = attrip->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_trans *tp;
>> + int error = 0;
>> + struct xfs_attri_log_format *attrp;
>> +
>> + ASSERT(!test_bit(XFS_ATTRI_RECOVERED, &attrip->flags));
>> +
>> + /*
>> + * First check the validity of the attr described by the
>> + * ATTRI. If any are bad, then assume that all are bad and
>> + * just toss the ATTRI. A valid attr must have a name length,
>> + * a value length, and either a "set" or "remove" op flag
>> + */
>> + attrp = &attrip->format;
>> + if (attrp->alfi_value_len == 0 ||
>> + attrp->alfi_name_len == 0 ||
>> + !(attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_SET ||
>> + attrp->alfi_op_flags == XFS_ATTR_OP_FLAGS_REMOVE) ) {
>
> The name/value len should be checked to ensure it isn't too long.
Ok, will add a check
>
>> + /*
>> + * This will pull the ATTRI from the AIL and
>> + * free the memory associated with it.
>> + */
>> + set_bit(XFS_ATTRI_RECOVERED, &attrip->flags);
>> + xfs_attri_release(attrip);
>> + return -EIO;
>> + }
>> +
>> + error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
>> + if (error)
>> + return error;
>> + attrdp = xfs_trans_get_attrd(tp, attrip);
>> + attrp = &attrip->format;
>> +
>> + error = xfs_iget(mp, tp, attrp->alfi_ino, 0, 0, &ip);
>> + if (error)
>> + return error;
>> +
>> + error = xfs_trans_attr(tp, attrdp, ip,
>> + attrp->alfi_op_flags,
>> + attrp->alfi_attr_flags,
>> + attrp->alfi_name_len,
>> + attrp->alfi_value_len,
>> + attrip->name,
>> + attrip->value);
>> + if (error)
>> + goto abort_error;
>> +
>> +
>> + set_bit(XFS_ATTRI_RECOVERED, &attrip->flags);
>> + error = xfs_trans_commit(tp);
>> + return error;
>> +
>> +abort_error:
>> + xfs_trans_cancel(tp);
>> + return error;
>> +}
>> diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h
>> new file mode 100644
>> index 0000000..6ff07cc
>> --- /dev/null
>> +++ b/fs/xfs/xfs_attr_item.h
>> @@ -0,0 +1,119 @@
>> +/*
>> + * Copyright (c) 2017 Oracle, Inc.
>> + * All Rights Reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it would be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write the Free Software Foundation Inc.
>> + */
>> +#ifndef __XFS_ATTR_ITEM_H__
>> +#define __XFS_ATTR_ITEM_H__
>> +
>> +/* kernel only ATTRI/ATTRD definitions */
>> +
>> +struct xfs_mount;
>> +struct kmem_zone;
>> +
>> +/*
>> + * Max number of attrs in fast allocation path.
>> + */
>> +#define XFS_ATTRI_MAX_FAST_ATTRS 1
>> +
>> +
>> +/*
>> + * Define ATTR flag bits. Manipulated by set/clear/test_bit operators.
>> + */
>> +#define XFS_ATTRI_RECOVERED 1
>> +
>> +
>> +/* nvecs must be in multiples of 4 */
>> +#define ATTR_NVEC_SIZE(size) (size == sizeof(int32_t) ? sizeof(int32_t) : \
>> + size + sizeof(int32_t) - \
>> + (size % sizeof(int32_t)))
>> +
>> +/*
>> + * This is the "attr intention" log item. It is used to log the fact
>> + * that some attrs need to be processed. It is used in conjunction with the
>> + * "attr done" log item described below.
>> + *
>> + * The ATTRI is reference counted so that it is not freed prior to both the
>> + * ATTRI and ATTRD being committed and unpinned. This ensures the ATTRI is
>> + * inserted into the AIL even in the event of out of order ATTRI/ATTRD
>> + * processing. In other words, an ATTRI is born with two references:
>> + *
>> + * 1.) an ATTRI held reference to track ATTRI AIL insertion
>> + * 2.) an ATTRD held reference to track ATTRD commit
>> + *
>> + * On allocation, both references are the responsibility of the caller. Once
>> + * the ATTRI is added to and dirtied in a transaction, ownership of reference
>> + * one transfers to the transaction. The reference is dropped once the ATTRI is
>> + * inserted to the AIL or in the event of failure along the way (e.g., commit
>> + * failure, log I/O error, etc.). Note that the caller remains responsible for
>> + * the ATTRD reference under all circumstances to this point. The caller has no
>> + * means to detect failure once the transaction is committed, however.
>> + * Therefore, an ATTRD is required after this point, even in the event of
>> + * unrelated failure.
>> + *
>> + * Once an ATTRD is allocated and dirtied in a transaction, reference two
>> + * transfers to the transaction. The ATTRD reference is dropped once it reaches
>> + * the unpin handler. Similar to the ATTRI, the reference also drops in the
>> + * event of commit failure or log I/O errors. Note that the ATTRD is not
>> + * inserted in the AIL, so at this point both the ATTI and ATTRD are freed.
>> + */
>> +struct xfs_attri_log_item {
>> + xfs_log_item_t item;
>> + atomic_t refcount;
>> + unsigned long flags; /* misc flags */
>> + int name_len;
>> + void *name;
>> + int value_len;
>> + void *value;
>> + struct xfs_attri_log_format format;
>> +};
>> +
>> +/*
>> + * This is the "attr done" log item. It is used to log
>> + * the fact that some attrs earlier mentioned in an attri item
>> + * have been freed.
>> + */
>> +struct xfs_attrd_log_item {
>> + struct xfs_log_item item;
>> + struct xfs_attri_log_item *attrip;
>> + uint next_attr;
>> + int name_len;
>> + void *name;
>> + int value_len;
>> + void *value;
>> + struct xfs_attrd_log_format format;
>> +};
>> +
>> +/*
>> + * Max number of attrs in fast allocation path.
>> + */
>> +#define XFS_ATTRD_MAX_FAST_ATTRS 1
>> +
>> +extern struct kmem_zone *xfs_attri_zone;
>> +extern struct kmem_zone *xfs_attrd_zone;
>> +
>> +struct xfs_attri_log_item *xfs_attri_init(struct xfs_mount *mp);
>> +struct xfs_attrd_log_item *xfs_attrd_init(struct xfs_mount *mp,
>> + struct xfs_attri_log_item *attrip);
>> +int xfs_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_recover.c b/fs/xfs/xfs_log_recover.c
>> index 2b2383f..696b6ff 100644
>> --- a/fs/xfs/xfs_log_recover.c
>> +++ b/fs/xfs/xfs_log_recover.c
>> @@ -34,6 +34,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"
>> @@ -1967,6 +1968,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);
>> @@ -3497,6 +3500,92 @@ xlog_recover_efd_pass2(
>> return 0;
>> }
>>
>> +STATIC int
>> +xlog_recover_attri_pass2(
>> + struct xlog *log,
>> + struct xlog_recover_item *item,
>> + xfs_lsn_t lsn)
>> +{
>> + int error;
>> + struct xfs_mount *mp = log->l_mp;
>> + struct xfs_attri_log_item *attrip;
>> + struct xfs_attr_log_format *attri_formatp;
>> +
>> + attri_formatp = item->ri_buf[0].i_addr;
>> +
>> + attrip = xfs_attri_init(mp);
>> + error = xfs_attri_copy_format(&item->ri_buf[0], &attrip->format);
>> + if (error) {
>> + xfs_attri_item_free(attrip);
>> + return error;
>> + }
>> +
>> + 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->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->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.
>> @@ -4116,6 +4205,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:
>> @@ -4677,6 +4770,31 @@ xlog_recover_cancel_efi(
>> 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, item);
>> + if (test_bit(XFS_ATTRI_RECOVERED, &attrip->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(
>> @@ -4920,6 +5038,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);
>
> Pass the &dfops into xlog_recover_process_attri -> xfs_attri_recover ->
> xfs_trans_attr so that deferred items generated during recovery of other
> deferred items are finished in the correct order. More information is
> in commit 509955823cc9 ("xfs: log recovery should replay deferred ops in
> order").
Oh ok, I will take a look at that one. Thx!
>
>> + break;
>> case XFS_LI_RUI:
>> error = xlog_recover_process_rui(log->l_mp, ailp, lip);
>> break;
>> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
>> index d714240..dce3baf 100644
>> --- a/fs/xfs/xfs_super.c
>> +++ b/fs/xfs/xfs_super.c
>> @@ -2077,6 +2077,7 @@ init_xfs_fs(void)
>> xfs_rmap_update_init_defer_op();
>> xfs_refcount_update_init_defer_op();
>> xfs_bmap_update_init_defer_op();
>> + xfs_attr_init_defer_op();
>>
>> xfs_dir_startup();
>>
>> diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
>> index 9d542df..abd0a46 100644
>> --- a/fs/xfs/xfs_trans.h
>> +++ b/fs/xfs/xfs_trans.h
>> @@ -40,6 +40,9 @@ struct xfs_cud_log_item;
>> struct xfs_defer_ops;
>> struct xfs_bui_log_item;
>> struct xfs_bud_log_item;
>> +struct xfs_attrd_log_item;
>> +struct xfs_attri_log_item;
>> +
>>
>> typedef struct xfs_log_item {
>> struct list_head li_ail; /* AIL pointers */
>> @@ -223,12 +226,22 @@ void xfs_trans_dirty_buf(struct xfs_trans *, struct xfs_buf *);
>> void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
>>
>> void xfs_extent_free_init_defer_op(void);
>> +void xfs_attr_init_defer_op(void);
>> +
>> struct xfs_efd_log_item *xfs_trans_get_efd(struct xfs_trans *,
>> struct xfs_efi_log_item *,
>> uint);
>> int xfs_trans_free_extent(struct xfs_trans *,
>> struct xfs_efd_log_item *, xfs_fsblock_t,
>> xfs_extlen_t, struct xfs_owner_info *);
>> +struct xfs_attrd_log_item *
>> +xfs_trans_get_attrd(struct xfs_trans *tp,
>> + struct xfs_attri_log_item *attrip);
>> +int xfs_trans_attr(struct xfs_trans *tp, struct xfs_attrd_log_item *attrdp,
>> + struct xfs_inode *ip, uint32_t attr_op_flags,
>> + uint32_t flags, uint32_t name_len, uint32_t value_len,
>> + char *name, char *value);
>> +
>> int xfs_trans_commit(struct xfs_trans *);
>> int xfs_trans_roll(struct xfs_trans **);
>> int xfs_trans_roll_inode(struct xfs_trans **, struct xfs_inode *);
>> diff --git a/fs/xfs/xfs_trans_attr.c b/fs/xfs/xfs_trans_attr.c
>> new file mode 100644
>> index 0000000..8e3a0a0
>> --- /dev/null
>> +++ b/fs/xfs/xfs_trans_attr.c
>> @@ -0,0 +1,283 @@
>> +/*
>> + * Copyright (c) 2017, Oracle Inc.
>> + * All Rights Reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it would be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write the Free Software Foundation Inc.
>> + */
>> +#include "xfs.h"
>> +#include "xfs_fs.h"
>> +#include "xfs_shared.h"
>> +#include "xfs_format.h"
>> +#include "xfs_log_format.h"
>> +#include "xfs_trans_resv.h"
>> +#include "xfs_bit.h"
>> +#include "xfs_mount.h"
>> +#include "xfs_defer.h"
>> +#include "xfs_trans.h"
>> +#include "xfs_trans_priv.h"
>> +#include "xfs_attr_item.h"
>> +#include "xfs_alloc.h"
>> +#include "xfs_bmap.h"
>> +#include "xfs_trace.h"
>> +#include "libxfs/xfs_da_format.h"
>> +#include "xfs_da_btree.h"
>> +#include "xfs_attr.h"
>> +#include "xfs_inode.h"
>> +#include "xfs_icache.h"
>> +#include "xfs_quota.h"
>> +
>> +/*
>> + * This routine is called to allocate an "extent free done"
>> + * log item that will hold nextents worth of extents. The
>> + * caller must use all nextents extents, because we are not
>> + * flexible about this at all.
>> + */
>> +struct xfs_attrd_log_item *
>> +xfs_trans_get_attrd(struct xfs_trans *tp,
>> + struct xfs_attri_log_item *attrip)
>> +{
>> + struct xfs_attrd_log_item *attrdp;
>> +
>> + ASSERT(tp != NULL);
>> +
>> + attrdp = xfs_attrd_init(tp->t_mountp, attrip);
>> + ASSERT(attrdp != NULL);
>> +
>> + /*
>> + * Get a log_item_desc to point at the new item.
>> + */
>> + xfs_trans_add_item(tp, &attrdp->item);
>> + return attrdp;
>> +}
>> +
>> +/*
>> + * Delete an attr and log it to the ATTRD. Note that the transaction is marked
>> + * dirty regardless of whether the attr delete succeeds or fails to support the
>> + * ATTRI/ATTRD lifecycle rules.
>> + */
>> +int
>> +xfs_trans_attr(
>> + struct xfs_trans *tp,
>> + struct xfs_attrd_log_item *attrdp,
>> + struct xfs_inode *ip,
>> + uint32_t op_flags,
>> + uint32_t flags,
>> + uint32_t name_len,
>> + uint32_t value_len,
>> + char *name,
>> + char *value)
>> +{
>> + int error;
>> + int local;
>> + struct xfs_da_args args;
>> + struct xfs_defer_ops dfops;
>
> Whitespace problems between type and name (the three lines leading up to
> this)?
Alrighty, will fix whitespace issues
>
>> + xfs_fsblock_t firstblock = NULLFSBLOCK;
>> + struct xfs_buf *leaf_bp = NULL;
>> +
>> + tp->t_flags |= XFS_TRANS_RESERVE;
>
> Why was this necessary? Usually the creator of the transaction knows if
> it's ok to dip into the free space reserves.
Oh, I think I had some related code in here earlier and forgot to take
it out. Will clean up.
>
>> +
>> + error = xfs_attr_args_init(&args, ip, name, flags);
>> + if (error)
>> + return error;
>> +
>> + xfs_defer_init(&dfops, &firstblock);
>
> See above comment about passing a dfops into this function to preserve
> correct finishing order of intents created by intent recovery.
>
>> + args.name = name;
>> + args.namelen = name_len;
>> + args.hashval = xfs_da_hashname(args.name, args.namelen);
>> + args.value = value;
>> + args.valuelen = value_len;
>> + args.dfops = &dfops;
>> + args.firstblock = &firstblock;
>> + args.op_flags = XFS_DA_OP_OKNOENT;
>> + args.total = xfs_attr_calc_size(&args, &local);
>> + args.trans = tp;
>> + ASSERT(local);
>> +
>> + error = xfs_qm_dqattach_locked(ip, 0);
>> + if (error)
>> + return error;
>> +
>> + switch (op_flags) {
>> + case XFS_ATTR_OP_FLAGS_SET:
>> + args.op_flags |= XFS_DA_OP_ADDNAME;
>> + error = xfs_attr_set_args(&args, flags,
>> + leaf_bp, false);
>> + break;
>> + case XFS_ATTR_OP_FLAGS_REMOVE:
>> + ASSERT(XFS_IFORK_Q((ip)));
>> + error = xfs_attr_remove_args(&args, flags, false);
>> + break;
>> + default:
>> + error = -EFSCORRUPTED;
>> + }
>> +
>> + if (error) {
>> + xfs_defer_cancel(&dfops);
>> + if (leaf_bp)
>> + xfs_trans_brelse(args.trans, leaf_bp);
>
> Leading whitespace problem (tabs not spacs)...
>
>> + }
>> +
>> + /*
>> + * Mark the transaction dirty, even on error. This ensures the
>> + * transaction is aborted, which:
>> + *
>> + * 1.) releases the ATTRI and frees the ATTRD
>> + * 2.) shuts down the filesystem
>> + */
>> + tp->t_flags |= XFS_TRANS_DIRTY;
>> + attrdp->item.li_desc->lid_flags |= XFS_LID_DIRTY;
>> + attrdp->name = name;
>> + attrdp->value = value;
>> + attrdp->name_len = name_len;
>> + attrdp->value_len = value_len;
>> + attrdp->next_attr++;
>> +
>> + return error;
>> +}
>> +
>> +static int
>> +xfs_attr_diff_items(
>> + void *priv,
>> + struct list_head *a,
>> + struct list_head *b)
>> +{
>> + return 0;
>> +}
>> +
>> +/* Get an ATTRI. */
>> +STATIC void *
>> +xfs_attr_create_intent(
>> + struct xfs_trans *tp,
>> + unsigned int count)
>> +{
>> + struct xfs_attri_log_item *attrip;
>> +
>> + ASSERT(tp != NULL);
>> + ASSERT(count == 1);
>> +
>> + attrip = xfs_attri_init(tp->t_mountp);
>> + ASSERT(attrip != NULL);
>> +
>> + /*
>> + * Get a log_item_desc to point at the new item.
>> + */
>> + xfs_trans_add_item(tp, &attrip->item);
>> + return attrip;
>> +}
>> +
>> +/* Log an attr to the intent item. */
>> +STATIC void
>> +xfs_attr_log_item(
>> + struct xfs_trans *tp,
>> + void *intent,
>> + struct list_head *item)
>> +{
>> + struct xfs_attri_log_item *attrip = intent;
>> + struct xfs_attr_item *free;
>> + struct xfs_attri_log_format *attrp;
>> + char *name_value;
>> +
>> + free = container_of(item, struct xfs_attr_item, xattri_list);
>> + name_value = ((char *)free) + sizeof(struct xfs_attr_item);
>> +
>> + tp->t_flags |= XFS_TRANS_DIRTY;
>> + attrip->item.li_desc->lid_flags |= XFS_LID_DIRTY;
>> +
>> + attrp = &attrip->format;
>> + attrp->alfi_ino = free->xattri_ip->i_ino;
>> + attrp->alfi_op_flags = free->xattri_op_flags;
>> + attrp->alfi_value_len = free->xattri_value_len;
>> + attrp->alfi_name_len = free->xattri_name_len;
>> + attrp->alfi_attr_flags = free->xattri_flags;
>> +
>> + attrip->name = name_value;
>> + attrip->value = &name_value[free->xattri_name_len];
>> + attrip->name_len = free->xattri_name_len;
>> + attrip->value_len = free->xattri_value_len;
>> +}
>> +
>> +/* Get an ATTRD so we can process all the attrs. */
>> +STATIC void *
>> +xfs_attr_create_done(
>> + struct xfs_trans *tp,
>> + void *intent,
>> + unsigned int count)
>> +{
>> + return xfs_trans_get_attrd(tp, intent);
>> +}
>> +
>> +/* Process an attr. */
>> +STATIC int
>> +xfs_attr_finish_item(
>> + struct xfs_trans *tp,
>> + struct xfs_defer_ops *dop,
>
> This dop really needs to be passed into xfs_trans_attr because any
> deferred ops created as a side effect of finishing this deferred op
> (e.g. if the attr set has to map a block into the attr fork and we have
> rmapbt=1) then the deferred rmap update has to be done in the correct
> order and in the same context as the original defer_ops.
>
> In other words we don't support nested defer_ops just like we don't
> support nested transactions because that's a mess to sort out.
>
> --D
Got it, I'll get those passed through correctly. Thx!
Allison
>
>> + struct list_head *item,
>> + void *done_item,
>> + void **state)
>> +{
>> + struct xfs_attr_item *free;
>> + char *name_value;
>> + int error;
>> +
>> + free = container_of(item, struct xfs_attr_item, xattri_list);
>> + name_value = ((char *)free) + sizeof(struct xfs_attr_item);
>> + error = xfs_trans_attr(tp, done_item,
>> + free->xattri_ip,
>> + free->xattri_op_flags,
>> + free->xattri_flags,
>> + free->xattri_name_len,
>> + free->xattri_value_len,
>> + name_value,
>> + &name_value[free->xattri_name_len]);
>> + kmem_free(free);
>> + return error;
>> +}
>> +
>> +/* Abort all pending ATTRs. */
>> +STATIC void
>> +xfs_attr_abort_intent(
>> + void *intent)
>> +{
>> + xfs_attri_release(intent);
>> +}
>> +
>> +/* Cancel an attr */
>> +STATIC void
>> +xfs_attr_cancel_item(
>> + struct list_head *item)
>> +{
>> + struct xfs_attr_item *free;
>> +
>> + free = container_of(item, struct xfs_attr_item, xattri_list);
>> + kmem_free(free);
>> +}
>> +
>> +static const struct xfs_defer_op_type xfs_attr_defer_type = {
>> + .type = XFS_DEFER_OPS_TYPE_ATTR,
>> + .max_items = XFS_ATTRI_MAX_FAST_ATTRS,
>> + .diff_items = xfs_attr_diff_items,
>> + .create_intent = xfs_attr_create_intent,
>> + .abort_intent = xfs_attr_abort_intent,
>> + .log_item = xfs_attr_log_item,
>> + .create_done = xfs_attr_create_done,
>> + .finish_item = xfs_attr_finish_item,
>> + .cancel_item = xfs_attr_cancel_item,
>> +};
>> +
>> +/* Register the deferred op type. */
>> +void
>> +xfs_attr_init_defer_op(void)
>> +{
>> + xfs_defer_init_op_type(&xfs_attr_defer_type);
>> +}
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 03/21] xfs: Add attibute set and helper functions
2018-05-07 23:36 ` Darrick J. Wong
2018-05-08 7:25 ` Amir Goldstein
@ 2018-05-08 17:01 ` Allison Henderson
1 sibling, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 17:01 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 05/07/2018 04:36 PM, Darrick J. Wong wrote:
> On Sun, May 06, 2018 at 10:24:36AM -0700, Allison Henderson wrote:
>> This patch adds xfs_attr_set_args and xfs_bmap_set_attrforkoff.
>> These sub-routines set the attributes specified in @args.
>> We will use this later for setting parent pointers as a deferred
>> attribute operation.
>>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
>> fs/xfs/libxfs/xfs_attr.c | 217 ++++++++++++++++++++++++++++-------------------
>> fs/xfs/libxfs/xfs_attr.h | 2 +
>> fs/xfs/libxfs/xfs_bmap.c | 49 ++++++-----
>> fs/xfs/libxfs/xfs_bmap.h | 1 +
>> 4 files changed, 165 insertions(+), 104 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 0ade22b..99c4a31 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -168,6 +168,134 @@ xfs_attr_get(
>> }
>>
>> /*
>> + * Set the attribute specified in @args. In the case of the parent attribute
>> + * being set, we do not want to roll the transaction on shortform-to-leaf
>> + * conversion, as the attribute must be added in the same transaction as the
>> + * parent directory modifications. Hence @roll_trans needs to be set
>> + * appropriately to control whether the transaction is committed during this
>> + * function.
>> + */
>> +int
>> +xfs_attr_set_args(
>> + struct xfs_da_args *args,
>> + int flags,
>> + struct xfs_buf *leaf_bp,
>> + bool roll_trans)
>> +{
>> + struct xfs_inode *dp = args->dp;
>> + struct xfs_mount *mp = dp->i_mount;
>> + int error = 0;
>> + int err2 = 0;
>> + int sf_size;
>> +
>> + /*
>> + * New inodes setting the parent pointer attr will
>> + * not have an attribute fork yet. So set the attribute
>> + * fork appropriately
>> + */
>> + if (XFS_IFORK_Q((args->dp)) == 0) {
>> + sf_size = sizeof(struct xfs_attr_sf_hdr) +
>> + XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
>> + xfs_bmap_set_attrforkoff(args->dp, sf_size, NULL);
>> + args->dp->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
>> + args->dp->i_afp->if_flags = XFS_IFEXTENTS;
>> + }
>> +
>> + xfs_trans_ijoin(args->trans, dp, 0);
>> + /*
>> + * If the attribute list is non-existent or a shortform list,
>> + * upgrade it to a single-leaf-block attribute list.
>> + */
>> + if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
>> + (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
>> + dp->i_d.di_anextents == 0)) {
>> +
>> + /*
>> + * Build initial attribute list (if required).
>> + */
>> + if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
>> + xfs_attr_shortform_create(args);
>> +
>> + /*
>> + * Try to add the attr to the attribute list in the inode.
>> + */
>> + error = xfs_attr_shortform_addname(args, roll_trans);
>> + if (error != -ENOSPC) {
>> + if (roll_trans) {
>
> I dislike this roll_trans parameter. Most other places in xfs when a
> function is passed in a defer_ops or a transaction it's assumed that we
> don't own the transaction or the defer_ops and so while it's ok to
> attach dirty things to the dfops or the tp, we let the caller decide
> when it's appropriate to start committing things.
>
> This function is getting rather long and indenty, can it be broken up
> into smaller pieces? That should make it easier to reuse the core
> logic of "try to stuff it in the sfattr, if it doesn't fit then convert
> to attr block and retry the add" without having to add extra parameters
> to control whether or not we commit transactions.
>
> This is more complex than in other parts of xfs because we're (for the
> moment anyway) leaving both the deferred and non-deferred paths, but at
> least the attr logic and the transaction management logic should be
> split into separate functions to handle the unique situations of both
> the deferred and non-deferred xattr setting code.
>
> Also, please don't hoist code into a helper function /and/ change its
> behavior & parameters in the same patch.
Sure, I'll see if I can split it up a little more to make it easier to
follow. Sorry, about the hoist and hijack... a lot of this comes from
collecting fixes on top of the set, and then moving them down to an
appropriate patch. The roll_trans and related probably should have gone
to the set below. I think there's more discussion concerning roll_trans
in the next patch, so I'll jump that way....
>
> --D
>
>> + /*
>> + * Commit the shortform mods, and we're done.
>> + * NOTE: this is also the error path (EEXIST, etc).
>> + */
>> + ASSERT(args->trans != NULL);
>> +
>> + /*
>> + * If this is a synchronous mount, make sure that
>> + * the transaction goes to disk before returning
>> + * to the user.
>> + */
>> + if (mp->m_flags & XFS_MOUNT_WSYNC)
>> + xfs_trans_set_sync(args->trans);
>> +
>> + if (!error && (flags & ATTR_KERNOTIME) == 0)
>> + xfs_trans_ichgtime(args->trans, dp,
>> + XFS_ICHGTIME_CHG);
>> +
>> + err2 = xfs_trans_commit(args->trans);
>> + error = error ? error : err2;
>> + }
>> + goto out;
>> + }
>> +
>> + /*
>> + * It won't fit in the shortform, transform to a leaf block.
>> + * GROT: another possible req'mt for a double-split btree op.
>> + */
>> + error = xfs_attr_shortform_to_leaf(args, &leaf_bp);
>> + if (error)
>> + goto out;
>> +
>> + xfs_defer_bjoin(args->dfops, leaf_bp);
>> + xfs_defer_ijoin(args->dfops, dp);
>> + if (roll_trans) {
>> + /*
>> + * Prevent the leaf buffer from being unlocked so that a
>> + * concurrent AIL push cannot grab the half-baked leaf
>> + * buffer and run into problems with the write verifier.
>> + */
>> + xfs_trans_bhold(args->trans, leaf_bp);
>> +
>> + error = xfs_defer_finish(&args->trans, args->dfops);
>> + if (error) {
>> + args->trans = NULL;
>> + goto out;
>> + }
>> +
>> + /*
>> + * Commit the leaf transformation. We'll need another
>> + * (linked) transaction to add the new attribute to the
>> + * leaf.
>> + */
>> + error = xfs_trans_roll_inode(&args->trans, dp);
>> + if (error)
>> + goto out;
>> + xfs_defer_ijoin(args->dfops, dp);
>> + xfs_trans_bjoin(args->trans, leaf_bp);
>> + leaf_bp = NULL;
>> + }
>> + }
>> +
>> + if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
>> + error = xfs_attr_leaf_addname(args, roll_trans);
>> + else
>> + error = xfs_attr_node_addname(args, roll_trans);
>> + if (error)
>> + goto out;
>> +
>> +out:
>> + return error;
>> +}
>> +
>> +/*
>> * Calculate how many blocks we need for the new attribute,
>> */
>> STATIC int
>> @@ -218,7 +346,7 @@ xfs_attr_set(
>> struct xfs_trans_res tres;
>> xfs_fsblock_t firstblock;
>> int rsvd = (flags & ATTR_ROOT) != 0;
>> - int error, err2, local;
>> + int error, local;
>>
>> XFS_STATS_INC(mp, xs_attr_set);
>>
>> @@ -279,88 +407,11 @@ xfs_attr_set(
>>
>> xfs_trans_ijoin(args.trans, dp, 0);
>>
>> - /*
>> - * If the attribute list is non-existent or a shortform list,
>> - * upgrade it to a single-leaf-block attribute list.
>> - */
>> - if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
>> - (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
>> - dp->i_d.di_anextents == 0)) {
>> -
>> - /*
>> - * Build initial attribute list (if required).
>> - */
>> - if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
>> - xfs_attr_shortform_create(&args);
>> -
>> - /*
>> - * Try to add the attr to the attribute list in
>> - * the inode.
>> - */
>> - error = xfs_attr_shortform_addname(&args, true);
>> - if (error != -ENOSPC) {
>> - /*
>> - * Commit the shortform mods, and we're done.
>> - * NOTE: this is also the error path (EEXIST, etc).
>> - */
>> - ASSERT(args.trans != NULL);
>> -
>> - /*
>> - * If this is a synchronous mount, make sure that
>> - * the transaction goes to disk before returning
>> - * to the user.
>> - */
>> - if (mp->m_flags & XFS_MOUNT_WSYNC)
>> - xfs_trans_set_sync(args.trans);
>> -
>> - if (!error && (flags & ATTR_KERNOTIME) == 0) {
>> - xfs_trans_ichgtime(args.trans, dp,
>> - XFS_ICHGTIME_CHG);
>> - }
>> - err2 = xfs_trans_commit(args.trans);
>> - xfs_iunlock(dp, XFS_ILOCK_EXCL);
>> -
>> - return error ? error : err2;
>> - }
>> -
>> - /*
>> - * It won't fit in the shortform, transform to a leaf block.
>> - * GROT: another possible req'mt for a double-split btree op.
>> - */
>> - xfs_defer_init(args.dfops, args.firstblock);
>> - error = xfs_attr_shortform_to_leaf(&args, &leaf_bp);
>> - if (error)
>> - goto out_defer_cancel;
>> - /*
>> - * Prevent the leaf buffer from being unlocked so that a
>> - * concurrent AIL push cannot grab the half-baked leaf
>> - * buffer and run into problems with the write verifier.
>> - */
>> - xfs_trans_bhold(args.trans, leaf_bp);
>> - xfs_defer_bjoin(args.dfops, leaf_bp);
>> - xfs_defer_ijoin(args.dfops, dp);
>> - error = xfs_defer_finish(&args.trans, args.dfops);
>> - if (error)
>> - goto out_defer_cancel;
>> -
>> - /*
>> - * Commit the leaf transformation. We'll need another (linked)
>> - * transaction to add the new attribute to the leaf, which
>> - * means that we have to hold & join the leaf buffer here too.
>> - */
>> - error = xfs_trans_roll_inode(&args.trans, dp);
>> - if (error)
>> - goto out;
>> - xfs_trans_bjoin(args.trans, leaf_bp);
>> - leaf_bp = NULL;
>> - }
>> + xfs_defer_init(args.dfops, args.firstblock);
>> + error = xfs_attr_set_args(&args, flags, leaf_bp, true);
>>
>> - if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
>> - error = xfs_attr_leaf_addname(&args, true);
>> - else
>> - error = xfs_attr_node_addname(&args, true);
>> if (error)
>> - goto out;
>> + goto out_defer_cancel;
>>
>> /*
>> * If this is a synchronous mount, make sure that the
>> @@ -369,9 +420,6 @@ xfs_attr_set(
>> if (mp->m_flags & XFS_MOUNT_WSYNC)
>> xfs_trans_set_sync(args.trans);
>>
>> - if ((flags & ATTR_KERNOTIME) == 0)
>> - xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
>> -
>> /*
>> * Commit the last in the sequence of transactions.
>> */
>> @@ -383,7 +431,6 @@ xfs_attr_set(
>>
>> out_defer_cancel:
>> xfs_defer_cancel(&dfops);
>> -out:
>> if (leaf_bp)
>> xfs_trans_brelse(args.trans, leaf_bp);
>> if (args.trans)
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index d07bf27..b5dc02c 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -152,6 +152,8 @@ int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
>> unsigned char *value, int *valuelenp, int flags);
>> int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
>> unsigned char *value, int valuelen, int flags);
>> +int xfs_attr_set_args(struct xfs_da_args *args, int flags,
>> + struct xfs_buf *leaf_bp, bool roll_trans);
>> int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
>> int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>> int flags, struct attrlist_cursor_kern *cursor);
>> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
>> index 6a7c2f0..4e16a5d 100644
>> --- a/fs/xfs/libxfs/xfs_bmap.c
>> +++ b/fs/xfs/libxfs/xfs_bmap.c
>> @@ -1031,6 +1031,34 @@ xfs_bmap_add_attrfork_local(
>> return -EFSCORRUPTED;
>> }
>>
>> +/* Set an inode attr fork off based on the format */
>> +int
>> +xfs_bmap_set_attrforkoff(
>> + struct xfs_inode *ip,
>> + int size,
>> + int *version)
>> +{
>> + switch (ip->i_d.di_format) {
>> + case XFS_DINODE_FMT_DEV:
>> + ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3;
>> + break;
>> + case XFS_DINODE_FMT_LOCAL:
>> + case XFS_DINODE_FMT_EXTENTS:
>> + case XFS_DINODE_FMT_BTREE:
>> + ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size);
>> + if (!ip->i_d.di_forkoff)
>> + ip->i_d.di_forkoff = xfs_default_attroffset(ip) >> 3;
>> + else if ((ip->i_mount->m_flags & XFS_MOUNT_ATTR2) && version)
>> + *version = 2;
>> + break;
>> + default:
>> + ASSERT(0);
>> + return -EINVAL;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> /*
>> * Convert inode from non-attributed to attributed.
>> * Must not be in a transaction, ip must not be locked.
>> @@ -1084,26 +1112,9 @@ xfs_bmap_add_attrfork(
>>
>> xfs_trans_ijoin(tp, ip, 0);
>> xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
>> -
>> - switch (ip->i_d.di_format) {
>> - case XFS_DINODE_FMT_DEV:
>> - ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3;
>> - break;
>> - case XFS_DINODE_FMT_LOCAL:
>> - case XFS_DINODE_FMT_EXTENTS:
>> - case XFS_DINODE_FMT_BTREE:
>> - ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size);
>> - if (!ip->i_d.di_forkoff)
>> - ip->i_d.di_forkoff = xfs_default_attroffset(ip) >> 3;
>> - else if (mp->m_flags & XFS_MOUNT_ATTR2)
>> - version = 2;
>> - break;
>> - default:
>> - ASSERT(0);
>> - error = -EINVAL;
>> + error = xfs_bmap_set_attrforkoff(ip, size, &version);
>> + if (error)
>> goto trans_cancel;
>> - }
>> -
>> ASSERT(ip->i_afp == NULL);
>> ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
>> ip->i_afp->if_flags = XFS_IFEXTENTS;
>> diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
>> index 2b766b3..50e9115 100644
>> --- a/fs/xfs/libxfs/xfs_bmap.h
>> +++ b/fs/xfs/libxfs/xfs_bmap.h
>> @@ -191,6 +191,7 @@ void xfs_trim_extent(struct xfs_bmbt_irec *irec, xfs_fileoff_t bno,
>> xfs_filblks_t len);
>> void xfs_trim_extent_eof(struct xfs_bmbt_irec *, struct xfs_inode *);
>> int xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd);
>> +int xfs_bmap_set_attrforkoff(struct xfs_inode *ip, int size, int *version);
>> void xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork);
>> void xfs_bmap_add_free(struct xfs_mount *mp, struct xfs_defer_ops *dfops,
>> xfs_fsblock_t bno, xfs_filblks_t len,
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 03/21] xfs: Add attibute set and helper functions
2018-05-08 7:25 ` Amir Goldstein
@ 2018-05-08 17:02 ` Allison Henderson
0 siblings, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 17:02 UTC (permalink / raw)
To: Amir Goldstein, Darrick J. Wong; +Cc: linux-xfs
On 05/08/2018 12:25 AM, Amir Goldstein wrote:
> On Tue, May 8, 2018 at 2:36 AM, Darrick J. Wong <darrick.wong@oracle.com> wrote:
>> On Sun, May 06, 2018 at 10:24:36AM -0700, Allison Henderson wrote:
>>> This patch adds xfs_attr_set_args and xfs_bmap_set_attrforkoff.
>>> These sub-routines set the attributes specified in @args.
>>> We will use this later for setting parent pointers as a deferred
>>> attribute operation.
>>>
>>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>>> ---
>>> fs/xfs/libxfs/xfs_attr.c | 217 ++++++++++++++++++++++++++++-------------------
>>> fs/xfs/libxfs/xfs_attr.h | 2 +
>>> fs/xfs/libxfs/xfs_bmap.c | 49 ++++++-----
>>> fs/xfs/libxfs/xfs_bmap.h | 1 +
>>> 4 files changed, 165 insertions(+), 104 deletions(-)
>>>
>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>> index 0ade22b..99c4a31 100644
>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>> @@ -168,6 +168,134 @@ xfs_attr_get(
>>> }
>>>
>>> /*
>>> + * Set the attribute specified in @args. In the case of the parent attribute
>>> + * being set, we do not want to roll the transaction on shortform-to-leaf
>>> + * conversion, as the attribute must be added in the same transaction as the
>>> + * parent directory modifications. Hence @roll_trans needs to be set
>>> + * appropriately to control whether the transaction is committed during this
>>> + * function.
>>> + */
>>> +int
>>> +xfs_attr_set_args(
>>> + struct xfs_da_args *args,
>>> + int flags,
>>> + struct xfs_buf *leaf_bp,
>>> + bool roll_trans)
>>> +{
>>> + struct xfs_inode *dp = args->dp;
>>> + struct xfs_mount *mp = dp->i_mount;
>>> + int error = 0;
>>> + int err2 = 0;
>>> + int sf_size;
>>> +
>>> + /*
>>> + * New inodes setting the parent pointer attr will
>>> + * not have an attribute fork yet. So set the attribute
>>> + * fork appropriately
>>> + */
>>> + if (XFS_IFORK_Q((args->dp)) == 0) {
>>> + sf_size = sizeof(struct xfs_attr_sf_hdr) +
>>> + XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
>>> + xfs_bmap_set_attrforkoff(args->dp, sf_size, NULL);
>>> + args->dp->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP);
>>> + args->dp->i_afp->if_flags = XFS_IFEXTENTS;
>>> + }
>>> +
>>> + xfs_trans_ijoin(args->trans, dp, 0);
>>> + /*
>>> + * If the attribute list is non-existent or a shortform list,
>>> + * upgrade it to a single-leaf-block attribute list.
>>> + */
>>> + if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
>>> + (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
>>> + dp->i_d.di_anextents == 0)) {
>>> +
>>> + /*
>>> + * Build initial attribute list (if required).
>>> + */
>>> + if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
>>> + xfs_attr_shortform_create(args);
>>> +
>>> + /*
>>> + * Try to add the attr to the attribute list in the inode.
>>> + */
>>> + error = xfs_attr_shortform_addname(args, roll_trans);
>>> + if (error != -ENOSPC) {
>>> + if (roll_trans) {
>>
>> I dislike this roll_trans parameter. Most other places in xfs when a
>> function is passed in a defer_ops or a transaction it's assumed that we
>> don't own the transaction or the defer_ops and so while it's ok to
>> attach dirty things to the dfops or the tp, we let the caller decide
>> when it's appropriate to start committing things.
>>
>> This function is getting rather long and indenty, can it be broken up
>> into smaller pieces? That should make it easier to reuse the core
>> logic of "try to stuff it in the sfattr, if it doesn't fit then convert
>> to attr block and retry the add" without having to add extra parameters
>> to control whether or not we commit transactions.
>>
>> This is more complex than in other parts of xfs because we're (for the
>> moment anyway) leaving both the deferred and non-deferred paths, but at
>> least the attr logic and the transaction management logic should be
>> split into separate functions to handle the unique situations of both
>> the deferred and non-deferred xattr setting code.
>>
>> Also, please don't hoist code into a helper function /and/ change its
>> behavior & parameters in the same patch.
>>
>
> Indeed. I was going to comment that the description should say
> "factor out helper" and "doesn't change logic" so reviewers can
> review it properly, although now I am not sure if that is really the
> case, so please make it the case.
>
> Thanks,
> Amir.
>
Sorry about that. Yes, the roll_trans logic should have gone to the
patch below, leaving this one just a refactor. Will fix. Thx! :-)
Allison
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 04/21] xfs: Add attibute remove and helper functions
2018-05-08 7:33 ` Amir Goldstein
@ 2018-05-08 17:02 ` Allison Henderson
2018-05-08 17:14 ` Darrick J. Wong
1 sibling, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 17:02 UTC (permalink / raw)
To: Amir Goldstein; +Cc: linux-xfs
On 05/08/2018 12:33 AM, Amir Goldstein wrote:
> On Sun, May 6, 2018 at 8:24 PM, Allison Henderson
> <allison.henderson@oracle.com> wrote:
>> This patch adds xfs_attr_remove_args. These sub-routines remove
>> the attributes specified in @args. We will use this later for setting
>> parent pointers as a deferred attribute operation.
>>
>
> But this patch also adds xfs_defer_init()+xfs_trans_ijoin()
> so maybe I am not understanding how this work, but it seems
> to be changing logic as well.
>
> Please say something about this in commit message.
>
> Thanks,
> Amir.
>
Oh, let me see if I can take those out. I think I had tried some code
in here earlier that used it, but I'm pretty sure it doesnt need to be
there now. Will clean up. Thx!
Allison
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 00/21] Parent Pointers v6
2018-05-08 5:36 ` [PATCH 00/21] Parent Pointers v6 Amir Goldstein
@ 2018-05-08 17:03 ` Allison Henderson
0 siblings, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 17:03 UTC (permalink / raw)
To: Amir Goldstein; +Cc: linux-xfs, Darrick J. Wong
On 05/07/2018 10:36 PM, Amir Goldstein wrote:
> On Sun, May 6, 2018 at 8:24 PM, Allison Henderson
> <allison.henderson@oracle.com> wrote:
>> Hi all,
>>
>> This is the 6th version of parent pointer attributes for xfs. The goal of
>
> Please try to remember to use git format-patch -v $N as it makes it easier
> to lookup old revisions of the patch in the mailbox.
>
> Looking back, I see that Darrick doesn't seem to be tagging individual
> patches with revision in his patch bombs as well...
>
> Thanks,
> Amir.
>
Sorry, will add the flag next time! Thx!
Allison
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 02/21] Add trans toggle to attr routines
2018-05-07 23:52 ` Darrick J. Wong
@ 2018-05-08 17:04 ` Allison Henderson
0 siblings, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-08 17:04 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 05/07/2018 04:52 PM, Darrick J. Wong wrote:
> On Sun, May 06, 2018 at 10:24:35AM -0700, Allison Henderson wrote:
>> This patch adds a roll_trans parameter to all attribute routines.
>> Calling functions may pass true to roll transactions as normal,
>> or false to hold them. We will need this later for delayed
>> attribute operations.
>
> /me kinda dislikes this, but I guess the reason for the roll_trans
> parameter is that we can't call defer_finish from a defer ops finishing
> function, right?
>
> Under the existing attr code we do things like:
>
> _trans_alloc
> _defer_init
> *dirty transaction, accumulate dfops*
> _defer_finish
> *finish items*
> *dirty transaction again, accumulate more dfops*
> _defer_finish
> *finish_items*
> _trans_commit
>
> But since we /really/ can't have nested _defer_finish calls I guess we
> have to do something like this?
>
> _defer_finish
> _attr_finish_item
> *dirty transaction, accumulate dfops*
> bail out with EAGAIN
> _defer_roll
> _attr_finish_item (again)
> *dirty transaction again, accumulate more dfops*
> _defer_roll
> *finish items*
>
> Thoughts?
>
> --D
I suppose I could try it? So instead of roll_trans jumping over defer
finish, we return EAGAIN, and start another defer_roll?
>
>> Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
>> ---
>> fs/xfs/libxfs/xfs_attr.c | 144 +++++++++++++++++++++++-------------------
>> fs/xfs/libxfs/xfs_attr_leaf.c | 12 ++--
>> fs/xfs/libxfs/xfs_attr_leaf.h | 8 +--
>> 3 files changed, 90 insertions(+), 74 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index ce4a34a..0ade22b 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -55,21 +55,21 @@
>> /*
>> * Internal routines when attribute list fits inside the inode.
>> */
>> -STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>> +STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args, bool roll_trans);
>>
>> /*
>> * Internal routines when attribute list is one block.
>> */
>> STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
>> -STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
>> -STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>> +STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args, bool roll_trans);
>> +STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args, bool roll_trans);
>>
>> /*
>> * Internal routines when attribute list is more than one block.
>> */
>> STATIC int xfs_attr_node_get(xfs_da_args_t *args);
>> -STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
>> -STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
>> +STATIC int xfs_attr_node_addname(xfs_da_args_t *args, bool roll_trans);
>> +STATIC int xfs_attr_node_removename(xfs_da_args_t *args, bool roll_trans);
>> STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>> STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>>
>> @@ -297,7 +297,7 @@ xfs_attr_set(
>> * Try to add the attr to the attribute list in
>> * the inode.
>> */
>> - error = xfs_attr_shortform_addname(&args);
>> + error = xfs_attr_shortform_addname(&args, true);
>> if (error != -ENOSPC) {
>> /*
>> * Commit the shortform mods, and we're done.
>> @@ -356,9 +356,9 @@ xfs_attr_set(
>> }
>>
>> if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
>> - error = xfs_attr_leaf_addname(&args);
>> + error = xfs_attr_leaf_addname(&args, true);
>> else
>> - error = xfs_attr_node_addname(&args);
>> + error = xfs_attr_node_addname(&args, true);
>> if (error)
>> goto out;
>>
>> @@ -453,11 +453,11 @@ xfs_attr_remove(
>> error = -ENOATTR;
>> } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>> ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
>> - error = xfs_attr_shortform_remove(&args);
>> + error = xfs_attr_shortform_remove(&args, true);
>> } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> - error = xfs_attr_leaf_removename(&args);
>> + error = xfs_attr_leaf_removename(&args, true);
>> } else {
>> - error = xfs_attr_node_removename(&args);
>> + error = xfs_attr_node_removename(&args, true);
>> }
>>
>> if (error)
>> @@ -498,7 +498,7 @@ xfs_attr_remove(
>> * This is the external routine.
>> */
>> STATIC int
>> -xfs_attr_shortform_addname(xfs_da_args_t *args)
>> +xfs_attr_shortform_addname(xfs_da_args_t *args, bool roll_trans)
>> {
>> int newsize, forkoff, retval;
>>
>> @@ -510,7 +510,7 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>> } else if (retval == -EEXIST) {
>> if (args->flags & ATTR_CREATE)
>> return retval;
>> - retval = xfs_attr_shortform_remove(args);
>> + retval = xfs_attr_shortform_remove(args, roll_trans);
>> ASSERT(retval == 0);
>> }
>>
>> @@ -525,7 +525,7 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>> if (!forkoff)
>> return -ENOSPC;
>>
>> - xfs_attr_shortform_add(args, forkoff);
>> + xfs_attr_shortform_add(args, forkoff, roll_trans);
>> return 0;
>> }
>>
>> @@ -541,7 +541,7 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>> * if bmap_one_block() says there is only one block (ie: no remote blks).
>> */
>> STATIC int
>> -xfs_attr_leaf_addname(xfs_da_args_t *args)
>> +xfs_attr_leaf_addname(xfs_da_args_t *args, bool roll_trans)
>> {
>> xfs_inode_t *dp;
>> struct xfs_buf *bp;
>> @@ -604,36 +604,42 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
>> * can manage its own transactions.
>> */
>> xfs_defer_init(args->dfops, args->firstblock);
>> - error = xfs_attr3_leaf_to_node(args);
>> - if (error)
>> - goto out_defer_cancel;
>> - xfs_defer_ijoin(args->dfops, dp);
>> - error = xfs_defer_finish(&args->trans, args->dfops);
>> + error = xfs_attr3_leaf_to_node(args, roll_trans);
>> if (error)
>> goto out_defer_cancel;
>> + if (roll_trans) {
>> + xfs_defer_ijoin(args->dfops, dp);
>> + error = xfs_defer_finish(&args->trans, args->dfops);
>> + if (error)
>> + goto out_defer_cancel;
>>
>> - /*
>> - * Commit the current trans (including the inode) and start
>> - * a new one.
>> - */
>> - error = xfs_trans_roll_inode(&args->trans, dp);
>> - if (error)
>> - return error;
>> + /*
>> + * Commit the current trans (including the inode) and start
>> + * a new one.
>> + */
>> + error = xfs_trans_roll_inode(&args->trans, dp);
>> + if (error)
>> + return error;
>> + }
>>
>> /*
>> * Fob the whole rest of the problem off on the Btree code.
>> */
>> - error = xfs_attr_node_addname(args);
>> + error = xfs_attr_node_addname(args, roll_trans);
>> +
>> return error;
>> }
>>
>> - /*
>> - * Commit the transaction that added the attr name so that
>> - * later routines can manage their own transactions.
>> - */
>> - error = xfs_trans_roll_inode(&args->trans, dp);
>> - if (error)
>> - return error;
>> +
>> + if (roll_trans) {
>> + /*
>> + * Commit the transaction that added the attr name so that
>> + * later routines can manage their own transactions.
>> + */
>> + error = xfs_trans_roll_inode(&args->trans, dp);
>> + if (error)
>> + return error;
>> + }
>>
>> /*
>> * If there was an out-of-line value, allocate the blocks we
>> @@ -691,9 +697,9 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
>> /*
>> * If the result is small enough, shrink it all into the inode.
>> */
>> - if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
>> + if ((forkoff = xfs_attr_shortform_allfit(bp, dp)) && roll_trans) {
>> xfs_defer_init(args->dfops, args->firstblock);
>> - error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
>> + error = xfs_attr3_leaf_to_shortform(bp, args, forkoff, roll_trans);
>> /* bp is gone due to xfs_da_shrink_inode */
>> if (error)
>> goto out_defer_cancel;
>> @@ -727,7 +733,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
>> * if bmap_one_block() says there is only one block (ie: no remote blks).
>> */
>> STATIC int
>> -xfs_attr_leaf_removename(xfs_da_args_t *args)
>> +xfs_attr_leaf_removename(xfs_da_args_t *args, bool roll_trans)
>> {
>> xfs_inode_t *dp;
>> struct xfs_buf *bp;
>> @@ -755,9 +761,9 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
>> /*
>> * If the result is small enough, shrink it all into the inode.
>> */
>> - if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
>> + if ((forkoff = xfs_attr_shortform_allfit(bp, dp)) && roll_trans) {
>> xfs_defer_init(args->dfops, args->firstblock);
>> - error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
>> + error = xfs_attr3_leaf_to_shortform(bp, args, forkoff, roll_trans);
>> /* bp is gone due to xfs_da_shrink_inode */
>> if (error)
>> goto out_defer_cancel;
>> @@ -819,7 +825,7 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>> * add a whole extra layer of confusion on top of that.
>> */
>> STATIC int
>> -xfs_attr_node_addname(xfs_da_args_t *args)
>> +xfs_attr_node_addname(xfs_da_args_t *args, bool roll_trans)
>> {
>> xfs_da_state_t *state;
>> xfs_da_state_blk_t *blk;
>> @@ -885,21 +891,23 @@ xfs_attr_node_addname(xfs_da_args_t *args)
>> xfs_da_state_free(state);
>> state = NULL;
>> xfs_defer_init(args->dfops, args->firstblock);
>> - error = xfs_attr3_leaf_to_node(args);
>> + error = xfs_attr3_leaf_to_node(args, roll_trans);
>> if (error)
>> goto out_defer_cancel;
>> xfs_defer_ijoin(args->dfops, dp);
>> - error = xfs_defer_finish(&args->trans, args->dfops);
>> - if (error)
>> - goto out_defer_cancel;
>> -
>> - /*
>> - * Commit the node conversion and start the next
>> - * trans in the chain.
>> - */
>> - error = xfs_trans_roll_inode(&args->trans, dp);
>> - if (error)
>> - goto out;
>> + if (roll_trans) {
>> + error = xfs_defer_finish(&args->trans, args->dfops);
>> + if (error)
>> + goto out_defer_cancel;
>> +
>> + /*
>> + * Commit the node conversion and start the next
>> + * trans in the chain.
>> + */
>> + error = xfs_trans_roll_inode(&args->trans, dp);
>> + if (error)
>> + goto out;
>> + }
>>
>> goto restart;
>> }
>> @@ -915,9 +923,11 @@ xfs_attr_node_addname(xfs_da_args_t *args)
>> if (error)
>> goto out_defer_cancel;
>> xfs_defer_ijoin(args->dfops, dp);
>> - error = xfs_defer_finish(&args->trans, args->dfops);
>> - if (error)
>> - goto out_defer_cancel;
>> + if (roll_trans) {
>> + error = xfs_defer_finish(&args->trans, args->dfops);
>> + if (error)
>> + goto out_defer_cancel;
>> + }
>> } else {
>> /*
>> * Addition succeeded, update Btree hashvals.
>> @@ -936,9 +946,11 @@ xfs_attr_node_addname(xfs_da_args_t *args)
>> * Commit the leaf addition or btree split and start the next
>> * trans in the chain.
>> */
>> - error = xfs_trans_roll_inode(&args->trans, dp);
>> - if (error)
>> - goto out;
>> + if (roll_trans) {
>> + error = xfs_trans_roll_inode(&args->trans, dp);
>> + if (error)
>> + goto out;
>> + }
>>
>> /*
>> * If there was an out-of-line value, allocate the blocks we
>> @@ -1013,9 +1025,11 @@ xfs_attr_node_addname(xfs_da_args_t *args)
>> if (error)
>> goto out_defer_cancel;
>> xfs_defer_ijoin(args->dfops, dp);
>> - error = xfs_defer_finish(&args->trans, args->dfops);
>> - if (error)
>> - goto out_defer_cancel;
>> + if (roll_trans) {
>> + error = xfs_defer_finish(&args->trans, args->dfops);
>> + if (error)
>> + goto out_defer_cancel;
>> + }
>> }
>>
>> /*
>> @@ -1054,7 +1068,7 @@ xfs_attr_node_addname(xfs_da_args_t *args)
>> * the root node (a special case of an intermediate node).
>> */
>> STATIC int
>> -xfs_attr_node_removename(xfs_da_args_t *args)
>> +xfs_attr_node_removename(xfs_da_args_t *args, bool roll_trans)
>> {
>> xfs_da_state_t *state;
>> xfs_da_state_blk_t *blk;
>> @@ -1163,9 +1177,9 @@ xfs_attr_node_removename(xfs_da_args_t *args)
>> if (error)
>> goto out;
>>
>> - if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
>> + if ((forkoff = xfs_attr_shortform_allfit(bp, dp)) && roll_trans) {
>> xfs_defer_init(args->dfops, args->firstblock);
>> - error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
>> + error = xfs_attr3_leaf_to_shortform(bp, args, forkoff, roll_trans);
>> /* bp is gone due to xfs_da_shrink_inode */
>> if (error)
>> goto out_defer_cancel;
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>> index 2135b8e..01935fe 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -546,7 +546,7 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
>> * Overflow from the inode has already been checked for.
>> */
>> void
>> -xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>> +xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff, bool roll_trans)
>> {
>> xfs_attr_shortform_t *sf;
>> xfs_attr_sf_entry_t *sfe;
>> @@ -618,7 +618,7 @@ xfs_attr_fork_remove(
>> * Remove an attribute from the shortform attribute list structure.
>> */
>> int
>> -xfs_attr_shortform_remove(xfs_da_args_t *args)
>> +xfs_attr_shortform_remove(xfs_da_args_t *args, bool roll_trans)
>> {
>> xfs_attr_shortform_t *sf;
>> xfs_attr_sf_entry_t *sfe;
>> @@ -970,7 +970,8 @@ int
>> xfs_attr3_leaf_to_shortform(
>> struct xfs_buf *bp,
>> struct xfs_da_args *args,
>> - int forkoff)
>> + int forkoff,
>> + bool roll_trans)
>> {
>> struct xfs_attr_leafblock *leaf;
>> struct xfs_attr3_icleaf_hdr ichdr;
>> @@ -1039,7 +1040,7 @@ xfs_attr3_leaf_to_shortform(
>> nargs.valuelen = be16_to_cpu(name_loc->valuelen);
>> nargs.hashval = be32_to_cpu(entry->hashval);
>> nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags);
>> - xfs_attr_shortform_add(&nargs, forkoff);
>> + xfs_attr_shortform_add(&nargs, forkoff, roll_trans);
>> }
>> error = 0;
>>
>> @@ -1053,7 +1054,8 @@ xfs_attr3_leaf_to_shortform(
>> */
>> int
>> xfs_attr3_leaf_to_node(
>> - struct xfs_da_args *args)
>> + struct xfs_da_args *args,
>> + bool roll_trans)
>> {
>> struct xfs_attr_leafblock *leaf;
>> struct xfs_attr3_icleaf_hdr icleafhdr;
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
>> index 4da08af..b5dea0e 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
>> @@ -45,12 +45,12 @@ typedef struct xfs_attr_inactive_list {
>> * Internal routines when attribute fork size < XFS_LITINO(mp).
>> */
>> void xfs_attr_shortform_create(struct xfs_da_args *args);
>> -void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff);
>> +void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff, bool roll_trans);
>> int xfs_attr_shortform_lookup(struct xfs_da_args *args);
>> int xfs_attr_shortform_getvalue(struct xfs_da_args *args);
>> int xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
>> struct xfs_buf **leaf_bp);
>> -int xfs_attr_shortform_remove(struct xfs_da_args *args);
>> +int xfs_attr_shortform_remove(struct xfs_da_args *args, bool roll_trans);
>> int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
>> int xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes);
>> xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_inode *ip);
>> @@ -59,9 +59,9 @@ void xfs_attr_fork_remove(struct xfs_inode *ip, struct xfs_trans *tp);
>> /*
>> * Internal routines when attribute fork size == XFS_LBSIZE(mp).
>> */
>> -int xfs_attr3_leaf_to_node(struct xfs_da_args *args);
>> +int xfs_attr3_leaf_to_node(struct xfs_da_args *args, bool roll_trans);
>> int xfs_attr3_leaf_to_shortform(struct xfs_buf *bp,
>> - struct xfs_da_args *args, int forkoff);
>> + struct xfs_da_args *args, int forkoff, bool roll_trans);
>> int xfs_attr3_leaf_clearflag(struct xfs_da_args *args);
>> int xfs_attr3_leaf_setflag(struct xfs_da_args *args);
>> int xfs_attr3_leaf_flipflags(struct xfs_da_args *args);
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 04/21] xfs: Add attibute remove and helper functions
2018-05-08 7:33 ` Amir Goldstein
2018-05-08 17:02 ` Allison Henderson
@ 2018-05-08 17:14 ` Darrick J. Wong
1 sibling, 0 replies; 72+ messages in thread
From: Darrick J. Wong @ 2018-05-08 17:14 UTC (permalink / raw)
To: Amir Goldstein; +Cc: Allison Henderson, linux-xfs
On Tue, May 08, 2018 at 10:33:05AM +0300, Amir Goldstein wrote:
> On Sun, May 6, 2018 at 8:24 PM, Allison Henderson
> <allison.henderson@oracle.com> wrote:
> > This patch adds xfs_attr_remove_args. These sub-routines remove
> > the attributes specified in @args. We will use this later for setting
> > parent pointers as a deferred attribute operation.
> >
>
> But this patch also adds xfs_defer_init()+xfs_trans_ijoin()
> so maybe I am not understanding how this work, but it seems
> to be changing logic as well.
Sooooo... I went and took another look at this, having realized that
xfs_da_args.dfops is a *pointer* to a dfops, not the dfops itself.
Subsequently we have a bunch of calls to:
xfs_defer_init(args->dfops, ...);
which AFAICT is careful enough that we always pair the init with a
_finish or a _cancel... but this is really gross behavior. The da_args
creators will declare a separate dfops on the stack and set args.dfops
to the uninitialized dfops(!) and then the attr code blindly assumes
that it owns this dfops pointer and can therefore reinitialize it at
will.
That will need fixing.
> Please say something about this in commit message.
"Mugga wugga mugga wugga mugga wugga mugga wugga mugga wugga wugggga!!!"
--D
>
> Thanks,
> Amir.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 20/21] xfs: Add parent pointer ioctl
2018-05-06 17:24 ` [PATCH 20/21] xfs: Add parent pointer ioctl Allison Henderson
2018-05-07 21:36 ` Darrick J. Wong
@ 2018-05-15 16:27 ` Catalin Iacob
2018-05-15 16:52 ` Allison Henderson
1 sibling, 1 reply; 72+ messages in thread
From: Catalin Iacob @ 2018-05-15 16:27 UTC (permalink / raw)
To: Allison Henderson; +Cc: linux-xfs
On Sun, May 6, 2018 at 7:24 PM, Allison Henderson
<allison.henderson@oracle.com> wrote:
> This patch adds a new file ioctl to retrieve the parent
> pointer of a given inode
Looking through the patch I spotted some typos and use of outdated
names in comments.
> +#define XFS_PPTR_MAXNAMELEN 255
> +
> +/* return parents of the handle, not the open fd */
> +#define XFS_PPTR_IFLAG_HANDLE (1U << 0)
> +
> +/* Get an inode parent pointer through ioctl */
> +struct xfs_parent_ptr {
> + __u64 xpp_ino; /* Inode */
> + __u32 xpp_gen; /* Inode generation */
> + __u32 xpp_diroffset; /* Directory offset */
> + __u32 xpp_namelen; /* File name length */
> + __u8 xpp_name[XFS_PPTR_MAXNAMELEN]; /* File name */
> +};
> +
> +/* Iterate though an inodes parent pointers */
typo through
> +struct xfs_pptr_info {
> + struct xfs_handle pi_handle;
> + struct xfs_attrlist_cursor pi_cursor;
> + __u32 pi_flags;
> + __u32 pi_reserved;
> + __u32 pi_ptrs_size;
> + __u32 pi_ptrs_used;
> + __u64 pi_reserved2[6];
> +
> + /*
> + * An array of struct xfs_pptr follows the header
Should be struct xfs_parent_ptr
> + * information. Use XFS_PPINFO_TO_PP() to access the
> + * parent pointer array entries.
> + */
> +};
> +
> +#define XFS_PPTR_INFO_SIZEOF(nr_ptrs) sizeof (struct xfs_pptr_info) + \
> + nr_ptrs * sizeof(struct xfs_parent_ptr)
> +
> +#define XFS_PPINFO_TO_PP(info, idx) \
> + (&(((struct xfs_parent_ptr *)((char *)(info) + sizeof(*(info))))[(idx)]))
> +
> /*
> * ioctl limits
> */
> @@ -596,6 +633,7 @@ struct xfs_scrub_metadata {
> #define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_fs_eofblocks)
> /* XFS_IOC_GETFSMAP ------ hoisted 59 */
> #define XFS_IOC_SCRUB_METADATA _IOWR('X', 60, struct xfs_scrub_metadata)
> +#define XFS_IOC_GETPPOINTER _IOR ('X', 61, struct xfs_parent_ptr)
>
> /*
> * ioctl commands that replace IRIX syssgi()'s
> diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
> index e6de97c..61f1961 100644
> --- a/fs/xfs/libxfs/xfs_parent.c
> +++ b/fs/xfs/libxfs/xfs_parent.c
> @@ -32,6 +32,16 @@
> #include "xfs_attr_sf.h"
> #include "xfs_bmap.h"
>
> +/* Initializes a xfs_parent_ptr from an xfs_parent_name_rec */
> +void
> +xfs_init_parent_ptr(struct xfs_parent_ptr *xpp,
> + struct xfs_parent_name_rec *rec)
> +{
> + xpp->xpp_ino = be64_to_cpu(rec->p_ino);
> + xpp->xpp_gen = be32_to_cpu(rec->p_gen);
> + xpp->xpp_diroffset = be32_to_cpu(rec->p_diroffset);
> +}
> +
> /*
> * Parent pointer attribute handling.
> *
> diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h
> index 298562b..1a321db 100644
> --- a/fs/xfs/libxfs/xfs_parent.h
> +++ b/fs/xfs/libxfs/xfs_parent.h
> @@ -33,4 +33,6 @@ int xfs_parent_add(struct xfs_trans *tp, struct xfs_inode *parent,
> struct xfs_inode *child, struct xfs_name *child_name,
> uint32_t diroffset, xfs_fsblock_t *firstblock,
> struct xfs_defer_ops *dfops);
> +void xfs_init_parent_ptr(struct xfs_parent_ptr *xpp,
> + struct xfs_parent_name_rec *rec);
> #endif /* __XFS_PARENT_H__ */
> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
> index 3e59a34..bdbe9fb 100644
> --- a/fs/xfs/xfs_attr_list.c
> +++ b/fs/xfs/xfs_attr_list.c
> @@ -581,6 +581,9 @@ xfs_attr_put_listent(
> if (((context->flags & ATTR_ROOT) == 0) !=
> ((flags & XFS_ATTR_ROOT) == 0))
> return;
> + if (((context->flags & ATTR_PARENT) == 0) !=
> + ((flags & XFS_ATTR_PARENT) == 0))
> + return;
>
> arraytop = sizeof(*alist) +
> context->count * sizeof(alist->al_offset[0]);
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index 844480a..ee544f2 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -46,6 +46,8 @@
> #include "xfs_fsmap.h"
> #include "scrub/xfs_scrub.h"
> #include "xfs_sb.h"
> +#include "xfs_da_format.h"
> +#include "xfs_parent_utils.h"
>
> #include <linux/capability.h>
> #include <linux/cred.h>
> @@ -1738,6 +1740,62 @@ xfs_ioc_scrub_metadata(
> return 0;
> }
>
> +/*
> + * IOCTL routine to get the parent pointer of an inode and return it to user
> + * space. Caller must pass an struct xfs_parent_name_irec with a name buffer
> + * large enough to hold the file name. Returns 0 on success or non-zero on
> + * failure
> + */
xfs_parent_name_irec should be xfs_pptr_info
> +STATIC int
> +xfs_ioc_get_parent_pointer(
> + struct file *filp,
> + void __user *arg)
> +{
> + struct xfs_inode *ip;
> + struct xfs_pptr_info *ppi;
> + struct dentry *dentry;
> + int error = 0;
> +
> + /* Allocate an xfs_pptr_info to put the user data */
> + ppi = kmem_alloc(sizeof(struct xfs_pptr_info), KM_SLEEP);
> + if (!ppi)
> + return -ENOMEM;
> +
> + /* Copy the data from the user */
> + copy_from_user(ppi, arg, sizeof(struct xfs_pptr_info));
> +
> + /*
> + * Now that we know how big the trailing buffer is, expand
> + * our kernel xfs_pptr_info to be the same size
> + */
> + ppi = kmem_realloc(ppi, XFS_PPTR_INFO_SIZEOF(ppi->pi_ptrs_size),
> + KM_SLEEP);
> + if (!ppi)
> + return -ENOMEM;
> +
> + if (ppi->pi_flags == XFS_PPTR_IFLAG_HANDLE) {
> + dentry = xfs_handle_to_dentry(filp, &ppi->pi_handle,
> + sizeof(struct xfs_handle));
> + if (IS_ERR(dentry))
> + return PTR_ERR(dentry);
> + ip = XFS_I(d_inode(dentry));
> + } else
> + ip = XFS_I(file_inode(filp));
> +
> + /* Get the parent pointers */
> + error = xfs_attr_get_parent_pointer(ip, ppi);
> +
> + if (error)
> + goto out;
> +
> + /* Copy the parent pointers back to the user */
> + copy_to_user(arg, ppi, XFS_PPTR_INFO_SIZEOF(ppi->pi_ptrs_size));
> +
> +out:
> + kmem_free(ppi);
> + return error;
> +}
> +
> int
> xfs_ioc_swapext(
> xfs_swapext_t *sxp)
> @@ -1894,7 +1952,8 @@ xfs_file_ioctl(
> return xfs_ioc_getxflags(ip, arg);
> case XFS_IOC_SETXFLAGS:
> return xfs_ioc_setxflags(ip, filp, arg);
> -
> + case XFS_IOC_GETPPOINTER:
> + return xfs_ioc_get_parent_pointer(filp, arg);
> case XFS_IOC_FSSETDM: {
> struct fsdmidata dmi;
>
> diff --git a/fs/xfs/xfs_parent_utils.c b/fs/xfs/xfs_parent_utils.c
> index 0fd48b8..1df003a 100644
> --- a/fs/xfs/xfs_parent_utils.c
> +++ b/fs/xfs/xfs_parent_utils.c
> @@ -68,3 +68,69 @@ xfs_parent_remove_deferred(
> ATTR_PARENT);
> }
>
> +/*
> + * Get the parent pointers for a given inode
> + *
> + * Returns 0 on success and non zero on error
> + */
> +int
> +xfs_attr_get_parent_pointer(struct xfs_inode *ip,
> + struct xfs_pptr_info *ppi)
> +
> +{
> +
> + struct attrlist *alist;
> + struct attrlist_ent *aent;
> + struct xfs_parent_ptr *xpp;
> + struct xfs_parent_name_rec *xpnr;
> + char *namebuf;
> + unsigned int namebuf_size;
> + int name_len;
> + int error = 0;
> + unsigned int flags = ATTR_PARENT;
> + int i;
> +
> + /* Allocate a buffer to store the attribute names */
> + namebuf_size = sizeof(struct attrlist) +
> + (ppi->pi_ptrs_size) * sizeof(struct attrlist_ent);
> + namebuf = kmem_zalloc_large(namebuf_size, KM_SLEEP);
> + if (!namebuf)
> + return -ENOMEM;
> +
> + error = xfs_attr_list(ip, namebuf, namebuf_size, flags,
> + (attrlist_cursor_kern_t *)&ppi->pi_cursor);
> + if (error)
> + goto out_kfree;
> +
> + alist = (struct attrlist *)namebuf;
> +
> + for (i = 0; i < alist->al_count; i++) {
> + xpp = XFS_PPINFO_TO_PP(ppi, i);
> + memset(xpp, 0, sizeof(struct xfs_parent_ptr));
> + aent = (struct attrlist_ent *) &namebuf[alist->al_offset[i]];
> + xpnr = (struct xfs_parent_name_rec *)(aent->a_name);
> +
> + if (aent->a_valuelen > XFS_PPTR_MAXNAMELEN) {
> + error = -ERANGE;
> + goto out_kfree;
> + }
> +
> + name_len = aent->a_valuelen;
> + error = xfs_attr_get(ip, (char *)xpnr,
> + sizeof(struct xfs_parent_name_rec),
> + (unsigned char *)(xpp->xpp_name),
> + &name_len, flags);
> + if (error)
> + goto out_kfree;
> +
> + xpp->xpp_namelen = name_len;
> + xfs_init_parent_ptr(xpp, xpnr);
> + }
> + ppi->pi_ptrs_used = alist->al_count;
> +
> +out_kfree:
> + kmem_free(namebuf);
> +
> + return error;
> +}
> +
> diff --git a/fs/xfs/xfs_parent_utils.h b/fs/xfs/xfs_parent_utils.h
> index 9e0ac13..33e3b2c 100644
> --- a/fs/xfs/xfs_parent_utils.h
> +++ b/fs/xfs/xfs_parent_utils.h
> @@ -27,4 +27,6 @@ int xfs_parent_remove_deferred(struct xfs_inode *parent,
> struct xfs_inode *child,
> xfs_dir2_dataptr_t diroffset,
> struct xfs_defer_ops *dfops);
> +int xfs_attr_get_parent_pointer(struct xfs_inode *ip,
> + struct xfs_pptr_info *ppi);
> #endif /* __XFS_PARENT_UTILS_H__ */
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 20/21] xfs: Add parent pointer ioctl
2018-05-15 16:27 ` Catalin Iacob
@ 2018-05-15 16:52 ` Allison Henderson
0 siblings, 0 replies; 72+ messages in thread
From: Allison Henderson @ 2018-05-15 16:52 UTC (permalink / raw)
To: Catalin Iacob; +Cc: linux-xfs
Thanks Catalin! I will add your feedback to my notes and get them fixed
on the next set. Thx for the review!
Allison
On 05/15/2018 09:27 AM, Catalin Iacob wrote:
> On Sun, May 6, 2018 at 7:24 PM, Allison Henderson
> <allison.henderson@oracle.com> wrote:
>> This patch adds a new file ioctl to retrieve the parent
>> pointer of a given inode
>
> Looking through the patch I spotted some typos and use of outdated
> names in comments.
>
>> +#define XFS_PPTR_MAXNAMELEN 255
>> +
>> +/* return parents of the handle, not the open fd */
>> +#define XFS_PPTR_IFLAG_HANDLE (1U << 0)
>> +
>> +/* Get an inode parent pointer through ioctl */
>> +struct xfs_parent_ptr {
>> + __u64 xpp_ino; /* Inode */
>> + __u32 xpp_gen; /* Inode generation */
>> + __u32 xpp_diroffset; /* Directory offset */
>> + __u32 xpp_namelen; /* File name length */
>> + __u8 xpp_name[XFS_PPTR_MAXNAMELEN]; /* File name */
>> +};
>> +
>> +/* Iterate though an inodes parent pointers */
>
> typo through
>
>> +struct xfs_pptr_info {
>> + struct xfs_handle pi_handle;
>> + struct xfs_attrlist_cursor pi_cursor;
>> + __u32 pi_flags;
>> + __u32 pi_reserved;
>> + __u32 pi_ptrs_size;
>> + __u32 pi_ptrs_used;
>> + __u64 pi_reserved2[6];
>> +
>> + /*
>> + * An array of struct xfs_pptr follows the header
>
> Should be struct xfs_parent_ptr
>
>> + * information. Use XFS_PPINFO_TO_PP() to access the
>> + * parent pointer array entries.
>> + */
>> +};
>> +
>> +#define XFS_PPTR_INFO_SIZEOF(nr_ptrs) sizeof (struct xfs_pptr_info) + \
>> + nr_ptrs * sizeof(struct xfs_parent_ptr)
>> +
>> +#define XFS_PPINFO_TO_PP(info, idx) \
>> + (&(((struct xfs_parent_ptr *)((char *)(info) + sizeof(*(info))))[(idx)]))
>> +
>> /*
>> * ioctl limits
>> */
>> @@ -596,6 +633,7 @@ struct xfs_scrub_metadata {
>> #define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_fs_eofblocks)
>> /* XFS_IOC_GETFSMAP ------ hoisted 59 */
>> #define XFS_IOC_SCRUB_METADATA _IOWR('X', 60, struct xfs_scrub_metadata)
>> +#define XFS_IOC_GETPPOINTER _IOR ('X', 61, struct xfs_parent_ptr)
>>
>> /*
>> * ioctl commands that replace IRIX syssgi()'s
>> diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c
>> index e6de97c..61f1961 100644
>> --- a/fs/xfs/libxfs/xfs_parent.c
>> +++ b/fs/xfs/libxfs/xfs_parent.c
>> @@ -32,6 +32,16 @@
>> #include "xfs_attr_sf.h"
>> #include "xfs_bmap.h"
>>
>> +/* Initializes a xfs_parent_ptr from an xfs_parent_name_rec */
>> +void
>> +xfs_init_parent_ptr(struct xfs_parent_ptr *xpp,
>> + struct xfs_parent_name_rec *rec)
>> +{
>> + xpp->xpp_ino = be64_to_cpu(rec->p_ino);
>> + xpp->xpp_gen = be32_to_cpu(rec->p_gen);
>> + xpp->xpp_diroffset = be32_to_cpu(rec->p_diroffset);
>> +}
>> +
>> /*
>> * Parent pointer attribute handling.
>> *
>> diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h
>> index 298562b..1a321db 100644
>> --- a/fs/xfs/libxfs/xfs_parent.h
>> +++ b/fs/xfs/libxfs/xfs_parent.h
>> @@ -33,4 +33,6 @@ int xfs_parent_add(struct xfs_trans *tp, struct xfs_inode *parent,
>> struct xfs_inode *child, struct xfs_name *child_name,
>> uint32_t diroffset, xfs_fsblock_t *firstblock,
>> struct xfs_defer_ops *dfops);
>> +void xfs_init_parent_ptr(struct xfs_parent_ptr *xpp,
>> + struct xfs_parent_name_rec *rec);
>> #endif /* __XFS_PARENT_H__ */
>> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
>> index 3e59a34..bdbe9fb 100644
>> --- a/fs/xfs/xfs_attr_list.c
>> +++ b/fs/xfs/xfs_attr_list.c
>> @@ -581,6 +581,9 @@ xfs_attr_put_listent(
>> if (((context->flags & ATTR_ROOT) == 0) !=
>> ((flags & XFS_ATTR_ROOT) == 0))
>> return;
>> + if (((context->flags & ATTR_PARENT) == 0) !=
>> + ((flags & XFS_ATTR_PARENT) == 0))
>> + return;
>>
>> arraytop = sizeof(*alist) +
>> context->count * sizeof(alist->al_offset[0]);
>> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
>> index 844480a..ee544f2 100644
>> --- a/fs/xfs/xfs_ioctl.c
>> +++ b/fs/xfs/xfs_ioctl.c
>> @@ -46,6 +46,8 @@
>> #include "xfs_fsmap.h"
>> #include "scrub/xfs_scrub.h"
>> #include "xfs_sb.h"
>> +#include "xfs_da_format.h"
>> +#include "xfs_parent_utils.h"
>>
>> #include <linux/capability.h>
>> #include <linux/cred.h>
>> @@ -1738,6 +1740,62 @@ xfs_ioc_scrub_metadata(
>> return 0;
>> }
>>
>> +/*
>> + * IOCTL routine to get the parent pointer of an inode and return it to user
>> + * space. Caller must pass an struct xfs_parent_name_irec with a name buffer
>> + * large enough to hold the file name. Returns 0 on success or non-zero on
>> + * failure
>> + */
>
> xfs_parent_name_irec should be xfs_pptr_info
>
>> +STATIC int
>> +xfs_ioc_get_parent_pointer(
>> + struct file *filp,
>> + void __user *arg)
>> +{
>> + struct xfs_inode *ip;
>> + struct xfs_pptr_info *ppi;
>> + struct dentry *dentry;
>> + int error = 0;
>> +
>> + /* Allocate an xfs_pptr_info to put the user data */
>> + ppi = kmem_alloc(sizeof(struct xfs_pptr_info), KM_SLEEP);
>> + if (!ppi)
>> + return -ENOMEM;
>> +
>> + /* Copy the data from the user */
>> + copy_from_user(ppi, arg, sizeof(struct xfs_pptr_info));
>> +
>> + /*
>> + * Now that we know how big the trailing buffer is, expand
>> + * our kernel xfs_pptr_info to be the same size
>> + */
>> + ppi = kmem_realloc(ppi, XFS_PPTR_INFO_SIZEOF(ppi->pi_ptrs_size),
>> + KM_SLEEP);
>> + if (!ppi)
>> + return -ENOMEM;
>> +
>> + if (ppi->pi_flags == XFS_PPTR_IFLAG_HANDLE) {
>> + dentry = xfs_handle_to_dentry(filp, &ppi->pi_handle,
>> + sizeof(struct xfs_handle));
>> + if (IS_ERR(dentry))
>> + return PTR_ERR(dentry);
>> + ip = XFS_I(d_inode(dentry));
>> + } else
>> + ip = XFS_I(file_inode(filp));
>> +
>> + /* Get the parent pointers */
>> + error = xfs_attr_get_parent_pointer(ip, ppi);
>> +
>> + if (error)
>> + goto out;
>> +
>> + /* Copy the parent pointers back to the user */
>> + copy_to_user(arg, ppi, XFS_PPTR_INFO_SIZEOF(ppi->pi_ptrs_size));
>> +
>> +out:
>> + kmem_free(ppi);
>> + return error;
>> +}
>> +
>> int
>> xfs_ioc_swapext(
>> xfs_swapext_t *sxp)
>> @@ -1894,7 +1952,8 @@ xfs_file_ioctl(
>> return xfs_ioc_getxflags(ip, arg);
>> case XFS_IOC_SETXFLAGS:
>> return xfs_ioc_setxflags(ip, filp, arg);
>> -
>> + case XFS_IOC_GETPPOINTER:
>> + return xfs_ioc_get_parent_pointer(filp, arg);
>> case XFS_IOC_FSSETDM: {
>> struct fsdmidata dmi;
>>
>> diff --git a/fs/xfs/xfs_parent_utils.c b/fs/xfs/xfs_parent_utils.c
>> index 0fd48b8..1df003a 100644
>> --- a/fs/xfs/xfs_parent_utils.c
>> +++ b/fs/xfs/xfs_parent_utils.c
>> @@ -68,3 +68,69 @@ xfs_parent_remove_deferred(
>> ATTR_PARENT);
>> }
>>
>> +/*
>> + * Get the parent pointers for a given inode
>> + *
>> + * Returns 0 on success and non zero on error
>> + */
>> +int
>> +xfs_attr_get_parent_pointer(struct xfs_inode *ip,
>> + struct xfs_pptr_info *ppi)
>> +
>> +{
>> +
>> + struct attrlist *alist;
>> + struct attrlist_ent *aent;
>> + struct xfs_parent_ptr *xpp;
>> + struct xfs_parent_name_rec *xpnr;
>> + char *namebuf;
>> + unsigned int namebuf_size;
>> + int name_len;
>> + int error = 0;
>> + unsigned int flags = ATTR_PARENT;
>> + int i;
>> +
>> + /* Allocate a buffer to store the attribute names */
>> + namebuf_size = sizeof(struct attrlist) +
>> + (ppi->pi_ptrs_size) * sizeof(struct attrlist_ent);
>> + namebuf = kmem_zalloc_large(namebuf_size, KM_SLEEP);
>> + if (!namebuf)
>> + return -ENOMEM;
>> +
>> + error = xfs_attr_list(ip, namebuf, namebuf_size, flags,
>> + (attrlist_cursor_kern_t *)&ppi->pi_cursor);
>> + if (error)
>> + goto out_kfree;
>> +
>> + alist = (struct attrlist *)namebuf;
>> +
>> + for (i = 0; i < alist->al_count; i++) {
>> + xpp = XFS_PPINFO_TO_PP(ppi, i);
>> + memset(xpp, 0, sizeof(struct xfs_parent_ptr));
>> + aent = (struct attrlist_ent *) &namebuf[alist->al_offset[i]];
>> + xpnr = (struct xfs_parent_name_rec *)(aent->a_name);
>> +
>> + if (aent->a_valuelen > XFS_PPTR_MAXNAMELEN) {
>> + error = -ERANGE;
>> + goto out_kfree;
>> + }
>> +
>> + name_len = aent->a_valuelen;
>> + error = xfs_attr_get(ip, (char *)xpnr,
>> + sizeof(struct xfs_parent_name_rec),
>> + (unsigned char *)(xpp->xpp_name),
>> + &name_len, flags);
>> + if (error)
>> + goto out_kfree;
>> +
>> + xpp->xpp_namelen = name_len;
>> + xfs_init_parent_ptr(xpp, xpnr);
>> + }
>> + ppi->pi_ptrs_used = alist->al_count;
>> +
>> +out_kfree:
>> + kmem_free(namebuf);
>> +
>> + return error;
>> +}
>> +
>> diff --git a/fs/xfs/xfs_parent_utils.h b/fs/xfs/xfs_parent_utils.h
>> index 9e0ac13..33e3b2c 100644
>> --- a/fs/xfs/xfs_parent_utils.h
>> +++ b/fs/xfs/xfs_parent_utils.h
>> @@ -27,4 +27,6 @@ int xfs_parent_remove_deferred(struct xfs_inode *parent,
>> struct xfs_inode *child,
>> xfs_dir2_dataptr_t diroffset,
>> struct xfs_defer_ops *dfops);
>> +int xfs_attr_get_parent_pointer(struct xfs_inode *ip,
>> + struct xfs_pptr_info *ppi);
>> #endif /* __XFS_PARENT_UTILS_H__ */
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at https://urldefense.proofpoint.com/v2/url?u=http-3A__vger.kernel.org_majordomo-2Dinfo.html&d=DwIBaQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=LHZQ8fHvy6wDKXGTWcm97burZH5sQKHRDMaY1UthQxc&m=rT6fqylaLIZODivKoMiqJLy1rQ9Q4ekQDl23WaFRLK8&s=6bEV7cBMtfEELKOavGTkkBQnwjhxRJ5WeXRtY8o1SDc&e=
^ permalink raw reply [flat|nested] 72+ messages in thread
end of thread, other threads:[~2018-05-15 16:52 UTC | newest]
Thread overview: 72+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-06 17:24 [PATCH 00/21] Parent Pointers v6 Allison Henderson
2018-05-06 17:24 ` [PATCH 01/21] xfs: Move fs/xfs/xfs_attr.h to fs/xfs/libxfs/xfs_attr.h Allison Henderson
2018-05-07 23:39 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 02/21] Add trans toggle to attr routines Allison Henderson
2018-05-07 23:52 ` Darrick J. Wong
2018-05-08 17:04 ` Allison Henderson
2018-05-06 17:24 ` [PATCH 03/21] xfs: Add attibute set and helper functions Allison Henderson
2018-05-07 23:36 ` Darrick J. Wong
2018-05-08 7:25 ` Amir Goldstein
2018-05-08 17:02 ` Allison Henderson
2018-05-08 17:01 ` Allison Henderson
2018-05-06 17:24 ` [PATCH 04/21] xfs: Add attibute remove " Allison Henderson
2018-05-07 23:21 ` Darrick J. Wong
2018-05-08 7:33 ` Amir Goldstein
2018-05-08 17:02 ` Allison Henderson
2018-05-08 17:14 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 05/21] xfs: Set up infastructure for deferred attribute operations Allison Henderson
2018-05-07 23:19 ` Darrick J. Wong
2018-05-08 17:01 ` Allison Henderson
2018-05-08 9:55 ` Amir Goldstein
2018-05-06 17:24 ` [PATCH 06/21] xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred Allison Henderson
2018-05-07 22:59 ` Darrick J. Wong
2018-05-08 17:01 ` Allison Henderson
2018-05-06 17:24 ` [PATCH 07/21] xfs: Remove all strlen calls in all xfs_attr_* functions for attr names Allison Henderson
2018-05-07 22:54 ` Darrick J. Wong
2018-05-08 17:00 ` Allison Henderson
2018-05-06 17:24 ` [PATCH 08/21] xfs: get directory offset when adding directory name Allison Henderson
2018-05-07 22:50 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 09/21] xfs: get directory offset when removing " Allison Henderson
2018-05-07 22:48 ` Darrick J. Wong
2018-05-08 17:00 ` Allison Henderson
2018-05-06 17:24 ` [PATCH 10/21] xfs: get directory offset when replacing a " Allison Henderson
2018-05-07 22:45 ` Darrick J. Wong
2018-05-08 17:00 ` Allison Henderson
2018-05-06 17:24 ` [PATCH 11/21] xfs: add parent pointer support to attribute code Allison Henderson
2018-05-07 22:36 ` Darrick J. Wong
2018-05-06 17:24 ` [PATCH 12/21] xfs: define parent pointer xattr format Allison Henderson
2018-05-07 22:35 ` Darrick J. Wong
2018-05-08 17:00 ` Allison Henderson
2018-05-06 17:24 ` [PATCH 13/21] xfs: extent transaction reservations for parent attributes Allison Henderson
2018-05-07 22:34 ` Darrick J. Wong
2018-05-08 17:00 ` Allison Henderson
2018-05-06 17:24 ` [PATCH 14/21] Add lock_flags to xfs_ialloc and xfs_dir_ialloc Allison Henderson
2018-05-07 22:30 ` Darrick J. Wong
2018-05-08 16:59 ` Allison Henderson
2018-05-06 17:24 ` [PATCH 15/21] xfs: parent pointer attribute creation Allison Henderson
2018-05-07 22:19 ` Darrick J. Wong
2018-05-08 16:58 ` Allison Henderson
2018-05-06 17:24 ` [PATCH 16/21] xfs: add parent attributes to link Allison Henderson
2018-05-07 22:12 ` Darrick J. Wong
2018-05-08 16:58 ` Allison Henderson
2018-05-06 17:24 ` [PATCH 17/21] xfs: remove parent pointers in unlink Allison Henderson
2018-05-07 21:59 ` Darrick J. Wong
2018-05-08 16:58 ` Allison Henderson
2018-05-06 17:24 ` [PATCH 18/21] xfs: Add parent pointers to rename Allison Henderson
2018-05-07 21:52 ` Darrick J. Wong
2018-05-08 16:58 ` Allison Henderson
2018-05-08 10:04 ` Amir Goldstein
2018-05-06 17:24 ` [PATCH 19/21] xfs: Add the parent pointer support to the superblock version 5 Allison Henderson
2018-05-07 21:38 ` Darrick J. Wong
2018-05-08 16:58 ` Allison Henderson
2018-05-06 17:24 ` [PATCH 20/21] xfs: Add parent pointer ioctl Allison Henderson
2018-05-07 21:36 ` Darrick J. Wong
2018-05-08 10:24 ` Amir Goldstein
2018-05-08 10:25 ` Amir Goldstein
2018-05-08 16:57 ` Allison Henderson
2018-05-15 16:27 ` Catalin Iacob
2018-05-15 16:52 ` Allison Henderson
2018-05-06 17:24 ` [PATCH 21/21] xfs: Add delayed attributes error tag Allison Henderson
2018-05-07 20:57 ` Darrick J. Wong
2018-05-08 5:36 ` [PATCH 00/21] Parent Pointers v6 Amir Goldstein
2018-05-08 17:03 ` Allison Henderson
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.