Commit 7ae46097 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'erofs-for-6.1-rc2-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs

Pull erofs fixes from Gao Xiang:

 - Fix invalid unmapped accesses when initializing compressed inodes

 - Fix up very rare hung on page lock after enabling compressed data
   deduplication

 - Fix up inplace decompression success rate

 - Take s_inode_list_lock to protect sb->s_inodes for fscache shared
   domain

* tag 'erofs-for-6.1-rc2-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs:
  erofs: protect s_inodes with s_inode_list_lock for fscache
  erofs: fix up inplace decompression success rate
  erofs: shouldn't churn the mapping page for duplicated copies
  erofs: fix illegal unmapped accesses in z_erofs_fill_inode_lazy()
parents bb1a1146 ce4b8156
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -590,14 +590,17 @@ struct erofs_fscache *erofs_domain_register_cookie(struct super_block *sb,
	struct super_block *psb = erofs_pseudo_mnt->mnt_sb;

	mutex_lock(&erofs_domain_cookies_lock);
	spin_lock(&psb->s_inode_list_lock);
	list_for_each_entry(inode, &psb->s_inodes, i_sb_list) {
		ctx = inode->i_private;
		if (!ctx || ctx->domain != domain || strcmp(ctx->name, name))
			continue;
		igrab(inode);
		spin_unlock(&psb->s_inode_list_lock);
		mutex_unlock(&erofs_domain_cookies_lock);
		return ctx;
	}
	spin_unlock(&psb->s_inode_list_lock);
	ctx = erofs_fscache_domain_init_cookie(sb, name, need_inode);
	mutex_unlock(&erofs_domain_cookies_lock);
	return ctx;
+7 −10
Original line number Diff line number Diff line
@@ -813,15 +813,14 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe,
	++spiltted;
	if (fe->pcl->pageofs_out != (map->m_la & ~PAGE_MASK))
		fe->pcl->multibases = true;

	if ((map->m_flags & EROFS_MAP_FULL_MAPPED) &&
	    !(map->m_flags & EROFS_MAP_PARTIAL_REF) &&
	    fe->pcl->length == map->m_llen)
		fe->pcl->partial = false;
	if (fe->pcl->length < offset + end - map->m_la) {
		fe->pcl->length = offset + end - map->m_la;
		fe->pcl->pageofs_out = map->m_la & ~PAGE_MASK;
	}
	if ((map->m_flags & EROFS_MAP_FULL_MAPPED) &&
	    !(map->m_flags & EROFS_MAP_PARTIAL_REF) &&
	    fe->pcl->length == map->m_llen)
		fe->pcl->partial = false;
next_part:
	/* shorten the remaining extent to update progress */
	map->m_llen = offset + cur - map->m_la;
@@ -888,16 +887,14 @@ static void z_erofs_do_decompressed_bvec(struct z_erofs_decompress_backend *be,

	if (!((bvec->offset + be->pcl->pageofs_out) & ~PAGE_MASK)) {
		unsigned int pgnr;
		struct page *oldpage;

		pgnr = (bvec->offset + be->pcl->pageofs_out) >> PAGE_SHIFT;
		DBG_BUGON(pgnr >= be->nr_pages);
		oldpage = be->decompressed_pages[pgnr];
		if (!be->decompressed_pages[pgnr]) {
			be->decompressed_pages[pgnr] = bvec->page;

		if (!oldpage)
			return;
		}
	}

	/* (cold path) one pcluster is requested multiple times */
	item = kmalloc(sizeof(*item), GFP_KERNEL | __GFP_NOFAIL);
+3 −3
Original line number Diff line number Diff line
@@ -126,10 +126,10 @@ static inline unsigned int z_erofs_pclusterpages(struct z_erofs_pcluster *pcl)
}

/*
 * bit 31: I/O error occurred on this page
 * bit 0 - 30: remaining parts to complete this page
 * bit 30: I/O error occurred on this page
 * bit 0 - 29: remaining parts to complete this page
 */
#define Z_EROFS_PAGE_EIO			(1 << 31)
#define Z_EROFS_PAGE_EIO			(1 << 30)

static inline void z_erofs_onlinepage_init(struct page *page)
{
+10 −12
Original line number Diff line number Diff line
@@ -57,8 +57,7 @@ static int z_erofs_fill_inode_lazy(struct inode *inode)

	pos = ALIGN(iloc(EROFS_SB(sb), vi->nid) + vi->inode_isize +
		    vi->xattr_isize, 8);
	kaddr = erofs_read_metabuf(&buf, sb, erofs_blknr(pos),
				   EROFS_KMAP_ATOMIC);
	kaddr = erofs_read_metabuf(&buf, sb, erofs_blknr(pos), EROFS_KMAP);
	if (IS_ERR(kaddr)) {
		err = PTR_ERR(kaddr);
		goto out_unlock;
@@ -73,7 +72,7 @@ static int z_erofs_fill_inode_lazy(struct inode *inode)
		vi->z_advise = Z_EROFS_ADVISE_FRAGMENT_PCLUSTER;
		vi->z_fragmentoff = le64_to_cpu(*(__le64 *)h) ^ (1ULL << 63);
		vi->z_tailextent_headlcn = 0;
		goto unmap_done;
		goto done;
	}
	vi->z_advise = le16_to_cpu(h->h_advise);
	vi->z_algorithmtype[0] = h->h_algorithmtype & 15;
@@ -85,7 +84,7 @@ static int z_erofs_fill_inode_lazy(struct inode *inode)
		erofs_err(sb, "unknown HEAD%u format %u for nid %llu, please upgrade kernel",
			  headnr + 1, vi->z_algorithmtype[headnr], vi->nid);
		err = -EOPNOTSUPP;
		goto unmap_done;
		goto out_put_metabuf;
	}

	vi->z_logical_clusterbits = LOG_BLOCK_SIZE + (h->h_clusterbits & 7);
@@ -95,7 +94,7 @@ static int z_erofs_fill_inode_lazy(struct inode *inode)
		erofs_err(sb, "per-inode big pcluster without sb feature for nid %llu",
			  vi->nid);
		err = -EFSCORRUPTED;
		goto unmap_done;
		goto out_put_metabuf;
	}
	if (vi->datalayout == EROFS_INODE_FLAT_COMPRESSION &&
	    !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1) ^
@@ -103,12 +102,8 @@ static int z_erofs_fill_inode_lazy(struct inode *inode)
		erofs_err(sb, "big pcluster head1/2 of compact indexes should be consistent for nid %llu",
			  vi->nid);
		err = -EFSCORRUPTED;
		goto unmap_done;
		goto out_put_metabuf;
	}
unmap_done:
	erofs_put_metabuf(&buf);
	if (err)
		goto out_unlock;

	if (vi->z_advise & Z_EROFS_ADVISE_INLINE_PCLUSTER) {
		struct erofs_map_blocks map = {
@@ -127,7 +122,7 @@ static int z_erofs_fill_inode_lazy(struct inode *inode)
			err = -EFSCORRUPTED;
		}
		if (err < 0)
			goto out_unlock;
			goto out_put_metabuf;
	}

	if (vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER &&
@@ -141,11 +136,14 @@ static int z_erofs_fill_inode_lazy(struct inode *inode)
					    EROFS_GET_BLOCKS_FINDTAIL);
		erofs_put_metabuf(&map.buf);
		if (err < 0)
			goto out_unlock;
			goto out_put_metabuf;
	}
done:
	/* paired with smp_mb() at the beginning of the function */
	smp_mb();
	set_bit(EROFS_I_Z_INITED_BIT, &vi->flags);
out_put_metabuf:
	erofs_put_metabuf(&buf);
out_unlock:
	clear_and_wake_up_bit(EROFS_I_BL_Z_BIT, &vi->flags);
	return err;