📄 xfs_rtalloc.c
字号:
xfs_sb_t *sbp; /* old superblock */ xfs_fsblock_t sumbno; /* summary block number */ xfs_trans_t *tp; /* transaction pointer */ sbp = &mp->m_sb; /* * Initial error checking. */ if (mp->m_rtdev_targp == NULL || mp->m_rbmip == NULL || (nrblocks = in->newblocks) <= sbp->sb_rblocks || (sbp->sb_rblocks && (in->extsize != sbp->sb_rextsize))) return XFS_ERROR(EINVAL); if ((error = xfs_sb_validate_fsb_count(sbp, nrblocks))) return error; /* * Read in the last block of the device, make sure it exists. */ error = xfs_read_buf(mp, mp->m_rtdev_targp, XFS_FSB_TO_BB(mp, nrblocks - 1), XFS_FSB_TO_BB(mp, 1), 0, &bp); if (error) return error; ASSERT(bp); xfs_buf_relse(bp); /* * Calculate new parameters. These are the final values to be reached. */ nrextents = nrblocks; do_div(nrextents, in->extsize); nrbmblocks = howmany_64(nrextents, NBBY * sbp->sb_blocksize); nrextslog = xfs_highbit32(nrextents); nrsumlevels = nrextslog + 1; nrsumsize = (uint)sizeof(xfs_suminfo_t) * nrsumlevels * nrbmblocks; nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize); nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks); /* * New summary size can't be more than half the size of * the log. This prevents us from getting a log overflow, * since we'll log basically the whole summary file at once. */ if (nrsumblocks > (mp->m_sb.sb_logblocks >> 1)) return XFS_ERROR(EINVAL); /* * Get the old block counts for bitmap and summary inodes. * These can't change since other growfs callers are locked out. */ rbmblocks = XFS_B_TO_FSB(mp, mp->m_rbmip->i_d.di_size); rsumblocks = XFS_B_TO_FSB(mp, mp->m_rsumip->i_d.di_size); /* * Allocate space to the bitmap and summary files, as necessary. */ if ((error = xfs_growfs_rt_alloc(mp, rbmblocks, nrbmblocks, mp->m_sb.sb_rbmino))) return error; if ((error = xfs_growfs_rt_alloc(mp, rsumblocks, nrsumblocks, mp->m_sb.sb_rsumino))) return error; /* * Allocate a new (fake) mount/sb. */ nmp = kmem_alloc(sizeof(*nmp), KM_SLEEP); /* * Loop over the bitmap blocks. * We will do everything one bitmap block at a time. * Skip the current block if it is exactly full. * This also deals with the case where there were no rtextents before. */ for (bmbno = sbp->sb_rbmblocks - ((sbp->sb_rextents & ((1 << mp->m_blkbit_log) - 1)) != 0); bmbno < nrbmblocks; bmbno++) { *nmp = *mp; nsbp = &nmp->m_sb; /* * Calculate new sb and mount fields for this round. */ nsbp->sb_rextsize = in->extsize; nsbp->sb_rbmblocks = bmbno + 1; nsbp->sb_rblocks = XFS_RTMIN(nrblocks, nsbp->sb_rbmblocks * NBBY * nsbp->sb_blocksize * nsbp->sb_rextsize); nsbp->sb_rextents = nsbp->sb_rblocks; do_div(nsbp->sb_rextents, nsbp->sb_rextsize); nsbp->sb_rextslog = xfs_highbit32(nsbp->sb_rextents); nrsumlevels = nmp->m_rsumlevels = nsbp->sb_rextslog + 1; nrsumsize = (uint)sizeof(xfs_suminfo_t) * nrsumlevels * nsbp->sb_rbmblocks; nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize); nmp->m_rsumsize = nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks); /* * Start a transaction, get the log reservation. */ tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_FREE); cancelflags = 0; if ((error = xfs_trans_reserve(tp, 0, XFS_GROWRTFREE_LOG_RES(nmp), 0, 0, 0))) break; /* * Lock out other callers by grabbing the bitmap inode lock. */ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip))) break; ASSERT(ip == mp->m_rbmip); /* * Update the bitmap inode's size. */ mp->m_rbmip->i_d.di_size = nsbp->sb_rbmblocks * nsbp->sb_blocksize; xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE); cancelflags |= XFS_TRANS_ABORT; /* * Get the summary inode into the transaction. */ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0, XFS_ILOCK_EXCL, &ip))) break; ASSERT(ip == mp->m_rsumip); /* * Update the summary inode's size. */ mp->m_rsumip->i_d.di_size = nmp->m_rsumsize; xfs_trans_log_inode(tp, mp->m_rsumip, XFS_ILOG_CORE); /* * Copy summary data from old to new sizes. * Do this when the real size (not block-aligned) changes. */ if (sbp->sb_rbmblocks != nsbp->sb_rbmblocks || mp->m_rsumlevels != nmp->m_rsumlevels) { error = xfs_rtcopy_summary(mp, nmp, tp); if (error) break; } /* * Update superblock fields. */ if (nsbp->sb_rextsize != sbp->sb_rextsize) xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTSIZE, nsbp->sb_rextsize - sbp->sb_rextsize); if (nsbp->sb_rbmblocks != sbp->sb_rbmblocks) xfs_trans_mod_sb(tp, XFS_TRANS_SB_RBMBLOCKS, nsbp->sb_rbmblocks - sbp->sb_rbmblocks); if (nsbp->sb_rblocks != sbp->sb_rblocks) xfs_trans_mod_sb(tp, XFS_TRANS_SB_RBLOCKS, nsbp->sb_rblocks - sbp->sb_rblocks); if (nsbp->sb_rextents != sbp->sb_rextents) xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTENTS, nsbp->sb_rextents - sbp->sb_rextents); if (nsbp->sb_rextslog != sbp->sb_rextslog) xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTSLOG, nsbp->sb_rextslog - sbp->sb_rextslog); /* * Free new extent. */ bp = NULL; error = xfs_rtfree_range(nmp, tp, sbp->sb_rextents, nsbp->sb_rextents - sbp->sb_rextents, &bp, &sumbno); if (error) break; /* * Mark more blocks free in the superblock. */ xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, nsbp->sb_rextents - sbp->sb_rextents); /* * Update mp values into the real mp structure. */ mp->m_rsumlevels = nrsumlevels; mp->m_rsumsize = nrsumsize; /* * Commit the transaction. */ xfs_trans_commit(tp, 0); } if (error) xfs_trans_cancel(tp, cancelflags); /* * Free the fake mp structure. */ kmem_free(nmp, sizeof(*nmp)); return error;}/* * Allocate an extent in the realtime subvolume, with the usual allocation * parameters. The length units are all in realtime extents, as is the * result block number. */int /* error */xfs_rtallocate_extent( xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t bno, /* starting block number to allocate */ xfs_extlen_t minlen, /* minimum length to allocate */ xfs_extlen_t maxlen, /* maximum length to allocate */ xfs_extlen_t *len, /* out: actual length allocated */ xfs_alloctype_t type, /* allocation type XFS_ALLOCTYPE... */ int wasdel, /* was a delayed allocation extent */ xfs_extlen_t prod, /* extent product factor */ xfs_rtblock_t *rtblock) /* out: start block allocated */{ int error; /* error value */ xfs_inode_t *ip; /* inode for bitmap file */ xfs_mount_t *mp; /* file system mount structure */ xfs_rtblock_t r; /* result allocated block */ xfs_fsblock_t sb; /* summary file block number */ xfs_buf_t *sumbp; /* summary file block buffer */ ASSERT(minlen > 0 && minlen <= maxlen); mp = tp->t_mountp; /* * If prod is set then figure out what to do to minlen and maxlen. */ if (prod > 1) { xfs_extlen_t i; if ((i = maxlen % prod)) maxlen -= i; if ((i = minlen % prod)) minlen += prod - i; if (maxlen < minlen) { *rtblock = NULLRTBLOCK; return 0; } } /* * Lock out other callers by grabbing the bitmap inode lock. */ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip))) return error; sumbp = NULL; /* * Allocate by size, or near another block, or exactly at some block. */ switch (type) { case XFS_ALLOCTYPE_ANY_AG: error = xfs_rtallocate_extent_size(mp, tp, minlen, maxlen, len, &sumbp, &sb, prod, &r); break; case XFS_ALLOCTYPE_NEAR_BNO: error = xfs_rtallocate_extent_near(mp, tp, bno, minlen, maxlen, len, &sumbp, &sb, prod, &r); break; case XFS_ALLOCTYPE_THIS_BNO: error = xfs_rtallocate_extent_exact(mp, tp, bno, minlen, maxlen, len, &sumbp, &sb, prod, &r); break; default: ASSERT(0); } if (error) { return error; } /* * If it worked, update the superblock. */ if (r != NULLRTBLOCK) { long slen = (long)*len; ASSERT(*len >= minlen && *len <= maxlen); if (wasdel) xfs_trans_mod_sb(tp, XFS_TRANS_SB_RES_FREXTENTS, -slen); else xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, -slen); } *rtblock = r; return 0;}/* * Free an extent in the realtime subvolume. Length is expressed in * realtime extents, as is the block number. */int /* error */xfs_rtfree_extent( xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t bno, /* starting block number to free */ xfs_extlen_t len) /* length of extent freed */{ int error; /* error value */ xfs_inode_t *ip; /* bitmap file inode */ xfs_mount_t *mp; /* file system mount structure */ xfs_fsblock_t sb; /* summary file block number */ xfs_buf_t *sumbp; /* summary file block buffer */ mp = tp->t_mountp; /* * Synchronize by locking the bitmap inode. */ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip))) return error;#if defined(__KERNEL__) && defined(DEBUG) /* * Check to see that this whole range is currently allocated. */ { int stat; /* result from checking range */ error = xfs_rtcheck_alloc_range(mp, tp, bno, len, &stat); if (error) { return error; } ASSERT(stat); }#endif sumbp = NULL; /* * Free the range of realtime blocks. */ error = xfs_rtfree_range(mp, tp, bno, len, &sumbp, &sb); if (error) { return error; } /* * Mark more blocks free in the superblock. */ xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, (long)len); /* * If we've now freed all the blocks, reset the file sequence * number to 0. */ if (tp->t_frextents_delta + mp->m_sb.sb_frextents == mp->m_sb.sb_rextents) { if (!(ip->i_d.di_flags & XFS_DIFLAG_NEWRTBM)) ip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM; *(__uint64_t *)&ip->i_d.di_atime = 0; xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); } return 0;}/* * Initialize realtime fields in the mount structure. */int /* error */xfs_rtmount_init( xfs_mount_t *mp) /* file system mount structure */{ xfs_buf_t *bp; /* buffer for last block of subvolume */ xfs_daddr_t d; /* address of last block of subvolume */ int error; /* error return value */ xfs_sb_t *sbp; /* filesystem superblock copy in mount */ sbp = &mp->m_sb; if (sbp->sb_rblocks == 0) return 0; if (mp->m_rtdev_targp == NULL) { cmn_err(CE_WARN, "XFS: This filesystem has a realtime volume, use rtdev=device option"); return XFS_ERROR(ENODEV); } mp->m_rsumlevels = sbp->sb_rextslog + 1; mp->m_rsumsize = (uint)sizeof(xfs_suminfo_t) * mp->m_rsumlevels * sbp->sb_rbmblocks; mp->m_rsumsize = roundup(mp->m_rsumsize, sbp->sb_blocksize); mp->m_rbmip = mp->m_rsumip = NULL; /* * Check that the realtime section is an ok size. */ d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks); if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_rblocks) { cmn_err(CE_WARN, "XFS: realtime mount -- %llu != %llu", (unsigned long long) XFS_BB_TO_FSB(mp, d), (unsigned long long) mp->m_sb.sb_rblocks); return XFS_ERROR(E2BIG); } error = xfs_read_buf(mp, mp->m_rtdev_targp, d - XFS_FSB_TO_BB(mp, 1), XFS_FSB_TO_BB(mp, 1), 0, &bp); if (error) { cmn_err(CE_WARN, "XFS: realtime mount -- xfs_read_buf failed, returned %d", error); if (error == ENOSPC) return XFS_ERROR(E2BIG); return error; } xfs_buf_relse(bp); return 0;}/* * Get the bitmap and summary inodes into the mount structure * at mount time. */int /* error */xfs_rtmount_inodes( xfs_mount_t *mp) /* file system mount structure */{ int error; /* error return value */ xfs_sb_t *sbp; sbp = &mp->m_sb; if (sbp->sb_rbmino == NULLFSINO) return 0; error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, 0, &mp->m_rbmip, 0); if (error) return error; ASSERT(mp->m_rbmip != NULL); ASSERT(sbp->sb_rsumino != NULLFSINO); error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, 0, &mp->m_rsumip, 0); if (error) { VN_RELE(XFS_ITOV(mp->m_rbmip)); return error; } ASSERT(mp->m_rsumip != NULL); return 0;}/* * Pick an extent for allocation at the start of a new realtime file. * Use the sequence number stored in the atime field of the bitmap inode. * Translate this to a fraction of the rtextents, and return the product * of rtextents and the fraction. * The fraction sequence is 0, 1/2, 1/4, 3/4, 1/8, ..., 7/8, 1/16, ... */int /* error */xfs_rtpick_extent( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_extlen_t len, /* allocation length (rtextents) */ xfs_rtblock_t *pick) /* result rt extent */{ xfs_rtblock_t b; /* result block */ int error; /* error return value */ xfs_inode_t *ip; /* bitmap incore inode */ int log2; /* log of sequence number */ __uint64_t resid; /* residual after log removed */ __uint64_t seq; /* sequence number of file creation */ __uint64_t *seqp; /* pointer to seqno in inode */ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip))) return error; ASSERT(ip == mp->m_rbmip); seqp = (__uint64_t *)&ip->i_d.di_atime; if (!(ip->i_d.di_flags & XFS_DIFLAG_NEWRTBM)) { ip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM; *seqp = 0; } seq = *seqp; if ((log2 = xfs_highbit64(seq)) == -1) b = 0; else { resid = seq - (1ULL << log2); b = (mp->m_sb.sb_rextents * ((resid << 1) + 1ULL)) >> (log2 + 1); if (b >= mp->m_sb.sb_rextents) b = do_mod(b, mp->m_sb.sb_rextents); if (b + len > mp->m_sb.sb_rextents) b = mp->m_sb.sb_rextents - len; } *seqp = seq + 1; xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); *pick = b; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -