aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.com>2016-06-02 02:19:52 -0400
committerShaohua Li <shli@fb.com>2016-06-13 14:54:18 -0400
commit707a6a420ccf31634f2b15d8f06f09536e2de079 (patch)
treebd4661927839a5e2e65a8e8de6ef3572841d6ea1
parent854abd75841413f7966bc4fed83b36e78a1c285c (diff)
md/raid1: add rcu protection to rdev in fix_read_error
Since remove_and_add_spares() was added to hot_remove_disk() it has been possible for an rdev to be hot-removed while fix_read_error() was running, so we need to be more careful, and take a reference to the rdev while performing IO. Signed-off-by: NeilBrown <neilb@suse.com> Signed-off-by: Shaohua Li <shli@fb.com>
-rw-r--r--drivers/md/raid1.c52
1 files changed, 32 insertions, 20 deletions
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 60c293df03f1..34f20c03d1f6 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2056,29 +2056,30 @@ static void fix_read_error(struct r1conf *conf, int read_disk,
2056 s = PAGE_SIZE >> 9; 2056 s = PAGE_SIZE >> 9;
2057 2057
2058 do { 2058 do {
2059 /* Note: no rcu protection needed here
2060 * as this is synchronous in the raid1d thread
2061 * which is the thread that might remove
2062 * a device. If raid1d ever becomes multi-threaded....
2063 */
2064 sector_t first_bad; 2059 sector_t first_bad;
2065 int bad_sectors; 2060 int bad_sectors;
2066 2061
2067 rdev = conf->mirrors[d].rdev; 2062 rcu_read_lock();
2063 rdev = rcu_dereference(conf->mirrors[d].rdev);
2068 if (rdev && 2064 if (rdev &&
2069 (test_bit(In_sync, &rdev->flags) || 2065 (test_bit(In_sync, &rdev->flags) ||
2070 (!test_bit(Faulty, &rdev->flags) && 2066 (!test_bit(Faulty, &rdev->flags) &&
2071 rdev->recovery_offset >= sect + s)) && 2067 rdev->recovery_offset >= sect + s)) &&
2072 is_badblock(rdev, sect, s, 2068 is_badblock(rdev, sect, s,
2073 &first_bad, &bad_sectors) == 0 && 2069 &first_bad, &bad_sectors) == 0) {
2074 sync_page_io(rdev, sect, s<<9, 2070 atomic_inc(&rdev->nr_pending);
2075 conf->tmppage, READ, false)) 2071 rcu_read_unlock();
2076 success = 1; 2072 if (sync_page_io(rdev, sect, s<<9,
2077 else { 2073 conf->tmppage, READ, false))
2078 d++; 2074 success = 1;
2079 if (d == conf->raid_disks * 2) 2075 rdev_dec_pending(rdev, mddev);
2080 d = 0; 2076 if (success)
2081 } 2077 break;
2078 } else
2079 rcu_read_unlock();
2080 d++;
2081 if (d == conf->raid_disks * 2)
2082 d = 0;
2082 } while (!success && d != read_disk); 2083 } while (!success && d != read_disk);
2083 2084
2084 if (!success) { 2085 if (!success) {
@@ -2094,11 +2095,17 @@ static void fix_read_error(struct r1conf *conf, int read_disk,
2094 if (d==0) 2095 if (d==0)
2095 d = conf->raid_disks * 2; 2096 d = conf->raid_disks * 2;
2096 d--; 2097 d--;
2097 rdev = conf->mirrors[d].rdev; 2098 rcu_read_lock();
2099 rdev = rcu_dereference(conf->mirrors[d].rdev);
2098 if (rdev && 2100 if (rdev &&
2099 !test_bit(Faulty, &rdev->flags)) 2101 !test_bit(Faulty, &rdev->flags)) {
2102 atomic_inc(&rdev->nr_pending);
2103 rcu_read_unlock();
2100 r1_sync_page_io(rdev, sect, s, 2104 r1_sync_page_io(rdev, sect, s,
2101 conf->tmppage, WRITE); 2105 conf->tmppage, WRITE);
2106 rdev_dec_pending(rdev, mddev);
2107 } else
2108 rcu_read_unlock();
2102 } 2109 }
2103 d = start; 2110 d = start;
2104 while (d != read_disk) { 2111 while (d != read_disk) {
@@ -2106,9 +2113,12 @@ static void fix_read_error(struct r1conf *conf, int read_disk,
2106 if (d==0) 2113 if (d==0)
2107 d = conf->raid_disks * 2; 2114 d = conf->raid_disks * 2;
2108 d--; 2115 d--;
2109 rdev = conf->mirrors[d].rdev; 2116 rcu_read_lock();
2117 rdev = rcu_dereference(conf->mirrors[d].rdev);
2110 if (rdev && 2118 if (rdev &&
2111 !test_bit(Faulty, &rdev->flags)) { 2119 !test_bit(Faulty, &rdev->flags)) {
2120 atomic_inc(&rdev->nr_pending);
2121 rcu_read_unlock();
2112 if (r1_sync_page_io(rdev, sect, s, 2122 if (r1_sync_page_io(rdev, sect, s,
2113 conf->tmppage, READ)) { 2123 conf->tmppage, READ)) {
2114 atomic_add(s, &rdev->corrected_errors); 2124 atomic_add(s, &rdev->corrected_errors);
@@ -2117,10 +2127,12 @@ static void fix_read_error(struct r1conf *conf, int read_disk,
2117 "(%d sectors at %llu on %s)\n", 2127 "(%d sectors at %llu on %s)\n",
2118 mdname(mddev), s, 2128 mdname(mddev), s,
2119 (unsigned long long)(sect + 2129 (unsigned long long)(sect +
2120 rdev->data_offset), 2130 rdev->data_offset),
2121 bdevname(rdev->bdev, b)); 2131 bdevname(rdev->bdev, b));
2122 } 2132 }
2123 } 2133 rdev_dec_pending(rdev, mddev);
2134 } else
2135 rcu_read_unlock();
2124 } 2136 }
2125 sectors -= s; 2137 sectors -= s;
2126 sect += s; 2138 sect += s;