📄 xfs_dir2_leaf.c
字号:
*/ curdb = xfs_dir2_da_to_db(mp, map->br_startoff); error = xfs_da_read_buf(NULL, dp, map->br_startoff, map->br_blockcount >= mp->m_dirblkfsbs ? XFS_FSB_TO_DADDR(mp, map->br_startblock) : -1, &bp, XFS_DATA_FORK); /* * Should just skip over the data block instead * of giving up. */ if (error) break; /* XXX */ /* * Adjust the current amount of read-ahead: we just * read a block that was previously ra. */ if (ra_current) ra_current -= mp->m_dirblkfsbs; /* * Do we need more readahead? */ for (ra_index = ra_offset = i = 0; ra_want > ra_current && i < map_blocks; i += mp->m_dirblkfsbs) { ASSERT(ra_index < map_valid); /* * Read-ahead a contiguous directory block. */ if (i > ra_current && map[ra_index].br_blockcount >= mp->m_dirblkfsbs) { xfs_baread(mp->m_ddev_targp, XFS_FSB_TO_DADDR(mp, map[ra_index].br_startblock + ra_offset), (int)BTOBB(mp->m_dirblksize)); ra_current = i; } /* * Read-ahead a non-contiguous directory block. * This doesn't use our mapping, but this * is a very rare case. */ else if (i > ra_current) { (void)xfs_da_reada_buf(NULL, dp, map[ra_index].br_startoff + ra_offset, XFS_DATA_FORK); ra_current = i; } /* * Advance offset through the mapping table. */ for (j = 0; j < mp->m_dirblkfsbs; j++) { /* * The rest of this extent but not * more than a dir block. */ length = MIN(mp->m_dirblkfsbs, (int)(map[ra_index].br_blockcount - ra_offset)); j += length; ra_offset += length; /* * Advance to the next mapping if * this one is used up. */ if (ra_offset == map[ra_index].br_blockcount) { ra_offset = 0; ra_index++; } } } /* * Having done a read, we need to set a new offset. */ newoff = xfs_dir2_db_off_to_byte(mp, curdb, 0); /* * Start of the current block. */ if (curoff < newoff) curoff = newoff; /* * Make sure we're in the right block. */ else if (curoff > newoff) ASSERT(xfs_dir2_byte_to_db(mp, curoff) == curdb); data = bp->data; xfs_dir2_data_check(dp, bp); /* * Find our position in the block. */ ptr = (char *)&data->u; byteoff = xfs_dir2_byte_to_off(mp, curoff); /* * Skip past the header. */ if (byteoff == 0) curoff += (uint)sizeof(data->hdr); /* * Skip past entries until we reach our offset. */ else { while ((char *)ptr - (char *)data < byteoff) { dup = (xfs_dir2_data_unused_t *)ptr; if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { length = be16_to_cpu(dup->length); ptr += length; continue; } dep = (xfs_dir2_data_entry_t *)ptr; length = xfs_dir2_data_entsize(dep->namelen); ptr += length; } /* * Now set our real offset. */ curoff = xfs_dir2_db_off_to_byte(mp, xfs_dir2_byte_to_db(mp, curoff), (char *)ptr - (char *)data); if (ptr >= (char *)data + mp->m_dirblksize) { continue; } } } /* * We have a pointer to an entry. * Is it a live one? */ dup = (xfs_dir2_data_unused_t *)ptr; /* * No, it's unused, skip over it. */ if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { length = be16_to_cpu(dup->length); ptr += length; curoff += length; continue; } /* * Copy the entry into the putargs, and try formatting it. */ dep = (xfs_dir2_data_entry_t *)ptr; length = xfs_dir2_data_entsize(dep->namelen); ino = be64_to_cpu(dep->inumber);#if XFS_BIG_INUMS ino += mp->m_inoadd;#endif /* * Won't fit. Return to caller. */ if (filldir(dirent, dep->name, dep->namelen, xfs_dir2_byte_to_dataptr(mp, curoff), ino, DT_UNKNOWN)) break; /* * Advance to next entry in the block. */ ptr += length; curoff += length; bufsize -= length; } /* * All done. Set output offset value to current offset. */ if (curoff > xfs_dir2_dataptr_to_byte(mp, XFS_DIR2_MAX_DATAPTR)) *offset = XFS_DIR2_MAX_DATAPTR; else *offset = xfs_dir2_byte_to_dataptr(mp, curoff); kmem_free(map, map_size * sizeof(*map)); if (bp) xfs_da_brelse(NULL, bp); return error;}/* * Initialize a new leaf block, leaf1 or leafn magic accepted. */intxfs_dir2_leaf_init( xfs_da_args_t *args, /* operation arguments */ xfs_dir2_db_t bno, /* directory block number */ xfs_dabuf_t **bpp, /* out: leaf buffer */ int magic) /* magic number for block */{ xfs_dabuf_t *bp; /* leaf buffer */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ xfs_mount_t *mp; /* filesystem mount point */ xfs_trans_t *tp; /* transaction pointer */ dp = args->dp; ASSERT(dp != NULL); tp = args->trans; mp = dp->i_mount; ASSERT(bno >= XFS_DIR2_LEAF_FIRSTDB(mp) && bno < XFS_DIR2_FREE_FIRSTDB(mp)); /* * Get the buffer for the block. */ error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, bno), -1, &bp, XFS_DATA_FORK); if (error) { return error; } ASSERT(bp != NULL); leaf = bp->data; /* * Initialize the header. */ leaf->hdr.info.magic = cpu_to_be16(magic); leaf->hdr.info.forw = 0; leaf->hdr.info.back = 0; leaf->hdr.count = 0; leaf->hdr.stale = 0; xfs_dir2_leaf_log_header(tp, bp); /* * If it's a leaf-format directory initialize the tail. * In this case our caller has the real bests table to copy into * the block. */ if (magic == XFS_DIR2_LEAF1_MAGIC) { ltp = xfs_dir2_leaf_tail_p(mp, leaf); ltp->bestcount = 0; xfs_dir2_leaf_log_tail(tp, bp); } *bpp = bp; return 0;}/* * Log the bests entries indicated from a leaf1 block. */static voidxfs_dir2_leaf_log_bests( xfs_trans_t *tp, /* transaction pointer */ xfs_dabuf_t *bp, /* leaf buffer */ int first, /* first entry to log */ int last) /* last entry to log */{ __be16 *firstb; /* pointer to first entry */ __be16 *lastb; /* pointer to last entry */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ leaf = bp->data; ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC); ltp = xfs_dir2_leaf_tail_p(tp->t_mountp, leaf); firstb = xfs_dir2_leaf_bests_p(ltp) + first; lastb = xfs_dir2_leaf_bests_p(ltp) + last; xfs_da_log_buf(tp, bp, (uint)((char *)firstb - (char *)leaf), (uint)((char *)lastb - (char *)leaf + sizeof(*lastb) - 1));}/* * Log the leaf entries indicated from a leaf1 or leafn block. */voidxfs_dir2_leaf_log_ents( xfs_trans_t *tp, /* transaction pointer */ xfs_dabuf_t *bp, /* leaf buffer */ int first, /* first entry to log */ int last) /* last entry to log */{ xfs_dir2_leaf_entry_t *firstlep; /* pointer to first entry */ xfs_dir2_leaf_entry_t *lastlep; /* pointer to last entry */ xfs_dir2_leaf_t *leaf; /* leaf structure */ leaf = bp->data; ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC || be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC); firstlep = &leaf->ents[first]; lastlep = &leaf->ents[last]; xfs_da_log_buf(tp, bp, (uint)((char *)firstlep - (char *)leaf), (uint)((char *)lastlep - (char *)leaf + sizeof(*lastlep) - 1));}/* * Log the header of the leaf1 or leafn block. */voidxfs_dir2_leaf_log_header( xfs_trans_t *tp, /* transaction pointer */ xfs_dabuf_t *bp) /* leaf buffer */{ xfs_dir2_leaf_t *leaf; /* leaf structure */ leaf = bp->data; ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC || be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC); xfs_da_log_buf(tp, bp, (uint)((char *)&leaf->hdr - (char *)leaf), (uint)(sizeof(leaf->hdr) - 1));}/* * Log the tail of the leaf1 block. */STATIC voidxfs_dir2_leaf_log_tail( xfs_trans_t *tp, /* transaction pointer */ xfs_dabuf_t *bp) /* leaf buffer */{ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ xfs_mount_t *mp; /* filesystem mount point */ mp = tp->t_mountp; leaf = bp->data; ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC); ltp = xfs_dir2_leaf_tail_p(mp, leaf); xfs_da_log_buf(tp, bp, (uint)((char *)ltp - (char *)leaf), (uint)(mp->m_dirblksize - 1));}/* * Look up the entry referred to by args in the leaf format directory. * Most of the work is done by the xfs_dir2_leaf_lookup_int routine which * is also used by the node-format code. */intxfs_dir2_leaf_lookup( xfs_da_args_t *args) /* operation arguments */{ xfs_dabuf_t *dbp; /* data block buffer */ xfs_dir2_data_entry_t *dep; /* data block entry */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ int index; /* found entry index */ xfs_dabuf_t *lbp; /* leaf buffer */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_trans_t *tp; /* transaction pointer */ xfs_dir2_trace_args("leaf_lookup", args); /* * Look up name in the leaf block, returning both buffers and index. */ if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { return error; } tp = args->trans; dp = args->dp; xfs_dir2_leaf_check(dp, lbp); leaf = lbp->data; /* * Get to the leaf entry and contained data entry address. */ lep = &leaf->ents[index]; /* * Point to the data entry. */ dep = (xfs_dir2_data_entry_t *) ((char *)dbp->data + xfs_dir2_dataptr_to_off(dp->i_mount, be32_to_cpu(lep->address))); /* * Return the found inode number. */ args->inumber = be64_to_cpu(dep->inumber); xfs_da_brelse(tp, dbp); xfs_da_brelse(tp, lbp); return XFS_ERROR(EEXIST);}/* * Look up name/hash in the leaf block. * Fill in indexp with the found index, and dbpp with the data buffer. * If not found dbpp will be NULL, and ENOENT comes back. * lbpp will always be filled in with the leaf buffer unless there's an error. */static int /* error */xfs_dir2_leaf_lookup_int( xfs_da_args_t *args, /* operation arguments */ xfs_dabuf_t **lbpp, /* out: leaf buffer */ int *indexp, /* out: index in leaf block */ xfs_dabuf_t **dbpp) /* out: data buffer */{ xfs_dir2_db_t curdb; /* current data block number */ xfs_dabuf_t *dbp; /* data buffer */ xfs_dir2_data_entry_t *dep; /* data entry */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ int index; /* index in leaf block */ xfs_dabuf_t *lbp; /* leaf buffer */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_mount_t *mp; /* filesystem mount point */ xfs_dir2_db_t newdb; /* new data block number */ xfs_trans_t *tp; /* transaction pointer */ dp = args->dp; tp = args->trans; mp = dp->i_mount; /* * Read the leaf block into the buffer. */ if ((error = xfs_da_read_buf(tp, dp, mp->m_dirleafblk, -1, &lbp, XFS_DATA_FORK))) { return error; } *lbpp = lbp; leaf = lbp->data; xfs_dir2_leaf_check(dp, lbp); /* * Look for the first leaf entry with our hash value. */ index = xfs_dir2_leaf_search_hash(args, lbp); /* * Loop over all the entries with the right hash value * looking to match the name. */ for (lep = &leaf->ents[index], dbp = NULL, curdb = -1; index < be16_to_cpu(leaf->hdr.count) && be32_to_cpu(lep->hashval) == args->hashval; lep++, index++) { /* * Skip over stale leaf entries. */ if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) continue; /* * Get the new data block number. */ newdb = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address)); /* * If it's not the same as the old data block number, * need to pitch the old one and read the new one. */ if (newdb != curdb) { if (dbp) xfs_da_brelse(tp, dbp); if ((error = xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, newdb), -1, &dbp, XFS_DATA_FORK))) { xfs_da_brelse(tp, lbp); return error; } xfs_dir2_data_check(dp, dbp); curdb = newdb; } /* * Point to the data entry. */ dep = (xfs_dir2_data_entry_t *) ((char *)dbp->data + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address))); /* * If it matches then return it. */ if (dep->namelen == args->namelen &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -