@@ -252,6 +252,8 @@ xfs_attr_get_ilocked(
* If the attribute is found, but exceeds the size limit set by the caller in
* args->valuelen, return -ERANGE with the size of the attribute that was found
* in args->valuelen.
+ *
+ * Using XFS_DA_OP_BUFFER the caller have to release the buffer args->bp.
*/
int
xfs_attr_get(
@@ -270,7 +272,8 @@ xfs_attr_get(
args->hashval = xfs_da_hashname(args->name, args->namelen);
/* Entirely possible to look up a name which doesn't exist */
- args->op_flags = XFS_DA_OP_OKNOENT;
+ args->op_flags = XFS_DA_OP_OKNOENT |
+ (args->op_flags & XFS_DA_OP_BUFFER);
lock_mode = xfs_ilock_attr_map_shared(args->dp);
error = xfs_attr_get_ilocked(args);
@@ -2449,6 +2449,13 @@ xfs_attr3_leaf_getvalue(
name_loc = xfs_attr3_leaf_name_local(leaf, args->index);
ASSERT(name_loc->namelen == args->namelen);
ASSERT(memcmp(args->name, name_loc->nameval, args->namelen) == 0);
+
+ /* must be released by the caller */
+ if (args->op_flags & XFS_DA_OP_BUFFER) {
+ xfs_buf_hold(bp);
+ args->bp = bp;
+ }
+
return xfs_attr_copy_value(args,
&name_loc->nameval[args->namelen],
be16_to_cpu(name_loc->valuelen));
@@ -424,9 +424,18 @@ xfs_attr_rmtval_get(
error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
&offset, &valuelen,
&dst);
- xfs_buf_relse(bp);
- if (error)
+ xfs_buf_unlock(bp);
+ /* must be released by the caller */
+ if (args->op_flags & XFS_DA_OP_BUFFER)
+ args->bp = bp;
+ else
+ xfs_buf_rele(bp);
+
+ if (error) {
+ if (args->op_flags & XFS_DA_OP_BUFFER)
+ xfs_buf_rele(args->bp);
return error;
+ }
/* roll attribute extent map forwards */
lblkno += map[i].br_blockcount;
@@ -59,6 +59,7 @@ typedef struct xfs_da_args {
uint8_t filetype; /* filetype of inode for directories */
void *value; /* set of bytes (maybe contain NULLs) */
int valuelen; /* length of value */
+ struct xfs_buf *bp; /* OUT: xfs_buf which contains the attr */
unsigned int attr_filter; /* XFS_ATTR_{ROOT,SECURE,INCOMPLETE} */
unsigned int attr_flags; /* XATTR_{CREATE,REPLACE} */
xfs_dahash_t hashval; /* hash value of name */
@@ -93,6 +94,7 @@ typedef struct xfs_da_args {
#define XFS_DA_OP_REMOVE (1u << 6) /* this is a remove operation */
#define XFS_DA_OP_RECOVERY (1u << 7) /* Log recovery operation */
#define XFS_DA_OP_LOGGED (1u << 8) /* Use intent items to track op */
+#define XFS_DA_OP_BUFFER (1u << 9) /* Return underlying buffer */
#define XFS_DA_OP_FLAGS \
{ XFS_DA_OP_JUSTCHECK, "JUSTCHECK" }, \
@@ -103,7 +105,8 @@ typedef struct xfs_da_args {
{ XFS_DA_OP_NOTIME, "NOTIME" }, \
{ XFS_DA_OP_REMOVE, "REMOVE" }, \
{ XFS_DA_OP_RECOVERY, "RECOVERY" }, \
- { XFS_DA_OP_LOGGED, "LOGGED" }
+ { XFS_DA_OP_LOGGED, "LOGGED" }, \
+ { XFS_DA_OP_BUFFER, "BUFFER" }
/*
* Storage for holding state during Btree searches and split/join ops.
With XBF_VERITY_SEEN flag on xfs_buf XFS can track which buffers contain verified Merkle tree blocks. However, we also need to expose the buffer to pass a reference of underlying page to fs-verity. This patch adds XFS_DA_OP_BUFFER to tell xfs_attr_get() to xfs_buf_hold() underlying buffer and return it as xfs_da_args->bp. The caller must then xfs_buf_rele() the buffer. Therefore, XFS will hold a reference to xfs_buf till fs-verity is verifying xfs_buf's content. Signed-off-by: Andrey Albershteyn <aalbersh@redhat.com> --- fs/xfs/libxfs/xfs_attr.c | 5 ++++- fs/xfs/libxfs/xfs_attr_leaf.c | 7 +++++++ fs/xfs/libxfs/xfs_attr_remote.c | 13 +++++++++++-- fs/xfs/libxfs/xfs_da_btree.h | 5 ++++- 4 files changed, 26 insertions(+), 4 deletions(-)