// SPDX-License-Identifier: GPL-2.0-or-later /* * 842 Software Compression * * Copyright (C) 2015 Dan Streetman, IBM Corp * * See 842.h for details of the 842 compressed format.
*/
/* By default, we allow compressing input buffers of any length, but we must * use the non-standard "short data" template so the decompressor can correctly * reproduce the uncompressed data buffer at the right length. However the * hardware 842 compressor will not recognize the "short data" template, and * will fail to decompress any compressed buffer containing it (I have no idea * why anyone would want to use software to compress and hardware to decompress * but that's beside the point). This parameter forces the compression * function to simply reject any input buffer that isn't a multiple of 8 bytes * long, instead of using the "short data" template, so that all compressed * buffers produced by this function will be decompressable by the 842 hardware * decompressor. Unless you have a specific need for that, leave this disabled * so that any length buffer can be compressed.
*/ staticbool sw842_strict;
module_param_named(strict, sw842_strict, bool, 0644);
/* split this up if writing to > 8 bytes (i.e. n == 64 && p->bit > 0), * or if we're at the end of the output buffer and would write past end
*/ if (bits > 64) return __split_add_bits(p, d, n, 32); elseif (p->olen < 8 && bits > 32 && bits <= 56) return __split_add_bits(p, d, n, 16); elseif (p->olen < 4 && bits > 16 && bits <= 24) return __split_add_bits(p, d, n, 8);
if (DIV_ROUND_UP(bits, 8) > p->olen) return -ENOSPC;
if (sw842_template_counts)
atomic_inc(&template_count[t[4]]);
return 0;
}
staticint add_repeat_template(struct sw842_param *p, u8 r)
{ int ret;
/* repeat param is 0-based */ if (!r || --r > REPEAT_BITS_MAX) return -EINVAL;
ret = add_bits(p, OP_REPEAT, OP_BITS); if (ret) return ret;
ret = add_bits(p, r, REPEAT_BITS); if (ret) return ret;
if (sw842_template_counts)
atomic_inc(&template_repeat_count);
return 0;
}
staticint add_short_data_template(struct sw842_param *p, u8 b)
{ int ret, i;
if (!b || b > SHORT_DATA_BITS_MAX) return -EINVAL;
ret = add_bits(p, OP_SHORT_DATA, OP_BITS); if (ret) return ret;
ret = add_bits(p, b, SHORT_DATA_BITS); if (ret) return ret;
for (i = 0; i < b; i++) {
ret = add_bits(p, p->in[i], 8); if (ret) return ret;
}
if (sw842_template_counts)
atomic_inc(&template_short_data_count);
return 0;
}
staticint add_zeros_template(struct sw842_param *p)
{ int ret = add_bits(p, OP_ZEROS, OP_BITS);
if (ret) return ret;
if (sw842_template_counts)
atomic_inc(&template_zeros_count);
return 0;
}
staticint add_end_template(struct sw842_param *p)
{ int ret = add_bits(p, OP_END, OP_BITS);
if (ret) return ret;
if (sw842_template_counts)
atomic_inc(&template_end_count);
return 0;
}
staticbool check_template(struct sw842_param *p, u8 c)
{
u8 *t = comp_ops[c]; int i, match, b = 0;
if (c >= OPS_MAX) returnfalse;
for (i = 0; i < 4; i++) { if (t[i] & OP_ACTION_INDEX) { if (t[i] & OP_AMOUNT_2)
match = check_index(p, 2, b >> 1); elseif (t[i] & OP_AMOUNT_4)
match = check_index(p, 4, b >> 2); elseif (t[i] & OP_AMOUNT_8)
match = check_index(p, 8, 0); else returnfalse; if (!match) returnfalse;
}
/* find the next template to use, and add it * the p->dataN fields must already be set for the current 8 byte block
*/ staticint process_next(struct sw842_param *p)
{ int ret, i;
/* check up to OPS_MAX - 1; last op is our fallback */ for (i = 0; i < OPS_MAX - 1; i++) { if (check_template(p, i)) break;
}
ret = add_template(p, i); if (ret) return ret;
return 0;
}
/** * sw842_compress * * Compress the uncompressed buffer of length @ilen at @in to the output buffer * @out, using no more than @olen bytes, using the 842 compression format. * * Returns: 0 on success, error on failure. The @olen parameter * will contain the number of output bytes written on success, or * 0 on error.
*/ int sw842_compress(const u8 *in, unsignedint ilen,
u8 *out, unsignedint *olen, void *wmem)
{ struct sw842_param *p = (struct sw842_param *)wmem; int ret;
u64 last, next, pad, total;
u8 repeat_count = 0;
u32 crc;
/* if using strict mode, we can only compress a multiple of 8 */ if (sw842_strict && (ilen % 8)) {
pr_err("Using strict mode, can't compress len %d\n", ilen); return -EINVAL;
}
/* let's compress at least 8 bytes, mkay? */ if (unlikely(ilen < 8)) goto skip_comp;
/* make initial 'last' different so we don't match the first time */
last = ~get_unaligned((u64 *)p->in);
while (p->ilen > 7) {
next = get_unaligned((u64 *)p->in);
/* must get the next data, as we need to update the hashtable * entries with the new data every time
*/
get_next_data(p);
/* we don't care about endianness in last or next; * we're just comparing 8 bytes to another 8 bytes, * they're both the same endianness
*/ if (next == last) { /* repeat count bits are 0-based, so we stop at +1 */ if (++repeat_count <= REPEAT_BITS_MAX) goto repeat;
} if (repeat_count) {
ret = add_repeat_template(p, repeat_count); if (ret) return ret;
repeat_count = 0; if (next == last) /* reached max repeat bits */ goto repeat;
}
if (next == 0)
ret = add_zeros_template(p); else
ret = process_next(p);
if (repeat_count) {
ret = add_repeat_template(p, repeat_count); if (ret) return ret;
}
skip_comp: if (p->ilen > 0) {
ret = add_short_data_template(p, p->ilen); if (ret) return ret;
p->in += p->ilen;
p->ilen = 0;
}
ret = add_end_template(p); if (ret) return ret;
/* * crc(0:31) is appended to target data starting with the next * bit after End of stream template. * nx842 calculates CRC for data in big-endian format. So doing * same here so that sw842 decompression can be used for both * compressed data.
*/
crc = crc32_be(0, in, ilen);
ret = add_bits(p, crc, CRC_BITS); if (ret) return ret;
if (p->bit) {
p->out++;
p->olen--;
p->bit = 0;
}
/* pad compressed length to multiple of 8 */
pad = (8 - ((total - p->olen) % 8)) % 8; if (pad) { if (pad > p->olen) /* we were so close! */ return -ENOSPC;
memset(p->out, 0, pad);
p->out += pad;
p->olen -= pad;
}
if (unlikely((total - p->olen) > UINT_MAX)) return -ENOSPC;
*olen = total - p->olen;
return 0;
}
EXPORT_SYMBOL_GPL(sw842_compress);
staticint __init sw842_init(void)
{ if (sw842_template_counts)
sw842_debugfs_create();
return 0;
}
module_init(sw842_init);
staticvoid __exit sw842_exit(void)
{ if (sw842_template_counts)
sw842_debugfs_remove();
}
module_exit(sw842_exit);
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.1Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.