#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
+#include "xfs_dir.h"
#include "xfs_dir2.h"
#include "xfs_dmapi.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
#include "xfs_alloc_btree.h"
#include "xfs_ialloc_btree.h"
+#include "xfs_dir_sf.h"
#include "xfs_dir2_sf.h"
#include "xfs_attr_sf.h"
#include "xfs_dinode.h"
#include "xfs_bmap.h"
#include "xfs_attr.h"
#include "xfs_attr_leaf.h"
+#include "xfs_dir_leaf.h"
#include "xfs_dir2_data.h"
#include "xfs_dir2_leaf.h"
#include "xfs_dir2_block.h"
max = state->path.active - 1;
ASSERT((max >= 0) && (max < XFS_DA_NODE_MAXDEPTH));
ASSERT(state->path.blk[max].magic == XFS_ATTR_LEAF_MAGIC ||
- state->path.blk[max].magic == XFS_DIR2_LEAFN_MAGIC);
+ state->path.blk[max].magic == XFS_DIRX_LEAF_MAGIC(state->mp));
addblk = &state->path.blk[max]; /* initial dummy value */
for (i = max; (i >= 0) && addblk; state->path.active--, i--) {
return(error); /* GROT: attr inconsistent */
addblk = newblk;
break;
+ case XFS_DIR_LEAF_MAGIC:
+ ASSERT(XFS_DIR_IS_V1(state->mp));
+ error = xfs_dir_leaf_split(state, oldblk, newblk);
+ if ((error != 0) && (error != ENOSPC)) {
+ return(error); /* GROT: dir is inconsistent */
+ }
+ if (!error) {
+ addblk = newblk;
+ break;
+ }
+ /*
+ * Entry wouldn't fit, split the leaf again.
+ */
+ state->extravalid = 1;
+ if (state->inleaf) {
+ state->extraafter = 0; /* before newblk */
+ error = xfs_dir_leaf_split(state, oldblk,
+ &state->extrablk);
+ if (error)
+ return(error); /* GROT: dir incon. */
+ addblk = newblk;
+ } else {
+ state->extraafter = 1; /* after newblk */
+ error = xfs_dir_leaf_split(state, newblk,
+ &state->extrablk);
+ if (error)
+ return(error); /* GROT: dir incon. */
+ addblk = newblk;
+ }
+ break;
case XFS_DIR2_LEAFN_MAGIC:
+ ASSERT(XFS_DIR_IS_V2(state->mp));
error = xfs_dir2_leafn_split(state, oldblk, newblk);
if (error)
return error;
size = (int)((char *)&oldroot->btree[be16_to_cpu(oldroot->hdr.count)] -
(char *)oldroot);
} else {
+ ASSERT(XFS_DIR_IS_V2(mp));
ASSERT(be16_to_cpu(oldroot->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
leaf = (xfs_dir2_leaf_t *)oldroot;
size = (int)((char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] -
* Set up the new root node.
*/
error = xfs_da_node_create(args,
- (args->whichfork == XFS_DATA_FORK) ? mp->m_dirleafblk : 0,
+ args->whichfork == XFS_DATA_FORK &&
+ XFS_DIR_IS_V2(mp) ? mp->m_dirleafblk : 0,
be16_to_cpu(node->hdr.level) + 1, &bp, args->whichfork);
if (error)
return(error);
ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
/*
- * With V2 dirs the extra block is data or freespace.
+ * With V2 the extra block is data or freespace.
*/
- useextra = state->extravalid && state->args->whichfork == XFS_ATTR_FORK;
+ useextra = state->extravalid && (XFS_DIR_IS_V1(state->mp) ||
+ state->args->whichfork == XFS_ATTR_FORK);
newcount = 1 + useextra;
/*
* Do we have to split the node?
ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
ASSERT((oldblk->index >= 0) && (oldblk->index <= be16_to_cpu(node->hdr.count)));
ASSERT(newblk->blkno != 0);
- if (state->args->whichfork == XFS_DATA_FORK)
+ if (state->args->whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(mp))
ASSERT(newblk->blkno >= mp->m_dirleafblk &&
newblk->blkno < mp->m_dirfreeblk);
save_blk = &state->altpath.blk[ state->path.active-1 ];
ASSERT(state->path.blk[0].magic == XFS_DA_NODE_MAGIC);
ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC ||
- drop_blk->magic == XFS_DIR2_LEAFN_MAGIC);
+ drop_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp));
/*
* Walk back up the tree joining/deallocating as necessary.
return(0);
xfs_attr_leaf_unbalance(state, drop_blk, save_blk);
break;
+ case XFS_DIR_LEAF_MAGIC:
+ ASSERT(XFS_DIR_IS_V1(state->mp));
+ error = xfs_dir_leaf_toosmall(state, &action);
+ if (error)
+ return(error);
+ if (action == 0)
+ return(0);
+ xfs_dir_leaf_unbalance(state, drop_blk, save_blk);
+ break;
case XFS_DIR2_LEAFN_MAGIC:
+ ASSERT(XFS_DIR_IS_V2(state->mp));
error = xfs_dir2_leafn_toosmall(state, &action);
if (error)
return error;
ASSERT(bp != NULL);
blkinfo = bp->data;
if (be16_to_cpu(oldroot->hdr.level) == 1) {
- ASSERT(be16_to_cpu(blkinfo->magic) == XFS_DIR2_LEAFN_MAGIC ||
+ ASSERT(be16_to_cpu(blkinfo->magic) == XFS_DIRX_LEAF_MAGIC(state->mp) ||
be16_to_cpu(blkinfo->magic) == XFS_ATTR_LEAF_MAGIC);
} else {
ASSERT(be16_to_cpu(blkinfo->magic) == XFS_DA_NODE_MAGIC);
if (count == 0)
return;
break;
+ case XFS_DIR_LEAF_MAGIC:
+ ASSERT(XFS_DIR_IS_V1(state->mp));
+ lasthash = xfs_dir_leaf_lasthash(blk->bp, &count);
+ if (count == 0)
+ return;
+ break;
case XFS_DIR2_LEAFN_MAGIC:
+ ASSERT(XFS_DIR_IS_V2(state->mp));
lasthash = xfs_dir2_leafn_lasthash(blk->bp, &count);
if (count == 0)
return;
* Descend thru the B-tree searching each level for the right
* node to use, until the right hashval is found.
*/
- blkno = (args->whichfork == XFS_DATA_FORK)? state->mp->m_dirleafblk : 0;
+ if (args->whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(state->mp))
+ blkno = state->mp->m_dirleafblk;
+ else
+ blkno = 0;
for (blk = &state->path.blk[0], state->path.active = 1;
state->path.active <= XFS_DA_NODE_MAXDEPTH;
blk++, state->path.active++) {
}
curr = blk->bp->data;
ASSERT(be16_to_cpu(curr->magic) == XFS_DA_NODE_MAGIC ||
- be16_to_cpu(curr->magic) == XFS_DIR2_LEAFN_MAGIC ||
+ be16_to_cpu(curr->magic) == XFS_DIRX_LEAF_MAGIC(state->mp) ||
be16_to_cpu(curr->magic) == XFS_ATTR_LEAF_MAGIC);
/*
blk->index = probe;
blkno = be32_to_cpu(btree->before);
}
- } else if (be16_to_cpu(curr->magic) == XFS_ATTR_LEAF_MAGIC) {
+ }
+ else if (be16_to_cpu(curr->magic) == XFS_ATTR_LEAF_MAGIC) {
blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL);
break;
- } else if (be16_to_cpu(curr->magic) == XFS_DIR2_LEAFN_MAGIC) {
+ }
+ else if (be16_to_cpu(curr->magic) == XFS_DIR_LEAF_MAGIC) {
+ blk->hashval = xfs_dir_leaf_lasthash(blk->bp, NULL);
+ break;
+ }
+ else if (be16_to_cpu(curr->magic) == XFS_DIR2_LEAFN_MAGIC) {
blk->hashval = xfs_dir2_leafn_lasthash(blk->bp, NULL);
break;
}
* next leaf and keep searching.
*/
for (;;) {
- if (blk->magic == XFS_DIR2_LEAFN_MAGIC) {
+ if (blk->magic == XFS_DIR_LEAF_MAGIC) {
+ ASSERT(XFS_DIR_IS_V1(state->mp));
+ retval = xfs_dir_leaf_lookup_int(blk->bp, args,
+ &blk->index);
+ } else if (blk->magic == XFS_DIR2_LEAFN_MAGIC) {
+ ASSERT(XFS_DIR_IS_V2(state->mp));
retval = xfs_dir2_leafn_lookup_int(blk->bp, args,
&blk->index, state);
}
old_info = old_blk->bp->data;
new_info = new_blk->bp->data;
ASSERT(old_blk->magic == XFS_DA_NODE_MAGIC ||
- old_blk->magic == XFS_DIR2_LEAFN_MAGIC ||
+ old_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp) ||
old_blk->magic == XFS_ATTR_LEAF_MAGIC);
ASSERT(old_blk->magic == be16_to_cpu(old_info->magic));
ASSERT(new_blk->magic == be16_to_cpu(new_info->magic));
case XFS_ATTR_LEAF_MAGIC:
before = xfs_attr_leaf_order(old_blk->bp, new_blk->bp);
break;
+ case XFS_DIR_LEAF_MAGIC:
+ ASSERT(XFS_DIR_IS_V1(state->mp));
+ before = xfs_dir_leaf_order(old_blk->bp, new_blk->bp);
+ break;
case XFS_DIR2_LEAFN_MAGIC:
+ ASSERT(XFS_DIR_IS_V2(state->mp));
before = xfs_dir2_leafn_order(old_blk->bp, new_blk->bp);
break;
case XFS_DA_NODE_MAGIC:
save_info = save_blk->bp->data;
drop_info = drop_blk->bp->data;
ASSERT(save_blk->magic == XFS_DA_NODE_MAGIC ||
- save_blk->magic == XFS_DIR2_LEAFN_MAGIC ||
+ save_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp) ||
save_blk->magic == XFS_ATTR_LEAF_MAGIC);
ASSERT(save_blk->magic == be16_to_cpu(save_info->magic));
ASSERT(drop_blk->magic == be16_to_cpu(drop_info->magic));
ASSERT(blk->bp != NULL);
info = blk->bp->data;
ASSERT(be16_to_cpu(info->magic) == XFS_DA_NODE_MAGIC ||
- be16_to_cpu(info->magic) == XFS_DIR2_LEAFN_MAGIC ||
+ be16_to_cpu(info->magic) == XFS_DIRX_LEAF_MAGIC(state->mp) ||
be16_to_cpu(info->magic) == XFS_ATTR_LEAF_MAGIC);
blk->magic = be16_to_cpu(info->magic);
if (blk->magic == XFS_DA_NODE_MAGIC) {
blk->hashval = xfs_attr_leaf_lasthash(blk->bp,
NULL);
break;
+ case XFS_DIR_LEAF_MAGIC:
+ ASSERT(XFS_DIR_IS_V1(state->mp));
+ blk->hashval = xfs_dir_leaf_lasthash(blk->bp,
+ NULL);
+ break;
case XFS_DIR2_LEAFN_MAGIC:
+ ASSERT(XFS_DIR_IS_V2(state->mp));
blk->hashval = xfs_dir2_leafn_lasthash(blk->bp,
NULL);
break;
default:
ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC ||
- blk->magic == XFS_DIR2_LEAFN_MAGIC);
+ blk->magic ==
+ XFS_DIRX_LEAF_MAGIC(state->mp));
break;
}
}
xfs_bmbt_irec_t *mapp;
xfs_inode_t *dp;
int nmap, error, w, count, c, got, i, mapi;
+ xfs_fsize_t size;
xfs_trans_t *tp;
xfs_mount_t *mp;
/*
* For new directories adjust the file offset and block count.
*/
- if (w == XFS_DATA_FORK) {
+ if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) {
bno = mp->m_dirleafblk;
count = mp->m_dirblkfsbs;
} else {
/*
* Find a spot in the file space to put the new block.
*/
- if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, w)))
+ if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, w))) {
return error;
- if (w == XFS_DATA_FORK)
+ }
+ if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp))
ASSERT(bno >= mp->m_dirleafblk && bno < mp->m_dirfreeblk);
/*
* Try mapping it in one filesystem block.
XFS_BMAPI_AFLAG(w)|XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|
XFS_BMAPI_CONTIG,
args->firstblock, args->total, &map, &nmap,
- args->flist, NULL))) {
+ args->flist))) {
return error;
}
ASSERT(nmap <= 1);
XFS_BMAPI_AFLAG(w)|XFS_BMAPI_WRITE|
XFS_BMAPI_METADATA,
args->firstblock, args->total,
- &mapp[mapi], &nmap, args->flist,
- NULL))) {
+ &mapp[mapi], &nmap, args->flist))) {
kmem_free(mapp, sizeof(*mapp) * count);
return error;
}
if (mapp != &map)
kmem_free(mapp, sizeof(*mapp) * count);
*new_blkno = (xfs_dablk_t)bno;
+ /*
+ * For version 1 directories, adjust the file size if it changed.
+ */
+ if (w == XFS_DATA_FORK && XFS_DIR_IS_V1(mp)) {
+ ASSERT(mapi == 1);
+ if ((error = xfs_bmap_last_offset(tp, dp, &bno, w)))
+ return error;
+ size = XFS_FSB_TO_B(mp, bno);
+ if (size != dp->i_d.di_size) {
+ dp->i_d.di_size = size;
+ xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
+ }
+ }
return 0;
}
int error, w, entno, level, dead_level;
xfs_da_blkinfo_t *dead_info, *sib_info;
xfs_da_intnode_t *par_node, *dead_node;
+ xfs_dir_leafblock_t *dead_leaf;
xfs_dir2_leaf_t *dead_leaf2;
xfs_dahash_t dead_hash;
w = args->whichfork;
ASSERT(w == XFS_DATA_FORK);
mp = ip->i_mount;
- lastoff = mp->m_dirfreeblk;
- error = xfs_bmap_last_before(tp, ip, &lastoff, w);
+ if (XFS_DIR_IS_V2(mp)) {
+ lastoff = mp->m_dirfreeblk;
+ error = xfs_bmap_last_before(tp, ip, &lastoff, w);
+ } else
+ error = xfs_bmap_last_offset(tp, ip, &lastoff, w);
if (error)
return error;
if (unlikely(lastoff == 0)) {
/*
* Get values from the moved block.
*/
- if (be16_to_cpu(dead_info->magic) == XFS_DIR2_LEAFN_MAGIC) {
+ if (be16_to_cpu(dead_info->magic) == XFS_DIR_LEAF_MAGIC) {
+ ASSERT(XFS_DIR_IS_V1(mp));
+ dead_leaf = (xfs_dir_leafblock_t *)dead_info;
+ dead_level = 0;
+ dead_hash =
+ INT_GET(dead_leaf->entries[INT_GET(dead_leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT);
+ } else if (be16_to_cpu(dead_info->magic) == XFS_DIR2_LEAFN_MAGIC) {
+ ASSERT(XFS_DIR_IS_V2(mp));
dead_leaf2 = (xfs_dir2_leaf_t *)dead_info;
dead_level = 0;
dead_hash = be32_to_cpu(dead_leaf2->ents[be16_to_cpu(dead_leaf2->hdr.count) - 1].hashval);
xfs_da_buf_done(sib_buf);
sib_buf = NULL;
}
- par_blkno = mp->m_dirleafblk;
+ par_blkno = XFS_DIR_IS_V1(mp) ? 0 : mp->m_dirleafblk;
level = -1;
/*
* Walk down the tree looking for the parent of the moved block.
{
xfs_inode_t *dp;
int done, error, w, count;
+ xfs_fileoff_t bno;
+ xfs_fsize_t size;
xfs_trans_t *tp;
xfs_mount_t *mp;
w = args->whichfork;
tp = args->trans;
mp = dp->i_mount;
- if (w == XFS_DATA_FORK)
+ if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp))
count = mp->m_dirblkfsbs;
else
count = 1;
*/
if ((error = xfs_bunmapi(tp, dp, dead_blkno, count,
XFS_BMAPI_AFLAG(w)|XFS_BMAPI_METADATA,
- 0, args->firstblock, args->flist, NULL,
+ 0, args->firstblock, args->flist,
&done)) == ENOSPC) {
if (w != XFS_DATA_FORK)
- break;
+ goto done;
if ((error = xfs_da_swap_lastblock(args, &dead_blkno,
&dead_buf)))
- break;
- } else {
+ goto done;
+ } else if (error)
+ goto done;
+ else
break;
+ }
+ ASSERT(done);
+ xfs_da_binval(tp, dead_buf);
+ /*
+ * Adjust the directory size for version 1.
+ */
+ if (w == XFS_DATA_FORK && XFS_DIR_IS_V1(mp)) {
+ if ((error = xfs_bmap_last_offset(tp, dp, &bno, w)))
+ return error;
+ size = XFS_FSB_TO_B(dp->i_mount, bno);
+ if (size != dp->i_d.di_size) {
+ dp->i_d.di_size = size;
+ xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
}
}
+ return 0;
+done:
xfs_da_binval(tp, dead_buf);
return error;
}
xfs_dabuf_t *rbp;
mp = dp->i_mount;
- nfsb = (whichfork == XFS_DATA_FORK) ? mp->m_dirblkfsbs : 1;
+ if (whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(mp))
+ nfsb = mp->m_dirblkfsbs;
+ else
+ nfsb = 1;
mappedbno = *mappedbnop;
/*
* Caller doesn't have a mapping. -2 means don't complain
nfsb,
XFS_BMAPI_METADATA |
XFS_BMAPI_AFLAG(whichfork),
- NULL, 0, mapp, &nmap, NULL, NULL)))
+ NULL, 0, mapp, &nmap, NULL)))
goto exit0;
}
} else {
magic1 = be32_to_cpu(data->hdr.magic);
if (unlikely(
XFS_TEST_ERROR((magic != XFS_DA_NODE_MAGIC) &&
+ (magic != XFS_DIR_LEAF_MAGIC) &&
(magic != XFS_ATTR_LEAF_MAGIC) &&
(magic != XFS_DIR2_LEAF1_MAGIC) &&
(magic != XFS_DIR2_LEAFN_MAGIC) &&