Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[deliverable/linux.git] / fs / f2fs / file.c
index 5674ba13102be9373be7a168fbf44f1980e3d86d..98dac27bc3f733975fabc96404ab30a916b20e7c 100644 (file)
@@ -26,6 +26,7 @@
 #include "segment.h"
 #include "xattr.h"
 #include "acl.h"
+#include "trace.h"
 #include <trace/events/f2fs.h>
 
 static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
@@ -245,6 +246,10 @@ go_write:
 sync_nodes:
        sync_node_pages(sbi, ino, &wbc);
 
+       /* if cp_error was enabled, we should avoid infinite loop */
+       if (unlikely(f2fs_cp_error(sbi)))
+               goto out;
+
        if (need_inode_block_update(sbi, ino)) {
                mark_inode_dirty_sync(inode);
                f2fs_write_inode(inode, NULL);
@@ -264,6 +269,7 @@ flush_out:
        ret = f2fs_issue_flush(sbi);
 out:
        trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret);
+       f2fs_trace_ios(NULL, NULL, 1);
        return ret;
 }
 
@@ -350,7 +356,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
                /* find data/hole in dnode block */
                for (; dn.ofs_in_node < end_offset;
                                dn.ofs_in_node++, pgofs++,
-                               data_ofs = pgofs << PAGE_CACHE_SHIFT) {
+                               data_ofs = (loff_t)pgofs << PAGE_CACHE_SHIFT) {
                        block_t blkaddr;
                        blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
 
@@ -426,7 +432,8 @@ int truncate_data_blocks_range(struct dnode_of_data *dn, int count)
                if (blkaddr == NULL_ADDR)
                        continue;
 
-               update_extent_cache(NULL_ADDR, dn);
+               dn->data_blkaddr = NULL_ADDR;
+               update_extent_cache(dn);
                invalidate_blocks(sbi, blkaddr);
                nr_free++;
        }
@@ -483,8 +490,7 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock)
 
        trace_f2fs_truncate_blocks_enter(inode, from);
 
-       free_from = (pgoff_t)
-               ((from + blocksize - 1) >> (sbi->log_blocksize));
+       free_from = (pgoff_t)F2FS_BYTES_TO_BLK(from + blocksize - 1);
 
        if (lock)
                f2fs_lock_op(sbi);
@@ -835,6 +841,19 @@ static long f2fs_fallocate(struct file *file, int mode,
        return ret;
 }
 
+static int f2fs_release_file(struct inode *inode, struct file *filp)
+{
+       /* some remained atomic pages should discarded */
+       if (f2fs_is_atomic_file(inode))
+               commit_inmem_pages(inode, true);
+       if (f2fs_is_volatile_file(inode)) {
+               set_inode_flag(F2FS_I(inode), FI_DROP_CACHE);
+               filemap_fdatawrite(inode->i_mapping);
+               clear_inode_flag(F2FS_I(inode), FI_DROP_CACHE);
+       }
+       return 0;
+}
+
 #define F2FS_REG_FLMASK                (~(FS_DIRSYNC_FL | FS_TOPDIR_FL))
 #define F2FS_OTHER_FLMASK      (FS_NODUMP_FL | FS_NOATIME_FL)
 
@@ -905,29 +924,30 @@ out:
        return ret;
 }
 
+static int f2fs_ioc_getversion(struct file *filp, unsigned long arg)
+{
+       struct inode *inode = file_inode(filp);
+
+       return put_user(inode->i_generation, (int __user *)arg);
+}
+
 static int f2fs_ioc_start_atomic_write(struct file *filp)
 {
        struct inode *inode = file_inode(filp);
-       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
 
        if (!inode_owner_or_capable(inode))
                return -EACCES;
 
-       f2fs_balance_fs(sbi);
+       f2fs_balance_fs(F2FS_I_SB(inode));
+
+       if (f2fs_is_atomic_file(inode))
+               return 0;
 
        set_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
 
        return f2fs_convert_inline_inode(inode);
 }
 
-static int f2fs_release_file(struct inode *inode, struct file *filp)
-{
-       /* some remained atomic pages should discarded */
-       if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode))
-               commit_inmem_pages(inode, true);
-       return 0;
-}
-
 static int f2fs_ioc_commit_atomic_write(struct file *filp)
 {
        struct inode *inode = file_inode(filp);
@@ -948,6 +968,7 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp)
 
        ret = f2fs_sync_file(filp, 0, LONG_MAX, 0);
        mnt_drop_write_file(filp);
+       clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
        return ret;
 }
 
@@ -958,11 +979,56 @@ static int f2fs_ioc_start_volatile_write(struct file *filp)
        if (!inode_owner_or_capable(inode))
                return -EACCES;
 
+       if (f2fs_is_volatile_file(inode))
+               return 0;
+
        set_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE);
 
        return f2fs_convert_inline_inode(inode);
 }
 
+static int f2fs_ioc_release_volatile_write(struct file *filp)
+{
+       struct inode *inode = file_inode(filp);
+
+       if (!inode_owner_or_capable(inode))
+               return -EACCES;
+
+       if (!f2fs_is_volatile_file(inode))
+               return 0;
+
+       punch_hole(inode, 0, F2FS_BLKSIZE);
+       return 0;
+}
+
+static int f2fs_ioc_abort_volatile_write(struct file *filp)
+{
+       struct inode *inode = file_inode(filp);
+       int ret;
+
+       if (!inode_owner_or_capable(inode))
+               return -EACCES;
+
+       ret = mnt_want_write_file(filp);
+       if (ret)
+               return ret;
+
+       f2fs_balance_fs(F2FS_I_SB(inode));
+
+       if (f2fs_is_atomic_file(inode)) {
+               commit_inmem_pages(inode, false);
+               clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
+       }
+
+       if (f2fs_is_volatile_file(inode)) {
+               clear_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE);
+               filemap_fdatawrite(inode->i_mapping);
+               set_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE);
+       }
+       mnt_drop_write_file(filp);
+       return ret;
+}
+
 static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg)
 {
        struct inode *inode = file_inode(filp);
@@ -1000,12 +1066,18 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                return f2fs_ioc_getflags(filp, arg);
        case F2FS_IOC_SETFLAGS:
                return f2fs_ioc_setflags(filp, arg);
+       case F2FS_IOC_GETVERSION:
+               return f2fs_ioc_getversion(filp, arg);
        case F2FS_IOC_START_ATOMIC_WRITE:
                return f2fs_ioc_start_atomic_write(filp);
        case F2FS_IOC_COMMIT_ATOMIC_WRITE:
                return f2fs_ioc_commit_atomic_write(filp);
        case F2FS_IOC_START_VOLATILE_WRITE:
                return f2fs_ioc_start_volatile_write(filp);
+       case F2FS_IOC_RELEASE_VOLATILE_WRITE:
+               return f2fs_ioc_release_volatile_write(filp);
+       case F2FS_IOC_ABORT_VOLATILE_WRITE:
+               return f2fs_ioc_abort_volatile_write(filp);
        case FITRIM:
                return f2fs_ioc_fitrim(filp, arg);
        default:
This page took 0.043926 seconds and 5 git commands to generate.