mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-22 00:40:03 +00:00
![Brian Foster](/assets/img/avatar_default.png)
The filesystem quiesce sequence performs the operations necessary to drain all background work, push pending transactions through the log infrastructure and wait on I/O resulting from the final AIL push. We have had reports of remount,ro hangs in xfs_log_quiesce() -> xfs_wait_buftarg(), however, and some instrumentation code to detect transaction commits at this point in the quiesce sequence has inculpated the eofblocks background scanner as a cause. While higher level remount code generally prevents user modifications by the time the filesystem has made it to xfs_log_quiesce(), the background scanner may still be alive and can perform pending work at any time. If this occurs between the xfs_log_force() and xfs_wait_buftarg() calls within xfs_log_quiesce(), this can lead to an indefinite lockup in xfs_wait_buftarg(). To prevent this problem, cancel the background eofblocks scan worker during the remount read-only quiesce sequence. This suspends background trimming when a filesystem is remounted read-only. This is only done in the remount path because the freeze codepath has already locked out new transactions by the time the filesystem attempts to quiesce (and thus waiting on an active work item could deadlock). Kick the eofblocks worker to pick up where it left off once an fs is remounted back to read-write. Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Eric Sandeen <sandeen@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
116 lines
3.5 KiB
C
116 lines
3.5 KiB
C
/*
|
|
* Copyright (c) 2000-2006 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_SYNC_H
|
|
#define XFS_SYNC_H 1
|
|
|
|
struct xfs_mount;
|
|
struct xfs_perag;
|
|
|
|
struct xfs_eofblocks {
|
|
__u32 eof_flags;
|
|
kuid_t eof_uid;
|
|
kgid_t eof_gid;
|
|
prid_t eof_prid;
|
|
__u64 eof_min_file_size;
|
|
xfs_ino_t eof_scan_owner;
|
|
};
|
|
|
|
#define SYNC_WAIT 0x0001 /* wait for i/o to complete */
|
|
#define SYNC_TRYLOCK 0x0002 /* only try to lock inodes */
|
|
|
|
/*
|
|
* tags for inode radix tree
|
|
*/
|
|
#define XFS_ICI_NO_TAG (-1) /* special flag for an untagged lookup
|
|
in xfs_inode_ag_iterator */
|
|
#define XFS_ICI_RECLAIM_TAG 0 /* inode is to be reclaimed */
|
|
#define XFS_ICI_EOFBLOCKS_TAG 1 /* inode has blocks beyond EOF */
|
|
|
|
/*
|
|
* Flags for xfs_iget()
|
|
*/
|
|
#define XFS_IGET_CREATE 0x1
|
|
#define XFS_IGET_UNTRUSTED 0x2
|
|
#define XFS_IGET_DONTCACHE 0x4
|
|
|
|
int xfs_iget(struct xfs_mount *mp, struct xfs_trans *tp, xfs_ino_t ino,
|
|
uint flags, uint lock_flags, xfs_inode_t **ipp);
|
|
|
|
/* recovery needs direct inode allocation capability */
|
|
struct xfs_inode * xfs_inode_alloc(struct xfs_mount *mp, xfs_ino_t ino);
|
|
void xfs_inode_free(struct xfs_inode *ip);
|
|
|
|
void xfs_reclaim_worker(struct work_struct *work);
|
|
|
|
int xfs_reclaim_inodes(struct xfs_mount *mp, int mode);
|
|
int xfs_reclaim_inodes_count(struct xfs_mount *mp);
|
|
long xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan);
|
|
|
|
void xfs_inode_set_reclaim_tag(struct xfs_inode *ip);
|
|
|
|
void xfs_inode_set_eofblocks_tag(struct xfs_inode *ip);
|
|
void xfs_inode_clear_eofblocks_tag(struct xfs_inode *ip);
|
|
int xfs_icache_free_eofblocks(struct xfs_mount *, struct xfs_eofblocks *);
|
|
int xfs_inode_free_quota_eofblocks(struct xfs_inode *ip);
|
|
void xfs_eofblocks_worker(struct work_struct *);
|
|
void xfs_queue_eofblocks(struct xfs_mount *);
|
|
|
|
int xfs_inode_ag_iterator(struct xfs_mount *mp,
|
|
int (*execute)(struct xfs_inode *ip, int flags, void *args),
|
|
int flags, void *args);
|
|
int xfs_inode_ag_iterator_tag(struct xfs_mount *mp,
|
|
int (*execute)(struct xfs_inode *ip, int flags, void *args),
|
|
int flags, void *args, int tag);
|
|
|
|
static inline int
|
|
xfs_fs_eofblocks_from_user(
|
|
struct xfs_fs_eofblocks *src,
|
|
struct xfs_eofblocks *dst)
|
|
{
|
|
if (src->eof_version != XFS_EOFBLOCKS_VERSION)
|
|
return -EINVAL;
|
|
|
|
if (src->eof_flags & ~XFS_EOF_FLAGS_VALID)
|
|
return -EINVAL;
|
|
|
|
if (memchr_inv(&src->pad32, 0, sizeof(src->pad32)) ||
|
|
memchr_inv(src->pad64, 0, sizeof(src->pad64)))
|
|
return -EINVAL;
|
|
|
|
dst->eof_flags = src->eof_flags;
|
|
dst->eof_prid = src->eof_prid;
|
|
dst->eof_min_file_size = src->eof_min_file_size;
|
|
dst->eof_scan_owner = NULLFSINO;
|
|
|
|
dst->eof_uid = INVALID_UID;
|
|
if (src->eof_flags & XFS_EOF_FLAGS_UID) {
|
|
dst->eof_uid = make_kuid(current_user_ns(), src->eof_uid);
|
|
if (!uid_valid(dst->eof_uid))
|
|
return -EINVAL;
|
|
}
|
|
|
|
dst->eof_gid = INVALID_GID;
|
|
if (src->eof_flags & XFS_EOF_FLAGS_GID) {
|
|
dst->eof_gid = make_kgid(current_user_ns(), src->eof_gid);
|
|
if (!gid_valid(dst->eof_gid))
|
|
return -EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endif
|