|
@@ -150,6 +150,7 @@ 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 */
|
|
|
+ int dsize;
|
|
|
xfs_mount_t *mp = dp->i_mount;
|
|
|
|
|
|
offset = (XFS_LITINO(mp) - bytes) >> 3; /* rounded down */
|
|
@@ -169,8 +170,43 @@ xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes)
|
|
|
return 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));
|
|
|
+ dsize = dp->i_df.if_bytes;
|
|
|
+
|
|
|
+ switch (dp->i_d.di_format) {
|
|
|
+ case XFS_DINODE_FMT_EXTENTS:
|
|
|
+ /*
|
|
|
+ * If there is no attr fork and the data fork is extents,
|
|
|
+ * determine if creating the default attr fork will result
|
|
|
+ * in the extents form migrating to btree. If so, the
|
|
|
+ * minimum offset only needs to be the space required for
|
|
|
+ * the btree root.
|
|
|
+ */
|
|
|
+ if (!dp->i_d.di_forkoff && dp->i_df.if_bytes > mp->m_attroffset)
|
|
|
+ dsize = XFS_BMDR_SPACE_CALC(MINDBTPTRS);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case XFS_DINODE_FMT_BTREE:
|
|
|
+ /*
|
|
|
+ * If have data btree then keep forkoff if we have one,
|
|
|
+ * otherwise we are adding a new attr, so then we set
|
|
|
+ * minforkoff to where the btree root can finish so we have
|
|
|
+ * plenty of room for attrs
|
|
|
+ */
|
|
|
+ if (dp->i_d.di_forkoff) {
|
|
|
+ if (offset < dp->i_d.di_forkoff)
|
|
|
+ return 0;
|
|
|
+ else
|
|
|
+ return dp->i_d.di_forkoff;
|
|
|
+ } else
|
|
|
+ dsize = XFS_BMAP_BROOT_SPACE(dp->i_df.if_broot);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * A data fork btree root must have space for at least
|
|
|
+ * MINDBTPTRS key/ptr pairs if the data fork is small or empty.
|
|
|
+ */
|
|
|
+ minforkoff = MAX(dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS));
|
|
|
minforkoff = roundup(minforkoff, 8) >> 3;
|
|
|
|
|
|
/* attr fork btree root can have at least this many key/ptr pairs */
|
|
@@ -336,7 +372,8 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
|
|
|
*/
|
|
|
totsize -= size;
|
|
|
if (totsize == sizeof(xfs_attr_sf_hdr_t) && !args->addname &&
|
|
|
- (mp->m_flags & XFS_MOUNT_ATTR2)) {
|
|
|
+ (mp->m_flags & XFS_MOUNT_ATTR2) &&
|
|
|
+ (dp->i_d.di_format != XFS_DINODE_FMT_BTREE)) {
|
|
|
/*
|
|
|
* Last attribute now removed, revert to original
|
|
|
* inode format making all literal area available
|
|
@@ -748,6 +785,7 @@ xfs_attr_shortform_allfit(xfs_dabuf_t *bp, xfs_inode_t *dp)
|
|
|
+ be16_to_cpu(name_loc->valuelen);
|
|
|
}
|
|
|
if ((dp->i_mount->m_flags & XFS_MOUNT_ATTR2) &&
|
|
|
+ (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) &&
|
|
|
(bytes == sizeof(struct xfs_attr_sf_hdr)))
|
|
|
return(-1);
|
|
|
return(xfs_attr_shortform_bytesfit(dp, bytes));
|
|
@@ -786,6 +824,7 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff)
|
|
|
|
|
|
if (forkoff == -1) {
|
|
|
ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2);
|
|
|
+ ASSERT(dp->i_d.di_format != XFS_DINODE_FMT_BTREE);
|
|
|
|
|
|
/*
|
|
|
* Last attribute was removed, revert to original
|