Merge 6.1.128 into android14-6.1-lts

Changes in 6.1.128
	ASoC: wm8994: Add depends on MFD core
	ASoC: samsung: Add missing selects for MFD_WM8994
	seccomp: Stub for !CONFIG_SECCOMP
	scsi: iscsi: Fix redundant response for ISCSI_UEVENT_GET_HOST_STATS request
	drm/amd/display: Use HW lock mgr for PSR1
	irqchip/sunxi-nmi: Add missing SKIP_WAKE flag
	ASoC: samsung: midas_wm1811: Map missing jack kcontrols
	ASoC: samsung: Add missing depends on I2C
	regmap: detach regmap from dev on regmap_exit
	ipv6: Fix soft lockups in fib6_select_path under high next hop churn
	softirq: Allow raising SCHED_SOFTIRQ from SMP-call-function on RT kernel
	xfs: bump max fsgeom struct version
	xfs: hoist freeing of rt data fork extent mappings
	xfs: prevent rt growfs when quota is enabled
	xfs: rt stubs should return negative errnos when rt disabled
	xfs: fix units conversion error in xfs_bmap_del_extent_delay
	xfs: make sure maxlen is still congruent with prod when rounding down
	xfs: introduce protection for drop nlink
	xfs: handle nimaps=0 from xfs_bmapi_write in xfs_alloc_file_space
	xfs: allow read IO and FICLONE to run concurrently
	xfs: factor out xfs_defer_pending_abort
	xfs: abort intent items when recovery intents fail
	xfs: only remap the written blocks in xfs_reflink_end_cow_extent
	xfs: up(ic_sema) if flushing data device fails
	xfs: fix internal error from AGFL exhaustion
	xfs: inode recovery does not validate the recovered inode
	xfs: clean up dqblk extraction
	xfs: dquot recovery does not validate the recovered dquot
	xfs: clean up FS_XFLAG_REALTIME handling in xfs_ioctl_setattr_xflags
	xfs: respect the stable writes flag on the RT device
	gfs2: Truncate address space when flipping GFS2_DIF_JDATA flag
	io_uring: fix waiters missing wake ups
	net: sched: fix ets qdisc OOB Indexing
	block: fix integer overflow in BLKSECDISCARD
	Revert "HID: multitouch: Add support for lenovo Y9000P Touchpad"
	vfio/platform: check the bounds of read/write syscalls
	ext4: fix access to uninitialised lock in fc replay path
	ipv4: ip_tunnel: Fix suspicious RCU usage warning in ip_tunnel_find()
	scsi: storvsc: Ratelimit warning logs to prevent VM denial of service
	wifi: iwlwifi: add a few rate index validity checks
	smb: client: fix UAF in async decryption
	USB: serial: quatech2: fix null-ptr-deref in qt2_process_read_urb()
	Revert "usb: gadget: u_serial: Disable ep before setting port to null to fix the crash caused by port being null"
	ALSA: usb-audio: Add delay quirk for USB Audio Device
	Input: atkbd - map F23 key to support default copilot shortcut
	Input: xpad - add unofficial Xbox 360 wireless receiver clone
	Input: xpad - add support for wooting two he (arm)
	smb: client: fix NULL ptr deref in crypto_aead_setkey()
	ASoC: samsung: midas_wm1811: Fix 'Headphone Switch' control creation
	drm/v3d: Assign job pointer to NULL before signaling the fence
	Linux 6.1.128

Change-Id: Ia1ddc5824b498862a5eb730dd99bd3a76dd16015
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman
2025-02-06 11:46:32 +00:00
committed by Treehugger Robot
55 changed files with 774 additions and 194 deletions

View File

@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
VERSION = 6
PATCHLEVEL = 1
SUBLEVEL = 127
SUBLEVEL = 128
EXTRAVERSION =
NAME = Curry Ramen

View File

@@ -115,7 +115,7 @@ static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
return -EINVAL;
filemap_invalidate_lock(inode->i_mapping);
err = truncate_bdev_range(bdev, mode, start, start + len - 1);
err = truncate_bdev_range(bdev, mode, start, end - 1);
if (err)
goto fail;
err = blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_KERNEL);
@@ -127,7 +127,7 @@ fail:
static int blk_ioctl_secure_erase(struct block_device *bdev, fmode_t mode,
void __user *argp)
{
uint64_t start, len;
uint64_t start, len, end;
uint64_t range[2];
int err;
@@ -142,11 +142,12 @@ static int blk_ioctl_secure_erase(struct block_device *bdev, fmode_t mode,
len = range[1];
if ((start & 511) || (len & 511))
return -EINVAL;
if (start + len > bdev_nr_bytes(bdev))
if (check_add_overflow(start, len, &end) ||
end > bdev_nr_bytes(bdev))
return -EINVAL;
filemap_invalidate_lock(bdev->bd_inode->i_mapping);
err = truncate_bdev_range(bdev, mode, start, start + len - 1);
err = truncate_bdev_range(bdev, mode, start, end - 1);
if (!err)
err = blkdev_issue_secure_erase(bdev, start >> 9, len >> 9,
GFP_KERNEL);

View File

@@ -652,6 +652,17 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
}
EXPORT_SYMBOL_GPL(regmap_attach_dev);
static int dev_get_regmap_match(struct device *dev, void *res, void *data);
static int regmap_detach_dev(struct device *dev, struct regmap *map)
{
if (!dev)
return 0;
return devres_release(dev, dev_get_regmap_release,
dev_get_regmap_match, (void *)map->name);
}
static enum regmap_endian regmap_get_reg_endian(const struct regmap_bus *bus,
const struct regmap_config *config)
{
@@ -1536,6 +1547,7 @@ void regmap_exit(struct regmap *map)
{
struct regmap_async *async;
regmap_detach_dev(map->dev, map);
regcache_exit(map);
regmap_debugfs_exit(map);
regmap_range_exit(map);

View File

@@ -65,7 +65,8 @@ void dmub_hw_lock_mgr_inbox0_cmd(struct dc_dmub_srv *dmub_srv,
bool should_use_dmub_lock(struct dc_link *link)
{
if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1)
if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1 ||
link->psr_settings.psr_version == DC_PSR_VERSION_1)
return true;
return false;
}

View File

@@ -102,8 +102,10 @@ v3d_irq(int irq, void *arg)
to_v3d_fence(v3d->bin_job->base.irq_fence);
trace_v3d_bcl_irq(&v3d->drm, fence->seqno);
dma_fence_signal(&fence->base);
v3d->bin_job = NULL;
dma_fence_signal(&fence->base);
status = IRQ_HANDLED;
}
@@ -112,8 +114,10 @@ v3d_irq(int irq, void *arg)
to_v3d_fence(v3d->render_job->base.irq_fence);
trace_v3d_rcl_irq(&v3d->drm, fence->seqno);
dma_fence_signal(&fence->base);
v3d->render_job = NULL;
dma_fence_signal(&fence->base);
status = IRQ_HANDLED;
}
@@ -122,8 +126,10 @@ v3d_irq(int irq, void *arg)
to_v3d_fence(v3d->csd_job->base.irq_fence);
trace_v3d_csd_irq(&v3d->drm, fence->seqno);
dma_fence_signal(&fence->base);
v3d->csd_job = NULL;
dma_fence_signal(&fence->base);
status = IRQ_HANDLED;
}
@@ -159,8 +165,10 @@ v3d_hub_irq(int irq, void *arg)
to_v3d_fence(v3d->tfu_job->base.irq_fence);
trace_v3d_tfu_irq(&v3d->drm, fence->seqno);
dma_fence_signal(&fence->base);
v3d->tfu_job = NULL;
dma_fence_signal(&fence->base);
status = IRQ_HANDLED;
}

View File

@@ -507,7 +507,6 @@
#define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_E100 0xe100
#define I2C_VENDOR_ID_GOODIX 0x27c6
#define I2C_DEVICE_ID_GOODIX_01E0 0x01e0
#define I2C_DEVICE_ID_GOODIX_01E8 0x01e8
#define I2C_DEVICE_ID_GOODIX_01E9 0x01e9
#define I2C_DEVICE_ID_GOODIX_01F0 0x01f0

View File

@@ -1447,8 +1447,7 @@ static __u8 *mt_report_fixup(struct hid_device *hdev, __u8 *rdesc,
{
if (hdev->vendor == I2C_VENDOR_ID_GOODIX &&
(hdev->product == I2C_DEVICE_ID_GOODIX_01E8 ||
hdev->product == I2C_DEVICE_ID_GOODIX_01E9 ||
hdev->product == I2C_DEVICE_ID_GOODIX_01E0)) {
hdev->product == I2C_DEVICE_ID_GOODIX_01E9)) {
if (rdesc[607] == 0x15) {
rdesc[607] = 0x25;
dev_info(
@@ -2073,10 +2072,7 @@ static const struct hid_device_id mt_devices[] = {
I2C_DEVICE_ID_GOODIX_01E8) },
{ .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU,
HID_DEVICE(BUS_I2C, HID_GROUP_ANY, I2C_VENDOR_ID_GOODIX,
I2C_DEVICE_ID_GOODIX_01E9) },
{ .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU,
HID_DEVICE(BUS_I2C, HID_GROUP_ANY, I2C_VENDOR_ID_GOODIX,
I2C_DEVICE_ID_GOODIX_01E0) },
I2C_DEVICE_ID_GOODIX_01E8) },
/* GoodTouch panels */
{ .driver_data = MT_CLS_NSMU,

View File

@@ -145,6 +145,7 @@ static const struct xpad_device {
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
{ 0x045e, 0x028f, "Microsoft X-Box 360 pad v2", 0, XTYPE_XBOX360 },
{ 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x045e, 0x02a9, "Xbox 360 Wireless Receiver (Unofficial)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
{ 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE },
{ 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", MAP_PADDLES, XTYPE_XBOXONE },
@@ -366,6 +367,7 @@ static const struct xpad_device {
{ 0x31e3, 0x1200, "Wooting Two", 0, XTYPE_XBOX360 },
{ 0x31e3, 0x1210, "Wooting Lekker", 0, XTYPE_XBOX360 },
{ 0x31e3, 0x1220, "Wooting Two HE", 0, XTYPE_XBOX360 },
{ 0x31e3, 0x1230, "Wooting Two HE (ARM)", 0, XTYPE_XBOX360 },
{ 0x31e3, 0x1300, "Wooting 60HE (AVR)", 0, XTYPE_XBOX360 },
{ 0x31e3, 0x1310, "Wooting 60HE (ARM)", 0, XTYPE_XBOX360 },
{ 0x3285, 0x0607, "Nacon GC-100", 0, XTYPE_XBOX360 },

View File

@@ -89,7 +89,7 @@ static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = {
0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
0, 89, 40, 0, 26, 13, 0,193, 58, 54, 28, 27, 0, 43, 0, 85,
0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,

View File

@@ -187,7 +187,8 @@ static int __init sunxi_sc_nmi_irq_init(struct device_node *node,
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
gc->chip_types[0].chip.irq_eoi = irq_gc_ack_set_bit;
gc->chip_types[0].chip.irq_set_type = sunxi_sc_nmi_set_type;
gc->chip_types[0].chip.flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED;
gc->chip_types[0].chip.flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED |
IRQCHIP_SKIP_SET_WAKE;
gc->chip_types[0].regs.ack = reg_offs->pend;
gc->chip_types[0].regs.mask = reg_offs->enable;
gc->chip_types[0].regs.type = reg_offs->ctrl;

View File

@@ -2,7 +2,7 @@
/******************************************************************************
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright (C) 2019 - 2020, 2022 Intel Corporation
* Copyright (C) 2019 - 2020, 2022 - 2023 Intel Corporation
*****************************************************************************/
#include <linux/kernel.h>
#include <linux/skbuff.h>
@@ -125,7 +125,7 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
return idx;
}
return -1;
return IWL_RATE_INVALID;
}
static void rs_rate_scale_perform(struct iwl_priv *priv,
@@ -3146,7 +3146,10 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
index = iwl_hwrate_to_plcp_idx(
le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags));
if (is_legacy(tbl->lq_type)) {
if (index == IWL_RATE_INVALID) {
desc += sprintf(buff + desc, " rate[%d] 0x%X invalid rate\n",
i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags));
} else if (is_legacy(tbl->lq_type)) {
desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps\n",
i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags),
iwl_rate_mcs[index].mbps);

View File

@@ -1072,10 +1072,13 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
rate->bw = RATE_MCS_CHAN_WIDTH_20;
WARN_ON_ONCE(rate->index < IWL_RATE_MCS_0_INDEX ||
rate->index > IWL_RATE_MCS_9_INDEX);
if (WARN_ON_ONCE(rate->index < IWL_RATE_MCS_0_INDEX))
rate->index = rs_ht_to_legacy[IWL_RATE_MCS_0_INDEX];
else if (WARN_ON_ONCE(rate->index > IWL_RATE_MCS_9_INDEX))
rate->index = rs_ht_to_legacy[IWL_RATE_MCS_9_INDEX];
else
rate->index = rs_ht_to_legacy[rate->index];
rate->index = rs_ht_to_legacy[rate->index];
rate->ldpc = false;
} else {
/* Downgrade to SISO with same MCS if in MIMO */

View File

@@ -4102,7 +4102,7 @@ iscsi_if_rx(struct sk_buff *skb)
}
do {
/*
* special case for GET_STATS:
* special case for GET_STATS, GET_CHAP and GET_HOST_STATS:
* on success - sending reply and stats from
* inside of if_recv_msg(),
* on error - fall through.
@@ -4111,6 +4111,8 @@ iscsi_if_rx(struct sk_buff *skb)
break;
if (ev->type == ISCSI_UEVENT_GET_CHAP && !err)
break;
if (ev->type == ISCSI_UEVENT_GET_HOST_STATS && !err)
break;
err = iscsi_if_send_reply(portid, nlh->nlmsg_type,
ev, sizeof(*ev));
if (err == -EAGAIN && --retries < 0) {

View File

@@ -171,6 +171,12 @@ do { \
dev_warn(&(dev)->device, fmt, ##__VA_ARGS__); \
} while (0)
#define storvsc_log_ratelimited(dev, level, fmt, ...) \
do { \
if (do_logging(level)) \
dev_warn_ratelimited(&(dev)->device, fmt, ##__VA_ARGS__); \
} while (0)
struct vmscsi_request {
u16 length;
u8 srb_status;
@@ -1168,7 +1174,7 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device,
int loglevel = (stor_pkt->vm_srb.cdb[0] == TEST_UNIT_READY) ?
STORVSC_LOGGING_WARN : STORVSC_LOGGING_ERROR;
storvsc_log(device, loglevel,
storvsc_log_ratelimited(device, loglevel,
"tag#%d cmd 0x%x status: scsi 0x%x srb 0x%x hv 0x%x\n",
scsi_cmd_to_rq(request->cmd)->tag,
stor_pkt->vm_srb.cdb[0],

View File

@@ -1403,10 +1403,6 @@ void gserial_disconnect(struct gserial *gser)
/* REVISIT as above: how best to track this? */
port->port_line_coding = gser->port_line_coding;
/* disable endpoints, aborting down any active I/O */
usb_ep_disable(gser->out);
usb_ep_disable(gser->in);
port->port_usb = NULL;
gser->ioport = NULL;
if (port->port.count > 0) {
@@ -1418,6 +1414,10 @@ void gserial_disconnect(struct gserial *gser)
spin_unlock(&port->port_lock);
spin_unlock_irqrestore(&serial_port_lock, flags);
/* disable endpoints, aborting down any active I/O */
usb_ep_disable(gser->out);
usb_ep_disable(gser->in);
/* finally, free any unused/unusable I/O buffers */
spin_lock_irqsave(&port->port_lock, flags);
if (port->port.count == 0)

View File

@@ -511,7 +511,7 @@ static void qt2_process_read_urb(struct urb *urb)
newport = *(ch + 3);
if (newport > serial->num_ports) {
if (newport >= serial->num_ports) {
dev_err(&port->dev,
"%s - port change to invalid port: %i\n",
__func__, newport);

View File

@@ -391,6 +391,11 @@ static ssize_t vfio_platform_read_mmio(struct vfio_platform_region *reg,
{
unsigned int done = 0;
if (off >= reg->size)
return -EINVAL;
count = min_t(size_t, count, reg->size - off);
if (!reg->ioaddr) {
reg->ioaddr =
ioremap(reg->addr, reg->size);
@@ -470,6 +475,11 @@ static ssize_t vfio_platform_write_mmio(struct vfio_platform_region *reg,
{
unsigned int done = 0;
if (off >= reg->size)
return -EINVAL;
count = min_t(size_t, count, reg->size - off);
if (!reg->ioaddr) {
reg->ioaddr =
ioremap(reg->addr, reg->size);

View File

@@ -5256,6 +5256,8 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
mutex_init(&sbi->s_orphan_lock);
spin_lock_init(&sbi->s_bdev_wb_lock);
ext4_fast_commit_init(sb);
sb->s_root = NULL;
@@ -5501,7 +5503,6 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
* Save the original bdev mapping's wb_err value which could be
* used to detect the metadata async write error.
*/
spin_lock_init(&sbi->s_bdev_wb_lock);
errseq_check_and_advance(&sb->s_bdev->bd_inode->i_mapping->wb_err,
&sbi->s_bdev_wb_err);
sb->s_bdev->bd_super = sb;

View File

@@ -250,6 +250,7 @@ static int do_gfs2_set_flags(struct inode *inode, u32 reqflags, u32 mask)
error = filemap_fdatawait(inode->i_mapping);
if (error)
goto out;
truncate_inode_pages(inode->i_mapping, 0);
if (new_flags & GFS2_DIF_JDATA)
gfs2_ordered_del_inode(ip);
}

View File

@@ -4488,7 +4488,7 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key)
*/
static int
crypt_message(struct TCP_Server_Info *server, int num_rqst,
struct smb_rqst *rqst, int enc)
struct smb_rqst *rqst, int enc, struct crypto_aead *tfm)
{
struct smb2_transform_hdr *tr_hdr =
(struct smb2_transform_hdr *)rqst[0].rq_iov[0].iov_base;
@@ -4499,8 +4499,6 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
u8 key[SMB3_ENC_DEC_KEY_SIZE];
struct aead_request *req;
u8 *iv;
DECLARE_CRYPTO_WAIT(wait);
struct crypto_aead *tfm;
unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
void *creq;
@@ -4511,14 +4509,6 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
return rc;
}
rc = smb3_crypto_aead_allocate(server);
if (rc) {
cifs_server_dbg(VFS, "%s: crypto alloc failed\n", __func__);
return rc;
}
tfm = enc ? server->secmech.enc : server->secmech.dec;
if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) ||
(server->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
rc = crypto_aead_setkey(tfm, key, SMB3_GCM256_CRYPTKEY_SIZE);
@@ -4557,11 +4547,7 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
aead_request_set_crypt(req, sg, sg, crypt_len, iv);
aead_request_set_ad(req, assoc_data_len);
aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
crypto_req_done, &wait);
rc = crypto_wait_req(enc ? crypto_aead_encrypt(req)
: crypto_aead_decrypt(req), &wait);
rc = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req);
if (!rc && enc)
memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE);
@@ -4650,7 +4636,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
/* fill the 1st iov with a transform header */
fill_transform_hdr(tr_hdr, orig_len, old_rq, server->cipher_type);
rc = crypt_message(server, num_rqst, new_rq, 1);
rc = crypt_message(server, num_rqst, new_rq, 1, server->secmech.enc);
cifs_dbg(FYI, "Encrypt message returned %d\n", rc);
if (rc)
goto err_free;
@@ -4676,8 +4662,9 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
unsigned int npages, unsigned int page_data_size,
bool is_offloaded)
{
struct kvec iov[2];
struct crypto_aead *tfm;
struct smb_rqst rqst = {NULL};
struct kvec iov[2];
int rc;
iov[0].iov_base = buf;
@@ -4692,9 +4679,31 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
rqst.rq_pagesz = PAGE_SIZE;
rqst.rq_tailsz = (page_data_size % PAGE_SIZE) ? : PAGE_SIZE;
rc = crypt_message(server, 1, &rqst, 0);
if (is_offloaded) {
if ((server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) ||
(server->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
tfm = crypto_alloc_aead("gcm(aes)", 0, 0);
else
tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
if (IS_ERR(tfm)) {
rc = PTR_ERR(tfm);
cifs_server_dbg(VFS, "%s: Failed alloc decrypt TFM, rc=%d\n", __func__, rc);
return rc;
}
} else {
if (unlikely(!server->secmech.dec))
return -EIO;
tfm = server->secmech.dec;
}
rc = crypt_message(server, 1, &rqst, 0, tfm);
cifs_dbg(FYI, "Decrypt message returned %d\n", rc);
if (is_offloaded)
crypto_free_aead(tfm);
if (rc)
return rc;

View File

@@ -1070,7 +1070,9 @@ SMB2_negotiate(const unsigned int xid,
* SMB3.0 supports only 1 cipher and doesn't have a encryption neg context
* Set the cipher type manually.
*/
if (server->dialect == SMB30_PROT_ID && (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION))
if ((server->dialect == SMB30_PROT_ID ||
server->dialect == SMB302_PROT_ID) &&
(server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION))
server->cipher_type = SMB2_ENCRYPTION_AES128_CCM;
security_blob = smb2_get_data_area_len(&blob_offset, &blob_length,
@@ -1105,6 +1107,12 @@ SMB2_negotiate(const unsigned int xid,
else
cifs_server_dbg(VFS, "Missing expected negotiate contexts\n");
}
if (server->cipher_type && !rc) {
rc = smb3_crypto_aead_allocate(server);
if (rc)
cifs_server_dbg(VFS, "%s: crypto alloc failed, rc=%d\n", __func__, rc);
}
neg_exit:
free_rsp_buf(resp_buftype, rsp);
return rc;

View File

@@ -2273,16 +2273,37 @@ xfs_alloc_min_freelist(
ASSERT(mp->m_alloc_maxlevels > 0);
/*
* For a btree shorter than the maximum height, the worst case is that
* every level gets split and a new level is added, then while inserting
* another entry to refill the AGFL, every level under the old root gets
* split again. This is:
*
* (full height split reservation) + (AGFL refill split height)
* = (current height + 1) + (current height - 1)
* = (new height) + (new height - 2)
* = 2 * new height - 2
*
* For a btree of maximum height, the worst case is that every level
* under the root gets split, then while inserting another entry to
* refill the AGFL, every level under the root gets split again. This is
* also:
*
* 2 * (current height - 1)
* = 2 * (new height - 1)
* = 2 * new height - 2
*/
/* space needed by-bno freespace btree */
min_free = min_t(unsigned int, levels[XFS_BTNUM_BNOi] + 1,
mp->m_alloc_maxlevels);
mp->m_alloc_maxlevels) * 2 - 2;
/* space needed by-size freespace btree */
min_free += min_t(unsigned int, levels[XFS_BTNUM_CNTi] + 1,
mp->m_alloc_maxlevels);
mp->m_alloc_maxlevels) * 2 - 2;
/* space needed reverse mapping used space btree */
if (xfs_has_rmapbt(mp))
min_free += min_t(unsigned int, levels[XFS_BTNUM_RMAPi] + 1,
mp->m_rmap_maxlevels);
mp->m_rmap_maxlevels) * 2 - 2;
return min_free;
}

View File

@@ -4805,7 +4805,7 @@ xfs_bmap_del_extent_delay(
ASSERT(got_endoff >= del_endoff);
if (isrt) {
uint64_t rtexts = XFS_FSB_TO_B(mp, del->br_blockcount);
uint64_t rtexts = del->br_blockcount;
do_div(rtexts, mp->m_sb.sb_rextsize);
xfs_mod_frextents(mp, rtexts);
@@ -5035,33 +5035,20 @@ xfs_bmap_del_extent_real(
flags = XFS_ILOG_CORE;
if (whichfork == XFS_DATA_FORK && XFS_IS_REALTIME_INODE(ip)) {
xfs_filblks_t len;
xfs_extlen_t mod;
len = div_u64_rem(del->br_blockcount, mp->m_sb.sb_rextsize,
&mod);
ASSERT(mod == 0);
if (!(bflags & XFS_BMAPI_REMAP)) {
xfs_fsblock_t bno;
bno = div_u64_rem(del->br_startblock,
mp->m_sb.sb_rextsize, &mod);
ASSERT(mod == 0);
error = xfs_rtfree_extent(tp, bno, (xfs_extlen_t)len);
error = xfs_rtfree_blocks(tp, del->br_startblock,
del->br_blockcount);
if (error)
goto done;
}
do_fx = 0;
nblks = len * mp->m_sb.sb_rextsize;
qfield = XFS_TRANS_DQ_RTBCOUNT;
} else {
do_fx = 1;
nblks = del->br_blockcount;
qfield = XFS_TRANS_DQ_BCOUNT;
}
nblks = del->br_blockcount;
del_endblock = del->br_startblock + del->br_blockcount;
if (cur) {

View File

@@ -245,26 +245,33 @@ xfs_defer_create_intents(
return ret;
}
STATIC void
xfs_defer_pending_abort(
struct xfs_mount *mp,
struct list_head *dop_list)
{
struct xfs_defer_pending *dfp;
const struct xfs_defer_op_type *ops;
/* Abort intent items that don't have a done item. */
list_for_each_entry(dfp, dop_list, dfp_list) {
ops = defer_op_types[dfp->dfp_type];
trace_xfs_defer_pending_abort(mp, dfp);
if (dfp->dfp_intent && !dfp->dfp_done) {
ops->abort_intent(dfp->dfp_intent);
dfp->dfp_intent = NULL;
}
}
}
/* Abort all the intents that were committed. */
STATIC void
xfs_defer_trans_abort(
struct xfs_trans *tp,
struct list_head *dop_pending)
{
struct xfs_defer_pending *dfp;
const struct xfs_defer_op_type *ops;
trace_xfs_defer_trans_abort(tp, _RET_IP_);
/* Abort intent items that don't have a done item. */
list_for_each_entry(dfp, dop_pending, dfp_list) {
ops = defer_op_types[dfp->dfp_type];
trace_xfs_defer_pending_abort(tp->t_mountp, dfp);
if (dfp->dfp_intent && !dfp->dfp_done) {
ops->abort_intent(dfp->dfp_intent);
dfp->dfp_intent = NULL;
}
}
xfs_defer_pending_abort(tp->t_mountp, dop_pending);
}
/*
@@ -754,12 +761,13 @@ xfs_defer_ops_capture(
/* Release all resources that we used to capture deferred ops. */
void
xfs_defer_ops_capture_free(
xfs_defer_ops_capture_abort(
struct xfs_mount *mp,
struct xfs_defer_capture *dfc)
{
unsigned short i;
xfs_defer_pending_abort(mp, &dfc->dfc_dfops);
xfs_defer_cancel_list(mp, &dfc->dfc_dfops);
for (i = 0; i < dfc->dfc_held.dr_bufs; i++)
@@ -800,7 +808,7 @@ xfs_defer_ops_capture_and_commit(
/* Commit the transaction and add the capture structure to the list. */
error = xfs_trans_commit(tp);
if (error) {
xfs_defer_ops_capture_free(mp, dfc);
xfs_defer_ops_capture_abort(mp, dfc);
return error;
}

View File

@@ -121,7 +121,7 @@ int xfs_defer_ops_capture_and_commit(struct xfs_trans *tp,
struct list_head *capture_list);
void xfs_defer_ops_continue(struct xfs_defer_capture *d, struct xfs_trans *tp,
struct xfs_defer_resources *dres);
void xfs_defer_ops_capture_free(struct xfs_mount *mp,
void xfs_defer_ops_capture_abort(struct xfs_mount *mp,
struct xfs_defer_capture *d);
void xfs_defer_resources_rele(struct xfs_defer_resources *dres);

View File

@@ -507,6 +507,9 @@ xfs_dinode_verify(
if (mode && nextents + naextents > nblocks)
return __this_address;
if (nextents + naextents == 0 && nblocks != 0)
return __this_address;
if (S_ISDIR(mode) && nextents > mp->m_dir_geo->max_extents)
return __this_address;

View File

@@ -1005,6 +1005,39 @@ xfs_rtfree_extent(
return 0;
}
/*
* Free some blocks in the realtime subvolume. rtbno and rtlen are in units of
* rt blocks, not rt extents; must be aligned to the rt extent size; and rtlen
* cannot exceed XFS_MAX_BMBT_EXTLEN.
*/
int
xfs_rtfree_blocks(
struct xfs_trans *tp,
xfs_fsblock_t rtbno,
xfs_filblks_t rtlen)
{
struct xfs_mount *mp = tp->t_mountp;
xfs_rtblock_t bno;
xfs_filblks_t len;
xfs_extlen_t mod;
ASSERT(rtlen <= XFS_MAX_BMBT_EXTLEN);
len = div_u64_rem(rtlen, mp->m_sb.sb_rextsize, &mod);
if (mod) {
ASSERT(mod == 0);
return -EIO;
}
bno = div_u64_rem(rtbno, mp->m_sb.sb_rextsize, &mod);
if (mod) {
ASSERT(mod == 0);
return -EIO;
}
return xfs_rtfree_extent(tp, bno, len);
}
/* Find all the free records within a given range. */
int
xfs_rtalloc_query_range(

View File

@@ -25,7 +25,7 @@ extern uint64_t xfs_sb_version_to_features(struct xfs_sb *sbp);
extern int xfs_update_secondary_sbs(struct xfs_mount *mp);
#define XFS_FS_GEOM_MAX_STRUCT_VER (4)
#define XFS_FS_GEOM_MAX_STRUCT_VER (5)
extern void xfs_fs_geometry(struct xfs_mount *mp, struct xfs_fsop_geom *geo,
int struct_version);
extern int xfs_sb_read_secondary(struct xfs_mount *mp,

View File

@@ -780,12 +780,10 @@ xfs_alloc_file_space(
{
xfs_mount_t *mp = ip->i_mount;
xfs_off_t count;
xfs_filblks_t allocated_fsb;
xfs_filblks_t allocatesize_fsb;
xfs_extlen_t extsz, temp;
xfs_fileoff_t startoffset_fsb;
xfs_fileoff_t endoffset_fsb;
int nimaps;
int rt;
xfs_trans_t *tp;
xfs_bmbt_irec_t imaps[1], *imapp;
@@ -808,7 +806,6 @@ xfs_alloc_file_space(
count = len;
imapp = &imaps[0];
nimaps = 1;
startoffset_fsb = XFS_B_TO_FSBT(mp, offset);
endoffset_fsb = XFS_B_TO_FSB(mp, offset + count);
allocatesize_fsb = endoffset_fsb - startoffset_fsb;
@@ -819,6 +816,7 @@ xfs_alloc_file_space(
while (allocatesize_fsb && !error) {
xfs_fileoff_t s, e;
unsigned int dblocks, rblocks, resblks;
int nimaps = 1;
/*
* Determine space reservations for data/realtime.
@@ -884,15 +882,19 @@ xfs_alloc_file_space(
if (error)
break;
allocated_fsb = imapp->br_blockcount;
if (nimaps == 0) {
error = -ENOSPC;
break;
/*
* If the allocator cannot find a single free extent large
* enough to cover the start block of the requested range,
* xfs_bmapi_write will return 0 but leave *nimaps set to 0.
*
* In that case we simply need to keep looping with the same
* startoffset_fsb so that one of the following allocations
* will eventually reach the requested range.
*/
if (nimaps) {
startoffset_fsb += imapp->br_blockcount;
allocatesize_fsb -= imapp->br_blockcount;
}
startoffset_fsb += allocated_fsb;
allocatesize_fsb -= allocated_fsb;
}
return error;

View File

@@ -562,7 +562,8 @@ xfs_dquot_from_disk(
struct xfs_dquot *dqp,
struct xfs_buf *bp)
{
struct xfs_disk_dquot *ddqp = bp->b_addr + dqp->q_bufoffset;
struct xfs_dqblk *dqb = xfs_buf_offset(bp, dqp->q_bufoffset);
struct xfs_disk_dquot *ddqp = &dqb->dd_diskdq;
/*
* Ensure that we got the type and ID we were looking for.
@@ -1250,7 +1251,7 @@ xfs_qm_dqflush(
}
/* Flush the incore dquot to the ondisk buffer. */
dqblk = bp->b_addr + dqp->q_bufoffset;
dqblk = xfs_buf_offset(bp, dqp->q_bufoffset);
xfs_dquot_to_disk(&dqblk->dd_diskdq, dqp);
/*

View File

@@ -19,6 +19,7 @@
#include "xfs_log.h"
#include "xfs_log_priv.h"
#include "xfs_log_recover.h"
#include "xfs_error.h"
STATIC void
xlog_recover_dquot_ra_pass2(
@@ -65,6 +66,7 @@ xlog_recover_dquot_commit_pass2(
{
struct xfs_mount *mp = log->l_mp;
struct xfs_buf *bp;
struct xfs_dqblk *dqb;
struct xfs_disk_dquot *ddq, *recddq;
struct xfs_dq_logformat *dq_f;
xfs_failaddr_t fa;
@@ -130,14 +132,14 @@ xlog_recover_dquot_commit_pass2(
return error;
ASSERT(bp);
ddq = xfs_buf_offset(bp, dq_f->qlf_boffset);
dqb = xfs_buf_offset(bp, dq_f->qlf_boffset);
ddq = &dqb->dd_diskdq;
/*
* If the dquot has an LSN in it, recover the dquot only if it's less
* than the lsn of the transaction we are replaying.
*/
if (xfs_has_crc(mp)) {
struct xfs_dqblk *dqb = (struct xfs_dqblk *)ddq;
xfs_lsn_t lsn = be64_to_cpu(dqb->dd_lsn);
if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) {
@@ -147,10 +149,23 @@ xlog_recover_dquot_commit_pass2(
memcpy(ddq, recddq, item->ri_buf[1].i_len);
if (xfs_has_crc(mp)) {
xfs_update_cksum((char *)ddq, sizeof(struct xfs_dqblk),
xfs_update_cksum((char *)dqb, sizeof(struct xfs_dqblk),
XFS_DQUOT_CRC_OFF);
}
/* Validate the recovered dquot. */
fa = xfs_dqblk_verify(log->l_mp, dqb, dq_f->qlf_id);
if (fa) {
XFS_CORRUPTION_ERROR("Bad dquot after recovery",
XFS_ERRLEVEL_LOW, mp, dqb,
sizeof(struct xfs_dqblk));
xfs_alert(mp,
"Metadata corruption detected at %pS, dquot 0x%x",
fa, dq_f->qlf_id);
error = -EFSCORRUPTED;
goto out_release;
}
ASSERT(dq_f->qlf_size == 2);
ASSERT(bp->b_mount == mp);
bp->b_flags |= _XBF_LOGRECOVERY;

View File

@@ -214,6 +214,43 @@ xfs_ilock_iocb(
return 0;
}
static int
xfs_ilock_iocb_for_write(
struct kiocb *iocb,
unsigned int *lock_mode)
{
ssize_t ret;
struct xfs_inode *ip = XFS_I(file_inode(iocb->ki_filp));
ret = xfs_ilock_iocb(iocb, *lock_mode);
if (ret)
return ret;
if (*lock_mode == XFS_IOLOCK_EXCL)
return 0;
if (!xfs_iflags_test(ip, XFS_IREMAPPING))
return 0;
xfs_iunlock(ip, *lock_mode);
*lock_mode = XFS_IOLOCK_EXCL;
return xfs_ilock_iocb(iocb, *lock_mode);
}
static unsigned int
xfs_ilock_for_write_fault(
struct xfs_inode *ip)
{
/* get a shared lock if no remapping in progress */
xfs_ilock(ip, XFS_MMAPLOCK_SHARED);
if (!xfs_iflags_test(ip, XFS_IREMAPPING))
return XFS_MMAPLOCK_SHARED;
/* wait for remapping to complete */
xfs_iunlock(ip, XFS_MMAPLOCK_SHARED);
xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
return XFS_MMAPLOCK_EXCL;
}
STATIC ssize_t
xfs_file_dio_read(
struct kiocb *iocb,
@@ -523,7 +560,7 @@ xfs_file_dio_write_aligned(
unsigned int iolock = XFS_IOLOCK_SHARED;
ssize_t ret;
ret = xfs_ilock_iocb(iocb, iolock);
ret = xfs_ilock_iocb_for_write(iocb, &iolock);
if (ret)
return ret;
ret = xfs_file_write_checks(iocb, from, &iolock);
@@ -590,7 +627,7 @@ retry_exclusive:
flags = IOMAP_DIO_FORCE_WAIT;
}
ret = xfs_ilock_iocb(iocb, iolock);
ret = xfs_ilock_iocb_for_write(iocb, &iolock);
if (ret)
return ret;
@@ -1158,7 +1195,7 @@ xfs_file_remap_range(
if (xfs_file_sync_writes(file_in) || xfs_file_sync_writes(file_out))
xfs_log_force_inode(dest);
out_unlock:
xfs_iunlock2_io_mmap(src, dest);
xfs_iunlock2_remapping(src, dest);
if (ret)
trace_xfs_reflink_remap_range_error(dest, ret, _RET_IP_);
/*
@@ -1313,6 +1350,7 @@ __xfs_filemap_fault(
struct inode *inode = file_inode(vmf->vma->vm_file);
struct xfs_inode *ip = XFS_I(inode);
vm_fault_t ret;
unsigned int lock_mode = 0;
trace_xfs_filemap_fault(ip, pe_size, write_fault);
@@ -1321,25 +1359,24 @@ __xfs_filemap_fault(
file_update_time(vmf->vma->vm_file);
}
if (IS_DAX(inode) || write_fault)
lock_mode = xfs_ilock_for_write_fault(XFS_I(inode));
if (IS_DAX(inode)) {
pfn_t pfn;
xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
ret = xfs_dax_fault(vmf, pe_size, write_fault, &pfn);
if (ret & VM_FAULT_NEEDDSYNC)
ret = dax_finish_sync_fault(vmf, pe_size, pfn);
xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
} else if (write_fault) {
ret = iomap_page_mkwrite(vmf, &xfs_page_mkwrite_iomap_ops);
} else {
if (write_fault) {
xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
ret = iomap_page_mkwrite(vmf,
&xfs_page_mkwrite_iomap_ops);
xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
} else {
ret = filemap_fault(vmf);
}
ret = filemap_fault(vmf);
}
if (lock_mode)
xfs_iunlock(XFS_I(inode), lock_mode);
if (write_fault)
sb_end_pagefault(inode->i_sb);
return ret;

View File

@@ -919,6 +919,13 @@ xfs_droplink(
xfs_trans_t *tp,
xfs_inode_t *ip)
{
if (VFS_I(ip)->i_nlink == 0) {
xfs_alert(ip->i_mount,
"%s: Attempt to drop inode (%llu) with nlink zero.",
__func__, ip->i_ino);
return -EFSCORRUPTED;
}
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
drop_nlink(VFS_I(ip));
@@ -3637,6 +3644,23 @@ xfs_iunlock2_io_mmap(
inode_unlock(VFS_I(ip1));
}
/* Drop the MMAPLOCK and the IOLOCK after a remap completes. */
void
xfs_iunlock2_remapping(
struct xfs_inode *ip1,
struct xfs_inode *ip2)
{
xfs_iflags_clear(ip1, XFS_IREMAPPING);
if (ip1 != ip2)
xfs_iunlock(ip1, XFS_MMAPLOCK_SHARED);
xfs_iunlock(ip2, XFS_MMAPLOCK_EXCL);
if (ip1 != ip2)
inode_unlock_shared(VFS_I(ip1));
inode_unlock(VFS_I(ip2));
}
/*
* Reload the incore inode list for this inode. Caller should ensure that
* the link count cannot change, either by taking ILOCK_SHARED or otherwise

View File

@@ -347,6 +347,14 @@ static inline bool xfs_inode_has_large_extent_counts(struct xfs_inode *ip)
/* Quotacheck is running but inode has not been added to quota counts. */
#define XFS_IQUOTAUNCHECKED (1 << 14)
/*
* Remap in progress. Callers that wish to update file data while
* holding a shared IOLOCK or MMAPLOCK must drop the lock and retake
* the lock in exclusive mode. Relocking the file will block until
* IREMAPPING is cleared.
*/
#define XFS_IREMAPPING (1U << 15)
/* All inode state flags related to inode reclaim. */
#define XFS_ALL_IRECLAIM_FLAGS (XFS_IRECLAIMABLE | \
XFS_IRECLAIM | \
@@ -561,6 +569,14 @@ extern void xfs_setup_inode(struct xfs_inode *ip);
extern void xfs_setup_iops(struct xfs_inode *ip);
extern void xfs_diflags_to_iflags(struct xfs_inode *ip, bool init);
static inline void xfs_update_stable_writes(struct xfs_inode *ip)
{
if (bdev_stable_writes(xfs_inode_buftarg(ip)->bt_bdev))
mapping_set_stable_writes(VFS_I(ip)->i_mapping);
else
mapping_clear_stable_writes(VFS_I(ip)->i_mapping);
}
/*
* When setting up a newly allocated inode, we need to call
* xfs_finish_inode_setup() once the inode is fully instantiated at
@@ -595,6 +611,7 @@ void xfs_end_io(struct work_struct *work);
int xfs_ilock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
void xfs_iunlock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
void xfs_iunlock2_remapping(struct xfs_inode *ip1, struct xfs_inode *ip2);
static inline bool
xfs_inode_unlinked_incomplete(

View File

@@ -286,6 +286,7 @@ xlog_recover_inode_commit_pass2(
struct xfs_log_dinode *ldip;
uint isize;
int need_free = 0;
xfs_failaddr_t fa;
if (item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format)) {
in_f = item->ri_buf[0].i_addr;
@@ -530,8 +531,19 @@ out_owner_change:
(dip->di_mode != 0))
error = xfs_recover_inode_owner_change(mp, dip, in_f,
buffer_list);
/* re-generate the checksum. */
/* re-generate the checksum and validate the recovered inode. */
xfs_dinode_calc_crc(log->l_mp, dip);
fa = xfs_dinode_verify(log->l_mp, in_f->ilf_ino, dip);
if (fa) {
XFS_CORRUPTION_ERROR(
"Bad dinode after recovery",
XFS_ERRLEVEL_LOW, mp, dip, sizeof(*dip));
xfs_alert(mp,
"Metadata corruption detected at %pS, inode 0x%llx",
fa, in_f->ilf_ino);
error = -EFSCORRUPTED;
goto out_release;
}
ASSERT(bp->b_mount == mp);
bp->b_flags |= _XBF_LOGRECOVERY;

View File

@@ -1120,23 +1120,25 @@ xfs_ioctl_setattr_xflags(
struct fileattr *fa)
{
struct xfs_mount *mp = ip->i_mount;
bool rtflag = (fa->fsx_xflags & FS_XFLAG_REALTIME);
uint64_t i_flags2;
/* Can't change realtime flag if any extents are allocated. */
if ((ip->i_df.if_nextents || ip->i_delayed_blks) &&
XFS_IS_REALTIME_INODE(ip) != (fa->fsx_xflags & FS_XFLAG_REALTIME))
return -EINVAL;
/* If realtime flag is set then must have realtime device */
if (fa->fsx_xflags & FS_XFLAG_REALTIME) {
if (mp->m_sb.sb_rblocks == 0 || mp->m_sb.sb_rextsize == 0 ||
(ip->i_extsize % mp->m_sb.sb_rextsize))
if (rtflag != XFS_IS_REALTIME_INODE(ip)) {
/* Can't change realtime flag if any extents are allocated. */
if (ip->i_df.if_nextents || ip->i_delayed_blks)
return -EINVAL;
}
/* Clear reflink if we are actually able to set the rt flag. */
if ((fa->fsx_xflags & FS_XFLAG_REALTIME) && xfs_is_reflink_inode(ip))
ip->i_diflags2 &= ~XFS_DIFLAG2_REFLINK;
if (rtflag) {
/* If realtime flag is set then must have realtime device */
if (mp->m_sb.sb_rblocks == 0 || mp->m_sb.sb_rextsize == 0 ||
(ip->i_extsize % mp->m_sb.sb_rextsize))
return -EINVAL;
/* Clear reflink if we are actually able to set the rt flag. */
if (xfs_is_reflink_inode(ip))
ip->i_diflags2 &= ~XFS_DIFLAG2_REFLINK;
}
/* Don't allow us to set DAX mode for a reflinked file for now. */
if ((fa->fsx_xflags & FS_XFLAG_DAX) && xfs_is_reflink_inode(ip))
@@ -1151,6 +1153,14 @@ xfs_ioctl_setattr_xflags(
ip->i_diflags2 = i_flags2;
xfs_diflags_to_iflags(ip, false);
/*
* Make the stable writes flag match that of the device the inode
* resides on when flipping the RT flag.
*/
if (rtflag != XFS_IS_REALTIME_INODE(ip) && S_ISREG(VFS_I(ip)->i_mode))
xfs_update_stable_writes(ip);
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
XFS_STATS_INC(mp, xs_ig_attrchg);

View File

@@ -1291,6 +1291,13 @@ xfs_setup_inode(
gfp_mask = mapping_gfp_mask(inode->i_mapping);
mapping_set_gfp_mask(inode->i_mapping, (gfp_mask & ~(__GFP_FS)));
/*
* For real-time inodes update the stable write flags to that of the RT
* device instead of the data device.
*/
if (S_ISREG(inode->i_mode) && XFS_IS_REALTIME_INODE(ip))
xfs_update_stable_writes(ip);
/*
* If there is no attribute fork no ACL can exist on this inode,
* and it can't have any file capabilities attached to it either.

View File

@@ -1891,9 +1891,7 @@ xlog_write_iclog(
* the buffer manually, the code needs to be kept in sync
* with the I/O completion path.
*/
xlog_state_done_syncing(iclog);
up(&iclog->ic_sema);
return;
goto sync;
}
/*
@@ -1923,20 +1921,17 @@ xlog_write_iclog(
* avoid shutdown re-entering this path and erroring out again.
*/
if (log->l_targ != log->l_mp->m_ddev_targp &&
blkdev_issue_flush(log->l_mp->m_ddev_targp->bt_bdev)) {
xlog_force_shutdown(log, SHUTDOWN_LOG_IO_ERROR);
return;
}
blkdev_issue_flush(log->l_mp->m_ddev_targp->bt_bdev))
goto shutdown;
}
if (iclog->ic_flags & XLOG_ICL_NEED_FUA)
iclog->ic_bio.bi_opf |= REQ_FUA;
iclog->ic_flags &= ~(XLOG_ICL_NEED_FLUSH | XLOG_ICL_NEED_FUA);
if (xlog_map_iclog_data(&iclog->ic_bio, iclog->ic_data, count)) {
xlog_force_shutdown(log, SHUTDOWN_LOG_IO_ERROR);
return;
}
if (xlog_map_iclog_data(&iclog->ic_bio, iclog->ic_data, count))
goto shutdown;
if (is_vmalloc_addr(iclog->ic_data))
flush_kernel_vmap_range(iclog->ic_data, count);
@@ -1957,6 +1952,12 @@ xlog_write_iclog(
}
submit_bio(&iclog->ic_bio);
return;
shutdown:
xlog_force_shutdown(log, SHUTDOWN_LOG_IO_ERROR);
sync:
xlog_state_done_syncing(iclog);
up(&iclog->ic_sema);
}
/*

View File

@@ -2514,7 +2514,7 @@ xlog_abort_defer_ops(
list_for_each_entry_safe(dfc, next, capture_list, dfc_list) {
list_del_init(&dfc->dfc_list);
xfs_defer_ops_capture_free(mp, dfc);
xfs_defer_ops_capture_abort(mp, dfc);
}
}

View File

@@ -783,6 +783,7 @@ xfs_reflink_end_cow_extent(
}
}
del = got;
xfs_trim_extent(&del, *offset_fsb, end_fsb - *offset_fsb);
/* Grab the corresponding mapping in the data fork. */
nmaps = 1;
@@ -1539,6 +1540,10 @@ xfs_reflink_remap_prep(
if (ret)
goto out_unlock;
xfs_iflags_set(src, XFS_IREMAPPING);
if (inode_in != inode_out)
xfs_ilock_demote(src, XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL);
return 0;
out_unlock:
xfs_iunlock2_io_mmap(src, dest);

View File

@@ -211,6 +211,23 @@ xfs_rtallocate_range(
return error;
}
/*
* Make sure we don't run off the end of the rt volume. Be careful that
* adjusting maxlen downwards doesn't cause us to fail the alignment checks.
*/
static inline xfs_extlen_t
xfs_rtallocate_clamp_len(
struct xfs_mount *mp,
xfs_rtblock_t startrtx,
xfs_extlen_t rtxlen,
xfs_extlen_t prod)
{
xfs_extlen_t ret;
ret = min(mp->m_sb.sb_rextents, startrtx + rtxlen) - startrtx;
return rounddown(ret, prod);
}
/*
* Attempt to allocate an extent minlen<=len<=maxlen starting from
* bitmap block bbno. If we don't get maxlen then use prod to trim
@@ -248,7 +265,7 @@ xfs_rtallocate_extent_block(
i <= end;
i++) {
/* Make sure we don't scan off the end of the rt volume. */
maxlen = min(mp->m_sb.sb_rextents, i + maxlen) - i;
maxlen = xfs_rtallocate_clamp_len(mp, i, maxlen, prod);
/*
* See if there's a free extent of maxlen starting at i.
@@ -355,7 +372,8 @@ xfs_rtallocate_extent_exact(
int isfree; /* extent is free */
xfs_rtblock_t next; /* next block to try (dummy) */
ASSERT(minlen % prod == 0 && maxlen % prod == 0);
ASSERT(minlen % prod == 0);
ASSERT(maxlen % prod == 0);
/*
* Check if the range in question (for maxlen) is free.
*/
@@ -438,7 +456,9 @@ xfs_rtallocate_extent_near(
xfs_rtblock_t n; /* next block to try */
xfs_rtblock_t r; /* result block */
ASSERT(minlen % prod == 0 && maxlen % prod == 0);
ASSERT(minlen % prod == 0);
ASSERT(maxlen % prod == 0);
/*
* If the block number given is off the end, silently set it to
* the last block.
@@ -447,7 +467,7 @@ xfs_rtallocate_extent_near(
bno = mp->m_sb.sb_rextents - 1;
/* Make sure we don't run off the end of the rt volume. */
maxlen = min(mp->m_sb.sb_rextents, bno + maxlen) - bno;
maxlen = xfs_rtallocate_clamp_len(mp, bno, maxlen, prod);
if (maxlen < minlen) {
*rtblock = NULLRTBLOCK;
return 0;
@@ -638,7 +658,8 @@ xfs_rtallocate_extent_size(
xfs_rtblock_t r; /* result block number */
xfs_suminfo_t sum; /* summary information for extents */
ASSERT(minlen % prod == 0 && maxlen % prod == 0);
ASSERT(minlen % prod == 0);
ASSERT(maxlen % prod == 0);
ASSERT(maxlen != 0);
/*
@@ -954,7 +975,7 @@ xfs_growfs_rt(
return -EINVAL;
/* Unsupported realtime features. */
if (xfs_has_rmapbt(mp) || xfs_has_reflink(mp))
if (xfs_has_rmapbt(mp) || xfs_has_reflink(mp) || xfs_has_quota(mp))
return -EOPNOTSUPP;
nrblocks = in->newblocks;

View File

@@ -58,6 +58,10 @@ xfs_rtfree_extent(
xfs_rtblock_t bno, /* starting block number to free */
xfs_extlen_t len); /* length of extent freed */
/* Same as above, but in units of rt blocks. */
int xfs_rtfree_blocks(struct xfs_trans *tp, xfs_fsblock_t rtbno,
xfs_filblks_t rtlen);
/*
* Initialize realtime fields in the mount structure.
*/
@@ -137,16 +141,17 @@ int xfs_rtalloc_extent_is_free(struct xfs_mount *mp, struct xfs_trans *tp,
bool *is_free);
int xfs_rtalloc_reinit_frextents(struct xfs_mount *mp);
#else
# define xfs_rtallocate_extent(t,b,min,max,l,f,p,rb) (ENOSYS)
# define xfs_rtfree_extent(t,b,l) (ENOSYS)
# define xfs_rtpick_extent(m,t,l,rb) (ENOSYS)
# define xfs_growfs_rt(mp,in) (ENOSYS)
# define xfs_rtalloc_query_range(t,l,h,f,p) (ENOSYS)
# define xfs_rtalloc_query_all(m,t,f,p) (ENOSYS)
# define xfs_rtbuf_get(m,t,b,i,p) (ENOSYS)
# define xfs_verify_rtbno(m, r) (false)
# define xfs_rtalloc_extent_is_free(m,t,s,l,i) (ENOSYS)
# define xfs_rtalloc_reinit_frextents(m) (0)
# define xfs_rtallocate_extent(t,b,min,max,l,f,p,rb) (-ENOSYS)
# define xfs_rtfree_extent(t,b,l) (-ENOSYS)
# define xfs_rtfree_blocks(t,rb,rl) (-ENOSYS)
# define xfs_rtpick_extent(m,t,l,rb) (-ENOSYS)
# define xfs_growfs_rt(mp,in) (-ENOSYS)
# define xfs_rtalloc_query_range(m,t,l,h,f,p) (-ENOSYS)
# define xfs_rtalloc_query_all(m,t,f,p) (-ENOSYS)
# define xfs_rtbuf_get(m,t,b,i,p) (-ENOSYS)
# define xfs_verify_rtbno(m, r) (false)
# define xfs_rtalloc_extent_is_free(m,t,s,l,i) (-ENOSYS)
# define xfs_rtalloc_reinit_frextents(m) (0)
static inline int /* error */
xfs_rtmount_init(
xfs_mount_t *mp) /* file system mount structure */
@@ -157,7 +162,7 @@ xfs_rtmount_init(
xfs_warn(mp, "Not built with CONFIG_XFS_RT");
return -ENOSYS;
}
# define xfs_rtmount_inodes(m) (((mp)->m_sb.sb_rblocks == 0)? 0 : (ENOSYS))
# define xfs_rtmount_inodes(m) (((mp)->m_sb.sb_rblocks == 0)? 0 : (-ENOSYS))
# define xfs_rtunmount_inodes(m)
#endif /* CONFIG_XFS_RT */

View File

@@ -69,10 +69,10 @@ struct seccomp_data;
#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
static inline int secure_computing(void) { return 0; }
static inline int __secure_computing(const struct seccomp_data *sd) { return 0; }
#else
static inline void secure_computing_strict(int this_syscall) { return; }
#endif
static inline int __secure_computing(const struct seccomp_data *sd) { return 0; }
static inline long prctl_get_seccomp(void)
{

View File

@@ -597,8 +597,10 @@ static inline void __io_cq_unlock_post_flush(struct io_ring_ctx *ctx)
io_commit_cqring(ctx);
spin_unlock(&ctx->completion_lock);
io_commit_cqring_flush(ctx);
if (!(ctx->flags & IORING_SETUP_DEFER_TASKRUN))
if (!(ctx->flags & IORING_SETUP_DEFER_TASKRUN)) {
smp_mb();
__io_cqring_wake(ctx);
}
}
void io_cq_unlock_post(struct io_ring_ctx *ctx)

View File

@@ -321,17 +321,24 @@ static inline void invoke_softirq(void)
wakeup_softirqd();
}
#define SCHED_SOFTIRQ_MASK BIT(SCHED_SOFTIRQ)
/*
* flush_smp_call_function_queue() can raise a soft interrupt in a function
* call. On RT kernels this is undesired and the only known functionality
* in the block layer which does this is disabled on RT. If soft interrupts
* get raised which haven't been raised before the flush, warn so it can be
* call. On RT kernels this is undesired and the only known functionalities
* are in the block layer which is disabled on RT, and in the scheduler for
* idle load balancing. If soft interrupts get raised which haven't been
* raised before the flush, warn if it is not a SCHED_SOFTIRQ so it can be
* investigated.
*/
void do_softirq_post_smp_call_flush(unsigned int was_pending)
{
if (WARN_ON_ONCE(was_pending != local_softirq_pending()))
unsigned int is_pending = local_softirq_pending();
if (unlikely(was_pending != is_pending)) {
WARN_ON_ONCE(was_pending != (is_pending & ~SCHED_SOFTIRQ_MASK));
invoke_softirq();
}
}
#else /* CONFIG_PREEMPT_RT */

View File

@@ -218,7 +218,7 @@ static struct ip_tunnel *ip_tunnel_find(struct ip_tunnel_net *itn,
struct ip_tunnel *t = NULL;
struct hlist_head *head = ip_bucket(itn, parms);
hlist_for_each_entry_rcu(t, head, hash_node) {
hlist_for_each_entry_rcu(t, head, hash_node, lockdep_rtnl_is_held()) {
if (local == t->parms.iph.saddr &&
remote == t->parms.iph.daddr &&
link == t->parms.link &&

View File

@@ -1180,8 +1180,8 @@ next_iter:
while (sibling) {
if (sibling->fib6_metric == rt->fib6_metric &&
rt6_qualify_for_ecmp(sibling)) {
list_add_tail(&rt->fib6_siblings,
&sibling->fib6_siblings);
list_add_tail_rcu(&rt->fib6_siblings,
&sibling->fib6_siblings);
break;
}
sibling = rcu_dereference_protected(sibling->fib6_next,
@@ -1242,7 +1242,7 @@ add:
fib6_siblings)
sibling->fib6_nsiblings--;
rt->fib6_nsiblings = 0;
list_del_init(&rt->fib6_siblings);
list_del_rcu(&rt->fib6_siblings);
rt6_multipath_rebalance(next_sibling);
return err;
}
@@ -1955,7 +1955,7 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
&rt->fib6_siblings, fib6_siblings)
sibling->fib6_nsiblings--;
rt->fib6_nsiblings = 0;
list_del_init(&rt->fib6_siblings);
list_del_rcu(&rt->fib6_siblings);
rt6_multipath_rebalance(next_sibling);
}

View File

@@ -417,8 +417,8 @@ void fib6_select_path(const struct net *net, struct fib6_result *res,
struct flowi6 *fl6, int oif, bool have_oif_match,
const struct sk_buff *skb, int strict)
{
struct fib6_info *sibling, *next_sibling;
struct fib6_info *match = res->f6i;
struct fib6_info *sibling;
if (!match->nh && (!match->fib6_nsiblings || have_oif_match))
goto out;
@@ -444,8 +444,8 @@ void fib6_select_path(const struct net *net, struct fib6_result *res,
if (fl6->mp_hash <= atomic_read(&match->fib6_nh->fib_nh_upper_bound))
goto out;
list_for_each_entry_safe(sibling, next_sibling, &match->fib6_siblings,
fib6_siblings) {
list_for_each_entry_rcu(sibling, &match->fib6_siblings,
fib6_siblings) {
const struct fib6_nh *nh = sibling->fib6_nh;
int nh_upper_bound;
@@ -5169,14 +5169,18 @@ static void ip6_route_mpath_notify(struct fib6_info *rt,
* nexthop. Since sibling routes are always added at the end of
* the list, find the first sibling of the last route appended
*/
rcu_read_lock();
if ((nlflags & NLM_F_APPEND) && rt_last && rt_last->fib6_nsiblings) {
rt = list_first_entry(&rt_last->fib6_siblings,
struct fib6_info,
fib6_siblings);
rt = list_first_or_null_rcu(&rt_last->fib6_siblings,
struct fib6_info,
fib6_siblings);
}
if (rt)
inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
rcu_read_unlock();
}
static bool ip6_route_mpath_should_notify(const struct fib6_info *rt)
@@ -5521,17 +5525,21 @@ static size_t rt6_nlmsg_size(struct fib6_info *f6i)
nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_nlmsg_size,
&nexthop_len);
} else {
struct fib6_info *sibling, *next_sibling;
struct fib6_nh *nh = f6i->fib6_nh;
struct fib6_info *sibling;
nexthop_len = 0;
if (f6i->fib6_nsiblings) {
rt6_nh_nlmsg_size(nh, &nexthop_len);
list_for_each_entry_safe(sibling, next_sibling,
&f6i->fib6_siblings, fib6_siblings) {
rcu_read_lock();
list_for_each_entry_rcu(sibling, &f6i->fib6_siblings,
fib6_siblings) {
rt6_nh_nlmsg_size(sibling->fib6_nh, &nexthop_len);
}
rcu_read_unlock();
}
nexthop_len += lwtunnel_get_encap_size(nh->fib_nh_lws);
}
@@ -5695,7 +5703,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
lwtunnel_fill_encap(skb, dst->lwtstate, RTA_ENCAP, RTA_ENCAP_TYPE) < 0)
goto nla_put_failure;
} else if (rt->fib6_nsiblings) {
struct fib6_info *sibling, *next_sibling;
struct fib6_info *sibling;
struct nlattr *mp;
mp = nla_nest_start_noflag(skb, RTA_MULTIPATH);
@@ -5707,14 +5715,21 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
0) < 0)
goto nla_put_failure;
list_for_each_entry_safe(sibling, next_sibling,
&rt->fib6_siblings, fib6_siblings) {
rcu_read_lock();
list_for_each_entry_rcu(sibling, &rt->fib6_siblings,
fib6_siblings) {
if (fib_add_nexthop(skb, &sibling->fib6_nh->nh_common,
sibling->fib6_nh->fib_nh_weight,
AF_INET6, 0) < 0)
AF_INET6, 0) < 0) {
rcu_read_unlock();
goto nla_put_failure;
}
}
rcu_read_unlock();
nla_nest_end(skb, mp);
} else if (rt->nh) {
if (nla_put_u32(skb, RTA_NH_ID, rt->nh->id))
@@ -6151,7 +6166,7 @@ void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
err = -ENOBUFS;
seq = info->nlh ? info->nlh->nlmsg_seq : 0;
skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
skb = nlmsg_new(rt6_nlmsg_size(rt), GFP_ATOMIC);
if (!skb)
goto errout;
@@ -6164,7 +6179,7 @@ void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,
goto errout;
}
rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
info->nlh, gfp_any());
info->nlh, GFP_ATOMIC);
return;
errout:
if (err < 0)

View File

@@ -91,6 +91,8 @@ ets_class_from_arg(struct Qdisc *sch, unsigned long arg)
{
struct ets_sched *q = qdisc_priv(sch);
if (arg == 0 || arg > q->nbands)
return NULL;
return &q->classes[arg - 1];
}

View File

@@ -1982,6 +1982,7 @@ config SND_SOC_WM8993
config SND_SOC_WM8994
tristate
depends on MFD_WM8994
config SND_SOC_WM8995
tristate

View File

@@ -220,8 +220,9 @@ config SND_SOC_SAMSUNG_TM2_WM5110
config SND_SOC_SAMSUNG_ARIES_WM8994
tristate "SoC I2S Audio support for WM8994 on Aries"
depends on SND_SOC_SAMSUNG && MFD_WM8994 && IIO && EXTCON
depends on SND_SOC_SAMSUNG && I2C && IIO && EXTCON
select SND_SOC_BT_SCO
select MFD_WM8994
select SND_SOC_WM8994
select SND_SAMSUNG_I2S
help
@@ -233,8 +234,9 @@ config SND_SOC_SAMSUNG_ARIES_WM8994
config SND_SOC_SAMSUNG_MIDAS_WM1811
tristate "SoC I2S Audio support for Midas boards"
depends on SND_SOC_SAMSUNG
depends on SND_SOC_SAMSUNG && I2C
select SND_SAMSUNG_I2S
select MFD_WM8994
select SND_SOC_WM8994
help
Say Y if you want to add support for SoC audio on the Midas boards.

View File

@@ -38,6 +38,17 @@ struct midas_priv {
struct snd_soc_jack headset_jack;
};
static struct snd_soc_jack_pin headset_jack_pins[] = {
{
.pin = "Headphone",
.mask = SND_JACK_HEADPHONE,
},
{
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
};
static int midas_start_fll1(struct snd_soc_pcm_runtime *rtd, unsigned int rate)
{
struct snd_soc_card *card = rtd->card;
@@ -261,6 +272,7 @@ static const struct snd_soc_dapm_widget midas_dapm_widgets[] = {
SND_SOC_DAPM_LINE("HDMI", NULL),
SND_SOC_DAPM_LINE("FM In", midas_fm_set),
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Main Mic", midas_mic_bias),
SND_SOC_DAPM_MIC("Sub Mic", midas_submic_bias),
@@ -305,11 +317,13 @@ static int midas_late_probe(struct snd_soc_card *card)
return ret;
}
ret = snd_soc_card_jack_new(card, "Headset",
SND_JACK_HEADSET | SND_JACK_MECHANICAL |
SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5,
&priv->headset_jack);
ret = snd_soc_card_jack_new_pins(card, "Headset",
SND_JACK_HEADSET | SND_JACK_MECHANICAL |
SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5,
&priv->headset_jack,
headset_jack_pins,
ARRAY_SIZE(headset_jack_pins));
if (ret)
return ret;

View File

@@ -2137,6 +2137,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_CTL_MSG_DELAY_1M),
DEVICE_FLG(0x0c45, 0x6340, /* Sonix HD USB Camera */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x0d8c, 0x0014, /* USB Audio Device */
QUIRK_FLAG_CTL_MSG_DELAY_1M),
DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */
QUIRK_FLAG_FIXED_RATE),
DEVICE_FLG(0x0ecb, 0x2069, /* JBL Quantum810 Wireless */

View File

@@ -72,6 +72,7 @@ TEST_GEN_PROGS += sk_bind_sendto_listen
TEST_GEN_PROGS += sk_connect_zero_addr
TEST_PROGS += test_ingress_egress_chaining.sh
TEST_GEN_FILES += nat6to4.o
TEST_PROGS += ipv6_route_update_soft_lockup.sh
TEST_FILES := settings

View File

@@ -0,0 +1,262 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Testing for potential kernel soft lockup during IPv6 routing table
# refresh under heavy outgoing IPv6 traffic. If a kernel soft lockup
# occurs, a kernel panic will be triggered to prevent associated issues.
#
#
# Test Environment Layout
#
# ┌----------------┐ ┌----------------┐
# | SOURCE_NS | | SINK_NS |
# | NAMESPACE | | NAMESPACE |
# |(iperf3 clients)| |(iperf3 servers)|
# | | | |
# | | | |
# | ┌-----------| nexthops |---------┐ |
# | |veth_source|<--------------------------------------->|veth_sink|<┐ |
# | └-----------|2001:0DB8:1::0:1/96 2001:0DB8:1::1:1/96 |---------┘ | |
# | | ^ 2001:0DB8:1::1:2/96 | | |
# | | . . | fwd | |
# | ┌---------┐ | . . | | |
# | | IPv6 | | . . | V |
# | | routing | | . 2001:0DB8:1::1:80/96| ┌-----┐ |
# | | table | | . | | lo | |
# | | nexthop | | . └--------┴-----┴-┘
# | | update | | ............................> 2001:0DB8:2::1:1/128
# | └-------- ┘ |
# └----------------┘
#
# The test script sets up two network namespaces, source_ns and sink_ns,
# connected via a veth link. Within source_ns, it continuously updates the
# IPv6 routing table by flushing and inserting IPV6_NEXTHOP_ADDR_COUNT nexthop
# IPs destined for SINK_LOOPBACK_IP_ADDR in sink_ns. This refresh occurs at a
# rate of 1/ROUTING_TABLE_REFRESH_PERIOD per second for TEST_DURATION seconds.
#
# Simultaneously, multiple iperf3 clients within source_ns generate heavy
# outgoing IPv6 traffic. Each client is assigned a unique port number starting
# at 5000 and incrementing sequentially. Each client targets a unique iperf3
# server running in sink_ns, connected to the SINK_LOOPBACK_IFACE interface
# using the same port number.
#
# The number of iperf3 servers and clients is set to half of the total
# available cores on each machine.
#
# NOTE: We have tested this script on machines with various CPU specifications,
# ranging from lower to higher performance as listed below. The test script
# effectively triggered a kernel soft lockup on machines running an unpatched
# kernel in under a minute:
#
# - 1x Intel Xeon E-2278G 8-Core Processor @ 3.40GHz
# - 1x Intel Xeon E-2378G Processor 8-Core @ 2.80GHz
# - 1x AMD EPYC 7401P 24-Core Processor @ 2.00GHz
# - 1x AMD EPYC 7402P 24-Core Processor @ 2.80GHz
# - 2x Intel Xeon Gold 5120 14-Core Processor @ 2.20GHz
# - 1x Ampere Altra Q80-30 80-Core Processor @ 3.00GHz
# - 2x Intel Xeon Gold 5120 14-Core Processor @ 2.20GHz
# - 2x Intel Xeon Silver 4214 24-Core Processor @ 2.20GHz
# - 1x AMD EPYC 7502P 32-Core @ 2.50GHz
# - 1x Intel Xeon Gold 6314U 32-Core Processor @ 2.30GHz
# - 2x Intel Xeon Gold 6338 32-Core Processor @ 2.00GHz
#
# On less performant machines, you may need to increase the TEST_DURATION
# parameter to enhance the likelihood of encountering a race condition leading
# to a kernel soft lockup and avoid a false negative result.
#
# NOTE: The test may not produce the expected result in virtualized
# environments (e.g., qemu) due to differences in timing and CPU handling,
# which can affect the conditions needed to trigger a soft lockup.
source lib.sh
source net_helper.sh
TEST_DURATION=300
ROUTING_TABLE_REFRESH_PERIOD=0.01
IPERF3_BITRATE="300m"
IPV6_NEXTHOP_ADDR_COUNT="128"
IPV6_NEXTHOP_ADDR_MASK="96"
IPV6_NEXTHOP_PREFIX="2001:0DB8:1"
SOURCE_TEST_IFACE="veth_source"
SOURCE_TEST_IP_ADDR="2001:0DB8:1::0:1/96"
SINK_TEST_IFACE="veth_sink"
# ${SINK_TEST_IFACE} is populated with the following range of IPv6 addresses:
# 2001:0DB8:1::1:1 to 2001:0DB8:1::1:${IPV6_NEXTHOP_ADDR_COUNT}
SINK_LOOPBACK_IFACE="lo"
SINK_LOOPBACK_IP_MASK="128"
SINK_LOOPBACK_IP_ADDR="2001:0DB8:2::1:1"
nexthop_ip_list=""
termination_signal=""
kernel_softlokup_panic_prev_val=""
terminate_ns_processes_by_pattern() {
local ns=$1
local pattern=$2
for pid in $(ip netns pids ${ns}); do
[ -e /proc/$pid/cmdline ] && grep -qe "${pattern}" /proc/$pid/cmdline && kill -9 $pid
done
}
cleanup() {
echo "info: cleaning up namespaces and terminating all processes within them..."
# Terminate iperf3 instances running in the source_ns. To avoid race
# conditions, first iterate over the PIDs and terminate those
# associated with the bash shells running the
# `while true; do iperf3 -c ...; done` loops. In a second iteration,
# terminate the individual `iperf3 -c ...` instances.
terminate_ns_processes_by_pattern ${source_ns} while
terminate_ns_processes_by_pattern ${source_ns} iperf3
# Repeat the same process for sink_ns
terminate_ns_processes_by_pattern ${sink_ns} while
terminate_ns_processes_by_pattern ${sink_ns} iperf3
# Check if any iperf3 instances are still running. This could happen
# if a core has entered an infinite loop and the timeout for detecting
# the soft lockup has not expired, but either the test interval has
# already elapsed or the test was terminated manually (e.g., with ^C)
for pid in $(ip netns pids ${source_ns}); do
if [ -e /proc/$pid/cmdline ] && grep -qe 'iperf3' /proc/$pid/cmdline; then
echo "FAIL: unable to terminate some iperf3 instances. Soft lockup is underway. A kernel panic is on the way!"
exit ${ksft_fail}
fi
done
if [ "$termination_signal" == "SIGINT" ]; then
echo "SKIP: Termination due to ^C (SIGINT)"
elif [ "$termination_signal" == "SIGALRM" ]; then
echo "PASS: No kernel soft lockup occurred during this ${TEST_DURATION} second test"
fi
cleanup_ns ${source_ns} ${sink_ns}
sysctl -qw kernel.softlockup_panic=${kernel_softlokup_panic_prev_val}
}
setup_prepare() {
setup_ns source_ns sink_ns
ip -n ${source_ns} link add name ${SOURCE_TEST_IFACE} type veth peer name ${SINK_TEST_IFACE} netns ${sink_ns}
# Setting up the Source namespace
ip -n ${source_ns} addr add ${SOURCE_TEST_IP_ADDR} dev ${SOURCE_TEST_IFACE}
ip -n ${source_ns} link set dev ${SOURCE_TEST_IFACE} qlen 10000
ip -n ${source_ns} link set dev ${SOURCE_TEST_IFACE} up
ip netns exec ${source_ns} sysctl -qw net.ipv6.fib_multipath_hash_policy=1
# Setting up the Sink namespace
ip -n ${sink_ns} addr add ${SINK_LOOPBACK_IP_ADDR}/${SINK_LOOPBACK_IP_MASK} dev ${SINK_LOOPBACK_IFACE}
ip -n ${sink_ns} link set dev ${SINK_LOOPBACK_IFACE} up
ip netns exec ${sink_ns} sysctl -qw net.ipv6.conf.${SINK_LOOPBACK_IFACE}.forwarding=1
ip -n ${sink_ns} link set ${SINK_TEST_IFACE} up
ip netns exec ${sink_ns} sysctl -qw net.ipv6.conf.${SINK_TEST_IFACE}.forwarding=1
# Populate nexthop IPv6 addresses on the test interface in the sink_ns
echo "info: populating ${IPV6_NEXTHOP_ADDR_COUNT} IPv6 addresses on the ${SINK_TEST_IFACE} interface ..."
for IP in $(seq 1 ${IPV6_NEXTHOP_ADDR_COUNT}); do
ip -n ${sink_ns} addr add ${IPV6_NEXTHOP_PREFIX}::$(printf "1:%x" "${IP}")/${IPV6_NEXTHOP_ADDR_MASK} dev ${SINK_TEST_IFACE};
done
# Preparing list of nexthops
for IP in $(seq 1 ${IPV6_NEXTHOP_ADDR_COUNT}); do
nexthop_ip_list=$nexthop_ip_list" nexthop via ${IPV6_NEXTHOP_PREFIX}::$(printf "1:%x" $IP) dev ${SOURCE_TEST_IFACE} weight 1"
done
}
test_soft_lockup_during_routing_table_refresh() {
# Start num_of_iperf_servers iperf3 servers in the sink_ns namespace,
# each listening on ports starting at 5001 and incrementing
# sequentially. Since iperf3 instances may terminate unexpectedly, a
# while loop is used to automatically restart them in such cases.
echo "info: starting ${num_of_iperf_servers} iperf3 servers in the sink_ns namespace ..."
for i in $(seq 1 ${num_of_iperf_servers}); do
cmd="iperf3 --bind ${SINK_LOOPBACK_IP_ADDR} -s -p $(printf '5%03d' ${i}) --rcv-timeout 200 &>/dev/null"
ip netns exec ${sink_ns} bash -c "while true; do ${cmd}; done &" &>/dev/null
done
# Wait for the iperf3 servers to be ready
for i in $(seq ${num_of_iperf_servers}); do
port=$(printf '5%03d' ${i});
wait_local_port_listen ${sink_ns} ${port} tcp
done
# Continuously refresh the routing table in the background within
# the source_ns namespace
ip netns exec ${source_ns} bash -c "
while \$(ip netns list | grep -q ${source_ns}); do
ip -6 route add ${SINK_LOOPBACK_IP_ADDR}/${SINK_LOOPBACK_IP_MASK} ${nexthop_ip_list};
sleep ${ROUTING_TABLE_REFRESH_PERIOD};
ip -6 route delete ${SINK_LOOPBACK_IP_ADDR}/${SINK_LOOPBACK_IP_MASK};
done &"
# Start num_of_iperf_servers iperf3 clients in the source_ns namespace,
# each sending TCP traffic on sequential ports starting at 5001.
# Since iperf3 instances may terminate unexpectedly (e.g., if the route
# to the server is deleted in the background during a route refresh), a
# while loop is used to automatically restart them in such cases.
echo "info: starting ${num_of_iperf_servers} iperf3 clients in the source_ns namespace ..."
for i in $(seq 1 ${num_of_iperf_servers}); do
cmd="iperf3 -c ${SINK_LOOPBACK_IP_ADDR} -p $(printf '5%03d' ${i}) --length 64 --bitrate ${IPERF3_BITRATE} -t 0 --connect-timeout 150 &>/dev/null"
ip netns exec ${source_ns} bash -c "while true; do ${cmd}; done &" &>/dev/null
done
echo "info: IPv6 routing table is being updated at the rate of $(echo "1/${ROUTING_TABLE_REFRESH_PERIOD}" | bc)/s for ${TEST_DURATION} seconds ..."
echo "info: A kernel soft lockup, if detected, results in a kernel panic!"
wait
}
# Make sure 'iperf3' is installed, skip the test otherwise
if [ ! -x "$(command -v "iperf3")" ]; then
echo "SKIP: 'iperf3' is not installed. Skipping the test."
exit ${ksft_skip}
fi
# Determine the number of cores on the machine
num_of_iperf_servers=$(( $(nproc)/2 ))
# Check if we are running on a multi-core machine, skip the test otherwise
if [ "${num_of_iperf_servers}" -eq 0 ]; then
echo "SKIP: This test is not valid on a single core machine!"
exit ${ksft_skip}
fi
# Since the kernel soft lockup we're testing causes at least one core to enter
# an infinite loop, destabilizing the host and likely affecting subsequent
# tests, we trigger a kernel panic instead of reporting a failure and
# continuing
kernel_softlokup_panic_prev_val=$(sysctl -n kernel.softlockup_panic)
sysctl -qw kernel.softlockup_panic=1
handle_sigint() {
termination_signal="SIGINT"
cleanup
exit ${ksft_skip}
}
handle_sigalrm() {
termination_signal="SIGALRM"
cleanup
exit ${ksft_pass}
}
trap handle_sigint SIGINT
trap handle_sigalrm SIGALRM
(sleep ${TEST_DURATION} && kill -s SIGALRM $$)&
setup_prepare
test_soft_lockup_during_routing_table_refresh