diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2011-04-13 18:00:59 -0700 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-08 16:45:18 +0100 |
commit | cd64397c0b7be5050c4127aba242c5d0ae6acaed (patch) | |
tree | c980f9327a5927fc17090d4fd980fea873338384 /drivers/block | |
parent | 303d1448a048fb5b099babc5f41d0b1e22238778 (diff) | |
download | linux-stable-cd64397c0b7be5050c4127aba242c5d0ae6acaed.tar.gz linux-stable-cd64397c0b7be5050c4127aba242c5d0ae6acaed.tar.bz2 linux-stable-cd64397c0b7be5050c4127aba242c5d0ae6acaed.zip |
drbd: Check consistency of net options when the get changed online
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 79 |
1 files changed, 45 insertions, 34 deletions
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index dbaffcaf8e1b..40de384aade6 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1665,6 +1665,45 @@ static bool conn_ov_running(struct drbd_tconn *tconn) return rv; } +static enum drbd_ret_code +check_net_options(struct drbd_tconn *tconn, struct net_conf *new_conf) +{ + struct drbd_conf *mdev; + int i; + + if (new_conf->two_primaries && + (new_conf->wire_protocol != DRBD_PROT_C)) + return ERR_NOT_PROTO_C; + + rcu_read_lock(); + idr_for_each_entry(&tconn->volumes, mdev, i) { + if (get_ldev(mdev)) { + enum drbd_fencing_p fp = mdev->ldev->dc.fencing; + put_ldev(mdev); + if (new_conf->wire_protocol == DRBD_PROT_A && fp == FP_STONITH) { + rcu_read_unlock(); + return ERR_STONITH_AND_PROT_A; + } + } + if (mdev->state.role == R_PRIMARY && new_conf->want_lose) { + rcu_read_unlock(); + return ERR_DISCARD; + } + if (!mdev->bitmap) { + if(drbd_bm_init(mdev)) { + rcu_read_unlock(); + return ERR_NOMEM; + } + } + } + rcu_read_unlock(); + + if (new_conf->on_congestion != OC_BLOCK && new_conf->wire_protocol != DRBD_PROT_A) + return ERR_CONG_NOT_PROTO_A; + + return NO_ERROR; +} + int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) { enum drbd_ret_code retcode; @@ -1709,6 +1748,10 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) goto fail; } + retcode = check_net_options(tconn, new_conf); + if (retcode != NO_ERROR) + goto fail; + /* re-sync running */ rsr = conn_resync_running(tconn); if (rsr && strcmp(new_conf->csums_alg, tconn->net_conf->csums_alg)) { @@ -1868,39 +1911,9 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) goto fail; } - if (new_conf->two_primaries - && (new_conf->wire_protocol != DRBD_PROT_C)) { - retcode = ERR_NOT_PROTO_C; - goto fail; - } - - rcu_read_lock(); - idr_for_each_entry(&tconn->volumes, mdev, i) { - if (get_ldev(mdev)) { - enum drbd_fencing_p fp = mdev->ldev->dc.fencing; - put_ldev(mdev); - if (new_conf->wire_protocol == DRBD_PROT_A && fp == FP_STONITH) { - retcode = ERR_STONITH_AND_PROT_A; - goto fail_rcu_unlock; - } - } - if (mdev->state.role == R_PRIMARY && new_conf->want_lose) { - retcode = ERR_DISCARD; - goto fail_rcu_unlock; - } - if (!mdev->bitmap) { - if(drbd_bm_init(mdev)) { - retcode = ERR_NOMEM; - goto fail_rcu_unlock; - } - } - } - rcu_read_unlock(); - - if (new_conf->on_congestion != OC_BLOCK && new_conf->wire_protocol != DRBD_PROT_A) { - retcode = ERR_CONG_NOT_PROTO_A; + retcode = check_net_options(tconn, new_conf); + if (retcode != NO_ERROR) goto fail; - } retcode = NO_ERROR; @@ -2020,8 +2033,6 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) drbd_adm_finish(info, retcode); return 0; -fail_rcu_unlock: - rcu_read_unlock(); fail: kfree(int_dig_in); kfree(int_dig_vv); |