Merge branch 'xfs-misc-fixes-3.17-2' into for-next

This commit is contained in:
Dave Chinner 2014-08-04 13:55:27 +10:00
commit 645f985721
16 changed files with 175 additions and 161 deletions

View File

@ -386,10 +386,11 @@ xfs_sb_quota_from_disk(struct xfs_sb *sbp)
} }
} }
void static void
xfs_sb_from_disk( __xfs_sb_from_disk(
struct xfs_sb *to, struct xfs_sb *to,
xfs_dsb_t *from) xfs_dsb_t *from,
bool convert_xquota)
{ {
to->sb_magicnum = be32_to_cpu(from->sb_magicnum); to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
to->sb_blocksize = be32_to_cpu(from->sb_blocksize); to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
@ -445,6 +446,17 @@ xfs_sb_from_disk(
to->sb_pad = 0; to->sb_pad = 0;
to->sb_pquotino = be64_to_cpu(from->sb_pquotino); to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
to->sb_lsn = be64_to_cpu(from->sb_lsn); to->sb_lsn = be64_to_cpu(from->sb_lsn);
/* Convert on-disk flags to in-memory flags? */
if (convert_xquota)
xfs_sb_quota_from_disk(to);
}
void
xfs_sb_from_disk(
struct xfs_sb *to,
xfs_dsb_t *from)
{
__xfs_sb_from_disk(to, from, true);
} }
static inline void static inline void
@ -577,7 +589,11 @@ xfs_sb_verify(
struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_mount *mp = bp->b_target->bt_mount;
struct xfs_sb sb; struct xfs_sb sb;
xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp)); /*
* Use call variant which doesn't convert quota flags from disk
* format, because xfs_mount_validate_sb checks the on-disk flags.
*/
__xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp), false);
/* /*
* Only check the in progress field for the primary superblock as * Only check the in progress field for the primary superblock as

View File

@ -809,7 +809,7 @@ xfs_can_free_eofblocks(struct xfs_inode *ip, bool force)
* have speculative prealloc/delalloc blocks to remove. * have speculative prealloc/delalloc blocks to remove.
*/ */
if (VFS_I(ip)->i_size == 0 && if (VFS_I(ip)->i_size == 0 &&
VN_CACHED(VFS_I(ip)) == 0 && VFS_I(ip)->i_mapping->nrpages == 0 &&
ip->i_delayed_blks == 0) ip->i_delayed_blks == 0)
return false; return false;
@ -1618,6 +1618,30 @@ xfs_swap_extents_check_format(
return 0; return 0;
} }
int
xfs_swap_extent_flush(
struct xfs_inode *ip)
{
int error;
error = filemap_write_and_wait(VFS_I(ip)->i_mapping);
if (error)
return error;
truncate_pagecache_range(VFS_I(ip), 0, -1);
/* Verify O_DIRECT for ftmp */
if (VFS_I(ip)->i_mapping->nrpages)
return -EINVAL;
/*
* Don't try to swap extents on mmap()d files because we can't lock
* out races against page faults safely.
*/
if (mapping_mapped(VFS_I(ip)->i_mapping))
return -EBUSY;
return 0;
}
int int
xfs_swap_extents( xfs_swap_extents(
xfs_inode_t *ip, /* target inode */ xfs_inode_t *ip, /* target inode */
@ -1633,6 +1657,7 @@ xfs_swap_extents(
int aforkblks = 0; int aforkblks = 0;
int taforkblks = 0; int taforkblks = 0;
__uint64_t tmp; __uint64_t tmp;
int lock_flags;
tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL); tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL);
if (!tempifp) { if (!tempifp) {
@ -1641,13 +1666,13 @@ xfs_swap_extents(
} }
/* /*
* we have to do two separate lock calls here to keep lockdep * Lock up the inodes against other IO and truncate to begin with.
* happy. If we try to get all the locks in one call, lock will * Then we can ensure the inodes are flushed and have no page cache
* report false positives when we drop the ILOCK and regain them * safely. Once we have done this we can take the ilocks and do the rest
* below. * of the checks.
*/ */
lock_flags = XFS_IOLOCK_EXCL;
xfs_lock_two_inodes(ip, tip, XFS_IOLOCK_EXCL); xfs_lock_two_inodes(ip, tip, XFS_IOLOCK_EXCL);
xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
/* Verify that both files have the same format */ /* Verify that both files have the same format */
if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) { if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) {
@ -1661,23 +1686,28 @@ xfs_swap_extents(
goto out_unlock; goto out_unlock;
} }
error = filemap_write_and_wait(VFS_I(tip)->i_mapping); error = xfs_swap_extent_flush(ip);
if (error)
goto out_unlock;
error = xfs_swap_extent_flush(tip);
if (error) if (error)
goto out_unlock; goto out_unlock;
truncate_pagecache_range(VFS_I(tip), 0, -1);
/* Verify O_DIRECT for ftmp */ tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT);
if (VN_CACHED(VFS_I(tip)) != 0) { error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
error = -EINVAL; if (error) {
xfs_trans_cancel(tp, 0);
goto out_unlock; goto out_unlock;
} }
xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
lock_flags |= XFS_ILOCK_EXCL;
/* Verify all data are being swapped */ /* Verify all data are being swapped */
if (sxp->sx_offset != 0 || if (sxp->sx_offset != 0 ||
sxp->sx_length != ip->i_d.di_size || sxp->sx_length != ip->i_d.di_size ||
sxp->sx_length != tip->i_d.di_size) { sxp->sx_length != tip->i_d.di_size) {
error = -EFAULT; error = -EFAULT;
goto out_unlock; goto out_trans_cancel;
} }
trace_xfs_swap_extent_before(ip, 0); trace_xfs_swap_extent_before(ip, 0);
@ -1689,7 +1719,7 @@ xfs_swap_extents(
xfs_notice(mp, xfs_notice(mp,
"%s: inode 0x%llx format is incompatible for exchanging.", "%s: inode 0x%llx format is incompatible for exchanging.",
__func__, ip->i_ino); __func__, ip->i_ino);
goto out_unlock; goto out_trans_cancel;
} }
/* /*
@ -1704,42 +1734,8 @@ xfs_swap_extents(
(sbp->bs_mtime.tv_sec != VFS_I(ip)->i_mtime.tv_sec) || (sbp->bs_mtime.tv_sec != VFS_I(ip)->i_mtime.tv_sec) ||
(sbp->bs_mtime.tv_nsec != VFS_I(ip)->i_mtime.tv_nsec)) { (sbp->bs_mtime.tv_nsec != VFS_I(ip)->i_mtime.tv_nsec)) {
error = -EBUSY; error = -EBUSY;
goto out_unlock; goto out_trans_cancel;
} }
/* We need to fail if the file is memory mapped. Once we have tossed
* all existing pages, the page fault will have no option
* but to go to the filesystem for pages. By making the page fault call
* vop_read (or write in the case of autogrow) they block on the iolock
* until we have switched the extents.
*/
if (VN_MAPPED(VFS_I(ip))) {
error = -EBUSY;
goto out_unlock;
}
xfs_iunlock(ip, XFS_ILOCK_EXCL);
xfs_iunlock(tip, XFS_ILOCK_EXCL);
/*
* There is a race condition here since we gave up the
* ilock. However, the data fork will not change since
* we have the iolock (locked for truncation too) so we
* are safe. We don't really care if non-io related
* fields change.
*/
truncate_pagecache_range(VFS_I(ip), 0, -1);
tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT);
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
if (error) {
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
xfs_iunlock(tip, XFS_IOLOCK_EXCL);
xfs_trans_cancel(tp, 0);
goto out;
}
xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
/* /*
* Count the number of extended attribute blocks * Count the number of extended attribute blocks
*/ */
@ -1757,8 +1753,8 @@ xfs_swap_extents(
goto out_trans_cancel; goto out_trans_cancel;
} }
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); xfs_trans_ijoin(tp, ip, lock_flags);
xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); xfs_trans_ijoin(tp, tip, lock_flags);
/* /*
* Before we've swapped the forks, lets set the owners of the forks * Before we've swapped the forks, lets set the owners of the forks
@ -1887,8 +1883,8 @@ out:
return error; return error;
out_unlock: out_unlock:
xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); xfs_iunlock(ip, lock_flags);
xfs_iunlock(tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); xfs_iunlock(tip, lock_flags);
goto out; goto out;
out_trans_cancel: out_trans_cancel:

View File

@ -1330,6 +1330,20 @@ _xfs_buf_ioapply(
SHUTDOWN_CORRUPT_INCORE); SHUTDOWN_CORRUPT_INCORE);
return; return;
} }
} else if (bp->b_bn != XFS_BUF_DADDR_NULL) {
struct xfs_mount *mp = bp->b_target->bt_mount;
/*
* non-crc filesystems don't attach verifiers during
* log recovery, so don't warn for such filesystems.
*/
if (xfs_sb_version_hascrc(&mp->m_sb)) {
xfs_warn(mp,
"%s: no ops on block 0x%llx/0x%x",
__func__, bp->b_bn, bp->b_length);
xfs_hex_dump(bp->b_addr, 64);
dump_stack();
}
} }
} else if (bp->b_flags & XBF_READ_AHEAD) { } else if (bp->b_flags & XBF_READ_AHEAD) {
rw = READA; rw = READA;

View File

@ -974,7 +974,8 @@ xfs_qm_dqflush(
* Get the buffer containing the on-disk dquot * Get the buffer containing the on-disk dquot
*/ */
error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dqp->q_blkno, error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dqp->q_blkno,
mp->m_quotainfo->qi_dqchunklen, 0, &bp, NULL); mp->m_quotainfo->qi_dqchunklen, 0, &bp,
&xfs_dquot_buf_ops);
if (error) if (error)
goto out_unlock; goto out_unlock;

View File

@ -247,11 +247,11 @@ xfs_file_read_iter(
XFS_STATS_INC(xs_read_calls); XFS_STATS_INC(xs_read_calls);
if (unlikely(file->f_flags & O_DIRECT)) if (unlikely(file->f_flags & O_DIRECT))
ioflags |= IO_ISDIRECT; ioflags |= XFS_IO_ISDIRECT;
if (file->f_mode & FMODE_NOCMTIME) if (file->f_mode & FMODE_NOCMTIME)
ioflags |= IO_INVIS; ioflags |= XFS_IO_INVIS;
if (unlikely(ioflags & IO_ISDIRECT)) { if (unlikely(ioflags & XFS_IO_ISDIRECT)) {
xfs_buftarg_t *target = xfs_buftarg_t *target =
XFS_IS_REALTIME_INODE(ip) ? XFS_IS_REALTIME_INODE(ip) ?
mp->m_rtdev_targp : mp->m_ddev_targp; mp->m_rtdev_targp : mp->m_ddev_targp;
@ -284,7 +284,7 @@ xfs_file_read_iter(
* proceeed concurrently without serialisation. * proceeed concurrently without serialisation.
*/ */
xfs_rw_ilock(ip, XFS_IOLOCK_SHARED); xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
if ((ioflags & IO_ISDIRECT) && inode->i_mapping->nrpages) { if ((ioflags & XFS_IO_ISDIRECT) && inode->i_mapping->nrpages) {
xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED); xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
xfs_rw_ilock(ip, XFS_IOLOCK_EXCL); xfs_rw_ilock(ip, XFS_IOLOCK_EXCL);
@ -326,7 +326,7 @@ xfs_file_splice_read(
XFS_STATS_INC(xs_read_calls); XFS_STATS_INC(xs_read_calls);
if (infilp->f_mode & FMODE_NOCMTIME) if (infilp->f_mode & FMODE_NOCMTIME)
ioflags |= IO_INVIS; ioflags |= XFS_IO_INVIS;
if (XFS_FORCED_SHUTDOWN(ip->i_mount)) if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return -EIO; return -EIO;

View File

@ -1635,7 +1635,7 @@ xfs_release(
truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED); truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED);
if (truncated) { if (truncated) {
xfs_iflags_clear(ip, XFS_IDIRTY_RELEASE); xfs_iflags_clear(ip, XFS_IDIRTY_RELEASE);
if (VN_DIRTY(VFS_I(ip)) && ip->i_delayed_blks > 0) { if (ip->i_delayed_blks > 0) {
error = filemap_flush(VFS_I(ip)->i_mapping); error = filemap_flush(VFS_I(ip)->i_mapping);
if (error) if (error)
return error; return error;

View File

@ -398,4 +398,14 @@ do { \
extern struct kmem_zone *xfs_inode_zone; extern struct kmem_zone *xfs_inode_zone;
/*
* Flags for read/write calls
*/
#define XFS_IO_ISDIRECT 0x00001 /* bypass page cache */
#define XFS_IO_INVIS 0x00002 /* don't update inode timestamps */
#define XFS_IO_FLAGS \
{ XFS_IO_ISDIRECT, "DIRECT" }, \
{ XFS_IO_INVIS, "INVIS"}
#endif /* __XFS_INODE_H__ */ #endif /* __XFS_INODE_H__ */

View File

@ -736,7 +736,7 @@ xfs_ioc_space(
xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
if (!(ioflags & IO_INVIS)) { if (!(ioflags & XFS_IO_INVIS)) {
ip->i_d.di_mode &= ~S_ISUID; ip->i_d.di_mode &= ~S_ISUID;
if (ip->i_d.di_mode & S_IXGRP) if (ip->i_d.di_mode & S_IXGRP)
ip->i_d.di_mode &= ~S_ISGID; ip->i_d.di_mode &= ~S_ISGID;
@ -1376,7 +1376,7 @@ xfs_ioc_getbmap(
return -EINVAL; return -EINVAL;
bmx.bmv_iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0); bmx.bmv_iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0);
if (ioflags & IO_INVIS) if (ioflags & XFS_IO_INVIS)
bmx.bmv_iflags |= BMV_IF_NO_DMAPI_READ; bmx.bmv_iflags |= BMV_IF_NO_DMAPI_READ;
error = xfs_getbmap(ip, &bmx, xfs_getbmap_format, error = xfs_getbmap(ip, &bmx, xfs_getbmap_format,
@ -1520,7 +1520,7 @@ xfs_file_ioctl(
int error; int error;
if (filp->f_mode & FMODE_NOCMTIME) if (filp->f_mode & FMODE_NOCMTIME)
ioflags |= IO_INVIS; ioflags |= XFS_IO_INVIS;
trace_xfs_file_ioctl(ip); trace_xfs_file_ioctl(ip);

View File

@ -28,7 +28,6 @@
#include "xfs_sb.h" #include "xfs_sb.h"
#include "xfs_ag.h" #include "xfs_ag.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_vnode.h"
#include "xfs_inode.h" #include "xfs_inode.h"
#include "xfs_itable.h" #include "xfs_itable.h"
#include "xfs_error.h" #include "xfs_error.h"
@ -537,7 +536,7 @@ xfs_file_compat_ioctl(
int error; int error;
if (filp->f_mode & FMODE_NOCMTIME) if (filp->f_mode & FMODE_NOCMTIME)
ioflags |= IO_INVIS; ioflags |= XFS_IO_INVIS;
trace_xfs_file_compat_ioctl(ip); trace_xfs_file_compat_ioctl(ip);

View File

@ -1055,12 +1055,12 @@ xfs_vn_fiemap(
return error; return error;
/* Set up bmap header for xfs internal routine */ /* Set up bmap header for xfs internal routine */
bm.bmv_offset = BTOBB(start); bm.bmv_offset = BTOBBT(start);
/* Special case for whole file */ /* Special case for whole file */
if (length == FIEMAP_MAX_OFFSET) if (length == FIEMAP_MAX_OFFSET)
bm.bmv_length = -1LL; bm.bmv_length = -1LL;
else else
bm.bmv_length = BTOBB(length); bm.bmv_length = BTOBB(start + length) - bm.bmv_offset;
/* We add one because in getbmap world count includes the header */ /* We add one because in getbmap world count includes the header */
bm.bmv_count = !fieinfo->fi_extents_max ? MAXEXTNUM : bm.bmv_count = !fieinfo->fi_extents_max ? MAXEXTNUM :

View File

@ -101,7 +101,7 @@ typedef __uint64_t __psunsigned_t;
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include "xfs_vnode.h" #include "xfs_fs.h"
#include "xfs_stats.h" #include "xfs_stats.h"
#include "xfs_sysctl.h" #include "xfs_sysctl.h"
#include "xfs_iops.h" #include "xfs_iops.h"

View File

@ -1378,8 +1378,14 @@ xlog_alloc_log(
xlog_get_iclog_buffer_size(mp, log); xlog_get_iclog_buffer_size(mp, log);
/*
* Use a NULL block for the extra log buffer used during splits so that
* it will trigger errors if we ever try to do IO on it without first
* having set it up properly.
*/
error = -ENOMEM; error = -ENOMEM;
bp = xfs_buf_alloc(mp->m_logdev_targp, 0, BTOBB(log->l_iclog_size), 0); bp = xfs_buf_alloc(mp->m_logdev_targp, XFS_BUF_DADDR_NULL,
BTOBB(log->l_iclog_size), 0);
if (!bp) if (!bp)
goto out_free_log; goto out_free_log;

View File

@ -2126,6 +2126,17 @@ xlog_recover_validate_buf_type(
__uint16_t magic16; __uint16_t magic16;
__uint16_t magicda; __uint16_t magicda;
/*
* We can only do post recovery validation on items on CRC enabled
* fielsystems as we need to know when the buffer was written to be able
* to determine if we should have replayed the item. If we replay old
* metadata over a newer buffer, then it will enter a temporarily
* inconsistent state resulting in verification failures. Hence for now
* just avoid the verification stage for non-crc filesystems
*/
if (!xfs_sb_version_hascrc(&mp->m_sb))
return;
magic32 = be32_to_cpu(*(__be32 *)bp->b_addr); magic32 = be32_to_cpu(*(__be32 *)bp->b_addr);
magic16 = be16_to_cpu(*(__be16*)bp->b_addr); magic16 = be16_to_cpu(*(__be16*)bp->b_addr);
magicda = be16_to_cpu(info->magic); magicda = be16_to_cpu(info->magic);
@ -2163,8 +2174,6 @@ xlog_recover_validate_buf_type(
bp->b_ops = &xfs_agf_buf_ops; bp->b_ops = &xfs_agf_buf_ops;
break; break;
case XFS_BLFT_AGFL_BUF: case XFS_BLFT_AGFL_BUF:
if (!xfs_sb_version_hascrc(&mp->m_sb))
break;
if (magic32 != XFS_AGFL_MAGIC) { if (magic32 != XFS_AGFL_MAGIC) {
xfs_warn(mp, "Bad AGFL block magic!"); xfs_warn(mp, "Bad AGFL block magic!");
ASSERT(0); ASSERT(0);
@ -2197,10 +2206,6 @@ xlog_recover_validate_buf_type(
#endif #endif
break; break;
case XFS_BLFT_DINO_BUF: case XFS_BLFT_DINO_BUF:
/*
* we get here with inode allocation buffers, not buffers that
* track unlinked list changes.
*/
if (magic16 != XFS_DINODE_MAGIC) { if (magic16 != XFS_DINODE_MAGIC) {
xfs_warn(mp, "Bad INODE block magic!"); xfs_warn(mp, "Bad INODE block magic!");
ASSERT(0); ASSERT(0);
@ -2280,8 +2285,6 @@ xlog_recover_validate_buf_type(
bp->b_ops = &xfs_attr3_leaf_buf_ops; bp->b_ops = &xfs_attr3_leaf_buf_ops;
break; break;
case XFS_BLFT_ATTR_RMT_BUF: case XFS_BLFT_ATTR_RMT_BUF:
if (!xfs_sb_version_hascrc(&mp->m_sb))
break;
if (magic32 != XFS_ATTR3_RMT_MAGIC) { if (magic32 != XFS_ATTR3_RMT_MAGIC) {
xfs_warn(mp, "Bad attr remote magic!"); xfs_warn(mp, "Bad attr remote magic!");
ASSERT(0); ASSERT(0);
@ -2388,15 +2391,6 @@ xlog_recover_do_reg_buffer(
/* Shouldn't be any more regions */ /* Shouldn't be any more regions */
ASSERT(i == item->ri_total); ASSERT(i == item->ri_total);
/*
* We can only do post recovery validation on items on CRC enabled
* fielsystems as we need to know when the buffer was written to be able
* to determine if we should have replayed the item. If we replay old
* metadata over a newer buffer, then it will enter a temporarily
* inconsistent state resulting in verification failures. Hence for now
* just avoid the verification stage for non-crc filesystems
*/
if (xfs_sb_version_hascrc(&mp->m_sb))
xlog_recover_validate_buf_type(mp, bp, buf_f); xlog_recover_validate_buf_type(mp, bp, buf_f);
} }
@ -2405,8 +2399,11 @@ xlog_recover_do_reg_buffer(
* Simple algorithm: if we have found a QUOTAOFF log item of the same type * Simple algorithm: if we have found a QUOTAOFF log item of the same type
* (ie. USR or GRP), then just toss this buffer away; don't recover it. * (ie. USR or GRP), then just toss this buffer away; don't recover it.
* Else, treat it as a regular buffer and do recovery. * Else, treat it as a regular buffer and do recovery.
*
* Return false if the buffer was tossed and true if we recovered the buffer to
* indicate to the caller if the buffer needs writing.
*/ */
STATIC void STATIC bool
xlog_recover_do_dquot_buffer( xlog_recover_do_dquot_buffer(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xlog *log, struct xlog *log,
@ -2421,9 +2418,8 @@ xlog_recover_do_dquot_buffer(
/* /*
* Filesystems are required to send in quota flags at mount time. * Filesystems are required to send in quota flags at mount time.
*/ */
if (mp->m_qflags == 0) { if (!mp->m_qflags)
return; return false;
}
type = 0; type = 0;
if (buf_f->blf_flags & XFS_BLF_UDQUOT_BUF) if (buf_f->blf_flags & XFS_BLF_UDQUOT_BUF)
@ -2436,9 +2432,10 @@ xlog_recover_do_dquot_buffer(
* This type of quotas was turned off, so ignore this buffer * This type of quotas was turned off, so ignore this buffer
*/ */
if (log->l_quotaoffs_flag & type) if (log->l_quotaoffs_flag & type)
return; return false;
xlog_recover_do_reg_buffer(mp, item, bp, buf_f); xlog_recover_do_reg_buffer(mp, item, bp, buf_f);
return true;
} }
/* /*
@ -2505,23 +2502,44 @@ xlog_recover_buffer_pass2(
} }
/* /*
* recover the buffer only if we get an LSN from it and it's less than * Recover the buffer only if we get an LSN from it and it's less than
* the lsn of the transaction we are replaying. * the lsn of the transaction we are replaying.
*
* Note that we have to be extremely careful of readahead here.
* Readahead does not attach verfiers to the buffers so if we don't
* actually do any replay after readahead because of the LSN we found
* in the buffer if more recent than that current transaction then we
* need to attach the verifier directly. Failure to do so can lead to
* future recovery actions (e.g. EFI and unlinked list recovery) can
* operate on the buffers and they won't get the verifier attached. This
* can lead to blocks on disk having the correct content but a stale
* CRC.
*
* It is safe to assume these clean buffers are currently up to date.
* If the buffer is dirtied by a later transaction being replayed, then
* the verifier will be reset to match whatever recover turns that
* buffer into.
*/ */
lsn = xlog_recover_get_buf_lsn(mp, bp); lsn = xlog_recover_get_buf_lsn(mp, bp);
if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) {
xlog_recover_validate_buf_type(mp, bp, buf_f);
goto out_release; goto out_release;
}
if (buf_f->blf_flags & XFS_BLF_INODE_BUF) { if (buf_f->blf_flags & XFS_BLF_INODE_BUF) {
error = xlog_recover_do_inode_buffer(mp, item, bp, buf_f); error = xlog_recover_do_inode_buffer(mp, item, bp, buf_f);
if (error)
goto out_release;
} else if (buf_f->blf_flags & } else if (buf_f->blf_flags &
(XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) { (XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) {
xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f); bool dirty;
dirty = xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f);
if (!dirty)
goto out_release;
} else { } else {
xlog_recover_do_reg_buffer(mp, item, bp, buf_f); xlog_recover_do_reg_buffer(mp, item, bp, buf_f);
} }
if (error)
goto out_release;
/* /*
* Perform delayed write on the buffer. Asynchronous writes will be * Perform delayed write on the buffer. Asynchronous writes will be
@ -3011,27 +3029,22 @@ xlog_recover_dquot_pass2(
return -EIO; return -EIO;
ASSERT(dq_f->qlf_len == 1); ASSERT(dq_f->qlf_len == 1);
/*
* At this point we are assuming that the dquots have been allocated
* and hence the buffer has valid dquots stamped in it. It should,
* therefore, pass verifier validation. If the dquot is bad, then the
* we'll return an error here, so we don't need to specifically check
* the dquot in the buffer after the verifier has run.
*/
error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dq_f->qlf_blkno, error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dq_f->qlf_blkno,
XFS_FSB_TO_BB(mp, dq_f->qlf_len), 0, &bp, XFS_FSB_TO_BB(mp, dq_f->qlf_len), 0, &bp,
NULL); &xfs_dquot_buf_ops);
if (error) if (error)
return error; return error;
ASSERT(bp); ASSERT(bp);
ddq = (xfs_disk_dquot_t *)xfs_buf_offset(bp, dq_f->qlf_boffset); ddq = (xfs_disk_dquot_t *)xfs_buf_offset(bp, dq_f->qlf_boffset);
/*
* At least the magic num portion should be on disk because this
* was among a chunk of dquots created earlier, and we did some
* minimal initialization then.
*/
error = xfs_dqcheck(mp, ddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN,
"xlog_recover_dquot_pass2");
if (error) {
xfs_buf_relse(bp);
return -EIO;
}
/* /*
* If the dquot has an LSN in it, recover the dquot only if it's less * If the dquot has an LSN in it, recover the dquot only if it's less
* than the lsn of the transaction we are replaying. * than the lsn of the transaction we are replaying.

View File

@ -323,7 +323,6 @@ reread:
* Initialize the mount structure from the superblock. * Initialize the mount structure from the superblock.
*/ */
xfs_sb_from_disk(sbp, XFS_BUF_TO_SBP(bp)); xfs_sb_from_disk(sbp, XFS_BUF_TO_SBP(bp));
xfs_sb_quota_from_disk(sbp);
/* /*
* If we haven't validated the superblock, do so now before we try * If we haven't validated the superblock, do so now before we try

View File

@ -911,6 +911,12 @@ xfs_qm_dqiter_bufs(
if (error) if (error)
break; break;
/*
* A corrupt buffer might not have a verifier attached, so
* make sure we have the correct one attached before writeback
* occurs.
*/
bp->b_ops = &xfs_dquot_buf_ops;
xfs_qm_reset_dqcounts(mp, bp, firstid, type); xfs_qm_reset_dqcounts(mp, bp, firstid, type);
xfs_buf_delwri_queue(bp, buffer_list); xfs_buf_delwri_queue(bp, buffer_list);
xfs_buf_relse(bp); xfs_buf_relse(bp);
@ -996,7 +1002,7 @@ xfs_qm_dqiterate(
xfs_buf_readahead(mp->m_ddev_targp, xfs_buf_readahead(mp->m_ddev_targp,
XFS_FSB_TO_DADDR(mp, rablkno), XFS_FSB_TO_DADDR(mp, rablkno),
mp->m_quotainfo->qi_dqchunklen, mp->m_quotainfo->qi_dqchunklen,
NULL); &xfs_dquot_buf_ops);
rablkno++; rablkno++;
} }
} }

View File

@ -1,46 +0,0 @@
/*
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __XFS_VNODE_H__
#define __XFS_VNODE_H__
#include "xfs_fs.h"
struct file;
struct xfs_inode;
struct attrlist_cursor_kern;
/*
* Flags for read/write calls - same values as IRIX
*/
#define IO_ISDIRECT 0x00004 /* bypass page cache */
#define IO_INVIS 0x00020 /* don't update inode timestamps */
#define XFS_IO_FLAGS \
{ IO_ISDIRECT, "DIRECT" }, \
{ IO_INVIS, "INVIS"}
/*
* Some useful predicates.
*/
#define VN_MAPPED(vp) mapping_mapped(vp->i_mapping)
#define VN_CACHED(vp) (vp->i_mapping->nrpages)
#define VN_DIRTY(vp) mapping_tagged(vp->i_mapping, \
PAGECACHE_TAG_DIRTY)
#endif /* __XFS_VNODE_H__ */