kernel是如何调用sbi里面的函数

本文详细阐述了OpenSBI0.9版本中kernel如何调用SBI(SimpleBootInterface)内部函数的过程。当发生Mmode异常时,控制流会进入Trap_HANDLER,经过汇编代码处理后调用C语言实现的sbi_trap_handler函数。该函数根据mcause寄存器的值执行相应的分支,特别是ECALL异常,会通过sbi_ecall_find_extension找到对应的扩展处理函数。在sbi_ecall_init中,各种异常处理函数被注册到ecall_exts_list链表中,以便后续调用。kernel通过sbi_ecall函数触发Mmode异常,调用预先注册的handler执行特定操作,如启动core等。
部署运行你感兴趣的模型镜像

本文以OpenSBI 0.9版本为参考进行讲解

现在分析kernel是如何调用sbi里面的函数的

  1. 在sbi的初始化过程中,在fw_base.S里面会设置M mode的异常处理函数:
    la a4, _trap_handler

    csrw CSR_MTVEC, a4
    设置完成后,只要发生M mode的异常就会进入到_trap_handler里面处理,
    _trap_handler这个函数在fw_base.S里面有定义,是汇编代码,实现了异常/中断调用的各个流程,
    _trap_handler:
    TRAP_SAVE_AND_SETUP_SP_T0

     TRAP_SAVE_MEPC_MSTATUS 0
    
     TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0
    
     TRAP_CALL_C_ROUTINE   --------------------------这里进入异常处理的c函数,也就是sbi_trap_handler
    
     TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
    
     TRAP_RESTORE_MEPC_MSTATUS 0
    
     TRAP_RESTORE_SP_T0
    
     mret
    

    sbi_trap_handler函数实现在/lib/sbi/sbi_trap.c里面。
    发生异常/中断的时候会进入到sbi_trap_handler函数,根据 mcause = csr_read(CSR_MCAUSE);
    的值,进入不同的处理分支,kernel下发的ecall会进入到:
    case CAUSE_SUPERVISOR_ECALL:
    case CAUSE_MACHINE_ECALL:
    rc = sbi_ecall_handler(regs);
    这里面,接着调用 sbi_ecall_find_extension(extension_id);
    struct sbi_ecall_extension *sbi_ecall_find_extension(unsigned long extid)
    {
    struct sbi_ecall_extension *t, *ret = NULL;

     	sbi_list_for_each_entry(t, &ecall_exts_list, head) {
     		if (t->extid_start <= extid && extid <= t->extid_end) {
     			ret = t;
     			break;
     		}
     	}
    
     	return ret;
     }
    

    通过extid获取到具体extension的handler,所有的异常处理在sbi初始化阶段,调用sbi_ecall_init
    的时候,全部注册在了ecall_exts_list里面。这个时候会从ecall_exts_list里面找到
    对应的handler。

  2. 以sbi_ecall_init()为例,介绍异常处理handler的处理过程
    2.1 注册了很多的异常回调handler
    int sbi_ecall_init(void)
    {
    int ret;

     	/* The order of below registrations is performance optimized */
     	ret = sbi_ecall_register_extension(&ecall_time);
     	if (ret)
     		return ret;
     	ret = sbi_ecall_register_extension(&ecall_rfence);
     	if (ret)
     		return ret;
     	ret = sbi_ecall_register_extension(&ecall_ipi);
     	if (ret)
     		return ret;
     	ret = sbi_ecall_register_extension(&ecall_base);
     	if (ret)
     		return ret;
     	ret = sbi_ecall_register_extension(&ecall_hsm);
     	if (ret)
     		return ret;
     	ret = sbi_ecall_register_extension(&ecall_srst);
     	if (ret)
     		return ret;
     	ret = sbi_ecall_register_extension(&ecall_legacy);
     	if (ret)
     		return ret;
     	ret = sbi_ecall_register_extension(&ecall_vendor);
     	if (ret)
     		return ret;
    
     	return 0;
     }
    

    2.2
    sbi_ecall_register_extension(&ecall_hsm);
    int sbi_ecall_register_extension(struct sbi_ecall_extension *ext)
    {
    struct sbi_ecall_extension *t;

     		if (!ext || (ext->extid_end < ext->extid_start) || !ext->handle)
     			return SBI_EINVAL;
    
     		sbi_list_for_each_entry(t, &ecall_exts_list, head) {
     			unsigned long start = t->extid_start;
     			unsigned long end = t->extid_end;
     			if (end < ext->extid_start || ext->extid_end < start)
     				/* no overlap */;
     			else
     				return SBI_EINVAL;
     		}
    
     		SBI_INIT_LIST_HEAD(&ext->head);
     		sbi_list_add_tail(&ext->head, &ecall_exts_list);
    
     		return 0;
     	}
     会把ecall_hsm放到ecall_exts_list链表里面,ecall_hsm里面有extid和具体的handler。
     struct sbi_ecall_extension ecall_hsm = {
     	.extid_start = SBI_EXT_HSM,
     	.extid_end = SBI_EXT_HSM,
     	.handle = sbi_ecall_hsm_handler,
     };
    

到这里,sbi中M mode的异常处理已经注册完成,这时候只要出发M mode的异常就会进入M mode,进入对应的handler。

  1. kernel是如何出发M mode的异常的:
    3.1
    在arch/riscv/kernel/sbi.c里面有sbi_ecall()调用函数,kernel可以通过sbi_ecall来出发M mode的异常处理。
    struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
    unsigned long arg1, unsigned long arg2,
    unsigned long arg3, unsigned long arg4,
    unsigned long arg5)
    {
    struct sbiret ret;

     	register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);
     	register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);
     	register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);
     	register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3);
     	register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4);
     	register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5);
     	register uintptr_t a6 asm ("a6") = (uintptr_t)(fid);
     	register uintptr_t a7 asm ("a7") = (uintptr_t)(ext);
     	asm volatile ("ecall"
     			  : "+r" (a0), "+r" (a1)
     			  : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
     			  : "memory");
     	ret.error = a0;
     	ret.value = a1;
    
     	return ret;
     }
    
     各种异常都是通过sbi_ecall来实现的,在sbi.c以及cpu_ops_sbi.c里面已经封装了各种的实现,
     如启动core的函数sbi_hsm_hart_start -> 
     sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_START, hartid, saddr, priv, 0, 0, 0);
     最终调用的就是sbi里面注册的ecall_hsm。
    

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

4463 static int f2fs_fill_super(struct super_block *sb, void *data, int silent) 4464 { 4465 struct f2fs_sb_info *sbi; 4466 struct f2fs_super_block *raw_super; 4467 struct inode *root; 4468 int err; 4469 bool skip_recovery = false, need_fsck = false; 4470 char *options = NULL; 4471 int recovery, i, valid_super_block; 4472 struct curseg_info *seg_i; 4473 int retry_cnt = 1; 4474 #ifdef CONFIG_QUOTA 4475 bool quota_enabled = false; 4476 #endif 4477 4478 try_onemore: 4479 err = -EINVAL; 4480 raw_super = NULL; 4481 valid_super_block = -1; 4482 recovery = 0; 4483 4484 /* allocate memory for f2fs-specific super block info */ 4485 sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL); 4486 if (!sbi) 4487 return -ENOMEM; 4488 4489 sbi->sb = sb; 4490 4491 /* initialize locks within allocated memory */ 4492 init_f2fs_rwsem(&sbi->gc_lock); 4493 mutex_init(&sbi->writepages); 4494 init_f2fs_rwsem(&sbi->cp_global_sem); 4495 init_f2fs_rwsem(&sbi->node_write); 4496 init_f2fs_rwsem(&sbi->node_change); 4497 spin_lock_init(&sbi->stat_lock); 4498 init_f2fs_rwsem(&sbi->cp_rwsem); 4499 init_f2fs_rwsem(&sbi->quota_sem); 4500 init_waitqueue_head(&sbi->cp_wait); 4501 spin_lock_init(&sbi->error_lock); 4502 4503 for (i = 0; i < NR_INODE_TYPE; i++) { 4504 INIT_LIST_HEAD(&sbi->inode_list[i]); 4505 spin_lock_init(&sbi->inode_lock[i]); 4506 } 4507 mutex_init(&sbi->flush_lock); 4508 4509 /* Load the checksum driver */ 4510 sbi->s_chksum_driver = crypto_alloc_shash("crc32", 0, 0); 4511 if (IS_ERR(sbi->s_chksum_driver)) { 4512 f2fs_err(sbi, "Cannot load crc32 driver."); 4513 err = PTR_ERR(sbi->s_chksum_driver); 4514 sbi->s_chksum_driver = NULL; 4515 goto free_sbi; 4516 } 4517 4518 /* set a block size */ 4519 if (unlikely(!sb_set_blocksize(sb, F2FS_BLKSIZE))) { 4520 f2fs_err(sbi, "unable to set blocksize"); 4521 goto free_sbi; 4522 } 4523 4524 err = read_raw_super_block(sbi, &raw_super, &valid_super_block, 4525 &recovery); 4526 if (err) 4527 goto free_sbi; 4528 4529 sb->s_fs_info = sbi; 4530 sbi->raw_super = raw_super; 4531 4532 INIT_WORK(&sbi->s_error_work, f2fs_record_error_work); 4533 memcpy(sbi->errors, raw_super->s_errors, MAX_F2FS_ERRORS); 4534 memcpy(sbi->stop_reason, raw_super->s_stop_reason, MAX_STOP_REASON); 4535 4536 /* precompute checksum seed for metadata */ 4537 if (f2fs_sb_has_inode_chksum(sbi)) 4538 sbi->s_chksum_seed = f2fs_chksum(sbi, ~0, raw_super->uuid, 4539 sizeof(raw_super->uuid)); 4540 4541 default_options(sbi, false); 4542 /* parse mount options */ 4543 options = kstrdup((const char *)data, GFP_KERNEL); 4544 if (data && !options) { 4545 err = -ENOMEM; 4546 goto free_sb_buf; 4547 } 4548 4549 err = parse_options(sb, options, false); 4550 if (err) 4551 goto free_options; 4552 4553 sb->s_maxbytes = max_file_blocks(NULL) << 4554 le32_to_cpu(raw_super->log_blocksize); 4555 sb->s_max_links = F2FS_LINK_MAX; 4556 4557 err = f2fs_setup_casefold(sbi); 4558 if (err) 4559 goto free_options; 4560 4561 #ifdef CONFIG_QUOTA 4562 sb->dq_op = &f2fs_quota_operations; 4563 sb->s_qcop = &f2fs_quotactl_ops; 4564 sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ; 4565 4566 if (f2fs_sb_has_quota_ino(sbi)) { 4567 for (i = 0; i < MAXQUOTAS; i++) { 4568 if (f2fs_qf_ino(sbi->sb, i)) 4569 sbi->nquota_files++; 4570 } 4571 } 4572 #endif 4573 4574 sb->s_op = &f2fs_sops; 4575 #ifdef CONFIG_FS_ENCRYPTION 4576 sb->s_cop = &f2fs_cryptops; 4577 #endif 4578 #ifdef CONFIG_FS_VERITY 4579 sb->s_vop = &f2fs_verityops; 4580 #endif 4581 sb->s_xattr = f2fs_xattr_handlers; 4582 sb->s_export_op = &f2fs_export_ops; 4583 sb->s_magic = F2FS_SUPER_MAGIC; 4584 sb->s_time_gran = 1; 4585 sb->s_flags = (sb->s_flags & ~SB_POSIXACL) | 4586 (test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0); 4587 memcpy(&sb->s_uuid, raw_super->uuid, sizeof(raw_super->uuid)); 4588 sb->s_iflags |= SB_I_CGROUPWB; 4589 4590 /* init f2fs-specific super block info */ 4591 sbi->valid_super_block = valid_super_block; 4592 4593 /* disallow all the data/node/meta page writes */ 4594 set_sbi_flag(sbi, SBI_POR_DOING); 4595 4596 err = f2fs_init_write_merge_io(sbi); 4597 if (err) 4598 goto free_bio_info; 4599 4600 init_sb_info(sbi); 4601 4602 err = f2fs_init_iostat(sbi); 4603 if (err) 4604 goto free_bio_info; 4605 4606 err = init_percpu_info(sbi); 4607 if (err) 4608 goto free_iostat; 4609 4610 /* init per sbi slab cache */ 4611 err = f2fs_init_xattr_caches(sbi); 4612 if (err) 4613 goto free_percpu; 4614 err = f2fs_init_page_array_cache(sbi); 4615 if (err) 4616 goto free_xattr_cache; 4617 4618 /* get an inode for meta space */ 4619 sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi)); 4620 if (IS_ERR(sbi->meta_inode)) { 4621 f2fs_err(sbi, "Failed to read F2FS meta data inode"); 4622 err = PTR_ERR(sbi->meta_inode); 4623 goto free_page_array_cache; 4624 } 4625 4626 err = f2fs_get_valid_checkpoint(sbi); 4627 if (err) { 4628 f2fs_err(sbi, "Failed to get valid F2FS checkpoint"); 4629 goto free_meta_inode; 4630 } 4631 4632 if (__is_set_ckpt_flags(F2FS_CKPT(sbi), CP_QUOTA_NEED_FSCK_FLAG)) 4633 set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); 4634 if (__is_set_ckpt_flags(F2FS_CKPT(sbi), CP_DISABLED_QUICK_FLAG)) { 4635 set_sbi_flag(sbi, SBI_CP_DISABLED_QUICK); 4636 sbi->interval_time[DISABLE_TIME] = DEF_DISABLE_QUICK_INTERVAL; 4637 } 4638 4639 if (__is_set_ckpt_flags(F2FS_CKPT(sbi), CP_FSCK_FLAG)) 4640 set_sbi_flag(sbi, SBI_NEED_FSCK); 4641 4642 /* Initialize device list */ 4643 err = f2fs_scan_devices(sbi); 4644 if (err) { 4645 f2fs_err(sbi, "Failed to find devices"); 4646 goto free_devices; 4647 } 4648 4649 err = f2fs_init_post_read_wq(sbi); 4650 if (err) { 4651 f2fs_err(sbi, "Failed to initialize post read workqueue"); 4652 goto free_devices; 4653 } 4654 4655 sbi->total_valid_node_count = 4656 le32_to_cpu(sbi->ckpt->valid_node_count); 4657 percpu_counter_set(&sbi->total_valid_inode_count, 4658 le32_to_cpu(sbi->ckpt->valid_inode_count)); 4659 sbi->user_block_count = le64_to_cpu(sbi->ckpt->user_block_count); 4660 sbi->total_valid_block_count = 4661 le64_to_cpu(sbi->ckpt->valid_block_count); 4662 sbi->last_valid_block_count = sbi->total_valid_block_count; 4663 sbi->reserved_blocks = 0; 4664 sbi->current_reserved_blocks = 0; 4665 limit_reserve_root(sbi); 4666 adjust_unusable_cap_perc(sbi); 4667 4668 f2fs_init_extent_cache_info(sbi); 4669 4670 f2fs_init_ino_entry_info(sbi); 4671 4672 f2fs_init_fsync_node_info(sbi); 4673 4674 /* setup checkpoint request control and start checkpoint issue thread */ 4675 f2fs_init_ckpt_req_control(sbi); 4676 if (!f2fs_readonly(sb) && !test_opt(sbi, DISABLE_CHECKPOINT) && 4677 test_opt(sbi, MERGE_CHECKPOINT)) { 4678 err = f2fs_start_ckpt_thread(sbi); 4679 if (err) { 4680 f2fs_err(sbi, 4681 "Failed to start F2FS issue_checkpoint_thread (%d)", 4682 err); 4683 goto stop_ckpt_thread; 4684 } 4685 } 4686 4687 /* setup f2fs internal modules */ 4688 err = f2fs_build_segment_manager(sbi); 4689 if (err) { 4690 f2fs_err(sbi, "Failed to initialize F2FS segment manager (%d)", 4691 err); 4692 goto free_sm; 4693 } 4694 err = f2fs_build_node_manager(sbi); 4695 if (err) { 4696 f2fs_err(sbi, "Failed to initialize F2FS node manager (%d)", 4697 err); 4698 goto free_nm; 4699 } 4700 4701 /* For write statistics */ 4702 sbi->sectors_written_start = f2fs_get_sectors_written(sbi); 4703 4704 /* Read accumulated write IO statistics if exists */ 4705 seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE); 4706 if (__exist_node_summaries(sbi)) 4707 sbi->kbytes_written = 4708 le64_to_cpu(seg_i->journal->info.kbytes_written); 4709 4710 f2fs_build_gc_manager(sbi); 4711 4712 err = f2fs_build_stats(sbi); 4713 if (err) 4714 goto free_nm; 4715 4716 /* get an inode for node space */ 4717 sbi->node_inode = f2fs_iget(sb, F2FS_NODE_INO(sbi)); 4718 if (IS_ERR(sbi->node_inode)) { 4719 f2fs_err(sbi, "Failed to read node inode"); 4720 err = PTR_ERR(sbi->node_inode); 4721 goto free_stats; 4722 } 4723 4724 /* read root inode and dentry */ 4725 root = f2fs_iget(sb, F2FS_ROOT_INO(sbi)); 4726 if (IS_ERR(root)) { 4727 f2fs_err(sbi, "Failed to read root inode"); 4728 err = PTR_ERR(root); 4729 goto free_node_inode; 4730 } 4731 if (!S_ISDIR(root->i_mode) || !root->i_blocks || 4732 !root->i_size || !root->i_nlink) { 4733 iput(root); 4734 err = -EINVAL; 4735 goto free_node_inode; 4736 } 4737 4738 sb->s_root = d_make_root(root); /* allocate root dentry */ 4739 if (!sb->s_root) { 4740 err = -ENOMEM; 4741 goto free_node_inode; 4742 } 4743 4744 err = f2fs_init_compress_inode(sbi); 4745 if (err) 4746 goto free_root_inode; 4747 4748 err = f2fs_register_sysfs(sbi); 4749 if (err) 4750 goto free_compress_inode; 4751 4752 #ifdef CONFIG_QUOTA 4753 /* Enable quota usage during mount */ 4754 if (f2fs_sb_has_quota_ino(sbi) && !f2fs_readonly(sb)) { 4755 err = f2fs_enable_quotas(sb); 4756 if (err) 4757 f2fs_err(sbi, "Cannot turn on quotas: error %d", err); 4758 } 4759 4760 quota_enabled = f2fs_recover_quota_begin(sbi); 4761 #endif 4762 /* if there are any orphan inodes, free them */ 4763 err = f2fs_recover_orphan_inodes(sbi); 4764 if (err) 4765 goto free_meta; 4766 4767 if (unlikely(is_set_ckpt_flags(sbi, CP_DISABLED_FLAG))) 4768 goto reset_checkpoint; 4769 4770 /* recover fsynced data */ 4771 if (!test_opt(sbi, DISABLE_ROLL_FORWARD) && 4772 !test_opt(sbi, NORECOVERY)) { 4773 /* 4774 * mount should be failed, when device has readonly mode, and 4775 * previous checkpoint was not done by clean system shutdown. 4776 */ 4777 if (f2fs_hw_is_readonly(sbi)) { 4778 if (!is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) { 4779 err = f2fs_recover_fsync_data(sbi, true); 4780 if (err > 0) { 4781 err = -EROFS; 4782 f2fs_err(sbi, "Need to recover fsync data, but " 4783 "write access unavailable, please try " 4784 "mount w/ disable_roll_forward or norecovery"); 4785 } 4786 if (err < 0) 4787 goto free_meta; 4788 } 4789 f2fs_info(sbi, "write access unavailable, skipping recovery"); 4790 goto reset_checkpoint; 4791 } 4792 4793 if (need_fsck) 4794 set_sbi_flag(sbi, SBI_NEED_FSCK); 4795 4796 if (skip_recovery) 4797 goto reset_checkpoint; 4798 4799 err = f2fs_recover_fsync_data(sbi, false); 4800 if (err < 0) { 4801 if (err != -ENOMEM) 4802 skip_recovery = true; 4803 need_fsck = true; 4804 f2fs_err(sbi, "Cannot recover all fsync data errno=%d", 4805 err); 4806 goto free_meta; 4807 } 4808 } else { 4809 err = f2fs_recover_fsync_data(sbi, true); 4810 4811 if (!f2fs_readonly(sb) && err > 0) { 4812 err = -EINVAL; 4813 f2fs_err(sbi, "Need to recover fsync data"); 4814 goto free_meta; 4815 } 4816 } 4817 4818 #ifdef CONFIG_QUOTA 4819 f2fs_recover_quota_end(sbi, quota_enabled); 4820 #endif 4821 reset_checkpoint: 4822 /* 4823 * If the f2fs is not readonly and fsync data recovery succeeds, 4824 * check zoned block devices' write pointer consistency. 4825 */ 4826 if (f2fs_sb_has_blkzoned(sbi) && !f2fs_readonly(sb)) { 4827 int err2; 4828 4829 f2fs_notice(sbi, "Checking entire write pointers"); 4830 err2 = f2fs_check_write_pointer(sbi); 4831 if (err2) 4832 err = err2; 4833 } 4834 if (err) 4835 goto free_meta; 4836 4837 err = f2fs_init_inmem_curseg(sbi); 4838 if (err) 4839 goto sync_free_meta; 4840 4841 /* f2fs_recover_fsync_data() cleared this already */ 4842 clear_sbi_flag(sbi, SBI_POR_DOING); 4843 4844 if (test_opt(sbi, DISABLE_CHECKPOINT)) { 4845 err = f2fs_disable_checkpoint(sbi); 4846 if (err) 4847 goto sync_free_meta; 4848 } else if (is_set_ckpt_flags(sbi, CP_DISABLED_FLAG)) { 4849 f2fs_enable_checkpoint(sbi); 4850 } 4851 4852 /* 4853 * If filesystem is not mounted as read-only then 4854 * do start the gc_thread. 4855 */ 4856 if ((F2FS_OPTION(sbi).bggc_mode != BGGC_MODE_OFF || 4857 test_opt(sbi, GC_MERGE)) && !f2fs_readonly(sb)) { 4858 /* After POR, we can run background GC thread.*/ 4859 err = f2fs_start_gc_thread(sbi); 4860 if (err) 4861 goto sync_free_meta; 4862 } 4863 kvfree(options); 4864 4865 /* recover broken superblock */ 4866 if (recovery) { 4867 err = f2fs_commit_super(sbi, true); 4868 f2fs_info(sbi, "Try to recover %dth superblock, ret: %d", 4869 sbi->valid_super_block ? 1 : 2, err); 4870 } 4871 4872 f2fs_join_shrinker(sbi); 4873 4874 f2fs_tuning_parameters(sbi); 4875 4876 f2fs_notice(sbi, "Mounted with checkpoint version = %llx", 4877 cur_cp_version(F2FS_CKPT(sbi))); 4878 f2fs_update_time(sbi, CP_TIME); 4879 f2fs_update_time(sbi, REQ_TIME); 4880 clear_sbi_flag(sbi, SBI_CP_DISABLED_QUICK); 4881 4882 cleancache_init_fs(sb); 4883 return 0; 4884 4885 sync_free_meta: 4886 /* safe to flush all the data */ 4887 sync_filesystem(sbi->sb); 4888 retry_cnt = 0; 4889 4890 free_meta: 4891 #ifdef CONFIG_QUOTA 4892 f2fs_truncate_quota_inode_pages(sb); 4893 if (f2fs_sb_has_quota_ino(sbi) && !f2fs_readonly(sb)) 4894 f2fs_quota_off_umount(sbi->sb); 4895 #endif 4896 /* 4897 * Some dirty meta pages can be produced by f2fs_recover_orphan_inodes() 4898 * failed by EIO. Then, iput(node_inode) can trigger balance_fs_bg() 4899 * followed by f2fs_write_checkpoint() through f2fs_write_node_pages(), which 4900 * falls into an infinite loop in f2fs_sync_meta_pages(). 4901 */ 4902 truncate_inode_pages_final(META_MAPPING(sbi)); 4903 /* evict some inodes being cached by GC */ 4904 evict_inodes(sb); 4905 f2fs_unregister_sysfs(sbi); 4906 free_compress_inode: 4907 f2fs_destroy_compress_inode(sbi); 4908 free_root_inode: 4909 dput(sb->s_root); 4910 sb->s_root = NULL; 4911 free_node_inode: 4912 f2fs_release_ino_entry(sbi, true); 4913 truncate_inode_pages_final(NODE_MAPPING(sbi)); 4914 iput(sbi->node_inode); 4915 sbi->node_inode = NULL; 4916 free_stats: 4917 f2fs_destroy_stats(sbi); 4918 free_nm: 4919 /* stop discard thread before destroying node manager */ 4920 f2fs_stop_discard_thread(sbi); 4921 f2fs_destroy_node_manager(sbi); 4922 free_sm: 4923 f2fs_destroy_segment_manager(sbi); 4924 stop_ckpt_thread: 4925 f2fs_stop_ckpt_thread(sbi); 4926 /* flush s_error_work before sbi destroy */ 4927 flush_work(&sbi->s_error_work); 4928 f2fs_destroy_post_read_wq(sbi); 4929 free_devices: 4930 destroy_device_list(sbi); 4931 kvfree(sbi->ckpt); 4932 free_meta_inode: 4933 make_bad_inode(sbi->meta_inode); 4934 iput(sbi->meta_inode); 4935 sbi->meta_inode = NULL; 4936 free_page_array_cache: 4937 f2fs_destroy_page_array_cache(sbi); 4938 free_xattr_cache: 4939 f2fs_destroy_xattr_caches(sbi); 4940 free_percpu: 4941 destroy_percpu_info(sbi); 4942 free_iostat: 4943 f2fs_destroy_iostat(sbi); 4944 free_bio_info: 4945 for (i = 0; i < NR_PAGE_TYPE; i++) 4946 kvfree(sbi->write_io[i]); 4947 4948 #if IS_ENABLED(CONFIG_UNICODE) 4949 utf8_unload(sb->s_encoding); 4950 sb->s_encoding = NULL; 4951 #endif 4952 free_options: 4953 #ifdef CONFIG_QUOTA 4954 for (i = 0; i < MAXQUOTAS; i++) 4955 kfree(F2FS_OPTION(sbi).s_qf_names[i]); 4956 #endif 4957 fscrypt_free_dummy_policy(&F2FS_OPTION(sbi).dummy_enc_policy); 4958 kvfree(options); 4959 free_sb_buf: 4960 kfree(raw_super); 4961 free_sbi: 4962 if (sbi->s_chksum_driver) 4963 crypto_free_shash(sbi->s_chksum_driver); 4964 kfree(sbi); 4965 sb->s_fs_info = NULL; 4966 4967 /* give only one another chance */ 4968 if (retry_cnt > 0 && skip_recovery) { 4969 retry_cnt--; 4970 shrink_dcache_sb(sb); 4971 goto try_onemore; 4972 } 4973 return err; 4974 } 4975
最新发布
06-18
### F2FS文件系统中 `f2fs_fill_super` 函数的实现细节解析 `f2fs_fill_super` 是 F2FS 文件系统挂载过程中一个关键函数,主要用于初始化超级块(super block)及相关数据结构。以下是该函数的主要实现细节和功能分解: #### 1. 超级块读取与校验 `f2fs_fill_super` 首先会从磁盘上读取超级块信息,并将其加载到内存中。超级块包含文件系统的元数据,例如段数、块大小等重要参数。在加载超级块后,会对超级块进行一系列的校验操作以确保其完整性。如果校验失败,则挂载过程将终止[^1]。 ```c struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); if (sanity_check_ckpt(sbi)) { return -EFSCORRUPTED; } ``` 上述代码片段展示了对超级块的校验逻辑,其中调用了 `sanity_check_ckpt` 函数来验证检查点信息是否有效。如果检查点中的保留段数量或其他字段超出合理范围,或者设置了错误标志(CP_ERROR_FLAG),则返回错误码 `-EFSCORRUPTED`[^3]。 #### 2. 元数据结构初始化 `f2fs_fill_super` 还负责初始化多个重要的元数据结构,这些结构用于管理文件系统的核心组件。主要包括以下几部分: - **SM(Segment Manager)初始化**:通过调用 `build_sm_info` 函数,初始化段管理器的数据结构,包括段位图、废弃块位图等[^4]。 - **SIT(Summary Information Table)初始化**:通过调用 `build_sit_info` 函数,分配并初始化 SIT 相关的数据结构,如段入口表(seg_entry)、当前有效位图(cur_valid_map)等[^4]。 - **NAT(Node Address Table)初始化**:通过调用 `build_node_manager` 函数,初始化节点地址表及其相关数据结构。 以下是 `build_sit_info` 的简化示例代码: ```c sit_info->sentries = kzalloc(sizeof(struct seg_entry) * total_segs, GFP_KERNEL); sit_info->cur_valid_map = kzalloc(BITS_TO_LONGS(total_segs) * sizeof(long), GFP_KERNEL); sit_info->ckpt_valid_map = kzalloc(BITS_TO_LONGS(total_segs) * sizeof(long), GFP_KERNEL); ``` #### 3. 文件系统状态恢复 在挂载过程中,`f2fs_fill_super` 会根据检查点(checkpoint)信息恢复文件系统状态。这包括重新构建未完成的操作记录、清理废弃块以及更新元数据。如果检测到文件系统处于不一致状态,则可能需要运行文件系统检查工具(fsck)[^3]。 #### 4. 挂载选项处理 `f2fs_fill_super` 还会解析用户提供的挂载选项(mount options),并根据这些选项调整文件系统的运行行为。例如,支持只读挂载、压缩功能启用等。 ```c if (test_opt(sb, DISABLE_EXTENT_CACHE)) sbi->sb->s_flags |= SB_NOEXT; ``` 上述代码片段展示了如何根据挂载选项禁用扩展缓存功能[^2]。 #### 5. 返回值与错误处理 如果所有初始化步骤均成功完成,则 `f2fs_fill_super` 返回指向根目录的 `dentry` 结构。否则,返回适当的错误码以指示挂载失败的原因。 --- ### 总结 `f2fs_fill_super` 是 F2FS 文件系统挂载过程的核心函数,主要负责超级块的加载与校验、元数据结构的初始化、文件系统状态的恢复以及挂载选项的处理。它确保了文件系统在挂载时能够正确初始化并进入可用状态。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值