📄 xfs_mount.c
字号:
/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */#include "xfs.h"#include "xfs_fs.h"#include "xfs_types.h"#include "xfs_bit.h"#include "xfs_log.h"#include "xfs_inum.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir2.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_bmap_btree.h"#include "xfs_alloc_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_dir2_sf.h"#include "xfs_attr_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_btree.h"#include "xfs_ialloc.h"#include "xfs_alloc.h"#include "xfs_rtalloc.h"#include "xfs_bmap.h"#include "xfs_error.h"#include "xfs_rw.h"#include "xfs_quota.h"#include "xfs_fsops.h"STATIC void xfs_mount_log_sbunit(xfs_mount_t *, __int64_t);STATIC int xfs_uuid_mount(xfs_mount_t *);STATIC void xfs_uuid_unmount(xfs_mount_t *mp);STATIC void xfs_unmountfs_wait(xfs_mount_t *);#ifdef HAVE_PERCPU_SBSTATIC void xfs_icsb_destroy_counters(xfs_mount_t *);STATIC void xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t, int, int);STATIC void xfs_icsb_sync_counters(xfs_mount_t *);STATIC int xfs_icsb_modify_counters(xfs_mount_t *, xfs_sb_field_t, int64_t, int);STATIC int xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t);#else#define xfs_icsb_destroy_counters(mp) do { } while (0)#define xfs_icsb_balance_counter(mp, a, b, c) do { } while (0)#define xfs_icsb_sync_counters(mp) do { } while (0)#define xfs_icsb_modify_counters(mp, a, b, c) do { } while (0)#endifstatic const struct { short offset; short type; /* 0 = integer * 1 = binary / string (no translation) */} xfs_sb_info[] = { { offsetof(xfs_sb_t, sb_magicnum), 0 }, { offsetof(xfs_sb_t, sb_blocksize), 0 }, { offsetof(xfs_sb_t, sb_dblocks), 0 }, { offsetof(xfs_sb_t, sb_rblocks), 0 }, { offsetof(xfs_sb_t, sb_rextents), 0 }, { offsetof(xfs_sb_t, sb_uuid), 1 }, { offsetof(xfs_sb_t, sb_logstart), 0 }, { offsetof(xfs_sb_t, sb_rootino), 0 }, { offsetof(xfs_sb_t, sb_rbmino), 0 }, { offsetof(xfs_sb_t, sb_rsumino), 0 }, { offsetof(xfs_sb_t, sb_rextsize), 0 }, { offsetof(xfs_sb_t, sb_agblocks), 0 }, { offsetof(xfs_sb_t, sb_agcount), 0 }, { offsetof(xfs_sb_t, sb_rbmblocks), 0 }, { offsetof(xfs_sb_t, sb_logblocks), 0 }, { offsetof(xfs_sb_t, sb_versionnum), 0 }, { offsetof(xfs_sb_t, sb_sectsize), 0 }, { offsetof(xfs_sb_t, sb_inodesize), 0 }, { offsetof(xfs_sb_t, sb_inopblock), 0 }, { offsetof(xfs_sb_t, sb_fname[0]), 1 }, { offsetof(xfs_sb_t, sb_blocklog), 0 }, { offsetof(xfs_sb_t, sb_sectlog), 0 }, { offsetof(xfs_sb_t, sb_inodelog), 0 }, { offsetof(xfs_sb_t, sb_inopblog), 0 }, { offsetof(xfs_sb_t, sb_agblklog), 0 }, { offsetof(xfs_sb_t, sb_rextslog), 0 }, { offsetof(xfs_sb_t, sb_inprogress), 0 }, { offsetof(xfs_sb_t, sb_imax_pct), 0 }, { offsetof(xfs_sb_t, sb_icount), 0 }, { offsetof(xfs_sb_t, sb_ifree), 0 }, { offsetof(xfs_sb_t, sb_fdblocks), 0 }, { offsetof(xfs_sb_t, sb_frextents), 0 }, { offsetof(xfs_sb_t, sb_uquotino), 0 }, { offsetof(xfs_sb_t, sb_gquotino), 0 }, { offsetof(xfs_sb_t, sb_qflags), 0 }, { offsetof(xfs_sb_t, sb_flags), 0 }, { offsetof(xfs_sb_t, sb_shared_vn), 0 }, { offsetof(xfs_sb_t, sb_inoalignmt), 0 }, { offsetof(xfs_sb_t, sb_unit), 0 }, { offsetof(xfs_sb_t, sb_width), 0 }, { offsetof(xfs_sb_t, sb_dirblklog), 0 }, { offsetof(xfs_sb_t, sb_logsectlog), 0 }, { offsetof(xfs_sb_t, sb_logsectsize),0 }, { offsetof(xfs_sb_t, sb_logsunit), 0 }, { offsetof(xfs_sb_t, sb_features2), 0 }, { sizeof(xfs_sb_t), 0 }};/* * Return a pointer to an initialized xfs_mount structure. */xfs_mount_t *xfs_mount_init(void){ xfs_mount_t *mp; mp = kmem_zalloc(sizeof(xfs_mount_t), KM_SLEEP); if (xfs_icsb_init_counters(mp)) { mp->m_flags |= XFS_MOUNT_NO_PERCPU_SB; } AIL_LOCKINIT(&mp->m_ail_lock, "xfs_ail"); spinlock_init(&mp->m_sb_lock, "xfs_sb"); mutex_init(&mp->m_ilock); mutex_init(&mp->m_growlock); /* * Initialize the AIL. */ xfs_trans_ail_init(mp); atomic_set(&mp->m_active_trans, 0); return mp;}/* * Free up the resources associated with a mount structure. Assume that * the structure was initially zeroed, so we can tell which fields got * initialized. */voidxfs_mount_free( xfs_mount_t *mp){ if (mp->m_perag) { int agno; for (agno = 0; agno < mp->m_maxagi; agno++) if (mp->m_perag[agno].pagb_list) kmem_free(mp->m_perag[agno].pagb_list, sizeof(xfs_perag_busy_t) * XFS_PAGB_NUM_SLOTS); kmem_free(mp->m_perag, sizeof(xfs_perag_t) * mp->m_sb.sb_agcount); } AIL_LOCK_DESTROY(&mp->m_ail_lock); spinlock_destroy(&mp->m_sb_lock); mutex_destroy(&mp->m_ilock); mutex_destroy(&mp->m_growlock); if (mp->m_quotainfo) XFS_QM_DONE(mp); if (mp->m_fsname != NULL) kmem_free(mp->m_fsname, mp->m_fsname_len); if (mp->m_rtname != NULL) kmem_free(mp->m_rtname, strlen(mp->m_rtname) + 1); if (mp->m_logname != NULL) kmem_free(mp->m_logname, strlen(mp->m_logname) + 1); xfs_icsb_destroy_counters(mp);}/* * Check size of device based on the (data/realtime) block count. * Note: this check is used by the growfs code as well as mount. */intxfs_sb_validate_fsb_count( xfs_sb_t *sbp, __uint64_t nblocks){ ASSERT(PAGE_SHIFT >= sbp->sb_blocklog); ASSERT(sbp->sb_blocklog >= BBSHIFT);#if XFS_BIG_BLKNOS /* Limited by ULONG_MAX of page cache index */ if (nblocks >> (PAGE_CACHE_SHIFT - sbp->sb_blocklog) > ULONG_MAX) return E2BIG;#else /* Limited by UINT_MAX of sectors */ if (nblocks << (sbp->sb_blocklog - BBSHIFT) > UINT_MAX) return E2BIG;#endif return 0;}/* * Check the validity of the SB found. */STATIC intxfs_mount_validate_sb( xfs_mount_t *mp, xfs_sb_t *sbp, int flags){ /* * If the log device and data device have the * same device number, the log is internal. * Consequently, the sb_logstart should be non-zero. If * we have a zero sb_logstart in this case, we may be trying to mount * a volume filesystem in a non-volume manner. */ if (sbp->sb_magicnum != XFS_SB_MAGIC) { xfs_fs_mount_cmn_err(flags, "bad magic number"); return XFS_ERROR(EWRONGFS); } if (!XFS_SB_GOOD_VERSION(sbp)) { xfs_fs_mount_cmn_err(flags, "bad version"); return XFS_ERROR(EWRONGFS); } if (unlikely( sbp->sb_logstart == 0 && mp->m_logdev_targp == mp->m_ddev_targp)) { xfs_fs_mount_cmn_err(flags, "filesystem is marked as having an external log; " "specify logdev on the\nmount command line."); return XFS_ERROR(EINVAL); } if (unlikely( sbp->sb_logstart != 0 && mp->m_logdev_targp != mp->m_ddev_targp)) { xfs_fs_mount_cmn_err(flags, "filesystem is marked as having an internal log; " "do not specify logdev on\nthe mount command line."); return XFS_ERROR(EINVAL); } /* * More sanity checking. These were stolen directly from * xfs_repair. */ if (unlikely( sbp->sb_agcount <= 0 || sbp->sb_sectsize < XFS_MIN_SECTORSIZE || sbp->sb_sectsize > XFS_MAX_SECTORSIZE || sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG || sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG || sbp->sb_blocksize < XFS_MIN_BLOCKSIZE || sbp->sb_blocksize > XFS_MAX_BLOCKSIZE || sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || sbp->sb_inodesize < XFS_DINODE_MIN_SIZE || sbp->sb_inodesize > XFS_DINODE_MAX_SIZE || sbp->sb_inodelog < XFS_DINODE_MIN_LOG || sbp->sb_inodelog > XFS_DINODE_MAX_LOG || (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) || (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) || (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */))) { xfs_fs_mount_cmn_err(flags, "SB sanity check 1 failed"); return XFS_ERROR(EFSCORRUPTED); } /* * Sanity check AG count, size fields against data size field */ if (unlikely( sbp->sb_dblocks == 0 || sbp->sb_dblocks > (xfs_drfsbno_t)sbp->sb_agcount * sbp->sb_agblocks || sbp->sb_dblocks < (xfs_drfsbno_t)(sbp->sb_agcount - 1) * sbp->sb_agblocks + XFS_MIN_AG_BLOCKS)) { xfs_fs_mount_cmn_err(flags, "SB sanity check 2 failed"); return XFS_ERROR(EFSCORRUPTED); } if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) || xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) { xfs_fs_mount_cmn_err(flags, "file system too large to be mounted on this system."); return XFS_ERROR(E2BIG); } if (unlikely(sbp->sb_inprogress)) { xfs_fs_mount_cmn_err(flags, "file system busy"); return XFS_ERROR(EFSCORRUPTED); } /* * Version 1 directory format has never worked on Linux. */ if (unlikely(!XFS_SB_VERSION_HASDIRV2(sbp))) { xfs_fs_mount_cmn_err(flags, "file system using version 1 directory format"); return XFS_ERROR(ENOSYS); } /* * Until this is fixed only page-sized or smaller data blocks work. */ if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) { xfs_fs_mount_cmn_err(flags, "file system with blocksize %d bytes", sbp->sb_blocksize); xfs_fs_mount_cmn_err(flags, "only pagesize (%ld) or less will currently work.", PAGE_SIZE); return XFS_ERROR(ENOSYS); } return 0;}STATIC voidxfs_initialize_perag_icache( xfs_perag_t *pag){ if (!pag->pag_ici_init) { rwlock_init(&pag->pag_ici_lock); INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC); pag->pag_ici_init = 1; }}xfs_agnumber_txfs_initialize_perag( xfs_mount_t *mp, xfs_agnumber_t agcount){ xfs_agnumber_t index, max_metadata; xfs_perag_t *pag; xfs_agino_t agino; xfs_ino_t ino; xfs_sb_t *sbp = &mp->m_sb; xfs_ino_t max_inum = XFS_MAXINUMBER_32; /* Check to see if the filesystem can overflow 32 bit inodes */ agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0); ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino); /* Clear the mount flag if no inode can overflow 32 bits * on this filesystem, or if specifically requested.. */ if ((mp->m_flags & XFS_MOUNT_SMALL_INUMS) && ino > max_inum) { mp->m_flags |= XFS_MOUNT_32BITINODES; } else { mp->m_flags &= ~XFS_MOUNT_32BITINODES; } /* If we can overflow then setup the ag headers accordingly */ if (mp->m_flags & XFS_MOUNT_32BITINODES) { /* Calculate how much should be reserved for inodes to * meet the max inode percentage. */ if (mp->m_maxicount) { __uint64_t icount; icount = sbp->sb_dblocks * sbp->sb_imax_pct; do_div(icount, 100); icount += sbp->sb_agblocks - 1; do_div(icount, sbp->sb_agblocks); max_metadata = icount; } else { max_metadata = agcount; } for (index = 0; index < agcount; index++) { ino = XFS_AGINO_TO_INO(mp, index, agino); if (ino > max_inum) { index++; break; } /* This ag is preferred for inodes */ pag = &mp->m_perag[index]; pag->pagi_inodeok = 1; if (index < max_metadata) pag->pagf_metadata = 1; xfs_initialize_perag_icache(pag); } } else { /* Setup default behavior for smaller filesystems */ for (index = 0; index < agcount; index++) { pag = &mp->m_perag[index]; pag->pagi_inodeok = 1; xfs_initialize_perag_icache(pag); } } return index;}voidxfs_sb_from_disk( xfs_sb_t *to, xfs_dsb_t *from){ to->sb_magicnum = be32_to_cpu(from->sb_magicnum); to->sb_blocksize = be32_to_cpu(from->sb_blocksize); to->sb_dblocks = be64_to_cpu(from->sb_dblocks); to->sb_rblocks = be64_to_cpu(from->sb_rblocks); to->sb_rextents = be64_to_cpu(from->sb_rextents); memcpy(&to->sb_uuid, &from->sb_uuid, sizeof(to->sb_uuid)); to->sb_logstart = be64_to_cpu(from->sb_logstart); to->sb_rootino = be64_to_cpu(from->sb_rootino); to->sb_rbmino = be64_to_cpu(from->sb_rbmino); to->sb_rsumino = be64_to_cpu(from->sb_rsumino); to->sb_rextsize = be32_to_cpu(from->sb_rextsize); to->sb_agblocks = be32_to_cpu(from->sb_agblocks); to->sb_agcount = be32_to_cpu(from->sb_agcount); to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks); to->sb_logblocks = be32_to_cpu(from->sb_logblocks); to->sb_versionnum = be16_to_cpu(from->sb_versionnum); to->sb_sectsize = be16_to_cpu(from->sb_sectsize); to->sb_inodesize = be16_to_cpu(from->sb_inodesize); to->sb_inopblock = be16_to_cpu(from->sb_inopblock); memcpy(&to->sb_fname, &from->sb_fname, sizeof(to->sb_fname)); to->sb_blocklog = from->sb_blocklog; to->sb_sectlog = from->sb_sectlog; to->sb_inodelog = from->sb_inodelog; to->sb_inopblog = from->sb_inopblog; to->sb_agblklog = from->sb_agblklog; to->sb_rextslog = from->sb_rextslog; to->sb_inprogress = from->sb_inprogress; to->sb_imax_pct = from->sb_imax_pct; to->sb_icount = be64_to_cpu(from->sb_icount); to->sb_ifree = be64_to_cpu(from->sb_ifree); to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks); to->sb_frextents = be64_to_cpu(from->sb_frextents); to->sb_uquotino = be64_to_cpu(from->sb_uquotino); to->sb_gquotino = be64_to_cpu(from->sb_gquotino); to->sb_qflags = be16_to_cpu(from->sb_qflags); to->sb_flags = from->sb_flags; to->sb_shared_vn = from->sb_shared_vn; to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt); to->sb_unit = be32_to_cpu(from->sb_unit); to->sb_width = be32_to_cpu(from->sb_width); to->sb_dirblklog = from->sb_dirblklog; to->sb_logsectlog = from->sb_logsectlog; to->sb_logsectsize = be16_to_cpu(from->sb_logsectsize); to->sb_logsunit = be32_to_cpu(from->sb_logsunit); to->sb_features2 = be32_to_cpu(from->sb_features2);}/* * Copy in core superblock to ondisk one. * * The fields argument is mask of superblock fields to copy. */voidxfs_sb_to_disk( xfs_dsb_t *to, xfs_sb_t *from, __int64_t fields){ xfs_caddr_t to_ptr = (xfs_caddr_t)to; xfs_caddr_t from_ptr = (xfs_caddr_t)from; xfs_sb_field_t f; int first; int size; ASSERT(fields); if (!fields) return; while (fields) { f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields); first = xfs_sb_info[f].offset; size = xfs_sb_info[f + 1].offset - first; ASSERT(xfs_sb_info[f].type == 0 || xfs_sb_info[f].type == 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -