diff options
author | Barry Naujok <bnaujok@sgi.com> | 2007-02-10 02:35:58 -0500 |
---|---|---|
committer | Tim Shimmin <tes@sgi.com> | 2007-02-10 02:35:58 -0500 |
commit | e5889e90dda328443161e9512f1123c9814d03de (patch) | |
tree | 36c0fd406520251c8ec2f419cad45f800a2e2f3d /fs/xfs/xfs_attr_leaf.c | |
parent | 7666ab5fb378678a9d5eb3c0dc8d3170e274e7a4 (diff) |
[XFS] Fix attr2 corruption with btree data extents
SGI-PV: 958747
SGI-Modid: xfs-linux-melb:xfs-kern:27792a
Signed-off-by: Barry Naujok <bnaujok@sgi.com>
Signed-off-by: Russell Cattelan <cattelan@thebarn.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_attr_leaf.c')
-rw-r--r-- | fs/xfs/xfs_attr_leaf.c | 45 |
1 files changed, 42 insertions, 3 deletions
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index cc4ffa413da4..e4664136843d 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c | |||
@@ -150,6 +150,7 @@ xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes) | |||
150 | int offset; | 150 | int offset; |
151 | int minforkoff; /* lower limit on valid forkoff locations */ | 151 | int minforkoff; /* lower limit on valid forkoff locations */ |
152 | int maxforkoff; /* upper limit on valid forkoff locations */ | 152 | int maxforkoff; /* upper limit on valid forkoff locations */ |
153 | int dsize; | ||
153 | xfs_mount_t *mp = dp->i_mount; | 154 | xfs_mount_t *mp = dp->i_mount; |
154 | 155 | ||
155 | offset = (XFS_LITINO(mp) - bytes) >> 3; /* rounded down */ | 156 | offset = (XFS_LITINO(mp) - bytes) >> 3; /* rounded down */ |
@@ -169,8 +170,43 @@ xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes) | |||
169 | return 0; | 170 | return 0; |
170 | } | 171 | } |
171 | 172 | ||
172 | /* data fork btree root can have at least this many key/ptr pairs */ | 173 | dsize = dp->i_df.if_bytes; |
173 | minforkoff = MAX(dp->i_df.if_bytes, XFS_BMDR_SPACE_CALC(MINDBTPTRS)); | 174 | |
175 | switch (dp->i_d.di_format) { | ||
176 | case XFS_DINODE_FMT_EXTENTS: | ||
177 | /* | ||
178 | * If there is no attr fork and the data fork is extents, | ||
179 | * determine if creating the default attr fork will result | ||
180 | * in the extents form migrating to btree. If so, the | ||
181 | * minimum offset only needs to be the space required for | ||
182 | * the btree root. | ||
183 | */ | ||
184 | if (!dp->i_d.di_forkoff && dp->i_df.if_bytes > mp->m_attroffset) | ||
185 | dsize = XFS_BMDR_SPACE_CALC(MINDBTPTRS); | ||
186 | break; | ||
187 | |||
188 | case XFS_DINODE_FMT_BTREE: | ||
189 | /* | ||
190 | * If have data btree then keep forkoff if we have one, | ||
191 | * otherwise we are adding a new attr, so then we set | ||
192 | * minforkoff to where the btree root can finish so we have | ||
193 | * plenty of room for attrs | ||
194 | */ | ||
195 | if (dp->i_d.di_forkoff) { | ||
196 | if (offset < dp->i_d.di_forkoff) | ||
197 | return 0; | ||
198 | else | ||
199 | return dp->i_d.di_forkoff; | ||
200 | } else | ||
201 | dsize = XFS_BMAP_BROOT_SPACE(dp->i_df.if_broot); | ||
202 | break; | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * A data fork btree root must have space for at least | ||
207 | * MINDBTPTRS key/ptr pairs if the data fork is small or empty. | ||
208 | */ | ||
209 | minforkoff = MAX(dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS)); | ||
174 | minforkoff = roundup(minforkoff, 8) >> 3; | 210 | minforkoff = roundup(minforkoff, 8) >> 3; |
175 | 211 | ||
176 | /* attr fork btree root can have at least this many key/ptr pairs */ | 212 | /* 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) | |||
336 | */ | 372 | */ |
337 | totsize -= size; | 373 | totsize -= size; |
338 | if (totsize == sizeof(xfs_attr_sf_hdr_t) && !args->addname && | 374 | if (totsize == sizeof(xfs_attr_sf_hdr_t) && !args->addname && |
339 | (mp->m_flags & XFS_MOUNT_ATTR2)) { | 375 | (mp->m_flags & XFS_MOUNT_ATTR2) && |
376 | (dp->i_d.di_format != XFS_DINODE_FMT_BTREE)) { | ||
340 | /* | 377 | /* |
341 | * Last attribute now removed, revert to original | 378 | * Last attribute now removed, revert to original |
342 | * inode format making all literal area available | 379 | * inode format making all literal area available |
@@ -748,6 +785,7 @@ xfs_attr_shortform_allfit(xfs_dabuf_t *bp, xfs_inode_t *dp) | |||
748 | + be16_to_cpu(name_loc->valuelen); | 785 | + be16_to_cpu(name_loc->valuelen); |
749 | } | 786 | } |
750 | if ((dp->i_mount->m_flags & XFS_MOUNT_ATTR2) && | 787 | if ((dp->i_mount->m_flags & XFS_MOUNT_ATTR2) && |
788 | (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) && | ||
751 | (bytes == sizeof(struct xfs_attr_sf_hdr))) | 789 | (bytes == sizeof(struct xfs_attr_sf_hdr))) |
752 | return(-1); | 790 | return(-1); |
753 | return(xfs_attr_shortform_bytesfit(dp, bytes)); | 791 | 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) | |||
786 | 824 | ||
787 | if (forkoff == -1) { | 825 | if (forkoff == -1) { |
788 | ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2); | 826 | ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2); |
827 | ASSERT(dp->i_d.di_format != XFS_DINODE_FMT_BTREE); | ||
789 | 828 | ||
790 | /* | 829 | /* |
791 | * Last attribute was removed, revert to original | 830 | * Last attribute was removed, revert to original |