Import of kernel-5.14.0-611.45.1.el9_7

This commit is contained in:
almalinux-bot-kernel 2026-04-03 04:50:42 +00:00
parent d728804b2e
commit 6f42de9b0c
23 changed files with 173 additions and 82 deletions

View File

@ -12,7 +12,7 @@ RHEL_MINOR = 7
#
# Use this spot to avoid future merge conflicts.
# Do not trim this comment.
RHEL_RELEASE = 611.42.1
RHEL_RELEASE = 611.45.1
#
# ZSTREAM

View File

@ -1053,10 +1053,8 @@ zl3073x_dpll_output_pin_phase_adjust_get(const struct dpll_pin *dpll_pin,
out_id = zl3073x_output_pin_out_get(pin->id);
out = zl3073x_out_state_get(zldev, out_id);
/* Convert value to ps and reverse two's complement negation applied
* during 'set'
*/
*phase_adjust = -out->phase_comp * pin->phase_gran;
/* The value in the register is expressed in half synth clock cycles. */
*phase_adjust = out->phase_comp * pin->phase_gran;
return 0;
}
@ -1078,10 +1076,8 @@ zl3073x_dpll_output_pin_phase_adjust_set(const struct dpll_pin *dpll_pin,
out_id = zl3073x_output_pin_out_get(pin->id);
out = *zl3073x_out_state_get(zldev, out_id);
/* The value in the register is stored as two's complement negation
* of requested value and expressed in half synth clock cycles.
*/
out.phase_comp = -phase_adjust / pin->phase_gran;
/* The value in the register is expressed in half synth clock cycles. */
out.phase_comp = phase_adjust / pin->phase_gran;
/* Update output configuration from mailbox */
return zl3073x_out_state_set(zldev, out_id, &out);

View File

@ -949,13 +949,14 @@ int drm_sched_job_add_resv_dependencies(struct drm_sched_job *job,
dma_resv_assert_held(resv);
dma_resv_for_each_fence(&cursor, resv, usage, fence) {
/* Make sure to grab an additional ref on the added fence */
dma_fence_get(fence);
ret = drm_sched_job_add_dependency(job, fence);
if (ret) {
dma_fence_put(fence);
/*
* As drm_sched_job_add_dependency always consumes the fence
* reference (even when it fails), and dma_resv_for_each_fence
* is not obtaining one, we need to grab one before calling.
*/
ret = drm_sched_job_add_dependency(job, dma_fence_get(fence));
if (ret)
return ret;
}
}
return 0;
}

View File

@ -3347,10 +3347,12 @@ static int __iommu_set_group_pasid(struct iommu_domain *domain,
int ret;
for_each_group_device(group, device) {
ret = domain->ops->set_dev_pasid(domain, device->dev,
pasid, NULL);
if (ret)
goto err_revert;
if (device->dev->iommu->max_pasids > 0) {
ret = domain->ops->set_dev_pasid(domain, device->dev,
pasid, NULL);
if (ret)
goto err_revert;
}
}
return 0;
@ -3360,7 +3362,9 @@ err_revert:
for_each_group_device(group, device) {
if (device == last_gdev)
break;
iommu_remove_dev_pasid(device->dev, pasid, domain);
if (device->dev->iommu->max_pasids > 0) {
iommu_remove_dev_pasid(device->dev, pasid, domain);
}
}
return ret;
}
@ -3371,8 +3375,10 @@ static void __iommu_remove_group_pasid(struct iommu_group *group,
{
struct group_device *device;
for_each_group_device(group, device)
iommu_remove_dev_pasid(device->dev, pasid, domain);
for_each_group_device(group, device) {
if (device->dev->iommu->max_pasids > 0)
iommu_remove_dev_pasid(device->dev, pasid, domain);
}
}
/*
@ -3409,7 +3415,13 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
mutex_lock(&group->mutex);
for_each_group_device(group, device) {
if (pasid >= device->dev->iommu->max_pasids) {
/*
* Skip PASID validation for devices without PASID support
* (max_pasids = 0). These devices cannot issue transactions
* with PASID, so they don't affect group's PASID usage.
*/
if ((device->dev->iommu->max_pasids > 0) &&
(pasid >= device->dev->iommu->max_pasids)) {
ret = -EINVAL;
goto out_unlock;
}

View File

@ -2380,11 +2380,6 @@ skip_mac_set:
unblock_netpoll_tx();
}
/* broadcast mode uses the all_slaves to loop through slaves. */
if (bond_mode_can_use_xmit_hash(bond) ||
BOND_MODE(bond) == BOND_MODE_BROADCAST)
bond_update_slave_arr(bond, NULL);
if (!slave_dev->netdev_ops->ndo_bpf ||
!slave_dev->netdev_ops->ndo_xdp_xmit) {
if (bond->xdp_prog) {
@ -2418,6 +2413,11 @@ skip_mac_set:
bpf_prog_inc(bond->xdp_prog);
}
/* broadcast mode uses the all_slaves to loop through slaves. */
if (bond_mode_can_use_xmit_hash(bond) ||
BOND_MODE(bond) == BOND_MODE_BROADCAST)
bond_update_slave_arr(bond, NULL);
bond_xdp_set_features(bond_dev);
slave_info(bond_dev, slave_dev, "Enslaving as %s interface with %s link\n",

View File

@ -1562,10 +1562,16 @@ destroy_macvlan_port:
/* the macvlan port may be freed by macvlan_uninit when fail to register.
* so we destroy the macvlan port only when it's valid.
*/
if (create && macvlan_port_get_rtnl(lowerdev)) {
if (macvlan_port_get_rtnl(lowerdev)) {
macvlan_flush_sources(port, vlan);
macvlan_port_destroy(port->dev);
if (create)
macvlan_port_destroy(port->dev);
}
/* @dev might have been made visible before an error was detected.
* Make sure to observe an RCU grace period before our caller
* (rtnl_newlink()) frees it.
*/
synchronize_net();
return err;
}
EXPORT_SYMBOL_GPL(macvlan_common_newlink);

View File

@ -449,6 +449,8 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
if (kstrtoull(buf, 0, (unsigned long long *) &fcp_lun))
return -EINVAL;
flush_work(&port->rport_work);
retval = zfcp_unit_add(port, fcp_lun);
if (retval)
return retval;

View File

@ -785,8 +785,11 @@ void iscsit_dec_session_usage_count(struct iscsit_session *sess)
spin_lock_bh(&sess->session_usage_lock);
sess->session_usage_count--;
if (!sess->session_usage_count && sess->session_waiting_on_uc)
if (!sess->session_usage_count && sess->session_waiting_on_uc) {
spin_unlock_bh(&sess->session_usage_lock);
complete(&sess->session_waiting_on_uc_comp);
return;
}
spin_unlock_bh(&sess->session_usage_lock);
}

View File

@ -215,6 +215,7 @@ nfsd_file_alloc(struct net *net, struct inode *inode, unsigned char need,
return NULL;
INIT_LIST_HEAD(&nf->nf_lru);
INIT_LIST_HEAD(&nf->nf_gc);
nf->nf_birthtime = ktime_get();
nf->nf_file = NULL;
nf->nf_cred = get_current_cred();
@ -392,8 +393,8 @@ nfsd_file_dispose_list(struct list_head *dispose)
struct nfsd_file *nf;
while (!list_empty(dispose)) {
nf = list_first_entry(dispose, struct nfsd_file, nf_lru);
list_del_init(&nf->nf_lru);
nf = list_first_entry(dispose, struct nfsd_file, nf_gc);
list_del_init(&nf->nf_gc);
nfsd_file_free(nf);
}
}
@ -410,13 +411,13 @@ nfsd_file_dispose_list_delayed(struct list_head *dispose)
{
while(!list_empty(dispose)) {
struct nfsd_file *nf = list_first_entry(dispose,
struct nfsd_file, nf_lru);
struct nfsd_file, nf_gc);
struct nfsd_net *nn = net_generic(nf->nf_net, nfsd_net_id);
struct nfsd_fcache_disposal *l = nn->fcache_disposal;
struct svc_serv *serv;
spin_lock(&l->lock);
list_move_tail(&nf->nf_lru, &l->freeme);
list_move_tail(&nf->nf_gc, &l->freeme);
spin_unlock(&l->lock);
/*
@ -511,7 +512,8 @@ nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru,
/* Refcount went to zero. Unhash it and queue it to the dispose list */
nfsd_file_unhash(nf);
list_lru_isolate_move(lru, &nf->nf_lru, head);
list_lru_isolate(lru, &nf->nf_lru);
list_add(&nf->nf_gc, head);
this_cpu_inc(nfsd_file_evictions);
trace_nfsd_file_gc_disposed(nf);
return LRU_REMOVED;
@ -590,7 +592,7 @@ nfsd_file_cond_queue(struct nfsd_file *nf, struct list_head *dispose)
/* If refcount goes to 0, then put on the dispose list */
if (refcount_sub_and_test(decrement, &nf->nf_ref)) {
list_add(&nf->nf_lru, dispose);
list_add(&nf->nf_gc, dispose);
trace_nfsd_file_closing(nf);
}
}
@ -666,8 +668,8 @@ nfsd_file_close_inode_sync(struct inode *inode)
nfsd_file_queue_for_close(inode, &dispose);
while (!list_empty(&dispose)) {
nf = list_first_entry(&dispose, struct nfsd_file, nf_lru);
list_del_init(&nf->nf_lru);
nf = list_first_entry(&dispose, struct nfsd_file, nf_gc);
list_del_init(&nf->nf_gc);
nfsd_file_free(nf);
}
}

View File

@ -44,6 +44,7 @@ struct nfsd_file {
struct nfsd_file_mark *nf_mark;
struct list_head nf_lru;
struct list_head nf_gc;
struct rcu_head nf_rcu;
ktime_t nf_birthtime;
};

View File

@ -36,10 +36,10 @@ struct cached_fid {
struct list_head entry;
struct cached_fids *cfids;
const char *path;
bool has_lease:1;
bool is_open:1;
bool on_list:1;
bool file_all_info_is_valid:1;
bool has_lease;
bool is_open;
bool on_list;
bool file_all_info_is_valid;
unsigned long time; /* jiffies of when lease was taken */
unsigned long last_access_time; /* jiffies of when last accessed */
struct kref refcount;

View File

@ -177,6 +177,9 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32
rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov,
&err_buftype);
if (rc == -EACCES && retry_without_read_attributes) {
free_rsp_buf(err_buftype, err_iov.iov_base);
memset(&err_iov, 0, sizeof(err_iov));
err_buftype = CIFS_NO_BUFFER;
oparms->desired_access &= ~FILE_READ_ATTRIBUTES;
rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov,
&err_buftype);

View File

@ -1205,6 +1205,7 @@ again:
memset(resp_buftype, 0, sizeof(resp_buftype));
memset(rsp_iov, 0, sizeof(rsp_iov));
memset(open_iov, 0, sizeof(open_iov));
rqst[0].rq_iov = open_iov;
rqst[0].rq_nvec = ARRAY_SIZE(open_iov);
@ -1229,14 +1230,15 @@ again:
creq = rqst[0].rq_iov[0].iov_base;
creq->ShareAccess = FILE_SHARE_DELETE_LE;
memset(&close_iov, 0, sizeof(close_iov));
rqst[1].rq_iov = &close_iov;
rqst[1].rq_nvec = 1;
rc = SMB2_close_init(tcon, server, &rqst[1],
COMPOUND_FID, COMPOUND_FID, false);
smb2_set_related(&rqst[1]);
if (rc)
goto err_free;
smb2_set_related(&rqst[1]);
if (retries) {
for (int i = 0; i < ARRAY_SIZE(rqst); i++)

View File

@ -1145,6 +1145,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
replay_again:
/* reinitialize for possible replay */
used_len = 0;
flags = CIFS_CP_CREATE_CLOSE_OP;
oplock = SMB2_OPLOCK_LEVEL_NONE;
server = cifs_pick_channel(ses);
@ -1541,6 +1542,7 @@ smb2_ioctl_query_info(const unsigned int xid,
replay_again:
/* reinitialize for possible replay */
buffer = NULL;
flags = CIFS_CP_CREATE_CLOSE_OP;
oplock = SMB2_OPLOCK_LEVEL_NONE;
server = cifs_pick_channel(ses);

View File

@ -2840,6 +2840,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
replay_again:
/* reinitialize for possible replay */
pc_buf = NULL;
flags = 0;
n_iov = 2;
server = cifs_pick_channel(ses);

View File

@ -4020,6 +4020,18 @@ skb_header_pointer(const struct sk_buff *skb, int offset, int len, void *buffer)
skb_headlen(skb), buffer);
}
/* Variant of skb_header_pointer() where @offset is user-controlled
* and potentially negative.
*/
static inline void * __must_check
skb_header_pointer_careful(const struct sk_buff *skb, int offset,
int len, void *buffer)
{
if (unlikely(offset < 0 && -offset > skb_headroom(skb)))
return NULL;
return skb_header_pointer(skb, offset, len, buffer);
}
/**
* skb_needs_linearize - check if we need to linearize a given skb
* depending on the given device features.

View File

@ -716,7 +716,7 @@ static int damon_sysfs_context_add_dirs(struct damon_sysfs_context *context)
err = damon_sysfs_context_set_targets(context);
if (err)
goto put_attrs_out;
goto rmdir_put_attrs_out;
err = damon_sysfs_context_set_schemes(context);
if (err)
@ -726,7 +726,8 @@ static int damon_sysfs_context_add_dirs(struct damon_sysfs_context *context)
put_targets_attrs_out:
kobject_put(&context->targets->kobj);
context->targets = NULL;
put_attrs_out:
rmdir_put_attrs_out:
damon_sysfs_attrs_rm_dirs(context->attrs);
kobject_put(&context->attrs->kobj);
context->attrs = NULL;
return err;

View File

@ -124,6 +124,7 @@ static unsigned char bus_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
/* Device structures */
static struct net_device *dev_lec[MAX_LEC_ITF];
static DEFINE_MUTEX(lec_mutex);
#if IS_ENABLED(CONFIG_BRIDGE)
static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
@ -686,6 +687,7 @@ static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
int bytes_left;
struct atmlec_ioc ioc_data;
lockdep_assert_held(&lec_mutex);
/* Lecd must be up in this case */
bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc));
if (bytes_left != 0)
@ -711,6 +713,7 @@ static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
static int lec_mcast_attach(struct atm_vcc *vcc, int arg)
{
lockdep_assert_held(&lec_mutex);
if (arg < 0 || arg >= MAX_LEC_ITF)
return -EINVAL;
arg = array_index_nospec(arg, MAX_LEC_ITF);
@ -726,6 +729,7 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
int i;
struct lec_priv *priv;
lockdep_assert_held(&lec_mutex);
if (arg < 0)
arg = 0;
if (arg >= MAX_LEC_ITF)
@ -743,6 +747,7 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i);
if (register_netdev(dev_lec[i])) {
free_netdev(dev_lec[i]);
dev_lec[i] = NULL;
return -EINVAL;
}
@ -905,7 +910,6 @@ static void *lec_itf_walk(struct lec_state *state, loff_t *l)
v = (dev && netdev_priv(dev)) ?
lec_priv_walk(state, l, netdev_priv(dev)) : NULL;
if (!v && dev) {
dev_put(dev);
/* Partial state reset for the next time we get called */
dev = NULL;
}
@ -929,6 +933,7 @@ static void *lec_seq_start(struct seq_file *seq, loff_t *pos)
{
struct lec_state *state = seq->private;
mutex_lock(&lec_mutex);
state->itf = 0;
state->dev = NULL;
state->locked = NULL;
@ -946,8 +951,9 @@ static void lec_seq_stop(struct seq_file *seq, void *v)
if (state->dev) {
spin_unlock_irqrestore(&state->locked->lec_arp_lock,
state->flags);
dev_put(state->dev);
state->dev = NULL;
}
mutex_unlock(&lec_mutex);
}
static void *lec_seq_next(struct seq_file *seq, void *v, loff_t *pos)
@ -1004,6 +1010,7 @@ static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return -ENOIOCTLCMD;
}
mutex_lock(&lec_mutex);
switch (cmd) {
case ATMLEC_CTRL:
err = lecd_attach(vcc, (int)arg);
@ -1018,6 +1025,7 @@ static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
break;
}
mutex_unlock(&lec_mutex);
return err;
}

View File

@ -161,10 +161,8 @@ next_knode:
int toff = off + key->off + (off2 & key->offmask);
__be32 *data, hdata;
if (skb_headroom(skb) + toff > INT_MAX)
goto out;
data = skb_header_pointer(skb, toff, 4, &hdata);
data = skb_header_pointer_careful(skb, toff, 4,
&hdata);
if (!data)
goto out;
if ((*data ^ key->val) & key->mask) {
@ -214,8 +212,9 @@ check_terminal:
if (ht->divisor) {
__be32 *data, hdata;
data = skb_header_pointer(skb, off + n->sel.hoff, 4,
&hdata);
data = skb_header_pointer_careful(skb,
off + n->sel.hoff,
4, &hdata);
if (!data)
goto out;
sel = ht->divisor & u32_hash_fold(*data, &n->sel,
@ -229,7 +228,7 @@ check_terminal:
if (n->sel.flags & TC_U32_VAROFFSET) {
__be16 *data, hdata;
data = skb_header_pointer(skb,
data = skb_header_pointer_careful(skb,
off + n->sel.offoff,
2, &hdata);
if (!data)

View File

@ -17,7 +17,7 @@ class CommitTags:
r'(\d{4,8})\s*$',
r'https?://bugzilla\.redhat\.com/(?:show_bug\.cgi\?id=)?(\d{4,8})',
],
'JIRA': [r'https://issues\.redhat\.com/(?:browse|projects/RHEL/issues)/(RHEL-\d{1,8})'],
'JIRA': [r'https://(?:issues\.redhat\.com|redhat\.atlassian\.net)/(?:browse|projects/RHEL/issues)/(RHEL-\d{1,8})'],
'CVE': [r'(CVE-\d{4}-\d{4,7})'],
'MR': [r'(.*)'],
'Y-Commit': [r'([0-9a-fA-F]+)'],

View File

@ -1,3 +1,33 @@
* Sat Mar 21 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-611.45.1.el9_7]
- net/sched: cls_u32: use skb_header_pointer_careful() (Paolo Abeni) [RHEL-150403] {CVE-2026-23204}
- net: add skb_header_pointer_careful() helper (Paolo Abeni) [RHEL-150403]
- iommu: Skip PASID validation for devices without PASID capability (Eder Zulian) [RHEL-95264]
Resolves: RHEL-150403, RHEL-95264
* Thu Mar 19 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-611.44.1.el9_7]
- nfsd: add list_head nf_gc to struct nfsd_file (Roberto Bergantinos Corpas) [RHEL-152551]
- redhat: genlog: add new JIRA cloud server hostname (Jan Stancek)
- smb: client: fix oops due to uninitialised var in smb2_unlink() (Paulo Alcantara) [RHEL-154395]
- cifs: some missing initializations on replay (Paulo Alcantara) [RHEL-154395]
- smb: client: fix potential UAF and double free in smb2_open_file() (Paulo Alcantara) [RHEL-154395]
- smb/client: fix memory leak in smb2_open_file() (Paulo Alcantara) [RHEL-154395]
- smb: client: split cached_fid bitfields to avoid shared-byte RMW races (Paulo Alcantara) [RHEL-154395]
- bonding: fix use-after-free due to enslave fail after slave array update (CKI Backport Bot) [RHEL-152383] {CVE-2026-23171}
- mm/damon/sysfs: cleanup attrs subdirs on context dir setup failure (CKI Backport Bot) [RHEL-150477] {CVE-2026-23144}
- macvlan: observe an RCU grace period in macvlan_common_newlink() error path (Hangbin Liu) [RHEL-150226]
- macvlan: fix error recovery in macvlan_common_newlink() (CKI Backport Bot) [RHEL-150226] {CVE-2026-23209}
- dpll: zl3073x: Fix output pin phase adjustment sign (CKI Backport Bot) [RHEL-149764]
- scsi: s390: zfcp: Ensure synchronous unit_add (CKI Backport Bot) [RHEL-143736]
Resolves: RHEL-143736, RHEL-149764, RHEL-150226, RHEL-150477, RHEL-152383, RHEL-152551, RHEL-154395
* Tue Mar 17 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-611.43.1.el9_7]
- scsi: target: iscsi: Fix use-after-free in iscsit_dec_session_usage_count() (CKI Backport Bot) [RHEL-150422] {CVE-2026-23193}
- ALSA: aloop: Fix racy access at PCM trigger (CKI Backport Bot) [RHEL-150130] {CVE-2026-23191}
- net: atm: fix /proc/net/atm/lec handling (Hangbin Liu) [RHEL-146421] {CVE-2025-38180}
- net: atm: add lec_mutex (Hangbin Liu) [RHEL-146421] {CVE-2025-38323}
- drm/sched: Fix potential double free in drm_sched_job_add_resv_dependencies (Mika Penttilä) [RHEL-125460] {CVE-2025-40096}
Resolves: RHEL-125460, RHEL-146421, RHEL-150130, RHEL-150422
* Thu Mar 12 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-611.42.1.el9_7]
- scsi: qla2xxx: Allow recovery for tape devices (Ewan D. Milne) [RHEL-153437]
- xfs: set max_agbno to allow sparse alloc of last full inode chunk (Brian Foster) [RHEL-142600]

View File

@ -335,37 +335,43 @@ static bool is_access_interleaved(snd_pcm_access_t access)
static int loopback_check_format(struct loopback_cable *cable, int stream)
{
struct loopback_pcm *dpcm_play, *dpcm_capt;
struct snd_pcm_runtime *runtime, *cruntime;
struct loopback_setup *setup;
struct snd_card *card;
bool stop_capture = false;
int check;
if (cable->valid != CABLE_VALID_BOTH) {
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
goto __notify;
return 0;
}
runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
substream->runtime;
cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
substream->runtime;
check = runtime->format != cruntime->format ||
runtime->rate != cruntime->rate ||
runtime->channels != cruntime->channels ||
is_access_interleaved(runtime->access) !=
is_access_interleaved(cruntime->access);
if (!check)
return 0;
if (stream == SNDRV_PCM_STREAM_CAPTURE) {
return -EIO;
} else {
snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
substream, SNDRV_PCM_STATE_DRAINING);
__notify:
runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
substream->runtime;
setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]);
card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card;
scoped_guard(spinlock_irqsave, &cable->lock) {
dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK];
dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE];
if (cable->valid != CABLE_VALID_BOTH) {
if (stream == SNDRV_PCM_STREAM_CAPTURE || !dpcm_play)
return 0;
} else {
if (!dpcm_play || !dpcm_capt)
return -EIO;
runtime = dpcm_play->substream->runtime;
cruntime = dpcm_capt->substream->runtime;
if (!runtime || !cruntime)
return -EIO;
check = runtime->format != cruntime->format ||
runtime->rate != cruntime->rate ||
runtime->channels != cruntime->channels ||
is_access_interleaved(runtime->access) !=
is_access_interleaved(cruntime->access);
if (!check)
return 0;
if (stream == SNDRV_PCM_STREAM_CAPTURE)
return -EIO;
else if (cruntime->state == SNDRV_PCM_STATE_RUNNING)
stop_capture = true;
}
setup = get_setup(dpcm_play);
card = dpcm_play->loopback->card;
runtime = dpcm_play->substream->runtime;
if (setup->format != runtime->format) {
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
&setup->format_id);
@ -388,6 +394,10 @@ static int loopback_check_format(struct loopback_cable *cable, int stream)
setup->access = runtime->access;
}
}
if (stop_capture)
snd_pcm_stop(dpcm_capt->substream, SNDRV_PCM_STATE_DRAINING);
return 0;
}