|
@@ -1,5 +1,6 @@
|
|
|
/*
|
|
|
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
|
|
|
+ * Copyright (c) 2013 Red Hat, Inc.
|
|
|
* All Rights Reserved.
|
|
|
*
|
|
|
* This program is free software; you can redistribute it and/or
|
|
@@ -33,77 +34,263 @@
|
|
|
#include "xfs_dir2_priv.h"
|
|
|
#include "xfs_error.h"
|
|
|
#include "xfs_trace.h"
|
|
|
+#include "xfs_buf_item.h"
|
|
|
+#include "xfs_cksum.h"
|
|
|
|
|
|
/*
|
|
|
* Local function declarations.
|
|
|
*/
|
|
|
-#ifdef DEBUG
|
|
|
-static void xfs_dir2_leaf_check(struct xfs_inode *dp, struct xfs_buf *bp);
|
|
|
-#else
|
|
|
-#define xfs_dir2_leaf_check(dp, bp)
|
|
|
-#endif
|
|
|
static int xfs_dir2_leaf_lookup_int(xfs_da_args_t *args, struct xfs_buf **lbpp,
|
|
|
int *indexp, struct xfs_buf **dbpp);
|
|
|
-static void xfs_dir2_leaf_log_bests(struct xfs_trans *tp, struct xfs_buf *bp,
|
|
|
+static void xfs_dir3_leaf_log_bests(struct xfs_trans *tp, struct xfs_buf *bp,
|
|
|
int first, int last);
|
|
|
-static void xfs_dir2_leaf_log_tail(struct xfs_trans *tp, struct xfs_buf *bp);
|
|
|
+static void xfs_dir3_leaf_log_tail(struct xfs_trans *tp, struct xfs_buf *bp);
|
|
|
|
|
|
-static void
|
|
|
-xfs_dir2_leaf_verify(
|
|
|
+/*
|
|
|
+ * Check the internal consistency of a leaf1 block.
|
|
|
+ * Pop an assert if something is wrong.
|
|
|
+ */
|
|
|
+#ifdef DEBUG
|
|
|
+#define xfs_dir3_leaf_check(mp, bp) \
|
|
|
+do { \
|
|
|
+ if (!xfs_dir3_leaf1_check((mp), (bp))) \
|
|
|
+ ASSERT(0); \
|
|
|
+} while (0);
|
|
|
+
|
|
|
+STATIC bool
|
|
|
+xfs_dir3_leaf1_check(
|
|
|
+ struct xfs_mount *mp,
|
|
|
+ struct xfs_buf *bp)
|
|
|
+{
|
|
|
+ struct xfs_dir2_leaf *leaf = bp->b_addr;
|
|
|
+ struct xfs_dir3_icleaf_hdr leafhdr;
|
|
|
+
|
|
|
+ xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
|
|
|
+
|
|
|
+ if (leafhdr.magic == XFS_DIR3_LEAF1_MAGIC) {
|
|
|
+ struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr;
|
|
|
+ if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn)
|
|
|
+ return false;
|
|
|
+ } else if (leafhdr.magic != XFS_DIR2_LEAF1_MAGIC)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ return xfs_dir3_leaf_check_int(mp, &leafhdr, leaf);
|
|
|
+}
|
|
|
+#else
|
|
|
+#define xfs_dir3_leaf_check(mp, bp)
|
|
|
+#endif
|
|
|
+
|
|
|
+void
|
|
|
+xfs_dir3_leaf_hdr_from_disk(
|
|
|
+ struct xfs_dir3_icleaf_hdr *to,
|
|
|
+ struct xfs_dir2_leaf *from)
|
|
|
+{
|
|
|
+ if (from->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) ||
|
|
|
+ from->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC)) {
|
|
|
+ to->forw = be32_to_cpu(from->hdr.info.forw);
|
|
|
+ to->back = be32_to_cpu(from->hdr.info.back);
|
|
|
+ to->magic = be16_to_cpu(from->hdr.info.magic);
|
|
|
+ to->count = be16_to_cpu(from->hdr.count);
|
|
|
+ to->stale = be16_to_cpu(from->hdr.stale);
|
|
|
+ } else {
|
|
|
+ struct xfs_dir3_leaf_hdr *hdr3 = (struct xfs_dir3_leaf_hdr *)from;
|
|
|
+
|
|
|
+ to->forw = be32_to_cpu(hdr3->info.hdr.forw);
|
|
|
+ to->back = be32_to_cpu(hdr3->info.hdr.back);
|
|
|
+ to->magic = be16_to_cpu(hdr3->info.hdr.magic);
|
|
|
+ to->count = be16_to_cpu(hdr3->count);
|
|
|
+ to->stale = be16_to_cpu(hdr3->stale);
|
|
|
+ }
|
|
|
+
|
|
|
+ ASSERT(to->magic == XFS_DIR2_LEAF1_MAGIC ||
|
|
|
+ to->magic == XFS_DIR3_LEAF1_MAGIC ||
|
|
|
+ to->magic == XFS_DIR2_LEAFN_MAGIC ||
|
|
|
+ to->magic == XFS_DIR3_LEAFN_MAGIC);
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+xfs_dir3_leaf_hdr_to_disk(
|
|
|
+ struct xfs_dir2_leaf *to,
|
|
|
+ struct xfs_dir3_icleaf_hdr *from)
|
|
|
+{
|
|
|
+ ASSERT(from->magic == XFS_DIR2_LEAF1_MAGIC ||
|
|
|
+ from->magic == XFS_DIR3_LEAF1_MAGIC ||
|
|
|
+ from->magic == XFS_DIR2_LEAFN_MAGIC ||
|
|
|
+ from->magic == XFS_DIR3_LEAFN_MAGIC);
|
|
|
+
|
|
|
+ if (from->magic == XFS_DIR2_LEAF1_MAGIC ||
|
|
|
+ from->magic == XFS_DIR2_LEAFN_MAGIC) {
|
|
|
+ to->hdr.info.forw = cpu_to_be32(from->forw);
|
|
|
+ to->hdr.info.back = cpu_to_be32(from->back);
|
|
|
+ to->hdr.info.magic = cpu_to_be16(from->magic);
|
|
|
+ to->hdr.count = cpu_to_be16(from->count);
|
|
|
+ to->hdr.stale = cpu_to_be16(from->stale);
|
|
|
+ } else {
|
|
|
+ struct xfs_dir3_leaf_hdr *hdr3 = (struct xfs_dir3_leaf_hdr *)to;
|
|
|
+
|
|
|
+ hdr3->info.hdr.forw = cpu_to_be32(from->forw);
|
|
|
+ hdr3->info.hdr.back = cpu_to_be32(from->back);
|
|
|
+ hdr3->info.hdr.magic = cpu_to_be16(from->magic);
|
|
|
+ hdr3->count = cpu_to_be16(from->count);
|
|
|
+ hdr3->stale = cpu_to_be16(from->stale);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+bool
|
|
|
+xfs_dir3_leaf_check_int(
|
|
|
+ struct xfs_mount *mp,
|
|
|
+ struct xfs_dir3_icleaf_hdr *hdr,
|
|
|
+ struct xfs_dir2_leaf *leaf)
|
|
|
+{
|
|
|
+ struct xfs_dir2_leaf_entry *ents;
|
|
|
+ xfs_dir2_leaf_tail_t *ltp;
|
|
|
+ int stale;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ ents = xfs_dir3_leaf_ents_p(leaf);
|
|
|
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * XXX (dgc): 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.
|
|
|
+ */
|
|
|
+ if (hdr->count > xfs_dir3_max_leaf_ents(mp, leaf))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /* Leaves and bests don't overlap in leaf format. */
|
|
|
+ if ((hdr->magic == XFS_DIR2_LEAF1_MAGIC ||
|
|
|
+ hdr->magic == XFS_DIR3_LEAF1_MAGIC) &&
|
|
|
+ (char *)&ents[hdr->count] > (char *)xfs_dir2_leaf_bests_p(ltp))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /* Check hash value order, count stale entries. */
|
|
|
+ for (i = stale = 0; i < hdr->count; i++) {
|
|
|
+ if (i + 1 < hdr->count) {
|
|
|
+ if (be32_to_cpu(ents[i].hashval) >
|
|
|
+ be32_to_cpu(ents[i + 1].hashval))
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (ents[i].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
|
|
|
+ stale++;
|
|
|
+ }
|
|
|
+ if (hdr->stale != stale)
|
|
|
+ return false;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static bool
|
|
|
+xfs_dir3_leaf_verify(
|
|
|
struct xfs_buf *bp,
|
|
|
- __be16 magic)
|
|
|
+ __uint16_t magic)
|
|
|
+{
|
|
|
+ struct xfs_mount *mp = bp->b_target->bt_mount;
|
|
|
+ struct xfs_dir2_leaf *leaf = bp->b_addr;
|
|
|
+ struct xfs_dir3_icleaf_hdr leafhdr;
|
|
|
+
|
|
|
+ ASSERT(magic == XFS_DIR2_LEAF1_MAGIC || magic == XFS_DIR2_LEAFN_MAGIC);
|
|
|
+
|
|
|
+ xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
|
|
|
+ if (xfs_sb_version_hascrc(&mp->m_sb)) {
|
|
|
+ struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr;
|
|
|
+
|
|
|
+ if ((magic == XFS_DIR2_LEAF1_MAGIC &&
|
|
|
+ leafhdr.magic != XFS_DIR3_LEAF1_MAGIC) ||
|
|
|
+ (magic == XFS_DIR2_LEAFN_MAGIC &&
|
|
|
+ leafhdr.magic != XFS_DIR3_LEAFN_MAGIC))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_uuid))
|
|
|
+ return false;
|
|
|
+ if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn)
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ if (leafhdr.magic != magic)
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return xfs_dir3_leaf_check_int(mp, &leafhdr, leaf);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+__read_verify(
|
|
|
+ struct xfs_buf *bp,
|
|
|
+ __uint16_t magic)
|
|
|
+{
|
|
|
+ struct xfs_mount *mp = bp->b_target->bt_mount;
|
|
|
+
|
|
|
+ if ((xfs_sb_version_hascrc(&mp->m_sb) &&
|
|
|
+ !xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
|
|
|
+ XFS_DIR3_LEAF_CRC_OFF)) ||
|
|
|
+ !xfs_dir3_leaf_verify(bp, magic)) {
|
|
|
+ XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
|
|
|
+ xfs_buf_ioerror(bp, EFSCORRUPTED);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+__write_verify(
|
|
|
+ struct xfs_buf *bp,
|
|
|
+ __uint16_t magic)
|
|
|
{
|
|
|
struct xfs_mount *mp = bp->b_target->bt_mount;
|
|
|
- struct xfs_dir2_leaf_hdr *hdr = bp->b_addr;
|
|
|
- int block_ok = 0;
|
|
|
+ struct xfs_buf_log_item *bip = bp->b_fspriv;
|
|
|
+ struct xfs_dir3_leaf_hdr *hdr3 = bp->b_addr;
|
|
|
|
|
|
- block_ok = hdr->info.magic == magic;
|
|
|
- if (!block_ok) {
|
|
|
- XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, hdr);
|
|
|
+ if (!xfs_dir3_leaf_verify(bp, magic)) {
|
|
|
+ XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
|
|
|
xfs_buf_ioerror(bp, EFSCORRUPTED);
|
|
|
+ return;
|
|
|
}
|
|
|
+
|
|
|
+ if (!xfs_sb_version_hascrc(&mp->m_sb))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (bip)
|
|
|
+ hdr3->info.lsn = cpu_to_be64(bip->bli_item.li_lsn);
|
|
|
+
|
|
|
+ xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), XFS_DIR3_LEAF_CRC_OFF);
|
|
|
}
|
|
|
|
|
|
static void
|
|
|
-xfs_dir2_leaf1_read_verify(
|
|
|
+xfs_dir3_leaf1_read_verify(
|
|
|
struct xfs_buf *bp)
|
|
|
{
|
|
|
- xfs_dir2_leaf_verify(bp, cpu_to_be16(XFS_DIR2_LEAF1_MAGIC));
|
|
|
+ __read_verify(bp, XFS_DIR2_LEAF1_MAGIC);
|
|
|
}
|
|
|
|
|
|
static void
|
|
|
-xfs_dir2_leaf1_write_verify(
|
|
|
+xfs_dir3_leaf1_write_verify(
|
|
|
struct xfs_buf *bp)
|
|
|
{
|
|
|
- xfs_dir2_leaf_verify(bp, cpu_to_be16(XFS_DIR2_LEAF1_MAGIC));
|
|
|
+ __write_verify(bp, XFS_DIR2_LEAF1_MAGIC);
|
|
|
}
|
|
|
|
|
|
-void
|
|
|
-xfs_dir2_leafn_read_verify(
|
|
|
+static void
|
|
|
+xfs_dir3_leafn_read_verify(
|
|
|
struct xfs_buf *bp)
|
|
|
{
|
|
|
- xfs_dir2_leaf_verify(bp, cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
|
|
|
+ __read_verify(bp, XFS_DIR2_LEAFN_MAGIC);
|
|
|
}
|
|
|
|
|
|
-void
|
|
|
-xfs_dir2_leafn_write_verify(
|
|
|
+static void
|
|
|
+xfs_dir3_leafn_write_verify(
|
|
|
struct xfs_buf *bp)
|
|
|
{
|
|
|
- xfs_dir2_leaf_verify(bp, cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
|
|
|
+ __write_verify(bp, XFS_DIR2_LEAFN_MAGIC);
|
|
|
}
|
|
|
|
|
|
-static const struct xfs_buf_ops xfs_dir2_leaf1_buf_ops = {
|
|
|
- .verify_read = xfs_dir2_leaf1_read_verify,
|
|
|
- .verify_write = xfs_dir2_leaf1_write_verify,
|
|
|
+static const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops = {
|
|
|
+ .verify_read = xfs_dir3_leaf1_read_verify,
|
|
|
+ .verify_write = xfs_dir3_leaf1_write_verify,
|
|
|
};
|
|
|
|
|
|
-const struct xfs_buf_ops xfs_dir2_leafn_buf_ops = {
|
|
|
- .verify_read = xfs_dir2_leafn_read_verify,
|
|
|
- .verify_write = xfs_dir2_leafn_write_verify,
|
|
|
+const struct xfs_buf_ops xfs_dir3_leafn_buf_ops = {
|
|
|
+ .verify_read = xfs_dir3_leafn_read_verify,
|
|
|
+ .verify_write = xfs_dir3_leafn_write_verify,
|
|
|
};
|
|
|
|
|
|
static int
|
|
|
-xfs_dir2_leaf_read(
|
|
|
+xfs_dir3_leaf_read(
|
|
|
struct xfs_trans *tp,
|
|
|
struct xfs_inode *dp,
|
|
|
xfs_dablk_t fbno,
|
|
@@ -111,11 +298,11 @@ xfs_dir2_leaf_read(
|
|
|
struct xfs_buf **bpp)
|
|
|
{
|
|
|
return xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,
|
|
|
- XFS_DATA_FORK, &xfs_dir2_leaf1_buf_ops);
|
|
|
+ XFS_DATA_FORK, &xfs_dir3_leaf1_buf_ops);
|
|
|
}
|
|
|
|
|
|
int
|
|
|
-xfs_dir2_leafn_read(
|
|
|
+xfs_dir3_leafn_read(
|
|
|
struct xfs_trans *tp,
|
|
|
struct xfs_inode *dp,
|
|
|
xfs_dablk_t fbno,
|
|
@@ -123,7 +310,81 @@ xfs_dir2_leafn_read(
|
|
|
struct xfs_buf **bpp)
|
|
|
{
|
|
|
return xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,
|
|
|
- XFS_DATA_FORK, &xfs_dir2_leafn_buf_ops);
|
|
|
+ XFS_DATA_FORK, &xfs_dir3_leafn_buf_ops);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Initialize a new leaf block, leaf1 or leafn magic accepted.
|
|
|
+ */
|
|
|
+static void
|
|
|
+xfs_dir3_leaf_init(
|
|
|
+ struct xfs_mount *mp,
|
|
|
+ struct xfs_buf *bp,
|
|
|
+ xfs_ino_t owner,
|
|
|
+ __uint16_t type)
|
|
|
+{
|
|
|
+ struct xfs_dir2_leaf *leaf = bp->b_addr;
|
|
|
+
|
|
|
+ ASSERT(type == XFS_DIR2_LEAF1_MAGIC || type == XFS_DIR2_LEAFN_MAGIC);
|
|
|
+
|
|
|
+ if (xfs_sb_version_hascrc(&mp->m_sb)) {
|
|
|
+ struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr;
|
|
|
+
|
|
|
+ memset(leaf3, 0, sizeof(*leaf3));
|
|
|
+
|
|
|
+ leaf3->info.hdr.magic = (type == XFS_DIR2_LEAF1_MAGIC)
|
|
|
+ ? cpu_to_be16(XFS_DIR3_LEAF1_MAGIC)
|
|
|
+ : cpu_to_be16(XFS_DIR3_LEAFN_MAGIC);
|
|
|
+ leaf3->info.blkno = cpu_to_be64(bp->b_bn);
|
|
|
+ leaf3->info.owner = cpu_to_be64(owner);
|
|
|
+ uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_uuid);
|
|
|
+ } else {
|
|
|
+ memset(leaf, 0, sizeof(*leaf));
|
|
|
+ leaf->hdr.info.magic = cpu_to_be16(type);
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If it's a leaf-format directory initialize the tail.
|
|
|
+ * Caller is responsible for initialising the bests table.
|
|
|
+ */
|
|
|
+ if (type == XFS_DIR2_LEAF1_MAGIC) {
|
|
|
+ struct xfs_dir2_leaf_tail *ltp;
|
|
|
+
|
|
|
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
|
|
|
+ ltp->bestcount = 0;
|
|
|
+ bp->b_ops = &xfs_dir3_leaf1_buf_ops;
|
|
|
+ } else
|
|
|
+ bp->b_ops = &xfs_dir3_leafn_buf_ops;
|
|
|
+}
|
|
|
+
|
|
|
+int
|
|
|
+xfs_dir3_leaf_get_buf(
|
|
|
+ xfs_da_args_t *args,
|
|
|
+ xfs_dir2_db_t bno,
|
|
|
+ struct xfs_buf **bpp,
|
|
|
+ __uint16_t magic)
|
|
|
+{
|
|
|
+ struct xfs_inode *dp = args->dp;
|
|
|
+ struct xfs_trans *tp = args->trans;
|
|
|
+ struct xfs_mount *mp = dp->i_mount;
|
|
|
+ struct xfs_buf *bp;
|
|
|
+ int error;
|
|
|
+
|
|
|
+ ASSERT(magic == XFS_DIR2_LEAF1_MAGIC || magic == XFS_DIR2_LEAFN_MAGIC);
|
|
|
+ ASSERT(bno >= XFS_DIR2_LEAF_FIRSTDB(mp) &&
|
|
|
+ bno < XFS_DIR2_FREE_FIRSTDB(mp));
|
|
|
+
|
|
|
+ error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, bno), -1, &bp,
|
|
|
+ XFS_DATA_FORK);
|
|
|
+ if (error)
|
|
|
+ return error;
|
|
|
+
|
|
|
+ xfs_dir3_leaf_init(mp, bp, dp->i_ino, magic);
|
|
|
+ xfs_dir3_leaf_log_header(tp, bp);
|
|
|
+ if (magic == XFS_DIR2_LEAF1_MAGIC)
|
|
|
+ xfs_dir3_leaf_log_tail(tp, bp);
|
|
|
+ *bpp = bp;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -150,6 +411,8 @@ xfs_dir2_block_to_leaf(
|
|
|
int needscan; /* need to rescan bestfree */
|
|
|
xfs_trans_t *tp; /* transaction pointer */
|
|
|
struct xfs_dir2_data_free *bf;
|
|
|
+ struct xfs_dir2_leaf_entry *ents;
|
|
|
+ struct xfs_dir3_icleaf_hdr leafhdr;
|
|
|
|
|
|
trace_xfs_dir2_block_to_leaf(args);
|
|
|
|
|
@@ -169,27 +432,33 @@ xfs_dir2_block_to_leaf(
|
|
|
/*
|
|
|
* Initialize the leaf block, get a buffer for it.
|
|
|
*/
|
|
|
- if ((error = xfs_dir2_leaf_init(args, ldb, &lbp, XFS_DIR2_LEAF1_MAGIC))) {
|
|
|
+ error = xfs_dir3_leaf_get_buf(args, ldb, &lbp, XFS_DIR2_LEAF1_MAGIC);
|
|
|
+ if (error)
|
|
|
return error;
|
|
|
- }
|
|
|
- ASSERT(lbp != NULL);
|
|
|
+
|
|
|
leaf = lbp->b_addr;
|
|
|
hdr = dbp->b_addr;
|
|
|
xfs_dir3_data_check(dp, dbp);
|
|
|
btp = xfs_dir2_block_tail_p(mp, hdr);
|
|
|
blp = xfs_dir2_block_leaf_p(btp);
|
|
|
bf = xfs_dir3_data_bestfree_p(hdr);
|
|
|
+ ents = xfs_dir3_leaf_ents_p(leaf);
|
|
|
+
|
|
|
/*
|
|
|
* Set the counts in the leaf header.
|
|
|
*/
|
|
|
- leaf->hdr.count = cpu_to_be16(be32_to_cpu(btp->count));
|
|
|
- leaf->hdr.stale = cpu_to_be16(be32_to_cpu(btp->stale));
|
|
|
+ xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
|
|
|
+ leafhdr.count = be32_to_cpu(btp->count);
|
|
|
+ leafhdr.stale = be32_to_cpu(btp->stale);
|
|
|
+ xfs_dir3_leaf_hdr_to_disk(leaf, &leafhdr);
|
|
|
+ xfs_dir3_leaf_log_header(tp, lbp);
|
|
|
+
|
|
|
/*
|
|
|
* Could compact these but I think we always do the conversion
|
|
|
* after squeezing out stale entries.
|
|
|
*/
|
|
|
- memcpy(leaf->ents, blp, be32_to_cpu(btp->count) * sizeof(xfs_dir2_leaf_entry_t));
|
|
|
- xfs_dir2_leaf_log_ents(tp, lbp, 0, be16_to_cpu(leaf->hdr.count) - 1);
|
|
|
+ memcpy(ents, blp, be32_to_cpu(btp->count) * sizeof(xfs_dir2_leaf_entry_t));
|
|
|
+ xfs_dir3_leaf_log_ents(tp, lbp, 0, leafhdr.count - 1);
|
|
|
needscan = 0;
|
|
|
needlog = 1;
|
|
|
/*
|
|
@@ -224,15 +493,16 @@ xfs_dir2_block_to_leaf(
|
|
|
*/
|
|
|
if (needlog)
|
|
|
xfs_dir2_data_log_header(tp, dbp);
|
|
|
- xfs_dir2_leaf_check(dp, lbp);
|
|
|
+ xfs_dir3_leaf_check(mp, lbp);
|
|
|
xfs_dir3_data_check(dp, dbp);
|
|
|
- xfs_dir2_leaf_log_bests(tp, lbp, 0, 0);
|
|
|
+ xfs_dir3_leaf_log_bests(tp, lbp, 0, 0);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
STATIC void
|
|
|
-xfs_dir2_leaf_find_stale(
|
|
|
- struct xfs_dir2_leaf *leaf,
|
|
|
+xfs_dir3_leaf_find_stale(
|
|
|
+ struct xfs_dir3_icleaf_hdr *leafhdr,
|
|
|
+ struct xfs_dir2_leaf_entry *ents,
|
|
|
int index,
|
|
|
int *lowstale,
|
|
|
int *highstale)
|
|
@@ -241,7 +511,7 @@ xfs_dir2_leaf_find_stale(
|
|
|
* Find the first stale entry before our index, if any.
|
|
|
*/
|
|
|
for (*lowstale = index - 1; *lowstale >= 0; --*lowstale) {
|
|
|
- if (leaf->ents[*lowstale].address ==
|
|
|
+ if (ents[*lowstale].address ==
|
|
|
cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
|
|
|
break;
|
|
|
}
|
|
@@ -251,10 +521,8 @@ xfs_dir2_leaf_find_stale(
|
|
|
* Stop if the result would require moving more entries than using
|
|
|
* lowstale.
|
|
|
*/
|
|
|
- for (*highstale = index;
|
|
|
- *highstale < be16_to_cpu(leaf->hdr.count);
|
|
|
- ++*highstale) {
|
|
|
- if (leaf->ents[*highstale].address ==
|
|
|
+ for (*highstale = index; *highstale < leafhdr->count; ++*highstale) {
|
|
|
+ if (ents[*highstale].address ==
|
|
|
cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
|
|
|
break;
|
|
|
if (*lowstale >= 0 && index - *lowstale <= *highstale - index)
|
|
@@ -263,8 +531,9 @@ xfs_dir2_leaf_find_stale(
|
|
|
}
|
|
|
|
|
|
struct xfs_dir2_leaf_entry *
|
|
|
-xfs_dir2_leaf_find_entry(
|
|
|
- xfs_dir2_leaf_t *leaf, /* leaf structure */
|
|
|
+xfs_dir3_leaf_find_entry(
|
|
|
+ struct xfs_dir3_icleaf_hdr *leafhdr,
|
|
|
+ struct xfs_dir2_leaf_entry *ents,
|
|
|
int index, /* leaf table position */
|
|
|
int compact, /* need to compact leaves */
|
|
|
int lowstale, /* index of prev stale leaf */
|
|
@@ -272,7 +541,7 @@ xfs_dir2_leaf_find_entry(
|
|
|
int *lfloglow, /* low leaf logging index */
|
|
|
int *lfloghigh) /* high leaf logging index */
|
|
|
{
|
|
|
- if (!leaf->hdr.stale) {
|
|
|
+ if (!leafhdr->stale) {
|
|
|
xfs_dir2_leaf_entry_t *lep; /* leaf entry table pointer */
|
|
|
|
|
|
/*
|
|
@@ -280,18 +549,16 @@ xfs_dir2_leaf_find_entry(
|
|
|
*
|
|
|
* If there are no stale entries, just insert a hole at index.
|
|
|
*/
|
|
|
- lep = &leaf->ents[index];
|
|
|
- if (index < be16_to_cpu(leaf->hdr.count))
|
|
|
+ lep = &ents[index];
|
|
|
+ if (index < leafhdr->count)
|
|
|
memmove(lep + 1, lep,
|
|
|
- (be16_to_cpu(leaf->hdr.count) - index) *
|
|
|
- sizeof(*lep));
|
|
|
+ (leafhdr->count - index) * sizeof(*lep));
|
|
|
|
|
|
/*
|
|
|
* Record low and high logging indices for the leaf.
|
|
|
*/
|
|
|
*lfloglow = index;
|
|
|
- *lfloghigh = be16_to_cpu(leaf->hdr.count);
|
|
|
- be16_add_cpu(&leaf->hdr.count, 1);
|
|
|
+ *lfloghigh = leafhdr->count++;
|
|
|
return lep;
|
|
|
}
|
|
|
|
|
@@ -305,16 +572,17 @@ xfs_dir2_leaf_find_entry(
|
|
|
* entries before and after our insertion point.
|
|
|
*/
|
|
|
if (compact == 0)
|
|
|
- xfs_dir2_leaf_find_stale(leaf, index, &lowstale, &highstale);
|
|
|
+ xfs_dir3_leaf_find_stale(leafhdr, ents, index,
|
|
|
+ &lowstale, &highstale);
|
|
|
|
|
|
/*
|
|
|
* If the low one is better, use it.
|
|
|
*/
|
|
|
if (lowstale >= 0 &&
|
|
|
- (highstale == be16_to_cpu(leaf->hdr.count) ||
|
|
|
+ (highstale == leafhdr->count ||
|
|
|
index - lowstale - 1 < highstale - index)) {
|
|
|
ASSERT(index - lowstale - 1 >= 0);
|
|
|
- ASSERT(leaf->ents[lowstale].address ==
|
|
|
+ ASSERT(ents[lowstale].address ==
|
|
|
cpu_to_be32(XFS_DIR2_NULL_DATAPTR));
|
|
|
|
|
|
/*
|
|
@@ -322,37 +590,34 @@ xfs_dir2_leaf_find_entry(
|
|
|
* for the new entry.
|
|
|
*/
|
|
|
if (index - lowstale - 1 > 0) {
|
|
|
- memmove(&leaf->ents[lowstale],
|
|
|
- &leaf->ents[lowstale + 1],
|
|
|
+ memmove(&ents[lowstale], &ents[lowstale + 1],
|
|
|
(index - lowstale - 1) *
|
|
|
- sizeof(xfs_dir2_leaf_entry_t));
|
|
|
+ sizeof(xfs_dir2_leaf_entry_t));
|
|
|
}
|
|
|
*lfloglow = MIN(lowstale, *lfloglow);
|
|
|
*lfloghigh = MAX(index - 1, *lfloghigh);
|
|
|
- be16_add_cpu(&leaf->hdr.stale, -1);
|
|
|
- return &leaf->ents[index - 1];
|
|
|
+ leafhdr->stale--;
|
|
|
+ return &ents[index - 1];
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* The high one is better, so use that one.
|
|
|
*/
|
|
|
ASSERT(highstale - index >= 0);
|
|
|
- ASSERT(leaf->ents[highstale].address ==
|
|
|
- cpu_to_be32(XFS_DIR2_NULL_DATAPTR));
|
|
|
+ ASSERT(ents[highstale].address == cpu_to_be32(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],
|
|
|
+ memmove(&ents[index + 1], &ents[index],
|
|
|
(highstale - index) * sizeof(xfs_dir2_leaf_entry_t));
|
|
|
}
|
|
|
*lfloglow = MIN(index, *lfloglow);
|
|
|
*lfloghigh = MAX(highstale, *lfloghigh);
|
|
|
- be16_add_cpu(&leaf->hdr.stale, -1);
|
|
|
- return &leaf->ents[index];
|
|
|
+ leafhdr->stale--;
|
|
|
+ return &ents[index];
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -390,6 +655,8 @@ xfs_dir2_leaf_addname(
|
|
|
xfs_trans_t *tp; /* transaction pointer */
|
|
|
xfs_dir2_db_t use_block; /* data block number */
|
|
|
struct xfs_dir2_data_free *bf; /* bestfree table */
|
|
|
+ struct xfs_dir2_leaf_entry *ents;
|
|
|
+ struct xfs_dir3_icleaf_hdr leafhdr;
|
|
|
|
|
|
trace_xfs_dir2_leaf_addname(args);
|
|
|
|
|
@@ -397,7 +664,7 @@ xfs_dir2_leaf_addname(
|
|
|
tp = args->trans;
|
|
|
mp = dp->i_mount;
|
|
|
|
|
|
- error = xfs_dir2_leaf_read(tp, dp, mp->m_dirleafblk, -1, &lbp);
|
|
|
+ error = xfs_dir3_leaf_read(tp, dp, mp->m_dirleafblk, -1, &lbp);
|
|
|
if (error)
|
|
|
return error;
|
|
|
|
|
@@ -410,16 +677,19 @@ xfs_dir2_leaf_addname(
|
|
|
index = xfs_dir2_leaf_search_hash(args, lbp);
|
|
|
leaf = lbp->b_addr;
|
|
|
ltp = xfs_dir2_leaf_tail_p(mp, leaf);
|
|
|
+ ents = xfs_dir3_leaf_ents_p(leaf);
|
|
|
+ xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
|
|
|
bestsp = xfs_dir2_leaf_bests_p(ltp);
|
|
|
length = xfs_dir2_data_entsize(args->namelen);
|
|
|
+
|
|
|
/*
|
|
|
* See if there are any entries with the same hash value
|
|
|
* and space in their block for the new entry.
|
|
|
* This is good because it puts multiple same-hash value entries
|
|
|
* in a data block, improving the lookup of those entries.
|
|
|
*/
|
|
|
- for (use_block = -1, lep = &leaf->ents[index];
|
|
|
- index < be16_to_cpu(leaf->hdr.count) && be32_to_cpu(lep->hashval) == args->hashval;
|
|
|
+ for (use_block = -1, lep = &ents[index];
|
|
|
+ index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval;
|
|
|
index++, lep++) {
|
|
|
if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
|
|
|
continue;
|
|
@@ -452,7 +722,7 @@ xfs_dir2_leaf_addname(
|
|
|
* How many bytes do we need in the leaf block?
|
|
|
*/
|
|
|
needbytes = 0;
|
|
|
- if (!leaf->hdr.stale)
|
|
|
+ if (!leafhdr.stale)
|
|
|
needbytes += sizeof(xfs_dir2_leaf_entry_t);
|
|
|
if (use_block == -1)
|
|
|
needbytes += sizeof(xfs_dir2_data_off_t);
|
|
@@ -467,16 +737,15 @@ xfs_dir2_leaf_addname(
|
|
|
* If we don't have enough free bytes but we can make enough
|
|
|
* by compacting out stale entries, we'll do that.
|
|
|
*/
|
|
|
- if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] <
|
|
|
- needbytes && be16_to_cpu(leaf->hdr.stale) > 1) {
|
|
|
+ if ((char *)bestsp - (char *)&ents[leafhdr.count] < needbytes &&
|
|
|
+ leafhdr.stale > 1)
|
|
|
compact = 1;
|
|
|
- }
|
|
|
+
|
|
|
/*
|
|
|
* Otherwise if we don't have enough free bytes we need to
|
|
|
* convert to node form.
|
|
|
*/
|
|
|
- else if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu(
|
|
|
- leaf->hdr.count)] < needbytes) {
|
|
|
+ else if ((char *)bestsp - (char *)&ents[leafhdr.count] < needbytes) {
|
|
|
/*
|
|
|
* Just checking or no space reservation, give up.
|
|
|
*/
|
|
@@ -524,15 +793,15 @@ xfs_dir2_leaf_addname(
|
|
|
* point later.
|
|
|
*/
|
|
|
if (compact) {
|
|
|
- xfs_dir2_leaf_compact_x1(lbp, &index, &lowstale, &highstale,
|
|
|
- &lfloglow, &lfloghigh);
|
|
|
+ xfs_dir3_leaf_compact_x1(&leafhdr, ents, &index, &lowstale,
|
|
|
+ &highstale, &lfloglow, &lfloghigh);
|
|
|
}
|
|
|
/*
|
|
|
* There are stale entries, so we'll need log-low and log-high
|
|
|
* impossibly bad values later.
|
|
|
*/
|
|
|
- else if (be16_to_cpu(leaf->hdr.stale)) {
|
|
|
- lfloglow = be16_to_cpu(leaf->hdr.count);
|
|
|
+ else if (leafhdr.stale) {
|
|
|
+ lfloglow = leafhdr.count;
|
|
|
lfloghigh = -1;
|
|
|
}
|
|
|
/*
|
|
@@ -564,14 +833,14 @@ xfs_dir2_leaf_addname(
|
|
|
memmove(&bestsp[0], &bestsp[1],
|
|
|
be32_to_cpu(ltp->bestcount) * sizeof(bestsp[0]));
|
|
|
be32_add_cpu(<p->bestcount, 1);
|
|
|
- xfs_dir2_leaf_log_tail(tp, lbp);
|
|
|
- xfs_dir2_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
|
|
|
+ xfs_dir3_leaf_log_tail(tp, lbp);
|
|
|
+ xfs_dir3_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
|
|
|
}
|
|
|
/*
|
|
|
* If we're filling in a previously empty block just log it.
|
|
|
*/
|
|
|
else
|
|
|
- xfs_dir2_leaf_log_bests(tp, lbp, use_block, use_block);
|
|
|
+ xfs_dir3_leaf_log_bests(tp, lbp, use_block, use_block);
|
|
|
hdr = dbp->b_addr;
|
|
|
bf = xfs_dir3_data_bestfree_p(hdr);
|
|
|
bestsp[use_block] = bf[0].length;
|
|
@@ -632,10 +901,10 @@ xfs_dir2_leaf_addname(
|
|
|
if (be16_to_cpu(bestsp[use_block]) != be16_to_cpu(bf[0].length)) {
|
|
|
bestsp[use_block] = bf[0].length;
|
|
|
if (!grown)
|
|
|
- xfs_dir2_leaf_log_bests(tp, lbp, use_block, use_block);
|
|
|
+ xfs_dir3_leaf_log_bests(tp, lbp, use_block, use_block);
|
|
|
}
|
|
|
|
|
|
- lep = xfs_dir2_leaf_find_entry(leaf, index, compact, lowstale,
|
|
|
+ lep = xfs_dir3_leaf_find_entry(&leafhdr, ents, index, compact, lowstale,
|
|
|
highstale, &lfloglow, &lfloghigh);
|
|
|
|
|
|
/*
|
|
@@ -647,82 +916,40 @@ xfs_dir2_leaf_addname(
|
|
|
/*
|
|
|
* 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_dir3_leaf_hdr_to_disk(leaf, &leafhdr);
|
|
|
+ xfs_dir3_leaf_log_header(tp, lbp);
|
|
|
+ xfs_dir3_leaf_log_ents(tp, lbp, lfloglow, lfloghigh);
|
|
|
+ xfs_dir3_leaf_check(mp, lbp);
|
|
|
xfs_dir3_data_check(dp, dbp);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-#ifdef DEBUG
|
|
|
-/*
|
|
|
- * Check the internal consistency of a leaf1 block.
|
|
|
- * Pop an assert if something is wrong.
|
|
|
- */
|
|
|
-STATIC void
|
|
|
-xfs_dir2_leaf_check(
|
|
|
- struct xfs_inode *dp, /* incore directory inode */
|
|
|
- struct xfs_buf *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->b_addr;
|
|
|
- mp = dp->i_mount;
|
|
|
- ASSERT(leaf->hdr.info.magic == cpu_to_be16(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 (leaf->ents[i].address == cpu_to_be32(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.
|
|
|
*/
|
|
|
void
|
|
|
-xfs_dir2_leaf_compact(
|
|
|
+xfs_dir3_leaf_compact(
|
|
|
xfs_da_args_t *args, /* operation arguments */
|
|
|
+ struct xfs_dir3_icleaf_hdr *leafhdr,
|
|
|
struct xfs_buf *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 */
|
|
|
+ struct xfs_dir2_leaf_entry *ents;
|
|
|
|
|
|
leaf = bp->b_addr;
|
|
|
- if (!leaf->hdr.stale) {
|
|
|
+ if (!leafhdr->stale)
|
|
|
return;
|
|
|
- }
|
|
|
+
|
|
|
/*
|
|
|
* Compress out the stale entries in place.
|
|
|
*/
|
|
|
- for (from = to = 0, loglow = -1; from < be16_to_cpu(leaf->hdr.count); from++) {
|
|
|
- if (leaf->ents[from].address ==
|
|
|
- cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
|
|
|
+ ents = xfs_dir3_leaf_ents_p(leaf);
|
|
|
+ for (from = to = 0, loglow = -1; from < leafhdr->count; from++) {
|
|
|
+ if (ents[from].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
|
|
|
continue;
|
|
|
/*
|
|
|
* Only actually copy the entries that are different.
|
|
@@ -730,19 +957,21 @@ xfs_dir2_leaf_compact(
|
|
|
if (from > to) {
|
|
|
if (loglow == -1)
|
|
|
loglow = to;
|
|
|
- leaf->ents[to] = leaf->ents[from];
|
|
|
+ ents[to] = ents[from];
|
|
|
}
|
|
|
to++;
|
|
|
}
|
|
|
/*
|
|
|
* Update and log the header, log the leaf entries.
|
|
|
*/
|
|
|
- ASSERT(be16_to_cpu(leaf->hdr.stale) == from - to);
|
|
|
- be16_add_cpu(&leaf->hdr.count, -(be16_to_cpu(leaf->hdr.stale)));
|
|
|
- leaf->hdr.stale = 0;
|
|
|
- xfs_dir2_leaf_log_header(args->trans, bp);
|
|
|
+ ASSERT(leafhdr->stale == from - to);
|
|
|
+ leafhdr->count -= leafhdr->stale;
|
|
|
+ leafhdr->stale = 0;
|
|
|
+
|
|
|
+ xfs_dir3_leaf_hdr_to_disk(leaf, leafhdr);
|
|
|
+ xfs_dir3_leaf_log_header(args->trans, bp);
|
|
|
if (loglow != -1)
|
|
|
- xfs_dir2_leaf_log_ents(args->trans, bp, loglow, to - 1);
|
|
|
+ xfs_dir3_leaf_log_ents(args->trans, bp, loglow, to - 1);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -754,8 +983,9 @@ xfs_dir2_leaf_compact(
|
|
|
* and leaf logging indices.
|
|
|
*/
|
|
|
void
|
|
|
-xfs_dir2_leaf_compact_x1(
|
|
|
- struct xfs_buf *bp, /* leaf buffer */
|
|
|
+xfs_dir3_leaf_compact_x1(
|
|
|
+ struct xfs_dir3_icleaf_hdr *leafhdr,
|
|
|
+ struct xfs_dir2_leaf_entry *ents,
|
|
|
int *indexp, /* insertion index */
|
|
|
int *lowstalep, /* out: stale entry before us */
|
|
|
int *highstalep, /* out: stale entry after us */
|
|
@@ -766,22 +996,20 @@ xfs_dir2_leaf_compact_x1(
|
|
|
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->b_addr;
|
|
|
- ASSERT(be16_to_cpu(leaf->hdr.stale) > 1);
|
|
|
+ ASSERT(leafhdr->stale > 1);
|
|
|
index = *indexp;
|
|
|
|
|
|
- xfs_dir2_leaf_find_stale(leaf, index, &lowstale, &highstale);
|
|
|
+ xfs_dir3_leaf_find_stale(leafhdr, ents, index, &lowstale, &highstale);
|
|
|
|
|
|
/*
|
|
|
* Pick the better of lowstale and highstale.
|
|
|
*/
|
|
|
if (lowstale >= 0 &&
|
|
|
- (highstale == be16_to_cpu(leaf->hdr.count) ||
|
|
|
+ (highstale == leafhdr->count ||
|
|
|
index - lowstale <= highstale - index))
|
|
|
keepstale = lowstale;
|
|
|
else
|
|
@@ -790,15 +1018,14 @@ xfs_dir2_leaf_compact_x1(
|
|
|
* Copy the entries in place, removing all the stale entries
|
|
|
* except keepstale.
|
|
|
*/
|
|
|
- for (from = to = 0; from < be16_to_cpu(leaf->hdr.count); from++) {
|
|
|
+ for (from = to = 0; from < leafhdr->count; from++) {
|
|
|
/*
|
|
|
* Notice the new value of index.
|
|
|
*/
|
|
|
if (index == from)
|
|
|
newindex = to;
|
|
|
if (from != keepstale &&
|
|
|
- leaf->ents[from].address ==
|
|
|
- cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) {
|
|
|
+ ents[from].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) {
|
|
|
if (from == to)
|
|
|
*lowlogp = to;
|
|
|
continue;
|
|
@@ -812,7 +1039,7 @@ xfs_dir2_leaf_compact_x1(
|
|
|
* Copy only the entries that have moved.
|
|
|
*/
|
|
|
if (from > to)
|
|
|
- leaf->ents[to] = leaf->ents[from];
|
|
|
+ ents[to] = ents[from];
|
|
|
to++;
|
|
|
}
|
|
|
ASSERT(from > to);
|
|
@@ -826,8 +1053,8 @@ xfs_dir2_leaf_compact_x1(
|
|
|
/*
|
|
|
* Adjust the leaf header values.
|
|
|
*/
|
|
|
- be16_add_cpu(&leaf->hdr.count, -(from - to));
|
|
|
- leaf->hdr.stale = cpu_to_be16(1);
|
|
|
+ leafhdr->count -= from - to;
|
|
|
+ leafhdr->stale = 1;
|
|
|
/*
|
|
|
* Remember the low/high stale value only in the "right"
|
|
|
* direction.
|
|
@@ -835,8 +1062,8 @@ xfs_dir2_leaf_compact_x1(
|
|
|
if (lowstale >= newindex)
|
|
|
lowstale = -1;
|
|
|
else
|
|
|
- highstale = be16_to_cpu(leaf->hdr.count);
|
|
|
- *highlogp = be16_to_cpu(leaf->hdr.count) - 1;
|
|
|
+ highstale = leafhdr->count;
|
|
|
+ *highlogp = leafhdr->count - 1;
|
|
|
*lowstalep = lowstale;
|
|
|
*highstalep = highstale;
|
|
|
}
|
|
@@ -1229,69 +1456,12 @@ xfs_dir2_leaf_getdents(
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Initialize a new leaf block, leaf1 or leafn magic accepted.
|
|
|
- */
|
|
|
-int
|
|
|
-xfs_dir2_leaf_init(
|
|
|
- xfs_da_args_t *args, /* operation arguments */
|
|
|
- xfs_dir2_db_t bno, /* directory block number */
|
|
|
- struct xfs_buf **bpp, /* out: leaf buffer */
|
|
|
- int magic) /* magic number for block */
|
|
|
-{
|
|
|
- struct xfs_buf *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;
|
|
|
-
|
|
|
- /*
|
|
|
- * Initialize the header.
|
|
|
- */
|
|
|
- leaf = bp->b_addr;
|
|
|
- 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) {
|
|
|
- bp->b_ops = &xfs_dir2_leaf1_buf_ops;
|
|
|
- ltp = xfs_dir2_leaf_tail_p(mp, leaf);
|
|
|
- ltp->bestcount = 0;
|
|
|
- xfs_dir2_leaf_log_tail(tp, bp);
|
|
|
- } else
|
|
|
- bp->b_ops = &xfs_dir2_leafn_buf_ops;
|
|
|
- *bpp = bp;
|
|
|
- return 0;
|
|
|
-}
|
|
|
|
|
|
/*
|
|
|
* Log the bests entries indicated from a leaf1 block.
|
|
|
*/
|
|
|
static void
|
|
|
-xfs_dir2_leaf_log_bests(
|
|
|
+xfs_dir3_leaf_log_bests(
|
|
|
xfs_trans_t *tp, /* transaction pointer */
|
|
|
struct xfs_buf *bp, /* leaf buffer */
|
|
|
int first, /* first entry to log */
|
|
@@ -1299,11 +1469,12 @@ xfs_dir2_leaf_log_bests(
|
|
|
{
|
|
|
__be16 *firstb; /* pointer to first entry */
|
|
|
__be16 *lastb; /* pointer to last entry */
|
|
|
- xfs_dir2_leaf_t *leaf; /* leaf structure */
|
|
|
+ struct xfs_dir2_leaf *leaf = bp->b_addr;
|
|
|
xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */
|
|
|
|
|
|
- leaf = bp->b_addr;
|
|
|
- ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC));
|
|
|
+ ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) ||
|
|
|
+ leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_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;
|
|
@@ -1315,7 +1486,7 @@ xfs_dir2_leaf_log_bests(
|
|
|
* Log the leaf entries indicated from a leaf1 or leafn block.
|
|
|
*/
|
|
|
void
|
|
|
-xfs_dir2_leaf_log_ents(
|
|
|
+xfs_dir3_leaf_log_ents(
|
|
|
xfs_trans_t *tp, /* transaction pointer */
|
|
|
struct xfs_buf *bp, /* leaf buffer */
|
|
|
int first, /* first entry to log */
|
|
@@ -1323,13 +1494,17 @@ xfs_dir2_leaf_log_ents(
|
|
|
{
|
|
|
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 */
|
|
|
+ struct xfs_dir2_leaf *leaf = bp->b_addr;
|
|
|
+ struct xfs_dir2_leaf_entry *ents;
|
|
|
|
|
|
- leaf = bp->b_addr;
|
|
|
ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) ||
|
|
|
- leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
|
|
|
- firstlep = &leaf->ents[first];
|
|
|
- lastlep = &leaf->ents[last];
|
|
|
+ leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) ||
|
|
|
+ leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
|
|
|
+ leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC));
|
|
|
+
|
|
|
+ ents = xfs_dir3_leaf_ents_p(leaf);
|
|
|
+ firstlep = &ents[first];
|
|
|
+ lastlep = &ents[last];
|
|
|
xfs_trans_log_buf(tp, bp, (uint)((char *)firstlep - (char *)leaf),
|
|
|
(uint)((char *)lastlep - (char *)leaf + sizeof(*lastlep) - 1));
|
|
|
}
|
|
@@ -1338,34 +1513,38 @@ xfs_dir2_leaf_log_ents(
|
|
|
* Log the header of the leaf1 or leafn block.
|
|
|
*/
|
|
|
void
|
|
|
-xfs_dir2_leaf_log_header(
|
|
|
+xfs_dir3_leaf_log_header(
|
|
|
struct xfs_trans *tp,
|
|
|
struct xfs_buf *bp)
|
|
|
{
|
|
|
- xfs_dir2_leaf_t *leaf; /* leaf structure */
|
|
|
+ struct xfs_dir2_leaf *leaf = bp->b_addr;
|
|
|
|
|
|
- leaf = bp->b_addr;
|
|
|
ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) ||
|
|
|
- leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
|
|
|
+ leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) ||
|
|
|
+ leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
|
|
|
+ leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC));
|
|
|
+
|
|
|
xfs_trans_log_buf(tp, bp, (uint)((char *)&leaf->hdr - (char *)leaf),
|
|
|
- (uint)(sizeof(leaf->hdr) - 1));
|
|
|
+ xfs_dir3_leaf_hdr_size(leaf) - 1);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* Log the tail of the leaf1 block.
|
|
|
*/
|
|
|
STATIC void
|
|
|
-xfs_dir2_leaf_log_tail(
|
|
|
+xfs_dir3_leaf_log_tail(
|
|
|
struct xfs_trans *tp,
|
|
|
struct xfs_buf *bp)
|
|
|
{
|
|
|
- xfs_dir2_leaf_t *leaf; /* leaf structure */
|
|
|
+ struct xfs_dir2_leaf *leaf = bp->b_addr;
|
|
|
xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */
|
|
|
- xfs_mount_t *mp; /* filesystem mount point */
|
|
|
+ struct xfs_mount *mp = tp->t_mountp;
|
|
|
+
|
|
|
+ ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) ||
|
|
|
+ leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) ||
|
|
|
+ leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
|
|
|
+ leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC));
|
|
|
|
|
|
- mp = tp->t_mountp;
|
|
|
- leaf = bp->b_addr;
|
|
|
- ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC));
|
|
|
ltp = xfs_dir2_leaf_tail_p(mp, leaf);
|
|
|
xfs_trans_log_buf(tp, bp, (uint)((char *)ltp - (char *)leaf),
|
|
|
(uint)(mp->m_dirblksize - 1));
|
|
@@ -1389,6 +1568,7 @@ xfs_dir2_leaf_lookup(
|
|
|
xfs_dir2_leaf_t *leaf; /* leaf structure */
|
|
|
xfs_dir2_leaf_entry_t *lep; /* leaf entry */
|
|
|
xfs_trans_t *tp; /* transaction pointer */
|
|
|
+ struct xfs_dir2_leaf_entry *ents;
|
|
|
|
|
|
trace_xfs_dir2_leaf_lookup(args);
|
|
|
|
|
@@ -1400,12 +1580,14 @@ xfs_dir2_leaf_lookup(
|
|
|
}
|
|
|
tp = args->trans;
|
|
|
dp = args->dp;
|
|
|
- xfs_dir2_leaf_check(dp, lbp);
|
|
|
+ xfs_dir3_leaf_check(dp->i_mount, lbp);
|
|
|
leaf = lbp->b_addr;
|
|
|
+ ents = xfs_dir3_leaf_ents_p(leaf);
|
|
|
/*
|
|
|
* Get to the leaf entry and contained data entry address.
|
|
|
*/
|
|
|
- lep = &leaf->ents[index];
|
|
|
+ lep = &ents[index];
|
|
|
+
|
|
|
/*
|
|
|
* Point to the data entry.
|
|
|
*/
|
|
@@ -1449,18 +1631,23 @@ xfs_dir2_leaf_lookup_int(
|
|
|
xfs_trans_t *tp; /* transaction pointer */
|
|
|
xfs_dir2_db_t cidb = -1; /* case match data block no. */
|
|
|
enum xfs_dacmp cmp; /* name compare result */
|
|
|
+ struct xfs_dir2_leaf_entry *ents;
|
|
|
+ struct xfs_dir3_icleaf_hdr leafhdr;
|
|
|
|
|
|
dp = args->dp;
|
|
|
tp = args->trans;
|
|
|
mp = dp->i_mount;
|
|
|
|
|
|
- error = xfs_dir2_leaf_read(tp, dp, mp->m_dirleafblk, -1, &lbp);
|
|
|
+ error = xfs_dir3_leaf_read(tp, dp, mp->m_dirleafblk, -1, &lbp);
|
|
|
if (error)
|
|
|
return error;
|
|
|
|
|
|
*lbpp = lbp;
|
|
|
leaf = lbp->b_addr;
|
|
|
- xfs_dir2_leaf_check(dp, lbp);
|
|
|
+ xfs_dir3_leaf_check(mp, lbp);
|
|
|
+ ents = xfs_dir3_leaf_ents_p(leaf);
|
|
|
+ xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
|
|
|
+
|
|
|
/*
|
|
|
* Look for the first leaf entry with our hash value.
|
|
|
*/
|
|
@@ -1469,9 +1656,9 @@ xfs_dir2_leaf_lookup_int(
|
|
|
* Loop over all the entries with the right hash value
|
|
|
* looking to match the name.
|
|
|
*/
|
|
|
- for (lep = &leaf->ents[index]; index < be16_to_cpu(leaf->hdr.count) &&
|
|
|
- be32_to_cpu(lep->hashval) == args->hashval;
|
|
|
- lep++, index++) {
|
|
|
+ for (lep = &ents[index];
|
|
|
+ index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval;
|
|
|
+ lep++, index++) {
|
|
|
/*
|
|
|
* Skip over stale leaf entries.
|
|
|
*/
|
|
@@ -1576,6 +1763,8 @@ xfs_dir2_leaf_removename(
|
|
|
xfs_dir2_data_off_t oldbest; /* old value of best free */
|
|
|
xfs_trans_t *tp; /* transaction pointer */
|
|
|
struct xfs_dir2_data_free *bf; /* bestfree table */
|
|
|
+ struct xfs_dir2_leaf_entry *ents;
|
|
|
+ struct xfs_dir3_icleaf_hdr leafhdr;
|
|
|
|
|
|
trace_xfs_dir2_leaf_removename(args);
|
|
|
|
|
@@ -1590,12 +1779,14 @@ xfs_dir2_leaf_removename(
|
|
|
mp = dp->i_mount;
|
|
|
leaf = lbp->b_addr;
|
|
|
hdr = dbp->b_addr;
|
|
|
- bf = xfs_dir3_data_bestfree_p(hdr);
|
|
|
xfs_dir3_data_check(dp, dbp);
|
|
|
+ bf = xfs_dir3_data_bestfree_p(hdr);
|
|
|
+ xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
|
|
|
+ ents = xfs_dir3_leaf_ents_p(leaf);
|
|
|
/*
|
|
|
* Point to the leaf entry, use that to point to the data entry.
|
|
|
*/
|
|
|
- lep = &leaf->ents[index];
|
|
|
+ lep = &ents[index];
|
|
|
db = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
|
|
|
dep = (xfs_dir2_data_entry_t *)
|
|
|
((char *)hdr + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
|
|
@@ -1613,10 +1804,13 @@ xfs_dir2_leaf_removename(
|
|
|
/*
|
|
|
* We just mark the leaf entry stale by putting a null in it.
|
|
|
*/
|
|
|
- be16_add_cpu(&leaf->hdr.stale, 1);
|
|
|
- xfs_dir2_leaf_log_header(tp, lbp);
|
|
|
+ leafhdr.stale++;
|
|
|
+ xfs_dir3_leaf_hdr_to_disk(leaf, &leafhdr);
|
|
|
+ xfs_dir3_leaf_log_header(tp, lbp);
|
|
|
+
|
|
|
lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR);
|
|
|
- xfs_dir2_leaf_log_ents(tp, lbp, index, index);
|
|
|
+ xfs_dir3_leaf_log_ents(tp, lbp, index, index);
|
|
|
+
|
|
|
/*
|
|
|
* Scan the freespace in the data block again if necessary,
|
|
|
* log the data block header if necessary.
|
|
@@ -1631,7 +1825,7 @@ xfs_dir2_leaf_removename(
|
|
|
*/
|
|
|
if (be16_to_cpu(bf[0].length) != oldbest) {
|
|
|
bestsp[db] = bf[0].length;
|
|
|
- xfs_dir2_leaf_log_bests(tp, lbp, db, db);
|
|
|
+ xfs_dir3_leaf_log_bests(tp, lbp, db, db);
|
|
|
}
|
|
|
xfs_dir3_data_check(dp, dbp);
|
|
|
/*
|
|
@@ -1649,7 +1843,7 @@ xfs_dir2_leaf_removename(
|
|
|
*/
|
|
|
if (error == ENOSPC && args->total == 0)
|
|
|
error = 0;
|
|
|
- xfs_dir2_leaf_check(dp, lbp);
|
|
|
+ xfs_dir3_leaf_check(mp, lbp);
|
|
|
return error;
|
|
|
}
|
|
|
dbp = NULL;
|
|
@@ -1672,8 +1866,8 @@ xfs_dir2_leaf_removename(
|
|
|
memmove(&bestsp[db - i], bestsp,
|
|
|
(be32_to_cpu(ltp->bestcount) - (db - i)) * sizeof(*bestsp));
|
|
|
be32_add_cpu(<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);
|
|
|
+ xfs_dir3_leaf_log_tail(tp, lbp);
|
|
|
+ xfs_dir3_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
|
|
|
} else
|
|
|
bestsp[db] = cpu_to_be16(NULLDATAOFF);
|
|
|
}
|
|
@@ -1683,7 +1877,7 @@ xfs_dir2_leaf_removename(
|
|
|
else if (db != mp->m_dirdatablk)
|
|
|
dbp = NULL;
|
|
|
|
|
|
- xfs_dir2_leaf_check(dp, lbp);
|
|
|
+ xfs_dir3_leaf_check(mp, lbp);
|
|
|
/*
|
|
|
* See if we can convert to block form.
|
|
|
*/
|
|
@@ -1706,6 +1900,7 @@ xfs_dir2_leaf_replace(
|
|
|
xfs_dir2_leaf_t *leaf; /* leaf structure */
|
|
|
xfs_dir2_leaf_entry_t *lep; /* leaf entry */
|
|
|
xfs_trans_t *tp; /* transaction pointer */
|
|
|
+ struct xfs_dir2_leaf_entry *ents;
|
|
|
|
|
|
trace_xfs_dir2_leaf_replace(args);
|
|
|
|
|
@@ -1717,10 +1912,11 @@ xfs_dir2_leaf_replace(
|
|
|
}
|
|
|
dp = args->dp;
|
|
|
leaf = lbp->b_addr;
|
|
|
+ ents = xfs_dir3_leaf_ents_p(leaf);
|
|
|
/*
|
|
|
* Point to the leaf entry, get data address from it.
|
|
|
*/
|
|
|
- lep = &leaf->ents[index];
|
|
|
+ lep = &ents[index];
|
|
|
/*
|
|
|
* Point to the data entry.
|
|
|
*/
|
|
@@ -1734,7 +1930,7 @@ xfs_dir2_leaf_replace(
|
|
|
dep->inumber = cpu_to_be64(args->inumber);
|
|
|
tp = args->trans;
|
|
|
xfs_dir2_data_log_entry(tp, dbp, dep);
|
|
|
- xfs_dir2_leaf_check(dp, lbp);
|
|
|
+ xfs_dir3_leaf_check(dp->i_mount, lbp);
|
|
|
xfs_trans_brelse(tp, lbp);
|
|
|
return 0;
|
|
|
}
|
|
@@ -1756,17 +1952,22 @@ xfs_dir2_leaf_search_hash(
|
|
|
xfs_dir2_leaf_t *leaf; /* leaf structure */
|
|
|
xfs_dir2_leaf_entry_t *lep; /* leaf entry */
|
|
|
int mid=0; /* current leaf index */
|
|
|
+ struct xfs_dir2_leaf_entry *ents;
|
|
|
+ struct xfs_dir3_icleaf_hdr leafhdr;
|
|
|
|
|
|
leaf = lbp->b_addr;
|
|
|
+ ents = xfs_dir3_leaf_ents_p(leaf);
|
|
|
+ xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
|
|
|
+
|
|
|
#ifndef __KERNEL__
|
|
|
- if (!leaf->hdr.count)
|
|
|
+ if (!leafhdr.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,
|
|
|
+ for (lep = ents, low = 0, high = leafhdr.count - 1,
|
|
|
hashwant = args->hashval;
|
|
|
low <= high; ) {
|
|
|
mid = (low + high) >> 1;
|
|
@@ -1852,23 +2053,29 @@ xfs_dir2_leaf_trim_data(
|
|
|
bestsp = xfs_dir2_leaf_bests_p(ltp);
|
|
|
be32_add_cpu(<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);
|
|
|
+ xfs_dir3_leaf_log_tail(tp, lbp);
|
|
|
+ xfs_dir3_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static inline size_t
|
|
|
-xfs_dir2_leaf_size(
|
|
|
- struct xfs_dir2_leaf_hdr *hdr,
|
|
|
+xfs_dir3_leaf_size(
|
|
|
+ struct xfs_dir3_icleaf_hdr *hdr,
|
|
|
int counts)
|
|
|
{
|
|
|
- int entries;
|
|
|
+ int entries;
|
|
|
+ int hdrsize;
|
|
|
+
|
|
|
+ entries = hdr->count - hdr->stale;
|
|
|
+ if (hdr->magic == XFS_DIR2_LEAF1_MAGIC ||
|
|
|
+ hdr->magic == XFS_DIR2_LEAFN_MAGIC)
|
|
|
+ hdrsize = sizeof(struct xfs_dir2_leaf_hdr);
|
|
|
+ else
|
|
|
+ hdrsize = sizeof(struct xfs_dir3_leaf_hdr);
|
|
|
|
|
|
- entries = be16_to_cpu(hdr->count) - be16_to_cpu(hdr->stale);
|
|
|
- return sizeof(xfs_dir2_leaf_hdr_t) +
|
|
|
- entries * sizeof(xfs_dir2_leaf_entry_t) +
|
|
|
- counts * sizeof(xfs_dir2_data_off_t) +
|
|
|
- sizeof(xfs_dir2_leaf_tail_t);
|
|
|
+ return hdrsize + entries * sizeof(xfs_dir2_leaf_entry_t)
|
|
|
+ + counts * sizeof(xfs_dir2_data_off_t)
|
|
|
+ + sizeof(xfs_dir2_leaf_tail_t);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1892,6 +2099,7 @@ xfs_dir2_node_to_leaf(
|
|
|
xfs_mount_t *mp; /* filesystem mount point */
|
|
|
int rval; /* successful free trim? */
|
|
|
xfs_trans_t *tp; /* transaction pointer */
|
|
|
+ struct xfs_dir3_icleaf_hdr leafhdr;
|
|
|
struct xfs_dir3_icfree_hdr freehdr;
|
|
|
|
|
|
/*
|
|
@@ -1942,7 +2150,11 @@ xfs_dir2_node_to_leaf(
|
|
|
return 0;
|
|
|
lbp = state->path.blk[0].bp;
|
|
|
leaf = lbp->b_addr;
|
|
|
- ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
|
|
|
+ xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
|
|
|
+
|
|
|
+ ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC ||
|
|
|
+ leafhdr.magic == XFS_DIR3_LEAFN_MAGIC);
|
|
|
+
|
|
|
/*
|
|
|
* Read the freespace block.
|
|
|
*/
|
|
@@ -1958,36 +2170,40 @@ xfs_dir2_node_to_leaf(
|
|
|
* Now see if the leafn and free data will fit in a leaf1.
|
|
|
* If not, release the buffer and give up.
|
|
|
*/
|
|
|
- if (xfs_dir2_leaf_size(&leaf->hdr, freehdr.nvalid) > mp->m_dirblksize) {
|
|
|
+ if (xfs_dir3_leaf_size(&leafhdr, freehdr.nvalid) > mp->m_dirblksize) {
|
|
|
xfs_trans_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);
|
|
|
+ if (leafhdr.stale)
|
|
|
+ xfs_dir3_leaf_compact(args, &leafhdr, lbp);
|
|
|
|
|
|
- lbp->b_ops = &xfs_dir2_leaf1_buf_ops;
|
|
|
- leaf->hdr.info.magic = cpu_to_be16(XFS_DIR2_LEAF1_MAGIC);
|
|
|
+ lbp->b_ops = &xfs_dir3_leaf1_buf_ops;
|
|
|
+ leafhdr.magic = (leafhdr.magic == XFS_DIR2_LEAFN_MAGIC)
|
|
|
+ ? XFS_DIR2_LEAF1_MAGIC
|
|
|
+ : XFS_DIR3_LEAF1_MAGIC;
|
|
|
|
|
|
/*
|
|
|
* Set up the leaf tail from the freespace block.
|
|
|
*/
|
|
|
ltp = xfs_dir2_leaf_tail_p(mp, leaf);
|
|
|
ltp->bestcount = cpu_to_be32(freehdr.nvalid);
|
|
|
+
|
|
|
/*
|
|
|
* Set up the leaf bests table.
|
|
|
*/
|
|
|
memcpy(xfs_dir2_leaf_bests_p(ltp), xfs_dir3_free_bests_p(mp, free),
|
|
|
freehdr.nvalid * sizeof(xfs_dir2_data_off_t));
|
|
|
- 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);
|
|
|
+
|
|
|
+ xfs_dir3_leaf_hdr_to_disk(leaf, &leafhdr);
|
|
|
+ xfs_dir3_leaf_log_header(tp, lbp);
|
|
|
+ xfs_dir3_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
|
|
|
+ xfs_dir3_leaf_log_tail(tp, lbp);
|
|
|
+ xfs_dir3_leaf_check(mp, lbp);
|
|
|
+
|
|
|
/*
|
|
|
* Get rid of the freespace block.
|
|
|
*/
|