Skip to content

Commit 0b9aad4

Browse files
konisakpm00
authored andcommitted
nilfs2: do not propagate ENOENT error from sufile during GC
nilfs_sufile_freev(), which is used to free segments in GC, aborts with -ENOENT if the target segment usage is on a hole block. This error only occurs if one of the segment numbers to be freed passed by the GC ioctl is invalid, so return -EINVAL instead. To avoid impairing readability, introduce a wrapper function that encapsulates error handling including the error code conversion (and error message output). Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Ryusuke Konishi <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 5b527d3 commit 0b9aad4

File tree

1 file changed

+56
-8
lines changed

1 file changed

+56
-8
lines changed

fs/nilfs2/segment.c

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,12 +1102,64 @@ static int nilfs_segctor_scan_file_dsync(struct nilfs_sc_info *sci,
11021102
return err;
11031103
}
11041104

1105+
/**
1106+
* nilfs_free_segments - free the segments given by an array of segment numbers
1107+
* @nilfs: nilfs object
1108+
* @segnumv: array of segment numbers to be freed
1109+
* @nsegs: number of segments to be freed in @segnumv
1110+
*
1111+
* nilfs_free_segments() wraps nilfs_sufile_freev() and
1112+
* nilfs_sufile_cancel_freev(), and edits the segment usage metadata file
1113+
* (sufile) to free all segments given by @segnumv and @nsegs at once. If
1114+
* it fails midway, it cancels the changes so that none of the segments are
1115+
* freed. If @nsegs is 0, this function does nothing.
1116+
*
1117+
* The freeing of segments is not finalized until the writing of a log with
1118+
* a super root block containing this sufile change is complete, and it can
1119+
* be canceled with nilfs_sufile_cancel_freev() until then.
1120+
*
1121+
* Return: 0 on success, or the following negative error code on failure.
1122+
* * %-EINVAL - Invalid segment number.
1123+
* * %-EIO - I/O error (including metadata corruption).
1124+
* * %-ENOMEM - Insufficient memory available.
1125+
*/
1126+
static int nilfs_free_segments(struct the_nilfs *nilfs, __u64 *segnumv,
1127+
size_t nsegs)
1128+
{
1129+
size_t ndone;
1130+
int ret;
1131+
1132+
if (!nsegs)
1133+
return 0;
1134+
1135+
ret = nilfs_sufile_freev(nilfs->ns_sufile, segnumv, nsegs, &ndone);
1136+
if (unlikely(ret)) {
1137+
nilfs_sufile_cancel_freev(nilfs->ns_sufile, segnumv, ndone,
1138+
NULL);
1139+
/*
1140+
* If a segment usage of the segments to be freed is in a
1141+
* hole block, nilfs_sufile_freev() will return -ENOENT.
1142+
* In this case, -EINVAL should be returned to the caller
1143+
* since there is something wrong with the given segment
1144+
* number array. This error can only occur during GC, so
1145+
* there is no need to worry about it propagating to other
1146+
* callers (such as fsync).
1147+
*/
1148+
if (ret == -ENOENT) {
1149+
nilfs_err(nilfs->ns_sb,
1150+
"The segment usage entry %llu to be freed is invalid (in a hole)",
1151+
(unsigned long long)segnumv[ndone]);
1152+
ret = -EINVAL;
1153+
}
1154+
}
1155+
return ret;
1156+
}
1157+
11051158
static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode)
11061159
{
11071160
struct the_nilfs *nilfs = sci->sc_super->s_fs_info;
11081161
struct list_head *head;
11091162
struct nilfs_inode_info *ii;
1110-
size_t ndone;
11111163
int err = 0;
11121164

11131165
switch (nilfs_sc_cstage_get(sci)) {
@@ -1201,14 +1253,10 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode)
12011253
nilfs_sc_cstage_inc(sci);
12021254
fallthrough;
12031255
case NILFS_ST_SUFILE:
1204-
err = nilfs_sufile_freev(nilfs->ns_sufile, sci->sc_freesegs,
1205-
sci->sc_nfreesegs, &ndone);
1206-
if (unlikely(err)) {
1207-
nilfs_sufile_cancel_freev(nilfs->ns_sufile,
1208-
sci->sc_freesegs, ndone,
1209-
NULL);
1256+
err = nilfs_free_segments(nilfs, sci->sc_freesegs,
1257+
sci->sc_nfreesegs);
1258+
if (unlikely(err))
12101259
break;
1211-
}
12121260
sci->sc_stage.flags |= NILFS_CF_SUFREED;
12131261

12141262
err = nilfs_segctor_scan_file(sci, nilfs->ns_sufile,

0 commit comments

Comments
 (0)