/* * Removing an attribute. * the inode: inode size * the attribute btree could join: max depth * block size * the inode bmap btree could join or split: max depth * block size * And the bmap_finish transaction can free the attr blocks freed giving: * the agf for the ag in which the blocks live: 2 * sector size * the agfl for the ag in which the blocks live: 2 * sector size * the superblock for the free block count: sector size * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size */ STATIC uint xfs_calc_attrrm_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + MAX((xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_DA_NODE_MAXDEPTH, XFS_FSB_TO_B(mp, 1)) + (uint)XFS_FSB_TO_B(mp, XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK), 0)), (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2), XFS_FSB_TO_B(mp, 1)))); }
/* * Setting an attribute at runtime, transaction space unit per block. * the superblock for allocations: sector size * the inode bmap btree could join or split: max depth * block size * Since the runtime attribute transaction space is dependent on the total * blocks needed for the 1st bmap, here we calculate out the space unit for * one block so that the caller could figure out the total space according * to the attibute extent length in blocks by: * ext * M_RES(mp)->tr_attrsetrt.tr_logres */ STATIC uint xfs_calc_attrsetrt_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK), XFS_FSB_TO_B(mp, 1)); }
/* * Removing the attribute fork of a file * the inode being truncated: inode size * the inode's bmap btree: max depth * block size * And the bmap_finish transaction can free the blocks and bmap blocks: * the agf for each of the ags: 4 * sector size * the agfl for each of the ags: 4 * sector size * the super block to reflect the freed blocks: sector size * worst case split in allocation btrees per extent assuming 4 extents: * 4 exts * 2 trees * (2 * max depth - 1) * block size */ STATIC uint xfs_calc_attrinval_reservation( struct xfs_mount *mp) { return MAX((xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK), XFS_FSB_TO_B(mp, 1))), (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 4), XFS_FSB_TO_B(mp, 1)))); }
/* * Growing the rt section of the filesystem. * In the first set of transactions (ALLOC) we allocate space to the * bitmap or summary files. * superblock: sector size * agf of the ag from which the extent is allocated: sector size * bmap btree for bitmap/summary inode: max depth * blocksize * bitmap/summary inode: inode size * allocation btrees for 1 block alloc: 2 * (2 * maxdepth - 1) * blocksize */ STATIC uint xfs_calc_growrtalloc_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK), XFS_FSB_TO_B(mp, 1)) + xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), XFS_FSB_TO_B(mp, 1)); }
/* * Removing the attribute fork of a file * the inode being truncated: inode size * the inode's bmap btree: max depth * block size * And the bmap_finish transaction can free the blocks and bmap blocks: * the agf for each of the ags: 4 * sector size * the agfl for each of the ags: 4 * sector size * the super block to reflect the freed blocks: sector size * worst case split in allocation btrees per extent assuming 4 extents: * 4 exts * 2 trees * (2 * max depth - 1) * block size */ STATIC uint xfs_calc_attrinval_reservation( struct xfs_mount *mp) { return max((xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK), XFS_FSB_TO_B(mp, 1))), (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(xfs_allocfree_log_count(mp, 4), XFS_FSB_TO_B(mp, 1)))); }
/* * In truncating a file we free up to two extents at once. We can modify: * the inode being truncated: inode size * the inode's bmap btree: (max depth + 1) * block size * And the bmap_finish transaction can free the blocks and bmap blocks: * the agf for each of the ags: 4 * sector size * the agfl for each of the ags: 4 * sector size * the super block to reflect the freed blocks: sector size * worst case split in allocation btrees per extent assuming 4 extents: * 4 exts * 2 trees * (2 * max depth - 1) * block size */ STATIC uint xfs_calc_itruncate_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + max((xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + 1, XFS_FSB_TO_B(mp, 1))), (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(xfs_allocfree_log_count(mp, 4), XFS_FSB_TO_B(mp, 1)))); }
/* * In truncating a file we free up to two extents at once. We can modify: * the inode being truncated: inode size * the inode's bmap btree: (max depth + 1) * block size * And the bmap_finish transaction can free the blocks and bmap blocks: * the agf for each of the ags: 4 * sector size * the agfl for each of the ags: 4 * sector size * the super block to reflect the freed blocks: sector size * worst case split in allocation btrees per extent assuming 4 extents: * 4 exts * 2 trees * (2 * max depth - 1) * block size * the inode btree: max depth * blocksize * the allocation btrees: 2 trees * (max depth - 1) * block size */ STATIC uint xfs_calc_itruncate_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + MAX((xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + 1, XFS_FSB_TO_B(mp, 1))), (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 4), XFS_FSB_TO_B(mp, 1)) + xfs_calc_buf_res(5, 0) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), XFS_FSB_TO_B(mp, 1)) + xfs_calc_buf_res(2 + mp->m_ialloc_blks + mp->m_in_maxlevels, 0))); }
int xfs_bm_maxlevels(xfs_mount_t *mp, int w) { return XFS_BM_MAXLEVELS(mp, w); }
/* * Allocate the realtime bitmap and summary inodes, and fill in data if any. */ static void rtinit( xfs_mount_t *mp) { xfs_dfiloff_t bno; int committed; xfs_dfiloff_t ebno; xfs_bmbt_irec_t *ep; int error; xfs_fsblock_t first; xfs_bmap_free_t flist; int i; xfs_bmbt_irec_t map[XFS_BMAP_MAX_NMAP]; xfs_extlen_t nsumblocks; int nmap; xfs_inode_t *rbmip; xfs_inode_t *rsumip; xfs_trans_t *tp; struct cred creds; struct fsxattr fsxattrs; /* * First, allocate the inodes. */ tp = libxfs_trans_alloc(mp, 0); if ((i = libxfs_trans_reserve(tp, MKFS_BLOCKRES_INODE, 0, 0, 0, 0))) res_failed(i); memset(&creds, 0, sizeof(creds)); memset(&fsxattrs, 0, sizeof(fsxattrs)); error = libxfs_inode_alloc(&tp, NULL, S_IFREG, 1, 0, &creds, &fsxattrs, &rbmip); if (error) { fail(_("Realtime bitmap inode allocation failed"), error); } /* * Do our thing with rbmip before allocating rsumip, * because the next call to ialloc() may * commit the transaction in which rbmip was allocated. */ mp->m_sb.sb_rbmino = rbmip->i_ino; rbmip->i_d.di_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize; rbmip->i_d.di_flags = XFS_DIFLAG_NEWRTBM; *(__uint64_t *)&rbmip->i_d.di_atime = 0; libxfs_trans_log_inode(tp, rbmip, XFS_ILOG_CORE); libxfs_mod_sb(tp, XFS_SB_RBMINO); libxfs_trans_ihold(tp, rbmip); mp->m_rbmip = rbmip; error = libxfs_inode_alloc(&tp, NULL, S_IFREG, 1, 0, &creds, &fsxattrs, &rsumip); if (error) { fail(_("Realtime summary inode allocation failed"), error); } mp->m_sb.sb_rsumino = rsumip->i_ino; rsumip->i_d.di_size = mp->m_rsumsize; libxfs_trans_log_inode(tp, rsumip, XFS_ILOG_CORE); libxfs_mod_sb(tp, XFS_SB_RSUMINO); libxfs_trans_ihold(tp, rsumip); libxfs_trans_commit(tp, 0); mp->m_rsumip = rsumip; /* * Next, give the bitmap file some zero-filled blocks. */ tp = libxfs_trans_alloc(mp, 0); if ((i = libxfs_trans_reserve(tp, mp->m_sb.sb_rbmblocks + (XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1), 0, 0, 0, 0))) res_failed(i); libxfs_trans_ijoin(tp, rbmip, 0); libxfs_trans_ihold(tp, rbmip); bno = 0; xfs_bmap_init(&flist, &first); while (bno < mp->m_sb.sb_rbmblocks) { nmap = XFS_BMAP_MAX_NMAP; error = libxfs_bmapi(tp, rbmip, bno, (xfs_extlen_t)(mp->m_sb.sb_rbmblocks - bno), XFS_BMAPI_WRITE, &first, mp->m_sb.sb_rbmblocks, map, &nmap, &flist); if (error) { fail(_("Allocation of the realtime bitmap failed"), error); } for (i = 0, ep = map; i < nmap; i++, ep++) { libxfs_device_zero(mp->m_dev, XFS_FSB_TO_DADDR(mp, ep->br_startblock), XFS_FSB_TO_BB(mp, ep->br_blockcount)); bno += ep->br_blockcount; } } error = libxfs_bmap_finish(&tp, &flist, &committed); if (error) { fail(_("Completion of the realtime bitmap failed"), error); } libxfs_trans_commit(tp, 0); /* * Give the summary file some zero-filled blocks. */ tp = libxfs_trans_alloc(mp, 0); nsumblocks = mp->m_rsumsize >> mp->m_sb.sb_blocklog; if ((i = libxfs_trans_reserve(tp, nsumblocks + (XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1), 0, 0, 0, 0))) res_failed(i); libxfs_trans_ijoin(tp, rsumip, 0); libxfs_trans_ihold(tp, rsumip); bno = 0; xfs_bmap_init(&flist, &first); while (bno < nsumblocks) { nmap = XFS_BMAP_MAX_NMAP; error = libxfs_bmapi(tp, rsumip, bno, (xfs_extlen_t)(nsumblocks - bno), XFS_BMAPI_WRITE, &first, nsumblocks, map, &nmap, &flist); if (error) { fail(_("Allocation of the realtime summary failed"), error); } for (i = 0, ep = map; i < nmap; i++, ep++) { libxfs_device_zero(mp->m_dev, XFS_FSB_TO_DADDR(mp, ep->br_startblock), XFS_FSB_TO_BB(mp, ep->br_blockcount)); bno += ep->br_blockcount; } } error = libxfs_bmap_finish(&tp, &flist, &committed); if (error) { fail(_("Completion of the realtime summary failed"), error); } libxfs_trans_commit(tp, 0); /* * Free the whole area using transactions. * Do one transaction per bitmap block. */ for (bno = 0; bno < mp->m_sb.sb_rextents; bno = ebno) { tp = libxfs_trans_alloc(mp, 0); if ((i = libxfs_trans_reserve(tp, 0, 0, 0, 0, 0))) res_failed(i); xfs_bmap_init(&flist, &first); ebno = XFS_RTMIN(mp->m_sb.sb_rextents, bno + NBBY * mp->m_sb.sb_blocksize); error = libxfs_rtfree_extent(tp, bno, (xfs_extlen_t)(ebno-bno)); if (error) { fail(_("Error initializing the realtime space"), error); } error = libxfs_bmap_finish(&tp, &flist, &committed); if (error) { fail(_("Error completing the realtime space"), error); } libxfs_trans_commit(tp, 0); } }