Skip to content

Commit c4a9d18

Browse files
committed
GFS2: Fix non-recursive truncate bug
Before this patch if you truncated a file to a smaller size it wasn't freeing all the blocks properly. There are two reasons. First, the metapath comparison was not comparing previous heights. I added a function, mp_eq_to_hgt, which checks the metapath at all heights prior to the target height. Second, in function find_nonnull_ptr, it needed to zero out all pointers for heights following the target height. Translated into decimal integer terms, this way a number like 299, when incremented, becomes 300, not 399. The 2 gets incremented to 3, and the following digits need to be reset. These two things allow the truncate state machine to properly find the blocks it needs to delete. Signed-off-by: Bob Peterson <[email protected]>
1 parent d296b15 commit c4a9d18

File tree

1 file changed

+16
-3
lines changed

1 file changed

+16
-3
lines changed

fs/gfs2/bmap.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,8 +1104,15 @@ static bool find_nonnull_ptr(struct gfs2_sbd *sdp, struct metapath *mp,
11041104

11051105
while (true) {
11061106
ptr = metapointer(h, mp);
1107-
if (*ptr) /* if we have a non-null pointer */
1107+
if (*ptr) { /* if we have a non-null pointer */
1108+
/* Now zero the metapath after the current height. */
1109+
h++;
1110+
if (h < GFS2_MAX_META_HEIGHT)
1111+
memset(&mp->mp_list[h], 0,
1112+
(GFS2_MAX_META_HEIGHT - h) *
1113+
sizeof(mp->mp_list[0]));
11081114
return true;
1115+
}
11091116

11101117
if (mp->mp_list[h] < ptrs)
11111118
mp->mp_list[h]++;
@@ -1121,6 +1128,13 @@ enum dealloc_states {
11211128
DEALLOC_DONE = 3, /* process complete */
11221129
};
11231130

1131+
static bool mp_eq_to_hgt(struct metapath *mp, __u16 *nbof, unsigned int h)
1132+
{
1133+
if (memcmp(mp->mp_list, nbof, h * sizeof(mp->mp_list[0])))
1134+
return false;
1135+
return true;
1136+
}
1137+
11241138
/**
11251139
* trunc_dealloc - truncate a file down to a desired size
11261140
* @ip: inode to truncate
@@ -1198,8 +1212,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
11981212
/* If we're truncating to a non-zero size and the mp is
11991213
at the beginning of file for the strip height, we
12001214
need to preserve the first metadata pointer. */
1201-
preserve1 = (newsize &&
1202-
(mp.mp_list[mp_h] == nbof[mp_h]));
1215+
preserve1 = (newsize && mp_eq_to_hgt(&mp, nbof, mp_h));
12031216
bh = mp.mp_bh[mp_h];
12041217
gfs2_assert_withdraw(sdp, bh);
12051218
if (gfs2_assert_withdraw(sdp,

0 commit comments

Comments
 (0)