XFS: Fixes for 6.14-rc4
-----BEGIN PGP SIGNATURE----- iJUEABMJAB0WIQSmtYVZ/MfVMGUq1GNcsMJ8RxYuYwUCZ7Wo6gAKCRBcsMJ8RxYu Y9HaAYDN4tE42EfG1U60xfNiaIHG2fsEb3zlHrm0Hha0U0bmZgUvDFuGfS1VztVq a5RkVIYBf0BlWvLR30u6Sku6Zb+pHYAFbcImAIQymrKMAnKfADmN23VIbYTDcWTF LZ1PRt3Mkg== =K9n1 -----END PGP SIGNATURE----- Merge tag 'xfs-fixes-6.14-rc4' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux Pull xfs fixes from Carlos Maiolino: "Just a collection of bug fixes, nothing really stands out" * tag 'xfs-fixes-6.14-rc4' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: xfs: flush inodegc before swapon xfs: rename xfs_iomap_swapfile_activate to xfs_vm_swap_activate xfs: Do not allow norecovery mount with quotacheck xfs: do not check NEEDSREPAIR if ro,norecovery mount. xfs: fix data fork format filtering during inode repair xfs: fix online repair probing when CONFIG_XFS_ONLINE_REPAIR=n
This commit is contained in:
commit
770b7eec04
7 changed files with 114 additions and 30 deletions
|
@ -224,7 +224,6 @@ static inline bool xchk_skip_xref(struct xfs_scrub_metadata *sm)
|
|||
bool xchk_dir_looks_zapped(struct xfs_inode *dp);
|
||||
bool xchk_pptr_looks_zapped(struct xfs_inode *ip);
|
||||
|
||||
#ifdef CONFIG_XFS_ONLINE_REPAIR
|
||||
/* Decide if a repair is required. */
|
||||
static inline bool xchk_needs_repair(const struct xfs_scrub_metadata *sm)
|
||||
{
|
||||
|
@ -244,10 +243,6 @@ static inline bool xchk_could_repair(const struct xfs_scrub *sc)
|
|||
return (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) &&
|
||||
!(sc->flags & XREP_ALREADY_FIXED);
|
||||
}
|
||||
#else
|
||||
# define xchk_needs_repair(sc) (false)
|
||||
# define xchk_could_repair(sc) (false)
|
||||
#endif /* CONFIG_XFS_ONLINE_REPAIR */
|
||||
|
||||
int xchk_metadata_inode_forks(struct xfs_scrub *sc);
|
||||
|
||||
|
|
|
@ -1055,9 +1055,17 @@ xrep_dinode_check_dfork(
|
|||
return true;
|
||||
break;
|
||||
case S_IFREG:
|
||||
if (fmt == XFS_DINODE_FMT_LOCAL)
|
||||
switch (fmt) {
|
||||
case XFS_DINODE_FMT_LOCAL:
|
||||
return true;
|
||||
fallthrough;
|
||||
case XFS_DINODE_FMT_EXTENTS:
|
||||
case XFS_DINODE_FMT_BTREE:
|
||||
case XFS_DINODE_FMT_META_BTREE:
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case S_IFLNK:
|
||||
case S_IFDIR:
|
||||
switch (fmt) {
|
||||
|
|
|
@ -191,7 +191,16 @@ int xrep_reset_metafile_resv(struct xfs_scrub *sc);
|
|||
#else
|
||||
|
||||
#define xrep_ino_dqattach(sc) (0)
|
||||
#define xrep_will_attempt(sc) (false)
|
||||
|
||||
/*
|
||||
* When online repair is not built into the kernel, we still want to attempt
|
||||
* the repair so that the stub xrep_attempt below will return EOPNOTSUPP.
|
||||
*/
|
||||
static inline bool xrep_will_attempt(const struct xfs_scrub *sc)
|
||||
{
|
||||
return (sc->sm->sm_flags & XFS_SCRUB_IFLAG_FORCE_REBUILD) ||
|
||||
xchk_needs_repair(sc->sm);
|
||||
}
|
||||
|
||||
static inline int
|
||||
xrep_attempt(
|
||||
|
|
|
@ -149,6 +149,18 @@ xchk_probe(
|
|||
if (xchk_should_terminate(sc, &error))
|
||||
return error;
|
||||
|
||||
/*
|
||||
* If the caller is probing to see if repair works but repair isn't
|
||||
* built into the kernel, return EOPNOTSUPP because that's the signal
|
||||
* that userspace expects. If online repair is built in, set the
|
||||
* CORRUPT flag (without any of the usual tracing/logging) to force us
|
||||
* into xrep_probe.
|
||||
*/
|
||||
if (xchk_could_repair(sc)) {
|
||||
if (!IS_ENABLED(CONFIG_XFS_ONLINE_REPAIR))
|
||||
return -EOPNOTSUPP;
|
||||
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "xfs_reflink.h"
|
||||
#include "xfs_errortag.h"
|
||||
#include "xfs_error.h"
|
||||
#include "xfs_icache.h"
|
||||
|
||||
struct xfs_writepage_ctx {
|
||||
struct iomap_writepage_ctx ctx;
|
||||
|
@ -528,12 +529,44 @@ xfs_vm_readahead(
|
|||
}
|
||||
|
||||
static int
|
||||
xfs_iomap_swapfile_activate(
|
||||
xfs_vm_swap_activate(
|
||||
struct swap_info_struct *sis,
|
||||
struct file *swap_file,
|
||||
sector_t *span)
|
||||
{
|
||||
sis->bdev = xfs_inode_buftarg(XFS_I(file_inode(swap_file)))->bt_bdev;
|
||||
struct xfs_inode *ip = XFS_I(file_inode(swap_file));
|
||||
|
||||
/*
|
||||
* Swap file activation can race against concurrent shared extent
|
||||
* removal in files that have been cloned. If this happens,
|
||||
* iomap_swapfile_iter() can fail because it encountered a shared
|
||||
* extent even though an operation is in progress to remove those
|
||||
* shared extents.
|
||||
*
|
||||
* This race becomes problematic when we defer extent removal
|
||||
* operations beyond the end of a syscall (i.e. use async background
|
||||
* processing algorithms). Users think the extents are no longer
|
||||
* shared, but iomap_swapfile_iter() still sees them as shared
|
||||
* because the refcountbt entries for the extents being removed have
|
||||
* not yet been updated. Hence the swapon call fails unexpectedly.
|
||||
*
|
||||
* The race condition is currently most obvious from the unlink()
|
||||
* operation as extent removal is deferred until after the last
|
||||
* reference to the inode goes away. We then process the extent
|
||||
* removal asynchronously, hence triggers the "syscall completed but
|
||||
* work not done" condition mentioned above. To close this race
|
||||
* window, we need to flush any pending inodegc operations to ensure
|
||||
* they have updated the refcountbt records before we try to map the
|
||||
* swapfile.
|
||||
*/
|
||||
xfs_inodegc_flush(ip->i_mount);
|
||||
|
||||
/*
|
||||
* Direct the swap code to the correct block device when this file
|
||||
* sits on the RT device.
|
||||
*/
|
||||
sis->bdev = xfs_inode_buftarg(ip)->bt_bdev;
|
||||
|
||||
return iomap_swapfile_activate(sis, swap_file, span,
|
||||
&xfs_read_iomap_ops);
|
||||
}
|
||||
|
@ -549,11 +582,11 @@ const struct address_space_operations xfs_address_space_operations = {
|
|||
.migrate_folio = filemap_migrate_folio,
|
||||
.is_partially_uptodate = iomap_is_partially_uptodate,
|
||||
.error_remove_folio = generic_error_remove_folio,
|
||||
.swap_activate = xfs_iomap_swapfile_activate,
|
||||
.swap_activate = xfs_vm_swap_activate,
|
||||
};
|
||||
|
||||
const struct address_space_operations xfs_dax_aops = {
|
||||
.writepages = xfs_dax_writepages,
|
||||
.dirty_folio = noop_dirty_folio,
|
||||
.swap_activate = xfs_iomap_swapfile_activate,
|
||||
.swap_activate = xfs_vm_swap_activate,
|
||||
};
|
||||
|
|
|
@ -78,6 +78,28 @@ xfs_qm_statvfs(
|
|||
}
|
||||
}
|
||||
|
||||
STATIC int
|
||||
xfs_qm_validate_state_change(
|
||||
struct xfs_mount *mp,
|
||||
uint uqd,
|
||||
uint gqd,
|
||||
uint pqd)
|
||||
{
|
||||
int state;
|
||||
|
||||
/* Is quota state changing? */
|
||||
state = ((uqd && !XFS_IS_UQUOTA_ON(mp)) ||
|
||||
(!uqd && XFS_IS_UQUOTA_ON(mp)) ||
|
||||
(gqd && !XFS_IS_GQUOTA_ON(mp)) ||
|
||||
(!gqd && XFS_IS_GQUOTA_ON(mp)) ||
|
||||
(pqd && !XFS_IS_PQUOTA_ON(mp)) ||
|
||||
(!pqd && XFS_IS_PQUOTA_ON(mp)));
|
||||
|
||||
return state &&
|
||||
(xfs_dev_is_read_only(mp, "changing quota state") ||
|
||||
xfs_has_norecovery(mp));
|
||||
}
|
||||
|
||||
int
|
||||
xfs_qm_newmount(
|
||||
xfs_mount_t *mp,
|
||||
|
@ -97,24 +119,25 @@ xfs_qm_newmount(
|
|||
}
|
||||
|
||||
/*
|
||||
* If the device itself is read-only, we can't allow
|
||||
* the user to change the state of quota on the mount -
|
||||
* this would generate a transaction on the ro device,
|
||||
* which would lead to an I/O error and shutdown
|
||||
* If the device itself is read-only and/or in norecovery
|
||||
* mode, we can't allow the user to change the state of
|
||||
* quota on the mount - this would generate a transaction
|
||||
* on the ro device, which would lead to an I/O error and
|
||||
* shutdown.
|
||||
*/
|
||||
|
||||
if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) ||
|
||||
(!uquotaondisk && XFS_IS_UQUOTA_ON(mp)) ||
|
||||
(gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
|
||||
(!gquotaondisk && XFS_IS_GQUOTA_ON(mp)) ||
|
||||
(pquotaondisk && !XFS_IS_PQUOTA_ON(mp)) ||
|
||||
(!pquotaondisk && XFS_IS_PQUOTA_ON(mp))) &&
|
||||
xfs_dev_is_read_only(mp, "changing quota state")) {
|
||||
xfs_warn(mp, "please mount with%s%s%s%s.",
|
||||
(!quotaondisk ? "out quota" : ""),
|
||||
(uquotaondisk ? " usrquota" : ""),
|
||||
(gquotaondisk ? " grpquota" : ""),
|
||||
(pquotaondisk ? " prjquota" : ""));
|
||||
if (xfs_qm_validate_state_change(mp, uquotaondisk,
|
||||
gquotaondisk, pquotaondisk)) {
|
||||
|
||||
if (xfs_has_metadir(mp))
|
||||
xfs_warn(mp,
|
||||
"metadir enabled, please mount without any quota mount options");
|
||||
else
|
||||
xfs_warn(mp, "please mount with%s%s%s%s.",
|
||||
(!quotaondisk ? "out quota" : ""),
|
||||
(uquotaondisk ? " usrquota" : ""),
|
||||
(gquotaondisk ? " grpquota" : ""),
|
||||
(pquotaondisk ? " prjquota" : ""));
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
|
|
|
@ -1661,8 +1661,12 @@ xfs_fs_fill_super(
|
|||
#endif
|
||||
}
|
||||
|
||||
/* Filesystem claims it needs repair, so refuse the mount. */
|
||||
if (xfs_has_needsrepair(mp)) {
|
||||
/*
|
||||
* Filesystem claims it needs repair, so refuse the mount unless
|
||||
* norecovery is also specified, in which case the filesystem can
|
||||
* be mounted with no risk of further damage.
|
||||
*/
|
||||
if (xfs_has_needsrepair(mp) && !xfs_has_norecovery(mp)) {
|
||||
xfs_warn(mp, "Filesystem needs repair. Please run xfs_repair.");
|
||||
error = -EFSCORRUPTED;
|
||||
goto out_free_sb;
|
||||
|
|
Loading…
Add table
Reference in a new issue