--- .pc/attr2_tes/fs/xfs/xfs_attr.c 2006-10-26 17:45:01.000000000 +1000 +++ fs/xfs/xfs_attr.c 2006-11-27 22:58:49.753629073 +1100 @@ -210,7 +210,19 @@ xfs_attr_set_int(xfs_inode_t *dp, const * (inode must not be locked when we call this routine) */ if (XFS_IFORK_Q(dp) == 0) { - if ((error = xfs_bmap_add_attrfork(dp, size, rsvd))) + int req_size; + int sf_size = sizeof(xfs_attr_sf_hdr_t) + XFS_ATTR_SF_ENTSIZE_BYNAME(namelen, valuelen); + + if (local && (sf_size <= (XFS_LITINO(mp) - xfs_ifork_dsize_used(dp)))) + req_size = sf_size; + else + /* + * We can't fit our SF EA inline, so leave space for 2 EA extents + * which should cover most initial EAs and most EAs in general + */ + req_size = 2 * sizeof(xfs_bmbt_rec_t); + + if ((error = xfs_bmap_add_attrfork(dp, req_size, rsvd))) return(error); } --- .pc/attr2_tes/fs/xfs/xfs_attr_leaf.c 2006-10-26 17:45:01.000000000 +1000 +++ fs/xfs/xfs_attr_leaf.c 2006-11-27 22:59:07.295306537 +1100 @@ -170,18 +170,25 @@ xfs_attr_shortform_bytesfit(xfs_inode_t } /* 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 = MAX(xfs_ifork_dsize_used(dp), 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; + /* we can't fit inline */ + if (offset < minforkoff) + return 0; + + /* don't move the forkoff for data btree */ + if (dp->i_d.di_format == XFS_DINODE_FMT_BTREE && dp->i_d.di_forkoff) + return dp->i_d.di_forkoff << 3; + if (offset >= maxforkoff) return maxforkoff; - return 0; + else + return offset; } /* --- .pc/attr2_tes/fs/xfs/xfs_bmap.c 2006-11-17 14:35:46.000000000 +1100 +++ fs/xfs/xfs_bmap.c 2006-11-27 15:54:33.166590715 +1100 @@ -3543,6 +3543,7 @@ xfs_bmap_forkoff_reset( if (whichfork == XFS_ATTR_FORK && (ip->i_d.di_format != XFS_DINODE_FMT_DEV) && (ip->i_d.di_format != XFS_DINODE_FMT_UUID) && + (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) && ((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) / --- .pc/attr2_tes/fs/xfs/xfs_inode.c 2006-11-27 23:20:19.000000000 +1100 +++ fs/xfs/xfs_inode.c 2006-11-27 23:21:29.604958540 +1100 @@ -4747,3 +4747,34 @@ xfs_iext_irec_update_extoffs( ifp->if_u1.if_ext_irec[i].er_extoff += ext_diff; } } + +/* + * return how much space is used by the inode's data fork + */ +int +xfs_ifork_dsize_used(xfs_inode_t *ip) +{ + switch (ip->i_d.di_format) { + case XFS_DINODE_FMT_DEV: + return sizeof(xfs_dev_t); + case XFS_DINODE_FMT_UUID: + return sizeof(uuid_t); + case XFS_DINODE_FMT_LOCAL: + case XFS_DINODE_FMT_EXTENTS: + return ip->i_df.if_bytes; + case XFS_DINODE_FMT_BTREE: + if (ip->i_d.di_forkoff) + return ip->i_d.di_forkoff << 3; + else + /* + * For new attr fork, data btree takes all the space, + * so no room for any attrs with the current layout + * but we can know how much space it really needs + * i.e. the ptrs are half way along but we could compress to + * preserve the num of records. + */ + return XFS_BMDR_SPACE_CALC(XFS_BMAP_BROOT_NUMRECS(ip->i_df.if_broot)); + default: + return 0; + } +} --- .pc/attr2_tes/fs/xfs/xfs_inode.h 2006-11-17 14:35:46.000000000 +1100 +++ fs/xfs/xfs_inode.h 2006-11-27 23:24:09.376554289 +1100 @@ -535,6 +535,7 @@ void xfs_iext_irec_compact(xfs_ifork_t void xfs_iext_irec_compact_pages(xfs_ifork_t *); void xfs_iext_irec_compact_full(xfs_ifork_t *); void xfs_iext_irec_update_extoffs(xfs_ifork_t *, int, int); +int xfs_ifork_dsize_used(xfs_inode_t *); #define xfs_ipincount(ip) ((unsigned int) atomic_read(&ip->i_pincount))