📄 xfs_dir2_leaf.c
字号:
for (lowstale = index - 1; lowstale >= 0 && be32_to_cpu(leaf->ents[lowstale].address) != XFS_DIR2_NULL_DATAPTR; lowstale--) continue; /* * Find the next stale entry at or after the insertion * point, if any. Stop if we go so far that the * lowstale entry would be better. */ for (highstale = index; highstale < be16_to_cpu(leaf->hdr.count) && be32_to_cpu(leaf->ents[highstale].address) != XFS_DIR2_NULL_DATAPTR && (lowstale < 0 || index - lowstale - 1 >= highstale - index); highstale++) continue; } /* * If the low one is better, use it. */ if (lowstale >= 0 && (highstale == be16_to_cpu(leaf->hdr.count) || index - lowstale - 1 < highstale - index)) { ASSERT(index - lowstale - 1 >= 0); ASSERT(be32_to_cpu(leaf->ents[lowstale].address) == XFS_DIR2_NULL_DATAPTR); /* * Copy entries up to cover the stale entry * and make room for the new entry. */ if (index - lowstale - 1 > 0) memmove(&leaf->ents[lowstale], &leaf->ents[lowstale + 1], (index - lowstale - 1) * sizeof(*lep)); lep = &leaf->ents[index - 1]; lfloglow = MIN(lowstale, lfloglow); lfloghigh = MAX(index - 1, lfloghigh); } /* * The high one is better, so use that one. */ else { ASSERT(highstale - index >= 0); ASSERT(be32_to_cpu(leaf->ents[highstale].address) == XFS_DIR2_NULL_DATAPTR); /* * Copy entries down to cover the stale entry * and make room for the new entry. */ if (highstale - index > 0) memmove(&leaf->ents[index + 1], &leaf->ents[index], (highstale - index) * sizeof(*lep)); lep = &leaf->ents[index]; lfloglow = MIN(index, lfloglow); lfloghigh = MAX(highstale, lfloghigh); } be16_add(&leaf->hdr.stale, -1); } /* * Fill in the new leaf entry. */ lep->hashval = cpu_to_be32(args->hashval); lep->address = cpu_to_be32(xfs_dir2_db_off_to_dataptr(mp, use_block, be16_to_cpu(*tagp))); /* * Log the leaf fields and give up the buffers. */ xfs_dir2_leaf_log_header(tp, lbp); xfs_dir2_leaf_log_ents(tp, lbp, lfloglow, lfloghigh); xfs_dir2_leaf_check(dp, lbp); xfs_da_buf_done(lbp); xfs_dir2_data_check(dp, dbp); xfs_da_buf_done(dbp); return 0;}#ifdef DEBUG/* * Check the internal consistency of a leaf1 block. * Pop an assert if something is wrong. */voidxfs_dir2_leaf_check( xfs_inode_t *dp, /* incore directory inode */ xfs_dabuf_t *bp) /* leaf's buffer */{ int i; /* leaf index */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_tail_t *ltp; /* leaf tail pointer */ xfs_mount_t *mp; /* filesystem mount point */ int stale; /* count of stale leaves */ leaf = bp->data; mp = dp->i_mount; ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC); /* * This value is not restrictive enough. * Should factor in the size of the bests table as well. * We can deduce a value for that from di_size. */ ASSERT(be16_to_cpu(leaf->hdr.count) <= xfs_dir2_max_leaf_ents(mp)); ltp = xfs_dir2_leaf_tail_p(mp, leaf); /* * Leaves and bests don't overlap. */ ASSERT((char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] <= (char *)xfs_dir2_leaf_bests_p(ltp)); /* * Check hash value order, count stale entries. */ for (i = stale = 0; i < be16_to_cpu(leaf->hdr.count); i++) { if (i + 1 < be16_to_cpu(leaf->hdr.count)) ASSERT(be32_to_cpu(leaf->ents[i].hashval) <= be32_to_cpu(leaf->ents[i + 1].hashval)); if (be32_to_cpu(leaf->ents[i].address) == XFS_DIR2_NULL_DATAPTR) stale++; } ASSERT(be16_to_cpu(leaf->hdr.stale) == stale);}#endif /* DEBUG *//* * Compact out any stale entries in the leaf. * Log the header and changed leaf entries, if any. */voidxfs_dir2_leaf_compact( xfs_da_args_t *args, /* operation arguments */ xfs_dabuf_t *bp) /* leaf buffer */{ int from; /* source leaf index */ xfs_dir2_leaf_t *leaf; /* leaf structure */ int loglow; /* first leaf entry to log */ int to; /* target leaf index */ leaf = bp->data; if (!leaf->hdr.stale) { return; } /* * Compress out the stale entries in place. */ for (from = to = 0, loglow = -1; from < be16_to_cpu(leaf->hdr.count); from++) { if (be32_to_cpu(leaf->ents[from].address) == XFS_DIR2_NULL_DATAPTR) continue; /* * Only actually copy the entries that are different. */ if (from > to) { if (loglow == -1) loglow = to; leaf->ents[to] = leaf->ents[from]; } to++; } /* * Update and log the header, log the leaf entries. */ ASSERT(be16_to_cpu(leaf->hdr.stale) == from - to); be16_add(&leaf->hdr.count, -(be16_to_cpu(leaf->hdr.stale))); leaf->hdr.stale = 0; xfs_dir2_leaf_log_header(args->trans, bp); if (loglow != -1) xfs_dir2_leaf_log_ents(args->trans, bp, loglow, to - 1);}/* * Compact the leaf entries, removing stale ones. * Leave one stale entry behind - the one closest to our * insertion index - and the caller will shift that one to our insertion * point later. * Return new insertion index, where the remaining stale entry is, * and leaf logging indices. */voidxfs_dir2_leaf_compact_x1( xfs_dabuf_t *bp, /* leaf buffer */ int *indexp, /* insertion index */ int *lowstalep, /* out: stale entry before us */ int *highstalep, /* out: stale entry after us */ int *lowlogp, /* out: low log index */ int *highlogp) /* out: high log index */{ int from; /* source copy index */ int highstale; /* stale entry at/after index */ int index; /* insertion index */ int keepstale; /* source index of kept stale */ xfs_dir2_leaf_t *leaf; /* leaf structure */ int lowstale; /* stale entry before index */ int newindex=0; /* new insertion index */ int to; /* destination copy index */ leaf = bp->data; ASSERT(be16_to_cpu(leaf->hdr.stale) > 1); index = *indexp; /* * Find the first stale entry before our index, if any. */ for (lowstale = index - 1; lowstale >= 0 && be32_to_cpu(leaf->ents[lowstale].address) != XFS_DIR2_NULL_DATAPTR; lowstale--) continue; /* * Find the first stale entry at or after our index, if any. * Stop if the answer would be worse than lowstale. */ for (highstale = index; highstale < be16_to_cpu(leaf->hdr.count) && be32_to_cpu(leaf->ents[highstale].address) != XFS_DIR2_NULL_DATAPTR && (lowstale < 0 || index - lowstale > highstale - index); highstale++) continue; /* * Pick the better of lowstale and highstale. */ if (lowstale >= 0 && (highstale == be16_to_cpu(leaf->hdr.count) || index - lowstale <= highstale - index)) keepstale = lowstale; else keepstale = highstale; /* * Copy the entries in place, removing all the stale entries * except keepstale. */ for (from = to = 0; from < be16_to_cpu(leaf->hdr.count); from++) { /* * Notice the new value of index. */ if (index == from) newindex = to; if (from != keepstale && be32_to_cpu(leaf->ents[from].address) == XFS_DIR2_NULL_DATAPTR) { if (from == to) *lowlogp = to; continue; } /* * Record the new keepstale value for the insertion. */ if (from == keepstale) lowstale = highstale = to; /* * Copy only the entries that have moved. */ if (from > to) leaf->ents[to] = leaf->ents[from]; to++; } ASSERT(from > to); /* * If the insertion point was past the last entry, * set the new insertion point accordingly. */ if (index == from) newindex = to; *indexp = newindex; /* * Adjust the leaf header values. */ be16_add(&leaf->hdr.count, -(from - to)); leaf->hdr.stale = cpu_to_be16(1); /* * Remember the low/high stale value only in the "right" * direction. */ if (lowstale >= newindex) lowstale = -1; else highstale = be16_to_cpu(leaf->hdr.count); *highlogp = be16_to_cpu(leaf->hdr.count) - 1; *lowstalep = lowstale; *highstalep = highstale;}/* * Getdents (readdir) for leaf and node directories. * This reads the data blocks only, so is the same for both forms. */int /* error */xfs_dir2_leaf_getdents( xfs_inode_t *dp, /* incore directory inode */ void *dirent, size_t bufsize, xfs_off_t *offset, filldir_t filldir){ xfs_dabuf_t *bp; /* data block buffer */ int byteoff; /* offset in current block */ xfs_dir2_db_t curdb; /* db for current block */ xfs_dir2_off_t curoff; /* current overall offset */ xfs_dir2_data_t *data; /* data block structure */ xfs_dir2_data_entry_t *dep; /* data entry */ xfs_dir2_data_unused_t *dup; /* unused entry */ int error = 0; /* error return value */ int i; /* temporary loop index */ int j; /* temporary loop index */ int length; /* temporary length value */ xfs_bmbt_irec_t *map; /* map vector for blocks */ xfs_extlen_t map_blocks; /* number of fsbs in map */ xfs_dablk_t map_off; /* last mapped file offset */ int map_size; /* total entries in *map */ int map_valid; /* valid entries in *map */ xfs_mount_t *mp; /* filesystem mount point */ xfs_dir2_off_t newoff; /* new curoff after new blk */ int nmap; /* mappings to ask xfs_bmapi */ char *ptr = NULL; /* pointer to current data */ int ra_current; /* number of read-ahead blks */ int ra_index; /* *map index for read-ahead */ int ra_offset; /* map entry offset for ra */ int ra_want; /* readahead count wanted */ xfs_ino_t ino; /* * If the offset is at or past the largest allowed value, * give up right away. */ if (*offset >= XFS_DIR2_MAX_DATAPTR) return 0; mp = dp->i_mount; /* * Set up to bmap a number of blocks based on the caller's * buffer size, the directory block size, and the filesystem * block size. */ map_size = howmany(bufsize + mp->m_dirblksize, mp->m_sb.sb_blocksize); map = kmem_alloc(map_size * sizeof(*map), KM_SLEEP); map_valid = ra_index = ra_offset = ra_current = map_blocks = 0; bp = NULL; /* * Inside the loop we keep the main offset value as a byte offset * in the directory file. */ curoff = xfs_dir2_dataptr_to_byte(mp, *offset); /* * Force this conversion through db so we truncate the offset * down to get the start of the data block. */ map_off = xfs_dir2_db_to_da(mp, xfs_dir2_byte_to_db(mp, curoff)); /* * Loop over directory entries until we reach the end offset. * Get more blocks and readahead as necessary. */ while (curoff < XFS_DIR2_LEAF_OFFSET) { /* * If we have no buffer, or we're off the end of the * current buffer, need to get another one. */ if (!bp || ptr >= (char *)bp->data + mp->m_dirblksize) { /* * If we have a buffer, we need to release it and * take it out of the mapping. */ if (bp) { xfs_da_brelse(NULL, bp); bp = NULL; map_blocks -= mp->m_dirblkfsbs; /* * Loop to get rid of the extents for the * directory block. */ for (i = mp->m_dirblkfsbs; i > 0; ) { j = MIN((int)map->br_blockcount, i); map->br_blockcount -= j; map->br_startblock += j; map->br_startoff += j; /* * If mapping is done, pitch it from * the table. */ if (!map->br_blockcount && --map_valid) memmove(&map[0], &map[1], sizeof(map[0]) * map_valid); i -= j; } } /* * Recalculate the readahead blocks wanted. */ ra_want = howmany(bufsize + mp->m_dirblksize, mp->m_sb.sb_blocksize) - 1; /* * If we don't have as many as we want, and we haven't * run out of data blocks, get some more mappings. */ if (1 + ra_want > map_blocks && map_off < xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET)) { /* * Get more bmaps, fill in after the ones * we already have in the table. */ nmap = map_size - map_valid; error = xfs_bmapi(NULL, dp, map_off, xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET) - map_off, XFS_BMAPI_METADATA, NULL, 0, &map[map_valid], &nmap, NULL, NULL); /* * Don't know if we should ignore this or * try to return an error. * The trouble with returning errors * is that readdir will just stop without * actually passing the error through. */ if (error) break; /* XXX */ /* * If we got all the mappings we asked for, * set the final map offset based on the * last bmap value received. * Otherwise, we've reached the end. */ if (nmap == map_size - map_valid) map_off = map[map_valid + nmap - 1].br_startoff + map[map_valid + nmap - 1].br_blockcount; else map_off = xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET); /* * Look for holes in the mapping, and * eliminate them. Count up the valid blocks. */ for (i = map_valid; i < map_valid + nmap; ) { if (map[i].br_startblock == HOLESTARTBLOCK) { nmap--; length = map_valid + nmap - i; if (length) memmove(&map[i], &map[i + 1], sizeof(map[i]) * length); } else { map_blocks += map[i].br_blockcount; i++; } } map_valid += nmap; } /* * No valid mappings, so no more data blocks. */ if (!map_valid) { curoff = xfs_dir2_da_to_byte(mp, map_off); break; } /* * Read the directory block starting at the first * mapping.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -