f2fs: handle inline data operations
[cascardo/linux.git] / fs / f2fs / file.c
index 7d714f4..dd80e72 100644 (file)
@@ -33,7 +33,6 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
        struct page *page = vmf->page;
        struct inode *inode = file_inode(vma->vm_file);
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-       block_t old_blk_addr;
        struct dnode_of_data dn;
        int err;
 
@@ -44,30 +43,16 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
        /* block allocation */
        f2fs_lock_op(sbi);
        set_new_dnode(&dn, inode, NULL, NULL, 0);
-       err = get_dnode_of_data(&dn, page->index, ALLOC_NODE);
-       if (err) {
-               f2fs_unlock_op(sbi);
-               goto out;
-       }
-
-       old_blk_addr = dn.data_blkaddr;
-
-       if (old_blk_addr == NULL_ADDR) {
-               err = reserve_new_block(&dn);
-               if (err) {
-                       f2fs_put_dnode(&dn);
-                       f2fs_unlock_op(sbi);
-                       goto out;
-               }
-       }
-       f2fs_put_dnode(&dn);
+       err = f2fs_reserve_block(&dn, page->index);
        f2fs_unlock_op(sbi);
+       if (err)
+               goto out;
 
        file_update_time(vma->vm_file);
        lock_page(page);
-       if (page->mapping != inode->i_mapping ||
+       if (unlikely(page->mapping != inode->i_mapping ||
                        page_offset(page) > i_size_read(inode) ||
-                       !PageUptodate(page)) {
+                       !PageUptodate(page))) {
                unlock_page(page);
                err = -EFAULT;
                goto out;
@@ -135,7 +120,7 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
                .for_reclaim = 0,
        };
 
-       if (f2fs_readonly(inode->i_sb))
+       if (unlikely(f2fs_readonly(inode->i_sb)))
                return 0;
 
        trace_f2fs_sync_file_enter(inode);
@@ -256,7 +241,7 @@ static void truncate_partial_data_page(struct inode *inode, u64 from)
                return;
 
        lock_page(page);
-       if (page->mapping != inode->i_mapping) {
+       if (unlikely(page->mapping != inode->i_mapping)) {
                f2fs_put_page(page, 1);
                return;
        }
@@ -272,8 +257,7 @@ static int truncate_blocks(struct inode *inode, u64 from)
        unsigned int blocksize = inode->i_sb->s_blocksize;
        struct dnode_of_data dn;
        pgoff_t free_from;
-       int count = 0;
-       int err;
+       int count = 0, err = 0;
 
        trace_f2fs_truncate_blocks_enter(inode, from);
 
@@ -281,6 +265,10 @@ static int truncate_blocks(struct inode *inode, u64 from)
                        ((from + blocksize - 1) >> (sbi->log_blocksize));
 
        f2fs_lock_op(sbi);
+
+       if (f2fs_has_inline_data(inode))
+               goto done;
+
        set_new_dnode(&dn, inode, NULL, NULL, 0);
        err = get_dnode_of_data(&dn, free_from, LOOKUP_NODE);
        if (err) {
@@ -307,6 +295,7 @@ static int truncate_blocks(struct inode *inode, u64 from)
        f2fs_put_dnode(&dn);
 free_next:
        err = truncate_inode_blocks(inode, free_from);
+done:
        f2fs_unlock_op(sbi);
 
        /* lastly zero out the first data page */
@@ -382,8 +371,17 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
 
        if ((attr->ia_valid & ATTR_SIZE) &&
                        attr->ia_size != i_size_read(inode)) {
+               if (f2fs_has_inline_data(inode) &&
+                               (attr->ia_size > MAX_INLINE_DATA)) {
+                       unsigned flags = AOP_FLAG_NOFS;
+                       err = f2fs_convert_inline_data(inode, NULL, flags);
+                       if (err)
+                               return err;
+               }
+
                truncate_setsize(inode, attr->ia_size);
-               f2fs_truncate(inode);
+               if (!f2fs_has_inline_data(inode))
+                       f2fs_truncate(inode);
                f2fs_balance_fs(F2FS_SB(inode->i_sb));
        }
 
@@ -459,12 +457,32 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end)
        return 0;
 }
 
-static int punch_hole(struct inode *inode, loff_t offset, loff_t len, int mode)
+static int punch_hole(struct inode *inode, loff_t offset, loff_t len)
 {
        pgoff_t pg_start, pg_end;
        loff_t off_start, off_end;
        int ret = 0;
 
+       if (f2fs_has_inline_data(inode)) {
+               struct page *page;
+               unsigned flags = AOP_FLAG_NOFS;
+               page = grab_cache_page_write_begin(inode->i_mapping, 0, flags);
+               if (IS_ERR(page))
+                       return PTR_ERR(page);
+               if (offset + len > MAX_INLINE_DATA) {
+                       ret = f2fs_convert_inline_data(inode, page, flags);
+                       f2fs_put_page(page, 1);
+                       if (ret)
+                               return ret;
+               } else {
+                       zero_user_segment(page, offset, offset + len);
+                       SetPageUptodate(page);
+                       set_page_dirty(page);
+                       f2fs_put_page(page, 1);
+                       return ret;
+               }
+       }
+
        pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT;
        pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT;
 
@@ -499,12 +517,6 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len, int mode)
                }
        }
 
-       if (!(mode & FALLOC_FL_KEEP_SIZE) &&
-               i_size_read(inode) <= (offset + len)) {
-               i_size_write(inode, offset);
-               mark_inode_dirty(inode);
-       }
-
        return ret;
 }
 
@@ -517,6 +529,12 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
        loff_t off_start, off_end;
        int ret = 0;
 
+       if (f2fs_has_inline_data(inode) && (offset + len > MAX_INLINE_DATA)) {
+               ret = f2fs_convert_inline_data(inode, NULL, AOP_FLAG_NOFS);
+               if (ret)
+                       return ret;
+       }
+
        ret = inode_newsize_ok(inode, (len + offset));
        if (ret)
                return ret;
@@ -532,22 +550,10 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
 
                f2fs_lock_op(sbi);
                set_new_dnode(&dn, inode, NULL, NULL, 0);
-               ret = get_dnode_of_data(&dn, index, ALLOC_NODE);
-               if (ret) {
-                       f2fs_unlock_op(sbi);
-                       break;
-               }
-
-               if (dn.data_blkaddr == NULL_ADDR) {
-                       ret = reserve_new_block(&dn);
-                       if (ret) {
-                               f2fs_put_dnode(&dn);
-                               f2fs_unlock_op(sbi);
-                               break;
-                       }
-               }
-               f2fs_put_dnode(&dn);
+               ret = f2fs_reserve_block(&dn, index);
                f2fs_unlock_op(sbi);
+               if (ret)
+                       break;
 
                if (pg_start == pg_end)
                        new_size = offset + len;
@@ -578,7 +584,7 @@ static long f2fs_fallocate(struct file *file, int mode,
                return -EOPNOTSUPP;
 
        if (mode & FALLOC_FL_PUNCH_HOLE)
-               ret = punch_hole(inode, offset, len, mode);
+               ret = punch_hole(inode, offset, len);
        else
                ret = expand_inode_data(inode, offset, len, mode);