Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

f2fs: handle error cases of memory donation

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 <daehojeong@google.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>

authored by

Daeho Jeong and committed by
Jaegeuk Kim
cf7cd17c bb5eb8a5

+27 -10
+1
fs/f2fs/f2fs.h
··· 828 828 FI_ATOMIC_DIRTIED, /* indicate atomic file is dirtied */ 829 829 FI_ATOMIC_REPLACE, /* indicate atomic replace */ 830 830 FI_OPENED_FILE, /* indicate file has been opened */ 831 + FI_DONATE_FINISHED, /* indicate page donation of file has been finished */ 831 832 FI_MAX, /* max flag, never be used */ 832 833 }; 833 834
+16 -7
fs/f2fs/file.c
··· 2468 2468 return ret; 2469 2469 } 2470 2470 2471 - static void f2fs_keep_noreuse_range(struct inode *inode, 2471 + static int f2fs_keep_noreuse_range(struct inode *inode, 2472 2472 loff_t offset, loff_t len) 2473 2473 { 2474 2474 struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 2475 2475 u64 max_bytes = F2FS_BLK_TO_BYTES(max_file_blocks(inode)); 2476 2476 u64 start, end; 2477 + int ret = 0; 2477 2478 2478 2479 if (!S_ISREG(inode->i_mode)) 2479 - return; 2480 + return 0; 2480 2481 2481 2482 if (offset >= max_bytes || len > max_bytes || 2482 2483 (offset + len) > max_bytes) 2483 - return; 2484 + return 0; 2484 2485 2485 2486 start = offset >> PAGE_SHIFT; 2486 2487 end = DIV_ROUND_UP(offset + len, PAGE_SIZE); ··· 2489 2488 inode_lock(inode); 2490 2489 if (f2fs_is_atomic_file(inode)) { 2491 2490 inode_unlock(inode); 2492 - return; 2491 + return 0; 2493 2492 } 2494 2493 2495 2494 spin_lock(&sbi->inode_lock[DONATE_INODE]); ··· 2498 2497 if (!list_empty(&F2FS_I(inode)->gdonate_list)) { 2499 2498 list_del_init(&F2FS_I(inode)->gdonate_list); 2500 2499 sbi->donate_files--; 2501 - } 2500 + if (is_inode_flag_set(inode, FI_DONATE_FINISHED)) 2501 + ret = -EALREADY; 2502 + else 2503 + set_inode_flag(inode, FI_DONATE_FINISHED); 2504 + } else 2505 + ret = -ENOENT; 2502 2506 } else { 2503 2507 if (list_empty(&F2FS_I(inode)->gdonate_list)) { 2504 2508 list_add_tail(&F2FS_I(inode)->gdonate_list, ··· 2515 2509 } 2516 2510 F2FS_I(inode)->donate_start = start; 2517 2511 F2FS_I(inode)->donate_end = end - 1; 2512 + clear_inode_flag(inode, FI_DONATE_FINISHED); 2518 2513 } 2519 2514 spin_unlock(&sbi->inode_lock[DONATE_INODE]); 2520 2515 inode_unlock(inode); 2516 + 2517 + return ret; 2521 2518 } 2522 2519 2523 2520 static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg) ··· 5251 5242 f2fs_compressed_file(inode))) 5252 5243 f2fs_invalidate_compress_pages(F2FS_I_SB(inode), inode->i_ino); 5253 5244 else if (advice == POSIX_FADV_NOREUSE) 5254 - f2fs_keep_noreuse_range(inode, offset, len); 5255 - return 0; 5245 + err = f2fs_keep_noreuse_range(inode, offset, len); 5246 + return err; 5256 5247 } 5257 5248 5258 5249 #ifdef CONFIG_COMPAT
+10 -3
fs/f2fs/shrinker.c
··· 184 184 if (!inode) 185 185 continue; 186 186 187 - len = fi->donate_end - fi->donate_start + 1; 188 - npages = npages < len ? 0 : npages - len; 189 - invalidate_inode_pages2_range(inode->i_mapping, 187 + inode_lock(inode); 188 + if (!is_inode_flag_set(inode, FI_DONATE_FINISHED)) { 189 + len = fi->donate_end - fi->donate_start + 1; 190 + npages = npages < len ? 0 : npages - len; 191 + 192 + invalidate_inode_pages2_range(inode->i_mapping, 190 193 fi->donate_start, fi->donate_end); 194 + set_inode_flag(inode, FI_DONATE_FINISHED); 195 + } 196 + inode_unlock(inode); 197 + 191 198 iput(inode); 192 199 cond_resched(); 193 200 }