xfs_mount.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,582 行 · 第 1/3 页
C
1,582 行
/* * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 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. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like. Any license provided herein, whether implied or * otherwise, applies only to this software file. Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU General Public License along * with this program; if not, write the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston MA 02111-1307, USA. * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA 94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */#include "xfs.h"#include "xfs_macros.h"#include "xfs_types.h"#include "xfs_inum.h"#include "xfs_log.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir.h"#include "xfs_dir2.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_alloc_btree.h"#include "xfs_bmap_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_btree.h"#include "xfs_ialloc.h"#include "xfs_attr_sf.h"#include "xfs_dir_sf.h"#include "xfs_dir2_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_alloc.h"#include "xfs_rtalloc.h"#include "xfs_bmap.h"#include "xfs_error.h"#include "xfs_bit.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);void xfs_xlatesb(void *, xfs_sb_t *, int, xfs_arch_t, __int64_t);static 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(*mp), KM_SLEEP); AIL_LOCKINIT(&mp->m_ail_lock, "xfs_ail"); spinlock_init(&mp->m_sb_lock, "xfs_sb"); mutex_init(&mp->m_ilock, MUTEX_DEFAULT, "xfs_ilock"); initnsema(&mp->m_growlock, 1, "xfs_grow"); /* * 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, int remove_bhv){ if (mp->m_ihash) xfs_ihash_free(mp); if (mp->m_chash) xfs_chash_free(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); freesema(&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 (remove_bhv) { struct vfs *vfsp = XFS_MTOVFS(mp); bhv_remove_all_vfsops(vfsp, 0); VFS_REMOVEBHV(vfsp, &mp->m_bhv); } kmem_free(mp, sizeof(xfs_mount_t));}/* * Check the validity of the SB found. */STATIC intxfs_mount_validate_sb( xfs_mount_t *mp, xfs_sb_t *sbp){ /* * 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) { cmn_err(CE_WARN, "XFS: bad magic number"); return XFS_ERROR(EWRONGFS); } if (!XFS_SB_GOOD_VERSION(sbp)) { cmn_err(CE_WARN, "XFS: bad version"); return XFS_ERROR(EWRONGFS); } if (unlikely( sbp->sb_logstart == 0 && mp->m_logdev_targp == mp->m_ddev_targp)) { cmn_err(CE_WARN, "XFS: filesystem is marked as having an external log; " "specify logdev on the\nmount command line."); XFS_CORRUPTION_ERROR("xfs_mount_validate_sb(1)", XFS_ERRLEVEL_HIGH, mp, sbp); return XFS_ERROR(EFSCORRUPTED); } if (unlikely( sbp->sb_logstart != 0 && mp->m_logdev_targp != mp->m_ddev_targp)) { cmn_err(CE_WARN, "XFS: filesystem is marked as having an internal log; " "don't specify logdev on\nthe mount command line."); XFS_CORRUPTION_ERROR("xfs_mount_validate_sb(2)", XFS_ERRLEVEL_HIGH, mp, sbp); return XFS_ERROR(EFSCORRUPTED); } /* * 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_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) || sbp->sb_imax_pct > 100)) { cmn_err(CE_WARN, "XFS: SB sanity check 1 failed"); XFS_CORRUPTION_ERROR("xfs_mount_validate_sb(3)", XFS_ERRLEVEL_LOW, mp, sbp); 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)) { cmn_err(CE_WARN, "XFS: SB sanity check 2 failed"); XFS_ERROR_REPORT("xfs_mount_validate_sb(4)", XFS_ERRLEVEL_LOW, mp); return XFS_ERROR(EFSCORRUPTED); } ASSERT(PAGE_SHIFT >= sbp->sb_blocklog); ASSERT(sbp->sb_blocklog >= BBSHIFT);#if XFS_BIG_BLKNOS /* Limited by ULONG_MAX of page cache index */ if (unlikely( (sbp->sb_dblocks >> (PAGE_SHIFT - sbp->sb_blocklog)) > ULONG_MAX || (sbp->sb_rblocks >> (PAGE_SHIFT - sbp->sb_blocklog)) > ULONG_MAX)) {#else /* Limited by UINT_MAX of sectors */ if (unlikely( (sbp->sb_dblocks << (sbp->sb_blocklog - BBSHIFT)) > UINT_MAX || (sbp->sb_rblocks << (sbp->sb_blocklog - BBSHIFT)) > UINT_MAX)) {#endif cmn_err(CE_WARN, "XFS: File system is too large to be mounted on this system."); return XFS_ERROR(E2BIG); } if (unlikely(sbp->sb_inprogress)) { cmn_err(CE_WARN, "XFS: file system busy"); XFS_ERROR_REPORT("xfs_mount_validate_sb(5)", XFS_ERRLEVEL_LOW, mp); return XFS_ERROR(EFSCORRUPTED); } /* * Until this is fixed only page-sized or smaller data blocks work. */ if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) { cmn_err(CE_WARN, "XFS: Attempted to mount file system with blocksize %d bytes", sbp->sb_blocksize); cmn_err(CE_WARN, "XFS: Only page-sized (%d) or less blocksizes currently work.", PAGE_SIZE); return XFS_ERROR(ENOSYS); } return 0;}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_32BITINOOPT) && 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, mp->m_ialloc_blks); 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 prefered for inodes */ pag = &mp->m_perag[index]; pag->pagi_inodeok = 1; if (index < max_metadata) pag->pagf_metadata = 1; } } else { /* Setup default behavior for smaller filesystems */ for (index = 0; index < agcount; index++) { pag = &mp->m_perag[index]; pag->pagi_inodeok = 1; } } return index;}/* * xfs_xlatesb * * data - on disk version of sb * sb - a superblock * dir - conversion direction: <0 - convert sb to buf * >0 - convert buf to sb * arch - architecture to read/write from/to buf * fields - which fields to copy (bitmask) */voidxfs_xlatesb( void *data, xfs_sb_t *sb, int dir, xfs_arch_t arch, __int64_t fields){ xfs_caddr_t buf_ptr; xfs_caddr_t mem_ptr; xfs_sb_field_t f; int first; int size; ASSERT(dir); ASSERT(fields); if (!fields) return; buf_ptr = (xfs_caddr_t)data; mem_ptr = (xfs_caddr_t)sb; 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); if (arch == ARCH_NOCONVERT || size == 1 || xfs_sb_info[f].type == 1) { if (dir > 0) { memcpy(mem_ptr + first, buf_ptr + first, size); } else { memcpy(buf_ptr + first, mem_ptr + first, size); } } else { switch (size) { case 2: INT_XLATE(*(__uint16_t*)(buf_ptr+first), *(__uint16_t*)(mem_ptr+first), dir, arch); break; case 4: INT_XLATE(*(__uint32_t*)(buf_ptr+first), *(__uint32_t*)(mem_ptr+first), dir, arch); break; case 8: INT_XLATE(*(__uint64_t*)(buf_ptr+first), *(__uint64_t*)(mem_ptr+first), dir, arch); break; default: ASSERT(0); } } fields &= ~(1LL << f); }}/* * xfs_readsb * * Does the initial read of the superblock. */intxfs_readsb(xfs_mount_t *mp){ unsigned int sector_size; unsigned int extra_flags; xfs_buf_t *bp; xfs_sb_t *sbp; int error; ASSERT(mp->m_sb_bp == NULL); ASSERT(mp->m_ddev_targp != NULL); /* * Allocate a (locked) buffer to hold the superblock. * This will be kept around at all times to optimize * access to the superblock. */ sector_size = xfs_getsize_buftarg(mp->m_ddev_targp); extra_flags = XFS_BUF_LOCK | XFS_BUF_MANAGE | XFS_BUF_MAPPED; bp = xfs_buf_read_flags(mp->m_ddev_targp, XFS_SB_DADDR, BTOBB(sector_size), extra_flags); if (!bp || XFS_BUF_ISERROR(bp)) { cmn_err(CE_WARN, "XFS: SB read failed"); error = bp ? XFS_BUF_GETERROR(bp) : ENOMEM; goto fail; } ASSERT(XFS_BUF_ISBUSY(bp)); ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); /* * Initialize the mount structure from the superblock. * But first do some basic consistency checking. */ sbp = XFS_BUF_TO_SBP(bp); xfs_xlatesb(XFS_BUF_PTR(bp), &(mp->m_sb), 1, ARCH_CONVERT, XFS_SB_ALL_BITS); error = xfs_mount_validate_sb(mp, &(mp->m_sb)); if (error) { cmn_err(CE_WARN, "XFS: SB validate failed"); goto fail; } /* * We must be able to do sector-sized and sector-aligned IO. */ if (sector_size > mp->m_sb.sb_sectsize) { cmn_err(CE_WARN, "XFS: device supports only %u byte sectors (not %u)", sector_size, mp->m_sb.sb_sectsize); error = ENOSYS; goto fail; } /* * If device sector size is smaller than the superblock size, * re-read the superblock so the buffer is correctly sized. */ if (sector_size < mp->m_sb.sb_sectsize) { XFS_BUF_UNMANAGE(bp); xfs_buf_relse(bp); sector_size = mp->m_sb.sb_sectsize; bp = xfs_buf_read_flags(mp->m_ddev_targp, XFS_SB_DADDR, BTOBB(sector_size), extra_flags); if (!bp || XFS_BUF_ISERROR(bp)) { cmn_err(CE_WARN, "XFS: SB re-read failed"); error = bp ? XFS_BUF_GETERROR(bp) : ENOMEM;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?