linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] f2fs: compress: fix potential deadlock of compress file
       [not found] <CGME20211210043017epcas1p38cc53389a50e33752e97618498b18f33@epcas1p3.samsung.com>
@ 2021-12-10  4:30 ` Hyeong-Jun Kim
  2021-12-10  6:32   ` [f2fs-dev] " fengnan chang
  2021-12-10 14:59   ` Chao Yu
  0 siblings, 2 replies; 3+ messages in thread
From: Hyeong-Jun Kim @ 2021-12-10  4:30 UTC (permalink / raw)
  To: Jaegeuk Kim, Chao Yu
  Cc: Hyeong-Jun Kim, Sungjong Seo, Youngjin Gil, linux-f2fs-devel,
	linux-kernel

There is a potential deadlock between writeback process and a process
performing write_begin() or write_cache_pages() while trying to write
same compress file, but not compressable, as below:

[Process A] - doing checkpoint
[Process B]                     [Process C]
f2fs_write_cache_pages()
- lock_page() [all pages in cluster, 0-31]
- f2fs_write_multi_pages()
 - f2fs_write_raw_pages()
  - f2fs_write_single_data_page()
   - f2fs_do_write_data_page()
     - return -EAGAIN [f2fs_trylock_op() failed]
   - unlock_page(page) [e.g., page 0]
                                - generic_perform_write()
                                 - f2fs_write_begin()
                                  - f2fs_prepare_compress_overwrite()
                                   - prepare_compress_overwrite()
                                    - lock_page() [e.g., page 0]
                                    - lock_page() [e.g., page 1]
   - lock_page(page) [e.g., page 0]

Since there is no compress process, it is no longer necessary to hold
locks on every pages in cluster within f2fs_write_raw_pages().

This patch changes f2fs_write_raw_pages() to release all locks first
and then perform write same as the non-compress file in
f2fs_write_cache_pages().

Fixes: 4c8ff7095bef ("f2fs: support data compression")
Signed-off-by: Hyeong-Jun Kim <hj514.kim@samsung.com>
Signed-off-by: Sungjong Seo <sj1557.seo@samsung.com>
Signed-off-by: Youngjin Gil <youngjin.gil@samsung.com>
---
 fs/f2fs/compress.c | 50 ++++++++++++++++++++--------------------------
 1 file changed, 22 insertions(+), 28 deletions(-)

diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index 7588e4e817b8..5aae63b5eb5c 100644
--- a/fs/f2fs/compress.c
+++ b/fs/f2fs/compress.c
@@ -1467,25 +1467,38 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,
 					enum iostat_type io_type)
 {
 	struct address_space *mapping = cc->inode->i_mapping;
-	int _submitted, compr_blocks, ret;
-	int i = -1, err = 0;
+	int _submitted, compr_blocks, ret, i;
 
 	compr_blocks = f2fs_compressed_blocks(cc);
-	if (compr_blocks < 0) {
-		err = compr_blocks;
-		goto out_err;
+
+	for (i = 0; i < cc->cluster_size; i++) {
+		if (!cc->rpages[i])
+			continue;
+
+		redirty_page_for_writepage(wbc, cc->rpages[i]);
+		unlock_page(cc->rpages[i]);
 	}
 
+	if (compr_blocks < 0)
+		return compr_blocks;
+
 	for (i = 0; i < cc->cluster_size; i++) {
 		if (!cc->rpages[i])
 			continue;
 retry_write:
+		lock_page(cc->rpages[i]);
+
 		if (cc->rpages[i]->mapping != mapping) {
+continue_unlock:
 			unlock_page(cc->rpages[i]);
 			continue;
 		}
 
-		BUG_ON(!PageLocked(cc->rpages[i]));
+		if (!PageDirty(cc->rpages[i]))
+			goto continue_unlock;
+
+		if (!clear_page_dirty_for_io(cc->rpages[i]))
+			goto continue_unlock;
 
 		ret = f2fs_write_single_data_page(cc->rpages[i], &_submitted,
 						NULL, NULL, wbc, io_type,
@@ -1500,26 +1513,15 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,
 				 * avoid deadlock caused by cluster update race
 				 * from foreground operation.
 				 */
-				if (IS_NOQUOTA(cc->inode)) {
-					err = 0;
-					goto out_err;
-				}
+				if (IS_NOQUOTA(cc->inode))
+					return 0;
 				ret = 0;
 				cond_resched();
 				congestion_wait(BLK_RW_ASYNC,
 						DEFAULT_IO_TIMEOUT);
-				lock_page(cc->rpages[i]);
-
-				if (!PageDirty(cc->rpages[i])) {
-					unlock_page(cc->rpages[i]);
-					continue;
-				}
-
-				clear_page_dirty_for_io(cc->rpages[i]);
 				goto retry_write;
 			}
-			err = ret;
-			goto out_err;
+			return ret;
 		}
 
 		*submitted += _submitted;
@@ -1528,14 +1530,6 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,
 	f2fs_balance_fs(F2FS_M_SB(mapping), true);
 
 	return 0;
-out_err:
-	for (++i; i < cc->cluster_size; i++) {
-		if (!cc->rpages[i])
-			continue;
-		redirty_page_for_writepage(wbc, cc->rpages[i]);
-		unlock_page(cc->rpages[i]);
-	}
-	return err;
 }
 
 int f2fs_write_multi_pages(struct compress_ctx *cc,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [f2fs-dev] [PATCH] f2fs: compress: fix potential deadlock of compress file
  2021-12-10  4:30 ` [PATCH] f2fs: compress: fix potential deadlock of compress file Hyeong-Jun Kim
@ 2021-12-10  6:32   ` fengnan chang
  2021-12-10 14:59   ` Chao Yu
  1 sibling, 0 replies; 3+ messages in thread
From: fengnan chang @ 2021-12-10  6:32 UTC (permalink / raw)
  To: Hyeong-Jun Kim
  Cc: Jaegeuk Kim, Chao Yu, linux-kernel, linux-f2fs-devel, Sungjong Seo

Great work,it fix my problem.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] f2fs: compress: fix potential deadlock of compress file
  2021-12-10  4:30 ` [PATCH] f2fs: compress: fix potential deadlock of compress file Hyeong-Jun Kim
  2021-12-10  6:32   ` [f2fs-dev] " fengnan chang
@ 2021-12-10 14:59   ` Chao Yu
  1 sibling, 0 replies; 3+ messages in thread
From: Chao Yu @ 2021-12-10 14:59 UTC (permalink / raw)
  To: Hyeong-Jun Kim, Fengnan Chang, Jaegeuk Kim
  Cc: Sungjong Seo, Youngjin Gil, linux-f2fs-devel, linux-kernel

On 2021/12/10 12:30, Hyeong-Jun Kim wrote:
> There is a potential deadlock between writeback process and a process
> performing write_begin() or write_cache_pages() while trying to write
> same compress file, but not compressable, as below:
> 
> [Process A] - doing checkpoint
> [Process B]                     [Process C]
> f2fs_write_cache_pages()
> - lock_page() [all pages in cluster, 0-31]
> - f2fs_write_multi_pages()
>   - f2fs_write_raw_pages()
>    - f2fs_write_single_data_page()
>     - f2fs_do_write_data_page()
>       - return -EAGAIN [f2fs_trylock_op() failed]
>     - unlock_page(page) [e.g., page 0]
>                                  - generic_perform_write()
>                                   - f2fs_write_begin()
>                                    - f2fs_prepare_compress_overwrite()
>                                     - prepare_compress_overwrite()
>                                      - lock_page() [e.g., page 0]
>                                      - lock_page() [e.g., page 1]
>     - lock_page(page) [e.g., page 0]
> 
> Since there is no compress process, it is no longer necessary to hold
> locks on every pages in cluster within f2fs_write_raw_pages().
> 
> This patch changes f2fs_write_raw_pages() to release all locks first
> and then perform write same as the non-compress file in
> f2fs_write_cache_pages().
> 
> Fixes: 4c8ff7095bef ("f2fs: support data compression")
> Signed-off-by: Hyeong-Jun Kim <hj514.kim@samsung.com>
> Signed-off-by: Sungjong Seo <sj1557.seo@samsung.com>
> Signed-off-by: Youngjin Gil <youngjin.gil@samsung.com>

Looks good to me, thanks for Fengnan and Hyeong-Jun's report and Hyeong-Jun's
fixing. :)

Reviewed-by: Chao Yu <chao@kernel.org>

Thanks,

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-12-10 14:59 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CGME20211210043017epcas1p38cc53389a50e33752e97618498b18f33@epcas1p3.samsung.com>
2021-12-10  4:30 ` [PATCH] f2fs: compress: fix potential deadlock of compress file Hyeong-Jun Kim
2021-12-10  6:32   ` [f2fs-dev] " fengnan chang
2021-12-10 14:59   ` Chao Yu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).