diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2011-01-17 12:39:18 -0500 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2011-03-10 05:45:40 -0500 |
commit | 2deb8336d04106f215c21ad1b029e78d12033d02 (patch) | |
tree | 19a6efb58bf425002630c58826c6b53099fe73a1 /drivers/block | |
parent | 94f2b05f03fbc605f83ae501682c85ff4535bb6d (diff) |
drbd: Fixed P_NEG_ACK processing for protocol A and B
Protocol A has no P_WRITE_ACKs, but has P_NEG_ACKs.
The master bio might already be completed, therefore the
request is no longer in the collision hash.
=> Do not try to validate block_id as request
In Protocol B we might already have got a P_RECV_ACK
but then get a P_NEG_ACK after wards.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 45 |
1 files changed, 33 insertions, 12 deletions
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 2207d2886f84..a7f5b6d134e3 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c | |||
@@ -1633,9 +1633,6 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
1633 | u32 dp_flags; | 1633 | u32 dp_flags; |
1634 | 1634 | ||
1635 | if (!get_ldev(mdev)) { | 1635 | if (!get_ldev(mdev)) { |
1636 | if (__ratelimit(&drbd_ratelimit_state)) | ||
1637 | dev_err(DEV, "Can not write mirrored data block " | ||
1638 | "to local disk.\n"); | ||
1639 | spin_lock(&mdev->peer_seq_lock); | 1636 | spin_lock(&mdev->peer_seq_lock); |
1640 | if (mdev->peer_seq+1 == be32_to_cpu(p->seq_num)) | 1637 | if (mdev->peer_seq+1 == be32_to_cpu(p->seq_num)) |
1641 | mdev->peer_seq++; | 1638 | mdev->peer_seq++; |
@@ -4247,8 +4244,6 @@ static struct drbd_request *_ack_id_to_req(struct drbd_conf *mdev, | |||
4247 | return req; | 4244 | return req; |
4248 | } | 4245 | } |
4249 | } | 4246 | } |
4250 | dev_err(DEV, "_ack_id_to_req: failed to find req %p, sector %llus in list\n", | ||
4251 | (void *)(unsigned long)id, (unsigned long long)sector); | ||
4252 | return NULL; | 4247 | return NULL; |
4253 | } | 4248 | } |
4254 | 4249 | ||
@@ -4266,7 +4261,9 @@ static int validate_req_change_req_state(struct drbd_conf *mdev, | |||
4266 | req = validator(mdev, id, sector); | 4261 | req = validator(mdev, id, sector); |
4267 | if (unlikely(!req)) { | 4262 | if (unlikely(!req)) { |
4268 | spin_unlock_irq(&mdev->req_lock); | 4263 | spin_unlock_irq(&mdev->req_lock); |
4269 | dev_err(DEV, "%s: got a corrupt block_id/sector pair\n", func); | 4264 | |
4265 | dev_err(DEV, "%s: failed to find req %p, sector %llus\n", func, | ||
4266 | (void *)(unsigned long)id, (unsigned long long)sector); | ||
4270 | return false; | 4267 | return false; |
4271 | } | 4268 | } |
4272 | __req_mod(req, what, &m); | 4269 | __req_mod(req, what, &m); |
@@ -4321,20 +4318,44 @@ static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) | |||
4321 | { | 4318 | { |
4322 | struct p_block_ack *p = (struct p_block_ack *)h; | 4319 | struct p_block_ack *p = (struct p_block_ack *)h; |
4323 | sector_t sector = be64_to_cpu(p->sector); | 4320 | sector_t sector = be64_to_cpu(p->sector); |
4324 | 4321 | int size = be32_to_cpu(p->blksize); | |
4325 | if (__ratelimit(&drbd_ratelimit_state)) | 4322 | struct drbd_request *req; |
4326 | dev_warn(DEV, "Got NegAck packet. Peer is in troubles?\n"); | 4323 | struct bio_and_error m; |
4327 | 4324 | ||
4328 | update_peer_seq(mdev, be32_to_cpu(p->seq_num)); | 4325 | update_peer_seq(mdev, be32_to_cpu(p->seq_num)); |
4329 | 4326 | ||
4330 | if (is_syncer_block_id(p->block_id)) { | 4327 | if (is_syncer_block_id(p->block_id)) { |
4331 | int size = be32_to_cpu(p->blksize); | ||
4332 | dec_rs_pending(mdev); | 4328 | dec_rs_pending(mdev); |
4333 | drbd_rs_failed_io(mdev, sector, size); | 4329 | drbd_rs_failed_io(mdev, sector, size); |
4334 | return true; | 4330 | return true; |
4335 | } | 4331 | } |
4336 | return validate_req_change_req_state(mdev, p->block_id, sector, | 4332 | |
4337 | _ack_id_to_req, __func__ , neg_acked); | 4333 | spin_lock_irq(&mdev->req_lock); |
4334 | req = _ack_id_to_req(mdev, p->block_id, sector); | ||
4335 | if (!req) { | ||
4336 | spin_unlock_irq(&mdev->req_lock); | ||
4337 | if (mdev->net_conf->wire_protocol == DRBD_PROT_A || | ||
4338 | mdev->net_conf->wire_protocol == DRBD_PROT_B) { | ||
4339 | /* Protocol A has no P_WRITE_ACKs, but has P_NEG_ACKs. | ||
4340 | The master bio might already be completed, therefore the | ||
4341 | request is no longer in the collision hash. | ||
4342 | => Do not try to validate block_id as request. */ | ||
4343 | /* In Protocol B we might already have got a P_RECV_ACK | ||
4344 | but then get a P_NEG_ACK after wards. */ | ||
4345 | drbd_set_out_of_sync(mdev, sector, size); | ||
4346 | return true; | ||
4347 | } else { | ||
4348 | dev_err(DEV, "%s: failed to find req %p, sector %llus\n", __func__, | ||
4349 | (void *)(unsigned long)p->block_id, (unsigned long long)sector); | ||
4350 | return false; | ||
4351 | } | ||
4352 | } | ||
4353 | __req_mod(req, neg_acked, &m); | ||
4354 | spin_unlock_irq(&mdev->req_lock); | ||
4355 | |||
4356 | if (m.bio) | ||
4357 | complete_master_bio(mdev, &m); | ||
4358 | return true; | ||
4338 | } | 4359 | } |
4339 | 4360 | ||
4340 | static int got_NegDReply(struct drbd_conf *mdev, struct p_header80 *h) | 4361 | static int got_NegDReply(struct drbd_conf *mdev, struct p_header80 *h) |