[DLM] block dlm_recv in recovery transition
[safe/jmp/linux-2.6] / fs / xfs / xfs_attr_leaf.c
index cc4ffa4..81f45da 100644 (file)
@@ -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
@@ -355,7 +392,8 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
                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 ||
-                       !(mp->m_flags & XFS_MOUNT_ATTR2));
+                       !(mp->m_flags & XFS_MOUNT_ATTR2) ||
+                       dp->i_d.di_format == XFS_DINODE_FMT_BTREE);
                dp->i_afp->if_ext_max =
                        XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
                dp->i_df.if_ext_max =
@@ -748,6 +786,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 +825,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
@@ -3013,7 +3053,7 @@ xfs_attr_rolltrans(xfs_trans_t **transp, xfs_inode_t *dp)
         * is in progress. The caller takes the responsibility to cancel
         * the duplicate transaction that gets returned.
         */
-       if ((error = xfs_trans_commit(trans, 0, NULL)))
+       if ((error = xfs_trans_commit(trans, 0)))
                return (error);
 
        trans = *transp;