11da177e4SLinus Torvalds /* 27b718769SNathan Scott * Copyright (c) 2000-2005 Silicon Graphics, Inc. 37b718769SNathan Scott * All Rights Reserved. 41da177e4SLinus Torvalds * 57b718769SNathan Scott * This program is free software; you can redistribute it and/or 67b718769SNathan Scott * modify it under the terms of the GNU General Public License as 71da177e4SLinus Torvalds * published by the Free Software Foundation. 81da177e4SLinus Torvalds * 97b718769SNathan Scott * This program is distributed in the hope that it would be useful, 107b718769SNathan Scott * but WITHOUT ANY WARRANTY; without even the implied warranty of 117b718769SNathan Scott * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 127b718769SNathan Scott * GNU General Public License for more details. 131da177e4SLinus Torvalds * 147b718769SNathan Scott * You should have received a copy of the GNU General Public License 157b718769SNathan Scott * along with this program; if not, write the Free Software Foundation, 167b718769SNathan Scott * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 171da177e4SLinus Torvalds */ 181da177e4SLinus Torvalds #include "xfs.h" 19a844f451SNathan Scott #include "xfs_fs.h" 201da177e4SLinus Torvalds #include "xfs_types.h" 21a844f451SNathan Scott #include "xfs_bit.h" 221da177e4SLinus Torvalds #include "xfs_log.h" 23a844f451SNathan Scott #include "xfs_inum.h" 241da177e4SLinus Torvalds #include "xfs_trans.h" 251da177e4SLinus Torvalds #include "xfs_sb.h" 261da177e4SLinus Torvalds #include "xfs_ag.h" 271da177e4SLinus Torvalds #include "xfs_dir2.h" 281da177e4SLinus Torvalds #include "xfs_dmapi.h" 291da177e4SLinus Torvalds #include "xfs_mount.h" 301da177e4SLinus Torvalds #include "xfs_bmap_btree.h" 31a844f451SNathan Scott #include "xfs_alloc_btree.h" 321da177e4SLinus Torvalds #include "xfs_ialloc_btree.h" 331da177e4SLinus Torvalds #include "xfs_dir2_sf.h" 34a844f451SNathan Scott #include "xfs_attr_sf.h" 351da177e4SLinus Torvalds #include "xfs_dinode.h" 361da177e4SLinus Torvalds #include "xfs_inode.h" 37a844f451SNathan Scott #include "xfs_btree.h" 38a844f451SNathan Scott #include "xfs_ialloc.h" 391da177e4SLinus Torvalds #include "xfs_alloc.h" 401da177e4SLinus Torvalds #include "xfs_rtalloc.h" 411da177e4SLinus Torvalds #include "xfs_bmap.h" 421da177e4SLinus Torvalds #include "xfs_error.h" 431da177e4SLinus Torvalds #include "xfs_rw.h" 441da177e4SLinus Torvalds #include "xfs_quota.h" 451da177e4SLinus Torvalds #include "xfs_fsops.h" 4643355099SChristoph Hellwig #include "xfs_utils.h" 471da177e4SLinus Torvalds 48e5720eecSDavid Chinner STATIC int xfs_mount_log_sb(xfs_mount_t *, __int64_t); 491da177e4SLinus Torvalds STATIC int xfs_uuid_mount(xfs_mount_t *); 50ba0f32d4SChristoph Hellwig STATIC void xfs_unmountfs_wait(xfs_mount_t *); 511da177e4SLinus Torvalds 528d280b98SDavid Chinner 538d280b98SDavid Chinner #ifdef HAVE_PERCPU_SB 5420f4ebf2SDavid Chinner STATIC void xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t, 5545af6c6dSChristoph Hellwig int); 5645af6c6dSChristoph Hellwig STATIC void xfs_icsb_balance_counter_locked(xfs_mount_t *, xfs_sb_field_t, 5745af6c6dSChristoph Hellwig int); 588d280b98SDavid Chinner STATIC int xfs_icsb_modify_counters(xfs_mount_t *, xfs_sb_field_t, 5920f4ebf2SDavid Chinner int64_t, int); 6036fbe6e6SDavid Chinner STATIC void xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t); 618d280b98SDavid Chinner 628d280b98SDavid Chinner #else 638d280b98SDavid Chinner 6445af6c6dSChristoph Hellwig #define xfs_icsb_balance_counter(mp, a, b) do { } while (0) 6545af6c6dSChristoph Hellwig #define xfs_icsb_balance_counter_locked(mp, a, b) do { } while (0) 668d280b98SDavid Chinner #define xfs_icsb_modify_counters(mp, a, b, c) do { } while (0) 678d280b98SDavid Chinner 688d280b98SDavid Chinner #endif 698d280b98SDavid Chinner 701df84c93SChristoph Hellwig static const struct { 711da177e4SLinus Torvalds short offset; 721da177e4SLinus Torvalds short type; /* 0 = integer 731da177e4SLinus Torvalds * 1 = binary / string (no translation) 741da177e4SLinus Torvalds */ 751da177e4SLinus Torvalds } xfs_sb_info[] = { 761da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_magicnum), 0 }, 771da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_blocksize), 0 }, 781da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_dblocks), 0 }, 791da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_rblocks), 0 }, 801da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_rextents), 0 }, 811da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_uuid), 1 }, 821da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_logstart), 0 }, 831da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_rootino), 0 }, 841da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_rbmino), 0 }, 851da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_rsumino), 0 }, 861da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_rextsize), 0 }, 871da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_agblocks), 0 }, 881da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_agcount), 0 }, 891da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_rbmblocks), 0 }, 901da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_logblocks), 0 }, 911da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_versionnum), 0 }, 921da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_sectsize), 0 }, 931da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_inodesize), 0 }, 941da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_inopblock), 0 }, 951da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_fname[0]), 1 }, 961da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_blocklog), 0 }, 971da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_sectlog), 0 }, 981da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_inodelog), 0 }, 991da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_inopblog), 0 }, 1001da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_agblklog), 0 }, 1011da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_rextslog), 0 }, 1021da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_inprogress), 0 }, 1031da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_imax_pct), 0 }, 1041da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_icount), 0 }, 1051da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_ifree), 0 }, 1061da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_fdblocks), 0 }, 1071da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_frextents), 0 }, 1081da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_uquotino), 0 }, 1091da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_gquotino), 0 }, 1101da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_qflags), 0 }, 1111da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_flags), 0 }, 1121da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_shared_vn), 0 }, 1131da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_inoalignmt), 0 }, 1141da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_unit), 0 }, 1151da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_width), 0 }, 1161da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_dirblklog), 0 }, 1171da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_logsectlog), 0 }, 1181da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_logsectsize),0 }, 1191da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_logsunit), 0 }, 1201da177e4SLinus Torvalds { offsetof(xfs_sb_t, sb_features2), 0 }, 121ee1c0908SDavid Chinner { offsetof(xfs_sb_t, sb_bad_features2), 0 }, 1221da177e4SLinus Torvalds { sizeof(xfs_sb_t), 0 } 1231da177e4SLinus Torvalds }; 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds /* 1261da177e4SLinus Torvalds * Free up the resources associated with a mount structure. Assume that 1271da177e4SLinus Torvalds * the structure was initially zeroed, so we can tell which fields got 1281da177e4SLinus Torvalds * initialized. 1291da177e4SLinus Torvalds */ 130c962fb79SChristoph Hellwig STATIC void 1311da177e4SLinus Torvalds xfs_mount_free( 132745f6919SChristoph Hellwig xfs_mount_t *mp) 1331da177e4SLinus Torvalds { 1341da177e4SLinus Torvalds if (mp->m_perag) { 1351da177e4SLinus Torvalds int agno; 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds for (agno = 0; agno < mp->m_maxagi; agno++) 1381da177e4SLinus Torvalds if (mp->m_perag[agno].pagb_list) 139f0e2d93cSDenys Vlasenko kmem_free(mp->m_perag[agno].pagb_list); 140f0e2d93cSDenys Vlasenko kmem_free(mp->m_perag); 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds 143287f3dadSDonald Douwsma spinlock_destroy(&mp->m_ail_lock); 1441da177e4SLinus Torvalds spinlock_destroy(&mp->m_sb_lock); 1451da177e4SLinus Torvalds mutex_destroy(&mp->m_ilock); 146cc92e7acSChristoph Hellwig mutex_destroy(&mp->m_growlock); 1471da177e4SLinus Torvalds if (mp->m_quotainfo) 1481da177e4SLinus Torvalds XFS_QM_DONE(mp); 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 1514cc929eeSNathan Scott /* 1524cc929eeSNathan Scott * Check size of device based on the (data/realtime) block count. 1534cc929eeSNathan Scott * Note: this check is used by the growfs code as well as mount. 1544cc929eeSNathan Scott */ 1554cc929eeSNathan Scott int 1564cc929eeSNathan Scott xfs_sb_validate_fsb_count( 1574cc929eeSNathan Scott xfs_sb_t *sbp, 1584cc929eeSNathan Scott __uint64_t nblocks) 1594cc929eeSNathan Scott { 1604cc929eeSNathan Scott ASSERT(PAGE_SHIFT >= sbp->sb_blocklog); 1614cc929eeSNathan Scott ASSERT(sbp->sb_blocklog >= BBSHIFT); 1624cc929eeSNathan Scott 1634cc929eeSNathan Scott #if XFS_BIG_BLKNOS /* Limited by ULONG_MAX of page cache index */ 1644cc929eeSNathan Scott if (nblocks >> (PAGE_CACHE_SHIFT - sbp->sb_blocklog) > ULONG_MAX) 1654cc929eeSNathan Scott return E2BIG; 1664cc929eeSNathan Scott #else /* Limited by UINT_MAX of sectors */ 1674cc929eeSNathan Scott if (nblocks << (sbp->sb_blocklog - BBSHIFT) > UINT_MAX) 1684cc929eeSNathan Scott return E2BIG; 1694cc929eeSNathan Scott #endif 1704cc929eeSNathan Scott return 0; 1714cc929eeSNathan Scott } 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds /* 1741da177e4SLinus Torvalds * Check the validity of the SB found. 1751da177e4SLinus Torvalds */ 1761da177e4SLinus Torvalds STATIC int 1771da177e4SLinus Torvalds xfs_mount_validate_sb( 1781da177e4SLinus Torvalds xfs_mount_t *mp, 179764d1f89SNathan Scott xfs_sb_t *sbp, 180764d1f89SNathan Scott int flags) 1811da177e4SLinus Torvalds { 1821da177e4SLinus Torvalds /* 1831da177e4SLinus Torvalds * If the log device and data device have the 1841da177e4SLinus Torvalds * same device number, the log is internal. 1851da177e4SLinus Torvalds * Consequently, the sb_logstart should be non-zero. If 1861da177e4SLinus Torvalds * we have a zero sb_logstart in this case, we may be trying to mount 1871da177e4SLinus Torvalds * a volume filesystem in a non-volume manner. 1881da177e4SLinus Torvalds */ 1891da177e4SLinus Torvalds if (sbp->sb_magicnum != XFS_SB_MAGIC) { 190764d1f89SNathan Scott xfs_fs_mount_cmn_err(flags, "bad magic number"); 1911da177e4SLinus Torvalds return XFS_ERROR(EWRONGFS); 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds 19462118709SEric Sandeen if (!xfs_sb_good_version(sbp)) { 195764d1f89SNathan Scott xfs_fs_mount_cmn_err(flags, "bad version"); 1961da177e4SLinus Torvalds return XFS_ERROR(EWRONGFS); 1971da177e4SLinus Torvalds } 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds if (unlikely( 2001da177e4SLinus Torvalds sbp->sb_logstart == 0 && mp->m_logdev_targp == mp->m_ddev_targp)) { 201764d1f89SNathan Scott xfs_fs_mount_cmn_err(flags, 202764d1f89SNathan Scott "filesystem is marked as having an external log; " 2031da177e4SLinus Torvalds "specify logdev on the\nmount command line."); 204764d1f89SNathan Scott return XFS_ERROR(EINVAL); 2051da177e4SLinus Torvalds } 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds if (unlikely( 2081da177e4SLinus Torvalds sbp->sb_logstart != 0 && mp->m_logdev_targp != mp->m_ddev_targp)) { 209764d1f89SNathan Scott xfs_fs_mount_cmn_err(flags, 210764d1f89SNathan Scott "filesystem is marked as having an internal log; " 211764d1f89SNathan Scott "do not specify logdev on\nthe mount command line."); 212764d1f89SNathan Scott return XFS_ERROR(EINVAL); 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds /* 2161da177e4SLinus Torvalds * More sanity checking. These were stolen directly from 2171da177e4SLinus Torvalds * xfs_repair. 2181da177e4SLinus Torvalds */ 2191da177e4SLinus Torvalds if (unlikely( 2201da177e4SLinus Torvalds sbp->sb_agcount <= 0 || 2211da177e4SLinus Torvalds sbp->sb_sectsize < XFS_MIN_SECTORSIZE || 2221da177e4SLinus Torvalds sbp->sb_sectsize > XFS_MAX_SECTORSIZE || 2231da177e4SLinus Torvalds sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG || 2241da177e4SLinus Torvalds sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG || 2251da177e4SLinus Torvalds sbp->sb_blocksize < XFS_MIN_BLOCKSIZE || 2261da177e4SLinus Torvalds sbp->sb_blocksize > XFS_MAX_BLOCKSIZE || 2271da177e4SLinus Torvalds sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || 2281da177e4SLinus Torvalds sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || 2291da177e4SLinus Torvalds sbp->sb_inodesize < XFS_DINODE_MIN_SIZE || 2301da177e4SLinus Torvalds sbp->sb_inodesize > XFS_DINODE_MAX_SIZE || 2319f989c94SNathan Scott sbp->sb_inodelog < XFS_DINODE_MIN_LOG || 2329f989c94SNathan Scott sbp->sb_inodelog > XFS_DINODE_MAX_LOG || 2339f989c94SNathan Scott (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) || 2341da177e4SLinus Torvalds (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || 2351da177e4SLinus Torvalds (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) || 236e50bd16fSNathan Scott (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */))) { 237764d1f89SNathan Scott xfs_fs_mount_cmn_err(flags, "SB sanity check 1 failed"); 2381da177e4SLinus Torvalds return XFS_ERROR(EFSCORRUPTED); 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds /* 2421da177e4SLinus Torvalds * Sanity check AG count, size fields against data size field 2431da177e4SLinus Torvalds */ 2441da177e4SLinus Torvalds if (unlikely( 2451da177e4SLinus Torvalds sbp->sb_dblocks == 0 || 2461da177e4SLinus Torvalds sbp->sb_dblocks > 2471da177e4SLinus Torvalds (xfs_drfsbno_t)sbp->sb_agcount * sbp->sb_agblocks || 2481da177e4SLinus Torvalds sbp->sb_dblocks < (xfs_drfsbno_t)(sbp->sb_agcount - 1) * 2491da177e4SLinus Torvalds sbp->sb_agblocks + XFS_MIN_AG_BLOCKS)) { 250764d1f89SNathan Scott xfs_fs_mount_cmn_err(flags, "SB sanity check 2 failed"); 2511da177e4SLinus Torvalds return XFS_ERROR(EFSCORRUPTED); 2521da177e4SLinus Torvalds } 2531da177e4SLinus Torvalds 2542edbddd5SLachlan McIlroy /* 2552edbddd5SLachlan McIlroy * Until this is fixed only page-sized or smaller data blocks work. 2562edbddd5SLachlan McIlroy */ 2572edbddd5SLachlan McIlroy if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) { 2582edbddd5SLachlan McIlroy xfs_fs_mount_cmn_err(flags, 2592edbddd5SLachlan McIlroy "file system with blocksize %d bytes", 2602edbddd5SLachlan McIlroy sbp->sb_blocksize); 2612edbddd5SLachlan McIlroy xfs_fs_mount_cmn_err(flags, 2622edbddd5SLachlan McIlroy "only pagesize (%ld) or less will currently work.", 2632edbddd5SLachlan McIlroy PAGE_SIZE); 2642edbddd5SLachlan McIlroy return XFS_ERROR(ENOSYS); 2652edbddd5SLachlan McIlroy } 2662edbddd5SLachlan McIlroy 2674cc929eeSNathan Scott if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) || 2684cc929eeSNathan Scott xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) { 269764d1f89SNathan Scott xfs_fs_mount_cmn_err(flags, 270764d1f89SNathan Scott "file system too large to be mounted on this system."); 2711da177e4SLinus Torvalds return XFS_ERROR(E2BIG); 2721da177e4SLinus Torvalds } 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds if (unlikely(sbp->sb_inprogress)) { 275764d1f89SNathan Scott xfs_fs_mount_cmn_err(flags, "file system busy"); 2761da177e4SLinus Torvalds return XFS_ERROR(EFSCORRUPTED); 2771da177e4SLinus Torvalds } 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds /* 280de20614bSNathan Scott * Version 1 directory format has never worked on Linux. 281de20614bSNathan Scott */ 28262118709SEric Sandeen if (unlikely(!xfs_sb_version_hasdirv2(sbp))) { 283764d1f89SNathan Scott xfs_fs_mount_cmn_err(flags, 284764d1f89SNathan Scott "file system using version 1 directory format"); 285de20614bSNathan Scott return XFS_ERROR(ENOSYS); 286de20614bSNathan Scott } 287de20614bSNathan Scott 2881da177e4SLinus Torvalds return 0; 2891da177e4SLinus Torvalds } 2901da177e4SLinus Torvalds 291da353b0dSDavid Chinner STATIC void 292da353b0dSDavid Chinner xfs_initialize_perag_icache( 293da353b0dSDavid Chinner xfs_perag_t *pag) 294da353b0dSDavid Chinner { 295da353b0dSDavid Chinner if (!pag->pag_ici_init) { 296da353b0dSDavid Chinner rwlock_init(&pag->pag_ici_lock); 297da353b0dSDavid Chinner INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC); 298da353b0dSDavid Chinner pag->pag_ici_init = 1; 299da353b0dSDavid Chinner } 300da353b0dSDavid Chinner } 301da353b0dSDavid Chinner 3021da177e4SLinus Torvalds xfs_agnumber_t 303c11e2c36SNathan Scott xfs_initialize_perag( 304c11e2c36SNathan Scott xfs_mount_t *mp, 305c11e2c36SNathan Scott xfs_agnumber_t agcount) 3061da177e4SLinus Torvalds { 3071da177e4SLinus Torvalds xfs_agnumber_t index, max_metadata; 3081da177e4SLinus Torvalds xfs_perag_t *pag; 3091da177e4SLinus Torvalds xfs_agino_t agino; 3101da177e4SLinus Torvalds xfs_ino_t ino; 3111da177e4SLinus Torvalds xfs_sb_t *sbp = &mp->m_sb; 3121da177e4SLinus Torvalds xfs_ino_t max_inum = XFS_MAXINUMBER_32; 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds /* Check to see if the filesystem can overflow 32 bit inodes */ 3151da177e4SLinus Torvalds agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0); 3161da177e4SLinus Torvalds ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino); 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds /* Clear the mount flag if no inode can overflow 32 bits 3191da177e4SLinus Torvalds * on this filesystem, or if specifically requested.. 3201da177e4SLinus Torvalds */ 321bd186aa9SChristoph Hellwig if ((mp->m_flags & XFS_MOUNT_SMALL_INUMS) && ino > max_inum) { 3221da177e4SLinus Torvalds mp->m_flags |= XFS_MOUNT_32BITINODES; 3231da177e4SLinus Torvalds } else { 3241da177e4SLinus Torvalds mp->m_flags &= ~XFS_MOUNT_32BITINODES; 3251da177e4SLinus Torvalds } 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds /* If we can overflow then setup the ag headers accordingly */ 3281da177e4SLinus Torvalds if (mp->m_flags & XFS_MOUNT_32BITINODES) { 3291da177e4SLinus Torvalds /* Calculate how much should be reserved for inodes to 3301da177e4SLinus Torvalds * meet the max inode percentage. 3311da177e4SLinus Torvalds */ 3321da177e4SLinus Torvalds if (mp->m_maxicount) { 3331da177e4SLinus Torvalds __uint64_t icount; 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds icount = sbp->sb_dblocks * sbp->sb_imax_pct; 3361da177e4SLinus Torvalds do_div(icount, 100); 3371da177e4SLinus Torvalds icount += sbp->sb_agblocks - 1; 338a749ee86SEric Sandeen do_div(icount, sbp->sb_agblocks); 3391da177e4SLinus Torvalds max_metadata = icount; 3401da177e4SLinus Torvalds } else { 3411da177e4SLinus Torvalds max_metadata = agcount; 3421da177e4SLinus Torvalds } 3431da177e4SLinus Torvalds for (index = 0; index < agcount; index++) { 3441da177e4SLinus Torvalds ino = XFS_AGINO_TO_INO(mp, index, agino); 3451da177e4SLinus Torvalds if (ino > max_inum) { 3461da177e4SLinus Torvalds index++; 3471da177e4SLinus Torvalds break; 3481da177e4SLinus Torvalds } 3491da177e4SLinus Torvalds 350c41564b5SNathan Scott /* This ag is preferred for inodes */ 3511da177e4SLinus Torvalds pag = &mp->m_perag[index]; 3521da177e4SLinus Torvalds pag->pagi_inodeok = 1; 3531da177e4SLinus Torvalds if (index < max_metadata) 3541da177e4SLinus Torvalds pag->pagf_metadata = 1; 355da353b0dSDavid Chinner xfs_initialize_perag_icache(pag); 3561da177e4SLinus Torvalds } 3571da177e4SLinus Torvalds } else { 3581da177e4SLinus Torvalds /* Setup default behavior for smaller filesystems */ 3591da177e4SLinus Torvalds for (index = 0; index < agcount; index++) { 3601da177e4SLinus Torvalds pag = &mp->m_perag[index]; 3611da177e4SLinus Torvalds pag->pagi_inodeok = 1; 362da353b0dSDavid Chinner xfs_initialize_perag_icache(pag); 3631da177e4SLinus Torvalds } 3641da177e4SLinus Torvalds } 3651da177e4SLinus Torvalds return index; 3661da177e4SLinus Torvalds } 3671da177e4SLinus Torvalds 3682bdf7cd0SChristoph Hellwig void 3692bdf7cd0SChristoph Hellwig xfs_sb_from_disk( 3702bdf7cd0SChristoph Hellwig xfs_sb_t *to, 3712bdf7cd0SChristoph Hellwig xfs_dsb_t *from) 3722bdf7cd0SChristoph Hellwig { 3732bdf7cd0SChristoph Hellwig to->sb_magicnum = be32_to_cpu(from->sb_magicnum); 3742bdf7cd0SChristoph Hellwig to->sb_blocksize = be32_to_cpu(from->sb_blocksize); 3752bdf7cd0SChristoph Hellwig to->sb_dblocks = be64_to_cpu(from->sb_dblocks); 3762bdf7cd0SChristoph Hellwig to->sb_rblocks = be64_to_cpu(from->sb_rblocks); 3772bdf7cd0SChristoph Hellwig to->sb_rextents = be64_to_cpu(from->sb_rextents); 3782bdf7cd0SChristoph Hellwig memcpy(&to->sb_uuid, &from->sb_uuid, sizeof(to->sb_uuid)); 3792bdf7cd0SChristoph Hellwig to->sb_logstart = be64_to_cpu(from->sb_logstart); 3802bdf7cd0SChristoph Hellwig to->sb_rootino = be64_to_cpu(from->sb_rootino); 3812bdf7cd0SChristoph Hellwig to->sb_rbmino = be64_to_cpu(from->sb_rbmino); 3822bdf7cd0SChristoph Hellwig to->sb_rsumino = be64_to_cpu(from->sb_rsumino); 3832bdf7cd0SChristoph Hellwig to->sb_rextsize = be32_to_cpu(from->sb_rextsize); 3842bdf7cd0SChristoph Hellwig to->sb_agblocks = be32_to_cpu(from->sb_agblocks); 3852bdf7cd0SChristoph Hellwig to->sb_agcount = be32_to_cpu(from->sb_agcount); 3862bdf7cd0SChristoph Hellwig to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks); 3872bdf7cd0SChristoph Hellwig to->sb_logblocks = be32_to_cpu(from->sb_logblocks); 3882bdf7cd0SChristoph Hellwig to->sb_versionnum = be16_to_cpu(from->sb_versionnum); 3892bdf7cd0SChristoph Hellwig to->sb_sectsize = be16_to_cpu(from->sb_sectsize); 3902bdf7cd0SChristoph Hellwig to->sb_inodesize = be16_to_cpu(from->sb_inodesize); 3912bdf7cd0SChristoph Hellwig to->sb_inopblock = be16_to_cpu(from->sb_inopblock); 3922bdf7cd0SChristoph Hellwig memcpy(&to->sb_fname, &from->sb_fname, sizeof(to->sb_fname)); 3932bdf7cd0SChristoph Hellwig to->sb_blocklog = from->sb_blocklog; 3942bdf7cd0SChristoph Hellwig to->sb_sectlog = from->sb_sectlog; 3952bdf7cd0SChristoph Hellwig to->sb_inodelog = from->sb_inodelog; 3962bdf7cd0SChristoph Hellwig to->sb_inopblog = from->sb_inopblog; 3972bdf7cd0SChristoph Hellwig to->sb_agblklog = from->sb_agblklog; 3982bdf7cd0SChristoph Hellwig to->sb_rextslog = from->sb_rextslog; 3992bdf7cd0SChristoph Hellwig to->sb_inprogress = from->sb_inprogress; 4002bdf7cd0SChristoph Hellwig to->sb_imax_pct = from->sb_imax_pct; 4012bdf7cd0SChristoph Hellwig to->sb_icount = be64_to_cpu(from->sb_icount); 4022bdf7cd0SChristoph Hellwig to->sb_ifree = be64_to_cpu(from->sb_ifree); 4032bdf7cd0SChristoph Hellwig to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks); 4042bdf7cd0SChristoph Hellwig to->sb_frextents = be64_to_cpu(from->sb_frextents); 4052bdf7cd0SChristoph Hellwig to->sb_uquotino = be64_to_cpu(from->sb_uquotino); 4062bdf7cd0SChristoph Hellwig to->sb_gquotino = be64_to_cpu(from->sb_gquotino); 4072bdf7cd0SChristoph Hellwig to->sb_qflags = be16_to_cpu(from->sb_qflags); 4082bdf7cd0SChristoph Hellwig to->sb_flags = from->sb_flags; 4092bdf7cd0SChristoph Hellwig to->sb_shared_vn = from->sb_shared_vn; 4102bdf7cd0SChristoph Hellwig to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt); 4112bdf7cd0SChristoph Hellwig to->sb_unit = be32_to_cpu(from->sb_unit); 4122bdf7cd0SChristoph Hellwig to->sb_width = be32_to_cpu(from->sb_width); 4132bdf7cd0SChristoph Hellwig to->sb_dirblklog = from->sb_dirblklog; 4142bdf7cd0SChristoph Hellwig to->sb_logsectlog = from->sb_logsectlog; 4152bdf7cd0SChristoph Hellwig to->sb_logsectsize = be16_to_cpu(from->sb_logsectsize); 4162bdf7cd0SChristoph Hellwig to->sb_logsunit = be32_to_cpu(from->sb_logsunit); 4172bdf7cd0SChristoph Hellwig to->sb_features2 = be32_to_cpu(from->sb_features2); 418ee1c0908SDavid Chinner to->sb_bad_features2 = be32_to_cpu(from->sb_bad_features2); 4192bdf7cd0SChristoph Hellwig } 4202bdf7cd0SChristoph Hellwig 4211da177e4SLinus Torvalds /* 4222bdf7cd0SChristoph Hellwig * Copy in core superblock to ondisk one. 4231da177e4SLinus Torvalds * 4242bdf7cd0SChristoph Hellwig * The fields argument is mask of superblock fields to copy. 4251da177e4SLinus Torvalds */ 4261da177e4SLinus Torvalds void 4272bdf7cd0SChristoph Hellwig xfs_sb_to_disk( 4282bdf7cd0SChristoph Hellwig xfs_dsb_t *to, 4292bdf7cd0SChristoph Hellwig xfs_sb_t *from, 4301da177e4SLinus Torvalds __int64_t fields) 4311da177e4SLinus Torvalds { 4322bdf7cd0SChristoph Hellwig xfs_caddr_t to_ptr = (xfs_caddr_t)to; 4332bdf7cd0SChristoph Hellwig xfs_caddr_t from_ptr = (xfs_caddr_t)from; 4341da177e4SLinus Torvalds xfs_sb_field_t f; 4351da177e4SLinus Torvalds int first; 4361da177e4SLinus Torvalds int size; 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds ASSERT(fields); 4391da177e4SLinus Torvalds if (!fields) 4401da177e4SLinus Torvalds return; 4411da177e4SLinus Torvalds 4421da177e4SLinus Torvalds while (fields) { 4431da177e4SLinus Torvalds f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields); 4441da177e4SLinus Torvalds first = xfs_sb_info[f].offset; 4451da177e4SLinus Torvalds size = xfs_sb_info[f + 1].offset - first; 4461da177e4SLinus Torvalds 4471da177e4SLinus Torvalds ASSERT(xfs_sb_info[f].type == 0 || xfs_sb_info[f].type == 1); 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds if (size == 1 || xfs_sb_info[f].type == 1) { 4502bdf7cd0SChristoph Hellwig memcpy(to_ptr + first, from_ptr + first, size); 4511da177e4SLinus Torvalds } else { 4521da177e4SLinus Torvalds switch (size) { 4531da177e4SLinus Torvalds case 2: 4542bdf7cd0SChristoph Hellwig *(__be16 *)(to_ptr + first) = 4552bdf7cd0SChristoph Hellwig cpu_to_be16(*(__u16 *)(from_ptr + first)); 4561da177e4SLinus Torvalds break; 4571da177e4SLinus Torvalds case 4: 4582bdf7cd0SChristoph Hellwig *(__be32 *)(to_ptr + first) = 4592bdf7cd0SChristoph Hellwig cpu_to_be32(*(__u32 *)(from_ptr + first)); 4601da177e4SLinus Torvalds break; 4611da177e4SLinus Torvalds case 8: 4622bdf7cd0SChristoph Hellwig *(__be64 *)(to_ptr + first) = 4632bdf7cd0SChristoph Hellwig cpu_to_be64(*(__u64 *)(from_ptr + first)); 4641da177e4SLinus Torvalds break; 4651da177e4SLinus Torvalds default: 4661da177e4SLinus Torvalds ASSERT(0); 4671da177e4SLinus Torvalds } 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds fields &= ~(1LL << f); 4711da177e4SLinus Torvalds } 4721da177e4SLinus Torvalds } 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds /* 4751da177e4SLinus Torvalds * xfs_readsb 4761da177e4SLinus Torvalds * 4771da177e4SLinus Torvalds * Does the initial read of the superblock. 4781da177e4SLinus Torvalds */ 4791da177e4SLinus Torvalds int 480764d1f89SNathan Scott xfs_readsb(xfs_mount_t *mp, int flags) 4811da177e4SLinus Torvalds { 4821da177e4SLinus Torvalds unsigned int sector_size; 4831da177e4SLinus Torvalds unsigned int extra_flags; 4841da177e4SLinus Torvalds xfs_buf_t *bp; 4851da177e4SLinus Torvalds int error; 4861da177e4SLinus Torvalds 4871da177e4SLinus Torvalds ASSERT(mp->m_sb_bp == NULL); 4881da177e4SLinus Torvalds ASSERT(mp->m_ddev_targp != NULL); 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds /* 4911da177e4SLinus Torvalds * Allocate a (locked) buffer to hold the superblock. 4921da177e4SLinus Torvalds * This will be kept around at all times to optimize 4931da177e4SLinus Torvalds * access to the superblock. 4941da177e4SLinus Torvalds */ 4951da177e4SLinus Torvalds sector_size = xfs_getsize_buftarg(mp->m_ddev_targp); 4961da177e4SLinus Torvalds extra_flags = XFS_BUF_LOCK | XFS_BUF_MANAGE | XFS_BUF_MAPPED; 4971da177e4SLinus Torvalds 4981da177e4SLinus Torvalds bp = xfs_buf_read_flags(mp->m_ddev_targp, XFS_SB_DADDR, 4991da177e4SLinus Torvalds BTOBB(sector_size), extra_flags); 5001da177e4SLinus Torvalds if (!bp || XFS_BUF_ISERROR(bp)) { 501764d1f89SNathan Scott xfs_fs_mount_cmn_err(flags, "SB read failed"); 5021da177e4SLinus Torvalds error = bp ? XFS_BUF_GETERROR(bp) : ENOMEM; 5031da177e4SLinus Torvalds goto fail; 5041da177e4SLinus Torvalds } 5051da177e4SLinus Torvalds ASSERT(XFS_BUF_ISBUSY(bp)); 5061da177e4SLinus Torvalds ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds /* 5091da177e4SLinus Torvalds * Initialize the mount structure from the superblock. 5101da177e4SLinus Torvalds * But first do some basic consistency checking. 5111da177e4SLinus Torvalds */ 5122bdf7cd0SChristoph Hellwig xfs_sb_from_disk(&mp->m_sb, XFS_BUF_TO_SBP(bp)); 5131da177e4SLinus Torvalds 514764d1f89SNathan Scott error = xfs_mount_validate_sb(mp, &(mp->m_sb), flags); 5151da177e4SLinus Torvalds if (error) { 516764d1f89SNathan Scott xfs_fs_mount_cmn_err(flags, "SB validate failed"); 5171da177e4SLinus Torvalds goto fail; 5181da177e4SLinus Torvalds } 5191da177e4SLinus Torvalds 5201da177e4SLinus Torvalds /* 5211da177e4SLinus Torvalds * We must be able to do sector-sized and sector-aligned IO. 5221da177e4SLinus Torvalds */ 5231da177e4SLinus Torvalds if (sector_size > mp->m_sb.sb_sectsize) { 524764d1f89SNathan Scott xfs_fs_mount_cmn_err(flags, 525764d1f89SNathan Scott "device supports only %u byte sectors (not %u)", 5261da177e4SLinus Torvalds sector_size, mp->m_sb.sb_sectsize); 5271da177e4SLinus Torvalds error = ENOSYS; 5281da177e4SLinus Torvalds goto fail; 5291da177e4SLinus Torvalds } 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds /* 5321da177e4SLinus Torvalds * If device sector size is smaller than the superblock size, 5331da177e4SLinus Torvalds * re-read the superblock so the buffer is correctly sized. 5341da177e4SLinus Torvalds */ 5351da177e4SLinus Torvalds if (sector_size < mp->m_sb.sb_sectsize) { 5361da177e4SLinus Torvalds XFS_BUF_UNMANAGE(bp); 5371da177e4SLinus Torvalds xfs_buf_relse(bp); 5381da177e4SLinus Torvalds sector_size = mp->m_sb.sb_sectsize; 5391da177e4SLinus Torvalds bp = xfs_buf_read_flags(mp->m_ddev_targp, XFS_SB_DADDR, 5401da177e4SLinus Torvalds BTOBB(sector_size), extra_flags); 5411da177e4SLinus Torvalds if (!bp || XFS_BUF_ISERROR(bp)) { 542764d1f89SNathan Scott xfs_fs_mount_cmn_err(flags, "SB re-read failed"); 5431da177e4SLinus Torvalds error = bp ? XFS_BUF_GETERROR(bp) : ENOMEM; 5441da177e4SLinus Torvalds goto fail; 5451da177e4SLinus Torvalds } 5461da177e4SLinus Torvalds ASSERT(XFS_BUF_ISBUSY(bp)); 5471da177e4SLinus Torvalds ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); 5481da177e4SLinus Torvalds } 5491da177e4SLinus Torvalds 5505478eeadSLachlan McIlroy /* Initialize per-cpu counters */ 5515478eeadSLachlan McIlroy xfs_icsb_reinit_counters(mp); 5528d280b98SDavid Chinner 5531da177e4SLinus Torvalds mp->m_sb_bp = bp; 5541da177e4SLinus Torvalds xfs_buf_relse(bp); 5551da177e4SLinus Torvalds ASSERT(XFS_BUF_VALUSEMA(bp) > 0); 5561da177e4SLinus Torvalds return 0; 5571da177e4SLinus Torvalds 5581da177e4SLinus Torvalds fail: 5591da177e4SLinus Torvalds if (bp) { 5601da177e4SLinus Torvalds XFS_BUF_UNMANAGE(bp); 5611da177e4SLinus Torvalds xfs_buf_relse(bp); 5621da177e4SLinus Torvalds } 5631da177e4SLinus Torvalds return error; 5641da177e4SLinus Torvalds } 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds 5671da177e4SLinus Torvalds /* 5681da177e4SLinus Torvalds * xfs_mount_common 5691da177e4SLinus Torvalds * 5701da177e4SLinus Torvalds * Mount initialization code establishing various mount 5711da177e4SLinus Torvalds * fields from the superblock associated with the given 5721da177e4SLinus Torvalds * mount structure 5731da177e4SLinus Torvalds */ 574ba0f32d4SChristoph Hellwig STATIC void 5751da177e4SLinus Torvalds xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp) 5761da177e4SLinus Torvalds { 5771da177e4SLinus Torvalds int i; 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds mp->m_agfrotor = mp->m_agirotor = 0; 580007c61c6SEric Sandeen spin_lock_init(&mp->m_agirotor_lock); 5811da177e4SLinus Torvalds mp->m_maxagi = mp->m_sb.sb_agcount; 5821da177e4SLinus Torvalds mp->m_blkbit_log = sbp->sb_blocklog + XFS_NBBYLOG; 5831da177e4SLinus Torvalds mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT; 5841da177e4SLinus Torvalds mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT; 5851da177e4SLinus Torvalds mp->m_agno_log = xfs_highbit32(sbp->sb_agcount - 1) + 1; 5861da177e4SLinus Torvalds mp->m_agino_log = sbp->sb_inopblog + sbp->sb_agblklog; 5871da177e4SLinus Torvalds mp->m_litino = sbp->sb_inodesize - 5881da177e4SLinus Torvalds ((uint)sizeof(xfs_dinode_core_t) + (uint)sizeof(xfs_agino_t)); 5891da177e4SLinus Torvalds mp->m_blockmask = sbp->sb_blocksize - 1; 5901da177e4SLinus Torvalds mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG; 5911da177e4SLinus Torvalds mp->m_blockwmask = mp->m_blockwsize - 1; 5921da177e4SLinus Torvalds INIT_LIST_HEAD(&mp->m_del_inodes); 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds /* 5951da177e4SLinus Torvalds * Setup for attributes, in case they get created. 5961da177e4SLinus Torvalds * This value is for inodes getting attributes for the first time, 5971da177e4SLinus Torvalds * the per-inode value is for old attribute values. 5981da177e4SLinus Torvalds */ 5991da177e4SLinus Torvalds ASSERT(sbp->sb_inodesize >= 256 && sbp->sb_inodesize <= 2048); 6001da177e4SLinus Torvalds switch (sbp->sb_inodesize) { 6011da177e4SLinus Torvalds case 256: 602d8cc890dSNathan Scott mp->m_attroffset = XFS_LITINO(mp) - 603d8cc890dSNathan Scott XFS_BMDR_SPACE_CALC(MINABTPTRS); 6041da177e4SLinus Torvalds break; 6051da177e4SLinus Torvalds case 512: 6061da177e4SLinus Torvalds case 1024: 6071da177e4SLinus Torvalds case 2048: 608d8cc890dSNathan Scott mp->m_attroffset = XFS_BMDR_SPACE_CALC(6 * MINABTPTRS); 6091da177e4SLinus Torvalds break; 6101da177e4SLinus Torvalds default: 6111da177e4SLinus Torvalds ASSERT(0); 6121da177e4SLinus Torvalds } 6131da177e4SLinus Torvalds ASSERT(mp->m_attroffset < XFS_LITINO(mp)); 6141da177e4SLinus Torvalds 6151da177e4SLinus Torvalds for (i = 0; i < 2; i++) { 6161da177e4SLinus Torvalds mp->m_alloc_mxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, 6171da177e4SLinus Torvalds xfs_alloc, i == 0); 6181da177e4SLinus Torvalds mp->m_alloc_mnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, 6191da177e4SLinus Torvalds xfs_alloc, i == 0); 6201da177e4SLinus Torvalds } 6211da177e4SLinus Torvalds for (i = 0; i < 2; i++) { 6221da177e4SLinus Torvalds mp->m_bmap_dmxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, 6231da177e4SLinus Torvalds xfs_bmbt, i == 0); 6241da177e4SLinus Torvalds mp->m_bmap_dmnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, 6251da177e4SLinus Torvalds xfs_bmbt, i == 0); 6261da177e4SLinus Torvalds } 6271da177e4SLinus Torvalds for (i = 0; i < 2; i++) { 6281da177e4SLinus Torvalds mp->m_inobt_mxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, 6291da177e4SLinus Torvalds xfs_inobt, i == 0); 6301da177e4SLinus Torvalds mp->m_inobt_mnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, 6311da177e4SLinus Torvalds xfs_inobt, i == 0); 6321da177e4SLinus Torvalds } 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds mp->m_bsize = XFS_FSB_TO_BB(mp, 1); 6351da177e4SLinus Torvalds mp->m_ialloc_inos = (int)MAX((__uint16_t)XFS_INODES_PER_CHUNK, 6361da177e4SLinus Torvalds sbp->sb_inopblock); 6371da177e4SLinus Torvalds mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog; 6381da177e4SLinus Torvalds } 63992821e2bSDavid Chinner 64092821e2bSDavid Chinner /* 64192821e2bSDavid Chinner * xfs_initialize_perag_data 64292821e2bSDavid Chinner * 64392821e2bSDavid Chinner * Read in each per-ag structure so we can count up the number of 64492821e2bSDavid Chinner * allocated inodes, free inodes and used filesystem blocks as this 64592821e2bSDavid Chinner * information is no longer persistent in the superblock. Once we have 64692821e2bSDavid Chinner * this information, write it into the in-core superblock structure. 64792821e2bSDavid Chinner */ 64892821e2bSDavid Chinner STATIC int 64992821e2bSDavid Chinner xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount) 65092821e2bSDavid Chinner { 65192821e2bSDavid Chinner xfs_agnumber_t index; 65292821e2bSDavid Chinner xfs_perag_t *pag; 65392821e2bSDavid Chinner xfs_sb_t *sbp = &mp->m_sb; 65492821e2bSDavid Chinner uint64_t ifree = 0; 65592821e2bSDavid Chinner uint64_t ialloc = 0; 65692821e2bSDavid Chinner uint64_t bfree = 0; 65792821e2bSDavid Chinner uint64_t bfreelst = 0; 65892821e2bSDavid Chinner uint64_t btree = 0; 65992821e2bSDavid Chinner int error; 66092821e2bSDavid Chinner 66192821e2bSDavid Chinner for (index = 0; index < agcount; index++) { 66292821e2bSDavid Chinner /* 66392821e2bSDavid Chinner * read the agf, then the agi. This gets us 66492821e2bSDavid Chinner * all the inforamtion we need and populates the 66592821e2bSDavid Chinner * per-ag structures for us. 66692821e2bSDavid Chinner */ 66792821e2bSDavid Chinner error = xfs_alloc_pagf_init(mp, NULL, index, 0); 66892821e2bSDavid Chinner if (error) 66992821e2bSDavid Chinner return error; 67092821e2bSDavid Chinner 67192821e2bSDavid Chinner error = xfs_ialloc_pagi_init(mp, NULL, index); 67292821e2bSDavid Chinner if (error) 67392821e2bSDavid Chinner return error; 67492821e2bSDavid Chinner pag = &mp->m_perag[index]; 67592821e2bSDavid Chinner ifree += pag->pagi_freecount; 67692821e2bSDavid Chinner ialloc += pag->pagi_count; 67792821e2bSDavid Chinner bfree += pag->pagf_freeblks; 67892821e2bSDavid Chinner bfreelst += pag->pagf_flcount; 67992821e2bSDavid Chinner btree += pag->pagf_btreeblks; 68092821e2bSDavid Chinner } 68192821e2bSDavid Chinner /* 68292821e2bSDavid Chinner * Overwrite incore superblock counters with just-read data 68392821e2bSDavid Chinner */ 6843685c2a1SEric Sandeen spin_lock(&mp->m_sb_lock); 68592821e2bSDavid Chinner sbp->sb_ifree = ifree; 68692821e2bSDavid Chinner sbp->sb_icount = ialloc; 68792821e2bSDavid Chinner sbp->sb_fdblocks = bfree + bfreelst + btree; 6883685c2a1SEric Sandeen spin_unlock(&mp->m_sb_lock); 68992821e2bSDavid Chinner 69092821e2bSDavid Chinner /* Fixup the per-cpu counters as well. */ 69192821e2bSDavid Chinner xfs_icsb_reinit_counters(mp); 69292821e2bSDavid Chinner 69392821e2bSDavid Chinner return 0; 69492821e2bSDavid Chinner } 69592821e2bSDavid Chinner 6961da177e4SLinus Torvalds /* 6970771fb45SEric Sandeen * Update alignment values based on mount options and sb values 6981da177e4SLinus Torvalds */ 6990771fb45SEric Sandeen STATIC int 7000771fb45SEric Sandeen xfs_update_alignment(xfs_mount_t *mp, int mfsi_flags, __uint64_t *update_flags) 7011da177e4SLinus Torvalds { 7021da177e4SLinus Torvalds xfs_sb_t *sbp = &(mp->m_sb); 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds if (mp->m_dalign && !(mfsi_flags & XFS_MFSI_SECOND)) { 7051da177e4SLinus Torvalds /* 7061da177e4SLinus Torvalds * If stripe unit and stripe width are not multiples 7071da177e4SLinus Torvalds * of the fs blocksize turn off alignment. 7081da177e4SLinus Torvalds */ 7091da177e4SLinus Torvalds if ((BBTOB(mp->m_dalign) & mp->m_blockmask) || 7101da177e4SLinus Torvalds (BBTOB(mp->m_swidth) & mp->m_blockmask)) { 7111da177e4SLinus Torvalds if (mp->m_flags & XFS_MOUNT_RETERR) { 7121da177e4SLinus Torvalds cmn_err(CE_WARN, 7131da177e4SLinus Torvalds "XFS: alignment check 1 failed"); 7140771fb45SEric Sandeen return XFS_ERROR(EINVAL); 7151da177e4SLinus Torvalds } 7161da177e4SLinus Torvalds mp->m_dalign = mp->m_swidth = 0; 7171da177e4SLinus Torvalds } else { 7181da177e4SLinus Torvalds /* 7191da177e4SLinus Torvalds * Convert the stripe unit and width to FSBs. 7201da177e4SLinus Torvalds */ 7211da177e4SLinus Torvalds mp->m_dalign = XFS_BB_TO_FSBT(mp, mp->m_dalign); 7221da177e4SLinus Torvalds if (mp->m_dalign && (sbp->sb_agblocks % mp->m_dalign)) { 7231da177e4SLinus Torvalds if (mp->m_flags & XFS_MOUNT_RETERR) { 7240771fb45SEric Sandeen return XFS_ERROR(EINVAL); 7251da177e4SLinus Torvalds } 7261da177e4SLinus Torvalds xfs_fs_cmn_err(CE_WARN, mp, 7271da177e4SLinus Torvalds "stripe alignment turned off: sunit(%d)/swidth(%d) incompatible with agsize(%d)", 7281da177e4SLinus Torvalds mp->m_dalign, mp->m_swidth, 7291da177e4SLinus Torvalds sbp->sb_agblocks); 7301da177e4SLinus Torvalds 7311da177e4SLinus Torvalds mp->m_dalign = 0; 7321da177e4SLinus Torvalds mp->m_swidth = 0; 7331da177e4SLinus Torvalds } else if (mp->m_dalign) { 7341da177e4SLinus Torvalds mp->m_swidth = XFS_BB_TO_FSBT(mp, mp->m_swidth); 7351da177e4SLinus Torvalds } else { 7361da177e4SLinus Torvalds if (mp->m_flags & XFS_MOUNT_RETERR) { 7371da177e4SLinus Torvalds xfs_fs_cmn_err(CE_WARN, mp, 7381da177e4SLinus Torvalds "stripe alignment turned off: sunit(%d) less than bsize(%d)", 7391da177e4SLinus Torvalds mp->m_dalign, 7401da177e4SLinus Torvalds mp->m_blockmask +1); 7410771fb45SEric Sandeen return XFS_ERROR(EINVAL); 7421da177e4SLinus Torvalds } 7431da177e4SLinus Torvalds mp->m_swidth = 0; 7441da177e4SLinus Torvalds } 7451da177e4SLinus Torvalds } 7461da177e4SLinus Torvalds 7471da177e4SLinus Torvalds /* 7481da177e4SLinus Torvalds * Update superblock with new values 7491da177e4SLinus Torvalds * and log changes 7501da177e4SLinus Torvalds */ 75162118709SEric Sandeen if (xfs_sb_version_hasdalign(sbp)) { 7521da177e4SLinus Torvalds if (sbp->sb_unit != mp->m_dalign) { 7531da177e4SLinus Torvalds sbp->sb_unit = mp->m_dalign; 7540771fb45SEric Sandeen *update_flags |= XFS_SB_UNIT; 7551da177e4SLinus Torvalds } 7561da177e4SLinus Torvalds if (sbp->sb_width != mp->m_swidth) { 7571da177e4SLinus Torvalds sbp->sb_width = mp->m_swidth; 7580771fb45SEric Sandeen *update_flags |= XFS_SB_WIDTH; 7591da177e4SLinus Torvalds } 7601da177e4SLinus Torvalds } 7611da177e4SLinus Torvalds } else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN && 76262118709SEric Sandeen xfs_sb_version_hasdalign(&mp->m_sb)) { 7631da177e4SLinus Torvalds mp->m_dalign = sbp->sb_unit; 7641da177e4SLinus Torvalds mp->m_swidth = sbp->sb_width; 7651da177e4SLinus Torvalds } 7661da177e4SLinus Torvalds 7670771fb45SEric Sandeen return 0; 7680771fb45SEric Sandeen } 7691da177e4SLinus Torvalds 7700771fb45SEric Sandeen /* 7710771fb45SEric Sandeen * Set the maximum inode count for this filesystem 7720771fb45SEric Sandeen */ 7730771fb45SEric Sandeen STATIC void 7740771fb45SEric Sandeen xfs_set_maxicount(xfs_mount_t *mp) 7750771fb45SEric Sandeen { 7760771fb45SEric Sandeen xfs_sb_t *sbp = &(mp->m_sb); 7771da177e4SLinus Torvalds __uint64_t icount; 7781da177e4SLinus Torvalds 7790771fb45SEric Sandeen if (sbp->sb_imax_pct) { 7800771fb45SEric Sandeen /* 7810771fb45SEric Sandeen * Make sure the maximum inode count is a multiple 7820771fb45SEric Sandeen * of the units we allocate inodes in. 7831da177e4SLinus Torvalds */ 7841da177e4SLinus Torvalds icount = sbp->sb_dblocks * sbp->sb_imax_pct; 7851da177e4SLinus Torvalds do_div(icount, 100); 7861da177e4SLinus Torvalds do_div(icount, mp->m_ialloc_blks); 7871da177e4SLinus Torvalds mp->m_maxicount = (icount * mp->m_ialloc_blks) << 7881da177e4SLinus Torvalds sbp->sb_inopblog; 7890771fb45SEric Sandeen } else { 7901da177e4SLinus Torvalds mp->m_maxicount = 0; 7911da177e4SLinus Torvalds } 7921da177e4SLinus Torvalds } 7931da177e4SLinus Torvalds 7941da177e4SLinus Torvalds /* 7951da177e4SLinus Torvalds * Set the default minimum read and write sizes unless 7961da177e4SLinus Torvalds * already specified in a mount option. 7971da177e4SLinus Torvalds * We use smaller I/O sizes when the file system 7981da177e4SLinus Torvalds * is being used for NFS service (wsync mount option). 7991da177e4SLinus Torvalds */ 8000771fb45SEric Sandeen STATIC void 8010771fb45SEric Sandeen xfs_set_rw_sizes(xfs_mount_t *mp) 8020771fb45SEric Sandeen { 8030771fb45SEric Sandeen xfs_sb_t *sbp = &(mp->m_sb); 8040771fb45SEric Sandeen int readio_log, writeio_log; 8050771fb45SEric Sandeen 8061da177e4SLinus Torvalds if (!(mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)) { 8071da177e4SLinus Torvalds if (mp->m_flags & XFS_MOUNT_WSYNC) { 8081da177e4SLinus Torvalds readio_log = XFS_WSYNC_READIO_LOG; 8091da177e4SLinus Torvalds writeio_log = XFS_WSYNC_WRITEIO_LOG; 8101da177e4SLinus Torvalds } else { 8111da177e4SLinus Torvalds readio_log = XFS_READIO_LOG_LARGE; 8121da177e4SLinus Torvalds writeio_log = XFS_WRITEIO_LOG_LARGE; 8131da177e4SLinus Torvalds } 8141da177e4SLinus Torvalds } else { 8151da177e4SLinus Torvalds readio_log = mp->m_readio_log; 8161da177e4SLinus Torvalds writeio_log = mp->m_writeio_log; 8171da177e4SLinus Torvalds } 8181da177e4SLinus Torvalds 8191da177e4SLinus Torvalds if (sbp->sb_blocklog > readio_log) { 8201da177e4SLinus Torvalds mp->m_readio_log = sbp->sb_blocklog; 8211da177e4SLinus Torvalds } else { 8221da177e4SLinus Torvalds mp->m_readio_log = readio_log; 8231da177e4SLinus Torvalds } 8241da177e4SLinus Torvalds mp->m_readio_blocks = 1 << (mp->m_readio_log - sbp->sb_blocklog); 8251da177e4SLinus Torvalds if (sbp->sb_blocklog > writeio_log) { 8261da177e4SLinus Torvalds mp->m_writeio_log = sbp->sb_blocklog; 8271da177e4SLinus Torvalds } else { 8281da177e4SLinus Torvalds mp->m_writeio_log = writeio_log; 8291da177e4SLinus Torvalds } 8301da177e4SLinus Torvalds mp->m_writeio_blocks = 1 << (mp->m_writeio_log - sbp->sb_blocklog); 8310771fb45SEric Sandeen } 832425f9dddSEric Sandeen 8331da177e4SLinus Torvalds /* 8341da177e4SLinus Torvalds * Set whether we're using inode alignment. 8351da177e4SLinus Torvalds */ 8360771fb45SEric Sandeen STATIC void 8370771fb45SEric Sandeen xfs_set_inoalignment(xfs_mount_t *mp) 8380771fb45SEric Sandeen { 83962118709SEric Sandeen if (xfs_sb_version_hasalign(&mp->m_sb) && 8401da177e4SLinus Torvalds mp->m_sb.sb_inoalignmt >= 8411da177e4SLinus Torvalds XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size)) 8421da177e4SLinus Torvalds mp->m_inoalign_mask = mp->m_sb.sb_inoalignmt - 1; 8431da177e4SLinus Torvalds else 8441da177e4SLinus Torvalds mp->m_inoalign_mask = 0; 8451da177e4SLinus Torvalds /* 8461da177e4SLinus Torvalds * If we are using stripe alignment, check whether 8471da177e4SLinus Torvalds * the stripe unit is a multiple of the inode alignment 8481da177e4SLinus Torvalds */ 8491da177e4SLinus Torvalds if (mp->m_dalign && mp->m_inoalign_mask && 8501da177e4SLinus Torvalds !(mp->m_dalign & mp->m_inoalign_mask)) 8511da177e4SLinus Torvalds mp->m_sinoalign = mp->m_dalign; 8521da177e4SLinus Torvalds else 8531da177e4SLinus Torvalds mp->m_sinoalign = 0; 8540771fb45SEric Sandeen } 8550771fb45SEric Sandeen 8561da177e4SLinus Torvalds /* 8571da177e4SLinus Torvalds * Check that the data (and log if separate) are an ok size. 8581da177e4SLinus Torvalds */ 8590771fb45SEric Sandeen STATIC int 8600771fb45SEric Sandeen xfs_check_sizes(xfs_mount_t *mp, int mfsi_flags) 8610771fb45SEric Sandeen { 8620771fb45SEric Sandeen xfs_buf_t *bp; 8630771fb45SEric Sandeen xfs_daddr_t d; 8640771fb45SEric Sandeen int error; 8650771fb45SEric Sandeen 8661da177e4SLinus Torvalds d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks); 8671da177e4SLinus Torvalds if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) { 8681da177e4SLinus Torvalds cmn_err(CE_WARN, "XFS: size check 1 failed"); 8690771fb45SEric Sandeen return XFS_ERROR(E2BIG); 8701da177e4SLinus Torvalds } 8711da177e4SLinus Torvalds error = xfs_read_buf(mp, mp->m_ddev_targp, 8721da177e4SLinus Torvalds d - XFS_FSS_TO_BB(mp, 1), 8731da177e4SLinus Torvalds XFS_FSS_TO_BB(mp, 1), 0, &bp); 8741da177e4SLinus Torvalds if (!error) { 8751da177e4SLinus Torvalds xfs_buf_relse(bp); 8761da177e4SLinus Torvalds } else { 8771da177e4SLinus Torvalds cmn_err(CE_WARN, "XFS: size check 2 failed"); 8780771fb45SEric Sandeen if (error == ENOSPC) 8791da177e4SLinus Torvalds error = XFS_ERROR(E2BIG); 8800771fb45SEric Sandeen return error; 8811da177e4SLinus Torvalds } 8821da177e4SLinus Torvalds 8831da177e4SLinus Torvalds if (((mfsi_flags & XFS_MFSI_CLIENT) == 0) && 8841da177e4SLinus Torvalds mp->m_logdev_targp != mp->m_ddev_targp) { 8851da177e4SLinus Torvalds d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); 8861da177e4SLinus Torvalds if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) { 8871da177e4SLinus Torvalds cmn_err(CE_WARN, "XFS: size check 3 failed"); 8880771fb45SEric Sandeen return XFS_ERROR(E2BIG); 8891da177e4SLinus Torvalds } 8901da177e4SLinus Torvalds error = xfs_read_buf(mp, mp->m_logdev_targp, 8911da177e4SLinus Torvalds d - XFS_FSB_TO_BB(mp, 1), 8921da177e4SLinus Torvalds XFS_FSB_TO_BB(mp, 1), 0, &bp); 8931da177e4SLinus Torvalds if (!error) { 8941da177e4SLinus Torvalds xfs_buf_relse(bp); 8951da177e4SLinus Torvalds } else { 8961da177e4SLinus Torvalds cmn_err(CE_WARN, "XFS: size check 3 failed"); 8970771fb45SEric Sandeen if (error == ENOSPC) 8981da177e4SLinus Torvalds error = XFS_ERROR(E2BIG); 8990771fb45SEric Sandeen return error; 9001da177e4SLinus Torvalds } 9010771fb45SEric Sandeen } 9020771fb45SEric Sandeen return 0; 9030771fb45SEric Sandeen } 9040771fb45SEric Sandeen 9050771fb45SEric Sandeen /* 9060771fb45SEric Sandeen * xfs_mountfs 9070771fb45SEric Sandeen * 9080771fb45SEric Sandeen * This function does the following on an initial mount of a file system: 9090771fb45SEric Sandeen * - reads the superblock from disk and init the mount struct 9100771fb45SEric Sandeen * - if we're a 32-bit kernel, do a size check on the superblock 9110771fb45SEric Sandeen * so we don't mount terabyte filesystems 9120771fb45SEric Sandeen * - init mount struct realtime fields 9130771fb45SEric Sandeen * - allocate inode hash table for fs 9140771fb45SEric Sandeen * - init directory manager 9150771fb45SEric Sandeen * - perform recovery and init the log manager 9160771fb45SEric Sandeen */ 9170771fb45SEric Sandeen int 9180771fb45SEric Sandeen xfs_mountfs( 9190771fb45SEric Sandeen xfs_mount_t *mp, 9200771fb45SEric Sandeen int mfsi_flags) 9210771fb45SEric Sandeen { 9220771fb45SEric Sandeen xfs_sb_t *sbp = &(mp->m_sb); 9230771fb45SEric Sandeen xfs_inode_t *rip; 9240771fb45SEric Sandeen __uint64_t resblks; 9250771fb45SEric Sandeen __int64_t update_flags = 0LL; 9260771fb45SEric Sandeen uint quotamount, quotaflags; 9270771fb45SEric Sandeen int agno; 9280771fb45SEric Sandeen int uuid_mounted = 0; 9290771fb45SEric Sandeen int error = 0; 9300771fb45SEric Sandeen 9310771fb45SEric Sandeen xfs_mount_common(mp, sbp); 9320771fb45SEric Sandeen 9330771fb45SEric Sandeen /* 934e6957ea4SEric Sandeen * Check for a mismatched features2 values. Older kernels 935e6957ea4SEric Sandeen * read & wrote into the wrong sb offset for sb_features2 936e6957ea4SEric Sandeen * on some platforms due to xfs_sb_t not being 64bit size aligned 937e6957ea4SEric Sandeen * when sb_features2 was added, which made older superblock 938e6957ea4SEric Sandeen * reading/writing routines swap it as a 64-bit value. 939ee1c0908SDavid Chinner * 940e6957ea4SEric Sandeen * For backwards compatibility, we make both slots equal. 941e6957ea4SEric Sandeen * 942e6957ea4SEric Sandeen * If we detect a mismatched field, we OR the set bits into the 943e6957ea4SEric Sandeen * existing features2 field in case it has already been modified; we 944e6957ea4SEric Sandeen * don't want to lose any features. We then update the bad location 945e6957ea4SEric Sandeen * with the ORed value so that older kernels will see any features2 946e6957ea4SEric Sandeen * flags, and mark the two fields as needing updates once the 947e6957ea4SEric Sandeen * transaction subsystem is online. 948ee1c0908SDavid Chinner */ 949e6957ea4SEric Sandeen if (xfs_sb_has_mismatched_features2(sbp)) { 950ee1c0908SDavid Chinner cmn_err(CE_WARN, 951ee1c0908SDavid Chinner "XFS: correcting sb_features alignment problem"); 952ee1c0908SDavid Chinner sbp->sb_features2 |= sbp->sb_bad_features2; 953e6957ea4SEric Sandeen sbp->sb_bad_features2 = sbp->sb_features2; 954ee1c0908SDavid Chinner update_flags |= XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2; 955e6957ea4SEric Sandeen 956e6957ea4SEric Sandeen /* 957e6957ea4SEric Sandeen * Re-check for ATTR2 in case it was found in bad_features2 958e6957ea4SEric Sandeen * slot. 959e6957ea4SEric Sandeen */ 9607c12f296STim Shimmin if (xfs_sb_version_hasattr2(&mp->m_sb) && 9617c12f296STim Shimmin !(mp->m_flags & XFS_MOUNT_NOATTR2)) 962e6957ea4SEric Sandeen mp->m_flags |= XFS_MOUNT_ATTR2; 9637c12f296STim Shimmin } 964e6957ea4SEric Sandeen 9657c12f296STim Shimmin if (xfs_sb_version_hasattr2(&mp->m_sb) && 9667c12f296STim Shimmin (mp->m_flags & XFS_MOUNT_NOATTR2)) { 9677c12f296STim Shimmin xfs_sb_version_removeattr2(&mp->m_sb); 9687c12f296STim Shimmin update_flags |= XFS_SB_FEATURES2; 9697c12f296STim Shimmin 9707c12f296STim Shimmin /* update sb_versionnum for the clearing of the morebits */ 9717c12f296STim Shimmin if (!sbp->sb_features2) 9727c12f296STim Shimmin update_flags |= XFS_SB_VERSIONNUM; 973ee1c0908SDavid Chinner } 974ee1c0908SDavid Chinner 975ee1c0908SDavid Chinner /* 9760771fb45SEric Sandeen * Check if sb_agblocks is aligned at stripe boundary 9770771fb45SEric Sandeen * If sb_agblocks is NOT aligned turn off m_dalign since 9780771fb45SEric Sandeen * allocator alignment is within an ag, therefore ag has 9790771fb45SEric Sandeen * to be aligned at stripe boundary. 9800771fb45SEric Sandeen */ 9810771fb45SEric Sandeen error = xfs_update_alignment(mp, mfsi_flags, &update_flags); 9820771fb45SEric Sandeen if (error) 9830771fb45SEric Sandeen goto error1; 9840771fb45SEric Sandeen 9850771fb45SEric Sandeen xfs_alloc_compute_maxlevels(mp); 9860771fb45SEric Sandeen xfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK); 9870771fb45SEric Sandeen xfs_bmap_compute_maxlevels(mp, XFS_ATTR_FORK); 9880771fb45SEric Sandeen xfs_ialloc_compute_maxlevels(mp); 9890771fb45SEric Sandeen 9900771fb45SEric Sandeen xfs_set_maxicount(mp); 9910771fb45SEric Sandeen 9920771fb45SEric Sandeen mp->m_maxioffset = xfs_max_file_offset(sbp->sb_blocklog); 9930771fb45SEric Sandeen 9940771fb45SEric Sandeen /* 9950771fb45SEric Sandeen * XFS uses the uuid from the superblock as the unique 9960771fb45SEric Sandeen * identifier for fsid. We can not use the uuid from the volume 9970771fb45SEric Sandeen * since a single partition filesystem is identical to a single 9980771fb45SEric Sandeen * partition volume/filesystem. 9990771fb45SEric Sandeen */ 10000771fb45SEric Sandeen if ((mfsi_flags & XFS_MFSI_SECOND) == 0 && 10010771fb45SEric Sandeen (mp->m_flags & XFS_MOUNT_NOUUID) == 0) { 10020771fb45SEric Sandeen if (xfs_uuid_mount(mp)) { 10030771fb45SEric Sandeen error = XFS_ERROR(EINVAL); 10041da177e4SLinus Torvalds goto error1; 10051da177e4SLinus Torvalds } 10060771fb45SEric Sandeen uuid_mounted=1; 10071da177e4SLinus Torvalds } 10081da177e4SLinus Torvalds 10091da177e4SLinus Torvalds /* 10100771fb45SEric Sandeen * Set the minimum read and write sizes 10110771fb45SEric Sandeen */ 10120771fb45SEric Sandeen xfs_set_rw_sizes(mp); 10130771fb45SEric Sandeen 10140771fb45SEric Sandeen /* 10150771fb45SEric Sandeen * Set the inode cluster size. 10160771fb45SEric Sandeen * This may still be overridden by the file system 10170771fb45SEric Sandeen * block size if it is larger than the chosen cluster size. 10180771fb45SEric Sandeen */ 10190771fb45SEric Sandeen mp->m_inode_cluster_size = XFS_INODE_BIG_CLUSTER_SIZE; 10200771fb45SEric Sandeen 10210771fb45SEric Sandeen /* 10220771fb45SEric Sandeen * Set inode alignment fields 10230771fb45SEric Sandeen */ 10240771fb45SEric Sandeen xfs_set_inoalignment(mp); 10250771fb45SEric Sandeen 10260771fb45SEric Sandeen /* 10270771fb45SEric Sandeen * Check that the data (and log if separate) are an ok size. 10280771fb45SEric Sandeen */ 10290771fb45SEric Sandeen error = xfs_check_sizes(mp, mfsi_flags); 10300771fb45SEric Sandeen if (error) 10310771fb45SEric Sandeen goto error1; 10320771fb45SEric Sandeen 10330771fb45SEric Sandeen /* 10341da177e4SLinus Torvalds * Initialize realtime fields in the mount structure 10351da177e4SLinus Torvalds */ 10360771fb45SEric Sandeen error = xfs_rtmount_init(mp); 10370771fb45SEric Sandeen if (error) { 10381da177e4SLinus Torvalds cmn_err(CE_WARN, "XFS: RT mount failed"); 10391da177e4SLinus Torvalds goto error1; 10401da177e4SLinus Torvalds } 10411da177e4SLinus Torvalds 10421da177e4SLinus Torvalds /* 10431da177e4SLinus Torvalds * For client case we are done now 10441da177e4SLinus Torvalds */ 10451da177e4SLinus Torvalds if (mfsi_flags & XFS_MFSI_CLIENT) { 1046014c2544SJesper Juhl return 0; 10471da177e4SLinus Torvalds } 10481da177e4SLinus Torvalds 10491da177e4SLinus Torvalds /* 10501da177e4SLinus Torvalds * Copies the low order bits of the timestamp and the randomly 10511da177e4SLinus Torvalds * set "sequence" number out of a UUID. 10521da177e4SLinus Torvalds */ 10531da177e4SLinus Torvalds uuid_getnodeuniq(&sbp->sb_uuid, mp->m_fixedfsid); 10541da177e4SLinus Torvalds 10551da177e4SLinus Torvalds mp->m_dmevmask = 0; /* not persistent; set after each mount */ 10561da177e4SLinus Torvalds 1057f6c2d1faSNathan Scott xfs_dir_mount(mp); 10581da177e4SLinus Torvalds 10591da177e4SLinus Torvalds /* 10601da177e4SLinus Torvalds * Initialize the attribute manager's entries. 10611da177e4SLinus Torvalds */ 10621da177e4SLinus Torvalds mp->m_attr_magicpct = (mp->m_sb.sb_blocksize * 37) / 100; 10631da177e4SLinus Torvalds 10641da177e4SLinus Torvalds /* 10651da177e4SLinus Torvalds * Initialize the precomputed transaction reservations values. 10661da177e4SLinus Torvalds */ 10671da177e4SLinus Torvalds xfs_trans_init(mp); 10681da177e4SLinus Torvalds 10691da177e4SLinus Torvalds /* 10701da177e4SLinus Torvalds * Allocate and initialize the per-ag data. 10711da177e4SLinus Torvalds */ 10721da177e4SLinus Torvalds init_rwsem(&mp->m_peraglock); 10731da177e4SLinus Torvalds mp->m_perag = 10741da177e4SLinus Torvalds kmem_zalloc(sbp->sb_agcount * sizeof(xfs_perag_t), KM_SLEEP); 10751da177e4SLinus Torvalds 1076b267ce99SChristoph Hellwig mp->m_maxagi = xfs_initialize_perag(mp, sbp->sb_agcount); 10771da177e4SLinus Torvalds 10781da177e4SLinus Torvalds /* 10791da177e4SLinus Torvalds * log's mount-time initialization. Perform 1st part recovery if needed 10801da177e4SLinus Torvalds */ 10811da177e4SLinus Torvalds if (likely(sbp->sb_logblocks > 0)) { /* check for volume case */ 10821da177e4SLinus Torvalds error = xfs_log_mount(mp, mp->m_logdev_targp, 10831da177e4SLinus Torvalds XFS_FSB_TO_DADDR(mp, sbp->sb_logstart), 10841da177e4SLinus Torvalds XFS_FSB_TO_BB(mp, sbp->sb_logblocks)); 10851da177e4SLinus Torvalds if (error) { 10861da177e4SLinus Torvalds cmn_err(CE_WARN, "XFS: log mount failed"); 10871da177e4SLinus Torvalds goto error2; 10881da177e4SLinus Torvalds } 10891da177e4SLinus Torvalds } else { /* No log has been defined */ 10901da177e4SLinus Torvalds cmn_err(CE_WARN, "XFS: no log defined"); 10911da177e4SLinus Torvalds XFS_ERROR_REPORT("xfs_mountfs_int(1)", XFS_ERRLEVEL_LOW, mp); 10921da177e4SLinus Torvalds error = XFS_ERROR(EFSCORRUPTED); 10931da177e4SLinus Torvalds goto error2; 10941da177e4SLinus Torvalds } 10951da177e4SLinus Torvalds 10961da177e4SLinus Torvalds /* 109792821e2bSDavid Chinner * Now the log is mounted, we know if it was an unclean shutdown or 109892821e2bSDavid Chinner * not. If it was, with the first phase of recovery has completed, we 109992821e2bSDavid Chinner * have consistent AG blocks on disk. We have not recovered EFIs yet, 110092821e2bSDavid Chinner * but they are recovered transactionally in the second recovery phase 110192821e2bSDavid Chinner * later. 110292821e2bSDavid Chinner * 110392821e2bSDavid Chinner * Hence we can safely re-initialise incore superblock counters from 110492821e2bSDavid Chinner * the per-ag data. These may not be correct if the filesystem was not 110592821e2bSDavid Chinner * cleanly unmounted, so we need to wait for recovery to finish before 110692821e2bSDavid Chinner * doing this. 110792821e2bSDavid Chinner * 110892821e2bSDavid Chinner * If the filesystem was cleanly unmounted, then we can trust the 110992821e2bSDavid Chinner * values in the superblock to be correct and we don't need to do 111092821e2bSDavid Chinner * anything here. 111192821e2bSDavid Chinner * 111292821e2bSDavid Chinner * If we are currently making the filesystem, the initialisation will 111392821e2bSDavid Chinner * fail as the perag data is in an undefined state. 111492821e2bSDavid Chinner */ 111592821e2bSDavid Chinner 111692821e2bSDavid Chinner if (xfs_sb_version_haslazysbcount(&mp->m_sb) && 111792821e2bSDavid Chinner !XFS_LAST_UNMOUNT_WAS_CLEAN(mp) && 111892821e2bSDavid Chinner !mp->m_sb.sb_inprogress) { 111992821e2bSDavid Chinner error = xfs_initialize_perag_data(mp, sbp->sb_agcount); 112092821e2bSDavid Chinner if (error) { 112192821e2bSDavid Chinner goto error2; 112292821e2bSDavid Chinner } 112392821e2bSDavid Chinner } 112492821e2bSDavid Chinner /* 11251da177e4SLinus Torvalds * Get and sanity-check the root inode. 11261da177e4SLinus Torvalds * Save the pointer to it in the mount structure. 11271da177e4SLinus Torvalds */ 11281da177e4SLinus Torvalds error = xfs_iget(mp, NULL, sbp->sb_rootino, 0, XFS_ILOCK_EXCL, &rip, 0); 11291da177e4SLinus Torvalds if (error) { 11301da177e4SLinus Torvalds cmn_err(CE_WARN, "XFS: failed to read root inode"); 11311da177e4SLinus Torvalds goto error3; 11321da177e4SLinus Torvalds } 11331da177e4SLinus Torvalds 11341da177e4SLinus Torvalds ASSERT(rip != NULL); 11351da177e4SLinus Torvalds 11361da177e4SLinus Torvalds if (unlikely((rip->i_d.di_mode & S_IFMT) != S_IFDIR)) { 11371da177e4SLinus Torvalds cmn_err(CE_WARN, "XFS: corrupted root inode"); 1138b6574520SNathan Scott cmn_err(CE_WARN, "Device %s - root %llu is not a directory", 1139b6574520SNathan Scott XFS_BUFTARG_NAME(mp->m_ddev_targp), 1140b6574520SNathan Scott (unsigned long long)rip->i_ino); 11411da177e4SLinus Torvalds xfs_iunlock(rip, XFS_ILOCK_EXCL); 11421da177e4SLinus Torvalds XFS_ERROR_REPORT("xfs_mountfs_int(2)", XFS_ERRLEVEL_LOW, 11431da177e4SLinus Torvalds mp); 11441da177e4SLinus Torvalds error = XFS_ERROR(EFSCORRUPTED); 11451da177e4SLinus Torvalds goto error4; 11461da177e4SLinus Torvalds } 11471da177e4SLinus Torvalds mp->m_rootip = rip; /* save it */ 11481da177e4SLinus Torvalds 11491da177e4SLinus Torvalds xfs_iunlock(rip, XFS_ILOCK_EXCL); 11501da177e4SLinus Torvalds 11511da177e4SLinus Torvalds /* 11521da177e4SLinus Torvalds * Initialize realtime inode pointers in the mount structure 11531da177e4SLinus Torvalds */ 11540771fb45SEric Sandeen error = xfs_rtmount_inodes(mp); 11550771fb45SEric Sandeen if (error) { 11561da177e4SLinus Torvalds /* 11571da177e4SLinus Torvalds * Free up the root inode. 11581da177e4SLinus Torvalds */ 11591da177e4SLinus Torvalds cmn_err(CE_WARN, "XFS: failed to read RT inodes"); 11601da177e4SLinus Torvalds goto error4; 11611da177e4SLinus Torvalds } 11621da177e4SLinus Torvalds 11631da177e4SLinus Torvalds /* 1164ee1c0908SDavid Chinner * If fs is not mounted readonly, then update the superblock changes. 11651da177e4SLinus Torvalds */ 1166e5720eecSDavid Chinner if (update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY)) { 1167e5720eecSDavid Chinner error = xfs_mount_log_sb(mp, update_flags); 1168e5720eecSDavid Chinner if (error) { 1169e5720eecSDavid Chinner cmn_err(CE_WARN, "XFS: failed to write sb changes"); 1170e5720eecSDavid Chinner goto error4; 1171e5720eecSDavid Chinner } 1172e5720eecSDavid Chinner } 11731da177e4SLinus Torvalds 11741da177e4SLinus Torvalds /* 11751da177e4SLinus Torvalds * Initialise the XFS quota management subsystem for this mount 11761da177e4SLinus Torvalds */ 11770771fb45SEric Sandeen error = XFS_QM_INIT(mp, "amount, "aflags); 11780771fb45SEric Sandeen if (error) 11791da177e4SLinus Torvalds goto error4; 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds /* 11821da177e4SLinus Torvalds * Finish recovering the file system. This part needed to be 11831da177e4SLinus Torvalds * delayed until after the root and real-time bitmap inodes 11841da177e4SLinus Torvalds * were consistently read in. 11851da177e4SLinus Torvalds */ 11861da177e4SLinus Torvalds error = xfs_log_mount_finish(mp, mfsi_flags); 11871da177e4SLinus Torvalds if (error) { 11881da177e4SLinus Torvalds cmn_err(CE_WARN, "XFS: log mount finish failed"); 11891da177e4SLinus Torvalds goto error4; 11901da177e4SLinus Torvalds } 11911da177e4SLinus Torvalds 11921da177e4SLinus Torvalds /* 11931da177e4SLinus Torvalds * Complete the quota initialisation, post-log-replay component. 11941da177e4SLinus Torvalds */ 11950771fb45SEric Sandeen error = XFS_QM_MOUNT(mp, quotamount, quotaflags, mfsi_flags); 11960771fb45SEric Sandeen if (error) 11971da177e4SLinus Torvalds goto error4; 11981da177e4SLinus Torvalds 119984e1e99fSDavid Chinner /* 120084e1e99fSDavid Chinner * Now we are mounted, reserve a small amount of unused space for 120184e1e99fSDavid Chinner * privileged transactions. This is needed so that transaction 120284e1e99fSDavid Chinner * space required for critical operations can dip into this pool 120384e1e99fSDavid Chinner * when at ENOSPC. This is needed for operations like create with 120484e1e99fSDavid Chinner * attr, unwritten extent conversion at ENOSPC, etc. Data allocations 120584e1e99fSDavid Chinner * are not allowed to use this reserved space. 120684e1e99fSDavid Chinner * 120784e1e99fSDavid Chinner * We default to 5% or 1024 fsbs of space reserved, whichever is smaller. 120884e1e99fSDavid Chinner * This may drive us straight to ENOSPC on mount, but that implies 1209714082bcSDavid Chinner * we were already there on the last unmount. Warn if this occurs. 121084e1e99fSDavid Chinner */ 121139726be2SChristoph Hellwig resblks = mp->m_sb.sb_dblocks; 121239726be2SChristoph Hellwig do_div(resblks, 20); 121339726be2SChristoph Hellwig resblks = min_t(__uint64_t, resblks, 1024); 1214714082bcSDavid Chinner error = xfs_reserve_blocks(mp, &resblks, NULL); 1215714082bcSDavid Chinner if (error) 1216714082bcSDavid Chinner cmn_err(CE_WARN, "XFS: Unable to allocate reserve blocks. " 1217714082bcSDavid Chinner "Continuing without a reserve pool."); 121884e1e99fSDavid Chinner 12191da177e4SLinus Torvalds return 0; 12201da177e4SLinus Torvalds 12211da177e4SLinus Torvalds error4: 12221da177e4SLinus Torvalds /* 12231da177e4SLinus Torvalds * Free up the root inode. 12241da177e4SLinus Torvalds */ 122543355099SChristoph Hellwig IRELE(rip); 12261da177e4SLinus Torvalds error3: 12271da177e4SLinus Torvalds xfs_log_unmount_dealloc(mp); 12281da177e4SLinus Torvalds error2: 12291da177e4SLinus Torvalds for (agno = 0; agno < sbp->sb_agcount; agno++) 12301da177e4SLinus Torvalds if (mp->m_perag[agno].pagb_list) 1231f0e2d93cSDenys Vlasenko kmem_free(mp->m_perag[agno].pagb_list); 1232f0e2d93cSDenys Vlasenko kmem_free(mp->m_perag); 12331da177e4SLinus Torvalds mp->m_perag = NULL; 12341da177e4SLinus Torvalds /* FALLTHROUGH */ 12351da177e4SLinus Torvalds error1: 12361da177e4SLinus Torvalds if (uuid_mounted) 1237fa6adbe0SChristoph Hellwig uuid_table_remove(&mp->m_sb.sb_uuid); 12381da177e4SLinus Torvalds return error; 12391da177e4SLinus Torvalds } 12401da177e4SLinus Torvalds 12411da177e4SLinus Torvalds /* 12421da177e4SLinus Torvalds * xfs_unmountfs 12431da177e4SLinus Torvalds * 12441da177e4SLinus Torvalds * This flushes out the inodes,dquots and the superblock, unmounts the 12451da177e4SLinus Torvalds * log and makes sure that incore structures are freed. 12461da177e4SLinus Torvalds */ 12471da177e4SLinus Torvalds int 124819f354d4SChristoph Hellwig xfs_unmountfs(xfs_mount_t *mp) 12491da177e4SLinus Torvalds { 125084e1e99fSDavid Chinner __uint64_t resblks; 1251714082bcSDavid Chinner int error = 0; 12521da177e4SLinus Torvalds 1253*77508ec8SChristoph Hellwig IRELE(mp->m_rootip); 1254*77508ec8SChristoph Hellwig 1255641c56fbSDavid Chinner /* 1256641c56fbSDavid Chinner * We can potentially deadlock here if we have an inode cluster 1257641c56fbSDavid Chinner * that has been freed has it's buffer still pinned in memory because 1258641c56fbSDavid Chinner * the transaction is still sitting in a iclog. The stale inodes 1259641c56fbSDavid Chinner * on that buffer will have their flush locks held until the 1260641c56fbSDavid Chinner * transaction hits the disk and the callbacks run. the inode 1261641c56fbSDavid Chinner * flush takes the flush lock unconditionally and with nothing to 1262641c56fbSDavid Chinner * push out the iclog we will never get that unlocked. hence we 1263641c56fbSDavid Chinner * need to force the log first. 1264641c56fbSDavid Chinner */ 1265641c56fbSDavid Chinner xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); 1266efa80278SChristoph Hellwig xfs_iflush_all(mp); 12671da177e4SLinus Torvalds 1268ee2a4f7cSNathan Scott XFS_QM_DQPURGEALL(mp, XFS_QMOPT_QUOTALL | XFS_QMOPT_UMOUNTING); 12691da177e4SLinus Torvalds 12701da177e4SLinus Torvalds /* 12711da177e4SLinus Torvalds * Flush out the log synchronously so that we know for sure 12721da177e4SLinus Torvalds * that nothing is pinned. This is important because bflush() 12731da177e4SLinus Torvalds * will skip pinned buffers. 12741da177e4SLinus Torvalds */ 12751da177e4SLinus Torvalds xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); 12761da177e4SLinus Torvalds 12771da177e4SLinus Torvalds xfs_binval(mp->m_ddev_targp); 12781da177e4SLinus Torvalds if (mp->m_rtdev_targp) { 12791da177e4SLinus Torvalds xfs_binval(mp->m_rtdev_targp); 12801da177e4SLinus Torvalds } 12811da177e4SLinus Torvalds 128284e1e99fSDavid Chinner /* 128384e1e99fSDavid Chinner * Unreserve any blocks we have so that when we unmount we don't account 128484e1e99fSDavid Chinner * the reserved free space as used. This is really only necessary for 128584e1e99fSDavid Chinner * lazy superblock counting because it trusts the incore superblock 128684e1e99fSDavid Chinner * counters to be aboslutely correct on clean unmount. 128784e1e99fSDavid Chinner * 128884e1e99fSDavid Chinner * We don't bother correcting this elsewhere for lazy superblock 128984e1e99fSDavid Chinner * counting because on mount of an unclean filesystem we reconstruct the 129084e1e99fSDavid Chinner * correct counter value and this is irrelevant. 129184e1e99fSDavid Chinner * 129284e1e99fSDavid Chinner * For non-lazy counter filesystems, this doesn't matter at all because 129384e1e99fSDavid Chinner * we only every apply deltas to the superblock and hence the incore 129484e1e99fSDavid Chinner * value does not matter.... 129584e1e99fSDavid Chinner */ 129684e1e99fSDavid Chinner resblks = 0; 1297714082bcSDavid Chinner error = xfs_reserve_blocks(mp, &resblks, NULL); 1298714082bcSDavid Chinner if (error) 1299714082bcSDavid Chinner cmn_err(CE_WARN, "XFS: Unable to free reserved block pool. " 1300714082bcSDavid Chinner "Freespace may not be correct on next mount."); 1301714082bcSDavid Chinner 1302e5720eecSDavid Chinner error = xfs_log_sbcount(mp, 1); 1303e5720eecSDavid Chinner if (error) 1304e5720eecSDavid Chinner cmn_err(CE_WARN, "XFS: Unable to update superblock counters. " 1305e5720eecSDavid Chinner "Freespace may not be correct on next mount."); 13061da177e4SLinus Torvalds xfs_unmountfs_writesb(mp); 13071da177e4SLinus Torvalds xfs_unmountfs_wait(mp); /* wait for async bufs */ 13081da177e4SLinus Torvalds xfs_log_unmount(mp); /* Done! No more fs ops. */ 13091da177e4SLinus Torvalds 13101da177e4SLinus Torvalds xfs_freesb(mp); 13111da177e4SLinus Torvalds 13121da177e4SLinus Torvalds /* 13131da177e4SLinus Torvalds * All inodes from this mount point should be freed. 13141da177e4SLinus Torvalds */ 13151da177e4SLinus Torvalds ASSERT(mp->m_inodes == NULL); 13161da177e4SLinus Torvalds 13171da177e4SLinus Torvalds if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0) 1318fa6adbe0SChristoph Hellwig uuid_table_remove(&mp->m_sb.sb_uuid); 13191da177e4SLinus Torvalds 13201550d0b0SChristoph Hellwig #if defined(DEBUG) 13210ce4cfd4SChristoph Hellwig xfs_errortag_clearall(mp, 0); 13221da177e4SLinus Torvalds #endif 1323745f6919SChristoph Hellwig xfs_mount_free(mp); 13241da177e4SLinus Torvalds return 0; 13251da177e4SLinus Torvalds } 13261da177e4SLinus Torvalds 1327ba0f32d4SChristoph Hellwig STATIC void 13281da177e4SLinus Torvalds xfs_unmountfs_wait(xfs_mount_t *mp) 13291da177e4SLinus Torvalds { 13301da177e4SLinus Torvalds if (mp->m_logdev_targp != mp->m_ddev_targp) 13311da177e4SLinus Torvalds xfs_wait_buftarg(mp->m_logdev_targp); 13321da177e4SLinus Torvalds if (mp->m_rtdev_targp) 13331da177e4SLinus Torvalds xfs_wait_buftarg(mp->m_rtdev_targp); 13341da177e4SLinus Torvalds xfs_wait_buftarg(mp->m_ddev_targp); 13351da177e4SLinus Torvalds } 13361da177e4SLinus Torvalds 13371da177e4SLinus Torvalds int 133892821e2bSDavid Chinner xfs_fs_writable(xfs_mount_t *mp) 133992821e2bSDavid Chinner { 1340b267ce99SChristoph Hellwig return !(xfs_test_for_freeze(mp) || XFS_FORCED_SHUTDOWN(mp) || 1341bd186aa9SChristoph Hellwig (mp->m_flags & XFS_MOUNT_RDONLY)); 134292821e2bSDavid Chinner } 134392821e2bSDavid Chinner 134492821e2bSDavid Chinner /* 134592821e2bSDavid Chinner * xfs_log_sbcount 134692821e2bSDavid Chinner * 134792821e2bSDavid Chinner * Called either periodically to keep the on disk superblock values 134892821e2bSDavid Chinner * roughly up to date or from unmount to make sure the values are 134992821e2bSDavid Chinner * correct on a clean unmount. 135092821e2bSDavid Chinner * 135192821e2bSDavid Chinner * Note this code can be called during the process of freezing, so 135292821e2bSDavid Chinner * we may need to use the transaction allocator which does not not 135392821e2bSDavid Chinner * block when the transaction subsystem is in its frozen state. 135492821e2bSDavid Chinner */ 135592821e2bSDavid Chinner int 135692821e2bSDavid Chinner xfs_log_sbcount( 135792821e2bSDavid Chinner xfs_mount_t *mp, 135892821e2bSDavid Chinner uint sync) 135992821e2bSDavid Chinner { 136092821e2bSDavid Chinner xfs_trans_t *tp; 136192821e2bSDavid Chinner int error; 136292821e2bSDavid Chinner 136392821e2bSDavid Chinner if (!xfs_fs_writable(mp)) 136492821e2bSDavid Chinner return 0; 136592821e2bSDavid Chinner 1366d4d90b57SChristoph Hellwig xfs_icsb_sync_counters(mp, 0); 136792821e2bSDavid Chinner 136892821e2bSDavid Chinner /* 136992821e2bSDavid Chinner * we don't need to do this if we are updating the superblock 137092821e2bSDavid Chinner * counters on every modification. 137192821e2bSDavid Chinner */ 137292821e2bSDavid Chinner if (!xfs_sb_version_haslazysbcount(&mp->m_sb)) 137392821e2bSDavid Chinner return 0; 137492821e2bSDavid Chinner 137592821e2bSDavid Chinner tp = _xfs_trans_alloc(mp, XFS_TRANS_SB_COUNT); 137692821e2bSDavid Chinner error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, 137792821e2bSDavid Chinner XFS_DEFAULT_LOG_COUNT); 137892821e2bSDavid Chinner if (error) { 137992821e2bSDavid Chinner xfs_trans_cancel(tp, 0); 138092821e2bSDavid Chinner return error; 138192821e2bSDavid Chinner } 138292821e2bSDavid Chinner 138392821e2bSDavid Chinner xfs_mod_sb(tp, XFS_SB_IFREE | XFS_SB_ICOUNT | XFS_SB_FDBLOCKS); 138492821e2bSDavid Chinner if (sync) 138592821e2bSDavid Chinner xfs_trans_set_sync(tp); 1386e5720eecSDavid Chinner error = xfs_trans_commit(tp, 0); 1387e5720eecSDavid Chinner return error; 138892821e2bSDavid Chinner } 138992821e2bSDavid Chinner 13902bdf7cd0SChristoph Hellwig STATIC void 13912bdf7cd0SChristoph Hellwig xfs_mark_shared_ro( 13922bdf7cd0SChristoph Hellwig xfs_mount_t *mp, 13932bdf7cd0SChristoph Hellwig xfs_buf_t *bp) 13942bdf7cd0SChristoph Hellwig { 13952bdf7cd0SChristoph Hellwig xfs_dsb_t *sb = XFS_BUF_TO_SBP(bp); 13962bdf7cd0SChristoph Hellwig __uint16_t version; 13972bdf7cd0SChristoph Hellwig 13982bdf7cd0SChristoph Hellwig if (!(sb->sb_flags & XFS_SBF_READONLY)) 13992bdf7cd0SChristoph Hellwig sb->sb_flags |= XFS_SBF_READONLY; 14002bdf7cd0SChristoph Hellwig 14012bdf7cd0SChristoph Hellwig version = be16_to_cpu(sb->sb_versionnum); 14022bdf7cd0SChristoph Hellwig if ((version & XFS_SB_VERSION_NUMBITS) != XFS_SB_VERSION_4 || 14032bdf7cd0SChristoph Hellwig !(version & XFS_SB_VERSION_SHAREDBIT)) 14042bdf7cd0SChristoph Hellwig version |= XFS_SB_VERSION_SHAREDBIT; 14052bdf7cd0SChristoph Hellwig sb->sb_versionnum = cpu_to_be16(version); 14062bdf7cd0SChristoph Hellwig } 14072bdf7cd0SChristoph Hellwig 140892821e2bSDavid Chinner int 14091da177e4SLinus Torvalds xfs_unmountfs_writesb(xfs_mount_t *mp) 14101da177e4SLinus Torvalds { 14111da177e4SLinus Torvalds xfs_buf_t *sbp; 14121da177e4SLinus Torvalds int error = 0; 14131da177e4SLinus Torvalds 14141da177e4SLinus Torvalds /* 14151da177e4SLinus Torvalds * skip superblock write if fs is read-only, or 14161da177e4SLinus Torvalds * if we are doing a forced umount. 14171da177e4SLinus Torvalds */ 1418bd186aa9SChristoph Hellwig if (!((mp->m_flags & XFS_MOUNT_RDONLY) || 14191da177e4SLinus Torvalds XFS_FORCED_SHUTDOWN(mp))) { 14208d280b98SDavid Chinner 142192821e2bSDavid Chinner sbp = xfs_getsb(mp, 0); 14228d280b98SDavid Chinner 14231da177e4SLinus Torvalds /* 14241da177e4SLinus Torvalds * mark shared-readonly if desired 14251da177e4SLinus Torvalds */ 14262bdf7cd0SChristoph Hellwig if (mp->m_mk_sharedro) 14272bdf7cd0SChristoph Hellwig xfs_mark_shared_ro(mp, sbp); 142892821e2bSDavid Chinner 14291da177e4SLinus Torvalds XFS_BUF_UNDONE(sbp); 14301da177e4SLinus Torvalds XFS_BUF_UNREAD(sbp); 14311da177e4SLinus Torvalds XFS_BUF_UNDELAYWRITE(sbp); 14321da177e4SLinus Torvalds XFS_BUF_WRITE(sbp); 14331da177e4SLinus Torvalds XFS_BUF_UNASYNC(sbp); 14341da177e4SLinus Torvalds ASSERT(XFS_BUF_TARGET(sbp) == mp->m_ddev_targp); 14351da177e4SLinus Torvalds xfsbdstrat(mp, sbp); 14361da177e4SLinus Torvalds error = xfs_iowait(sbp); 14371da177e4SLinus Torvalds if (error) 14381da177e4SLinus Torvalds xfs_ioerror_alert("xfs_unmountfs_writesb", 14391da177e4SLinus Torvalds mp, sbp, XFS_BUF_ADDR(sbp)); 14401da177e4SLinus Torvalds if (error && mp->m_mk_sharedro) 14411da177e4SLinus Torvalds xfs_fs_cmn_err(CE_ALERT, mp, "Superblock write error detected while unmounting. Filesystem may not be marked shared readonly"); 14421da177e4SLinus Torvalds xfs_buf_relse(sbp); 144392821e2bSDavid Chinner } 1444014c2544SJesper Juhl return error; 14451da177e4SLinus Torvalds } 14461da177e4SLinus Torvalds 14471da177e4SLinus Torvalds /* 14481da177e4SLinus Torvalds * xfs_mod_sb() can be used to copy arbitrary changes to the 14491da177e4SLinus Torvalds * in-core superblock into the superblock buffer to be logged. 14501da177e4SLinus Torvalds * It does not provide the higher level of locking that is 14511da177e4SLinus Torvalds * needed to protect the in-core superblock from concurrent 14521da177e4SLinus Torvalds * access. 14531da177e4SLinus Torvalds */ 14541da177e4SLinus Torvalds void 14551da177e4SLinus Torvalds xfs_mod_sb(xfs_trans_t *tp, __int64_t fields) 14561da177e4SLinus Torvalds { 14571da177e4SLinus Torvalds xfs_buf_t *bp; 14581da177e4SLinus Torvalds int first; 14591da177e4SLinus Torvalds int last; 14601da177e4SLinus Torvalds xfs_mount_t *mp; 14611da177e4SLinus Torvalds xfs_sb_field_t f; 14621da177e4SLinus Torvalds 14631da177e4SLinus Torvalds ASSERT(fields); 14641da177e4SLinus Torvalds if (!fields) 14651da177e4SLinus Torvalds return; 14661da177e4SLinus Torvalds mp = tp->t_mountp; 14671da177e4SLinus Torvalds bp = xfs_trans_getsb(tp, mp, 0); 14681da177e4SLinus Torvalds first = sizeof(xfs_sb_t); 14691da177e4SLinus Torvalds last = 0; 14701da177e4SLinus Torvalds 14711da177e4SLinus Torvalds /* translate/copy */ 14721da177e4SLinus Torvalds 14732bdf7cd0SChristoph Hellwig xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, fields); 14741da177e4SLinus Torvalds 14751da177e4SLinus Torvalds /* find modified range */ 14761da177e4SLinus Torvalds 14771da177e4SLinus Torvalds f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields); 14781da177e4SLinus Torvalds ASSERT((1LL << f) & XFS_SB_MOD_BITS); 14791da177e4SLinus Torvalds first = xfs_sb_info[f].offset; 14801da177e4SLinus Torvalds 14811da177e4SLinus Torvalds f = (xfs_sb_field_t)xfs_highbit64((__uint64_t)fields); 14821da177e4SLinus Torvalds ASSERT((1LL << f) & XFS_SB_MOD_BITS); 14831da177e4SLinus Torvalds last = xfs_sb_info[f + 1].offset - 1; 14841da177e4SLinus Torvalds 14851da177e4SLinus Torvalds xfs_trans_log_buf(tp, bp, first, last); 14861da177e4SLinus Torvalds } 1487d210a28cSYingping Lu 1488d210a28cSYingping Lu 14891da177e4SLinus Torvalds /* 14901da177e4SLinus Torvalds * xfs_mod_incore_sb_unlocked() is a utility routine common used to apply 14911da177e4SLinus Torvalds * a delta to a specified field in the in-core superblock. Simply 14921da177e4SLinus Torvalds * switch on the field indicated and apply the delta to that field. 14931da177e4SLinus Torvalds * Fields are not allowed to dip below zero, so if the delta would 14941da177e4SLinus Torvalds * do this do not apply it and return EINVAL. 14951da177e4SLinus Torvalds * 14963685c2a1SEric Sandeen * The m_sb_lock must be held when this routine is called. 14971da177e4SLinus Torvalds */ 14988d280b98SDavid Chinner int 149920f4ebf2SDavid Chinner xfs_mod_incore_sb_unlocked( 150020f4ebf2SDavid Chinner xfs_mount_t *mp, 150120f4ebf2SDavid Chinner xfs_sb_field_t field, 150220f4ebf2SDavid Chinner int64_t delta, 150320f4ebf2SDavid Chinner int rsvd) 15041da177e4SLinus Torvalds { 15051da177e4SLinus Torvalds int scounter; /* short counter for 32 bit fields */ 15061da177e4SLinus Torvalds long long lcounter; /* long counter for 64 bit fields */ 15071da177e4SLinus Torvalds long long res_used, rem; 15081da177e4SLinus Torvalds 15091da177e4SLinus Torvalds /* 15101da177e4SLinus Torvalds * With the in-core superblock spin lock held, switch 15111da177e4SLinus Torvalds * on the indicated field. Apply the delta to the 15121da177e4SLinus Torvalds * proper field. If the fields value would dip below 15131da177e4SLinus Torvalds * 0, then do not apply the delta and return EINVAL. 15141da177e4SLinus Torvalds */ 15151da177e4SLinus Torvalds switch (field) { 15161da177e4SLinus Torvalds case XFS_SBS_ICOUNT: 15171da177e4SLinus Torvalds lcounter = (long long)mp->m_sb.sb_icount; 15181da177e4SLinus Torvalds lcounter += delta; 15191da177e4SLinus Torvalds if (lcounter < 0) { 15201da177e4SLinus Torvalds ASSERT(0); 1521014c2544SJesper Juhl return XFS_ERROR(EINVAL); 15221da177e4SLinus Torvalds } 15231da177e4SLinus Torvalds mp->m_sb.sb_icount = lcounter; 1524014c2544SJesper Juhl return 0; 15251da177e4SLinus Torvalds case XFS_SBS_IFREE: 15261da177e4SLinus Torvalds lcounter = (long long)mp->m_sb.sb_ifree; 15271da177e4SLinus Torvalds lcounter += delta; 15281da177e4SLinus Torvalds if (lcounter < 0) { 15291da177e4SLinus Torvalds ASSERT(0); 1530014c2544SJesper Juhl return XFS_ERROR(EINVAL); 15311da177e4SLinus Torvalds } 15321da177e4SLinus Torvalds mp->m_sb.sb_ifree = lcounter; 1533014c2544SJesper Juhl return 0; 15341da177e4SLinus Torvalds case XFS_SBS_FDBLOCKS: 15354be536deSDavid Chinner lcounter = (long long) 15364be536deSDavid Chinner mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); 15371da177e4SLinus Torvalds res_used = (long long)(mp->m_resblks - mp->m_resblks_avail); 15381da177e4SLinus Torvalds 15391da177e4SLinus Torvalds if (delta > 0) { /* Putting blocks back */ 15401da177e4SLinus Torvalds if (res_used > delta) { 15411da177e4SLinus Torvalds mp->m_resblks_avail += delta; 15421da177e4SLinus Torvalds } else { 15431da177e4SLinus Torvalds rem = delta - res_used; 15441da177e4SLinus Torvalds mp->m_resblks_avail = mp->m_resblks; 15451da177e4SLinus Torvalds lcounter += rem; 15461da177e4SLinus Torvalds } 15471da177e4SLinus Torvalds } else { /* Taking blocks away */ 15481da177e4SLinus Torvalds 15491da177e4SLinus Torvalds lcounter += delta; 15501da177e4SLinus Torvalds 15511da177e4SLinus Torvalds /* 15521da177e4SLinus Torvalds * If were out of blocks, use any available reserved blocks if 15531da177e4SLinus Torvalds * were allowed to. 15541da177e4SLinus Torvalds */ 15551da177e4SLinus Torvalds 15561da177e4SLinus Torvalds if (lcounter < 0) { 15571da177e4SLinus Torvalds if (rsvd) { 15581da177e4SLinus Torvalds lcounter = (long long)mp->m_resblks_avail + delta; 15591da177e4SLinus Torvalds if (lcounter < 0) { 1560014c2544SJesper Juhl return XFS_ERROR(ENOSPC); 15611da177e4SLinus Torvalds } 15621da177e4SLinus Torvalds mp->m_resblks_avail = lcounter; 1563014c2544SJesper Juhl return 0; 15641da177e4SLinus Torvalds } else { /* not reserved */ 1565014c2544SJesper Juhl return XFS_ERROR(ENOSPC); 15661da177e4SLinus Torvalds } 15671da177e4SLinus Torvalds } 15681da177e4SLinus Torvalds } 15691da177e4SLinus Torvalds 15704be536deSDavid Chinner mp->m_sb.sb_fdblocks = lcounter + XFS_ALLOC_SET_ASIDE(mp); 1571014c2544SJesper Juhl return 0; 15721da177e4SLinus Torvalds case XFS_SBS_FREXTENTS: 15731da177e4SLinus Torvalds lcounter = (long long)mp->m_sb.sb_frextents; 15741da177e4SLinus Torvalds lcounter += delta; 15751da177e4SLinus Torvalds if (lcounter < 0) { 1576014c2544SJesper Juhl return XFS_ERROR(ENOSPC); 15771da177e4SLinus Torvalds } 15781da177e4SLinus Torvalds mp->m_sb.sb_frextents = lcounter; 1579014c2544SJesper Juhl return 0; 15801da177e4SLinus Torvalds case XFS_SBS_DBLOCKS: 15811da177e4SLinus Torvalds lcounter = (long long)mp->m_sb.sb_dblocks; 15821da177e4SLinus Torvalds lcounter += delta; 15831da177e4SLinus Torvalds if (lcounter < 0) { 15841da177e4SLinus Torvalds ASSERT(0); 1585014c2544SJesper Juhl return XFS_ERROR(EINVAL); 15861da177e4SLinus Torvalds } 15871da177e4SLinus Torvalds mp->m_sb.sb_dblocks = lcounter; 1588014c2544SJesper Juhl return 0; 15891da177e4SLinus Torvalds case XFS_SBS_AGCOUNT: 15901da177e4SLinus Torvalds scounter = mp->m_sb.sb_agcount; 15911da177e4SLinus Torvalds scounter += delta; 15921da177e4SLinus Torvalds if (scounter < 0) { 15931da177e4SLinus Torvalds ASSERT(0); 1594014c2544SJesper Juhl return XFS_ERROR(EINVAL); 15951da177e4SLinus Torvalds } 15961da177e4SLinus Torvalds mp->m_sb.sb_agcount = scounter; 1597014c2544SJesper Juhl return 0; 15981da177e4SLinus Torvalds case XFS_SBS_IMAX_PCT: 15991da177e4SLinus Torvalds scounter = mp->m_sb.sb_imax_pct; 16001da177e4SLinus Torvalds scounter += delta; 16011da177e4SLinus Torvalds if (scounter < 0) { 16021da177e4SLinus Torvalds ASSERT(0); 1603014c2544SJesper Juhl return XFS_ERROR(EINVAL); 16041da177e4SLinus Torvalds } 16051da177e4SLinus Torvalds mp->m_sb.sb_imax_pct = scounter; 1606014c2544SJesper Juhl return 0; 16071da177e4SLinus Torvalds case XFS_SBS_REXTSIZE: 16081da177e4SLinus Torvalds scounter = mp->m_sb.sb_rextsize; 16091da177e4SLinus Torvalds scounter += delta; 16101da177e4SLinus Torvalds if (scounter < 0) { 16111da177e4SLinus Torvalds ASSERT(0); 1612014c2544SJesper Juhl return XFS_ERROR(EINVAL); 16131da177e4SLinus Torvalds } 16141da177e4SLinus Torvalds mp->m_sb.sb_rextsize = scounter; 1615014c2544SJesper Juhl return 0; 16161da177e4SLinus Torvalds case XFS_SBS_RBMBLOCKS: 16171da177e4SLinus Torvalds scounter = mp->m_sb.sb_rbmblocks; 16181da177e4SLinus Torvalds scounter += delta; 16191da177e4SLinus Torvalds if (scounter < 0) { 16201da177e4SLinus Torvalds ASSERT(0); 1621014c2544SJesper Juhl return XFS_ERROR(EINVAL); 16221da177e4SLinus Torvalds } 16231da177e4SLinus Torvalds mp->m_sb.sb_rbmblocks = scounter; 1624014c2544SJesper Juhl return 0; 16251da177e4SLinus Torvalds case XFS_SBS_RBLOCKS: 16261da177e4SLinus Torvalds lcounter = (long long)mp->m_sb.sb_rblocks; 16271da177e4SLinus Torvalds lcounter += delta; 16281da177e4SLinus Torvalds if (lcounter < 0) { 16291da177e4SLinus Torvalds ASSERT(0); 1630014c2544SJesper Juhl return XFS_ERROR(EINVAL); 16311da177e4SLinus Torvalds } 16321da177e4SLinus Torvalds mp->m_sb.sb_rblocks = lcounter; 1633014c2544SJesper Juhl return 0; 16341da177e4SLinus Torvalds case XFS_SBS_REXTENTS: 16351da177e4SLinus Torvalds lcounter = (long long)mp->m_sb.sb_rextents; 16361da177e4SLinus Torvalds lcounter += delta; 16371da177e4SLinus Torvalds if (lcounter < 0) { 16381da177e4SLinus Torvalds ASSERT(0); 1639014c2544SJesper Juhl return XFS_ERROR(EINVAL); 16401da177e4SLinus Torvalds } 16411da177e4SLinus Torvalds mp->m_sb.sb_rextents = lcounter; 1642014c2544SJesper Juhl return 0; 16431da177e4SLinus Torvalds case XFS_SBS_REXTSLOG: 16441da177e4SLinus Torvalds scounter = mp->m_sb.sb_rextslog; 16451da177e4SLinus Torvalds scounter += delta; 16461da177e4SLinus Torvalds if (scounter < 0) { 16471da177e4SLinus Torvalds ASSERT(0); 1648014c2544SJesper Juhl return XFS_ERROR(EINVAL); 16491da177e4SLinus Torvalds } 16501da177e4SLinus Torvalds mp->m_sb.sb_rextslog = scounter; 1651014c2544SJesper Juhl return 0; 16521da177e4SLinus Torvalds default: 16531da177e4SLinus Torvalds ASSERT(0); 1654014c2544SJesper Juhl return XFS_ERROR(EINVAL); 16551da177e4SLinus Torvalds } 16561da177e4SLinus Torvalds } 16571da177e4SLinus Torvalds 16581da177e4SLinus Torvalds /* 16591da177e4SLinus Torvalds * xfs_mod_incore_sb() is used to change a field in the in-core 16601da177e4SLinus Torvalds * superblock structure by the specified delta. This modification 16613685c2a1SEric Sandeen * is protected by the m_sb_lock. Just use the xfs_mod_incore_sb_unlocked() 16621da177e4SLinus Torvalds * routine to do the work. 16631da177e4SLinus Torvalds */ 16641da177e4SLinus Torvalds int 166520f4ebf2SDavid Chinner xfs_mod_incore_sb( 166620f4ebf2SDavid Chinner xfs_mount_t *mp, 166720f4ebf2SDavid Chinner xfs_sb_field_t field, 166820f4ebf2SDavid Chinner int64_t delta, 166920f4ebf2SDavid Chinner int rsvd) 16701da177e4SLinus Torvalds { 16711da177e4SLinus Torvalds int status; 16721da177e4SLinus Torvalds 16738d280b98SDavid Chinner /* check for per-cpu counters */ 16748d280b98SDavid Chinner switch (field) { 16758d280b98SDavid Chinner #ifdef HAVE_PERCPU_SB 16768d280b98SDavid Chinner case XFS_SBS_ICOUNT: 16778d280b98SDavid Chinner case XFS_SBS_IFREE: 16788d280b98SDavid Chinner case XFS_SBS_FDBLOCKS: 16798d280b98SDavid Chinner if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) { 16808d280b98SDavid Chinner status = xfs_icsb_modify_counters(mp, field, 16818d280b98SDavid Chinner delta, rsvd); 16828d280b98SDavid Chinner break; 16838d280b98SDavid Chinner } 16848d280b98SDavid Chinner /* FALLTHROUGH */ 16858d280b98SDavid Chinner #endif 16868d280b98SDavid Chinner default: 16873685c2a1SEric Sandeen spin_lock(&mp->m_sb_lock); 16881da177e4SLinus Torvalds status = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd); 16893685c2a1SEric Sandeen spin_unlock(&mp->m_sb_lock); 16908d280b98SDavid Chinner break; 16918d280b98SDavid Chinner } 16928d280b98SDavid Chinner 1693014c2544SJesper Juhl return status; 16941da177e4SLinus Torvalds } 16951da177e4SLinus Torvalds 16961da177e4SLinus Torvalds /* 16971da177e4SLinus Torvalds * xfs_mod_incore_sb_batch() is used to change more than one field 16981da177e4SLinus Torvalds * in the in-core superblock structure at a time. This modification 16991da177e4SLinus Torvalds * is protected by a lock internal to this module. The fields and 17001da177e4SLinus Torvalds * changes to those fields are specified in the array of xfs_mod_sb 17011da177e4SLinus Torvalds * structures passed in. 17021da177e4SLinus Torvalds * 17031da177e4SLinus Torvalds * Either all of the specified deltas will be applied or none of 17041da177e4SLinus Torvalds * them will. If any modified field dips below 0, then all modifications 17051da177e4SLinus Torvalds * will be backed out and EINVAL will be returned. 17061da177e4SLinus Torvalds */ 17071da177e4SLinus Torvalds int 17081da177e4SLinus Torvalds xfs_mod_incore_sb_batch(xfs_mount_t *mp, xfs_mod_sb_t *msb, uint nmsb, int rsvd) 17091da177e4SLinus Torvalds { 17101da177e4SLinus Torvalds int status=0; 17111da177e4SLinus Torvalds xfs_mod_sb_t *msbp; 17121da177e4SLinus Torvalds 17131da177e4SLinus Torvalds /* 17141da177e4SLinus Torvalds * Loop through the array of mod structures and apply each 17151da177e4SLinus Torvalds * individually. If any fail, then back out all those 17161da177e4SLinus Torvalds * which have already been applied. Do all of this within 17173685c2a1SEric Sandeen * the scope of the m_sb_lock so that all of the changes will 17181da177e4SLinus Torvalds * be atomic. 17191da177e4SLinus Torvalds */ 17203685c2a1SEric Sandeen spin_lock(&mp->m_sb_lock); 17211da177e4SLinus Torvalds msbp = &msb[0]; 17221da177e4SLinus Torvalds for (msbp = &msbp[0]; msbp < (msb + nmsb); msbp++) { 17231da177e4SLinus Torvalds /* 17241da177e4SLinus Torvalds * Apply the delta at index n. If it fails, break 17251da177e4SLinus Torvalds * from the loop so we'll fall into the undo loop 17261da177e4SLinus Torvalds * below. 17271da177e4SLinus Torvalds */ 17288d280b98SDavid Chinner switch (msbp->msb_field) { 17298d280b98SDavid Chinner #ifdef HAVE_PERCPU_SB 17308d280b98SDavid Chinner case XFS_SBS_ICOUNT: 17318d280b98SDavid Chinner case XFS_SBS_IFREE: 17328d280b98SDavid Chinner case XFS_SBS_FDBLOCKS: 17338d280b98SDavid Chinner if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) { 17343685c2a1SEric Sandeen spin_unlock(&mp->m_sb_lock); 173520b64285SDavid Chinner status = xfs_icsb_modify_counters(mp, 17368d280b98SDavid Chinner msbp->msb_field, 17371da177e4SLinus Torvalds msbp->msb_delta, rsvd); 17383685c2a1SEric Sandeen spin_lock(&mp->m_sb_lock); 17398d280b98SDavid Chinner break; 17408d280b98SDavid Chinner } 17418d280b98SDavid Chinner /* FALLTHROUGH */ 17428d280b98SDavid Chinner #endif 17438d280b98SDavid Chinner default: 17448d280b98SDavid Chinner status = xfs_mod_incore_sb_unlocked(mp, 17458d280b98SDavid Chinner msbp->msb_field, 17468d280b98SDavid Chinner msbp->msb_delta, rsvd); 17478d280b98SDavid Chinner break; 17488d280b98SDavid Chinner } 17498d280b98SDavid Chinner 17501da177e4SLinus Torvalds if (status != 0) { 17511da177e4SLinus Torvalds break; 17521da177e4SLinus Torvalds } 17531da177e4SLinus Torvalds } 17541da177e4SLinus Torvalds 17551da177e4SLinus Torvalds /* 17561da177e4SLinus Torvalds * If we didn't complete the loop above, then back out 17571da177e4SLinus Torvalds * any changes made to the superblock. If you add code 17581da177e4SLinus Torvalds * between the loop above and here, make sure that you 17591da177e4SLinus Torvalds * preserve the value of status. Loop back until 17601da177e4SLinus Torvalds * we step below the beginning of the array. Make sure 17611da177e4SLinus Torvalds * we don't touch anything back there. 17621da177e4SLinus Torvalds */ 17631da177e4SLinus Torvalds if (status != 0) { 17641da177e4SLinus Torvalds msbp--; 17651da177e4SLinus Torvalds while (msbp >= msb) { 17668d280b98SDavid Chinner switch (msbp->msb_field) { 17678d280b98SDavid Chinner #ifdef HAVE_PERCPU_SB 17688d280b98SDavid Chinner case XFS_SBS_ICOUNT: 17698d280b98SDavid Chinner case XFS_SBS_IFREE: 17708d280b98SDavid Chinner case XFS_SBS_FDBLOCKS: 17718d280b98SDavid Chinner if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) { 17723685c2a1SEric Sandeen spin_unlock(&mp->m_sb_lock); 177320b64285SDavid Chinner status = xfs_icsb_modify_counters(mp, 17748d280b98SDavid Chinner msbp->msb_field, 17758d280b98SDavid Chinner -(msbp->msb_delta), 17768d280b98SDavid Chinner rsvd); 17773685c2a1SEric Sandeen spin_lock(&mp->m_sb_lock); 17788d280b98SDavid Chinner break; 17798d280b98SDavid Chinner } 17808d280b98SDavid Chinner /* FALLTHROUGH */ 17818d280b98SDavid Chinner #endif 17828d280b98SDavid Chinner default: 17831da177e4SLinus Torvalds status = xfs_mod_incore_sb_unlocked(mp, 17848d280b98SDavid Chinner msbp->msb_field, 17858d280b98SDavid Chinner -(msbp->msb_delta), 17868d280b98SDavid Chinner rsvd); 17878d280b98SDavid Chinner break; 17888d280b98SDavid Chinner } 17891da177e4SLinus Torvalds ASSERT(status == 0); 17901da177e4SLinus Torvalds msbp--; 17911da177e4SLinus Torvalds } 17921da177e4SLinus Torvalds } 17933685c2a1SEric Sandeen spin_unlock(&mp->m_sb_lock); 1794014c2544SJesper Juhl return status; 17951da177e4SLinus Torvalds } 17961da177e4SLinus Torvalds 17971da177e4SLinus Torvalds /* 17981da177e4SLinus Torvalds * xfs_getsb() is called to obtain the buffer for the superblock. 17991da177e4SLinus Torvalds * The buffer is returned locked and read in from disk. 18001da177e4SLinus Torvalds * The buffer should be released with a call to xfs_brelse(). 18011da177e4SLinus Torvalds * 18021da177e4SLinus Torvalds * If the flags parameter is BUF_TRYLOCK, then we'll only return 18031da177e4SLinus Torvalds * the superblock buffer if it can be locked without sleeping. 18041da177e4SLinus Torvalds * If it can't then we'll return NULL. 18051da177e4SLinus Torvalds */ 18061da177e4SLinus Torvalds xfs_buf_t * 18071da177e4SLinus Torvalds xfs_getsb( 18081da177e4SLinus Torvalds xfs_mount_t *mp, 18091da177e4SLinus Torvalds int flags) 18101da177e4SLinus Torvalds { 18111da177e4SLinus Torvalds xfs_buf_t *bp; 18121da177e4SLinus Torvalds 18131da177e4SLinus Torvalds ASSERT(mp->m_sb_bp != NULL); 18141da177e4SLinus Torvalds bp = mp->m_sb_bp; 18151da177e4SLinus Torvalds if (flags & XFS_BUF_TRYLOCK) { 18161da177e4SLinus Torvalds if (!XFS_BUF_CPSEMA(bp)) { 18171da177e4SLinus Torvalds return NULL; 18181da177e4SLinus Torvalds } 18191da177e4SLinus Torvalds } else { 18201da177e4SLinus Torvalds XFS_BUF_PSEMA(bp, PRIBIO); 18211da177e4SLinus Torvalds } 18221da177e4SLinus Torvalds XFS_BUF_HOLD(bp); 18231da177e4SLinus Torvalds ASSERT(XFS_BUF_ISDONE(bp)); 1824014c2544SJesper Juhl return bp; 18251da177e4SLinus Torvalds } 18261da177e4SLinus Torvalds 18271da177e4SLinus Torvalds /* 18281da177e4SLinus Torvalds * Used to free the superblock along various error paths. 18291da177e4SLinus Torvalds */ 18301da177e4SLinus Torvalds void 18311da177e4SLinus Torvalds xfs_freesb( 18321da177e4SLinus Torvalds xfs_mount_t *mp) 18331da177e4SLinus Torvalds { 18341da177e4SLinus Torvalds xfs_buf_t *bp; 18351da177e4SLinus Torvalds 18361da177e4SLinus Torvalds /* 18371da177e4SLinus Torvalds * Use xfs_getsb() so that the buffer will be locked 18381da177e4SLinus Torvalds * when we call xfs_buf_relse(). 18391da177e4SLinus Torvalds */ 18401da177e4SLinus Torvalds bp = xfs_getsb(mp, 0); 18411da177e4SLinus Torvalds XFS_BUF_UNMANAGE(bp); 18421da177e4SLinus Torvalds xfs_buf_relse(bp); 18431da177e4SLinus Torvalds mp->m_sb_bp = NULL; 18441da177e4SLinus Torvalds } 18451da177e4SLinus Torvalds 18461da177e4SLinus Torvalds /* 18471da177e4SLinus Torvalds * See if the UUID is unique among mounted XFS filesystems. 18481da177e4SLinus Torvalds * Mount fails if UUID is nil or a FS with the same UUID is already mounted. 18491da177e4SLinus Torvalds */ 18501da177e4SLinus Torvalds STATIC int 18511da177e4SLinus Torvalds xfs_uuid_mount( 18521da177e4SLinus Torvalds xfs_mount_t *mp) 18531da177e4SLinus Torvalds { 18541da177e4SLinus Torvalds if (uuid_is_nil(&mp->m_sb.sb_uuid)) { 18551da177e4SLinus Torvalds cmn_err(CE_WARN, 18561da177e4SLinus Torvalds "XFS: Filesystem %s has nil UUID - can't mount", 18571da177e4SLinus Torvalds mp->m_fsname); 18581da177e4SLinus Torvalds return -1; 18591da177e4SLinus Torvalds } 18601da177e4SLinus Torvalds if (!uuid_table_insert(&mp->m_sb.sb_uuid)) { 18611da177e4SLinus Torvalds cmn_err(CE_WARN, 18621da177e4SLinus Torvalds "XFS: Filesystem %s has duplicate UUID - can't mount", 18631da177e4SLinus Torvalds mp->m_fsname); 18641da177e4SLinus Torvalds return -1; 18651da177e4SLinus Torvalds } 18661da177e4SLinus Torvalds return 0; 18671da177e4SLinus Torvalds } 18681da177e4SLinus Torvalds 18691da177e4SLinus Torvalds /* 18701da177e4SLinus Torvalds * Used to log changes to the superblock unit and width fields which could 1871e6957ea4SEric Sandeen * be altered by the mount options, as well as any potential sb_features2 1872e6957ea4SEric Sandeen * fixup. Only the first superblock is updated. 18731da177e4SLinus Torvalds */ 1874e5720eecSDavid Chinner STATIC int 1875ee1c0908SDavid Chinner xfs_mount_log_sb( 18761da177e4SLinus Torvalds xfs_mount_t *mp, 18771da177e4SLinus Torvalds __int64_t fields) 18781da177e4SLinus Torvalds { 18791da177e4SLinus Torvalds xfs_trans_t *tp; 1880e5720eecSDavid Chinner int error; 18811da177e4SLinus Torvalds 1882ee1c0908SDavid Chinner ASSERT(fields & (XFS_SB_UNIT | XFS_SB_WIDTH | XFS_SB_UUID | 18834b166de0SDavid Chinner XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2 | 18844b166de0SDavid Chinner XFS_SB_VERSIONNUM)); 18851da177e4SLinus Torvalds 18861da177e4SLinus Torvalds tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT); 1887e5720eecSDavid Chinner error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, 1888e5720eecSDavid Chinner XFS_DEFAULT_LOG_COUNT); 1889e5720eecSDavid Chinner if (error) { 18901da177e4SLinus Torvalds xfs_trans_cancel(tp, 0); 1891e5720eecSDavid Chinner return error; 18921da177e4SLinus Torvalds } 18931da177e4SLinus Torvalds xfs_mod_sb(tp, fields); 1894e5720eecSDavid Chinner error = xfs_trans_commit(tp, 0); 1895e5720eecSDavid Chinner return error; 18961da177e4SLinus Torvalds } 18978d280b98SDavid Chinner 18988d280b98SDavid Chinner 18998d280b98SDavid Chinner #ifdef HAVE_PERCPU_SB 19008d280b98SDavid Chinner /* 19018d280b98SDavid Chinner * Per-cpu incore superblock counters 19028d280b98SDavid Chinner * 19038d280b98SDavid Chinner * Simple concept, difficult implementation 19048d280b98SDavid Chinner * 19058d280b98SDavid Chinner * Basically, replace the incore superblock counters with a distributed per cpu 19068d280b98SDavid Chinner * counter for contended fields (e.g. free block count). 19078d280b98SDavid Chinner * 19088d280b98SDavid Chinner * Difficulties arise in that the incore sb is used for ENOSPC checking, and 19098d280b98SDavid Chinner * hence needs to be accurately read when we are running low on space. Hence 19108d280b98SDavid Chinner * there is a method to enable and disable the per-cpu counters based on how 19118d280b98SDavid Chinner * much "stuff" is available in them. 19128d280b98SDavid Chinner * 19138d280b98SDavid Chinner * Basically, a counter is enabled if there is enough free resource to justify 19148d280b98SDavid Chinner * running a per-cpu fast-path. If the per-cpu counter runs out (i.e. a local 19158d280b98SDavid Chinner * ENOSPC), then we disable the counters to synchronise all callers and 19168d280b98SDavid Chinner * re-distribute the available resources. 19178d280b98SDavid Chinner * 19188d280b98SDavid Chinner * If, once we redistributed the available resources, we still get a failure, 19198d280b98SDavid Chinner * we disable the per-cpu counter and go through the slow path. 19208d280b98SDavid Chinner * 19218d280b98SDavid Chinner * The slow path is the current xfs_mod_incore_sb() function. This means that 19228d280b98SDavid Chinner * when we disable a per-cpu counter, we need to drain it's resources back to 19238d280b98SDavid Chinner * the global superblock. We do this after disabling the counter to prevent 19248d280b98SDavid Chinner * more threads from queueing up on the counter. 19258d280b98SDavid Chinner * 19268d280b98SDavid Chinner * Essentially, this means that we still need a lock in the fast path to enable 19278d280b98SDavid Chinner * synchronisation between the global counters and the per-cpu counters. This 19288d280b98SDavid Chinner * is not a problem because the lock will be local to a CPU almost all the time 19298d280b98SDavid Chinner * and have little contention except when we get to ENOSPC conditions. 19308d280b98SDavid Chinner * 19318d280b98SDavid Chinner * Basically, this lock becomes a barrier that enables us to lock out the fast 19328d280b98SDavid Chinner * path while we do things like enabling and disabling counters and 19338d280b98SDavid Chinner * synchronising the counters. 19348d280b98SDavid Chinner * 19358d280b98SDavid Chinner * Locking rules: 19368d280b98SDavid Chinner * 19373685c2a1SEric Sandeen * 1. m_sb_lock before picking up per-cpu locks 19388d280b98SDavid Chinner * 2. per-cpu locks always picked up via for_each_online_cpu() order 19393685c2a1SEric Sandeen * 3. accurate counter sync requires m_sb_lock + per cpu locks 19408d280b98SDavid Chinner * 4. modifying per-cpu counters requires holding per-cpu lock 19413685c2a1SEric Sandeen * 5. modifying global counters requires holding m_sb_lock 19423685c2a1SEric Sandeen * 6. enabling or disabling a counter requires holding the m_sb_lock 19438d280b98SDavid Chinner * and _none_ of the per-cpu locks. 19448d280b98SDavid Chinner * 19458d280b98SDavid Chinner * Disabled counters are only ever re-enabled by a balance operation 19468d280b98SDavid Chinner * that results in more free resources per CPU than a given threshold. 19478d280b98SDavid Chinner * To ensure counters don't remain disabled, they are rebalanced when 19488d280b98SDavid Chinner * the global resource goes above a higher threshold (i.e. some hysteresis 19498d280b98SDavid Chinner * is present to prevent thrashing). 19508d280b98SDavid Chinner */ 1951e8234a68SDavid Chinner 19525a67e4c5SChandra Seetharaman #ifdef CONFIG_HOTPLUG_CPU 1953e8234a68SDavid Chinner /* 1954e8234a68SDavid Chinner * hot-plug CPU notifier support. 1955e8234a68SDavid Chinner * 19565a67e4c5SChandra Seetharaman * We need a notifier per filesystem as we need to be able to identify 19575a67e4c5SChandra Seetharaman * the filesystem to balance the counters out. This is achieved by 19585a67e4c5SChandra Seetharaman * having a notifier block embedded in the xfs_mount_t and doing pointer 19595a67e4c5SChandra Seetharaman * magic to get the mount pointer from the notifier block address. 1960e8234a68SDavid Chinner */ 1961e8234a68SDavid Chinner STATIC int 1962e8234a68SDavid Chinner xfs_icsb_cpu_notify( 1963e8234a68SDavid Chinner struct notifier_block *nfb, 1964e8234a68SDavid Chinner unsigned long action, 1965e8234a68SDavid Chinner void *hcpu) 1966e8234a68SDavid Chinner { 1967e8234a68SDavid Chinner xfs_icsb_cnts_t *cntp; 1968e8234a68SDavid Chinner xfs_mount_t *mp; 1969e8234a68SDavid Chinner 1970e8234a68SDavid Chinner mp = (xfs_mount_t *)container_of(nfb, xfs_mount_t, m_icsb_notifier); 1971e8234a68SDavid Chinner cntp = (xfs_icsb_cnts_t *) 1972e8234a68SDavid Chinner per_cpu_ptr(mp->m_sb_cnts, (unsigned long)hcpu); 1973e8234a68SDavid Chinner switch (action) { 1974e8234a68SDavid Chinner case CPU_UP_PREPARE: 19758bb78442SRafael J. Wysocki case CPU_UP_PREPARE_FROZEN: 1976e8234a68SDavid Chinner /* Easy Case - initialize the area and locks, and 1977e8234a68SDavid Chinner * then rebalance when online does everything else for us. */ 197801e1b69cSDavid Chinner memset(cntp, 0, sizeof(xfs_icsb_cnts_t)); 1979e8234a68SDavid Chinner break; 1980e8234a68SDavid Chinner case CPU_ONLINE: 19818bb78442SRafael J. Wysocki case CPU_ONLINE_FROZEN: 198203135cf7SDavid Chinner xfs_icsb_lock(mp); 198345af6c6dSChristoph Hellwig xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0); 198445af6c6dSChristoph Hellwig xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0); 198545af6c6dSChristoph Hellwig xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0); 198603135cf7SDavid Chinner xfs_icsb_unlock(mp); 1987e8234a68SDavid Chinner break; 1988e8234a68SDavid Chinner case CPU_DEAD: 19898bb78442SRafael J. Wysocki case CPU_DEAD_FROZEN: 1990e8234a68SDavid Chinner /* Disable all the counters, then fold the dead cpu's 1991e8234a68SDavid Chinner * count into the total on the global superblock and 1992e8234a68SDavid Chinner * re-enable the counters. */ 199303135cf7SDavid Chinner xfs_icsb_lock(mp); 19943685c2a1SEric Sandeen spin_lock(&mp->m_sb_lock); 1995e8234a68SDavid Chinner xfs_icsb_disable_counter(mp, XFS_SBS_ICOUNT); 1996e8234a68SDavid Chinner xfs_icsb_disable_counter(mp, XFS_SBS_IFREE); 1997e8234a68SDavid Chinner xfs_icsb_disable_counter(mp, XFS_SBS_FDBLOCKS); 1998e8234a68SDavid Chinner 1999e8234a68SDavid Chinner mp->m_sb.sb_icount += cntp->icsb_icount; 2000e8234a68SDavid Chinner mp->m_sb.sb_ifree += cntp->icsb_ifree; 2001e8234a68SDavid Chinner mp->m_sb.sb_fdblocks += cntp->icsb_fdblocks; 2002e8234a68SDavid Chinner 200301e1b69cSDavid Chinner memset(cntp, 0, sizeof(xfs_icsb_cnts_t)); 2004e8234a68SDavid Chinner 200545af6c6dSChristoph Hellwig xfs_icsb_balance_counter_locked(mp, XFS_SBS_ICOUNT, 0); 200645af6c6dSChristoph Hellwig xfs_icsb_balance_counter_locked(mp, XFS_SBS_IFREE, 0); 200745af6c6dSChristoph Hellwig xfs_icsb_balance_counter_locked(mp, XFS_SBS_FDBLOCKS, 0); 20083685c2a1SEric Sandeen spin_unlock(&mp->m_sb_lock); 200903135cf7SDavid Chinner xfs_icsb_unlock(mp); 2010e8234a68SDavid Chinner break; 2011e8234a68SDavid Chinner } 2012e8234a68SDavid Chinner 2013e8234a68SDavid Chinner return NOTIFY_OK; 2014e8234a68SDavid Chinner } 20155a67e4c5SChandra Seetharaman #endif /* CONFIG_HOTPLUG_CPU */ 2016e8234a68SDavid Chinner 20178d280b98SDavid Chinner int 20188d280b98SDavid Chinner xfs_icsb_init_counters( 20198d280b98SDavid Chinner xfs_mount_t *mp) 20208d280b98SDavid Chinner { 20218d280b98SDavid Chinner xfs_icsb_cnts_t *cntp; 20228d280b98SDavid Chinner int i; 20238d280b98SDavid Chinner 20248d280b98SDavid Chinner mp->m_sb_cnts = alloc_percpu(xfs_icsb_cnts_t); 20258d280b98SDavid Chinner if (mp->m_sb_cnts == NULL) 20268d280b98SDavid Chinner return -ENOMEM; 20278d280b98SDavid Chinner 20285a67e4c5SChandra Seetharaman #ifdef CONFIG_HOTPLUG_CPU 2029e8234a68SDavid Chinner mp->m_icsb_notifier.notifier_call = xfs_icsb_cpu_notify; 2030e8234a68SDavid Chinner mp->m_icsb_notifier.priority = 0; 20315a67e4c5SChandra Seetharaman register_hotcpu_notifier(&mp->m_icsb_notifier); 20325a67e4c5SChandra Seetharaman #endif /* CONFIG_HOTPLUG_CPU */ 2033e8234a68SDavid Chinner 20348d280b98SDavid Chinner for_each_online_cpu(i) { 20358d280b98SDavid Chinner cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i); 203601e1b69cSDavid Chinner memset(cntp, 0, sizeof(xfs_icsb_cnts_t)); 20378d280b98SDavid Chinner } 203820b64285SDavid Chinner 203920b64285SDavid Chinner mutex_init(&mp->m_icsb_mutex); 204020b64285SDavid Chinner 20418d280b98SDavid Chinner /* 20428d280b98SDavid Chinner * start with all counters disabled so that the 20438d280b98SDavid Chinner * initial balance kicks us off correctly 20448d280b98SDavid Chinner */ 20458d280b98SDavid Chinner mp->m_icsb_counters = -1; 20468d280b98SDavid Chinner return 0; 20478d280b98SDavid Chinner } 20488d280b98SDavid Chinner 20495478eeadSLachlan McIlroy void 20505478eeadSLachlan McIlroy xfs_icsb_reinit_counters( 20515478eeadSLachlan McIlroy xfs_mount_t *mp) 20525478eeadSLachlan McIlroy { 20535478eeadSLachlan McIlroy xfs_icsb_lock(mp); 20545478eeadSLachlan McIlroy /* 20555478eeadSLachlan McIlroy * start with all counters disabled so that the 20565478eeadSLachlan McIlroy * initial balance kicks us off correctly 20575478eeadSLachlan McIlroy */ 20585478eeadSLachlan McIlroy mp->m_icsb_counters = -1; 205945af6c6dSChristoph Hellwig xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0); 206045af6c6dSChristoph Hellwig xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0); 206145af6c6dSChristoph Hellwig xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0); 20625478eeadSLachlan McIlroy xfs_icsb_unlock(mp); 20635478eeadSLachlan McIlroy } 20645478eeadSLachlan McIlroy 2065c962fb79SChristoph Hellwig void 20668d280b98SDavid Chinner xfs_icsb_destroy_counters( 20678d280b98SDavid Chinner xfs_mount_t *mp) 20688d280b98SDavid Chinner { 2069e8234a68SDavid Chinner if (mp->m_sb_cnts) { 20705a67e4c5SChandra Seetharaman unregister_hotcpu_notifier(&mp->m_icsb_notifier); 20718d280b98SDavid Chinner free_percpu(mp->m_sb_cnts); 20728d280b98SDavid Chinner } 207303135cf7SDavid Chinner mutex_destroy(&mp->m_icsb_mutex); 2074e8234a68SDavid Chinner } 20758d280b98SDavid Chinner 20767989cb8eSDavid Chinner STATIC_INLINE void 207701e1b69cSDavid Chinner xfs_icsb_lock_cntr( 207801e1b69cSDavid Chinner xfs_icsb_cnts_t *icsbp) 207901e1b69cSDavid Chinner { 208001e1b69cSDavid Chinner while (test_and_set_bit(XFS_ICSB_FLAG_LOCK, &icsbp->icsb_flags)) { 208101e1b69cSDavid Chinner ndelay(1000); 208201e1b69cSDavid Chinner } 208301e1b69cSDavid Chinner } 208401e1b69cSDavid Chinner 20857989cb8eSDavid Chinner STATIC_INLINE void 208601e1b69cSDavid Chinner xfs_icsb_unlock_cntr( 208701e1b69cSDavid Chinner xfs_icsb_cnts_t *icsbp) 208801e1b69cSDavid Chinner { 208901e1b69cSDavid Chinner clear_bit(XFS_ICSB_FLAG_LOCK, &icsbp->icsb_flags); 209001e1b69cSDavid Chinner } 209101e1b69cSDavid Chinner 20928d280b98SDavid Chinner 20937989cb8eSDavid Chinner STATIC_INLINE void 20948d280b98SDavid Chinner xfs_icsb_lock_all_counters( 20958d280b98SDavid Chinner xfs_mount_t *mp) 20968d280b98SDavid Chinner { 20978d280b98SDavid Chinner xfs_icsb_cnts_t *cntp; 20988d280b98SDavid Chinner int i; 20998d280b98SDavid Chinner 21008d280b98SDavid Chinner for_each_online_cpu(i) { 21018d280b98SDavid Chinner cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i); 210201e1b69cSDavid Chinner xfs_icsb_lock_cntr(cntp); 21038d280b98SDavid Chinner } 21048d280b98SDavid Chinner } 21058d280b98SDavid Chinner 21067989cb8eSDavid Chinner STATIC_INLINE void 21078d280b98SDavid Chinner xfs_icsb_unlock_all_counters( 21088d280b98SDavid Chinner xfs_mount_t *mp) 21098d280b98SDavid Chinner { 21108d280b98SDavid Chinner xfs_icsb_cnts_t *cntp; 21118d280b98SDavid Chinner int i; 21128d280b98SDavid Chinner 21138d280b98SDavid Chinner for_each_online_cpu(i) { 21148d280b98SDavid Chinner cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i); 211501e1b69cSDavid Chinner xfs_icsb_unlock_cntr(cntp); 21168d280b98SDavid Chinner } 21178d280b98SDavid Chinner } 21188d280b98SDavid Chinner 21198d280b98SDavid Chinner STATIC void 21208d280b98SDavid Chinner xfs_icsb_count( 21218d280b98SDavid Chinner xfs_mount_t *mp, 21228d280b98SDavid Chinner xfs_icsb_cnts_t *cnt, 21238d280b98SDavid Chinner int flags) 21248d280b98SDavid Chinner { 21258d280b98SDavid Chinner xfs_icsb_cnts_t *cntp; 21268d280b98SDavid Chinner int i; 21278d280b98SDavid Chinner 21288d280b98SDavid Chinner memset(cnt, 0, sizeof(xfs_icsb_cnts_t)); 21298d280b98SDavid Chinner 21308d280b98SDavid Chinner if (!(flags & XFS_ICSB_LAZY_COUNT)) 21318d280b98SDavid Chinner xfs_icsb_lock_all_counters(mp); 21328d280b98SDavid Chinner 21338d280b98SDavid Chinner for_each_online_cpu(i) { 21348d280b98SDavid Chinner cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i); 21358d280b98SDavid Chinner cnt->icsb_icount += cntp->icsb_icount; 21368d280b98SDavid Chinner cnt->icsb_ifree += cntp->icsb_ifree; 21378d280b98SDavid Chinner cnt->icsb_fdblocks += cntp->icsb_fdblocks; 21388d280b98SDavid Chinner } 21398d280b98SDavid Chinner 21408d280b98SDavid Chinner if (!(flags & XFS_ICSB_LAZY_COUNT)) 21418d280b98SDavid Chinner xfs_icsb_unlock_all_counters(mp); 21428d280b98SDavid Chinner } 21438d280b98SDavid Chinner 21448d280b98SDavid Chinner STATIC int 21458d280b98SDavid Chinner xfs_icsb_counter_disabled( 21468d280b98SDavid Chinner xfs_mount_t *mp, 21478d280b98SDavid Chinner xfs_sb_field_t field) 21488d280b98SDavid Chinner { 21498d280b98SDavid Chinner ASSERT((field >= XFS_SBS_ICOUNT) && (field <= XFS_SBS_FDBLOCKS)); 21508d280b98SDavid Chinner return test_bit(field, &mp->m_icsb_counters); 21518d280b98SDavid Chinner } 21528d280b98SDavid Chinner 215336fbe6e6SDavid Chinner STATIC void 21548d280b98SDavid Chinner xfs_icsb_disable_counter( 21558d280b98SDavid Chinner xfs_mount_t *mp, 21568d280b98SDavid Chinner xfs_sb_field_t field) 21578d280b98SDavid Chinner { 21588d280b98SDavid Chinner xfs_icsb_cnts_t cnt; 21598d280b98SDavid Chinner 21608d280b98SDavid Chinner ASSERT((field >= XFS_SBS_ICOUNT) && (field <= XFS_SBS_FDBLOCKS)); 21618d280b98SDavid Chinner 216220b64285SDavid Chinner /* 216320b64285SDavid Chinner * If we are already disabled, then there is nothing to do 216420b64285SDavid Chinner * here. We check before locking all the counters to avoid 216520b64285SDavid Chinner * the expensive lock operation when being called in the 216620b64285SDavid Chinner * slow path and the counter is already disabled. This is 216720b64285SDavid Chinner * safe because the only time we set or clear this state is under 216820b64285SDavid Chinner * the m_icsb_mutex. 216920b64285SDavid Chinner */ 217020b64285SDavid Chinner if (xfs_icsb_counter_disabled(mp, field)) 217136fbe6e6SDavid Chinner return; 217220b64285SDavid Chinner 21738d280b98SDavid Chinner xfs_icsb_lock_all_counters(mp); 21748d280b98SDavid Chinner if (!test_and_set_bit(field, &mp->m_icsb_counters)) { 21758d280b98SDavid Chinner /* drain back to superblock */ 21768d280b98SDavid Chinner 2177ce46193bSChristoph Hellwig xfs_icsb_count(mp, &cnt, XFS_ICSB_LAZY_COUNT); 21788d280b98SDavid Chinner switch(field) { 21798d280b98SDavid Chinner case XFS_SBS_ICOUNT: 21808d280b98SDavid Chinner mp->m_sb.sb_icount = cnt.icsb_icount; 21818d280b98SDavid Chinner break; 21828d280b98SDavid Chinner case XFS_SBS_IFREE: 21838d280b98SDavid Chinner mp->m_sb.sb_ifree = cnt.icsb_ifree; 21848d280b98SDavid Chinner break; 21858d280b98SDavid Chinner case XFS_SBS_FDBLOCKS: 21868d280b98SDavid Chinner mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks; 21878d280b98SDavid Chinner break; 21888d280b98SDavid Chinner default: 21898d280b98SDavid Chinner BUG(); 21908d280b98SDavid Chinner } 21918d280b98SDavid Chinner } 21928d280b98SDavid Chinner 21938d280b98SDavid Chinner xfs_icsb_unlock_all_counters(mp); 21948d280b98SDavid Chinner } 21958d280b98SDavid Chinner 21968d280b98SDavid Chinner STATIC void 21978d280b98SDavid Chinner xfs_icsb_enable_counter( 21988d280b98SDavid Chinner xfs_mount_t *mp, 21998d280b98SDavid Chinner xfs_sb_field_t field, 22008d280b98SDavid Chinner uint64_t count, 22018d280b98SDavid Chinner uint64_t resid) 22028d280b98SDavid Chinner { 22038d280b98SDavid Chinner xfs_icsb_cnts_t *cntp; 22048d280b98SDavid Chinner int i; 22058d280b98SDavid Chinner 22068d280b98SDavid Chinner ASSERT((field >= XFS_SBS_ICOUNT) && (field <= XFS_SBS_FDBLOCKS)); 22078d280b98SDavid Chinner 22088d280b98SDavid Chinner xfs_icsb_lock_all_counters(mp); 22098d280b98SDavid Chinner for_each_online_cpu(i) { 22108d280b98SDavid Chinner cntp = per_cpu_ptr(mp->m_sb_cnts, i); 22118d280b98SDavid Chinner switch (field) { 22128d280b98SDavid Chinner case XFS_SBS_ICOUNT: 22138d280b98SDavid Chinner cntp->icsb_icount = count + resid; 22148d280b98SDavid Chinner break; 22158d280b98SDavid Chinner case XFS_SBS_IFREE: 22168d280b98SDavid Chinner cntp->icsb_ifree = count + resid; 22178d280b98SDavid Chinner break; 22188d280b98SDavid Chinner case XFS_SBS_FDBLOCKS: 22198d280b98SDavid Chinner cntp->icsb_fdblocks = count + resid; 22208d280b98SDavid Chinner break; 22218d280b98SDavid Chinner default: 22228d280b98SDavid Chinner BUG(); 22238d280b98SDavid Chinner break; 22248d280b98SDavid Chinner } 22258d280b98SDavid Chinner resid = 0; 22268d280b98SDavid Chinner } 22278d280b98SDavid Chinner clear_bit(field, &mp->m_icsb_counters); 22288d280b98SDavid Chinner xfs_icsb_unlock_all_counters(mp); 22298d280b98SDavid Chinner } 22308d280b98SDavid Chinner 2231dbcabad1SDavid Chinner void 2232d4d90b57SChristoph Hellwig xfs_icsb_sync_counters_locked( 22338d280b98SDavid Chinner xfs_mount_t *mp, 22348d280b98SDavid Chinner int flags) 22358d280b98SDavid Chinner { 22368d280b98SDavid Chinner xfs_icsb_cnts_t cnt; 22378d280b98SDavid Chinner 22388d280b98SDavid Chinner xfs_icsb_count(mp, &cnt, flags); 22398d280b98SDavid Chinner 22408d280b98SDavid Chinner if (!xfs_icsb_counter_disabled(mp, XFS_SBS_ICOUNT)) 22418d280b98SDavid Chinner mp->m_sb.sb_icount = cnt.icsb_icount; 22428d280b98SDavid Chinner if (!xfs_icsb_counter_disabled(mp, XFS_SBS_IFREE)) 22438d280b98SDavid Chinner mp->m_sb.sb_ifree = cnt.icsb_ifree; 22448d280b98SDavid Chinner if (!xfs_icsb_counter_disabled(mp, XFS_SBS_FDBLOCKS)) 22458d280b98SDavid Chinner mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks; 22468d280b98SDavid Chinner } 22478d280b98SDavid Chinner 22488d280b98SDavid Chinner /* 22498d280b98SDavid Chinner * Accurate update of per-cpu counters to incore superblock 22508d280b98SDavid Chinner */ 2251d4d90b57SChristoph Hellwig void 22528d280b98SDavid Chinner xfs_icsb_sync_counters( 2253d4d90b57SChristoph Hellwig xfs_mount_t *mp, 2254d4d90b57SChristoph Hellwig int flags) 22558d280b98SDavid Chinner { 2256d4d90b57SChristoph Hellwig spin_lock(&mp->m_sb_lock); 2257d4d90b57SChristoph Hellwig xfs_icsb_sync_counters_locked(mp, flags); 2258d4d90b57SChristoph Hellwig spin_unlock(&mp->m_sb_lock); 22598d280b98SDavid Chinner } 22608d280b98SDavid Chinner 22618d280b98SDavid Chinner /* 22628d280b98SDavid Chinner * Balance and enable/disable counters as necessary. 22638d280b98SDavid Chinner * 226420b64285SDavid Chinner * Thresholds for re-enabling counters are somewhat magic. inode counts are 226520b64285SDavid Chinner * chosen to be the same number as single on disk allocation chunk per CPU, and 226620b64285SDavid Chinner * free blocks is something far enough zero that we aren't going thrash when we 226720b64285SDavid Chinner * get near ENOSPC. We also need to supply a minimum we require per cpu to 226820b64285SDavid Chinner * prevent looping endlessly when xfs_alloc_space asks for more than will 226920b64285SDavid Chinner * be distributed to a single CPU but each CPU has enough blocks to be 227020b64285SDavid Chinner * reenabled. 227120b64285SDavid Chinner * 227220b64285SDavid Chinner * Note that we can be called when counters are already disabled. 227320b64285SDavid Chinner * xfs_icsb_disable_counter() optimises the counter locking in this case to 227420b64285SDavid Chinner * prevent locking every per-cpu counter needlessly. 22758d280b98SDavid Chinner */ 227620b64285SDavid Chinner 227720b64285SDavid Chinner #define XFS_ICSB_INO_CNTR_REENABLE (uint64_t)64 22784be536deSDavid Chinner #define XFS_ICSB_FDBLK_CNTR_REENABLE(mp) \ 227920b64285SDavid Chinner (uint64_t)(512 + XFS_ALLOC_SET_ASIDE(mp)) 22808d280b98SDavid Chinner STATIC void 228145af6c6dSChristoph Hellwig xfs_icsb_balance_counter_locked( 22828d280b98SDavid Chinner xfs_mount_t *mp, 22838d280b98SDavid Chinner xfs_sb_field_t field, 228420b64285SDavid Chinner int min_per_cpu) 22858d280b98SDavid Chinner { 22866fdf8cccSNathan Scott uint64_t count, resid; 22878d280b98SDavid Chinner int weight = num_online_cpus(); 228820b64285SDavid Chinner uint64_t min = (uint64_t)min_per_cpu; 22898d280b98SDavid Chinner 22908d280b98SDavid Chinner /* disable counter and sync counter */ 22918d280b98SDavid Chinner xfs_icsb_disable_counter(mp, field); 22928d280b98SDavid Chinner 22938d280b98SDavid Chinner /* update counters - first CPU gets residual*/ 22948d280b98SDavid Chinner switch (field) { 22958d280b98SDavid Chinner case XFS_SBS_ICOUNT: 22968d280b98SDavid Chinner count = mp->m_sb.sb_icount; 22978d280b98SDavid Chinner resid = do_div(count, weight); 229820b64285SDavid Chinner if (count < max(min, XFS_ICSB_INO_CNTR_REENABLE)) 229945af6c6dSChristoph Hellwig return; 23008d280b98SDavid Chinner break; 23018d280b98SDavid Chinner case XFS_SBS_IFREE: 23028d280b98SDavid Chinner count = mp->m_sb.sb_ifree; 23038d280b98SDavid Chinner resid = do_div(count, weight); 230420b64285SDavid Chinner if (count < max(min, XFS_ICSB_INO_CNTR_REENABLE)) 230545af6c6dSChristoph Hellwig return; 23068d280b98SDavid Chinner break; 23078d280b98SDavid Chinner case XFS_SBS_FDBLOCKS: 23088d280b98SDavid Chinner count = mp->m_sb.sb_fdblocks; 23098d280b98SDavid Chinner resid = do_div(count, weight); 231020b64285SDavid Chinner if (count < max(min, XFS_ICSB_FDBLK_CNTR_REENABLE(mp))) 231145af6c6dSChristoph Hellwig return; 23128d280b98SDavid Chinner break; 23138d280b98SDavid Chinner default: 23148d280b98SDavid Chinner BUG(); 23156fdf8cccSNathan Scott count = resid = 0; /* quiet, gcc */ 23168d280b98SDavid Chinner break; 23178d280b98SDavid Chinner } 23188d280b98SDavid Chinner 23198d280b98SDavid Chinner xfs_icsb_enable_counter(mp, field, count, resid); 232045af6c6dSChristoph Hellwig } 232145af6c6dSChristoph Hellwig 232245af6c6dSChristoph Hellwig STATIC void 232345af6c6dSChristoph Hellwig xfs_icsb_balance_counter( 232445af6c6dSChristoph Hellwig xfs_mount_t *mp, 232545af6c6dSChristoph Hellwig xfs_sb_field_t fields, 232645af6c6dSChristoph Hellwig int min_per_cpu) 232745af6c6dSChristoph Hellwig { 232845af6c6dSChristoph Hellwig spin_lock(&mp->m_sb_lock); 232945af6c6dSChristoph Hellwig xfs_icsb_balance_counter_locked(mp, fields, min_per_cpu); 23303685c2a1SEric Sandeen spin_unlock(&mp->m_sb_lock); 23318d280b98SDavid Chinner } 23328d280b98SDavid Chinner 2333a8272ce0SDavid Chinner STATIC int 233420b64285SDavid Chinner xfs_icsb_modify_counters( 23358d280b98SDavid Chinner xfs_mount_t *mp, 23368d280b98SDavid Chinner xfs_sb_field_t field, 233720f4ebf2SDavid Chinner int64_t delta, 233820b64285SDavid Chinner int rsvd) 23398d280b98SDavid Chinner { 23408d280b98SDavid Chinner xfs_icsb_cnts_t *icsbp; 23418d280b98SDavid Chinner long long lcounter; /* long counter for 64 bit fields */ 2342007c61c6SEric Sandeen int cpu, ret = 0; 23438d280b98SDavid Chinner 234420b64285SDavid Chinner might_sleep(); 23458d280b98SDavid Chinner again: 23468d280b98SDavid Chinner cpu = get_cpu(); 234720b64285SDavid Chinner icsbp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, cpu); 234820b64285SDavid Chinner 234920b64285SDavid Chinner /* 235020b64285SDavid Chinner * if the counter is disabled, go to slow path 235120b64285SDavid Chinner */ 23528d280b98SDavid Chinner if (unlikely(xfs_icsb_counter_disabled(mp, field))) 23538d280b98SDavid Chinner goto slow_path; 235420b64285SDavid Chinner xfs_icsb_lock_cntr(icsbp); 235520b64285SDavid Chinner if (unlikely(xfs_icsb_counter_disabled(mp, field))) { 235620b64285SDavid Chinner xfs_icsb_unlock_cntr(icsbp); 235720b64285SDavid Chinner goto slow_path; 235820b64285SDavid Chinner } 23598d280b98SDavid Chinner 23608d280b98SDavid Chinner switch (field) { 23618d280b98SDavid Chinner case XFS_SBS_ICOUNT: 23628d280b98SDavid Chinner lcounter = icsbp->icsb_icount; 23638d280b98SDavid Chinner lcounter += delta; 23648d280b98SDavid Chinner if (unlikely(lcounter < 0)) 236520b64285SDavid Chinner goto balance_counter; 23668d280b98SDavid Chinner icsbp->icsb_icount = lcounter; 23678d280b98SDavid Chinner break; 23688d280b98SDavid Chinner 23698d280b98SDavid Chinner case XFS_SBS_IFREE: 23708d280b98SDavid Chinner lcounter = icsbp->icsb_ifree; 23718d280b98SDavid Chinner lcounter += delta; 23728d280b98SDavid Chinner if (unlikely(lcounter < 0)) 237320b64285SDavid Chinner goto balance_counter; 23748d280b98SDavid Chinner icsbp->icsb_ifree = lcounter; 23758d280b98SDavid Chinner break; 23768d280b98SDavid Chinner 23778d280b98SDavid Chinner case XFS_SBS_FDBLOCKS: 23788d280b98SDavid Chinner BUG_ON((mp->m_resblks - mp->m_resblks_avail) != 0); 23798d280b98SDavid Chinner 23804be536deSDavid Chinner lcounter = icsbp->icsb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); 23818d280b98SDavid Chinner lcounter += delta; 23828d280b98SDavid Chinner if (unlikely(lcounter < 0)) 238320b64285SDavid Chinner goto balance_counter; 23844be536deSDavid Chinner icsbp->icsb_fdblocks = lcounter + XFS_ALLOC_SET_ASIDE(mp); 23858d280b98SDavid Chinner break; 23868d280b98SDavid Chinner default: 23878d280b98SDavid Chinner BUG(); 23888d280b98SDavid Chinner break; 23898d280b98SDavid Chinner } 239001e1b69cSDavid Chinner xfs_icsb_unlock_cntr(icsbp); 23918d280b98SDavid Chinner put_cpu(); 23928d280b98SDavid Chinner return 0; 23938d280b98SDavid Chinner 23948d280b98SDavid Chinner slow_path: 239520b64285SDavid Chinner put_cpu(); 239620b64285SDavid Chinner 239720b64285SDavid Chinner /* 239820b64285SDavid Chinner * serialise with a mutex so we don't burn lots of cpu on 239920b64285SDavid Chinner * the superblock lock. We still need to hold the superblock 240020b64285SDavid Chinner * lock, however, when we modify the global structures. 240120b64285SDavid Chinner */ 240203135cf7SDavid Chinner xfs_icsb_lock(mp); 240320b64285SDavid Chinner 240420b64285SDavid Chinner /* 240520b64285SDavid Chinner * Now running atomically. 240620b64285SDavid Chinner * 240720b64285SDavid Chinner * If the counter is enabled, someone has beaten us to rebalancing. 240820b64285SDavid Chinner * Drop the lock and try again in the fast path.... 240920b64285SDavid Chinner */ 241020b64285SDavid Chinner if (!(xfs_icsb_counter_disabled(mp, field))) { 241103135cf7SDavid Chinner xfs_icsb_unlock(mp); 241220b64285SDavid Chinner goto again; 241320b64285SDavid Chinner } 241420b64285SDavid Chinner 241520b64285SDavid Chinner /* 241620b64285SDavid Chinner * The counter is currently disabled. Because we are 241720b64285SDavid Chinner * running atomically here, we know a rebalance cannot 241820b64285SDavid Chinner * be in progress. Hence we can go straight to operating 241920b64285SDavid Chinner * on the global superblock. We do not call xfs_mod_incore_sb() 24203685c2a1SEric Sandeen * here even though we need to get the m_sb_lock. Doing so 242120b64285SDavid Chinner * will cause us to re-enter this function and deadlock. 24223685c2a1SEric Sandeen * Hence we get the m_sb_lock ourselves and then call 242320b64285SDavid Chinner * xfs_mod_incore_sb_unlocked() as the unlocked path operates 242420b64285SDavid Chinner * directly on the global counters. 242520b64285SDavid Chinner */ 24263685c2a1SEric Sandeen spin_lock(&mp->m_sb_lock); 242720b64285SDavid Chinner ret = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd); 24283685c2a1SEric Sandeen spin_unlock(&mp->m_sb_lock); 242920b64285SDavid Chinner 243020b64285SDavid Chinner /* 243120b64285SDavid Chinner * Now that we've modified the global superblock, we 243220b64285SDavid Chinner * may be able to re-enable the distributed counters 243320b64285SDavid Chinner * (e.g. lots of space just got freed). After that 243420b64285SDavid Chinner * we are done. 243520b64285SDavid Chinner */ 243620b64285SDavid Chinner if (ret != ENOSPC) 243745af6c6dSChristoph Hellwig xfs_icsb_balance_counter(mp, field, 0); 243803135cf7SDavid Chinner xfs_icsb_unlock(mp); 243920b64285SDavid Chinner return ret; 244020b64285SDavid Chinner 244120b64285SDavid Chinner balance_counter: 244201e1b69cSDavid Chinner xfs_icsb_unlock_cntr(icsbp); 24438d280b98SDavid Chinner put_cpu(); 24448d280b98SDavid Chinner 244520b64285SDavid Chinner /* 244620b64285SDavid Chinner * We may have multiple threads here if multiple per-cpu 244720b64285SDavid Chinner * counters run dry at the same time. This will mean we can 244820b64285SDavid Chinner * do more balances than strictly necessary but it is not 244920b64285SDavid Chinner * the common slowpath case. 245020b64285SDavid Chinner */ 245103135cf7SDavid Chinner xfs_icsb_lock(mp); 245220b64285SDavid Chinner 245320b64285SDavid Chinner /* 245420b64285SDavid Chinner * running atomically. 245520b64285SDavid Chinner * 245620b64285SDavid Chinner * This will leave the counter in the correct state for future 245720b64285SDavid Chinner * accesses. After the rebalance, we simply try again and our retry 245820b64285SDavid Chinner * will either succeed through the fast path or slow path without 245920b64285SDavid Chinner * another balance operation being required. 246020b64285SDavid Chinner */ 246145af6c6dSChristoph Hellwig xfs_icsb_balance_counter(mp, field, delta); 246203135cf7SDavid Chinner xfs_icsb_unlock(mp); 24638d280b98SDavid Chinner goto again; 24648d280b98SDavid Chinner } 24658d280b98SDavid Chinner 24668d280b98SDavid Chinner #endif 2467