]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ubifs: Pass folios to acomp
authorHerbert Xu <herbert@gondor.apana.org.au>
Sat, 15 Mar 2025 10:30:50 +0000 (18:30 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Fri, 21 Mar 2025 09:39:05 +0000 (17:39 +0800)
As the acomp interface supports folios, use that instead of mapping
the data in ubifs.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Zhihao Cheng <chengzhihao1@huawei.com> # For xfstests
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
fs/ubifs/compress.c
fs/ubifs/file.c
fs/ubifs/journal.c
fs/ubifs/ubifs.h

index a241ba01c9a884c294204f4a90650360c9e297c3..ea6f06adcd43ac1f2e16d2d6ba2677e4a2b2cdad 100644 (file)
@@ -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 @@ no_compr:
        *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);
        }
index 5130123005e4d92c8dad624f5b66a3ee41aa568f..bf311c38d9a898364541f1d121f7dafd361d9986 100644 (file)
@@ -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 @@ dump:
 
 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 @@ out:
        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,
-                                              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 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 @@ out_hole:
        }
 
        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",
index 7629ca9ecfe8adda3fe741ae84164d017ebe6484..ee954e64ce7fea3d990aa1d9a55fd66c599f4191 100644 (file)
@@ -845,14 +845,16 @@ out_ro:
  * @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) {
index 7d0aaf5d2e2318df74189cd8eac0e6ae2ad176d6..256dbaeeb0de173885c41350479065ca39c71a05 100644 (file)
@@ -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);