⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xfs_mount.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		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);	mp->m_dmevmask = 0;	/* not persistent; set after each mount */	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 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;	}	/*	 * Now the log is mounted, we know if it was an unclean shutdown or	 * not. If it was, with the first phase of recovery has completed, we	 * have consistent AG blocks on disk. We have not recovered EFIs yet,	 * but they are recovered transactionally in the second recovery phase	 * later.	 *	 * Hence we can safely re-initialise incore superblock counters from	 * the per-ag data. These may not be correct if the filesystem was not	 * cleanly unmounted, so we need to wait for recovery to finish before	 * doing this.	 *	 * If the filesystem was cleanly unmounted, then we can trust the	 * values in the superblock to be correct and we don't need to do	 * anything here.	 *	 * If we are currently making the filesystem, the initialisation will	 * fail as the perag data is in an undefined state.	 */	if (xfs_sb_version_haslazysbcount(&mp->m_sb) &&	    !XFS_LAST_UNMOUNT_WAS_CLEAN(mp) &&	     !mp->m_sb.sb_inprogress) {		error = xfs_initialize_perag_data(mp, sbp->sb_agcount);		if (error) {			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, 0, 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");		cmn_err(CE_WARN, "Device %s - root %llu is not a directory",			XFS_BUFTARG_NAME(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 && !(mp->m_flags & XFS_MOUNT_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, mfsi_flags)))		goto error4;	/*	 * Now we are mounted, reserve a small amount of unused space for	 * privileged transactions. This is needed so that transaction	 * space required for critical operations can dip into this pool	 * when at ENOSPC. This is needed for operations like create with	 * attr, unwritten extent conversion at ENOSPC, etc. Data allocations	 * are not allowed to use this reserved space.	 *	 * We default to 5% or 1024 fsbs of space reserved, whichever is smaller.	 * This may drive us straight to ENOSPC on mount, but that implies	 * we were already there on the last unmount.	 */	resblks = mp->m_sb.sb_dblocks;	do_div(resblks, 20);	resblks = min_t(__uint64_t, resblks, 1024);	xfs_reserve_blocks(mp, &resblks, NULL);	return 0; error4:	/*	 * Free up the root inode.	 */	VN_RELE(rvp); error3:	xfs_log_unmount_dealloc(mp); error2:	for (agno = 0; agno < sbp->sb_agcount; 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, sbp->sb_agcount * sizeof(xfs_perag_t));	mp->m_perag = NULL;	/* FALLTHROUGH */ error1:	if (uuid_mounted)		xfs_uuid_unmount(mp);	xfs_freesb(mp);	return error;}/* * xfs_unmountfs * * This flushes out the inodes,dquots and the superblock, unmounts the * log and makes sure that incore structures are freed. */intxfs_unmountfs(xfs_mount_t *mp, struct cred *cr){	__uint64_t	resblks;	/*	 * We can potentially deadlock here if we have an inode cluster	 * that has been freed has it's buffer still pinned in memory because	 * the transaction is still sitting in a iclog. The stale inodes	 * on that buffer will have their flush locks held until the	 * transaction hits the disk and the callbacks run. the inode	 * flush takes the flush lock unconditionally and with nothing to	 * push out the iclog we will never get that unlocked. hence we	 * need to force the log first.	 */	xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);	xfs_iflush_all(mp);	XFS_QM_DQPURGEALL(mp, XFS_QMOPT_QUOTALL | XFS_QMOPT_UMOUNTING);	/*	 * Flush out the log synchronously so that we know for sure	 * that nothing is pinned.  This is important because bflush()	 * will skip pinned buffers.	 */	xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);	xfs_binval(mp->m_ddev_targp);	if (mp->m_rtdev_targp) {		xfs_binval(mp->m_rtdev_targp);	}	/*	 * Unreserve any blocks we have so that when we unmount we don't account	 * the reserved free space as used. This is really only necessary for	 * lazy superblock counting because it trusts the incore superblock	 * counters to be aboslutely correct on clean unmount.	 *	 * We don't bother correcting this elsewhere for lazy superblock	 * counting because on mount of an unclean filesystem we reconstruct the	 * correct counter value and this is irrelevant.	 *	 * For non-lazy counter filesystems, this doesn't matter at all because	 * we only every apply deltas to the superblock and hence the incore	 * value does not matter....	 */	resblks = 0;	xfs_reserve_blocks(mp, &resblks, NULL);	xfs_log_sbcount(mp, 1);	xfs_unmountfs_writesb(mp);	xfs_unmountfs_wait(mp); 		/* wait for async bufs */	xfs_log_unmount(mp);			/* Done! No more fs ops. */	xfs_freesb(mp);	/*	 * All inodes from this mount point should be freed.	 */	ASSERT(mp->m_inodes == NULL);	xfs_unmountfs_close(mp, cr);	if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0)		xfs_uuid_unmount(mp);#if defined(DEBUG) || defined(INDUCE_IO_ERROR)	xfs_errortag_clearall(mp, 0);#endif	XFS_IODONE(mp);	xfs_mount_free(mp);	return 0;}voidxfs_unmountfs_close(xfs_mount_t *mp, struct cred *cr){	if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp)		xfs_free_buftarg(mp->m_logdev_targp, 1);	if (mp->m_rtdev_targp)		xfs_free_buftarg(mp->m_rtdev_targp, 1);	xfs_free_buftarg(mp->m_ddev_targp, 0);}STATIC voidxfs_unmountfs_wait(xfs_mount_t *mp){	if (mp->m_logdev_targp != mp->m_ddev_targp)		xfs_wait_buftarg(mp->m_logdev_targp);	if (mp->m_rtdev_targp)		xfs_wait_buftarg(mp->m_rtdev_targp);	xfs_wait_buftarg(mp->m_ddev_targp);}intxfs_fs_writable(xfs_mount_t *mp){	return !(xfs_test_for_freeze(mp) || XFS_FORCED_SHUTDOWN(mp) ||		(mp->m_flags & XFS_MOUNT_RDONLY));}/* * xfs_log_sbcount * * Called either periodically to keep the on disk superblock values * roughly up to date or from unmount to make sure the values are * correct on a clean unmount. * * Note this code can be called during the process of freezing, so * we may need to use the transaction allocator which does not not * block when the transaction subsystem is in its frozen state. */intxfs_log_sbcount(	xfs_mount_t	*mp,	uint		sync){	xfs_trans_t	*tp;	int		error;	if (!xfs_fs_writable(mp))		return 0;	xfs_icsb_sync_counters(mp);	/*	 * we don't need to do this if we are updating the superblock	 * counters on every modification.	 */	if (!xfs_sb_version_haslazysbcount(&mp->m_sb))		return 0;	tp = _xfs_trans_alloc(mp, XFS_TRANS_SB_COUNT);	error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,					XFS_DEFAULT_LOG_COUNT);	if (error) {		xfs_trans_cancel(tp, 0);		return error;	}	xfs_mod_sb(tp, XFS_SB_IFREE | XFS_SB_ICOUNT | XFS_SB_FDBLOCKS);	if (sync)		xfs_trans_set_sync(tp);	xfs_trans_commit(tp, 0);	return 0;}STATIC voidxfs_mark_shared_ro(	xfs_mount_t	*mp,	xfs_buf_t	*bp){	xfs_dsb_t	*sb = XFS_BUF_TO_SBP(bp);	__uint16_t	version;	if (!(sb->sb_flags & XFS_SBF_READONLY))		sb->sb_flags |= XFS_SBF_READONLY;	version = be16_to_cpu(sb->sb_versionnum);	if ((version & XFS_SB_VERSION_NUMBITS) != XFS_SB_VERSION_4 ||	    !(version & XFS_SB_VERSION_SHAREDBIT))		version |= XFS_SB_VERSION_SHAREDBIT;	sb->sb_versionnum = cpu_to_be16(version);}intxfs_unmountfs_writesb(xfs_mount_t *mp){	xfs_buf_t	*sbp;	int		error = 0;	/*	 * skip superblock write if fs is read-only, or	 * if we are doing a forced umount.	 */	if (!((mp->m_flags & XFS_MOUNT_RDONLY) ||		XFS_FORCED_SHUTDOWN(mp))) {		sbp = xfs_getsb(mp, 0);		/*		 * mark shared-readonly if desired		 */		if (mp->m_mk_sharedro)			xfs_mark_shared_ro(mp, sbp);		XFS_BUF_UNDONE(sbp);		XFS_BUF_UNREAD(sbp);		XFS_BUF_UNDELAYWRITE(sbp);		XFS_BUF_WRITE(sbp);		XFS_BUF_UNASYNC(sbp);		ASSERT(XFS_BUF_TARGET(sbp) == mp->m_ddev_targp);		xfsbdstrat(mp, sbp);		/* Nevermind errors we might get here. */		error = xfs_iowait(sbp);		if (error)			xfs_ioerror_alert("xfs_unmountfs_writesb",					  mp, sbp, XFS_BUF_ADDR(sbp));		if (error && mp->m_mk_sharedro)			xfs_fs_cmn_err(CE_ALERT, mp, "Superblock write error detected while unmounting.  Filesystem may not be marked shared readonly");		xfs_buf_relse(sbp);	}	return error;}/* * xfs_mod_sb() can be used to copy arbitrary changes to the * in-core superblock into the superblock buffer to be logged. * It does not provide the higher level of locking that is * needed to protect the in-core superblock from concurrent * access. */voidxfs_mod_sb(xfs_trans_t *tp, __int64_t fields){	xfs_buf_t	*bp;	int		first;	int		last;	xfs_mount_t	*mp;	xfs_sb_field_t	f;	ASSERT(fields);	if (!fields)		return;	mp = tp->t_mountp;	bp = xfs_trans_getsb(tp, mp, 0);	first = sizeof(xfs_sb_t);	last = 0;	/* translate/copy */	xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, fields);	/* find modified range */	f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields);	ASSERT((1LL << f) & XFS_SB_MOD_BITS);	first = xfs_sb_info[f].offset;	f = (xfs_sb_field_t)xfs_highbit64((__uint64_t)fields);	ASSERT((1LL << f) & XFS_SB_MOD_BITS);	last = xfs_sb_info[f + 1].offset - 1;	xfs_trans_log_buf(tp, bp, first, last);}/* * xfs_mod_incore_sb_unlocked() is a utility routine common used to apply * a delta to a specified field in the in-core superblock.  Simply * switch on the field indicated and apply the delta to that field. * Fields are not allowed to dip below zero, so if the delta would * do this do not apply it and return EINVAL. * * The SB_LOCK must be held when this routine is called. */intxfs_mod_incore_sb_unlocked(	xfs_mount_t	*mp,	xfs_sb_field_t	field,	int64_t		delta,	int		rsvd){	int		scounter;	/* short counter for 32 bit fields */	long long	lcounter;	/* long counter for 64 bit fields */	long long	res_used, rem;	/*	 * With the in-core superblock spin lock held, switch

⌨️ 快捷键说明

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