Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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/20240821154627.11848-5-konishi.ryusuke@gmail.com
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Ryusuke Konishi and committed by
Andrew Morton
0b9aad46 5b527d38

+56 -8
+56 -8
fs/nilfs2/segment.c
··· 1102 1102 return err; 1103 1103 } 1104 1104 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 + 1105 1158 static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode) 1106 1159 { 1107 1160 struct the_nilfs *nilfs = sci->sc_super->s_fs_info; 1108 1161 struct list_head *head; 1109 1162 struct nilfs_inode_info *ii; 1110 - size_t ndone; 1111 1163 int err = 0; 1112 1164 1113 1165 switch (nilfs_sc_cstage_get(sci)) { ··· 1253 1201 nilfs_sc_cstage_inc(sci); 1254 1202 fallthrough; 1255 1203 case NILFS_ST_SUFILE: 1256 - err = nilfs_sufile_freev(nilfs->ns_sufile, sci->sc_freesegs, 1257 - sci->sc_nfreesegs, &ndone); 1258 - if (unlikely(err)) { 1259 - nilfs_sufile_cancel_freev(nilfs->ns_sufile, 1260 - sci->sc_freesegs, ndone, 1261 - NULL); 1204 + err = nilfs_free_segments(nilfs, sci->sc_freesegs, 1205 + sci->sc_nfreesegs); 1206 + if (unlikely(err)) 1262 1207 break; 1263 - } 1264 1208 sci->sc_stage.flags |= NILFS_CF_SUFREED; 1265 1209 1266 1210 err = nilfs_segctor_scan_file(sci, nilfs->ns_sufile,