Commit 06a4d0d8 authored by Yu Kuai's avatar Yu Kuai Committed by Song Liu

md/raid5-cache: use READ_ONCE/WRITE_ONCE for 'conf->log'

'conf->log' is set with 'reconfig_mutex' grabbed, however, readers are
not procted, hence protect it with READ_ONCE/WRITE_ONCE to prevent
reading abnormal values.
Signed-off-by: default avatarYu Kuai <yukuai3@huawei.com>
Signed-off-by: default avatarSong Liu <song@kernel.org>
Link: https://lore.kernel.org/r/20231010151958.145896-3-yukuai1@huaweicloud.com
parent 617787f1
...@@ -327,8 +327,9 @@ void r5l_wake_reclaim(struct r5l_log *log, sector_t space); ...@@ -327,8 +327,9 @@ void r5l_wake_reclaim(struct r5l_log *log, sector_t space);
void r5c_check_stripe_cache_usage(struct r5conf *conf) void r5c_check_stripe_cache_usage(struct r5conf *conf)
{ {
int total_cached; int total_cached;
struct r5l_log *log = READ_ONCE(conf->log);
if (!r5c_is_writeback(conf->log)) if (!r5c_is_writeback(log))
return; return;
total_cached = atomic_read(&conf->r5c_cached_partial_stripes) + total_cached = atomic_read(&conf->r5c_cached_partial_stripes) +
...@@ -344,7 +345,7 @@ void r5c_check_stripe_cache_usage(struct r5conf *conf) ...@@ -344,7 +345,7 @@ void r5c_check_stripe_cache_usage(struct r5conf *conf)
*/ */
if (total_cached > conf->min_nr_stripes * 1 / 2 || if (total_cached > conf->min_nr_stripes * 1 / 2 ||
atomic_read(&conf->empty_inactive_list_nr) > 0) atomic_read(&conf->empty_inactive_list_nr) > 0)
r5l_wake_reclaim(conf->log, 0); r5l_wake_reclaim(log, 0);
} }
/* /*
...@@ -353,7 +354,9 @@ void r5c_check_stripe_cache_usage(struct r5conf *conf) ...@@ -353,7 +354,9 @@ void r5c_check_stripe_cache_usage(struct r5conf *conf)
*/ */
void r5c_check_cached_full_stripe(struct r5conf *conf) void r5c_check_cached_full_stripe(struct r5conf *conf)
{ {
if (!r5c_is_writeback(conf->log)) struct r5l_log *log = READ_ONCE(conf->log);
if (!r5c_is_writeback(log))
return; return;
/* /*
...@@ -363,7 +366,7 @@ void r5c_check_cached_full_stripe(struct r5conf *conf) ...@@ -363,7 +366,7 @@ void r5c_check_cached_full_stripe(struct r5conf *conf)
if (atomic_read(&conf->r5c_cached_full_stripes) >= if (atomic_read(&conf->r5c_cached_full_stripes) >=
min(R5C_FULL_STRIPE_FLUSH_BATCH(conf), min(R5C_FULL_STRIPE_FLUSH_BATCH(conf),
conf->chunk_sectors >> RAID5_STRIPE_SHIFT(conf))) conf->chunk_sectors >> RAID5_STRIPE_SHIFT(conf)))
r5l_wake_reclaim(conf->log, 0); r5l_wake_reclaim(log, 0);
} }
/* /*
...@@ -396,7 +399,7 @@ void r5c_check_cached_full_stripe(struct r5conf *conf) ...@@ -396,7 +399,7 @@ void r5c_check_cached_full_stripe(struct r5conf *conf)
*/ */
static sector_t r5c_log_required_to_flush_cache(struct r5conf *conf) static sector_t r5c_log_required_to_flush_cache(struct r5conf *conf)
{ {
struct r5l_log *log = conf->log; struct r5l_log *log = READ_ONCE(conf->log);
if (!r5c_is_writeback(log)) if (!r5c_is_writeback(log))
return 0; return 0;
...@@ -449,7 +452,7 @@ static inline void r5c_update_log_state(struct r5l_log *log) ...@@ -449,7 +452,7 @@ static inline void r5c_update_log_state(struct r5l_log *log)
void r5c_make_stripe_write_out(struct stripe_head *sh) void r5c_make_stripe_write_out(struct stripe_head *sh)
{ {
struct r5conf *conf = sh->raid_conf; struct r5conf *conf = sh->raid_conf;
struct r5l_log *log = conf->log; struct r5l_log *log = READ_ONCE(conf->log);
BUG_ON(!r5c_is_writeback(log)); BUG_ON(!r5c_is_writeback(log));
...@@ -491,7 +494,7 @@ static void r5c_handle_parity_cached(struct stripe_head *sh) ...@@ -491,7 +494,7 @@ static void r5c_handle_parity_cached(struct stripe_head *sh)
*/ */
static void r5c_finish_cache_stripe(struct stripe_head *sh) static void r5c_finish_cache_stripe(struct stripe_head *sh)
{ {
struct r5l_log *log = sh->raid_conf->log; struct r5l_log *log = READ_ONCE(sh->raid_conf->log);
if (log->r5c_journal_mode == R5C_JOURNAL_MODE_WRITE_THROUGH) { if (log->r5c_journal_mode == R5C_JOURNAL_MODE_WRITE_THROUGH) {
BUG_ON(test_bit(STRIPE_R5C_CACHING, &sh->state)); BUG_ON(test_bit(STRIPE_R5C_CACHING, &sh->state));
...@@ -692,7 +695,7 @@ static void r5c_disable_writeback_async(struct work_struct *work) ...@@ -692,7 +695,7 @@ static void r5c_disable_writeback_async(struct work_struct *work)
/* wait superblock change before suspend */ /* wait superblock change before suspend */
wait_event(mddev->sb_wait, wait_event(mddev->sb_wait,
conf->log == NULL || !READ_ONCE(conf->log) ||
(!test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags) && (!test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags) &&
(locked = mddev_trylock(mddev)))); (locked = mddev_trylock(mddev))));
if (locked) { if (locked) {
...@@ -1151,7 +1154,7 @@ static void r5l_run_no_space_stripes(struct r5l_log *log) ...@@ -1151,7 +1154,7 @@ static void r5l_run_no_space_stripes(struct r5l_log *log)
static sector_t r5c_calculate_new_cp(struct r5conf *conf) static sector_t r5c_calculate_new_cp(struct r5conf *conf)
{ {
struct stripe_head *sh; struct stripe_head *sh;
struct r5l_log *log = conf->log; struct r5l_log *log = READ_ONCE(conf->log);
sector_t new_cp; sector_t new_cp;
unsigned long flags; unsigned long flags;
...@@ -1159,12 +1162,12 @@ static sector_t r5c_calculate_new_cp(struct r5conf *conf) ...@@ -1159,12 +1162,12 @@ static sector_t r5c_calculate_new_cp(struct r5conf *conf)
return log->next_checkpoint; return log->next_checkpoint;
spin_lock_irqsave(&log->stripe_in_journal_lock, flags); spin_lock_irqsave(&log->stripe_in_journal_lock, flags);
if (list_empty(&conf->log->stripe_in_journal_list)) { if (list_empty(&log->stripe_in_journal_list)) {
/* all stripes flushed */ /* all stripes flushed */
spin_unlock_irqrestore(&log->stripe_in_journal_lock, flags); spin_unlock_irqrestore(&log->stripe_in_journal_lock, flags);
return log->next_checkpoint; return log->next_checkpoint;
} }
sh = list_first_entry(&conf->log->stripe_in_journal_list, sh = list_first_entry(&log->stripe_in_journal_list,
struct stripe_head, r5c); struct stripe_head, r5c);
new_cp = sh->log_start; new_cp = sh->log_start;
spin_unlock_irqrestore(&log->stripe_in_journal_lock, flags); spin_unlock_irqrestore(&log->stripe_in_journal_lock, flags);
...@@ -1399,7 +1402,7 @@ void r5c_flush_cache(struct r5conf *conf, int num) ...@@ -1399,7 +1402,7 @@ void r5c_flush_cache(struct r5conf *conf, int num)
struct stripe_head *sh, *next; struct stripe_head *sh, *next;
lockdep_assert_held(&conf->device_lock); lockdep_assert_held(&conf->device_lock);
if (!conf->log) if (!READ_ONCE(conf->log))
return; return;
count = 0; count = 0;
...@@ -1420,7 +1423,7 @@ void r5c_flush_cache(struct r5conf *conf, int num) ...@@ -1420,7 +1423,7 @@ void r5c_flush_cache(struct r5conf *conf, int num)
static void r5c_do_reclaim(struct r5conf *conf) static void r5c_do_reclaim(struct r5conf *conf)
{ {
struct r5l_log *log = conf->log; struct r5l_log *log = READ_ONCE(conf->log);
struct stripe_head *sh; struct stripe_head *sh;
int count = 0; int count = 0;
unsigned long flags; unsigned long flags;
...@@ -1549,7 +1552,7 @@ static void r5l_reclaim_thread(struct md_thread *thread) ...@@ -1549,7 +1552,7 @@ static void r5l_reclaim_thread(struct md_thread *thread)
{ {
struct mddev *mddev = thread->mddev; struct mddev *mddev = thread->mddev;
struct r5conf *conf = mddev->private; struct r5conf *conf = mddev->private;
struct r5l_log *log = conf->log; struct r5l_log *log = READ_ONCE(conf->log);
if (!log) if (!log)
return; return;
...@@ -1591,7 +1594,7 @@ void r5l_quiesce(struct r5l_log *log, int quiesce) ...@@ -1591,7 +1594,7 @@ void r5l_quiesce(struct r5l_log *log, int quiesce)
bool r5l_log_disk_error(struct r5conf *conf) bool r5l_log_disk_error(struct r5conf *conf)
{ {
struct r5l_log *log = conf->log; struct r5l_log *log = READ_ONCE(conf->log);
/* don't allow write if journal disk is missing */ /* don't allow write if journal disk is missing */
if (!log) if (!log)
...@@ -2635,7 +2638,7 @@ int r5c_try_caching_write(struct r5conf *conf, ...@@ -2635,7 +2638,7 @@ int r5c_try_caching_write(struct r5conf *conf,
struct stripe_head_state *s, struct stripe_head_state *s,
int disks) int disks)
{ {
struct r5l_log *log = conf->log; struct r5l_log *log = READ_ONCE(conf->log);
int i; int i;
struct r5dev *dev; struct r5dev *dev;
int to_cache = 0; int to_cache = 0;
...@@ -2802,7 +2805,7 @@ void r5c_finish_stripe_write_out(struct r5conf *conf, ...@@ -2802,7 +2805,7 @@ void r5c_finish_stripe_write_out(struct r5conf *conf,
struct stripe_head *sh, struct stripe_head *sh,
struct stripe_head_state *s) struct stripe_head_state *s)
{ {
struct r5l_log *log = conf->log; struct r5l_log *log = READ_ONCE(conf->log);
int i; int i;
int do_wakeup = 0; int do_wakeup = 0;
sector_t tree_index; sector_t tree_index;
...@@ -2941,7 +2944,7 @@ int r5c_cache_data(struct r5l_log *log, struct stripe_head *sh) ...@@ -2941,7 +2944,7 @@ int r5c_cache_data(struct r5l_log *log, struct stripe_head *sh)
/* check whether this big stripe is in write back cache. */ /* check whether this big stripe is in write back cache. */
bool r5c_big_stripe_cached(struct r5conf *conf, sector_t sect) bool r5c_big_stripe_cached(struct r5conf *conf, sector_t sect)
{ {
struct r5l_log *log = conf->log; struct r5l_log *log = READ_ONCE(conf->log);
sector_t tree_index; sector_t tree_index;
void *slot; void *slot;
...@@ -3049,14 +3052,14 @@ int r5l_start(struct r5l_log *log) ...@@ -3049,14 +3052,14 @@ int r5l_start(struct r5l_log *log)
void r5c_update_on_rdev_error(struct mddev *mddev, struct md_rdev *rdev) void r5c_update_on_rdev_error(struct mddev *mddev, struct md_rdev *rdev)
{ {
struct r5conf *conf = mddev->private; struct r5conf *conf = mddev->private;
struct r5l_log *log = conf->log; struct r5l_log *log = READ_ONCE(conf->log);
if (!log) if (!log)
return; return;
if ((raid5_calc_degraded(conf) > 0 || if ((raid5_calc_degraded(conf) > 0 ||
test_bit(Journal, &rdev->flags)) && test_bit(Journal, &rdev->flags)) &&
conf->log->r5c_journal_mode == R5C_JOURNAL_MODE_WRITE_BACK) log->r5c_journal_mode == R5C_JOURNAL_MODE_WRITE_BACK)
schedule_work(&log->disable_writeback_work); schedule_work(&log->disable_writeback_work);
} }
...@@ -3145,7 +3148,7 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev) ...@@ -3145,7 +3148,7 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev)
spin_lock_init(&log->stripe_in_journal_lock); spin_lock_init(&log->stripe_in_journal_lock);
atomic_set(&log->stripe_in_journal_count, 0); atomic_set(&log->stripe_in_journal_count, 0);
conf->log = log; WRITE_ONCE(conf->log, log);
set_bit(MD_HAS_JOURNAL, &conf->mddev->flags); set_bit(MD_HAS_JOURNAL, &conf->mddev->flags);
return 0; return 0;
...@@ -3173,7 +3176,7 @@ void r5l_exit_log(struct r5conf *conf) ...@@ -3173,7 +3176,7 @@ void r5l_exit_log(struct r5conf *conf)
* 'reconfig_mutex' is held by caller, set 'confg->log' to NULL to * 'reconfig_mutex' is held by caller, set 'confg->log' to NULL to
* ensure disable_writeback_work wakes up and exits. * ensure disable_writeback_work wakes up and exits.
*/ */
conf->log = NULL; WRITE_ONCE(conf->log, NULL);
wake_up(&conf->mddev->sb_wait); wake_up(&conf->mddev->sb_wait);
flush_work(&log->disable_writeback_work); flush_work(&log->disable_writeback_work);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment