1e18c65b2SHuajun Li /* 2e18c65b2SHuajun Li * fs/f2fs/inline.c 3e18c65b2SHuajun Li * Copyright (c) 2013, Intel Corporation 4e18c65b2SHuajun Li * Authors: Huajun Li <huajun.li@intel.com> 5e18c65b2SHuajun Li * Haicheng Li <haicheng.li@intel.com> 6e18c65b2SHuajun Li * This program is free software; you can redistribute it and/or modify 7e18c65b2SHuajun Li * it under the terms of the GNU General Public License version 2 as 8e18c65b2SHuajun Li * published by the Free Software Foundation. 9e18c65b2SHuajun Li */ 10e18c65b2SHuajun Li 11e18c65b2SHuajun Li #include <linux/fs.h> 12e18c65b2SHuajun Li #include <linux/f2fs_fs.h> 13e18c65b2SHuajun Li 14e18c65b2SHuajun Li #include "f2fs.h" 15e18c65b2SHuajun Li 16e18c65b2SHuajun Li bool f2fs_may_inline(struct inode *inode) 17e18c65b2SHuajun Li { 184081363fSJaegeuk Kim if (!test_opt(F2FS_I_SB(inode), INLINE_DATA)) 19e18c65b2SHuajun Li return false; 20e18c65b2SHuajun Li 2188b88a66SJaegeuk Kim if (f2fs_is_atomic_file(inode)) 2288b88a66SJaegeuk Kim return false; 2388b88a66SJaegeuk Kim 24b3d208f9SJaegeuk Kim if (!S_ISREG(inode->i_mode)) 25e18c65b2SHuajun Li return false; 26e18c65b2SHuajun Li 27e18c65b2SHuajun Li return true; 28e18c65b2SHuajun Li } 29e18c65b2SHuajun Li 30b3d208f9SJaegeuk Kim void read_inline_data(struct page *page, struct page *ipage) 31e18c65b2SHuajun Li { 32e18c65b2SHuajun Li void *src_addr, *dst_addr; 33e18c65b2SHuajun Li 34b3d208f9SJaegeuk Kim if (PageUptodate(page)) 35b3d208f9SJaegeuk Kim return; 3604a17fb1SChao Yu 37b3d208f9SJaegeuk Kim f2fs_bug_on(F2FS_P_SB(page), page->index); 38e18c65b2SHuajun Li 3918309aaaSChao Yu zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE); 40e18c65b2SHuajun Li 41e18c65b2SHuajun Li /* Copy the whole inline data block */ 42e18c65b2SHuajun Li src_addr = inline_data_addr(ipage); 43f1e33a04SJaegeuk Kim dst_addr = kmap_atomic(page); 44e18c65b2SHuajun Li memcpy(dst_addr, src_addr, MAX_INLINE_DATA); 45427a45c8SJaegeuk Kim flush_dcache_page(page); 46f1e33a04SJaegeuk Kim kunmap_atomic(dst_addr); 47e18c65b2SHuajun Li SetPageUptodate(page); 48b3d208f9SJaegeuk Kim } 49e18c65b2SHuajun Li 50b3d208f9SJaegeuk Kim int f2fs_read_inline_data(struct inode *inode, struct page *page) 51b3d208f9SJaegeuk Kim { 52b3d208f9SJaegeuk Kim struct page *ipage; 53b3d208f9SJaegeuk Kim 54b3d208f9SJaegeuk Kim ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino); 55b3d208f9SJaegeuk Kim if (IS_ERR(ipage)) { 56b3d208f9SJaegeuk Kim unlock_page(page); 57b3d208f9SJaegeuk Kim return PTR_ERR(ipage); 58b3d208f9SJaegeuk Kim } 59b3d208f9SJaegeuk Kim 60b3d208f9SJaegeuk Kim if (!f2fs_has_inline_data(inode)) { 61b3d208f9SJaegeuk Kim f2fs_put_page(ipage, 1); 62b3d208f9SJaegeuk Kim return -EAGAIN; 63b3d208f9SJaegeuk Kim } 64b3d208f9SJaegeuk Kim 65b3d208f9SJaegeuk Kim if (page->index) 66b3d208f9SJaegeuk Kim zero_user_segment(page, 0, PAGE_CACHE_SIZE); 67b3d208f9SJaegeuk Kim else 68b3d208f9SJaegeuk Kim read_inline_data(page, ipage); 69b3d208f9SJaegeuk Kim 70b3d208f9SJaegeuk Kim SetPageUptodate(page); 71b3d208f9SJaegeuk Kim f2fs_put_page(ipage, 1); 72b3d208f9SJaegeuk Kim unlock_page(page); 73e18c65b2SHuajun Li return 0; 74e18c65b2SHuajun Li } 75e18c65b2SHuajun Li 76b3d208f9SJaegeuk Kim int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page) 77e18c65b2SHuajun Li { 78e18c65b2SHuajun Li void *src_addr, *dst_addr; 79e18c65b2SHuajun Li block_t new_blk_addr; 80e18c65b2SHuajun Li struct f2fs_io_info fio = { 81e18c65b2SHuajun Li .type = DATA, 82e18c65b2SHuajun Li .rw = WRITE_SYNC | REQ_PRIO, 83e18c65b2SHuajun Li }; 84b3d208f9SJaegeuk Kim int err; 85e18c65b2SHuajun Li 86b3d208f9SJaegeuk Kim f2fs_bug_on(F2FS_I_SB(dn->inode), page->index); 87e18c65b2SHuajun Li 88b3d208f9SJaegeuk Kim if (!f2fs_exist_data(dn->inode)) 89b3d208f9SJaegeuk Kim goto clear_out; 90ec4e7af4SJaegeuk Kim 91b3d208f9SJaegeuk Kim err = f2fs_reserve_block(dn, 0); 9215c6e3aaSJaegeuk Kim if (err) 93b3d208f9SJaegeuk Kim return err; 94e18c65b2SHuajun Li 959ac1349aSJaegeuk Kim f2fs_wait_on_page_writeback(page, DATA); 96b3d208f9SJaegeuk Kim 97b3d208f9SJaegeuk Kim if (PageUptodate(page)) 98b3d208f9SJaegeuk Kim goto no_update; 99b3d208f9SJaegeuk Kim 10018309aaaSChao Yu zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE); 101e18c65b2SHuajun Li 102e18c65b2SHuajun Li /* Copy the whole inline data block */ 103b3d208f9SJaegeuk Kim src_addr = inline_data_addr(dn->inode_page); 104f1e33a04SJaegeuk Kim dst_addr = kmap_atomic(page); 105e18c65b2SHuajun Li memcpy(dst_addr, src_addr, MAX_INLINE_DATA); 106f1e33a04SJaegeuk Kim kunmap_atomic(dst_addr); 1079e09fc85SJaegeuk Kim SetPageUptodate(page); 108b3d208f9SJaegeuk Kim no_update: 109e18c65b2SHuajun Li /* write data page to try to make data consistent */ 110e18c65b2SHuajun Li set_page_writeback(page); 111b3d208f9SJaegeuk Kim 112b3d208f9SJaegeuk Kim write_data_page(page, dn, &new_blk_addr, &fio); 113b3d208f9SJaegeuk Kim update_extent_cache(new_blk_addr, dn); 1145514f0aaSYuan Zhong f2fs_wait_on_page_writeback(page, DATA); 115e18c65b2SHuajun Li 116e18c65b2SHuajun Li /* clear inline data and flag after data writeback */ 117b3d208f9SJaegeuk Kim truncate_inline_data(dn->inode_page, 0); 118b3d208f9SJaegeuk Kim clear_out: 119b3d208f9SJaegeuk Kim stat_dec_inline_inode(dn->inode); 120*57e2a2c0SJaegeuk Kim f2fs_clear_inline_inode(dn->inode); 121b3d208f9SJaegeuk Kim sync_inode_page(dn); 122b3d208f9SJaegeuk Kim f2fs_put_dnode(dn); 123b3d208f9SJaegeuk Kim return 0; 124e18c65b2SHuajun Li } 125e18c65b2SHuajun Li 126b3d208f9SJaegeuk Kim int f2fs_convert_inline_inode(struct inode *inode) 127e18c65b2SHuajun Li { 128b3d208f9SJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 129b3d208f9SJaegeuk Kim struct dnode_of_data dn; 130b3d208f9SJaegeuk Kim struct page *ipage, *page; 131b3d208f9SJaegeuk Kim int err = 0; 132e18c65b2SHuajun Li 133b3d208f9SJaegeuk Kim page = grab_cache_page(inode->i_mapping, 0); 134b3d208f9SJaegeuk Kim if (!page) 1359e09fc85SJaegeuk Kim return -ENOMEM; 136b3d208f9SJaegeuk Kim 137b3d208f9SJaegeuk Kim f2fs_lock_op(sbi); 138b3d208f9SJaegeuk Kim 139b3d208f9SJaegeuk Kim ipage = get_node_page(sbi, inode->i_ino); 140b3d208f9SJaegeuk Kim if (IS_ERR(ipage)) { 141b3d208f9SJaegeuk Kim f2fs_unlock_op(sbi); 142b3d208f9SJaegeuk Kim return PTR_ERR(ipage); 143b067ba1fSJaegeuk Kim } 144e18c65b2SHuajun Li 145b3d208f9SJaegeuk Kim set_new_dnode(&dn, inode, ipage, ipage, 0); 146b3d208f9SJaegeuk Kim 147b3d208f9SJaegeuk Kim if (f2fs_has_inline_data(inode)) 148b3d208f9SJaegeuk Kim err = f2fs_convert_inline_page(&dn, page); 149b3d208f9SJaegeuk Kim 150b3d208f9SJaegeuk Kim f2fs_put_dnode(&dn); 151b3d208f9SJaegeuk Kim 152b3d208f9SJaegeuk Kim f2fs_unlock_op(sbi); 153b3d208f9SJaegeuk Kim 154b3d208f9SJaegeuk Kim f2fs_put_page(page, 1); 155e18c65b2SHuajun Li return err; 156e18c65b2SHuajun Li } 157e18c65b2SHuajun Li 158b3d208f9SJaegeuk Kim int f2fs_write_inline_data(struct inode *inode, struct page *page) 159e18c65b2SHuajun Li { 160e18c65b2SHuajun Li void *src_addr, *dst_addr; 161e18c65b2SHuajun Li struct dnode_of_data dn; 162e18c65b2SHuajun Li int err; 163e18c65b2SHuajun Li 164e18c65b2SHuajun Li set_new_dnode(&dn, inode, NULL, NULL, 0); 165e18c65b2SHuajun Li err = get_dnode_of_data(&dn, 0, LOOKUP_NODE); 166e18c65b2SHuajun Li if (err) 167e18c65b2SHuajun Li return err; 168e18c65b2SHuajun Li 169c08a690bSJaegeuk Kim if (!f2fs_has_inline_data(inode)) { 170b3d208f9SJaegeuk Kim f2fs_put_dnode(&dn); 171b3d208f9SJaegeuk Kim return -EAGAIN; 172c08a690bSJaegeuk Kim } 173c08a690bSJaegeuk Kim 174b3d208f9SJaegeuk Kim f2fs_bug_on(F2FS_I_SB(inode), page->index); 175b3d208f9SJaegeuk Kim 176b3d208f9SJaegeuk Kim f2fs_wait_on_page_writeback(dn.inode_page, NODE); 177f1e33a04SJaegeuk Kim src_addr = kmap_atomic(page); 178b3d208f9SJaegeuk Kim dst_addr = inline_data_addr(dn.inode_page); 179b3d208f9SJaegeuk Kim memcpy(dst_addr, src_addr, MAX_INLINE_DATA); 180f1e33a04SJaegeuk Kim kunmap_atomic(src_addr); 181e18c65b2SHuajun Li 182fff04f90SJaegeuk Kim set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE); 183b3d208f9SJaegeuk Kim set_inode_flag(F2FS_I(inode), FI_DATA_EXIST); 184b3d208f9SJaegeuk Kim 185e18c65b2SHuajun Li sync_inode_page(&dn); 186e18c65b2SHuajun Li f2fs_put_dnode(&dn); 187e18c65b2SHuajun Li return 0; 188e18c65b2SHuajun Li } 1891e1bb4baSJaegeuk Kim 190b3d208f9SJaegeuk Kim void truncate_inline_data(struct page *ipage, u64 from) 1918aa6f1c5SChao Yu { 192b3d208f9SJaegeuk Kim void *addr; 1938aa6f1c5SChao Yu 1948aa6f1c5SChao Yu if (from >= MAX_INLINE_DATA) 1958aa6f1c5SChao Yu return; 1968aa6f1c5SChao Yu 19754b591dfSJaegeuk Kim f2fs_wait_on_page_writeback(ipage, NODE); 19854b591dfSJaegeuk Kim 199b3d208f9SJaegeuk Kim addr = inline_data_addr(ipage); 200b3d208f9SJaegeuk Kim memset(addr + from, 0, MAX_INLINE_DATA - from); 2018aa6f1c5SChao Yu } 2028aa6f1c5SChao Yu 2030342fd30SJaegeuk Kim bool recover_inline_data(struct inode *inode, struct page *npage) 2041e1bb4baSJaegeuk Kim { 2054081363fSJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 2061e1bb4baSJaegeuk Kim struct f2fs_inode *ri = NULL; 2071e1bb4baSJaegeuk Kim void *src_addr, *dst_addr; 2081e1bb4baSJaegeuk Kim struct page *ipage; 2091e1bb4baSJaegeuk Kim 2101e1bb4baSJaegeuk Kim /* 2111e1bb4baSJaegeuk Kim * The inline_data recovery policy is as follows. 2121e1bb4baSJaegeuk Kim * [prev.] [next] of inline_data flag 2131e1bb4baSJaegeuk Kim * o o -> recover inline_data 2141e1bb4baSJaegeuk Kim * o x -> remove inline_data, and then recover data blocks 2151e1bb4baSJaegeuk Kim * x o -> remove inline_data, and then recover inline_data 2161e1bb4baSJaegeuk Kim * x x -> recover data blocks 2171e1bb4baSJaegeuk Kim */ 2181e1bb4baSJaegeuk Kim if (IS_INODE(npage)) 2191e1bb4baSJaegeuk Kim ri = F2FS_INODE(npage); 2201e1bb4baSJaegeuk Kim 2211e1bb4baSJaegeuk Kim if (f2fs_has_inline_data(inode) && 2220342fd30SJaegeuk Kim ri && (ri->i_inline & F2FS_INLINE_DATA)) { 2231e1bb4baSJaegeuk Kim process_inline: 2241e1bb4baSJaegeuk Kim ipage = get_node_page(sbi, inode->i_ino); 2259850cf4aSJaegeuk Kim f2fs_bug_on(sbi, IS_ERR(ipage)); 2261e1bb4baSJaegeuk Kim 22754b591dfSJaegeuk Kim f2fs_wait_on_page_writeback(ipage, NODE); 22854b591dfSJaegeuk Kim 2291e1bb4baSJaegeuk Kim src_addr = inline_data_addr(npage); 2301e1bb4baSJaegeuk Kim dst_addr = inline_data_addr(ipage); 2311e1bb4baSJaegeuk Kim memcpy(dst_addr, src_addr, MAX_INLINE_DATA); 232b3d208f9SJaegeuk Kim 233b3d208f9SJaegeuk Kim set_inode_flag(F2FS_I(inode), FI_INLINE_DATA); 234b3d208f9SJaegeuk Kim set_inode_flag(F2FS_I(inode), FI_DATA_EXIST); 235b3d208f9SJaegeuk Kim 2361e1bb4baSJaegeuk Kim update_inode(inode, ipage); 2371e1bb4baSJaegeuk Kim f2fs_put_page(ipage, 1); 2380342fd30SJaegeuk Kim return true; 2391e1bb4baSJaegeuk Kim } 2401e1bb4baSJaegeuk Kim 2411e1bb4baSJaegeuk Kim if (f2fs_has_inline_data(inode)) { 2421e1bb4baSJaegeuk Kim ipage = get_node_page(sbi, inode->i_ino); 2439850cf4aSJaegeuk Kim f2fs_bug_on(sbi, IS_ERR(ipage)); 244b3d208f9SJaegeuk Kim truncate_inline_data(ipage, 0); 245b3d208f9SJaegeuk Kim f2fs_clear_inline_inode(inode); 2461e1bb4baSJaegeuk Kim update_inode(inode, ipage); 2471e1bb4baSJaegeuk Kim f2fs_put_page(ipage, 1); 2480342fd30SJaegeuk Kim } else if (ri && (ri->i_inline & F2FS_INLINE_DATA)) { 249764aa3e9SJaegeuk Kim truncate_blocks(inode, 0, false); 2501e1bb4baSJaegeuk Kim goto process_inline; 2511e1bb4baSJaegeuk Kim } 2520342fd30SJaegeuk Kim return false; 2531e1bb4baSJaegeuk Kim } 254201a05beSChao Yu 255201a05beSChao Yu struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir, 256201a05beSChao Yu struct qstr *name, struct page **res_page) 257201a05beSChao Yu { 258201a05beSChao Yu struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); 2594e6ebf6dSJaegeuk Kim struct f2fs_inline_dentry *inline_dentry; 260201a05beSChao Yu struct f2fs_dir_entry *de; 2617b3cd7d6SJaegeuk Kim struct f2fs_dentry_ptr d; 2624e6ebf6dSJaegeuk Kim struct page *ipage; 263201a05beSChao Yu 264201a05beSChao Yu ipage = get_node_page(sbi, dir->i_ino); 265201a05beSChao Yu if (IS_ERR(ipage)) 266201a05beSChao Yu return NULL; 267201a05beSChao Yu 2684e6ebf6dSJaegeuk Kim inline_dentry = inline_data_addr(ipage); 269201a05beSChao Yu 2707b3cd7d6SJaegeuk Kim make_dentry_ptr(&d, (void *)inline_dentry, 2); 2717b3cd7d6SJaegeuk Kim de = find_target_dentry(name, NULL, &d); 2727b3cd7d6SJaegeuk Kim 2734e6ebf6dSJaegeuk Kim unlock_page(ipage); 2744e6ebf6dSJaegeuk Kim if (de) 275201a05beSChao Yu *res_page = ipage; 2764e6ebf6dSJaegeuk Kim else 2774e6ebf6dSJaegeuk Kim f2fs_put_page(ipage, 0); 278201a05beSChao Yu 279201a05beSChao Yu /* 280201a05beSChao Yu * For the most part, it should be a bug when name_len is zero. 2814e6ebf6dSJaegeuk Kim * We stop here for figuring out where the bugs has occurred. 282201a05beSChao Yu */ 2837b3cd7d6SJaegeuk Kim f2fs_bug_on(sbi, d.max < 0); 284201a05beSChao Yu return de; 285201a05beSChao Yu } 286201a05beSChao Yu 287201a05beSChao Yu struct f2fs_dir_entry *f2fs_parent_inline_dir(struct inode *dir, 288201a05beSChao Yu struct page **p) 289201a05beSChao Yu { 290201a05beSChao Yu struct f2fs_sb_info *sbi = F2FS_I_SB(dir); 291201a05beSChao Yu struct page *ipage; 292201a05beSChao Yu struct f2fs_dir_entry *de; 293201a05beSChao Yu struct f2fs_inline_dentry *dentry_blk; 294201a05beSChao Yu 295201a05beSChao Yu ipage = get_node_page(sbi, dir->i_ino); 296201a05beSChao Yu if (IS_ERR(ipage)) 297201a05beSChao Yu return NULL; 298201a05beSChao Yu 299201a05beSChao Yu dentry_blk = inline_data_addr(ipage); 300201a05beSChao Yu de = &dentry_blk->dentry[1]; 301201a05beSChao Yu *p = ipage; 302201a05beSChao Yu unlock_page(ipage); 303201a05beSChao Yu return de; 304201a05beSChao Yu } 305201a05beSChao Yu 306201a05beSChao Yu int make_empty_inline_dir(struct inode *inode, struct inode *parent, 307201a05beSChao Yu struct page *ipage) 308201a05beSChao Yu { 309201a05beSChao Yu struct f2fs_inline_dentry *dentry_blk; 310062a3e7bSJaegeuk Kim struct f2fs_dentry_ptr d; 311201a05beSChao Yu 312201a05beSChao Yu dentry_blk = inline_data_addr(ipage); 313201a05beSChao Yu 314062a3e7bSJaegeuk Kim make_dentry_ptr(&d, (void *)dentry_blk, 2); 315062a3e7bSJaegeuk Kim do_make_empty_dir(inode, parent, &d); 316201a05beSChao Yu 317201a05beSChao Yu set_page_dirty(ipage); 318201a05beSChao Yu 319201a05beSChao Yu /* update i_size to MAX_INLINE_DATA */ 320201a05beSChao Yu if (i_size_read(inode) < MAX_INLINE_DATA) { 321201a05beSChao Yu i_size_write(inode, MAX_INLINE_DATA); 322201a05beSChao Yu set_inode_flag(F2FS_I(inode), FI_UPDATE_DIR); 323201a05beSChao Yu } 324201a05beSChao Yu return 0; 325201a05beSChao Yu } 326201a05beSChao Yu 327d64948a4SJaegeuk Kim static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage, 328201a05beSChao Yu struct f2fs_inline_dentry *inline_dentry) 329201a05beSChao Yu { 330201a05beSChao Yu struct page *page; 331201a05beSChao Yu struct dnode_of_data dn; 332201a05beSChao Yu struct f2fs_dentry_block *dentry_blk; 333201a05beSChao Yu int err; 334201a05beSChao Yu 335201a05beSChao Yu page = grab_cache_page(dir->i_mapping, 0); 336201a05beSChao Yu if (!page) 337201a05beSChao Yu return -ENOMEM; 338201a05beSChao Yu 339201a05beSChao Yu set_new_dnode(&dn, dir, ipage, NULL, 0); 340201a05beSChao Yu err = f2fs_reserve_block(&dn, 0); 341201a05beSChao Yu if (err) 342201a05beSChao Yu goto out; 343201a05beSChao Yu 344201a05beSChao Yu f2fs_wait_on_page_writeback(page, DATA); 345201a05beSChao Yu zero_user_segment(page, 0, PAGE_CACHE_SIZE); 346201a05beSChao Yu 347f1e33a04SJaegeuk Kim dentry_blk = kmap_atomic(page); 348201a05beSChao Yu 349201a05beSChao Yu /* copy data from inline dentry block to new dentry block */ 350201a05beSChao Yu memcpy(dentry_blk->dentry_bitmap, inline_dentry->dentry_bitmap, 351201a05beSChao Yu INLINE_DENTRY_BITMAP_SIZE); 352201a05beSChao Yu memcpy(dentry_blk->dentry, inline_dentry->dentry, 353201a05beSChao Yu sizeof(struct f2fs_dir_entry) * NR_INLINE_DENTRY); 354201a05beSChao Yu memcpy(dentry_blk->filename, inline_dentry->filename, 355201a05beSChao Yu NR_INLINE_DENTRY * F2FS_SLOT_LEN); 356201a05beSChao Yu 357f1e33a04SJaegeuk Kim kunmap_atomic(dentry_blk); 358201a05beSChao Yu SetPageUptodate(page); 359201a05beSChao Yu set_page_dirty(page); 360201a05beSChao Yu 361201a05beSChao Yu /* clear inline dir and flag after data writeback */ 362b3d208f9SJaegeuk Kim truncate_inline_data(ipage, 0); 363b3d208f9SJaegeuk Kim 3643289c061SJaegeuk Kim stat_dec_inline_dir(dir); 365622f28aeSChao Yu clear_inode_flag(F2FS_I(dir), FI_INLINE_DENTRY); 366201a05beSChao Yu 367201a05beSChao Yu if (i_size_read(dir) < PAGE_CACHE_SIZE) { 368201a05beSChao Yu i_size_write(dir, PAGE_CACHE_SIZE); 369201a05beSChao Yu set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); 370201a05beSChao Yu } 371201a05beSChao Yu 372201a05beSChao Yu sync_inode_page(&dn); 373201a05beSChao Yu out: 374201a05beSChao Yu f2fs_put_page(page, 1); 375201a05beSChao Yu return err; 376201a05beSChao Yu } 377201a05beSChao Yu 378201a05beSChao Yu int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name, 379201a05beSChao Yu struct inode *inode) 380201a05beSChao Yu { 381201a05beSChao Yu struct f2fs_sb_info *sbi = F2FS_I_SB(dir); 382201a05beSChao Yu struct page *ipage; 383201a05beSChao Yu unsigned int bit_pos; 384201a05beSChao Yu f2fs_hash_t name_hash; 385201a05beSChao Yu struct f2fs_dir_entry *de; 386201a05beSChao Yu size_t namelen = name->len; 387201a05beSChao Yu struct f2fs_inline_dentry *dentry_blk = NULL; 388201a05beSChao Yu int slots = GET_DENTRY_SLOTS(namelen); 389201a05beSChao Yu struct page *page; 390201a05beSChao Yu int err = 0; 391201a05beSChao Yu int i; 392201a05beSChao Yu 393201a05beSChao Yu name_hash = f2fs_dentry_hash(name); 394201a05beSChao Yu 395201a05beSChao Yu ipage = get_node_page(sbi, dir->i_ino); 396201a05beSChao Yu if (IS_ERR(ipage)) 397201a05beSChao Yu return PTR_ERR(ipage); 398201a05beSChao Yu 399201a05beSChao Yu dentry_blk = inline_data_addr(ipage); 400a82afa20SJaegeuk Kim bit_pos = room_for_filename(&dentry_blk->dentry_bitmap, 401a82afa20SJaegeuk Kim slots, NR_INLINE_DENTRY); 402201a05beSChao Yu if (bit_pos >= NR_INLINE_DENTRY) { 403201a05beSChao Yu err = f2fs_convert_inline_dir(dir, ipage, dentry_blk); 404201a05beSChao Yu if (!err) 405201a05beSChao Yu err = -EAGAIN; 406201a05beSChao Yu goto out; 407201a05beSChao Yu } 408201a05beSChao Yu 409201a05beSChao Yu down_write(&F2FS_I(inode)->i_sem); 410bce8d112SJaegeuk Kim page = init_inode_metadata(inode, dir, name, ipage); 411201a05beSChao Yu if (IS_ERR(page)) { 412201a05beSChao Yu err = PTR_ERR(page); 413201a05beSChao Yu goto fail; 414201a05beSChao Yu } 415bce8d112SJaegeuk Kim 416bce8d112SJaegeuk Kim f2fs_wait_on_page_writeback(ipage, NODE); 417201a05beSChao Yu de = &dentry_blk->dentry[bit_pos]; 418201a05beSChao Yu de->hash_code = name_hash; 419201a05beSChao Yu de->name_len = cpu_to_le16(namelen); 420201a05beSChao Yu memcpy(dentry_blk->filename[bit_pos], name->name, name->len); 421201a05beSChao Yu de->ino = cpu_to_le32(inode->i_ino); 422201a05beSChao Yu set_de_type(de, inode); 423201a05beSChao Yu for (i = 0; i < slots; i++) 424201a05beSChao Yu test_and_set_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap); 425201a05beSChao Yu set_page_dirty(ipage); 426201a05beSChao Yu 427201a05beSChao Yu /* we don't need to mark_inode_dirty now */ 428201a05beSChao Yu F2FS_I(inode)->i_pino = dir->i_ino; 429201a05beSChao Yu update_inode(inode, page); 430201a05beSChao Yu f2fs_put_page(page, 1); 431201a05beSChao Yu 432201a05beSChao Yu update_parent_metadata(dir, inode, 0); 433201a05beSChao Yu fail: 434201a05beSChao Yu up_write(&F2FS_I(inode)->i_sem); 435201a05beSChao Yu 436201a05beSChao Yu if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) { 437201a05beSChao Yu update_inode(dir, ipage); 438201a05beSChao Yu clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); 439201a05beSChao Yu } 440201a05beSChao Yu out: 441201a05beSChao Yu f2fs_put_page(ipage, 1); 442201a05beSChao Yu return err; 443201a05beSChao Yu } 444201a05beSChao Yu 445201a05beSChao Yu void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry, struct page *page, 446201a05beSChao Yu struct inode *dir, struct inode *inode) 447201a05beSChao Yu { 448201a05beSChao Yu struct f2fs_inline_dentry *inline_dentry; 449201a05beSChao Yu int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len)); 450201a05beSChao Yu unsigned int bit_pos; 451201a05beSChao Yu int i; 452201a05beSChao Yu 453201a05beSChao Yu lock_page(page); 45459a06155SJaegeuk Kim f2fs_wait_on_page_writeback(page, NODE); 455201a05beSChao Yu 456201a05beSChao Yu inline_dentry = inline_data_addr(page); 457201a05beSChao Yu bit_pos = dentry - inline_dentry->dentry; 458201a05beSChao Yu for (i = 0; i < slots; i++) 459201a05beSChao Yu test_and_clear_bit_le(bit_pos + i, 460201a05beSChao Yu &inline_dentry->dentry_bitmap); 461201a05beSChao Yu 462201a05beSChao Yu set_page_dirty(page); 463201a05beSChao Yu 464201a05beSChao Yu dir->i_ctime = dir->i_mtime = CURRENT_TIME; 465201a05beSChao Yu 466201a05beSChao Yu if (inode) 467201a05beSChao Yu f2fs_drop_nlink(dir, inode, page); 468201a05beSChao Yu 469201a05beSChao Yu f2fs_put_page(page, 1); 470201a05beSChao Yu } 471201a05beSChao Yu 472201a05beSChao Yu bool f2fs_empty_inline_dir(struct inode *dir) 473201a05beSChao Yu { 474201a05beSChao Yu struct f2fs_sb_info *sbi = F2FS_I_SB(dir); 475201a05beSChao Yu struct page *ipage; 476201a05beSChao Yu unsigned int bit_pos = 2; 477201a05beSChao Yu struct f2fs_inline_dentry *dentry_blk; 478201a05beSChao Yu 479201a05beSChao Yu ipage = get_node_page(sbi, dir->i_ino); 480201a05beSChao Yu if (IS_ERR(ipage)) 481201a05beSChao Yu return false; 482201a05beSChao Yu 483201a05beSChao Yu dentry_blk = inline_data_addr(ipage); 484201a05beSChao Yu bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, 485201a05beSChao Yu NR_INLINE_DENTRY, 486201a05beSChao Yu bit_pos); 487201a05beSChao Yu 488201a05beSChao Yu f2fs_put_page(ipage, 1); 489201a05beSChao Yu 490201a05beSChao Yu if (bit_pos < NR_INLINE_DENTRY) 491201a05beSChao Yu return false; 492201a05beSChao Yu 493201a05beSChao Yu return true; 494201a05beSChao Yu } 495201a05beSChao Yu 496201a05beSChao Yu int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx) 497201a05beSChao Yu { 498201a05beSChao Yu struct inode *inode = file_inode(file); 499201a05beSChao Yu struct f2fs_inline_dentry *inline_dentry = NULL; 500201a05beSChao Yu struct page *ipage = NULL; 5017b3cd7d6SJaegeuk Kim struct f2fs_dentry_ptr d; 502201a05beSChao Yu 503201a05beSChao Yu if (ctx->pos == NR_INLINE_DENTRY) 504201a05beSChao Yu return 0; 505201a05beSChao Yu 50638594de7SJaegeuk Kim ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino); 507201a05beSChao Yu if (IS_ERR(ipage)) 508201a05beSChao Yu return PTR_ERR(ipage); 509201a05beSChao Yu 510201a05beSChao Yu inline_dentry = inline_data_addr(ipage); 511201a05beSChao Yu 5127b3cd7d6SJaegeuk Kim make_dentry_ptr(&d, (void *)inline_dentry, 2); 5137b3cd7d6SJaegeuk Kim 5147b3cd7d6SJaegeuk Kim if (!f2fs_fill_dentries(ctx, &d, 0)) 515201a05beSChao Yu ctx->pos = NR_INLINE_DENTRY; 516201a05beSChao Yu 51738594de7SJaegeuk Kim f2fs_put_page(ipage, 1); 518201a05beSChao Yu return 0; 519201a05beSChao Yu } 520