static void page_symlink(struct f2fs_sb_info *sbi, struct f2fs_node *inode, const char *symname, int symlen) { nid_t ino = le32_to_cpu(inode->footer.ino); struct f2fs_summary sum; struct node_info ni; char *data_blk; block_t blkaddr = NULL_ADDR; int ret; get_node_info(sbi, ino, &ni); /* store into inline_data */ if ((unsigned long)(symlen + 1) <= MAX_INLINE_DATA(inode)) { inode->i.i_inline |= F2FS_INLINE_DATA; inode->i.i_inline |= F2FS_DATA_EXIST; memcpy(inline_data_addr(inode), symname, symlen); return; } data_blk = calloc(BLOCK_SZ, 1); ASSERT(data_blk); memcpy(data_blk, symname, symlen); set_summary(&sum, ino, 0, ni.version); reserve_new_block(sbi, &blkaddr, &sum, CURSEG_WARM_DATA); ret = dev_write_block(data_blk, blkaddr); ASSERT(ret >= 0); inode->i.i_addr[get_extra_isize(inode)] = cpu_to_le32(blkaddr); free(data_blk); }
static void __recover_inline_status(struct inode *inode, struct page *ipage) { void *inline_data = inline_data_addr(inode, ipage); __le32 *start = inline_data; __le32 *end = start + MAX_INLINE_DATA(inode) / sizeof(__le32); while (start < end) { if (*start++) { f2fs_wait_on_page_writeback(ipage, NODE, true); set_inode_flag(inode, FI_DATA_EXIST); set_raw_inline(inode, F2FS_INODE(ipage)); set_page_dirty(ipage); return; } } return; }
int convert_inline_dentry(struct f2fs_sb_info *sbi, struct f2fs_node *node, block_t p_blkaddr) { struct f2fs_inode *inode = &(node->i); unsigned int dir_level = node->i.i_dir_level; nid_t ino = le32_to_cpu(node->footer.ino); char inline_data[MAX_INLINE_DATA(node)]; struct dnode_of_data dn; struct f2fs_dentry_ptr d; unsigned long bit_pos = 0; int ret = 0; if (!(inode->i_inline & F2FS_INLINE_DENTRY)) return 0; memcpy(inline_data, inline_data_addr(node), MAX_INLINE_DATA(node)); memset(inline_data_addr(node), 0, MAX_INLINE_DATA(node)); inode->i_inline &= ~F2FS_INLINE_DENTRY; ret = dev_write_block(node, p_blkaddr); ASSERT(ret >= 0); memset(&dn, 0, sizeof(dn)); if (!dir_level) { struct f2fs_dentry_block *dentry_blk; struct f2fs_dentry_ptr src, dst; dentry_blk = calloc(BLOCK_SZ, 1); ASSERT(dentry_blk); set_new_dnode(&dn, node, NULL, ino); get_dnode_of_data(sbi, &dn, 0, ALLOC_NODE); if (dn.data_blkaddr == NULL_ADDR) new_data_block(sbi, dentry_blk, &dn, CURSEG_HOT_DATA); make_dentry_ptr(&src, node, (void *)inline_data, 2); make_dentry_ptr(&dst, NULL, (void *)dentry_blk, 1); /* copy data from inline dentry block to new dentry block */ memcpy(dst.bitmap, src.bitmap, src.nr_bitmap); memset(dst.bitmap + src.nr_bitmap, 0, dst.nr_bitmap - src.nr_bitmap); memcpy(dst.dentry, src.dentry, SIZE_OF_DIR_ENTRY * src.max); memcpy(dst.filename, src.filename, src.max * F2FS_SLOT_LEN); ret = dev_write_block(dentry_blk, dn.data_blkaddr); ASSERT(ret >= 0); MSG(1, "%s: copy inline entry to block\n", __func__); free(dentry_blk); return ret; } make_empty_dir(sbi, node); make_dentry_ptr(&d, node, (void *)inline_data, 2); while (bit_pos < (unsigned long)d.max) { struct f2fs_dir_entry *de; const unsigned char *filename; int namelen; if (!test_bit_le(bit_pos, d.bitmap)) { bit_pos++; continue; } de = &d.dentry[bit_pos]; if (!de->name_len) { bit_pos++; continue; } filename = d.filename[bit_pos]; namelen = le32_to_cpu(de->name_len); if (is_dot_dotdot(filename, namelen)) { bit_pos += GET_DENTRY_SLOTS(namelen); continue; } ret = f2fs_add_link(sbi, node, filename, namelen, le32_to_cpu(de->ino), de->file_type, p_blkaddr, 0); if (ret) MSG(0, "Convert file \"%s\" ERR=%d\n", filename, ret); else MSG(1, "%s: add inline entry to block\n", __func__); bit_pos += GET_DENTRY_SLOTS(namelen); } return 0; }
static void init_inode_block(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk, struct dentry *de) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); mode_t mode = de->mode; int links = 1; unsigned int size; int blocks = 1; if (de->file_type == F2FS_FT_DIR) { mode |= S_IFDIR; size = 4096; links++; blocks++; } else if (de->file_type == F2FS_FT_REG_FILE) { mode |= S_IFREG; size = 0; } else if (de->file_type == F2FS_FT_SYMLINK) { ASSERT(de->link); mode |= S_IFLNK; size = strlen(de->link); if (size + 1 > MAX_INLINE_DATA(node_blk)) blocks++; } else { ASSERT(0); } node_blk->i.i_mode = cpu_to_le16(mode); node_blk->i.i_advise = 0; node_blk->i.i_uid = cpu_to_le32(de->uid); node_blk->i.i_gid = cpu_to_le32(de->gid); node_blk->i.i_links = cpu_to_le32(links); node_blk->i.i_size = cpu_to_le32(size); node_blk->i.i_blocks = cpu_to_le32(blocks); node_blk->i.i_atime = cpu_to_le64(de->mtime); node_blk->i.i_ctime = cpu_to_le64(de->mtime); node_blk->i.i_mtime = cpu_to_le64(de->mtime); node_blk->i.i_atime_nsec = 0; node_blk->i.i_ctime_nsec = 0; node_blk->i.i_mtime_nsec = 0; node_blk->i.i_generation = 0; node_blk->i.i_current_depth = cpu_to_le32(1); node_blk->i.i_xattr_nid = 0; node_blk->i.i_flags = 0; node_blk->i.i_inline = F2FS_INLINE_XATTR; node_blk->i.i_pino = cpu_to_le32(de->pino); node_blk->i.i_namelen = cpu_to_le32(de->len); memcpy(node_blk->i.i_name, de->name, de->len); node_blk->i.i_name[de->len] = 0; if (c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR)) { node_blk->i.i_inline |= F2FS_EXTRA_ATTR; node_blk->i.i_extra_isize = cpu_to_le16(F2FS_TOTAL_EXTRA_ATTR_SIZE); } node_blk->footer.ino = cpu_to_le32(de->ino); node_blk->footer.nid = cpu_to_le32(de->ino); node_blk->footer.flag = 0; node_blk->footer.cp_ver = ckpt->checkpoint_ver; if (S_ISDIR(mode)) make_empty_dir(sbi, node_blk); else if (S_ISLNK(mode)) page_symlink(sbi, node_blk, de->link, size); if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM)) node_blk->i.i_inode_checksum = cpu_to_le32(f2fs_inode_chksum(node_blk)); }