f2fs: restructure f2fs page.private layout
authorChao Yu <yuchao0@huawei.com>
Wed, 28 Apr 2021 09:20:31 +0000 (17:20 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Fri, 14 May 2021 18:22:08 +0000 (11:22 -0700)
commitb763f3bedc2da2edf81bba550430847f561eae0e
tree576dba8be5b414c801d8c4d61626505f7780189b
parentee68d27181f060fab29e60d1d31aab6a42703dd4
f2fs: restructure f2fs page.private layout

Restruct f2fs page private layout for below reasons:

There are some cases that f2fs wants to set a flag in a page to
indicate a specified status of page:
a) page is in transaction list for atomic write
b) page contains dummy data for aligned write
c) page is migrating for GC
d) page contains inline data for inline inode flush
e) page belongs to merkle tree, and is verified for fsverity
f) page is dirty and has filesystem/inode reference count for writeback
g) page is temporary and has decompress io context reference for compression

There are existed places in page structure we can use to store
f2fs private status/data:
- page.flags: PG_checked, PG_private
- page.private

However it was a mess when we using them, which may cause potential
confliction:
page.private PG_private PG_checked page._refcount (+1 at most)
a) -1 set +1
b) -2 set
c), d), e) set
f) 0 set +1
g) pointer set

The other problem is page.flags has no free slot, if we can avoid set
zero to page.private and set PG_private flag, then we use non-zero value
to indicate PG_private status, so that we may have chance to reclaim
PG_private slot for other usage. [1]

The other concern is f2fs has bad scalability in aspect of indicating
more page status.

So in this patch, let's restructure f2fs' page.private as below to
solve above issues:

Layout A: lowest bit should be 1
| bit0 = 1 | bit1 | bit2 | ... | bit MAX | private data .... |
 bit 0 PAGE_PRIVATE_NOT_POINTER
 bit 1 PAGE_PRIVATE_ATOMIC_WRITE
 bit 2 PAGE_PRIVATE_DUMMY_WRITE
 bit 3 PAGE_PRIVATE_ONGOING_MIGRATION
 bit 4 PAGE_PRIVATE_INLINE_INODE
 bit 5 PAGE_PRIVATE_REF_RESOURCE
 bit 6- f2fs private data

Layout B: lowest bit should be 0
 page.private is a wrapped pointer.

After the change:
page.private PG_private PG_checked page._refcount (+1 at most)
a) 11 set +1
b) 101 set +1
c) 1001 set +1
d) 10001 set +1
e) set
f) 100001 set +1
g) pointer set +1

[1] https://lore.kernel.org/linux-f2fs-devel/20210422154705.GO3596236@casper.infradead.org/T/#u

Cc: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/checkpoint.c
fs/f2fs/compress.c
fs/f2fs/data.c
fs/f2fs/dir.c
fs/f2fs/f2fs.h
fs/f2fs/gc.c
fs/f2fs/inline.c
fs/f2fs/inode.c
fs/f2fs/node.c
fs/f2fs/node.h
fs/f2fs/segment.c