aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2015-10-12 00:40:24 -0400
committerDave Chinner <david@fromorbit.com>2015-10-12 00:40:24 -0400
commitb7cdc66be54b64daef593894d12ecc405f117829 (patch)
treeb0f6c6ee7bc6123f2e0a9ea9ac6d1de7634cf77b /fs
parent1f93e4a96c9109378204c147b3eec0d0e8100fde (diff)
xfs: log local to remote symlink conversions correctly on v5 supers
A local format symlink inode is converted to extent format when an extended attribute is set on an inode as part of the attribute fork creation. This means a block is allocated, the local symlink target name is copied to the block and the block is logged. Currently, xfs_bmap_local_to_extents() handles logging the remote block data based on the size of the data fork prior to the conversion. This is not correct on v5 superblock filesystems, which add an additional header to remote symlink blocks that is nonexistent in local format inodes. As a result, the full length of the remote symlink block content is not logged. This can lead to corruption should a crash occur and log recovery replay this transaction. Since a callout is already used to initialize the new remote symlink block, update the local-to-extents conversion mechanism to make the callout also responsible for logging the block. It is already required to set the log buffer type and format the block appropriately based on the superblock version. This ensures the remote symlink is always logged correctly. Note that xfs_bmap_local_to_extents() is only called for symlinks so there are no other callouts that require modification. Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/libxfs/xfs_bmap.c10
-rw-r--r--fs/xfs/libxfs/xfs_symlink_remote.c3
2 files changed, 9 insertions, 4 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 8e2010d53b07..b5cb61ecd5bb 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -948,14 +948,16 @@ xfs_bmap_local_to_extents(
948 bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0); 948 bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
949 949
950 /* 950 /*
951 * Initialise the block and copy the data 951 * Initialize the block, copy the data and log the remote buffer.
952 * 952 *
953 * Note: init_fn must set the buffer log item type correctly! 953 * The callout is responsible for logging because the remote format
954 * might differ from the local format and thus we don't know how much to
955 * log here. Note that init_fn must also set the buffer log item type
956 * correctly.
954 */ 957 */
955 init_fn(tp, bp, ip, ifp); 958 init_fn(tp, bp, ip, ifp);
956 959
957 /* account for the change in fork size and log everything */ 960 /* account for the change in fork size */
958 xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
959 xfs_idata_realloc(ip, -ifp->if_bytes, whichfork); 961 xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
960 xfs_bmap_local_to_extents_empty(ip, whichfork); 962 xfs_bmap_local_to_extents_empty(ip, whichfork);
961 flags |= XFS_ILOG_CORE; 963 flags |= XFS_ILOG_CORE;
diff --git a/fs/xfs/libxfs/xfs_symlink_remote.c b/fs/xfs/libxfs/xfs_symlink_remote.c
index 8f8af05b3f13..b9884aab46d3 100644
--- a/fs/xfs/libxfs/xfs_symlink_remote.c
+++ b/fs/xfs/libxfs/xfs_symlink_remote.c
@@ -183,6 +183,7 @@ xfs_symlink_local_to_remote(
183 if (!xfs_sb_version_hascrc(&mp->m_sb)) { 183 if (!xfs_sb_version_hascrc(&mp->m_sb)) {
184 bp->b_ops = NULL; 184 bp->b_ops = NULL;
185 memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes); 185 memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
186 xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
186 return; 187 return;
187 } 188 }
188 189
@@ -198,4 +199,6 @@ xfs_symlink_local_to_remote(
198 buf = bp->b_addr; 199 buf = bp->b_addr;
199 buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp); 200 buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp);
200 memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes); 201 memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes);
202 xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) +
203 ifp->if_bytes - 1);
201} 204}