From: Daeho Jeong <daehoje...@google.com>

In cases of removing memory donation, we need to handle some error cases
like ENOENT and EACCES (indicating the range already has been donated).

Signed-off-by: Daeho Jeong <daehoje...@google.com>
---
v2: use proper error code
    rename FI_DONATE_FINISHED and use it to fix race conditions
---
 fs/f2fs/f2fs.h     |  1 +
 fs/f2fs/file.c     | 23 ++++++++++++++++-------
 fs/f2fs/shrinker.c | 13 ++++++++++---
 3 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index f1576dc6ec67..01ee8bbb5c84 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -821,6 +821,7 @@ enum {
        FI_ATOMIC_DIRTIED,      /* indicate atomic file is dirtied */
        FI_ATOMIC_REPLACE,      /* indicate atomic replace */
        FI_OPENED_FILE,         /* indicate file has been opened */
+       FI_DONATE_FINISHED,     /* indicate page donation of file has been 
finished */
        FI_MAX,                 /* max flag, never be used */
 };
 
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index abbcbb5865a3..61b88431fd43 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -2464,19 +2464,20 @@ static int f2fs_ioc_shutdown(struct file *filp, 
unsigned long arg)
        return ret;
 }
 
-static void f2fs_keep_noreuse_range(struct inode *inode,
+static int f2fs_keep_noreuse_range(struct inode *inode,
                                loff_t offset, loff_t len)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        u64 max_bytes = F2FS_BLK_TO_BYTES(max_file_blocks(inode));
        u64 start, end;
+       int ret = 0;
 
        if (!S_ISREG(inode->i_mode))
-               return;
+               return 0;
 
        if (offset >= max_bytes || len > max_bytes ||
            (offset + len) > max_bytes)
-               return;
+               return 0;
 
        start = offset >> PAGE_SHIFT;
        end = DIV_ROUND_UP(offset + len, PAGE_SIZE);
@@ -2484,7 +2485,7 @@ static void f2fs_keep_noreuse_range(struct inode *inode,
        inode_lock(inode);
        if (f2fs_is_atomic_file(inode)) {
                inode_unlock(inode);
-               return;
+               return 0;
        }
 
        spin_lock(&sbi->inode_lock[DONATE_INODE]);
@@ -2493,7 +2494,12 @@ static void f2fs_keep_noreuse_range(struct inode *inode,
                if (!list_empty(&F2FS_I(inode)->gdonate_list)) {
                        list_del_init(&F2FS_I(inode)->gdonate_list);
                        sbi->donate_files--;
-               }
+                       if (is_inode_flag_set(inode, FI_DONATE_FINISHED))
+                               ret = -EALREADY;
+                       else
+                               set_inode_flag(inode, FI_DONATE_FINISHED);
+               } else
+                       ret = -ENOENT;
        } else {
                if (list_empty(&F2FS_I(inode)->gdonate_list)) {
                        list_add_tail(&F2FS_I(inode)->gdonate_list,
@@ -2505,9 +2511,12 @@ static void f2fs_keep_noreuse_range(struct inode *inode,
                }
                F2FS_I(inode)->donate_start = start;
                F2FS_I(inode)->donate_end = end - 1;
+               clear_inode_flag(inode, FI_DONATE_FINISHED);
        }
        spin_unlock(&sbi->inode_lock[DONATE_INODE]);
        inode_unlock(inode);
+
+       return ret;
 }
 
 static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg)
@@ -5236,8 +5245,8 @@ static int f2fs_file_fadvise(struct file *filp, loff_t 
offset, loff_t len,
             f2fs_compressed_file(inode)))
                f2fs_invalidate_compress_pages(F2FS_I_SB(inode), inode->i_ino);
        else if (advice == POSIX_FADV_NOREUSE)
-               f2fs_keep_noreuse_range(inode, offset, len);
-       return 0;
+               err = f2fs_keep_noreuse_range(inode, offset, len);
+       return err;
 }
 
 #ifdef CONFIG_COMPAT
diff --git a/fs/f2fs/shrinker.c b/fs/f2fs/shrinker.c
index 9c8d3aee89af..b88babcf6ab4 100644
--- a/fs/f2fs/shrinker.c
+++ b/fs/f2fs/shrinker.c
@@ -184,10 +184,17 @@ static unsigned int do_reclaim_caches(struct f2fs_sb_info 
*sbi,
                if (!inode)
                        continue;
 
-               len = fi->donate_end - fi->donate_start + 1;
-               npages = npages < len ? 0 : npages - len;
-               invalidate_inode_pages2_range(inode->i_mapping,
+               inode_lock(inode);
+               if (!is_inode_flag_set(inode, FI_DONATE_FINISHED)) {
+                       len = fi->donate_end - fi->donate_start + 1;
+                       npages = npages < len ? 0 : npages - len;
+
+                       invalidate_inode_pages2_range(inode->i_mapping,
                                        fi->donate_start, fi->donate_end);
+                       set_inode_flag(inode, FI_DONATE_FINISHED);
+               }
+               inode_unlock(inode);
+
                iput(inode);
                cond_resched();
        }
-- 
2.49.0.805.g082f7c87e0-goog



_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

Reply via email to