Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull second vfs pile from Al Viro: "The stuff in there: fsfreeze deadlock fixes by Jan (essentially, the deadlock reproduced by xfstests 068), symlink and hardlink restriction patches, plus assorted cleanups and fixes. Note that another fsfreeze deadlock (emergency thaw one) is *not* dealt with - the series by Fernando conflicts a lot with Jan's, breaks userland ABI (FIFREEZE semantics gets changed) and trades the deadlock for massive vfsmount leak; this is going to be handled next cycle. There probably will be another pull request, but that stuff won't be in it." Fix up trivial conflicts due to unrelated changes next to each other in drivers/{staging/gdm72xx/usb_boot.c, usb/gadget/storage_common.c} * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (54 commits) delousing target_core_file a bit Documentation: Correct s_umount state for freeze_fs/unfreeze_fs fs: Remove old freezing mechanism ext2: Implement freezing btrfs: Convert to new freezing mechanism nilfs2: Convert to new freezing mechanism ntfs: Convert to new freezing mechanism fuse: Convert to new freezing mechanism gfs2: Convert to new freezing mechanism ocfs2: Convert to new freezing mechanism xfs: Convert to new freezing code ext4: Convert to new freezing mechanism fs: Protect write paths by sb_start_write - sb_end_write fs: Skip atime update on frozen filesystem fs: Add freezing handling to mnt_want_write() / mnt_drop_write() fs: Improve filesystem freezing handling switch the protection of percpu_counter list to spinlock nfsd: Push mnt_want_write() outside of i_mutex btrfs: Push mnt_want_write() outside of i_mutex fat: Push mnt_want_write() outside of i_mutex ...
This commit is contained in:
@@ -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.
|
||||
@@ -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;
|
||||
@@ -1425,6 +1440,9 @@ out_trans_cancel:
|
||||
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:
|
||||
|
@@ -770,10 +770,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);
|
||||
@@ -792,6 +794,8 @@ xfs_file_aio_write(
|
||||
ret = err;
|
||||
}
|
||||
|
||||
out:
|
||||
sb_end_write(inode->i_sb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
@@ -382,6 +388,7 @@ xfs_fssetdm_by_handle(
|
||||
fsd.fsd_dmstate);
|
||||
|
||||
out:
|
||||
mnt_drop_write_file(parfilp);
|
||||
dput(dentry);
|
||||
return error;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -600,7 +600,11 @@ 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: {
|
||||
@@ -608,7 +612,11 @@ xfs_file_compat_ioctl(
|
||||
|
||||
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
|
||||
@@ -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:
|
||||
|
@@ -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,
|
||||
|
@@ -1551,7 +1551,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));
|
||||
}
|
||||
|
||||
|
@@ -311,9 +311,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
|
||||
*/
|
||||
|
@@ -403,7 +403,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
|
||||
|
@@ -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 *
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
@@ -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.
|
||||
|
Reference in New Issue
Block a user