f2fs: avoid stucking GC due to atomic write
f2fs doesn't allow abuse on atomic write class interface, so except limiting in-mem pages' total memory usage capacity, we need to limit atomic-write usage as well when filesystem is seriously fragmented, otherwise we may run into infinite loop during foreground GC because target blocks in victim segment are belong to atomic opened file for long time. Now, we will detect failure due to atomic write in foreground GC, if the count exceeds threshold, we will drop all atomic written data in cache, by this, I expect it can keep our system running safely to prevent Dos attack. In addition, his patch adds to show GC skip information in debugfs, now it just shows count of skipped caused by atomic write. Signed-off-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
此提交包含在:
@@ -1697,6 +1697,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)
|
||||
goto out;
|
||||
skip_flush:
|
||||
set_inode_flag(inode, FI_ATOMIC_FILE);
|
||||
clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST);
|
||||
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
|
||||
|
||||
F2FS_I(inode)->inmem_task = current;
|
||||
@@ -1738,12 +1739,17 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp)
|
||||
ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true);
|
||||
if (!ret) {
|
||||
clear_inode_flag(inode, FI_ATOMIC_FILE);
|
||||
F2FS_I(inode)->i_gc_failures[GC_FAILURE_ATOMIC] = 0;
|
||||
stat_dec_atomic_write(inode);
|
||||
}
|
||||
} else {
|
||||
ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 1, false);
|
||||
}
|
||||
err_out:
|
||||
if (is_inode_flag_set(inode, FI_ATOMIC_REVOKE_REQUEST)) {
|
||||
clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
||||
inode_unlock(inode);
|
||||
mnt_drop_write_file(filp);
|
||||
@@ -2720,12 +2726,14 @@ int f2fs_pin_file_control(struct inode *inode, bool inc)
|
||||
|
||||
/* Use i_gc_failures for normal file as a risk signal. */
|
||||
if (inc)
|
||||
f2fs_i_gc_failures_write(inode, fi->i_gc_failures + 1);
|
||||
f2fs_i_gc_failures_write(inode,
|
||||
fi->i_gc_failures[GC_FAILURE_PIN] + 1);
|
||||
|
||||
if (fi->i_gc_failures > sbi->gc_pin_file_threshold) {
|
||||
if (fi->i_gc_failures[GC_FAILURE_PIN] > sbi->gc_pin_file_threshold) {
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"%s: Enable GC = ino %lx after %x GC trials\n",
|
||||
__func__, inode->i_ino, fi->i_gc_failures);
|
||||
__func__, inode->i_ino,
|
||||
fi->i_gc_failures[GC_FAILURE_PIN]);
|
||||
clear_inode_flag(inode, FI_PIN_FILE);
|
||||
return -EAGAIN;
|
||||
}
|
||||
@@ -2763,7 +2771,7 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
|
||||
|
||||
if (!pin) {
|
||||
clear_inode_flag(inode, FI_PIN_FILE);
|
||||
F2FS_I(inode)->i_gc_failures = 1;
|
||||
F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN] = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -2776,7 +2784,7 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
|
||||
goto out;
|
||||
|
||||
set_inode_flag(inode, FI_PIN_FILE);
|
||||
ret = F2FS_I(inode)->i_gc_failures;
|
||||
ret = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN];
|
||||
done:
|
||||
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
|
||||
out:
|
||||
@@ -2791,7 +2799,7 @@ static int f2fs_ioc_get_pin_file(struct file *filp, unsigned long arg)
|
||||
__u32 pin = 0;
|
||||
|
||||
if (is_inode_flag_set(inode, FI_PIN_FILE))
|
||||
pin = F2FS_I(inode)->i_gc_failures;
|
||||
pin = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN];
|
||||
return put_user(pin, (u32 __user *)arg);
|
||||
}
|
||||
|
||||
|
新增問題並參考
封鎖使用者