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