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