diff --git a/mm/memcontrol.c b/mm/memcontrol.c index ff64d2c36749edbd0daa6639397271747b8eab08..fff8b93225219c6b5e99e6b114516f0aa3e02e02 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -4415,21 +4415,21 @@ static int sysctl_memcg_swap_qos_handler(struct ctl_table *table, int write, void __user *buffer, size_t *length, loff_t *ppos) { int ret; - int qos_stat_old = sysctl_memcg_swap_qos_stat; + int qos_stat_old; int swap_type; + static DEFINE_MUTEX(sysctl_mutex); + mutex_lock(&sysctl_mutex); + qos_stat_old = sysctl_memcg_swap_qos_stat; ret = proc_dointvec_minmax(table, write, buffer, length, ppos); - if (ret) - return ret; - - if (write) { + if (write && !ret) { if (qos_stat_old == sysctl_memcg_swap_qos_stat) - return 0; + goto unlock; switch (sysctl_memcg_swap_qos_stat) { case MEMCG_SWAP_STAT_DISABLE: static_branch_disable(&memcg_swap_qos_key); - return 0; + goto unlock; case MEMCG_SWAP_STAT_ALL: swap_type = SWAP_TYPE_ALL; break; @@ -4438,16 +4438,26 @@ static int sysctl_memcg_swap_qos_handler(struct ctl_table *table, int write, break; } + /* + * Enable the feature when it is in disabled state. + * If it is already in enabled state, don't allowed + * to switch it to other state directly since it is + * dangerous that will impact all memory cgroups. + */ if (qos_stat_old == MEMCG_SWAP_STAT_DISABLE) { memcg_swap_qos_reset(swap_type); static_branch_enable(&memcg_swap_qos_key); enable_swap_slots_cache_max(); } else { - return -EINVAL; + sysctl_memcg_swap_qos_stat = qos_stat_old; + ret = -EINVAL; } } - return 0; +unlock: + mutex_unlock(&sysctl_mutex); + + return ret; } #endif diff --git a/mm/swapfile.c b/mm/swapfile.c index ddb50283f2f1d4f76e42744d0859b3067f1728c5..744e5c8bd66b7d7fa6912bd2aa756c0023481011 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1171,15 +1171,13 @@ int get_swap_pages(int n_goal, swp_entry_t swp_entries[], int entry_order, start_over: node = numa_node_id(); plist_for_each_entry_safe(si, next, &swap_avail_heads[node], avail_lists[node]) { + if (should_skip_swap_type(si->type, type)) + goto nextsi; + /* requeue si to after same-priority siblings */ plist_requeue(&si->avail_lists[node], &swap_avail_heads[node]); spin_unlock(&swap_avail_lock); spin_lock(&si->lock); - if (should_skip_swap_type(si->type, type)) { - spin_unlock(&si->lock); - spin_lock(&swap_avail_lock); - goto nextsi; - } if (!si->highest_bit || !(si->flags & SWP_WRITEOK)) { spin_lock(&swap_avail_lock); if (plist_node_empty(&si->avail_lists[node])) {