xfs_dir2_data.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 856 行 · 第 1/2 页
C
856 行
*/ error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, blkno), -1, &bp, XFS_DATA_FORK); if (error) { return error; } ASSERT(bp != NULL); /* * Initialize the header. */ d = bp->data; INT_SET(d->hdr.magic, ARCH_CONVERT, XFS_DIR2_DATA_MAGIC); INT_SET(d->hdr.bestfree[0].offset, ARCH_CONVERT, (xfs_dir2_data_off_t)sizeof(d->hdr)); for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) { INT_ZERO(d->hdr.bestfree[i].length, ARCH_CONVERT); INT_ZERO(d->hdr.bestfree[i].offset, ARCH_CONVERT); } /* * Set up an unused entry for the block's body. */ dup = &d->u[0].unused; INT_SET(dup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); t=mp->m_dirblksize - (uint)sizeof(d->hdr); INT_SET(d->hdr.bestfree[0].length, ARCH_CONVERT, t); INT_SET(dup->length, ARCH_CONVERT, t); INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dup - (char *)d)); /* * Log it and return it. */ xfs_dir2_data_log_header(tp, bp); xfs_dir2_data_log_unused(tp, bp, dup); *bpp = bp; return 0;}/* * Log an active data entry from the block. */voidxfs_dir2_data_log_entry( xfs_trans_t *tp, /* transaction pointer */ xfs_dabuf_t *bp, /* block buffer */ xfs_dir2_data_entry_t *dep) /* data entry pointer */{ xfs_dir2_data_t *d; /* data block pointer */ d = bp->data; ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); xfs_da_log_buf(tp, bp, (uint)((char *)dep - (char *)d), (uint)((char *)(XFS_DIR2_DATA_ENTRY_TAG_P(dep) + 1) - (char *)d - 1));}/* * Log a data block header. */voidxfs_dir2_data_log_header( xfs_trans_t *tp, /* transaction pointer */ xfs_dabuf_t *bp) /* block buffer */{ xfs_dir2_data_t *d; /* data block pointer */ d = bp->data; ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); xfs_da_log_buf(tp, bp, (uint)((char *)&d->hdr - (char *)d), (uint)(sizeof(d->hdr) - 1));}/* * Log a data unused entry. */voidxfs_dir2_data_log_unused( xfs_trans_t *tp, /* transaction pointer */ xfs_dabuf_t *bp, /* block buffer */ xfs_dir2_data_unused_t *dup) /* data unused pointer */{ xfs_dir2_data_t *d; /* data block pointer */ d = bp->data; ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); /* * Log the first part of the unused entry. */ xfs_da_log_buf(tp, bp, (uint)((char *)dup - (char *)d), (uint)((char *)&dup->length + sizeof(dup->length) - 1 - (char *)d)); /* * Log the end (tag) of the unused entry. */ xfs_da_log_buf(tp, bp, (uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT) - (char *)d), (uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT) - (char *)d + sizeof(xfs_dir2_data_off_t) - 1));}/* * Make a byte range in the data block unused. * Its current contents are unimportant. */voidxfs_dir2_data_make_free( xfs_trans_t *tp, /* transaction pointer */ xfs_dabuf_t *bp, /* block buffer */ xfs_dir2_data_aoff_t offset, /* starting byte offset */ xfs_dir2_data_aoff_t len, /* length in bytes */ int *needlogp, /* out: log header */ int *needscanp) /* out: regen bestfree */{ xfs_dir2_data_t *d; /* data block pointer */ xfs_dir2_data_free_t *dfp; /* bestfree pointer */ char *endptr; /* end of data area */ xfs_mount_t *mp; /* filesystem mount point */ int needscan; /* need to regen bestfree */ xfs_dir2_data_unused_t *newdup; /* new unused entry */ xfs_dir2_data_unused_t *postdup; /* unused entry after us */ xfs_dir2_data_unused_t *prevdup; /* unused entry before us */ mp = tp->t_mountp; d = bp->data; /* * Figure out where the end of the data area is. */ if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC) endptr = (char *)d + mp->m_dirblksize; else { xfs_dir2_block_tail_t *btp; /* block tail */ ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d); endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); } /* * If this isn't the start of the block, then back up to * the previous entry and see if it's free. */ if (offset > sizeof(d->hdr)) { xfs_dir2_data_off_t *tagp; /* tag just before us */ tagp = (xfs_dir2_data_off_t *)((char *)d + offset) - 1; prevdup = (xfs_dir2_data_unused_t *)((char *)d + INT_GET(*tagp, ARCH_CONVERT)); if (INT_GET(prevdup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG) prevdup = NULL; } else prevdup = NULL; /* * If this isn't the end of the block, see if the entry after * us is free. */ if ((char *)d + offset + len < endptr) { postdup = (xfs_dir2_data_unused_t *)((char *)d + offset + len); if (INT_GET(postdup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG) postdup = NULL; } else postdup = NULL; ASSERT(*needscanp == 0); needscan = 0; /* * Previous and following entries are both free, * merge everything into a single free entry. */ if (prevdup && postdup) { xfs_dir2_data_free_t *dfp2; /* another bestfree pointer */ /* * See if prevdup and/or postdup are in bestfree table. */ dfp = xfs_dir2_data_freefind(d, prevdup); dfp2 = xfs_dir2_data_freefind(d, postdup); /* * We need a rescan unless there are exactly 2 free entries * namely our two. Then we know what's happening, otherwise * since the third bestfree is there, there might be more * entries. */ needscan = !INT_ISZERO(d->hdr.bestfree[2].length, ARCH_CONVERT); /* * Fix up the new big freespace. */ INT_MOD(prevdup->length, ARCH_CONVERT, len + INT_GET(postdup->length, ARCH_CONVERT)); INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(prevdup, ARCH_CONVERT), ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)prevdup - (char *)d)); xfs_dir2_data_log_unused(tp, bp, prevdup); if (!needscan) { /* * Has to be the case that entries 0 and 1 are * dfp and dfp2 (don't know which is which), and * entry 2 is empty. * Remove entry 1 first then entry 0. */ ASSERT(dfp && dfp2); if (dfp == &d->hdr.bestfree[1]) { dfp = &d->hdr.bestfree[0]; ASSERT(dfp2 == dfp); dfp2 = &d->hdr.bestfree[1]; } xfs_dir2_data_freeremove(d, dfp2, needlogp); xfs_dir2_data_freeremove(d, dfp, needlogp); /* * Now insert the new entry. */ dfp = xfs_dir2_data_freeinsert(d, prevdup, needlogp); ASSERT(dfp == &d->hdr.bestfree[0]); ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(prevdup->length, ARCH_CONVERT)); ASSERT(INT_ISZERO(dfp[1].length, ARCH_CONVERT)); ASSERT(INT_ISZERO(dfp[2].length, ARCH_CONVERT)); } } /* * The entry before us is free, merge with it. */ else if (prevdup) { dfp = xfs_dir2_data_freefind(d, prevdup); INT_MOD(prevdup->length, ARCH_CONVERT, len); INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(prevdup, ARCH_CONVERT), ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)prevdup - (char *)d)); xfs_dir2_data_log_unused(tp, bp, prevdup); /* * If the previous entry was in the table, the new entry * is longer, so it will be in the table too. Remove * the old one and add the new one. */ if (dfp) { xfs_dir2_data_freeremove(d, dfp, needlogp); (void)xfs_dir2_data_freeinsert(d, prevdup, needlogp); } /* * Otherwise we need a scan if the new entry is big enough. */ else needscan = INT_GET(prevdup->length, ARCH_CONVERT) > INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT); } /* * The following entry is free, merge with it. */ else if (postdup) { dfp = xfs_dir2_data_freefind(d, postdup); newdup = (xfs_dir2_data_unused_t *)((char *)d + offset); INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); INT_SET(newdup->length, ARCH_CONVERT, len + INT_GET(postdup->length, ARCH_CONVERT)); INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); xfs_dir2_data_log_unused(tp, bp, newdup); /* * If the following entry was in the table, the new entry * is longer, so it will be in the table too. Remove * the old one and add the new one. */ if (dfp) { xfs_dir2_data_freeremove(d, dfp, needlogp); (void)xfs_dir2_data_freeinsert(d, newdup, needlogp); } /* * Otherwise we need a scan if the new entry is big enough. */ else needscan = INT_GET(newdup->length, ARCH_CONVERT) > INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT); } /* * Neither neighbor is free. Make a new entry. */ else { newdup = (xfs_dir2_data_unused_t *)((char *)d + offset); INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); INT_SET(newdup->length, ARCH_CONVERT, len); INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); xfs_dir2_data_log_unused(tp, bp, newdup); (void)xfs_dir2_data_freeinsert(d, newdup, needlogp); } *needscanp = needscan;}/* * Take a byte range out of an existing unused space and make it un-free. */voidxfs_dir2_data_use_free( xfs_trans_t *tp, /* transaction pointer */ xfs_dabuf_t *bp, /* data block buffer */ xfs_dir2_data_unused_t *dup, /* unused entry */ xfs_dir2_data_aoff_t offset, /* starting offset to use */ xfs_dir2_data_aoff_t len, /* length to use */ int *needlogp, /* out: need to log header */ int *needscanp) /* out: need regen bestfree */{ xfs_dir2_data_t *d; /* data block */ xfs_dir2_data_free_t *dfp; /* bestfree pointer */ int matchback; /* matches end of freespace */ int matchfront; /* matches start of freespace */ int needscan; /* need to regen bestfree */ xfs_dir2_data_unused_t *newdup; /* new unused entry */ xfs_dir2_data_unused_t *newdup2; /* another new unused entry */ int oldlen; /* old unused entry's length */ d = bp->data; ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); ASSERT(INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG); ASSERT(offset >= (char *)dup - (char *)d); ASSERT(offset + len <= (char *)dup + INT_GET(dup->length, ARCH_CONVERT) - (char *)d); ASSERT((char *)dup - (char *)d == INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT)); /* * Look up the entry in the bestfree table. */ dfp = xfs_dir2_data_freefind(d, dup); oldlen = INT_GET(dup->length, ARCH_CONVERT); ASSERT(dfp || oldlen <= INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT)); /* * Check for alignment with front and back of the entry. */ matchfront = (char *)dup - (char *)d == offset; matchback = (char *)dup + oldlen - (char *)d == offset + len; ASSERT(*needscanp == 0); needscan = 0; /* * If we matched it exactly we just need to get rid of it from * the bestfree table. */ if (matchfront && matchback) { if (dfp) { needscan = !INT_ISZERO(d->hdr.bestfree[2].offset, ARCH_CONVERT); if (!needscan) xfs_dir2_data_freeremove(d, dfp, needlogp); } } /* * We match the first part of the entry. * Make a new entry with the remaining freespace. */ else if (matchfront) { newdup = (xfs_dir2_data_unused_t *)((char *)d + offset + len); INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); INT_SET(newdup->length, ARCH_CONVERT, oldlen - len); INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); xfs_dir2_data_log_unused(tp, bp, newdup); /* * If it was in the table, remove it and add the new one. */ if (dfp) { xfs_dir2_data_freeremove(d, dfp, needlogp); dfp = xfs_dir2_data_freeinsert(d, newdup, needlogp); ASSERT(dfp != NULL); ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(newdup->length, ARCH_CONVERT)); ASSERT(INT_GET(dfp->offset, ARCH_CONVERT) == (char *)newdup - (char *)d); /* * If we got inserted at the last slot, * that means we don't know if there was a better * choice for the last slot, or not. Rescan. */ needscan = dfp == &d->hdr.bestfree[2]; } } /* * We match the last part of the entry. * Trim the allocated space off the tail of the entry. */ else if (matchback) { newdup = dup; INT_SET(newdup->length, ARCH_CONVERT, (xfs_dir2_data_off_t) (((char *)d + offset) - (char *)newdup)); INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); xfs_dir2_data_log_unused(tp, bp, newdup); /* * If it was in the table, remove it and add the new one. */ if (dfp) { xfs_dir2_data_freeremove(d, dfp, needlogp); dfp = xfs_dir2_data_freeinsert(d, newdup, needlogp); ASSERT(dfp != NULL); ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(newdup->length, ARCH_CONVERT)); ASSERT(INT_GET(dfp->offset, ARCH_CONVERT) == (char *)newdup - (char *)d); /* * If we got inserted at the last slot, * that means we don't know if there was a better * choice for the last slot, or not. Rescan. */ needscan = dfp == &d->hdr.bestfree[2]; } } /* * Poking out the middle of an entry. * Make two new entries. */ else { newdup = dup; INT_SET(newdup->length, ARCH_CONVERT, (xfs_dir2_data_off_t) (((char *)d + offset) - (char *)newdup)); INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); xfs_dir2_data_log_unused(tp, bp, newdup); newdup2 = (xfs_dir2_data_unused_t *)((char *)d + offset + len); INT_SET(newdup2->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); INT_SET(newdup2->length, ARCH_CONVERT, oldlen - len - INT_GET(newdup->length, ARCH_CONVERT)); INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup2, ARCH_CONVERT), ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)newdup2 - (char *)d)); xfs_dir2_data_log_unused(tp, bp, newdup2); /* * If the old entry was in the table, we need to scan * if the 3rd entry was valid, since these entries * are smaller than the old one. * If we don't need to scan that means there were 1 or 2 * entries in the table, and removing the old and adding * the 2 new will work. */ if (dfp) { needscan = !INT_ISZERO(d->hdr.bestfree[2].length, ARCH_CONVERT); if (!needscan) { xfs_dir2_data_freeremove(d, dfp, needlogp); (void)xfs_dir2_data_freeinsert(d, newdup, needlogp); (void)xfs_dir2_data_freeinsert(d, newdup2, needlogp); } } } *needscanp = needscan;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?