Skip to content

Commit 770b7ee

Browse files
committed
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
2 parents 87a132e + 2d873ef commit 770b7ee

File tree

7 files changed

+114
-30
lines changed

7 files changed

+114
-30
lines changed

fs/xfs/scrub/common.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,6 @@ static inline bool xchk_skip_xref(struct xfs_scrub_metadata *sm)
224224
bool xchk_dir_looks_zapped(struct xfs_inode *dp);
225225
bool xchk_pptr_looks_zapped(struct xfs_inode *ip);
226226

227-
#ifdef CONFIG_XFS_ONLINE_REPAIR
228227
/* Decide if a repair is required. */
229228
static inline bool xchk_needs_repair(const struct xfs_scrub_metadata *sm)
230229
{
@@ -244,10 +243,6 @@ static inline bool xchk_could_repair(const struct xfs_scrub *sc)
244243
return (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) &&
245244
!(sc->flags & XREP_ALREADY_FIXED);
246245
}
247-
#else
248-
# define xchk_needs_repair(sc) (false)
249-
# define xchk_could_repair(sc) (false)
250-
#endif /* CONFIG_XFS_ONLINE_REPAIR */
251246

252247
int xchk_metadata_inode_forks(struct xfs_scrub *sc);
253248

fs/xfs/scrub/inode_repair.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,9 +1055,17 @@ xrep_dinode_check_dfork(
10551055
return true;
10561056
break;
10571057
case S_IFREG:
1058-
if (fmt == XFS_DINODE_FMT_LOCAL)
1058+
switch (fmt) {
1059+
case XFS_DINODE_FMT_LOCAL:
10591060
return true;
1060-
fallthrough;
1061+
case XFS_DINODE_FMT_EXTENTS:
1062+
case XFS_DINODE_FMT_BTREE:
1063+
case XFS_DINODE_FMT_META_BTREE:
1064+
break;
1065+
default:
1066+
return true;
1067+
}
1068+
break;
10611069
case S_IFLNK:
10621070
case S_IFDIR:
10631071
switch (fmt) {

fs/xfs/scrub/repair.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,16 @@ int xrep_reset_metafile_resv(struct xfs_scrub *sc);
191191
#else
192192

193193
#define xrep_ino_dqattach(sc) (0)
194-
#define xrep_will_attempt(sc) (false)
194+
195+
/*
196+
* When online repair is not built into the kernel, we still want to attempt
197+
* the repair so that the stub xrep_attempt below will return EOPNOTSUPP.
198+
*/
199+
static inline bool xrep_will_attempt(const struct xfs_scrub *sc)
200+
{
201+
return (sc->sm->sm_flags & XFS_SCRUB_IFLAG_FORCE_REBUILD) ||
202+
xchk_needs_repair(sc->sm);
203+
}
195204

196205
static inline int
197206
xrep_attempt(

fs/xfs/scrub/scrub.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,18 @@ xchk_probe(
149149
if (xchk_should_terminate(sc, &error))
150150
return error;
151151

152+
/*
153+
* If the caller is probing to see if repair works but repair isn't
154+
* built into the kernel, return EOPNOTSUPP because that's the signal
155+
* that userspace expects. If online repair is built in, set the
156+
* CORRUPT flag (without any of the usual tracing/logging) to force us
157+
* into xrep_probe.
158+
*/
159+
if (xchk_could_repair(sc)) {
160+
if (!IS_ENABLED(CONFIG_XFS_ONLINE_REPAIR))
161+
return -EOPNOTSUPP;
162+
sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
163+
}
152164
return 0;
153165
}
154166

fs/xfs/xfs_aops.c

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "xfs_reflink.h"
2020
#include "xfs_errortag.h"
2121
#include "xfs_error.h"
22+
#include "xfs_icache.h"
2223

2324
struct xfs_writepage_ctx {
2425
struct iomap_writepage_ctx ctx;
@@ -528,12 +529,44 @@ xfs_vm_readahead(
528529
}
529530

530531
static int
531-
xfs_iomap_swapfile_activate(
532+
xfs_vm_swap_activate(
532533
struct swap_info_struct *sis,
533534
struct file *swap_file,
534535
sector_t *span)
535536
{
536-
sis->bdev = xfs_inode_buftarg(XFS_I(file_inode(swap_file)))->bt_bdev;
537+
struct xfs_inode *ip = XFS_I(file_inode(swap_file));
538+
539+
/*
540+
* Swap file activation can race against concurrent shared extent
541+
* removal in files that have been cloned. If this happens,
542+
* iomap_swapfile_iter() can fail because it encountered a shared
543+
* extent even though an operation is in progress to remove those
544+
* shared extents.
545+
*
546+
* This race becomes problematic when we defer extent removal
547+
* operations beyond the end of a syscall (i.e. use async background
548+
* processing algorithms). Users think the extents are no longer
549+
* shared, but iomap_swapfile_iter() still sees them as shared
550+
* because the refcountbt entries for the extents being removed have
551+
* not yet been updated. Hence the swapon call fails unexpectedly.
552+
*
553+
* The race condition is currently most obvious from the unlink()
554+
* operation as extent removal is deferred until after the last
555+
* reference to the inode goes away. We then process the extent
556+
* removal asynchronously, hence triggers the "syscall completed but
557+
* work not done" condition mentioned above. To close this race
558+
* window, we need to flush any pending inodegc operations to ensure
559+
* they have updated the refcountbt records before we try to map the
560+
* swapfile.
561+
*/
562+
xfs_inodegc_flush(ip->i_mount);
563+
564+
/*
565+
* Direct the swap code to the correct block device when this file
566+
* sits on the RT device.
567+
*/
568+
sis->bdev = xfs_inode_buftarg(ip)->bt_bdev;
569+
537570
return iomap_swapfile_activate(sis, swap_file, span,
538571
&xfs_read_iomap_ops);
539572
}
@@ -549,11 +582,11 @@ const struct address_space_operations xfs_address_space_operations = {
549582
.migrate_folio = filemap_migrate_folio,
550583
.is_partially_uptodate = iomap_is_partially_uptodate,
551584
.error_remove_folio = generic_error_remove_folio,
552-
.swap_activate = xfs_iomap_swapfile_activate,
585+
.swap_activate = xfs_vm_swap_activate,
553586
};
554587

555588
const struct address_space_operations xfs_dax_aops = {
556589
.writepages = xfs_dax_writepages,
557590
.dirty_folio = noop_dirty_folio,
558-
.swap_activate = xfs_iomap_swapfile_activate,
591+
.swap_activate = xfs_vm_swap_activate,
559592
};

fs/xfs/xfs_qm_bhv.c

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,28 @@ xfs_qm_statvfs(
7878
}
7979
}
8080

81+
STATIC int
82+
xfs_qm_validate_state_change(
83+
struct xfs_mount *mp,
84+
uint uqd,
85+
uint gqd,
86+
uint pqd)
87+
{
88+
int state;
89+
90+
/* Is quota state changing? */
91+
state = ((uqd && !XFS_IS_UQUOTA_ON(mp)) ||
92+
(!uqd && XFS_IS_UQUOTA_ON(mp)) ||
93+
(gqd && !XFS_IS_GQUOTA_ON(mp)) ||
94+
(!gqd && XFS_IS_GQUOTA_ON(mp)) ||
95+
(pqd && !XFS_IS_PQUOTA_ON(mp)) ||
96+
(!pqd && XFS_IS_PQUOTA_ON(mp)));
97+
98+
return state &&
99+
(xfs_dev_is_read_only(mp, "changing quota state") ||
100+
xfs_has_norecovery(mp));
101+
}
102+
81103
int
82104
xfs_qm_newmount(
83105
xfs_mount_t *mp,
@@ -97,24 +119,25 @@ xfs_qm_newmount(
97119
}
98120

99121
/*
100-
* If the device itself is read-only, we can't allow
101-
* the user to change the state of quota on the mount -
102-
* this would generate a transaction on the ro device,
103-
* which would lead to an I/O error and shutdown
122+
* If the device itself is read-only and/or in norecovery
123+
* mode, we can't allow the user to change the state of
124+
* quota on the mount - this would generate a transaction
125+
* on the ro device, which would lead to an I/O error and
126+
* shutdown.
104127
*/
105128

106-
if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) ||
107-
(!uquotaondisk && XFS_IS_UQUOTA_ON(mp)) ||
108-
(gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
109-
(!gquotaondisk && XFS_IS_GQUOTA_ON(mp)) ||
110-
(pquotaondisk && !XFS_IS_PQUOTA_ON(mp)) ||
111-
(!pquotaondisk && XFS_IS_PQUOTA_ON(mp))) &&
112-
xfs_dev_is_read_only(mp, "changing quota state")) {
113-
xfs_warn(mp, "please mount with%s%s%s%s.",
114-
(!quotaondisk ? "out quota" : ""),
115-
(uquotaondisk ? " usrquota" : ""),
116-
(gquotaondisk ? " grpquota" : ""),
117-
(pquotaondisk ? " prjquota" : ""));
129+
if (xfs_qm_validate_state_change(mp, uquotaondisk,
130+
gquotaondisk, pquotaondisk)) {
131+
132+
if (xfs_has_metadir(mp))
133+
xfs_warn(mp,
134+
"metadir enabled, please mount without any quota mount options");
135+
else
136+
xfs_warn(mp, "please mount with%s%s%s%s.",
137+
(!quotaondisk ? "out quota" : ""),
138+
(uquotaondisk ? " usrquota" : ""),
139+
(gquotaondisk ? " grpquota" : ""),
140+
(pquotaondisk ? " prjquota" : ""));
118141
return -EPERM;
119142
}
120143

fs/xfs/xfs_super.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,8 +1661,12 @@ xfs_fs_fill_super(
16611661
#endif
16621662
}
16631663

1664-
/* Filesystem claims it needs repair, so refuse the mount. */
1665-
if (xfs_has_needsrepair(mp)) {
1664+
/*
1665+
* Filesystem claims it needs repair, so refuse the mount unless
1666+
* norecovery is also specified, in which case the filesystem can
1667+
* be mounted with no risk of further damage.
1668+
*/
1669+
if (xfs_has_needsrepair(mp) && !xfs_has_norecovery(mp)) {
16661670
xfs_warn(mp, "Filesystem needs repair. Please run xfs_repair.");
16671671
error = -EFSCORRUPTED;
16681672
goto out_free_sb;

0 commit comments

Comments
 (0)