Skip to content

Commit 377ad0c

Browse files
committed
Merge tag 'erofs-for-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs
Pull erofs updates from Gao Xiang: "Updates with a XArray adaptation, several fixes for shrinker and corrupted images are ready for this cycle. All commits have been stress tested with no noticeable smoke out and have been in linux-next as well. Summary: - Convert radix tree usage to XArray - Fix shrink scan count on multiple filesystem instances - Better handling for specific corrupted images - Update my email address in MAINTAINERS" * tag 'erofs-for-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs: MAINTAINERS: erofs: update my email address erofs: handle corrupted images whose decompressed size less than it'd be erofs: use LZ4_decompress_safe() for full decoding erofs: correct the remaining shrink objects erofs: convert workstn to XArray
2 parents 481ed29 + 20741a6 commit 377ad0c

File tree

6 files changed

+94
-106
lines changed

6 files changed

+94
-106
lines changed

MAINTAINERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6248,7 +6248,7 @@ F: drivers/video/fbdev/s1d13xxxfb.c
62486248
F: include/video/s1d13xxxfb.h
62496249

62506250
EROFS FILE SYSTEM
6251-
M: Gao Xiang <[email protected]>
6251+
M: Gao Xiang <[email protected]>
62526252
M: Chao Yu <[email protected]>
62536253
62546254
S: Maintained

fs/erofs/decompressor.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,17 +157,27 @@ static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq, u8 *out)
157157
}
158158
}
159159

160-
ret = LZ4_decompress_safe_partial(src + inputmargin, out,
161-
inlen, rq->outputsize,
162-
rq->outputsize);
163-
if (ret < 0) {
164-
erofs_err(rq->sb, "failed to decompress, in[%u, %u] out[%u]",
165-
inlen, inputmargin, rq->outputsize);
160+
/* legacy format could compress extra data in a pcluster. */
161+
if (rq->partial_decoding || !support_0padding)
162+
ret = LZ4_decompress_safe_partial(src + inputmargin, out,
163+
inlen, rq->outputsize,
164+
rq->outputsize);
165+
else
166+
ret = LZ4_decompress_safe(src + inputmargin, out,
167+
inlen, rq->outputsize);
168+
169+
if (ret != rq->outputsize) {
170+
erofs_err(rq->sb, "failed to decompress %d in[%u, %u] out[%u]",
171+
ret, inlen, inputmargin, rq->outputsize);
172+
166173
WARN_ON(1);
167174
print_hex_dump(KERN_DEBUG, "[ in]: ", DUMP_PREFIX_OFFSET,
168175
16, 1, src + inputmargin, inlen, true);
169176
print_hex_dump(KERN_DEBUG, "[out]: ", DUMP_PREFIX_OFFSET,
170177
16, 1, out, rq->outputsize, true);
178+
179+
if (ret >= 0)
180+
memset(out + ret, 0, rq->outputsize - ret);
171181
ret = -EIO;
172182
}
173183

fs/erofs/internal.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ struct erofs_sb_info {
5252
struct list_head list;
5353
struct mutex umount_mutex;
5454

55-
/* the dedicated workstation for compression */
56-
struct radix_tree_root workstn_tree;
55+
/* managed XArray arranged in physical block number */
56+
struct xarray managed_pslots;
5757

5858
/* threshold for decompression synchronously */
5959
unsigned int max_sync_decompress_pages;
@@ -402,8 +402,8 @@ static inline void *erofs_get_pcpubuf(unsigned int pagenr)
402402
int erofs_workgroup_put(struct erofs_workgroup *grp);
403403
struct erofs_workgroup *erofs_find_workgroup(struct super_block *sb,
404404
pgoff_t index);
405-
int erofs_register_workgroup(struct super_block *sb,
406-
struct erofs_workgroup *grp);
405+
struct erofs_workgroup *erofs_insert_workgroup(struct super_block *sb,
406+
struct erofs_workgroup *grp);
407407
void erofs_workgroup_free_rcu(struct erofs_workgroup *grp);
408408
void erofs_shrinker_register(struct super_block *sb);
409409
void erofs_shrinker_unregister(struct super_block *sb);

fs/erofs/super.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ static int erofs_fill_super(struct super_block *sb, void *data, int silent)
425425
sb->s_flags &= ~SB_POSIXACL;
426426

427427
#ifdef CONFIG_EROFS_FS_ZIP
428-
INIT_RADIX_TREE(&sbi->workstn_tree, GFP_ATOMIC);
428+
xa_init(&sbi->managed_pslots);
429429
#endif
430430

431431
/* get the root inode */

fs/erofs/utils.c

Lines changed: 33 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,6 @@ void *erofs_get_pcpubuf(unsigned int pagenr)
3737
/* global shrink count (for all mounted EROFS instances) */
3838
static atomic_long_t erofs_global_shrink_cnt;
3939

40-
#define __erofs_workgroup_get(grp) atomic_inc(&(grp)->refcount)
41-
#define __erofs_workgroup_put(grp) atomic_dec(&(grp)->refcount)
42-
4340
static int erofs_workgroup_get(struct erofs_workgroup *grp)
4441
{
4542
int o;
@@ -66,7 +63,7 @@ struct erofs_workgroup *erofs_find_workgroup(struct super_block *sb,
6663

6764
repeat:
6865
rcu_read_lock();
69-
grp = radix_tree_lookup(&sbi->workstn_tree, index);
66+
grp = xa_load(&sbi->managed_pslots, index);
7067
if (grp) {
7168
if (erofs_workgroup_get(grp)) {
7269
/* prefer to relax rcu read side */
@@ -80,43 +77,37 @@ struct erofs_workgroup *erofs_find_workgroup(struct super_block *sb,
8077
return grp;
8178
}
8279

83-
int erofs_register_workgroup(struct super_block *sb,
84-
struct erofs_workgroup *grp)
80+
struct erofs_workgroup *erofs_insert_workgroup(struct super_block *sb,
81+
struct erofs_workgroup *grp)
8582
{
86-
struct erofs_sb_info *sbi;
87-
int err;
88-
89-
/* grp shouldn't be broken or used before */
90-
if (atomic_read(&grp->refcount) != 1) {
91-
DBG_BUGON(1);
92-
return -EINVAL;
93-
}
94-
95-
err = radix_tree_preload(GFP_NOFS);
96-
if (err)
97-
return err;
98-
99-
sbi = EROFS_SB(sb);
100-
xa_lock(&sbi->workstn_tree);
83+
struct erofs_sb_info *const sbi = EROFS_SB(sb);
84+
struct erofs_workgroup *pre;
10185

10286
/*
103-
* Bump up reference count before making this workgroup
104-
* visible to other users in order to avoid potential UAF
105-
* without serialized by workstn_lock.
87+
* Bump up a reference count before making this visible
88+
* to others for the XArray in order to avoid potential
89+
* UAF without serialized by xa_lock.
10690
*/
107-
__erofs_workgroup_get(grp);
108-
109-
err = radix_tree_insert(&sbi->workstn_tree, grp->index, grp);
110-
if (err)
111-
/*
112-
* it's safe to decrease since the workgroup isn't visible
113-
* and refcount >= 2 (cannot be freezed).
114-
*/
115-
__erofs_workgroup_put(grp);
91+
atomic_inc(&grp->refcount);
11692

117-
xa_unlock(&sbi->workstn_tree);
118-
radix_tree_preload_end();
119-
return err;
93+
repeat:
94+
xa_lock(&sbi->managed_pslots);
95+
pre = __xa_cmpxchg(&sbi->managed_pslots, grp->index,
96+
NULL, grp, GFP_NOFS);
97+
if (pre) {
98+
if (xa_is_err(pre)) {
99+
pre = ERR_PTR(xa_err(pre));
100+
} else if (erofs_workgroup_get(pre)) {
101+
/* try to legitimize the current in-tree one */
102+
xa_unlock(&sbi->managed_pslots);
103+
cond_resched();
104+
goto repeat;
105+
}
106+
atomic_dec(&grp->refcount);
107+
grp = pre;
108+
}
109+
xa_unlock(&sbi->managed_pslots);
110+
return grp;
120111
}
121112

122113
static void __erofs_workgroup_free(struct erofs_workgroup *grp)
@@ -155,7 +146,7 @@ static bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi,
155146

156147
/*
157148
* Note that all cached pages should be unattached
158-
* before deleted from the radix tree. Otherwise some
149+
* before deleted from the XArray. Otherwise some
159150
* cached pages could be still attached to the orphan
160151
* old workgroup when the new one is available in the tree.
161152
*/
@@ -169,7 +160,7 @@ static bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi,
169160
* however in order to avoid some race conditions, add a
170161
* DBG_BUGON to observe this in advance.
171162
*/
172-
DBG_BUGON(radix_tree_delete(&sbi->workstn_tree, grp->index) != grp);
163+
DBG_BUGON(xa_erase(&sbi->managed_pslots, grp->index) != grp);
173164

174165
/*
175166
* If managed cache is on, last refcount should indicate
@@ -182,22 +173,11 @@ static bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi,
182173
static unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi,
183174
unsigned long nr_shrink)
184175
{
185-
pgoff_t first_index = 0;
186-
void *batch[PAGEVEC_SIZE];
176+
struct erofs_workgroup *grp;
187177
unsigned int freed = 0;
178+
unsigned long index;
188179

189-
int i, found;
190-
repeat:
191-
xa_lock(&sbi->workstn_tree);
192-
193-
found = radix_tree_gang_lookup(&sbi->workstn_tree,
194-
batch, first_index, PAGEVEC_SIZE);
195-
196-
for (i = 0; i < found; ++i) {
197-
struct erofs_workgroup *grp = batch[i];
198-
199-
first_index = grp->index + 1;
200-
180+
xa_for_each(&sbi->managed_pslots, index, grp) {
201181
/* try to shrink each valid workgroup */
202182
if (!erofs_try_to_release_workgroup(sbi, grp))
203183
continue;
@@ -206,10 +186,6 @@ static unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi,
206186
if (!--nr_shrink)
207187
break;
208188
}
209-
xa_unlock(&sbi->workstn_tree);
210-
211-
if (i && nr_shrink)
212-
goto repeat;
213189
return freed;
214190
}
215191

@@ -286,7 +262,7 @@ static unsigned long erofs_shrink_scan(struct shrinker *shrink,
286262
spin_unlock(&erofs_sb_list_lock);
287263
sbi->shrinker_run_no = run_no;
288264

289-
freed += erofs_shrink_workstation(sbi, nr);
265+
freed += erofs_shrink_workstation(sbi, nr - freed);
290266

291267
spin_lock(&erofs_sb_list_lock);
292268
/* Get the next list element before we move this one */

fs/erofs/zdata.c

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,6 @@ static void z_erofs_pcluster_init_once(void *ptr)
6767
pcl->compressed_pages[i] = NULL;
6868
}
6969

70-
static void z_erofs_pcluster_init_always(struct z_erofs_pcluster *pcl)
71-
{
72-
struct z_erofs_collection *cl = z_erofs_primarycollection(pcl);
73-
74-
atomic_set(&pcl->obj.refcount, 1);
75-
76-
DBG_BUGON(cl->nr_pages);
77-
DBG_BUGON(cl->vcnt);
78-
}
79-
8070
int __init z_erofs_init_zip_subsystem(void)
8171
{
8272
pcluster_cachep = kmem_cache_create("erofs_compress",
@@ -341,34 +331,26 @@ static int z_erofs_lookup_collection(struct z_erofs_collector *clt,
341331
struct inode *inode,
342332
struct erofs_map_blocks *map)
343333
{
344-
struct erofs_workgroup *grp;
345-
struct z_erofs_pcluster *pcl;
334+
struct z_erofs_pcluster *pcl = clt->pcl;
346335
struct z_erofs_collection *cl;
347336
unsigned int length;
348337

349-
grp = erofs_find_workgroup(inode->i_sb, map->m_pa >> PAGE_SHIFT);
350-
if (!grp)
351-
return -ENOENT;
352-
353-
pcl = container_of(grp, struct z_erofs_pcluster, obj);
338+
/* to avoid unexpected loop formed by corrupted images */
354339
if (clt->owned_head == &pcl->next || pcl == clt->tailpcl) {
355340
DBG_BUGON(1);
356-
erofs_workgroup_put(grp);
357341
return -EFSCORRUPTED;
358342
}
359343

360344
cl = z_erofs_primarycollection(pcl);
361345
if (cl->pageofs != (map->m_la & ~PAGE_MASK)) {
362346
DBG_BUGON(1);
363-
erofs_workgroup_put(grp);
364347
return -EFSCORRUPTED;
365348
}
366349

367350
length = READ_ONCE(pcl->length);
368351
if (length & Z_EROFS_PCLUSTER_FULL_LENGTH) {
369352
if ((map->m_llen << Z_EROFS_PCLUSTER_LENGTH_BIT) > length) {
370353
DBG_BUGON(1);
371-
erofs_workgroup_put(grp);
372354
return -EFSCORRUPTED;
373355
}
374356
} else {
@@ -391,7 +373,6 @@ static int z_erofs_lookup_collection(struct z_erofs_collector *clt,
391373
/* clean tailpcl if the current owned_head is Z_EROFS_PCLUSTER_TAIL */
392374
if (clt->owned_head == Z_EROFS_PCLUSTER_TAIL)
393375
clt->tailpcl = NULL;
394-
clt->pcl = pcl;
395376
clt->cl = cl;
396377
return 0;
397378
}
@@ -402,14 +383,15 @@ static int z_erofs_register_collection(struct z_erofs_collector *clt,
402383
{
403384
struct z_erofs_pcluster *pcl;
404385
struct z_erofs_collection *cl;
386+
struct erofs_workgroup *grp;
405387
int err;
406388

407389
/* no available workgroup, let's allocate one */
408390
pcl = kmem_cache_alloc(pcluster_cachep, GFP_NOFS);
409391
if (!pcl)
410392
return -ENOMEM;
411393

412-
z_erofs_pcluster_init_always(pcl);
394+
atomic_set(&pcl->obj.refcount, 1);
413395
pcl->obj.index = map->m_pa >> PAGE_SHIFT;
414396

415397
pcl->length = (map->m_llen << Z_EROFS_PCLUSTER_LENGTH_BIT) |
@@ -429,19 +411,29 @@ static int z_erofs_register_collection(struct z_erofs_collector *clt,
429411
clt->mode = COLLECT_PRIMARY_FOLLOWED;
430412

431413
cl = z_erofs_primarycollection(pcl);
414+
415+
/* must be cleaned before freeing to slab */
416+
DBG_BUGON(cl->nr_pages);
417+
DBG_BUGON(cl->vcnt);
418+
432419
cl->pageofs = map->m_la & ~PAGE_MASK;
433420

434421
/*
435422
* lock all primary followed works before visible to others
436423
* and mutex_trylock *never* fails for a new pcluster.
437424
*/
438-
mutex_trylock(&cl->lock);
425+
DBG_BUGON(!mutex_trylock(&cl->lock));
439426

440-
err = erofs_register_workgroup(inode->i_sb, &pcl->obj);
441-
if (err) {
442-
mutex_unlock(&cl->lock);
443-
kmem_cache_free(pcluster_cachep, pcl);
444-
return -EAGAIN;
427+
grp = erofs_insert_workgroup(inode->i_sb, &pcl->obj);
428+
if (IS_ERR(grp)) {
429+
err = PTR_ERR(grp);
430+
goto err_out;
431+
}
432+
433+
if (grp != &pcl->obj) {
434+
clt->pcl = container_of(grp, struct z_erofs_pcluster, obj);
435+
err = -EEXIST;
436+
goto err_out;
445437
}
446438
/* used to check tail merging loop due to corrupted images */
447439
if (clt->owned_head == Z_EROFS_PCLUSTER_TAIL)
@@ -450,12 +442,18 @@ static int z_erofs_register_collection(struct z_erofs_collector *clt,
450442
clt->pcl = pcl;
451443
clt->cl = cl;
452444
return 0;
445+
446+
err_out:
447+
mutex_unlock(&cl->lock);
448+
kmem_cache_free(pcluster_cachep, pcl);
449+
return err;
453450
}
454451

455452
static int z_erofs_collector_begin(struct z_erofs_collector *clt,
456453
struct inode *inode,
457454
struct erofs_map_blocks *map)
458455
{
456+
struct erofs_workgroup *grp;
459457
int ret;
460458

461459
DBG_BUGON(clt->cl);
@@ -469,21 +467,25 @@ static int z_erofs_collector_begin(struct z_erofs_collector *clt,
469467
return -EINVAL;
470468
}
471469

472-
repeat:
473-
ret = z_erofs_lookup_collection(clt, inode, map);
474-
if (ret == -ENOENT) {
470+
grp = erofs_find_workgroup(inode->i_sb, map->m_pa >> PAGE_SHIFT);
471+
if (grp) {
472+
clt->pcl = container_of(grp, struct z_erofs_pcluster, obj);
473+
} else {
475474
ret = z_erofs_register_collection(clt, inode, map);
476475

477-
/* someone registered at the same time, give another try */
478-
if (ret == -EAGAIN) {
479-
cond_resched();
480-
goto repeat;
481-
}
476+
if (!ret)
477+
goto out;
478+
if (ret != -EEXIST)
479+
return ret;
482480
}
483481

484-
if (ret)
482+
ret = z_erofs_lookup_collection(clt, inode, map);
483+
if (ret) {
484+
erofs_workgroup_put(&clt->pcl->obj);
485485
return ret;
486+
}
486487

488+
out:
487489
z_erofs_pagevec_ctor_init(&clt->vector, Z_EROFS_NR_INLINE_PAGEVECS,
488490
clt->cl->pagevec, clt->cl->vcnt);
489491

0 commit comments

Comments
 (0)