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 + -
显示快捷键?