Commit e18c65b2ac91aa59f89333da595d5155184f76cf

Authored by Huajun Li
Committed by Jaegeuk Kim
1 parent 0d47c1adc2

f2fs: key functions to handle inline data

Functions to implement inline data read/write, and move inline data to
normal data block when file size exceeds inline data limitation.

Signed-off-by: Huajun Li <huajun.li@intel.com>
Signed-off-by: Haicheng Li <haicheng.li@linux.intel.com>
Signed-off-by: Weihong Xu <weihong.xu@intel.com>
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>

Showing 3 changed files with 185 additions and 1 deletions Side-by-side Diff

1 1 obj-$(CONFIG_F2FS_FS) += f2fs.o
2 2  
3   -f2fs-y := dir.o file.o inode.o namei.o hash.o super.o
  3 +f2fs-y := dir.o file.o inode.o namei.o hash.o super.o inline.o
4 4 f2fs-y += checkpoint.o gc.o data.o node.o segment.o recovery.o
5 5 f2fs-$(CONFIG_F2FS_STAT_FS) += debug.o
6 6 f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o
... ... @@ -1296,5 +1296,13 @@
1296 1296 extern const struct inode_operations f2fs_symlink_inode_operations;
1297 1297 extern const struct inode_operations f2fs_special_inode_operations;
1298 1298  
  1299 +/*
  1300 + * inline.c
  1301 + */
  1302 +inline int f2fs_has_inline_data(struct inode *);
  1303 +bool f2fs_may_inline(struct inode *);
  1304 +int f2fs_read_inline_data(struct inode *, struct page *);
  1305 +int f2fs_convert_inline_data(struct inode *, struct page *, unsigned);
  1306 +int f2fs_write_inline_data(struct inode *, struct page *, unsigned int);
1299 1307 #endif
  1 +/*
  2 + * fs/f2fs/inline.c
  3 + * Copyright (c) 2013, Intel Corporation
  4 + * Authors: Huajun Li <huajun.li@intel.com>
  5 + * Haicheng Li <haicheng.li@intel.com>
  6 + * This program is free software; you can redistribute it and/or modify
  7 + * it under the terms of the GNU General Public License version 2 as
  8 + * published by the Free Software Foundation.
  9 + */
  10 +
  11 +#include <linux/fs.h>
  12 +#include <linux/f2fs_fs.h>
  13 +
  14 +#include "f2fs.h"
  15 +
  16 +inline int f2fs_has_inline_data(struct inode *inode)
  17 +{
  18 + return is_inode_flag_set(F2FS_I(inode), FI_INLINE_DATA);
  19 +}
  20 +
  21 +bool f2fs_may_inline(struct inode *inode)
  22 +{
  23 + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
  24 + block_t nr_blocks;
  25 + loff_t i_size;
  26 +
  27 + if (!test_opt(sbi, INLINE_DATA))
  28 + return false;
  29 +
  30 + nr_blocks = F2FS_I(inode)->i_xattr_nid ? 3 : 2;
  31 + if (inode->i_blocks > nr_blocks)
  32 + return false;
  33 +
  34 + i_size = i_size_read(inode);
  35 + if (i_size > MAX_INLINE_DATA)
  36 + return false;
  37 +
  38 + return true;
  39 +}
  40 +
  41 +int f2fs_read_inline_data(struct inode *inode, struct page *page)
  42 +{
  43 + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
  44 + struct page *ipage;
  45 + void *src_addr, *dst_addr;
  46 +
  47 + ipage = get_node_page(sbi, inode->i_ino);
  48 + if (IS_ERR(ipage))
  49 + return PTR_ERR(ipage);
  50 +
  51 + zero_user_segment(page, INLINE_DATA_OFFSET,
  52 + INLINE_DATA_OFFSET + MAX_INLINE_DATA);
  53 +
  54 + /* Copy the whole inline data block */
  55 + src_addr = inline_data_addr(ipage);
  56 + dst_addr = kmap(page);
  57 + memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
  58 + kunmap(page);
  59 + f2fs_put_page(ipage, 1);
  60 +
  61 + SetPageUptodate(page);
  62 + unlock_page(page);
  63 +
  64 + return 0;
  65 +}
  66 +
  67 +static int __f2fs_convert_inline_data(struct inode *inode, struct page *page)
  68 +{
  69 + int err;
  70 + struct page *ipage;
  71 + struct dnode_of_data dn;
  72 + void *src_addr, *dst_addr;
  73 + block_t new_blk_addr;
  74 + struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
  75 + struct f2fs_io_info fio = {
  76 + .type = DATA,
  77 + .rw = WRITE_SYNC | REQ_PRIO,
  78 + };
  79 +
  80 + f2fs_lock_op(sbi);
  81 + ipage = get_node_page(sbi, inode->i_ino);
  82 + if (IS_ERR(ipage))
  83 + return PTR_ERR(ipage);
  84 +
  85 + /*
  86 + * i_addr[0] is not used for inline data,
  87 + * so reserving new block will not destroy inline data
  88 + */
  89 + set_new_dnode(&dn, inode, ipage, ipage, 0);
  90 + err = f2fs_reserve_block(&dn, 0);
  91 + if (err) {
  92 + f2fs_put_page(ipage, 1);
  93 + f2fs_unlock_op(sbi);
  94 + return err;
  95 + }
  96 +
  97 + zero_user_segment(page, 0, PAGE_CACHE_SIZE);
  98 +
  99 + /* Copy the whole inline data block */
  100 + src_addr = inline_data_addr(ipage);
  101 + dst_addr = kmap(page);
  102 + memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
  103 + kunmap(page);
  104 +
  105 + /* write data page to try to make data consistent */
  106 + set_page_writeback(page);
  107 + write_data_page(page, &dn, &new_blk_addr, &fio);
  108 + update_extent_cache(new_blk_addr, &dn);
  109 + f2fs_wait_on_page_writeback(page, DATA, true);
  110 +
  111 + /* clear inline data and flag after data writeback */
  112 + zero_user_segment(ipage, INLINE_DATA_OFFSET,
  113 + INLINE_DATA_OFFSET + MAX_INLINE_DATA);
  114 + clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
  115 +
  116 + sync_inode_page(&dn);
  117 + f2fs_put_page(ipage, 1);
  118 + f2fs_unlock_op(sbi);
  119 +
  120 + return err;
  121 +}
  122 +
  123 +int f2fs_convert_inline_data(struct inode *inode,
  124 + struct page *p, unsigned flags)
  125 +{
  126 + int err;
  127 + struct page *page;
  128 +
  129 + if (!p || p->index) {
  130 + page = grab_cache_page_write_begin(inode->i_mapping, 0, flags);
  131 + if (IS_ERR(page))
  132 + return PTR_ERR(page);
  133 + } else {
  134 + page = p;
  135 + }
  136 +
  137 + err = __f2fs_convert_inline_data(inode, page);
  138 +
  139 + if (!p || p->index)
  140 + f2fs_put_page(page, 1);
  141 +
  142 + return err;
  143 +}
  144 +
  145 +int f2fs_write_inline_data(struct inode *inode,
  146 + struct page *page, unsigned size)
  147 +{
  148 + void *src_addr, *dst_addr;
  149 + struct page *ipage;
  150 + struct dnode_of_data dn;
  151 + int err;
  152 +
  153 + set_new_dnode(&dn, inode, NULL, NULL, 0);
  154 + err = get_dnode_of_data(&dn, 0, LOOKUP_NODE);
  155 + if (err)
  156 + return err;
  157 + ipage = dn.inode_page;
  158 +
  159 + zero_user_segment(ipage, INLINE_DATA_OFFSET,
  160 + INLINE_DATA_OFFSET + MAX_INLINE_DATA);
  161 + src_addr = kmap(page);
  162 + dst_addr = inline_data_addr(ipage);
  163 + memcpy(dst_addr, src_addr, size);
  164 + kunmap(page);
  165 +
  166 + /* Release the first data block if it is allocated */
  167 + if (!f2fs_has_inline_data(inode)) {
  168 + truncate_data_blocks_range(&dn, 1);
  169 + set_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
  170 + }
  171 +
  172 + sync_inode_page(&dn);
  173 + f2fs_put_dnode(&dn);
  174 +
  175 + return 0;
  176 +}