|
@@ -18,6 +18,19 @@
|
|
|
|
|
|
#ifdef CONFIG_CPUSETS
|
|
#ifdef CONFIG_CPUSETS
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Static branch rewrites can happen in an arbitrary order for a given
|
|
|
|
+ * key. In code paths where we need to loop with read_mems_allowed_begin() and
|
|
|
|
+ * read_mems_allowed_retry() to get a consistent view of mems_allowed, we need
|
|
|
|
+ * to ensure that begin() always gets rewritten before retry() in the
|
|
|
|
+ * disabled -> enabled transition. If not, then if local irqs are disabled
|
|
|
|
+ * around the loop, we can deadlock since retry() would always be
|
|
|
|
+ * comparing the latest value of the mems_allowed seqcount against 0 as
|
|
|
|
+ * begin() still would see cpusets_enabled() as false. The enabled -> disabled
|
|
|
|
+ * transition should happen in reverse order for the same reasons (want to stop
|
|
|
|
+ * looking at real value of mems_allowed.sequence in retry() first).
|
|
|
|
+ */
|
|
|
|
+extern struct static_key_false cpusets_pre_enable_key;
|
|
extern struct static_key_false cpusets_enabled_key;
|
|
extern struct static_key_false cpusets_enabled_key;
|
|
static inline bool cpusets_enabled(void)
|
|
static inline bool cpusets_enabled(void)
|
|
{
|
|
{
|
|
@@ -32,12 +45,14 @@ static inline int nr_cpusets(void)
|
|
|
|
|
|
static inline void cpuset_inc(void)
|
|
static inline void cpuset_inc(void)
|
|
{
|
|
{
|
|
|
|
+ static_branch_inc(&cpusets_pre_enable_key);
|
|
static_branch_inc(&cpusets_enabled_key);
|
|
static_branch_inc(&cpusets_enabled_key);
|
|
}
|
|
}
|
|
|
|
|
|
static inline void cpuset_dec(void)
|
|
static inline void cpuset_dec(void)
|
|
{
|
|
{
|
|
static_branch_dec(&cpusets_enabled_key);
|
|
static_branch_dec(&cpusets_enabled_key);
|
|
|
|
+ static_branch_dec(&cpusets_pre_enable_key);
|
|
}
|
|
}
|
|
|
|
|
|
extern int cpuset_init(void);
|
|
extern int cpuset_init(void);
|
|
@@ -115,7 +130,7 @@ extern void cpuset_print_current_mems_allowed(void);
|
|
*/
|
|
*/
|
|
static inline unsigned int read_mems_allowed_begin(void)
|
|
static inline unsigned int read_mems_allowed_begin(void)
|
|
{
|
|
{
|
|
- if (!cpusets_enabled())
|
|
|
|
|
|
+ if (!static_branch_unlikely(&cpusets_pre_enable_key))
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
return read_seqcount_begin(¤t->mems_allowed_seq);
|
|
return read_seqcount_begin(¤t->mems_allowed_seq);
|
|
@@ -129,7 +144,7 @@ static inline unsigned int read_mems_allowed_begin(void)
|
|
*/
|
|
*/
|
|
static inline bool read_mems_allowed_retry(unsigned int seq)
|
|
static inline bool read_mems_allowed_retry(unsigned int seq)
|
|
{
|
|
{
|
|
- if (!cpusets_enabled())
|
|
|
|
|
|
+ if (!static_branch_unlikely(&cpusets_enabled_key))
|
|
return false;
|
|
return false;
|
|
|
|
|
|
return read_seqcount_retry(¤t->mems_allowed_seq, seq);
|
|
return read_seqcount_retry(¤t->mems_allowed_seq, seq);
|