int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name, struct inode *inode, nid_t ino, umode_t mode) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct page *ipage; unsigned int bit_pos; f2fs_hash_t name_hash; size_t namelen = name->len; struct f2fs_inline_dentry *dentry_blk = NULL; struct f2fs_dentry_ptr d; int slots = GET_DENTRY_SLOTS(namelen); struct page *page = NULL; int err = 0; ipage = get_node_page(sbi, dir->i_ino); if (IS_ERR(ipage)) return PTR_ERR(ipage); dentry_blk = inline_data_addr(ipage); bit_pos = room_for_filename(&dentry_blk->dentry_bitmap, slots, NR_INLINE_DENTRY); if (bit_pos >= NR_INLINE_DENTRY) { err = f2fs_convert_inline_dir(dir, ipage, dentry_blk); if (err) return err; err = -EAGAIN; goto out; } if (inode) { down_write(&F2FS_I(inode)->i_sem); page = init_inode_metadata(inode, dir, name, ipage); if (IS_ERR(page)) { err = PTR_ERR(page); goto fail; } } f2fs_wait_on_page_writeback(ipage, NODE, true); name_hash = f2fs_dentry_hash(name); make_dentry_ptr(NULL, &d, (void *)dentry_blk, 2); f2fs_update_dentry(ino, mode, &d, name, name_hash, bit_pos); set_page_dirty(ipage); /* we don't need to mark_inode_dirty now */ if (inode) { f2fs_i_pino_write(inode, dir->i_ino); f2fs_put_page(page, 1); } update_parent_metadata(dir, inode, 0); fail: if (inode) up_write(&F2FS_I(inode)->i_sem); out: f2fs_put_page(ipage, 1); return err; }
/* * f2fs_add_link - Add a new file(dir) to parent dir. */ int f2fs_add_link(struct f2fs_sb_info *sbi, struct f2fs_node *parent, const unsigned char *name, int name_len, nid_t ino, int file_type, block_t p_blkaddr, int inc_link) { int level = 0, current_depth, bit_pos; int nbucket, nblock, bidx, block; int slots = GET_DENTRY_SLOTS(name_len); f2fs_hash_t dentry_hash = f2fs_dentry_hash(name, name_len); struct f2fs_dentry_block *dentry_blk; struct f2fs_dentry_ptr d; struct dnode_of_data dn; nid_t pino = le32_to_cpu(parent->footer.ino); unsigned int dir_level = parent->i.i_dir_level; int ret; if (parent == NULL) return -EINVAL; if (!pino) { ERR_MSG("Wrong parent ino:%d \n", pino); return -EINVAL; } dentry_blk = calloc(BLOCK_SZ, 1); ASSERT(dentry_blk); current_depth = le32_to_cpu(parent->i.i_current_depth); start: if (current_depth == MAX_DIR_HASH_DEPTH) { free(dentry_blk); ERR_MSG("\tError: MAX_DIR_HASH\n"); return -ENOSPC; } /* Need a new dentry block */ if (level == current_depth) ++current_depth; nbucket = dir_buckets(level, dir_level); nblock = bucket_blocks(level); bidx = dir_block_index(level, dir_level, le32_to_cpu(dentry_hash) % nbucket); memset(&dn, 0, sizeof(dn)); for (block = bidx; block <= (bidx + nblock - 1); block++) { /* Firstly, we should know the direct node of target data blk */ if (dn.node_blk && dn.node_blk != dn.inode_blk) free(dn.node_blk); set_new_dnode(&dn, parent, NULL, pino); get_dnode_of_data(sbi, &dn, block, ALLOC_NODE); if (dn.data_blkaddr == NULL_ADDR) { new_data_block(sbi, dentry_blk, &dn, CURSEG_HOT_DATA); } else { ret = dev_read_block(dentry_blk, dn.data_blkaddr); ASSERT(ret >= 0); } bit_pos = room_for_filename(dentry_blk->dentry_bitmap, slots, NR_DENTRY_IN_BLOCK); if (bit_pos < NR_DENTRY_IN_BLOCK) goto add_dentry; } level ++; goto start; add_dentry: make_dentry_ptr(&d, NULL, (void *)dentry_blk, 1); f2fs_update_dentry(ino, file_type, &d, name, name_len, dentry_hash, bit_pos); ret = dev_write_block(dentry_blk, dn.data_blkaddr); ASSERT(ret >= 0); /* * Parent inode needs updating, because its inode info may be changed. * such as i_current_depth and i_blocks. */ if (parent->i.i_current_depth != cpu_to_le32(current_depth)) { parent->i.i_current_depth = cpu_to_le32(current_depth); dn.idirty = 1; } /* Update parent's i_links info*/ if (inc_link && (file_type == F2FS_FT_DIR)){ u32 links = le32_to_cpu(parent->i.i_links); parent->i.i_links = cpu_to_le32(links + 1); dn.idirty = 1; } if ((__u64)((block + 1) * F2FS_BLKSIZE) > le64_to_cpu(parent->i.i_size)) { parent->i.i_size = cpu_to_le64((block + 1) * F2FS_BLKSIZE); dn.idirty = 1; } if (dn.ndirty) { ret = dev_write_block(dn.node_blk, dn.node_blkaddr); ASSERT(ret >= 0); } if (dn.idirty) { ASSERT(parent == dn.inode_blk); ret = dev_write_block(dn.inode_blk, p_blkaddr); ASSERT(ret >= 0); } if (dn.node_blk != dn.inode_blk) free(dn.node_blk); free(dentry_blk); return 0; }
/* * Caller should grab and release a rwsem by calling f2fs_lock_op() and * f2fs_unlock_op(). */ int __f2fs_add_link(struct inode *dir, const struct qstr *name, struct inode *inode) { unsigned int bit_pos; unsigned int level; unsigned int current_depth; unsigned long bidx, block; f2fs_hash_t dentry_hash; unsigned int nbucket, nblock; size_t namelen = name->len; struct page *dentry_page = NULL; struct f2fs_dentry_block *dentry_blk = NULL; struct f2fs_dentry_ptr d; int slots = GET_DENTRY_SLOTS(namelen); struct page *page; int err = 0; if (f2fs_has_inline_dentry(dir)) { err = f2fs_add_inline_entry(dir, name, inode); if (!err || err != -EAGAIN) return err; else err = 0; } dentry_hash = f2fs_dentry_hash(name); level = 0; current_depth = F2FS_I(dir)->i_current_depth; if (F2FS_I(dir)->chash == dentry_hash) { level = F2FS_I(dir)->clevel; F2FS_I(dir)->chash = 0; } start: if (unlikely(current_depth == MAX_DIR_HASH_DEPTH)) return -ENOSPC; /* Increase the depth, if required */ if (level == current_depth) ++current_depth; nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level); nblock = bucket_blocks(level); bidx = dir_block_index(level, F2FS_I(dir)->i_dir_level, (le32_to_cpu(dentry_hash) % nbucket)); for (block = bidx; block <= (bidx + nblock - 1); block++) { dentry_page = get_new_data_page(dir, NULL, block, true); if (IS_ERR(dentry_page)) return PTR_ERR(dentry_page); dentry_blk = kmap(dentry_page); bit_pos = room_for_filename(&dentry_blk->dentry_bitmap, slots, NR_DENTRY_IN_BLOCK); if (bit_pos < NR_DENTRY_IN_BLOCK) goto add_dentry; kunmap(dentry_page); f2fs_put_page(dentry_page, 1); } /* Move to next level to find the empty slot for new dentry */ ++level; goto start; add_dentry: f2fs_wait_on_page_writeback(dentry_page, DATA); down_write(&F2FS_I(inode)->i_sem); page = init_inode_metadata(inode, dir, name, NULL); if (IS_ERR(page)) { err = PTR_ERR(page); goto fail; } make_dentry_ptr(&d, (void *)dentry_blk, 1); f2fs_update_dentry(inode, &d, name, dentry_hash, bit_pos); set_page_dirty(dentry_page); /* we don't need to mark_inode_dirty now */ F2FS_I(inode)->i_pino = dir->i_ino; update_inode(inode, page); f2fs_put_page(page, 1); update_parent_metadata(dir, inode, current_depth); fail: up_write(&F2FS_I(inode)->i_sem); if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) { update_inode_page(dir); clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); } kunmap(dentry_page); f2fs_put_page(dentry_page, 1); return err; }