c259cc9cb4
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEZH8oZUiU471FcZm+ONu9yGCSaT4FAmUlrb4ACgkQONu9yGCS aT4b+hAAgvFC6P+XmyyNXJ9ISHLkgSlcIAdatb+qeOCUtdiWHqfxIha13FdnCdhL WS2c/O9ORfAzjFwnYWF6LBwH8ArxRSkAXrGCMuCkEFBP3cG/j2HD+XLAAYEuBjjb sf1fw8e8VSgaPEOnwXie5rTfAY4VnZKEtZjAxjyIQnJKVVKfxQRb8CyaWDPzPD0Z tL/iABt7UWNHZayHTHsh0YhF2UhXtOjHinWigEarcZQEvOB2qRQtFl71cnqosi+t 3ZRZzepH7/Fx3v6/H/6PNq+GSI/ZzhOiCQolVV5YcMGHXsW9cP6arjLUxco5pzpk pEg0vdMq47JOZYQ2pIewG4t7+NLmFIxCRFnKQVbxeFNSY9c1jhd8g5lhx9YEXwjT BzMtV5DnZoaoMdq2P1STw/+RVYrDI1Lm6jqfgw/D27b7LzQ13VsGM9BJ1rCs8Hm7 UhWyjwFcgo0vhpfML1RF0RtT9Mo5SOnpGPfpbFdjg8jdXlGknNH0QsH+EY/BpF8l h77P5BvoNIjsIN3B1YunfXtFXhx3h0sI8zZrqHR+zhOeWGsXcqQ5mZ/lYdYKkKuH R8LRB7shPndF4xdRX0uRXwomcXhs+60eA5xEvE9u0CqqdpXfQN5oTwixfCm2C8MS O5Fc7hfvK11XtR3ja+y3KRhiNG3YsfW2PXnlOfZxMZ6iPqXtA/o= =5/pn -----END PGP SIGNATURE----- Merge 6.1.57 into android14-6.1-lts Changes in 6.1.57 spi: zynqmp-gqspi: fix clock imbalance on probe failure ASoC: soc-utils: Export snd_soc_dai_is_dummy() symbol ASoC: tegra: Fix redundant PLLA and PLLA_OUT0 updates mptcp: rename timer related helper to less confusing names mptcp: fix dangling connection hang-up mptcp: annotate lockless accesses to sk->sk_err mptcp: move __mptcp_error_report in protocol.c mptcp: process pending subflow error on close ata,scsi: do not issue START STOP UNIT on resume scsi: sd: Differentiate system and runtime start/stop management scsi: sd: Do not issue commands to suspended disks on shutdown scsi: core: Improve type safety of scsi_rescan_device() scsi: Do not attempt to rescan suspended devices ata: libata-scsi: Fix delayed scsi_rescan_device() execution NFS: Cleanup unused rpc_clnt variable NFS: rename nfs_client_kset to nfs_kset NFSv4: Fix a state manager thread deadlock regression mm/memory: add vm_normal_folio() mm/mempolicy: convert queue_pages_pmd() to queue_folios_pmd() mm/mempolicy: convert queue_pages_pte_range() to queue_folios_pte_range() mm/mempolicy: convert migrate_page_add() to migrate_folio_add() mm: mempolicy: keep VMA walk if both MPOL_MF_STRICT and MPOL_MF_MOVE are specified mm/page_alloc: always remove pages from temporary list mm/page_alloc: leave IRQs enabled for per-cpu page allocations mm: page_alloc: fix CMA and HIGHATOMIC landing on the wrong buddy list ring-buffer: remove obsolete comment for free_buffer_page() ring-buffer: Fix bytes info in per_cpu buffer stats btrfs: use struct qstr instead of name and namelen pairs btrfs: setup qstr from dentrys using fscrypt helper btrfs: use struct fscrypt_str instead of struct qstr Revert "NFSv4: Retry LOCK on OLD_STATEID during delegation return" arm64: Avoid repeated AA64MMFR1_EL1 register read on pagefault path net: add sysctl accept_ra_min_rtr_lft net: change accept_ra_min_rtr_lft to affect all RA lifetimes net: release reference to inet6_dev pointer arm64: cpufeature: Fix CLRBHB and BC detection drm/amd/display: Adjust the MST resume flow iommu/arm-smmu-v3: Set TTL invalidation hint better iommu/arm-smmu-v3: Avoid constructing invalid range commands rbd: move rbd_dev_refresh() definition rbd: decouple header read-in from updating rbd_dev->header rbd: decouple parent info read-in from updating rbd_dev rbd: take header_rwsem in rbd_dev_refresh() only when updating block: fix use-after-free of q->q_usage_counter hwmon: (nzxt-smart2) Add device id hwmon: (nzxt-smart2) add another USB ID i40e: fix the wrong PTP frequency calculation scsi: zfcp: Fix a double put in zfcp_port_enqueue() iommu/vt-d: Avoid memory allocation in iommu_suspend() vringh: don't use vringh_kiov_advance() in vringh_iov_xfer() net: ethernet: mediatek: disable irq before schedule napi mptcp: userspace pm allow creating id 0 subflow qed/red_ll2: Fix undefined behavior bug in struct qed_ll2_info Bluetooth: hci_codec: Fix leaking content of local_codecs Bluetooth: hci_sync: Fix handling of HCI_QUIRK_STRICT_DUPLICATE_FILTER wifi: mwifiex: Fix tlv_buf_left calculation md/raid5: release batch_last before waiting for another stripe_head PCI: qcom: Fix IPQ8074 enumeration net: replace calls to sock->ops->connect() with kernel_connect() net: prevent rewrite of msg_name in sock_sendmsg() drm/amd: Fix detection of _PR3 on the PCIe root port drm/amd: Fix logic error in sienna_cichlid_update_pcie_parameters() arm64: Add Cortex-A520 CPU part definition arm64: errata: Add Cortex-A520 speculative unprivileged load workaround HID: sony: Fix a potential memory leak in sony_probe() ubi: Refuse attaching if mtd's erasesize is 0 erofs: fix memory leak of LZMA global compressed deduplication wifi: iwlwifi: dbg_ini: fix structure packing wifi: iwlwifi: mvm: Fix a memory corruption issue wifi: cfg80211: hold wiphy lock in auto-disconnect wifi: cfg80211: move wowlan disable under locks wifi: cfg80211: add a work abstraction with special semantics wifi: cfg80211: fix cqm_config access race wifi: cfg80211: add missing kernel-doc for cqm_rssi_work wifi: mwifiex: Fix oob check condition in mwifiex_process_rx_packet leds: Drop BUG_ON check for LED_COLOR_ID_MULTI bpf: Fix tr dereferencing regulator: mt6358: Drop *_SSHUB regulators regulator: mt6358: Use linear voltage helpers for single range regulators regulator: mt6358: split ops for buck and linear range LDO regulators Bluetooth: Delete unused hci_req_prepare_suspend() declaration Bluetooth: ISO: Fix handling of listen for unicast drivers/net: process the result of hdlc_open() and add call of hdlc_close() in uhdlc_close() wifi: mt76: mt76x02: fix MT76x0 external LNA gain handling perf/x86/amd/core: Fix overflow reset on hotplug regmap: rbtree: Fix wrong register marked as in-cache when creating new node wifi: mac80211: fix potential key use-after-free perf/x86/amd: Do not WARN() on every IRQ iommu/mediatek: Fix share pgtable for iova over 4GB regulator/core: regulator_register: set device->class earlier ima: Finish deprecation of IMA_TRUSTED_KEYRING Kconfig scsi: target: core: Fix deadlock due to recursive locking ima: rework CONFIG_IMA dependency block NFSv4: Fix a nfs4_state_manager() race bpf: tcp_read_skb needs to pop skb regardless of seq bpf, sockmap: Do not inc copied_seq when PEEK flag set bpf, sockmap: Reject sk_msg egress redirects to non-TCP sockets modpost: add missing else to the "of" check net: fix possible store tearing in neigh_periodic_work() bpf: Add BPF_FIB_LOOKUP_SKIP_NEIGH for bpf_fib_lookup neighbour: annotate lockless accesses to n->nud_state neighbour: switch to standard rcu, instead of rcu_bh neighbour: fix data-races around n->output ipv4, ipv6: Fix handling of transhdrlen in __ip{,6}_append_data() ptp: ocp: Fix error handling in ptp_ocp_device_init net: dsa: mv88e6xxx: Avoid EEPROM timeout when EEPROM is absent ipv6: tcp: add a missing nf_reset_ct() in 3WHS handling net: usb: smsc75xx: Fix uninit-value access in __smsc75xx_read_reg net: nfc: llcp: Add lock when modifying device list net: ethernet: ti: am65-cpsw: Fix error code in am65_cpsw_nuss_init_tx_chns() ibmveth: Remove condition to recompute TCP header checksum. netfilter: handle the connecting collision properly in nf_conntrack_proto_sctp selftests: netfilter: Test nf_tables audit logging selftests: netfilter: Extend nft_audit.sh netfilter: nf_tables: Deduplicate nft_register_obj audit logs netfilter: nf_tables: nft_set_rbtree: fix spurious insertion failure ipv4: Set offload_failed flag in fibmatch results net: stmmac: dwmac-stm32: fix resume on STM32 MCU tipc: fix a potential deadlock on &tx->lock tcp: fix quick-ack counting to count actual ACKs of new data tcp: fix delayed ACKs for MSS boundary condition sctp: update transport state when processing a dupcook packet sctp: update hb timer immediately after users change hb_interval netlink: split up copies in the ack construction netlink: Fix potential skb memleak in netlink_ack netlink: annotate data-races around sk->sk_err HID: sony: remove duplicate NULL check before calling usb_free_urb() HID: intel-ish-hid: ipc: Disable and reenable ACPI GPE bit intel_idle: add Emerald Rapids Xeon support smb: use kernel_connect() and kernel_bind() parisc: Fix crash with nr_cpus=1 option dm zoned: free dmz->ddev array in dmz_put_zoned_devices RDMA/core: Require admin capabilities to set system parameters of: dynamic: Fix potential memory leak in of_changeset_action() IB/mlx4: Fix the size of a buffer in add_port_entries() gpio: aspeed: fix the GPIO number passed to pinctrl_gpio_set_config() gpio: pxa: disable pinctrl calls for MMP_GPIO RDMA/cma: Initialize ib_sa_multicast structure to 0 when join RDMA/cma: Fix truncation compilation warning in make_cma_ports RDMA/uverbs: Fix typo of sizeof argument RDMA/srp: Do not call scsi_done() from srp_abort() RDMA/siw: Fix connection failure handling RDMA/mlx5: Fix mutex unlocking on error flow for steering anchor creation RDMA/mlx5: Fix NULL string error x86/sev: Use the GHCB protocol when available for SNP CPUID requests ksmbd: fix race condition between session lookup and expire ksmbd: fix uaf in smb20_oplock_break_ack parisc: Restore __ldcw_align for PA-RISC 2.0 processors ipv6: remove nexthop_fib6_nh_bh() vrf: Fix lockdep splat in output path btrfs: fix an error handling path in btrfs_rename() btrfs: fix fscrypt name leak after failure to join log transaction netlink: remove the flex array from struct nlmsghdr btrfs: file_remove_privs needs an exclusive lock in direct io write ipv6: remove one read_lock()/read_unlock() pair in rt6_check_neigh() xen/events: replace evtchn_rwlock with RCU Linux 6.1.57 Change-Id: I2c200264df72a9043d91d31479c91b0d7f94863e Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
295 lines
7.7 KiB
C
295 lines
7.7 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
#include <linux/xz.h>
|
|
#include <linux/module.h>
|
|
#include "compress.h"
|
|
|
|
struct z_erofs_lzma {
|
|
struct z_erofs_lzma *next;
|
|
struct xz_dec_microlzma *state;
|
|
struct xz_buf buf;
|
|
u8 bounce[PAGE_SIZE];
|
|
};
|
|
|
|
/* considering the LZMA performance, no need to use a lockless list for now */
|
|
static DEFINE_SPINLOCK(z_erofs_lzma_lock);
|
|
static unsigned int z_erofs_lzma_max_dictsize;
|
|
static unsigned int z_erofs_lzma_nstrms, z_erofs_lzma_avail_strms;
|
|
static struct z_erofs_lzma *z_erofs_lzma_head;
|
|
static DECLARE_WAIT_QUEUE_HEAD(z_erofs_lzma_wq);
|
|
|
|
module_param_named(lzma_streams, z_erofs_lzma_nstrms, uint, 0444);
|
|
|
|
void z_erofs_lzma_exit(void)
|
|
{
|
|
/* there should be no running fs instance */
|
|
while (z_erofs_lzma_avail_strms) {
|
|
struct z_erofs_lzma *strm;
|
|
|
|
spin_lock(&z_erofs_lzma_lock);
|
|
strm = z_erofs_lzma_head;
|
|
if (!strm) {
|
|
spin_unlock(&z_erofs_lzma_lock);
|
|
DBG_BUGON(1);
|
|
return;
|
|
}
|
|
z_erofs_lzma_head = NULL;
|
|
spin_unlock(&z_erofs_lzma_lock);
|
|
|
|
while (strm) {
|
|
struct z_erofs_lzma *n = strm->next;
|
|
|
|
if (strm->state)
|
|
xz_dec_microlzma_end(strm->state);
|
|
kfree(strm);
|
|
--z_erofs_lzma_avail_strms;
|
|
strm = n;
|
|
}
|
|
}
|
|
}
|
|
|
|
int z_erofs_lzma_init(void)
|
|
{
|
|
unsigned int i;
|
|
|
|
/* by default, use # of possible CPUs instead */
|
|
if (!z_erofs_lzma_nstrms)
|
|
z_erofs_lzma_nstrms = num_possible_cpus();
|
|
|
|
for (i = 0; i < z_erofs_lzma_nstrms; ++i) {
|
|
struct z_erofs_lzma *strm = kzalloc(sizeof(*strm), GFP_KERNEL);
|
|
|
|
if (!strm) {
|
|
z_erofs_lzma_exit();
|
|
return -ENOMEM;
|
|
}
|
|
spin_lock(&z_erofs_lzma_lock);
|
|
strm->next = z_erofs_lzma_head;
|
|
z_erofs_lzma_head = strm;
|
|
spin_unlock(&z_erofs_lzma_lock);
|
|
++z_erofs_lzma_avail_strms;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int z_erofs_load_lzma_config(struct super_block *sb,
|
|
struct erofs_super_block *dsb,
|
|
struct z_erofs_lzma_cfgs *lzma, int size)
|
|
{
|
|
static DEFINE_MUTEX(lzma_resize_mutex);
|
|
unsigned int dict_size, i;
|
|
struct z_erofs_lzma *strm, *head = NULL;
|
|
int err;
|
|
|
|
if (!lzma || size < sizeof(struct z_erofs_lzma_cfgs)) {
|
|
erofs_err(sb, "invalid lzma cfgs, size=%u", size);
|
|
return -EINVAL;
|
|
}
|
|
if (lzma->format) {
|
|
erofs_err(sb, "unidentified lzma format %x, please check kernel version",
|
|
le16_to_cpu(lzma->format));
|
|
return -EINVAL;
|
|
}
|
|
dict_size = le32_to_cpu(lzma->dict_size);
|
|
if (dict_size > Z_EROFS_LZMA_MAX_DICT_SIZE || dict_size < 4096) {
|
|
erofs_err(sb, "unsupported lzma dictionary size %u",
|
|
dict_size);
|
|
return -EINVAL;
|
|
}
|
|
|
|
erofs_info(sb, "EXPERIMENTAL MicroLZMA in use. Use at your own risk!");
|
|
|
|
/* in case 2 z_erofs_load_lzma_config() race to avoid deadlock */
|
|
mutex_lock(&lzma_resize_mutex);
|
|
|
|
if (z_erofs_lzma_max_dictsize >= dict_size) {
|
|
mutex_unlock(&lzma_resize_mutex);
|
|
return 0;
|
|
}
|
|
|
|
/* 1. collect/isolate all streams for the following check */
|
|
for (i = 0; i < z_erofs_lzma_avail_strms; ++i) {
|
|
struct z_erofs_lzma *last;
|
|
|
|
again:
|
|
spin_lock(&z_erofs_lzma_lock);
|
|
strm = z_erofs_lzma_head;
|
|
if (!strm) {
|
|
spin_unlock(&z_erofs_lzma_lock);
|
|
wait_event(z_erofs_lzma_wq,
|
|
READ_ONCE(z_erofs_lzma_head));
|
|
goto again;
|
|
}
|
|
z_erofs_lzma_head = NULL;
|
|
spin_unlock(&z_erofs_lzma_lock);
|
|
|
|
for (last = strm; last->next; last = last->next)
|
|
++i;
|
|
last->next = head;
|
|
head = strm;
|
|
}
|
|
|
|
err = 0;
|
|
/* 2. walk each isolated stream and grow max dict_size if needed */
|
|
for (strm = head; strm; strm = strm->next) {
|
|
if (strm->state)
|
|
xz_dec_microlzma_end(strm->state);
|
|
strm->state = xz_dec_microlzma_alloc(XZ_PREALLOC, dict_size);
|
|
if (!strm->state)
|
|
err = -ENOMEM;
|
|
}
|
|
|
|
/* 3. push back all to the global list and update max dict_size */
|
|
spin_lock(&z_erofs_lzma_lock);
|
|
DBG_BUGON(z_erofs_lzma_head);
|
|
z_erofs_lzma_head = head;
|
|
spin_unlock(&z_erofs_lzma_lock);
|
|
wake_up_all(&z_erofs_lzma_wq);
|
|
|
|
z_erofs_lzma_max_dictsize = dict_size;
|
|
mutex_unlock(&lzma_resize_mutex);
|
|
return err;
|
|
}
|
|
|
|
int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
|
|
struct page **pagepool)
|
|
{
|
|
const unsigned int nrpages_out =
|
|
PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
|
|
const unsigned int nrpages_in =
|
|
PAGE_ALIGN(rq->inputsize) >> PAGE_SHIFT;
|
|
unsigned int inlen, outlen, pageofs;
|
|
struct z_erofs_lzma *strm;
|
|
u8 *kin;
|
|
bool bounced = false;
|
|
int no, ni, j, err = 0;
|
|
|
|
/* 1. get the exact LZMA compressed size */
|
|
kin = kmap(*rq->in);
|
|
err = z_erofs_fixup_insize(rq, kin + rq->pageofs_in,
|
|
min_t(unsigned int, rq->inputsize,
|
|
rq->sb->s_blocksize - rq->pageofs_in));
|
|
if (err) {
|
|
kunmap(*rq->in);
|
|
return err;
|
|
}
|
|
|
|
/* 2. get an available lzma context */
|
|
again:
|
|
spin_lock(&z_erofs_lzma_lock);
|
|
strm = z_erofs_lzma_head;
|
|
if (!strm) {
|
|
spin_unlock(&z_erofs_lzma_lock);
|
|
wait_event(z_erofs_lzma_wq, READ_ONCE(z_erofs_lzma_head));
|
|
goto again;
|
|
}
|
|
z_erofs_lzma_head = strm->next;
|
|
spin_unlock(&z_erofs_lzma_lock);
|
|
|
|
/* 3. multi-call decompress */
|
|
inlen = rq->inputsize;
|
|
outlen = rq->outputsize;
|
|
xz_dec_microlzma_reset(strm->state, inlen, outlen,
|
|
!rq->partial_decoding);
|
|
pageofs = rq->pageofs_out;
|
|
strm->buf.in = kin + rq->pageofs_in;
|
|
strm->buf.in_pos = 0;
|
|
strm->buf.in_size = min_t(u32, inlen, PAGE_SIZE - rq->pageofs_in);
|
|
inlen -= strm->buf.in_size;
|
|
strm->buf.out = NULL;
|
|
strm->buf.out_pos = 0;
|
|
strm->buf.out_size = 0;
|
|
|
|
for (ni = 0, no = -1;;) {
|
|
enum xz_ret xz_err;
|
|
|
|
if (strm->buf.out_pos == strm->buf.out_size) {
|
|
if (strm->buf.out) {
|
|
kunmap(rq->out[no]);
|
|
strm->buf.out = NULL;
|
|
}
|
|
|
|
if (++no >= nrpages_out || !outlen) {
|
|
erofs_err(rq->sb, "decompressed buf out of bound");
|
|
err = -EFSCORRUPTED;
|
|
break;
|
|
}
|
|
strm->buf.out_pos = 0;
|
|
strm->buf.out_size = min_t(u32, outlen,
|
|
PAGE_SIZE - pageofs);
|
|
outlen -= strm->buf.out_size;
|
|
if (!rq->out[no] && rq->fillgaps) { /* deduped */
|
|
rq->out[no] = erofs_allocpage(pagepool,
|
|
GFP_KERNEL | __GFP_NOFAIL);
|
|
set_page_private(rq->out[no],
|
|
Z_EROFS_SHORTLIVED_PAGE);
|
|
}
|
|
if (rq->out[no])
|
|
strm->buf.out = kmap(rq->out[no]) + pageofs;
|
|
pageofs = 0;
|
|
} else if (strm->buf.in_pos == strm->buf.in_size) {
|
|
kunmap(rq->in[ni]);
|
|
|
|
if (++ni >= nrpages_in || !inlen) {
|
|
erofs_err(rq->sb, "compressed buf out of bound");
|
|
err = -EFSCORRUPTED;
|
|
break;
|
|
}
|
|
strm->buf.in_pos = 0;
|
|
strm->buf.in_size = min_t(u32, inlen, PAGE_SIZE);
|
|
inlen -= strm->buf.in_size;
|
|
kin = kmap(rq->in[ni]);
|
|
strm->buf.in = kin;
|
|
bounced = false;
|
|
}
|
|
|
|
/*
|
|
* Handle overlapping: Use bounced buffer if the compressed
|
|
* data is under processing; Otherwise, Use short-lived pages
|
|
* from the on-stack pagepool where pages share with the same
|
|
* request.
|
|
*/
|
|
if (!bounced && rq->out[no] == rq->in[ni]) {
|
|
memcpy(strm->bounce, strm->buf.in, strm->buf.in_size);
|
|
strm->buf.in = strm->bounce;
|
|
bounced = true;
|
|
}
|
|
for (j = ni + 1; j < nrpages_in; ++j) {
|
|
struct page *tmppage;
|
|
|
|
if (rq->out[no] != rq->in[j])
|
|
continue;
|
|
|
|
DBG_BUGON(erofs_page_is_managed(EROFS_SB(rq->sb),
|
|
rq->in[j]));
|
|
tmppage = erofs_allocpage(pagepool,
|
|
GFP_KERNEL | __GFP_NOFAIL);
|
|
set_page_private(tmppage, Z_EROFS_SHORTLIVED_PAGE);
|
|
copy_highpage(tmppage, rq->in[j]);
|
|
rq->in[j] = tmppage;
|
|
}
|
|
xz_err = xz_dec_microlzma_run(strm->state, &strm->buf);
|
|
DBG_BUGON(strm->buf.out_pos > strm->buf.out_size);
|
|
DBG_BUGON(strm->buf.in_pos > strm->buf.in_size);
|
|
|
|
if (xz_err != XZ_OK) {
|
|
if (xz_err == XZ_STREAM_END && !outlen)
|
|
break;
|
|
erofs_err(rq->sb, "failed to decompress %d in[%u] out[%u]",
|
|
xz_err, rq->inputsize, rq->outputsize);
|
|
err = -EFSCORRUPTED;
|
|
break;
|
|
}
|
|
}
|
|
if (no < nrpages_out && strm->buf.out)
|
|
kunmap(rq->out[no]);
|
|
if (ni < nrpages_in)
|
|
kunmap(rq->in[ni]);
|
|
/* 4. push back LZMA stream context to the global list */
|
|
spin_lock(&z_erofs_lzma_lock);
|
|
strm->next = z_erofs_lzma_head;
|
|
z_erofs_lzma_head = strm;
|
|
spin_unlock(&z_erofs_lzma_lock);
|
|
wake_up(&z_erofs_lzma_wq);
|
|
return err;
|
|
}
|