📄 xfs_vfsops.c
字号:
} 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; if (mp->m_flags & XFS_MOUNT_BARRIER) xfs_mountfs_check_barriers(mp); if ((error = xfs_filestream_mount(mp))) goto error2; error = XFS_IOINIT(mp, args, flags); if (error) goto error2; XFS_SEND_MOUNT(mp, DM_RIGHT_NULL, args->mtpt, args->fsname); 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); xfs_qmops_put(mp); xfs_dmops_put(mp); return error;}intxfs_unmount( xfs_mount_t *mp, int flags, cred_t *credp){ xfs_inode_t *rip; bhv_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);#ifdef HAVE_DMAPI if (mp->m_flags & XFS_MOUNT_DMAPI) { error = XFS_SEND_PREUNMOUNT(mp, 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; }#endif /* * First blow any referenced inode from this file system * out of the reference cache, and delete the timer. */ xfs_refcache_purge_mp(mp); /* * Blow away any referenced inode in the filestreams cache. * This can and will cause log traffic as inodes go inactive * here. */ xfs_filestream_unmount(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, SYNC_WAIT | SYNC_CLOSE); 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, 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); xfs_qmops_put(mp); xfs_dmops_put(mp); kmem_free(mp, sizeof(xfs_mount_t)); } return XFS_ERROR(error);}STATIC intxfs_quiesce_fs( xfs_mount_t *mp){ int count = 0, pincount; 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 { xfs_syncsub(mp, SYNC_INODE_QUIESCE, NULL); pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1); if (!pincount) { delay(50); count++; } } while (count < 2); return 0;}/* * Second stage of a quiesce. The data is already synced, now we have to take * care of the metadata. New transactions are already blocked, so we need to * wait for any remaining transactions to drain out before proceding. */STATIC voidxfs_attr_quiesce( xfs_mount_t *mp){ /* wait for all modifications to complete */ while (atomic_read(&mp->m_active_trans) > 0) delay(100); /* flush inodes and push all remaining buffers out to disk */ xfs_quiesce_fs(mp); ASSERT_ALWAYS(atomic_read(&mp->m_active_trans) == 0); /* Push the superblock and write an unmount record */ xfs_log_sbcount(mp, 1); xfs_log_unmount_write(mp); xfs_unmountfs_writesb(mp);}intxfs_mntupdate( struct xfs_mount *mp, int *flags, struct xfs_mount_args *args){ if (!(*flags & MS_RDONLY)) { /* rw/ro -> rw */ if (mp->m_flags & XFS_MOUNT_RDONLY) mp->m_flags &= ~XFS_MOUNT_RDONLY; if (args->flags & XFSMNT_BARRIER) { mp->m_flags |= XFS_MOUNT_BARRIER; xfs_mountfs_check_barriers(mp); } else { mp->m_flags &= ~XFS_MOUNT_BARRIER; } } else if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { /* rw -> ro */ xfs_filestream_flush(mp); xfs_sync(mp, SYNC_DATA_QUIESCE); xfs_attr_quiesce(mp); mp->m_flags |= XFS_MOUNT_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; bhv_vnode_t *rvp = XFS_ITOV(rip); int error; xfs_ilock(rip, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); 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 */intxfs_root( xfs_mount_t *mp, bhv_vnode_t **vpp){ bhv_vnode_t *vp; vp = XFS_ITOV(mp->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. */intxfs_statvfs( xfs_mount_t *mp, bhv_statvfs_t *statp, bhv_vnode_t *vp){ __uint64_t fakeinos; xfs_extlen_t lsize; xfs_sb_t *sbp; unsigned long s; sbp = &(mp->m_sb); statp->f_type = XFS_SB_MAGIC; xfs_icsb_sync_counters_flags(mp, XFS_ICSB_LAZY_COUNT); 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 - XFS_ALLOC_SET_ASIDE(mp); 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); xfs_statvfs_fsid(statp, mp); statp->f_namelen = MAXNAMELEN - 1; if (vp) XFS_QM_DQSTATVFS(xfs_vtoi(vp), statp); 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 everything. * SYNC_FSDATA - This indicates that the caller would like to make * sure the superblock is safe on disk. We can ensure * this by simply making sure the log gets flushed * if SYNC_BDFLUSH is set, and by actually writing it * out otherwise. * SYNC_IOWAIT - The caller wants us to wait for all data I/O to complete * before we return (including direct I/O). Forms the drain * side of the write barrier needed to safely quiesce the * filesystem. * */intxfs_sync( xfs_mount_t *mp, int flags){ int error; /* * Get the Quota Manager to flush the dquots. * * If XFS quota support is not enabled or this filesystem * instance does not use quotas XFS_QM_DQSYNC will always * return zero. */ error = XFS_QM_DQSYNC(mp, flags); if (error) { /* * If we got an IO error, we will be shutting down. * So, there's nothing more for us to do here. */ ASSERT(error != EIO || XFS_FORCED_SHUTDOWN(mp)); if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(error); } if (flags & SYNC_IOWAIT) xfs_filestream_flush(mp); return xfs_syncsub(mp, flags, 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. * */intxfs_sync_inodes( xfs_mount_t *mp, int flags, int *bypassed){ xfs_inode_t *ip = NULL; xfs_inode_t *ip_next; xfs_buf_t *bp; bhv_vnode_t *vp = NULL; 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; \ }#define XFS_PREEMPT_MASK 0x7f if (bypassed) *bypassed = 0; if (mp->m_flags & XFS_MOUNT_RDONLY) return 0; error = 0; last_error = 0; preempt = 0; /* Allocate a reference marker */ ipointer = (xfs_iptr_t *)kmem_zalloc(sizeof(xfs_iptr_t), KM_SLEEP); fflag = XFS_B_ASYNC; /* default is don't wait */ if (flags & (SYNC_BDFLUSH | SYNC_DELWRI)) fflag = XFS_B_DELWRI; if (flags & SYNC_WAIT) fflag = 0; /* synchronous overrides all */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -