Merge tag 'char-misc-6.18-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc

Pull char/misc driver fixes from Greg KH:
 "Here are some small char/misc/android driver fixes for 6.18-rc3 for
  reported issues. Included in here are:

   - rust binder fixes for reported issues

   - mei device id addition

   - mei driver fixes

   - comedi bugfix

   - most usb driver bugfixes

   - fastrpc memory leak fix

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'char-misc-6.18-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc:
  most: usb: hdm_probe: Fix calling put_device() before device initialization
  most: usb: Fix use-after-free in hdm_disconnect
  binder: remove "invalid inc weak" check
  mei: txe: fix initialization order
  comedi: fix divide-by-zero in comedi_buf_munge()
  mei: late_bind: Fix -Wincompatible-function-pointer-types-strict
  misc: fastrpc: Fix dma_buf object leak in fastrpc_map_lookup
  mei: me: add wildcat lake P DID
  misc: amd-sbi: Clarify that this is a BMC driver
  nvmem: rcar-efuse: add missing MODULE_DEVICE_TABLE
  binder: Fix missing kernel-doc entries in binder.c
  rust_binder: report freeze notification only when fully frozen
  rust_binder: don't delete FreezeListener if there are pending duplicates
  rust_binder: freeze_notif_done should resend if wrong state
  rust_binder: remove warning about orphan mappings
  rust_binder: clean `clippy::mem_replace_with_default` warning
This commit is contained in:
Linus Torvalds
2025-10-26 10:33:46 -07:00
14 changed files with 93 additions and 62 deletions

View File

@@ -851,17 +851,8 @@ static int binder_inc_node_nilocked(struct binder_node *node, int strong,
} else { } else {
if (!internal) if (!internal)
node->local_weak_refs++; node->local_weak_refs++;
if (!node->has_weak_ref && list_empty(&node->work.entry)) { if (!node->has_weak_ref && target_list && list_empty(&node->work.entry))
if (target_list == NULL) {
pr_err("invalid inc weak node for %d\n",
node->debug_id);
return -EINVAL;
}
/*
* See comment above
*/
binder_enqueue_work_ilocked(&node->work, target_list); binder_enqueue_work_ilocked(&node->work, target_list);
}
} }
return 0; return 0;
} }
@@ -2418,10 +2409,10 @@ err_fd_not_accepted:
/** /**
* struct binder_ptr_fixup - data to be fixed-up in target buffer * struct binder_ptr_fixup - data to be fixed-up in target buffer
* @offset offset in target buffer to fixup * @offset: offset in target buffer to fixup
* @skip_size bytes to skip in copy (fixup will be written later) * @skip_size: bytes to skip in copy (fixup will be written later)
* @fixup_data data to write at fixup offset * @fixup_data: data to write at fixup offset
* @node list node * @node: list node
* *
* This is used for the pointer fixup list (pf) which is created and consumed * This is used for the pointer fixup list (pf) which is created and consumed
* during binder_transaction() and is only accessed locally. No * during binder_transaction() and is only accessed locally. No
@@ -2438,10 +2429,10 @@ struct binder_ptr_fixup {
/** /**
* struct binder_sg_copy - scatter-gather data to be copied * struct binder_sg_copy - scatter-gather data to be copied
* @offset offset in target buffer * @offset: offset in target buffer
* @sender_uaddr user address in source buffer * @sender_uaddr: user address in source buffer
* @length bytes to copy * @length: bytes to copy
* @node list node * @node: list node
* *
* This is used for the sg copy list (sgc) which is created and consumed * This is used for the sg copy list (sgc) which is created and consumed
* during binder_transaction() and is only accessed locally. No * during binder_transaction() and is only accessed locally. No
@@ -4063,14 +4054,15 @@ binder_freeze_notification_done(struct binder_proc *proc,
/** /**
* binder_free_buf() - free the specified buffer * binder_free_buf() - free the specified buffer
* @proc: binder proc that owns buffer * @proc: binder proc that owns buffer
* @buffer: buffer to be freed * @thread: binder thread performing the buffer release
* @is_failure: failed to send transaction * @buffer: buffer to be freed
* @is_failure: failed to send transaction
* *
* If buffer for an async transaction, enqueue the next async * If the buffer is for an async transaction, enqueue the next async
* transaction from the node. * transaction from the node.
* *
* Cleanup buffer and free it. * Cleanup the buffer and free it.
*/ */
static void static void
binder_free_buf(struct binder_proc *proc, binder_free_buf(struct binder_proc *proc,

View File

@@ -106,13 +106,22 @@ impl DeliverToRead for FreezeMessage {
return Ok(true); return Ok(true);
} }
if freeze.is_clearing { if freeze.is_clearing {
_removed_listener = freeze_entry.remove_node(); kernel::warn_on!(freeze.num_cleared_duplicates != 0);
if freeze.num_pending_duplicates > 0 {
// The primary freeze listener was deleted, so convert a pending duplicate back
// into the primary one.
freeze.num_pending_duplicates -= 1;
freeze.is_pending = true;
freeze.is_clearing = true;
} else {
_removed_listener = freeze_entry.remove_node();
}
drop(node_refs); drop(node_refs);
writer.write_code(BR_CLEAR_FREEZE_NOTIFICATION_DONE)?; writer.write_code(BR_CLEAR_FREEZE_NOTIFICATION_DONE)?;
writer.write_payload(&self.cookie.0)?; writer.write_payload(&self.cookie.0)?;
Ok(true) Ok(true)
} else { } else {
let is_frozen = freeze.node.owner.inner.lock().is_frozen; let is_frozen = freeze.node.owner.inner.lock().is_frozen.is_fully_frozen();
if freeze.last_is_frozen == Some(is_frozen) { if freeze.last_is_frozen == Some(is_frozen) {
return Ok(true); return Ok(true);
} }
@@ -245,8 +254,9 @@ impl Process {
); );
return Err(EINVAL); return Err(EINVAL);
} }
if freeze.is_clearing { let is_frozen = freeze.node.owner.inner.lock().is_frozen.is_fully_frozen();
// Immediately send another FreezeMessage for BR_CLEAR_FREEZE_NOTIFICATION_DONE. if freeze.is_clearing || freeze.last_is_frozen != Some(is_frozen) {
// Immediately send another FreezeMessage.
clear_msg = Some(FreezeMessage::init(alloc, cookie)); clear_msg = Some(FreezeMessage::init(alloc, cookie));
} }
freeze.is_pending = false; freeze.is_pending = false;

View File

@@ -687,7 +687,7 @@ impl Node {
); );
} }
if inner.freeze_list.is_empty() { if inner.freeze_list.is_empty() {
_unused_capacity = mem::replace(&mut inner.freeze_list, KVVec::new()); _unused_capacity = mem::take(&mut inner.freeze_list);
} }
} }

View File

@@ -72,6 +72,33 @@ impl Mapping {
const PROC_DEFER_FLUSH: u8 = 1; const PROC_DEFER_FLUSH: u8 = 1;
const PROC_DEFER_RELEASE: u8 = 2; const PROC_DEFER_RELEASE: u8 = 2;
#[derive(Copy, Clone)]
pub(crate) enum IsFrozen {
Yes,
No,
InProgress,
}
impl IsFrozen {
/// Whether incoming transactions should be rejected due to freeze.
pub(crate) fn is_frozen(self) -> bool {
match self {
IsFrozen::Yes => true,
IsFrozen::No => false,
IsFrozen::InProgress => true,
}
}
/// Whether freeze notifications consider this process frozen.
pub(crate) fn is_fully_frozen(self) -> bool {
match self {
IsFrozen::Yes => true,
IsFrozen::No => false,
IsFrozen::InProgress => false,
}
}
}
/// The fields of `Process` protected by the spinlock. /// The fields of `Process` protected by the spinlock.
pub(crate) struct ProcessInner { pub(crate) struct ProcessInner {
is_manager: bool, is_manager: bool,
@@ -98,7 +125,7 @@ pub(crate) struct ProcessInner {
/// are woken up. /// are woken up.
outstanding_txns: u32, outstanding_txns: u32,
/// Process is frozen and unable to service binder transactions. /// Process is frozen and unable to service binder transactions.
pub(crate) is_frozen: bool, pub(crate) is_frozen: IsFrozen,
/// Process received sync transactions since last frozen. /// Process received sync transactions since last frozen.
pub(crate) sync_recv: bool, pub(crate) sync_recv: bool,
/// Process received async transactions since last frozen. /// Process received async transactions since last frozen.
@@ -124,7 +151,7 @@ impl ProcessInner {
started_thread_count: 0, started_thread_count: 0,
defer_work: 0, defer_work: 0,
outstanding_txns: 0, outstanding_txns: 0,
is_frozen: false, is_frozen: IsFrozen::No,
sync_recv: false, sync_recv: false,
async_recv: false, async_recv: false,
binderfs_file: None, binderfs_file: None,
@@ -1260,7 +1287,7 @@ impl Process {
let is_manager = { let is_manager = {
let mut inner = self.inner.lock(); let mut inner = self.inner.lock();
inner.is_dead = true; inner.is_dead = true;
inner.is_frozen = false; inner.is_frozen = IsFrozen::No;
inner.sync_recv = false; inner.sync_recv = false;
inner.async_recv = false; inner.async_recv = false;
inner.is_manager inner.is_manager
@@ -1346,10 +1373,6 @@ impl Process {
.alloc .alloc
.take_for_each(|offset, size, debug_id, odata| { .take_for_each(|offset, size, debug_id, odata| {
let ptr = offset + address; let ptr = offset + address;
pr_warn!(
"{}: removing orphan mapping {offset}:{size}\n",
self.pid_in_current_ns()
);
let mut alloc = let mut alloc =
Allocation::new(self.clone(), debug_id, offset, size, ptr, false); Allocation::new(self.clone(), debug_id, offset, size, ptr, false);
if let Some(data) = odata { if let Some(data) = odata {
@@ -1371,7 +1394,7 @@ impl Process {
return; return;
} }
inner.outstanding_txns -= 1; inner.outstanding_txns -= 1;
inner.is_frozen && inner.outstanding_txns == 0 inner.is_frozen.is_frozen() && inner.outstanding_txns == 0
}; };
if wake { if wake {
@@ -1385,7 +1408,7 @@ impl Process {
let mut inner = self.inner.lock(); let mut inner = self.inner.lock();
inner.sync_recv = false; inner.sync_recv = false;
inner.async_recv = false; inner.async_recv = false;
inner.is_frozen = false; inner.is_frozen = IsFrozen::No;
drop(inner); drop(inner);
msgs.send_messages(); msgs.send_messages();
return Ok(()); return Ok(());
@@ -1394,7 +1417,7 @@ impl Process {
let mut inner = self.inner.lock(); let mut inner = self.inner.lock();
inner.sync_recv = false; inner.sync_recv = false;
inner.async_recv = false; inner.async_recv = false;
inner.is_frozen = true; inner.is_frozen = IsFrozen::InProgress;
if info.timeout_ms > 0 { if info.timeout_ms > 0 {
let mut jiffies = kernel::time::msecs_to_jiffies(info.timeout_ms); let mut jiffies = kernel::time::msecs_to_jiffies(info.timeout_ms);
@@ -1408,7 +1431,7 @@ impl Process {
.wait_interruptible_timeout(&mut inner, jiffies) .wait_interruptible_timeout(&mut inner, jiffies)
{ {
CondVarTimeoutResult::Signal { .. } => { CondVarTimeoutResult::Signal { .. } => {
inner.is_frozen = false; inner.is_frozen = IsFrozen::No;
return Err(ERESTARTSYS); return Err(ERESTARTSYS);
} }
CondVarTimeoutResult::Woken { jiffies: remaining } => { CondVarTimeoutResult::Woken { jiffies: remaining } => {
@@ -1422,17 +1445,18 @@ impl Process {
} }
if inner.txns_pending_locked() { if inner.txns_pending_locked() {
inner.is_frozen = false; inner.is_frozen = IsFrozen::No;
Err(EAGAIN) Err(EAGAIN)
} else { } else {
drop(inner); drop(inner);
match self.prepare_freeze_messages() { match self.prepare_freeze_messages() {
Ok(batch) => { Ok(batch) => {
self.inner.lock().is_frozen = IsFrozen::Yes;
batch.send_messages(); batch.send_messages();
Ok(()) Ok(())
} }
Err(kernel::alloc::AllocError) => { Err(kernel::alloc::AllocError) => {
self.inner.lock().is_frozen = false; self.inner.lock().is_frozen = IsFrozen::No;
Err(ENOMEM) Err(ENOMEM)
} }
} }

View File

@@ -249,7 +249,7 @@ impl Transaction {
if oneway { if oneway {
if let Some(target_node) = self.target_node.clone() { if let Some(target_node) = self.target_node.clone() {
if process_inner.is_frozen { if process_inner.is_frozen.is_frozen() {
process_inner.async_recv = true; process_inner.async_recv = true;
if self.flags & TF_UPDATE_TXN != 0 { if self.flags & TF_UPDATE_TXN != 0 {
if let Some(t_outdated) = if let Some(t_outdated) =
@@ -270,7 +270,7 @@ impl Transaction {
} }
} }
if process_inner.is_frozen { if process_inner.is_frozen.is_frozen() {
return Err(BinderError::new_frozen_oneway()); return Err(BinderError::new_frozen_oneway());
} else { } else {
return Ok(()); return Ok(());
@@ -280,7 +280,7 @@ impl Transaction {
} }
} }
if process_inner.is_frozen { if process_inner.is_frozen.is_frozen() {
process_inner.sync_recv = true; process_inner.sync_recv = true;
return Err(BinderError::new_frozen()); return Err(BinderError::new_frozen());
} }

View File

@@ -317,7 +317,7 @@ static unsigned int comedi_buf_munge(struct comedi_subdevice *s,
unsigned int count = 0; unsigned int count = 0;
const unsigned int num_sample_bytes = comedi_bytes_per_sample(s); const unsigned int num_sample_bytes = comedi_bytes_per_sample(s);
if (!s->munge || (async->cmd.flags & CMDF_RAWDATA)) { if (!s->munge || (async->cmd.flags & CMDF_RAWDATA) || async->cmd.chanlist_len == 0) {
async->munge_count += num_bytes; async->munge_count += num_bytes;
return num_bytes; return num_bytes;
} }

View File

@@ -2,9 +2,11 @@
config AMD_SBRMI_I2C config AMD_SBRMI_I2C
tristate "AMD side band RMI support" tristate "AMD side band RMI support"
depends on I2C depends on I2C
depends on ARM || ARM64 || COMPILE_TEST
select REGMAP_I2C select REGMAP_I2C
help help
Side band RMI over I2C support for AMD out of band management. Side band RMI over I2C support for AMD out of band management.
This driver is intended to run on the BMC, not the managed node.
This driver can also be built as a module. If so, the module will This driver can also be built as a module. If so, the module will
be called sbrmi-i2c. be called sbrmi-i2c.

View File

@@ -381,6 +381,8 @@ static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd,
} }
spin_unlock(&fl->lock); spin_unlock(&fl->lock);
dma_buf_put(buf);
return ret; return ret;
} }

View File

@@ -120,6 +120,8 @@
#define MEI_DEV_ID_PTL_H 0xE370 /* Panther Lake H */ #define MEI_DEV_ID_PTL_H 0xE370 /* Panther Lake H */
#define MEI_DEV_ID_PTL_P 0xE470 /* Panther Lake P */ #define MEI_DEV_ID_PTL_P 0xE470 /* Panther Lake P */
#define MEI_DEV_ID_WCL_P 0x4D70 /* Wildcat Lake P */
/* /*
* MEI HW Section * MEI HW Section
*/ */

View File

@@ -134,8 +134,7 @@ static bool mei_lb_check_response(const struct device *dev, ssize_t bytes,
return true; return true;
} }
static int mei_lb_push_payload(struct device *dev, static int mei_lb_push_payload(struct device *dev, u32 type, u32 flags,
enum intel_lb_type type, u32 flags,
const void *payload, size_t payload_size) const void *payload, size_t payload_size)
{ {
struct mei_cl_device *cldev; struct mei_cl_device *cldev;

View File

@@ -127,6 +127,8 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
{MEI_PCI_DEVICE(MEI_DEV_ID_PTL_H, MEI_ME_PCH15_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_PTL_H, MEI_ME_PCH15_CFG)},
{MEI_PCI_DEVICE(MEI_DEV_ID_PTL_P, MEI_ME_PCH15_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_PTL_P, MEI_ME_PCH15_CFG)},
{MEI_PCI_DEVICE(MEI_DEV_ID_WCL_P, MEI_ME_PCH15_CFG)},
/* required last entry */ /* required last entry */
{0, } {0, }
}; };

View File

@@ -109,19 +109,19 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto end; goto end;
} }
err = mei_register(dev, &pdev->dev);
if (err)
goto release_irq;
if (mei_start(dev)) { if (mei_start(dev)) {
dev_err(&pdev->dev, "init hw failure.\n"); dev_err(&pdev->dev, "init hw failure.\n");
err = -ENODEV; err = -ENODEV;
goto release_irq; goto deregister;
} }
pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_TXI_RPM_TIMEOUT); pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_TXI_RPM_TIMEOUT);
pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev);
err = mei_register(dev, &pdev->dev);
if (err)
goto stop;
pci_set_drvdata(pdev, dev); pci_set_drvdata(pdev, dev);
/* /*
@@ -144,8 +144,8 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0; return 0;
stop: deregister:
mei_stop(dev); mei_deregister(dev);
release_irq: release_irq:
mei_cancel_work(dev); mei_cancel_work(dev);
mei_disable_interrupts(dev); mei_disable_interrupts(dev);

View File

@@ -929,6 +929,10 @@ static void release_mdev(struct device *dev)
{ {
struct most_dev *mdev = to_mdev_from_dev(dev); struct most_dev *mdev = to_mdev_from_dev(dev);
kfree(mdev->busy_urbs);
kfree(mdev->cap);
kfree(mdev->conf);
kfree(mdev->ep_address);
kfree(mdev); kfree(mdev);
} }
/** /**
@@ -1093,7 +1097,7 @@ err_free_cap:
err_free_conf: err_free_conf:
kfree(mdev->conf); kfree(mdev->conf);
err_free_mdev: err_free_mdev:
put_device(&mdev->dev); kfree(mdev);
return ret; return ret;
} }
@@ -1121,13 +1125,6 @@ static void hdm_disconnect(struct usb_interface *interface)
if (mdev->dci) if (mdev->dci)
device_unregister(&mdev->dci->dev); device_unregister(&mdev->dci->dev);
most_deregister_interface(&mdev->iface); most_deregister_interface(&mdev->iface);
kfree(mdev->busy_urbs);
kfree(mdev->cap);
kfree(mdev->conf);
kfree(mdev->ep_address);
put_device(&mdev->dci->dev);
put_device(&mdev->dev);
} }
static int hdm_suspend(struct usb_interface *interface, pm_message_t message) static int hdm_suspend(struct usb_interface *interface, pm_message_t message)

View File

@@ -127,6 +127,7 @@ static const struct of_device_id rcar_fuse_match[] = {
{ .compatible = "renesas,r8a779h0-otp", .data = &rcar_fuse_v4m }, { .compatible = "renesas,r8a779h0-otp", .data = &rcar_fuse_v4m },
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, rcar_fuse_match);
static struct platform_driver rcar_fuse_driver = { static struct platform_driver rcar_fuse_driver = {
.probe = rcar_fuse_probe, .probe = rcar_fuse_probe,