|
@@ -159,11 +159,10 @@ xfs_attr3_rmt_write_verify(
|
|
struct xfs_buf *bp)
|
|
struct xfs_buf *bp)
|
|
{
|
|
{
|
|
struct xfs_mount *mp = bp->b_target->bt_mount;
|
|
struct xfs_mount *mp = bp->b_target->bt_mount;
|
|
- struct xfs_buf_log_item *bip = bp->b_fspriv;
|
|
|
|
|
|
+ int blksize = mp->m_attr_geo->blksize;
|
|
char *ptr;
|
|
char *ptr;
|
|
int len;
|
|
int len;
|
|
xfs_daddr_t bno;
|
|
xfs_daddr_t bno;
|
|
- int blksize = mp->m_attr_geo->blksize;
|
|
|
|
|
|
|
|
/* no verification of non-crc buffers */
|
|
/* no verification of non-crc buffers */
|
|
if (!xfs_sb_version_hascrc(&mp->m_sb))
|
|
if (!xfs_sb_version_hascrc(&mp->m_sb))
|
|
@@ -175,16 +174,22 @@ xfs_attr3_rmt_write_verify(
|
|
ASSERT(len >= blksize);
|
|
ASSERT(len >= blksize);
|
|
|
|
|
|
while (len > 0) {
|
|
while (len > 0) {
|
|
|
|
+ struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr;
|
|
|
|
+
|
|
if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
|
|
if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
|
|
xfs_buf_ioerror(bp, -EFSCORRUPTED);
|
|
xfs_buf_ioerror(bp, -EFSCORRUPTED);
|
|
xfs_verifier_error(bp);
|
|
xfs_verifier_error(bp);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
- if (bip) {
|
|
|
|
- struct xfs_attr3_rmt_hdr *rmt;
|
|
|
|
|
|
|
|
- rmt = (struct xfs_attr3_rmt_hdr *)ptr;
|
|
|
|
- rmt->rm_lsn = cpu_to_be64(bip->bli_item.li_lsn);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Ensure we aren't writing bogus LSNs to disk. See
|
|
|
|
+ * xfs_attr3_rmt_hdr_set() for the explanation.
|
|
|
|
+ */
|
|
|
|
+ if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) {
|
|
|
|
+ xfs_buf_ioerror(bp, -EFSCORRUPTED);
|
|
|
|
+ xfs_verifier_error(bp);
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
|
|
xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
|
|
|
|
|
|
@@ -221,6 +226,18 @@ xfs_attr3_rmt_hdr_set(
|
|
rmt->rm_owner = cpu_to_be64(ino);
|
|
rmt->rm_owner = cpu_to_be64(ino);
|
|
rmt->rm_blkno = cpu_to_be64(bno);
|
|
rmt->rm_blkno = cpu_to_be64(bno);
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Remote attribute blocks are written synchronously, so we don't
|
|
|
|
+ * have an LSN that we can stamp in them that makes any sense to log
|
|
|
|
+ * recovery. To ensure that log recovery handles overwrites of these
|
|
|
|
+ * blocks sanely (i.e. once they've been freed and reallocated as some
|
|
|
|
+ * other type of metadata) we need to ensure that the LSN has a value
|
|
|
|
+ * that tells log recovery to ignore the LSN and overwrite the buffer
|
|
|
|
+ * with whatever is in it's log. To do this, we use the magic
|
|
|
|
+ * NULLCOMMITLSN to indicate that the LSN is invalid.
|
|
|
|
+ */
|
|
|
|
+ rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN);
|
|
|
|
+
|
|
return sizeof(struct xfs_attr3_rmt_hdr);
|
|
return sizeof(struct xfs_attr3_rmt_hdr);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -434,14 +451,21 @@ xfs_attr_rmtval_set(
|
|
|
|
|
|
/*
|
|
/*
|
|
* Allocate a single extent, up to the size of the value.
|
|
* Allocate a single extent, up to the size of the value.
|
|
|
|
+ *
|
|
|
|
+ * Note that we have to consider this a data allocation as we
|
|
|
|
+ * write the remote attribute without logging the contents.
|
|
|
|
+ * Hence we must ensure that we aren't using blocks that are on
|
|
|
|
+ * the busy list so that we don't overwrite blocks which have
|
|
|
|
+ * recently been freed but their transactions are not yet
|
|
|
|
+ * committed to disk. If we overwrite the contents of a busy
|
|
|
|
+ * extent and then crash then the block may not contain the
|
|
|
|
+ * correct metadata after log recovery occurs.
|
|
*/
|
|
*/
|
|
xfs_bmap_init(args->flist, args->firstblock);
|
|
xfs_bmap_init(args->flist, args->firstblock);
|
|
nmap = 1;
|
|
nmap = 1;
|
|
error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
|
|
error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
|
|
- blkcnt,
|
|
|
|
- XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
|
|
|
|
- args->firstblock, args->total, &map, &nmap,
|
|
|
|
- args->flist);
|
|
|
|
|
|
+ blkcnt, XFS_BMAPI_ATTRFORK, args->firstblock,
|
|
|
|
+ args->total, &map, &nmap, args->flist);
|
|
if (!error) {
|
|
if (!error) {
|
|
error = xfs_bmap_finish(&args->trans, args->flist,
|
|
error = xfs_bmap_finish(&args->trans, args->flist,
|
|
&committed);
|
|
&committed);
|