xfs: record inode generation in xattr update log intent items
authorDarrick J. Wong <djwong@kernel.org>
Mon, 22 Apr 2024 16:47:43 +0000 (09:47 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 23 Apr 2024 14:46:57 +0000 (07:46 -0700)
For parent pointer updates, record the i_generation of the file that is
being updated so that we don't accidentally jump generations.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/libxfs/xfs_log_format.h
fs/xfs/xfs_attr_item.c

index 632dd97324557a04d69042d452be230d41a49c82..3e6682ed656b30b8d9189324cc8a57735b9c318d 100644 (file)
@@ -1049,7 +1049,7 @@ struct xfs_icreate_log {
 struct xfs_attri_log_format {
        uint16_t        alfi_type;      /* attri log item type */
        uint16_t        alfi_size;      /* size of this item */
-       uint32_t        __pad;          /* pad to 64 bit aligned */
+       uint32_t        alfi_igen;      /* generation of alfi_ino for pptr ops */
        uint64_t        alfi_id;        /* attri identifier */
        uint64_t        alfi_ino;       /* the inode for this attr operation */
        uint32_t        alfi_op_flags;  /* marks the op as a set or remove */
index be5064f5a5315a750b748630667d2477b634d1b1..2898eeb16366e30f93564960b470a5b790ee20ff 100644 (file)
@@ -388,9 +388,14 @@ xfs_attr_log_item(
        case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:
                ASSERT(nv->value.i_len == nv->new_value.i_len);
 
+               attrp->alfi_igen = VFS_I(args->dp)->i_generation;
                attrp->alfi_old_name_len = nv->name.i_len;
                attrp->alfi_new_name_len = nv->new_name.i_len;
                break;
+       case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:
+       case XFS_ATTRI_OP_FLAGS_PPTR_SET:
+               attrp->alfi_igen = VFS_I(args->dp)->i_generation;
+               fallthrough;
        default:
                attrp->alfi_name_len = nv->name.i_len;
                break;
@@ -545,9 +550,6 @@ xfs_attri_validate(
 {
        unsigned int                    op = xfs_attr_log_item_op(attrp);
 
-       if (attrp->__pad != 0)
-               return false;
-
        if (attrp->alfi_op_flags & ~XFS_ATTRI_OP_FLAGS_TYPE_MASK)
                return false;
 
@@ -639,9 +641,27 @@ xfs_attri_recover_work(
        int                             local;
        int                             error;
 
-       error = xlog_recover_iget(mp,  attrp->alfi_ino, &ip);
-       if (error)
-               return ERR_PTR(error);
+       /*
+        * Parent pointer attr items record the generation but regular logged
+        * xattrs do not; select the right iget function.
+        */
+       switch (xfs_attr_log_item_op(attrp)) {
+       case XFS_ATTRI_OP_FLAGS_PPTR_SET:
+       case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:
+       case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:
+               error = xlog_recover_iget_handle(mp, attrp->alfi_ino,
+                               attrp->alfi_igen, &ip);
+               break;
+       default:
+               error = xlog_recover_iget(mp, attrp->alfi_ino, &ip);
+               break;
+       }
+       if (error) {
+               xfs_irele(ip);
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, attrp,
+                               sizeof(*attrp));
+               return ERR_PTR(-EFSCORRUPTED);
+       }
 
        if (xfs_inode_has_attr_fork(ip)) {
                error = xfs_attri_iread_extents(ip);
@@ -793,6 +813,7 @@ xfs_attr_relog_intent(
        new_attrp = &new_attrip->attri_format;
 
        new_attrp->alfi_ino = old_attrp->alfi_ino;
+       new_attrp->alfi_igen = old_attrp->alfi_igen;
        new_attrp->alfi_op_flags = old_attrp->alfi_op_flags;
        new_attrp->alfi_value_len = old_attrp->alfi_value_len;