xref: /aosp_15_r20/external/f2fs-tools/fsck/inject.c (revision 59bfda1f02d633cd6b8b69f31eee485d40f6eef6)
1 /**
2  * inject.c
3  *
4  * Copyright (c) 2024 OPPO Mobile Comm Corp., Ltd.
5  *             http://www.oppo.com/
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 
12 #include <getopt.h>
13 #include "node.h"
14 #include "inject.h"
15 
print_raw_nat_entry_info(struct f2fs_nat_entry * ne)16 static void print_raw_nat_entry_info(struct f2fs_nat_entry *ne)
17 {
18 	if (!c.dbg_lv)
19 		return;
20 
21 	DISP_u8(ne, version);
22 	DISP_u32(ne, ino);
23 	DISP_u32(ne, block_addr);
24 }
25 
print_raw_sit_entry_info(struct f2fs_sit_entry * se)26 static void print_raw_sit_entry_info(struct f2fs_sit_entry *se)
27 {
28 	int i;
29 
30 	if (!c.dbg_lv)
31 		return;
32 
33 	DISP_u16(se, vblocks);
34 	if (c.layout)
35 		printf("%-30s ", "valid_map:");
36 	else
37 		printf("%-30s\t\t[", "valid_map");
38 	for (i = 0; i < SIT_VBLOCK_MAP_SIZE; i++)
39 		printf("%02x", se->valid_map[i]);
40 	if (c.layout)
41 		printf("\n");
42 	else
43 		printf("]\n");
44 	DISP_u64(se, mtime);
45 }
46 
print_raw_sum_entry_info(struct f2fs_summary * sum)47 static void print_raw_sum_entry_info(struct f2fs_summary *sum)
48 {
49 	if (!c.dbg_lv)
50 		return;
51 
52 	DISP_u32(sum, nid);
53 	DISP_u8(sum, version);
54 	DISP_u16(sum, ofs_in_node);
55 }
56 
print_sum_footer_info(struct summary_footer * footer)57 static void print_sum_footer_info(struct summary_footer *footer)
58 {
59 	if (!c.dbg_lv)
60 		return;
61 
62 	DISP_u8(footer, entry_type);
63 	DISP_u32(footer, check_sum);
64 }
65 
print_node_footer_info(struct node_footer * footer)66 static void print_node_footer_info(struct node_footer *footer)
67 {
68 	if (!c.dbg_lv)
69 		return;
70 
71 	DISP_u32(footer, nid);
72 	DISP_u32(footer, ino);
73 	DISP_u32(footer, flag);
74 	DISP_u64(footer, cp_ver);
75 	DISP_u32(footer, next_blkaddr);
76 }
77 
print_raw_dentry_info(struct f2fs_dir_entry * dentry)78 static void print_raw_dentry_info(struct f2fs_dir_entry *dentry)
79 {
80 	if (!c.dbg_lv)
81 		return;
82 
83 	DISP_u32(dentry, hash_code);
84 	DISP_u32(dentry, ino);
85 	DISP_u16(dentry, name_len);
86 	DISP_u8(dentry, file_type);
87 }
88 
inject_usage(void)89 void inject_usage(void)
90 {
91 	MSG(0, "\nUsage: inject.f2fs [options] device\n");
92 	MSG(0, "[options]:\n");
93 	MSG(0, "  -d debug level [default:0]\n");
94 	MSG(0, "  -V print the version number and exit\n");
95 	MSG(0, "  --mb <member name> which member is injected in a struct\n");
96 	MSG(0, "  --val <new value> new value to set\n");
97 	MSG(0, "  --str <new string> new string to set\n");
98 	MSG(0, "  --idx <slot index> which slot is injected in an array\n");
99 	MSG(0, "  --nid <nid> which nid is injected\n");
100 	MSG(0, "  --blk <blkaddr> which blkaddr is injected\n");
101 	MSG(0, "  --sb <0|1|2> --mb <name> [--idx <index>] --val/str <value/string> inject superblock\n");
102 	MSG(0, "  --cp <0|1|2> --mb <name> [--idx <index>] --val <value> inject checkpoint\n");
103 	MSG(0, "  --nat <0|1|2> --mb <name> --nid <nid> --val <value> inject nat entry\n");
104 	MSG(0, "  --sit <0|1|2> --mb <name> --blk <blk> [--idx <index>] --val <value> inject sit entry\n");
105 	MSG(0, "  --ssa --mb <name> --blk <blk> [--idx <index>] --val <value> inject summary entry\n");
106 	MSG(0, "  --node --mb <name> --nid <nid> [--idx <index>] --val <value> inject node\n");
107 	MSG(0, "  --dent --mb <name> --nid <ino> [--idx <index>] --val <value> inject ino's dentry\n");
108 	MSG(0, "  --dry-run do not really inject\n");
109 
110 	exit(1);
111 }
112 
inject_sb_usage(void)113 static void inject_sb_usage(void)
114 {
115 	MSG(0, "inject.f2fs --sb <0|1|2> --mb <name> [--idx <index>] --val/str <value/string>\n");
116 	MSG(0, "[sb]:\n");
117 	MSG(0, "  0: auto select the first super block\n");
118 	MSG(0, "  1: select the first super block\n");
119 	MSG(0, "  2: select the second super block\n");
120 	MSG(0, "[mb]:\n");
121 	MSG(0, "  magic: inject magic number\n");
122 	MSG(0, "  s_stop_reason: inject s_stop_reason array selected by --idx <index>\n");
123 	MSG(0, "  s_errors: inject s_errors array selected by --idx <index>\n");
124 	MSG(0, "  devs.path: inject path in devs array selected by --idx <index> specified by --str <string>\n");
125 }
126 
inject_cp_usage(void)127 static void inject_cp_usage(void)
128 {
129 	MSG(0, "inject.f2fs --cp <0|1|2> --mb <name> [--idx <index>] --val <value> inject checkpoint\n");
130 	MSG(0, "[cp]:\n");
131 	MSG(0, "  0: auto select the current cp pack\n");
132 	MSG(0, "  1: select the first cp pack\n");
133 	MSG(0, "  2: select the second cp pack\n");
134 	MSG(0, "[mb]:\n");
135 	MSG(0, "  checkpoint_ver: inject checkpoint_ver\n");
136 	MSG(0, "  ckpt_flags: inject ckpt_flags\n");
137 	MSG(0, "  cur_node_segno: inject cur_node_segno array selected by --idx <index>\n");
138 	MSG(0, "  cur_node_blkoff: inject cur_node_blkoff array selected by --idx <index>\n");
139 	MSG(0, "  cur_data_segno: inject cur_data_segno array selected by --idx <index>\n");
140 	MSG(0, "  cur_data_blkoff: inject cur_data_blkoff array selected by --idx <index>\n");
141 }
142 
inject_nat_usage(void)143 static void inject_nat_usage(void)
144 {
145 	MSG(0, "inject.f2fs --nat <0|1|2> --mb <name> --nid <nid> --val <value> inject nat entry\n");
146 	MSG(0, "[nat]:\n");
147 	MSG(0, "  0: auto select the current nat pack\n");
148 	MSG(0, "  1: select the first nat pack\n");
149 	MSG(0, "  2: select the second nat pack\n");
150 	MSG(0, "[mb]:\n");
151 	MSG(0, "  version: inject nat entry version\n");
152 	MSG(0, "  ino: inject nat entry ino\n");
153 	MSG(0, "  block_addr: inject nat entry block_addr\n");
154 }
155 
inject_sit_usage(void)156 static void inject_sit_usage(void)
157 {
158 	MSG(0, "inject.f2fs --sit <0|1|2> --mb <name> --blk <blk> [--idx <index>] --val <value> inject sit entry\n");
159 	MSG(0, "[sit]:\n");
160 	MSG(0, "  0: auto select the current sit pack\n");
161 	MSG(0, "  1: select the first sit pack\n");
162 	MSG(0, "  2: select the second sit pack\n");
163 	MSG(0, "[mb]:\n");
164 	MSG(0, "  vblocks: inject sit entry vblocks\n");
165 	MSG(0, "  valid_map: inject sit entry valid_map\n");
166 	MSG(0, "  mtime: inject sit entry mtime\n");
167 }
168 
inject_ssa_usage(void)169 static void inject_ssa_usage(void)
170 {
171 	MSG(0, "inject.f2fs --ssa --mb <name> --blk <blk> [--idx <index>] --val <value> inject summary entry\n");
172 	MSG(0, "[mb]:\n");
173 	MSG(0, "  entry_type: inject summary block footer entry_type\n");
174 	MSG(0, "  check_sum: inject summary block footer check_sum\n");
175 	MSG(0, "  nid: inject summary entry nid selected by --idx <index\n");
176 	MSG(0, "  version: inject summary entry version selected by --idx <index\n");
177 	MSG(0, "  ofs_in_node: inject summary entry ofs_in_node selected by --idx <index\n");
178 }
179 
inject_node_usage(void)180 static void inject_node_usage(void)
181 {
182 	MSG(0, "inject.f2fs --node --mb <name> --nid <nid> [--idx <index>] --val <value> inject node\n");
183 	MSG(0, "[mb]:\n");
184 	MSG(0, "  nid: inject node footer nid\n");
185 	MSG(0, "  ino: inject node footer ino\n");
186 	MSG(0, "  flag: inject node footer flag\n");
187 	MSG(0, "  cp_ver: inject node footer cp_ver\n");
188 	MSG(0, "  next_blkaddr: inject node footer next_blkaddr\n");
189 	MSG(0, "  i_mode: inject inode i_mode\n");
190 	MSG(0, "  i_advise: inject inode i_advise\n");
191 	MSG(0, "  i_inline: inject inode i_inline\n");
192 	MSG(0, "  i_links: inject inode i_links\n");
193 	MSG(0, "  i_size: inject inode i_size\n");
194 	MSG(0, "  i_blocks: inject inode i_blocks\n");
195 	MSG(0, "  i_extra_isize: inject inode i_extra_isize\n");
196 	MSG(0, "  i_inode_checksum: inject inode i_inode_checksum\n");
197 	MSG(0, "  i_addr: inject inode i_addr array selected by --idx <index>\n");
198 	MSG(0, "  i_nid: inject inode i_nid array selected by --idx <index>\n");
199 	MSG(0, "  addr: inject {in}direct node nid/addr array selected by --idx <index>\n");
200 }
201 
inject_dent_usage(void)202 static void inject_dent_usage(void)
203 {
204 	MSG(0, "inject.f2fs --dent --mb <name> --nid <nid> [--idx <index>] --val <value> inject dentry\n");
205 	MSG(0, "[mb]:\n");
206 	MSG(0, "  d_bitmap: inject dentry block d_bitmap of nid\n");
207 	MSG(0, "  d_hash: inject dentry hash\n");
208 	MSG(0, "  d_ino: inject dentry ino\n");
209 	MSG(0, "  d_ftype: inject dentry ftype\n");
210 }
211 
inject_parse_options(int argc,char * argv[],struct inject_option * opt)212 int inject_parse_options(int argc, char *argv[], struct inject_option *opt)
213 {
214 	int o = 0;
215 	const char *pack[] = {"auto", "1", "2"};
216 	const char *option_string = "d:Vh";
217 	char *endptr;
218 	struct option long_opt[] = {
219 		{"dry-run", no_argument, 0, 1},
220 		{"mb", required_argument, 0, 2},
221 		{"idx", required_argument, 0, 3},
222 		{"val", required_argument, 0, 4},
223 		{"str", required_argument, 0, 5},
224 		{"sb", required_argument, 0, 6},
225 		{"cp", required_argument, 0, 7},
226 		{"nat", required_argument, 0, 8},
227 		{"nid", required_argument, 0, 9},
228 		{"sit", required_argument, 0, 10},
229 		{"blk", required_argument, 0, 11},
230 		{"ssa", no_argument, 0, 12},
231 		{"node", no_argument, 0, 13},
232 		{"dent", no_argument, 0, 14},
233 		{0, 0, 0, 0}
234 	};
235 
236 	while ((o = getopt_long(argc, argv, option_string,
237 				long_opt, NULL)) != EOF) {
238 		long nid, blk;
239 
240 		switch (o) {
241 		case 1:
242 			c.dry_run = 1;
243 			MSG(0, "Info: Dry run\n");
244 			break;
245 		case 2:
246 			opt->mb = optarg;
247 			MSG(0, "Info: inject member %s\n", optarg);
248 			break;
249 		case 3:
250 			if (!is_digits(optarg))
251 				return EWRONG_OPT;
252 			opt->idx = atoi(optarg);
253 			MSG(0, "Info: inject slot index %d\n", opt->idx);
254 			break;
255 		case 4:
256 			opt->val = strtoll(optarg, &endptr, 0);
257 			if (opt->val == LLONG_MAX || opt->val == LLONG_MIN ||
258 			    *endptr != '\0')
259 				return -ERANGE;
260 			MSG(0, "Info: inject value %lld : 0x%llx\n", opt->val,
261 			    (unsigned long long)opt->val);
262 			break;
263 		case 5:
264 			opt->str = strdup(optarg);
265 			if (!opt->str)
266 				return -ENOMEM;
267 			MSG(0, "Info: inject string %s\n", opt->str);
268 			break;
269 		case 6:
270 			if (!is_digits(optarg))
271 				return EWRONG_OPT;
272 			opt->sb = atoi(optarg);
273 			if (opt->sb < 0 || opt->sb > 2)
274 				return -ERANGE;
275 			MSG(0, "Info: inject sb %s\n", pack[opt->sb]);
276 			break;
277 		case 7:
278 			if (!is_digits(optarg))
279 				return EWRONG_OPT;
280 			opt->cp = atoi(optarg);
281 			if (opt->cp < 0 || opt->cp > 2)
282 				return -ERANGE;
283 			MSG(0, "Info: inject cp pack %s\n", pack[opt->cp]);
284 			break;
285 		case 8:
286 			if (!is_digits(optarg))
287 				return EWRONG_OPT;
288 			opt->nat = atoi(optarg);
289 			if (opt->nat < 0 || opt->nat > 2)
290 				return -ERANGE;
291 			MSG(0, "Info: inject nat pack %s\n", pack[opt->nat]);
292 			break;
293 		case 9:
294 			nid = strtol(optarg, &endptr, 0);
295 			if (nid >= UINT_MAX || nid < 0 ||
296 			    *endptr != '\0')
297 				return -ERANGE;
298 			opt->nid = nid;
299 			MSG(0, "Info: inject nid %u : 0x%x\n", opt->nid, opt->nid);
300 			break;
301 		case 10:
302 			if (!is_digits(optarg))
303 				return EWRONG_OPT;
304 			opt->sit = atoi(optarg);
305 			if (opt->sit < 0 || opt->sit > 2)
306 				return -ERANGE;
307 			MSG(0, "Info: inject sit pack %s\n", pack[opt->sit]);
308 			break;
309 		case 11:
310 			blk = strtol(optarg, &endptr, 0);
311 			if (blk >= UINT_MAX || blk < 0 ||
312 			    *endptr != '\0')
313 				return -ERANGE;
314 			opt->blk = blk;
315 			MSG(0, "Info: inject blkaddr %u : 0x%x\n", opt->blk, opt->blk);
316 			break;
317 		case 12:
318 			opt->ssa = true;
319 			MSG(0, "Info: inject ssa\n");
320 			break;
321 		case 13:
322 			opt->node = true;
323 			MSG(0, "Info: inject node\n");
324 			break;
325 		case 14:
326 			opt->dent = true;
327 			MSG(0, "Info: inject dentry\n");
328 			break;
329 		case 'd':
330 			if (optarg[0] == '-' || !is_digits(optarg))
331 				return EWRONG_OPT;
332 			c.dbg_lv = atoi(optarg);
333 			MSG(0, "Info: Debug level = %d\n", c.dbg_lv);
334 			break;
335 		case 'V':
336 			show_version("inject.f2fs");
337 			exit(0);
338 		case 'h':
339 		default:
340 			if (opt->sb >= 0) {
341 				inject_sb_usage();
342 				exit(0);
343 			} else if (opt->cp >= 0) {
344 				inject_cp_usage();
345 				exit(0);
346 			} else if (opt->nat >= 0) {
347 				inject_nat_usage();
348 				exit(0);
349 			} else if (opt->sit >= 0) {
350 				inject_sit_usage();
351 				exit(0);
352 			} else if (opt->ssa) {
353 				inject_ssa_usage();
354 				exit(0);
355 			} else if (opt->node) {
356 				inject_node_usage();
357 				exit(0);
358 			} else if (opt->dent) {
359 				inject_dent_usage();
360 				exit(0);
361 			}
362 			return EUNKNOWN_OPT;
363 		}
364 	}
365 
366 	return 0;
367 }
368 
inject_sb(struct f2fs_sb_info * sbi,struct inject_option * opt)369 static int inject_sb(struct f2fs_sb_info *sbi, struct inject_option *opt)
370 {
371 	struct f2fs_super_block *sb;
372 	char *buf;
373 	int ret;
374 
375 	buf = calloc(1, F2FS_BLKSIZE);
376 	ASSERT(buf != NULL);
377 
378 	if (opt->sb == 0)
379 		opt->sb = 1;
380 
381 	ret = dev_read_block(buf, opt->sb == 1 ? SB0_ADDR : SB1_ADDR);
382 	ASSERT(ret >= 0);
383 
384 	sb = (struct f2fs_super_block *)(buf + F2FS_SUPER_OFFSET);
385 
386 	if (!strcmp(opt->mb, "magic")) {
387 		MSG(0, "Info: inject magic of sb %d: 0x%x -> 0x%x\n",
388 		    opt->sb, get_sb(magic), (u32)opt->val);
389 		set_sb(magic, (u32)opt->val);
390 	} else if (!strcmp(opt->mb, "s_stop_reason")) {
391 		if (opt->idx >= MAX_STOP_REASON) {
392 			ERR_MSG("invalid index %u of sb->s_stop_reason[]\n",
393 				opt->idx);
394 			ret = -EINVAL;
395 			goto out;
396 		}
397 		MSG(0, "Info: inject s_stop_reason[%d] of sb %d: %d -> %d\n",
398 		    opt->idx, opt->sb, sb->s_stop_reason[opt->idx],
399 		    (u8)opt->val);
400 		sb->s_stop_reason[opt->idx] = (u8)opt->val;
401 	} else if (!strcmp(opt->mb, "s_errors")) {
402 		if (opt->idx >= MAX_F2FS_ERRORS) {
403 			ERR_MSG("invalid index %u of sb->s_errors[]\n",
404 				opt->idx);
405 			ret = -EINVAL;
406 			goto out;
407 		}
408 		MSG(0, "Info: inject s_errors[%d] of sb %d: %x -> %x\n",
409 		    opt->idx, opt->sb, sb->s_errors[opt->idx], (u8)opt->val);
410 		sb->s_errors[opt->idx] = (u8)opt->val;
411 	} else if (!strcmp(opt->mb, "devs.path")) {
412 		if (opt->idx >= MAX_DEVICES) {
413 			ERR_MSG("invalid index %u of sb->devs[]\n", opt->idx);
414 			ret = -EINVAL;
415 			goto out;
416 		}
417 		if (strlen(opt->str) >= MAX_PATH_LEN) {
418 			ERR_MSG("invalid length of option str\n");
419 			ret = -EINVAL;
420 			goto out;
421 		}
422 		MSG(0, "Info: inject devs[%d].path of sb %d: %s -> %s\n",
423 		    opt->idx, opt->sb, (char *)sb->devs[opt->idx].path, opt->str);
424 		strcpy((char *)sb->devs[opt->idx].path, opt->str);
425 	} else {
426 		ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb);
427 		ret = -EINVAL;
428 		goto out;
429 	}
430 
431 	print_raw_sb_info(sb);
432 	update_superblock(sb, SB_MASK((u32)opt->sb - 1));
433 
434 out:
435 	free(buf);
436 	free(opt->str);
437 	return ret;
438 }
439 
inject_cp(struct f2fs_sb_info * sbi,struct inject_option * opt)440 static int inject_cp(struct f2fs_sb_info *sbi, struct inject_option *opt)
441 {
442 	struct f2fs_checkpoint *cp, *cur_cp = F2FS_CKPT(sbi);
443 	char *buf = NULL;
444 	int ret = 0;
445 
446 	if (opt->cp == 0)
447 		opt->cp = sbi->cur_cp;
448 
449 	if (opt->cp != sbi->cur_cp) {
450 		struct f2fs_super_block *sb = sbi->raw_super;
451 		block_t cp_addr;
452 
453 		buf = calloc(1, F2FS_BLKSIZE);
454 		ASSERT(buf != NULL);
455 
456 		cp_addr = get_sb(cp_blkaddr);
457 		if (opt->cp == 2)
458 			cp_addr += 1 << get_sb(log_blocks_per_seg);
459 		ret = dev_read_block(buf, cp_addr);
460 		ASSERT(ret >= 0);
461 
462 		cp = (struct f2fs_checkpoint *)buf;
463 		sbi->ckpt = cp;
464 		sbi->cur_cp = opt->cp;
465 	} else {
466 		cp = cur_cp;
467 	}
468 
469 	if (!strcmp(opt->mb, "checkpoint_ver")) {
470 		MSG(0, "Info: inject checkpoint_ver of cp %d: 0x%llx -> 0x%"PRIx64"\n",
471 		    opt->cp, get_cp(checkpoint_ver), (u64)opt->val);
472 		set_cp(checkpoint_ver, (u64)opt->val);
473 	} else if (!strcmp(opt->mb, "ckpt_flags")) {
474 		MSG(0, "Info: inject ckpt_flags of cp %d: 0x%x -> 0x%x\n",
475 		    opt->cp, get_cp(ckpt_flags), (u32)opt->val);
476 		set_cp(ckpt_flags, (u32)opt->val);
477 	} else if (!strcmp(opt->mb, "cur_node_segno")) {
478 		if (opt->idx >= MAX_ACTIVE_NODE_LOGS) {
479 			ERR_MSG("invalid index %u of cp->cur_node_segno[]\n",
480 				opt->idx);
481 			ret = -EINVAL;
482 			goto out;
483 		}
484 		MSG(0, "Info: inject cur_node_segno[%d] of cp %d: 0x%x -> 0x%x\n",
485 		    opt->idx, opt->cp, get_cp(cur_node_segno[opt->idx]),
486 		    (u32)opt->val);
487 		set_cp(cur_node_segno[opt->idx], (u32)opt->val);
488 	} else if (!strcmp(opt->mb, "cur_node_blkoff")) {
489 		if (opt->idx >= MAX_ACTIVE_NODE_LOGS) {
490 			ERR_MSG("invalid index %u of cp->cur_node_blkoff[]\n",
491 				opt->idx);
492 			ret = -EINVAL;
493 			goto out;
494 		}
495 		MSG(0, "Info: inject cur_node_blkoff[%d] of cp %d: 0x%x -> 0x%x\n",
496 		    opt->idx, opt->cp, get_cp(cur_node_blkoff[opt->idx]),
497 		    (u16)opt->val);
498 		set_cp(cur_node_blkoff[opt->idx], (u16)opt->val);
499 	} else if (!strcmp(opt->mb, "cur_data_segno")) {
500 		if (opt->idx >= MAX_ACTIVE_DATA_LOGS) {
501 			ERR_MSG("invalid index %u of cp->cur_data_segno[]\n",
502 				opt->idx);
503 			ret = -EINVAL;
504 			goto out;
505 		}
506 		MSG(0, "Info: inject cur_data_segno[%d] of cp %d: 0x%x -> 0x%x\n",
507 		    opt->idx, opt->cp, get_cp(cur_data_segno[opt->idx]),
508 		    (u32)opt->val);
509 		set_cp(cur_data_segno[opt->idx], (u32)opt->val);
510 	} else if (!strcmp(opt->mb, "cur_data_blkoff")) {
511 		if (opt->idx >= MAX_ACTIVE_DATA_LOGS) {
512 			ERR_MSG("invalid index %u of cp->cur_data_blkoff[]\n",
513 				opt->idx);
514 			ret = -EINVAL;
515 			goto out;
516 		}
517 		MSG(0, "Info: inject cur_data_blkoff[%d] of cp %d: 0x%x -> 0x%x\n",
518 		    opt->idx, opt->cp, get_cp(cur_data_blkoff[opt->idx]),
519 		    (u16)opt->val);
520 		set_cp(cur_data_blkoff[opt->idx], (u16)opt->val);
521 	} else {
522 		ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb);
523 		ret = -EINVAL;
524 		goto out;
525 	}
526 
527 	print_ckpt_info(sbi);
528 	write_raw_cp_blocks(sbi, cp, opt->cp);
529 
530 out:
531 	free(buf);
532 	sbi->ckpt = cur_cp;
533 	return ret;
534 }
535 
inject_nat(struct f2fs_sb_info * sbi,struct inject_option * opt)536 static int inject_nat(struct f2fs_sb_info *sbi, struct inject_option *opt)
537 {
538 	struct f2fs_nm_info *nm_i = NM_I(sbi);
539 	struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
540 	struct f2fs_nat_block *nat_blk;
541 	struct f2fs_nat_entry *ne;
542 	block_t blk_addr;
543 	unsigned int offs;
544 	bool is_set;
545 	int ret;
546 
547 	if (!IS_VALID_NID(sbi, opt->nid)) {
548 		ERR_MSG("Invalid nid %u range [%u:%"PRIu64"]\n", opt->nid, 0,
549 			NAT_ENTRY_PER_BLOCK *
550 			((get_sb(segment_count_nat) << 1) <<
551 			 sbi->log_blocks_per_seg));
552 		return -EINVAL;
553 	}
554 
555 	nat_blk = calloc(F2FS_BLKSIZE, 1);
556 	ASSERT(nat_blk);
557 
558 	/* change NAT version bitmap temporarily to select specified pack */
559 	is_set = f2fs_test_bit(opt->nid, nm_i->nat_bitmap);
560 	if (opt->nat == 0) {
561 		opt->nat = is_set ? 2 : 1;
562 	} else {
563 		if (opt->nat == 1)
564 			f2fs_clear_bit(opt->nid, nm_i->nat_bitmap);
565 		else
566 			f2fs_set_bit(opt->nid, nm_i->nat_bitmap);
567 	}
568 
569 	blk_addr = current_nat_addr(sbi, opt->nid, NULL);
570 
571 	ret = dev_read_block(nat_blk, blk_addr);
572 	ASSERT(ret >= 0);
573 
574 	offs = opt->nid % NAT_ENTRY_PER_BLOCK;
575 	ne = &nat_blk->entries[offs];
576 
577 	if (!strcmp(opt->mb, "version")) {
578 		MSG(0, "Info: inject nat entry version of nid %u "
579 		    "in pack %d: %d -> %d\n", opt->nid, opt->nat,
580 		    ne->version, (u8)opt->val);
581 		ne->version = (u8)opt->val;
582 	} else if (!strcmp(opt->mb, "ino")) {
583 		MSG(0, "Info: inject nat entry ino of nid %u "
584 		    "in pack %d: %d -> %d\n", opt->nid, opt->nat,
585 		    le32_to_cpu(ne->ino), (nid_t)opt->val);
586 		ne->ino = cpu_to_le32((nid_t)opt->val);
587 	} else if (!strcmp(opt->mb, "block_addr")) {
588 		MSG(0, "Info: inject nat entry block_addr of nid %u "
589 		    "in pack %d: 0x%x -> 0x%x\n", opt->nid, opt->nat,
590 		    le32_to_cpu(ne->block_addr), (block_t)opt->val);
591 		ne->block_addr = cpu_to_le32((block_t)opt->val);
592 	} else {
593 		ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb);
594 		free(nat_blk);
595 		return -EINVAL;
596 	}
597 	print_raw_nat_entry_info(ne);
598 
599 	ret = dev_write_block(nat_blk, blk_addr, WRITE_LIFE_NONE);
600 	ASSERT(ret >= 0);
601 	/* restore NAT version bitmap */
602 	if (is_set)
603 		f2fs_set_bit(opt->nid, nm_i->nat_bitmap);
604 	else
605 		f2fs_clear_bit(opt->nid, nm_i->nat_bitmap);
606 
607 	free(nat_blk);
608 	return ret;
609 }
610 
inject_sit(struct f2fs_sb_info * sbi,struct inject_option * opt)611 static int inject_sit(struct f2fs_sb_info *sbi, struct inject_option *opt)
612 {
613 	struct sit_info *sit_i = SIT_I(sbi);
614 	struct f2fs_sit_block *sit_blk;
615 	struct f2fs_sit_entry *sit;
616 	unsigned int segno, offs;
617 	bool is_set;
618 
619 	if (!f2fs_is_valid_blkaddr(sbi, opt->blk, DATA_GENERIC)) {
620 		ERR_MSG("Invalid blkaddr 0x%x (valid range [0x%x:0x%lx])\n",
621 			opt->blk, SM_I(sbi)->main_blkaddr,
622 			(unsigned long)le64_to_cpu(F2FS_RAW_SUPER(sbi)->block_count));
623 		return -EINVAL;
624 	}
625 
626 	sit_blk = calloc(F2FS_BLKSIZE, 1);
627 	ASSERT(sit_blk);
628 
629 	segno = GET_SEGNO(sbi, opt->blk);
630 	/* change SIT version bitmap temporarily to select specified pack */
631 	is_set = f2fs_test_bit(segno, sit_i->sit_bitmap);
632 	if (opt->sit == 0) {
633 		opt->sit = is_set ? 2 : 1;
634 	} else {
635 		if (opt->sit == 1)
636 			f2fs_clear_bit(segno, sit_i->sit_bitmap);
637 		else
638 			f2fs_set_bit(segno, sit_i->sit_bitmap);
639 	}
640 	get_current_sit_page(sbi, segno, sit_blk);
641 	offs = SIT_ENTRY_OFFSET(sit_i, segno);
642 	sit = &sit_blk->entries[offs];
643 
644 	if (!strcmp(opt->mb, "vblocks")) {
645 		MSG(0, "Info: inject sit entry vblocks of block 0x%x "
646 		    "in pack %d: %u -> %u\n", opt->blk, opt->sit,
647 		    le16_to_cpu(sit->vblocks), (u16)opt->val);
648 		sit->vblocks = cpu_to_le16((u16)opt->val);
649 	} else if (!strcmp(opt->mb, "valid_map")) {
650 		if (opt->idx == -1) {
651 			MSG(0, "Info: auto idx = %u\n", offs);
652 			opt->idx = offs;
653 		}
654 		if (opt->idx >= SIT_VBLOCK_MAP_SIZE) {
655 			ERR_MSG("invalid idx %u of valid_map[]\n", opt->idx);
656 			free(sit_blk);
657 			return -ERANGE;
658 		}
659 		MSG(0, "Info: inject sit entry valid_map[%d] of block 0x%x "
660 		    "in pack %d: 0x%02x -> 0x%02x\n", opt->idx, opt->blk,
661 		    opt->sit, sit->valid_map[opt->idx], (u8)opt->val);
662 		sit->valid_map[opt->idx] = (u8)opt->val;
663 	} else if (!strcmp(opt->mb, "mtime")) {
664 		MSG(0, "Info: inject sit entry mtime of block 0x%x "
665 		    "in pack %d: %"PRIu64" -> %"PRIu64"\n", opt->blk, opt->sit,
666 		    le64_to_cpu(sit->mtime), (u64)opt->val);
667 		sit->mtime = cpu_to_le64((u64)opt->val);
668 	} else {
669 		ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb);
670 		free(sit_blk);
671 		return -EINVAL;
672 	}
673 	print_raw_sit_entry_info(sit);
674 
675 	rewrite_current_sit_page(sbi, segno, sit_blk);
676 	/* restore SIT version bitmap */
677 	if (is_set)
678 		f2fs_set_bit(segno, sit_i->sit_bitmap);
679 	else
680 		f2fs_clear_bit(segno, sit_i->sit_bitmap);
681 
682 	free(sit_blk);
683 	return 0;
684 }
685 
inject_ssa(struct f2fs_sb_info * sbi,struct inject_option * opt)686 static int inject_ssa(struct f2fs_sb_info *sbi, struct inject_option *opt)
687 {
688 	struct f2fs_summary_block *sum_blk;
689 	struct summary_footer *footer;
690 	struct f2fs_summary *sum;
691 	u32 segno, offset;
692 	block_t ssa_blkaddr;
693 	int type;
694 	int ret;
695 
696 	if (!f2fs_is_valid_blkaddr(sbi, opt->blk, DATA_GENERIC)) {
697 		ERR_MSG("Invalid blkaddr %#x (valid range [%#x:%#lx])\n",
698 			opt->blk, SM_I(sbi)->main_blkaddr,
699 			(unsigned long)le64_to_cpu(F2FS_RAW_SUPER(sbi)->block_count));
700 		return -ERANGE;
701 	}
702 
703 	segno = GET_SEGNO(sbi, opt->blk);
704 	offset = OFFSET_IN_SEG(sbi, opt->blk);
705 
706 	sum_blk = get_sum_block(sbi, segno, &type);
707 	sum = &sum_blk->entries[offset];
708 	footer = F2FS_SUMMARY_BLOCK_FOOTER(sum_blk);
709 
710 	if (!strcmp(opt->mb, "entry_type")) {
711 		MSG(0, "Info: inject summary block footer entry_type of "
712 		    "block 0x%x: %d -> %d\n", opt->blk, footer->entry_type,
713 		    (unsigned char)opt->val);
714 		footer->entry_type = (unsigned char)opt->val;
715 	} else 	if (!strcmp(opt->mb, "check_sum")) {
716 		MSG(0, "Info: inject summary block footer check_sum of "
717 		    "block 0x%x: 0x%x -> 0x%x\n", opt->blk,
718 		    le32_to_cpu(footer->check_sum), (u32)opt->val);
719 		footer->check_sum = cpu_to_le32((u32)opt->val);
720 	} else {
721 		if (opt->idx == -1) {
722 			MSG(0, "Info: auto idx = %u\n", offset);
723 			opt->idx = offset;
724 		}
725 		if (opt->idx >= ENTRIES_IN_SUM) {
726 			ERR_MSG("invalid idx %u of entries[]\n", opt->idx);
727 			ret = -EINVAL;
728 			goto out;
729 		}
730 		sum = &sum_blk->entries[opt->idx];
731 		if (!strcmp(opt->mb, "nid")) {
732 			MSG(0, "Info: inject summary entry nid of "
733 			    "block 0x%x: 0x%x -> 0x%x\n", opt->blk,
734 			    le32_to_cpu(sum->nid), (u32)opt->val);
735 			sum->nid = cpu_to_le32((u32)opt->val);
736 		} else if (!strcmp(opt->mb, "version")) {
737 			MSG(0, "Info: inject summary entry version of "
738 			    "block 0x%x: %d -> %d\n", opt->blk,
739 			    sum->version, (u8)opt->val);
740 			sum->version = (u8)opt->val;
741 		} else if (!strcmp(opt->mb, "ofs_in_node")) {
742 			MSG(0, "Info: inject summary entry ofs_in_node of "
743 			    "block 0x%x: %d -> %d\n", opt->blk,
744 			    sum->ofs_in_node, (u16)opt->val);
745 			sum->ofs_in_node = cpu_to_le16((u16)opt->val);
746 		} else {
747 			ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb);
748 			ret = -EINVAL;
749 			goto out;
750 		}
751 
752 		print_raw_sum_entry_info(sum);
753 	}
754 
755 	print_sum_footer_info(footer);
756 
757 	ssa_blkaddr = GET_SUM_BLKADDR(sbi, segno);
758 	ret = dev_write_block(sum_blk, ssa_blkaddr, WRITE_LIFE_NONE);
759 	ASSERT(ret >= 0);
760 
761 out:
762 	if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA ||
763 	    type == SEG_TYPE_MAX)
764 		free(sum_blk);
765 	return ret;
766 }
767 
inject_inode(struct f2fs_sb_info * sbi,struct f2fs_node * node,struct inject_option * opt)768 static int inject_inode(struct f2fs_sb_info *sbi, struct f2fs_node *node,
769 			struct inject_option *opt)
770 {
771 	struct f2fs_inode *inode = &node->i;
772 
773 	if (!strcmp(opt->mb, "i_mode")) {
774 		MSG(0, "Info: inject inode i_mode of nid %u: 0x%x -> 0x%x\n",
775 		    opt->nid, le16_to_cpu(inode->i_mode), (u16)opt->val);
776 		inode->i_mode = cpu_to_le16((u16)opt->val);
777 	} else if (!strcmp(opt->mb, "i_advise")) {
778 		MSG(0, "Info: inject inode i_advise of nid %u: 0x%x -> 0x%x\n",
779 		    opt->nid, inode->i_advise, (u8)opt->val);
780 		inode->i_advise = (u8)opt->val;
781 	} else if (!strcmp(opt->mb, "i_inline")) {
782 		MSG(0, "Info: inject inode i_inline of nid %u: 0x%x -> 0x%x\n",
783 		    opt->nid, inode->i_inline, (u8)opt->val);
784 		inode->i_inline = (u8)opt->val;
785 	} else if (!strcmp(opt->mb, "i_links")) {
786 		MSG(0, "Info: inject inode i_links of nid %u: %u -> %u\n",
787 		    opt->nid, le32_to_cpu(inode->i_links), (u32)opt->val);
788 		inode->i_links = cpu_to_le32((u32)opt->val);
789 	} else if (!strcmp(opt->mb, "i_size")) {
790 		MSG(0, "Info: inject inode i_size of nid %u: %"PRIu64" -> %"PRIu64"\n",
791 		    opt->nid, le64_to_cpu(inode->i_size), (u64)opt->val);
792 		inode->i_size = cpu_to_le64((u64)opt->val);
793 	} else if (!strcmp(opt->mb, "i_blocks")) {
794 		MSG(0, "Info: inject inode i_blocks of nid %u: %"PRIu64" -> %"PRIu64"\n",
795 		    opt->nid, le64_to_cpu(inode->i_blocks), (u64)opt->val);
796 		inode->i_blocks = cpu_to_le64((u64)opt->val);
797 	} else if (!strcmp(opt->mb, "i_extra_isize")) {
798 		/* do not care if F2FS_EXTRA_ATTR is enabled */
799 		MSG(0, "Info: inject inode i_extra_isize of nid %u: %d -> %d\n",
800 		    opt->nid, le16_to_cpu(inode->i_extra_isize), (u16)opt->val);
801 		inode->i_extra_isize = cpu_to_le16((u16)opt->val);
802 	} else if (!strcmp(opt->mb, "i_inode_checksum")) {
803 		MSG(0, "Info: inject inode i_inode_checksum of nid %u: "
804 		    "0x%x -> 0x%x\n", opt->nid,
805 		    le32_to_cpu(inode->i_inode_checksum), (u32)opt->val);
806 		inode->i_inode_checksum = cpu_to_le32((u32)opt->val);
807 	} else if (!strcmp(opt->mb, "i_addr")) {
808 		/* do not care if it is inline data */
809 		if (opt->idx >= DEF_ADDRS_PER_INODE) {
810 			ERR_MSG("invalid index %u of i_addr[]\n", opt->idx);
811 			return -EINVAL;
812 		}
813 		MSG(0, "Info: inject inode i_addr[%d] of nid %u: "
814 		    "0x%x -> 0x%x\n", opt->idx, opt->nid,
815 		    le32_to_cpu(inode->i_addr[opt->idx]), (u32)opt->val);
816 		inode->i_addr[opt->idx] = cpu_to_le32((block_t)opt->val);
817 	} else if (!strcmp(opt->mb, "i_nid")) {
818 		if (opt->idx >= 5) {
819 			ERR_MSG("invalid index %u of i_nid[]\n", opt->idx);
820 			return -EINVAL;
821 		}
822 		MSG(0, "Info: inject inode i_nid[%d] of nid %u: "
823 		    "0x%x -> 0x%x\n", opt->idx, opt->nid,
824 		    le32_to_cpu(F2FS_INODE_I_NID(inode, opt->idx)),
825 		    (u32)opt->val);
826 		F2FS_INODE_I_NID(inode, opt->idx) = cpu_to_le32((nid_t)opt->val);
827 	} else {
828 		ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb);
829 		return -EINVAL;
830 	}
831 
832 	if (c.dbg_lv > 0)
833 		print_node_info(sbi, node, 1);
834 
835 	return 0;
836 }
837 
inject_index_node(struct f2fs_sb_info * sbi,struct f2fs_node * node,struct inject_option * opt)838 static int inject_index_node(struct f2fs_sb_info *sbi, struct f2fs_node *node,
839 			     struct inject_option *opt)
840 {
841 	struct direct_node *dn = &node->dn;
842 
843 	if (strcmp(opt->mb, "addr")) {
844 		ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb);
845 		return -EINVAL;
846 	}
847 
848 	if (opt->idx >= DEF_ADDRS_PER_BLOCK) {
849 		ERR_MSG("invalid index %u of nid/addr[]\n", opt->idx);
850 		return -EINVAL;
851 	}
852 
853 	MSG(0, "Info: inject node nid/addr[%d] of nid %u: 0x%x -> 0x%x\n",
854 	    opt->idx, opt->nid, le32_to_cpu(dn->addr[opt->idx]),
855 	    (block_t)opt->val);
856 	dn->addr[opt->idx] = cpu_to_le32((block_t)opt->val);
857 
858 	if (c.dbg_lv > 0)
859 		print_node_info(sbi, node, 1);
860 
861 	return 0;
862 }
863 
inject_node(struct f2fs_sb_info * sbi,struct inject_option * opt)864 static int inject_node(struct f2fs_sb_info *sbi, struct inject_option *opt)
865 {
866 	struct f2fs_super_block *sb = sbi->raw_super;
867 	struct node_info ni;
868 	struct f2fs_node *node_blk;
869 	struct node_footer *footer;
870 	int ret;
871 
872 	if (!IS_VALID_NID(sbi, opt->nid)) {
873 		ERR_MSG("Invalid nid %u range [%u:%"PRIu64"]\n", opt->nid, 0,
874 			NAT_ENTRY_PER_BLOCK *
875 			((get_sb(segment_count_nat) << 1) <<
876 			 sbi->log_blocks_per_seg));
877 		return -EINVAL;
878 	}
879 
880 	node_blk = calloc(F2FS_BLKSIZE, 1);
881 	ASSERT(node_blk);
882 
883 	get_node_info(sbi, opt->nid, &ni);
884 	ret = dev_read_block(node_blk, ni.blk_addr);
885 	ASSERT(ret >= 0);
886 	footer = F2FS_NODE_FOOTER(node_blk);
887 
888 	if (!strcmp(opt->mb, "nid")) {
889 		MSG(0, "Info: inject node footer nid of nid %u: %u -> %u\n",
890 		    opt->nid, le32_to_cpu(footer->nid), (u32)opt->val);
891 		footer->nid = cpu_to_le32((u32)opt->val);
892 	} else if (!strcmp(opt->mb, "ino")) {
893 		MSG(0, "Info: inject node footer ino of nid %u: %u -> %u\n",
894 		    opt->nid, le32_to_cpu(footer->ino), (u32)opt->val);
895 		footer->ino = cpu_to_le32((u32)opt->val);
896 	} else if (!strcmp(opt->mb, "flag")) {
897 		MSG(0, "Info: inject node footer flag of nid %u: "
898 		    "0x%x -> 0x%x\n", opt->nid, le32_to_cpu(footer->flag),
899 		    (u32)opt->val);
900 		footer->flag = cpu_to_le32((u32)opt->val);
901 	} else if (!strcmp(opt->mb, "cp_ver")) {
902 		MSG(0, "Info: inject node footer cp_ver of nid %u: "
903 		    "0x%"PRIx64" -> 0x%"PRIx64"\n", opt->nid, le64_to_cpu(footer->cp_ver),
904 		    (u64)opt->val);
905 		footer->cp_ver = cpu_to_le64((u64)opt->val);
906 	} else if (!strcmp(opt->mb, "next_blkaddr")) {
907 		MSG(0, "Info: inject node footer next_blkaddr of nid %u: "
908 		    "0x%x -> 0x%x\n", opt->nid,
909 		    le32_to_cpu(footer->next_blkaddr), (u32)opt->val);
910 		footer->next_blkaddr = cpu_to_le32((u32)opt->val);
911 	} else if (ni.nid == ni.ino) {
912 		ret = inject_inode(sbi, node_blk, opt);
913 	} else {
914 		ret = inject_index_node(sbi, node_blk, opt);
915 	}
916 	if (ret)
917 		goto out;
918 
919 	print_node_footer_info(footer);
920 
921 	/*
922 	 * if i_inode_checksum is injected, should call update_block() to
923 	 * avoid recalculate inode checksum
924 	 */
925 	if (ni.nid == ni.ino && strcmp(opt->mb, "i_inode_checksum"))
926 		ret = update_inode(sbi, node_blk, &ni.blk_addr);
927 	else
928 		ret = update_block(sbi, node_blk, &ni.blk_addr, NULL);
929 	ASSERT(ret >= 0);
930 
931 out:
932 	free(node_blk);
933 	return ret;
934 }
935 
find_dir_entry(struct f2fs_dentry_ptr * d,nid_t ino)936 static int find_dir_entry(struct f2fs_dentry_ptr *d, nid_t ino)
937 {
938 	struct f2fs_dir_entry *de;
939 	int slot = 0;
940 
941 	while (slot < d->max) {
942 		if (!test_bit_le(slot, d->bitmap)) {
943 			slot++;
944 			continue;
945 		}
946 
947 		de = &d->dentry[slot];
948 		if (le32_to_cpu(de->ino) == ino && de->hash_code != 0)
949 			return slot;
950 		if (de->name_len == 0) {
951 			slot++;
952 			continue;
953 		}
954 		slot += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
955 	}
956 
957 	return -ENOENT;
958 }
959 
inject_dentry(struct f2fs_sb_info * sbi,struct inject_option * opt)960 static int inject_dentry(struct f2fs_sb_info *sbi, struct inject_option *opt)
961 {
962 	struct node_info ni;
963 	struct f2fs_node *node_blk = NULL;
964 	struct f2fs_inode *inode;
965 	struct f2fs_dentry_ptr d;
966 	void *inline_dentry;
967 	struct f2fs_dentry_block *dent_blk = NULL;
968 	block_t addr = 0;
969 	void *buf = NULL;
970 	struct f2fs_dir_entry *dent = NULL;
971 	struct dnode_of_data dn;
972 	nid_t pino;
973 	int slot = -ENOENT, ret;
974 
975 	node_blk = malloc(F2FS_BLKSIZE);
976 	ASSERT(node_blk != NULL);
977 
978 	/* get child inode */
979 	get_node_info(sbi, opt->nid, &ni);
980 	ret = dev_read_block(node_blk, ni.blk_addr);
981 	ASSERT(ret >= 0);
982 	pino = le32_to_cpu(node_blk->i.i_pino);
983 
984 	/* get parent inode */
985 	get_node_info(sbi, pino, &ni);
986 	ret = dev_read_block(node_blk, ni.blk_addr);
987 	ASSERT(ret >= 0);
988 	inode = &node_blk->i;
989 
990 	/* find child dentry */
991 	if (inode->i_inline & F2FS_INLINE_DENTRY) {
992 		inline_dentry = inline_data_addr(node_blk);
993 		make_dentry_ptr(&d, node_blk, inline_dentry, 2);
994 		addr = ni.blk_addr;
995 		buf = node_blk;
996 
997 		slot = find_dir_entry(&d, opt->nid);
998 		if (slot >= 0)
999 			dent = &d.dentry[slot];
1000 	} else {
1001 		unsigned int level, dirlevel, nbucket;
1002 		unsigned long i, end;
1003 
1004 		level = le32_to_cpu(inode->i_current_depth);
1005 		dirlevel = le32_to_cpu(inode->i_dir_level);
1006 		nbucket = dir_buckets(level, dirlevel);
1007 		end = dir_block_index(level, dirlevel, nbucket) +
1008 						bucket_blocks(level);
1009 
1010 		dent_blk = malloc(F2FS_BLKSIZE);
1011 		ASSERT(dent_blk != NULL);
1012 
1013 		for (i = 0; i < end; i++) {
1014 			memset(&dn, 0, sizeof(dn));
1015 			set_new_dnode(&dn, node_blk, NULL, pino);
1016 			ret = get_dnode_of_data(sbi, &dn, i, LOOKUP_NODE);
1017 			if (ret < 0)
1018 				break;
1019 			addr = dn.data_blkaddr;
1020 			if (dn.inode_blk != dn.node_blk)
1021 				free(dn.node_blk);
1022 			if (addr == NULL_ADDR || addr == NEW_ADDR)
1023 				continue;
1024 			if (!f2fs_is_valid_blkaddr(sbi, addr, DATA_GENERIC)) {
1025 				MSG(0, "invalid blkaddr 0x%x at offset %lu\n",
1026 				    addr, i);
1027 				continue;
1028 			}
1029 			ret = dev_read_block(dent_blk, addr);
1030 			ASSERT(ret >= 0);
1031 
1032 			make_dentry_ptr(&d, node_blk, dent_blk, 1);
1033 			slot = find_dir_entry(&d, opt->nid);
1034 			if (slot >= 0) {
1035 				dent = &d.dentry[slot];
1036 				buf = dent_blk;
1037 				break;
1038 			}
1039 		}
1040 	}
1041 
1042 	if (slot < 0) {
1043 		ERR_MSG("dentry of ino %u not found\n", opt->nid);
1044 		ret = -ENOENT;
1045 		goto out;
1046 	}
1047 
1048 	if (!strcmp(opt->mb, "d_bitmap")) {
1049 		MSG(0, "Info: inject dentry bitmap of nid %u: 1 -> 0\n",
1050 		    opt->nid);
1051 		test_and_clear_bit_le(slot, d.bitmap);
1052 	} else if (!strcmp(opt->mb, "d_hash")) {
1053 		MSG(0, "Info: inject dentry d_hash of nid %u: "
1054 		    "0x%x -> 0x%x\n", opt->nid, le32_to_cpu(dent->hash_code),
1055 		    (u32)opt->val);
1056 		dent->hash_code = cpu_to_le32((u32)opt->val);
1057 	} else if (!strcmp(opt->mb, "d_ino")) {
1058 		MSG(0, "Info: inject dentry d_ino of nid %u: "
1059 		    "%u -> %u\n", opt->nid, le32_to_cpu(dent->ino),
1060 		    (nid_t)opt->val);
1061 		dent->ino = cpu_to_le32((nid_t)opt->val);
1062 	} else if (!strcmp(opt->mb, "d_ftype")) {
1063 		MSG(0, "Info: inject dentry d_type of nid %u: "
1064 		    "%d -> %d\n", opt->nid, dent->file_type,
1065 		    (u8)opt->val);
1066 		dent->file_type = (u8)opt->val;
1067 	} else {
1068 		ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb);
1069 		ret = -EINVAL;
1070 		goto out;
1071 	}
1072 
1073 	print_raw_dentry_info(dent);
1074 
1075 	if (inode->i_inline & F2FS_INLINE_DENTRY)
1076 		ret = update_inode(sbi, buf, &addr);
1077 	else
1078 		ret = update_block(sbi, buf, &addr, NULL);
1079 	ASSERT(ret >= 0);
1080 
1081 out:
1082 	free(node_blk);
1083 	free(dent_blk);
1084 	return ret;
1085 }
1086 
do_inject(struct f2fs_sb_info * sbi)1087 int do_inject(struct f2fs_sb_info *sbi)
1088 {
1089 	struct inject_option *opt = (struct inject_option *)c.private;
1090 	int ret = -EINVAL;
1091 
1092 	if (opt->sb >= 0)
1093 		ret = inject_sb(sbi, opt);
1094 	else if (opt->cp >= 0)
1095 		ret = inject_cp(sbi, opt);
1096 	else if (opt->nat >= 0)
1097 		ret = inject_nat(sbi, opt);
1098 	else if (opt->sit >= 0)
1099 		ret = inject_sit(sbi, opt);
1100 	else if (opt->ssa)
1101 		ret = inject_ssa(sbi, opt);
1102 	else if (opt->node)
1103 		ret = inject_node(sbi, opt);
1104 	else if (opt->dent)
1105 		ret = inject_dentry(sbi, opt);
1106 
1107 	return ret;
1108 }
1109