xfs: capture inode generation numbers in the ondisk exchmaps log item
authorDarrick J. Wong <djwong@kernel.org>
Mon, 15 Apr 2024 21:54:24 +0000 (14:54 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Mon, 15 Apr 2024 21:54:24 +0000 (14:54 -0700)
Per some very late review comments, capture the generation numbers of
both inodes involved in a file content exchange operation so that we
don't accidentally target files with have been reallocated.

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/libxfs/xfs_log_recover.h
fs/xfs/xfs_exchmaps_item.c
fs/xfs/xfs_log_recover.c

index 8dbe1f997dfd5d697437ad9d15c7ab68ca0098cd..accba2acd623df9ebdf4d080b56153d2300d007f 100644 (file)
@@ -896,6 +896,8 @@ struct xfs_xmi_log_format {
 
        uint64_t                xmi_inode1;     /* inumber of first file */
        uint64_t                xmi_inode2;     /* inumber of second file */
+       uint32_t                xmi_igen1;      /* generation of first file */
+       uint32_t                xmi_igen2;      /* generation of second file */
        uint64_t                xmi_startoff1;  /* block offset into file1 */
        uint64_t                xmi_startoff2;  /* block offset into file2 */
        uint64_t                xmi_blockcount; /* number of blocks */
index 47b758b49cb3522cdef967ab6caf4df3996212b4..521d327e4c89edf18dd5dba9ba42bb1af9b712b2 100644 (file)
@@ -123,6 +123,8 @@ bool xlog_is_buffer_cancelled(struct xlog *log, xfs_daddr_t blkno, uint len);
 
 int xlog_recover_iget(struct xfs_mount *mp, xfs_ino_t ino,
                struct xfs_inode **ipp);
+int xlog_recover_iget_handle(struct xfs_mount *mp, xfs_ino_t ino, uint32_t gen,
+               struct xfs_inode **ipp);
 void xlog_recover_release_intent(struct xlog *log, unsigned short intent_type,
                uint64_t intent_id);
 int xlog_alloc_buf_cancel_table(struct xlog *log);
index a40216f33214c6ce66f4e9995bca4e193b5a3089..264a121c5e16d2120705b4daa6173601146072ba 100644 (file)
@@ -231,7 +231,9 @@ xfs_exchmaps_create_intent(
        xlf = &xmi_lip->xmi_format;
 
        xlf->xmi_inode1 = xmi->xmi_ip1->i_ino;
+       xlf->xmi_igen1 = VFS_I(xmi->xmi_ip1)->i_generation;
        xlf->xmi_inode2 = xmi->xmi_ip2->i_ino;
+       xlf->xmi_igen2 = VFS_I(xmi->xmi_ip2)->i_generation;
        xlf->xmi_startoff1 = xmi->xmi_startoff1;
        xlf->xmi_startoff2 = xmi->xmi_startoff2;
        xlf->xmi_blockcount = xmi->xmi_blockcount;
@@ -368,14 +370,25 @@ xfs_xmi_item_recover_intent(
        /*
         * Grab both inodes and set IRECOVERY to prevent trimming of post-eof
         * mappings and freeing of unlinked inodes until we're totally done
-        * processing files.
+        * processing files.  The ondisk format of this new log item contains
+        * file handle information, which is why recovery for other items do
+        * not check the inode generation number.
         */
-       error = xlog_recover_iget(mp, xlf->xmi_inode1, &ip1);
-       if (error)
+       error = xlog_recover_iget_handle(mp, xlf->xmi_inode1, xlf->xmi_igen1,
+                       &ip1);
+       if (error) {
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, xlf,
+                               sizeof(*xlf));
                return ERR_PTR(error);
-       error = xlog_recover_iget(mp, xlf->xmi_inode2, &ip2);
-       if (error)
+       }
+
+       error = xlog_recover_iget_handle(mp, xlf->xmi_inode2, xlf->xmi_igen2,
+                       &ip2);
+       if (error) {
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, xlf,
+                               sizeof(*xlf));
                goto err_rele1;
+       }
 
        req->ip1 = ip1;
        req->ip2 = ip2;
@@ -485,6 +498,8 @@ xfs_exchmaps_relog_intent(
 
        new_xlf->xmi_inode1     = old_xlf->xmi_inode1;
        new_xlf->xmi_inode2     = old_xlf->xmi_inode2;
+       new_xlf->xmi_igen1      = old_xlf->xmi_igen1;
+       new_xlf->xmi_igen2      = old_xlf->xmi_igen2;
        new_xlf->xmi_startoff1  = old_xlf->xmi_startoff1;
        new_xlf->xmi_startoff2  = old_xlf->xmi_startoff2;
        new_xlf->xmi_blockcount = old_xlf->xmi_blockcount;
index 1e5ba95adf2c76cde764ba6cbe94d7cf5f7e00ce..b445e8ce4a7d21f2955603dcdc88b01f320ed662 100644 (file)
@@ -1767,6 +1767,37 @@ xlog_recover_iget(
        return 0;
 }
 
+/*
+ * Get an inode so that we can recover a log operation.
+ *
+ * Log intent items that target inodes effectively contain a file handle.
+ * Check that the generation number matches the intent item like we do for
+ * other file handles.  Log intent items defined after this validation weakness
+ * was identified must use this function.
+ */
+int
+xlog_recover_iget_handle(
+       struct xfs_mount        *mp,
+       xfs_ino_t               ino,
+       uint32_t                gen,
+       struct xfs_inode        **ipp)
+{
+       struct xfs_inode        *ip;
+       int                     error;
+
+       error = xlog_recover_iget(mp, ino, &ip);
+       if (error)
+               return error;
+
+       if (VFS_I(ip)->i_generation != gen) {
+               xfs_irele(ip);
+               return -EFSCORRUPTED;
+       }
+
+       *ipp = ip;
+       return 0;
+}
+
 /******************************************************************************
  *
  *             Log recover routines