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

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
Loading
Loading
Loading
Loading
+25 −22
Original line number Diff line number Diff line
@@ -327,8 +327,9 @@ void r5l_wake_reclaim(struct r5l_log *log, sector_t space);
void r5c_check_stripe_cache_usage(struct r5conf *conf)
{
	int total_cached;
	struct r5l_log *log = READ_ONCE(conf->log);

	if (!r5c_is_writeback(conf->log))
	if (!r5c_is_writeback(log))
		return;

	total_cached = atomic_read(&conf->r5c_cached_partial_stripes) +
@@ -344,7 +345,7 @@ void r5c_check_stripe_cache_usage(struct r5conf *conf)
	 */
	if (total_cached > conf->min_nr_stripes * 1 / 2 ||
	    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)
 */
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;

	/*
@@ -363,7 +366,7 @@ void r5c_check_cached_full_stripe(struct r5conf *conf)
	if (atomic_read(&conf->r5c_cached_full_stripes) >=
	    min(R5C_FULL_STRIPE_FLUSH_BATCH(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)
 */
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))
		return 0;
@@ -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)
{
	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));

@@ -491,7 +494,7 @@ static void r5c_handle_parity_cached(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) {
		BUG_ON(test_bit(STRIPE_R5C_CACHING, &sh->state));
@@ -692,7 +695,7 @@ static void r5c_disable_writeback_async(struct work_struct *work)

	/* wait superblock change before suspend */
	wait_event(mddev->sb_wait,
		   conf->log == NULL ||
		   !READ_ONCE(conf->log) ||
		   (!test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags) &&
		    (locked = mddev_trylock(mddev))));
	if (locked) {
@@ -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)
{
	struct stripe_head *sh;
	struct r5l_log *log = conf->log;
	struct r5l_log *log = READ_ONCE(conf->log);
	sector_t new_cp;
	unsigned long flags;

@@ -1159,12 +1162,12 @@ static sector_t r5c_calculate_new_cp(struct r5conf *conf)
		return log->next_checkpoint;

	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 */
		spin_unlock_irqrestore(&log->stripe_in_journal_lock, flags);
		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);
	new_cp = sh->log_start;
	spin_unlock_irqrestore(&log->stripe_in_journal_lock, flags);
@@ -1399,7 +1402,7 @@ void r5c_flush_cache(struct r5conf *conf, int num)
	struct stripe_head *sh, *next;

	lockdep_assert_held(&conf->device_lock);
	if (!conf->log)
	if (!READ_ONCE(conf->log))
		return;

	count = 0;
@@ -1420,7 +1423,7 @@ void r5c_flush_cache(struct r5conf *conf, int num)

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;
	int count = 0;
	unsigned long flags;
@@ -1549,7 +1552,7 @@ static void r5l_reclaim_thread(struct md_thread *thread)
{
	struct mddev *mddev = thread->mddev;
	struct r5conf *conf = mddev->private;
	struct r5l_log *log = conf->log;
	struct r5l_log *log = READ_ONCE(conf->log);

	if (!log)
		return;
@@ -1591,7 +1594,7 @@ void r5l_quiesce(struct r5l_log *log, int quiesce)

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 */
	if (!log)
@@ -2635,7 +2638,7 @@ int r5c_try_caching_write(struct r5conf *conf,
			  struct stripe_head_state *s,
			  int disks)
{
	struct r5l_log *log = conf->log;
	struct r5l_log *log = READ_ONCE(conf->log);
	int i;
	struct r5dev *dev;
	int to_cache = 0;
@@ -2802,7 +2805,7 @@ void r5c_finish_stripe_write_out(struct r5conf *conf,
				 struct stripe_head *sh,
				 struct stripe_head_state *s)
{
	struct r5l_log *log = conf->log;
	struct r5l_log *log = READ_ONCE(conf->log);
	int i;
	int do_wakeup = 0;
	sector_t tree_index;
@@ -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. */
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;
	void *slot;

@@ -3049,14 +3052,14 @@ int r5l_start(struct r5l_log *log)
void r5c_update_on_rdev_error(struct mddev *mddev, struct md_rdev *rdev)
{
	struct r5conf *conf = mddev->private;
	struct r5l_log *log = conf->log;
	struct r5l_log *log = READ_ONCE(conf->log);

	if (!log)
		return;

	if ((raid5_calc_degraded(conf) > 0 ||
	     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);
}

@@ -3145,7 +3148,7 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev)
	spin_lock_init(&log->stripe_in_journal_lock);
	atomic_set(&log->stripe_in_journal_count, 0);

	conf->log = log;
	WRITE_ONCE(conf->log, log);

	set_bit(MD_HAS_JOURNAL, &conf->mddev->flags);
	return 0;
@@ -3173,7 +3176,7 @@ void r5l_exit_log(struct r5conf *conf)
	 * 'reconfig_mutex' is held by caller, set 'confg->log' to NULL to
	 * ensure disable_writeback_work wakes up and exits.
	 */
	conf->log = NULL;
	WRITE_ONCE(conf->log, NULL);
	wake_up(&conf->mddev->sb_wait);
	flush_work(&log->disable_writeback_work);