📄 xfs_mount.c
字号:
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, "amount, "aflags))) 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 + -