This patch adds last time that user requested filesystem operations.
This information is used to detect whether system is idle or not later.
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
 Description:
                 Controls the checkpoint timing.
 
+What:          /sys/fs/f2fs/<disk>/idle_interval
+Date:          January 2016
+Contact:       "Jaegeuk Kim" <jaegeuk@kernel.org>
+Description:
+                Controls the idle timing.
+
 What:          /sys/fs/f2fs/<disk>/ra_nid_pages
 Date:          October 2015
 Contact:       "Chao Yu" <chao2.yu@samsung.com>
 
        }
 
        f2fs_put_page(page, 1);
+       f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
        return copied;
 }
 
 
        f2fs_put_page(dentry_page, 1);
 out:
        f2fs_fname_free_filename(&fname);
+       f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
        return err;
 }
 
        clear_inode_flag(F2FS_I(inode), FI_NEW_INODE);
 fail:
        up_write(&F2FS_I(inode)->i_sem);
+       f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
        return err;
 }
 
        int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len));
        int i;
 
+       f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
+
        if (f2fs_has_inline_dentry(dir))
                return f2fs_delete_inline_entry(dentry, page, dir, inode);
 
 
 #include <linux/sched.h>
 #include <linux/vmalloc.h>
 #include <linux/bio.h>
+#include <linux/blkdev.h>
 
 #ifdef CONFIG_F2FS_CHECK_FS
 #define f2fs_bug_on(sbi, condition)    BUG_ON(condition)
 #define BATCHED_TRIM_BLOCKS(sbi)       \
                (BATCHED_TRIM_SEGMENTS(sbi) << (sbi)->log_blocks_per_seg)
 #define DEF_CP_INTERVAL                        60      /* 60 secs */
+#define DEF_IDLE_INTERVAL              120     /* 2 mins */
 
 struct cp_control {
        int reason;
 
 enum {
        CP_TIME,
+       REQ_TIME,
        MAX_TIME,
 };
 
        return time_after(jiffies, sbi->last_time[type] + interval);
 }
 
+static inline bool is_idle(struct f2fs_sb_info *sbi)
+{
+       struct block_device *bdev = sbi->sb->s_bdev;
+       struct request_queue *q = bdev_get_queue(bdev);
+       struct request_list *rl = &q->root_rl;
+
+       if (rl->count[BLK_RW_SYNC] || rl->count[BLK_RW_ASYNC])
+               return 0;
+
+       return f2fs_time_over(sbi, REQ_TIME);
+}
+
 /*
  * Inline functions
  */
 
        clear_cold_data(page);
 out:
        sb_end_pagefault(inode->i_sb);
+       f2fs_update_time(sbi, REQ_TIME);
        return block_page_mkwrite_return(err);
 }
 
        remove_ino_entry(sbi, ino, UPDATE_INO);
        clear_inode_flag(fi, FI_UPDATE_WRITE);
        ret = f2fs_issue_flush(sbi);
+       f2fs_update_time(sbi, REQ_TIME);
 out:
        trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret);
        f2fs_trace_ios(NULL, 1);
        }
        dn->ofs_in_node = ofs;
 
+       f2fs_update_time(sbi, REQ_TIME);
        trace_f2fs_truncate_data_blocks_range(dn->inode, dn->nid,
                                         dn->ofs_in_node, nr_free);
        return nr_free;
        if (!ret) {
                inode->i_mtime = inode->i_ctime = CURRENT_TIME;
                mark_inode_dirty(inode);
+               f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
        }
 
 out:
                return ret;
 
        set_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
+       f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
+
        return 0;
 }
 
                return ret;
 
        set_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE);
+       f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
        return 0;
 }
 
        }
 
        mnt_drop_write_file(filp);
+       f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
        return ret;
 }
 
        default:
                return -EINVAL;
        }
+       f2fs_update_time(sbi, REQ_TIME);
        return 0;
 }
 
        if (copy_to_user((struct fstrim_range __user *)arg, &range,
                                sizeof(range)))
                return -EFAULT;
+       f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
        return 0;
 }
 
                                sizeof(policy)))
                return -EFAULT;
 
+       f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
        return f2fs_process_policy(&policy, inode);
 #else
        return -EOPNOTSUPP;
        }
 
        err = f2fs_defragment_range(sbi, filp, &range);
+       f2fs_update_time(sbi, REQ_TIME);
        if (err < 0)
                goto out;
 
 
 #include <linux/kthread.h>
 #include <linux/delay.h>
 #include <linux/freezer.h>
-#include <linux/blkdev.h>
 
 #include "f2fs.h"
 #include "node.h"
 
                return true;
        return false;
 }
-
-static inline int is_idle(struct f2fs_sb_info *sbi)
-{
-       struct block_device *bdev = sbi->sb->s_bdev;
-       struct request_queue *q = bdev_get_queue(bdev);
-       struct request_list *rl = &q->root_rl;
-       return !(rl->count[BLK_RW_SYNC]) && !(rl->count[BLK_RW_ASYNC]);
-}
 
        if (!available_free_memory(sbi, NAT_ENTRIES) ||
                        excess_prefree_segs(sbi) ||
                        !available_free_memory(sbi, INO_ENTRIES) ||
-                       f2fs_time_over(sbi, CP_TIME)) {
+                       (is_idle(sbi) && f2fs_time_over(sbi, CP_TIME))) {
                if (test_opt(sbi, DATA_FLUSH))
                        sync_dirty_inodes(sbi, FILE_INODE);
                f2fs_sync_fs(sbi->sb, true);
 
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]);
 
 #define ATTR_LIST(name) (&f2fs_attr_##name.attr)
 static struct attribute *f2fs_attrs[] = {
        ATTR_LIST(ram_thresh),
        ATTR_LIST(ra_nid_pages),
        ATTR_LIST(cp_interval),
+       ATTR_LIST(idle_interval),
        NULL,
 };
 
 
        sbi->dir_level = DEF_DIR_LEVEL;
        sbi->interval_time[CP_TIME] = DEF_CP_INTERVAL;
+       sbi->interval_time[REQ_TIME] = DEF_IDLE_INTERVAL;
        clear_sbi_flag(sbi, SBI_NEED_FSCK);
 
        INIT_LIST_HEAD(&sbi->s_list);
        }
 
        f2fs_update_time(sbi, CP_TIME);
+       f2fs_update_time(sbi, REQ_TIME);
        return 0;
 
 free_kobj:
 
        up_write(&F2FS_I(inode)->i_sem);
        f2fs_unlock_op(sbi);
 
+       f2fs_update_time(sbi, REQ_TIME);
        return err;
 }