diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2012-08-16 08:25:58 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2012-10-30 03:39:01 -0400 |
commit | 9f2247bb9b75b2be65a12167c89271121b2c90c5 (patch) | |
tree | 3fe1fffca38eddf1a47cc91142cf74fadc82cae6 | |
parent | 35fd3dc58da675d659513384221349ef90749a01 (diff) |
drbd: Protect accesses to the uuid set with a spinlock
There is at least the worker context, the receiver context, the context of
receiving netlink packts and processes reading a sysfs attribute that access
the uuids.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r-- | drivers/block/drbd/drbd_int.h | 4 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 33 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 5 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 11 |
4 files changed, 43 insertions, 10 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index b953cc7c9c00..9a6d3a4a739a 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h | |||
@@ -912,6 +912,7 @@ struct drbd_md { | |||
912 | u64 md_offset; /* sector offset to 'super' block */ | 912 | u64 md_offset; /* sector offset to 'super' block */ |
913 | 913 | ||
914 | u64 la_size_sect; /* last agreed size, unit sectors */ | 914 | u64 la_size_sect; /* last agreed size, unit sectors */ |
915 | spinlock_t uuid_lock; | ||
915 | u64 uuid[UI_SIZE]; | 916 | u64 uuid[UI_SIZE]; |
916 | u64 device_uuid; | 917 | u64 device_uuid; |
917 | u32 flags; | 918 | u32 flags; |
@@ -1283,8 +1284,9 @@ extern int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev); | |||
1283 | extern void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local); | 1284 | extern void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local); |
1284 | extern void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local); | 1285 | extern void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local); |
1285 | extern void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local); | 1286 | extern void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local); |
1286 | extern void _drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local); | ||
1287 | extern void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local); | 1287 | extern void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local); |
1288 | extern void drbd_uuid_move_history(struct drbd_conf *mdev) __must_hold(local); | ||
1289 | extern void __drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local); | ||
1288 | extern void drbd_md_set_flag(struct drbd_conf *mdev, int flags) __must_hold(local); | 1290 | extern void drbd_md_set_flag(struct drbd_conf *mdev, int flags) __must_hold(local); |
1289 | extern void drbd_md_clear_flag(struct drbd_conf *mdev, int flags)__must_hold(local); | 1291 | extern void drbd_md_clear_flag(struct drbd_conf *mdev, int flags)__must_hold(local); |
1290 | extern int drbd_md_test_flag(struct drbd_backing_dev *, int); | 1292 | extern int drbd_md_test_flag(struct drbd_backing_dev *, int); |
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index f55683ad4ffa..dfa08b7411c0 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c | |||
@@ -2125,8 +2125,10 @@ int _drbd_send_uuids(struct drbd_conf *mdev, u64 uuid_flags) | |||
2125 | if (!get_ldev_if_state(mdev, D_NEGOTIATING)) | 2125 | if (!get_ldev_if_state(mdev, D_NEGOTIATING)) |
2126 | return 1; | 2126 | return 1; |
2127 | 2127 | ||
2128 | spin_lock_irq(&mdev->ldev->md.uuid_lock); | ||
2128 | for (i = UI_CURRENT; i < UI_SIZE; i++) | 2129 | for (i = UI_CURRENT; i < UI_SIZE; i++) |
2129 | p.uuid[i] = mdev->ldev ? cpu_to_be64(mdev->ldev->md.uuid[i]) : 0; | 2130 | p.uuid[i] = mdev->ldev ? cpu_to_be64(mdev->ldev->md.uuid[i]) : 0; |
2131 | spin_unlock_irq(&mdev->ldev->md.uuid_lock); | ||
2130 | 2132 | ||
2131 | mdev->comm_bm_set = drbd_bm_total_weight(mdev); | 2133 | mdev->comm_bm_set = drbd_bm_total_weight(mdev); |
2132 | p.uuid[UI_SIZE] = cpu_to_be64(mdev->comm_bm_set); | 2134 | p.uuid[UI_SIZE] = cpu_to_be64(mdev->comm_bm_set); |
@@ -4011,7 +4013,7 @@ void drbd_md_mark_dirty(struct drbd_conf *mdev) | |||
4011 | } | 4013 | } |
4012 | #endif | 4014 | #endif |
4013 | 4015 | ||
4014 | static void drbd_uuid_move_history(struct drbd_conf *mdev) __must_hold(local) | 4016 | void drbd_uuid_move_history(struct drbd_conf *mdev) __must_hold(local) |
4015 | { | 4017 | { |
4016 | int i; | 4018 | int i; |
4017 | 4019 | ||
@@ -4019,7 +4021,7 @@ static void drbd_uuid_move_history(struct drbd_conf *mdev) __must_hold(local) | |||
4019 | mdev->ldev->md.uuid[i+1] = mdev->ldev->md.uuid[i]; | 4021 | mdev->ldev->md.uuid[i+1] = mdev->ldev->md.uuid[i]; |
4020 | } | 4022 | } |
4021 | 4023 | ||
4022 | void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) | 4024 | void __drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) |
4023 | { | 4025 | { |
4024 | if (idx == UI_CURRENT) { | 4026 | if (idx == UI_CURRENT) { |
4025 | if (mdev->state.role == R_PRIMARY) | 4027 | if (mdev->state.role == R_PRIMARY) |
@@ -4034,14 +4036,24 @@ void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) | |||
4034 | drbd_md_mark_dirty(mdev); | 4036 | drbd_md_mark_dirty(mdev); |
4035 | } | 4037 | } |
4036 | 4038 | ||
4039 | void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) | ||
4040 | { | ||
4041 | unsigned long flags; | ||
4042 | spin_lock_irqsave(&mdev->ldev->md.uuid_lock, flags); | ||
4043 | __drbd_uuid_set(mdev, idx, val); | ||
4044 | spin_unlock_irqrestore(&mdev->ldev->md.uuid_lock, flags); | ||
4045 | } | ||
4037 | 4046 | ||
4038 | void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) | 4047 | void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) |
4039 | { | 4048 | { |
4049 | unsigned long flags; | ||
4050 | spin_lock_irqsave(&mdev->ldev->md.uuid_lock, flags); | ||
4040 | if (mdev->ldev->md.uuid[idx]) { | 4051 | if (mdev->ldev->md.uuid[idx]) { |
4041 | drbd_uuid_move_history(mdev); | 4052 | drbd_uuid_move_history(mdev); |
4042 | mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[idx]; | 4053 | mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[idx]; |
4043 | } | 4054 | } |
4044 | _drbd_uuid_set(mdev, idx, val); | 4055 | __drbd_uuid_set(mdev, idx, val); |
4056 | spin_unlock_irqrestore(&mdev->ldev->md.uuid_lock, flags); | ||
4045 | } | 4057 | } |
4046 | 4058 | ||
4047 | /** | 4059 | /** |
@@ -4054,15 +4066,20 @@ void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) | |||
4054 | void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local) | 4066 | void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local) |
4055 | { | 4067 | { |
4056 | u64 val; | 4068 | u64 val; |
4057 | unsigned long long bm_uuid = mdev->ldev->md.uuid[UI_BITMAP]; | 4069 | unsigned long long bm_uuid; |
4070 | |||
4071 | get_random_bytes(&val, sizeof(u64)); | ||
4072 | |||
4073 | spin_lock_irq(&mdev->ldev->md.uuid_lock); | ||
4074 | bm_uuid = mdev->ldev->md.uuid[UI_BITMAP]; | ||
4058 | 4075 | ||
4059 | if (bm_uuid) | 4076 | if (bm_uuid) |
4060 | dev_warn(DEV, "bm UUID was already set: %llX\n", bm_uuid); | 4077 | dev_warn(DEV, "bm UUID was already set: %llX\n", bm_uuid); |
4061 | 4078 | ||
4062 | mdev->ldev->md.uuid[UI_BITMAP] = mdev->ldev->md.uuid[UI_CURRENT]; | 4079 | mdev->ldev->md.uuid[UI_BITMAP] = mdev->ldev->md.uuid[UI_CURRENT]; |
4080 | __drbd_uuid_set(mdev, UI_CURRENT, val); | ||
4081 | spin_unlock_irq(&mdev->ldev->md.uuid_lock); | ||
4063 | 4082 | ||
4064 | get_random_bytes(&val, sizeof(u64)); | ||
4065 | _drbd_uuid_set(mdev, UI_CURRENT, val); | ||
4066 | drbd_print_uuids(mdev, "new current UUID"); | 4083 | drbd_print_uuids(mdev, "new current UUID"); |
4067 | /* get it to stable storage _now_ */ | 4084 | /* get it to stable storage _now_ */ |
4068 | drbd_md_sync(mdev); | 4085 | drbd_md_sync(mdev); |
@@ -4070,9 +4087,11 @@ void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local) | |||
4070 | 4087 | ||
4071 | void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local) | 4088 | void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local) |
4072 | { | 4089 | { |
4090 | unsigned long flags; | ||
4073 | if (mdev->ldev->md.uuid[UI_BITMAP] == 0 && val == 0) | 4091 | if (mdev->ldev->md.uuid[UI_BITMAP] == 0 && val == 0) |
4074 | return; | 4092 | return; |
4075 | 4093 | ||
4094 | spin_lock_irqsave(&mdev->ldev->md.uuid_lock, flags); | ||
4076 | if (val == 0) { | 4095 | if (val == 0) { |
4077 | drbd_uuid_move_history(mdev); | 4096 | drbd_uuid_move_history(mdev); |
4078 | mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[UI_BITMAP]; | 4097 | mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[UI_BITMAP]; |
@@ -4084,6 +4103,8 @@ void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local) | |||
4084 | 4103 | ||
4085 | mdev->ldev->md.uuid[UI_BITMAP] = val & ~((u64)1); | 4104 | mdev->ldev->md.uuid[UI_BITMAP] = val & ~((u64)1); |
4086 | } | 4105 | } |
4106 | spin_unlock_irqrestore(&mdev->ldev->md.uuid_lock, flags); | ||
4107 | |||
4087 | drbd_md_mark_dirty(mdev); | 4108 | drbd_md_mark_dirty(mdev); |
4088 | } | 4109 | } |
4089 | 4110 | ||
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index edb490aad8b4..ab660556a001 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c | |||
@@ -977,6 +977,8 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp | |||
977 | nbc->dc.fencing = DRBD_FENCING_DEF; | 977 | nbc->dc.fencing = DRBD_FENCING_DEF; |
978 | nbc->dc.max_bio_bvecs = DRBD_MAX_BIO_BVECS_DEF; | 978 | nbc->dc.max_bio_bvecs = DRBD_MAX_BIO_BVECS_DEF; |
979 | 979 | ||
980 | spin_lock_init(&nbc->md.uuid_lock); | ||
981 | |||
980 | if (!disk_conf_from_tags(mdev, nlp->tag_list, &nbc->dc)) { | 982 | if (!disk_conf_from_tags(mdev, nlp->tag_list, &nbc->dc)) { |
981 | retcode = ERR_MANDATORY_TAG; | 983 | retcode = ERR_MANDATORY_TAG; |
982 | goto fail; | 984 | goto fail; |
@@ -2170,8 +2172,11 @@ static int drbd_nl_get_uuids(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp | |||
2170 | tl = reply->tag_list; | 2172 | tl = reply->tag_list; |
2171 | 2173 | ||
2172 | if (get_ldev(mdev)) { | 2174 | if (get_ldev(mdev)) { |
2175 | unsigned long flags; | ||
2176 | spin_lock_irqsave(&mdev->ldev->md.uuid_lock, flags); | ||
2173 | tl = tl_add_blob(tl, T_uuids, mdev->ldev->md.uuid, UI_SIZE*sizeof(u64)); | 2177 | tl = tl_add_blob(tl, T_uuids, mdev->ldev->md.uuid, UI_SIZE*sizeof(u64)); |
2174 | tl = tl_add_int(tl, T_uuids_flags, &mdev->ldev->md.flags); | 2178 | tl = tl_add_int(tl, T_uuids_flags, &mdev->ldev->md.flags); |
2179 | spin_unlock_irqrestore(&mdev->ldev->md.uuid_lock, flags); | ||
2175 | put_ldev(mdev); | 2180 | put_ldev(mdev); |
2176 | } | 2181 | } |
2177 | put_unaligned(TT_END, tl++); /* Close the tag list */ | 2182 | put_unaligned(TT_END, tl++); /* Close the tag list */ |
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index c74ca2df7431..434adf75259a 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c | |||
@@ -2392,7 +2392,9 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l | |||
2392 | if ((mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1)) && | 2392 | if ((mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1)) && |
2393 | (mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1))) { | 2393 | (mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1))) { |
2394 | dev_info(DEV, "was SyncSource, missed the resync finished event, corrected myself:\n"); | 2394 | dev_info(DEV, "was SyncSource, missed the resync finished event, corrected myself:\n"); |
2395 | drbd_uuid_set_bm(mdev, 0UL); | 2395 | drbd_uuid_move_history(mdev); |
2396 | mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[UI_BITMAP]; | ||
2397 | mdev->ldev->md.uuid[UI_BITMAP] = 0; | ||
2396 | 2398 | ||
2397 | drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid, | 2399 | drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid, |
2398 | mdev->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(mdev) : 0, 0); | 2400 | mdev->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(mdev) : 0, 0); |
@@ -2500,8 +2502,8 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l | |||
2500 | if (mdev->agreed_pro_version < 91) | 2502 | if (mdev->agreed_pro_version < 91) |
2501 | return -1091; | 2503 | return -1091; |
2502 | 2504 | ||
2503 | _drbd_uuid_set(mdev, UI_BITMAP, mdev->ldev->md.uuid[UI_HISTORY_START]); | 2505 | __drbd_uuid_set(mdev, UI_BITMAP, mdev->ldev->md.uuid[UI_HISTORY_START]); |
2504 | _drbd_uuid_set(mdev, UI_HISTORY_START, mdev->ldev->md.uuid[UI_HISTORY_START + 1]); | 2506 | __drbd_uuid_set(mdev, UI_HISTORY_START, mdev->ldev->md.uuid[UI_HISTORY_START + 1]); |
2505 | 2507 | ||
2506 | dev_info(DEV, "Last syncUUID did not get through, corrected:\n"); | 2508 | dev_info(DEV, "Last syncUUID did not get through, corrected:\n"); |
2507 | drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid, | 2509 | drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid, |
@@ -2554,11 +2556,14 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol | |||
2554 | mydisk = mdev->new_state_tmp.disk; | 2556 | mydisk = mdev->new_state_tmp.disk; |
2555 | 2557 | ||
2556 | dev_info(DEV, "drbd_sync_handshake:\n"); | 2558 | dev_info(DEV, "drbd_sync_handshake:\n"); |
2559 | |||
2560 | spin_lock_irq(&mdev->ldev->md.uuid_lock); | ||
2557 | drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid, mdev->comm_bm_set, 0); | 2561 | drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid, mdev->comm_bm_set, 0); |
2558 | drbd_uuid_dump(mdev, "peer", mdev->p_uuid, | 2562 | drbd_uuid_dump(mdev, "peer", mdev->p_uuid, |
2559 | mdev->p_uuid[UI_SIZE], mdev->p_uuid[UI_FLAGS]); | 2563 | mdev->p_uuid[UI_SIZE], mdev->p_uuid[UI_FLAGS]); |
2560 | 2564 | ||
2561 | hg = drbd_uuid_compare(mdev, &rule_nr); | 2565 | hg = drbd_uuid_compare(mdev, &rule_nr); |
2566 | spin_unlock_irq(&mdev->ldev->md.uuid_lock); | ||
2562 | 2567 | ||
2563 | dev_info(DEV, "uuid_compare()=%d by rule %d\n", hg, rule_nr); | 2568 | dev_info(DEV, "uuid_compare()=%d by rule %d\n", hg, rule_nr); |
2564 | 2569 | ||