diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2014-05-05 17:42:24 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2014-07-10 12:35:14 -0400 |
commit | 21ae5d7f95aa1a64f35b03c91f8714ced3ab61a9 (patch) | |
tree | 9e5d90197118d8110c9a65f07f639c5eae000044 /drivers/block | |
parent | ad3fee790088d36ad862e31535b5b99c25adeef4 (diff) |
drbd: track timing details of peer_requests
To be able to present timing details in debugfs,
we need to track preparation/submit times of peer requests.
Track peer request flags early,
before they are put on the epoch_entry lists.
Waiting for activity log transactions may be a major latency factor.
We want to be able to present the peer_request state accurately in
debugfs, and what it is waiting for.
Consistently mark/unmark peer requests with EE_CALL_AL_COMPLETE_IO.
Set it only *after* calling drbd_al_begin_io(),
clear it as soon as we call drbd_al_complete_io().
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_int.h | 15 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 78 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_worker.c | 1 |
3 files changed, 64 insertions, 30 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 81f4af49b8ac..c7a409f3aaf8 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h | |||
@@ -422,6 +422,7 @@ struct drbd_peer_request { | |||
422 | struct drbd_interval i; | 422 | struct drbd_interval i; |
423 | /* see comments on ee flag bits below */ | 423 | /* see comments on ee flag bits below */ |
424 | unsigned long flags; | 424 | unsigned long flags; |
425 | unsigned long submit_jif; | ||
425 | union { | 426 | union { |
426 | u64 block_id; | 427 | u64 block_id; |
427 | struct digest_info *digest; | 428 | struct digest_info *digest; |
@@ -464,6 +465,17 @@ enum { | |||
464 | 465 | ||
465 | /* Is set when net_conf had two_primaries set while creating this peer_req */ | 466 | /* Is set when net_conf had two_primaries set while creating this peer_req */ |
466 | __EE_IN_INTERVAL_TREE, | 467 | __EE_IN_INTERVAL_TREE, |
468 | |||
469 | /* for debugfs: */ | ||
470 | /* has this been submitted, or does it still wait for something else? */ | ||
471 | __EE_SUBMITTED, | ||
472 | |||
473 | /* this is/was a write request */ | ||
474 | __EE_WRITE, | ||
475 | |||
476 | /* this originates from application on peer | ||
477 | * (not some resync or verify or other DRBD internal request) */ | ||
478 | __EE_APPLICATION, | ||
467 | }; | 479 | }; |
468 | #define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO) | 480 | #define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO) |
469 | #define EE_MAY_SET_IN_SYNC (1<<__EE_MAY_SET_IN_SYNC) | 481 | #define EE_MAY_SET_IN_SYNC (1<<__EE_MAY_SET_IN_SYNC) |
@@ -475,6 +487,9 @@ enum { | |||
475 | #define EE_RESTART_REQUESTS (1<<__EE_RESTART_REQUESTS) | 487 | #define EE_RESTART_REQUESTS (1<<__EE_RESTART_REQUESTS) |
476 | #define EE_SEND_WRITE_ACK (1<<__EE_SEND_WRITE_ACK) | 488 | #define EE_SEND_WRITE_ACK (1<<__EE_SEND_WRITE_ACK) |
477 | #define EE_IN_INTERVAL_TREE (1<<__EE_IN_INTERVAL_TREE) | 489 | #define EE_IN_INTERVAL_TREE (1<<__EE_IN_INTERVAL_TREE) |
490 | #define EE_SUBMITTED (1<<__EE_SUBMITTED) | ||
491 | #define EE_WRITE (1<<__EE_WRITE) | ||
492 | #define EE_APPLICATION (1<<__EE_APPLICATION) | ||
478 | 493 | ||
479 | /* flag bits per device */ | 494 | /* flag bits per device */ |
480 | enum { | 495 | enum { |
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 0d3cbd8e4b9c..2f67dc03d403 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c | |||
@@ -389,11 +389,16 @@ drbd_alloc_peer_req(struct drbd_peer_device *peer_device, u64 id, sector_t secto | |||
389 | void __drbd_free_peer_req(struct drbd_device *device, struct drbd_peer_request *peer_req, | 389 | void __drbd_free_peer_req(struct drbd_device *device, struct drbd_peer_request *peer_req, |
390 | int is_net) | 390 | int is_net) |
391 | { | 391 | { |
392 | might_sleep(); | ||
392 | if (peer_req->flags & EE_HAS_DIGEST) | 393 | if (peer_req->flags & EE_HAS_DIGEST) |
393 | kfree(peer_req->digest); | 394 | kfree(peer_req->digest); |
394 | drbd_free_pages(device, peer_req->pages, is_net); | 395 | drbd_free_pages(device, peer_req->pages, is_net); |
395 | D_ASSERT(device, atomic_read(&peer_req->pending_bios) == 0); | 396 | D_ASSERT(device, atomic_read(&peer_req->pending_bios) == 0); |
396 | D_ASSERT(device, drbd_interval_empty(&peer_req->i)); | 397 | D_ASSERT(device, drbd_interval_empty(&peer_req->i)); |
398 | if (!expect(!(peer_req->flags & EE_CALL_AL_COMPLETE_IO))) { | ||
399 | peer_req->flags &= ~EE_CALL_AL_COMPLETE_IO; | ||
400 | drbd_al_complete_io(device, &peer_req->i); | ||
401 | } | ||
397 | mempool_free(peer_req, drbd_ee_mempool); | 402 | mempool_free(peer_req, drbd_ee_mempool); |
398 | } | 403 | } |
399 | 404 | ||
@@ -1372,6 +1377,8 @@ int drbd_submit_peer_request(struct drbd_device *device, | |||
1372 | conn_wait_active_ee_empty(first_peer_device(device)->connection); | 1377 | conn_wait_active_ee_empty(first_peer_device(device)->connection); |
1373 | /* add it to the active list now, | 1378 | /* add it to the active list now, |
1374 | * so we can find it to present it in debugfs */ | 1379 | * so we can find it to present it in debugfs */ |
1380 | peer_req->submit_jif = jiffies; | ||
1381 | peer_req->flags |= EE_SUBMITTED; | ||
1375 | spin_lock_irq(&device->resource->req_lock); | 1382 | spin_lock_irq(&device->resource->req_lock); |
1376 | list_add_tail(&peer_req->w.list, &device->active_ee); | 1383 | list_add_tail(&peer_req->w.list, &device->active_ee); |
1377 | spin_unlock_irq(&device->resource->req_lock); | 1384 | spin_unlock_irq(&device->resource->req_lock); |
@@ -1443,6 +1450,9 @@ submit: | |||
1443 | D_ASSERT(device, page == NULL); | 1450 | D_ASSERT(device, page == NULL); |
1444 | 1451 | ||
1445 | atomic_set(&peer_req->pending_bios, n_bios); | 1452 | atomic_set(&peer_req->pending_bios, n_bios); |
1453 | /* for debugfs: update timestamp, mark as submitted */ | ||
1454 | peer_req->submit_jif = jiffies; | ||
1455 | peer_req->flags |= EE_SUBMITTED; | ||
1446 | do { | 1456 | do { |
1447 | bio = bios; | 1457 | bio = bios; |
1448 | bios = bios->bi_next; | 1458 | bios = bios->bi_next; |
@@ -1624,6 +1634,7 @@ read_in_block(struct drbd_peer_device *peer_device, u64 id, sector_t sector, | |||
1624 | if (!peer_req) | 1634 | if (!peer_req) |
1625 | return NULL; | 1635 | return NULL; |
1626 | 1636 | ||
1637 | peer_req->flags |= EE_WRITE; | ||
1627 | if (trim) | 1638 | if (trim) |
1628 | return peer_req; | 1639 | return peer_req; |
1629 | 1640 | ||
@@ -1780,6 +1791,7 @@ static int recv_resync_read(struct drbd_peer_device *peer_device, sector_t secto | |||
1780 | * respective _drbd_clear_done_ee */ | 1791 | * respective _drbd_clear_done_ee */ |
1781 | 1792 | ||
1782 | peer_req->w.cb = e_end_resync_block; | 1793 | peer_req->w.cb = e_end_resync_block; |
1794 | peer_req->submit_jif = jiffies; | ||
1783 | 1795 | ||
1784 | spin_lock_irq(&device->resource->req_lock); | 1796 | spin_lock_irq(&device->resource->req_lock); |
1785 | list_add_tail(&peer_req->w.list, &device->sync_ee); | 1797 | list_add_tail(&peer_req->w.list, &device->sync_ee); |
@@ -2196,7 +2208,6 @@ static int handle_write_conflicts(struct drbd_device *device, | |||
2196 | (unsigned long long)sector, size, | 2208 | (unsigned long long)sector, size, |
2197 | superseded ? "local" : "remote"); | 2209 | superseded ? "local" : "remote"); |
2198 | 2210 | ||
2199 | inc_unacked(device); | ||
2200 | peer_req->w.cb = superseded ? e_send_superseded : | 2211 | peer_req->w.cb = superseded ? e_send_superseded : |
2201 | e_send_retry_write; | 2212 | e_send_retry_write; |
2202 | list_add_tail(&peer_req->w.list, &device->done_ee); | 2213 | list_add_tail(&peer_req->w.list, &device->done_ee); |
@@ -2255,6 +2266,7 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info * | |||
2255 | { | 2266 | { |
2256 | struct drbd_peer_device *peer_device; | 2267 | struct drbd_peer_device *peer_device; |
2257 | struct drbd_device *device; | 2268 | struct drbd_device *device; |
2269 | struct net_conf *nc; | ||
2258 | sector_t sector; | 2270 | sector_t sector; |
2259 | struct drbd_peer_request *peer_req; | 2271 | struct drbd_peer_request *peer_req; |
2260 | struct p_data *p = pi->data; | 2272 | struct p_data *p = pi->data; |
@@ -2294,6 +2306,8 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info * | |||
2294 | } | 2306 | } |
2295 | 2307 | ||
2296 | peer_req->w.cb = e_end_block; | 2308 | peer_req->w.cb = e_end_block; |
2309 | peer_req->submit_jif = jiffies; | ||
2310 | peer_req->flags |= EE_APPLICATION; | ||
2297 | 2311 | ||
2298 | dp_flags = be32_to_cpu(p->dp_flags); | 2312 | dp_flags = be32_to_cpu(p->dp_flags); |
2299 | rw |= wire_flags_to_bio(dp_flags); | 2313 | rw |= wire_flags_to_bio(dp_flags); |
@@ -2320,9 +2334,36 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info * | |||
2320 | spin_unlock(&connection->epoch_lock); | 2334 | spin_unlock(&connection->epoch_lock); |
2321 | 2335 | ||
2322 | rcu_read_lock(); | 2336 | rcu_read_lock(); |
2323 | tp = rcu_dereference(peer_device->connection->net_conf)->two_primaries; | 2337 | nc = rcu_dereference(peer_device->connection->net_conf); |
2338 | tp = nc->two_primaries; | ||
2339 | if (peer_device->connection->agreed_pro_version < 100) { | ||
2340 | switch (nc->wire_protocol) { | ||
2341 | case DRBD_PROT_C: | ||
2342 | dp_flags |= DP_SEND_WRITE_ACK; | ||
2343 | break; | ||
2344 | case DRBD_PROT_B: | ||
2345 | dp_flags |= DP_SEND_RECEIVE_ACK; | ||
2346 | break; | ||
2347 | } | ||
2348 | } | ||
2324 | rcu_read_unlock(); | 2349 | rcu_read_unlock(); |
2350 | |||
2351 | if (dp_flags & DP_SEND_WRITE_ACK) { | ||
2352 | peer_req->flags |= EE_SEND_WRITE_ACK; | ||
2353 | inc_unacked(device); | ||
2354 | /* corresponding dec_unacked() in e_end_block() | ||
2355 | * respective _drbd_clear_done_ee */ | ||
2356 | } | ||
2357 | |||
2358 | if (dp_flags & DP_SEND_RECEIVE_ACK) { | ||
2359 | /* I really don't like it that the receiver thread | ||
2360 | * sends on the msock, but anyways */ | ||
2361 | drbd_send_ack(first_peer_device(device), P_RECV_ACK, peer_req); | ||
2362 | } | ||
2363 | |||
2325 | if (tp) { | 2364 | if (tp) { |
2365 | /* two primaries implies protocol C */ | ||
2366 | D_ASSERT(device, dp_flags & DP_SEND_WRITE_ACK); | ||
2326 | peer_req->flags |= EE_IN_INTERVAL_TREE; | 2367 | peer_req->flags |= EE_IN_INTERVAL_TREE; |
2327 | err = wait_for_and_update_peer_seq(peer_device, peer_seq); | 2368 | err = wait_for_and_update_peer_seq(peer_device, peer_seq); |
2328 | if (err) | 2369 | if (err) |
@@ -2352,38 +2393,12 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info * | |||
2352 | if (device->state.conn == C_SYNC_TARGET) | 2393 | if (device->state.conn == C_SYNC_TARGET) |
2353 | wait_event(device->ee_wait, !overlapping_resync_write(device, peer_req)); | 2394 | wait_event(device->ee_wait, !overlapping_resync_write(device, peer_req)); |
2354 | 2395 | ||
2355 | if (peer_device->connection->agreed_pro_version < 100) { | ||
2356 | rcu_read_lock(); | ||
2357 | switch (rcu_dereference(peer_device->connection->net_conf)->wire_protocol) { | ||
2358 | case DRBD_PROT_C: | ||
2359 | dp_flags |= DP_SEND_WRITE_ACK; | ||
2360 | break; | ||
2361 | case DRBD_PROT_B: | ||
2362 | dp_flags |= DP_SEND_RECEIVE_ACK; | ||
2363 | break; | ||
2364 | } | ||
2365 | rcu_read_unlock(); | ||
2366 | } | ||
2367 | |||
2368 | if (dp_flags & DP_SEND_WRITE_ACK) { | ||
2369 | peer_req->flags |= EE_SEND_WRITE_ACK; | ||
2370 | inc_unacked(device); | ||
2371 | /* corresponding dec_unacked() in e_end_block() | ||
2372 | * respective _drbd_clear_done_ee */ | ||
2373 | } | ||
2374 | |||
2375 | if (dp_flags & DP_SEND_RECEIVE_ACK) { | ||
2376 | /* I really don't like it that the receiver thread | ||
2377 | * sends on the msock, but anyways */ | ||
2378 | drbd_send_ack(first_peer_device(device), P_RECV_ACK, peer_req); | ||
2379 | } | ||
2380 | |||
2381 | if (device->state.pdsk < D_INCONSISTENT) { | 2396 | if (device->state.pdsk < D_INCONSISTENT) { |
2382 | /* In case we have the only disk of the cluster, */ | 2397 | /* In case we have the only disk of the cluster, */ |
2383 | drbd_set_out_of_sync(device, peer_req->i.sector, peer_req->i.size); | 2398 | drbd_set_out_of_sync(device, peer_req->i.sector, peer_req->i.size); |
2384 | peer_req->flags |= EE_CALL_AL_COMPLETE_IO; | ||
2385 | peer_req->flags &= ~EE_MAY_SET_IN_SYNC; | 2399 | peer_req->flags &= ~EE_MAY_SET_IN_SYNC; |
2386 | drbd_al_begin_io(device, &peer_req->i); | 2400 | drbd_al_begin_io(device, &peer_req->i); |
2401 | peer_req->flags |= EE_CALL_AL_COMPLETE_IO; | ||
2387 | } | 2402 | } |
2388 | 2403 | ||
2389 | err = drbd_submit_peer_request(device, peer_req, rw, DRBD_FAULT_DT_WR); | 2404 | err = drbd_submit_peer_request(device, peer_req, rw, DRBD_FAULT_DT_WR); |
@@ -2396,8 +2411,10 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info * | |||
2396 | list_del(&peer_req->w.list); | 2411 | list_del(&peer_req->w.list); |
2397 | drbd_remove_epoch_entry_interval(device, peer_req); | 2412 | drbd_remove_epoch_entry_interval(device, peer_req); |
2398 | spin_unlock_irq(&device->resource->req_lock); | 2413 | spin_unlock_irq(&device->resource->req_lock); |
2399 | if (peer_req->flags & EE_CALL_AL_COMPLETE_IO) | 2414 | if (peer_req->flags & EE_CALL_AL_COMPLETE_IO) { |
2415 | peer_req->flags &= ~EE_CALL_AL_COMPLETE_IO; | ||
2400 | drbd_al_complete_io(device, &peer_req->i); | 2416 | drbd_al_complete_io(device, &peer_req->i); |
2417 | } | ||
2401 | 2418 | ||
2402 | out_interrupted: | 2419 | out_interrupted: |
2403 | drbd_may_finish_epoch(connection, peer_req->epoch, EV_PUT + EV_CLEANUP); | 2420 | drbd_may_finish_epoch(connection, peer_req->epoch, EV_PUT + EV_CLEANUP); |
@@ -2561,6 +2578,7 @@ static int receive_DataRequest(struct drbd_connection *connection, struct packet | |||
2561 | peer_req->w.cb = w_e_end_data_req; | 2578 | peer_req->w.cb = w_e_end_data_req; |
2562 | fault_type = DRBD_FAULT_DT_RD; | 2579 | fault_type = DRBD_FAULT_DT_RD; |
2563 | /* application IO, don't drbd_rs_begin_io */ | 2580 | /* application IO, don't drbd_rs_begin_io */ |
2581 | peer_req->flags |= EE_APPLICATION; | ||
2564 | goto submit; | 2582 | goto submit; |
2565 | 2583 | ||
2566 | case P_RS_DATA_REQUEST: | 2584 | case P_RS_DATA_REQUEST: |
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 48975a264985..b908e9b3f63e 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c | |||
@@ -132,6 +132,7 @@ void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __releases(l | |||
132 | i = peer_req->i; | 132 | i = peer_req->i; |
133 | do_al_complete_io = peer_req->flags & EE_CALL_AL_COMPLETE_IO; | 133 | do_al_complete_io = peer_req->flags & EE_CALL_AL_COMPLETE_IO; |
134 | block_id = peer_req->block_id; | 134 | block_id = peer_req->block_id; |
135 | peer_req->flags &= ~EE_CALL_AL_COMPLETE_IO; | ||
135 | 136 | ||
136 | spin_lock_irqsave(&device->resource->req_lock, flags); | 137 | spin_lock_irqsave(&device->resource->req_lock, flags); |
137 | device->writ_cnt += peer_req->i.size >> 9; | 138 | device->writ_cnt += peer_req->i.size >> 9; |