aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@linbit.com>2011-07-17 17:06:12 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-11-08 10:57:59 -0500
commit7d4c782cbda4af0d7dc39cb8e7d50a927781aa1f (patch)
tree6876345c8a624293cf269471f87b8621449e6e9b
parent71fc7eedb37585ab2f1bec2e615202908bd4f4b7 (diff)
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 137935037664..c941d3a2b30c 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)
1775 1775
1776 sock = &mdev->tconn->data; 1776 sock = &mdev->tconn->data;
1777 p = drbd_prepare_command(mdev, sock); 1777 p = drbd_prepare_command(mdev, sock);
1778 dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->tconn->integrity_tfm) ? 1778 dgs = mdev->tconn->integrity_tfm ? crypto_hash_digestsize(mdev->tconn->integrity_tfm) : 0;
1779 crypto_hash_digestsize(mdev->tconn->integrity_tfm) : 0;
1780 1779
1781 if (!p) 1780 if (!p)
1782 return -EIO; 1781 return -EIO;
@@ -1849,8 +1848,7 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd,
1849 sock = &mdev->tconn->data; 1848 sock = &mdev->tconn->data;
1850 p = drbd_prepare_command(mdev, sock); 1849 p = drbd_prepare_command(mdev, sock);
1851 1850
1852 dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->tconn->integrity_tfm) ? 1851 dgs = mdev->tconn->integrity_tfm ? crypto_hash_digestsize(mdev->tconn->integrity_tfm) : 0;
1853 crypto_hash_digestsize(mdev->tconn->integrity_tfm) : 0;
1854 1852
1855 if (!p) 1853 if (!p)
1856 return -EIO; 1854 return -EIO;
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index bae49bba1cc3..853e0a2873fd 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -1824,8 +1824,6 @@ struct crypto {
1824 struct crypto_hash *csums_tfm; 1824 struct crypto_hash *csums_tfm;
1825 struct crypto_hash *cram_hmac_tfm; 1825 struct crypto_hash *cram_hmac_tfm;
1826 struct crypto_hash *integrity_tfm; 1826 struct crypto_hash *integrity_tfm;
1827 void *int_dig_in;
1828 void *int_dig_vv;
1829}; 1827};
1830 1828
1831static int 1829static int
@@ -1848,7 +1846,6 @@ alloc_crypto(struct crypto *crypto, struct net_conf *new_conf)
1848{ 1846{
1849 char hmac_name[CRYPTO_MAX_ALG_NAME]; 1847 char hmac_name[CRYPTO_MAX_ALG_NAME];
1850 enum drbd_ret_code rv; 1848 enum drbd_ret_code rv;
1851 int hash_size;
1852 1849
1853 rv = alloc_hash(&crypto->csums_tfm, new_conf->csums_alg, 1850 rv = alloc_hash(&crypto->csums_tfm, new_conf->csums_alg,
1854 ERR_CSUMS_ALG); 1851 ERR_CSUMS_ALG);
@@ -1869,23 +1866,12 @@ alloc_crypto(struct crypto *crypto, struct net_conf *new_conf)
1869 rv = alloc_hash(&crypto->cram_hmac_tfm, hmac_name, 1866 rv = alloc_hash(&crypto->cram_hmac_tfm, hmac_name,
1870 ERR_AUTH_ALG); 1867 ERR_AUTH_ALG);
1871 } 1868 }
1872 if (crypto->integrity_tfm) {
1873 hash_size = crypto_hash_digestsize(crypto->integrity_tfm);
1874 crypto->int_dig_in = kmalloc(hash_size, GFP_KERNEL);
1875 if (!crypto->int_dig_in)
1876 return ERR_NOMEM;
1877 crypto->int_dig_vv = kmalloc(hash_size, GFP_KERNEL);
1878 if (!crypto->int_dig_vv)
1879 return ERR_NOMEM;
1880 }
1881 1869
1882 return rv; 1870 return rv;
1883} 1871}
1884 1872
1885static void free_crypto(struct crypto *crypto) 1873static void free_crypto(struct crypto *crypto)
1886{ 1874{
1887 kfree(crypto->int_dig_in);
1888 kfree(crypto->int_dig_vv);
1889 crypto_free_hash(crypto->cram_hmac_tfm); 1875 crypto_free_hash(crypto->cram_hmac_tfm);
1890 crypto_free_hash(crypto->integrity_tfm); 1876 crypto_free_hash(crypto->integrity_tfm);
1891 crypto_free_hash(crypto->csums_tfm); 1877 crypto_free_hash(crypto->csums_tfm);
@@ -1974,10 +1960,6 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
1974 crypto.verify_tfm = NULL; 1960 crypto.verify_tfm = NULL;
1975 } 1961 }
1976 1962
1977 kfree(tconn->int_dig_in);
1978 tconn->int_dig_in = crypto.int_dig_in;
1979 kfree(tconn->int_dig_vv);
1980 tconn->int_dig_vv = crypto.int_dig_vv;
1981 crypto_free_hash(tconn->integrity_tfm); 1963 crypto_free_hash(tconn->integrity_tfm);
1982 tconn->integrity_tfm = crypto.integrity_tfm; 1964 tconn->integrity_tfm = crypto.integrity_tfm;
1983 if (tconn->cstate >= C_WF_REPORT_PARAMS && tconn->agreed_pro_version >= 100) 1965 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)
2094 rcu_assign_pointer(tconn->net_conf, new_conf); 2076 rcu_assign_pointer(tconn->net_conf, new_conf);
2095 2077
2096 conn_free_crypto(tconn); 2078 conn_free_crypto(tconn);
2097 tconn->int_dig_in = crypto.int_dig_in;
2098 tconn->int_dig_vv = crypto.int_dig_vv;
2099 tconn->cram_hmac_tfm = crypto.cram_hmac_tfm; 2079 tconn->cram_hmac_tfm = crypto.cram_hmac_tfm;
2100 tconn->integrity_tfm = crypto.integrity_tfm; 2080 tconn->integrity_tfm = crypto.integrity_tfm;
2101 tconn->csums_tfm = crypto.csums_tfm; 2081 tconn->csums_tfm = crypto.csums_tfm;
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index 68a5abaf5ea3..8d5212194806 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)
3024 integrity_alg[SHARED_SECRET_MAX - 1] = 0; 3024 integrity_alg[SHARED_SECRET_MAX - 1] = 0;
3025 } 3025 }
3026 3026
3027 if (pi->cmd == P_PROTOCOL_UPDATE) { 3027 if (pi->cmd != P_PROTOCOL_UPDATE) {
3028 if (integrity_alg[0]) {
3029 int hash_size;
3030
3031 /*
3032 * We can only change the peer data integrity algorithm
3033 * here. Changing our own data integrity algorithm
3034 * requires that we send a P_PROTOCOL_UPDATE packet at
3035 * the same time; otherwise, the peer has no way to
3036 * tell between which packets the algorithm should
3037 * change.
3038 */
3039
3040 peer_integrity_tfm = crypto_alloc_hash(integrity_alg, 0, CRYPTO_ALG_ASYNC);
3041 if (!peer_integrity_tfm) {
3042 conn_err(tconn, "peer data-integrity-alg %s not supported\n",
3043 integrity_alg);
3044 goto disconnect;
3045 }
3046
3047 hash_size = crypto_hash_digestsize(peer_integrity_tfm);
3048 int_dig_in = kmalloc(hash_size, GFP_KERNEL);
3049 int_dig_vv = kmalloc(hash_size, GFP_KERNEL);
3050 if (!(int_dig_in && int_dig_vv)) {
3051 conn_err(tconn, "Allocation of buffers for data integrity checking failed\n");
3052 goto disconnect;
3053 }
3054 }
3055
3056 new_net_conf = kmalloc(sizeof(struct net_conf), GFP_KERNEL);
3057 if (!new_net_conf) {
3058 conn_err(tconn, "Allocation of new net_conf failed\n");
3059 goto disconnect;
3060 }
3061
3062 mutex_lock(&tconn->data.mutex);
3063 mutex_lock(&tconn->conf_update);
3064 old_net_conf = tconn->net_conf;
3065 *new_net_conf = *old_net_conf;
3066
3067 new_net_conf->wire_protocol = p_proto;
3068 new_net_conf->after_sb_0p = convert_after_sb(p_after_sb_0p);
3069 new_net_conf->after_sb_1p = convert_after_sb(p_after_sb_1p);
3070 new_net_conf->after_sb_2p = convert_after_sb(p_after_sb_2p);
3071 new_net_conf->two_primaries = p_two_primaries;
3072 strcpy(new_net_conf->integrity_alg, integrity_alg);
3073 new_net_conf->integrity_alg_len = strlen(integrity_alg) + 1;
3074
3075 rcu_assign_pointer(tconn->net_conf, new_net_conf);
3076 mutex_unlock(&tconn->conf_update);
3077 mutex_unlock(&tconn->data.mutex);
3078
3079 crypto_free_hash(tconn->peer_integrity_tfm);
3080 kfree(tconn->int_dig_in);
3081 kfree(tconn->int_dig_vv);
3082 tconn->peer_integrity_tfm = peer_integrity_tfm;
3083 tconn->int_dig_in = int_dig_in;
3084 tconn->int_dig_vv = int_dig_vv;
3085
3086 if (strcmp(old_net_conf->integrity_alg, integrity_alg))
3087 conn_info(tconn, "peer data-integrity-alg: %s\n",
3088 integrity_alg[0] ? integrity_alg : "(none)");
3089
3090 synchronize_rcu();
3091 kfree(old_net_conf);
3092 } else {
3093 clear_bit(CONN_DRY_RUN, &tconn->flags); 3028 clear_bit(CONN_DRY_RUN, &tconn->flags);
3094 3029
3095 if (cf & CF_DRY_RUN) 3030 if (cf & CF_DRY_RUN)
@@ -3135,6 +3070,69 @@ static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi)
3135 3070
3136 rcu_read_unlock(); 3071 rcu_read_unlock();
3137 } 3072 }
3073
3074 if (integrity_alg[0]) {
3075 int hash_size;
3076
3077 /*
3078 * We can only change the peer data integrity algorithm
3079 * here. Changing our own data integrity algorithm
3080 * requires that we send a P_PROTOCOL_UPDATE packet at
3081 * the same time; otherwise, the peer has no way to
3082 * tell between which packets the algorithm should
3083 * change.
3084 */
3085
3086 peer_integrity_tfm = crypto_alloc_hash(integrity_alg, 0, CRYPTO_ALG_ASYNC);
3087 if (!peer_integrity_tfm) {
3088 conn_err(tconn, "peer data-integrity-alg %s not supported\n",
3089 integrity_alg);
3090 goto disconnect;
3091 }
3092
3093 hash_size = crypto_hash_digestsize(peer_integrity_tfm);
3094 int_dig_in = kmalloc(hash_size, GFP_KERNEL);
3095 int_dig_vv = kmalloc(hash_size, GFP_KERNEL);
3096 if (!(int_dig_in && int_dig_vv)) {
3097 conn_err(tconn, "Allocation of buffers for data integrity checking failed\n");
3098 goto disconnect;
3099 }
3100 }
3101
3102 new_net_conf = kmalloc(sizeof(struct net_conf), GFP_KERNEL);
3103 if (!new_net_conf) {
3104 conn_err(tconn, "Allocation of new net_conf failed\n");
3105 goto disconnect;
3106 }
3107
3108 mutex_lock(&tconn->data.mutex);
3109 mutex_lock(&tconn->conf_update);
3110 old_net_conf = tconn->net_conf;
3111 *new_net_conf = *old_net_conf;
3112
3113 new_net_conf->wire_protocol = p_proto;
3114 new_net_conf->after_sb_0p = convert_after_sb(p_after_sb_0p);
3115 new_net_conf->after_sb_1p = convert_after_sb(p_after_sb_1p);
3116 new_net_conf->after_sb_2p = convert_after_sb(p_after_sb_2p);
3117 new_net_conf->two_primaries = p_two_primaries;
3118
3119 rcu_assign_pointer(tconn->net_conf, new_net_conf);
3120 mutex_unlock(&tconn->conf_update);
3121 mutex_unlock(&tconn->data.mutex);
3122
3123 crypto_free_hash(tconn->peer_integrity_tfm);
3124 kfree(tconn->int_dig_in);
3125 kfree(tconn->int_dig_vv);
3126 tconn->peer_integrity_tfm = peer_integrity_tfm;
3127 tconn->int_dig_in = int_dig_in;
3128 tconn->int_dig_vv = int_dig_vv;
3129
3130 if (strcmp(old_net_conf->integrity_alg, integrity_alg))
3131 conn_info(tconn, "peer data-integrity-alg: %s\n",
3132 integrity_alg[0] ? integrity_alg : "(none)");
3133
3134 synchronize_rcu();
3135 kfree(old_net_conf);
3138 return 0; 3136 return 0;
3139 3137
3140disconnect_rcu_unlock: 3138disconnect_rcu_unlock: