📄 xfs_ialloc.c
字号:
"xfs_difree: agno >= mp->m_sb.sb_agcount (%d >= %d) on %s. Returning EINVAL.", agno, mp->m_sb.sb_agcount, mp->m_fsname); ASSERT(0); return XFS_ERROR(EINVAL); } agino = XFS_INO_TO_AGINO(mp, inode); if (inode != XFS_AGINO_TO_INO(mp, agno, agino)) { cmn_err(CE_WARN, "xfs_difree: inode != XFS_AGINO_TO_INO() " "(%llu != %llu) on %s. Returning EINVAL.", (unsigned long long)inode, (unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino), mp->m_fsname); ASSERT(0); return XFS_ERROR(EINVAL); } agbno = XFS_AGINO_TO_AGBNO(mp, agino); if (agbno >= mp->m_sb.sb_agblocks) { cmn_err(CE_WARN, "xfs_difree: agbno >= mp->m_sb.sb_agblocks (%d >= %d) on %s. Returning EINVAL.", agbno, mp->m_sb.sb_agblocks, mp->m_fsname); ASSERT(0); return XFS_ERROR(EINVAL); } /* * Get the allocation group header. */ down_read(&mp->m_peraglock); error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); up_read(&mp->m_peraglock); if (error) { cmn_err(CE_WARN, "xfs_difree: xfs_ialloc_read_agi() returned an error %d on %s. Returning error.", error, mp->m_fsname); return error; } agi = XFS_BUF_TO_AGI(agbp); ASSERT(be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC); ASSERT(agbno < be32_to_cpu(agi->agi_length)); /* * Initialize the cursor. */ cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO, (xfs_inode_t *)0, 0);#ifdef DEBUG if (cur->bc_nlevels == 1) { int freecount = 0; if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) goto error0; do { if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, &rec.ir_freecount, &rec.ir_free, &i))) goto error0; if (i) { freecount += rec.ir_freecount; if ((error = xfs_inobt_increment(cur, 0, &i))) goto error0; } } while (i == 1); ASSERT(freecount == be32_to_cpu(agi->agi_freecount) || XFS_FORCED_SHUTDOWN(mp)); }#endif /* * Look for the entry describing this inode. */ if ((error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i))) { cmn_err(CE_WARN, "xfs_difree: xfs_inobt_lookup_le returned() an error %d on %s. Returning error.", error, mp->m_fsname); goto error0; } XFS_WANT_CORRUPTED_GOTO(i == 1, error0); if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, &rec.ir_freecount, &rec.ir_free, &i))) { cmn_err(CE_WARN, "xfs_difree: xfs_inobt_get_rec() returned an error %d on %s. Returning error.", error, mp->m_fsname); goto error0; } XFS_WANT_CORRUPTED_GOTO(i == 1, error0); /* * Get the offset in the inode chunk. */ off = agino - rec.ir_startino; ASSERT(off >= 0 && off < XFS_INODES_PER_CHUNK); ASSERT(!XFS_INOBT_IS_FREE(&rec, off)); /* * Mark the inode free & increment the count. */ XFS_INOBT_SET_FREE(&rec, off); rec.ir_freecount++; /* * When an inode cluster is free, it becomes eligible for removal */ if ((mp->m_flags & XFS_MOUNT_IDELETE) && (rec.ir_freecount == XFS_IALLOC_INODES(mp))) { *delete = 1; *first_ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino); /* * Remove the inode cluster from the AGI B+Tree, adjust the * AGI and Superblock inode counts, and mark the disk space * to be freed when the transaction is committed. */ ilen = XFS_IALLOC_INODES(mp); be32_add(&agi->agi_count, -ilen); be32_add(&agi->agi_freecount, -(ilen - 1)); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_COUNT | XFS_AGI_FREECOUNT); down_read(&mp->m_peraglock); mp->m_perag[agno].pagi_freecount -= ilen - 1; up_read(&mp->m_peraglock); xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, -ilen); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -(ilen - 1)); if ((error = xfs_inobt_delete(cur, &i))) { cmn_err(CE_WARN, "xfs_difree: xfs_inobt_delete returned an error %d on %s.\n", error, mp->m_fsname); goto error0; } xfs_bmap_add_free(XFS_AGB_TO_FSB(mp, agno, XFS_INO_TO_AGBNO(mp,rec.ir_startino)), XFS_IALLOC_BLOCKS(mp), flist, mp); } else { *delete = 0; if ((error = xfs_inobt_update(cur, rec.ir_startino, rec.ir_freecount, rec.ir_free))) { cmn_err(CE_WARN, "xfs_difree: xfs_inobt_update() returned an error %d on %s. Returning error.", error, mp->m_fsname); goto error0; } /* * Change the inode free counts and log the ag/sb changes. */ be32_add(&agi->agi_freecount, 1); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); down_read(&mp->m_peraglock); mp->m_perag[agno].pagi_freecount++; up_read(&mp->m_peraglock); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1); }#ifdef DEBUG if (cur->bc_nlevels == 1) { int freecount = 0; if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) goto error0; do { if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, &rec.ir_freecount, &rec.ir_free, &i))) goto error0; if (i) { freecount += rec.ir_freecount; if ((error = xfs_inobt_increment(cur, 0, &i))) goto error0; } } while (i == 1); ASSERT(freecount == be32_to_cpu(agi->agi_freecount) || XFS_FORCED_SHUTDOWN(mp)); }#endif xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); return 0;error0: xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); return error;}/* * Return the location of the inode in bno/off, for mapping it into a buffer. *//*ARGSUSED*/intxfs_dilocate( xfs_mount_t *mp, /* file system mount structure */ xfs_trans_t *tp, /* transaction pointer */ xfs_ino_t ino, /* inode to locate */ xfs_fsblock_t *bno, /* output: block containing inode */ int *len, /* output: num blocks in inode cluster */ int *off, /* output: index in block of inode */ uint flags) /* flags concerning inode lookup */{ xfs_agblock_t agbno; /* block number of inode in the alloc group */ xfs_buf_t *agbp; /* agi buffer */ xfs_agino_t agino; /* inode number within alloc group */ xfs_agnumber_t agno; /* allocation group number */ int blks_per_cluster; /* num blocks per inode cluster */ xfs_agblock_t chunk_agbno; /* first block in inode chunk */ xfs_agino_t chunk_agino; /* first agino in inode chunk */ __int32_t chunk_cnt; /* count of free inodes in chunk */ xfs_inofree_t chunk_free; /* mask of free inodes in chunk */ xfs_agblock_t cluster_agbno; /* first block in inode cluster */ xfs_btree_cur_t *cur; /* inode btree cursor */ int error; /* error code */ int i; /* temp state */ int offset; /* index of inode in its buffer */ int offset_agbno; /* blks from chunk start to inode */ ASSERT(ino != NULLFSINO); /* * Split up the inode number into its parts. */ agno = XFS_INO_TO_AGNO(mp, ino); agino = XFS_INO_TO_AGINO(mp, ino); agbno = XFS_AGINO_TO_AGBNO(mp, agino); if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks || ino != XFS_AGINO_TO_INO(mp, agno, agino)) {#ifdef DEBUG /* no diagnostics for bulkstat, ino comes from userspace */ if (flags & XFS_IMAP_BULKSTAT) return XFS_ERROR(EINVAL); if (agno >= mp->m_sb.sb_agcount) { xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: agno (%d) >= " "mp->m_sb.sb_agcount (%d)", agno, mp->m_sb.sb_agcount); } if (agbno >= mp->m_sb.sb_agblocks) { xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: agbno (0x%llx) >= " "mp->m_sb.sb_agblocks (0x%lx)", (unsigned long long) agbno, (unsigned long) mp->m_sb.sb_agblocks); } if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) { xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: ino (0x%llx) != " "XFS_AGINO_TO_INO(mp, agno, agino) " "(0x%llx)", ino, XFS_AGINO_TO_INO(mp, agno, agino)); } xfs_stack_trace();#endif /* DEBUG */ return XFS_ERROR(EINVAL); } if ((mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) || !(flags & XFS_IMAP_LOOKUP)) { offset = XFS_INO_TO_OFFSET(mp, ino); ASSERT(offset < mp->m_sb.sb_inopblock); *bno = XFS_AGB_TO_FSB(mp, agno, agbno); *off = offset; *len = 1; return 0; } blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog; if (*bno != NULLFSBLOCK) { offset = XFS_INO_TO_OFFSET(mp, ino); ASSERT(offset < mp->m_sb.sb_inopblock); cluster_agbno = XFS_FSB_TO_AGBNO(mp, *bno); *off = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + offset; *len = blks_per_cluster; return 0; } if (mp->m_inoalign_mask) { offset_agbno = agbno & mp->m_inoalign_mask; chunk_agbno = agbno - offset_agbno; } else { down_read(&mp->m_peraglock); error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); up_read(&mp->m_peraglock); if (error) {#ifdef DEBUG xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: " "xfs_ialloc_read_agi() returned " "error %d, agno %d", error, agno);#endif /* DEBUG */ return error; } cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO, (xfs_inode_t *)0, 0); if ((error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i))) {#ifdef DEBUG xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: " "xfs_inobt_lookup_le() failed");#endif /* DEBUG */ goto error0; } if ((error = xfs_inobt_get_rec(cur, &chunk_agino, &chunk_cnt, &chunk_free, &i))) {#ifdef DEBUG xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: " "xfs_inobt_get_rec() failed");#endif /* DEBUG */ goto error0; } if (i == 0) {#ifdef DEBUG xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: " "xfs_inobt_get_rec() failed");#endif /* DEBUG */ error = XFS_ERROR(EINVAL); } xfs_trans_brelse(tp, agbp); xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); if (error) return error; chunk_agbno = XFS_AGINO_TO_AGBNO(mp, chunk_agino); offset_agbno = agbno - chunk_agbno; } ASSERT(agbno >= chunk_agbno); cluster_agbno = chunk_agbno + ((offset_agbno / blks_per_cluster) * blks_per_cluster); offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + XFS_INO_TO_OFFSET(mp, ino); *bno = XFS_AGB_TO_FSB(mp, agno, cluster_agbno); *off = offset; *len = blks_per_cluster; return 0;error0: xfs_trans_brelse(tp, agbp); xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); return error;}/* * Compute and fill in value of m_in_maxlevels. */voidxfs_ialloc_compute_maxlevels( xfs_mount_t *mp) /* file system mount structure */{ int level; uint maxblocks; uint maxleafents; int minleafrecs; int minnoderecs; maxleafents = (1LL << XFS_INO_AGINO_BITS(mp)) >> XFS_INODES_PER_CHUNK_LOG; minleafrecs = mp->m_alloc_mnr[0]; minnoderecs = mp->m_alloc_mnr[1]; maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; for (level = 1; maxblocks > 1; level++) maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs; mp->m_in_maxlevels = level;}/* * Log specified fields for the ag hdr (inode section) */voidxfs_ialloc_log_agi( xfs_trans_t *tp, /* transaction pointer */ xfs_buf_t *bp, /* allocation group header buffer */ int fields) /* bitmask of fields to log */{ int first; /* first byte number */ int last; /* last byte number */ static const short offsets[] = { /* field starting offsets */ /* keep in sync with bit definitions */ offsetof(xfs_agi_t, agi_magicnum), offsetof(xfs_agi_t, agi_versionnum), offsetof(xfs_agi_t, agi_seqno), offsetof(xfs_agi_t, agi_length), offsetof(xfs_agi_t, agi_count), offsetof(xfs_agi_t, agi_root), offsetof(xfs_agi_t, agi_level), offsetof(xfs_agi_t, agi_freecount), offsetof(xfs_agi_t, agi_newino), offsetof(xfs_agi_t, agi_dirino), offsetof(xfs_agi_t, agi_unlinked), sizeof(xfs_agi_t) };#ifdef DEBUG xfs_agi_t *agi; /* allocation group header */ agi = XFS_BUF_TO_AGI(bp); ASSERT(be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC);#endif /* * Compute byte offsets for the first and last fields. */ xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS, &first, &last); /* * Log the allocation group inode header buffer. */ xfs_trans_log_buf(tp, bp, first, last);}/* * Read in the allocation group header (inode allocation section) */intxfs_ialloc_read_agi( xfs_mount_t *mp, /* file system mount structure */ xfs_trans_t *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ xfs_buf_t **bpp) /* allocation group hdr buf */{ xfs_agi_t *agi; /* allocation group header */ int agi_ok; /* agi is consistent */ xfs_buf_t *bp; /* allocation group hdr buf */ xfs_perag_t *pag; /* per allocation group data */ int error; ASSERT(agno != NULLAGNUMBER); error = xfs_trans_read_buf( mp, tp, mp->m_ddev_targp, XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), 0, &bp); if (error) return error; ASSERT(bp && !XFS_BUF_GETERROR(bp)); /* * Validate the magic number of the agi block. */ agi = XFS_BUF_TO_AGI(bp); agi_ok = be32_to_cpu(agi->agi_magicnum) == XFS_AGI_MAGIC && XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)); if (unlikely(XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IALLOC_READ_AGI, XFS_RANDOM_IALLOC_READ_AGI))) { XFS_CORRUPTION_ERROR("xfs_ialloc_read_agi", XFS_ERRLEVEL_LOW, mp, agi); xfs_trans_brelse(tp, bp); return XFS_ERROR(EFSCORRUPTED); } pag = &mp->m_perag[agno]; if (!pag->pagi_init) { pag->pagi_freecount = be32_to_cpu(agi->agi_freecount); pag->pagi_count = be32_to_cpu(agi->agi_count); pag->pagi_init = 1; } else { /* * It's possible for these to be out of sync if * we are in the middle of a forced shutdown. */ ASSERT(pag->pagi_freecount == be32_to_cpu(agi->agi_freecount) || XFS_FORCED_SHUTDOWN(mp)); }#ifdef DEBUG { int i; for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) ASSERT(agi->agi_unlinked[i]); }#endif XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGI, XFS_AGI_REF); *bpp = bp; return 0;}/* * Read in the agi to initialise the per-ag data in the mount structure */intxfs_ialloc_pagi_init( xfs_mount_t *mp, /* file system mount structure */ xfs_trans_t *tp, /* transaction pointer */ xfs_agnumber_t agno) /* allocation group number */{ xfs_buf_t *bp = NULL; int error; error = xfs_ialloc_read_agi(mp, tp, agno, &bp); if (error) return error; if (bp) xfs_trans_brelse(tp, bp); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -