summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_mount.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-08-14 18:56:02 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2018-08-14 18:56:02 +0300
commit781fca5b104693bc9242199cc47c690dcaf6a4cb (patch)
treed216d4299ae5715331a535c84bab390a907bebd6 /fs/xfs/xfs_mount.c
parent10f3e23f07cb0c20f9bcb77a5b5a7eb2a1b2a2fe (diff)
parent01239d77b9dd978863d1a75f0d095ab942a1fe66 (diff)
downloadlinux-781fca5b104693bc9242199cc47c690dcaf6a4cb.tar.xz
Merge tag 'xfs-4.19-merge-6' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull xfs updates from Darrick Wong: "This is the second part of the XFS changes for 4.19. The biggest changes are the removal of buffer heads frm XFS, a massive reworking of the deferred transaction operations handling code, the removal of the long defunct barrier/nobarrier mount options, and the addition of a few more online repair functions. Summary: - Use extent maps to track pagecache page status instead of bufferhead state. - Refactor pagecache read and write paths to use the new iomap library functions, which enable us to drop the old bufferhead code for pagesize == blocksize filesystems. - Set up parallel per-block-per-page metadata to track subpage information that was tracked by buffer heads, which enables us to drop the old bufferhead code for pagesize > blocksize filesystems. - Tie a deferred ops control structure to a transaction so that we can take advantage of an upper-level dfops without having to plumb pointer passing through the code. - Refactor the deferred ops code to track deferred ops as part of the transaction structure (instead of as a separate data structure) so that we can simplify the scoping rules around defer_ops. - Refactor twisty delwri buffer submission code to avoid deadlocks. - Shorten and fix indenting problems in the scrub code. - Detect obviously bad summary counts at mount and fix them. - Directly associate deferred ops control structure with a transaction so that callers no longer have to manage it themselves. - Remove a couple of IRIX-era inode macros. - Remove the long-deprecated 'barrier' and 'nobarrier' mount options. - Clean up the inode fork structure a bit. - Check for bad fs summary counter values in the superblock. - Reduce COW fork lookups during writeback. - Refactor the deferred ops control structures into the transaction structure, thereby eliminating the need for transaction users to handle the deferred ops as a separate data structure. - Add the ability to repair AG headers online. - Fix a crash due to insufficient return value checking. - Various fixes and cleanups" * tag 'xfs-4.19-merge-6' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: (155 commits) xfs: fix a null pointer dereference in xfs_bmap_extents_to_btree xfs: remove b_last_holder & associated macros iomap: Switch to offset_in_page for clarity xfs: Close race between direct IO and xfs_break_layouts() xfs: repair the AGI xfs: repair the AGFL xfs: repair the AGF xfs: remove dead error handling code in xfs_dquot_disk_alloc() xfs: use WRITE_ONCE to update if_seq xfs: fix a comment in xfs_log_reserve xfs: only validate summary counts on primary superblock xfs: substitute spaces with tabs xfs: fold dfops into the transaction xfs: always defer agfl block frees xfs: pass transaction to xfs_defer_add() xfs: replace xfs_defer_ops ->dop_pending with on-stack list xfs: cancel dfops on xfs_defer_finish() error xfs: clean out superfluous dfops dop params/vars xfs: drop dop param from xfs_defer_op_type ->finish_item() callback xfs: automatic dfops inode relogging ...
Diffstat (limited to 'fs/xfs/xfs_mount.c')
-rw-r--r--fs/xfs/xfs_mount.c100
1 files changed, 72 insertions, 28 deletions
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index a3378252baa1..99db27d6ac8a 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -207,6 +207,9 @@ xfs_initialize_perag(
if (xfs_buf_hash_init(pag))
goto out_free_pag;
init_waitqueue_head(&pag->pagb_wait);
+ spin_lock_init(&pag->pagb_lock);
+ pag->pagb_count = 0;
+ pag->pagb_tree = RB_ROOT;
if (radix_tree_preload(GFP_NOFS))
goto out_hash_destroy;
@@ -606,6 +609,56 @@ xfs_default_resblks(xfs_mount_t *mp)
return resblks;
}
+/* Ensure the summary counts are correct. */
+STATIC int
+xfs_check_summary_counts(
+ struct xfs_mount *mp)
+{
+ /*
+ * The AG0 superblock verifier rejects in-progress filesystems,
+ * so we should never see the flag set this far into mounting.
+ */
+ if (mp->m_sb.sb_inprogress) {
+ xfs_err(mp, "sb_inprogress set after log recovery??");
+ WARN_ON(1);
+ return -EFSCORRUPTED;
+ }
+
+ /*
+ * Now the log is mounted, we know if it was an unclean shutdown or
+ * not. If it was, with the first phase of recovery has completed, we
+ * have consistent AG blocks on disk. We have not recovered EFIs yet,
+ * but they are recovered transactionally in the second recovery phase
+ * later.
+ *
+ * If the log was clean when we mounted, we can check the summary
+ * counters. If any of them are obviously incorrect, we can recompute
+ * them from the AGF headers in the next step.
+ */
+ if (XFS_LAST_UNMOUNT_WAS_CLEAN(mp) &&
+ (mp->m_sb.sb_fdblocks > mp->m_sb.sb_dblocks ||
+ mp->m_sb.sb_ifree > mp->m_sb.sb_icount))
+ mp->m_flags |= XFS_MOUNT_BAD_SUMMARY;
+
+ /*
+ * We can safely re-initialise incore superblock counters from the
+ * per-ag data. These may not be correct if the filesystem was not
+ * cleanly unmounted, so we waited for recovery to finish before doing
+ * this.
+ *
+ * If the filesystem was cleanly unmounted or the previous check did
+ * not flag anything weird, then we can trust the values in the
+ * superblock to be correct and we don't need to do anything here.
+ * Otherwise, recalculate the summary counters.
+ */
+ if ((!xfs_sb_version_haslazysbcount(&mp->m_sb) ||
+ XFS_LAST_UNMOUNT_WAS_CLEAN(mp)) &&
+ !(mp->m_flags & XFS_MOUNT_BAD_SUMMARY))
+ return 0;
+
+ return xfs_initialize_perag_data(mp, mp->m_sb.sb_agcount);
+}
+
/*
* This function does the following on an initial mount of a file system:
* - reads the superblock from disk and init the mount struct
@@ -831,32 +884,10 @@ xfs_mountfs(
goto out_fail_wait;
}
- /*
- * Now the log is mounted, we know if it was an unclean shutdown or
- * not. If it was, with the first phase of recovery has completed, we
- * have consistent AG blocks on disk. We have not recovered EFIs yet,
- * but they are recovered transactionally in the second recovery phase
- * later.
- *
- * Hence we can safely re-initialise incore superblock counters from
- * the per-ag data. These may not be correct if the filesystem was not
- * cleanly unmounted, so we need to wait for recovery to finish before
- * doing this.
- *
- * If the filesystem was cleanly unmounted, then we can trust the
- * values in the superblock to be correct and we don't need to do
- * anything here.
- *
- * If we are currently making the filesystem, the initialisation will
- * fail as the perag data is in an undefined state.
- */
- if (xfs_sb_version_haslazysbcount(&mp->m_sb) &&
- !XFS_LAST_UNMOUNT_WAS_CLEAN(mp) &&
- !mp->m_sb.sb_inprogress) {
- error = xfs_initialize_perag_data(mp, sbp->sb_agcount);
- if (error)
- goto out_log_dealloc;
- }
+ /* Make sure the summary counts are ok. */
+ error = xfs_check_summary_counts(mp);
+ if (error)
+ goto out_log_dealloc;
/*
* Get and sanity-check the root inode.
@@ -1011,7 +1042,7 @@ xfs_mountfs(
out_rtunmount:
xfs_rtunmount_inodes(mp);
out_rele_rip:
- IRELE(rip);
+ xfs_irele(rip);
/* Clean out dquots that might be in memory after quotacheck. */
xfs_qm_unmount(mp);
/*
@@ -1067,7 +1098,7 @@ xfs_unmountfs(
xfs_fs_unreserve_ag_blocks(mp);
xfs_qm_unmount_quotas(mp);
xfs_rtunmount_inodes(mp);
- IRELE(mp->m_rootip);
+ xfs_irele(mp->m_rootip);
/*
* We can potentially deadlock here if we have an inode cluster
@@ -1395,3 +1426,16 @@ xfs_dev_is_read_only(
}
return 0;
}
+
+/* Force the summary counters to be recalculated at next mount. */
+void
+xfs_force_summary_recalc(
+ struct xfs_mount *mp)
+{
+ if (!xfs_sb_version_haslazysbcount(&mp->m_sb))
+ return;
+
+ spin_lock(&mp->m_sb_lock);
+ mp->m_flags |= XFS_MOUNT_BAD_SUMMARY;
+ spin_unlock(&mp->m_sb_lock);
+}