Commit 7e0969ba authored by Herbert Xu's avatar Herbert Xu
Browse files

ubifs: Pass folios to acomp



As the acomp interface supports folios, use that instead of mapping
the data in ubifs.

Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Tested-by: Zhihao Cheng <chengzhihao1@huawei.com> # For xfstests
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 37b605f5
Loading
Loading
Loading
Loading
+104 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
 */

#include <crypto/acompress.h>
#include <linux/highmem.h>
#include "ubifs.h"

/* Fake description object for the "none" compressor */
@@ -126,7 +127,7 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf,
	{
		ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);

		acomp_request_set_src_nondma(req, in_buf, in_len);
		acomp_request_set_src_dma(req, in_buf, in_len);
		err = ubifs_compress_req(c, req, out_buf, out_len, compr->name);
	}

@@ -141,6 +142,58 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf,
	*compr_type = UBIFS_COMPR_NONE;
}

/**
 * ubifs_compress_folio - compress folio.
 * @c: UBIFS file-system description object
 * @in_folio: data to compress
 * @in_offset: offset into @in_folio
 * @in_len: length of the data to compress
 * @out_buf: output buffer where compressed data should be stored
 * @out_len: output buffer length is returned here
 * @compr_type: type of compression to use on enter, actually used compression
 *              type on exit
 *
 * This function compresses input folio @in_folio of length @in_len and
 * stores the result in the output buffer @out_buf and the resulting length
 * in @out_len. If the input buffer does not compress, it is just copied
 * to the @out_buf. The same happens if @compr_type is %UBIFS_COMPR_NONE
 * or if compression error occurred.
 *
 * Note, if the input buffer was not compressed, it is copied to the output
 * buffer and %UBIFS_COMPR_NONE is returned in @compr_type.
 */
void ubifs_compress_folio(const struct ubifs_info *c, struct folio *in_folio,
			  size_t in_offset, int in_len, void *out_buf,
			  int *out_len, int *compr_type)
{
	int err;
	struct ubifs_compressor *compr = ubifs_compressors[*compr_type];

	if (*compr_type == UBIFS_COMPR_NONE)
		goto no_compr;

	/* If the input data is small, do not even try to compress it */
	if (in_len < UBIFS_MIN_COMPR_LEN)
		goto no_compr;

	{
		ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);

		acomp_request_set_src_folio(req, in_folio, in_offset, in_len);
		err = ubifs_compress_req(c, req, out_buf, out_len, compr->name);
	}

	if (err)
		goto no_compr;

	return;

no_compr:
	memcpy_from_folio(out_buf, in_folio, in_offset, in_len);
	*out_len = in_len;
	*compr_type = UBIFS_COMPR_NONE;
}

static int ubifs_decompress_req(const struct ubifs_info *c,
				struct acomp_req *req,
				const void *in_buf, int in_len, int *out_len,
@@ -205,7 +258,56 @@ int ubifs_decompress(const struct ubifs_info *c, const void *in_buf,
	{
		ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);

		acomp_request_set_dst_nondma(req, out_buf, *out_len);
		acomp_request_set_dst_dma(req, out_buf, *out_len);
		return ubifs_decompress_req(c, req, in_buf, in_len, out_len,
					    compr->name);
	}
}

/**
 * ubifs_decompress_folio - decompress folio.
 * @c: UBIFS file-system description object
 * @in_buf: data to decompress
 * @in_len: length of the data to decompress
 * @out_folio: output folio where decompressed data should
 * @out_offset: offset into @out_folio
 * @out_len: output length is returned here
 * @compr_type: type of compression
 *
 * This function decompresses data from buffer @in_buf into folio
 * @out_folio.  The length of the uncompressed data is returned in
 * @out_len.  This functions returns %0 on success or a negative error
 * code on failure.
 */
int ubifs_decompress_folio(const struct ubifs_info *c, const void *in_buf,
			   int in_len, struct folio *out_folio,
			   size_t out_offset, int *out_len, int compr_type)
{
	struct ubifs_compressor *compr;

	if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) {
		ubifs_err(c, "invalid compression type %d", compr_type);
		return -EINVAL;
	}

	compr = ubifs_compressors[compr_type];

	if (unlikely(!compr->capi_name)) {
		ubifs_err(c, "%s compression is not compiled in", compr->name);
		return -EINVAL;
	}

	if (compr_type == UBIFS_COMPR_NONE) {
		memcpy_to_folio(out_folio, out_offset, in_buf, in_len);
		*out_len = in_len;
		return 0;
	}

	{
		ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);

		acomp_request_set_dst_folio(req, out_folio, out_offset,
					    *out_len);
		return ubifs_decompress_req(c, req, in_buf, in_len, out_len,
					    compr->name);
	}
+25 −49
Original line number Diff line number Diff line
@@ -42,8 +42,8 @@
#include <linux/slab.h>
#include <linux/migrate.h>

static int read_block(struct inode *inode, void *addr, unsigned int block,
		      struct ubifs_data_node *dn)
static int read_block(struct inode *inode, struct folio *folio, size_t offset,
		      unsigned int block, struct ubifs_data_node *dn)
{
	struct ubifs_info *c = inode->i_sb->s_fs_info;
	int err, len, out_len;
@@ -55,7 +55,7 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
	if (err) {
		if (err == -ENOENT)
			/* Not found, so it must be a hole */
			memset(addr, 0, UBIFS_BLOCK_SIZE);
			folio_zero_range(folio, offset, UBIFS_BLOCK_SIZE);
		return err;
	}

@@ -74,8 +74,8 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
	}

	out_len = UBIFS_BLOCK_SIZE;
	err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len,
			       le16_to_cpu(dn->compr_type));
	err = ubifs_decompress_folio(c, &dn->data, dlen, folio, offset,
				     &out_len, le16_to_cpu(dn->compr_type));
	if (err || len != out_len)
		goto dump;

@@ -85,7 +85,7 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
	 * appending data). Ensure that the remainder is zeroed out.
	 */
	if (len < UBIFS_BLOCK_SIZE)
		memset(addr + len, 0, UBIFS_BLOCK_SIZE - len);
		folio_zero_range(folio, offset + len, UBIFS_BLOCK_SIZE - len);

	return 0;

@@ -98,27 +98,25 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,

static int do_readpage(struct folio *folio)
{
	void *addr;
	int err = 0, i;
	unsigned int block, beyond;
	struct ubifs_data_node *dn = NULL;
	struct inode *inode = folio->mapping->host;
	struct ubifs_info *c = inode->i_sb->s_fs_info;
	loff_t i_size = i_size_read(inode);
	size_t offset = 0;

	dbg_gen("ino %lu, pg %lu, i_size %lld, flags %#lx",
		inode->i_ino, folio->index, i_size, folio->flags);
	ubifs_assert(c, !folio_test_checked(folio));
	ubifs_assert(c, !folio->private);

	addr = kmap_local_folio(folio, 0);

	block = folio->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
	beyond = (i_size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
	if (block >= beyond) {
		/* Reading beyond inode */
		folio_set_checked(folio);
		addr = folio_zero_tail(folio, 0, addr);
		folio_zero_range(folio, 0, folio_size(folio));
		goto out;
	}

@@ -135,9 +133,9 @@ static int do_readpage(struct folio *folio)
		if (block >= beyond) {
			/* Reading beyond inode */
			err = -ENOENT;
			memset(addr, 0, UBIFS_BLOCK_SIZE);
			folio_zero_range(folio, offset, UBIFS_BLOCK_SIZE);
		} else {
			ret = read_block(inode, addr, block, dn);
			ret = read_block(inode, folio, offset, block, dn);
			if (ret) {
				err = ret;
				if (err != -ENOENT)
@@ -147,17 +145,13 @@ static int do_readpage(struct folio *folio)
				int ilen = i_size & (UBIFS_BLOCK_SIZE - 1);

				if (ilen && ilen < dlen)
					memset(addr + ilen, 0, dlen - ilen);
					folio_zero_range(folio, offset + ilen, dlen - ilen);
			}
		}
		if (++i >= (UBIFS_BLOCKS_PER_PAGE << folio_order(folio)))
			break;
		block += 1;
		addr += UBIFS_BLOCK_SIZE;
		if (folio_test_highmem(folio) && (offset_in_page(addr) == 0)) {
			kunmap_local(addr - UBIFS_BLOCK_SIZE);
			addr = kmap_local_folio(folio, i * UBIFS_BLOCK_SIZE);
		}
		offset += UBIFS_BLOCK_SIZE;
	}

	if (err) {
@@ -177,8 +171,6 @@ static int do_readpage(struct folio *folio)
	kfree(dn);
	if (!err)
		folio_mark_uptodate(folio);
	flush_dcache_folio(folio);
	kunmap_local(addr);
	return err;
}

@@ -602,18 +594,16 @@ static int populate_page(struct ubifs_info *c, struct folio *folio,
	struct inode *inode = folio->mapping->host;
	loff_t i_size = i_size_read(inode);
	unsigned int page_block;
	void *addr, *zaddr;
	size_t offset = 0;
	pgoff_t end_index;

	dbg_gen("ino %lu, pg %lu, i_size %lld, flags %#lx",
		inode->i_ino, folio->index, i_size, folio->flags);

	addr = zaddr = kmap_local_folio(folio, 0);

	end_index = (i_size - 1) >> PAGE_SHIFT;
	if (!i_size || folio->index > end_index) {
		hole = 1;
		addr = folio_zero_tail(folio, 0, addr);
		folio_zero_range(folio, 0, folio_size(folio));
		goto out_hole;
	}

@@ -623,7 +613,7 @@ static int populate_page(struct ubifs_info *c, struct folio *folio,

		if (nn >= bu->cnt) {
			hole = 1;
			memset(addr, 0, UBIFS_BLOCK_SIZE);
			folio_zero_range(folio, offset, UBIFS_BLOCK_SIZE);
		} else if (key_block(c, &bu->zbranch[nn].key) == page_block) {
			struct ubifs_data_node *dn;

@@ -645,13 +635,15 @@ static int populate_page(struct ubifs_info *c, struct folio *folio,
					goto out_err;
			}

			err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len,
			err = ubifs_decompress_folio(
				c, &dn->data, dlen, folio, offset, &out_len,
				le16_to_cpu(dn->compr_type));
			if (err || len != out_len)
				goto out_err;

			if (len < UBIFS_BLOCK_SIZE)
				memset(addr + len, 0, UBIFS_BLOCK_SIZE - len);
				folio_zero_range(folio, offset + len,
						 UBIFS_BLOCK_SIZE - len);

			nn += 1;
			read = (i << UBIFS_BLOCK_SHIFT) + len;
@@ -660,23 +652,19 @@ static int populate_page(struct ubifs_info *c, struct folio *folio,
			continue;
		} else {
			hole = 1;
			memset(addr, 0, UBIFS_BLOCK_SIZE);
			folio_zero_range(folio, offset, UBIFS_BLOCK_SIZE);
		}
		if (++i >= UBIFS_BLOCKS_PER_PAGE)
			break;
		addr += UBIFS_BLOCK_SIZE;
		offset += UBIFS_BLOCK_SIZE;
		page_block += 1;
		if (folio_test_highmem(folio) && (offset_in_page(addr) == 0)) {
			kunmap_local(addr - UBIFS_BLOCK_SIZE);
			addr = kmap_local_folio(folio, i * UBIFS_BLOCK_SIZE);
		}
	}

	if (end_index == folio->index) {
		int len = i_size & (PAGE_SIZE - 1);

		if (len && len < read)
			memset(zaddr + len, 0, read - len);
			folio_zero_range(folio, len, read - len);
	}

out_hole:
@@ -686,14 +674,10 @@ static int populate_page(struct ubifs_info *c, struct folio *folio,
	}

	folio_mark_uptodate(folio);
	flush_dcache_folio(folio);
	kunmap_local(addr);
	*n = nn;
	return 0;

out_err:
	flush_dcache_folio(folio);
	kunmap_local(addr);
	ubifs_err(c, "bad data node (block %u, inode %lu)",
		  page_block, inode->i_ino);
	return -EINVAL;
@@ -898,7 +882,6 @@ static int do_writepage(struct folio *folio, size_t len)
{
	int err = 0, blen;
	unsigned int block;
	void *addr;
	size_t offset = 0;
	union ubifs_key key;
	struct inode *inode = folio->mapping->host;
@@ -913,26 +896,19 @@ static int do_writepage(struct folio *folio, size_t len)

	folio_start_writeback(folio);

	addr = kmap_local_folio(folio, offset);
	block = folio->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
	for (;;) {
		blen = min_t(size_t, len, UBIFS_BLOCK_SIZE);
		data_key_init(c, &key, inode->i_ino, block);
		err = ubifs_jnl_write_data(c, inode, &key, addr, blen);
		err = ubifs_jnl_write_data(c, inode, &key, folio, offset, blen);
		if (err)
			break;
		len -= blen;
		if (!len)
			break;
		block += 1;
		addr += blen;
		if (folio_test_highmem(folio) && !offset_in_page(addr)) {
			kunmap_local(addr - blen);
			offset += PAGE_SIZE;
			addr = kmap_local_folio(folio, offset);
		}
		offset += blen;
	}
	kunmap_local(addr);
	if (err) {
		mapping_set_error(folio->mapping, err);
		ubifs_err(c, "cannot write folio %lu of inode %lu, error %d",
+6 −3
Original line number Diff line number Diff line
@@ -845,14 +845,16 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
 * @c: UBIFS file-system description object
 * @inode: inode the data node belongs to
 * @key: node key
 * @buf: buffer to write
 * @folio: buffer to write
 * @offset: offset to write at
 * @len: data length (must not exceed %UBIFS_BLOCK_SIZE)
 *
 * This function writes a data node to the journal. Returns %0 if the data node
 * was successfully written, and a negative error code in case of failure.
 */
int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
			 const union ubifs_key *key, const void *buf, int len)
			 const union ubifs_key *key, struct folio *folio,
			 size_t offset, int len)
{
	struct ubifs_data_node *data;
	int err, lnum, offs, compr_type, out_len, compr_len, auth_len;
@@ -896,7 +898,8 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
		compr_type = ui->compr_type;

	out_len = compr_len = dlen - UBIFS_DATA_NODE_SZ;
	ubifs_compress(c, buf, len, &data->data, &compr_len, &compr_type);
	ubifs_compress_folio(c, folio, offset, len, &data->data, &compr_len,
			     &compr_type);
	ubifs_assert(c, compr_len <= UBIFS_BLOCK_SIZE);

	if (encrypted) {
+10 −1
Original line number Diff line number Diff line
@@ -263,6 +263,8 @@ enum {
	ASSACT_PANIC,
};

struct folio;

/**
 * struct ubifs_old_idx - index node obsoleted since last commit start.
 * @rb: rb-tree node
@@ -1784,7 +1786,8 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
		     const struct fscrypt_name *nm, const struct inode *inode,
		     int deletion, int xent, int in_orphan);
int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
			 const union ubifs_key *key, const void *buf, int len);
			 const union ubifs_key *key, struct folio *folio,
			 size_t offset, int len);
int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode);
int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode);
int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
@@ -2084,8 +2087,14 @@ int __init ubifs_compressors_init(void);
void ubifs_compressors_exit(void);
void ubifs_compress(const struct ubifs_info *c, const void *in_buf, int in_len,
		    void *out_buf, int *out_len, int *compr_type);
void ubifs_compress_folio(const struct ubifs_info *c, struct folio *folio,
			 size_t offset, int in_len, void *out_buf,
			 int *out_len, int *compr_type);
int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len,
		     void *out, int *out_len, int compr_type);
int ubifs_decompress_folio(const struct ubifs_info *c, const void *buf,
			   int len, struct folio *folio, size_t offset,
			   int *out_len, int compr_type);

/* sysfs.c */
int ubifs_sysfs_init(void);