Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2016-present, Facebook, Inc.
0004  * All rights reserved.
0005  *
0006  */
0007 
0008 #include <linux/bio.h>
0009 #include <linux/bitmap.h>
0010 #include <linux/err.h>
0011 #include <linux/init.h>
0012 #include <linux/kernel.h>
0013 #include <linux/mm.h>
0014 #include <linux/sched/mm.h>
0015 #include <linux/pagemap.h>
0016 #include <linux/refcount.h>
0017 #include <linux/sched.h>
0018 #include <linux/slab.h>
0019 #include <linux/zstd.h>
0020 #include "misc.h"
0021 #include "compression.h"
0022 #include "ctree.h"
0023 
0024 #define ZSTD_BTRFS_MAX_WINDOWLOG 17
0025 #define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG)
0026 #define ZSTD_BTRFS_DEFAULT_LEVEL 3
0027 #define ZSTD_BTRFS_MAX_LEVEL 15
0028 /* 307s to avoid pathologically clashing with transaction commit */
0029 #define ZSTD_BTRFS_RECLAIM_JIFFIES (307 * HZ)
0030 
0031 static zstd_parameters zstd_get_btrfs_parameters(unsigned int level,
0032                          size_t src_len)
0033 {
0034     zstd_parameters params = zstd_get_params(level, src_len);
0035 
0036     if (params.cParams.windowLog > ZSTD_BTRFS_MAX_WINDOWLOG)
0037         params.cParams.windowLog = ZSTD_BTRFS_MAX_WINDOWLOG;
0038     WARN_ON(src_len > ZSTD_BTRFS_MAX_INPUT);
0039     return params;
0040 }
0041 
0042 struct workspace {
0043     void *mem;
0044     size_t size;
0045     char *buf;
0046     unsigned int level;
0047     unsigned int req_level;
0048     unsigned long last_used; /* jiffies */
0049     struct list_head list;
0050     struct list_head lru_list;
0051     zstd_in_buffer in_buf;
0052     zstd_out_buffer out_buf;
0053 };
0054 
0055 /*
0056  * Zstd Workspace Management
0057  *
0058  * Zstd workspaces have different memory requirements depending on the level.
0059  * The zstd workspaces are managed by having individual lists for each level
0060  * and a global lru.  Forward progress is maintained by protecting a max level
0061  * workspace.
0062  *
0063  * Getting a workspace is done by using the bitmap to identify the levels that
0064  * have available workspaces and scans up.  This lets us recycle higher level
0065  * workspaces because of the monotonic memory guarantee.  A workspace's
0066  * last_used is only updated if it is being used by the corresponding memory
0067  * level.  Putting a workspace involves adding it back to the appropriate places
0068  * and adding it back to the lru if necessary.
0069  *
0070  * A timer is used to reclaim workspaces if they have not been used for
0071  * ZSTD_BTRFS_RECLAIM_JIFFIES.  This helps keep only active workspaces around.
0072  * The upper bound is provided by the workqueue limit which is 2 (percpu limit).
0073  */
0074 
0075 struct zstd_workspace_manager {
0076     const struct btrfs_compress_op *ops;
0077     spinlock_t lock;
0078     struct list_head lru_list;
0079     struct list_head idle_ws[ZSTD_BTRFS_MAX_LEVEL];
0080     unsigned long active_map;
0081     wait_queue_head_t wait;
0082     struct timer_list timer;
0083 };
0084 
0085 static struct zstd_workspace_manager wsm;
0086 
0087 static size_t zstd_ws_mem_sizes[ZSTD_BTRFS_MAX_LEVEL];
0088 
0089 static inline struct workspace *list_to_workspace(struct list_head *list)
0090 {
0091     return container_of(list, struct workspace, list);
0092 }
0093 
0094 void zstd_free_workspace(struct list_head *ws);
0095 struct list_head *zstd_alloc_workspace(unsigned int level);
0096 
0097 /**
0098  * Timer callback to free unused workspaces.
0099  *
0100  * @t: timer
0101  *
0102  * This scans the lru_list and attempts to reclaim any workspace that hasn't
0103  * been used for ZSTD_BTRFS_RECLAIM_JIFFIES.
0104  *
0105  * The context is softirq and does not need the _bh locking primitives.
0106  */
0107 static void zstd_reclaim_timer_fn(struct timer_list *timer)
0108 {
0109     unsigned long reclaim_threshold = jiffies - ZSTD_BTRFS_RECLAIM_JIFFIES;
0110     struct list_head *pos, *next;
0111 
0112     spin_lock(&wsm.lock);
0113 
0114     if (list_empty(&wsm.lru_list)) {
0115         spin_unlock(&wsm.lock);
0116         return;
0117     }
0118 
0119     list_for_each_prev_safe(pos, next, &wsm.lru_list) {
0120         struct workspace *victim = container_of(pos, struct workspace,
0121                             lru_list);
0122         unsigned int level;
0123 
0124         if (time_after(victim->last_used, reclaim_threshold))
0125             break;
0126 
0127         /* workspace is in use */
0128         if (victim->req_level)
0129             continue;
0130 
0131         level = victim->level;
0132         list_del(&victim->lru_list);
0133         list_del(&victim->list);
0134         zstd_free_workspace(&victim->list);
0135 
0136         if (list_empty(&wsm.idle_ws[level - 1]))
0137             clear_bit(level - 1, &wsm.active_map);
0138 
0139     }
0140 
0141     if (!list_empty(&wsm.lru_list))
0142         mod_timer(&wsm.timer, jiffies + ZSTD_BTRFS_RECLAIM_JIFFIES);
0143 
0144     spin_unlock(&wsm.lock);
0145 }
0146 
0147 /*
0148  * zstd_calc_ws_mem_sizes - calculate monotonic memory bounds
0149  *
0150  * It is possible based on the level configurations that a higher level
0151  * workspace uses less memory than a lower level workspace.  In order to reuse
0152  * workspaces, this must be made a monotonic relationship.  This precomputes
0153  * the required memory for each level and enforces the monotonicity between
0154  * level and memory required.
0155  */
0156 static void zstd_calc_ws_mem_sizes(void)
0157 {
0158     size_t max_size = 0;
0159     unsigned int level;
0160 
0161     for (level = 1; level <= ZSTD_BTRFS_MAX_LEVEL; level++) {
0162         zstd_parameters params =
0163             zstd_get_btrfs_parameters(level, ZSTD_BTRFS_MAX_INPUT);
0164         size_t level_size =
0165             max_t(size_t,
0166                   zstd_cstream_workspace_bound(&params.cParams),
0167                   zstd_dstream_workspace_bound(ZSTD_BTRFS_MAX_INPUT));
0168 
0169         max_size = max_t(size_t, max_size, level_size);
0170         zstd_ws_mem_sizes[level - 1] = max_size;
0171     }
0172 }
0173 
0174 void zstd_init_workspace_manager(void)
0175 {
0176     struct list_head *ws;
0177     int i;
0178 
0179     zstd_calc_ws_mem_sizes();
0180 
0181     wsm.ops = &btrfs_zstd_compress;
0182     spin_lock_init(&wsm.lock);
0183     init_waitqueue_head(&wsm.wait);
0184     timer_setup(&wsm.timer, zstd_reclaim_timer_fn, 0);
0185 
0186     INIT_LIST_HEAD(&wsm.lru_list);
0187     for (i = 0; i < ZSTD_BTRFS_MAX_LEVEL; i++)
0188         INIT_LIST_HEAD(&wsm.idle_ws[i]);
0189 
0190     ws = zstd_alloc_workspace(ZSTD_BTRFS_MAX_LEVEL);
0191     if (IS_ERR(ws)) {
0192         pr_warn(
0193         "BTRFS: cannot preallocate zstd compression workspace\n");
0194     } else {
0195         set_bit(ZSTD_BTRFS_MAX_LEVEL - 1, &wsm.active_map);
0196         list_add(ws, &wsm.idle_ws[ZSTD_BTRFS_MAX_LEVEL - 1]);
0197     }
0198 }
0199 
0200 void zstd_cleanup_workspace_manager(void)
0201 {
0202     struct workspace *workspace;
0203     int i;
0204 
0205     spin_lock_bh(&wsm.lock);
0206     for (i = 0; i < ZSTD_BTRFS_MAX_LEVEL; i++) {
0207         while (!list_empty(&wsm.idle_ws[i])) {
0208             workspace = container_of(wsm.idle_ws[i].next,
0209                          struct workspace, list);
0210             list_del(&workspace->list);
0211             list_del(&workspace->lru_list);
0212             zstd_free_workspace(&workspace->list);
0213         }
0214     }
0215     spin_unlock_bh(&wsm.lock);
0216 
0217     del_timer_sync(&wsm.timer);
0218 }
0219 
0220 /*
0221  * zstd_find_workspace - find workspace
0222  * @level: compression level
0223  *
0224  * This iterates over the set bits in the active_map beginning at the requested
0225  * compression level.  This lets us utilize already allocated workspaces before
0226  * allocating a new one.  If the workspace is of a larger size, it is used, but
0227  * the place in the lru_list and last_used times are not updated.  This is to
0228  * offer the opportunity to reclaim the workspace in favor of allocating an
0229  * appropriately sized one in the future.
0230  */
0231 static struct list_head *zstd_find_workspace(unsigned int level)
0232 {
0233     struct list_head *ws;
0234     struct workspace *workspace;
0235     int i = level - 1;
0236 
0237     spin_lock_bh(&wsm.lock);
0238     for_each_set_bit_from(i, &wsm.active_map, ZSTD_BTRFS_MAX_LEVEL) {
0239         if (!list_empty(&wsm.idle_ws[i])) {
0240             ws = wsm.idle_ws[i].next;
0241             workspace = list_to_workspace(ws);
0242             list_del_init(ws);
0243             /* keep its place if it's a lower level using this */
0244             workspace->req_level = level;
0245             if (level == workspace->level)
0246                 list_del(&workspace->lru_list);
0247             if (list_empty(&wsm.idle_ws[i]))
0248                 clear_bit(i, &wsm.active_map);
0249             spin_unlock_bh(&wsm.lock);
0250             return ws;
0251         }
0252     }
0253     spin_unlock_bh(&wsm.lock);
0254 
0255     return NULL;
0256 }
0257 
0258 /*
0259  * zstd_get_workspace - zstd's get_workspace
0260  * @level: compression level
0261  *
0262  * If @level is 0, then any compression level can be used.  Therefore, we begin
0263  * scanning from 1.  We first scan through possible workspaces and then after
0264  * attempt to allocate a new workspace.  If we fail to allocate one due to
0265  * memory pressure, go to sleep waiting for the max level workspace to free up.
0266  */
0267 struct list_head *zstd_get_workspace(unsigned int level)
0268 {
0269     struct list_head *ws;
0270     unsigned int nofs_flag;
0271 
0272     /* level == 0 means we can use any workspace */
0273     if (!level)
0274         level = 1;
0275 
0276 again:
0277     ws = zstd_find_workspace(level);
0278     if (ws)
0279         return ws;
0280 
0281     nofs_flag = memalloc_nofs_save();
0282     ws = zstd_alloc_workspace(level);
0283     memalloc_nofs_restore(nofs_flag);
0284 
0285     if (IS_ERR(ws)) {
0286         DEFINE_WAIT(wait);
0287 
0288         prepare_to_wait(&wsm.wait, &wait, TASK_UNINTERRUPTIBLE);
0289         schedule();
0290         finish_wait(&wsm.wait, &wait);
0291 
0292         goto again;
0293     }
0294 
0295     return ws;
0296 }
0297 
0298 /*
0299  * zstd_put_workspace - zstd put_workspace
0300  * @ws: list_head for the workspace
0301  *
0302  * When putting back a workspace, we only need to update the LRU if we are of
0303  * the requested compression level.  Here is where we continue to protect the
0304  * max level workspace or update last_used accordingly.  If the reclaim timer
0305  * isn't set, it is also set here.  Only the max level workspace tries and wakes
0306  * up waiting workspaces.
0307  */
0308 void zstd_put_workspace(struct list_head *ws)
0309 {
0310     struct workspace *workspace = list_to_workspace(ws);
0311 
0312     spin_lock_bh(&wsm.lock);
0313 
0314     /* A node is only taken off the lru if we are the corresponding level */
0315     if (workspace->req_level == workspace->level) {
0316         /* Hide a max level workspace from reclaim */
0317         if (list_empty(&wsm.idle_ws[ZSTD_BTRFS_MAX_LEVEL - 1])) {
0318             INIT_LIST_HEAD(&workspace->lru_list);
0319         } else {
0320             workspace->last_used = jiffies;
0321             list_add(&workspace->lru_list, &wsm.lru_list);
0322             if (!timer_pending(&wsm.timer))
0323                 mod_timer(&wsm.timer,
0324                       jiffies + ZSTD_BTRFS_RECLAIM_JIFFIES);
0325         }
0326     }
0327 
0328     set_bit(workspace->level - 1, &wsm.active_map);
0329     list_add(&workspace->list, &wsm.idle_ws[workspace->level - 1]);
0330     workspace->req_level = 0;
0331 
0332     spin_unlock_bh(&wsm.lock);
0333 
0334     if (workspace->level == ZSTD_BTRFS_MAX_LEVEL)
0335         cond_wake_up(&wsm.wait);
0336 }
0337 
0338 void zstd_free_workspace(struct list_head *ws)
0339 {
0340     struct workspace *workspace = list_entry(ws, struct workspace, list);
0341 
0342     kvfree(workspace->mem);
0343     kfree(workspace->buf);
0344     kfree(workspace);
0345 }
0346 
0347 struct list_head *zstd_alloc_workspace(unsigned int level)
0348 {
0349     struct workspace *workspace;
0350 
0351     workspace = kzalloc(sizeof(*workspace), GFP_KERNEL);
0352     if (!workspace)
0353         return ERR_PTR(-ENOMEM);
0354 
0355     workspace->size = zstd_ws_mem_sizes[level - 1];
0356     workspace->level = level;
0357     workspace->req_level = level;
0358     workspace->last_used = jiffies;
0359     workspace->mem = kvmalloc(workspace->size, GFP_KERNEL);
0360     workspace->buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
0361     if (!workspace->mem || !workspace->buf)
0362         goto fail;
0363 
0364     INIT_LIST_HEAD(&workspace->list);
0365     INIT_LIST_HEAD(&workspace->lru_list);
0366 
0367     return &workspace->list;
0368 fail:
0369     zstd_free_workspace(&workspace->list);
0370     return ERR_PTR(-ENOMEM);
0371 }
0372 
0373 int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
0374         u64 start, struct page **pages, unsigned long *out_pages,
0375         unsigned long *total_in, unsigned long *total_out)
0376 {
0377     struct workspace *workspace = list_entry(ws, struct workspace, list);
0378     zstd_cstream *stream;
0379     int ret = 0;
0380     int nr_pages = 0;
0381     struct page *in_page = NULL;  /* The current page to read */
0382     struct page *out_page = NULL; /* The current page to write to */
0383     unsigned long tot_in = 0;
0384     unsigned long tot_out = 0;
0385     unsigned long len = *total_out;
0386     const unsigned long nr_dest_pages = *out_pages;
0387     unsigned long max_out = nr_dest_pages * PAGE_SIZE;
0388     zstd_parameters params = zstd_get_btrfs_parameters(workspace->req_level,
0389                                len);
0390 
0391     *out_pages = 0;
0392     *total_out = 0;
0393     *total_in = 0;
0394 
0395     /* Initialize the stream */
0396     stream = zstd_init_cstream(&params, len, workspace->mem,
0397             workspace->size);
0398     if (!stream) {
0399         pr_warn("BTRFS: zstd_init_cstream failed\n");
0400         ret = -EIO;
0401         goto out;
0402     }
0403 
0404     /* map in the first page of input data */
0405     in_page = find_get_page(mapping, start >> PAGE_SHIFT);
0406     workspace->in_buf.src = kmap_local_page(in_page);
0407     workspace->in_buf.pos = 0;
0408     workspace->in_buf.size = min_t(size_t, len, PAGE_SIZE);
0409 
0410 
0411     /* Allocate and map in the output buffer */
0412     out_page = alloc_page(GFP_NOFS);
0413     if (out_page == NULL) {
0414         ret = -ENOMEM;
0415         goto out;
0416     }
0417     pages[nr_pages++] = out_page;
0418     workspace->out_buf.dst = page_address(out_page);
0419     workspace->out_buf.pos = 0;
0420     workspace->out_buf.size = min_t(size_t, max_out, PAGE_SIZE);
0421 
0422     while (1) {
0423         size_t ret2;
0424 
0425         ret2 = zstd_compress_stream(stream, &workspace->out_buf,
0426                 &workspace->in_buf);
0427         if (zstd_is_error(ret2)) {
0428             pr_debug("BTRFS: zstd_compress_stream returned %d\n",
0429                     zstd_get_error_code(ret2));
0430             ret = -EIO;
0431             goto out;
0432         }
0433 
0434         /* Check to see if we are making it bigger */
0435         if (tot_in + workspace->in_buf.pos > 8192 &&
0436                 tot_in + workspace->in_buf.pos <
0437                 tot_out + workspace->out_buf.pos) {
0438             ret = -E2BIG;
0439             goto out;
0440         }
0441 
0442         /* We've reached the end of our output range */
0443         if (workspace->out_buf.pos >= max_out) {
0444             tot_out += workspace->out_buf.pos;
0445             ret = -E2BIG;
0446             goto out;
0447         }
0448 
0449         /* Check if we need more output space */
0450         if (workspace->out_buf.pos == workspace->out_buf.size) {
0451             tot_out += PAGE_SIZE;
0452             max_out -= PAGE_SIZE;
0453             if (nr_pages == nr_dest_pages) {
0454                 ret = -E2BIG;
0455                 goto out;
0456             }
0457             out_page = alloc_page(GFP_NOFS);
0458             if (out_page == NULL) {
0459                 ret = -ENOMEM;
0460                 goto out;
0461             }
0462             pages[nr_pages++] = out_page;
0463             workspace->out_buf.dst = page_address(out_page);
0464             workspace->out_buf.pos = 0;
0465             workspace->out_buf.size = min_t(size_t, max_out,
0466                             PAGE_SIZE);
0467         }
0468 
0469         /* We've reached the end of the input */
0470         if (workspace->in_buf.pos >= len) {
0471             tot_in += workspace->in_buf.pos;
0472             break;
0473         }
0474 
0475         /* Check if we need more input */
0476         if (workspace->in_buf.pos == workspace->in_buf.size) {
0477             tot_in += PAGE_SIZE;
0478             kunmap_local(workspace->in_buf.src);
0479             put_page(in_page);
0480             start += PAGE_SIZE;
0481             len -= PAGE_SIZE;
0482             in_page = find_get_page(mapping, start >> PAGE_SHIFT);
0483             workspace->in_buf.src = kmap_local_page(in_page);
0484             workspace->in_buf.pos = 0;
0485             workspace->in_buf.size = min_t(size_t, len, PAGE_SIZE);
0486         }
0487     }
0488     while (1) {
0489         size_t ret2;
0490 
0491         ret2 = zstd_end_stream(stream, &workspace->out_buf);
0492         if (zstd_is_error(ret2)) {
0493             pr_debug("BTRFS: zstd_end_stream returned %d\n",
0494                     zstd_get_error_code(ret2));
0495             ret = -EIO;
0496             goto out;
0497         }
0498         if (ret2 == 0) {
0499             tot_out += workspace->out_buf.pos;
0500             break;
0501         }
0502         if (workspace->out_buf.pos >= max_out) {
0503             tot_out += workspace->out_buf.pos;
0504             ret = -E2BIG;
0505             goto out;
0506         }
0507 
0508         tot_out += PAGE_SIZE;
0509         max_out -= PAGE_SIZE;
0510         if (nr_pages == nr_dest_pages) {
0511             ret = -E2BIG;
0512             goto out;
0513         }
0514         out_page = alloc_page(GFP_NOFS);
0515         if (out_page == NULL) {
0516             ret = -ENOMEM;
0517             goto out;
0518         }
0519         pages[nr_pages++] = out_page;
0520         workspace->out_buf.dst = page_address(out_page);
0521         workspace->out_buf.pos = 0;
0522         workspace->out_buf.size = min_t(size_t, max_out, PAGE_SIZE);
0523     }
0524 
0525     if (tot_out >= tot_in) {
0526         ret = -E2BIG;
0527         goto out;
0528     }
0529 
0530     ret = 0;
0531     *total_in = tot_in;
0532     *total_out = tot_out;
0533 out:
0534     *out_pages = nr_pages;
0535     if (workspace->in_buf.src) {
0536         kunmap_local(workspace->in_buf.src);
0537         put_page(in_page);
0538     }
0539     return ret;
0540 }
0541 
0542 int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
0543 {
0544     struct workspace *workspace = list_entry(ws, struct workspace, list);
0545     struct page **pages_in = cb->compressed_pages;
0546     size_t srclen = cb->compressed_len;
0547     zstd_dstream *stream;
0548     int ret = 0;
0549     unsigned long page_in_index = 0;
0550     unsigned long total_pages_in = DIV_ROUND_UP(srclen, PAGE_SIZE);
0551     unsigned long buf_start;
0552     unsigned long total_out = 0;
0553 
0554     stream = zstd_init_dstream(
0555             ZSTD_BTRFS_MAX_INPUT, workspace->mem, workspace->size);
0556     if (!stream) {
0557         pr_debug("BTRFS: zstd_init_dstream failed\n");
0558         ret = -EIO;
0559         goto done;
0560     }
0561 
0562     workspace->in_buf.src = kmap_local_page(pages_in[page_in_index]);
0563     workspace->in_buf.pos = 0;
0564     workspace->in_buf.size = min_t(size_t, srclen, PAGE_SIZE);
0565 
0566     workspace->out_buf.dst = workspace->buf;
0567     workspace->out_buf.pos = 0;
0568     workspace->out_buf.size = PAGE_SIZE;
0569 
0570     while (1) {
0571         size_t ret2;
0572 
0573         ret2 = zstd_decompress_stream(stream, &workspace->out_buf,
0574                 &workspace->in_buf);
0575         if (zstd_is_error(ret2)) {
0576             pr_debug("BTRFS: zstd_decompress_stream returned %d\n",
0577                     zstd_get_error_code(ret2));
0578             ret = -EIO;
0579             goto done;
0580         }
0581         buf_start = total_out;
0582         total_out += workspace->out_buf.pos;
0583         workspace->out_buf.pos = 0;
0584 
0585         ret = btrfs_decompress_buf2page(workspace->out_buf.dst,
0586                 total_out - buf_start, cb, buf_start);
0587         if (ret == 0)
0588             break;
0589 
0590         if (workspace->in_buf.pos >= srclen)
0591             break;
0592 
0593         /* Check if we've hit the end of a frame */
0594         if (ret2 == 0)
0595             break;
0596 
0597         if (workspace->in_buf.pos == workspace->in_buf.size) {
0598             kunmap_local(workspace->in_buf.src);
0599             page_in_index++;
0600             if (page_in_index >= total_pages_in) {
0601                 workspace->in_buf.src = NULL;
0602                 ret = -EIO;
0603                 goto done;
0604             }
0605             srclen -= PAGE_SIZE;
0606             workspace->in_buf.src = kmap_local_page(pages_in[page_in_index]);
0607             workspace->in_buf.pos = 0;
0608             workspace->in_buf.size = min_t(size_t, srclen, PAGE_SIZE);
0609         }
0610     }
0611     ret = 0;
0612     zero_fill_bio(cb->orig_bio);
0613 done:
0614     if (workspace->in_buf.src)
0615         kunmap_local(workspace->in_buf.src);
0616     return ret;
0617 }
0618 
0619 int zstd_decompress(struct list_head *ws, unsigned char *data_in,
0620         struct page *dest_page, unsigned long start_byte, size_t srclen,
0621         size_t destlen)
0622 {
0623     struct workspace *workspace = list_entry(ws, struct workspace, list);
0624     zstd_dstream *stream;
0625     int ret = 0;
0626     size_t ret2;
0627     unsigned long total_out = 0;
0628     unsigned long pg_offset = 0;
0629 
0630     stream = zstd_init_dstream(
0631             ZSTD_BTRFS_MAX_INPUT, workspace->mem, workspace->size);
0632     if (!stream) {
0633         pr_warn("BTRFS: zstd_init_dstream failed\n");
0634         ret = -EIO;
0635         goto finish;
0636     }
0637 
0638     destlen = min_t(size_t, destlen, PAGE_SIZE);
0639 
0640     workspace->in_buf.src = data_in;
0641     workspace->in_buf.pos = 0;
0642     workspace->in_buf.size = srclen;
0643 
0644     workspace->out_buf.dst = workspace->buf;
0645     workspace->out_buf.pos = 0;
0646     workspace->out_buf.size = PAGE_SIZE;
0647 
0648     ret2 = 1;
0649     while (pg_offset < destlen
0650            && workspace->in_buf.pos < workspace->in_buf.size) {
0651         unsigned long buf_start;
0652         unsigned long buf_offset;
0653         unsigned long bytes;
0654 
0655         /* Check if the frame is over and we still need more input */
0656         if (ret2 == 0) {
0657             pr_debug("BTRFS: zstd_decompress_stream ended early\n");
0658             ret = -EIO;
0659             goto finish;
0660         }
0661         ret2 = zstd_decompress_stream(stream, &workspace->out_buf,
0662                 &workspace->in_buf);
0663         if (zstd_is_error(ret2)) {
0664             pr_debug("BTRFS: zstd_decompress_stream returned %d\n",
0665                     zstd_get_error_code(ret2));
0666             ret = -EIO;
0667             goto finish;
0668         }
0669 
0670         buf_start = total_out;
0671         total_out += workspace->out_buf.pos;
0672         workspace->out_buf.pos = 0;
0673 
0674         if (total_out <= start_byte)
0675             continue;
0676 
0677         if (total_out > start_byte && buf_start < start_byte)
0678             buf_offset = start_byte - buf_start;
0679         else
0680             buf_offset = 0;
0681 
0682         bytes = min_t(unsigned long, destlen - pg_offset,
0683                 workspace->out_buf.size - buf_offset);
0684 
0685         memcpy_to_page(dest_page, pg_offset,
0686                    workspace->out_buf.dst + buf_offset, bytes);
0687 
0688         pg_offset += bytes;
0689     }
0690     ret = 0;
0691 finish:
0692     if (pg_offset < destlen) {
0693         memzero_page(dest_page, pg_offset, destlen - pg_offset);
0694     }
0695     return ret;
0696 }
0697 
0698 const struct btrfs_compress_op btrfs_zstd_compress = {
0699     /* ZSTD uses own workspace manager */
0700     .workspace_manager = NULL,
0701     .max_level  = ZSTD_BTRFS_MAX_LEVEL,
0702     .default_level  = ZSTD_BTRFS_DEFAULT_LEVEL,
0703 };