Skip to content

Commit

Permalink
xfs: Convert to new freezing code
Browse files Browse the repository at this point in the history
Generic code now blocks all writers from standard write paths. So we add
blocking of all writers coming from ioctl (we get a protection of ioctl against
racing remount read-only as a bonus) and convert xfs_file_aio_write() to a
non-racy freeze protection. We also keep freeze protection on transaction
start to block internal filesystem writes such as removal of preallocated
blocks.

CC: Ben Myers <bpm@sgi.com>
CC: Alex Elder <elder@kernel.org>
CC: xfs@oss.sgi.com
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
  • Loading branch information
Jan Kara authored and Al Viro committed Jul 31, 2012
1 parent 8e8ad8a commit d9457dc
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 16 deletions.
18 changes: 18 additions & 0 deletions fs/xfs/xfs_aops.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ xfs_setfilesize_trans_alloc(

ioend->io_append_trans = tp;

/*
* We will pass freeze protection with a transaction. So tell lockdep
* we released it.
*/
rwsem_release(&ioend->io_inode->i_sb->s_writers.lock_map[SB_FREEZE_FS-1],
1, _THIS_IP_);
/*
* We hand off the transaction to the completion thread now, so
* clear the flag here.
Expand Down Expand Up @@ -199,6 +205,15 @@ xfs_end_io(
struct xfs_inode *ip = XFS_I(ioend->io_inode);
int error = 0;

if (ioend->io_append_trans) {
/*
* We've got freeze protection passed with the transaction.
* Tell lockdep about it.
*/
rwsem_acquire_read(
&ioend->io_inode->i_sb->s_writers.lock_map[SB_FREEZE_FS-1],
0, 1, _THIS_IP_);
}
if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
ioend->io_error = -EIO;
goto done;
Expand Down Expand Up @@ -1410,6 +1425,9 @@ xfs_vm_direct_IO(
if (ioend->io_append_trans) {
current_set_flags_nested(&ioend->io_append_trans->t_pflags,
PF_FSTRANS);
rwsem_acquire_read(
&inode->i_sb->s_writers.lock_map[SB_FREEZE_FS-1],
0, 1, _THIS_IP_);
xfs_trans_cancel(ioend->io_append_trans, 0);
}
out_destroy_ioend:
Expand Down
10 changes: 7 additions & 3 deletions fs/xfs/xfs_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -781,10 +781,12 @@ xfs_file_aio_write(
if (ocount == 0)
return 0;

xfs_wait_for_freeze(ip->i_mount, SB_FREEZE_WRITE);
sb_start_write(inode->i_sb);

if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return -EIO;
if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
ret = -EIO;
goto out;
}

if (unlikely(file->f_flags & O_DIRECT))
ret = xfs_file_dio_aio_write(iocb, iovp, nr_segs, pos, ocount);
Expand All @@ -803,6 +805,8 @@ xfs_file_aio_write(
ret = err;
}

out:
sb_end_write(inode->i_sb);
return ret;
}

Expand Down
55 changes: 52 additions & 3 deletions fs/xfs/xfs_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,9 +364,15 @@ xfs_fssetdm_by_handle(
if (copy_from_user(&dmhreq, arg, sizeof(xfs_fsop_setdm_handlereq_t)))
return -XFS_ERROR(EFAULT);

error = mnt_want_write_file(parfilp);
if (error)
return error;

dentry = xfs_handlereq_to_dentry(parfilp, &dmhreq.hreq);
if (IS_ERR(dentry))
if (IS_ERR(dentry)) {
mnt_drop_write_file(parfilp);
return PTR_ERR(dentry);
}

if (IS_IMMUTABLE(dentry->d_inode) || IS_APPEND(dentry->d_inode)) {
error = -XFS_ERROR(EPERM);
Expand All @@ -382,6 +388,7 @@ xfs_fssetdm_by_handle(
fsd.fsd_dmstate);

out:
mnt_drop_write_file(parfilp);
dput(dentry);
return error;
}
Expand Down Expand Up @@ -634,7 +641,11 @@ xfs_ioc_space(
if (ioflags & IO_INVIS)
attr_flags |= XFS_ATTR_DMI;

error = mnt_want_write_file(filp);
if (error)
return error;
error = xfs_change_file_space(ip, cmd, bf, filp->f_pos, attr_flags);
mnt_drop_write_file(filp);
return -error;
}

Expand Down Expand Up @@ -1163,6 +1174,7 @@ xfs_ioc_fssetxattr(
{
struct fsxattr fa;
unsigned int mask;
int error;

if (copy_from_user(&fa, arg, sizeof(fa)))
return -EFAULT;
Expand All @@ -1171,7 +1183,12 @@ xfs_ioc_fssetxattr(
if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
mask |= FSX_NONBLOCK;

return -xfs_ioctl_setattr(ip, &fa, mask);
error = mnt_want_write_file(filp);
if (error)
return error;
error = xfs_ioctl_setattr(ip, &fa, mask);
mnt_drop_write_file(filp);
return -error;
}

STATIC int
Expand All @@ -1196,6 +1213,7 @@ xfs_ioc_setxflags(
struct fsxattr fa;
unsigned int flags;
unsigned int mask;
int error;

if (copy_from_user(&flags, arg, sizeof(flags)))
return -EFAULT;
Expand All @@ -1210,7 +1228,12 @@ xfs_ioc_setxflags(
mask |= FSX_NONBLOCK;
fa.fsx_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip));

return -xfs_ioctl_setattr(ip, &fa, mask);
error = mnt_want_write_file(filp);
if (error)
return error;
error = xfs_ioctl_setattr(ip, &fa, mask);
mnt_drop_write_file(filp);
return -error;
}

STATIC int
Expand Down Expand Up @@ -1385,8 +1408,13 @@ xfs_file_ioctl(
if (copy_from_user(&dmi, arg, sizeof(dmi)))
return -XFS_ERROR(EFAULT);

error = mnt_want_write_file(filp);
if (error)
return error;

error = xfs_set_dmattrs(ip, dmi.fsd_dmevmask,
dmi.fsd_dmstate);
mnt_drop_write_file(filp);
return -error;
}

Expand Down Expand Up @@ -1434,7 +1462,11 @@ xfs_file_ioctl(

if (copy_from_user(&sxp, arg, sizeof(xfs_swapext_t)))
return -XFS_ERROR(EFAULT);
error = mnt_want_write_file(filp);
if (error)
return error;
error = xfs_swapext(&sxp);
mnt_drop_write_file(filp);
return -error;
}

Expand Down Expand Up @@ -1463,9 +1495,14 @@ xfs_file_ioctl(
if (copy_from_user(&inout, arg, sizeof(inout)))
return -XFS_ERROR(EFAULT);

error = mnt_want_write_file(filp);
if (error)
return error;

/* input parameter is passed in resblks field of structure */
in = inout.resblks;
error = xfs_reserve_blocks(mp, &in, &inout);
mnt_drop_write_file(filp);
if (error)
return -error;

Expand Down Expand Up @@ -1496,7 +1533,11 @@ xfs_file_ioctl(
if (copy_from_user(&in, arg, sizeof(in)))
return -XFS_ERROR(EFAULT);

error = mnt_want_write_file(filp);
if (error)
return error;
error = xfs_growfs_data(mp, &in);
mnt_drop_write_file(filp);
return -error;
}

Expand All @@ -1506,7 +1547,11 @@ xfs_file_ioctl(
if (copy_from_user(&in, arg, sizeof(in)))
return -XFS_ERROR(EFAULT);

error = mnt_want_write_file(filp);
if (error)
return error;
error = xfs_growfs_log(mp, &in);
mnt_drop_write_file(filp);
return -error;
}

Expand All @@ -1516,7 +1561,11 @@ xfs_file_ioctl(
if (copy_from_user(&in, arg, sizeof(in)))
return -XFS_ERROR(EFAULT);

error = mnt_want_write_file(filp);
if (error)
return error;
error = xfs_growfs_rt(mp, &in);
mnt_drop_write_file(filp);
return -error;
}

Expand Down
12 changes: 12 additions & 0 deletions fs/xfs/xfs_ioctl32.c
Original file line number Diff line number Diff line change
Expand Up @@ -600,15 +600,23 @@ xfs_file_compat_ioctl(

if (xfs_compat_growfs_data_copyin(&in, arg))
return -XFS_ERROR(EFAULT);
error = mnt_want_write_file(filp);
if (error)
return error;
error = xfs_growfs_data(mp, &in);
mnt_drop_write_file(filp);
return -error;
}
case XFS_IOC_FSGROWFSRT_32: {
struct xfs_growfs_rt in;

if (xfs_compat_growfs_rt_copyin(&in, arg))
return -XFS_ERROR(EFAULT);
error = mnt_want_write_file(filp);
if (error)
return error;
error = xfs_growfs_rt(mp, &in);
mnt_drop_write_file(filp);
return -error;
}
#endif
Expand All @@ -627,7 +635,11 @@ xfs_file_compat_ioctl(
offsetof(struct xfs_swapext, sx_stat)) ||
xfs_ioctl32_bstat_copyin(&sxp.sx_stat, &sxu->sx_stat))
return -XFS_ERROR(EFAULT);
error = mnt_want_write_file(filp);
if (error)
return error;
error = xfs_swapext(&sxp);
mnt_drop_write_file(filp);
return -error;
}
case XFS_IOC_FSBULKSTAT_32:
Expand Down
4 changes: 2 additions & 2 deletions fs/xfs/xfs_iomap.c
Original file line number Diff line number Diff line change
Expand Up @@ -680,9 +680,9 @@ xfs_iomap_write_unwritten(
* the same inode that we complete here and might deadlock
* on the iolock.
*/
xfs_wait_for_freeze(mp, SB_FREEZE_TRANS);
sb_start_intwrite(mp->m_super);
tp = _xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE, KM_NOFS);
tp->t_flags |= XFS_TRANS_RESERVE;
tp->t_flags |= XFS_TRANS_RESERVE | XFS_TRANS_FREEZE_PROT;
error = xfs_trans_reserve(tp, resblks,
XFS_WRITE_LOG_RES(mp), 0,
XFS_TRANS_PERM_LOG_RES,
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_mount.c
Original file line number Diff line number Diff line change
Expand Up @@ -1544,7 +1544,7 @@ xfs_unmountfs(
int
xfs_fs_writable(xfs_mount_t *mp)
{
return !(xfs_test_for_freeze(mp) || XFS_FORCED_SHUTDOWN(mp) ||
return !(mp->m_super->s_writers.frozen || XFS_FORCED_SHUTDOWN(mp) ||
(mp->m_flags & XFS_MOUNT_RDONLY));
}

Expand Down
3 changes: 0 additions & 3 deletions fs/xfs/xfs_mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,9 +314,6 @@ void xfs_do_force_shutdown(struct xfs_mount *mp, int flags, char *fname,
#define SHUTDOWN_REMOTE_REQ 0x0010 /* shutdown came from remote cell */
#define SHUTDOWN_DEVICE_REQ 0x0020 /* failed all paths to the device */

#define xfs_test_for_freeze(mp) ((mp)->m_super->s_frozen)
#define xfs_wait_for_freeze(mp,l) vfs_check_frozen((mp)->m_super, (l))

/*
* Flags for xfs_mountfs
*/
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ xfs_sync_worker(
if (!(mp->m_super->s_flags & MS_ACTIVE) &&
!(mp->m_flags & XFS_MOUNT_RDONLY)) {
/* dgc: errors ignored here */
if (mp->m_super->s_frozen == SB_UNFROZEN &&
if (mp->m_super->s_writers.frozen == SB_UNFROZEN &&
xfs_log_need_covered(mp))
error = xfs_fs_log_dummy(mp);
else
Expand Down
17 changes: 14 additions & 3 deletions fs/xfs/xfs_trans.c
Original file line number Diff line number Diff line change
Expand Up @@ -576,8 +576,12 @@ xfs_trans_alloc(
xfs_mount_t *mp,
uint type)
{
xfs_wait_for_freeze(mp, SB_FREEZE_TRANS);
return _xfs_trans_alloc(mp, type, KM_SLEEP);
xfs_trans_t *tp;

sb_start_intwrite(mp->m_super);
tp = _xfs_trans_alloc(mp, type, KM_SLEEP);
tp->t_flags |= XFS_TRANS_FREEZE_PROT;
return tp;
}

xfs_trans_t *
Expand All @@ -588,6 +592,7 @@ _xfs_trans_alloc(
{
xfs_trans_t *tp;

WARN_ON(mp->m_super->s_writers.frozen == SB_FREEZE_COMPLETE);
atomic_inc(&mp->m_active_trans);

tp = kmem_zone_zalloc(xfs_trans_zone, memflags);
Expand All @@ -611,6 +616,8 @@ xfs_trans_free(
xfs_extent_busy_clear(tp->t_mountp, &tp->t_busy, false);

atomic_dec(&tp->t_mountp->m_active_trans);
if (tp->t_flags & XFS_TRANS_FREEZE_PROT)
sb_end_intwrite(tp->t_mountp->m_super);
xfs_trans_free_dqinfo(tp);
kmem_zone_free(xfs_trans_zone, tp);
}
Expand Down Expand Up @@ -643,7 +650,11 @@ xfs_trans_dup(
ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
ASSERT(tp->t_ticket != NULL);

ntp->t_flags = XFS_TRANS_PERM_LOG_RES | (tp->t_flags & XFS_TRANS_RESERVE);
ntp->t_flags = XFS_TRANS_PERM_LOG_RES |
(tp->t_flags & XFS_TRANS_RESERVE) |
(tp->t_flags & XFS_TRANS_FREEZE_PROT);
/* We gave our writer reference to the new transaction */
tp->t_flags &= ~XFS_TRANS_FREEZE_PROT;
ntp->t_ticket = xfs_log_ticket_get(tp->t_ticket);
ntp->t_blk_res = tp->t_blk_res - tp->t_blk_res_used;
tp->t_blk_res = tp->t_blk_res_used;
Expand Down
2 changes: 2 additions & 0 deletions fs/xfs/xfs_trans.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ struct xfs_log_item_desc {
#define XFS_TRANS_SYNC 0x08 /* make commit synchronous */
#define XFS_TRANS_DQ_DIRTY 0x10 /* at least one dquot in trx dirty */
#define XFS_TRANS_RESERVE 0x20 /* OK to use reserved data blocks */
#define XFS_TRANS_FREEZE_PROT 0x40 /* Transaction has elevated writer
count in superblock */

/*
* Values for call flags parameter.
Expand Down

0 comments on commit d9457dc

Please sign in to comment.