~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/lib/zlib_dfltcc/dfltcc_deflate.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: Zlib
  2 
  3 #include "../zlib_deflate/defutil.h"
  4 #include "dfltcc_util.h"
  5 #include "dfltcc_deflate.h"
  6 #include <asm/setup.h>
  7 #include <linux/export.h>
  8 #include <linux/zutil.h>
  9 
 10 #define GET_DFLTCC_DEFLATE_STATE(state) ((struct dfltcc_deflate_state *)GET_DFLTCC_STATE(state))
 11 
 12 /*
 13  * Compress.
 14  */
 15 int dfltcc_can_deflate(
 16     z_streamp strm
 17 )
 18 {
 19     deflate_state *state = (deflate_state *)strm->state;
 20     struct dfltcc_deflate_state *dfltcc_state = GET_DFLTCC_DEFLATE_STATE(state);
 21 
 22     /* Check for kernel dfltcc command line parameter */
 23     if (zlib_dfltcc_support == ZLIB_DFLTCC_DISABLED ||
 24             zlib_dfltcc_support == ZLIB_DFLTCC_INFLATE_ONLY)
 25         return 0;
 26 
 27     /* Unsupported compression settings */
 28     if (!dfltcc_are_params_ok(state->level, state->w_bits, state->strategy,
 29                               dfltcc_state->level_mask))
 30         return 0;
 31 
 32     /* Unsupported hardware */
 33     if (!is_bit_set(dfltcc_state->common.af.fns, DFLTCC_GDHT) ||
 34             !is_bit_set(dfltcc_state->common.af.fns, DFLTCC_CMPR) ||
 35             !is_bit_set(dfltcc_state->common.af.fmts, DFLTCC_FMT0))
 36         return 0;
 37 
 38     return 1;
 39 }
 40 EXPORT_SYMBOL(dfltcc_can_deflate);
 41 
 42 void dfltcc_reset_deflate_state(z_streamp strm) {
 43     deflate_state *state = (deflate_state *)strm->state;
 44     struct dfltcc_deflate_state *dfltcc_state = GET_DFLTCC_DEFLATE_STATE(state);
 45 
 46     dfltcc_reset_state(&dfltcc_state->common);
 47 
 48     /* Initialize tuning parameters */
 49     if (zlib_dfltcc_support == ZLIB_DFLTCC_FULL_DEBUG)
 50         dfltcc_state->level_mask = DFLTCC_LEVEL_MASK_DEBUG;
 51     else
 52         dfltcc_state->level_mask = DFLTCC_LEVEL_MASK;
 53     dfltcc_state->block_size = DFLTCC_BLOCK_SIZE;
 54     dfltcc_state->block_threshold = DFLTCC_FIRST_FHT_BLOCK_SIZE;
 55     dfltcc_state->dht_threshold = DFLTCC_DHT_MIN_SAMPLE_SIZE;
 56 }
 57 EXPORT_SYMBOL(dfltcc_reset_deflate_state);
 58 
 59 static void dfltcc_gdht(
 60     z_streamp strm
 61 )
 62 {
 63     deflate_state *state = (deflate_state *)strm->state;
 64     struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
 65     size_t avail_in = strm->avail_in;
 66 
 67     dfltcc(DFLTCC_GDHT,
 68            param, NULL, NULL,
 69            &strm->next_in, &avail_in, NULL);
 70 }
 71 
 72 static dfltcc_cc dfltcc_cmpr(
 73     z_streamp strm
 74 )
 75 {
 76     deflate_state *state = (deflate_state *)strm->state;
 77     struct dfltcc_param_v0 *param = &GET_DFLTCC_STATE(state)->param;
 78     size_t avail_in = strm->avail_in;
 79     size_t avail_out = strm->avail_out;
 80     dfltcc_cc cc;
 81 
 82     cc = dfltcc(DFLTCC_CMPR | HBT_CIRCULAR,
 83                 param, &strm->next_out, &avail_out,
 84                 &strm->next_in, &avail_in, state->window);
 85     strm->total_in += (strm->avail_in - avail_in);
 86     strm->total_out += (strm->avail_out - avail_out);
 87     strm->avail_in = avail_in;
 88     strm->avail_out = avail_out;
 89     return cc;
 90 }
 91 
 92 static void send_eobs(
 93     z_streamp strm,
 94     const struct dfltcc_param_v0 *param
 95 )
 96 {
 97     deflate_state *state = (deflate_state *)strm->state;
 98 
 99     zlib_tr_send_bits(
100           state,
101           bi_reverse(param->eobs >> (15 - param->eobl), param->eobl),
102           param->eobl);
103     flush_pending(strm);
104     if (state->pending != 0) {
105         /* The remaining data is located in pending_out[0:pending]. If someone
106          * calls put_byte() - this might happen in deflate() - the byte will be
107          * placed into pending_buf[pending], which is incorrect. Move the
108          * remaining data to the beginning of pending_buf so that put_byte() is
109          * usable again.
110          */
111         memmove(state->pending_buf, state->pending_out, state->pending);
112         state->pending_out = state->pending_buf;
113     }
114 #ifdef ZLIB_DEBUG
115     state->compressed_len += param->eobl;
116 #endif
117 }
118 
119 int dfltcc_deflate(
120     z_streamp strm,
121     int flush,
122     block_state *result
123 )
124 {
125     deflate_state *state = (deflate_state *)strm->state;
126     struct dfltcc_deflate_state *dfltcc_state = GET_DFLTCC_DEFLATE_STATE(state);
127     struct dfltcc_param_v0 *param = &dfltcc_state->common.param;
128     uInt masked_avail_in;
129     dfltcc_cc cc;
130     int need_empty_block;
131     int soft_bcc;
132     int no_flush;
133 
134     if (!dfltcc_can_deflate(strm)) {
135         /* Clear history. */
136         if (flush == Z_FULL_FLUSH)
137             param->hl = 0;
138         return 0;
139     }
140 
141 again:
142     masked_avail_in = 0;
143     soft_bcc = 0;
144     no_flush = flush == Z_NO_FLUSH;
145 
146     /* No input data. Return, except when Continuation Flag is set, which means
147      * that DFLTCC has buffered some output in the parameter block and needs to
148      * be called again in order to flush it.
149      */
150     if (strm->avail_in == 0 && !param->cf) {
151         /* A block is still open, and the hardware does not support closing
152          * blocks without adding data. Thus, close it manually.
153          */
154         if (!no_flush && param->bcf) {
155             send_eobs(strm, param);
156             param->bcf = 0;
157         }
158         /* Let one of deflate_* functions write a trailing empty block. */
159         if (flush == Z_FINISH)
160             return 0;
161         /* Clear history. */
162         if (flush == Z_FULL_FLUSH)
163             param->hl = 0;
164         /* Trigger block post-processing if necessary. */
165         *result = no_flush ? need_more : block_done;
166         return 1;
167     }
168 
169     /* There is an open non-BFINAL block, we are not going to close it just
170      * yet, we have compressed more than DFLTCC_BLOCK_SIZE bytes and we see
171      * more than DFLTCC_DHT_MIN_SAMPLE_SIZE bytes. Open a new block with a new
172      * DHT in order to adapt to a possibly changed input data distribution.
173      */
174     if (param->bcf && no_flush &&
175             strm->total_in > dfltcc_state->block_threshold &&
176             strm->avail_in >= dfltcc_state->dht_threshold) {
177         if (param->cf) {
178             /* We need to flush the DFLTCC buffer before writing the
179              * End-of-block Symbol. Mask the input data and proceed as usual.
180              */
181             masked_avail_in += strm->avail_in;
182             strm->avail_in = 0;
183             no_flush = 0;
184         } else {
185             /* DFLTCC buffer is empty, so we can manually write the
186              * End-of-block Symbol right away.
187              */
188             send_eobs(strm, param);
189             param->bcf = 0;
190             dfltcc_state->block_threshold =
191                 strm->total_in + dfltcc_state->block_size;
192         }
193     }
194 
195     /* No space for compressed data. If we proceed, dfltcc_cmpr() will return
196      * DFLTCC_CC_OP1_TOO_SHORT without buffering header bits, but we will still
197      * set BCF=1, which is wrong. Avoid complications and return early.
198      */
199     if (strm->avail_out == 0) {
200         *result = need_more;
201         return 1;
202     }
203 
204     /* The caller gave us too much data. Pass only one block worth of
205      * uncompressed data to DFLTCC and mask the rest, so that on the next
206      * iteration we start a new block.
207      */
208     if (no_flush && strm->avail_in > dfltcc_state->block_size) {
209         masked_avail_in += (strm->avail_in - dfltcc_state->block_size);
210         strm->avail_in = dfltcc_state->block_size;
211     }
212 
213     /* When we have an open non-BFINAL deflate block and caller indicates that
214      * the stream is ending, we need to close an open deflate block and open a
215      * BFINAL one.
216      */
217     need_empty_block = flush == Z_FINISH && param->bcf && !param->bhf;
218 
219     /* Translate stream to parameter block */
220     param->cvt = CVT_ADLER32;
221     if (!no_flush)
222         /* We need to close a block. Always do this in software - when there is
223          * no input data, the hardware will not hohor BCC. */
224         soft_bcc = 1;
225     if (flush == Z_FINISH && !param->bcf)
226         /* We are about to open a BFINAL block, set Block Header Final bit
227          * until the stream ends.
228          */
229         param->bhf = 1;
230     /* DFLTCC-CMPR will write to next_out, so make sure that buffers with
231      * higher precedence are empty.
232      */
233     Assert(state->pending == 0, "There must be no pending bytes");
234     Assert(state->bi_valid < 8, "There must be less than 8 pending bits");
235     param->sbb = (unsigned int)state->bi_valid;
236     if (param->sbb > 0)
237         *strm->next_out = (Byte)state->bi_buf;
238     /* Honor history and check value */
239     param->nt = 0;
240     param->cv = strm->adler;
241 
242     /* When opening a block, choose a Huffman-Table Type */
243     if (!param->bcf) {
244         if (strm->total_in == 0 && dfltcc_state->block_threshold > 0) {
245             param->htt = HTT_FIXED;
246         }
247         else {
248             param->htt = HTT_DYNAMIC;
249             dfltcc_gdht(strm);
250         }
251     }
252 
253     /* Deflate */
254     do {
255         cc = dfltcc_cmpr(strm);
256         if (strm->avail_in < 4096 && masked_avail_in > 0)
257             /* We are about to call DFLTCC with a small input buffer, which is
258              * inefficient. Since there is masked data, there will be at least
259              * one more DFLTCC call, so skip the current one and make the next
260              * one handle more data.
261              */
262             break;
263     } while (cc == DFLTCC_CC_AGAIN);
264 
265     /* Translate parameter block to stream */
266     strm->msg = oesc_msg(dfltcc_state->common.msg, param->oesc);
267     state->bi_valid = param->sbb;
268     if (state->bi_valid == 0)
269         state->bi_buf = 0; /* Avoid accessing next_out */
270     else
271         state->bi_buf = *strm->next_out & ((1 << state->bi_valid) - 1);
272     strm->adler = param->cv;
273 
274     /* Unmask the input data */
275     strm->avail_in += masked_avail_in;
276     masked_avail_in = 0;
277 
278     /* If we encounter an error, it means there is a bug in DFLTCC call */
279     Assert(cc != DFLTCC_CC_OP2_CORRUPT || param->oesc == 0, "BUG");
280 
281     /* Update Block-Continuation Flag. It will be used to check whether to call
282      * GDHT the next time.
283      */
284     if (cc == DFLTCC_CC_OK) {
285         if (soft_bcc) {
286             send_eobs(strm, param);
287             param->bcf = 0;
288             dfltcc_state->block_threshold =
289                 strm->total_in + dfltcc_state->block_size;
290         } else
291             param->bcf = 1;
292         if (flush == Z_FINISH) {
293             if (need_empty_block)
294                 /* Make the current deflate() call also close the stream */
295                 return 0;
296             else {
297                 bi_windup(state);
298                 *result = finish_done;
299             }
300         } else {
301             if (flush == Z_FULL_FLUSH)
302                 param->hl = 0; /* Clear history */
303             *result = flush == Z_NO_FLUSH ? need_more : block_done;
304         }
305     } else {
306         param->bcf = 1;
307         *result = need_more;
308     }
309     if (strm->avail_in != 0 && strm->avail_out != 0)
310         goto again; /* deflate() must use all input or all output */
311     return 1;
312 }
313 EXPORT_SYMBOL(dfltcc_deflate);
314 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php