162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2000-2006 Silicon Graphics, Inc.
462306a36Sopenharmony_ci * All Rights Reserved.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "xfs.h"
862306a36Sopenharmony_ci#include "xfs_shared.h"
962306a36Sopenharmony_ci#include "xfs_format.h"
1062306a36Sopenharmony_ci#include "xfs_log_format.h"
1162306a36Sopenharmony_ci#include "xfs_trans_resv.h"
1262306a36Sopenharmony_ci#include "xfs_sb.h"
1362306a36Sopenharmony_ci#include "xfs_mount.h"
1462306a36Sopenharmony_ci#include "xfs_inode.h"
1562306a36Sopenharmony_ci#include "xfs_btree.h"
1662306a36Sopenharmony_ci#include "xfs_bmap.h"
1762306a36Sopenharmony_ci#include "xfs_alloc.h"
1862306a36Sopenharmony_ci#include "xfs_fsops.h"
1962306a36Sopenharmony_ci#include "xfs_trans.h"
2062306a36Sopenharmony_ci#include "xfs_buf_item.h"
2162306a36Sopenharmony_ci#include "xfs_log.h"
2262306a36Sopenharmony_ci#include "xfs_log_priv.h"
2362306a36Sopenharmony_ci#include "xfs_dir2.h"
2462306a36Sopenharmony_ci#include "xfs_extfree_item.h"
2562306a36Sopenharmony_ci#include "xfs_mru_cache.h"
2662306a36Sopenharmony_ci#include "xfs_inode_item.h"
2762306a36Sopenharmony_ci#include "xfs_icache.h"
2862306a36Sopenharmony_ci#include "xfs_trace.h"
2962306a36Sopenharmony_ci#include "xfs_icreate_item.h"
3062306a36Sopenharmony_ci#include "xfs_filestream.h"
3162306a36Sopenharmony_ci#include "xfs_quota.h"
3262306a36Sopenharmony_ci#include "xfs_sysfs.h"
3362306a36Sopenharmony_ci#include "xfs_ondisk.h"
3462306a36Sopenharmony_ci#include "xfs_rmap_item.h"
3562306a36Sopenharmony_ci#include "xfs_refcount_item.h"
3662306a36Sopenharmony_ci#include "xfs_bmap_item.h"
3762306a36Sopenharmony_ci#include "xfs_reflink.h"
3862306a36Sopenharmony_ci#include "xfs_pwork.h"
3962306a36Sopenharmony_ci#include "xfs_ag.h"
4062306a36Sopenharmony_ci#include "xfs_defer.h"
4162306a36Sopenharmony_ci#include "xfs_attr_item.h"
4262306a36Sopenharmony_ci#include "xfs_xattr.h"
4362306a36Sopenharmony_ci#include "xfs_iunlink_item.h"
4462306a36Sopenharmony_ci#include "xfs_dahash_test.h"
4562306a36Sopenharmony_ci#include "scrub/stats.h"
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#include <linux/magic.h>
4862306a36Sopenharmony_ci#include <linux/fs_context.h>
4962306a36Sopenharmony_ci#include <linux/fs_parser.h>
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic const struct super_operations xfs_super_operations;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic struct dentry *xfs_debugfs;	/* top-level xfs debugfs dir */
5462306a36Sopenharmony_cistatic struct kset *xfs_kset;		/* top-level xfs sysfs dir */
5562306a36Sopenharmony_ci#ifdef DEBUG
5662306a36Sopenharmony_cistatic struct xfs_kobj xfs_dbg_kobj;	/* global debug sysfs attrs */
5762306a36Sopenharmony_ci#endif
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cienum xfs_dax_mode {
6062306a36Sopenharmony_ci	XFS_DAX_INODE = 0,
6162306a36Sopenharmony_ci	XFS_DAX_ALWAYS = 1,
6262306a36Sopenharmony_ci	XFS_DAX_NEVER = 2,
6362306a36Sopenharmony_ci};
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic void
6662306a36Sopenharmony_cixfs_mount_set_dax_mode(
6762306a36Sopenharmony_ci	struct xfs_mount	*mp,
6862306a36Sopenharmony_ci	enum xfs_dax_mode	mode)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	switch (mode) {
7162306a36Sopenharmony_ci	case XFS_DAX_INODE:
7262306a36Sopenharmony_ci		mp->m_features &= ~(XFS_FEAT_DAX_ALWAYS | XFS_FEAT_DAX_NEVER);
7362306a36Sopenharmony_ci		break;
7462306a36Sopenharmony_ci	case XFS_DAX_ALWAYS:
7562306a36Sopenharmony_ci		mp->m_features |= XFS_FEAT_DAX_ALWAYS;
7662306a36Sopenharmony_ci		mp->m_features &= ~XFS_FEAT_DAX_NEVER;
7762306a36Sopenharmony_ci		break;
7862306a36Sopenharmony_ci	case XFS_DAX_NEVER:
7962306a36Sopenharmony_ci		mp->m_features |= XFS_FEAT_DAX_NEVER;
8062306a36Sopenharmony_ci		mp->m_features &= ~XFS_FEAT_DAX_ALWAYS;
8162306a36Sopenharmony_ci		break;
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic const struct constant_table dax_param_enums[] = {
8662306a36Sopenharmony_ci	{"inode",	XFS_DAX_INODE },
8762306a36Sopenharmony_ci	{"always",	XFS_DAX_ALWAYS },
8862306a36Sopenharmony_ci	{"never",	XFS_DAX_NEVER },
8962306a36Sopenharmony_ci	{}
9062306a36Sopenharmony_ci};
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/*
9362306a36Sopenharmony_ci * Table driven mount option parser.
9462306a36Sopenharmony_ci */
9562306a36Sopenharmony_cienum {
9662306a36Sopenharmony_ci	Opt_logbufs, Opt_logbsize, Opt_logdev, Opt_rtdev,
9762306a36Sopenharmony_ci	Opt_wsync, Opt_noalign, Opt_swalloc, Opt_sunit, Opt_swidth, Opt_nouuid,
9862306a36Sopenharmony_ci	Opt_grpid, Opt_nogrpid, Opt_bsdgroups, Opt_sysvgroups,
9962306a36Sopenharmony_ci	Opt_allocsize, Opt_norecovery, Opt_inode64, Opt_inode32, Opt_ikeep,
10062306a36Sopenharmony_ci	Opt_noikeep, Opt_largeio, Opt_nolargeio, Opt_attr2, Opt_noattr2,
10162306a36Sopenharmony_ci	Opt_filestreams, Opt_quota, Opt_noquota, Opt_usrquota, Opt_grpquota,
10262306a36Sopenharmony_ci	Opt_prjquota, Opt_uquota, Opt_gquota, Opt_pquota,
10362306a36Sopenharmony_ci	Opt_uqnoenforce, Opt_gqnoenforce, Opt_pqnoenforce, Opt_qnoenforce,
10462306a36Sopenharmony_ci	Opt_discard, Opt_nodiscard, Opt_dax, Opt_dax_enum,
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic const struct fs_parameter_spec xfs_fs_parameters[] = {
10862306a36Sopenharmony_ci	fsparam_u32("logbufs",		Opt_logbufs),
10962306a36Sopenharmony_ci	fsparam_string("logbsize",	Opt_logbsize),
11062306a36Sopenharmony_ci	fsparam_string("logdev",	Opt_logdev),
11162306a36Sopenharmony_ci	fsparam_string("rtdev",		Opt_rtdev),
11262306a36Sopenharmony_ci	fsparam_flag("wsync",		Opt_wsync),
11362306a36Sopenharmony_ci	fsparam_flag("noalign",		Opt_noalign),
11462306a36Sopenharmony_ci	fsparam_flag("swalloc",		Opt_swalloc),
11562306a36Sopenharmony_ci	fsparam_u32("sunit",		Opt_sunit),
11662306a36Sopenharmony_ci	fsparam_u32("swidth",		Opt_swidth),
11762306a36Sopenharmony_ci	fsparam_flag("nouuid",		Opt_nouuid),
11862306a36Sopenharmony_ci	fsparam_flag("grpid",		Opt_grpid),
11962306a36Sopenharmony_ci	fsparam_flag("nogrpid",		Opt_nogrpid),
12062306a36Sopenharmony_ci	fsparam_flag("bsdgroups",	Opt_bsdgroups),
12162306a36Sopenharmony_ci	fsparam_flag("sysvgroups",	Opt_sysvgroups),
12262306a36Sopenharmony_ci	fsparam_string("allocsize",	Opt_allocsize),
12362306a36Sopenharmony_ci	fsparam_flag("norecovery",	Opt_norecovery),
12462306a36Sopenharmony_ci	fsparam_flag("inode64",		Opt_inode64),
12562306a36Sopenharmony_ci	fsparam_flag("inode32",		Opt_inode32),
12662306a36Sopenharmony_ci	fsparam_flag("ikeep",		Opt_ikeep),
12762306a36Sopenharmony_ci	fsparam_flag("noikeep",		Opt_noikeep),
12862306a36Sopenharmony_ci	fsparam_flag("largeio",		Opt_largeio),
12962306a36Sopenharmony_ci	fsparam_flag("nolargeio",	Opt_nolargeio),
13062306a36Sopenharmony_ci	fsparam_flag("attr2",		Opt_attr2),
13162306a36Sopenharmony_ci	fsparam_flag("noattr2",		Opt_noattr2),
13262306a36Sopenharmony_ci	fsparam_flag("filestreams",	Opt_filestreams),
13362306a36Sopenharmony_ci	fsparam_flag("quota",		Opt_quota),
13462306a36Sopenharmony_ci	fsparam_flag("noquota",		Opt_noquota),
13562306a36Sopenharmony_ci	fsparam_flag("usrquota",	Opt_usrquota),
13662306a36Sopenharmony_ci	fsparam_flag("grpquota",	Opt_grpquota),
13762306a36Sopenharmony_ci	fsparam_flag("prjquota",	Opt_prjquota),
13862306a36Sopenharmony_ci	fsparam_flag("uquota",		Opt_uquota),
13962306a36Sopenharmony_ci	fsparam_flag("gquota",		Opt_gquota),
14062306a36Sopenharmony_ci	fsparam_flag("pquota",		Opt_pquota),
14162306a36Sopenharmony_ci	fsparam_flag("uqnoenforce",	Opt_uqnoenforce),
14262306a36Sopenharmony_ci	fsparam_flag("gqnoenforce",	Opt_gqnoenforce),
14362306a36Sopenharmony_ci	fsparam_flag("pqnoenforce",	Opt_pqnoenforce),
14462306a36Sopenharmony_ci	fsparam_flag("qnoenforce",	Opt_qnoenforce),
14562306a36Sopenharmony_ci	fsparam_flag("discard",		Opt_discard),
14662306a36Sopenharmony_ci	fsparam_flag("nodiscard",	Opt_nodiscard),
14762306a36Sopenharmony_ci	fsparam_flag("dax",		Opt_dax),
14862306a36Sopenharmony_ci	fsparam_enum("dax",		Opt_dax_enum, dax_param_enums),
14962306a36Sopenharmony_ci	{}
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistruct proc_xfs_info {
15362306a36Sopenharmony_ci	uint64_t	flag;
15462306a36Sopenharmony_ci	char		*str;
15562306a36Sopenharmony_ci};
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic int
15862306a36Sopenharmony_cixfs_fs_show_options(
15962306a36Sopenharmony_ci	struct seq_file		*m,
16062306a36Sopenharmony_ci	struct dentry		*root)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	static struct proc_xfs_info xfs_info_set[] = {
16362306a36Sopenharmony_ci		/* the few simple ones we can get from the mount struct */
16462306a36Sopenharmony_ci		{ XFS_FEAT_IKEEP,		",ikeep" },
16562306a36Sopenharmony_ci		{ XFS_FEAT_WSYNC,		",wsync" },
16662306a36Sopenharmony_ci		{ XFS_FEAT_NOALIGN,		",noalign" },
16762306a36Sopenharmony_ci		{ XFS_FEAT_SWALLOC,		",swalloc" },
16862306a36Sopenharmony_ci		{ XFS_FEAT_NOUUID,		",nouuid" },
16962306a36Sopenharmony_ci		{ XFS_FEAT_NORECOVERY,		",norecovery" },
17062306a36Sopenharmony_ci		{ XFS_FEAT_ATTR2,		",attr2" },
17162306a36Sopenharmony_ci		{ XFS_FEAT_FILESTREAMS,		",filestreams" },
17262306a36Sopenharmony_ci		{ XFS_FEAT_GRPID,		",grpid" },
17362306a36Sopenharmony_ci		{ XFS_FEAT_DISCARD,		",discard" },
17462306a36Sopenharmony_ci		{ XFS_FEAT_LARGE_IOSIZE,	",largeio" },
17562306a36Sopenharmony_ci		{ XFS_FEAT_DAX_ALWAYS,		",dax=always" },
17662306a36Sopenharmony_ci		{ XFS_FEAT_DAX_NEVER,		",dax=never" },
17762306a36Sopenharmony_ci		{ 0, NULL }
17862306a36Sopenharmony_ci	};
17962306a36Sopenharmony_ci	struct xfs_mount	*mp = XFS_M(root->d_sb);
18062306a36Sopenharmony_ci	struct proc_xfs_info	*xfs_infop;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	for (xfs_infop = xfs_info_set; xfs_infop->flag; xfs_infop++) {
18362306a36Sopenharmony_ci		if (mp->m_features & xfs_infop->flag)
18462306a36Sopenharmony_ci			seq_puts(m, xfs_infop->str);
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	seq_printf(m, ",inode%d", xfs_has_small_inums(mp) ? 32 : 64);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	if (xfs_has_allocsize(mp))
19062306a36Sopenharmony_ci		seq_printf(m, ",allocsize=%dk",
19162306a36Sopenharmony_ci			   (1 << mp->m_allocsize_log) >> 10);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	if (mp->m_logbufs > 0)
19462306a36Sopenharmony_ci		seq_printf(m, ",logbufs=%d", mp->m_logbufs);
19562306a36Sopenharmony_ci	if (mp->m_logbsize > 0)
19662306a36Sopenharmony_ci		seq_printf(m, ",logbsize=%dk", mp->m_logbsize >> 10);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	if (mp->m_logname)
19962306a36Sopenharmony_ci		seq_show_option(m, "logdev", mp->m_logname);
20062306a36Sopenharmony_ci	if (mp->m_rtname)
20162306a36Sopenharmony_ci		seq_show_option(m, "rtdev", mp->m_rtname);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (mp->m_dalign > 0)
20462306a36Sopenharmony_ci		seq_printf(m, ",sunit=%d",
20562306a36Sopenharmony_ci				(int)XFS_FSB_TO_BB(mp, mp->m_dalign));
20662306a36Sopenharmony_ci	if (mp->m_swidth > 0)
20762306a36Sopenharmony_ci		seq_printf(m, ",swidth=%d",
20862306a36Sopenharmony_ci				(int)XFS_FSB_TO_BB(mp, mp->m_swidth));
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	if (mp->m_qflags & XFS_UQUOTA_ENFD)
21162306a36Sopenharmony_ci		seq_puts(m, ",usrquota");
21262306a36Sopenharmony_ci	else if (mp->m_qflags & XFS_UQUOTA_ACCT)
21362306a36Sopenharmony_ci		seq_puts(m, ",uqnoenforce");
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	if (mp->m_qflags & XFS_PQUOTA_ENFD)
21662306a36Sopenharmony_ci		seq_puts(m, ",prjquota");
21762306a36Sopenharmony_ci	else if (mp->m_qflags & XFS_PQUOTA_ACCT)
21862306a36Sopenharmony_ci		seq_puts(m, ",pqnoenforce");
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (mp->m_qflags & XFS_GQUOTA_ENFD)
22162306a36Sopenharmony_ci		seq_puts(m, ",grpquota");
22262306a36Sopenharmony_ci	else if (mp->m_qflags & XFS_GQUOTA_ACCT)
22362306a36Sopenharmony_ci		seq_puts(m, ",gqnoenforce");
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT))
22662306a36Sopenharmony_ci		seq_puts(m, ",noquota");
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	return 0;
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic bool
23262306a36Sopenharmony_cixfs_set_inode_alloc_perag(
23362306a36Sopenharmony_ci	struct xfs_perag	*pag,
23462306a36Sopenharmony_ci	xfs_ino_t		ino,
23562306a36Sopenharmony_ci	xfs_agnumber_t		max_metadata)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	if (!xfs_is_inode32(pag->pag_mount)) {
23862306a36Sopenharmony_ci		set_bit(XFS_AGSTATE_ALLOWS_INODES, &pag->pag_opstate);
23962306a36Sopenharmony_ci		clear_bit(XFS_AGSTATE_PREFERS_METADATA, &pag->pag_opstate);
24062306a36Sopenharmony_ci		return false;
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	if (ino > XFS_MAXINUMBER_32) {
24462306a36Sopenharmony_ci		clear_bit(XFS_AGSTATE_ALLOWS_INODES, &pag->pag_opstate);
24562306a36Sopenharmony_ci		clear_bit(XFS_AGSTATE_PREFERS_METADATA, &pag->pag_opstate);
24662306a36Sopenharmony_ci		return false;
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	set_bit(XFS_AGSTATE_ALLOWS_INODES, &pag->pag_opstate);
25062306a36Sopenharmony_ci	if (pag->pag_agno < max_metadata)
25162306a36Sopenharmony_ci		set_bit(XFS_AGSTATE_PREFERS_METADATA, &pag->pag_opstate);
25262306a36Sopenharmony_ci	else
25362306a36Sopenharmony_ci		clear_bit(XFS_AGSTATE_PREFERS_METADATA, &pag->pag_opstate);
25462306a36Sopenharmony_ci	return true;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci/*
25862306a36Sopenharmony_ci * Set parameters for inode allocation heuristics, taking into account
25962306a36Sopenharmony_ci * filesystem size and inode32/inode64 mount options; i.e. specifically
26062306a36Sopenharmony_ci * whether or not XFS_FEAT_SMALL_INUMS is set.
26162306a36Sopenharmony_ci *
26262306a36Sopenharmony_ci * Inode allocation patterns are altered only if inode32 is requested
26362306a36Sopenharmony_ci * (XFS_FEAT_SMALL_INUMS), and the filesystem is sufficiently large.
26462306a36Sopenharmony_ci * If altered, XFS_OPSTATE_INODE32 is set as well.
26562306a36Sopenharmony_ci *
26662306a36Sopenharmony_ci * An agcount independent of that in the mount structure is provided
26762306a36Sopenharmony_ci * because in the growfs case, mp->m_sb.sb_agcount is not yet updated
26862306a36Sopenharmony_ci * to the potentially higher ag count.
26962306a36Sopenharmony_ci *
27062306a36Sopenharmony_ci * Returns the maximum AG index which may contain inodes.
27162306a36Sopenharmony_ci */
27262306a36Sopenharmony_cixfs_agnumber_t
27362306a36Sopenharmony_cixfs_set_inode_alloc(
27462306a36Sopenharmony_ci	struct xfs_mount *mp,
27562306a36Sopenharmony_ci	xfs_agnumber_t	agcount)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	xfs_agnumber_t	index;
27862306a36Sopenharmony_ci	xfs_agnumber_t	maxagi = 0;
27962306a36Sopenharmony_ci	xfs_sb_t	*sbp = &mp->m_sb;
28062306a36Sopenharmony_ci	xfs_agnumber_t	max_metadata;
28162306a36Sopenharmony_ci	xfs_agino_t	agino;
28262306a36Sopenharmony_ci	xfs_ino_t	ino;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	/*
28562306a36Sopenharmony_ci	 * Calculate how much should be reserved for inodes to meet
28662306a36Sopenharmony_ci	 * the max inode percentage.  Used only for inode32.
28762306a36Sopenharmony_ci	 */
28862306a36Sopenharmony_ci	if (M_IGEO(mp)->maxicount) {
28962306a36Sopenharmony_ci		uint64_t	icount;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci		icount = sbp->sb_dblocks * sbp->sb_imax_pct;
29262306a36Sopenharmony_ci		do_div(icount, 100);
29362306a36Sopenharmony_ci		icount += sbp->sb_agblocks - 1;
29462306a36Sopenharmony_ci		do_div(icount, sbp->sb_agblocks);
29562306a36Sopenharmony_ci		max_metadata = icount;
29662306a36Sopenharmony_ci	} else {
29762306a36Sopenharmony_ci		max_metadata = agcount;
29862306a36Sopenharmony_ci	}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	/* Get the last possible inode in the filesystem */
30162306a36Sopenharmony_ci	agino =	XFS_AGB_TO_AGINO(mp, sbp->sb_agblocks - 1);
30262306a36Sopenharmony_ci	ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	/*
30562306a36Sopenharmony_ci	 * If user asked for no more than 32-bit inodes, and the fs is
30662306a36Sopenharmony_ci	 * sufficiently large, set XFS_OPSTATE_INODE32 if we must alter
30762306a36Sopenharmony_ci	 * the allocator to accommodate the request.
30862306a36Sopenharmony_ci	 */
30962306a36Sopenharmony_ci	if (xfs_has_small_inums(mp) && ino > XFS_MAXINUMBER_32)
31062306a36Sopenharmony_ci		set_bit(XFS_OPSTATE_INODE32, &mp->m_opstate);
31162306a36Sopenharmony_ci	else
31262306a36Sopenharmony_ci		clear_bit(XFS_OPSTATE_INODE32, &mp->m_opstate);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	for (index = 0; index < agcount; index++) {
31562306a36Sopenharmony_ci		struct xfs_perag	*pag;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci		ino = XFS_AGINO_TO_INO(mp, index, agino);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci		pag = xfs_perag_get(mp, index);
32062306a36Sopenharmony_ci		if (xfs_set_inode_alloc_perag(pag, ino, max_metadata))
32162306a36Sopenharmony_ci			maxagi++;
32262306a36Sopenharmony_ci		xfs_perag_put(pag);
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	return xfs_is_inode32(mp) ? maxagi : agcount;
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic int
32962306a36Sopenharmony_cixfs_setup_dax_always(
33062306a36Sopenharmony_ci	struct xfs_mount	*mp)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	if (!mp->m_ddev_targp->bt_daxdev &&
33362306a36Sopenharmony_ci	    (!mp->m_rtdev_targp || !mp->m_rtdev_targp->bt_daxdev)) {
33462306a36Sopenharmony_ci		xfs_alert(mp,
33562306a36Sopenharmony_ci			"DAX unsupported by block device. Turning off DAX.");
33662306a36Sopenharmony_ci		goto disable_dax;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (mp->m_super->s_blocksize != PAGE_SIZE) {
34062306a36Sopenharmony_ci		xfs_alert(mp,
34162306a36Sopenharmony_ci			"DAX not supported for blocksize. Turning off DAX.");
34262306a36Sopenharmony_ci		goto disable_dax;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (xfs_has_reflink(mp) &&
34662306a36Sopenharmony_ci	    bdev_is_partition(mp->m_ddev_targp->bt_bdev)) {
34762306a36Sopenharmony_ci		xfs_alert(mp,
34862306a36Sopenharmony_ci			"DAX and reflink cannot work with multi-partitions!");
34962306a36Sopenharmony_ci		return -EINVAL;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	xfs_warn(mp, "DAX enabled. Warning: EXPERIMENTAL, use at your own risk");
35362306a36Sopenharmony_ci	return 0;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cidisable_dax:
35662306a36Sopenharmony_ci	xfs_mount_set_dax_mode(mp, XFS_DAX_NEVER);
35762306a36Sopenharmony_ci	return 0;
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ciSTATIC int
36162306a36Sopenharmony_cixfs_blkdev_get(
36262306a36Sopenharmony_ci	xfs_mount_t		*mp,
36362306a36Sopenharmony_ci	const char		*name,
36462306a36Sopenharmony_ci	struct block_device	**bdevp)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	int			error = 0;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	*bdevp = blkdev_get_by_path(name, BLK_OPEN_READ | BLK_OPEN_WRITE,
36962306a36Sopenharmony_ci				    mp->m_super, &fs_holder_ops);
37062306a36Sopenharmony_ci	if (IS_ERR(*bdevp)) {
37162306a36Sopenharmony_ci		error = PTR_ERR(*bdevp);
37262306a36Sopenharmony_ci		xfs_warn(mp, "Invalid device [%s], error=%d", name, error);
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	return error;
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ciSTATIC void
37962306a36Sopenharmony_cixfs_shutdown_devices(
38062306a36Sopenharmony_ci	struct xfs_mount	*mp)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	/*
38362306a36Sopenharmony_ci	 * Udev is triggered whenever anyone closes a block device or unmounts
38462306a36Sopenharmony_ci	 * a file systemm on a block device.
38562306a36Sopenharmony_ci	 * The default udev rules invoke blkid to read the fs super and create
38662306a36Sopenharmony_ci	 * symlinks to the bdev under /dev/disk.  For this, it uses buffered
38762306a36Sopenharmony_ci	 * reads through the page cache.
38862306a36Sopenharmony_ci	 *
38962306a36Sopenharmony_ci	 * xfs_db also uses buffered reads to examine metadata.  There is no
39062306a36Sopenharmony_ci	 * coordination between xfs_db and udev, which means that they can run
39162306a36Sopenharmony_ci	 * concurrently.  Note there is no coordination between the kernel and
39262306a36Sopenharmony_ci	 * blkid either.
39362306a36Sopenharmony_ci	 *
39462306a36Sopenharmony_ci	 * On a system with 64k pages, the page cache can cache the superblock
39562306a36Sopenharmony_ci	 * and the root inode (and hence the root directory) with the same 64k
39662306a36Sopenharmony_ci	 * page.  If udev spawns blkid after the mkfs and the system is busy
39762306a36Sopenharmony_ci	 * enough that it is still running when xfs_db starts up, they'll both
39862306a36Sopenharmony_ci	 * read from the same page in the pagecache.
39962306a36Sopenharmony_ci	 *
40062306a36Sopenharmony_ci	 * The unmount writes updated inode metadata to disk directly.  The XFS
40162306a36Sopenharmony_ci	 * buffer cache does not use the bdev pagecache, so it needs to
40262306a36Sopenharmony_ci	 * invalidate that pagecache on unmount.  If the above scenario occurs,
40362306a36Sopenharmony_ci	 * the pagecache no longer reflects what's on disk, xfs_db reads the
40462306a36Sopenharmony_ci	 * stale metadata, and fails to find /a.  Most of the time this succeeds
40562306a36Sopenharmony_ci	 * because closing a bdev invalidates the page cache, but when processes
40662306a36Sopenharmony_ci	 * race, everyone loses.
40762306a36Sopenharmony_ci	 */
40862306a36Sopenharmony_ci	if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) {
40962306a36Sopenharmony_ci		blkdev_issue_flush(mp->m_logdev_targp->bt_bdev);
41062306a36Sopenharmony_ci		invalidate_bdev(mp->m_logdev_targp->bt_bdev);
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci	if (mp->m_rtdev_targp) {
41362306a36Sopenharmony_ci		blkdev_issue_flush(mp->m_rtdev_targp->bt_bdev);
41462306a36Sopenharmony_ci		invalidate_bdev(mp->m_rtdev_targp->bt_bdev);
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci	blkdev_issue_flush(mp->m_ddev_targp->bt_bdev);
41762306a36Sopenharmony_ci	invalidate_bdev(mp->m_ddev_targp->bt_bdev);
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci/*
42162306a36Sopenharmony_ci * The file system configurations are:
42262306a36Sopenharmony_ci *	(1) device (partition) with data and internal log
42362306a36Sopenharmony_ci *	(2) logical volume with data and log subvolumes.
42462306a36Sopenharmony_ci *	(3) logical volume with data, log, and realtime subvolumes.
42562306a36Sopenharmony_ci *
42662306a36Sopenharmony_ci * We only have to handle opening the log and realtime volumes here if
42762306a36Sopenharmony_ci * they are present.  The data subvolume has already been opened by
42862306a36Sopenharmony_ci * get_sb_bdev() and is stored in sb->s_bdev.
42962306a36Sopenharmony_ci */
43062306a36Sopenharmony_ciSTATIC int
43162306a36Sopenharmony_cixfs_open_devices(
43262306a36Sopenharmony_ci	struct xfs_mount	*mp)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	struct super_block	*sb = mp->m_super;
43562306a36Sopenharmony_ci	struct block_device	*ddev = sb->s_bdev;
43662306a36Sopenharmony_ci	struct block_device	*logdev = NULL, *rtdev = NULL;
43762306a36Sopenharmony_ci	int			error;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	/*
44062306a36Sopenharmony_ci	 * blkdev_put() can't be called under s_umount, see the comment
44162306a36Sopenharmony_ci	 * in get_tree_bdev() for more details
44262306a36Sopenharmony_ci	 */
44362306a36Sopenharmony_ci	up_write(&sb->s_umount);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	/*
44662306a36Sopenharmony_ci	 * Open real time and log devices - order is important.
44762306a36Sopenharmony_ci	 */
44862306a36Sopenharmony_ci	if (mp->m_logname) {
44962306a36Sopenharmony_ci		error = xfs_blkdev_get(mp, mp->m_logname, &logdev);
45062306a36Sopenharmony_ci		if (error)
45162306a36Sopenharmony_ci			goto out_relock;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	if (mp->m_rtname) {
45562306a36Sopenharmony_ci		error = xfs_blkdev_get(mp, mp->m_rtname, &rtdev);
45662306a36Sopenharmony_ci		if (error)
45762306a36Sopenharmony_ci			goto out_close_logdev;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci		if (rtdev == ddev || rtdev == logdev) {
46062306a36Sopenharmony_ci			xfs_warn(mp,
46162306a36Sopenharmony_ci	"Cannot mount filesystem with identical rtdev and ddev/logdev.");
46262306a36Sopenharmony_ci			error = -EINVAL;
46362306a36Sopenharmony_ci			goto out_close_rtdev;
46462306a36Sopenharmony_ci		}
46562306a36Sopenharmony_ci	}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	/*
46862306a36Sopenharmony_ci	 * Setup xfs_mount buffer target pointers
46962306a36Sopenharmony_ci	 */
47062306a36Sopenharmony_ci	error = -ENOMEM;
47162306a36Sopenharmony_ci	mp->m_ddev_targp = xfs_alloc_buftarg(mp, ddev);
47262306a36Sopenharmony_ci	if (!mp->m_ddev_targp)
47362306a36Sopenharmony_ci		goto out_close_rtdev;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	if (rtdev) {
47662306a36Sopenharmony_ci		mp->m_rtdev_targp = xfs_alloc_buftarg(mp, rtdev);
47762306a36Sopenharmony_ci		if (!mp->m_rtdev_targp)
47862306a36Sopenharmony_ci			goto out_free_ddev_targ;
47962306a36Sopenharmony_ci	}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	if (logdev && logdev != ddev) {
48262306a36Sopenharmony_ci		mp->m_logdev_targp = xfs_alloc_buftarg(mp, logdev);
48362306a36Sopenharmony_ci		if (!mp->m_logdev_targp)
48462306a36Sopenharmony_ci			goto out_free_rtdev_targ;
48562306a36Sopenharmony_ci	} else {
48662306a36Sopenharmony_ci		mp->m_logdev_targp = mp->m_ddev_targp;
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	error = 0;
49062306a36Sopenharmony_ciout_relock:
49162306a36Sopenharmony_ci	down_write(&sb->s_umount);
49262306a36Sopenharmony_ci	return error;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci out_free_rtdev_targ:
49562306a36Sopenharmony_ci	if (mp->m_rtdev_targp)
49662306a36Sopenharmony_ci		xfs_free_buftarg(mp->m_rtdev_targp);
49762306a36Sopenharmony_ci out_free_ddev_targ:
49862306a36Sopenharmony_ci	xfs_free_buftarg(mp->m_ddev_targp);
49962306a36Sopenharmony_ci out_close_rtdev:
50062306a36Sopenharmony_ci	 if (rtdev)
50162306a36Sopenharmony_ci		 blkdev_put(rtdev, sb);
50262306a36Sopenharmony_ci out_close_logdev:
50362306a36Sopenharmony_ci	if (logdev && logdev != ddev)
50462306a36Sopenharmony_ci		blkdev_put(logdev, sb);
50562306a36Sopenharmony_ci	goto out_relock;
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci/*
50962306a36Sopenharmony_ci * Setup xfs_mount buffer target pointers based on superblock
51062306a36Sopenharmony_ci */
51162306a36Sopenharmony_ciSTATIC int
51262306a36Sopenharmony_cixfs_setup_devices(
51362306a36Sopenharmony_ci	struct xfs_mount	*mp)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	int			error;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	error = xfs_setsize_buftarg(mp->m_ddev_targp, mp->m_sb.sb_sectsize);
51862306a36Sopenharmony_ci	if (error)
51962306a36Sopenharmony_ci		return error;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) {
52262306a36Sopenharmony_ci		unsigned int	log_sector_size = BBSIZE;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci		if (xfs_has_sector(mp))
52562306a36Sopenharmony_ci			log_sector_size = mp->m_sb.sb_logsectsize;
52662306a36Sopenharmony_ci		error = xfs_setsize_buftarg(mp->m_logdev_targp,
52762306a36Sopenharmony_ci					    log_sector_size);
52862306a36Sopenharmony_ci		if (error)
52962306a36Sopenharmony_ci			return error;
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci	if (mp->m_rtdev_targp) {
53262306a36Sopenharmony_ci		error = xfs_setsize_buftarg(mp->m_rtdev_targp,
53362306a36Sopenharmony_ci					    mp->m_sb.sb_sectsize);
53462306a36Sopenharmony_ci		if (error)
53562306a36Sopenharmony_ci			return error;
53662306a36Sopenharmony_ci	}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	return 0;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ciSTATIC int
54262306a36Sopenharmony_cixfs_init_mount_workqueues(
54362306a36Sopenharmony_ci	struct xfs_mount	*mp)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	mp->m_buf_workqueue = alloc_workqueue("xfs-buf/%s",
54662306a36Sopenharmony_ci			XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM),
54762306a36Sopenharmony_ci			1, mp->m_super->s_id);
54862306a36Sopenharmony_ci	if (!mp->m_buf_workqueue)
54962306a36Sopenharmony_ci		goto out;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	mp->m_unwritten_workqueue = alloc_workqueue("xfs-conv/%s",
55262306a36Sopenharmony_ci			XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM),
55362306a36Sopenharmony_ci			0, mp->m_super->s_id);
55462306a36Sopenharmony_ci	if (!mp->m_unwritten_workqueue)
55562306a36Sopenharmony_ci		goto out_destroy_buf;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	mp->m_reclaim_workqueue = alloc_workqueue("xfs-reclaim/%s",
55862306a36Sopenharmony_ci			XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM),
55962306a36Sopenharmony_ci			0, mp->m_super->s_id);
56062306a36Sopenharmony_ci	if (!mp->m_reclaim_workqueue)
56162306a36Sopenharmony_ci		goto out_destroy_unwritten;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	mp->m_blockgc_wq = alloc_workqueue("xfs-blockgc/%s",
56462306a36Sopenharmony_ci			XFS_WQFLAGS(WQ_UNBOUND | WQ_FREEZABLE | WQ_MEM_RECLAIM),
56562306a36Sopenharmony_ci			0, mp->m_super->s_id);
56662306a36Sopenharmony_ci	if (!mp->m_blockgc_wq)
56762306a36Sopenharmony_ci		goto out_destroy_reclaim;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	mp->m_inodegc_wq = alloc_workqueue("xfs-inodegc/%s",
57062306a36Sopenharmony_ci			XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM),
57162306a36Sopenharmony_ci			1, mp->m_super->s_id);
57262306a36Sopenharmony_ci	if (!mp->m_inodegc_wq)
57362306a36Sopenharmony_ci		goto out_destroy_blockgc;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	mp->m_sync_workqueue = alloc_workqueue("xfs-sync/%s",
57662306a36Sopenharmony_ci			XFS_WQFLAGS(WQ_FREEZABLE), 0, mp->m_super->s_id);
57762306a36Sopenharmony_ci	if (!mp->m_sync_workqueue)
57862306a36Sopenharmony_ci		goto out_destroy_inodegc;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	return 0;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ciout_destroy_inodegc:
58362306a36Sopenharmony_ci	destroy_workqueue(mp->m_inodegc_wq);
58462306a36Sopenharmony_ciout_destroy_blockgc:
58562306a36Sopenharmony_ci	destroy_workqueue(mp->m_blockgc_wq);
58662306a36Sopenharmony_ciout_destroy_reclaim:
58762306a36Sopenharmony_ci	destroy_workqueue(mp->m_reclaim_workqueue);
58862306a36Sopenharmony_ciout_destroy_unwritten:
58962306a36Sopenharmony_ci	destroy_workqueue(mp->m_unwritten_workqueue);
59062306a36Sopenharmony_ciout_destroy_buf:
59162306a36Sopenharmony_ci	destroy_workqueue(mp->m_buf_workqueue);
59262306a36Sopenharmony_ciout:
59362306a36Sopenharmony_ci	return -ENOMEM;
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ciSTATIC void
59762306a36Sopenharmony_cixfs_destroy_mount_workqueues(
59862306a36Sopenharmony_ci	struct xfs_mount	*mp)
59962306a36Sopenharmony_ci{
60062306a36Sopenharmony_ci	destroy_workqueue(mp->m_sync_workqueue);
60162306a36Sopenharmony_ci	destroy_workqueue(mp->m_blockgc_wq);
60262306a36Sopenharmony_ci	destroy_workqueue(mp->m_inodegc_wq);
60362306a36Sopenharmony_ci	destroy_workqueue(mp->m_reclaim_workqueue);
60462306a36Sopenharmony_ci	destroy_workqueue(mp->m_unwritten_workqueue);
60562306a36Sopenharmony_ci	destroy_workqueue(mp->m_buf_workqueue);
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_cistatic void
60962306a36Sopenharmony_cixfs_flush_inodes_worker(
61062306a36Sopenharmony_ci	struct work_struct	*work)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	struct xfs_mount	*mp = container_of(work, struct xfs_mount,
61362306a36Sopenharmony_ci						   m_flush_inodes_work);
61462306a36Sopenharmony_ci	struct super_block	*sb = mp->m_super;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	if (down_read_trylock(&sb->s_umount)) {
61762306a36Sopenharmony_ci		sync_inodes_sb(sb);
61862306a36Sopenharmony_ci		up_read(&sb->s_umount);
61962306a36Sopenharmony_ci	}
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci/*
62362306a36Sopenharmony_ci * Flush all dirty data to disk. Must not be called while holding an XFS_ILOCK
62462306a36Sopenharmony_ci * or a page lock. We use sync_inodes_sb() here to ensure we block while waiting
62562306a36Sopenharmony_ci * for IO to complete so that we effectively throttle multiple callers to the
62662306a36Sopenharmony_ci * rate at which IO is completing.
62762306a36Sopenharmony_ci */
62862306a36Sopenharmony_civoid
62962306a36Sopenharmony_cixfs_flush_inodes(
63062306a36Sopenharmony_ci	struct xfs_mount	*mp)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	/*
63362306a36Sopenharmony_ci	 * If flush_work() returns true then that means we waited for a flush
63462306a36Sopenharmony_ci	 * which was already in progress.  Don't bother running another scan.
63562306a36Sopenharmony_ci	 */
63662306a36Sopenharmony_ci	if (flush_work(&mp->m_flush_inodes_work))
63762306a36Sopenharmony_ci		return;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	queue_work(mp->m_sync_workqueue, &mp->m_flush_inodes_work);
64062306a36Sopenharmony_ci	flush_work(&mp->m_flush_inodes_work);
64162306a36Sopenharmony_ci}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci/* Catch misguided souls that try to use this interface on XFS */
64462306a36Sopenharmony_ciSTATIC struct inode *
64562306a36Sopenharmony_cixfs_fs_alloc_inode(
64662306a36Sopenharmony_ci	struct super_block	*sb)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	BUG();
64962306a36Sopenharmony_ci	return NULL;
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci/*
65362306a36Sopenharmony_ci * Now that the generic code is guaranteed not to be accessing
65462306a36Sopenharmony_ci * the linux inode, we can inactivate and reclaim the inode.
65562306a36Sopenharmony_ci */
65662306a36Sopenharmony_ciSTATIC void
65762306a36Sopenharmony_cixfs_fs_destroy_inode(
65862306a36Sopenharmony_ci	struct inode		*inode)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	struct xfs_inode	*ip = XFS_I(inode);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	trace_xfs_destroy_inode(ip);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	ASSERT(!rwsem_is_locked(&inode->i_rwsem));
66562306a36Sopenharmony_ci	XFS_STATS_INC(ip->i_mount, vn_rele);
66662306a36Sopenharmony_ci	XFS_STATS_INC(ip->i_mount, vn_remove);
66762306a36Sopenharmony_ci	xfs_inode_mark_reclaimable(ip);
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic void
67162306a36Sopenharmony_cixfs_fs_dirty_inode(
67262306a36Sopenharmony_ci	struct inode			*inode,
67362306a36Sopenharmony_ci	int				flags)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	struct xfs_inode		*ip = XFS_I(inode);
67662306a36Sopenharmony_ci	struct xfs_mount		*mp = ip->i_mount;
67762306a36Sopenharmony_ci	struct xfs_trans		*tp;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	if (!(inode->i_sb->s_flags & SB_LAZYTIME))
68062306a36Sopenharmony_ci		return;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	/*
68362306a36Sopenharmony_ci	 * Only do the timestamp update if the inode is dirty (I_DIRTY_SYNC)
68462306a36Sopenharmony_ci	 * and has dirty timestamp (I_DIRTY_TIME). I_DIRTY_TIME can be passed
68562306a36Sopenharmony_ci	 * in flags possibly together with I_DIRTY_SYNC.
68662306a36Sopenharmony_ci	 */
68762306a36Sopenharmony_ci	if ((flags & ~I_DIRTY_TIME) != I_DIRTY_SYNC || !(flags & I_DIRTY_TIME))
68862306a36Sopenharmony_ci		return;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	if (xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp))
69162306a36Sopenharmony_ci		return;
69262306a36Sopenharmony_ci	xfs_ilock(ip, XFS_ILOCK_EXCL);
69362306a36Sopenharmony_ci	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
69462306a36Sopenharmony_ci	xfs_trans_log_inode(tp, ip, XFS_ILOG_TIMESTAMP);
69562306a36Sopenharmony_ci	xfs_trans_commit(tp);
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci/*
69962306a36Sopenharmony_ci * Slab object creation initialisation for the XFS inode.
70062306a36Sopenharmony_ci * This covers only the idempotent fields in the XFS inode;
70162306a36Sopenharmony_ci * all other fields need to be initialised on allocation
70262306a36Sopenharmony_ci * from the slab. This avoids the need to repeatedly initialise
70362306a36Sopenharmony_ci * fields in the xfs inode that left in the initialise state
70462306a36Sopenharmony_ci * when freeing the inode.
70562306a36Sopenharmony_ci */
70662306a36Sopenharmony_ciSTATIC void
70762306a36Sopenharmony_cixfs_fs_inode_init_once(
70862306a36Sopenharmony_ci	void			*inode)
70962306a36Sopenharmony_ci{
71062306a36Sopenharmony_ci	struct xfs_inode	*ip = inode;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	memset(ip, 0, sizeof(struct xfs_inode));
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	/* vfs inode */
71562306a36Sopenharmony_ci	inode_init_once(VFS_I(ip));
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	/* xfs inode */
71862306a36Sopenharmony_ci	atomic_set(&ip->i_pincount, 0);
71962306a36Sopenharmony_ci	spin_lock_init(&ip->i_flags_lock);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER,
72262306a36Sopenharmony_ci		     "xfsino", ip->i_ino);
72362306a36Sopenharmony_ci}
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci/*
72662306a36Sopenharmony_ci * We do an unlocked check for XFS_IDONTCACHE here because we are already
72762306a36Sopenharmony_ci * serialised against cache hits here via the inode->i_lock and igrab() in
72862306a36Sopenharmony_ci * xfs_iget_cache_hit(). Hence a lookup that might clear this flag will not be
72962306a36Sopenharmony_ci * racing with us, and it avoids needing to grab a spinlock here for every inode
73062306a36Sopenharmony_ci * we drop the final reference on.
73162306a36Sopenharmony_ci */
73262306a36Sopenharmony_ciSTATIC int
73362306a36Sopenharmony_cixfs_fs_drop_inode(
73462306a36Sopenharmony_ci	struct inode		*inode)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	struct xfs_inode	*ip = XFS_I(inode);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	/*
73962306a36Sopenharmony_ci	 * If this unlinked inode is in the middle of recovery, don't
74062306a36Sopenharmony_ci	 * drop the inode just yet; log recovery will take care of
74162306a36Sopenharmony_ci	 * that.  See the comment for this inode flag.
74262306a36Sopenharmony_ci	 */
74362306a36Sopenharmony_ci	if (ip->i_flags & XFS_IRECOVERY) {
74462306a36Sopenharmony_ci		ASSERT(xlog_recovery_needed(ip->i_mount->m_log));
74562306a36Sopenharmony_ci		return 0;
74662306a36Sopenharmony_ci	}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	return generic_drop_inode(inode);
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_cistatic void
75262306a36Sopenharmony_cixfs_mount_free(
75362306a36Sopenharmony_ci	struct xfs_mount	*mp)
75462306a36Sopenharmony_ci{
75562306a36Sopenharmony_ci	/*
75662306a36Sopenharmony_ci	 * Free the buftargs here because blkdev_put needs to be called outside
75762306a36Sopenharmony_ci	 * of sb->s_umount, which is held around the call to ->put_super.
75862306a36Sopenharmony_ci	 */
75962306a36Sopenharmony_ci	if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp)
76062306a36Sopenharmony_ci		xfs_free_buftarg(mp->m_logdev_targp);
76162306a36Sopenharmony_ci	if (mp->m_rtdev_targp)
76262306a36Sopenharmony_ci		xfs_free_buftarg(mp->m_rtdev_targp);
76362306a36Sopenharmony_ci	if (mp->m_ddev_targp)
76462306a36Sopenharmony_ci		xfs_free_buftarg(mp->m_ddev_targp);
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	debugfs_remove(mp->m_debugfs);
76762306a36Sopenharmony_ci	kfree(mp->m_rtname);
76862306a36Sopenharmony_ci	kfree(mp->m_logname);
76962306a36Sopenharmony_ci	kmem_free(mp);
77062306a36Sopenharmony_ci}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ciSTATIC int
77362306a36Sopenharmony_cixfs_fs_sync_fs(
77462306a36Sopenharmony_ci	struct super_block	*sb,
77562306a36Sopenharmony_ci	int			wait)
77662306a36Sopenharmony_ci{
77762306a36Sopenharmony_ci	struct xfs_mount	*mp = XFS_M(sb);
77862306a36Sopenharmony_ci	int			error;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	trace_xfs_fs_sync_fs(mp, __return_address);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	/*
78362306a36Sopenharmony_ci	 * Doing anything during the async pass would be counterproductive.
78462306a36Sopenharmony_ci	 */
78562306a36Sopenharmony_ci	if (!wait)
78662306a36Sopenharmony_ci		return 0;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	error = xfs_log_force(mp, XFS_LOG_SYNC);
78962306a36Sopenharmony_ci	if (error)
79062306a36Sopenharmony_ci		return error;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	if (laptop_mode) {
79362306a36Sopenharmony_ci		/*
79462306a36Sopenharmony_ci		 * The disk must be active because we're syncing.
79562306a36Sopenharmony_ci		 * We schedule log work now (now that the disk is
79662306a36Sopenharmony_ci		 * active) instead of later (when it might not be).
79762306a36Sopenharmony_ci		 */
79862306a36Sopenharmony_ci		flush_delayed_work(&mp->m_log->l_work);
79962306a36Sopenharmony_ci	}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	/*
80262306a36Sopenharmony_ci	 * If we are called with page faults frozen out, it means we are about
80362306a36Sopenharmony_ci	 * to freeze the transaction subsystem. Take the opportunity to shut
80462306a36Sopenharmony_ci	 * down inodegc because once SB_FREEZE_FS is set it's too late to
80562306a36Sopenharmony_ci	 * prevent inactivation races with freeze. The fs doesn't get called
80662306a36Sopenharmony_ci	 * again by the freezing process until after SB_FREEZE_FS has been set,
80762306a36Sopenharmony_ci	 * so it's now or never.  Same logic applies to speculative allocation
80862306a36Sopenharmony_ci	 * garbage collection.
80962306a36Sopenharmony_ci	 *
81062306a36Sopenharmony_ci	 * We don't care if this is a normal syncfs call that does this or
81162306a36Sopenharmony_ci	 * freeze that does this - we can run this multiple times without issue
81262306a36Sopenharmony_ci	 * and we won't race with a restart because a restart can only occur
81362306a36Sopenharmony_ci	 * when the state is either SB_FREEZE_FS or SB_FREEZE_COMPLETE.
81462306a36Sopenharmony_ci	 */
81562306a36Sopenharmony_ci	if (sb->s_writers.frozen == SB_FREEZE_PAGEFAULT) {
81662306a36Sopenharmony_ci		xfs_inodegc_stop(mp);
81762306a36Sopenharmony_ci		xfs_blockgc_stop(mp);
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	return 0;
82162306a36Sopenharmony_ci}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ciSTATIC int
82462306a36Sopenharmony_cixfs_fs_statfs(
82562306a36Sopenharmony_ci	struct dentry		*dentry,
82662306a36Sopenharmony_ci	struct kstatfs		*statp)
82762306a36Sopenharmony_ci{
82862306a36Sopenharmony_ci	struct xfs_mount	*mp = XFS_M(dentry->d_sb);
82962306a36Sopenharmony_ci	xfs_sb_t		*sbp = &mp->m_sb;
83062306a36Sopenharmony_ci	struct xfs_inode	*ip = XFS_I(d_inode(dentry));
83162306a36Sopenharmony_ci	uint64_t		fakeinos, id;
83262306a36Sopenharmony_ci	uint64_t		icount;
83362306a36Sopenharmony_ci	uint64_t		ifree;
83462306a36Sopenharmony_ci	uint64_t		fdblocks;
83562306a36Sopenharmony_ci	xfs_extlen_t		lsize;
83662306a36Sopenharmony_ci	int64_t			ffree;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	/*
83962306a36Sopenharmony_ci	 * Expedite background inodegc but don't wait. We do not want to block
84062306a36Sopenharmony_ci	 * here waiting hours for a billion extent file to be truncated.
84162306a36Sopenharmony_ci	 */
84262306a36Sopenharmony_ci	xfs_inodegc_push(mp);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	statp->f_type = XFS_SUPER_MAGIC;
84562306a36Sopenharmony_ci	statp->f_namelen = MAXNAMELEN - 1;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	id = huge_encode_dev(mp->m_ddev_targp->bt_dev);
84862306a36Sopenharmony_ci	statp->f_fsid = u64_to_fsid(id);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	icount = percpu_counter_sum(&mp->m_icount);
85162306a36Sopenharmony_ci	ifree = percpu_counter_sum(&mp->m_ifree);
85262306a36Sopenharmony_ci	fdblocks = percpu_counter_sum(&mp->m_fdblocks);
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	spin_lock(&mp->m_sb_lock);
85562306a36Sopenharmony_ci	statp->f_bsize = sbp->sb_blocksize;
85662306a36Sopenharmony_ci	lsize = sbp->sb_logstart ? sbp->sb_logblocks : 0;
85762306a36Sopenharmony_ci	statp->f_blocks = sbp->sb_dblocks - lsize;
85862306a36Sopenharmony_ci	spin_unlock(&mp->m_sb_lock);
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	/* make sure statp->f_bfree does not underflow */
86162306a36Sopenharmony_ci	statp->f_bfree = max_t(int64_t, 0,
86262306a36Sopenharmony_ci				fdblocks - xfs_fdblocks_unavailable(mp));
86362306a36Sopenharmony_ci	statp->f_bavail = statp->f_bfree;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	fakeinos = XFS_FSB_TO_INO(mp, statp->f_bfree);
86662306a36Sopenharmony_ci	statp->f_files = min(icount + fakeinos, (uint64_t)XFS_MAXINUMBER);
86762306a36Sopenharmony_ci	if (M_IGEO(mp)->maxicount)
86862306a36Sopenharmony_ci		statp->f_files = min_t(typeof(statp->f_files),
86962306a36Sopenharmony_ci					statp->f_files,
87062306a36Sopenharmony_ci					M_IGEO(mp)->maxicount);
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	/* If sb_icount overshot maxicount, report actual allocation */
87362306a36Sopenharmony_ci	statp->f_files = max_t(typeof(statp->f_files),
87462306a36Sopenharmony_ci					statp->f_files,
87562306a36Sopenharmony_ci					sbp->sb_icount);
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	/* make sure statp->f_ffree does not underflow */
87862306a36Sopenharmony_ci	ffree = statp->f_files - (icount - ifree);
87962306a36Sopenharmony_ci	statp->f_ffree = max_t(int64_t, ffree, 0);
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	if ((ip->i_diflags & XFS_DIFLAG_PROJINHERIT) &&
88362306a36Sopenharmony_ci	    ((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD))) ==
88462306a36Sopenharmony_ci			      (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD))
88562306a36Sopenharmony_ci		xfs_qm_statvfs(ip, statp);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	if (XFS_IS_REALTIME_MOUNT(mp) &&
88862306a36Sopenharmony_ci	    (ip->i_diflags & (XFS_DIFLAG_RTINHERIT | XFS_DIFLAG_REALTIME))) {
88962306a36Sopenharmony_ci		s64	freertx;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci		statp->f_blocks = sbp->sb_rblocks;
89262306a36Sopenharmony_ci		freertx = percpu_counter_sum_positive(&mp->m_frextents);
89362306a36Sopenharmony_ci		statp->f_bavail = statp->f_bfree = freertx * sbp->sb_rextsize;
89462306a36Sopenharmony_ci	}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	return 0;
89762306a36Sopenharmony_ci}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ciSTATIC void
90062306a36Sopenharmony_cixfs_save_resvblks(struct xfs_mount *mp)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	uint64_t resblks = 0;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	mp->m_resblks_save = mp->m_resblks;
90562306a36Sopenharmony_ci	xfs_reserve_blocks(mp, &resblks, NULL);
90662306a36Sopenharmony_ci}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ciSTATIC void
90962306a36Sopenharmony_cixfs_restore_resvblks(struct xfs_mount *mp)
91062306a36Sopenharmony_ci{
91162306a36Sopenharmony_ci	uint64_t resblks;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	if (mp->m_resblks_save) {
91462306a36Sopenharmony_ci		resblks = mp->m_resblks_save;
91562306a36Sopenharmony_ci		mp->m_resblks_save = 0;
91662306a36Sopenharmony_ci	} else
91762306a36Sopenharmony_ci		resblks = xfs_default_resblks(mp);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	xfs_reserve_blocks(mp, &resblks, NULL);
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci/*
92362306a36Sopenharmony_ci * Second stage of a freeze. The data is already frozen so we only
92462306a36Sopenharmony_ci * need to take care of the metadata. Once that's done sync the superblock
92562306a36Sopenharmony_ci * to the log to dirty it in case of a crash while frozen. This ensures that we
92662306a36Sopenharmony_ci * will recover the unlinked inode lists on the next mount.
92762306a36Sopenharmony_ci */
92862306a36Sopenharmony_ciSTATIC int
92962306a36Sopenharmony_cixfs_fs_freeze(
93062306a36Sopenharmony_ci	struct super_block	*sb)
93162306a36Sopenharmony_ci{
93262306a36Sopenharmony_ci	struct xfs_mount	*mp = XFS_M(sb);
93362306a36Sopenharmony_ci	unsigned int		flags;
93462306a36Sopenharmony_ci	int			ret;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	/*
93762306a36Sopenharmony_ci	 * The filesystem is now frozen far enough that memory reclaim
93862306a36Sopenharmony_ci	 * cannot safely operate on the filesystem. Hence we need to
93962306a36Sopenharmony_ci	 * set a GFP_NOFS context here to avoid recursion deadlocks.
94062306a36Sopenharmony_ci	 */
94162306a36Sopenharmony_ci	flags = memalloc_nofs_save();
94262306a36Sopenharmony_ci	xfs_save_resvblks(mp);
94362306a36Sopenharmony_ci	ret = xfs_log_quiesce(mp);
94462306a36Sopenharmony_ci	memalloc_nofs_restore(flags);
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	/*
94762306a36Sopenharmony_ci	 * For read-write filesystems, we need to restart the inodegc on error
94862306a36Sopenharmony_ci	 * because we stopped it at SB_FREEZE_PAGEFAULT level and a thaw is not
94962306a36Sopenharmony_ci	 * going to be run to restart it now.  We are at SB_FREEZE_FS level
95062306a36Sopenharmony_ci	 * here, so we can restart safely without racing with a stop in
95162306a36Sopenharmony_ci	 * xfs_fs_sync_fs().
95262306a36Sopenharmony_ci	 */
95362306a36Sopenharmony_ci	if (ret && !xfs_is_readonly(mp)) {
95462306a36Sopenharmony_ci		xfs_blockgc_start(mp);
95562306a36Sopenharmony_ci		xfs_inodegc_start(mp);
95662306a36Sopenharmony_ci	}
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	return ret;
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ciSTATIC int
96262306a36Sopenharmony_cixfs_fs_unfreeze(
96362306a36Sopenharmony_ci	struct super_block	*sb)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	struct xfs_mount	*mp = XFS_M(sb);
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	xfs_restore_resvblks(mp);
96862306a36Sopenharmony_ci	xfs_log_work_queue(mp);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	/*
97162306a36Sopenharmony_ci	 * Don't reactivate the inodegc worker on a readonly filesystem because
97262306a36Sopenharmony_ci	 * inodes are sent directly to reclaim.  Don't reactivate the blockgc
97362306a36Sopenharmony_ci	 * worker because there are no speculative preallocations on a readonly
97462306a36Sopenharmony_ci	 * filesystem.
97562306a36Sopenharmony_ci	 */
97662306a36Sopenharmony_ci	if (!xfs_is_readonly(mp)) {
97762306a36Sopenharmony_ci		xfs_blockgc_start(mp);
97862306a36Sopenharmony_ci		xfs_inodegc_start(mp);
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	return 0;
98262306a36Sopenharmony_ci}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci/*
98562306a36Sopenharmony_ci * This function fills in xfs_mount_t fields based on mount args.
98662306a36Sopenharmony_ci * Note: the superblock _has_ now been read in.
98762306a36Sopenharmony_ci */
98862306a36Sopenharmony_ciSTATIC int
98962306a36Sopenharmony_cixfs_finish_flags(
99062306a36Sopenharmony_ci	struct xfs_mount	*mp)
99162306a36Sopenharmony_ci{
99262306a36Sopenharmony_ci	/* Fail a mount where the logbuf is smaller than the log stripe */
99362306a36Sopenharmony_ci	if (xfs_has_logv2(mp)) {
99462306a36Sopenharmony_ci		if (mp->m_logbsize <= 0 &&
99562306a36Sopenharmony_ci		    mp->m_sb.sb_logsunit > XLOG_BIG_RECORD_BSIZE) {
99662306a36Sopenharmony_ci			mp->m_logbsize = mp->m_sb.sb_logsunit;
99762306a36Sopenharmony_ci		} else if (mp->m_logbsize > 0 &&
99862306a36Sopenharmony_ci			   mp->m_logbsize < mp->m_sb.sb_logsunit) {
99962306a36Sopenharmony_ci			xfs_warn(mp,
100062306a36Sopenharmony_ci		"logbuf size must be greater than or equal to log stripe size");
100162306a36Sopenharmony_ci			return -EINVAL;
100262306a36Sopenharmony_ci		}
100362306a36Sopenharmony_ci	} else {
100462306a36Sopenharmony_ci		/* Fail a mount if the logbuf is larger than 32K */
100562306a36Sopenharmony_ci		if (mp->m_logbsize > XLOG_BIG_RECORD_BSIZE) {
100662306a36Sopenharmony_ci			xfs_warn(mp,
100762306a36Sopenharmony_ci		"logbuf size for version 1 logs must be 16K or 32K");
100862306a36Sopenharmony_ci			return -EINVAL;
100962306a36Sopenharmony_ci		}
101062306a36Sopenharmony_ci	}
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	/*
101362306a36Sopenharmony_ci	 * V5 filesystems always use attr2 format for attributes.
101462306a36Sopenharmony_ci	 */
101562306a36Sopenharmony_ci	if (xfs_has_crc(mp) && xfs_has_noattr2(mp)) {
101662306a36Sopenharmony_ci		xfs_warn(mp, "Cannot mount a V5 filesystem as noattr2. "
101762306a36Sopenharmony_ci			     "attr2 is always enabled for V5 filesystems.");
101862306a36Sopenharmony_ci		return -EINVAL;
101962306a36Sopenharmony_ci	}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	/*
102262306a36Sopenharmony_ci	 * prohibit r/w mounts of read-only filesystems
102362306a36Sopenharmony_ci	 */
102462306a36Sopenharmony_ci	if ((mp->m_sb.sb_flags & XFS_SBF_READONLY) && !xfs_is_readonly(mp)) {
102562306a36Sopenharmony_ci		xfs_warn(mp,
102662306a36Sopenharmony_ci			"cannot mount a read-only filesystem as read-write");
102762306a36Sopenharmony_ci		return -EROFS;
102862306a36Sopenharmony_ci	}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	if ((mp->m_qflags & XFS_GQUOTA_ACCT) &&
103162306a36Sopenharmony_ci	    (mp->m_qflags & XFS_PQUOTA_ACCT) &&
103262306a36Sopenharmony_ci	    !xfs_has_pquotino(mp)) {
103362306a36Sopenharmony_ci		xfs_warn(mp,
103462306a36Sopenharmony_ci		  "Super block does not support project and group quota together");
103562306a36Sopenharmony_ci		return -EINVAL;
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	return 0;
103962306a36Sopenharmony_ci}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_cistatic int
104262306a36Sopenharmony_cixfs_init_percpu_counters(
104362306a36Sopenharmony_ci	struct xfs_mount	*mp)
104462306a36Sopenharmony_ci{
104562306a36Sopenharmony_ci	int		error;
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	error = percpu_counter_init(&mp->m_icount, 0, GFP_KERNEL);
104862306a36Sopenharmony_ci	if (error)
104962306a36Sopenharmony_ci		return -ENOMEM;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	error = percpu_counter_init(&mp->m_ifree, 0, GFP_KERNEL);
105262306a36Sopenharmony_ci	if (error)
105362306a36Sopenharmony_ci		goto free_icount;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	error = percpu_counter_init(&mp->m_fdblocks, 0, GFP_KERNEL);
105662306a36Sopenharmony_ci	if (error)
105762306a36Sopenharmony_ci		goto free_ifree;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	error = percpu_counter_init(&mp->m_delalloc_blks, 0, GFP_KERNEL);
106062306a36Sopenharmony_ci	if (error)
106162306a36Sopenharmony_ci		goto free_fdblocks;
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	error = percpu_counter_init(&mp->m_frextents, 0, GFP_KERNEL);
106462306a36Sopenharmony_ci	if (error)
106562306a36Sopenharmony_ci		goto free_delalloc;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	return 0;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_cifree_delalloc:
107062306a36Sopenharmony_ci	percpu_counter_destroy(&mp->m_delalloc_blks);
107162306a36Sopenharmony_cifree_fdblocks:
107262306a36Sopenharmony_ci	percpu_counter_destroy(&mp->m_fdblocks);
107362306a36Sopenharmony_cifree_ifree:
107462306a36Sopenharmony_ci	percpu_counter_destroy(&mp->m_ifree);
107562306a36Sopenharmony_cifree_icount:
107662306a36Sopenharmony_ci	percpu_counter_destroy(&mp->m_icount);
107762306a36Sopenharmony_ci	return -ENOMEM;
107862306a36Sopenharmony_ci}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_civoid
108162306a36Sopenharmony_cixfs_reinit_percpu_counters(
108262306a36Sopenharmony_ci	struct xfs_mount	*mp)
108362306a36Sopenharmony_ci{
108462306a36Sopenharmony_ci	percpu_counter_set(&mp->m_icount, mp->m_sb.sb_icount);
108562306a36Sopenharmony_ci	percpu_counter_set(&mp->m_ifree, mp->m_sb.sb_ifree);
108662306a36Sopenharmony_ci	percpu_counter_set(&mp->m_fdblocks, mp->m_sb.sb_fdblocks);
108762306a36Sopenharmony_ci	percpu_counter_set(&mp->m_frextents, mp->m_sb.sb_frextents);
108862306a36Sopenharmony_ci}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_cistatic void
109162306a36Sopenharmony_cixfs_destroy_percpu_counters(
109262306a36Sopenharmony_ci	struct xfs_mount	*mp)
109362306a36Sopenharmony_ci{
109462306a36Sopenharmony_ci	percpu_counter_destroy(&mp->m_icount);
109562306a36Sopenharmony_ci	percpu_counter_destroy(&mp->m_ifree);
109662306a36Sopenharmony_ci	percpu_counter_destroy(&mp->m_fdblocks);
109762306a36Sopenharmony_ci	ASSERT(xfs_is_shutdown(mp) ||
109862306a36Sopenharmony_ci	       percpu_counter_sum(&mp->m_delalloc_blks) == 0);
109962306a36Sopenharmony_ci	percpu_counter_destroy(&mp->m_delalloc_blks);
110062306a36Sopenharmony_ci	percpu_counter_destroy(&mp->m_frextents);
110162306a36Sopenharmony_ci}
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_cistatic int
110462306a36Sopenharmony_cixfs_inodegc_init_percpu(
110562306a36Sopenharmony_ci	struct xfs_mount	*mp)
110662306a36Sopenharmony_ci{
110762306a36Sopenharmony_ci	struct xfs_inodegc	*gc;
110862306a36Sopenharmony_ci	int			cpu;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	mp->m_inodegc = alloc_percpu(struct xfs_inodegc);
111162306a36Sopenharmony_ci	if (!mp->m_inodegc)
111262306a36Sopenharmony_ci		return -ENOMEM;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	for_each_possible_cpu(cpu) {
111562306a36Sopenharmony_ci		gc = per_cpu_ptr(mp->m_inodegc, cpu);
111662306a36Sopenharmony_ci		gc->cpu = cpu;
111762306a36Sopenharmony_ci		gc->mp = mp;
111862306a36Sopenharmony_ci		init_llist_head(&gc->list);
111962306a36Sopenharmony_ci		gc->items = 0;
112062306a36Sopenharmony_ci		gc->error = 0;
112162306a36Sopenharmony_ci		INIT_DELAYED_WORK(&gc->work, xfs_inodegc_worker);
112262306a36Sopenharmony_ci	}
112362306a36Sopenharmony_ci	return 0;
112462306a36Sopenharmony_ci}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_cistatic void
112762306a36Sopenharmony_cixfs_inodegc_free_percpu(
112862306a36Sopenharmony_ci	struct xfs_mount	*mp)
112962306a36Sopenharmony_ci{
113062306a36Sopenharmony_ci	if (!mp->m_inodegc)
113162306a36Sopenharmony_ci		return;
113262306a36Sopenharmony_ci	free_percpu(mp->m_inodegc);
113362306a36Sopenharmony_ci}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_cistatic void
113662306a36Sopenharmony_cixfs_fs_put_super(
113762306a36Sopenharmony_ci	struct super_block	*sb)
113862306a36Sopenharmony_ci{
113962306a36Sopenharmony_ci	struct xfs_mount	*mp = XFS_M(sb);
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	xfs_notice(mp, "Unmounting Filesystem %pU", &mp->m_sb.sb_uuid);
114262306a36Sopenharmony_ci	xfs_filestream_unmount(mp);
114362306a36Sopenharmony_ci	xfs_unmountfs(mp);
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	xfs_freesb(mp);
114662306a36Sopenharmony_ci	xchk_mount_stats_free(mp);
114762306a36Sopenharmony_ci	free_percpu(mp->m_stats.xs_stats);
114862306a36Sopenharmony_ci	xfs_inodegc_free_percpu(mp);
114962306a36Sopenharmony_ci	xfs_destroy_percpu_counters(mp);
115062306a36Sopenharmony_ci	xfs_destroy_mount_workqueues(mp);
115162306a36Sopenharmony_ci	xfs_shutdown_devices(mp);
115262306a36Sopenharmony_ci}
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_cistatic long
115562306a36Sopenharmony_cixfs_fs_nr_cached_objects(
115662306a36Sopenharmony_ci	struct super_block	*sb,
115762306a36Sopenharmony_ci	struct shrink_control	*sc)
115862306a36Sopenharmony_ci{
115962306a36Sopenharmony_ci	/* Paranoia: catch incorrect calls during mount setup or teardown */
116062306a36Sopenharmony_ci	if (WARN_ON_ONCE(!sb->s_fs_info))
116162306a36Sopenharmony_ci		return 0;
116262306a36Sopenharmony_ci	return xfs_reclaim_inodes_count(XFS_M(sb));
116362306a36Sopenharmony_ci}
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_cistatic long
116662306a36Sopenharmony_cixfs_fs_free_cached_objects(
116762306a36Sopenharmony_ci	struct super_block	*sb,
116862306a36Sopenharmony_ci	struct shrink_control	*sc)
116962306a36Sopenharmony_ci{
117062306a36Sopenharmony_ci	return xfs_reclaim_inodes_nr(XFS_M(sb), sc->nr_to_scan);
117162306a36Sopenharmony_ci}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_cistatic void
117462306a36Sopenharmony_cixfs_fs_shutdown(
117562306a36Sopenharmony_ci	struct super_block	*sb)
117662306a36Sopenharmony_ci{
117762306a36Sopenharmony_ci	xfs_force_shutdown(XFS_M(sb), SHUTDOWN_DEVICE_REMOVED);
117862306a36Sopenharmony_ci}
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_cistatic const struct super_operations xfs_super_operations = {
118162306a36Sopenharmony_ci	.alloc_inode		= xfs_fs_alloc_inode,
118262306a36Sopenharmony_ci	.destroy_inode		= xfs_fs_destroy_inode,
118362306a36Sopenharmony_ci	.dirty_inode		= xfs_fs_dirty_inode,
118462306a36Sopenharmony_ci	.drop_inode		= xfs_fs_drop_inode,
118562306a36Sopenharmony_ci	.put_super		= xfs_fs_put_super,
118662306a36Sopenharmony_ci	.sync_fs		= xfs_fs_sync_fs,
118762306a36Sopenharmony_ci	.freeze_fs		= xfs_fs_freeze,
118862306a36Sopenharmony_ci	.unfreeze_fs		= xfs_fs_unfreeze,
118962306a36Sopenharmony_ci	.statfs			= xfs_fs_statfs,
119062306a36Sopenharmony_ci	.show_options		= xfs_fs_show_options,
119162306a36Sopenharmony_ci	.nr_cached_objects	= xfs_fs_nr_cached_objects,
119262306a36Sopenharmony_ci	.free_cached_objects	= xfs_fs_free_cached_objects,
119362306a36Sopenharmony_ci	.shutdown		= xfs_fs_shutdown,
119462306a36Sopenharmony_ci};
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_cistatic int
119762306a36Sopenharmony_cisuffix_kstrtoint(
119862306a36Sopenharmony_ci	const char	*s,
119962306a36Sopenharmony_ci	unsigned int	base,
120062306a36Sopenharmony_ci	int		*res)
120162306a36Sopenharmony_ci{
120262306a36Sopenharmony_ci	int		last, shift_left_factor = 0, _res;
120362306a36Sopenharmony_ci	char		*value;
120462306a36Sopenharmony_ci	int		ret = 0;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	value = kstrdup(s, GFP_KERNEL);
120762306a36Sopenharmony_ci	if (!value)
120862306a36Sopenharmony_ci		return -ENOMEM;
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	last = strlen(value) - 1;
121162306a36Sopenharmony_ci	if (value[last] == 'K' || value[last] == 'k') {
121262306a36Sopenharmony_ci		shift_left_factor = 10;
121362306a36Sopenharmony_ci		value[last] = '\0';
121462306a36Sopenharmony_ci	}
121562306a36Sopenharmony_ci	if (value[last] == 'M' || value[last] == 'm') {
121662306a36Sopenharmony_ci		shift_left_factor = 20;
121762306a36Sopenharmony_ci		value[last] = '\0';
121862306a36Sopenharmony_ci	}
121962306a36Sopenharmony_ci	if (value[last] == 'G' || value[last] == 'g') {
122062306a36Sopenharmony_ci		shift_left_factor = 30;
122162306a36Sopenharmony_ci		value[last] = '\0';
122262306a36Sopenharmony_ci	}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	if (kstrtoint(value, base, &_res))
122562306a36Sopenharmony_ci		ret = -EINVAL;
122662306a36Sopenharmony_ci	kfree(value);
122762306a36Sopenharmony_ci	*res = _res << shift_left_factor;
122862306a36Sopenharmony_ci	return ret;
122962306a36Sopenharmony_ci}
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_cistatic inline void
123262306a36Sopenharmony_cixfs_fs_warn_deprecated(
123362306a36Sopenharmony_ci	struct fs_context	*fc,
123462306a36Sopenharmony_ci	struct fs_parameter	*param,
123562306a36Sopenharmony_ci	uint64_t		flag,
123662306a36Sopenharmony_ci	bool			value)
123762306a36Sopenharmony_ci{
123862306a36Sopenharmony_ci	/* Don't print the warning if reconfiguring and current mount point
123962306a36Sopenharmony_ci	 * already had the flag set
124062306a36Sopenharmony_ci	 */
124162306a36Sopenharmony_ci	if ((fc->purpose & FS_CONTEXT_FOR_RECONFIGURE) &&
124262306a36Sopenharmony_ci            !!(XFS_M(fc->root->d_sb)->m_features & flag) == value)
124362306a36Sopenharmony_ci		return;
124462306a36Sopenharmony_ci	xfs_warn(fc->s_fs_info, "%s mount option is deprecated.", param->key);
124562306a36Sopenharmony_ci}
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci/*
124862306a36Sopenharmony_ci * Set mount state from a mount option.
124962306a36Sopenharmony_ci *
125062306a36Sopenharmony_ci * NOTE: mp->m_super is NULL here!
125162306a36Sopenharmony_ci */
125262306a36Sopenharmony_cistatic int
125362306a36Sopenharmony_cixfs_fs_parse_param(
125462306a36Sopenharmony_ci	struct fs_context	*fc,
125562306a36Sopenharmony_ci	struct fs_parameter	*param)
125662306a36Sopenharmony_ci{
125762306a36Sopenharmony_ci	struct xfs_mount	*parsing_mp = fc->s_fs_info;
125862306a36Sopenharmony_ci	struct fs_parse_result	result;
125962306a36Sopenharmony_ci	int			size = 0;
126062306a36Sopenharmony_ci	int			opt;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	opt = fs_parse(fc, xfs_fs_parameters, param, &result);
126362306a36Sopenharmony_ci	if (opt < 0)
126462306a36Sopenharmony_ci		return opt;
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	switch (opt) {
126762306a36Sopenharmony_ci	case Opt_logbufs:
126862306a36Sopenharmony_ci		parsing_mp->m_logbufs = result.uint_32;
126962306a36Sopenharmony_ci		return 0;
127062306a36Sopenharmony_ci	case Opt_logbsize:
127162306a36Sopenharmony_ci		if (suffix_kstrtoint(param->string, 10, &parsing_mp->m_logbsize))
127262306a36Sopenharmony_ci			return -EINVAL;
127362306a36Sopenharmony_ci		return 0;
127462306a36Sopenharmony_ci	case Opt_logdev:
127562306a36Sopenharmony_ci		kfree(parsing_mp->m_logname);
127662306a36Sopenharmony_ci		parsing_mp->m_logname = kstrdup(param->string, GFP_KERNEL);
127762306a36Sopenharmony_ci		if (!parsing_mp->m_logname)
127862306a36Sopenharmony_ci			return -ENOMEM;
127962306a36Sopenharmony_ci		return 0;
128062306a36Sopenharmony_ci	case Opt_rtdev:
128162306a36Sopenharmony_ci		kfree(parsing_mp->m_rtname);
128262306a36Sopenharmony_ci		parsing_mp->m_rtname = kstrdup(param->string, GFP_KERNEL);
128362306a36Sopenharmony_ci		if (!parsing_mp->m_rtname)
128462306a36Sopenharmony_ci			return -ENOMEM;
128562306a36Sopenharmony_ci		return 0;
128662306a36Sopenharmony_ci	case Opt_allocsize:
128762306a36Sopenharmony_ci		if (suffix_kstrtoint(param->string, 10, &size))
128862306a36Sopenharmony_ci			return -EINVAL;
128962306a36Sopenharmony_ci		parsing_mp->m_allocsize_log = ffs(size) - 1;
129062306a36Sopenharmony_ci		parsing_mp->m_features |= XFS_FEAT_ALLOCSIZE;
129162306a36Sopenharmony_ci		return 0;
129262306a36Sopenharmony_ci	case Opt_grpid:
129362306a36Sopenharmony_ci	case Opt_bsdgroups:
129462306a36Sopenharmony_ci		parsing_mp->m_features |= XFS_FEAT_GRPID;
129562306a36Sopenharmony_ci		return 0;
129662306a36Sopenharmony_ci	case Opt_nogrpid:
129762306a36Sopenharmony_ci	case Opt_sysvgroups:
129862306a36Sopenharmony_ci		parsing_mp->m_features &= ~XFS_FEAT_GRPID;
129962306a36Sopenharmony_ci		return 0;
130062306a36Sopenharmony_ci	case Opt_wsync:
130162306a36Sopenharmony_ci		parsing_mp->m_features |= XFS_FEAT_WSYNC;
130262306a36Sopenharmony_ci		return 0;
130362306a36Sopenharmony_ci	case Opt_norecovery:
130462306a36Sopenharmony_ci		parsing_mp->m_features |= XFS_FEAT_NORECOVERY;
130562306a36Sopenharmony_ci		return 0;
130662306a36Sopenharmony_ci	case Opt_noalign:
130762306a36Sopenharmony_ci		parsing_mp->m_features |= XFS_FEAT_NOALIGN;
130862306a36Sopenharmony_ci		return 0;
130962306a36Sopenharmony_ci	case Opt_swalloc:
131062306a36Sopenharmony_ci		parsing_mp->m_features |= XFS_FEAT_SWALLOC;
131162306a36Sopenharmony_ci		return 0;
131262306a36Sopenharmony_ci	case Opt_sunit:
131362306a36Sopenharmony_ci		parsing_mp->m_dalign = result.uint_32;
131462306a36Sopenharmony_ci		return 0;
131562306a36Sopenharmony_ci	case Opt_swidth:
131662306a36Sopenharmony_ci		parsing_mp->m_swidth = result.uint_32;
131762306a36Sopenharmony_ci		return 0;
131862306a36Sopenharmony_ci	case Opt_inode32:
131962306a36Sopenharmony_ci		parsing_mp->m_features |= XFS_FEAT_SMALL_INUMS;
132062306a36Sopenharmony_ci		return 0;
132162306a36Sopenharmony_ci	case Opt_inode64:
132262306a36Sopenharmony_ci		parsing_mp->m_features &= ~XFS_FEAT_SMALL_INUMS;
132362306a36Sopenharmony_ci		return 0;
132462306a36Sopenharmony_ci	case Opt_nouuid:
132562306a36Sopenharmony_ci		parsing_mp->m_features |= XFS_FEAT_NOUUID;
132662306a36Sopenharmony_ci		return 0;
132762306a36Sopenharmony_ci	case Opt_largeio:
132862306a36Sopenharmony_ci		parsing_mp->m_features |= XFS_FEAT_LARGE_IOSIZE;
132962306a36Sopenharmony_ci		return 0;
133062306a36Sopenharmony_ci	case Opt_nolargeio:
133162306a36Sopenharmony_ci		parsing_mp->m_features &= ~XFS_FEAT_LARGE_IOSIZE;
133262306a36Sopenharmony_ci		return 0;
133362306a36Sopenharmony_ci	case Opt_filestreams:
133462306a36Sopenharmony_ci		parsing_mp->m_features |= XFS_FEAT_FILESTREAMS;
133562306a36Sopenharmony_ci		return 0;
133662306a36Sopenharmony_ci	case Opt_noquota:
133762306a36Sopenharmony_ci		parsing_mp->m_qflags &= ~XFS_ALL_QUOTA_ACCT;
133862306a36Sopenharmony_ci		parsing_mp->m_qflags &= ~XFS_ALL_QUOTA_ENFD;
133962306a36Sopenharmony_ci		return 0;
134062306a36Sopenharmony_ci	case Opt_quota:
134162306a36Sopenharmony_ci	case Opt_uquota:
134262306a36Sopenharmony_ci	case Opt_usrquota:
134362306a36Sopenharmony_ci		parsing_mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ENFD);
134462306a36Sopenharmony_ci		return 0;
134562306a36Sopenharmony_ci	case Opt_qnoenforce:
134662306a36Sopenharmony_ci	case Opt_uqnoenforce:
134762306a36Sopenharmony_ci		parsing_mp->m_qflags |= XFS_UQUOTA_ACCT;
134862306a36Sopenharmony_ci		parsing_mp->m_qflags &= ~XFS_UQUOTA_ENFD;
134962306a36Sopenharmony_ci		return 0;
135062306a36Sopenharmony_ci	case Opt_pquota:
135162306a36Sopenharmony_ci	case Opt_prjquota:
135262306a36Sopenharmony_ci		parsing_mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ENFD);
135362306a36Sopenharmony_ci		return 0;
135462306a36Sopenharmony_ci	case Opt_pqnoenforce:
135562306a36Sopenharmony_ci		parsing_mp->m_qflags |= XFS_PQUOTA_ACCT;
135662306a36Sopenharmony_ci		parsing_mp->m_qflags &= ~XFS_PQUOTA_ENFD;
135762306a36Sopenharmony_ci		return 0;
135862306a36Sopenharmony_ci	case Opt_gquota:
135962306a36Sopenharmony_ci	case Opt_grpquota:
136062306a36Sopenharmony_ci		parsing_mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ENFD);
136162306a36Sopenharmony_ci		return 0;
136262306a36Sopenharmony_ci	case Opt_gqnoenforce:
136362306a36Sopenharmony_ci		parsing_mp->m_qflags |= XFS_GQUOTA_ACCT;
136462306a36Sopenharmony_ci		parsing_mp->m_qflags &= ~XFS_GQUOTA_ENFD;
136562306a36Sopenharmony_ci		return 0;
136662306a36Sopenharmony_ci	case Opt_discard:
136762306a36Sopenharmony_ci		parsing_mp->m_features |= XFS_FEAT_DISCARD;
136862306a36Sopenharmony_ci		return 0;
136962306a36Sopenharmony_ci	case Opt_nodiscard:
137062306a36Sopenharmony_ci		parsing_mp->m_features &= ~XFS_FEAT_DISCARD;
137162306a36Sopenharmony_ci		return 0;
137262306a36Sopenharmony_ci#ifdef CONFIG_FS_DAX
137362306a36Sopenharmony_ci	case Opt_dax:
137462306a36Sopenharmony_ci		xfs_mount_set_dax_mode(parsing_mp, XFS_DAX_ALWAYS);
137562306a36Sopenharmony_ci		return 0;
137662306a36Sopenharmony_ci	case Opt_dax_enum:
137762306a36Sopenharmony_ci		xfs_mount_set_dax_mode(parsing_mp, result.uint_32);
137862306a36Sopenharmony_ci		return 0;
137962306a36Sopenharmony_ci#endif
138062306a36Sopenharmony_ci	/* Following mount options will be removed in September 2025 */
138162306a36Sopenharmony_ci	case Opt_ikeep:
138262306a36Sopenharmony_ci		xfs_fs_warn_deprecated(fc, param, XFS_FEAT_IKEEP, true);
138362306a36Sopenharmony_ci		parsing_mp->m_features |= XFS_FEAT_IKEEP;
138462306a36Sopenharmony_ci		return 0;
138562306a36Sopenharmony_ci	case Opt_noikeep:
138662306a36Sopenharmony_ci		xfs_fs_warn_deprecated(fc, param, XFS_FEAT_IKEEP, false);
138762306a36Sopenharmony_ci		parsing_mp->m_features &= ~XFS_FEAT_IKEEP;
138862306a36Sopenharmony_ci		return 0;
138962306a36Sopenharmony_ci	case Opt_attr2:
139062306a36Sopenharmony_ci		xfs_fs_warn_deprecated(fc, param, XFS_FEAT_ATTR2, true);
139162306a36Sopenharmony_ci		parsing_mp->m_features |= XFS_FEAT_ATTR2;
139262306a36Sopenharmony_ci		return 0;
139362306a36Sopenharmony_ci	case Opt_noattr2:
139462306a36Sopenharmony_ci		xfs_fs_warn_deprecated(fc, param, XFS_FEAT_NOATTR2, true);
139562306a36Sopenharmony_ci		parsing_mp->m_features |= XFS_FEAT_NOATTR2;
139662306a36Sopenharmony_ci		return 0;
139762306a36Sopenharmony_ci	default:
139862306a36Sopenharmony_ci		xfs_warn(parsing_mp, "unknown mount option [%s].", param->key);
139962306a36Sopenharmony_ci		return -EINVAL;
140062306a36Sopenharmony_ci	}
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	return 0;
140362306a36Sopenharmony_ci}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_cistatic int
140662306a36Sopenharmony_cixfs_fs_validate_params(
140762306a36Sopenharmony_ci	struct xfs_mount	*mp)
140862306a36Sopenharmony_ci{
140962306a36Sopenharmony_ci	/* No recovery flag requires a read-only mount */
141062306a36Sopenharmony_ci	if (xfs_has_norecovery(mp) && !xfs_is_readonly(mp)) {
141162306a36Sopenharmony_ci		xfs_warn(mp, "no-recovery mounts must be read-only.");
141262306a36Sopenharmony_ci		return -EINVAL;
141362306a36Sopenharmony_ci	}
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	/*
141662306a36Sopenharmony_ci	 * We have not read the superblock at this point, so only the attr2
141762306a36Sopenharmony_ci	 * mount option can set the attr2 feature by this stage.
141862306a36Sopenharmony_ci	 */
141962306a36Sopenharmony_ci	if (xfs_has_attr2(mp) && xfs_has_noattr2(mp)) {
142062306a36Sopenharmony_ci		xfs_warn(mp, "attr2 and noattr2 cannot both be specified.");
142162306a36Sopenharmony_ci		return -EINVAL;
142262306a36Sopenharmony_ci	}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	if (xfs_has_noalign(mp) && (mp->m_dalign || mp->m_swidth)) {
142662306a36Sopenharmony_ci		xfs_warn(mp,
142762306a36Sopenharmony_ci	"sunit and swidth options incompatible with the noalign option");
142862306a36Sopenharmony_ci		return -EINVAL;
142962306a36Sopenharmony_ci	}
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_XFS_QUOTA) && mp->m_qflags != 0) {
143262306a36Sopenharmony_ci		xfs_warn(mp, "quota support not available in this kernel.");
143362306a36Sopenharmony_ci		return -EINVAL;
143462306a36Sopenharmony_ci	}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	if ((mp->m_dalign && !mp->m_swidth) ||
143762306a36Sopenharmony_ci	    (!mp->m_dalign && mp->m_swidth)) {
143862306a36Sopenharmony_ci		xfs_warn(mp, "sunit and swidth must be specified together");
143962306a36Sopenharmony_ci		return -EINVAL;
144062306a36Sopenharmony_ci	}
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	if (mp->m_dalign && (mp->m_swidth % mp->m_dalign != 0)) {
144362306a36Sopenharmony_ci		xfs_warn(mp,
144462306a36Sopenharmony_ci	"stripe width (%d) must be a multiple of the stripe unit (%d)",
144562306a36Sopenharmony_ci			mp->m_swidth, mp->m_dalign);
144662306a36Sopenharmony_ci		return -EINVAL;
144762306a36Sopenharmony_ci	}
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	if (mp->m_logbufs != -1 &&
145062306a36Sopenharmony_ci	    mp->m_logbufs != 0 &&
145162306a36Sopenharmony_ci	    (mp->m_logbufs < XLOG_MIN_ICLOGS ||
145262306a36Sopenharmony_ci	     mp->m_logbufs > XLOG_MAX_ICLOGS)) {
145362306a36Sopenharmony_ci		xfs_warn(mp, "invalid logbufs value: %d [not %d-%d]",
145462306a36Sopenharmony_ci			mp->m_logbufs, XLOG_MIN_ICLOGS, XLOG_MAX_ICLOGS);
145562306a36Sopenharmony_ci		return -EINVAL;
145662306a36Sopenharmony_ci	}
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	if (mp->m_logbsize != -1 &&
145962306a36Sopenharmony_ci	    mp->m_logbsize !=  0 &&
146062306a36Sopenharmony_ci	    (mp->m_logbsize < XLOG_MIN_RECORD_BSIZE ||
146162306a36Sopenharmony_ci	     mp->m_logbsize > XLOG_MAX_RECORD_BSIZE ||
146262306a36Sopenharmony_ci	     !is_power_of_2(mp->m_logbsize))) {
146362306a36Sopenharmony_ci		xfs_warn(mp,
146462306a36Sopenharmony_ci			"invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]",
146562306a36Sopenharmony_ci			mp->m_logbsize);
146662306a36Sopenharmony_ci		return -EINVAL;
146762306a36Sopenharmony_ci	}
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	if (xfs_has_allocsize(mp) &&
147062306a36Sopenharmony_ci	    (mp->m_allocsize_log > XFS_MAX_IO_LOG ||
147162306a36Sopenharmony_ci	     mp->m_allocsize_log < XFS_MIN_IO_LOG)) {
147262306a36Sopenharmony_ci		xfs_warn(mp, "invalid log iosize: %d [not %d-%d]",
147362306a36Sopenharmony_ci			mp->m_allocsize_log, XFS_MIN_IO_LOG, XFS_MAX_IO_LOG);
147462306a36Sopenharmony_ci		return -EINVAL;
147562306a36Sopenharmony_ci	}
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	return 0;
147862306a36Sopenharmony_ci}
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_cistruct dentry *
148162306a36Sopenharmony_cixfs_debugfs_mkdir(
148262306a36Sopenharmony_ci	const char	*name,
148362306a36Sopenharmony_ci	struct dentry	*parent)
148462306a36Sopenharmony_ci{
148562306a36Sopenharmony_ci	struct dentry	*child;
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	/* Apparently we're expected to ignore error returns?? */
148862306a36Sopenharmony_ci	child = debugfs_create_dir(name, parent);
148962306a36Sopenharmony_ci	if (IS_ERR(child))
149062306a36Sopenharmony_ci		return NULL;
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	return child;
149362306a36Sopenharmony_ci}
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_cistatic int
149662306a36Sopenharmony_cixfs_fs_fill_super(
149762306a36Sopenharmony_ci	struct super_block	*sb,
149862306a36Sopenharmony_ci	struct fs_context	*fc)
149962306a36Sopenharmony_ci{
150062306a36Sopenharmony_ci	struct xfs_mount	*mp = sb->s_fs_info;
150162306a36Sopenharmony_ci	struct inode		*root;
150262306a36Sopenharmony_ci	int			flags = 0, error;
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	mp->m_super = sb;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	/*
150762306a36Sopenharmony_ci	 * Copy VFS mount flags from the context now that all parameter parsing
150862306a36Sopenharmony_ci	 * is guaranteed to have been completed by either the old mount API or
150962306a36Sopenharmony_ci	 * the newer fsopen/fsconfig API.
151062306a36Sopenharmony_ci	 */
151162306a36Sopenharmony_ci	if (fc->sb_flags & SB_RDONLY)
151262306a36Sopenharmony_ci		set_bit(XFS_OPSTATE_READONLY, &mp->m_opstate);
151362306a36Sopenharmony_ci	if (fc->sb_flags & SB_DIRSYNC)
151462306a36Sopenharmony_ci		mp->m_features |= XFS_FEAT_DIRSYNC;
151562306a36Sopenharmony_ci	if (fc->sb_flags & SB_SYNCHRONOUS)
151662306a36Sopenharmony_ci		mp->m_features |= XFS_FEAT_WSYNC;
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	error = xfs_fs_validate_params(mp);
151962306a36Sopenharmony_ci	if (error)
152062306a36Sopenharmony_ci		return error;
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	sb_min_blocksize(sb, BBSIZE);
152362306a36Sopenharmony_ci	sb->s_xattr = xfs_xattr_handlers;
152462306a36Sopenharmony_ci	sb->s_export_op = &xfs_export_operations;
152562306a36Sopenharmony_ci#ifdef CONFIG_XFS_QUOTA
152662306a36Sopenharmony_ci	sb->s_qcop = &xfs_quotactl_operations;
152762306a36Sopenharmony_ci	sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ;
152862306a36Sopenharmony_ci#endif
152962306a36Sopenharmony_ci	sb->s_op = &xfs_super_operations;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	/*
153262306a36Sopenharmony_ci	 * Delay mount work if the debug hook is set. This is debug
153362306a36Sopenharmony_ci	 * instrumention to coordinate simulation of xfs mount failures with
153462306a36Sopenharmony_ci	 * VFS superblock operations
153562306a36Sopenharmony_ci	 */
153662306a36Sopenharmony_ci	if (xfs_globals.mount_delay) {
153762306a36Sopenharmony_ci		xfs_notice(mp, "Delaying mount for %d seconds.",
153862306a36Sopenharmony_ci			xfs_globals.mount_delay);
153962306a36Sopenharmony_ci		msleep(xfs_globals.mount_delay * 1000);
154062306a36Sopenharmony_ci	}
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	if (fc->sb_flags & SB_SILENT)
154362306a36Sopenharmony_ci		flags |= XFS_MFSI_QUIET;
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	error = xfs_open_devices(mp);
154662306a36Sopenharmony_ci	if (error)
154762306a36Sopenharmony_ci		return error;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	if (xfs_debugfs) {
155062306a36Sopenharmony_ci		mp->m_debugfs = xfs_debugfs_mkdir(mp->m_super->s_id,
155162306a36Sopenharmony_ci						  xfs_debugfs);
155262306a36Sopenharmony_ci	} else {
155362306a36Sopenharmony_ci		mp->m_debugfs = NULL;
155462306a36Sopenharmony_ci	}
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	error = xfs_init_mount_workqueues(mp);
155762306a36Sopenharmony_ci	if (error)
155862306a36Sopenharmony_ci		goto out_shutdown_devices;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	error = xfs_init_percpu_counters(mp);
156162306a36Sopenharmony_ci	if (error)
156262306a36Sopenharmony_ci		goto out_destroy_workqueues;
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	error = xfs_inodegc_init_percpu(mp);
156562306a36Sopenharmony_ci	if (error)
156662306a36Sopenharmony_ci		goto out_destroy_counters;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	/* Allocate stats memory before we do operations that might use it */
156962306a36Sopenharmony_ci	mp->m_stats.xs_stats = alloc_percpu(struct xfsstats);
157062306a36Sopenharmony_ci	if (!mp->m_stats.xs_stats) {
157162306a36Sopenharmony_ci		error = -ENOMEM;
157262306a36Sopenharmony_ci		goto out_destroy_inodegc;
157362306a36Sopenharmony_ci	}
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	error = xchk_mount_stats_alloc(mp);
157662306a36Sopenharmony_ci	if (error)
157762306a36Sopenharmony_ci		goto out_free_stats;
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	error = xfs_readsb(mp, flags);
158062306a36Sopenharmony_ci	if (error)
158162306a36Sopenharmony_ci		goto out_free_scrub_stats;
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	error = xfs_finish_flags(mp);
158462306a36Sopenharmony_ci	if (error)
158562306a36Sopenharmony_ci		goto out_free_sb;
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	error = xfs_setup_devices(mp);
158862306a36Sopenharmony_ci	if (error)
158962306a36Sopenharmony_ci		goto out_free_sb;
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	/* V4 support is undergoing deprecation. */
159262306a36Sopenharmony_ci	if (!xfs_has_crc(mp)) {
159362306a36Sopenharmony_ci#ifdef CONFIG_XFS_SUPPORT_V4
159462306a36Sopenharmony_ci		xfs_warn_once(mp,
159562306a36Sopenharmony_ci	"Deprecated V4 format (crc=0) will not be supported after September 2030.");
159662306a36Sopenharmony_ci#else
159762306a36Sopenharmony_ci		xfs_warn(mp,
159862306a36Sopenharmony_ci	"Deprecated V4 format (crc=0) not supported by kernel.");
159962306a36Sopenharmony_ci		error = -EINVAL;
160062306a36Sopenharmony_ci		goto out_free_sb;
160162306a36Sopenharmony_ci#endif
160262306a36Sopenharmony_ci	}
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci	/* ASCII case insensitivity is undergoing deprecation. */
160562306a36Sopenharmony_ci	if (xfs_has_asciici(mp)) {
160662306a36Sopenharmony_ci#ifdef CONFIG_XFS_SUPPORT_ASCII_CI
160762306a36Sopenharmony_ci		xfs_warn_once(mp,
160862306a36Sopenharmony_ci	"Deprecated ASCII case-insensitivity feature (ascii-ci=1) will not be supported after September 2030.");
160962306a36Sopenharmony_ci#else
161062306a36Sopenharmony_ci		xfs_warn(mp,
161162306a36Sopenharmony_ci	"Deprecated ASCII case-insensitivity feature (ascii-ci=1) not supported by kernel.");
161262306a36Sopenharmony_ci		error = -EINVAL;
161362306a36Sopenharmony_ci		goto out_free_sb;
161462306a36Sopenharmony_ci#endif
161562306a36Sopenharmony_ci	}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	/* Filesystem claims it needs repair, so refuse the mount. */
161862306a36Sopenharmony_ci	if (xfs_has_needsrepair(mp)) {
161962306a36Sopenharmony_ci		xfs_warn(mp, "Filesystem needs repair.  Please run xfs_repair.");
162062306a36Sopenharmony_ci		error = -EFSCORRUPTED;
162162306a36Sopenharmony_ci		goto out_free_sb;
162262306a36Sopenharmony_ci	}
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	/*
162562306a36Sopenharmony_ci	 * Don't touch the filesystem if a user tool thinks it owns the primary
162662306a36Sopenharmony_ci	 * superblock.  mkfs doesn't clear the flag from secondary supers, so
162762306a36Sopenharmony_ci	 * we don't check them at all.
162862306a36Sopenharmony_ci	 */
162962306a36Sopenharmony_ci	if (mp->m_sb.sb_inprogress) {
163062306a36Sopenharmony_ci		xfs_warn(mp, "Offline file system operation in progress!");
163162306a36Sopenharmony_ci		error = -EFSCORRUPTED;
163262306a36Sopenharmony_ci		goto out_free_sb;
163362306a36Sopenharmony_ci	}
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	/*
163662306a36Sopenharmony_ci	 * Until this is fixed only page-sized or smaller data blocks work.
163762306a36Sopenharmony_ci	 */
163862306a36Sopenharmony_ci	if (mp->m_sb.sb_blocksize > PAGE_SIZE) {
163962306a36Sopenharmony_ci		xfs_warn(mp,
164062306a36Sopenharmony_ci		"File system with blocksize %d bytes. "
164162306a36Sopenharmony_ci		"Only pagesize (%ld) or less will currently work.",
164262306a36Sopenharmony_ci				mp->m_sb.sb_blocksize, PAGE_SIZE);
164362306a36Sopenharmony_ci		error = -ENOSYS;
164462306a36Sopenharmony_ci		goto out_free_sb;
164562306a36Sopenharmony_ci	}
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	/* Ensure this filesystem fits in the page cache limits */
164862306a36Sopenharmony_ci	if (xfs_sb_validate_fsb_count(&mp->m_sb, mp->m_sb.sb_dblocks) ||
164962306a36Sopenharmony_ci	    xfs_sb_validate_fsb_count(&mp->m_sb, mp->m_sb.sb_rblocks)) {
165062306a36Sopenharmony_ci		xfs_warn(mp,
165162306a36Sopenharmony_ci		"file system too large to be mounted on this system.");
165262306a36Sopenharmony_ci		error = -EFBIG;
165362306a36Sopenharmony_ci		goto out_free_sb;
165462306a36Sopenharmony_ci	}
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	/*
165762306a36Sopenharmony_ci	 * XFS block mappings use 54 bits to store the logical block offset.
165862306a36Sopenharmony_ci	 * This should suffice to handle the maximum file size that the VFS
165962306a36Sopenharmony_ci	 * supports (currently 2^63 bytes on 64-bit and ULONG_MAX << PAGE_SHIFT
166062306a36Sopenharmony_ci	 * bytes on 32-bit), but as XFS and VFS have gotten the s_maxbytes
166162306a36Sopenharmony_ci	 * calculation wrong on 32-bit kernels in the past, we'll add a WARN_ON
166262306a36Sopenharmony_ci	 * to check this assertion.
166362306a36Sopenharmony_ci	 *
166462306a36Sopenharmony_ci	 * Avoid integer overflow by comparing the maximum bmbt offset to the
166562306a36Sopenharmony_ci	 * maximum pagecache offset in units of fs blocks.
166662306a36Sopenharmony_ci	 */
166762306a36Sopenharmony_ci	if (!xfs_verify_fileoff(mp, XFS_B_TO_FSBT(mp, MAX_LFS_FILESIZE))) {
166862306a36Sopenharmony_ci		xfs_warn(mp,
166962306a36Sopenharmony_ci"MAX_LFS_FILESIZE block offset (%llu) exceeds extent map maximum (%llu)!",
167062306a36Sopenharmony_ci			 XFS_B_TO_FSBT(mp, MAX_LFS_FILESIZE),
167162306a36Sopenharmony_ci			 XFS_MAX_FILEOFF);
167262306a36Sopenharmony_ci		error = -EINVAL;
167362306a36Sopenharmony_ci		goto out_free_sb;
167462306a36Sopenharmony_ci	}
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	error = xfs_filestream_mount(mp);
167762306a36Sopenharmony_ci	if (error)
167862306a36Sopenharmony_ci		goto out_free_sb;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	/*
168162306a36Sopenharmony_ci	 * we must configure the block size in the superblock before we run the
168262306a36Sopenharmony_ci	 * full mount process as the mount process can lookup and cache inodes.
168362306a36Sopenharmony_ci	 */
168462306a36Sopenharmony_ci	sb->s_magic = XFS_SUPER_MAGIC;
168562306a36Sopenharmony_ci	sb->s_blocksize = mp->m_sb.sb_blocksize;
168662306a36Sopenharmony_ci	sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1;
168762306a36Sopenharmony_ci	sb->s_maxbytes = MAX_LFS_FILESIZE;
168862306a36Sopenharmony_ci	sb->s_max_links = XFS_MAXLINK;
168962306a36Sopenharmony_ci	sb->s_time_gran = 1;
169062306a36Sopenharmony_ci	if (xfs_has_bigtime(mp)) {
169162306a36Sopenharmony_ci		sb->s_time_min = xfs_bigtime_to_unix(XFS_BIGTIME_TIME_MIN);
169262306a36Sopenharmony_ci		sb->s_time_max = xfs_bigtime_to_unix(XFS_BIGTIME_TIME_MAX);
169362306a36Sopenharmony_ci	} else {
169462306a36Sopenharmony_ci		sb->s_time_min = XFS_LEGACY_TIME_MIN;
169562306a36Sopenharmony_ci		sb->s_time_max = XFS_LEGACY_TIME_MAX;
169662306a36Sopenharmony_ci	}
169762306a36Sopenharmony_ci	trace_xfs_inode_timestamp_range(mp, sb->s_time_min, sb->s_time_max);
169862306a36Sopenharmony_ci	sb->s_iflags |= SB_I_CGROUPWB;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	set_posix_acl_flag(sb);
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci	/* version 5 superblocks support inode version counters. */
170362306a36Sopenharmony_ci	if (xfs_has_crc(mp))
170462306a36Sopenharmony_ci		sb->s_flags |= SB_I_VERSION;
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	if (xfs_has_dax_always(mp)) {
170762306a36Sopenharmony_ci		error = xfs_setup_dax_always(mp);
170862306a36Sopenharmony_ci		if (error)
170962306a36Sopenharmony_ci			goto out_filestream_unmount;
171062306a36Sopenharmony_ci	}
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	if (xfs_has_discard(mp) && !bdev_max_discard_sectors(sb->s_bdev)) {
171362306a36Sopenharmony_ci		xfs_warn(mp,
171462306a36Sopenharmony_ci	"mounting with \"discard\" option, but the device does not support discard");
171562306a36Sopenharmony_ci		mp->m_features &= ~XFS_FEAT_DISCARD;
171662306a36Sopenharmony_ci	}
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	if (xfs_has_reflink(mp)) {
171962306a36Sopenharmony_ci		if (mp->m_sb.sb_rblocks) {
172062306a36Sopenharmony_ci			xfs_alert(mp,
172162306a36Sopenharmony_ci	"reflink not compatible with realtime device!");
172262306a36Sopenharmony_ci			error = -EINVAL;
172362306a36Sopenharmony_ci			goto out_filestream_unmount;
172462306a36Sopenharmony_ci		}
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci		if (xfs_globals.always_cow) {
172762306a36Sopenharmony_ci			xfs_info(mp, "using DEBUG-only always_cow mode.");
172862306a36Sopenharmony_ci			mp->m_always_cow = true;
172962306a36Sopenharmony_ci		}
173062306a36Sopenharmony_ci	}
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	if (xfs_has_rmapbt(mp) && mp->m_sb.sb_rblocks) {
173362306a36Sopenharmony_ci		xfs_alert(mp,
173462306a36Sopenharmony_ci	"reverse mapping btree not compatible with realtime device!");
173562306a36Sopenharmony_ci		error = -EINVAL;
173662306a36Sopenharmony_ci		goto out_filestream_unmount;
173762306a36Sopenharmony_ci	}
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	error = xfs_mountfs(mp);
174062306a36Sopenharmony_ci	if (error)
174162306a36Sopenharmony_ci		goto out_filestream_unmount;
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	root = igrab(VFS_I(mp->m_rootip));
174462306a36Sopenharmony_ci	if (!root) {
174562306a36Sopenharmony_ci		error = -ENOENT;
174662306a36Sopenharmony_ci		goto out_unmount;
174762306a36Sopenharmony_ci	}
174862306a36Sopenharmony_ci	sb->s_root = d_make_root(root);
174962306a36Sopenharmony_ci	if (!sb->s_root) {
175062306a36Sopenharmony_ci		error = -ENOMEM;
175162306a36Sopenharmony_ci		goto out_unmount;
175262306a36Sopenharmony_ci	}
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	return 0;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci out_filestream_unmount:
175762306a36Sopenharmony_ci	xfs_filestream_unmount(mp);
175862306a36Sopenharmony_ci out_free_sb:
175962306a36Sopenharmony_ci	xfs_freesb(mp);
176062306a36Sopenharmony_ci out_free_scrub_stats:
176162306a36Sopenharmony_ci	xchk_mount_stats_free(mp);
176262306a36Sopenharmony_ci out_free_stats:
176362306a36Sopenharmony_ci	free_percpu(mp->m_stats.xs_stats);
176462306a36Sopenharmony_ci out_destroy_inodegc:
176562306a36Sopenharmony_ci	xfs_inodegc_free_percpu(mp);
176662306a36Sopenharmony_ci out_destroy_counters:
176762306a36Sopenharmony_ci	xfs_destroy_percpu_counters(mp);
176862306a36Sopenharmony_ci out_destroy_workqueues:
176962306a36Sopenharmony_ci	xfs_destroy_mount_workqueues(mp);
177062306a36Sopenharmony_ci out_shutdown_devices:
177162306a36Sopenharmony_ci	xfs_shutdown_devices(mp);
177262306a36Sopenharmony_ci	return error;
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci out_unmount:
177562306a36Sopenharmony_ci	xfs_filestream_unmount(mp);
177662306a36Sopenharmony_ci	xfs_unmountfs(mp);
177762306a36Sopenharmony_ci	goto out_free_sb;
177862306a36Sopenharmony_ci}
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_cistatic int
178162306a36Sopenharmony_cixfs_fs_get_tree(
178262306a36Sopenharmony_ci	struct fs_context	*fc)
178362306a36Sopenharmony_ci{
178462306a36Sopenharmony_ci	return get_tree_bdev(fc, xfs_fs_fill_super);
178562306a36Sopenharmony_ci}
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_cistatic int
178862306a36Sopenharmony_cixfs_remount_rw(
178962306a36Sopenharmony_ci	struct xfs_mount	*mp)
179062306a36Sopenharmony_ci{
179162306a36Sopenharmony_ci	struct xfs_sb		*sbp = &mp->m_sb;
179262306a36Sopenharmony_ci	int error;
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	if (xfs_has_norecovery(mp)) {
179562306a36Sopenharmony_ci		xfs_warn(mp,
179662306a36Sopenharmony_ci			"ro->rw transition prohibited on norecovery mount");
179762306a36Sopenharmony_ci		return -EINVAL;
179862306a36Sopenharmony_ci	}
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	if (xfs_sb_is_v5(sbp) &&
180162306a36Sopenharmony_ci	    xfs_sb_has_ro_compat_feature(sbp, XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) {
180262306a36Sopenharmony_ci		xfs_warn(mp,
180362306a36Sopenharmony_ci	"ro->rw transition prohibited on unknown (0x%x) ro-compat filesystem",
180462306a36Sopenharmony_ci			(sbp->sb_features_ro_compat &
180562306a36Sopenharmony_ci				XFS_SB_FEAT_RO_COMPAT_UNKNOWN));
180662306a36Sopenharmony_ci		return -EINVAL;
180762306a36Sopenharmony_ci	}
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	clear_bit(XFS_OPSTATE_READONLY, &mp->m_opstate);
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	/*
181262306a36Sopenharmony_ci	 * If this is the first remount to writeable state we might have some
181362306a36Sopenharmony_ci	 * superblock changes to update.
181462306a36Sopenharmony_ci	 */
181562306a36Sopenharmony_ci	if (mp->m_update_sb) {
181662306a36Sopenharmony_ci		error = xfs_sync_sb(mp, false);
181762306a36Sopenharmony_ci		if (error) {
181862306a36Sopenharmony_ci			xfs_warn(mp, "failed to write sb changes");
181962306a36Sopenharmony_ci			return error;
182062306a36Sopenharmony_ci		}
182162306a36Sopenharmony_ci		mp->m_update_sb = false;
182262306a36Sopenharmony_ci	}
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	/*
182562306a36Sopenharmony_ci	 * Fill out the reserve pool if it is empty. Use the stashed value if
182662306a36Sopenharmony_ci	 * it is non-zero, otherwise go with the default.
182762306a36Sopenharmony_ci	 */
182862306a36Sopenharmony_ci	xfs_restore_resvblks(mp);
182962306a36Sopenharmony_ci	xfs_log_work_queue(mp);
183062306a36Sopenharmony_ci	xfs_blockgc_start(mp);
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	/* Create the per-AG metadata reservation pool .*/
183362306a36Sopenharmony_ci	error = xfs_fs_reserve_ag_blocks(mp);
183462306a36Sopenharmony_ci	if (error && error != -ENOSPC)
183562306a36Sopenharmony_ci		return error;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	/* Re-enable the background inode inactivation worker. */
183862306a36Sopenharmony_ci	xfs_inodegc_start(mp);
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	return 0;
184162306a36Sopenharmony_ci}
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_cistatic int
184462306a36Sopenharmony_cixfs_remount_ro(
184562306a36Sopenharmony_ci	struct xfs_mount	*mp)
184662306a36Sopenharmony_ci{
184762306a36Sopenharmony_ci	struct xfs_icwalk	icw = {
184862306a36Sopenharmony_ci		.icw_flags	= XFS_ICWALK_FLAG_SYNC,
184962306a36Sopenharmony_ci	};
185062306a36Sopenharmony_ci	int			error;
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	/* Flush all the dirty data to disk. */
185362306a36Sopenharmony_ci	error = sync_filesystem(mp->m_super);
185462306a36Sopenharmony_ci	if (error)
185562306a36Sopenharmony_ci		return error;
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci	/*
185862306a36Sopenharmony_ci	 * Cancel background eofb scanning so it cannot race with the final
185962306a36Sopenharmony_ci	 * log force+buftarg wait and deadlock the remount.
186062306a36Sopenharmony_ci	 */
186162306a36Sopenharmony_ci	xfs_blockgc_stop(mp);
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	/*
186462306a36Sopenharmony_ci	 * Clear out all remaining COW staging extents and speculative post-EOF
186562306a36Sopenharmony_ci	 * preallocations so that we don't leave inodes requiring inactivation
186662306a36Sopenharmony_ci	 * cleanups during reclaim on a read-only mount.  We must process every
186762306a36Sopenharmony_ci	 * cached inode, so this requires a synchronous cache scan.
186862306a36Sopenharmony_ci	 */
186962306a36Sopenharmony_ci	error = xfs_blockgc_free_space(mp, &icw);
187062306a36Sopenharmony_ci	if (error) {
187162306a36Sopenharmony_ci		xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
187262306a36Sopenharmony_ci		return error;
187362306a36Sopenharmony_ci	}
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	/*
187662306a36Sopenharmony_ci	 * Stop the inodegc background worker.  xfs_fs_reconfigure already
187762306a36Sopenharmony_ci	 * flushed all pending inodegc work when it sync'd the filesystem.
187862306a36Sopenharmony_ci	 * The VFS holds s_umount, so we know that inodes cannot enter
187962306a36Sopenharmony_ci	 * xfs_fs_destroy_inode during a remount operation.  In readonly mode
188062306a36Sopenharmony_ci	 * we send inodes straight to reclaim, so no inodes will be queued.
188162306a36Sopenharmony_ci	 */
188262306a36Sopenharmony_ci	xfs_inodegc_stop(mp);
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	/* Free the per-AG metadata reservation pool. */
188562306a36Sopenharmony_ci	error = xfs_fs_unreserve_ag_blocks(mp);
188662306a36Sopenharmony_ci	if (error) {
188762306a36Sopenharmony_ci		xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
188862306a36Sopenharmony_ci		return error;
188962306a36Sopenharmony_ci	}
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	/*
189262306a36Sopenharmony_ci	 * Before we sync the metadata, we need to free up the reserve block
189362306a36Sopenharmony_ci	 * pool so that the used block count in the superblock on disk is
189462306a36Sopenharmony_ci	 * correct at the end of the remount. Stash the current* reserve pool
189562306a36Sopenharmony_ci	 * size so that if we get remounted rw, we can return it to the same
189662306a36Sopenharmony_ci	 * size.
189762306a36Sopenharmony_ci	 */
189862306a36Sopenharmony_ci	xfs_save_resvblks(mp);
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	xfs_log_clean(mp);
190162306a36Sopenharmony_ci	set_bit(XFS_OPSTATE_READONLY, &mp->m_opstate);
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	return 0;
190462306a36Sopenharmony_ci}
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci/*
190762306a36Sopenharmony_ci * Logically we would return an error here to prevent users from believing
190862306a36Sopenharmony_ci * they might have changed mount options using remount which can't be changed.
190962306a36Sopenharmony_ci *
191062306a36Sopenharmony_ci * But unfortunately mount(8) adds all options from mtab and fstab to the mount
191162306a36Sopenharmony_ci * arguments in some cases so we can't blindly reject options, but have to
191262306a36Sopenharmony_ci * check for each specified option if it actually differs from the currently
191362306a36Sopenharmony_ci * set option and only reject it if that's the case.
191462306a36Sopenharmony_ci *
191562306a36Sopenharmony_ci * Until that is implemented we return success for every remount request, and
191662306a36Sopenharmony_ci * silently ignore all options that we can't actually change.
191762306a36Sopenharmony_ci */
191862306a36Sopenharmony_cistatic int
191962306a36Sopenharmony_cixfs_fs_reconfigure(
192062306a36Sopenharmony_ci	struct fs_context *fc)
192162306a36Sopenharmony_ci{
192262306a36Sopenharmony_ci	struct xfs_mount	*mp = XFS_M(fc->root->d_sb);
192362306a36Sopenharmony_ci	struct xfs_mount        *new_mp = fc->s_fs_info;
192462306a36Sopenharmony_ci	int			flags = fc->sb_flags;
192562306a36Sopenharmony_ci	int			error;
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	/* version 5 superblocks always support version counters. */
192862306a36Sopenharmony_ci	if (xfs_has_crc(mp))
192962306a36Sopenharmony_ci		fc->sb_flags |= SB_I_VERSION;
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci	error = xfs_fs_validate_params(new_mp);
193262306a36Sopenharmony_ci	if (error)
193362306a36Sopenharmony_ci		return error;
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	/* inode32 -> inode64 */
193662306a36Sopenharmony_ci	if (xfs_has_small_inums(mp) && !xfs_has_small_inums(new_mp)) {
193762306a36Sopenharmony_ci		mp->m_features &= ~XFS_FEAT_SMALL_INUMS;
193862306a36Sopenharmony_ci		mp->m_maxagi = xfs_set_inode_alloc(mp, mp->m_sb.sb_agcount);
193962306a36Sopenharmony_ci	}
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	/* inode64 -> inode32 */
194262306a36Sopenharmony_ci	if (!xfs_has_small_inums(mp) && xfs_has_small_inums(new_mp)) {
194362306a36Sopenharmony_ci		mp->m_features |= XFS_FEAT_SMALL_INUMS;
194462306a36Sopenharmony_ci		mp->m_maxagi = xfs_set_inode_alloc(mp, mp->m_sb.sb_agcount);
194562306a36Sopenharmony_ci	}
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	/* ro -> rw */
194862306a36Sopenharmony_ci	if (xfs_is_readonly(mp) && !(flags & SB_RDONLY)) {
194962306a36Sopenharmony_ci		error = xfs_remount_rw(mp);
195062306a36Sopenharmony_ci		if (error)
195162306a36Sopenharmony_ci			return error;
195262306a36Sopenharmony_ci	}
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci	/* rw -> ro */
195562306a36Sopenharmony_ci	if (!xfs_is_readonly(mp) && (flags & SB_RDONLY)) {
195662306a36Sopenharmony_ci		error = xfs_remount_ro(mp);
195762306a36Sopenharmony_ci		if (error)
195862306a36Sopenharmony_ci			return error;
195962306a36Sopenharmony_ci	}
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	return 0;
196262306a36Sopenharmony_ci}
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_cistatic void
196562306a36Sopenharmony_cixfs_fs_free(
196662306a36Sopenharmony_ci	struct fs_context	*fc)
196762306a36Sopenharmony_ci{
196862306a36Sopenharmony_ci	struct xfs_mount	*mp = fc->s_fs_info;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	/*
197162306a36Sopenharmony_ci	 * mp is stored in the fs_context when it is initialized.
197262306a36Sopenharmony_ci	 * mp is transferred to the superblock on a successful mount,
197362306a36Sopenharmony_ci	 * but if an error occurs before the transfer we have to free
197462306a36Sopenharmony_ci	 * it here.
197562306a36Sopenharmony_ci	 */
197662306a36Sopenharmony_ci	if (mp)
197762306a36Sopenharmony_ci		xfs_mount_free(mp);
197862306a36Sopenharmony_ci}
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_cistatic const struct fs_context_operations xfs_context_ops = {
198162306a36Sopenharmony_ci	.parse_param = xfs_fs_parse_param,
198262306a36Sopenharmony_ci	.get_tree    = xfs_fs_get_tree,
198362306a36Sopenharmony_ci	.reconfigure = xfs_fs_reconfigure,
198462306a36Sopenharmony_ci	.free        = xfs_fs_free,
198562306a36Sopenharmony_ci};
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci/*
198862306a36Sopenharmony_ci * WARNING: do not initialise any parameters in this function that depend on
198962306a36Sopenharmony_ci * mount option parsing having already been performed as this can be called from
199062306a36Sopenharmony_ci * fsopen() before any parameters have been set.
199162306a36Sopenharmony_ci */
199262306a36Sopenharmony_cistatic int xfs_init_fs_context(
199362306a36Sopenharmony_ci	struct fs_context	*fc)
199462306a36Sopenharmony_ci{
199562306a36Sopenharmony_ci	struct xfs_mount	*mp;
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci	mp = kmem_alloc(sizeof(struct xfs_mount), KM_ZERO);
199862306a36Sopenharmony_ci	if (!mp)
199962306a36Sopenharmony_ci		return -ENOMEM;
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci	spin_lock_init(&mp->m_sb_lock);
200262306a36Sopenharmony_ci	INIT_RADIX_TREE(&mp->m_perag_tree, GFP_ATOMIC);
200362306a36Sopenharmony_ci	spin_lock_init(&mp->m_perag_lock);
200462306a36Sopenharmony_ci	mutex_init(&mp->m_growlock);
200562306a36Sopenharmony_ci	INIT_WORK(&mp->m_flush_inodes_work, xfs_flush_inodes_worker);
200662306a36Sopenharmony_ci	INIT_DELAYED_WORK(&mp->m_reclaim_work, xfs_reclaim_worker);
200762306a36Sopenharmony_ci	mp->m_kobj.kobject.kset = xfs_kset;
200862306a36Sopenharmony_ci	/*
200962306a36Sopenharmony_ci	 * We don't create the finobt per-ag space reservation until after log
201062306a36Sopenharmony_ci	 * recovery, so we must set this to true so that an ifree transaction
201162306a36Sopenharmony_ci	 * started during log recovery will not depend on space reservations
201262306a36Sopenharmony_ci	 * for finobt expansion.
201362306a36Sopenharmony_ci	 */
201462306a36Sopenharmony_ci	mp->m_finobt_nores = true;
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	/*
201762306a36Sopenharmony_ci	 * These can be overridden by the mount option parsing.
201862306a36Sopenharmony_ci	 */
201962306a36Sopenharmony_ci	mp->m_logbufs = -1;
202062306a36Sopenharmony_ci	mp->m_logbsize = -1;
202162306a36Sopenharmony_ci	mp->m_allocsize_log = 16; /* 64k */
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	fc->s_fs_info = mp;
202462306a36Sopenharmony_ci	fc->ops = &xfs_context_ops;
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	return 0;
202762306a36Sopenharmony_ci}
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_cistatic void
203062306a36Sopenharmony_cixfs_kill_sb(
203162306a36Sopenharmony_ci	struct super_block		*sb)
203262306a36Sopenharmony_ci{
203362306a36Sopenharmony_ci	kill_block_super(sb);
203462306a36Sopenharmony_ci	xfs_mount_free(XFS_M(sb));
203562306a36Sopenharmony_ci}
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_cistatic struct file_system_type xfs_fs_type = {
203862306a36Sopenharmony_ci	.owner			= THIS_MODULE,
203962306a36Sopenharmony_ci	.name			= "xfs",
204062306a36Sopenharmony_ci	.init_fs_context	= xfs_init_fs_context,
204162306a36Sopenharmony_ci	.parameters		= xfs_fs_parameters,
204262306a36Sopenharmony_ci	.kill_sb		= xfs_kill_sb,
204362306a36Sopenharmony_ci	.fs_flags		= FS_REQUIRES_DEV | FS_ALLOW_IDMAP,
204462306a36Sopenharmony_ci};
204562306a36Sopenharmony_ciMODULE_ALIAS_FS("xfs");
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ciSTATIC int __init
204862306a36Sopenharmony_cixfs_init_caches(void)
204962306a36Sopenharmony_ci{
205062306a36Sopenharmony_ci	int		error;
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	xfs_buf_cache = kmem_cache_create("xfs_buf", sizeof(struct xfs_buf), 0,
205362306a36Sopenharmony_ci					 SLAB_HWCACHE_ALIGN |
205462306a36Sopenharmony_ci					 SLAB_RECLAIM_ACCOUNT |
205562306a36Sopenharmony_ci					 SLAB_MEM_SPREAD,
205662306a36Sopenharmony_ci					 NULL);
205762306a36Sopenharmony_ci	if (!xfs_buf_cache)
205862306a36Sopenharmony_ci		goto out;
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	xfs_log_ticket_cache = kmem_cache_create("xfs_log_ticket",
206162306a36Sopenharmony_ci						sizeof(struct xlog_ticket),
206262306a36Sopenharmony_ci						0, 0, NULL);
206362306a36Sopenharmony_ci	if (!xfs_log_ticket_cache)
206462306a36Sopenharmony_ci		goto out_destroy_buf_cache;
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	error = xfs_btree_init_cur_caches();
206762306a36Sopenharmony_ci	if (error)
206862306a36Sopenharmony_ci		goto out_destroy_log_ticket_cache;
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci	error = xfs_defer_init_item_caches();
207162306a36Sopenharmony_ci	if (error)
207262306a36Sopenharmony_ci		goto out_destroy_btree_cur_cache;
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	xfs_da_state_cache = kmem_cache_create("xfs_da_state",
207562306a36Sopenharmony_ci					      sizeof(struct xfs_da_state),
207662306a36Sopenharmony_ci					      0, 0, NULL);
207762306a36Sopenharmony_ci	if (!xfs_da_state_cache)
207862306a36Sopenharmony_ci		goto out_destroy_defer_item_cache;
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci	xfs_ifork_cache = kmem_cache_create("xfs_ifork",
208162306a36Sopenharmony_ci					   sizeof(struct xfs_ifork),
208262306a36Sopenharmony_ci					   0, 0, NULL);
208362306a36Sopenharmony_ci	if (!xfs_ifork_cache)
208462306a36Sopenharmony_ci		goto out_destroy_da_state_cache;
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	xfs_trans_cache = kmem_cache_create("xfs_trans",
208762306a36Sopenharmony_ci					   sizeof(struct xfs_trans),
208862306a36Sopenharmony_ci					   0, 0, NULL);
208962306a36Sopenharmony_ci	if (!xfs_trans_cache)
209062306a36Sopenharmony_ci		goto out_destroy_ifork_cache;
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	/*
209462306a36Sopenharmony_ci	 * The size of the cache-allocated buf log item is the maximum
209562306a36Sopenharmony_ci	 * size possible under XFS.  This wastes a little bit of memory,
209662306a36Sopenharmony_ci	 * but it is much faster.
209762306a36Sopenharmony_ci	 */
209862306a36Sopenharmony_ci	xfs_buf_item_cache = kmem_cache_create("xfs_buf_item",
209962306a36Sopenharmony_ci					      sizeof(struct xfs_buf_log_item),
210062306a36Sopenharmony_ci					      0, 0, NULL);
210162306a36Sopenharmony_ci	if (!xfs_buf_item_cache)
210262306a36Sopenharmony_ci		goto out_destroy_trans_cache;
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	xfs_efd_cache = kmem_cache_create("xfs_efd_item",
210562306a36Sopenharmony_ci			xfs_efd_log_item_sizeof(XFS_EFD_MAX_FAST_EXTENTS),
210662306a36Sopenharmony_ci			0, 0, NULL);
210762306a36Sopenharmony_ci	if (!xfs_efd_cache)
210862306a36Sopenharmony_ci		goto out_destroy_buf_item_cache;
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	xfs_efi_cache = kmem_cache_create("xfs_efi_item",
211162306a36Sopenharmony_ci			xfs_efi_log_item_sizeof(XFS_EFI_MAX_FAST_EXTENTS),
211262306a36Sopenharmony_ci			0, 0, NULL);
211362306a36Sopenharmony_ci	if (!xfs_efi_cache)
211462306a36Sopenharmony_ci		goto out_destroy_efd_cache;
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	xfs_inode_cache = kmem_cache_create("xfs_inode",
211762306a36Sopenharmony_ci					   sizeof(struct xfs_inode), 0,
211862306a36Sopenharmony_ci					   (SLAB_HWCACHE_ALIGN |
211962306a36Sopenharmony_ci					    SLAB_RECLAIM_ACCOUNT |
212062306a36Sopenharmony_ci					    SLAB_MEM_SPREAD | SLAB_ACCOUNT),
212162306a36Sopenharmony_ci					   xfs_fs_inode_init_once);
212262306a36Sopenharmony_ci	if (!xfs_inode_cache)
212362306a36Sopenharmony_ci		goto out_destroy_efi_cache;
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	xfs_ili_cache = kmem_cache_create("xfs_ili",
212662306a36Sopenharmony_ci					 sizeof(struct xfs_inode_log_item), 0,
212762306a36Sopenharmony_ci					 SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
212862306a36Sopenharmony_ci					 NULL);
212962306a36Sopenharmony_ci	if (!xfs_ili_cache)
213062306a36Sopenharmony_ci		goto out_destroy_inode_cache;
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci	xfs_icreate_cache = kmem_cache_create("xfs_icr",
213362306a36Sopenharmony_ci					     sizeof(struct xfs_icreate_item),
213462306a36Sopenharmony_ci					     0, 0, NULL);
213562306a36Sopenharmony_ci	if (!xfs_icreate_cache)
213662306a36Sopenharmony_ci		goto out_destroy_ili_cache;
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	xfs_rud_cache = kmem_cache_create("xfs_rud_item",
213962306a36Sopenharmony_ci					 sizeof(struct xfs_rud_log_item),
214062306a36Sopenharmony_ci					 0, 0, NULL);
214162306a36Sopenharmony_ci	if (!xfs_rud_cache)
214262306a36Sopenharmony_ci		goto out_destroy_icreate_cache;
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	xfs_rui_cache = kmem_cache_create("xfs_rui_item",
214562306a36Sopenharmony_ci			xfs_rui_log_item_sizeof(XFS_RUI_MAX_FAST_EXTENTS),
214662306a36Sopenharmony_ci			0, 0, NULL);
214762306a36Sopenharmony_ci	if (!xfs_rui_cache)
214862306a36Sopenharmony_ci		goto out_destroy_rud_cache;
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	xfs_cud_cache = kmem_cache_create("xfs_cud_item",
215162306a36Sopenharmony_ci					 sizeof(struct xfs_cud_log_item),
215262306a36Sopenharmony_ci					 0, 0, NULL);
215362306a36Sopenharmony_ci	if (!xfs_cud_cache)
215462306a36Sopenharmony_ci		goto out_destroy_rui_cache;
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	xfs_cui_cache = kmem_cache_create("xfs_cui_item",
215762306a36Sopenharmony_ci			xfs_cui_log_item_sizeof(XFS_CUI_MAX_FAST_EXTENTS),
215862306a36Sopenharmony_ci			0, 0, NULL);
215962306a36Sopenharmony_ci	if (!xfs_cui_cache)
216062306a36Sopenharmony_ci		goto out_destroy_cud_cache;
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci	xfs_bud_cache = kmem_cache_create("xfs_bud_item",
216362306a36Sopenharmony_ci					 sizeof(struct xfs_bud_log_item),
216462306a36Sopenharmony_ci					 0, 0, NULL);
216562306a36Sopenharmony_ci	if (!xfs_bud_cache)
216662306a36Sopenharmony_ci		goto out_destroy_cui_cache;
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	xfs_bui_cache = kmem_cache_create("xfs_bui_item",
216962306a36Sopenharmony_ci			xfs_bui_log_item_sizeof(XFS_BUI_MAX_FAST_EXTENTS),
217062306a36Sopenharmony_ci			0, 0, NULL);
217162306a36Sopenharmony_ci	if (!xfs_bui_cache)
217262306a36Sopenharmony_ci		goto out_destroy_bud_cache;
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci	xfs_attrd_cache = kmem_cache_create("xfs_attrd_item",
217562306a36Sopenharmony_ci					    sizeof(struct xfs_attrd_log_item),
217662306a36Sopenharmony_ci					    0, 0, NULL);
217762306a36Sopenharmony_ci	if (!xfs_attrd_cache)
217862306a36Sopenharmony_ci		goto out_destroy_bui_cache;
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	xfs_attri_cache = kmem_cache_create("xfs_attri_item",
218162306a36Sopenharmony_ci					    sizeof(struct xfs_attri_log_item),
218262306a36Sopenharmony_ci					    0, 0, NULL);
218362306a36Sopenharmony_ci	if (!xfs_attri_cache)
218462306a36Sopenharmony_ci		goto out_destroy_attrd_cache;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	xfs_iunlink_cache = kmem_cache_create("xfs_iul_item",
218762306a36Sopenharmony_ci					     sizeof(struct xfs_iunlink_item),
218862306a36Sopenharmony_ci					     0, 0, NULL);
218962306a36Sopenharmony_ci	if (!xfs_iunlink_cache)
219062306a36Sopenharmony_ci		goto out_destroy_attri_cache;
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	return 0;
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci out_destroy_attri_cache:
219562306a36Sopenharmony_ci	kmem_cache_destroy(xfs_attri_cache);
219662306a36Sopenharmony_ci out_destroy_attrd_cache:
219762306a36Sopenharmony_ci	kmem_cache_destroy(xfs_attrd_cache);
219862306a36Sopenharmony_ci out_destroy_bui_cache:
219962306a36Sopenharmony_ci	kmem_cache_destroy(xfs_bui_cache);
220062306a36Sopenharmony_ci out_destroy_bud_cache:
220162306a36Sopenharmony_ci	kmem_cache_destroy(xfs_bud_cache);
220262306a36Sopenharmony_ci out_destroy_cui_cache:
220362306a36Sopenharmony_ci	kmem_cache_destroy(xfs_cui_cache);
220462306a36Sopenharmony_ci out_destroy_cud_cache:
220562306a36Sopenharmony_ci	kmem_cache_destroy(xfs_cud_cache);
220662306a36Sopenharmony_ci out_destroy_rui_cache:
220762306a36Sopenharmony_ci	kmem_cache_destroy(xfs_rui_cache);
220862306a36Sopenharmony_ci out_destroy_rud_cache:
220962306a36Sopenharmony_ci	kmem_cache_destroy(xfs_rud_cache);
221062306a36Sopenharmony_ci out_destroy_icreate_cache:
221162306a36Sopenharmony_ci	kmem_cache_destroy(xfs_icreate_cache);
221262306a36Sopenharmony_ci out_destroy_ili_cache:
221362306a36Sopenharmony_ci	kmem_cache_destroy(xfs_ili_cache);
221462306a36Sopenharmony_ci out_destroy_inode_cache:
221562306a36Sopenharmony_ci	kmem_cache_destroy(xfs_inode_cache);
221662306a36Sopenharmony_ci out_destroy_efi_cache:
221762306a36Sopenharmony_ci	kmem_cache_destroy(xfs_efi_cache);
221862306a36Sopenharmony_ci out_destroy_efd_cache:
221962306a36Sopenharmony_ci	kmem_cache_destroy(xfs_efd_cache);
222062306a36Sopenharmony_ci out_destroy_buf_item_cache:
222162306a36Sopenharmony_ci	kmem_cache_destroy(xfs_buf_item_cache);
222262306a36Sopenharmony_ci out_destroy_trans_cache:
222362306a36Sopenharmony_ci	kmem_cache_destroy(xfs_trans_cache);
222462306a36Sopenharmony_ci out_destroy_ifork_cache:
222562306a36Sopenharmony_ci	kmem_cache_destroy(xfs_ifork_cache);
222662306a36Sopenharmony_ci out_destroy_da_state_cache:
222762306a36Sopenharmony_ci	kmem_cache_destroy(xfs_da_state_cache);
222862306a36Sopenharmony_ci out_destroy_defer_item_cache:
222962306a36Sopenharmony_ci	xfs_defer_destroy_item_caches();
223062306a36Sopenharmony_ci out_destroy_btree_cur_cache:
223162306a36Sopenharmony_ci	xfs_btree_destroy_cur_caches();
223262306a36Sopenharmony_ci out_destroy_log_ticket_cache:
223362306a36Sopenharmony_ci	kmem_cache_destroy(xfs_log_ticket_cache);
223462306a36Sopenharmony_ci out_destroy_buf_cache:
223562306a36Sopenharmony_ci	kmem_cache_destroy(xfs_buf_cache);
223662306a36Sopenharmony_ci out:
223762306a36Sopenharmony_ci	return -ENOMEM;
223862306a36Sopenharmony_ci}
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ciSTATIC void
224162306a36Sopenharmony_cixfs_destroy_caches(void)
224262306a36Sopenharmony_ci{
224362306a36Sopenharmony_ci	/*
224462306a36Sopenharmony_ci	 * Make sure all delayed rcu free are flushed before we
224562306a36Sopenharmony_ci	 * destroy caches.
224662306a36Sopenharmony_ci	 */
224762306a36Sopenharmony_ci	rcu_barrier();
224862306a36Sopenharmony_ci	kmem_cache_destroy(xfs_iunlink_cache);
224962306a36Sopenharmony_ci	kmem_cache_destroy(xfs_attri_cache);
225062306a36Sopenharmony_ci	kmem_cache_destroy(xfs_attrd_cache);
225162306a36Sopenharmony_ci	kmem_cache_destroy(xfs_bui_cache);
225262306a36Sopenharmony_ci	kmem_cache_destroy(xfs_bud_cache);
225362306a36Sopenharmony_ci	kmem_cache_destroy(xfs_cui_cache);
225462306a36Sopenharmony_ci	kmem_cache_destroy(xfs_cud_cache);
225562306a36Sopenharmony_ci	kmem_cache_destroy(xfs_rui_cache);
225662306a36Sopenharmony_ci	kmem_cache_destroy(xfs_rud_cache);
225762306a36Sopenharmony_ci	kmem_cache_destroy(xfs_icreate_cache);
225862306a36Sopenharmony_ci	kmem_cache_destroy(xfs_ili_cache);
225962306a36Sopenharmony_ci	kmem_cache_destroy(xfs_inode_cache);
226062306a36Sopenharmony_ci	kmem_cache_destroy(xfs_efi_cache);
226162306a36Sopenharmony_ci	kmem_cache_destroy(xfs_efd_cache);
226262306a36Sopenharmony_ci	kmem_cache_destroy(xfs_buf_item_cache);
226362306a36Sopenharmony_ci	kmem_cache_destroy(xfs_trans_cache);
226462306a36Sopenharmony_ci	kmem_cache_destroy(xfs_ifork_cache);
226562306a36Sopenharmony_ci	kmem_cache_destroy(xfs_da_state_cache);
226662306a36Sopenharmony_ci	xfs_defer_destroy_item_caches();
226762306a36Sopenharmony_ci	xfs_btree_destroy_cur_caches();
226862306a36Sopenharmony_ci	kmem_cache_destroy(xfs_log_ticket_cache);
226962306a36Sopenharmony_ci	kmem_cache_destroy(xfs_buf_cache);
227062306a36Sopenharmony_ci}
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ciSTATIC int __init
227362306a36Sopenharmony_cixfs_init_workqueues(void)
227462306a36Sopenharmony_ci{
227562306a36Sopenharmony_ci	/*
227662306a36Sopenharmony_ci	 * The allocation workqueue can be used in memory reclaim situations
227762306a36Sopenharmony_ci	 * (writepage path), and parallelism is only limited by the number of
227862306a36Sopenharmony_ci	 * AGs in all the filesystems mounted. Hence use the default large
227962306a36Sopenharmony_ci	 * max_active value for this workqueue.
228062306a36Sopenharmony_ci	 */
228162306a36Sopenharmony_ci	xfs_alloc_wq = alloc_workqueue("xfsalloc",
228262306a36Sopenharmony_ci			XFS_WQFLAGS(WQ_MEM_RECLAIM | WQ_FREEZABLE), 0);
228362306a36Sopenharmony_ci	if (!xfs_alloc_wq)
228462306a36Sopenharmony_ci		return -ENOMEM;
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci	xfs_discard_wq = alloc_workqueue("xfsdiscard", XFS_WQFLAGS(WQ_UNBOUND),
228762306a36Sopenharmony_ci			0);
228862306a36Sopenharmony_ci	if (!xfs_discard_wq)
228962306a36Sopenharmony_ci		goto out_free_alloc_wq;
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	return 0;
229262306a36Sopenharmony_ciout_free_alloc_wq:
229362306a36Sopenharmony_ci	destroy_workqueue(xfs_alloc_wq);
229462306a36Sopenharmony_ci	return -ENOMEM;
229562306a36Sopenharmony_ci}
229662306a36Sopenharmony_ci
229762306a36Sopenharmony_ciSTATIC void
229862306a36Sopenharmony_cixfs_destroy_workqueues(void)
229962306a36Sopenharmony_ci{
230062306a36Sopenharmony_ci	destroy_workqueue(xfs_discard_wq);
230162306a36Sopenharmony_ci	destroy_workqueue(xfs_alloc_wq);
230262306a36Sopenharmony_ci}
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ciSTATIC int __init
230562306a36Sopenharmony_ciinit_xfs_fs(void)
230662306a36Sopenharmony_ci{
230762306a36Sopenharmony_ci	int			error;
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci	xfs_check_ondisk_structs();
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	error = xfs_dahash_test();
231262306a36Sopenharmony_ci	if (error)
231362306a36Sopenharmony_ci		return error;
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci	printk(KERN_INFO XFS_VERSION_STRING " with "
231662306a36Sopenharmony_ci			 XFS_BUILD_OPTIONS " enabled\n");
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci	xfs_dir_startup();
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_ci	error = xfs_init_caches();
232162306a36Sopenharmony_ci	if (error)
232262306a36Sopenharmony_ci		goto out;
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci	error = xfs_init_workqueues();
232562306a36Sopenharmony_ci	if (error)
232662306a36Sopenharmony_ci		goto out_destroy_caches;
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci	error = xfs_mru_cache_init();
232962306a36Sopenharmony_ci	if (error)
233062306a36Sopenharmony_ci		goto out_destroy_wq;
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci	error = xfs_init_procfs();
233362306a36Sopenharmony_ci	if (error)
233462306a36Sopenharmony_ci		goto out_mru_cache_uninit;
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci	error = xfs_sysctl_register();
233762306a36Sopenharmony_ci	if (error)
233862306a36Sopenharmony_ci		goto out_cleanup_procfs;
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci	xfs_debugfs = xfs_debugfs_mkdir("xfs", NULL);
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_ci	xfs_kset = kset_create_and_add("xfs", NULL, fs_kobj);
234362306a36Sopenharmony_ci	if (!xfs_kset) {
234462306a36Sopenharmony_ci		error = -ENOMEM;
234562306a36Sopenharmony_ci		goto out_debugfs_unregister;
234662306a36Sopenharmony_ci	}
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	xfsstats.xs_kobj.kobject.kset = xfs_kset;
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	xfsstats.xs_stats = alloc_percpu(struct xfsstats);
235162306a36Sopenharmony_ci	if (!xfsstats.xs_stats) {
235262306a36Sopenharmony_ci		error = -ENOMEM;
235362306a36Sopenharmony_ci		goto out_kset_unregister;
235462306a36Sopenharmony_ci	}
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	error = xfs_sysfs_init(&xfsstats.xs_kobj, &xfs_stats_ktype, NULL,
235762306a36Sopenharmony_ci			       "stats");
235862306a36Sopenharmony_ci	if (error)
235962306a36Sopenharmony_ci		goto out_free_stats;
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci	error = xchk_global_stats_setup(xfs_debugfs);
236262306a36Sopenharmony_ci	if (error)
236362306a36Sopenharmony_ci		goto out_remove_stats_kobj;
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_ci#ifdef DEBUG
236662306a36Sopenharmony_ci	xfs_dbg_kobj.kobject.kset = xfs_kset;
236762306a36Sopenharmony_ci	error = xfs_sysfs_init(&xfs_dbg_kobj, &xfs_dbg_ktype, NULL, "debug");
236862306a36Sopenharmony_ci	if (error)
236962306a36Sopenharmony_ci		goto out_remove_scrub_stats;
237062306a36Sopenharmony_ci#endif
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	error = xfs_qm_init();
237362306a36Sopenharmony_ci	if (error)
237462306a36Sopenharmony_ci		goto out_remove_dbg_kobj;
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci	error = register_filesystem(&xfs_fs_type);
237762306a36Sopenharmony_ci	if (error)
237862306a36Sopenharmony_ci		goto out_qm_exit;
237962306a36Sopenharmony_ci	return 0;
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci out_qm_exit:
238262306a36Sopenharmony_ci	xfs_qm_exit();
238362306a36Sopenharmony_ci out_remove_dbg_kobj:
238462306a36Sopenharmony_ci#ifdef DEBUG
238562306a36Sopenharmony_ci	xfs_sysfs_del(&xfs_dbg_kobj);
238662306a36Sopenharmony_ci out_remove_scrub_stats:
238762306a36Sopenharmony_ci#endif
238862306a36Sopenharmony_ci	xchk_global_stats_teardown();
238962306a36Sopenharmony_ci out_remove_stats_kobj:
239062306a36Sopenharmony_ci	xfs_sysfs_del(&xfsstats.xs_kobj);
239162306a36Sopenharmony_ci out_free_stats:
239262306a36Sopenharmony_ci	free_percpu(xfsstats.xs_stats);
239362306a36Sopenharmony_ci out_kset_unregister:
239462306a36Sopenharmony_ci	kset_unregister(xfs_kset);
239562306a36Sopenharmony_ci out_debugfs_unregister:
239662306a36Sopenharmony_ci	debugfs_remove(xfs_debugfs);
239762306a36Sopenharmony_ci	xfs_sysctl_unregister();
239862306a36Sopenharmony_ci out_cleanup_procfs:
239962306a36Sopenharmony_ci	xfs_cleanup_procfs();
240062306a36Sopenharmony_ci out_mru_cache_uninit:
240162306a36Sopenharmony_ci	xfs_mru_cache_uninit();
240262306a36Sopenharmony_ci out_destroy_wq:
240362306a36Sopenharmony_ci	xfs_destroy_workqueues();
240462306a36Sopenharmony_ci out_destroy_caches:
240562306a36Sopenharmony_ci	xfs_destroy_caches();
240662306a36Sopenharmony_ci out:
240762306a36Sopenharmony_ci	return error;
240862306a36Sopenharmony_ci}
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ciSTATIC void __exit
241162306a36Sopenharmony_ciexit_xfs_fs(void)
241262306a36Sopenharmony_ci{
241362306a36Sopenharmony_ci	xfs_qm_exit();
241462306a36Sopenharmony_ci	unregister_filesystem(&xfs_fs_type);
241562306a36Sopenharmony_ci#ifdef DEBUG
241662306a36Sopenharmony_ci	xfs_sysfs_del(&xfs_dbg_kobj);
241762306a36Sopenharmony_ci#endif
241862306a36Sopenharmony_ci	xchk_global_stats_teardown();
241962306a36Sopenharmony_ci	xfs_sysfs_del(&xfsstats.xs_kobj);
242062306a36Sopenharmony_ci	free_percpu(xfsstats.xs_stats);
242162306a36Sopenharmony_ci	kset_unregister(xfs_kset);
242262306a36Sopenharmony_ci	debugfs_remove(xfs_debugfs);
242362306a36Sopenharmony_ci	xfs_sysctl_unregister();
242462306a36Sopenharmony_ci	xfs_cleanup_procfs();
242562306a36Sopenharmony_ci	xfs_mru_cache_uninit();
242662306a36Sopenharmony_ci	xfs_destroy_workqueues();
242762306a36Sopenharmony_ci	xfs_destroy_caches();
242862306a36Sopenharmony_ci	xfs_uuid_table_free();
242962306a36Sopenharmony_ci}
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_cimodule_init(init_xfs_fs);
243262306a36Sopenharmony_cimodule_exit(exit_xfs_fs);
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ciMODULE_AUTHOR("Silicon Graphics, Inc.");
243562306a36Sopenharmony_ciMODULE_DESCRIPTION(XFS_VERSION_STRING " with " XFS_BUILD_OPTIONS " enabled");
243662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2437