📄 xfs_dir2_leaf.c
字号:
dep->name[0] == args->name[0] && memcmp(dep->name, args->name, args->namelen) == 0) { *dbpp = dbp; *indexp = index; return 0; } } /* * No match found, return ENOENT. */ ASSERT(args->oknoent); if (dbp) xfs_da_brelse(tp, dbp); xfs_da_brelse(tp, lbp); return XFS_ERROR(ENOENT);}/* * Remove an entry from a leaf format directory. */int /* error */xfs_dir2_leaf_removename( xfs_da_args_t *args) /* operation arguments */{ __be16 *bestsp; /* leaf block best freespace */ xfs_dir2_data_t *data; /* data block structure */ xfs_dir2_db_t db; /* data block number */ xfs_dabuf_t *dbp; /* data block buffer */ xfs_dir2_data_entry_t *dep; /* data entry structure */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ xfs_dir2_db_t i; /* temporary data block # */ int index; /* index into leaf entries */ xfs_dabuf_t *lbp; /* leaf buffer */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ xfs_mount_t *mp; /* filesystem mount point */ int needlog; /* need to log data header */ int needscan; /* need to rescan data frees */ xfs_dir2_data_off_t oldbest; /* old value of best free */ xfs_trans_t *tp; /* transaction pointer */ xfs_dir2_trace_args("leaf_removename", args); /* * Lookup the leaf entry, get the leaf and data blocks read in. */ if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { return error; } dp = args->dp; tp = args->trans; mp = dp->i_mount; leaf = lbp->data; data = dbp->data; xfs_dir2_data_check(dp, dbp); /* * Point to the leaf entry, use that to point to the data entry. */ lep = &leaf->ents[index]; db = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address)); dep = (xfs_dir2_data_entry_t *) ((char *)data + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address))); needscan = needlog = 0; oldbest = be16_to_cpu(data->hdr.bestfree[0].length); ltp = xfs_dir2_leaf_tail_p(mp, leaf); bestsp = xfs_dir2_leaf_bests_p(ltp); ASSERT(be16_to_cpu(bestsp[db]) == oldbest); /* * Mark the former data entry unused. */ xfs_dir2_data_make_free(tp, dbp, (xfs_dir2_data_aoff_t)((char *)dep - (char *)data), xfs_dir2_data_entsize(dep->namelen), &needlog, &needscan); /* * We just mark the leaf entry stale by putting a null in it. */ be16_add(&leaf->hdr.stale, 1); xfs_dir2_leaf_log_header(tp, lbp); lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR); xfs_dir2_leaf_log_ents(tp, lbp, index, index); /* * Scan the freespace in the data block again if necessary, * log the data block header if necessary. */ if (needscan) xfs_dir2_data_freescan(mp, data, &needlog); if (needlog) xfs_dir2_data_log_header(tp, dbp); /* * If the longest freespace in the data block has changed, * put the new value in the bests table and log that. */ if (be16_to_cpu(data->hdr.bestfree[0].length) != oldbest) { bestsp[db] = data->hdr.bestfree[0].length; xfs_dir2_leaf_log_bests(tp, lbp, db, db); } xfs_dir2_data_check(dp, dbp); /* * If the data block is now empty then get rid of the data block. */ if (be16_to_cpu(data->hdr.bestfree[0].length) == mp->m_dirblksize - (uint)sizeof(data->hdr)) { ASSERT(db != mp->m_dirdatablk); if ((error = xfs_dir2_shrink_inode(args, db, dbp))) { /* * Nope, can't get rid of it because it caused * allocation of a bmap btree block to do so. * Just go on, returning success, leaving the * empty block in place. */ if (error == ENOSPC && args->total == 0) { xfs_da_buf_done(dbp); error = 0; } xfs_dir2_leaf_check(dp, lbp); xfs_da_buf_done(lbp); return error; } dbp = NULL; /* * If this is the last data block then compact the * bests table by getting rid of entries. */ if (db == be32_to_cpu(ltp->bestcount) - 1) { /* * Look for the last active entry (i). */ for (i = db - 1; i > 0; i--) { if (be16_to_cpu(bestsp[i]) != NULLDATAOFF) break; } /* * Copy the table down so inactive entries at the * end are removed. */ memmove(&bestsp[db - i], bestsp, (be32_to_cpu(ltp->bestcount) - (db - i)) * sizeof(*bestsp)); be32_add(<p->bestcount, -(db - i)); xfs_dir2_leaf_log_tail(tp, lbp); xfs_dir2_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1); } else bestsp[db] = cpu_to_be16(NULLDATAOFF); } /* * If the data block was not the first one, drop it. */ else if (db != mp->m_dirdatablk && dbp != NULL) { xfs_da_buf_done(dbp); dbp = NULL; } xfs_dir2_leaf_check(dp, lbp); /* * See if we can convert to block form. */ return xfs_dir2_leaf_to_block(args, lbp, dbp);}/* * Replace the inode number in a leaf format directory entry. */int /* error */xfs_dir2_leaf_replace( 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; /* index of leaf entry */ 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_replace", args); /* * Look up the entry. */ if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { return error; } dp = args->dp; leaf = lbp->data; /* * Point to the leaf entry, get data address from it. */ 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))); ASSERT(args->inumber != be64_to_cpu(dep->inumber)); /* * Put the new inode number in, log it. */ dep->inumber = cpu_to_be64(args->inumber); tp = args->trans; xfs_dir2_data_log_entry(tp, dbp, dep); xfs_da_buf_done(dbp); xfs_dir2_leaf_check(dp, lbp); xfs_da_brelse(tp, lbp); return 0;}/* * Return index in the leaf block (lbp) which is either the first * one with this hash value, or if there are none, the insert point * for that hash value. */int /* index value */xfs_dir2_leaf_search_hash( xfs_da_args_t *args, /* operation arguments */ xfs_dabuf_t *lbp) /* leaf buffer */{ xfs_dahash_t hash=0; /* hash from this entry */ xfs_dahash_t hashwant; /* hash value looking for */ int high; /* high leaf index */ int low; /* low leaf index */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ int mid=0; /* current leaf index */ leaf = lbp->data;#ifndef __KERNEL__ if (!leaf->hdr.count) return 0;#endif /* * Note, the table cannot be empty, so we have to go through the loop. * Binary search the leaf entries looking for our hash value. */ for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) - 1, hashwant = args->hashval; low <= high; ) { mid = (low + high) >> 1; if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant) break; if (hash < hashwant) low = mid + 1; else high = mid - 1; } /* * Found one, back up through all the equal hash values. */ if (hash == hashwant) { while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant) { mid--; } } /* * Need to point to an entry higher than ours. */ else if (hash < hashwant) mid++; return mid;}/* * Trim off a trailing data block. We know it's empty since the leaf * freespace table says so. */int /* error */xfs_dir2_leaf_trim_data( xfs_da_args_t *args, /* operation arguments */ xfs_dabuf_t *lbp, /* leaf buffer */ xfs_dir2_db_t db) /* data block number */{ __be16 *bestsp; /* leaf bests table */#ifdef DEBUG xfs_dir2_data_t *data; /* data block structure */#endif xfs_dabuf_t *dbp; /* data block buffer */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return value */ 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; mp = dp->i_mount; tp = args->trans; /* * Read the offending data block. We need its buffer. */ if ((error = xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, db), -1, &dbp, XFS_DATA_FORK))) { return error; }#ifdef DEBUG data = dbp->data; ASSERT(be32_to_cpu(data->hdr.magic) == XFS_DIR2_DATA_MAGIC);#endif /* this seems to be an error * data is only valid if DEBUG is defined? * RMC 09/08/1999 */ leaf = lbp->data; ltp = xfs_dir2_leaf_tail_p(mp, leaf); ASSERT(be16_to_cpu(data->hdr.bestfree[0].length) == mp->m_dirblksize - (uint)sizeof(data->hdr)); ASSERT(db == be32_to_cpu(ltp->bestcount) - 1); /* * Get rid of the data block. */ if ((error = xfs_dir2_shrink_inode(args, db, dbp))) { ASSERT(error != ENOSPC); xfs_da_brelse(tp, dbp); return error; } /* * Eliminate the last bests entry from the table. */ bestsp = xfs_dir2_leaf_bests_p(ltp); be32_add(<p->bestcount, -1); memmove(&bestsp[1], &bestsp[0], be32_to_cpu(ltp->bestcount) * sizeof(*bestsp)); xfs_dir2_leaf_log_tail(tp, lbp); xfs_dir2_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1); return 0;}/* * Convert node form directory to leaf form directory. * The root of the node form dir needs to already be a LEAFN block. * Just return if we can't do anything. */int /* error */xfs_dir2_node_to_leaf( xfs_da_state_t *state) /* directory operation state */{ xfs_da_args_t *args; /* operation arguments */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ xfs_dabuf_t *fbp; /* buffer for freespace block */ xfs_fileoff_t fo; /* freespace file offset */ xfs_dir2_free_t *free; /* freespace structure */ xfs_dabuf_t *lbp; /* buffer for leaf block */ xfs_dir2_leaf_tail_t *ltp; /* tail of leaf structure */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_mount_t *mp; /* filesystem mount point */ int rval; /* successful free trim? */ xfs_trans_t *tp; /* transaction pointer */ /* * There's more than a leaf level in the btree, so there must * be multiple leafn blocks. Give up. */ if (state->path.active > 1) return 0; args = state->args; xfs_dir2_trace_args("node_to_leaf", args); mp = state->mp; dp = args->dp; tp = args->trans; /* * Get the last offset in the file. */ if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK))) { return error; } fo -= mp->m_dirblkfsbs; /* * If there are freespace blocks other than the first one, * take this opportunity to remove trailing empty freespace blocks * that may have been left behind during no-space-reservation * operations. */ while (fo > mp->m_dirfreeblk) { if ((error = xfs_dir2_node_trim_free(args, fo, &rval))) { return error; } if (rval) fo -= mp->m_dirblkfsbs; else return 0; } /* * Now find the block just before the freespace block. */ if ((error = xfs_bmap_last_before(tp, dp, &fo, XFS_DATA_FORK))) { return error; } /* * If it's not the single leaf block, give up. */ if (XFS_FSB_TO_B(mp, fo) > XFS_DIR2_LEAF_OFFSET + mp->m_dirblksize) return 0; lbp = state->path.blk[0].bp; leaf = lbp->data; ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC); /* * Read the freespace block. */ if ((error = xfs_da_read_buf(tp, dp, mp->m_dirfreeblk, -1, &fbp, XFS_DATA_FORK))) { return error; } free = fbp->data; ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC); ASSERT(!free->hdr.firstdb); /* * Now see if the leafn and free data will fit in a leaf1. * If not, release the buffer and give up. */ if ((uint)sizeof(leaf->hdr) + (be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale)) * (uint)sizeof(leaf->ents[0]) + be32_to_cpu(free->hdr.nvalid) * (uint)sizeof(leaf->bests[0]) + (uint)sizeof(leaf->tail) > mp->m_dirblksize) { xfs_da_brelse(tp, fbp); return 0; } /* * If the leaf has any stale entries in it, compress them out. * The compact routine will log the header. */ if (be16_to_cpu(leaf->hdr.stale)) xfs_dir2_leaf_compact(args, lbp); else xfs_dir2_leaf_log_header(tp, lbp); leaf->hdr.info.magic = cpu_to_be16(XFS_DIR2_LEAF1_MAGIC); /* * Set up the leaf tail from the freespace block. */ ltp = xfs_dir2_leaf_tail_p(mp, leaf); ltp->bestcount = free->hdr.nvalid; /* * Set up the leaf bests table. */ memcpy(xfs_dir2_leaf_bests_p(ltp), free->bests, be32_to_cpu(ltp->bestcount) * sizeof(leaf->bests[0])); xfs_dir2_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1); xfs_dir2_leaf_log_tail(tp, lbp); xfs_dir2_leaf_check(dp, lbp); /* * Get rid of the freespace block. */ error = xfs_dir2_shrink_inode(args, XFS_DIR2_FREE_FIRSTDB(mp), fbp); if (error) { /* * This can't fail here because it can only happen when * punching out the middle of an extent, and this is an * isolated block. */ ASSERT(error != ENOSPC); return error; } fbp = NULL; /* * Now see if we can convert the single-leaf directory * down to a block form directory. * This routine always kills the dabuf for the leaf, so * eliminate it from the path. */ error = xfs_dir2_leaf_to_block(args, lbp, NULL); state->path.blk[0].bp = NULL; return error;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -