aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2010-11-10 04:36:52 -0500
committerPhilipp Reisner <philipp.reisner@linbit.com>2011-03-10 05:19:08 -0500
commit470be44ab1841f3261a4d758450a42e6b79e9551 (patch)
tree1e6532855e065408b6e838bd27fe36629fb18487
parent5f9915bbb8e0975ce99f893c29b8e89100b33399 (diff)
drbd: detect modification of in-flight buffers
With data-integrity digest enabled, double-check on the sending side for modifications by upper layers of buffers under write back, so we can tell it appart from corruption on the "wire". 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.c28
-rw-r--r--drivers/block/drbd/drbd_receiver.c3
2 files changed, 29 insertions, 2 deletions
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 6afb81f807bd..451fc36a85cb 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -2537,10 +2537,36 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req)
2537 ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, 0); 2537 ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, 0);
2538 } 2538 }
2539 if (ok) { 2539 if (ok) {
2540 if (mdev->net_conf->wire_protocol == DRBD_PROT_A) 2540 /* For protocol A, we have to memcpy the payload into
2541 * socket buffers, as we may complete right away
2542 * as soon as we handed it over to tcp, at which point the data
2543 * pages may become invalid.
2544 *
2545 * For data-integrity enabled, we copy it as well, so we can be
2546 * sure that even if the bio pages may still be modified, it
2547 * won't change the data on the wire, thus if the digest checks
2548 * out ok after sending on this side, but does not fit on the
2549 * receiving side, we sure have detected corruption elsewhere.
2550 */
2551 if (mdev->net_conf->wire_protocol == DRBD_PROT_A || dgs)
2541 ok = _drbd_send_bio(mdev, req->master_bio); 2552 ok = _drbd_send_bio(mdev, req->master_bio);
2542 else 2553 else
2543 ok = _drbd_send_zc_bio(mdev, req->master_bio); 2554 ok = _drbd_send_zc_bio(mdev, req->master_bio);
2555
2556 /* double check digest, sometimes buffers have been modified in flight. */
2557 if (dgs > 0 && dgs <= 64) {
2558 /* 64 byte, 512 bit, is the larges digest size
2559 * currently supported in kernel crypto. */
2560 unsigned char digest[64];
2561 drbd_csum_bio(mdev, mdev->integrity_w_tfm, req->master_bio, digest);
2562 if (memcmp(mdev->int_dig_out, digest, dgs)) {
2563 dev_warn(DEV,
2564 "Digest mismatch, buffer modified by upper layers during write: %llus +%u\n",
2565 (unsigned long long)req->sector, req->size);
2566 }
2567 } /* else if (dgs > 64) {
2568 ... Be noisy about digest too large ...
2569 } */
2544 } 2570 }
2545 2571
2546 drbd_put_data_sock(mdev); 2572 drbd_put_data_sock(mdev);
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index d0e19a242af4..ca213c6e5f9d 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -1281,7 +1281,8 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __
1281 if (dgs) { 1281 if (dgs) {
1282 drbd_csum_ee(mdev, mdev->integrity_r_tfm, e, dig_vv); 1282 drbd_csum_ee(mdev, mdev->integrity_r_tfm, e, dig_vv);
1283 if (memcmp(dig_in, dig_vv, dgs)) { 1283 if (memcmp(dig_in, dig_vv, dgs)) {
1284 dev_err(DEV, "Digest integrity check FAILED.\n"); 1284 dev_err(DEV, "Digest integrity check FAILED: %llus +%u\n",
1285 (unsigned long long)sector, data_size);
1285 drbd_bcast_ee(mdev, "digest failed", 1286 drbd_bcast_ee(mdev, "digest failed",
1286 dgs, dig_in, dig_vv, e); 1287 dgs, dig_in, dig_vv, e);
1287 drbd_free_ee(mdev, e); 1288 drbd_free_ee(mdev, e);