aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@linbit.com>2011-07-17 23:06:12 +0200
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-11-08 16:57:59 +0100
commit7d4c782cbda4af0d7dc39cb8e7d50a927781aa1f (patch)
tree6876345c8a624293cf269471f87b8621449e6e9b
parent71fc7eedb37585ab2f1bec2e615202908bd4f4b7 (diff)
downloadvexpress-lsk-7d4c782cbda4af0d7dc39cb8e7d50a927781aa1f.tar.gz
drbd: Fix the data-integrity-alg setting
The last data-integrity-alg fix made data integrity checking work when the algorithm was changed for an established connection, but the common case of configuring the algorithm before connecting was still broken. Fix that. Signed-off-by: Andreas Gruenbacher <agruen@linbit.com> Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
-rw-r--r--drivers/block/drbd/drbd_main.c6
-rw-r--r--drivers/block/drbd/drbd_nl.c20
-rw-r--r--drivers/block/drbd/drbd_receiver.c130
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: