xfs_mount.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,582 行 · 第 1/3 页
C
1,582 行
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){ struct vfs *vfsp = XFS_MTOVFS(mp);#if defined(DEBUG) || defined(INDUCE_IO_ERROR) int64_t fsid;#endif xfs_iflush_all(mp, XFS_FLUSH_ALL); XFS_QM_DQPURGEALL(mp, XFS_QMOPT_UQUOTA | XFS_QMOPT_GQUOTA | 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); } xfs_unmountfs_writesb(mp); 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); /* * We may have bufs that are in the process of getting written still. * We must wait for the I/O completion of those. The sync flag here * does a two pass iteration thru the bufcache. */ if (XFS_FORCED_SHUTDOWN(mp)) { xfs_incore_relse(mp->m_ddev_targp, 0, 1); /* synchronous */ } xfs_unmountfs_close(mp, cr); if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0) xfs_uuid_unmount(mp);#if defined(DEBUG) || defined(INDUCE_IO_ERROR) /* * clear all error tags on this filesystem */ memcpy(&fsid, &vfsp->vfs_fsid, sizeof(int64_t)); xfs_errortag_clearall_umount(fsid, mp->m_fsname, 0);#endif XFS_IODONE(vfsp); xfs_mount_free(mp, 1); return 0;}voidxfs_unmountfs_close(xfs_mount_t *mp, struct cred *cr){ if (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);}intxfs_unmountfs_writesb(xfs_mount_t *mp){ xfs_buf_t *sbp; xfs_sb_t *sb; int error = 0; /* * skip superblock write if fs is read-only, or * if we are doing a forced umount. */ sbp = xfs_getsb(mp, 0); if (!(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY || XFS_FORCED_SHUTDOWN(mp))) { /* * mark shared-readonly if desired */ sb = XFS_BUF_TO_SBP(sbp); if (mp->m_mk_sharedro) { if (!(sb->sb_flags & XFS_SBF_READONLY)) sb->sb_flags |= XFS_SBF_READONLY; if (!XFS_SB_VERSION_HASSHARED(sb)) XFS_SB_VERSION_ADDSHARED(sb); xfs_fs_cmn_err(CE_NOTE, mp, "Unmounting, marking shared read-only"); } 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_t *sbp; xfs_sb_field_t f; ASSERT(fields); if (!fields) return; mp = tp->t_mountp; bp = xfs_trans_getsb(tp, mp, 0); sbp = XFS_BUF_TO_SBP(bp); first = sizeof(xfs_sb_t); last = 0; /* translate/copy */ xfs_xlatesb(XFS_BUF_PTR(bp), &(mp->m_sb), -1, ARCH_CONVERT, 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. */STATIC intxfs_mod_incore_sb_unlocked(xfs_mount_t *mp, xfs_sb_field_t field, int 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 * on the indicated field. Apply the delta to the * proper field. If the fields value would dip below * 0, then do not apply the delta and return EINVAL. */ switch (field) { case XFS_SBS_ICOUNT: lcounter = (long long)mp->m_sb.sb_icount; lcounter += delta; if (lcounter < 0) { ASSERT(0); return (XFS_ERROR(EINVAL)); } mp->m_sb.sb_icount = lcounter; return (0); case XFS_SBS_IFREE: lcounter = (long long)mp->m_sb.sb_ifree; lcounter += delta; if (lcounter < 0) { ASSERT(0); return (XFS_ERROR(EINVAL)); } mp->m_sb.sb_ifree = lcounter; return (0); case XFS_SBS_FDBLOCKS: lcounter = (long long)mp->m_sb.sb_fdblocks; res_used = (long long)(mp->m_resblks - mp->m_resblks_avail); if (delta > 0) { /* Putting blocks back */ if (res_used > delta) { mp->m_resblks_avail += delta; } else { rem = delta - res_used; mp->m_resblks_avail = mp->m_resblks; lcounter += rem; } } else { /* Taking blocks away */ lcounter += delta; /* * If were out of blocks, use any available reserved blocks if * were allowed to. */ if (lcounter < 0) { if (rsvd) { lcounter = (long long)mp->m_resblks_avail + delta; if (lcounter < 0) { return (XFS_ERROR(ENOSPC)); } mp->m_resblks_avail = lcounter; return (0); } else { /* not reserved */ return (XFS_ERROR(ENOSPC)); } } } mp->m_sb.sb_fdblocks = lcounter; return (0); case XFS_SBS_FREXTENTS: lcounter = (long long)mp->m_sb.sb_frextents; lcounter += delta; if (lcounter < 0) { return (XFS_ERROR(ENOSPC)); } mp->m_sb.sb_frextents = lcounter; return (0); case XFS_SBS_DBLOCKS: lcounter = (long long)mp->m_sb.sb_dblocks; lcounter += delta; if (lcounter < 0) { ASSERT(0); return (XFS_ERROR(EINVAL)); } mp->m_sb.sb_dblocks = lcounter; return (0); case XFS_SBS_AGCOUNT: scounter = mp->m_sb.sb_agcount; scounter += delta; if (scounter < 0) { ASSERT(0); return (XFS_ERROR(EINVAL)); } mp->m_sb.sb_agcount = scounter; return (0); case XFS_SBS_IMAX_PCT: scounter = mp->m_sb.sb_imax_pct; scounter += delta; if (scounter < 0) { ASSERT(0); return (XFS_ERROR(EINVAL)); } mp->m_sb.sb_imax_pct = scounter; return (0); case XFS_SBS_REXTSIZE: scounter = mp->m_sb.sb_rextsize; scounter += delta; if (scounter < 0) { ASSERT(0); return (XFS_ERROR(EINVAL)); } mp->m_sb.sb_rextsize = scounter; return (0); case XFS_SBS_RBMBLOCKS: scounter = mp->m_sb.sb_rbmblocks; scounter += delta; if (scounter < 0) { ASSERT(0); return (XFS_ERROR(EINVAL)); } mp->m_sb.sb_rbmblocks = scounter; return (0); case XFS_SBS_RBLOCKS: lcounter = (long long)mp->m_sb.sb_rblocks; lcounter += delta; if (lcounter < 0) { ASSERT(0); return (XFS_ERROR(EINVAL)); } mp->m_sb.sb_rblocks = lcounter; return (0); case XFS_SBS_REXTENTS: lcounter = (long long)mp->m_sb.sb_rextents; lcounter += delta; if (lcounter < 0) { ASSERT(0); return (XFS_ERROR(EINVAL)); } mp->m_sb.sb_rextents = lcounter; return (0); case XFS_SBS_REXTSLOG: scounter = mp->m_sb.sb_rextslog; scounter += delta; if (scounter < 0) { ASSERT(0); return (XFS_ERROR(EINVAL)); } mp->m_sb.sb_rextslog = scounter; return (0); default: ASSERT(0); return (XFS_ERROR(EINVAL)); }}/* * xfs_mod_incore_sb() is used to change a field in the in-core * superblock structure by the specified delta. This modification * is protected by the SB_LOCK. Just use the xfs_mod_incore_sb_unlocked() * routine to do the work. */intxfs_mod_incore_sb(xfs_mount_t *mp, xfs_sb_field_t field, int delta, int rsvd){ unsigned long s; int status; s = XFS_SB_LOCK(mp); status = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd); XFS_SB_UNLOCK(mp, s); return (status);}/* * xfs_mod_incore_sb_batch() is used to change more than one field * in the in-core superblock structure at a time. This modification * is protected by a lock internal to this module. The fields and * changes to those fields are specified in the array of xfs_mod_sb * structures passed in. * * Either all of the specified deltas will be applied or none of * them will. If any modified field dips below 0, then all modifications * will be backed out and EINVAL will be returned. */intxfs_mod_incore_sb_batch(xfs_mount_t *mp, xfs_mod_sb_t *msb, uint nmsb, int rsvd){ unsigned long s; int status=0; xfs_mod_sb_t *msbp; /* * Loop through the array of mod structures and apply each * individually. If any fail, then back out all those * which have already been applied. Do all of this within * the scope of the SB_LOCK so that all of the changes will * be atomic. */ s = XFS_SB_LOCK(mp); msbp = &msb[0]; for (msbp = &msbp[0]; msbp < (msb + nmsb); msbp++) { /* * Apply the delta at index n. If it fails, break * from the loop so we'll fall into the undo loop * below. */ status = xfs_mod_incore_sb_unlocked(mp, msbp->msb_field, msbp->msb_delta, rsvd); if (status != 0) { break; } } /* * If we didn't complete the loop above, then back out * any changes made to the superblock. If you add code * between the loop above and here, make sure that you * preserve the value of status. Loop back until * we step below the beginning of the array. Make sure * we don't touch anything back there. */ if (status != 0) { msbp--; while (msbp >= msb) { status = xfs_mod_incore_sb_unlocked(mp, msbp->msb_field, -(msbp->msb_delta), rsvd); ASSERT(status == 0); msbp--; } } XFS_SB_UNLOCK(mp, s); return (status);}/* * xfs_getsb() is called to obtain the buffer for the superblock. * The buffer is returned locked and read in from disk. * The buffer should be released with a call to xfs_brelse(). * * If the flags parameter is BUF_TRYLOCK, then we'll only return * the superblock buffer if it can be locked without sleeping. * If it can't then we'll return NULL. */xfs_buf_t *xfs_getsb( xfs_mount_t *mp, int flags){ xfs_buf_t *bp; ASSERT(mp->m_sb_bp != NULL); bp = mp->m_sb_bp; if (flags & XFS_BUF_TRYLOCK) { if (!XFS_BUF_CPSEMA(bp)) { return NULL; } } else { XFS_BUF_PSEMA(bp, PRIBIO); } XFS_BUF_HOLD(bp); ASSERT(XFS_BUF_ISDONE(bp)); return (bp);}/* * Used to free the superblock along various error paths. */voidxfs_freesb( xfs_mount_t *mp){ xfs_buf_t *bp; /* * Use xfs_getsb() so that the buffer will be locked * when we call xfs_buf_relse(). */ bp = xfs_getsb(mp, 0); XFS_BUF_UNMANAGE(bp); xfs_buf_relse(bp); mp->m_sb_bp = NULL;}/* * See if the UUID is unique among mounted XFS filesystems. * Mount fails if UUID is nil or a FS with the same UUID is already mounted. */STATIC intxfs_uuid_mount( xfs_mount_t *mp){ if (uuid_is_nil(&mp->m_sb.sb_uuid)) { cmn_err(CE_WARN, "XFS: Filesystem %s has nil UUID - can't mount", mp->m_fsname); return -1; } if (!uuid_table_insert(&mp->m_sb.sb_uuid)) { cmn_err(CE_WARN, "XFS: Filesystem %s has duplicate UUID - can't mount", mp->m_fsname); return -1; } return 0;}/* * Remove filesystem from the UUID table. */STATIC voidxfs_uuid_unmount( xfs_mount_t *mp){ uuid_table_remove(&mp->m_sb.sb_uuid);}/* * Used to log changes to the superblock unit and width fields which could * be altered by the mount options. Only the first superblock is updated. */STATIC voidxfs_mount_log_sbunit( xfs_mount_t *mp, __int64_t fields){ xfs_trans_t *tp; ASSERT(fields & (XFS_SB_UNIT|XFS_SB_WIDTH|XFS_SB_UUID)); tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT); if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, XFS_DEFAULT_LOG_COUNT)) { xfs_trans_cancel(tp, 0); return; } xfs_mod_sb(tp, fields); xfs_trans_commit(tp, 0, NULL);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?