diff options
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 6 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 20 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 130 |
3 files changed, 66 insertions, 90 deletions
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 13793503766..c941d3a2b30 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1775,8 +1775,7 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) sock = &mdev->tconn->data; p = drbd_prepare_command(mdev, sock); - dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->tconn->integrity_tfm) ? - crypto_hash_digestsize(mdev->tconn->integrity_tfm) : 0; + dgs = mdev->tconn->integrity_tfm ? crypto_hash_digestsize(mdev->tconn->integrity_tfm) : 0; if (!p) return -EIO; @@ -1849,8 +1848,7 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd, sock = &mdev->tconn->data; p = drbd_prepare_command(mdev, sock); - dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->tconn->integrity_tfm) ? - crypto_hash_digestsize(mdev->tconn->integrity_tfm) : 0; + dgs = mdev->tconn->integrity_tfm ? crypto_hash_digestsize(mdev->tconn->integrity_tfm) : 0; if (!p) return -EIO; diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index bae49bba1cc..853e0a2873f 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1824,8 +1824,6 @@ struct crypto { struct crypto_hash *csums_tfm; struct crypto_hash *cram_hmac_tfm; struct crypto_hash *integrity_tfm; - void *int_dig_in; - void *int_dig_vv; }; static int @@ -1848,7 +1846,6 @@ alloc_crypto(struct crypto *crypto, struct net_conf *new_conf) { char hmac_name[CRYPTO_MAX_ALG_NAME]; enum drbd_ret_code rv; - int hash_size; rv = alloc_hash(&crypto->csums_tfm, new_conf->csums_alg, ERR_CSUMS_ALG); @@ -1869,23 +1866,12 @@ alloc_crypto(struct crypto *crypto, struct net_conf *new_conf) rv = alloc_hash(&crypto->cram_hmac_tfm, hmac_name, ERR_AUTH_ALG); } - if (crypto->integrity_tfm) { - hash_size = crypto_hash_digestsize(crypto->integrity_tfm); - crypto->int_dig_in = kmalloc(hash_size, GFP_KERNEL); - if (!crypto->int_dig_in) - return ERR_NOMEM; - crypto->int_dig_vv = kmalloc(hash_size, GFP_KERNEL); - if (!crypto->int_dig_vv) - return ERR_NOMEM; - } return rv; } static void free_crypto(struct crypto *crypto) { - kfree(crypto->int_dig_in); - kfree(crypto->int_dig_vv); crypto_free_hash(crypto->cram_hmac_tfm); crypto_free_hash(crypto->integrity_tfm); crypto_free_hash(crypto->csums_tfm); @@ -1974,10 +1960,6 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) crypto.verify_tfm = NULL; } - kfree(tconn->int_dig_in); - tconn->int_dig_in = crypto.int_dig_in; - kfree(tconn->int_dig_vv); - tconn->int_dig_vv = crypto.int_dig_vv; crypto_free_hash(tconn->integrity_tfm); tconn->integrity_tfm = crypto.integrity_tfm; if (tconn->cstate >= C_WF_REPORT_PARAMS && tconn->agreed_pro_version >= 100) @@ -2094,8 +2076,6 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) rcu_assign_pointer(tconn->net_conf, new_conf); conn_free_crypto(tconn); - tconn->int_dig_in = crypto.int_dig_in; - tconn->int_dig_vv = crypto.int_dig_vv; tconn->cram_hmac_tfm = crypto.cram_hmac_tfm; tconn->integrity_tfm = crypto.integrity_tfm; tconn->csums_tfm = crypto.csums_tfm; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 68a5abaf5ea..8d521219480 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3024,72 +3024,7 @@ static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi) integrity_alg[SHARED_SECRET_MAX - 1] = 0; } - if (pi->cmd == P_PROTOCOL_UPDATE) { - if (integrity_alg[0]) { - int hash_size; - - /* - * We can only change the peer data integrity algorithm - * here. Changing our own data integrity algorithm - * requires that we send a P_PROTOCOL_UPDATE packet at - * the same time; otherwise, the peer has no way to - * tell between which packets the algorithm should - * change. - */ - - peer_integrity_tfm = crypto_alloc_hash(integrity_alg, 0, CRYPTO_ALG_ASYNC); - if (!peer_integrity_tfm) { - conn_err(tconn, "peer data-integrity-alg %s not supported\n", - integrity_alg); - goto disconnect; - } - - hash_size = crypto_hash_digestsize(peer_integrity_tfm); - int_dig_in = kmalloc(hash_size, GFP_KERNEL); - int_dig_vv = kmalloc(hash_size, GFP_KERNEL); - if (!(int_dig_in && int_dig_vv)) { - conn_err(tconn, "Allocation of buffers for data integrity checking failed\n"); - goto disconnect; - } - } - - new_net_conf = kmalloc(sizeof(struct net_conf), GFP_KERNEL); - if (!new_net_conf) { - conn_err(tconn, "Allocation of new net_conf failed\n"); - goto disconnect; - } - - mutex_lock(&tconn->data.mutex); - mutex_lock(&tconn->conf_update); - old_net_conf = tconn->net_conf; - *new_net_conf = *old_net_conf; - - new_net_conf->wire_protocol = p_proto; - new_net_conf->after_sb_0p = convert_after_sb(p_after_sb_0p); - new_net_conf->after_sb_1p = convert_after_sb(p_after_sb_1p); - new_net_conf->after_sb_2p = convert_after_sb(p_after_sb_2p); - new_net_conf->two_primaries = p_two_primaries; - strcpy(new_net_conf->integrity_alg, integrity_alg); - new_net_conf->integrity_alg_len = strlen(integrity_alg) + 1; - - rcu_assign_pointer(tconn->net_conf, new_net_conf); - mutex_unlock(&tconn->conf_update); - mutex_unlock(&tconn->data.mutex); - - crypto_free_hash(tconn->peer_integrity_tfm); - kfree(tconn->int_dig_in); - kfree(tconn->int_dig_vv); - tconn->peer_integrity_tfm = peer_integrity_tfm; - tconn->int_dig_in = int_dig_in; - tconn->int_dig_vv = int_dig_vv; - - if (strcmp(old_net_conf->integrity_alg, integrity_alg)) - conn_info(tconn, "peer data-integrity-alg: %s\n", - integrity_alg[0] ? integrity_alg : "(none)"); - - synchronize_rcu(); - kfree(old_net_conf); - } else { + if (pi->cmd != P_PROTOCOL_UPDATE) { clear_bit(CONN_DRY_RUN, &tconn->flags); if (cf & CF_DRY_RUN) @@ -3135,6 +3070,69 @@ static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi) rcu_read_unlock(); } + + if (integrity_alg[0]) { + int hash_size; + + /* + * We can only change the peer data integrity algorithm + * here. Changing our own data integrity algorithm + * requires that we send a P_PROTOCOL_UPDATE packet at + * the same time; otherwise, the peer has no way to + * tell between which packets the algorithm should + * change. + */ + + peer_integrity_tfm = crypto_alloc_hash(integrity_alg, 0, CRYPTO_ALG_ASYNC); + if (!peer_integrity_tfm) { + conn_err(tconn, "peer data-integrity-alg %s not supported\n", + integrity_alg); + goto disconnect; + } + + hash_size = crypto_hash_digestsize(peer_integrity_tfm); + int_dig_in = kmalloc(hash_size, GFP_KERNEL); + int_dig_vv = kmalloc(hash_size, GFP_KERNEL); + if (!(int_dig_in && int_dig_vv)) { + conn_err(tconn, "Allocation of buffers for data integrity checking failed\n"); + goto disconnect; + } + } + + new_net_conf = kmalloc(sizeof(struct net_conf), GFP_KERNEL); + if (!new_net_conf) { + conn_err(tconn, "Allocation of new net_conf failed\n"); + goto disconnect; + } + + mutex_lock(&tconn->data.mutex); + mutex_lock(&tconn->conf_update); + old_net_conf = tconn->net_conf; + *new_net_conf = *old_net_conf; + + new_net_conf->wire_protocol = p_proto; + new_net_conf->after_sb_0p = convert_after_sb(p_after_sb_0p); + new_net_conf->after_sb_1p = convert_after_sb(p_after_sb_1p); + new_net_conf->after_sb_2p = convert_after_sb(p_after_sb_2p); + new_net_conf->two_primaries = p_two_primaries; + + rcu_assign_pointer(tconn->net_conf, new_net_conf); + mutex_unlock(&tconn->conf_update); + mutex_unlock(&tconn->data.mutex); + + crypto_free_hash(tconn->peer_integrity_tfm); + kfree(tconn->int_dig_in); + kfree(tconn->int_dig_vv); + tconn->peer_integrity_tfm = peer_integrity_tfm; + tconn->int_dig_in = int_dig_in; + tconn->int_dig_vv = int_dig_vv; + + if (strcmp(old_net_conf->integrity_alg, integrity_alg)) + conn_info(tconn, "peer data-integrity-alg: %s\n", + integrity_alg[0] ? integrity_alg : "(none)"); + + synchronize_rcu(); + kfree(old_net_conf); return 0; disconnect_rcu_unlock: |