aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2014-03-18 07:22:14 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2014-07-10 12:34:59 -0400
commit6a8d68b1878e8839b4927150da236c8248703c70 (patch)
tree6bc5108111b8f695755f979dea7d7f7899a2d532 /drivers/block/drbd
parenta5655dac75b6c572e1ef430b61ad55245fffd523 (diff)
drbd: don't implicitly resize Diskless node beyond end of device
During handshake, we compare backend sizes, and user set limits, and agree on what device size we are going to expose. We remember that last-agreed-size in our meta data. But if we come up diskless, we have to accept what the peer presents us with. We used to accept the peers maximum potential capacity (backend size), which is wrong, and could lead to IO errors due to access beyond end of device. Instead, we need to accept the peer's current size. Unless that is communicated as 0, in which case we accept the backend size, or the user set limit, if set. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd')
-rw-r--r--drivers/block/drbd/drbd_receiver.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index 2fcc3af03bd8..5626c5babc3f 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -3657,7 +3657,7 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info
3657 struct drbd_device *device; 3657 struct drbd_device *device;
3658 struct p_sizes *p = pi->data; 3658 struct p_sizes *p = pi->data;
3659 enum determine_dev_size dd = DS_UNCHANGED; 3659 enum determine_dev_size dd = DS_UNCHANGED;
3660 sector_t p_size, p_usize, my_usize; 3660 sector_t p_size, p_usize, p_csize, my_usize;
3661 int ldsc = 0; /* local disk size changed */ 3661 int ldsc = 0; /* local disk size changed */
3662 enum dds_flags ddsf; 3662 enum dds_flags ddsf;
3663 3663
@@ -3668,6 +3668,7 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info
3668 3668
3669 p_size = be64_to_cpu(p->d_size); 3669 p_size = be64_to_cpu(p->d_size);
3670 p_usize = be64_to_cpu(p->u_size); 3670 p_usize = be64_to_cpu(p->u_size);
3671 p_csize = be64_to_cpu(p->c_size);
3671 3672
3672 /* just store the peer's disk size for now. 3673 /* just store the peer's disk size for now.
3673 * we still need to figure out whether we accept that. */ 3674 * we still need to figure out whether we accept that. */
@@ -3742,9 +3743,21 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info
3742 return -EIO; 3743 return -EIO;
3743 drbd_md_sync(device); 3744 drbd_md_sync(device);
3744 } else { 3745 } else {
3745 /* I am diskless, need to accept the peer's size. */ 3746 /*
3747 * I am diskless, need to accept the peer's *current* size.
3748 * I must NOT accept the peers backing disk size,
3749 * it may have been larger than mine all along...
3750 *
3751 * At this point, the peer knows more about my disk, or at
3752 * least about what we last agreed upon, than myself.
3753 * So if his c_size is less than his d_size, the most likely
3754 * reason is that *my* d_size was smaller last time we checked.
3755 *
3756 * However, if he sends a zero current size,
3757 * take his (user-capped or) backing disk size anyways.
3758 */
3746 drbd_reconsider_max_bio_size(device, NULL); 3759 drbd_reconsider_max_bio_size(device, NULL);
3747 drbd_set_my_capacity(device, p_size); 3760 drbd_set_my_capacity(device, p_csize ?: p_usize ?: p_size);
3748 } 3761 }
3749 3762
3750 if (get_ldev(device)) { 3763 if (get_ldev(device)) {