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