Skip to content

Commit b763f3b

Browse files
chaseyuJaegeuk Kim
authored andcommitted
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/[email protected]/T/#u Cc: Matthew Wilcox <[email protected]> Signed-off-by: Chao Yu <[email protected]> Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent ee68d27 commit b763f3b

File tree

11 files changed

+146
-109
lines changed

11 files changed

+146
-109
lines changed

fs/f2fs/checkpoint.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ static int f2fs_set_meta_page_dirty(struct page *page)
444444
if (!PageDirty(page)) {
445445
__set_page_dirty_nobuffers(page);
446446
inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_META);
447-
f2fs_set_page_private(page, 0);
447+
set_page_private_reference(page);
448448
return 1;
449449
}
450450
return 0;
@@ -1018,7 +1018,7 @@ void f2fs_update_dirty_page(struct inode *inode, struct page *page)
10181018
inode_inc_dirty_pages(inode);
10191019
spin_unlock(&sbi->inode_lock[type]);
10201020

1021-
f2fs_set_page_private(page, 0);
1021+
set_page_private_reference(page);
10221022
}
10231023

10241024
void f2fs_remove_dirty_inode(struct inode *inode)

fs/f2fs/compress.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ bool f2fs_is_compressed_page(struct page *page)
7474
return false;
7575
if (!page_private(page))
7676
return false;
77-
if (IS_ATOMIC_WRITTEN_PAGE(page) || IS_DUMMY_WRITTEN_PAGE(page))
77+
if (page_private_nonpointer(page))
7878
return false;
7979

8080
f2fs_bug_on(F2FS_M_SB(page->mapping),
@@ -85,8 +85,7 @@ bool f2fs_is_compressed_page(struct page *page)
8585
static void f2fs_set_compressed_page(struct page *page,
8686
struct inode *inode, pgoff_t index, void *data)
8787
{
88-
SetPagePrivate(page);
89-
set_page_private(page, (unsigned long)data);
88+
attach_page_private(page, (void *)data);
9089

9190
/* i_crypto_info and iv index */
9291
page->index = index;
@@ -589,8 +588,7 @@ static void f2fs_compress_free_page(struct page *page)
589588
{
590589
if (!page)
591590
return;
592-
set_page_private(page, (unsigned long)NULL);
593-
ClearPagePrivate(page);
591+
detach_page_private(page);
594592
page->mapping = NULL;
595593
unlock_page(page);
596594
mempool_free(page, compress_page_pool);
@@ -1405,7 +1403,7 @@ void f2fs_compress_write_end_io(struct bio *bio, struct page *page)
14051403

14061404
for (i = 0; i < cic->nr_rpages; i++) {
14071405
WARN_ON(!cic->rpages[i]);
1408-
clear_cold_data(cic->rpages[i]);
1406+
clear_page_private_gcing(cic->rpages[i]);
14091407
end_page_writeback(cic->rpages[i]);
14101408
}
14111409

fs/f2fs/data.c

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,19 @@ static bool __is_cp_guaranteed(struct page *page)
5858
if (!mapping)
5959
return false;
6060

61-
if (f2fs_is_compressed_page(page))
62-
return false;
63-
6461
inode = mapping->host;
6562
sbi = F2FS_I_SB(inode);
6663

6764
if (inode->i_ino == F2FS_META_INO(sbi) ||
6865
inode->i_ino == F2FS_NODE_INO(sbi) ||
69-
S_ISDIR(inode->i_mode) ||
70-
(S_ISREG(inode->i_mode) &&
66+
S_ISDIR(inode->i_mode))
67+
return true;
68+
69+
if (f2fs_is_compressed_page(page))
70+
return false;
71+
if ((S_ISREG(inode->i_mode) &&
7172
(f2fs_is_atomic_file(inode) || IS_NOQUOTA(inode))) ||
72-
is_cold_data(page))
73+
page_private_gcing(page))
7374
return true;
7475
return false;
7576
}
@@ -299,9 +300,8 @@ static void f2fs_write_end_io(struct bio *bio)
299300
struct page *page = bvec->bv_page;
300301
enum count_type type = WB_DATA_TYPE(page);
301302

302-
if (IS_DUMMY_WRITTEN_PAGE(page)) {
303-
set_page_private(page, (unsigned long)NULL);
304-
ClearPagePrivate(page);
303+
if (page_private_dummy(page)) {
304+
clear_page_private_dummy(page);
305305
unlock_page(page);
306306
mempool_free(page, sbi->write_io_dummy);
307307

@@ -331,7 +331,7 @@ static void f2fs_write_end_io(struct bio *bio)
331331
dec_page_count(sbi, type);
332332
if (f2fs_in_warm_node_list(sbi, page))
333333
f2fs_del_fsync_node_entry(sbi, page);
334-
clear_cold_data(page);
334+
clear_page_private_gcing(page);
335335
end_page_writeback(page);
336336
}
337337
if (!get_pages(sbi, F2FS_WB_CP_DATA) &&
@@ -455,10 +455,11 @@ static inline void __submit_bio(struct f2fs_sb_info *sbi,
455455
GFP_NOIO | __GFP_NOFAIL);
456456
f2fs_bug_on(sbi, !page);
457457

458-
zero_user_segment(page, 0, PAGE_SIZE);
459-
SetPagePrivate(page);
460-
set_page_private(page, DUMMY_WRITTEN_PAGE);
461458
lock_page(page);
459+
460+
zero_user_segment(page, 0, PAGE_SIZE);
461+
set_page_private_dummy(page);
462+
462463
if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE)
463464
f2fs_bug_on(sbi, 1);
464465
}
@@ -2482,9 +2483,9 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio)
24822483
if (f2fs_is_atomic_file(inode))
24832484
return true;
24842485
if (fio) {
2485-
if (is_cold_data(fio->page))
2486+
if (page_private_gcing(fio->page))
24862487
return true;
2487-
if (IS_ATOMIC_WRITTEN_PAGE(fio->page))
2488+
if (page_private_dummy(fio->page))
24882489
return true;
24892490
if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) &&
24902491
f2fs_is_checkpointed_data(sbi, fio->old_blkaddr)))
@@ -2540,7 +2541,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
25402541
/* This page is already truncated */
25412542
if (fio->old_blkaddr == NULL_ADDR) {
25422543
ClearPageUptodate(page);
2543-
clear_cold_data(page);
2544+
clear_page_private_gcing(page);
25442545
goto out_writepage;
25452546
}
25462547
got_it:
@@ -2750,7 +2751,7 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
27502751
inode_dec_dirty_pages(inode);
27512752
if (err) {
27522753
ClearPageUptodate(page);
2753-
clear_cold_data(page);
2754+
clear_page_private_gcing(page);
27542755
}
27552756

27562757
if (wbc->for_reclaim) {
@@ -3224,7 +3225,7 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
32243225
f2fs_do_read_inline_data(page, ipage);
32253226
set_inode_flag(inode, FI_DATA_EXIST);
32263227
if (inode->i_nlink)
3227-
set_inline_node(ipage);
3228+
set_page_private_inline(ipage);
32283229
} else {
32293230
err = f2fs_convert_inline_page(&dn, page);
32303231
if (err)
@@ -3615,12 +3616,13 @@ void f2fs_invalidate_page(struct page *page, unsigned int offset,
36153616
}
36163617
}
36173618

3618-
clear_cold_data(page);
3619+
clear_page_private_gcing(page);
36193620

3620-
if (IS_ATOMIC_WRITTEN_PAGE(page))
3621+
if (page_private_atomic(page))
36213622
return f2fs_drop_inmem_page(inode, page);
36223623

3623-
f2fs_clear_page_private(page);
3624+
detach_page_private(page);
3625+
set_page_private(page, 0);
36243626
}
36253627

36263628
int f2fs_release_page(struct page *page, gfp_t wait)
@@ -3630,11 +3632,13 @@ int f2fs_release_page(struct page *page, gfp_t wait)
36303632
return 0;
36313633

36323634
/* This is atomic written page, keep Private */
3633-
if (IS_ATOMIC_WRITTEN_PAGE(page))
3635+
if (page_private_atomic(page))
36343636
return 0;
36353637

3636-
clear_cold_data(page);
3637-
f2fs_clear_page_private(page);
3638+
clear_page_private_gcing(page);
3639+
3640+
detach_page_private(page);
3641+
set_page_private(page, 0);
36383642
return 1;
36393643
}
36403644

@@ -3650,7 +3654,7 @@ static int f2fs_set_data_page_dirty(struct page *page)
36503654
return __set_page_dirty_nobuffers(page);
36513655

36523656
if (f2fs_is_atomic_file(inode) && !f2fs_is_commit_atomic_write(inode)) {
3653-
if (!IS_ATOMIC_WRITTEN_PAGE(page)) {
3657+
if (!page_private_atomic(page)) {
36543658
f2fs_register_inmem_page(inode, page);
36553659
return 1;
36563660
}
@@ -3742,7 +3746,7 @@ int f2fs_migrate_page(struct address_space *mapping,
37423746
{
37433747
int rc, extra_count;
37443748
struct f2fs_inode_info *fi = F2FS_I(mapping->host);
3745-
bool atomic_written = IS_ATOMIC_WRITTEN_PAGE(page);
3749+
bool atomic_written = page_private_atomic(page);
37463750

37473751
BUG_ON(PageWriteback(page));
37483752

@@ -3778,8 +3782,13 @@ int f2fs_migrate_page(struct address_space *mapping,
37783782
}
37793783

37803784
if (PagePrivate(page)) {
3781-
f2fs_set_page_private(newpage, page_private(page));
3782-
f2fs_clear_page_private(page);
3785+
set_page_private(newpage, page_private(page));
3786+
SetPagePrivate(newpage);
3787+
get_page(newpage);
3788+
3789+
set_page_private(page, 0);
3790+
ClearPagePrivate(page);
3791+
put_page(page);
37833792
}
37843793

37853794
if (mode != MIGRATE_SYNC_NO_COPY)

fs/f2fs/dir.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -929,11 +929,15 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
929929
!f2fs_truncate_hole(dir, page->index, page->index + 1)) {
930930
f2fs_clear_page_cache_dirty_tag(page);
931931
clear_page_dirty_for_io(page);
932-
f2fs_clear_page_private(page);
933932
ClearPageUptodate(page);
934-
clear_cold_data(page);
933+
934+
clear_page_private_gcing(page);
935+
935936
inode_dec_dirty_pages(dir);
936937
f2fs_remove_dirty_inode(dir);
938+
939+
detach_page_private(page);
940+
set_page_private(page, 0);
937941
}
938942
f2fs_put_page(page, 1);
939943

fs/f2fs/f2fs.h

Lines changed: 76 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,17 +1291,85 @@ enum {
12911291
*/
12921292
};
12931293

1294+
static inline int f2fs_test_bit(unsigned int nr, char *addr);
1295+
static inline void f2fs_set_bit(unsigned int nr, char *addr);
1296+
static inline void f2fs_clear_bit(unsigned int nr, char *addr);
1297+
12941298
/*
1295-
* this value is set in page as a private data which indicate that
1296-
* the page is atomically written, and it is in inmem_pages list.
1299+
* Layout of f2fs page.private:
1300+
*
1301+
* Layout A: lowest bit should be 1
1302+
* | bit0 = 1 | bit1 | bit2 | ... | bit MAX | private data .... |
1303+
* bit 0 PAGE_PRIVATE_NOT_POINTER
1304+
* bit 1 PAGE_PRIVATE_ATOMIC_WRITE
1305+
* bit 2 PAGE_PRIVATE_DUMMY_WRITE
1306+
* bit 3 PAGE_PRIVATE_ONGOING_MIGRATION
1307+
* bit 4 PAGE_PRIVATE_INLINE_INODE
1308+
* bit 5 PAGE_PRIVATE_REF_RESOURCE
1309+
* bit 6- f2fs private data
1310+
*
1311+
* Layout B: lowest bit should be 0
1312+
* page.private is a wrapped pointer.
12971313
*/
1298-
#define ATOMIC_WRITTEN_PAGE ((unsigned long)-1)
1299-
#define DUMMY_WRITTEN_PAGE ((unsigned long)-2)
1314+
enum {
1315+
PAGE_PRIVATE_NOT_POINTER, /* private contains non-pointer data */
1316+
PAGE_PRIVATE_ATOMIC_WRITE, /* data page from atomic write path */
1317+
PAGE_PRIVATE_DUMMY_WRITE, /* data page for padding aligned IO */
1318+
PAGE_PRIVATE_ONGOING_MIGRATION, /* data page which is on-going migrating */
1319+
PAGE_PRIVATE_INLINE_INODE, /* inode page contains inline data */
1320+
PAGE_PRIVATE_REF_RESOURCE, /* dirty page has referenced resources */
1321+
PAGE_PRIVATE_MAX
1322+
};
1323+
1324+
#define PAGE_PRIVATE_GET_FUNC(name, flagname) \
1325+
static inline bool page_private_##name(struct page *page) \
1326+
{ \
1327+
return test_bit(PAGE_PRIVATE_NOT_POINTER, &page_private(page)) && \
1328+
test_bit(PAGE_PRIVATE_##flagname, &page_private(page)); \
1329+
}
1330+
1331+
#define PAGE_PRIVATE_SET_FUNC(name, flagname) \
1332+
static inline void set_page_private_##name(struct page *page) \
1333+
{ \
1334+
if (!PagePrivate(page)) { \
1335+
get_page(page); \
1336+
SetPagePrivate(page); \
1337+
} \
1338+
set_bit(PAGE_PRIVATE_NOT_POINTER, &page_private(page)); \
1339+
set_bit(PAGE_PRIVATE_##flagname, &page_private(page)); \
1340+
}
13001341

1301-
#define IS_ATOMIC_WRITTEN_PAGE(page) \
1302-
(page_private(page) == ATOMIC_WRITTEN_PAGE)
1303-
#define IS_DUMMY_WRITTEN_PAGE(page) \
1304-
(page_private(page) == DUMMY_WRITTEN_PAGE)
1342+
#define PAGE_PRIVATE_CLEAR_FUNC(name, flagname) \
1343+
static inline void clear_page_private_##name(struct page *page) \
1344+
{ \
1345+
clear_bit(PAGE_PRIVATE_##flagname, &page_private(page)); \
1346+
if (page_private(page) == 1 << PAGE_PRIVATE_NOT_POINTER) { \
1347+
set_page_private(page, 0); \
1348+
if (PagePrivate(page)) { \
1349+
ClearPagePrivate(page); \
1350+
put_page(page); \
1351+
}\
1352+
} \
1353+
}
1354+
1355+
PAGE_PRIVATE_GET_FUNC(nonpointer, NOT_POINTER);
1356+
PAGE_PRIVATE_GET_FUNC(reference, REF_RESOURCE);
1357+
PAGE_PRIVATE_GET_FUNC(inline, INLINE_INODE);
1358+
PAGE_PRIVATE_GET_FUNC(gcing, ONGOING_MIGRATION);
1359+
PAGE_PRIVATE_GET_FUNC(atomic, ATOMIC_WRITE);
1360+
PAGE_PRIVATE_GET_FUNC(dummy, DUMMY_WRITE);
1361+
1362+
PAGE_PRIVATE_SET_FUNC(reference, REF_RESOURCE);
1363+
PAGE_PRIVATE_SET_FUNC(inline, INLINE_INODE);
1364+
PAGE_PRIVATE_SET_FUNC(gcing, ONGOING_MIGRATION);
1365+
PAGE_PRIVATE_SET_FUNC(atomic, ATOMIC_WRITE);
1366+
PAGE_PRIVATE_SET_FUNC(dummy, DUMMY_WRITE);
1367+
1368+
PAGE_PRIVATE_CLEAR_FUNC(reference, REF_RESOURCE);
1369+
PAGE_PRIVATE_CLEAR_FUNC(inline, INLINE_INODE);
1370+
PAGE_PRIVATE_CLEAR_FUNC(gcing, ONGOING_MIGRATION);
1371+
PAGE_PRIVATE_CLEAR_FUNC(atomic, ATOMIC_WRITE);
1372+
PAGE_PRIVATE_CLEAR_FUNC(dummy, DUMMY_WRITE);
13051373

13061374
/* For compression */
13071375
enum compress_algorithm_type {
@@ -3169,20 +3237,6 @@ static inline bool __is_valid_data_blkaddr(block_t blkaddr)
31693237
return true;
31703238
}
31713239

3172-
static inline void f2fs_set_page_private(struct page *page,
3173-
unsigned long data)
3174-
{
3175-
if (PagePrivate(page))
3176-
return;
3177-
3178-
attach_page_private(page, (void *)data);
3179-
}
3180-
3181-
static inline void f2fs_clear_page_private(struct page *page)
3182-
{
3183-
detach_page_private(page);
3184-
}
3185-
31863240
/*
31873241
* file.c
31883242
*/

fs/f2fs/gc.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,7 +1336,7 @@ static int move_data_page(struct inode *inode, block_t bidx, int gc_type,
13361336
goto out;
13371337
}
13381338
set_page_dirty(page);
1339-
set_cold_data(page);
1339+
set_page_private_gcing(page);
13401340
} else {
13411341
struct f2fs_io_info fio = {
13421342
.sbi = F2FS_I_SB(inode),
@@ -1362,11 +1362,11 @@ static int move_data_page(struct inode *inode, block_t bidx, int gc_type,
13621362
f2fs_remove_dirty_inode(inode);
13631363
}
13641364

1365-
set_cold_data(page);
1365+
set_page_private_gcing(page);
13661366

13671367
err = f2fs_do_write_data_page(&fio);
13681368
if (err) {
1369-
clear_cold_data(page);
1369+
clear_page_private_gcing(page);
13701370
if (err == -ENOMEM) {
13711371
congestion_wait(BLK_RW_ASYNC,
13721372
DEFAULT_IO_TIMEOUT);

fs/f2fs/inline.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
173173

174174
/* clear inline data and flag after data writeback */
175175
f2fs_truncate_inline_inode(dn->inode, dn->inode_page, 0);
176-
clear_inline_node(dn->inode_page);
176+
clear_page_private_inline(dn->inode_page);
177177
clear_out:
178178
stat_dec_inline_inode(dn->inode);
179179
clear_inode_flag(dn->inode, FI_INLINE_DATA);
@@ -255,7 +255,7 @@ int f2fs_write_inline_data(struct inode *inode, struct page *page)
255255
set_inode_flag(inode, FI_APPEND_WRITE);
256256
set_inode_flag(inode, FI_DATA_EXIST);
257257

258-
clear_inline_node(dn.inode_page);
258+
clear_page_private_inline(dn.inode_page);
259259
f2fs_put_dnode(&dn);
260260
return 0;
261261
}

0 commit comments

Comments
 (0)