Skip to content

Commit

Permalink
Merge branch 'xfs-misc-fixes-3.17-2' into for-next
Browse files Browse the repository at this point in the history
  • Loading branch information
Dave Chinner committed Aug 4, 2014
2 parents b076d87 + 4ef897a commit 645f985
Show file tree
Hide file tree
Showing 16 changed files with 175 additions and 161 deletions.
24 changes: 20 additions & 4 deletions fs/xfs/libxfs/xfs_sb.c
Original file line number Diff line number Diff line change
Expand Up @@ -386,10 +386,11 @@ xfs_sb_quota_from_disk(struct xfs_sb *sbp)
}
}

void
xfs_sb_from_disk(
static void
__xfs_sb_from_disk(
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_blocksize = be32_to_cpu(from->sb_blocksize);
Expand Down Expand Up @@ -445,6 +446,17 @@ xfs_sb_from_disk(
to->sb_pad = 0;
to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
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
Expand Down Expand Up @@ -577,7 +589,11 @@ xfs_sb_verify(
struct xfs_mount *mp = bp->b_target->bt_mount;
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
Expand Down
100 changes: 48 additions & 52 deletions fs/xfs/xfs_bmap_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,7 @@ xfs_can_free_eofblocks(struct xfs_inode *ip, bool force)
* have speculative prealloc/delalloc blocks to remove.
*/
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)
return false;

Expand Down Expand Up @@ -1618,6 +1618,30 @@ xfs_swap_extents_check_format(
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
xfs_swap_extents(
xfs_inode_t *ip, /* target inode */
Expand All @@ -1633,6 +1657,7 @@ xfs_swap_extents(
int aforkblks = 0;
int taforkblks = 0;
__uint64_t tmp;
int lock_flags;

tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL);
if (!tempifp) {
Expand All @@ -1641,13 +1666,13 @@ xfs_swap_extents(
}

/*
* we have to do two separate lock calls here to keep lockdep
* happy. If we try to get all the locks in one call, lock will
* report false positives when we drop the ILOCK and regain them
* below.
* Lock up the inodes against other IO and truncate to begin with.
* Then we can ensure the inodes are flushed and have no page cache
* safely. Once we have done this we can take the ilocks and do the rest
* of the checks.
*/
lock_flags = 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 */
if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) {
Expand All @@ -1661,23 +1686,28 @@ xfs_swap_extents(
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)
goto out_unlock;
truncate_pagecache_range(VFS_I(tip), 0, -1);

/* Verify O_DIRECT for ftmp */
if (VN_CACHED(VFS_I(tip)) != 0) {
error = -EINVAL;
tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT);
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
if (error) {
xfs_trans_cancel(tp, 0);
goto out_unlock;
}
xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
lock_flags |= XFS_ILOCK_EXCL;

/* Verify all data are being swapped */
if (sxp->sx_offset != 0 ||
sxp->sx_length != ip->i_d.di_size ||
sxp->sx_length != tip->i_d.di_size) {
error = -EFAULT;
goto out_unlock;
goto out_trans_cancel;
}

trace_xfs_swap_extent_before(ip, 0);
Expand All @@ -1689,7 +1719,7 @@ xfs_swap_extents(
xfs_notice(mp,
"%s: inode 0x%llx format is incompatible for exchanging.",
__func__, ip->i_ino);
goto out_unlock;
goto out_trans_cancel;
}

/*
Expand All @@ -1704,42 +1734,8 @@ xfs_swap_extents(
(sbp->bs_mtime.tv_sec != VFS_I(ip)->i_mtime.tv_sec) ||
(sbp->bs_mtime.tv_nsec != VFS_I(ip)->i_mtime.tv_nsec)) {
error = -EBUSY;
goto out_unlock;
}

/* 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;
goto out_trans_cancel;
}
xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);

/*
* Count the number of extended attribute blocks
*/
Expand All @@ -1757,8 +1753,8 @@ xfs_swap_extents(
goto out_trans_cancel;
}

xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
xfs_trans_ijoin(tp, ip, lock_flags);
xfs_trans_ijoin(tp, tip, lock_flags);

/*
* Before we've swapped the forks, lets set the owners of the forks
Expand Down Expand Up @@ -1887,8 +1883,8 @@ xfs_swap_extents(
return error;

out_unlock:
xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
xfs_iunlock(tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
xfs_iunlock(ip, lock_flags);
xfs_iunlock(tip, lock_flags);
goto out;

out_trans_cancel:
Expand Down
14 changes: 14 additions & 0 deletions fs/xfs/xfs_buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,20 @@ _xfs_buf_ioapply(
SHUTDOWN_CORRUPT_INCORE);
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) {
rw = READA;
Expand Down
3 changes: 2 additions & 1 deletion fs/xfs/xfs_dquot.c
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,8 @@ xfs_qm_dqflush(
* Get the buffer containing the on-disk dquot
*/
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)
goto out_unlock;

Expand Down
10 changes: 5 additions & 5 deletions fs/xfs/xfs_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,11 +247,11 @@ xfs_file_read_iter(
XFS_STATS_INC(xs_read_calls);

if (unlikely(file->f_flags & O_DIRECT))
ioflags |= IO_ISDIRECT;
ioflags |= XFS_IO_ISDIRECT;
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_IS_REALTIME_INODE(ip) ?
mp->m_rtdev_targp : mp->m_ddev_targp;
Expand Down Expand Up @@ -284,7 +284,7 @@ xfs_file_read_iter(
* proceeed concurrently without serialisation.
*/
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_ilock(ip, XFS_IOLOCK_EXCL);

Expand Down Expand Up @@ -326,7 +326,7 @@ xfs_file_splice_read(
XFS_STATS_INC(xs_read_calls);

if (infilp->f_mode & FMODE_NOCMTIME)
ioflags |= IO_INVIS;
ioflags |= XFS_IO_INVIS;

if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return -EIO;
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1635,7 +1635,7 @@ xfs_release(
truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED);
if (truncated) {
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);
if (error)
return error;
Expand Down
10 changes: 10 additions & 0 deletions fs/xfs/xfs_inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -398,4 +398,14 @@ do { \

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__ */
6 changes: 3 additions & 3 deletions fs/xfs/xfs_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ xfs_ioc_space(
xfs_ilock(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;
if (ip->i_d.di_mode & S_IXGRP)
ip->i_d.di_mode &= ~S_ISGID;
Expand Down Expand Up @@ -1376,7 +1376,7 @@ xfs_ioc_getbmap(
return -EINVAL;

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;

error = xfs_getbmap(ip, &bmx, xfs_getbmap_format,
Expand Down Expand Up @@ -1520,7 +1520,7 @@ xfs_file_ioctl(
int error;

if (filp->f_mode & FMODE_NOCMTIME)
ioflags |= IO_INVIS;
ioflags |= XFS_IO_INVIS;

trace_xfs_file_ioctl(ip);

Expand Down
3 changes: 1 addition & 2 deletions fs/xfs/xfs_ioctl32.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_mount.h"
#include "xfs_vnode.h"
#include "xfs_inode.h"
#include "xfs_itable.h"
#include "xfs_error.h"
Expand Down Expand Up @@ -537,7 +536,7 @@ xfs_file_compat_ioctl(
int error;

if (filp->f_mode & FMODE_NOCMTIME)
ioflags |= IO_INVIS;
ioflags |= XFS_IO_INVIS;

trace_xfs_file_compat_ioctl(ip);

Expand Down
4 changes: 2 additions & 2 deletions fs/xfs/xfs_iops.c
Original file line number Diff line number Diff line change
Expand Up @@ -1055,12 +1055,12 @@ xfs_vn_fiemap(
return error;

/* Set up bmap header for xfs internal routine */
bm.bmv_offset = BTOBB(start);
bm.bmv_offset = BTOBBT(start);
/* Special case for whole file */
if (length == FIEMAP_MAX_OFFSET)
bm.bmv_length = -1LL;
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 */
bm.bmv_count = !fieinfo->fi_extents_max ? MAXEXTNUM :
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ typedef __uint64_t __psunsigned_t;
#include <asm/byteorder.h>
#include <asm/unaligned.h>

#include "xfs_vnode.h"
#include "xfs_fs.h"
#include "xfs_stats.h"
#include "xfs_sysctl.h"
#include "xfs_iops.h"
Expand Down
8 changes: 7 additions & 1 deletion fs/xfs/xfs_log.c
Original file line number Diff line number Diff line change
Expand Up @@ -1378,8 +1378,14 @@ xlog_alloc_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;
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)
goto out_free_log;

Expand Down
Loading

0 comments on commit 645f985

Please sign in to comment.