Skip to content

Commit 098c5dd

Browse files
committed
Merge tag 'erofs-for-6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs
Pull erofs updates from Gao Xiang: "No outstanding new feature for this cycle. Most of these commits are decompression cleanups which are part of the ongoing development for subpage/folio compression support as well as xattr cleanups for the upcoming xattr bloom filter optimization [1]. In addition, there are bugfixes to address some corner cases of compressed images due to global data de-duplication and arm64 16k pages. Summary: - Fix rare I/O hang on deduplicated compressed images due to loop hooked chains - Fix compact compression layout of 16k blocks on arm64 devices - Fix atomic context detection of async decompression - Decompression/Xattr code cleanups" Link: https://lore.kernel.org/r/20230621083209.116024-1-jefflexu@linux.alibaba.com [1] * tag 'erofs-for-6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs: erofs: clean up zmap.c erofs: remove unnecessary goto erofs: Fix detection of atomic context erofs: use separate xattr parsers for listxattr/getxattr erofs: unify inline/shared xattr iterators for listxattr/getxattr erofs: make the size of read data stored in buffer_ofs erofs: unify xattr_iter structures erofs: use absolute position in xattr iterator erofs: fix compact 4B support for 16k block size erofs: convert erofs_read_metabuf() to erofs_bread() for xattr erofs: use poison pointer to replace the hard-coded address erofs: use struct lockref to replace handcrafted approach erofs: adapt managed inode operations into folios erofs: kill hooked chains to avoid loops on deduplicated compressed images erofs: avoid on-stack pagepool directly passed by arguments erofs: allocate extra bvec pages directly instead of retrying erofs: clean up z_erofs_pcluster_readmore() erofs: remove the member readahead from struct z_erofs_decompress_frontend erofs: fold in z_erofs_decompress()
2 parents 74774e2 + 8241fdd commit 098c5dd

File tree

8 files changed

+438
-783
lines changed

8 files changed

+438
-783
lines changed

fs/erofs/compress.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,7 @@ static inline bool erofs_page_is_managed(const struct erofs_sb_info *sbi,
8989

9090
int z_erofs_fixup_insize(struct z_erofs_decompress_req *rq, const char *padbuf,
9191
unsigned int padbufsize);
92-
int z_erofs_decompress(struct z_erofs_decompress_req *rq,
93-
struct page **pagepool);
92+
extern const struct z_erofs_decompressor erofs_decompressors[];
9493

9594
/* prototypes for specific algorithms */
9695
int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,

fs/erofs/decompressor.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ static int z_erofs_transform_plain(struct z_erofs_decompress_req *rq,
363363
return 0;
364364
}
365365

366-
static struct z_erofs_decompressor decompressors[] = {
366+
const struct z_erofs_decompressor erofs_decompressors[] = {
367367
[Z_EROFS_COMPRESSION_SHIFTED] = {
368368
.decompress = z_erofs_transform_plain,
369369
.name = "shifted"
@@ -383,9 +383,3 @@ static struct z_erofs_decompressor decompressors[] = {
383383
},
384384
#endif
385385
};
386-
387-
int z_erofs_decompress(struct z_erofs_decompress_req *rq,
388-
struct page **pagepool)
389-
{
390-
return decompressors[rq->alg].decompress(rq, pagepool);
391-
}

fs/erofs/internal.h

Lines changed: 4 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -208,46 +208,12 @@ enum {
208208
EROFS_ZIP_CACHE_READAROUND
209209
};
210210

211-
#define EROFS_LOCKED_MAGIC (INT_MIN | 0xE0F510CCL)
212-
213211
/* basic unit of the workstation of a super_block */
214212
struct erofs_workgroup {
215-
/* the workgroup index in the workstation */
216213
pgoff_t index;
217-
218-
/* overall workgroup reference count */
219-
atomic_t refcount;
214+
struct lockref lockref;
220215
};
221216

222-
static inline bool erofs_workgroup_try_to_freeze(struct erofs_workgroup *grp,
223-
int val)
224-
{
225-
preempt_disable();
226-
if (val != atomic_cmpxchg(&grp->refcount, val, EROFS_LOCKED_MAGIC)) {
227-
preempt_enable();
228-
return false;
229-
}
230-
return true;
231-
}
232-
233-
static inline void erofs_workgroup_unfreeze(struct erofs_workgroup *grp,
234-
int orig_val)
235-
{
236-
/*
237-
* other observers should notice all modifications
238-
* in the freezing period.
239-
*/
240-
smp_mb();
241-
atomic_set(&grp->refcount, orig_val);
242-
preempt_enable();
243-
}
244-
245-
static inline int erofs_wait_on_workgroup_freezed(struct erofs_workgroup *grp)
246-
{
247-
return atomic_cond_read_relaxed(&grp->refcount,
248-
VAL != EROFS_LOCKED_MAGIC);
249-
}
250-
251217
enum erofs_kmap_type {
252218
EROFS_NO_KMAP, /* don't map the buffer */
253219
EROFS_KMAP, /* use kmap_local_page() to map the buffer */
@@ -486,7 +452,7 @@ static inline void erofs_pagepool_add(struct page **pagepool, struct page *page)
486452
void erofs_release_pages(struct page **pagepool);
487453

488454
#ifdef CONFIG_EROFS_FS_ZIP
489-
int erofs_workgroup_put(struct erofs_workgroup *grp);
455+
void erofs_workgroup_put(struct erofs_workgroup *grp);
490456
struct erofs_workgroup *erofs_find_workgroup(struct super_block *sb,
491457
pgoff_t index);
492458
struct erofs_workgroup *erofs_insert_workgroup(struct super_block *sb,
@@ -500,7 +466,6 @@ int __init z_erofs_init_zip_subsystem(void);
500466
void z_erofs_exit_zip_subsystem(void);
501467
int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi,
502468
struct erofs_workgroup *egrp);
503-
int erofs_try_to_free_cached_page(struct page *page);
504469
int z_erofs_load_lz4_config(struct super_block *sb,
505470
struct erofs_super_block *dsb,
506471
struct z_erofs_lz4_cfgs *lz4, int len);
@@ -511,6 +476,7 @@ void erofs_put_pcpubuf(void *ptr);
511476
int erofs_pcpubuf_growsize(unsigned int nrpages);
512477
void __init erofs_pcpubuf_init(void);
513478
void erofs_pcpubuf_exit(void);
479+
int erofs_init_managed_cache(struct super_block *sb);
514480
#else
515481
static inline void erofs_shrinker_register(struct super_block *sb) {}
516482
static inline void erofs_shrinker_unregister(struct super_block *sb) {}
@@ -530,6 +496,7 @@ static inline int z_erofs_load_lz4_config(struct super_block *sb,
530496
}
531497
static inline void erofs_pcpubuf_init(void) {}
532498
static inline void erofs_pcpubuf_exit(void) {}
499+
static inline int erofs_init_managed_cache(struct super_block *sb) { return 0; }
533500
#endif /* !CONFIG_EROFS_FS_ZIP */
534501

535502
#ifdef CONFIG_EROFS_FS_ZIP_LZMA

fs/erofs/super.c

Lines changed: 2 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -599,68 +599,6 @@ static int erofs_fc_parse_param(struct fs_context *fc,
599599
return 0;
600600
}
601601

602-
#ifdef CONFIG_EROFS_FS_ZIP
603-
static const struct address_space_operations managed_cache_aops;
604-
605-
static bool erofs_managed_cache_release_folio(struct folio *folio, gfp_t gfp)
606-
{
607-
bool ret = true;
608-
struct address_space *const mapping = folio->mapping;
609-
610-
DBG_BUGON(!folio_test_locked(folio));
611-
DBG_BUGON(mapping->a_ops != &managed_cache_aops);
612-
613-
if (folio_test_private(folio))
614-
ret = erofs_try_to_free_cached_page(&folio->page);
615-
616-
return ret;
617-
}
618-
619-
/*
620-
* It will be called only on inode eviction. In case that there are still some
621-
* decompression requests in progress, wait with rescheduling for a bit here.
622-
* We could introduce an extra locking instead but it seems unnecessary.
623-
*/
624-
static void erofs_managed_cache_invalidate_folio(struct folio *folio,
625-
size_t offset, size_t length)
626-
{
627-
const size_t stop = length + offset;
628-
629-
DBG_BUGON(!folio_test_locked(folio));
630-
631-
/* Check for potential overflow in debug mode */
632-
DBG_BUGON(stop > folio_size(folio) || stop < length);
633-
634-
if (offset == 0 && stop == folio_size(folio))
635-
while (!erofs_managed_cache_release_folio(folio, GFP_NOFS))
636-
cond_resched();
637-
}
638-
639-
static const struct address_space_operations managed_cache_aops = {
640-
.release_folio = erofs_managed_cache_release_folio,
641-
.invalidate_folio = erofs_managed_cache_invalidate_folio,
642-
};
643-
644-
static int erofs_init_managed_cache(struct super_block *sb)
645-
{
646-
struct erofs_sb_info *const sbi = EROFS_SB(sb);
647-
struct inode *const inode = new_inode(sb);
648-
649-
if (!inode)
650-
return -ENOMEM;
651-
652-
set_nlink(inode, 1);
653-
inode->i_size = OFFSET_MAX;
654-
655-
inode->i_mapping->a_ops = &managed_cache_aops;
656-
mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
657-
sbi->managed_cache = inode;
658-
return 0;
659-
}
660-
#else
661-
static int erofs_init_managed_cache(struct super_block *sb) { return 0; }
662-
#endif
663-
664602
static struct inode *erofs_nfs_get_inode(struct super_block *sb,
665603
u64 ino, u32 generation)
666604
{
@@ -1016,10 +954,8 @@ static int __init erofs_module_init(void)
1016954
sizeof(struct erofs_inode), 0,
1017955
SLAB_RECLAIM_ACCOUNT,
1018956
erofs_inode_init_once);
1019-
if (!erofs_inode_cachep) {
1020-
err = -ENOMEM;
1021-
goto icache_err;
1022-
}
957+
if (!erofs_inode_cachep)
958+
return -ENOMEM;
1023959

1024960
err = erofs_init_shrinker();
1025961
if (err)
@@ -1054,7 +990,6 @@ static int __init erofs_module_init(void)
1054990
erofs_exit_shrinker();
1055991
shrinker_err:
1056992
kmem_cache_destroy(erofs_inode_cachep);
1057-
icache_err:
1058993
return err;
1059994
}
1060995

fs/erofs/utils.c

Lines changed: 41 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
* https://www.huawei.com/
55
*/
66
#include "internal.h"
7-
#include <linux/pagevec.h>
87

98
struct page *erofs_allocpage(struct page **pagepool, gfp_t gfp)
109
{
@@ -33,22 +32,21 @@ void erofs_release_pages(struct page **pagepool)
3332
/* global shrink count (for all mounted EROFS instances) */
3433
static atomic_long_t erofs_global_shrink_cnt;
3534

36-
static int erofs_workgroup_get(struct erofs_workgroup *grp)
35+
static bool erofs_workgroup_get(struct erofs_workgroup *grp)
3736
{
38-
int o;
37+
if (lockref_get_not_zero(&grp->lockref))
38+
return true;
3939

40-
repeat:
41-
o = erofs_wait_on_workgroup_freezed(grp);
42-
if (o <= 0)
43-
return -1;
44-
45-
if (atomic_cmpxchg(&grp->refcount, o, o + 1) != o)
46-
goto repeat;
40+
spin_lock(&grp->lockref.lock);
41+
if (__lockref_is_dead(&grp->lockref)) {
42+
spin_unlock(&grp->lockref.lock);
43+
return false;
44+
}
4745

48-
/* decrease refcount paired by erofs_workgroup_put */
49-
if (o == 1)
46+
if (!grp->lockref.count++)
5047
atomic_long_dec(&erofs_global_shrink_cnt);
51-
return 0;
48+
spin_unlock(&grp->lockref.lock);
49+
return true;
5250
}
5351

5452
struct erofs_workgroup *erofs_find_workgroup(struct super_block *sb,
@@ -61,7 +59,7 @@ struct erofs_workgroup *erofs_find_workgroup(struct super_block *sb,
6159
rcu_read_lock();
6260
grp = xa_load(&sbi->managed_pslots, index);
6361
if (grp) {
64-
if (erofs_workgroup_get(grp)) {
62+
if (!erofs_workgroup_get(grp)) {
6563
/* prefer to relax rcu read side */
6664
rcu_read_unlock();
6765
goto repeat;
@@ -80,11 +78,10 @@ struct erofs_workgroup *erofs_insert_workgroup(struct super_block *sb,
8078
struct erofs_workgroup *pre;
8179

8280
/*
83-
* Bump up a reference count before making this visible
84-
* to others for the XArray in order to avoid potential
85-
* UAF without serialized by xa_lock.
81+
* Bump up before making this visible to others for the XArray in order
82+
* to avoid potential UAF without serialized by xa_lock.
8683
*/
87-
atomic_inc(&grp->refcount);
84+
lockref_get(&grp->lockref);
8885

8986
repeat:
9087
xa_lock(&sbi->managed_pslots);
@@ -93,13 +90,13 @@ struct erofs_workgroup *erofs_insert_workgroup(struct super_block *sb,
9390
if (pre) {
9491
if (xa_is_err(pre)) {
9592
pre = ERR_PTR(xa_err(pre));
96-
} else if (erofs_workgroup_get(pre)) {
93+
} else if (!erofs_workgroup_get(pre)) {
9794
/* try to legitimize the current in-tree one */
9895
xa_unlock(&sbi->managed_pslots);
9996
cond_resched();
10097
goto repeat;
10198
}
102-
atomic_dec(&grp->refcount);
99+
lockref_put_return(&grp->lockref);
103100
grp = pre;
104101
}
105102
xa_unlock(&sbi->managed_pslots);
@@ -112,38 +109,34 @@ static void __erofs_workgroup_free(struct erofs_workgroup *grp)
112109
erofs_workgroup_free_rcu(grp);
113110
}
114111

115-
int erofs_workgroup_put(struct erofs_workgroup *grp)
112+
void erofs_workgroup_put(struct erofs_workgroup *grp)
116113
{
117-
int count = atomic_dec_return(&grp->refcount);
114+
if (lockref_put_or_lock(&grp->lockref))
115+
return;
118116

119-
if (count == 1)
117+
DBG_BUGON(__lockref_is_dead(&grp->lockref));
118+
if (grp->lockref.count == 1)
120119
atomic_long_inc(&erofs_global_shrink_cnt);
121-
else if (!count)
122-
__erofs_workgroup_free(grp);
123-
return count;
120+
--grp->lockref.count;
121+
spin_unlock(&grp->lockref.lock);
124122
}
125123

126124
static bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi,
127125
struct erofs_workgroup *grp)
128126
{
129-
/*
130-
* If managed cache is on, refcount of workgroups
131-
* themselves could be < 0 (freezed). In other words,
132-
* there is no guarantee that all refcounts > 0.
133-
*/
134-
if (!erofs_workgroup_try_to_freeze(grp, 1))
135-
return false;
127+
int free = false;
128+
129+
spin_lock(&grp->lockref.lock);
130+
if (grp->lockref.count)
131+
goto out;
136132

137133
/*
138-
* Note that all cached pages should be unattached
139-
* before deleted from the XArray. Otherwise some
140-
* cached pages could be still attached to the orphan
141-
* old workgroup when the new one is available in the tree.
134+
* Note that all cached pages should be detached before deleted from
135+
* the XArray. Otherwise some cached pages could be still attached to
136+
* the orphan old workgroup when the new one is available in the tree.
142137
*/
143-
if (erofs_try_to_free_all_cached_pages(sbi, grp)) {
144-
erofs_workgroup_unfreeze(grp, 1);
145-
return false;
146-
}
138+
if (erofs_try_to_free_all_cached_pages(sbi, grp))
139+
goto out;
147140

148141
/*
149142
* It's impossible to fail after the workgroup is freezed,
@@ -152,10 +145,13 @@ static bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi,
152145
*/
153146
DBG_BUGON(__xa_erase(&sbi->managed_pslots, grp->index) != grp);
154147

155-
/* last refcount should be connected with its managed pslot. */
156-
erofs_workgroup_unfreeze(grp, 0);
157-
__erofs_workgroup_free(grp);
158-
return true;
148+
lockref_mark_dead(&grp->lockref);
149+
free = true;
150+
out:
151+
spin_unlock(&grp->lockref.lock);
152+
if (free)
153+
__erofs_workgroup_free(grp);
154+
return free;
159155
}
160156

161157
static unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi,

0 commit comments

Comments
 (0)