F2FS格式化过程

10 篇文章 0 订阅
5 篇文章 2 订阅

f2fs_super_block:

struct f2fs_super_block {
    __le32 magic;           /* Magic Number */
    __le16 major_ver;       /* Major Version */
    __le16 minor_ver;       /* Minor Version */
    __le32 log_sectorsize;     
        /*
            //log2 sector size in bytes
            默认值是9,是512=2^9的幂数,是格式化工具的默认配置
        */
    __le32 log_sectors_per_block;  
        /*
            log2 # of sectors per block
            默认值是3是8=2^3,也是格式化工具的默认配置
        */
    __le32 log_blocksize;      
        /*
            //log2 block size in bytes
            该值由log_sectorsize+log_sectors_per_block=12,即9(512=2^9)+3(8=2^3)=12
        */
    __le32 log_blocks_per_seg; 
        /*
            //log2 # of blocks per segment
            默认值是9,是512=2^9的幂数,是格式化工具的默认配置
        */
    __le32 segs_per_sec;       
        /*
            //# of segments per section
            目前是1
        */
    __le32 secs_per_zone;      
        /*
            //# of sections per zone
            目前是1
        */
    __le32 checksum_offset;    
        /*
            //checksum offset inside super block
            目前是0
        */
    __le64 block_count;    
        /* 
            //total # of user blocks //
            block_count=(该分区大小/log_sectorsize(=512))>>log_sectors_per_block,相当于该分区有多少个page(page=4096)
        */
 
 
    __le32 section_count;      
        /*
            total # of sections
            section_count = segment_count - ( segment_count_ckpt+segment_count_sit+segment_count_nat+segment_count_ssa )
        */
    __le32 segment_count;      
        /*
            //total # of segments
            segment_count=(该分区大小-zone_align_start_offset)/ segment_size_bytes
            一个segment=512*block_size=512*4096=2M
        */
    __le32 segment_count_ckpt; 
        /*
            # of segments for checkpoint
            默认是2
        */
    __le32 segment_count_sit;  
        /*
            # of segments for SIT
            segment_count_sit = sit_segments * 2;
         
            #define SIZE_ALIGN(val, size)   ((val) + (size) - 1) / (size)
            #define SEG_ALIGN(blks)     SIZE_ALIGN(blks, c.blks_per_seg)
            #define SIT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_sit_entry)) =55
             
            //一个block可以存放55个struct f2fs_sit_entry,一个struct f2fs_sit_entry可以描述512个blcok也就是一个segment,所以这个公式计算出来的是总共segment_count需要多少个block去存放struct f2fs_sit_entry
            blocks_for_sit = SIZE_ALIGN(get_sb(segment_count), SIT_ENTRY_PER_BLOCK);
 
 
            //获得存储blocks_for_sit个block , 需要多少个segment
            sit_segments = SEG_ALIGN(blocks_for_sit);
             
            //由于需要一个备份所以*2
            segment_count_sit = sit_segments * 2;
        */
    __le32 segment_count_nat;  
        /*
            # of segments for NAT
            #define SIZE_ALIGN(val, size)   ((val) + (size) - 1) / (size)
            #define SEG_ALIGN(blks)     SIZE_ALIGN(blks, c.blks_per_seg)
            #define NAT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_nat_entry)) = 455
 
 
            //总segment_count segment个数 减去 已经被ckpt和sit占用的segment 就获得了总的还剩可用block个数
            total_valid_blks_available = (segment_count - (segment_count_ckpt + segment_count_sit)) * c.blks_per_seg;
 
            //一个block可以存放NAT_ENTRY_PER_BLOCK(455)个struct f2fs_nat_entry,而一个struct f2fs_nat_entry可以描述一个block的地址和属于哪个ino,
            //那么这个公式计算的就是描述total_valid_blks_available个block需要多少个block去存储struct f2fs_nat_entry
            blocks_for_nat = SIZE_ALIGN(total_valid_blks_available,NAT_ENTRY_PER_BLOCK);
             
            //转换为多少个segment,*2需要备份
            segment_count_nat=SEG_ALIGN(blocks_for_nat) * 2;
        */
    __le32 segment_count_ssa;  
 
 
        /*
            # of segments for SSA
 
 
            //剩余可用block总数
            total_valid_blks_available = (segment_count - (segment_count_ckpt + segment_count_sit + segment_count_nat)) * c.blks_per_seg;
 
            //存放SSA需要多少个block
            blocks_for_ssa = total_valid_blks_available / c.blks_per_seg + 1;
 
            //转换为segment
            segment_count_ssa = SEG_ALIGN(blocks_for_ssa);
        */
    __le32 segment_count_main; 
        /*
            # of segments for main area
             
            segment_count_main = section_count * segs_per_sec,一般情况下等于section_count
        */
    __le32 segment0_blkaddr;
        /*
            //start block address of segment 0//
            segment0_blkaddr = zone_align_start_offset / blk_size_bytes;
            blk_size_bytes=4096;
            F2FS_BLKSIZE=4096;
            目前c.start_sector=0,c.sector_size=512;
            zone_size_bytes = blk_size_bytes * c.secs_per_zone * c.segs_per_sec * c.blks_per_seg=4096*1*1*512;
            zone_align_start_offset = (c.start_sector * c.sector_size +2 * F2FS_BLKSIZE + zone_size_bytes - 1) /zone_size_bytes * zone_size_bytes -c.start_sector * c.sector_size;
            zone_align_start_offset=4096*512;
            segment0_blkaddr = 512 = 0x200;
        */
    __le32 cp_blkaddr;
        /*
            start block address of checkpoint
            cp_blkaddr= segment0_blkaddr
        */     
    __le32 sit_blkaddr;    
        /*
            //start block address of SIT
            sit_blkaddr = segment0_blkaddr + segment_count_ckpt * blks_per_seg=512 + 2 * 512 = 0x600
        */
    __le32 nat_blkaddr;    
        /*
            start block address of NAT
            nat_blkaddr = sit_blkaddr + segment_count_sit * blks_per_seg = 0x600 + 2 * 512 = 0xA00
        */
    __le32 ssa_blkaddr;    
        /*
            start block address of SSA
 
 
            ssa_blkaddr = nat_blkaddr + segment_count_nat * c.blks_per_seg = 0xA00 + 2 * 512 = 0xE00           
        */
    __le32 main_blkaddr;       
        /*
            start block address of main area
            total_meta_zones=segment_count_ckpt+segment_count_sit+segment_count_nat+segment_count_ssa,即元数据segment总和
            main_blkaddr=segment0_blkaddr + total_meta_zones *c.segs_per_zone * c.blks_per_seg;
        */
    __le32 root_ino;       
        /*
            root inode number
            默认值是3
        */
    __le32 node_ino;       
        /*
            node inode number
            默认值是1
        */
    __le32 meta_ino;       
        /*
            meta inode number
            默认值是2
        */
    __u8 uuid[16];          /* 128-bit uuid for volume */
    __le16 volume_name[MAX_VOLUME_NAME];    /* volume name */
    __le32 extension_count;     /* # of extensions below */
    __u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */
    __le32 cp_payload;
        /*
            目前是0 ,用来扩展ckpt , 当分区非常大的时候
        */
    __u8 version[VERSION_LEN];  /* the kernel version */
    __u8 init_version[VERSION_LEN]; /* the initial kernel version */
    __le32 feature;         /* defined features */
    __u8 encryption_level;      /* versioning level for encryption */
    __u8 encrypt_pw_salt[16];   /* Salt used for string2key algorithm */
    struct f2fs_device devs[MAX_DEVICES];   /* device list */
    __le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */
    __u8 reserved[315];     /* valid reserved region */
} __attribute__((packed));

SIT初始化生成:

int f2fs_format_device(void)
{
    //初始化、计算、填充struct f2fs_super_block成员
    err= f2fs_prepare_super_block();
    //是否支持trim
    err = f2fs_trim_devices();
     
    //把sit区域填充0
    err = f2fs_init_sit_area();
    //把nat区域填充0
    err = f2fs_init_nat_area();
     
    err = f2fs_create_root_dir();
     
    err = f2fs_write_check_point_pack();
     
    err = f2fs_write_super_block();
     
    return err;
}

f2fs_prepare_super_block():

static inline double get_best_overprovision(struct f2fs_super_block *sb)
{
    double reserved, ovp, candidate, end, diff, space;
    double max_ovp = 0, max_space = 0;
 
    if (get_sb(segment_count_main) < 256) {
        candidate = 10;
        end = 95;
        diff = 5;
    } else {
        candidate = 0.01;
        end = 10;
        diff = 0.01;
    }
 
    for (; candidate <= end; candidate += diff) {
        reserved = (2 * (100 / candidate + 1) + 6) *get_sb(segs_per_sec);
        ovp = (get_sb(segment_count_main) - reserved) * candidate / 100;
        space = get_sb(segment_count_main) - reserved - ovp;
 
        if (max_space < space) {
            max_space = space;
            max_ovp = candidate;
        }
    }
    return max_ovp;
}

在这里插入图片描述

static int f2fs_create_root_dir(void)
{
    /*
        创建根inode,并初始化
        struct f2fs_node *raw_node = calloc(F2FS_BLKSIZE, 1);
        raw_node->footer.nid = sb->root_ino;
        raw_node->footer.ino = sb->root_ino;
        //计算下一个block地址
        raw_node->footer.next_blkaddr = cpu_to_le32(get_sb(main_blkaddr) +c.cur_seg[CURSEG_HOT_NODE] *c.blks_per_seg + 1);
        ....
        //计算root note数组存储地址
        data_blk_nor = get_sb(main_blkaddr) + c.cur_seg[CURSEG_HOT_DATA] * c.blks_per_seg;
        raw_node->i.i_addr[get_extra_isize(raw_node)] = cpu_to_le32(data_blk_nor);
        ....
        //计算root inode存储偏移位置
        main_area_node_seg_blk_offset = get_sb(main_blkaddr);
        main_area_node_seg_blk_offset += c.cur_seg[CURSEG_HOT_NODE] *c.blks_per_seg;
        偏移main_area_node_seg_blk_offset大小,以一个page大小把struct f2fs_node写入磁盘
        dev_write_block(raw_node, main_area_node_seg_blk_offset);
    */
    err = f2fs_write_root_inode();
 
    //类似root inode 创建qf inode 并初始化 写入磁盘指定位置
    err = f2fs_write_qf_inode(qtype);
     
    /*
        创建struct f2fs_nat_block 并初始化 写入磁盘指定位置
        struct f2fs_nat_block *nat_blk = calloc(F2FS_BLKSIZE, 1);
        /* update root */
        //前面已经初始化并写入磁盘了,所以block_addr位置已经固定了
        nat_blk->entries[get_sb(root_ino)].block_addr = cpu_to_le32(get_sb(main_blkaddr) +c.cur_seg[CURSEG_HOT_NODE] * c.blks_per_seg);
        nat_blk->entries[get_sb(root_ino)].ino = sb->root_ino;
 
        /* update node nat */
        nat_blk->entries[get_sb(node_ino)].block_addr = cpu_to_le32(1);
        nat_blk->entries[get_sb(node_ino)].ino = sb->node_ino;
 
        /* update meta nat */
        nat_blk->entries[get_sb(meta_ino)].block_addr = cpu_to_le32(1);
        nat_blk->entries[get_sb(meta_ino)].ino = sb->meta_ino;
 
        nat_seg_blk_offset = get_sb(nat_blkaddr);
        //指定位置写入struct f2fs_nat_block
        dev_write_block(nat_blk, nat_seg_blk_offset);
    */
    err = f2fs_update_nat_root();
 
    /*
        创建根目录项‘.’ 和 ‘..’,并初始化 写入磁盘指定位置
        struct f2fs_dentry_block * dent_blk = calloc(F2FS_BLKSIZE, 1);
        dent_blk->dentry[0].hash_code = 0;
        dent_blk->dentry[0].ino = sb->root_ino;
        dent_blk->dentry[0].name_len = cpu_to_le16(1);
        dent_blk->dentry[0].file_type = F2FS_FT_DIR;
        memcpy(dent_blk->filename[0], ".", 1);
 
        dent_blk->dentry[1].hash_code = 0;
        dent_blk->dentry[1].ino = sb->root_ino;
        dent_blk->dentry[1].name_len = cpu_to_le16(2);
        dent_blk->dentry[1].file_type = F2FS_FT_DIR;
        memcpy(dent_blk->filename[1], "..", 2);
 
        /* bitmap for . and .. */
        //设置位图
        test_and_set_bit_le(0, dent_blk->dentry_bitmap);
        test_and_set_bit_le(1, dent_blk->dentry_bitmap);
 
        //计算写入位置
        data_blk_offset = get_sb(main_blkaddr);
        data_blk_offset += c.cur_seg[CURSEG_HOT_DATA] * c.blks_per_seg;
        dev_write_block(dent_blk, data_blk_offset);
    */
    err = f2fs_add_default_dentry_root();
 
 
}

在这里插入图片描述

static int f2fs_write_check_point_pack(void)
{
    //分配struct f2fs_checkpoint , 并初始化 ,写入指定位置
    struct f2fs_checkpoint *cp = calloc(F2FS_BLKSIZE, 1);
 
 
    //设置版本号 用于恢复
    cp->checkpoint_ver = cpu_to_le64(rand() | 0x1);
 
 
    //设置node 、 data 的segment number
    set_cp(cur_node_segno[0], c.cur_seg[CURSEG_HOT_NODE]);
    set_cp(cur_node_segno[1], c.cur_seg[CURSEG_WARM_NODE]);
    set_cp(cur_node_segno[2], c.cur_seg[CURSEG_COLD_NODE]);
    set_cp(cur_data_segno[0], c.cur_seg[CURSEG_HOT_DATA]);
    set_cp(cur_data_segno[1], c.cur_seg[CURSEG_WARM_DATA]);
    set_cp(cur_data_segno[2], c.cur_seg[CURSEG_COLD_DATA]);
    for (i = 3; i < MAX_ACTIVE_NODE_LOGS; i++)
    {
        set_cp(cur_node_segno[i], 0xffffffff);
        set_cp(cur_data_segno[i], 0xffffffff);
    }
 
 
    //设置node 、 data的block offset 地址
    set_cp(cur_node_blkoff[0], 1 + quota_inum);
    set_cp(cur_data_blkoff[0], 1 + quota_dnum);
 
 
    //设置有效的block数量
    set_cp(valid_block_count, 2 + quota_inum + quota_dnum);
 
 
    //设置保留的segment数量
    set_cp(rsvd_segment_count, c.reserved_segments);
 
 
    //设置预留的segment数量
    set_cp(overprov_segment_count, (get_sb(segment_count_main) - get_cp(rsvd_segment_count)) * c.overprovision / 100);
    set_cp(overprov_segment_count, get_cp(overprov_segment_count) +get_cp(rsvd_segment_count));
    /* main segments - reserved segments - (node + data segments) */
    set_cp(free_segment_count, get_sb(segment_count_main) - 6);
    set_cp(user_block_count, ((get_cp(free_segment_count) + 6 -get_cp(overprov_segment_count)) * c.blks_per_seg));
    /* cp page (2), data summaries (1), node summaries (3) */
    set_cp(cp_pack_total_block_count, 6 + get_sb(cp_payload));
     
    //设置ckpt flag
    set_cp(ckpt_flags, flags);
 
 
     
    set_cp(cp_pack_start_sum, 1 + get_sb(cp_payload));
    set_cp(valid_node_count, 1 + quota_inum);
    set_cp(valid_inode_count, 1 + quota_inum);
    set_cp(next_free_nid, get_sb(root_ino) + 1 + quota_inum);
 
 
    //segment_count_sit或者segment_count_nat数量的segment 需要多少bit位来表示,并换算为byte
    set_cp(sit_ver_bitmap_bytesize, ((get_sb(segment_count_sit) / 2) << get_sb(log_blocks_per_seg)) / 8);
    set_cp(nat_ver_bitmap_bytesize, ((get_sb(segment_count_nat) / 2) << get_sb(log_blocks_per_seg)) / 8);
 
    set_cp(checksum_offset, CHECKSUM_OFFSET);
 
 
    //计算cp写入位置
    cp_seg_blk = get_sb(segment0_blkaddr);
 
 
    //cp page 1
    //指定位置写入struct f2fs_checkpoint
    dev_write_block(cp, cp_seg_blk);
 
 
 
 
    /* Prepare and write Segment summary for HOT/WARM/COLD DATA
     *
     * The structure of compact summary
     * +-------------------+
     * | nat_journal       |
     * +-------------------+
     * | sit_journal       |
     * +-------------------+
     * | hot data summary  |
     * +-------------------+
     * | warm data summary |
     * +-------------------+
     * | cold data summary |
     * +-------------------+
    */
 
 
    memset(sum, 0, sizeof(struct f2fs_summary_block));
    SET_SUM_TYPE((&sum->footer), SUM_TYPE_DATA);
    //nat for root
    journal = &sum->journal;
    journal->n_nats = cpu_to_le16(1 + quota_inum);
    journal->nat_j.entries[0].nid = sb->root_ino;
    journal->nat_j.entries[0].ne.version = 0;
    journal->nat_j.entries[0].ne.ino = sb->root_ino;
    journal->nat_j.entries[0].ne.block_addr = cpu_to_le32(get_sb(main_blkaddr) +get_cp(cur_node_segno[0]) * c.blks_per_seg);
 
 
    memset(sum, 0, sizeof(struct f2fs_summary_block));
    /* inode sit for root */
    journal->n_sits = cpu_to_le16(6);
    journal->sit_j.entries[0].segno = cp->cur_node_segno[0];
    journal->sit_j.entries[0].se.vblocks = cpu_to_le16((CURSEG_HOT_NODE << 10) | (1 + quota_inum));
    f2fs_set_bit(0, (char *)journal->sit_j.entries[0].se.valid_map);
     
    for (i = 1; i <= quota_inum; i++)
        f2fs_set_bit(i, (char *)journal->sit_j.entries[0].se.valid_map);
     
    journal->sit_j.entries[1].segno = cp->cur_node_segno[1];
    journal->sit_j.entries[1].se.vblocks = cpu_to_le16((CURSEG_WARM_NODE << 10));
     
    journal->sit_j.entries[2].segno = cp->cur_node_segno[2];
    journal->sit_j.entries[2].se.vblocks = cpu_to_le16((CURSEG_COLD_NODE << 10));
 
 
    /* data sit for root */
    journal->sit_j.entries[3].segno = cp->cur_data_segno[0];
    journal->sit_j.entries[3].se.vblocks = cpu_to_le16((CURSEG_HOT_DATA << 10) | (1 + quota_dnum));
    f2fs_set_bit(0, (char *)journal->sit_j.entries[3].se.valid_map);
     
    for (i = 1; i <= quota_dnum; i++)
        f2fs_set_bit(i, (char *)journal->sit_j.entries[3].se.valid_map);
 
    journal->sit_j.entries[4].segno = cp->cur_data_segno[1];
    journal->sit_j.entries[4].se.vblocks = cpu_to_le16((CURSEG_WARM_DATA << 10));
     
    journal->sit_j.entries[5].segno = cp->cur_data_segno[2];
    journal->sit_j.entries[5].se.vblocks = cpu_to_le16((CURSEG_COLD_DATA << 10));
 
    memcpy(sum_compact_p, &journal->n_sits, SUM_JOURNAL_SIZE);
    sum_compact_p += SUM_JOURNAL_SIZE;
 
 
    /* hot data summary */
    sum_entry = (struct f2fs_summary *)sum_compact_p;
    sum_entry->nid = sb->root_ino;
    sum_entry->ofs_in_node = 0;
 
 
    dev_write_block(sum_compact, cp_seg_blk);
 
 
    /* Prepare and write Segment summary for HOT_NODE */
    memset(sum, 0, sizeof(struct f2fs_summary_block));
    SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
 
    sum->entries[0].nid = sb->root_ino;
    sum->entries[0].ofs_in_node = 0;
    dev_write_block(sum, cp_seg_blk);
 
 
    /* Fill segment summary for WARM_NODE to zero. */
    memset(sum, 0, sizeof(struct f2fs_summary_block));
    SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
    dev_write_block(sum, cp_seg_blk);
 
 
    /* Fill segment summary for COLD_NODE to zero. */
    memset(sum, 0, sizeof(struct f2fs_summary_block));
    SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
    dev_write_block(sum, cp_seg_blk);
 
 
    /* cp page2 */
    dev_write_block(cp, cp_seg_blk);
     
 
 
    /* write NAT bits, if possible */
    for (i = 0; i < nat_bits_blocks; i++)
        dev_write_block(nat_bits + i *F2FS_BLKSIZE, cp_seg_blk + i);
 
 
    /* cp page 1 of check point pack 2
     * Initiatialize other checkpoint pack with version zero
     */
    cp->checkpoint_ver = 0;
    cp_seg_blk = get_sb(segment0_blkaddr) + c.blks_per_seg;
    dev_write_block(cp, cp_seg_blk);
 
 
    /* cp page 2 of check point pack 2 */
    cp_seg_blk += (le32_to_cpu(cp->cp_pack_total_block_count) -get_sb(cp_payload) - 1);
 
 
    dev_write_block(cp, cp_seg_blk);
 
 
}
#define F2FS_SUPER_OFFSET       1024    /* byte-size offset */
static int f2fs_write_super_block(void)
{
    u_int8_t *zero_buff;
    zero_buff = calloc(F2FS_BLKSIZE, 1);
    memcpy(zero_buff + F2FS_SUPER_OFFSET, sb, sizeof(*sb));
     
    for (index = 0; index < 2; index++)
        dev_write_block(zero_buff, index);
     
}

在这里插入图片描述

在Oracle数据库中,可以使用SUBSTR函数来截取字符串。该函数的语法是:SUBSTR(string, position, [, length]),其中string是要截取的字符串,position是要开始截取的位置,length是要截取的字符长度(可选)。 举个例子,我们可以使用SUBSTR函数从字符串中截取子字符串: SUBSTR('Hello, world!', 8) -- 返回'world!' 在上述例子中,从第8个字符开始截取到字符串的末尾。 如果我们想截取指定长度的子字符串,可以在函数中传入第三个参数length: SUBSTR('Hello, world!', 7, 5) -- 返回'world' 这样,就会从第7个字符开始截取5个字符。 另外,如果我们想要截取字符串中子字符串的第n次出现后的部分,可以结合使用INSTR函数和SUBSTR函数[2]。 INSTR函数用于检索子字符串在字符串中的位置,语法为:INSTR(string, substring [, start_position [, occurrence]])。 举个例子,我们可以使用INSTR函数找到子字符串在字符串中的位置,然后结合SUBSTR函数来截取子字符串之后的内容: SUBSTR('11.123.1234.12345', INSTR('11.123.1234.12345', '.', 1, 2) + 1) -- 返回'1234.12345' 在上述例子中,INSTR函数找到了第二个点号的位置,在此基础上使用SUBSTR函数将第二个点号之后的内容截取出来。 综上所述,Oracle数据库可以使用SUBSTR函数来截取字符串,同时可以结合使用INSTR函数来定位特定子字符串的位置并进行截取。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [oracle数据库截取字符串](https://download.csdn.net/download/chenmig7583/5170223)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Oracle 字符串截取的几方式](https://blog.csdn.net/qq_43040552/article/details/103734545)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值