xfs_mount.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,582 行 · 第 1/3 页

C
1,582
字号
			goto fail;		}		ASSERT(XFS_BUF_ISBUSY(bp));		ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);	}	mp->m_sb_bp = bp;	xfs_buf_relse(bp);	ASSERT(XFS_BUF_VALUSEMA(bp) > 0);	return 0; fail:	if (bp) {		XFS_BUF_UNMANAGE(bp);		xfs_buf_relse(bp);	}	return error;}/* * xfs_mount_common * * Mount initialization code establishing various mount * fields from the superblock associated with the given * mount structure */voidxfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp){	int	i;	mp->m_agfrotor = mp->m_agirotor = 0;	spinlock_init(&mp->m_agirotor_lock, "m_agirotor_lock");	mp->m_maxagi = mp->m_sb.sb_agcount;	mp->m_blkbit_log = sbp->sb_blocklog + XFS_NBBYLOG;	mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT;	mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT;	mp->m_agno_log = xfs_highbit32(sbp->sb_agcount - 1) + 1;	mp->m_agino_log = sbp->sb_inopblog + sbp->sb_agblklog;	mp->m_litino = sbp->sb_inodesize -		((uint)sizeof(xfs_dinode_core_t) + (uint)sizeof(xfs_agino_t));	mp->m_blockmask = sbp->sb_blocksize - 1;	mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG;	mp->m_blockwmask = mp->m_blockwsize - 1;	INIT_LIST_HEAD(&mp->m_del_inodes);	/*	 * Setup for attributes, in case they get created.	 * This value is for inodes getting attributes for the first time,	 * the per-inode value is for old attribute values.	 */	ASSERT(sbp->sb_inodesize >= 256 && sbp->sb_inodesize <= 2048);	switch (sbp->sb_inodesize) {	case 256:		mp->m_attroffset = XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(2);		break;	case 512:	case 1024:	case 2048:		mp->m_attroffset = XFS_BMDR_SPACE_CALC(12);		break;	default:		ASSERT(0);	}	ASSERT(mp->m_attroffset < XFS_LITINO(mp));	for (i = 0; i < 2; i++) {		mp->m_alloc_mxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize,			xfs_alloc, i == 0);		mp->m_alloc_mnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize,			xfs_alloc, i == 0);	}	for (i = 0; i < 2; i++) {		mp->m_bmap_dmxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize,			xfs_bmbt, i == 0);		mp->m_bmap_dmnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize,			xfs_bmbt, i == 0);	}	for (i = 0; i < 2; i++) {		mp->m_inobt_mxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize,			xfs_inobt, i == 0);		mp->m_inobt_mnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize,			xfs_inobt, i == 0);	}	mp->m_bsize = XFS_FSB_TO_BB(mp, 1);	mp->m_ialloc_inos = (int)MAX((__uint16_t)XFS_INODES_PER_CHUNK,					sbp->sb_inopblock);	mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog;}/* * xfs_mountfs * * This function does the following on an initial mount of a file system: *	- reads the superblock from disk and init the mount struct *	- if we're a 32-bit kernel, do a size check on the superblock *		so we don't mount terabyte filesystems *	- init mount struct realtime fields *	- allocate inode hash table for fs *	- init directory manager *	- perform recovery and init the log manager */intxfs_mountfs(	vfs_t		*vfsp,	xfs_mount_t	*mp,	int		mfsi_flags){	xfs_buf_t	*bp;	xfs_sb_t	*sbp = &(mp->m_sb);	xfs_inode_t	*rip;	vnode_t		*rvp = NULL;	int		readio_log, writeio_log;	xfs_daddr_t	d;	__uint64_t	ret64;	__int64_t	update_flags;	uint		quotamount, quotaflags;	int		agno;	int		uuid_mounted = 0;	int		error = 0;	if (mp->m_sb_bp == NULL) {		if ((error = xfs_readsb(mp))) {			return (error);		}	}	xfs_mount_common(mp, sbp);	/*	 * Check if sb_agblocks is aligned at stripe boundary	 * If sb_agblocks is NOT aligned turn off m_dalign since	 * allocator alignment is within an ag, therefore ag has	 * to be aligned at stripe boundary.	 */	update_flags = 0LL;	if (mp->m_dalign && !(mfsi_flags & XFS_MFSI_SECOND)) {		/*		 * If stripe unit and stripe width are not multiples		 * of the fs blocksize turn off alignment.		 */		if ((BBTOB(mp->m_dalign) & mp->m_blockmask) ||		    (BBTOB(mp->m_swidth) & mp->m_blockmask)) {			if (mp->m_flags & XFS_MOUNT_RETERR) {				cmn_err(CE_WARN,					"XFS: alignment check 1 failed");				error = XFS_ERROR(EINVAL);				goto error1;			}			mp->m_dalign = mp->m_swidth = 0;		} else {			/*			 * Convert the stripe unit and width to FSBs.			 */			mp->m_dalign = XFS_BB_TO_FSBT(mp, mp->m_dalign);			if (mp->m_dalign && (sbp->sb_agblocks % mp->m_dalign)) {				if (mp->m_flags & XFS_MOUNT_RETERR) {					error = XFS_ERROR(EINVAL);					goto error1;				}				xfs_fs_cmn_err(CE_WARN, mp,"stripe alignment turned off: sunit(%d)/swidth(%d) incompatible with agsize(%d)",					mp->m_dalign, mp->m_swidth,					sbp->sb_agblocks);				mp->m_dalign = 0;				mp->m_swidth = 0;			} else if (mp->m_dalign) {				mp->m_swidth = XFS_BB_TO_FSBT(mp, mp->m_swidth);			} else {				if (mp->m_flags & XFS_MOUNT_RETERR) {					xfs_fs_cmn_err(CE_WARN, mp,"stripe alignment turned off: sunit(%d) less than bsize(%d)",                                        	mp->m_dalign,						mp->m_blockmask +1);					error = XFS_ERROR(EINVAL);					goto error1;				}				mp->m_swidth = 0;			}		}		/*		 * Update superblock with new values		 * and log changes		 */		if (XFS_SB_VERSION_HASDALIGN(sbp)) {			if (sbp->sb_unit != mp->m_dalign) {				sbp->sb_unit = mp->m_dalign;				update_flags |= XFS_SB_UNIT;			}			if (sbp->sb_width != mp->m_swidth) {				sbp->sb_width = mp->m_swidth;				update_flags |= XFS_SB_WIDTH;			}		}	} else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN &&		    XFS_SB_VERSION_HASDALIGN(&mp->m_sb)) {			mp->m_dalign = sbp->sb_unit;			mp->m_swidth = sbp->sb_width;	}	xfs_alloc_compute_maxlevels(mp);	xfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK);	xfs_bmap_compute_maxlevels(mp, XFS_ATTR_FORK);	xfs_ialloc_compute_maxlevels(mp);	if (sbp->sb_imax_pct) {		__uint64_t	icount;		/* Make sure the maximum inode count is a multiple of the		 * units we allocate inodes in.		 */		icount = sbp->sb_dblocks * sbp->sb_imax_pct;		do_div(icount, 100);		do_div(icount, mp->m_ialloc_blks);		mp->m_maxicount = (icount * mp->m_ialloc_blks)  <<				   sbp->sb_inopblog;	} else		mp->m_maxicount = 0;	mp->m_maxioffset = xfs_max_file_offset(sbp->sb_blocklog);	/*	 * XFS uses the uuid from the superblock as the unique	 * identifier for fsid.  We can not use the uuid from the volume	 * since a single partition filesystem is identical to a single	 * partition volume/filesystem.	 */	if ((mfsi_flags & XFS_MFSI_SECOND) == 0 &&	    (mp->m_flags & XFS_MOUNT_NOUUID) == 0) {		if (xfs_uuid_mount(mp)) {			error = XFS_ERROR(EINVAL);			goto error1;		}		uuid_mounted=1;		ret64 = uuid_hash64(&sbp->sb_uuid);		memcpy(&vfsp->vfs_fsid, &ret64, sizeof(ret64));	}	/*	 * Set the default minimum read and write sizes unless	 * already specified in a mount option.	 * We use smaller I/O sizes when the file system	 * is being used for NFS service (wsync mount option).	 */	if (!(mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)) {		if (mp->m_flags & XFS_MOUNT_WSYNC) {			readio_log = XFS_WSYNC_READIO_LOG;			writeio_log = XFS_WSYNC_WRITEIO_LOG;		} else {			readio_log = XFS_READIO_LOG_LARGE;			writeio_log = XFS_WRITEIO_LOG_LARGE;		}	} else {		readio_log = mp->m_readio_log;		writeio_log = mp->m_writeio_log;	}	/*	 * Set the number of readahead buffers to use based on	 * physical memory size.	 */	if (xfs_physmem <= 4096)		/* <= 16MB */		mp->m_nreadaheads = XFS_RW_NREADAHEAD_16MB;	else if (xfs_physmem <= 8192)	/* <= 32MB */		mp->m_nreadaheads = XFS_RW_NREADAHEAD_32MB;	else		mp->m_nreadaheads = XFS_RW_NREADAHEAD_K32;	if (sbp->sb_blocklog > readio_log) {		mp->m_readio_log = sbp->sb_blocklog;	} else {		mp->m_readio_log = readio_log;	}	mp->m_readio_blocks = 1 << (mp->m_readio_log - sbp->sb_blocklog);	if (sbp->sb_blocklog > writeio_log) {		mp->m_writeio_log = sbp->sb_blocklog;	} else {		mp->m_writeio_log = writeio_log;	}	mp->m_writeio_blocks = 1 << (mp->m_writeio_log - sbp->sb_blocklog);	/*	 * Set the inode cluster size based on the physical memory	 * size.  This may still be overridden by the file system	 * block size if it is larger than the chosen cluster size.	 */	if (xfs_physmem <= btoc(32 * 1024 * 1024)) { /* <= 32 MB */		mp->m_inode_cluster_size = XFS_INODE_SMALL_CLUSTER_SIZE;	} else {		mp->m_inode_cluster_size = XFS_INODE_BIG_CLUSTER_SIZE;	}	/*	 * Set whether we're using inode alignment.	 */	if (XFS_SB_VERSION_HASALIGN(&mp->m_sb) &&	    mp->m_sb.sb_inoalignmt >=	    XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size))		mp->m_inoalign_mask = mp->m_sb.sb_inoalignmt - 1;	else		mp->m_inoalign_mask = 0;	/*	 * If we are using stripe alignment, check whether	 * the stripe unit is a multiple of the inode alignment	 */	if (mp->m_dalign && mp->m_inoalign_mask &&	    !(mp->m_dalign & mp->m_inoalign_mask))		mp->m_sinoalign = mp->m_dalign;	else		mp->m_sinoalign = 0;	/*	 * Check that the data (and log if separate) are an ok size.	 */	d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);	if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) {		cmn_err(CE_WARN, "XFS: size check 1 failed");		error = XFS_ERROR(E2BIG);		goto error1;	}	error = xfs_read_buf(mp, mp->m_ddev_targp,			     d - XFS_FSS_TO_BB(mp, 1),			     XFS_FSS_TO_BB(mp, 1), 0, &bp);	if (!error) {		xfs_buf_relse(bp);	} else {		cmn_err(CE_WARN, "XFS: size check 2 failed");		if (error == ENOSPC) {			error = XFS_ERROR(E2BIG);		}		goto error1;	}	if (((mfsi_flags & XFS_MFSI_CLIENT) == 0) &&	    mp->m_logdev_targp != mp->m_ddev_targp) {		d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);		if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) {			cmn_err(CE_WARN, "XFS: size check 3 failed");			error = XFS_ERROR(E2BIG);			goto error1;		}		error = xfs_read_buf(mp, mp->m_logdev_targp,				     d - XFS_FSB_TO_BB(mp, 1),				     XFS_FSB_TO_BB(mp, 1), 0, &bp);		if (!error) {			xfs_buf_relse(bp);		} else {			cmn_err(CE_WARN, "XFS: size check 3 failed");			if (error == ENOSPC) {				error = XFS_ERROR(E2BIG);			}			goto error1;		}	}	/*	 * Initialize realtime fields in the mount structure	 */	if ((error = xfs_rtmount_init(mp))) {		cmn_err(CE_WARN, "XFS: RT mount failed");		goto error1;	}	/*	 * For client case we are done now	 */	if (mfsi_flags & XFS_MFSI_CLIENT) {		return(0);	}	/*	 *  Copies the low order bits of the timestamp and the randomly	 *  set "sequence" number out of a UUID.	 */	uuid_getnodeuniq(&sbp->sb_uuid, mp->m_fixedfsid);	/*	 *  The vfs structure needs to have a file system independent	 *  way of checking for the invariant file system ID.  Since it	 *  can't look at mount structures it has a pointer to the data	 *  in the mount structure.	 *	 *  File systems that don't support user level file handles (i.e.	 *  all of them except for XFS) will leave vfs_altfsid as NULL.	 */	vfsp->vfs_altfsid = (xfs_fsid_t *)mp->m_fixedfsid;	mp->m_dmevmask = 0;	/* not persistent; set after each mount */	/*	 * Select the right directory manager.	 */	mp->m_dirops =		XFS_SB_VERSION_HASDIRV2(&mp->m_sb) ?			xfsv2_dirops :			xfsv1_dirops;	/*	 * Initialize directory manager's entries.	 */	XFS_DIR_MOUNT(mp);	/*	 * Initialize the attribute manager's entries.	 */	mp->m_attr_magicpct = (mp->m_sb.sb_blocksize * 37) / 100;	/*	 * Initialize the precomputed transaction reservations values.	 */	xfs_trans_init(mp);	/*	 * Allocate and initialize the inode hash table for this	 * file system.	 */	xfs_ihash_init(mp);	xfs_chash_init(mp);	/*	 * Allocate and initialize the per-ag data.	 */	init_rwsem(&mp->m_peraglock);	mp->m_perag =		kmem_zalloc(sbp->sb_agcount * sizeof(xfs_perag_t), KM_SLEEP);	mp->m_maxagi = xfs_initialize_perag(mp, sbp->sb_agcount);	/*	 * log's mount-time initialization. Perform 1st part recovery if needed	 */	if (likely(sbp->sb_logblocks > 0)) {	/* check for volume case */		error = xfs_log_mount(mp, mp->m_logdev_targp,				      XFS_FSB_TO_DADDR(mp, sbp->sb_logstart),				      XFS_FSB_TO_BB(mp, sbp->sb_logblocks));		if (error) {			cmn_err(CE_WARN, "XFS: log mount failed");			goto error2;		}	} else {	/* No log has been defined */		cmn_err(CE_WARN, "XFS: no log defined");		XFS_ERROR_REPORT("xfs_mountfs_int(1)", XFS_ERRLEVEL_LOW, mp);		error = XFS_ERROR(EFSCORRUPTED);		goto error2;	}	/*	 * Get and sanity-check the root inode.	 * Save the pointer to it in the mount structure.	 */	error = xfs_iget(mp, NULL, sbp->sb_rootino, XFS_ILOCK_EXCL, &rip, 0);	if (error) {		cmn_err(CE_WARN, "XFS: failed to read root inode");		goto error3;	}	ASSERT(rip != NULL);	rvp = XFS_ITOV(rip);	if (unlikely((rip->i_d.di_mode & S_IFMT) != S_IFDIR)) {		cmn_err(CE_WARN, "XFS: corrupted root inode");		prdev("Root inode %llu is not a directory",		      mp->m_ddev_targp, (unsigned long long)rip->i_ino);		xfs_iunlock(rip, XFS_ILOCK_EXCL);		XFS_ERROR_REPORT("xfs_mountfs_int(2)", XFS_ERRLEVEL_LOW,				 mp);		error = XFS_ERROR(EFSCORRUPTED);		goto error4;	}	mp->m_rootip = rip;	/* save it */	xfs_iunlock(rip, XFS_ILOCK_EXCL);	/*	 * Initialize realtime inode pointers in the mount structure	 */	if ((error = xfs_rtmount_inodes(mp))) {		/*		 * Free up the root inode.		 */		cmn_err(CE_WARN, "XFS: failed to read RT inodes");		goto error4;	}	/*	 * If fs is not mounted readonly, then update the superblock	 * unit and width changes.	 */	if (update_flags && !(vfsp->vfs_flag & VFS_RDONLY))		xfs_mount_log_sbunit(mp, update_flags);	/*	 * Initialise the XFS quota management subsystem for this mount	 */	if ((error = XFS_QM_INIT(mp, &quotamount, &quotaflags)))		goto error4;	/*	 * Finish recovering the file system.  This part needed to be	 * delayed until after the root and real-time bitmap inodes	 * were consistently read in.	 */	error = xfs_log_mount_finish(mp, mfsi_flags);	if (error) {		cmn_err(CE_WARN, "XFS: log mount finish failed");		goto error4;	}	/*	 * Complete the quota initialisation, post-log-replay component.	 */	if ((error = XFS_QM_MOUNT(mp, quotamount, quotaflags)))		goto error4;	return 0; error4:	/*	 * Free up the root inode.	 */	VN_RELE(rvp); error3:	xfs_log_unmount_dealloc(mp); error2:	xfs_ihash_free(mp);	xfs_chash_free(mp);	for (agno = 0; agno < sbp->sb_agcount; agno++)		if (mp->m_perag[agno].pagb_list)			kmem_free(mp->m_perag[agno].pagb_list,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?