[PATCH] btrfs: Implement lazytime

From: Kusanagi Kouichi
Date: Tue Jan 14 2020 - 03:59:46 EST


I tested with xfstests and lazytime didn't cause any new failures.

Signed-off-by: Kusanagi Kouichi <slash@xxxxxxxxxxxxxxx>
---
fs/btrfs/delayed-inode.c | 6 ++++++
fs/btrfs/file.c | 11 +++++++++++
fs/btrfs/inode.c | 28 +++++++++++++++++++++++++---
fs/btrfs/ioctl.c | 14 ++++++++++++++
fs/btrfs/super.c | 1 +
5 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index d3e15e1d4a91..b30b00678503 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -1722,6 +1722,12 @@ static void fill_stack_inode_item(struct btrfs_trans_handle *trans,
struct btrfs_inode_item *inode_item,
struct inode *inode)
{
+ if (inode->i_sb->s_flags & SB_LAZYTIME) {
+ spin_lock(&inode->i_lock);
+ inode->i_state &= ~(I_DIRTY_SYNC | I_DIRTY_TIME);
+ spin_unlock(&inode->i_lock);
+ }
+
btrfs_set_stack_inode_uid(inode_item, i_uid_read(inode));
btrfs_set_stack_inode_gid(inode_item, i_gid_read(inode));
btrfs_set_stack_inode_size(inode_item, BTRFS_I(inode)->disk_i_size);
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 8d47c76b7bd1..36aa75f4e532 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -2069,6 +2069,17 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)

trace_btrfs_sync_file(file, datasync);

+ if (!datasync && inode->i_sb->s_flags & SB_LAZYTIME) {
+ while (1) {
+ ret = sync_inode_metadata(inode, 0);
+ if (ret != -EAGAIN)
+ break;
+ flush_work(&fs_info->async_reclaim_work);
+ }
+ if (ret)
+ return ret;
+ }
+
btrfs_init_log_ctx(&ctx, inode);

/*
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 5509c41a4f43..a60aee76cc95 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3941,6 +3941,12 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,

btrfs_init_map_token(&token, leaf);

+ if (inode->i_sb->s_flags & SB_LAZYTIME) {
+ spin_lock(&inode->i_lock);
+ inode->i_state &= ~(I_DIRTY_SYNC | I_DIRTY_TIME);
+ spin_unlock(&inode->i_lock);
+ }
+
btrfs_set_token_inode_uid(leaf, item, i_uid_read(inode), &token);
btrfs_set_token_inode_gid(leaf, item, i_gid_read(inode), &token);
btrfs_set_token_inode_size(leaf, item, BTRFS_I(inode)->disk_i_size,
@@ -6188,6 +6194,16 @@ static int btrfs_dirty_inode(struct inode *inode)
return ret;
}

+int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc)
+{
+ if (work_busy(&btrfs_sb(inode->i_sb)->async_reclaim_work) & WORK_BUSY_RUNNING) {
+ mark_inode_dirty_sync(inode);
+ return -EAGAIN;
+ }
+
+ return btrfs_dirty_inode(inode);
+}
+
/*
* This is a copy of file_update_time. We need this so we can return error on
* ENOSPC for updating the inode in the case of file write and mmap writes.
@@ -6201,15 +6217,21 @@ static int btrfs_update_time(struct inode *inode, struct timespec64 *now,
if (btrfs_root_readonly(root))
return -EROFS;

- if (flags & S_VERSION)
- dirty |= inode_maybe_inc_iversion(inode, dirty);
+ if (!(flags & S_VERSION && inode_maybe_inc_iversion(inode, dirty))) {
+ if (unlikely(!dirty))
+ return 0;
+ if (inode->i_sb->s_flags & SB_LAZYTIME &&
+ !test_bit(BTRFS_INODE_DUMMY, &BTRFS_I(inode)->runtime_flags))
+ return generic_update_time(inode, now, flags);
+ }
+
if (flags & S_CTIME)
inode->i_ctime = *now;
if (flags & S_MTIME)
inode->i_mtime = *now;
if (flags & S_ATIME)
inode->i_atime = *now;
- return dirty ? btrfs_dirty_inode(inode) : 0;
+ return btrfs_dirty_inode(inode);
}

/*
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 18e328ce4b54..af47b4b046de 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -799,6 +799,14 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
if (ret)
goto dec_and_free;

+ /* For xfstests generic/003. Is it better to fix the test? */
+ if (dir->i_sb->s_flags & SB_LAZYTIME) {
+ down_read(&dir->i_sb->s_umount);
+ if (!sb_rdonly(dir->i_sb))
+ sync_inodes_sb(dir->i_sb);
+ up_read(&dir->i_sb->s_umount);
+ }
+
/*
* All previous writes have started writeback in NOCOW mode, so now
* we force future writes to fallback to COW mode during snapshot
@@ -5497,6 +5505,12 @@ long btrfs_ioctl(struct file *file, unsigned int
ret = btrfs_start_delalloc_roots(fs_info, -1);
if (ret)
return ret;
+ if (inode->i_sb->s_flags & SB_LAZYTIME) {
+ down_read(&inode->i_sb->s_umount);
+ if (!sb_rdonly(inode->i_sb))
+ sync_inodes_sb(inode->i_sb);
+ up_read(&inode->i_sb->s_umount);
+ }
ret = btrfs_sync_fs(inode->i_sb, 1);
/*
* The transaction thread may want to do more work,
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index f452a94abdc3..ccfe9aff1394 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -2281,6 +2281,7 @@ static int btrfs_show_devname(struct seq_file *m, struct dentry *root)
}

static const struct super_operations btrfs_super_ops = {
+ .write_inode = btrfs_write_inode,
.drop_inode = btrfs_drop_inode,
.evict_inode = btrfs_evict_inode,
.put_super = btrfs_put_super,
--
2.25.0.rc2