Commit d8cc890d authored by Nathan Scott's avatar Nathan Scott

[XFS] Ondisk format extension for extended attributes (attr2). Basically,

the data/attr forks now grow up/down from either end of the literal area,
rather than dividing the literal area into two chunks and growing both
upward.  Means we can now make much more efficient use of the attribute
space, incl. fitting DMF attributes inline in 256 byte inodes, and large
jumps in dbench3 performance numbers.  It is self enabling, but can be
forced on/off via the attr2/noattr2 mount options.

SGI-PV: 941645
SGI-Modid: xfs-linux:xfs-kern:23835a
Signed-off-by: default avatarNathan Scott <nathans@sgi.com>
parent aa82daa0
......@@ -200,7 +200,7 @@ xfs_attr_get(bhv_desc_t *bdp, char *name, char *value, int *valuelenp,
return(error);
}
int
STATIC int
xfs_attr_set_int(xfs_inode_t *dp, char *name, int namelen,
char *value, int valuelen, int flags)
{
......@@ -219,13 +219,19 @@ xfs_attr_set_int(xfs_inode_t *dp, char *name, int namelen,
if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
return (error);
/*
* Determine space new attribute will use, and if it would be
* "local" or "remote" (note: local != inline).
*/
size = xfs_attr_leaf_newentsize(namelen, valuelen,
mp->m_sb.sb_blocksize, &local);
/*
* If the inode doesn't have an attribute fork, add one.
* (inode must not be locked when we call this routine)
*/
if (XFS_IFORK_Q(dp) == 0) {
error = xfs_bmap_add_attrfork(dp, rsvd);
if (error)
if ((error = xfs_bmap_add_attrfork(dp, size, rsvd)))
return(error);
}
......@@ -243,14 +249,9 @@ xfs_attr_set_int(xfs_inode_t *dp, char *name, int namelen,
args.firstblock = &firstblock;
args.flist = &flist;
args.whichfork = XFS_ATTR_FORK;
args.addname = 1;
args.oknoent = 1;
/* Determine space new attribute will use, and if it will be inline
* or out of line.
*/
size = xfs_attr_leaf_newentsize(namelen, valuelen,
mp->m_sb.sb_blocksize, &local);
nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
if (local) {
if (size > (mp->m_sb.sb_blocksize >> 1)) {
......@@ -322,7 +323,7 @@ xfs_attr_set_int(xfs_inode_t *dp, char *name, int namelen,
* Build initial attribute list (if required).
*/
if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
(void)xfs_attr_shortform_create(&args);
xfs_attr_shortform_create(&args);
/*
* Try to add the attr to the attribute list in
......@@ -467,7 +468,7 @@ xfs_attr_set(bhv_desc_t *bdp, char *name, char *value, int valuelen, int flags,
* Generic handler routine to remove a name from an attribute list.
* Transitions attribute list from Btree to shortform as necessary.
*/
int
STATIC int
xfs_attr_remove_int(xfs_inode_t *dp, char *name, int namelen, int flags)
{
xfs_da_args_t args;
......@@ -523,7 +524,6 @@ xfs_attr_remove_int(xfs_inode_t *dp, char *name, int namelen, int flags)
XFS_ATTRRM_LOG_COUNT))) {
xfs_trans_cancel(args.trans, 0);
return(error);
}
xfs_ilock(dp, XFS_ILOCK_EXCL);
......@@ -822,7 +822,7 @@ xfs_attr_inactive(xfs_inode_t *dp)
STATIC int
xfs_attr_shortform_addname(xfs_da_args_t *args)
{
int newsize, retval;
int newsize, forkoff, retval;
retval = xfs_attr_shortform_lookup(args);
if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
......@@ -834,16 +834,18 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
ASSERT(retval == 0);
}
if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX)
return(XFS_ERROR(ENOSPC));
newsize = XFS_ATTR_SF_TOTSIZE(args->dp);
newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
if ((newsize <= XFS_IFORK_ASIZE(args->dp)) &&
(args->namelen < XFS_ATTR_SF_ENTSIZE_MAX) &&
(args->valuelen < XFS_ATTR_SF_ENTSIZE_MAX)) {
retval = xfs_attr_shortform_add(args);
ASSERT(retval == 0);
} else {
forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize);
if (!forkoff)
return(XFS_ERROR(ENOSPC));
}
xfs_attr_shortform_add(args, forkoff);
return(0);
}
......@@ -863,7 +865,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
{
xfs_inode_t *dp;
xfs_dabuf_t *bp;
int retval, error, committed;
int retval, error, committed, forkoff;
/*
* Read the (only) block in the attribute list in.
......@@ -1006,9 +1008,9 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
/*
* If the result is small enough, shrink it all into the inode.
*/
if (xfs_attr_shortform_allfit(bp, dp)) {
if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
XFS_BMAP_INIT(args->flist, args->firstblock);
error = xfs_attr_leaf_to_shortform(bp, args);
error = xfs_attr_leaf_to_shortform(bp, args, forkoff);
/* bp is gone due to xfs_da_shrink_inode */
if (!error) {
error = xfs_bmap_finish(&args->trans,
......@@ -1060,8 +1062,7 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
{
xfs_inode_t *dp;
xfs_dabuf_t *bp;
int committed;
int error;
int error, committed, forkoff;
/*
* Remove the attribute.
......@@ -1086,9 +1087,9 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
/*
* If the result is small enough, shrink it all into the inode.
*/
if (xfs_attr_shortform_allfit(bp, dp)) {
if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
XFS_BMAP_INIT(args->flist, args->firstblock);
error = xfs_attr_leaf_to_shortform(bp, args);
error = xfs_attr_leaf_to_shortform(bp, args, forkoff);
/* bp is gone due to xfs_da_shrink_inode */
if (!error) {
error = xfs_bmap_finish(&args->trans, args->flist,
......@@ -1459,7 +1460,7 @@ xfs_attr_node_removename(xfs_da_args_t *args)
xfs_da_state_blk_t *blk;
xfs_inode_t *dp;
xfs_dabuf_t *bp;
int retval, error, committed;
int retval, error, committed, forkoff;
/*
* Tie a string around our finger to remind us where we are.
......@@ -1580,9 +1581,9 @@ xfs_attr_node_removename(xfs_da_args_t *args)
bp->data)->hdr.info.magic, ARCH_CONVERT)
== XFS_ATTR_LEAF_MAGIC);
if (xfs_attr_shortform_allfit(bp, dp)) {
if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
XFS_BMAP_INIT(args->flist, args->firstblock);
error = xfs_attr_leaf_to_shortform(bp, args);
error = xfs_attr_leaf_to_shortform(bp, args, forkoff);
/* bp is gone due to xfs_da_shrink_inode */
if (!error) {
error = xfs_bmap_finish(&args->trans,
......
......@@ -118,13 +118,82 @@ STATIC int xfs_attr_put_listent(xfs_attr_list_context_t *context,
/*========================================================================
* External routines when dirsize < XFS_LITINO(mp).
* External routines when attribute fork size < XFS_LITINO(mp).
*========================================================================*/
/*
* Create the initial contents of a shortform attribute list.
* Query whether the requested number of additional bytes of extended
* attribute space will be able to fit inline.
* Returns zero if not, else the di_forkoff fork offset to be used in the
* literal area for attribute data once the new bytes have been added.
*
* di_forkoff must be 8 byte aligned, hence is stored as a >>3 value;
* special case for dev/uuid inodes, they have fixed size data forks.
*/
int
xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes)
{
int offset;
int minforkoff; /* lower limit on valid forkoff locations */
int maxforkoff; /* upper limit on valid forkoff locations */
xfs_mount_t *mp = dp->i_mount;
if (unlikely(mp->m_flags & XFS_MOUNT_COMPAT_ATTR)) {
if (bytes <= XFS_IFORK_ASIZE(dp))
return mp->m_attroffset >> 3;
return 0;
}
offset = (XFS_LITINO(mp) - bytes) >> 3; /* rounded down */
switch (dp->i_d.di_format) {
case XFS_DINODE_FMT_DEV:
minforkoff = roundup(sizeof(xfs_dev_t), 8) >> 3;
return (offset >= minforkoff) ? minforkoff : 0;
case XFS_DINODE_FMT_UUID:
minforkoff = roundup(sizeof(uuid_t), 8) >> 3;
return (offset >= minforkoff) ? minforkoff : 0;
}
/* data fork btree root can have at least this many key/ptr pairs */
minforkoff = MAX(dp->i_df.if_bytes, XFS_BMDR_SPACE_CALC(MINDBTPTRS));
minforkoff = roundup(minforkoff, 8) >> 3;
/* attr fork btree root can have at least this many key/ptr pairs */
maxforkoff = XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(MINABTPTRS);
maxforkoff = maxforkoff >> 3; /* rounded down */
if (offset >= minforkoff && offset < maxforkoff)
return offset;
if (offset >= maxforkoff)
return maxforkoff;
return 0;
}
/*
* Switch on the ATTR2 superblock bit (implies also FEATURES2)
*/
STATIC void
xfs_sbversion_add_attr2(xfs_mount_t *mp, xfs_trans_t *tp)
{
unsigned long s;
if (!(mp->m_flags & XFS_MOUNT_COMPAT_ATTR) &&
!(XFS_SB_VERSION_HASATTR2(&mp->m_sb))) {
s = XFS_SB_LOCK(mp);
if (!XFS_SB_VERSION_HASATTR2(&mp->m_sb)) {
XFS_SB_VERSION_ADDATTR2(&mp->m_sb);
XFS_SB_UNLOCK(mp, s);
xfs_mod_sb(tp, XFS_SB_VERSIONNUM | XFS_SB_FEATURES2);
} else
XFS_SB_UNLOCK(mp, s);
}
}
/*
* Create the initial contents of a shortform attribute list.
*/
void
xfs_attr_shortform_create(xfs_da_args_t *args)
{
xfs_attr_sf_hdr_t *hdr;
......@@ -148,29 +217,37 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
hdr->count = 0;
INT_SET(hdr->totsize, ARCH_CONVERT, sizeof(*hdr));
xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
return(0);
}
/*
* Add a name/value pair to the shortform attribute list.
* Overflow from the inode has already been checked for.
*/
int
xfs_attr_shortform_add(xfs_da_args_t *args)
void
xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
{
xfs_attr_shortform_t *sf;
xfs_attr_sf_entry_t *sfe;
int i, offset, size;
xfs_mount_t *mp;
xfs_inode_t *dp;
xfs_ifork_t *ifp;
dp = args->dp;
mp = dp->i_mount;
dp->i_d.di_forkoff = forkoff;
dp->i_df.if_ext_max =
XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
dp->i_afp->if_ext_max =
XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
ifp = dp->i_afp;
ASSERT(ifp->if_flags & XFS_IFINLINE);
sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
sfe = &sf->list[0];
for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT);
sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
#ifdef DEBUG
if (sfe->namelen != args->namelen)
continue;
if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
......@@ -181,7 +258,8 @@ xfs_attr_shortform_add(xfs_da_args_t *args)
if (((args->flags & ATTR_ROOT) != 0) !=
((sfe->flags & XFS_ATTR_ROOT) != 0))
continue;
return(XFS_ERROR(EEXIST));
ASSERT(0);
#endif
}
offset = (char *)sfe - (char *)sf;
......@@ -200,11 +278,11 @@ xfs_attr_shortform_add(xfs_da_args_t *args)
INT_MOD(sf->hdr.totsize, ARCH_CONVERT, size);
xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
return(0);
xfs_sbversion_add_attr2(mp, args->trans);
}
/*
* Remove a name from the shortform attribute list structure.
* Remove an attribute from the shortform attribute list structure.
*/
int
xfs_attr_shortform_remove(xfs_da_args_t *args)
......@@ -212,17 +290,16 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
xfs_attr_shortform_t *sf;
xfs_attr_sf_entry_t *sfe;
int base, size=0, end, totsize, i;
xfs_mount_t *mp;
xfs_inode_t *dp;
/*
* Remove the attribute.
*/
dp = args->dp;
mp = dp->i_mount;
base = sizeof(xfs_attr_sf_hdr_t);
sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
sfe = &sf->list[0];
for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT);
sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
end = INT_GET(sf->hdr.count, ARCH_CONVERT);
for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
base += size, i++) {
size = XFS_ATTR_SF_ENTSIZE(sfe);
if (sfe->namelen != args->namelen)
......@@ -237,19 +314,51 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
continue;
break;
}
if (i == INT_GET(sf->hdr.count, ARCH_CONVERT))
if (i == end)
return(XFS_ERROR(ENOATTR));
/*
* Fix up the attribute fork data, covering the hole
*/
end = base + size;
totsize = INT_GET(sf->hdr.totsize, ARCH_CONVERT);
if (end != totsize) {
memmove(&((char *)sf)[base], &((char *)sf)[end],
totsize - end);
}
if (end != totsize)
memmove(&((char *)sf)[base], &((char *)sf)[end], totsize - end);
INT_MOD(sf->hdr.count, ARCH_CONVERT, -1);
INT_MOD(sf->hdr.totsize, ARCH_CONVERT, -size);
xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);
xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
/*
* Fix up the start offset of the attribute fork
*/
totsize -= size;
if (totsize == sizeof(xfs_attr_sf_hdr_t) && !args->addname) {
/*
* Last attribute now removed, revert to original
* inode format making all literal area available
* to the data fork once more.
*/
xfs_idestroy_fork(dp, XFS_ATTR_FORK);
dp->i_d.di_forkoff = 0;
dp->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
ASSERT(dp->i_d.di_anextents == 0);
ASSERT(dp->i_afp == NULL);
dp->i_df.if_ext_max =
XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
} else {
xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);
dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize);
ASSERT(dp->i_d.di_forkoff);
ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) || args->addname);
dp->i_afp->if_ext_max =
XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
dp->i_df.if_ext_max =
XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
xfs_trans_log_inode(args->trans, dp,
XFS_ILOG_CORE | XFS_ILOG_ADATA);
}
xfs_sbversion_add_attr2(mp, args->trans);
return(0);
}
......@@ -649,14 +758,16 @@ xfs_attr_shortform_allfit(xfs_dabuf_t *bp, xfs_inode_t *dp)
+ name_loc->namelen
+ INT_GET(name_loc->valuelen, ARCH_CONVERT);
}
return( bytes < XFS_IFORK_ASIZE(dp) );
if (bytes == sizeof(struct xfs_attr_sf_hdr))
return(-1);
return(xfs_attr_shortform_bytesfit(dp, bytes));
}
/*
* Convert a leaf attribute list to shortform attribute list
*/
int
xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args)
xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff)
{
xfs_attr_leafblock_t *leaf;
xfs_attr_leaf_entry_t *entry;
......@@ -683,9 +794,25 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args)
error = xfs_da_shrink_inode(args, 0, bp);
if (error)
goto out;
error = xfs_attr_shortform_create(args);
if (error)
if (forkoff == -1) {
/*
* Last attribute was removed, revert to original
* inode format making all literal area available
* to the data fork once more.
*/
xfs_idestroy_fork(dp, XFS_ATTR_FORK);
dp->i_d.di_forkoff = 0;
dp->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
ASSERT(dp->i_d.di_anextents == 0);
ASSERT(dp->i_afp == NULL);
dp->i_df.if_ext_max =
XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
goto out;
}
xfs_attr_shortform_create(args);
/*
* Copy the attributes
......@@ -713,7 +840,7 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args)
nargs.hashval = INT_GET(entry->hashval, ARCH_CONVERT);
nargs.flags = (entry->flags & XFS_ATTR_SECURE) ? ATTR_SECURE :
((entry->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0);
xfs_attr_shortform_add(&nargs);
xfs_attr_shortform_add(&nargs, forkoff);
}
error = 0;
......
......@@ -238,23 +238,25 @@ typedef struct xfs_attr_inactive_list {
*========================================================================*/
/*
* Internal routines when dirsize < XFS_LITINO(mp).
* Internal routines when attribute fork size < XFS_LITINO(mp).
*/
int xfs_attr_shortform_create(struct xfs_da_args *args);
int xfs_attr_shortform_add(struct xfs_da_args *add);
void xfs_attr_shortform_create(struct xfs_da_args *args);
void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff);
int xfs_attr_shortform_lookup(struct xfs_da_args *args);
int xfs_attr_shortform_getvalue(struct xfs_da_args *args);
int xfs_attr_shortform_to_leaf(struct xfs_da_args *args);
int xfs_attr_shortform_remove(struct xfs_da_args *remove);
int xfs_attr_shortform_remove(struct xfs_da_args *args);
int xfs_attr_shortform_list(struct xfs_attr_list_context *context);
int xfs_attr_shortform_allfit(struct xfs_dabuf *bp, struct xfs_inode *dp);
int xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes);
/*
* Internal routines when dirsize == XFS_LBSIZE(mp).
* Internal routines when attribute fork size == XFS_LBSIZE(mp).
*/
int xfs_attr_leaf_to_node(struct xfs_da_args *args);
int xfs_attr_leaf_to_shortform(struct xfs_dabuf *bp,
struct xfs_da_args *args);
struct xfs_da_args *args, int forkoff);
int xfs_attr_leaf_clearflag(struct xfs_da_args *args);
int xfs_attr_leaf_setflag(struct xfs_da_args *args);
int xfs_attr_leaf_flipflags(xfs_da_args_t *args);
......
/*
* Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
* Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
......@@ -62,6 +62,7 @@
#include "xfs_error.h"
#include "xfs_da_btree.h"
#include "xfs_dir_leaf.h"
#include "xfs_attr_leaf.h"
#include "xfs_bit.h"
#include "xfs_rw.h"
#include "xfs_quota.h"
......@@ -3336,6 +3337,29 @@ xfs_bmap_insert_exlist(
xfs_bmbt_set_all(&base[to], new);
}
/*
* Helper routine to reset inode di_forkoff field when switching
* attribute fork from local to extent format - we reset it where
* possible to make space available for inline data fork extents.
*/
STATIC void
xfs_bmap_forkoff_reset(
xfs_mount_t *mp,
xfs_inode_t *ip,
int whichfork)
{
if (whichfork == XFS_ATTR_FORK &&
(ip->i_d.di_format != XFS_DINODE_FMT_DEV) &&
(ip->i_d.di_format != XFS_DINODE_FMT_UUID) &&
((mp->m_attroffset >> 3) > ip->i_d.di_forkoff)) {
ip->i_d.di_forkoff = mp->m_attroffset >> 3;
ip->i_df.if_ext_max = XFS_IFORK_DSIZE(ip) /
(uint)sizeof(xfs_bmbt_rec_t);
ip->i_afp->if_ext_max = XFS_IFORK_ASIZE(ip) /
(uint)sizeof(xfs_bmbt_rec_t);
}
}
/*
* Convert a local file to an extents file.
* This code is out of bounds for data forks of regular files,
......@@ -3403,6 +3427,7 @@ xfs_bmap_local_to_extents(
memcpy((char *)XFS_BUF_PTR(bp), ifp->if_u1.if_data,
ifp->if_bytes);
xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
xfs_bmap_forkoff_reset(args.mp, ip, whichfork);
xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
xfs_iext_realloc(ip, 1, whichfork);
ep = ifp->if_u1.if_extents;
......@@ -3413,8 +3438,10 @@ xfs_bmap_local_to_extents(
XFS_TRANS_MOD_DQUOT_BYINO(args.mp, tp, ip,
XFS_TRANS_DQ_BCOUNT, 1L);
flags |= XFS_ILOG_FEXT(whichfork);
} else
} else {
ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0);
xfs_bmap_forkoff_reset(ip->i_mount, ip, whichfork);
}
ifp->if_flags &= ~XFS_IFINLINE;
ifp->if_flags |= XFS_IFEXTENTS;
XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS);
......@@ -3796,22 +3823,24 @@ xfs_bunmap_trace(
int /* error code */
xfs_bmap_add_attrfork(
xfs_inode_t *ip, /* incore inode pointer */
int rsvd) /* OK to allocated reserved blocks in trans */
int size, /* space new attribute needs */
int rsvd) /* xact may use reserved blks */
{
int blks; /* space reservation */
int committed; /* xaction was committed */
int error; /* error return value */
xfs_fsblock_t firstblock; /* 1st block/ag allocated */
xfs_bmap_free_t flist; /* freed extent list */
int logflags; /* logging flags */
xfs_mount_t *mp; /* mount structure */
unsigned long s; /* spinlock spl value */
xfs_trans_t *tp; /* transaction pointer */
unsigned long s; /* spinlock spl value */
int blks; /* space reservation */
int version = 1; /* superblock attr version */
int committed; /* xaction was committed */
int logflags; /* logging flags */
int error; /* error return value */
ASSERT(XFS_IFORK_Q(ip) == 0);
ASSERT(ip->i_df.if_ext_max ==
XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t));
if (XFS_IFORK_Q(ip))
return 0;
mp = ip->i_mount;
ASSERT(!XFS_NOT_DQATTACHED(mp, ip));
tp = xfs_trans_alloc(mp, XFS_TRANS_ADDAFORK);
......@@ -3853,7 +3882,11 @@ xfs_bmap_add_attrfork(
case XFS_DINODE_FMT_LOCAL:
case XFS_DINODE_FMT_EXTENTS:
case XFS_DINODE_FMT_BTREE:
ip->i_d.di_forkoff = mp->m_attroffset >> 3;
ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size);
if (!ip->i_d.di_forkoff)
ip->i_d.di_forkoff = mp->m_attroffset >> 3;
else if (!(mp->m_flags & XFS_MOUNT_COMPAT_ATTR))
version = 2;
break;
default:
ASSERT(0);
......@@ -3890,12 +3923,21 @@ xfs_bmap_add_attrfork(
xfs_trans_log_inode(tp, ip, logflags);
if (error)
goto error2;
if (!XFS_SB_VERSION_HASATTR(&mp->m_sb)) {
if (!XFS_SB_VERSION_HASATTR(&mp->m_sb) ||
(!XFS_SB_VERSION_HASATTR2(&mp->m_sb) && version == 2)) {
logflags = 0;
s = XFS_SB_LOCK(mp);
if (!XFS_SB_VERSION_HASATTR(&mp->m_sb)) {
XFS_SB_VERSION_ADDATTR(&mp->m_sb);
logflags |= XFS_SB_VERSIONNUM;
}
if (!XFS_SB_VERSION_HASATTR2(&mp->m_sb) && version == 2) {
XFS_SB_VERSION_ADDATTR2(&mp->m_sb);
logflags |= (XFS_SB_VERSIONNUM | XFS_SB_FEATURES2);
}
if (logflags) {
XFS_SB_UNLOCK(mp, s);
xfs_mod_sb(tp, XFS_SB_VERSIONNUM);
xfs_mod_sb(tp, logflags);
} else
XFS_SB_UNLOCK(mp, s);
}
......@@ -3988,13 +4030,19 @@ xfs_bmap_compute_maxlevels(
* (a signed 32-bit number, xfs_extnum_t), or by di_anextents
* (a signed 16-bit number, xfs_aextnum_t).
*/
maxleafents = (whichfork == XFS_DATA_FORK) ? MAXEXTNUM : MAXAEXTNUM;
if (whichfork == XFS_DATA_FORK) {
maxleafents = MAXEXTNUM;
sz = (mp->m_flags & XFS_MOUNT_COMPAT_ATTR) ?
mp->m_attroffset : XFS_BMDR_SPACE_CALC(MINDBTPTRS);
} else {
maxleafents = MAXAEXTNUM;
sz = (mp->m_flags & XFS_MOUNT_COMPAT_ATTR) ?
mp->m_sb.sb_inodesize - mp->m_attroffset :
XFS_BMDR_SPACE_CALC(MINABTPTRS);
}
maxrootrecs = (int)XFS_BTREE_BLOCK_MAXRECS(sz, xfs_bmdr, 0);
minleafrecs = mp->m_bmap_dmnr[0];
minnoderecs = mp->m_bmap_dmnr[1];
sz = (whichfork == XFS_DATA_FORK) ?
mp->m_attroffset :
mp->m_sb.sb_inodesize - mp->m_attroffset;
maxrootrecs = (int)XFS_BTREE_BLOCK_MAXRECS(sz, xfs_bmdr, 0);
maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs;
for (level = 1; maxblocks > 1; level++) {
if (maxblocks <= maxrootrecs)
......
/*
* Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
......@@ -156,7 +156,8 @@ xfs_bmap_trace_exlist(
int /* error code */