diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2010-11-10 04:36:52 -0500 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2011-03-10 05:19:08 -0500 |
commit | 470be44ab1841f3261a4d758450a42e6b79e9551 (patch) | |
tree | 1e6532855e065408b6e838bd27fe36629fb18487 | |
parent | 5f9915bbb8e0975ce99f893c29b8e89100b33399 (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.c | 28 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 3 |
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); |