xfs_vfsops.c

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

C
1,927
字号
				xfs_alloc_buftarg(logdev) : mp->m_ddev_targp;	if (!mp->m_logdev_targp)		goto error0;	/*	 * Setup flags based on mount(2) options and then the superblock	 */	error = xfs_start_flags(vfsp, args, mp);	if (error)		goto error1;	error = xfs_readsb(mp);	if (error)		goto error1;	error = xfs_finish_flags(vfsp, args, mp);	if (error)		goto error2;	/*	 * Setup xfs_mount buffer target pointers based on superblock	 */	error = xfs_setsize_buftarg(mp->m_ddev_targp, mp->m_sb.sb_blocksize,				    mp->m_sb.sb_sectsize);	if (!error && logdev && logdev != ddev) {		unsigned int	log_sector_size = BBSIZE;		if (XFS_SB_VERSION_HASSECTOR(&mp->m_sb))			log_sector_size = mp->m_sb.sb_logsectsize;		error = xfs_setsize_buftarg(mp->m_logdev_targp,					    mp->m_sb.sb_blocksize,					    log_sector_size);	}	if (!error && rtdev)		error = xfs_setsize_buftarg(mp->m_rtdev_targp,					    mp->m_sb.sb_blocksize,					    mp->m_sb.sb_sectsize);	if (error)		goto error2;	error = XFS_IOINIT(vfsp, args, flags);	if (!error)		return 0;error2:	if (mp->m_sb_bp)		xfs_freesb(mp);error1:	xfs_binval(mp->m_ddev_targp);	if (logdev && logdev != ddev)		xfs_binval(mp->m_logdev_targp);	if (rtdev)		xfs_binval(mp->m_rtdev_targp);error0:	xfs_unmountfs_close(mp, credp);	return error;}STATIC intxfs_unmount(	bhv_desc_t	*bdp,	int		flags,	cred_t		*credp){	struct vfs	*vfsp = bhvtovfs(bdp);	xfs_mount_t	*mp = XFS_BHVTOM(bdp);	xfs_inode_t	*rip;	vnode_t		*rvp;	int		unmount_event_wanted = 0;	int		unmount_event_flags = 0;	int		xfs_unmountfs_needed = 0;	int		error;	rip = mp->m_rootip;	rvp = XFS_ITOV(rip);	if (vfsp->vfs_flag & VFS_DMI) {		error = XFS_SEND_PREUNMOUNT(mp, vfsp,				rvp, DM_RIGHT_NULL, rvp, DM_RIGHT_NULL,				NULL, NULL, 0, 0,				(mp->m_dmevmask & (1<<DM_EVENT_PREUNMOUNT))?					0:DM_FLAGS_UNWANTED);			if (error)				return XFS_ERROR(error);		unmount_event_wanted = 1;		unmount_event_flags = (mp->m_dmevmask & (1<<DM_EVENT_UNMOUNT))?					0 : DM_FLAGS_UNWANTED;	}	/*	 * First blow any referenced inode from this file system	 * out of the reference cache, and delete the timer.	 */	xfs_refcache_purge_mp(mp);	XFS_bflush(mp->m_ddev_targp);	error = xfs_unmount_flush(mp, 0);	if (error)		goto out;	ASSERT(vn_count(rvp) == 1);	/*	 * Drop the reference count	 */	VN_RELE(rvp);	/*	 * If we're forcing a shutdown, typically because of a media error,	 * we want to make sure we invalidate dirty pages that belong to	 * referenced vnodes as well.	 */	if (XFS_FORCED_SHUTDOWN(mp)) {		error = xfs_sync(&mp->m_bhv,			 (SYNC_WAIT | SYNC_CLOSE), credp);		ASSERT(error != EFSCORRUPTED);	}	xfs_unmountfs_needed = 1;out:	/*	Send DMAPI event, if required.	 *	Then do xfs_unmountfs() if needed.	 *	Then return error (or zero).	 */	if (unmount_event_wanted) {		/* Note: mp structure must still exist for		 * XFS_SEND_UNMOUNT() call.		 */		XFS_SEND_UNMOUNT(mp, vfsp, error == 0 ? rvp : NULL,			DM_RIGHT_NULL, 0, error, unmount_event_flags);	}	if (xfs_unmountfs_needed) {		/*		 * Call common unmount function to flush to disk		 * and free the super block buffer & mount structures.		 */		xfs_unmountfs(mp, credp);	}	return XFS_ERROR(error);}#define REMOUNT_READONLY_FLAGS	(SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT)STATIC intxfs_mntupdate(	bhv_desc_t			*bdp,	int				*flags,	struct xfs_mount_args		*args){	struct vfs	*vfsp = bhvtovfs(bdp);	xfs_mount_t	*mp = XFS_BHVTOM(bdp);	int		pincount, error;	int		count = 0;	if (args->flags & XFSMNT_NOATIME)		mp->m_flags |= XFS_MOUNT_NOATIME;	else		mp->m_flags &= ~XFS_MOUNT_NOATIME;	if (!(vfsp->vfs_flag & VFS_RDONLY)) {		VFS_SYNC(vfsp, SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR, NULL, error);	}	if (*flags & MS_RDONLY) {		xfs_refcache_purge_mp(mp);		xfs_flush_buftarg(mp->m_ddev_targp, 0);		xfs_finish_reclaim_all(mp, 0);		/* This loop must run at least twice.		 * The first instance of the loop will flush		 * most meta data but that will generate more		 * meta data (typically directory updates).		 * Which then must be flushed and logged before		 * we can write the unmount record.		 */ 		do {			VFS_SYNC(vfsp, REMOUNT_READONLY_FLAGS, NULL, error);			pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1);			if (!pincount) {				delay(50);				count++;			}		} while (count < 2);		/* Ok now write out an unmount record */		xfs_log_unmount_write(mp);		xfs_unmountfs_writesb(mp);		vfsp->vfs_flag |= VFS_RDONLY;	} else {		vfsp->vfs_flag &= ~VFS_RDONLY;	}	return 0;}/* * xfs_unmount_flush implements a set of flush operation on special * inodes, which are needed as a separate set of operations so that * they can be called as part of relocation process. */intxfs_unmount_flush(	xfs_mount_t	*mp,		/* Mount structure we are getting					   rid of. */	int             relocation)	/* Called from vfs relocation. */{	xfs_inode_t	*rip = mp->m_rootip;	xfs_inode_t	*rbmip;	xfs_inode_t	*rsumip = NULL;	vnode_t		*rvp = XFS_ITOV(rip);	int		error;	xfs_ilock(rip, XFS_ILOCK_EXCL);	xfs_iflock(rip);	/*	 * Flush out the real time inodes.	 */	if ((rbmip = mp->m_rbmip) != NULL) {		xfs_ilock(rbmip, XFS_ILOCK_EXCL);		xfs_iflock(rbmip);		error = xfs_iflush(rbmip, XFS_IFLUSH_SYNC);		xfs_iunlock(rbmip, XFS_ILOCK_EXCL);		if (error == EFSCORRUPTED)			goto fscorrupt_out;		ASSERT(vn_count(XFS_ITOV(rbmip)) == 1);		rsumip = mp->m_rsumip;		xfs_ilock(rsumip, XFS_ILOCK_EXCL);		xfs_iflock(rsumip);		error = xfs_iflush(rsumip, XFS_IFLUSH_SYNC);		xfs_iunlock(rsumip, XFS_ILOCK_EXCL);		if (error == EFSCORRUPTED)			goto fscorrupt_out;		ASSERT(vn_count(XFS_ITOV(rsumip)) == 1);	}	/*	 * Synchronously flush root inode to disk	 */	error = xfs_iflush(rip, XFS_IFLUSH_SYNC);	if (error == EFSCORRUPTED)		goto fscorrupt_out2;	if (vn_count(rvp) != 1 && !relocation) {		xfs_iunlock(rip, XFS_ILOCK_EXCL);		return XFS_ERROR(EBUSY);	}	/*	 * Release dquot that rootinode, rbmino and rsumino might be holding,	 * flush and purge the quota inodes.	 */	error = XFS_QM_UNMOUNT(mp);	if (error == EFSCORRUPTED)		goto fscorrupt_out2;	if (rbmip) {		VN_RELE(XFS_ITOV(rbmip));		VN_RELE(XFS_ITOV(rsumip));	}	xfs_iunlock(rip, XFS_ILOCK_EXCL);	return 0;fscorrupt_out:	xfs_ifunlock(rip);fscorrupt_out2:	xfs_iunlock(rip, XFS_ILOCK_EXCL);	return XFS_ERROR(EFSCORRUPTED);}/* * xfs_root extracts the root vnode from a vfs. * * vfsp -- the vfs struct for the desired file system * vpp  -- address of the caller's vnode pointer which should be *         set to the desired fs root vnode */STATIC intxfs_root(	bhv_desc_t	*bdp,	vnode_t		**vpp){	vnode_t		*vp;	vp = XFS_ITOV((XFS_BHVTOM(bdp))->m_rootip);	VN_HOLD(vp);	*vpp = vp;	return 0;}/* * xfs_statvfs * * Fill in the statvfs structure for the given file system.  We use * the superblock lock in the mount structure to ensure a consistent * snapshot of the counters returned. */STATIC intxfs_statvfs(	bhv_desc_t	*bdp,	xfs_statfs_t	*statp,	vnode_t		*vp){	__uint64_t	fakeinos;	xfs_extlen_t	lsize;	xfs_mount_t	*mp;	xfs_sb_t	*sbp;	unsigned long	s;	u64 id;	mp = XFS_BHVTOM(bdp);	sbp = &(mp->m_sb);	statp->f_type = XFS_SB_MAGIC;	s = XFS_SB_LOCK(mp);	statp->f_bsize = sbp->sb_blocksize;	lsize = sbp->sb_logstart ? sbp->sb_logblocks : 0;	statp->f_blocks = sbp->sb_dblocks - lsize;	statp->f_bfree = statp->f_bavail = sbp->sb_fdblocks;	fakeinos = statp->f_bfree << sbp->sb_inopblog;#if XFS_BIG_INUMS	fakeinos += mp->m_inoadd;#endif	statp->f_files =	    MIN(sbp->sb_icount + fakeinos, (__uint64_t)XFS_MAXINUMBER);	if (mp->m_maxicount)#if XFS_BIG_INUMS		if (!mp->m_inoadd)#endif			statp->f_files = min_t(typeof(statp->f_files),						statp->f_files,						mp->m_maxicount);	statp->f_ffree = statp->f_files - (sbp->sb_icount - sbp->sb_ifree);	XFS_SB_UNLOCK(mp, s);	id = huge_encode_dev(mp->m_dev);	statp->f_fsid.val[0] = (u32)id;	statp->f_fsid.val[1] = (u32)(id >> 32);	statp->f_namelen = MAXNAMELEN - 1;	return 0;}/* * xfs_sync flushes any pending I/O to file system vfsp. * * This routine is called by vfs_sync() to make sure that things make it * out to disk eventually, on sync() system calls to flush out everything, * and when the file system is unmounted.  For the vfs_sync() case, all * we really need to do is sync out the log to make all of our meta-data * updates permanent (except for timestamps).  For calls from pflushd(), * dirty pages are kept moving by calling pdflush() on the inodes * containing them.  We also flush the inodes that we can lock without * sleeping and the superblock if we can lock it without sleeping from * vfs_sync() so that items at the tail of the log are always moving out. * * Flags: *      SYNC_BDFLUSH - We're being called from vfs_sync() so we don't want *		       to sleep if we can help it.  All we really need *		       to do is ensure that the log is synced at least *		       periodically.  We also push the inodes and *		       superblock if we can lock them without sleeping *			and they are not pinned. *      SYNC_ATTR    - We need to flush the inodes.  If SYNC_BDFLUSH is not *		       set, then we really want to lock each inode and flush *		       it. *      SYNC_WAIT    - All the flushes that take place in this call should *		       be synchronous. *      SYNC_DELWRI  - This tells us to push dirty pages associated with *		       inodes.  SYNC_WAIT and SYNC_BDFLUSH are used to *		       determine if they should be flushed sync, async, or *		       delwri. *      SYNC_CLOSE   - This flag is passed when the system is being *		       unmounted.  We should sync and invalidate everthing. *      SYNC_FSDATA  - This indicates that the caller would like to make *		       sure the superblock is safe on disk.  We can ensure *		       this by simply makeing sure the log gets flushed *		       if SYNC_BDFLUSH is set, and by actually writing it *		       out otherwise. * *//*ARGSUSED*/STATIC intxfs_sync(	bhv_desc_t	*bdp,	int		flags,	cred_t		*credp){	xfs_mount_t	*mp;	mp = XFS_BHVTOM(bdp);	return (xfs_syncsub(mp, flags, 0, NULL));}/* * xfs sync routine for internal use * * This routine supports all of the flags defined for the generic VFS_SYNC * interface as explained above under xfs_sync.  In the interests of not * changing interfaces within the 6.5 family, additional internallly- * required functions are specified within a separate xflags parameter, * only available by calling this routine. * */STATIC intxfs_sync_inodes(	xfs_mount_t	*mp,	int		flags,	int             xflags,	int             *bypassed){	xfs_inode_t	*ip = NULL;	xfs_inode_t	*ip_next;	xfs_buf_t	*bp;	vnode_t		*vp = NULL;	vmap_t		vmap;	int		error;	int		last_error;	uint64_t	fflag;	uint		lock_flags;	uint		base_lock_flags;	boolean_t	mount_locked;	boolean_t	vnode_refed;	int		preempt;	xfs_dinode_t	*dip;	xfs_iptr_t	*ipointer;#ifdef DEBUG	boolean_t	ipointer_in = B_FALSE;#define IPOINTER_SET	ipointer_in = B_TRUE#define IPOINTER_CLR	ipointer_in = B_FALSE#else#define IPOINTER_SET#define IPOINTER_CLR#endif/* Insert a marker record into the inode list after inode ip. The list * must be locked when this is called. After the call the list will no * longer be locked. */#define IPOINTER_INSERT(ip, mp)	{ \		ASSERT(ipointer_in == B_FALSE); \		ipointer->ip_mnext = ip->i_mnext; \		ipointer->ip_mprev = ip; \		ip->i_mnext = (xfs_inode_t *)ipointer; \		ipointer->ip_mnext->i_mprev = (xfs_inode_t *)ipointer; \		preempt = 0; \		XFS_MOUNT_IUNLOCK(mp); \		mount_locked = B_FALSE; \		IPOINTER_SET; \	}/* Remove the marker from the inode list. If the marker was the only item * in the list then there are no remaining inodes and we should zero out * the whole list. If we are the current head of the list then move the head * past us. */#define IPOINTER_REMOVE(ip, mp)	{ \		ASSERT(ipointer_in == B_TRUE); \		if (ipointer->ip_mnext != (xfs_inode_t *)ipointer) { \			ip = ipointer->ip_mnext; \			ip->i_mprev = ipointer->ip_mprev; \			ipointer->ip_mprev->i_mnext = ip; \			if (mp->m_inodes == (xfs_inode_t *)ipointer) { \				mp->m_inodes = ip; \			} \		} else { \			ASSERT(mp->m_inodes == (xfs_inode_t *)ipointer); \			mp->m_inodes = NULL; \			ip = NULL; \		} \		IPOINTER_CLR; \	}

⌨️ 快捷键说明

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