提交 f5f3d9b0 编写于 作者: D Dave Chinner 提交者: Ben Myers

xfs: add CRC checks to block format directory blocks

Now that directory buffers are made from a single struct xfs_buf, we
can add CRC calculation and checking callbacks. While there, add all
the fields to the on disk structures for future functionality such
as d_type support, uuids, block numbers, owner inode, etc.

To distinguish between the different on disk formats, change the
magic numbers for the new format directory blocks.
Signed-off-by: NDave Chinner <dchinner@redhat.com>
Reviewed-by: NBen Myers <bpm@sgi.com>
Signed-off-by: NBen Myers <bpm@sgi.com>
上级 f948dd76
/* /*
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
* Copyright (c) 2013 Red Hat, Inc.
* All Rights Reserved. * All Rights Reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
...@@ -28,11 +29,13 @@ ...@@ -28,11 +29,13 @@
#include "xfs_dinode.h" #include "xfs_dinode.h"
#include "xfs_inode.h" #include "xfs_inode.h"
#include "xfs_inode_item.h" #include "xfs_inode_item.h"
#include "xfs_buf_item.h"
#include "xfs_dir2.h" #include "xfs_dir2.h"
#include "xfs_dir2_format.h" #include "xfs_dir2_format.h"
#include "xfs_dir2_priv.h" #include "xfs_dir2_priv.h"
#include "xfs_error.h" #include "xfs_error.h"
#include "xfs_trace.h" #include "xfs_trace.h"
#include "xfs_cksum.h"
/* /*
* Local function prototypes. * Local function prototypes.
...@@ -56,44 +59,74 @@ xfs_dir_startup(void) ...@@ -56,44 +59,74 @@ xfs_dir_startup(void)
xfs_dir_hash_dotdot = xfs_da_hashname((unsigned char *)"..", 2); xfs_dir_hash_dotdot = xfs_da_hashname((unsigned char *)"..", 2);
} }
static void static bool
xfs_dir2_block_verify( xfs_dir3_block_verify(
struct xfs_buf *bp) struct xfs_buf *bp)
{ {
struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_mount *mp = bp->b_target->bt_mount;
struct xfs_dir2_data_hdr *hdr = bp->b_addr; struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
int block_ok = 0;
if (xfs_sb_version_hascrc(&mp->m_sb)) {
block_ok = hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC); if (hdr3->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC))
block_ok = block_ok && __xfs_dir2_data_check(NULL, bp) == 0; return false;
if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
if (!block_ok) { return false;
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, hdr); if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
xfs_buf_ioerror(bp, EFSCORRUPTED); return false;
} else {
if (hdr3->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC))
return false;
} }
if (__xfs_dir2_data_check(NULL, bp))
return false;
return true;
} }
static void static void
xfs_dir2_block_read_verify( xfs_dir3_block_read_verify(
struct xfs_buf *bp) struct xfs_buf *bp)
{ {
xfs_dir2_block_verify(bp); 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_DATA_CRC_OFF)) ||
!xfs_dir3_block_verify(bp)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
xfs_buf_ioerror(bp, EFSCORRUPTED);
}
} }
static void static void
xfs_dir2_block_write_verify( xfs_dir3_block_write_verify(
struct xfs_buf *bp) struct xfs_buf *bp)
{ {
xfs_dir2_block_verify(bp); struct xfs_mount *mp = bp->b_target->bt_mount;
struct xfs_buf_log_item *bip = bp->b_fspriv;
struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
if (!xfs_dir3_block_verify(bp)) {
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->lsn = cpu_to_be64(bip->bli_item.li_lsn);
xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), XFS_DIR3_DATA_CRC_OFF);
} }
const struct xfs_buf_ops xfs_dir2_block_buf_ops = { const struct xfs_buf_ops xfs_dir3_block_buf_ops = {
.verify_read = xfs_dir2_block_read_verify, .verify_read = xfs_dir3_block_read_verify,
.verify_write = xfs_dir2_block_write_verify, .verify_write = xfs_dir3_block_write_verify,
}; };
static int static int
xfs_dir2_block_read( xfs_dir3_block_read(
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_inode *dp, struct xfs_inode *dp,
struct xfs_buf **bpp) struct xfs_buf **bpp)
...@@ -101,7 +134,29 @@ xfs_dir2_block_read( ...@@ -101,7 +134,29 @@ xfs_dir2_block_read(
struct xfs_mount *mp = dp->i_mount; struct xfs_mount *mp = dp->i_mount;
return xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, bpp, return xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, bpp,
XFS_DATA_FORK, &xfs_dir2_block_buf_ops); XFS_DATA_FORK, &xfs_dir3_block_buf_ops);
}
static void
xfs_dir3_block_init(
struct xfs_mount *mp,
struct xfs_buf *bp,
struct xfs_inode *dp)
{
struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
bp->b_ops = &xfs_dir3_block_buf_ops;
if (xfs_sb_version_hascrc(&mp->m_sb)) {
memset(hdr3, 0, sizeof(*hdr3));
hdr3->magic = cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
hdr3->blkno = cpu_to_be64(bp->b_bn);
hdr3->owner = cpu_to_be64(dp->i_ino);
uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
return;
}
hdr3->magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC);
} }
static void static void
...@@ -121,7 +176,7 @@ xfs_dir2_block_need_space( ...@@ -121,7 +176,7 @@ xfs_dir2_block_need_space(
struct xfs_dir2_data_unused *enddup = NULL; struct xfs_dir2_data_unused *enddup = NULL;
*compact = 0; *compact = 0;
bf = hdr->bestfree; bf = xfs_dir3_data_bestfree_p(hdr);
/* /*
* If there are stale entries we'll use one for the leaf. * If there are stale entries we'll use one for the leaf.
...@@ -303,7 +358,7 @@ xfs_dir2_block_addname( ...@@ -303,7 +358,7 @@ xfs_dir2_block_addname(
mp = dp->i_mount; mp = dp->i_mount;
/* Read the (one and only) directory block into bp. */ /* Read the (one and only) directory block into bp. */
error = xfs_dir2_block_read(tp, dp, &bp); error = xfs_dir3_block_read(tp, dp, &bp);
if (error) if (error)
return error; return error;
...@@ -531,7 +586,7 @@ xfs_dir2_block_getdents( ...@@ -531,7 +586,7 @@ xfs_dir2_block_getdents(
if (xfs_dir2_dataptr_to_db(mp, *offset) > mp->m_dirdatablk) if (xfs_dir2_dataptr_to_db(mp, *offset) > mp->m_dirdatablk)
return 0; return 0;
error = xfs_dir2_block_read(NULL, dp, &bp); error = xfs_dir3_block_read(NULL, dp, &bp);
if (error) if (error)
return error; return error;
...@@ -546,7 +601,7 @@ xfs_dir2_block_getdents( ...@@ -546,7 +601,7 @@ xfs_dir2_block_getdents(
* Set up values for the loop. * Set up values for the loop.
*/ */
btp = xfs_dir2_block_tail_p(mp, hdr); btp = xfs_dir2_block_tail_p(mp, hdr);
ptr = (char *)(hdr + 1); ptr = (char *)xfs_dir3_data_entry_p(hdr);
endptr = (char *)xfs_dir2_block_leaf_p(btp); endptr = (char *)xfs_dir2_block_leaf_p(btp);
/* /*
...@@ -711,7 +766,7 @@ xfs_dir2_block_lookup_int( ...@@ -711,7 +766,7 @@ xfs_dir2_block_lookup_int(
tp = args->trans; tp = args->trans;
mp = dp->i_mount; mp = dp->i_mount;
error = xfs_dir2_block_read(tp, dp, &bp); error = xfs_dir3_block_read(tp, dp, &bp);
if (error) if (error)
return error; return error;
...@@ -974,9 +1029,12 @@ xfs_dir2_leaf_to_block( ...@@ -974,9 +1029,12 @@ xfs_dir2_leaf_to_block(
* These will show up in the leaf bests table. * These will show up in the leaf bests table.
*/ */
while (dp->i_d.di_size > mp->m_dirblksize) { while (dp->i_d.di_size > mp->m_dirblksize) {
int hdrsz;
hdrsz = xfs_dir3_data_hdr_size(xfs_sb_version_hascrc(&mp->m_sb));
bestsp = xfs_dir2_leaf_bests_p(ltp); bestsp = xfs_dir2_leaf_bests_p(ltp);
if (be16_to_cpu(bestsp[be32_to_cpu(ltp->bestcount) - 1]) == if (be16_to_cpu(bestsp[be32_to_cpu(ltp->bestcount) - 1]) ==
mp->m_dirblksize - (uint)sizeof(*hdr)) { mp->m_dirblksize - hdrsz) {
if ((error = if ((error =
xfs_dir2_leaf_trim_data(args, lbp, xfs_dir2_leaf_trim_data(args, lbp,
(xfs_dir2_db_t)(be32_to_cpu(ltp->bestcount) - 1)))) (xfs_dir2_db_t)(be32_to_cpu(ltp->bestcount) - 1))))
...@@ -1014,8 +1072,8 @@ xfs_dir2_leaf_to_block( ...@@ -1014,8 +1072,8 @@ xfs_dir2_leaf_to_block(
/* /*
* Start converting it to block form. * Start converting it to block form.
*/ */
dbp->b_ops = &xfs_dir2_block_buf_ops; xfs_dir3_block_init(mp, dbp, dp);
hdr->magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC);
needlog = 1; needlog = 1;
needscan = 0; needscan = 0;
/* /*
...@@ -1137,16 +1195,16 @@ xfs_dir2_sf_to_block( ...@@ -1137,16 +1195,16 @@ xfs_dir2_sf_to_block(
return error; return error;
} }
/* /*
* Initialize the data block. * Initialize the data block, then convert it to block format.
*/ */
error = xfs_dir2_data_init(args, blkno, &bp); error = xfs_dir3_data_init(args, blkno, &bp);
if (error) { if (error) {
kmem_free(sfp); kmem_free(sfp);
return error; return error;
} }
bp->b_ops = &xfs_dir2_block_buf_ops; xfs_dir3_block_init(mp, bp, dp);
hdr = bp->b_addr; hdr = bp->b_addr;
hdr->magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC);
/* /*
* Compute size of block "tail" area. * Compute size of block "tail" area.
*/ */
...@@ -1156,7 +1214,7 @@ xfs_dir2_sf_to_block( ...@@ -1156,7 +1214,7 @@ xfs_dir2_sf_to_block(
* The whole thing is initialized to free by the init routine. * The whole thing is initialized to free by the init routine.
* Say we're using the leaf and tail area. * Say we're using the leaf and tail area.
*/ */
dup = (xfs_dir2_data_unused_t *)(hdr + 1); dup = xfs_dir3_data_unused_p(hdr);
needlog = needscan = 0; needlog = needscan = 0;
xfs_dir2_data_use_free(tp, bp, dup, mp->m_dirblksize - i, i, &needlog, xfs_dir2_data_use_free(tp, bp, dup, mp->m_dirblksize - i, i, &needlog,
&needscan); &needscan);
...@@ -1178,8 +1236,7 @@ xfs_dir2_sf_to_block( ...@@ -1178,8 +1236,7 @@ xfs_dir2_sf_to_block(
/* /*
* Create entry for . * Create entry for .
*/ */
dep = (xfs_dir2_data_entry_t *) dep = xfs_dir3_data_dot_entry_p(hdr);
((char *)hdr + XFS_DIR2_DATA_DOT_OFFSET);
dep->inumber = cpu_to_be64(dp->i_ino); dep->inumber = cpu_to_be64(dp->i_ino);
dep->namelen = 1; dep->namelen = 1;
dep->name[0] = '.'; dep->name[0] = '.';
...@@ -1192,8 +1249,7 @@ xfs_dir2_sf_to_block( ...@@ -1192,8 +1249,7 @@ xfs_dir2_sf_to_block(
/* /*
* Create entry for .. * Create entry for ..
*/ */
dep = (xfs_dir2_data_entry_t *) dep = xfs_dir3_data_dotdot_entry_p(hdr);
((char *)hdr + XFS_DIR2_DATA_DOTDOT_OFFSET);
dep->inumber = cpu_to_be64(xfs_dir2_sf_get_parent_ino(sfp)); dep->inumber = cpu_to_be64(xfs_dir2_sf_get_parent_ino(sfp));
dep->namelen = 2; dep->namelen = 2;
dep->name[0] = dep->name[1] = '.'; dep->name[0] = dep->name[1] = '.';
...@@ -1203,7 +1259,7 @@ xfs_dir2_sf_to_block( ...@@ -1203,7 +1259,7 @@ xfs_dir2_sf_to_block(
blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot); blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot);
blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp, blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
(char *)dep - (char *)hdr)); (char *)dep - (char *)hdr));
offset = XFS_DIR2_DATA_FIRST_OFFSET; offset = xfs_dir3_data_first_offset(hdr);
/* /*
* Loop over existing entries, stuff them in. * Loop over existing entries, stuff them in.
*/ */
......
/* /*
* Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
* Copyright (c) 2013 Red Hat, Inc.
* All Rights Reserved. * All Rights Reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
...@@ -65,10 +66,11 @@ __xfs_dir2_data_check( ...@@ -65,10 +66,11 @@ __xfs_dir2_data_check(
mp = bp->b_target->bt_mount; mp = bp->b_target->bt_mount;
hdr = bp->b_addr; hdr = bp->b_addr;
bf = hdr->bestfree; bf = xfs_dir3_data_bestfree_p(hdr);
p = (char *)(hdr + 1); p = (char *)xfs_dir3_data_entry_p(hdr);
switch (hdr->magic) { switch (hdr->magic) {
case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC):
case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC):
btp = xfs_dir2_block_tail_p(mp, hdr); btp = xfs_dir2_block_tail_p(mp, hdr);
lep = xfs_dir2_block_leaf_p(btp); lep = xfs_dir2_block_leaf_p(btp);
...@@ -148,7 +150,8 @@ __xfs_dir2_data_check( ...@@ -148,7 +150,8 @@ __xfs_dir2_data_check(
(char *)dep - (char *)hdr); (char *)dep - (char *)hdr);
count++; count++;
lastfree = 0; lastfree = 0;
if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) { if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) {
addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
(xfs_dir2_data_aoff_t) (xfs_dir2_data_aoff_t)
((char *)dep - (char *)hdr)); ((char *)dep - (char *)hdr));
...@@ -168,7 +171,8 @@ __xfs_dir2_data_check( ...@@ -168,7 +171,8 @@ __xfs_dir2_data_check(
* Need to have seen all the entries and all the bestfree slots. * Need to have seen all the entries and all the bestfree slots.
*/ */
XFS_WANT_CORRUPTED_RETURN(freeseen == 7); XFS_WANT_CORRUPTED_RETURN(freeseen == 7);
if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) { if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) {
for (i = stale = 0; i < be32_to_cpu(btp->count); i++) { for (i = stale = 0; i < be32_to_cpu(btp->count); i++) {
if (lep[i].address == if (lep[i].address ==
cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
...@@ -216,7 +220,8 @@ xfs_dir2_data_reada_verify( ...@@ -216,7 +220,8 @@ xfs_dir2_data_reada_verify(
switch (hdr->magic) { switch (hdr->magic) {
case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC):
bp->b_ops = &xfs_dir2_block_buf_ops; case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC):
bp->b_ops = &xfs_dir3_block_buf_ops;
bp->b_ops->verify_read(bp); bp->b_ops->verify_read(bp);
return; return;
case cpu_to_be32(XFS_DIR2_DATA_MAGIC): case cpu_to_be32(XFS_DIR2_DATA_MAGIC):
...@@ -288,12 +293,15 @@ xfs_dir2_data_freefind( ...@@ -288,12 +293,15 @@ xfs_dir2_data_freefind(
{ {
xfs_dir2_data_free_t *dfp; /* bestfree entry */ xfs_dir2_data_free_t *dfp; /* bestfree entry */
xfs_dir2_data_aoff_t off; /* offset value needed */ xfs_dir2_data_aoff_t off; /* offset value needed */
struct xfs_dir2_data_free *bf;
#if defined(DEBUG) && defined(__KERNEL__) #if defined(DEBUG) && defined(__KERNEL__)
int matched; /* matched the value */ int matched; /* matched the value */
int seenzero; /* saw a 0 bestfree entry */ int seenzero; /* saw a 0 bestfree entry */
#endif #endif
off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr); off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr);
bf = xfs_dir3_data_bestfree_p(hdr);
#if defined(DEBUG) && defined(__KERNEL__) #if defined(DEBUG) && defined(__KERNEL__)
/* /*
* Validate some consistency in the bestfree table. * Validate some consistency in the bestfree table.
...@@ -301,9 +309,10 @@ xfs_dir2_data_freefind( ...@@ -301,9 +309,10 @@ xfs_dir2_data_freefind(
* one we're looking for it has to be exact. * one we're looking for it has to be exact.
*/ */
ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
for (dfp = &hdr->bestfree[0], seenzero = matched = 0; hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
dfp < &hdr->bestfree[XFS_DIR2_DATA_FD_COUNT]; for (dfp = &bf[0], seenzero = matched = 0;
dfp < &bf[XFS_DIR2_DATA_FD_COUNT];
dfp++) { dfp++) {
if (!dfp->offset) { if (!dfp->offset) {
ASSERT(!dfp->length); ASSERT(!dfp->length);
...@@ -319,7 +328,7 @@ xfs_dir2_data_freefind( ...@@ -319,7 +328,7 @@ xfs_dir2_data_freefind(
else else
ASSERT(be16_to_cpu(dfp->offset) + be16_to_cpu(dfp->length) <= off); ASSERT(be16_to_cpu(dfp->offset) + be16_to_cpu(dfp->length) <= off);
ASSERT(matched || be16_to_cpu(dfp->length) >= be16_to_cpu(dup->length)); ASSERT(matched || be16_to_cpu(dfp->length) >= be16_to_cpu(dup->length));
if (dfp > &hdr->bestfree[0]) if (dfp > &bf[0])
ASSERT(be16_to_cpu(dfp[-1].length) >= be16_to_cpu(dfp[0].length)); ASSERT(be16_to_cpu(dfp[-1].length) >= be16_to_cpu(dfp[0].length));
} }
#endif #endif
...@@ -328,14 +337,12 @@ xfs_dir2_data_freefind( ...@@ -328,14 +337,12 @@ xfs_dir2_data_freefind(
* it can't be there since they're sorted. * it can't be there since they're sorted.
*/ */
if (be16_to_cpu(dup->length) < if (be16_to_cpu(dup->length) <
be16_to_cpu(hdr->bestfree[XFS_DIR2_DATA_FD_COUNT - 1].length)) be16_to_cpu(bf[XFS_DIR2_DATA_FD_COUNT - 1].length))
return NULL; return NULL;
/* /*
* Look at the three bestfree entries for our guy. * Look at the three bestfree entries for our guy.
*/ */
for (dfp = &hdr->bestfree[0]; for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) {
dfp < &hdr->bestfree[XFS_DIR2_DATA_FD_COUNT];
dfp++) {
if (!dfp->offset) if (!dfp->offset)
return NULL; return NULL;
if (be16_to_cpu(dfp->offset) == off) if (be16_to_cpu(dfp->offset) == off)
...@@ -359,11 +366,12 @@ xfs_dir2_data_freeinsert( ...@@ -359,11 +366,12 @@ xfs_dir2_data_freeinsert(
xfs_dir2_data_free_t *dfp; /* bestfree table pointer */ xfs_dir2_data_free_t *dfp; /* bestfree table pointer */
xfs_dir2_data_free_t new; /* new bestfree entry */ xfs_dir2_data_free_t new; /* new bestfree entry */
#ifdef __KERNEL__
ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
#endif hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
dfp = hdr->bestfree; hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
dfp = xfs_dir3_data_bestfree_p(hdr);
new.length = dup->length; new.length = dup->length;
new.offset = cpu_to_be16((char *)dup - (char *)hdr); new.offset = cpu_to_be16((char *)dup - (char *)hdr);
...@@ -400,32 +408,36 @@ xfs_dir2_data_freeremove( ...@@ -400,32 +408,36 @@ xfs_dir2_data_freeremove(
xfs_dir2_data_free_t *dfp, /* bestfree entry pointer */ xfs_dir2_data_free_t *dfp, /* bestfree entry pointer */
int *loghead) /* out: log data header */ int *loghead) /* out: log data header */
{ {
#ifdef __KERNEL__ struct xfs_dir2_data_free *bf;
ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
#endif hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
/* /*
* It's the first entry, slide the next 2 up. * It's the first entry, slide the next 2 up.
*/ */
if (dfp == &hdr->bestfree[0]) { bf = xfs_dir3_data_bestfree_p(hdr);
hdr->bestfree[0] = hdr->bestfree[1]; if (dfp == &bf[0]) {
hdr->bestfree[1] = hdr->bestfree[2]; bf[0] = bf[1];
bf[1] = bf[2];
} }
/* /*
* It's the second entry, slide the 3rd entry up. * It's the second entry, slide the 3rd entry up.
*/ */
else if (dfp == &hdr->bestfree[1]) else if (dfp == &bf[1])
hdr->bestfree[1] = hdr->bestfree[2]; bf[1] = bf[2];
/* /*
* Must be the last entry. * Must be the last entry.
*/ */
else else
ASSERT(dfp == &hdr->bestfree[2]); ASSERT(dfp == &bf[2]);
/* /*
* Clear the 3rd entry, must be zero now. * Clear the 3rd entry, must be zero now.
*/ */
hdr->bestfree[2].length = 0; bf[2].length = 0;
hdr->bestfree[2].offset = 0; bf[2].offset = 0;
*loghead = 1; *loghead = 1;
} }
...@@ -441,23 +453,26 @@ xfs_dir2_data_freescan( ...@@ -441,23 +453,26 @@ xfs_dir2_data_freescan(
xfs_dir2_block_tail_t *btp; /* block tail */ xfs_dir2_block_tail_t *btp; /* block tail */
xfs_dir2_data_entry_t *dep; /* active data entry */ xfs_dir2_data_entry_t *dep; /* active data entry */
xfs_dir2_data_unused_t *dup; /* unused data entry */ xfs_dir2_data_unused_t *dup; /* unused data entry */
struct xfs_dir2_data_free *bf;
char *endp; /* end of block's data */ char *endp; /* end of block's data */
char *p; /* current entry pointer */ char *p; /* current entry pointer */
#ifdef __KERNEL__
ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
#endif hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
/* /*
* Start by clearing the table. * Start by clearing the table.
*/ */
memset(hdr->bestfree, 0, sizeof(hdr->bestfree)); bf = xfs_dir3_data_bestfree_p(hdr);
memset(bf, 0, sizeof(*bf) * XFS_DIR2_DATA_FD_COUNT);
*loghead = 1; *loghead = 1;
/* /*
* Set up pointers. * Set up pointers.
*/ */
p = (char *)(hdr + 1); p = (char *)xfs_dir3_data_entry_p(hdr);
if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) { if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) {
btp = xfs_dir2_block_tail_p(mp, hdr); btp = xfs_dir2_block_tail_p(mp, hdr);
endp = (char *)xfs_dir2_block_leaf_p(btp); endp = (char *)xfs_dir2_block_leaf_p(btp);
} else } else
...@@ -493,7 +508,7 @@ xfs_dir2_data_freescan( ...@@ -493,7 +508,7 @@ xfs_dir2_data_freescan(
* Give back the buffer for the created block. * Give back the buffer for the created block.
*/ */
int /* error */ int /* error */
xfs_dir2_data_init( xfs_dir3_data_init(
xfs_da_args_t *args, /* directory operation args */ xfs_da_args_t *args, /* directory operation args */
xfs_dir2_db_t blkno, /* logical dir block number */ xfs_dir2_db_t blkno, /* logical dir block number */
struct xfs_buf **bpp) /* output block buffer */ struct xfs_buf **bpp) /* output block buffer */
...@@ -502,6 +517,7 @@ xfs_dir2_data_init( ...@@ -502,6 +517,7 @@ xfs_dir2_data_init(
xfs_dir2_data_hdr_t *hdr; /* data block header */ xfs_dir2_data_hdr_t *hdr; /* data block header */
xfs_inode_t *dp; /* incore directory inode */ xfs_inode_t *dp; /* incore directory inode */
xfs_dir2_data_unused_t *dup; /* unused entry pointer */ xfs_dir2_data_unused_t *dup; /* unused entry pointer */
struct xfs_dir2_data_free *bf;
int error; /* error return value */ int error; /* error return value */
int i; /* bestfree index */ int i; /* bestfree index */
xfs_mount_t *mp; /* filesystem mount point */ xfs_mount_t *mp; /* filesystem mount point */
...@@ -524,21 +540,34 @@ xfs_dir2_data_init( ...@@ -524,21 +540,34 @@ xfs_dir2_data_init(
* Initialize the header. * Initialize the header.
*/ */
hdr = bp->b_addr; hdr = bp->b_addr;
hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
hdr->bestfree[0].offset = cpu_to_be16(sizeof(*hdr)); if (xfs_sb_version_hascrc(&mp->m_sb)) {
struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
memset(hdr3, 0, sizeof(*hdr3));
hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC);
hdr3->blkno = cpu_to_be64(bp->b_bn);
hdr3->owner = cpu_to_be64(dp->i_ino);
uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
} else
hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
bf = xfs_dir3_data_bestfree_p(hdr);
bf[0].offset = cpu_to_be16(xfs_dir3_data_entry_offset(hdr));
for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) { for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) {
hdr->bestfree[i].length = 0; bf[i].length = 0;
hdr->bestfree[i].offset = 0; bf[i].offset = 0;
} }
/* /*
* Set up an unused entry for the block's body. * Set up an unused entry for the block's body.
*/ */
dup = (xfs_dir2_data_unused_t *)(hdr + 1); dup = xfs_dir3_data_unused_p(hdr);
dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
t = mp->m_dirblksize - (uint)sizeof(*hdr); t = mp->m_dirblksize - (uint)xfs_dir3_data_entry_offset(hdr);
hdr->bestfree[0].length = cpu_to_be16(t); bf[0].length = cpu_to_be16(t);
dup->length = cpu_to_be16(t); dup->length = cpu_to_be16(t);
*xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)hdr); *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)hdr);
/* /*
...@@ -562,7 +591,8 @@ xfs_dir2_data_log_entry( ...@@ -562,7 +591,8 @@ xfs_dir2_data_log_entry(
xfs_dir2_data_hdr_t *hdr = bp->b_addr; xfs_dir2_data_hdr_t *hdr = bp->b_addr;
ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
xfs_trans_log_buf(tp, bp, (uint)((char *)dep - (char *)hdr), xfs_trans_log_buf(tp, bp, (uint)((char *)dep - (char *)hdr),
(uint)((char *)(xfs_dir2_data_entry_tag_p(dep) + 1) - (uint)((char *)(xfs_dir2_data_entry_tag_p(dep) + 1) -
...@@ -580,9 +610,10 @@ xfs_dir2_data_log_header( ...@@ -580,9 +610,10 @@ xfs_dir2_data_log_header(
xfs_dir2_data_hdr_t *hdr = bp->b_addr; xfs_dir2_data_hdr_t *hdr = bp->b_addr;
ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
xfs_trans_log_buf(tp, bp, 0, sizeof(*hdr) - 1); xfs_trans_log_buf(tp, bp, 0, xfs_dir3_data_entry_offset(hdr) - 1);
} }
/* /*
...@@ -597,7 +628,8 @@ xfs_dir2_data_log_unused( ...@@ -597,7 +628,8 @@ xfs_dir2_data_log_unused(
xfs_dir2_data_hdr_t *hdr = bp->b_addr; xfs_dir2_data_hdr_t *hdr = bp->b_addr;
ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
/* /*
* Log the first part of the unused entry. * Log the first part of the unused entry.
...@@ -635,6 +667,7 @@ xfs_dir2_data_make_free( ...@@ -635,6 +667,7 @@ xfs_dir2_data_make_free(
xfs_dir2_data_unused_t *newdup; /* new unused entry */ xfs_dir2_data_unused_t *newdup; /* new unused entry */
xfs_dir2_data_unused_t *postdup; /* unused entry after us */ xfs_dir2_data_unused_t *postdup; /* unused entry after us */
xfs_dir2_data_unused_t *prevdup; /* unused entry before us */ xfs_dir2_data_unused_t *prevdup; /* unused entry before us */
struct xfs_dir2_data_free *bf;
mp = tp->t_mountp; mp = tp->t_mountp;
hdr = bp->b_addr; hdr = bp->b_addr;
...@@ -647,7 +680,8 @@ xfs_dir2_data_make_free( ...@@ -647,7 +680,8 @@ xfs_dir2_data_make_free(
else { else {
xfs_dir2_block_tail_t *btp; /* block tail */ xfs_dir2_block_tail_t *btp; /* block tail */
ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
btp = xfs_dir2_block_tail_p(mp, hdr); btp = xfs_dir2_block_tail_p(mp, hdr);
endptr = (char *)xfs_dir2_block_leaf_p(btp); endptr = (char *)xfs_dir2_block_leaf_p(btp);
} }
...@@ -655,7 +689,7 @@ xfs_dir2_data_make_free( ...@@ -655,7 +689,7 @@ xfs_dir2_data_make_free(
* If this isn't the start of the block, then back up to * If this isn't the start of the block, then back up to
* the previous entry and see if it's free. * the previous entry and see if it's free.
*/ */
if (offset > sizeof(*hdr)) { if (offset > xfs_dir3_data_entry_offset(hdr)) {
__be16 *tagp; /* tag just before us */ __be16 *tagp; /* tag just before us */
tagp = (__be16 *)((char *)hdr + offset) - 1; tagp = (__be16 *)((char *)hdr + offset) - 1;
...@@ -681,6 +715,7 @@ xfs_dir2_data_make_free( ...@@ -681,6 +715,7 @@ xfs_dir2_data_make_free(
* Previous and following entries are both free, * Previous and following entries are both free,
* merge everything into a single free entry. * merge everything into a single free entry.
*/ */
bf = xfs_dir3_data_bestfree_p(hdr);
if (prevdup && postdup) { if (prevdup && postdup) {
xfs_dir2_data_free_t *dfp2; /* another bestfree pointer */ xfs_dir2_data_free_t *dfp2; /* another bestfree pointer */
...@@ -695,7 +730,7 @@ xfs_dir2_data_make_free( ...@@ -695,7 +730,7 @@ xfs_dir2_data_make_free(
* since the third bestfree is there, there might be more * since the third bestfree is there, there might be more
* entries. * entries.
*/ */
needscan = (hdr->bestfree[2].length != 0); needscan = (bf[2].length != 0);
/* /*
* Fix up the new big freespace. * Fix up the new big freespace.
*/ */
...@@ -711,10 +746,10 @@ xfs_dir2_data_make_free( ...@@ -711,10 +746,10 @@ xfs_dir2_data_make_free(
* Remove entry 1 first then entry 0. * Remove entry 1 first then entry 0.
*/ */
ASSERT(dfp && dfp2); ASSERT(dfp && dfp2);
if (dfp == &hdr->bestfree[1]) { if (dfp == &bf[1]) {
dfp = &hdr->bestfree[0]; dfp = &bf[0];
ASSERT(dfp2 == dfp); ASSERT(dfp2 == dfp);
dfp2 = &hdr->bestfree[1]; dfp2 = &bf[1];
} }
xfs_dir2_data_freeremove(hdr, dfp2, needlogp); xfs_dir2_data_freeremove(hdr, dfp2, needlogp);
xfs_dir2_data_freeremove(hdr, dfp, needlogp); xfs_dir2_data_freeremove(hdr, dfp, needlogp);
...@@ -722,7 +757,7 @@ xfs_dir2_data_make_free( ...@@ -722,7 +757,7 @@ xfs_dir2_data_make_free(
* Now insert the new entry. * Now insert the new entry.
*/ */
dfp = xfs_dir2_data_freeinsert(hdr, prevdup, needlogp); dfp = xfs_dir2_data_freeinsert(hdr, prevdup, needlogp);
ASSERT(dfp == &hdr->bestfree[0]); ASSERT(dfp == &bf[0]);
ASSERT(dfp->length == prevdup->length); ASSERT(dfp->length == prevdup->length);
ASSERT(!dfp[1].length); ASSERT(!dfp[1].length);
ASSERT(!dfp[2].length); ASSERT(!dfp[2].length);
...@@ -751,7 +786,7 @@ xfs_dir2_data_make_free( ...@@ -751,7 +786,7 @@ xfs_dir2_data_make_free(
*/ */
else { else {
needscan = be16_to_cpu(prevdup->length) > needscan = be16_to_cpu(prevdup->length) >
be16_to_cpu(hdr->bestfree[2].length); be16_to_cpu(bf[2].length);
} }
} }
/* /*
...@@ -779,7 +814,7 @@ xfs_dir2_data_make_free( ...@@ -779,7 +814,7 @@ xfs_dir2_data_make_free(
*/ */
else { else {
needscan = be16_to_cpu(newdup->length) > needscan = be16_to_cpu(newdup->length) >
be16_to_cpu(hdr->bestfree[2].length); be16_to_cpu(bf[2].length);
} }
} }
/* /*
...@@ -818,10 +853,12 @@ xfs_dir2_data_use_free( ...@@ -818,10 +853,12 @@ xfs_dir2_data_use_free(
xfs_dir2_data_unused_t *newdup; /* new unused entry */ xfs_dir2_data_unused_t *newdup; /* new unused entry */
xfs_dir2_data_unused_t *newdup2; /* another new unused entry */ xfs_dir2_data_unused_t *newdup2; /* another new unused entry */
int oldlen; /* old unused entry's length */ int oldlen; /* old unused entry's length */
struct xfs_dir2_data_free *bf;
hdr = bp->b_addr; hdr = bp->b_addr;
ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG); ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG);
ASSERT(offset >= (char *)dup - (char *)hdr); ASSERT(offset >= (char *)dup - (char *)hdr);
ASSERT(offset + len <= (char *)dup + be16_to_cpu(dup->length) - (char *)hdr); ASSERT(offset + len <= (char *)dup + be16_to_cpu(dup->length) - (char *)hdr);
...@@ -831,7 +868,8 @@ xfs_dir2_data_use_free( ...@@ -831,7 +868,8 @@ xfs_dir2_data_use_free(
*/ */
dfp = xfs_dir2_data_freefind(hdr, dup); dfp = xfs_dir2_data_freefind(hdr, dup);
oldlen = be16_to_cpu(dup->length); oldlen = be16_to_cpu(dup->length);
ASSERT(dfp || oldlen <= be16_to_cpu(hdr->bestfree[2].length)); bf = xfs_dir3_data_bestfree_p(hdr);
ASSERT(dfp || oldlen <= be16_to_cpu(bf[2].length));
/* /*
* Check for alignment with front and back of the entry. * Check for alignment with front and back of the entry.
*/ */
...@@ -845,7 +883,7 @@ xfs_dir2_data_use_free( ...@@ -845,7 +883,7 @@ xfs_dir2_data_use_free(
*/ */
if (matchfront && matchback) { if (matchfront && matchback) {
if (dfp) { if (dfp) {
needscan = (hdr->bestfree[2].offset != 0); needscan = (bf[2].offset != 0);
if (!needscan) if (!needscan)
xfs_dir2_data_freeremove(hdr, dfp, needlogp); xfs_dir2_data_freeremove(hdr, dfp, needlogp);
} }
...@@ -875,7 +913,7 @@ xfs_dir2_data_use_free( ...@@ -875,7 +913,7 @@ xfs_dir2_data_use_free(
* that means we don't know if there was a better * that means we don't know if there was a better
* choice for the last slot, or not. Rescan. * choice for the last slot, or not. Rescan.
*/ */
needscan = dfp == &hdr->bestfree[2]; needscan = dfp == &bf[2];
} }
} }
/* /*
...@@ -902,7 +940,7 @@ xfs_dir2_data_use_free( ...@@ -902,7 +940,7 @@ xfs_dir2_data_use_free(
* that means we don't know if there was a better * that means we don't know if there was a better
* choice for the last slot, or not. Rescan. * choice for the last slot, or not. Rescan.
*/ */
needscan = dfp == &hdr->bestfree[2]; needscan = dfp == &bf[2];
} }
} }
/* /*
...@@ -930,7 +968,7 @@ xfs_dir2_data_use_free( ...@@ -930,7 +968,7 @@ xfs_dir2_data_use_free(
* the 2 new will work. * the 2 new will work.
*/ */
if (dfp) { if (dfp) {
needscan = (hdr->bestfree[2].length != 0); needscan = (bf[2].length != 0);
if (!needscan) { if (!needscan) {
xfs_dir2_data_freeremove(hdr, dfp, needlogp); xfs_dir2_data_freeremove(hdr, dfp, needlogp);
xfs_dir2_data_freeinsert(hdr, newdup, needlogp); xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
......
/* /*
* Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
* Copyright (c) 2013 Red Hat, Inc.
* All Rights Reserved. * All Rights Reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
...@@ -35,6 +36,37 @@ ...@@ -35,6 +36,37 @@
#define XFS_DIR2_DATA_MAGIC 0x58443244 /* XD2D: multiblock dirs */ #define XFS_DIR2_DATA_MAGIC 0x58443244 /* XD2D: multiblock dirs */
#define XFS_DIR2_FREE_MAGIC 0x58443246 /* XD2F: free index blocks */ #define XFS_DIR2_FREE_MAGIC 0x58443246 /* XD2F: free index blocks */
/*
* Directory Version 3 With CRCs.
*
* The tree formats are the same as for version 2 directories. The difference
* is in the block header and dirent formats. In many cases the v3 structures
* use v2 definitions as they are no different and this makes code sharing much
* easier.
*
* Also, the xfs_dir3_*() functions handle both v2 and v3 formats - if the
* format is v2 then they switch to the existing v2 code, or the format is v3
* they implement the v3 functionality. This means the existing dir2 is a mix of
* xfs_dir2/xfs_dir3 calls and functions. The xfs_dir3 functions are called
* where there is a difference in the formats, otherwise the code is unchanged.
*
* Where it is possible, the code decides what to do based on the magic numbers
* in the blocks rather than feature bits in the superblock. This means the code
* is as independent of the external XFS code as possible as doesn't require
* passing struct xfs_mount pointers into places where it isn't really
* necessary.
*
* Version 3 includes:
*
* - a larger block header for CRC and identification purposes and so the
* offsets of all the structures inside the blocks are different.
*
* - new magic numbers to be able to detect the v2/v3 types on the fly.
*/
#define XFS_DIR3_BLOCK_MAGIC 0x58444233 /* XDB3: single block dirs */
#define XFS_DIR3_DATA_MAGIC 0x58444433 /* XDD3: multiblock dirs */
/* /*
* Byte offset in data block and shortform entry. * Byte offset in data block and shortform entry.
*/ */
...@@ -225,6 +257,38 @@ typedef struct xfs_dir2_data_hdr { ...@@ -225,6 +257,38 @@ typedef struct xfs_dir2_data_hdr {
xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT]; xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT];
} xfs_dir2_data_hdr_t; } xfs_dir2_data_hdr_t;
/*
* define a structure for all the verification fields we are adding to the
* directory block structures. This will be used in several structures.
* The magic number must be the first entry to align with all the dir2
* structures so we determine how to decode them just by the magic number.
*/
struct xfs_dir3_blk_hdr {
__be32 magic; /* magic number */
__be32 crc; /* CRC of block */
__be64 blkno; /* first block of the buffer */
__be64 lsn; /* sequence number of last write */
uuid_t uuid; /* filesystem we belong to */
__be64 owner; /* inode that owns the block */
};
struct xfs_dir3_data_hdr {
struct xfs_dir3_blk_hdr hdr;
xfs_dir2_data_free_t best_free[XFS_DIR2_DATA_FD_COUNT];
};
#define XFS_DIR3_DATA_CRC_OFF offsetof(struct xfs_dir3_data_hdr, hdr.crc)
static inline struct xfs_dir2_data_free *
xfs_dir3_data_bestfree_p(struct xfs_dir2_data_hdr *hdr)
{
if (hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) {
struct xfs_dir3_data_hdr *hdr3 = (struct xfs_dir3_data_hdr *)hdr;
return hdr3->best_free;
}
return hdr->bestfree;
}
/* /*
* Active entry in a data block. * Active entry in a data block.
* *
...@@ -280,6 +344,85 @@ xfs_dir2_data_unused_tag_p(struct xfs_dir2_data_unused *dup) ...@@ -280,6 +344,85 @@ xfs_dir2_data_unused_tag_p(struct xfs_dir2_data_unused *dup)
be16_to_cpu(dup->length) - sizeof(__be16)); be16_to_cpu(dup->length) - sizeof(__be16));
} }
static inline struct xfs_dir2_data_unused *
xfs_dir3_data_unused_p(struct xfs_dir2_data_hdr *hdr)
{
if (hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) {
return (struct xfs_dir2_data_unused *)
((char *)hdr + sizeof(struct xfs_dir3_data_hdr));
}
return (struct xfs_dir2_data_unused *)
((char *)hdr + sizeof(struct xfs_dir2_data_hdr));
}
static inline size_t
xfs_dir3_data_hdr_size(bool dir3)
{
if (dir3)
return sizeof(struct xfs_dir3_data_hdr);
return sizeof(struct xfs_dir2_data_hdr);
}
static inline size_t
xfs_dir3_data_entry_offset(struct xfs_dir2_data_hdr *hdr)
{
bool dir3 = hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
return xfs_dir3_data_hdr_size(dir3);
}
static inline struct xfs_dir2_data_entry *
xfs_dir3_data_entry_p(struct xfs_dir2_data_hdr *hdr)
{
return (struct xfs_dir2_data_entry *)
((char *)hdr + xfs_dir3_data_entry_offset(hdr));
}
/*
* Offsets of . and .. in data space (always block 0)
*/
static inline xfs_dir2_data_aoff_t
xfs_dir3_data_dot_offset(struct xfs_dir2_data_hdr *hdr)
{
return xfs_dir3_data_entry_offset(hdr);
}
static inline xfs_dir2_data_aoff_t
xfs_dir3_data_dotdot_offset(struct xfs_dir2_data_hdr *hdr)
{
return xfs_dir3_data_dot_offset(hdr) + xfs_dir2_data_entsize(1);
}
static inline xfs_dir2_data_aoff_t
xfs_dir3_data_first_offset(struct xfs_dir2_data_hdr *hdr)
{
return xfs_dir3_data_dotdot_offset(hdr) + xfs_dir2_data_entsize(2);
}
/*
* location of . and .. in data space (always block 0)
*/
static inline struct xfs_dir2_data_entry *
xfs_dir3_data_dot_entry_p(struct xfs_dir2_data_hdr *hdr)
{
return (struct xfs_dir2_data_entry *)
((char *)hdr + xfs_dir3_data_dot_offset(hdr));
}
static inline struct xfs_dir2_data_entry *
xfs_dir3_data_dotdot_entry_p(struct xfs_dir2_data_hdr *hdr)
{
return (struct xfs_dir2_data_entry *)
((char *)hdr + xfs_dir3_data_dotdot_offset(hdr));
}
static inline struct xfs_dir2_data_entry *
xfs_dir3_data_first_entry_p(struct xfs_dir2_data_hdr *hdr)
{
return (struct xfs_dir2_data_entry *)
((char *)hdr + xfs_dir3_data_first_offset(hdr));
}
/* /*
* Leaf block structures. * Leaf block structures.
* *
......
...@@ -149,6 +149,7 @@ xfs_dir2_block_to_leaf( ...@@ -149,6 +149,7 @@ xfs_dir2_block_to_leaf(
int needlog; /* need to log block header */ int needlog; /* need to log block header */
int needscan; /* need to rescan bestfree */ int needscan; /* need to rescan bestfree */
xfs_trans_t *tp; /* transaction pointer */ xfs_trans_t *tp; /* transaction pointer */
struct xfs_dir2_data_free *bf;
trace_xfs_dir2_block_to_leaf(args); trace_xfs_dir2_block_to_leaf(args);
...@@ -177,6 +178,7 @@ xfs_dir2_block_to_leaf( ...@@ -177,6 +178,7 @@ xfs_dir2_block_to_leaf(
xfs_dir2_data_check(dp, dbp); xfs_dir2_data_check(dp, dbp);
btp = xfs_dir2_block_tail_p(mp, hdr); btp = xfs_dir2_block_tail_p(mp, hdr);
blp = xfs_dir2_block_leaf_p(btp); blp = xfs_dir2_block_leaf_p(btp);
bf = xfs_dir3_data_bestfree_p(hdr);
/* /*
* Set the counts in the leaf header. * Set the counts in the leaf header.
*/ */
...@@ -212,7 +214,7 @@ xfs_dir2_block_to_leaf( ...@@ -212,7 +214,7 @@ xfs_dir2_block_to_leaf(
ltp = xfs_dir2_leaf_tail_p(mp, leaf); ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ltp->bestcount = cpu_to_be32(1); ltp->bestcount = cpu_to_be32(1);
bestsp = xfs_dir2_leaf_bests_p(ltp); bestsp = xfs_dir2_leaf_bests_p(ltp);
bestsp[0] = hdr->bestfree[0].length; bestsp[0] = bf[0].length;
/* /*
* Log the data header and leaf bests table. * Log the data header and leaf bests table.
*/ */
...@@ -544,7 +546,7 @@ xfs_dir2_leaf_addname( ...@@ -544,7 +546,7 @@ xfs_dir2_leaf_addname(
/* /*
* Initialize the block. * Initialize the block.
*/ */
if ((error = xfs_dir2_data_init(args, use_block, &dbp))) { if ((error = xfs_dir3_data_init(args, use_block, &dbp))) {
xfs_trans_brelse(tp, lbp); xfs_trans_brelse(tp, lbp);
return error; return error;
} }
......
...@@ -1588,7 +1588,7 @@ xfs_dir2_node_addname_int( ...@@ -1588,7 +1588,7 @@ xfs_dir2_node_addname_int(
if (unlikely((error = xfs_dir2_grow_inode(args, if (unlikely((error = xfs_dir2_grow_inode(args,
XFS_DIR2_DATA_SPACE, XFS_DIR2_DATA_SPACE,
&dbno)) || &dbno)) ||
(error = xfs_dir2_data_init(args, dbno, &dbp)))) (error = xfs_dir3_data_init(args, dbno, &dbp))))
return error; return error;
/* /*
......
...@@ -30,7 +30,7 @@ extern int xfs_dir_cilookup_result(struct xfs_da_args *args, ...@@ -30,7 +30,7 @@ extern int xfs_dir_cilookup_result(struct xfs_da_args *args,
const unsigned char *name, int len); const unsigned char *name, int len);
/* xfs_dir2_block.c */ /* xfs_dir2_block.c */
extern const struct xfs_buf_ops xfs_dir2_block_buf_ops; extern const struct xfs_buf_ops xfs_dir3_block_buf_ops;
extern int xfs_dir2_block_addname(struct xfs_da_args *args); extern int xfs_dir2_block_addname(struct xfs_da_args *args);
extern int xfs_dir2_block_getdents(struct xfs_inode *dp, void *dirent, extern int xfs_dir2_block_getdents(struct xfs_inode *dp, void *dirent,
...@@ -61,7 +61,7 @@ xfs_dir2_data_freeinsert(struct xfs_dir2_data_hdr *hdr, ...@@ -61,7 +61,7 @@ xfs_dir2_data_freeinsert(struct xfs_dir2_data_hdr *hdr,
struct xfs_dir2_data_unused *dup, int *loghead); struct xfs_dir2_data_unused *dup, int *loghead);
extern void xfs_dir2_data_freescan(struct xfs_mount *mp, extern void xfs_dir2_data_freescan(struct xfs_mount *mp,
struct xfs_dir2_data_hdr *hdr, int *loghead); struct xfs_dir2_data_hdr *hdr, int *loghead);
extern int xfs_dir2_data_init(struct xfs_da_args *args, xfs_dir2_db_t blkno, extern int xfs_dir3_data_init(struct xfs_da_args *args, xfs_dir2_db_t blkno,
struct xfs_buf **bpp); struct xfs_buf **bpp);
extern void xfs_dir2_data_log_entry(struct xfs_trans *tp, struct xfs_buf *bp, extern void xfs_dir2_data_log_entry(struct xfs_trans *tp, struct xfs_buf *bp,
struct xfs_dir2_data_entry *dep); struct xfs_dir2_data_entry *dep);
......
...@@ -278,7 +278,7 @@ xfs_dir2_block_to_sf( ...@@ -278,7 +278,7 @@ xfs_dir2_block_to_sf(
* Set up to loop over the block's entries. * Set up to loop over the block's entries.
*/ */
btp = xfs_dir2_block_tail_p(mp, hdr); btp = xfs_dir2_block_tail_p(mp, hdr);
ptr = (char *)(hdr + 1); ptr = (char *)xfs_dir3_data_entry_p(hdr);
endptr = (char *)xfs_dir2_block_leaf_p(btp); endptr = (char *)xfs_dir2_block_leaf_p(btp);
sfep = xfs_dir2_sf_firstentry(sfp); sfep = xfs_dir2_sf_firstentry(sfp);
/* /*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册