Merge ecc64d2dc9 ("Merge tag 'sysctl-7.00-fixes-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/sysctl/sysctl") into android-mainline
Steps on the way to v7.0-rc3 Change-Id: Ie304ea1065476101b872fb01f45b426fa68e8e8f Signed-off-by: Carlos Llamas <cmllamas@google.com>
This commit is contained in:
commit
7a28cde1a6
47 files changed
+624
-339
No files matched your search
@@ -152,7 +152,7 @@ operations:
|
||||
- compound-ops
|
||||
-
|
||||
name: threads-set
|
||||
doc: set the number of running threads
|
||||
doc: set the maximum number of running threads
|
||||
attribute-set: server
|
||||
flags: [admin-perm]
|
||||
do:
|
||||
@@ -165,7 +165,7 @@ operations:
|
||||
- min-threads
|
||||
-
|
||||
name: threads-get
|
||||
doc: get the number of running threads
|
||||
doc: get the maximum number of running threads
|
||||
attribute-set: server
|
||||
do:
|
||||
reply:
|
||||
|
||||
@@ -228,6 +228,9 @@ static int handle_one_ule_extension( struct dvb_net_priv *p )
|
||||
unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8;
|
||||
unsigned char htype = p->ule_sndu_type & 0x00FF;
|
||||
|
||||
if (htype >= ARRAY_SIZE(ule_mandatory_ext_handlers))
|
||||
return -1;
|
||||
|
||||
/* Discriminate mandatory and optional extension headers. */
|
||||
if (hlen == 0) {
|
||||
/* Mandatory extension header */
|
||||
|
||||
@@ -574,10 +574,9 @@ static int cs42l43_pin_probe(struct platform_device *pdev)
|
||||
if (child) {
|
||||
ret = devm_add_action_or_reset(&pdev->dev,
|
||||
cs42l43_fwnode_put, child);
|
||||
if (ret) {
|
||||
fwnode_handle_put(child);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!child->dev)
|
||||
child->dev = priv->dev;
|
||||
fwnode = child;
|
||||
|
||||
@@ -522,11 +522,10 @@ static int __maybe_unused sky1_pinctrl_resume(struct device *dev)
|
||||
return pinctrl_force_default(spctl->pctl);
|
||||
}
|
||||
|
||||
const struct dev_pm_ops sky1_pinctrl_pm_ops = {
|
||||
static const struct dev_pm_ops sky1_pinctrl_pm_ops = {
|
||||
SET_LATE_SYSTEM_SLEEP_PM_OPS(sky1_pinctrl_suspend,
|
||||
sky1_pinctrl_resume)
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(sky1_pinctrl_pm_ops);
|
||||
|
||||
static int sky1_pinctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
||||
@@ -679,7 +679,6 @@ static int aml_dt_node_to_map_pinmux(struct pinctrl_dev *pctldev,
|
||||
unsigned int *num_maps)
|
||||
{
|
||||
struct device *dev = pctldev->dev;
|
||||
struct device_node *pnode;
|
||||
unsigned long *configs = NULL;
|
||||
unsigned int num_configs = 0;
|
||||
struct property *prop;
|
||||
@@ -693,7 +692,7 @@ static int aml_dt_node_to_map_pinmux(struct pinctrl_dev *pctldev,
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
pnode = of_get_parent(np);
|
||||
struct device_node *pnode __free(device_node) = of_get_parent(np);
|
||||
if (!pnode) {
|
||||
dev_info(dev, "Missing function node\n");
|
||||
return -EINVAL;
|
||||
|
||||
@@ -351,13 +351,13 @@ int pinconf_generic_parse_dt_config(struct device_node *np,
|
||||
|
||||
ret = parse_dt_cfg(np, dt_params, ARRAY_SIZE(dt_params), cfg, &ncfg);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
if (pctldev && pctldev->desc->num_custom_params &&
|
||||
pctldev->desc->custom_params) {
|
||||
ret = parse_dt_cfg(np, pctldev->desc->custom_params,
|
||||
pctldev->desc->num_custom_params, cfg, &ncfg);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* no configs found at all */
|
||||
|
||||
@@ -80,7 +80,7 @@ static int amdisp_get_group_pins(struct pinctrl_dev *pctldev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct pinctrl_ops amdisp_pinctrl_ops = {
|
||||
static const struct pinctrl_ops amdisp_pinctrl_ops = {
|
||||
.get_groups_count = amdisp_get_groups_count,
|
||||
.get_group_name = amdisp_get_group_name,
|
||||
.get_group_pins = amdisp_get_group_pins,
|
||||
|
||||
@@ -627,7 +627,7 @@ static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
|
||||
bitmap_scatter(tmask, mask, chip->map, MAX_LINE);
|
||||
bitmap_scatter(tval, val, chip->map, MAX_LINE);
|
||||
|
||||
for_each_set_clump8(offset, bits, tmask, chip->tpin) {
|
||||
for_each_set_clump8(offset, bits, tmask, chip->nport * BANK_SZ) {
|
||||
unsigned int i = offset / 8;
|
||||
|
||||
write_val = bitmap_get_value8(tval, offset);
|
||||
@@ -655,7 +655,7 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
|
||||
bitmap_scatter(tmask, mask, chip->map, MAX_LINE);
|
||||
bitmap_scatter(tval, val, chip->map, MAX_LINE);
|
||||
|
||||
for_each_set_clump8(offset, bits, tmask, chip->tpin) {
|
||||
for_each_set_clump8(offset, bits, tmask, chip->nport * BANK_SZ) {
|
||||
unsigned int i = offset / 8;
|
||||
|
||||
ret = cy8c95x0_regmap_read_bits(chip, reg, i, bits, &read_val);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#define PIN_NAME_LEN 10
|
||||
#define PAD_REG_OFF 0x100
|
||||
|
||||
static void eqbr_gpio_disable_irq(struct irq_data *d)
|
||||
static void eqbr_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
|
||||
@@ -36,7 +36,7 @@ static void eqbr_gpio_disable_irq(struct irq_data *d)
|
||||
gpiochip_disable_irq(gc, offset);
|
||||
}
|
||||
|
||||
static void eqbr_gpio_enable_irq(struct irq_data *d)
|
||||
static void eqbr_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
|
||||
@@ -50,7 +50,7 @@ static void eqbr_gpio_enable_irq(struct irq_data *d)
|
||||
raw_spin_unlock_irqrestore(&gctrl->lock, flags);
|
||||
}
|
||||
|
||||
static void eqbr_gpio_ack_irq(struct irq_data *d)
|
||||
static void eqbr_irq_ack(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
|
||||
@@ -62,10 +62,17 @@ static void eqbr_gpio_ack_irq(struct irq_data *d)
|
||||
raw_spin_unlock_irqrestore(&gctrl->lock, flags);
|
||||
}
|
||||
|
||||
static void eqbr_gpio_mask_ack_irq(struct irq_data *d)
|
||||
static void eqbr_irq_mask_ack(struct irq_data *d)
|
||||
{
|
||||
eqbr_gpio_disable_irq(d);
|
||||
eqbr_gpio_ack_irq(d);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
|
||||
unsigned int offset = irqd_to_hwirq(d);
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&gctrl->lock, flags);
|
||||
writel(BIT(offset), gctrl->membase + GPIO_IRNENCLR);
|
||||
writel(BIT(offset), gctrl->membase + GPIO_IRNCR);
|
||||
raw_spin_unlock_irqrestore(&gctrl->lock, flags);
|
||||
}
|
||||
|
||||
static inline void eqbr_cfg_bit(void __iomem *addr,
|
||||
@@ -92,7 +99,7 @@ static int eqbr_irq_type_cfg(struct gpio_irq_type *type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eqbr_gpio_set_irq_type(struct irq_data *d, unsigned int type)
|
||||
static int eqbr_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
|
||||
@@ -166,11 +173,11 @@ static void eqbr_irq_handler(struct irq_desc *desc)
|
||||
|
||||
static const struct irq_chip eqbr_irq_chip = {
|
||||
.name = "gpio_irq",
|
||||
.irq_mask = eqbr_gpio_disable_irq,
|
||||
.irq_unmask = eqbr_gpio_enable_irq,
|
||||
.irq_ack = eqbr_gpio_ack_irq,
|
||||
.irq_mask_ack = eqbr_gpio_mask_ack_irq,
|
||||
.irq_set_type = eqbr_gpio_set_irq_type,
|
||||
.irq_ack = eqbr_irq_ack,
|
||||
.irq_mask = eqbr_irq_mask,
|
||||
.irq_mask_ack = eqbr_irq_mask_ack,
|
||||
.irq_unmask = eqbr_irq_unmask,
|
||||
.irq_set_type = eqbr_irq_set_type,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
@@ -3640,14 +3640,10 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
|
||||
* or the gpio driver hasn't probed yet.
|
||||
*/
|
||||
scoped_guard(mutex, &bank->deferred_lock) {
|
||||
if (!gpio || !gpio->direction_output) {
|
||||
rc = rockchip_pinconf_defer_pin(bank,
|
||||
pin - bank->pin_base,
|
||||
param, arg);
|
||||
if (rc)
|
||||
return rc;
|
||||
break;
|
||||
}
|
||||
if (!gpio || !gpio->direction_output)
|
||||
return rockchip_pinconf_defer_pin(bank,
|
||||
pin - bank->pin_base,
|
||||
param, arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1067,6 +1067,7 @@ static const struct msm_pinctrl_soc_data qcs615_tlmm = {
|
||||
.ntiles = ARRAY_SIZE(qcs615_tiles),
|
||||
.wakeirq_map = qcs615_pdc_map,
|
||||
.nwakeirq_map = ARRAY_SIZE(qcs615_pdc_map),
|
||||
.wakeirq_dual_edge_errata = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id qcs615_tlmm_of_match[] = {
|
||||
|
||||
@@ -76,7 +76,7 @@ static const char * const pdm_clk_groups[] = { "gpio18" };
|
||||
static const char * const pdm_rx_groups[] = { "gpio21", "gpio23", "gpio25" };
|
||||
static const char * const pdm_sync_groups[] = { "gpio19" };
|
||||
|
||||
const struct lpi_pingroup sdm660_lpi_pinctrl_groups[] = {
|
||||
static const struct lpi_pingroup sdm660_lpi_pinctrl_groups[] = {
|
||||
LPI_PINGROUP_OFFSET(0, LPI_NO_SLEW, _, _, _, _, 0x0000),
|
||||
LPI_PINGROUP_OFFSET(1, LPI_NO_SLEW, _, _, _, _, 0x1000),
|
||||
LPI_PINGROUP_OFFSET(2, LPI_NO_SLEW, _, _, _, _, 0x2000),
|
||||
@@ -113,7 +113,7 @@ const struct lpi_pingroup sdm660_lpi_pinctrl_groups[] = {
|
||||
LPI_PINGROUP_OFFSET(31, LPI_NO_SLEW, _, _, _, _, 0xb010),
|
||||
};
|
||||
|
||||
const struct lpi_function sdm660_lpi_pinctrl_functions[] = {
|
||||
static const struct lpi_function sdm660_lpi_pinctrl_functions[] = {
|
||||
LPI_FUNCTION(comp_rx),
|
||||
LPI_FUNCTION(dmic1_clk),
|
||||
LPI_FUNCTION(dmic1_data),
|
||||
|
||||
@@ -204,6 +204,32 @@ sunxi_pinctrl_desc_find_function_by_pin(struct sunxi_pinctrl *pctl,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct sunxi_desc_function *
|
||||
sunxi_pinctrl_desc_find_function_by_pin_and_mux(struct sunxi_pinctrl *pctl,
|
||||
const u16 pin_num,
|
||||
const u8 muxval)
|
||||
{
|
||||
for (unsigned int i = 0; i < pctl->desc->npins; i++) {
|
||||
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
|
||||
struct sunxi_desc_function *func = pin->functions;
|
||||
|
||||
if (pin->pin.number != pin_num)
|
||||
continue;
|
||||
|
||||
if (pin->variant && !(pctl->variant & pin->variant))
|
||||
continue;
|
||||
|
||||
while (func->name) {
|
||||
if (func->muxval == muxval)
|
||||
return func;
|
||||
|
||||
func++;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int sunxi_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
||||
@@ -930,6 +956,30 @@ static const struct pinmux_ops sunxi_pmx_ops = {
|
||||
.strict = true,
|
||||
};
|
||||
|
||||
static int sunxi_pinctrl_gpio_get_direction(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
|
||||
const struct sunxi_desc_function *func;
|
||||
u32 pin = offset + chip->base;
|
||||
u32 reg, shift, mask;
|
||||
u8 muxval;
|
||||
|
||||
sunxi_mux_reg(pctl, offset, ®, &shift, &mask);
|
||||
|
||||
muxval = (readl(pctl->membase + reg) & mask) >> shift;
|
||||
|
||||
func = sunxi_pinctrl_desc_find_function_by_pin_and_mux(pctl, pin, muxval);
|
||||
if (!func)
|
||||
return -ENODEV;
|
||||
|
||||
if (!strcmp(func->name, "gpio_out"))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
if (!strcmp(func->name, "gpio_in") || !strcmp(func->name, "irq"))
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
{
|
||||
@@ -1599,6 +1649,7 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev,
|
||||
pctl->chip->request = gpiochip_generic_request;
|
||||
pctl->chip->free = gpiochip_generic_free;
|
||||
pctl->chip->set_config = gpiochip_generic_config;
|
||||
pctl->chip->get_direction = sunxi_pinctrl_gpio_get_direction;
|
||||
pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input;
|
||||
pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output;
|
||||
pctl->chip->get = sunxi_pinctrl_gpio_get;
|
||||
|
||||
@@ -3340,7 +3340,6 @@ again:
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out_put;
|
||||
}
|
||||
WARN_ON(ret);
|
||||
|
||||
/* We've already setup this transaction, go ahead and exit */
|
||||
if (block_group->cache_generation == trans->transid &&
|
||||
|
||||
@@ -1657,7 +1657,7 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
|
||||
if (unlikely(ret)) {
|
||||
btrfs_err(trans->fs_info,
|
||||
"failed to add delayed dir index item, root: %llu, inode: %llu, index: %llu, error: %d",
|
||||
index, btrfs_root_id(node->root), node->inode_id, ret);
|
||||
btrfs_root_id(node->root), node->inode_id, index, ret);
|
||||
btrfs_delayed_item_release_metadata(dir->root, item);
|
||||
btrfs_release_delayed_item(item);
|
||||
}
|
||||
|
||||
+21
-15
@@ -1994,7 +1994,7 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
|
||||
int level = btrfs_super_log_root_level(disk_super);
|
||||
|
||||
if (unlikely(fs_devices->rw_devices == 0)) {
|
||||
btrfs_warn(fs_info, "log replay required on RO media");
|
||||
btrfs_err(fs_info, "log replay required on RO media");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -2008,9 +2008,9 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
|
||||
check.owner_root = BTRFS_TREE_LOG_OBJECTID;
|
||||
log_tree_root->node = read_tree_block(fs_info, bytenr, &check);
|
||||
if (IS_ERR(log_tree_root->node)) {
|
||||
btrfs_warn(fs_info, "failed to read log tree");
|
||||
ret = PTR_ERR(log_tree_root->node);
|
||||
log_tree_root->node = NULL;
|
||||
btrfs_err(fs_info, "failed to read log tree with error: %d", ret);
|
||||
btrfs_put_root(log_tree_root);
|
||||
return ret;
|
||||
}
|
||||
@@ -2023,9 +2023,9 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
|
||||
/* returns with log_tree_root freed on success */
|
||||
ret = btrfs_recover_log_trees(log_tree_root);
|
||||
btrfs_put_root(log_tree_root);
|
||||
if (ret) {
|
||||
btrfs_handle_fs_error(fs_info, ret,
|
||||
"Failed to recover log tree");
|
||||
if (unlikely(ret)) {
|
||||
ASSERT(BTRFS_FS_ERROR(fs_info) != 0);
|
||||
btrfs_err(fs_info, "failed to recover log trees with error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2972,7 +2972,6 @@ static int btrfs_check_uuid_tree(struct btrfs_fs_info *fs_info)
|
||||
task = kthread_run(btrfs_uuid_rescan_kthread, fs_info, "btrfs-uuid");
|
||||
if (IS_ERR(task)) {
|
||||
/* fs_info->update_uuid_tree_gen remains 0 in all error case */
|
||||
btrfs_warn(fs_info, "failed to start uuid_rescan task");
|
||||
up(&fs_info->uuid_tree_rescan_sem);
|
||||
return PTR_ERR(task);
|
||||
}
|
||||
@@ -3188,7 +3187,7 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)
|
||||
if (incompat & ~BTRFS_FEATURE_INCOMPAT_SUPP) {
|
||||
btrfs_err(fs_info,
|
||||
"cannot mount because of unknown incompat features (0x%llx)",
|
||||
incompat);
|
||||
incompat & ~BTRFS_FEATURE_INCOMPAT_SUPP);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -3220,7 +3219,7 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)
|
||||
if (compat_ro_unsupp && is_rw_mount) {
|
||||
btrfs_err(fs_info,
|
||||
"cannot mount read-write because of unknown compat_ro features (0x%llx)",
|
||||
compat_ro);
|
||||
compat_ro_unsupp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -3233,7 +3232,7 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)
|
||||
!btrfs_test_opt(fs_info, NOLOGREPLAY)) {
|
||||
btrfs_err(fs_info,
|
||||
"cannot replay dirty log with unsupported compat_ro features (0x%llx), try rescue=nologreplay",
|
||||
compat_ro);
|
||||
compat_ro_unsupp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -3642,7 +3641,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
|
||||
fs_info->fs_root = btrfs_get_fs_root(fs_info, BTRFS_FS_TREE_OBJECTID, true);
|
||||
if (IS_ERR(fs_info->fs_root)) {
|
||||
ret = PTR_ERR(fs_info->fs_root);
|
||||
btrfs_warn(fs_info, "failed to read fs tree: %d", ret);
|
||||
btrfs_err(fs_info, "failed to read fs tree: %d", ret);
|
||||
fs_info->fs_root = NULL;
|
||||
goto fail_qgroup;
|
||||
}
|
||||
@@ -3663,8 +3662,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
|
||||
btrfs_info(fs_info, "checking UUID tree");
|
||||
ret = btrfs_check_uuid_tree(fs_info);
|
||||
if (ret) {
|
||||
btrfs_warn(fs_info,
|
||||
"failed to check the UUID tree: %d", ret);
|
||||
btrfs_err(fs_info, "failed to check the UUID tree: %d", ret);
|
||||
close_ctree(fs_info);
|
||||
return ret;
|
||||
}
|
||||
@@ -4399,9 +4397,17 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
|
||||
*/
|
||||
btrfs_flush_workqueue(fs_info->delayed_workers);
|
||||
|
||||
ret = btrfs_commit_super(fs_info);
|
||||
if (ret)
|
||||
btrfs_err(fs_info, "commit super ret %d", ret);
|
||||
/*
|
||||
* If the filesystem is shutdown, then an attempt to commit the
|
||||
* super block (or any write) will just fail. Since we freeze
|
||||
* the filesystem before shutting it down, the filesystem is in
|
||||
* a consistent state and we don't need to commit super blocks.
|
||||
*/
|
||||
if (!btrfs_is_shutdown(fs_info)) {
|
||||
ret = btrfs_commit_super(fs_info);
|
||||
if (ret)
|
||||
btrfs_err(fs_info, "commit super block returned %d", ret);
|
||||
}
|
||||
}
|
||||
|
||||
kthread_stop(fs_info->transaction_kthread);
|
||||
|
||||
@@ -2933,9 +2933,15 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
|
||||
while (!TRANS_ABORTED(trans) && cached_state) {
|
||||
struct extent_state *next_state;
|
||||
|
||||
if (btrfs_test_opt(fs_info, DISCARD_SYNC))
|
||||
if (btrfs_test_opt(fs_info, DISCARD_SYNC)) {
|
||||
ret = btrfs_discard_extent(fs_info, start,
|
||||
end + 1 - start, NULL, true);
|
||||
if (ret) {
|
||||
btrfs_warn(fs_info,
|
||||
"discard failed for extent [%llu, %llu]: errno=%d %s",
|
||||
start, end, ret, btrfs_decode_error(ret));
|
||||
}
|
||||
}
|
||||
|
||||
next_state = btrfs_next_extent_state(unpin, cached_state);
|
||||
btrfs_clear_extent_dirty(unpin, start, end, &cached_state);
|
||||
|
||||
+17
-2
@@ -1392,10 +1392,25 @@ static int cow_one_range(struct btrfs_inode *inode, struct folio *locked_folio,
|
||||
return ret;
|
||||
|
||||
free_reserved:
|
||||
/*
|
||||
* If we have reserved an extent for the current range and failed to
|
||||
* create the respective extent map or ordered extent, it means that
|
||||
* when we reserved the extent we decremented the extent's size from
|
||||
* the data space_info's bytes_may_use counter and
|
||||
* incremented the space_info's bytes_reserved counter by the same
|
||||
* amount.
|
||||
*
|
||||
* We must make sure extent_clear_unlock_delalloc() does not try
|
||||
* to decrement again the data space_info's bytes_may_use counter, which
|
||||
* will be handled by btrfs_free_reserved_extent().
|
||||
*
|
||||
* Therefore we do not pass it the flag EXTENT_CLEAR_DATA_RESV, but only
|
||||
* EXTENT_CLEAR_META_RESV.
|
||||
*/
|
||||
extent_clear_unlock_delalloc(inode, file_offset, cur_end, locked_folio, cached,
|
||||
EXTENT_LOCKED | EXTENT_DELALLOC |
|
||||
EXTENT_DELALLOC_NEW |
|
||||
EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING,
|
||||
EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV,
|
||||
PAGE_UNLOCK | PAGE_START_WRITEBACK |
|
||||
PAGE_END_WRITEBACK);
|
||||
btrfs_qgroup_free_data(inode, NULL, file_offset, cur_len, NULL);
|
||||
@@ -4764,7 +4779,7 @@ int btrfs_delete_subvolume(struct btrfs_inode *dir, struct dentry *dentry)
|
||||
spin_unlock(&dest->root_item_lock);
|
||||
btrfs_warn(fs_info,
|
||||
"attempt to delete subvolume %llu with active swapfile",
|
||||
btrfs_root_id(root));
|
||||
btrfs_root_id(dest));
|
||||
ret = -EPERM;
|
||||
goto out_up_write;
|
||||
}
|
||||
|
||||
+6
-1
@@ -4581,7 +4581,7 @@ static int btrfs_uring_read_extent(struct kiocb *iocb, struct iov_iter *iter,
|
||||
{
|
||||
struct btrfs_inode *inode = BTRFS_I(file_inode(iocb->ki_filp));
|
||||
struct extent_io_tree *io_tree = &inode->io_tree;
|
||||
struct page **pages;
|
||||
struct page **pages = NULL;
|
||||
struct btrfs_uring_priv *priv = NULL;
|
||||
unsigned long nr_pages;
|
||||
int ret;
|
||||
@@ -4639,6 +4639,11 @@ out_fail:
|
||||
btrfs_unlock_extent(io_tree, start, lockend, &cached_state);
|
||||
btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
|
||||
kfree(priv);
|
||||
for (int i = 0; i < nr_pages; i++) {
|
||||
if (pages[i])
|
||||
__free_page(pages[i]);
|
||||
}
|
||||
kfree(pages);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -370,7 +370,7 @@ static bool squota_check_parent_usage(struct btrfs_fs_info *fs_info, struct btrf
|
||||
nr_members++;
|
||||
}
|
||||
mismatch = (parent->excl != excl_sum || parent->rfer != rfer_sum ||
|
||||
parent->excl_cmpr != excl_cmpr_sum || parent->rfer_cmpr != excl_cmpr_sum);
|
||||
parent->excl_cmpr != excl_cmpr_sum || parent->rfer_cmpr != rfer_cmpr_sum);
|
||||
|
||||
WARN(mismatch,
|
||||
"parent squota qgroup %hu/%llu has mismatched usage from its %d members. "
|
||||
|
||||
@@ -4723,6 +4723,7 @@ int btrfs_last_identity_remap_gone(struct btrfs_chunk_map *chunk_map,
|
||||
ret = btrfs_remove_dev_extents(trans, chunk_map);
|
||||
if (unlikely(ret)) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
btrfs_end_transaction(trans);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -4732,6 +4733,7 @@ int btrfs_last_identity_remap_gone(struct btrfs_chunk_map *chunk_map,
|
||||
if (unlikely(ret)) {
|
||||
mutex_unlock(&trans->fs_info->chunk_mutex);
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
btrfs_end_transaction(trans);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -4750,6 +4752,7 @@ int btrfs_last_identity_remap_gone(struct btrfs_chunk_map *chunk_map,
|
||||
ret = remove_chunk_stripes(trans, chunk_map, path);
|
||||
if (unlikely(ret)) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
btrfs_end_transaction(trans);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -5982,6 +5985,9 @@ static int remove_range_from_remap_tree(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_block_group *dest_bg;
|
||||
|
||||
dest_bg = btrfs_lookup_block_group(fs_info, new_addr);
|
||||
if (unlikely(!dest_bg))
|
||||
return -EUCLEAN;
|
||||
|
||||
adjust_block_group_remap_bytes(trans, dest_bg, -overlap_length);
|
||||
btrfs_put_block_group(dest_bg);
|
||||
ret = btrfs_add_to_free_space_tree(trans,
|
||||
|
||||
+1
-1
@@ -743,7 +743,7 @@ static void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr
|
||||
btrfs_warn_rl(fs_info,
|
||||
"scrub: tree block %llu mirror %u has bad fsid, has %pU want %pU",
|
||||
logical, stripe->mirror_num,
|
||||
header->fsid, fs_info->fs_devices->fsid);
|
||||
header->fsid, fs_info->fs_devices->metadata_uuid);
|
||||
return;
|
||||
}
|
||||
if (memcmp(header->chunk_tree_uuid, fs_info->chunk_tree_uuid,
|
||||
|
||||
@@ -1740,7 +1740,7 @@ static int check_extent_data_ref(struct extent_buffer *leaf,
|
||||
objectid > BTRFS_LAST_FREE_OBJECTID)) {
|
||||
extent_err(leaf, slot,
|
||||
"invalid extent data backref objectid value %llu",
|
||||
root);
|
||||
objectid);
|
||||
return -EUCLEAN;
|
||||
}
|
||||
if (unlikely(!IS_ALIGNED(offset, leaf->fs_info->sectorsize))) {
|
||||
@@ -1921,7 +1921,7 @@ static int check_dev_extent_item(const struct extent_buffer *leaf,
|
||||
if (unlikely(prev_key->offset + prev_len > key->offset)) {
|
||||
generic_err(leaf, slot,
|
||||
"dev extent overlap, prev offset %llu len %llu current offset %llu",
|
||||
prev_key->objectid, prev_len, key->offset);
|
||||
prev_key->offset, prev_len, key->offset);
|
||||
return -EUCLEAN;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -6907,7 +6907,7 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
|
||||
|
||||
ret = btrfs_translate_remap(fs_info, &new_logical, length);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
if (new_logical != logical) {
|
||||
btrfs_free_chunk_map(map);
|
||||
@@ -6921,8 +6921,10 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
|
||||
}
|
||||
|
||||
num_copies = btrfs_chunk_map_num_copies(map);
|
||||
if (io_geom.mirror_num > num_copies)
|
||||
return -EINVAL;
|
||||
if (io_geom.mirror_num > num_copies) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
map_offset = logical - map->start;
|
||||
io_geom.raid56_full_stripe_start = (u64)-1;
|
||||
|
||||
+11
-11
@@ -377,15 +377,15 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
|
||||
}
|
||||
|
||||
/*
|
||||
* write_threads - Start NFSD, or report the current number of running threads
|
||||
* write_threads - Start NFSD, or report the configured number of threads
|
||||
*
|
||||
* Input:
|
||||
* buf: ignored
|
||||
* size: zero
|
||||
* Output:
|
||||
* On success: passed-in buffer filled with '\n'-terminated C
|
||||
* string numeric value representing the number of
|
||||
* running NFSD threads;
|
||||
* string numeric value representing the configured
|
||||
* number of NFSD threads;
|
||||
* return code is the size in bytes of the string
|
||||
* On error: return code is zero
|
||||
*
|
||||
@@ -399,8 +399,8 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
|
||||
* Output:
|
||||
* On success: NFS service is started;
|
||||
* passed-in buffer filled with '\n'-terminated C
|
||||
* string numeric value representing the number of
|
||||
* running NFSD threads;
|
||||
* string numeric value representing the configured
|
||||
* number of NFSD threads;
|
||||
* return code is the size in bytes of the string
|
||||
* On error: return code is zero or a negative errno value
|
||||
*/
|
||||
@@ -430,7 +430,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
|
||||
}
|
||||
|
||||
/*
|
||||
* write_pool_threads - Set or report the current number of threads per pool
|
||||
* write_pool_threads - Set or report the configured number of threads per pool
|
||||
*
|
||||
* Input:
|
||||
* buf: ignored
|
||||
@@ -447,7 +447,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
|
||||
* Output:
|
||||
* On success: passed-in buffer filled with '\n'-terminated C
|
||||
* string containing integer values representing the
|
||||
* number of NFSD threads in each pool;
|
||||
* configured number of NFSD threads in each pool;
|
||||
* return code is the size in bytes of the string
|
||||
* On error: return code is zero or a negative errno value
|
||||
*/
|
||||
@@ -1647,7 +1647,7 @@ int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
if (attr)
|
||||
nn->min_threads = nla_get_u32(attr);
|
||||
|
||||
ret = nfsd_svc(nrpools, nthreads, net, get_current_cred(), scope);
|
||||
ret = nfsd_svc(nrpools, nthreads, net, current_cred(), scope);
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
out_unlock:
|
||||
@@ -1657,7 +1657,7 @@ out_unlock:
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_nl_threads_get_doit - get the number of running threads
|
||||
* nfsd_nl_threads_get_doit - get the maximum number of running threads
|
||||
* @skb: reply buffer
|
||||
* @info: netlink metadata and command arguments
|
||||
*
|
||||
@@ -1700,7 +1700,7 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
struct svc_pool *sp = &nn->nfsd_serv->sv_pools[i];
|
||||
|
||||
err = nla_put_u32(skb, NFSD_A_SERVER_THREADS,
|
||||
sp->sp_nrthreads);
|
||||
sp->sp_nrthrmax);
|
||||
if (err)
|
||||
goto err_unlock;
|
||||
}
|
||||
@@ -2000,7 +2000,7 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
}
|
||||
|
||||
ret = svc_xprt_create_from_sa(serv, xcl_name, net, sa, 0,
|
||||
get_current_cred());
|
||||
current_cred());
|
||||
/* always save the latest error */
|
||||
if (ret < 0)
|
||||
err = ret;
|
||||
|
||||
+4
-3
@@ -239,12 +239,13 @@ static void nfsd_net_free(struct percpu_ref *ref)
|
||||
|
||||
int nfsd_nrthreads(struct net *net)
|
||||
{
|
||||
int rv = 0;
|
||||
int i, rv = 0;
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
if (nn->nfsd_serv)
|
||||
rv = nn->nfsd_serv->sv_nrthreads;
|
||||
for (i = 0; i < nn->nfsd_serv->sv_nrpools; ++i)
|
||||
rv += nn->nfsd_serv->sv_pools[i].sp_nrthrmax;
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
return rv;
|
||||
}
|
||||
@@ -659,7 +660,7 @@ int nfsd_get_nrthreads(int n, int *nthreads, struct net *net)
|
||||
|
||||
if (serv)
|
||||
for (i = 0; i < serv->sv_nrpools && i < n; i++)
|
||||
nthreads[i] = serv->sv_pools[i].sp_nrthreads;
|
||||
nthreads[i] = serv->sv_pools[i].sp_nrthrmax;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+20
-34
@@ -647,36 +647,22 @@ static inline void user_access_restore(unsigned long flags) { }
|
||||
/* Define RW variant so the below _mode macro expansion works */
|
||||
#define masked_user_rw_access_begin(u) masked_user_access_begin(u)
|
||||
#define user_rw_access_begin(u, s) user_access_begin(u, s)
|
||||
#define user_rw_access_end() user_access_end()
|
||||
|
||||
/* Scoped user access */
|
||||
#define USER_ACCESS_GUARD(_mode) \
|
||||
static __always_inline void __user * \
|
||||
class_user_##_mode##_begin(void __user *ptr) \
|
||||
{ \
|
||||
return ptr; \
|
||||
} \
|
||||
\
|
||||
static __always_inline void \
|
||||
class_user_##_mode##_end(void __user *ptr) \
|
||||
{ \
|
||||
user_##_mode##_access_end(); \
|
||||
} \
|
||||
\
|
||||
DEFINE_CLASS(user_ ##_mode## _access, void __user *, \
|
||||
class_user_##_mode##_end(_T), \
|
||||
class_user_##_mode##_begin(ptr), void __user *ptr) \
|
||||
\
|
||||
static __always_inline class_user_##_mode##_access_t \
|
||||
class_user_##_mode##_access_ptr(void __user *scope) \
|
||||
{ \
|
||||
return scope; \
|
||||
}
|
||||
|
||||
USER_ACCESS_GUARD(read)
|
||||
USER_ACCESS_GUARD(write)
|
||||
USER_ACCESS_GUARD(rw)
|
||||
#undef USER_ACCESS_GUARD
|
||||
/* Cleanup wrapper functions */
|
||||
static __always_inline void __scoped_user_read_access_end(const void *p)
|
||||
{
|
||||
user_read_access_end();
|
||||
};
|
||||
static __always_inline void __scoped_user_write_access_end(const void *p)
|
||||
{
|
||||
user_write_access_end();
|
||||
};
|
||||
static __always_inline void __scoped_user_rw_access_end(const void *p)
|
||||
{
|
||||
user_access_end();
|
||||
};
|
||||
|
||||
/**
|
||||
* __scoped_user_access_begin - Start a scoped user access
|
||||
@@ -750,13 +736,13 @@ USER_ACCESS_GUARD(rw)
|
||||
*
|
||||
* Don't use directly. Use scoped_masked_user_$MODE_access() instead.
|
||||
*/
|
||||
#define __scoped_user_access(mode, uptr, size, elbl) \
|
||||
for (bool done = false; !done; done = true) \
|
||||
for (void __user *_tmpptr = __scoped_user_access_begin(mode, uptr, size, elbl); \
|
||||
!done; done = true) \
|
||||
for (CLASS(user_##mode##_access, scope)(_tmpptr); !done; done = true) \
|
||||
/* Force modified pointer usage within the scope */ \
|
||||
for (const typeof(uptr) uptr = _tmpptr; !done; done = true)
|
||||
#define __scoped_user_access(mode, uptr, size, elbl) \
|
||||
for (bool done = false; !done; done = true) \
|
||||
for (auto _tmpptr = __scoped_user_access_begin(mode, uptr, size, elbl); \
|
||||
!done; done = true) \
|
||||
/* Force modified pointer usage within the scope */ \
|
||||
for (const auto uptr __cleanup(__scoped_user_##mode##_access_end) = \
|
||||
_tmpptr; !done; done = true)
|
||||
|
||||
/**
|
||||
* scoped_user_read_access_size - Start a scoped user read access with given size
|
||||
|
||||
@@ -2611,6 +2611,7 @@ static void cgroup_migrate_add_task(struct task_struct *task,
|
||||
|
||||
mgctx->tset.nr_tasks++;
|
||||
|
||||
css_set_skip_task_iters(cset, task);
|
||||
list_move_tail(&task->cg_list, &cset->mg_tasks);
|
||||
if (list_empty(&cset->mg_node))
|
||||
list_add_tail(&cset->mg_node,
|
||||
|
||||
+149
-73
@@ -61,6 +61,75 @@ static const char * const perr_strings[] = {
|
||||
[PERR_REMOTE] = "Have remote partition underneath",
|
||||
};
|
||||
|
||||
/*
|
||||
* CPUSET Locking Convention
|
||||
* -------------------------
|
||||
*
|
||||
* Below are the four global/local locks guarding cpuset structures in lock
|
||||
* acquisition order:
|
||||
* - cpuset_top_mutex
|
||||
* - cpu_hotplug_lock (cpus_read_lock/cpus_write_lock)
|
||||
* - cpuset_mutex
|
||||
* - callback_lock (raw spinlock)
|
||||
*
|
||||
* As cpuset will now indirectly flush a number of different workqueues in
|
||||
* housekeeping_update() to update housekeeping cpumasks when the set of
|
||||
* isolated CPUs is going to be changed, it may be vulnerable to deadlock
|
||||
* if we hold cpus_read_lock while calling into housekeeping_update().
|
||||
*
|
||||
* The first cpuset_top_mutex will be held except when calling into
|
||||
* cpuset_handle_hotplug() from the CPU hotplug code where cpus_write_lock
|
||||
* and cpuset_mutex will be held instead. The main purpose of this mutex
|
||||
* is to prevent regular cpuset control file write actions from interfering
|
||||
* with the call to housekeeping_update(), though CPU hotplug operation can
|
||||
* still happen in parallel. This mutex also provides protection for some
|
||||
* internal variables.
|
||||
*
|
||||
* A task must hold all the remaining three locks to modify externally visible
|
||||
* or used fields of cpusets, though some of the internally used cpuset fields
|
||||
* and internal variables can be modified without holding callback_lock. If only
|
||||
* reliable read access of the externally used fields are needed, a task can
|
||||
* hold either cpuset_mutex or callback_lock which are exposed to other
|
||||
* external subsystems.
|
||||
*
|
||||
* If a task holds cpu_hotplug_lock and cpuset_mutex, it blocks others,
|
||||
* ensuring that it is the only task able to also acquire callback_lock and
|
||||
* be able to modify cpusets. It can perform various checks on the cpuset
|
||||
* structure first, knowing nothing will change. It can also allocate memory
|
||||
* without holding callback_lock. While it is performing these checks, various
|
||||
* callback routines can briefly acquire callback_lock to query cpusets. Once
|
||||
* it is ready to make the changes, it takes callback_lock, blocking everyone
|
||||
* else.
|
||||
*
|
||||
* Calls to the kernel memory allocator cannot be made while holding
|
||||
* callback_lock which is a spinlock, as the memory allocator may sleep or
|
||||
* call back into cpuset code and acquire callback_lock.
|
||||
*
|
||||
* Now, the task_struct fields mems_allowed and mempolicy may be changed
|
||||
* by other task, we use alloc_lock in the task_struct fields to protect
|
||||
* them.
|
||||
*
|
||||
* The cpuset_common_seq_show() handlers only hold callback_lock across
|
||||
* small pieces of code, such as when reading out possibly multi-word
|
||||
* cpumasks and nodemasks.
|
||||
*/
|
||||
|
||||
static DEFINE_MUTEX(cpuset_top_mutex);
|
||||
static DEFINE_MUTEX(cpuset_mutex);
|
||||
|
||||
/*
|
||||
* File level internal variables below follow one of the following exclusion
|
||||
* rules.
|
||||
*
|
||||
* RWCS: Read/write-able by holding either cpus_write_lock (and optionally
|
||||
* cpuset_mutex) or both cpus_read_lock and cpuset_mutex.
|
||||
*
|
||||
* CSCB: Readable by holding either cpuset_mutex or callback_lock. Writable
|
||||
* by holding both cpuset_mutex and callback_lock.
|
||||
*
|
||||
* T: Read/write-able by holding the cpuset_top_mutex.
|
||||
*/
|
||||
|
||||
/*
|
||||
* For local partitions, update to subpartitions_cpus & isolated_cpus is done
|
||||
* in update_parent_effective_cpumask(). For remote partitions, it is done in
|
||||
@@ -70,19 +139,22 @@ static const char * const perr_strings[] = {
|
||||
* Exclusive CPUs distributed out to local or remote sub-partitions of
|
||||
* top_cpuset
|
||||
*/
|
||||
static cpumask_var_t subpartitions_cpus;
|
||||
static cpumask_var_t subpartitions_cpus; /* RWCS */
|
||||
|
||||
/*
|
||||
* Exclusive CPUs in isolated partitions
|
||||
* Exclusive CPUs in isolated partitions (shown in cpuset.cpus.isolated)
|
||||
*/
|
||||
static cpumask_var_t isolated_cpus;
|
||||
static cpumask_var_t isolated_cpus; /* CSCB */
|
||||
|
||||
/*
|
||||
* isolated_cpus updating flag (protected by cpuset_mutex)
|
||||
* Set if isolated_cpus is going to be updated in the current
|
||||
* cpuset_mutex crtical section.
|
||||
* Set if housekeeping cpumasks are to be updated.
|
||||
*/
|
||||
static bool isolated_cpus_updating;
|
||||
static bool update_housekeeping; /* RWCS */
|
||||
|
||||
/*
|
||||
* Copy of isolated_cpus to be passed to housekeeping_update()
|
||||
*/
|
||||
static cpumask_var_t isolated_hk_cpus; /* T */
|
||||
|
||||
/*
|
||||
* A flag to force sched domain rebuild at the end of an operation.
|
||||
@@ -98,7 +170,7 @@ static bool isolated_cpus_updating;
|
||||
* Note that update_relax_domain_level() in cpuset-v1.c can still call
|
||||
* rebuild_sched_domains_locked() directly without using this flag.
|
||||
*/
|
||||
static bool force_sd_rebuild;
|
||||
static bool force_sd_rebuild; /* RWCS */
|
||||
|
||||
/*
|
||||
* Partition root states:
|
||||
@@ -218,42 +290,6 @@ struct cpuset top_cpuset = {
|
||||
.partition_root_state = PRS_ROOT,
|
||||
};
|
||||
|
||||
/*
|
||||
* There are two global locks guarding cpuset structures - cpuset_mutex and
|
||||
* callback_lock. The cpuset code uses only cpuset_mutex. Other kernel
|
||||
* subsystems can use cpuset_lock()/cpuset_unlock() to prevent change to cpuset
|
||||
* structures. Note that cpuset_mutex needs to be a mutex as it is used in
|
||||
* paths that rely on priority inheritance (e.g. scheduler - on RT) for
|
||||
* correctness.
|
||||
*
|
||||
* A task must hold both locks to modify cpusets. If a task holds
|
||||
* cpuset_mutex, it blocks others, ensuring that it is the only task able to
|
||||
* also acquire callback_lock and be able to modify cpusets. It can perform
|
||||
* various checks on the cpuset structure first, knowing nothing will change.
|
||||
* It can also allocate memory while just holding cpuset_mutex. While it is
|
||||
* performing these checks, various callback routines can briefly acquire
|
||||
* callback_lock to query cpusets. Once it is ready to make the changes, it
|
||||
* takes callback_lock, blocking everyone else.
|
||||
*
|
||||
* Calls to the kernel memory allocator can not be made while holding
|
||||
* callback_lock, as that would risk double tripping on callback_lock
|
||||
* from one of the callbacks into the cpuset code from within
|
||||
* __alloc_pages().
|
||||
*
|
||||
* If a task is only holding callback_lock, then it has read-only
|
||||
* access to cpusets.
|
||||
*
|
||||
* Now, the task_struct fields mems_allowed and mempolicy may be changed
|
||||
* by other task, we use alloc_lock in the task_struct fields to protect
|
||||
* them.
|
||||
*
|
||||
* The cpuset_common_seq_show() handlers only hold callback_lock across
|
||||
* small pieces of code, such as when reading out possibly multi-word
|
||||
* cpumasks and nodemasks.
|
||||
*/
|
||||
|
||||
static DEFINE_MUTEX(cpuset_mutex);
|
||||
|
||||
/**
|
||||
* cpuset_lock - Acquire the global cpuset mutex
|
||||
*
|
||||
@@ -283,6 +319,7 @@ void lockdep_assert_cpuset_lock_held(void)
|
||||
*/
|
||||
void cpuset_full_lock(void)
|
||||
{
|
||||
mutex_lock(&cpuset_top_mutex);
|
||||
cpus_read_lock();
|
||||
mutex_lock(&cpuset_mutex);
|
||||
}
|
||||
@@ -291,12 +328,14 @@ void cpuset_full_unlock(void)
|
||||
{
|
||||
mutex_unlock(&cpuset_mutex);
|
||||
cpus_read_unlock();
|
||||
mutex_unlock(&cpuset_top_mutex);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
bool lockdep_is_cpuset_held(void)
|
||||
{
|
||||
return lockdep_is_held(&cpuset_mutex);
|
||||
return lockdep_is_held(&cpuset_mutex) ||
|
||||
lockdep_is_held(&cpuset_top_mutex);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -961,7 +1000,7 @@ void rebuild_sched_domains_locked(void)
|
||||
* offline CPUs, a warning is emitted and we return directly to
|
||||
* prevent the panic.
|
||||
*/
|
||||
for (i = 0; i < ndoms; ++i) {
|
||||
for (i = 0; doms && i < ndoms; i++) {
|
||||
if (WARN_ON_ONCE(!cpumask_subset(doms[i], cpu_active_mask)))
|
||||
return;
|
||||
}
|
||||
@@ -1162,12 +1201,18 @@ static void reset_partition_data(struct cpuset *cs)
|
||||
static void isolated_cpus_update(int old_prs, int new_prs, struct cpumask *xcpus)
|
||||
{
|
||||
WARN_ON_ONCE(old_prs == new_prs);
|
||||
if (new_prs == PRS_ISOLATED)
|
||||
lockdep_assert_held(&callback_lock);
|
||||
lockdep_assert_held(&cpuset_mutex);
|
||||
if (new_prs == PRS_ISOLATED) {
|
||||
if (cpumask_subset(xcpus, isolated_cpus))
|
||||
return;
|
||||
cpumask_or(isolated_cpus, isolated_cpus, xcpus);
|
||||
else
|
||||
} else {
|
||||
if (!cpumask_intersects(xcpus, isolated_cpus))
|
||||
return;
|
||||
cpumask_andnot(isolated_cpus, isolated_cpus, xcpus);
|
||||
|
||||
isolated_cpus_updating = true;
|
||||
}
|
||||
update_housekeeping = true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1220,8 +1265,8 @@ static void partition_xcpus_del(int old_prs, struct cpuset *parent,
|
||||
isolated_cpus_update(old_prs, parent->partition_root_state,
|
||||
xcpus);
|
||||
|
||||
cpumask_and(xcpus, xcpus, cpu_active_mask);
|
||||
cpumask_or(parent->effective_cpus, parent->effective_cpus, xcpus);
|
||||
cpumask_and(parent->effective_cpus, parent->effective_cpus, cpu_active_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1285,22 +1330,43 @@ static bool prstate_housekeeping_conflict(int prstate, struct cpumask *new_cpus)
|
||||
}
|
||||
|
||||
/*
|
||||
* update_isolation_cpumasks - Update external isolation related CPU masks
|
||||
* update_hk_sched_domains - Update HK cpumasks & rebuild sched domains
|
||||
*
|
||||
* The following external CPU masks will be updated if necessary:
|
||||
* - workqueue unbound cpumask
|
||||
* Update housekeeping cpumasks and rebuild sched domains if necessary.
|
||||
* This should be called at the end of cpuset or hotplug actions.
|
||||
*/
|
||||
static void update_isolation_cpumasks(void)
|
||||
static void update_hk_sched_domains(void)
|
||||
{
|
||||
int ret;
|
||||
if (update_housekeeping) {
|
||||
/* Updating HK cpumasks implies rebuild sched domains */
|
||||
update_housekeeping = false;
|
||||
force_sd_rebuild = true;
|
||||
cpumask_copy(isolated_hk_cpus, isolated_cpus);
|
||||
|
||||
if (!isolated_cpus_updating)
|
||||
return;
|
||||
/*
|
||||
* housekeeping_update() is now called without holding
|
||||
* cpus_read_lock and cpuset_mutex. Only cpuset_top_mutex
|
||||
* is still being held for mutual exclusion.
|
||||
*/
|
||||
mutex_unlock(&cpuset_mutex);
|
||||
cpus_read_unlock();
|
||||
WARN_ON_ONCE(housekeeping_update(isolated_hk_cpus));
|
||||
cpus_read_lock();
|
||||
mutex_lock(&cpuset_mutex);
|
||||
}
|
||||
/* force_sd_rebuild will be cleared in rebuild_sched_domains_locked() */
|
||||
if (force_sd_rebuild)
|
||||
rebuild_sched_domains_locked();
|
||||
}
|
||||
|
||||
ret = housekeeping_update(isolated_cpus);
|
||||
WARN_ON_ONCE(ret < 0);
|
||||
|
||||
isolated_cpus_updating = false;
|
||||
/*
|
||||
* Work function to invoke update_hk_sched_domains()
|
||||
*/
|
||||
static void hk_sd_workfn(struct work_struct *work)
|
||||
{
|
||||
cpuset_full_lock();
|
||||
update_hk_sched_domains();
|
||||
cpuset_full_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1451,7 +1517,6 @@ static int remote_partition_enable(struct cpuset *cs, int new_prs,
|
||||
cs->remote_partition = true;
|
||||
cpumask_copy(cs->effective_xcpus, tmp->new_cpus);
|
||||
spin_unlock_irq(&callback_lock);
|
||||
update_isolation_cpumasks();
|
||||
cpuset_force_rebuild();
|
||||
cs->prs_err = 0;
|
||||
|
||||
@@ -1496,7 +1561,6 @@ static void remote_partition_disable(struct cpuset *cs, struct tmpmasks *tmp)
|
||||
compute_excpus(cs, cs->effective_xcpus);
|
||||
reset_partition_data(cs);
|
||||
spin_unlock_irq(&callback_lock);
|
||||
update_isolation_cpumasks();
|
||||
cpuset_force_rebuild();
|
||||
|
||||
/*
|
||||
@@ -1567,7 +1631,6 @@ static void remote_cpus_update(struct cpuset *cs, struct cpumask *xcpus,
|
||||
if (xcpus)
|
||||
cpumask_copy(cs->exclusive_cpus, xcpus);
|
||||
spin_unlock_irq(&callback_lock);
|
||||
update_isolation_cpumasks();
|
||||
if (adding || deleting)
|
||||
cpuset_force_rebuild();
|
||||
|
||||
@@ -1911,7 +1974,6 @@ write_error:
|
||||
partition_xcpus_add(new_prs, parent, tmp->delmask);
|
||||
|
||||
spin_unlock_irq(&callback_lock);
|
||||
update_isolation_cpumasks();
|
||||
|
||||
if ((old_prs != new_prs) && (cmd == partcmd_update))
|
||||
update_partition_exclusive_flag(cs, new_prs);
|
||||
@@ -2156,7 +2218,7 @@ get_css:
|
||||
WARN_ON(!is_in_v2_mode() &&
|
||||
!cpumask_equal(cp->cpus_allowed, cp->effective_cpus));
|
||||
|
||||
cpuset_update_tasks_cpumask(cp, cp->effective_cpus);
|
||||
cpuset_update_tasks_cpumask(cp, tmp->new_cpus);
|
||||
|
||||
/*
|
||||
* On default hierarchy, inherit the CS_SCHED_LOAD_BALANCE
|
||||
@@ -2879,7 +2941,6 @@ out:
|
||||
else if (isolcpus_updated)
|
||||
isolated_cpus_update(old_prs, new_prs, cs->effective_xcpus);
|
||||
spin_unlock_irq(&callback_lock);
|
||||
update_isolation_cpumasks();
|
||||
|
||||
/* Force update if switching back to member & update effective_xcpus */
|
||||
update_cpumasks_hier(cs, &tmpmask, !new_prs);
|
||||
@@ -3169,9 +3230,8 @@ ssize_t cpuset_write_resmask(struct kernfs_open_file *of,
|
||||
}
|
||||
|
||||
free_cpuset(trialcs);
|
||||
if (force_sd_rebuild)
|
||||
rebuild_sched_domains_locked();
|
||||
out_unlock:
|
||||
update_hk_sched_domains();
|
||||
cpuset_full_unlock();
|
||||
if (of_cft(of)->private == FILE_MEMLIST)
|
||||
schedule_flush_migrate_mm();
|
||||
@@ -3279,6 +3339,7 @@ static ssize_t cpuset_partition_write(struct kernfs_open_file *of, char *buf,
|
||||
cpuset_full_lock();
|
||||
if (is_cpuset_online(cs))
|
||||
retval = update_prstate(cs, val);
|
||||
update_hk_sched_domains();
|
||||
cpuset_full_unlock();
|
||||
return retval ?: nbytes;
|
||||
}
|
||||
@@ -3453,6 +3514,7 @@ static void cpuset_css_killed(struct cgroup_subsys_state *css)
|
||||
/* Reset valid partition back to member */
|
||||
if (is_partition_valid(cs))
|
||||
update_prstate(cs, PRS_MEMBER);
|
||||
update_hk_sched_domains();
|
||||
cpuset_full_unlock();
|
||||
}
|
||||
|
||||
@@ -3608,6 +3670,7 @@ int __init cpuset_init(void)
|
||||
BUG_ON(!alloc_cpumask_var(&top_cpuset.exclusive_cpus, GFP_KERNEL));
|
||||
BUG_ON(!zalloc_cpumask_var(&subpartitions_cpus, GFP_KERNEL));
|
||||
BUG_ON(!zalloc_cpumask_var(&isolated_cpus, GFP_KERNEL));
|
||||
BUG_ON(!zalloc_cpumask_var(&isolated_hk_cpus, GFP_KERNEL));
|
||||
|
||||
cpumask_setall(top_cpuset.cpus_allowed);
|
||||
nodes_setall(top_cpuset.mems_allowed);
|
||||
@@ -3779,6 +3842,7 @@ unlock:
|
||||
*/
|
||||
static void cpuset_handle_hotplug(void)
|
||||
{
|
||||
static DECLARE_WORK(hk_sd_work, hk_sd_workfn);
|
||||
static cpumask_t new_cpus;
|
||||
static nodemask_t new_mems;
|
||||
bool cpus_updated, mems_updated;
|
||||
@@ -3860,9 +3924,21 @@ static void cpuset_handle_hotplug(void)
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/* rebuild sched domains if necessary */
|
||||
if (force_sd_rebuild)
|
||||
rebuild_sched_domains_cpuslocked();
|
||||
|
||||
/*
|
||||
* Queue a work to call housekeeping_update() & rebuild_sched_domains()
|
||||
* There will be a slight delay before the HK_TYPE_DOMAIN housekeeping
|
||||
* cpumask can correctly reflect what is in isolated_cpus.
|
||||
*
|
||||
* We rely on WORK_STRUCT_PENDING_BIT to not requeue a work item that
|
||||
* is still pending. Before the pending bit is cleared, the work data
|
||||
* is copied out and work item dequeued. So it is possible to queue
|
||||
* the work again before the hk_sd_workfn() is invoked to process the
|
||||
* previously queued work. Since hk_sd_workfn() doesn't use the work
|
||||
* item at all, this is not a problem.
|
||||
*/
|
||||
if (update_housekeeping || force_sd_rebuild)
|
||||
queue_work(system_unbound_wq, &hk_sd_work);
|
||||
|
||||
free_tmpmasks(ptmp);
|
||||
}
|
||||
|
||||
+83
-18
@@ -977,8 +977,12 @@ static bool scx_dsq_priq_less(struct rb_node *node_a,
|
||||
|
||||
static void dsq_mod_nr(struct scx_dispatch_q *dsq, s32 delta)
|
||||
{
|
||||
/* scx_bpf_dsq_nr_queued() reads ->nr without locking, use WRITE_ONCE() */
|
||||
WRITE_ONCE(dsq->nr, dsq->nr + delta);
|
||||
/*
|
||||
* scx_bpf_dsq_nr_queued() reads ->nr without locking. Use READ_ONCE()
|
||||
* on the read side and WRITE_ONCE() on the write side to properly
|
||||
* annotate the concurrent lockless access and avoid KCSAN warnings.
|
||||
*/
|
||||
WRITE_ONCE(dsq->nr, READ_ONCE(dsq->nr) + delta);
|
||||
}
|
||||
|
||||
static void refill_task_slice_dfl(struct scx_sched *sch, struct task_struct *p)
|
||||
@@ -2736,7 +2740,7 @@ static bool check_rq_for_timeouts(struct rq *rq)
|
||||
unsigned long last_runnable = p->scx.runnable_at;
|
||||
|
||||
if (unlikely(time_after(jiffies,
|
||||
last_runnable + scx_watchdog_timeout))) {
|
||||
last_runnable + READ_ONCE(scx_watchdog_timeout)))) {
|
||||
u32 dur_ms = jiffies_to_msecs(jiffies - last_runnable);
|
||||
|
||||
scx_exit(sch, SCX_EXIT_ERROR_STALL, 0,
|
||||
@@ -2764,7 +2768,7 @@ static void scx_watchdog_workfn(struct work_struct *work)
|
||||
cond_resched();
|
||||
}
|
||||
queue_delayed_work(system_unbound_wq, to_delayed_work(work),
|
||||
scx_watchdog_timeout / 2);
|
||||
READ_ONCE(scx_watchdog_timeout) / 2);
|
||||
}
|
||||
|
||||
void scx_tick(struct rq *rq)
|
||||
@@ -3586,7 +3590,6 @@ static int scx_cgroup_init(struct scx_sched *sch)
|
||||
ret = SCX_CALL_OP_RET(sch, SCX_KF_UNLOCKED, cgroup_init, NULL,
|
||||
css->cgroup, &args);
|
||||
if (ret) {
|
||||
css_put(css);
|
||||
scx_error(sch, "ops.cgroup_init() failed (%d)", ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -3709,7 +3712,9 @@ static void scx_kobj_release(struct kobject *kobj)
|
||||
static ssize_t scx_attr_ops_show(struct kobject *kobj,
|
||||
struct kobj_attribute *ka, char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "%s\n", scx_root->ops.name);
|
||||
struct scx_sched *sch = container_of(kobj, struct scx_sched, kobj);
|
||||
|
||||
return sysfs_emit(buf, "%s\n", sch->ops.name);
|
||||
}
|
||||
SCX_ATTR(ops);
|
||||
|
||||
@@ -3753,7 +3758,9 @@ static const struct kobj_type scx_ktype = {
|
||||
|
||||
static int scx_uevent(const struct kobject *kobj, struct kobj_uevent_env *env)
|
||||
{
|
||||
return add_uevent_var(env, "SCXOPS=%s", scx_root->ops.name);
|
||||
const struct scx_sched *sch = container_of(kobj, struct scx_sched, kobj);
|
||||
|
||||
return add_uevent_var(env, "SCXOPS=%s", sch->ops.name);
|
||||
}
|
||||
|
||||
static const struct kset_uevent_ops scx_uevent_ops = {
|
||||
@@ -4424,10 +4431,19 @@ done:
|
||||
scx_bypass(false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Claim the exit on @sch. The caller must ensure that the helper kthread work
|
||||
* is kicked before the current task can be preempted. Once exit_kind is
|
||||
* claimed, scx_error() can no longer trigger, so if the current task gets
|
||||
* preempted and the BPF scheduler fails to schedule it back, the helper work
|
||||
* will never be kicked and the whole system can wedge.
|
||||
*/
|
||||
static bool scx_claim_exit(struct scx_sched *sch, enum scx_exit_kind kind)
|
||||
{
|
||||
int none = SCX_EXIT_NONE;
|
||||
|
||||
lockdep_assert_preemption_disabled();
|
||||
|
||||
if (!atomic_try_cmpxchg(&sch->exit_kind, &none, kind))
|
||||
return false;
|
||||
|
||||
@@ -4450,6 +4466,7 @@ static void scx_disable(enum scx_exit_kind kind)
|
||||
rcu_read_lock();
|
||||
sch = rcu_dereference(scx_root);
|
||||
if (sch) {
|
||||
guard(preempt)();
|
||||
scx_claim_exit(sch, kind);
|
||||
kthread_queue_work(sch->helper, &sch->disable_work);
|
||||
}
|
||||
@@ -4772,6 +4789,8 @@ static bool scx_vexit(struct scx_sched *sch,
|
||||
{
|
||||
struct scx_exit_info *ei = sch->exit_info;
|
||||
|
||||
guard(preempt)();
|
||||
|
||||
if (!scx_claim_exit(sch, kind))
|
||||
return false;
|
||||
|
||||
@@ -4956,20 +4975,30 @@ static int validate_ops(struct scx_sched *sch, const struct sched_ext_ops *ops)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
|
||||
/*
|
||||
* scx_enable() is offloaded to a dedicated system-wide RT kthread to avoid
|
||||
* starvation. During the READY -> ENABLED task switching loop, the calling
|
||||
* thread's sched_class gets switched from fair to ext. As fair has higher
|
||||
* priority than ext, the calling thread can be indefinitely starved under
|
||||
* fair-class saturation, leading to a system hang.
|
||||
*/
|
||||
struct scx_enable_cmd {
|
||||
struct kthread_work work;
|
||||
struct sched_ext_ops *ops;
|
||||
int ret;
|
||||
};
|
||||
|
||||
static void scx_enable_workfn(struct kthread_work *work)
|
||||
{
|
||||
struct scx_enable_cmd *cmd =
|
||||
container_of(work, struct scx_enable_cmd, work);
|
||||
struct sched_ext_ops *ops = cmd->ops;
|
||||
struct scx_sched *sch;
|
||||
struct scx_task_iter sti;
|
||||
struct task_struct *p;
|
||||
unsigned long timeout;
|
||||
int i, cpu, ret;
|
||||
|
||||
if (!cpumask_equal(housekeeping_cpumask(HK_TYPE_DOMAIN),
|
||||
cpu_possible_mask)) {
|
||||
pr_err("sched_ext: Not compatible with \"isolcpus=\" domain isolation\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&scx_enable_mutex);
|
||||
|
||||
if (scx_enable_state() != SCX_DISABLED) {
|
||||
@@ -5061,7 +5090,7 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
|
||||
WRITE_ONCE(scx_watchdog_timeout, timeout);
|
||||
WRITE_ONCE(scx_watchdog_timestamp, jiffies);
|
||||
queue_delayed_work(system_unbound_wq, &scx_watchdog_work,
|
||||
scx_watchdog_timeout / 2);
|
||||
READ_ONCE(scx_watchdog_timeout) / 2);
|
||||
|
||||
/*
|
||||
* Once __scx_enabled is set, %current can be switched to SCX anytime.
|
||||
@@ -5186,13 +5215,15 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
|
||||
|
||||
atomic_long_inc(&scx_enable_seq);
|
||||
|
||||
return 0;
|
||||
cmd->ret = 0;
|
||||
return;
|
||||
|
||||
err_free_ksyncs:
|
||||
free_kick_syncs();
|
||||
err_unlock:
|
||||
mutex_unlock(&scx_enable_mutex);
|
||||
return ret;
|
||||
cmd->ret = ret;
|
||||
return;
|
||||
|
||||
err_disable_unlock_all:
|
||||
scx_cgroup_unlock();
|
||||
@@ -5211,7 +5242,41 @@ err_disable:
|
||||
*/
|
||||
scx_error(sch, "scx_enable() failed (%d)", ret);
|
||||
kthread_flush_work(&sch->disable_work);
|
||||
return 0;
|
||||
cmd->ret = 0;
|
||||
}
|
||||
|
||||
static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
|
||||
{
|
||||
static struct kthread_worker *helper;
|
||||
static DEFINE_MUTEX(helper_mutex);
|
||||
struct scx_enable_cmd cmd;
|
||||
|
||||
if (!cpumask_equal(housekeeping_cpumask(HK_TYPE_DOMAIN),
|
||||
cpu_possible_mask)) {
|
||||
pr_err("sched_ext: Not compatible with \"isolcpus=\" domain isolation\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!READ_ONCE(helper)) {
|
||||
mutex_lock(&helper_mutex);
|
||||
if (!helper) {
|
||||
helper = kthread_run_worker(0, "scx_enable_helper");
|
||||
if (IS_ERR_OR_NULL(helper)) {
|
||||
helper = NULL;
|
||||
mutex_unlock(&helper_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
sched_set_fifo(helper->task);
|
||||
}
|
||||
mutex_unlock(&helper_mutex);
|
||||
}
|
||||
|
||||
kthread_init_work(&cmd.work, scx_enable_workfn);
|
||||
cmd.ops = ops;
|
||||
|
||||
kthread_queue_work(READ_ONCE(helper), &cmd.work);
|
||||
kthread_flush_work(&cmd.work);
|
||||
return cmd.ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -663,9 +663,8 @@ void scx_idle_init_masks(void)
|
||||
BUG_ON(!alloc_cpumask_var(&scx_idle_global_masks.cpu, GFP_KERNEL));
|
||||
BUG_ON(!alloc_cpumask_var(&scx_idle_global_masks.smt, GFP_KERNEL));
|
||||
|
||||
/* Allocate per-node idle cpumasks */
|
||||
scx_idle_node_masks = kzalloc_objs(*scx_idle_node_masks,
|
||||
num_possible_nodes());
|
||||
/* Allocate per-node idle cpumasks (use nr_node_ids for non-contiguous NUMA nodes) */
|
||||
scx_idle_node_masks = kzalloc_objs(*scx_idle_node_masks, nr_node_ids);
|
||||
BUG_ON(!scx_idle_node_masks);
|
||||
|
||||
for_each_node(i) {
|
||||
|
||||
@@ -74,7 +74,7 @@ enum scx_exit_flags {
|
||||
* info communication. The following flag indicates whether ops.init()
|
||||
* finished successfully.
|
||||
*/
|
||||
SCX_EFLAG_INITIALIZED,
|
||||
SCX_EFLAG_INITIALIZED = 1LLU << 0,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -123,8 +123,6 @@ int housekeeping_update(struct cpumask *isol_mask)
|
||||
struct cpumask *trial, *old = NULL;
|
||||
int err;
|
||||
|
||||
lockdep_assert_cpus_held();
|
||||
|
||||
trial = kmalloc(cpumask_size(), GFP_KERNEL);
|
||||
if (!trial)
|
||||
return -ENOMEM;
|
||||
@@ -136,7 +134,7 @@ int housekeeping_update(struct cpumask *isol_mask)
|
||||
}
|
||||
|
||||
if (!housekeeping.flags)
|
||||
static_branch_enable_cpuslocked(&housekeeping_overridden);
|
||||
static_branch_enable(&housekeeping_overridden);
|
||||
|
||||
if (housekeeping.flags & HK_FLAG_DOMAIN)
|
||||
old = housekeeping_cpumask_dereference(HK_TYPE_DOMAIN);
|
||||
|
||||
@@ -256,8 +256,6 @@ EXPORT_SYMBOL(proc_dointvec_jiffies);
|
||||
int proc_dointvec_userhz_jiffies(const struct ctl_table *table, int dir,
|
||||
void *buffer, size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
if (SYSCTL_USER_TO_KERN(dir) && USER_HZ < HZ)
|
||||
return -EINVAL;
|
||||
return proc_dointvec_conv(table, dir, buffer, lenp, ppos,
|
||||
do_proc_int_conv_userhz_jiffies);
|
||||
}
|
||||
|
||||
@@ -1559,8 +1559,6 @@ int tmigr_isolated_exclude_cpumask(struct cpumask *exclude_cpumask)
|
||||
cpumask_var_t cpumask __free(free_cpumask_var) = CPUMASK_VAR_NULL;
|
||||
int cpu;
|
||||
|
||||
lockdep_assert_cpus_held();
|
||||
|
||||
if (!works)
|
||||
return -ENOMEM;
|
||||
if (!alloc_cpumask_var(&cpumask, GFP_KERNEL))
|
||||
@@ -1570,6 +1568,7 @@ int tmigr_isolated_exclude_cpumask(struct cpumask *exclude_cpumask)
|
||||
* First set previously isolated CPUs as available (unisolate).
|
||||
* This cpumask contains only CPUs that switched to available now.
|
||||
*/
|
||||
guard(cpus_read_lock)();
|
||||
cpumask_andnot(cpumask, cpu_online_mask, exclude_cpumask);
|
||||
cpumask_andnot(cpumask, cpumask, tmigr_available_cpumask);
|
||||
|
||||
@@ -1626,7 +1625,6 @@ static int __init tmigr_init_isolation(void)
|
||||
cpumask_andnot(cpumask, cpu_possible_mask, housekeeping_cpumask(HK_TYPE_DOMAIN));
|
||||
|
||||
/* Protect against RCU torture hotplug testing */
|
||||
guard(cpus_read_lock)();
|
||||
return tmigr_isolated_exclude_cpumask(cpumask);
|
||||
}
|
||||
late_initcall(tmigr_init_isolation);
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
# sched-ext mandatory options
|
||||
#
|
||||
CONFIG_BPF=y
|
||||
CONFIG_BPF_SYSCALL=y
|
||||
CONFIG_BPF_JIT=y
|
||||
CONFIG_DEBUG_INFO_BTF=y
|
||||
CONFIG_BPF_JIT_ALWAYS_ON=y
|
||||
CONFIG_BPF_JIT_DEFAULT_ON=y
|
||||
CONFIG_SCHED_CLASS_EXT=y
|
||||
|
||||
# Required by some rust schedulers (e.g. scx_p2dq)
|
||||
#
|
||||
CONFIG_KALLSYMS_ALL=y
|
||||
|
||||
# Required on arm64
|
||||
#
|
||||
# CONFIG_DEBUG_INFO_REDUCED is not set
|
||||
|
||||
# LAVD tracks futex to give an additional time slice for futex holder
|
||||
# (i.e., avoiding lock holder preemption) for better system-wide progress.
|
||||
# LAVD first tries to use ftrace to trace futex function calls.
|
||||
# If that is not available, it tries to use a tracepoint.
|
||||
CONFIG_FUNCTION_TRACER=y
|
||||
|
||||
# Enable scheduling debugging
|
||||
#
|
||||
CONFIG_SCHED_DEBUG=y
|
||||
|
||||
# Enable extra scheduling features (for a better code coverage while testing
|
||||
# the schedulers)
|
||||
#
|
||||
CONFIG_SCHED_AUTOGROUP=y
|
||||
CONFIG_SCHED_CORE=y
|
||||
CONFIG_SCHED_MC=y
|
||||
|
||||
# Enable fully preemptible kernel for a better test coverage of the schedulers
|
||||
#
|
||||
# CONFIG_PREEMPT_NONE is not set
|
||||
# CONFIG_PREEMPT_VOLUNTARY is not set
|
||||
CONFIG_PREEMPT=y
|
||||
CONFIG_PREEMPT_DYNAMIC=y
|
||||
|
||||
# Additional debugging information (useful to catch potential locking issues)
|
||||
CONFIG_DEBUG_LOCKDEP=y
|
||||
CONFIG_DEBUG_ATOMIC_SLEEP=y
|
||||
CONFIG_PROVE_LOCKING=y
|
||||
|
||||
# Bpftrace headers (for additional debug info)
|
||||
CONFIG_BPF_EVENTS=y
|
||||
CONFIG_FTRACE_SYSCALLS=y
|
||||
CONFIG_DYNAMIC_FTRACE=y
|
||||
CONFIG_KPROBES=y
|
||||
CONFIG_KPROBE_EVENTS=y
|
||||
CONFIG_UPROBES=y
|
||||
CONFIG_UPROBE_EVENTS=y
|
||||
CONFIG_DEBUG_FS=y
|
||||
|
||||
# Enable access to kernel configuration and headers at runtime
|
||||
CONFIG_IKHEADERS=y
|
||||
CONFIG_IKCONFIG_PROC=y
|
||||
CONFIG_IKCONFIG=y
|
||||
@@ -122,6 +122,8 @@ BPF_CFLAGS = -g -D__TARGET_ARCH_$(SRCARCH) \
|
||||
-I../../include \
|
||||
$(call get_sys_includes,$(CLANG)) \
|
||||
-Wall -Wno-compare-distinct-pointer-types \
|
||||
-Wno-microsoft-anon-tag \
|
||||
-fms-extensions \
|
||||
-O2 -mcpu=v3
|
||||
|
||||
# sort removes libbpf duplicates when not cross-building
|
||||
|
||||
@@ -58,14 +58,8 @@ CONFIG_SCHED_CLASS_EXT=y
|
||||
CONFIG_BPF_SYSCALL=y
|
||||
CONFIG_BPF_JIT=y
|
||||
CONFIG_DEBUG_INFO_BTF=y
|
||||
```
|
||||
|
||||
It's also recommended that you also include the following Kconfig options:
|
||||
|
||||
```
|
||||
CONFIG_BPF_JIT_ALWAYS_ON=y
|
||||
CONFIG_BPF_JIT_DEFAULT_ON=y
|
||||
CONFIG_PAHOLE_HAS_BTF_TAG=y
|
||||
```
|
||||
|
||||
There is a `Kconfig` file in this directory whose contents you can append to
|
||||
|
||||
@@ -125,6 +125,7 @@ static inline long scx_hotplug_seq(void)
|
||||
{
|
||||
int fd;
|
||||
char buf[32];
|
||||
char *endptr;
|
||||
ssize_t len;
|
||||
long val;
|
||||
|
||||
@@ -137,8 +138,10 @@ static inline long scx_hotplug_seq(void)
|
||||
buf[len] = 0;
|
||||
close(fd);
|
||||
|
||||
val = strtoul(buf, NULL, 10);
|
||||
SCX_BUG_ON(val < 0, "invalid num hotplug events: %lu", val);
|
||||
errno = 0;
|
||||
val = strtoul(buf, &endptr, 10);
|
||||
SCX_BUG_ON(errno == ERANGE || endptr == buf ||
|
||||
(*endptr != '\n' && *endptr != '\0'), "invalid num hotplug events: %ld", val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ restart:
|
||||
assert(skel->rodata->nr_cpu_ids > 0);
|
||||
assert(skel->rodata->nr_cpu_ids <= INT32_MAX);
|
||||
|
||||
while ((opt = getopt(argc, argv, "s:c:pvh")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "s:c:vh")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
skel->rodata->slice_ns = strtoull(optarg, NULL, 0) * 1000;
|
||||
|
||||
@@ -54,7 +54,7 @@ restart:
|
||||
optind = 1;
|
||||
skel = SCX_OPS_OPEN(sdt_ops, scx_sdt);
|
||||
|
||||
while ((opt = getopt(argc, argv, "fvh")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "vh")) != -1) {
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
verbose = true;
|
||||
|
||||
@@ -196,7 +196,6 @@ test_add_proc()
|
||||
# P<v> = set cpus.partition (0:member, 1:root, 2:isolated)
|
||||
# C<l> = add cpu-list to cpuset.cpus
|
||||
# X<l> = add cpu-list to cpuset.cpus.exclusive
|
||||
# S<p> = use prefix in subtree_control
|
||||
# T = put a task into cgroup
|
||||
# CX<l> = add cpu-list to both cpuset.cpus and cpuset.cpus.exclusive
|
||||
# O<c>=<v> = Write <v> to CPU online file of <c>
|
||||
@@ -209,44 +208,46 @@ test_add_proc()
|
||||
# sched-debug matching which includes offline CPUs and single-CPU partitions
|
||||
# while the second one is for matching cpuset.cpus.isolated.
|
||||
#
|
||||
SETUP_A123_PARTITIONS="C1-3:P1:S+ C2-3:P1:S+ C3:P1"
|
||||
SETUP_A123_PARTITIONS="C1-3:P1 C2-3:P1 C3:P1"
|
||||
TEST_MATRIX=(
|
||||
# old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
|
||||
# ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
|
||||
" C0-1 . . C2-3 S+ C4-5 . . 0 A2:0-1"
|
||||
" C0-1 . . C2-3 . C4-5 . . 0 A2:0-1"
|
||||
" C0-1 . . C2-3 P1 . . . 0 "
|
||||
" C0-1 . . C2-3 P1:S+ C0-1:P1 . . 0 "
|
||||
" C0-1 . . C2-3 P1:S+ C1:P1 . . 0 "
|
||||
" C0-1:S+ . . C2-3 . . . P1 0 "
|
||||
" C0-1:P1 . . C2-3 S+ C1 . . 0 "
|
||||
" C0-1:P1 . . C2-3 S+ C1:P1 . . 0 "
|
||||
" C0-1:P1 . . C2-3 S+ C1:P1 . P1 0 "
|
||||
" C0-1 . . C2-3 P1 C0-1:P1 . . 0 "
|
||||
" C0-1 . . C2-3 P1 C1:P1 . . 0 "
|
||||
" C0-1 . . C2-3 . . . P1 0 "
|
||||
" C0-1:P1 . . C2-3 . C1 . . 0 "
|
||||
" C0-1:P1 . . C2-3 . C1:P1 . . 0 "
|
||||
" C0-1:P1 . . C2-3 . C1:P1 . P1 0 "
|
||||
" C0-1:P1 . . C2-3 C4-5 . . . 0 A1:4-5"
|
||||
" C0-1:P1 . . C2-3 S+:C4-5 . . . 0 A1:4-5"
|
||||
" C0-1 . . C2-3:P1 . . . C2 0 "
|
||||
" C0-1 . . C2-3:P1 . . . C4-5 0 B1:4-5"
|
||||
"C0-3:P1:S+ C2-3:P1 . . . . . . 0 A1:0-1|A2:2-3|XA2:2-3"
|
||||
"C0-3:P1:S+ C2-3:P1 . . C1-3 . . . 0 A1:1|A2:2-3|XA2:2-3"
|
||||
"C2-3:P1:S+ C3:P1 . . C3 . . . 0 A1:|A2:3|XA2:3 A1:P1|A2:P1"
|
||||
"C2-3:P1:S+ C3:P1 . . C3 P0 . . 0 A1:3|A2:3 A1:P1|A2:P0"
|
||||
"C2-3:P1:S+ C2:P1 . . C2-4 . . . 0 A1:3-4|A2:2"
|
||||
"C2-3:P1:S+ C3:P1 . . C3 . . C0-2 0 A1:|B1:0-2 A1:P1|A2:P1"
|
||||
" C0-3:P1 C2-3:P1 . . . . . . 0 A1:0-1|A2:2-3|XA2:2-3"
|
||||
" C0-3:P1 C2-3:P1 . . C1-3 . . . 0 A1:1|A2:2-3|XA2:2-3"
|
||||
" C2-3:P1 C3:P1 . . C3 . . . 0 A1:|A2:3|XA2:3 A1:P1|A2:P1"
|
||||
" C2-3:P1 C3:P1 . . C3 P0 . . 0 A1:3|A2:3 A1:P1|A2:P0"
|
||||
" C2-3:P1 C2:P1 . . C2-4 . . . 0 A1:3-4|A2:2"
|
||||
" C2-3:P1 C3:P1 . . C3 . . C0-2 0 A1:|B1:0-2 A1:P1|A2:P1"
|
||||
"$SETUP_A123_PARTITIONS . C2-3 . . . 0 A1:|A2:2|A3:3 A1:P1|A2:P1|A3:P1"
|
||||
|
||||
# CPU offlining cases:
|
||||
" C0-1 . . C2-3 S+ C4-5 . O2=0 0 A1:0-1|B1:3"
|
||||
"C0-3:P1:S+ C2-3:P1 . . O2=0 . . . 0 A1:0-1|A2:3"
|
||||
"C0-3:P1:S+ C2-3:P1 . . O2=0 O2=1 . . 0 A1:0-1|A2:2-3"
|
||||
"C0-3:P1:S+ C2-3:P1 . . O1=0 . . . 0 A1:0|A2:2-3"
|
||||
"C0-3:P1:S+ C2-3:P1 . . O1=0 O1=1 . . 0 A1:0-1|A2:2-3"
|
||||
"C2-3:P1:S+ C3:P1 . . O3=0 O3=1 . . 0 A1:2|A2:3 A1:P1|A2:P1"
|
||||
"C2-3:P1:S+ C3:P2 . . O3=0 O3=1 . . 0 A1:2|A2:3 A1:P1|A2:P2"
|
||||
"C2-3:P1:S+ C3:P1 . . O2=0 O2=1 . . 0 A1:2|A2:3 A1:P1|A2:P1"
|
||||
"C2-3:P1:S+ C3:P2 . . O2=0 O2=1 . . 0 A1:2|A2:3 A1:P1|A2:P2"
|
||||
"C2-3:P1:S+ C3:P1 . . O2=0 . . . 0 A1:|A2:3 A1:P1|A2:P1"
|
||||
"C2-3:P1:S+ C3:P1 . . O3=0 . . . 0 A1:2|A2: A1:P1|A2:P1"
|
||||
"C2-3:P1:S+ C3:P1 . . T:O2=0 . . . 0 A1:3|A2:3 A1:P1|A2:P-1"
|
||||
"C2-3:P1:S+ C3:P1 . . . T:O3=0 . . 0 A1:2|A2:2 A1:P1|A2:P-1"
|
||||
" C0-1 . . C2-3 . C4-5 . O2=0 0 A1:0-1|B1:3"
|
||||
" C0-3:P1 C2-3:P1 . . O2=0 . . . 0 A1:0-1|A2:3"
|
||||
" C0-3:P1 C2-3:P1 . . O2=0 O2=1 . . 0 A1:0-1|A2:2-3"
|
||||
" C0-3:P1 C2-3:P1 . . O1=0 . . . 0 A1:0|A2:2-3"
|
||||
" C0-3:P1 C2-3:P1 . . O1=0 O1=1 . . 0 A1:0-1|A2:2-3"
|
||||
" C2-3:P1 C3:P1 . . O3=0 O3=1 . . 0 A1:2|A2:3 A1:P1|A2:P1"
|
||||
" C2-3:P1 C3:P2 . . O3=0 O3=1 . . 0 A1:2|A2:3 A1:P1|A2:P2"
|
||||
" C2-3:P1 C3:P1 . . O2=0 O2=1 . . 0 A1:2|A2:3 A1:P1|A2:P1"
|
||||
" C2-3:P1 C3:P2 . . O2=0 O2=1 . . 0 A1:2|A2:3 A1:P1|A2:P2"
|
||||
" C2-3:P1 C3:P1 . . O2=0 . . . 0 A1:|A2:3 A1:P1|A2:P1"
|
||||
" C2-3:P1 C3:P1 . . O3=0 . . . 0 A1:2|A2: A1:P1|A2:P1"
|
||||
" C2-3:P1 C3:P1 . . T:O2=0 . . . 0 A1:3|A2:3 A1:P1|A2:P-1"
|
||||
" C2-3:P1 C3:P1 . . . T:O3=0 . . 0 A1:2|A2:2 A1:P1|A2:P-1"
|
||||
" C2-3:P1 C3:P2 . . T:O2=0 . . . 0 A1:3|A2:3 A1:P1|A2:P-2"
|
||||
" C1-3:P1 C3:P2 . . . T:O3=0 . . 0 A1:1-2|A2:1-2 A1:P1|A2:P-2 3|"
|
||||
" C1-3:P1 C3:P2 . . . T:O3=0 O3=1 . 0 A1:1-2|A2:3 A1:P1|A2:P2 3"
|
||||
"$SETUP_A123_PARTITIONS . O1=0 . . . 0 A1:|A2:2|A3:3 A1:P1|A2:P1|A3:P1"
|
||||
"$SETUP_A123_PARTITIONS . O2=0 . . . 0 A1:1|A2:|A3:3 A1:P1|A2:P1|A3:P1"
|
||||
"$SETUP_A123_PARTITIONS . O3=0 . . . 0 A1:1|A2:2|A3: A1:P1|A2:P1|A3:P1"
|
||||
@@ -264,88 +265,87 @@ TEST_MATRIX=(
|
||||
#
|
||||
# Remote partition and cpuset.cpus.exclusive tests
|
||||
#
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 . . . 0 A1:0-3|A2:1-3|A3:2-3|XA1:2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3:P2 . . 0 A1:0-1|A2:2-3|A3:2-3 A1:P0|A2:P2 2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X3:P2 . . 0 A1:0-2|A2:3|A3:3 A1:P0|A2:P2 3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2 . 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2:C3 . 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C2-3 . . . P2 0 A1:0-1|A2:1|A3:1|B1:2-3 A1:P0|A3:P0|B1:P2"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4-5 . . . P2 0 B1:4-5 B1:P2 4-5"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3 X2-3:P2 P2 0 A3:2-3|B1:4 A3:P2|B1:P2 2-4"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3 X2-3:P2:C1-3 P2 0 A3:2-3|B1:4 A3:P2|B1:P2 2-4"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X1-3 X1-3:P2 P2 . 0 A2:1|A3:2-3 A2:P2|A3:P2 1-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3 X2-3:P2 P2:C4-5 0 A3:2-3|B1:4-5 A3:P2|B1:P2 2-5"
|
||||
" C4:X0-3:S+ X1-3:S+ X2-3 . . P2 . . 0 A1:4|A2:1-3|A3:1-3 A2:P2 1-3"
|
||||
" C4:X0-3:S+ X1-3:S+ X2-3 . . . P2 . 0 A1:4|A2:4|A3:2-3 A3:P2 2-3"
|
||||
" C0-3 C1-3 C2-3 . X2-3 . . . 0 A1:0-3|A2:1-3|A3:2-3|XA1:2-3"
|
||||
" C0-3 C1-3 C2-3 . X2-3 X2-3:P2 . . 0 A1:0-1|A2:2-3|A3:2-3 A1:P0|A2:P2 2-3"
|
||||
" C0-3 C1-3 C2-3 . X2-3 X3:P2 . . 0 A1:0-2|A2:3|A3:3 A1:P0|A2:P2 3"
|
||||
" C0-3 C1-3 C2-3 . X2-3 X2-3 X2-3:P2 . 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3"
|
||||
" C0-3 C1-3 C2-3 . X2-3 X2-3 X2-3:P2:C3 . 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3"
|
||||
" C0-3 C1-3 C2-3 C2-3 . . . P2 0 A1:0-1|A2:1|A3:1|B1:2-3 A1:P0|A3:P0|B1:P2"
|
||||
" C0-3 C1-3 C2-3 C4-5 . . . P2 0 B1:4-5 B1:P2 4-5"
|
||||
" C0-3 C1-3 C2-3 C4 X2-3 X2-3 X2-3:P2 P2 0 A3:2-3|B1:4 A3:P2|B1:P2 2-4"
|
||||
" C0-3 C1-3 C2-3 C4 X2-3 X2-3 X2-3:P2:C1-3 P2 0 A3:2-3|B1:4 A3:P2|B1:P2 2-4"
|
||||
" C0-3 C1-3 C2-3 C4 X1-3 X1-3:P2 P2 . 0 A2:1|A3:2-3 A2:P2|A3:P2 1-3"
|
||||
" C0-3 C1-3 C2-3 C4 X2-3 X2-3 X2-3:P2 P2:C4-5 0 A3:2-3|B1:4-5 A3:P2|B1:P2 2-5"
|
||||
" C4:X0-3 X1-3 X2-3 . . P2 . . 0 A1:4|A2:1-3|A3:1-3 A2:P2 1-3"
|
||||
" C4:X0-3 X1-3 X2-3 . . . P2 . 0 A1:4|A2:4|A3:2-3 A3:P2 2-3"
|
||||
|
||||
# Nested remote/local partition tests
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4-5 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:|A3:2-3|B1:4-5 \
|
||||
" C0-3 C1-3 C2-3 C4-5 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:|A3:2-3|B1:4-5 \
|
||||
A1:P0|A2:P1|A3:P2|B1:P1 2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:|A3:2-3|B1:4 \
|
||||
" C0-3 C1-3 C2-3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:|A3:2-3|B1:4 \
|
||||
A1:P0|A2:P1|A3:P2|B1:P1 2-4|2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3:P1 . P1 0 A1:0-1|A2:2-3|A3:2-3|B1:4 \
|
||||
" C0-3 C1-3 C2-3 C4 X2-3 X2-3:P1 . P1 0 A1:0-1|A2:2-3|A3:2-3|B1:4 \
|
||||
A1:P0|A2:P1|A3:P0|B1:P1"
|
||||
" C0-3:S+ C1-3:S+ C3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:2|A3:3|B1:4 \
|
||||
" C0-3 C1-3 C3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:2|A3:3|B1:4 \
|
||||
A1:P0|A2:P1|A3:P2|B1:P1 2-4|3"
|
||||
" C0-4:S+ C1-4:S+ C2-4 . X2-4 X2-4:P2 X4:P1 . 0 A1:0-1|A2:2-3|A3:4 \
|
||||
" C0-4 C1-4 C2-4 . X2-4 X2-4:P2 X4:P1 . 0 A1:0-1|A2:2-3|A3:4 \
|
||||
A1:P0|A2:P2|A3:P1 2-4|2-3"
|
||||
" C0-4:S+ C1-4:S+ C2-4 . X2-4 X2-4:P2 X3-4:P1 . 0 A1:0-1|A2:2|A3:3-4 \
|
||||
" C0-4 C1-4 C2-4 . X2-4 X2-4:P2 X3-4:P1 . 0 A1:0-1|A2:2|A3:3-4 \
|
||||
A1:P0|A2:P2|A3:P1 2"
|
||||
" C0-4:X2-4:S+ C1-4:X2-4:S+:P2 C2-4:X4:P1 \
|
||||
" C0-4:X2-4 C1-4:X2-4:P2 C2-4:X4:P1 \
|
||||
. . X5 . . 0 A1:0-4|A2:1-4|A3:2-4 \
|
||||
A1:P0|A2:P-2|A3:P-1 ."
|
||||
" C0-4:X2-4:S+ C1-4:X2-4:S+:P2 C2-4:X4:P1 \
|
||||
" C0-4:X2-4 C1-4:X2-4:P2 C2-4:X4:P1 \
|
||||
. . . X1 . 0 A1:0-1|A2:2-4|A3:2-4 \
|
||||
A1:P0|A2:P2|A3:P-1 2-4"
|
||||
|
||||
# Remote partition offline tests
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2:O2=0 . 0 A1:0-1|A2:1|A3:3 A1:P0|A3:P2 2-3"
|
||||
" C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2:O2=0 O2=1 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3"
|
||||
" C0-3:S+ C1-3:S+ C3 . X2-3 X2-3 P2:O3=0 . 0 A1:0-2|A2:1-2|A3: A1:P0|A3:P2 3"
|
||||
" C0-3:S+ C1-3:S+ C3 . X2-3 X2-3 T:P2:O3=0 . 0 A1:0-2|A2:1-2|A3:1-2 A1:P0|A3:P-2 3|"
|
||||
" C0-3 C1-3 C2-3 . X2-3 X2-3 X2-3:P2:O2=0 . 0 A1:0-1|A2:1|A3:3 A1:P0|A3:P2 2-3"
|
||||
" C0-3 C1-3 C2-3 . X2-3 X2-3 X2-3:P2:O2=0 O2=1 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3"
|
||||
" C0-3 C1-3 C3 . X2-3 X2-3 P2:O3=0 . 0 A1:0-2|A2:1-2|A3: A1:P0|A3:P2 3"
|
||||
" C0-3 C1-3 C3 . X2-3 X2-3 T:P2:O3=0 . 0 A1:0-2|A2:1-2|A3:1-2 A1:P0|A3:P-2 3|"
|
||||
|
||||
# An invalidated remote partition cannot self-recover from hotplug
|
||||
" C0-3:S+ C1-3:S+ C2 . X2-3 X2-3 T:P2:O2=0 O2=1 0 A1:0-3|A2:1-3|A3:2 A1:P0|A3:P-2 ."
|
||||
" C0-3 C1-3 C2 . X2-3 X2-3 T:P2:O2=0 O2=1 0 A1:0-3|A2:1-3|A3:2 A1:P0|A3:P-2 ."
|
||||
|
||||
# cpus.exclusive.effective clearing test
|
||||
" C0-3:S+ C1-3:S+ C2 . X2-3:X . . . 0 A1:0-3|A2:1-3|A3:2|XA1:"
|
||||
" C0-3 C1-3 C2 . X2-3:X . . . 0 A1:0-3|A2:1-3|A3:2|XA1:"
|
||||
|
||||
# Invalid to valid remote partition transition test
|
||||
" C0-3:S+ C1-3 . . . X3:P2 . . 0 A1:0-3|A2:1-3|XA2: A2:P-2 ."
|
||||
" C0-3:S+ C1-3:X3:P2
|
||||
. . X2-3 P2 . . 0 A1:0-2|A2:3|XA2:3 A2:P2 3"
|
||||
" C0-3 C1-3 . . . X3:P2 . . 0 A1:0-3|A2:1-3|XA2: A2:P-2 ."
|
||||
" C0-3 C1-3:X3:P2 . . X2-3 P2 . . 0 A1:0-2|A2:3|XA2:3 A2:P2 3"
|
||||
|
||||
# Invalid to valid local partition direct transition tests
|
||||
" C1-3:S+:P2 X4:P2 . . . . . . 0 A1:1-3|XA1:1-3|A2:1-3:XA2: A1:P2|A2:P-2 1-3"
|
||||
" C1-3:S+:P2 X4:P2 . . . X3:P2 . . 0 A1:1-2|XA1:1-3|A2:3:XA2:3 A1:P2|A2:P2 1-3"
|
||||
" C0-3:P2 . . C4-6 C0-4 . . . 0 A1:0-4|B1:5-6 A1:P2|B1:P0"
|
||||
" C0-3:P2 . . C4-6 C0-4:C0-3 . . . 0 A1:0-3|B1:4-6 A1:P2|B1:P0 0-3"
|
||||
" C1-3:P2 X4:P2 . . . . . . 0 A1:1-3|XA1:1-3|A2:1-3:XA2: A1:P2|A2:P-2 1-3"
|
||||
" C1-3:P2 X4:P2 . . . X3:P2 . . 0 A1:1-2|XA1:1-3|A2:3:XA2:3 A1:P2|A2:P2 1-3"
|
||||
" C0-3:P2 . . C4-6 C0-4 . . . 0 A1:0-4|B1:5-6 A1:P2|B1:P0"
|
||||
" C0-3:P2 . . C4-6 C0-4:C0-3 . . . 0 A1:0-3|B1:4-6 A1:P2|B1:P0 0-3"
|
||||
|
||||
# Local partition invalidation tests
|
||||
" C0-3:X1-3:S+:P2 C1-3:X2-3:S+:P2 C2-3:X3:P2 \
|
||||
" C0-3:X1-3:P2 C1-3:X2-3:P2 C2-3:X3:P2 \
|
||||
. . . . . 0 A1:1|A2:2|A3:3 A1:P2|A2:P2|A3:P2 1-3"
|
||||
" C0-3:X1-3:S+:P2 C1-3:X2-3:S+:P2 C2-3:X3:P2 \
|
||||
" C0-3:X1-3:P2 C1-3:X2-3:P2 C2-3:X3:P2 \
|
||||
. . X4 . . 0 A1:1-3|A2:1-3|A3:2-3|XA2:|XA3: A1:P2|A2:P-2|A3:P-2 1-3"
|
||||
" C0-3:X1-3:S+:P2 C1-3:X2-3:S+:P2 C2-3:X3:P2 \
|
||||
" C0-3:X1-3:P2 C1-3:X2-3:P2 C2-3:X3:P2 \
|
||||
. . C4:X . . 0 A1:1-3|A2:1-3|A3:2-3|XA2:|XA3: A1:P2|A2:P-2|A3:P-2 1-3"
|
||||
# Local partition CPU change tests
|
||||
" C0-5:S+:P2 C4-5:S+:P1 . . . C3-5 . . 0 A1:0-2|A2:3-5 A1:P2|A2:P1 0-2"
|
||||
" C0-5:S+:P2 C4-5:S+:P1 . . C1-5 . . . 0 A1:1-3|A2:4-5 A1:P2|A2:P1 1-3"
|
||||
" C0-5:P2 C4-5:P1 . . . C3-5 . . 0 A1:0-2|A2:3-5 A1:P2|A2:P1 0-2"
|
||||
" C0-5:P2 C4-5:P1 . . C1-5 . . . 0 A1:1-3|A2:4-5 A1:P2|A2:P1 1-3"
|
||||
|
||||
# cpus_allowed/exclusive_cpus update tests
|
||||
" C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \
|
||||
" C0-3:X2-3 C1-3:X2-3 C2-3:X2-3 \
|
||||
. X:C4 . P2 . 0 A1:4|A2:4|XA2:|XA3:|A3:4 \
|
||||
A1:P0|A3:P-2 ."
|
||||
" C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \
|
||||
" C0-3:X2-3 C1-3:X2-3 C2-3:X2-3 \
|
||||
. X1 . P2 . 0 A1:0-3|A2:1-3|XA1:1|XA2:|XA3:|A3:2-3 \
|
||||
A1:P0|A3:P-2 ."
|
||||
" C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \
|
||||
" C0-3:X2-3 C1-3:X2-3 C2-3:X2-3 \
|
||||
. . X3 P2 . 0 A1:0-2|A2:1-2|XA2:3|XA3:3|A3:3 \
|
||||
A1:P0|A3:P2 3"
|
||||
" C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3:P2 \
|
||||
" C0-3:X2-3 C1-3:X2-3 C2-3:X2-3:P2 \
|
||||
. . X3 . . 0 A1:0-2|A2:1-2|XA2:3|XA3:3|A3:3|XA3:3 \
|
||||
A1:P0|A3:P2 3"
|
||||
" C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3:P2 \
|
||||
" C0-3:X2-3 C1-3:X2-3 C2-3:X2-3:P2 \
|
||||
. X4 . . . 0 A1:0-3|A2:1-3|A3:2-3|XA1:4|XA2:|XA3 \
|
||||
A1:P0|A3:P-2"
|
||||
|
||||
@@ -356,37 +356,37 @@ TEST_MATRIX=(
|
||||
#
|
||||
# Adding CPUs to partition root that are not in parent's
|
||||
# cpuset.cpus is allowed, but those extra CPUs are ignored.
|
||||
"C2-3:P1:S+ C3:P1 . . . C2-4 . . 0 A1:|A2:2-3 A1:P1|A2:P1"
|
||||
" C2-3:P1 C3:P1 . . . C2-4 . . 0 A1:|A2:2-3 A1:P1|A2:P1"
|
||||
|
||||
# Taking away all CPUs from parent or itself if there are tasks
|
||||
# will make the partition invalid.
|
||||
"C2-3:P1:S+ C3:P1 . . T C2-3 . . 0 A1:2-3|A2:2-3 A1:P1|A2:P-1"
|
||||
" C3:P1:S+ C3 . . T P1 . . 0 A1:3|A2:3 A1:P1|A2:P-1"
|
||||
" C2-3:P1 C3:P1 . . T C2-3 . . 0 A1:2-3|A2:2-3 A1:P1|A2:P-1"
|
||||
" C3:P1 C3 . . T P1 . . 0 A1:3|A2:3 A1:P1|A2:P-1"
|
||||
"$SETUP_A123_PARTITIONS . T:C2-3 . . . 0 A1:2-3|A2:2-3|A3:3 A1:P1|A2:P-1|A3:P-1"
|
||||
"$SETUP_A123_PARTITIONS . T:C2-3:C1-3 . . . 0 A1:1|A2:2|A3:3 A1:P1|A2:P1|A3:P1"
|
||||
|
||||
# Changing a partition root to member makes child partitions invalid
|
||||
"C2-3:P1:S+ C3:P1 . . P0 . . . 0 A1:2-3|A2:3 A1:P0|A2:P-1"
|
||||
" C2-3:P1 C3:P1 . . P0 . . . 0 A1:2-3|A2:3 A1:P0|A2:P-1"
|
||||
"$SETUP_A123_PARTITIONS . C2-3 P0 . . 0 A1:2-3|A2:2-3|A3:3 A1:P1|A2:P0|A3:P-1"
|
||||
|
||||
# cpuset.cpus can contains cpus not in parent's cpuset.cpus as long
|
||||
# as they overlap.
|
||||
"C2-3:P1:S+ . . . . C3-4:P1 . . 0 A1:2|A2:3 A1:P1|A2:P1"
|
||||
" C2-3:P1 . . . . C3-4:P1 . . 0 A1:2|A2:3 A1:P1|A2:P1"
|
||||
|
||||
# Deletion of CPUs distributed to child cgroup is allowed.
|
||||
"C0-1:P1:S+ C1 . C2-3 C4-5 . . . 0 A1:4-5|A2:4-5"
|
||||
" C0-1:P1 C1 . C2-3 C4-5 . . . 0 A1:4-5|A2:4-5"
|
||||
|
||||
# To become a valid partition root, cpuset.cpus must overlap parent's
|
||||
# cpuset.cpus.
|
||||
" C0-1:P1 . . C2-3 S+ C4-5:P1 . . 0 A1:0-1|A2:0-1 A1:P1|A2:P-1"
|
||||
" C0-1:P1 . . C2-3 . C4-5:P1 . . 0 A1:0-1|A2:0-1 A1:P1|A2:P-1"
|
||||
|
||||
# Enabling partition with child cpusets is allowed
|
||||
" C0-1:S+ C1 . C2-3 P1 . . . 0 A1:0-1|A2:1 A1:P1"
|
||||
" C0-1 C1 . C2-3 P1 . . . 0 A1:0-1|A2:1 A1:P1"
|
||||
|
||||
# A partition root with non-partition root parent is invalid| but it
|
||||
# can be made valid if its parent becomes a partition root too.
|
||||
" C0-1:S+ C1 . C2-3 . P2 . . 0 A1:0-1|A2:1 A1:P0|A2:P-2"
|
||||
" C0-1:S+ C1:P2 . C2-3 P1 . . . 0 A1:0|A2:1 A1:P1|A2:P2 0-1|1"
|
||||
" C0-1 C1 . C2-3 . P2 . . 0 A1:0-1|A2:1 A1:P0|A2:P-2"
|
||||
" C0-1 C1:P2 . C2-3 P1 . . . 0 A1:0|A2:1 A1:P1|A2:P2 0-1|1"
|
||||
|
||||
# A non-exclusive cpuset.cpus change will not invalidate its siblings partition.
|
||||
" C0-1:P1 . . C2-3 C0-2 . . . 0 A1:0-2|B1:3 A1:P1|B1:P0"
|
||||
@@ -398,23 +398,23 @@ TEST_MATRIX=(
|
||||
|
||||
# Child partition root that try to take all CPUs from parent partition
|
||||
# with tasks will remain invalid.
|
||||
" C1-4:P1:S+ P1 . . . . . . 0 A1:1-4|A2:1-4 A1:P1|A2:P-1"
|
||||
" C1-4:P1:S+ P1 . . . C1-4 . . 0 A1|A2:1-4 A1:P1|A2:P1"
|
||||
" C1-4:P1:S+ P1 . . T C1-4 . . 0 A1:1-4|A2:1-4 A1:P1|A2:P-1"
|
||||
" C1-4:P1 P1 . . . . . . 0 A1:1-4|A2:1-4 A1:P1|A2:P-1"
|
||||
" C1-4:P1 P1 . . . C1-4 . . 0 A1|A2:1-4 A1:P1|A2:P1"
|
||||
" C1-4:P1 P1 . . T C1-4 . . 0 A1:1-4|A2:1-4 A1:P1|A2:P-1"
|
||||
|
||||
# Clearing of cpuset.cpus with a preset cpuset.cpus.exclusive shouldn't
|
||||
# affect cpuset.cpus.exclusive.effective.
|
||||
" C1-4:X3:S+ C1:X3 . . . C . . 0 A2:1-4|XA2:3"
|
||||
" C1-4:X3 C1:X3 . . . C . . 0 A2:1-4|XA2:3"
|
||||
|
||||
# cpuset.cpus can contain CPUs that overlap a sibling cpuset with cpus.exclusive
|
||||
# but creating a local partition out of it is not allowed. Similarly and change
|
||||
# in cpuset.cpus of a local partition that overlaps sibling exclusive CPUs will
|
||||
# invalidate it.
|
||||
" CX1-4:S+ CX2-4:P2 . C5-6 . . . P1 0 A1:1|A2:2-4|B1:5-6|XB1:5-6 \
|
||||
" CX1-4 CX2-4:P2 . C5-6 . . . P1 0 A1:1|A2:2-4|B1:5-6|XB1:5-6 \
|
||||
A1:P0|A2:P2:B1:P1 2-4"
|
||||
" CX1-4:S+ CX2-4:P2 . C3-6 . . . P1 0 A1:1|A2:2-4|B1:5-6 \
|
||||
" CX1-4 CX2-4:P2 . C3-6 . . . P1 0 A1:1|A2:2-4|B1:5-6 \
|
||||
A1:P0|A2:P2:B1:P-1 2-4"
|
||||
" CX1-4:S+ CX2-4:P2 . C5-6 . . . P1:C3-6 0 A1:1|A2:2-4|B1:5-6 \
|
||||
" CX1-4 CX2-4:P2 . C5-6 . . . P1:C3-6 0 A1:1|A2:2-4|B1:5-6 \
|
||||
A1:P0|A2:P2:B1:P-1 2-4"
|
||||
|
||||
# When multiple partitions with conflicting cpuset.cpus are created, the
|
||||
@@ -426,14 +426,14 @@ TEST_MATRIX=(
|
||||
" C1-3:X1-3 . . C4-5 . . . C1-2 0 A1:1-3|B1:1-2"
|
||||
|
||||
# cpuset.cpus can become empty with task in it as it inherits parent's effective CPUs
|
||||
" C1-3:S+ C2 . . . T:C . . 0 A1:1-3|A2:1-3"
|
||||
" C1-3 C2 . . . T:C . . 0 A1:1-3|A2:1-3"
|
||||
|
||||
# old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
|
||||
# ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
|
||||
# Failure cases:
|
||||
|
||||
# A task cannot be added to a partition with no cpu
|
||||
"C2-3:P1:S+ C3:P1 . . O2=0:T . . . 1 A1:|A2:3 A1:P1|A2:P1"
|
||||
" C2-3:P1 C3:P1 . . O2=0:T . . . 1 A1:|A2:3 A1:P1|A2:P1"
|
||||
|
||||
# Changes to cpuset.cpus.exclusive that violate exclusivity rule is rejected
|
||||
" C0-3 . . C4-5 X0-3 . . X3-5 1 A1:0-3|B1:4-5"
|
||||
@@ -465,31 +465,31 @@ REMOTE_TEST_MATRIX=(
|
||||
# old-p1 old-p2 old-c11 old-c12 old-c21 old-c22
|
||||
# new-p1 new-p2 new-c11 new-c12 new-c21 new-c22 ECPUs Pstate ISOLCPUS
|
||||
# ------ ------ ------- ------- ------- ------- ----- ------ --------
|
||||
" X1-3:S+ X4-6:S+ X1-2 X3 X4-5 X6 \
|
||||
" X1-3 X4-6 X1-2 X3 X4-5 X6 \
|
||||
. . P2 P2 P2 P2 c11:1-2|c12:3|c21:4-5|c22:6 \
|
||||
c11:P2|c12:P2|c21:P2|c22:P2 1-6"
|
||||
" CX1-4:S+ . X1-2:P2 C3 . . \
|
||||
" CX1-4 . X1-2:P2 C3 . . \
|
||||
. . . C3-4 . . p1:3-4|c11:1-2|c12:3-4 \
|
||||
p1:P0|c11:P2|c12:P0 1-2"
|
||||
" CX1-4:S+ . X1-2:P2 . . . \
|
||||
" CX1-4 . X1-2:P2 . . . \
|
||||
X2-4 . . . . . p1:1,3-4|c11:2 \
|
||||
p1:P0|c11:P2 2"
|
||||
" CX1-5:S+ . X1-2:P2 X3-5:P1 . . \
|
||||
" CX1-5 . X1-2:P2 X3-5:P1 . . \
|
||||
X2-4 . . . . . p1:1,5|c11:2|c12:3-4 \
|
||||
p1:P0|c11:P2|c12:P1 2"
|
||||
" CX1-4:S+ . X1-2:P2 X3-4:P1 . . \
|
||||
" CX1-4 . X1-2:P2 X3-4:P1 . . \
|
||||
. . X2 . . . p1:1|c11:2|c12:3-4 \
|
||||
p1:P0|c11:P2|c12:P1 2"
|
||||
# p1 as member, will get its effective CPUs from its parent rtest
|
||||
" CX1-4:S+ . X1-2:P2 X3-4:P1 . . \
|
||||
" CX1-4 . X1-2:P2 X3-4:P1 . . \
|
||||
. . X1 CX2-4 . . p1:5-7|c11:1|c12:2-4 \
|
||||
p1:P0|c11:P2|c12:P1 1"
|
||||
" CX1-4:S+ X5-6:P1:S+ . . . . \
|
||||
. . X1-2:P2 X4-5:P1 . X1-7:P2 p1:3|c11:1-2|c12:4:c22:5-6 \
|
||||
" CX1-4 X5-6:P1 . . . . \
|
||||
. . X1-2:P2 X4-5:P1 . X1-7:P2 p1:3|c11:1-2|c12:4:c22:5-6 \
|
||||
p1:P0|p2:P1|c11:P2|c12:P1|c22:P2 \
|
||||
1-2,4-6|1-2,5-6"
|
||||
# c12 whose cpuset.cpus CPUs are all granted to c11 will become invalid partition
|
||||
" C1-5:P1:S+ . C1-4:P1 C2-3 . . \
|
||||
" C1-5:P1 . C1-4:P1 C2-3 . . \
|
||||
. . . P1 . . p1:5|c11:1-4|c12:5 \
|
||||
p1:P1|c11:P1|c12:P-1"
|
||||
)
|
||||
@@ -530,7 +530,6 @@ set_ctrl_state()
|
||||
CGRP=$1
|
||||
STATE=$2
|
||||
SHOWERR=${3}
|
||||
CTRL=${CTRL:=$CONTROLLER}
|
||||
HASERR=0
|
||||
REDIRECT="2> $TMPMSG"
|
||||
[[ -z "$STATE" || "$STATE" = '.' ]] && return 0
|
||||
@@ -540,15 +539,16 @@ set_ctrl_state()
|
||||
for CMD in $(echo $STATE | sed -e "s/:/ /g")
|
||||
do
|
||||
TFILE=$CGRP/cgroup.procs
|
||||
SFILE=$CGRP/cgroup.subtree_control
|
||||
PFILE=$CGRP/cpuset.cpus.partition
|
||||
CFILE=$CGRP/cpuset.cpus
|
||||
XFILE=$CGRP/cpuset.cpus.exclusive
|
||||
case $CMD in
|
||||
S*) PREFIX=${CMD#?}
|
||||
COMM="echo ${PREFIX}${CTRL} > $SFILE"
|
||||
|
||||
# Enable cpuset controller if not enabled yet
|
||||
[[ -f $CFILE ]] || {
|
||||
COMM="echo +cpuset > $CGRP/../cgroup.subtree_control"
|
||||
eval $COMM $REDIRECT
|
||||
;;
|
||||
}
|
||||
case $CMD in
|
||||
X*)
|
||||
CPUS=${CMD#?}
|
||||
COMM="echo $CPUS > $XFILE"
|
||||
@@ -764,7 +764,7 @@ check_cgroup_states()
|
||||
# only CPUs in isolated partitions as well as those that are isolated at
|
||||
# boot time.
|
||||
#
|
||||
# $1 - expected isolated cpu list(s) <isolcpus1>{,<isolcpus2>}
|
||||
# $1 - expected isolated cpu list(s) <isolcpus1>{|<isolcpus2>}
|
||||
# <isolcpus1> - expected sched/domains value
|
||||
# <isolcpus2> - cpuset.cpus.isolated value = <isolcpus1> if not defined
|
||||
#
|
||||
@@ -773,6 +773,7 @@ check_isolcpus()
|
||||
EXPECTED_ISOLCPUS=$1
|
||||
ISCPUS=${CGROUP2}/cpuset.cpus.isolated
|
||||
ISOLCPUS=$(cat $ISCPUS)
|
||||
HKICPUS=$(cat /sys/devices/system/cpu/isolated)
|
||||
LASTISOLCPU=
|
||||
SCHED_DOMAINS=/sys/kernel/debug/sched/domains
|
||||
if [[ $EXPECTED_ISOLCPUS = . ]]
|
||||
@@ -810,6 +811,11 @@ check_isolcpus()
|
||||
ISOLCPUS=
|
||||
EXPECTED_ISOLCPUS=$EXPECTED_SDOMAIN
|
||||
|
||||
#
|
||||
# The inverse of HK_TYPE_DOMAIN cpumask in $HKICPUS should match $ISOLCPUS
|
||||
#
|
||||
[[ "$ISOLCPUS" != "$HKICPUS" ]] && return 1
|
||||
|
||||
#
|
||||
# Use the sched domain in debugfs to check isolated CPUs, if available
|
||||
#
|
||||
@@ -947,7 +953,6 @@ check_test_results()
|
||||
run_state_test()
|
||||
{
|
||||
TEST=$1
|
||||
CONTROLLER=cpuset
|
||||
CGROUP_LIST=". A1 A1/A2 A1/A2/A3 B1"
|
||||
RESET_LIST="A1/A2/A3 A1/A2 A1 B1"
|
||||
I=0
|
||||
@@ -1003,7 +1008,6 @@ run_state_test()
|
||||
run_remote_state_test()
|
||||
{
|
||||
TEST=$1
|
||||
CONTROLLER=cpuset
|
||||
[[ -d rtest ]] || mkdir rtest
|
||||
cd rtest
|
||||
echo +cpuset > cgroup.subtree_control
|
||||
|
||||
@@ -93,6 +93,8 @@ BPF_CFLAGS = -g -D__TARGET_ARCH_$(SRCARCH) \
|
||||
$(CLANG_SYS_INCLUDES) \
|
||||
-Wall -Wno-compare-distinct-pointer-types \
|
||||
-Wno-incompatible-function-pointer-types \
|
||||
-Wno-microsoft-anon-tag \
|
||||
-fms-extensions \
|
||||
-O2 -mcpu=v3
|
||||
|
||||
# sort removes libbpf duplicates when not cross-building
|
||||
|
||||
@@ -57,7 +57,8 @@ static enum scx_test_status run_test(bool global)
|
||||
char buf;
|
||||
|
||||
close(pipe_fds[1]);
|
||||
read(pipe_fds[0], &buf, 1);
|
||||
if (read(pipe_fds[0], &buf, 1) < 0)
|
||||
exit(1);
|
||||
close(pipe_fds[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -58,14 +58,14 @@ static void record_peek_result(long pid)
|
||||
{
|
||||
u32 slot_key;
|
||||
long *slot_pid_ptr;
|
||||
int ix;
|
||||
u32 ix;
|
||||
|
||||
if (pid <= 0)
|
||||
return;
|
||||
|
||||
/* Find an empty slot or one with the same PID */
|
||||
bpf_for(ix, 0, 10) {
|
||||
slot_key = (pid + ix) % MAX_SAMPLES;
|
||||
slot_key = ((u64)pid + ix) % MAX_SAMPLES;
|
||||
slot_pid_ptr = bpf_map_lookup_elem(&peek_results, &slot_key);
|
||||
if (!slot_pid_ptr)
|
||||
continue;
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <signal.h>
|
||||
#include <bpf/bpf.h>
|
||||
#include <scx/common.h>
|
||||
#include <unistd.h>
|
||||
#include "rt_stall.bpf.skel.h"
|
||||
#include "scx_test.h"
|
||||
#include "../kselftest.h"
|
||||
|
||||
@@ -166,6 +166,9 @@ int main(int argc, char **argv)
|
||||
enum scx_test_status status;
|
||||
struct scx_test *test = &__scx_tests[i];
|
||||
|
||||
if (exit_req)
|
||||
break;
|
||||
|
||||
if (list) {
|
||||
printf("%s\n", test->name);
|
||||
if (i == (__scx_num_tests - 1))
|
||||
|
||||
Reference in new issue
Block a user