diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/drbd/drbd_int.h | 8 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 1 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 26 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_worker.c | 4 |
4 files changed, 27 insertions, 12 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 79b877db9a39..eb1273d04caf 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h | |||
@@ -1077,7 +1077,8 @@ struct drbd_conf { | |||
1077 | int next_barrier_nr; | 1077 | int next_barrier_nr; |
1078 | struct hlist_head *app_reads_hash; /* is proteced by req_lock */ | 1078 | struct hlist_head *app_reads_hash; /* is proteced by req_lock */ |
1079 | struct list_head resync_reads; | 1079 | struct list_head resync_reads; |
1080 | atomic_t pp_in_use; | 1080 | atomic_t pp_in_use; /* allocated from page pool */ |
1081 | atomic_t pp_in_use_by_net; /* sendpage()d, still referenced by tcp */ | ||
1081 | wait_queue_head_t ee_wait; | 1082 | wait_queue_head_t ee_wait; |
1082 | struct page *md_io_page; /* one page buffer for md_io */ | 1083 | struct page *md_io_page; /* one page buffer for md_io */ |
1083 | struct page *md_io_tmpp; /* for logical_block_size != 512 */ | 1084 | struct page *md_io_tmpp; /* for logical_block_size != 512 */ |
@@ -1555,7 +1556,10 @@ extern struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, | |||
1555 | sector_t sector, | 1556 | sector_t sector, |
1556 | unsigned int data_size, | 1557 | unsigned int data_size, |
1557 | gfp_t gfp_mask) __must_hold(local); | 1558 | gfp_t gfp_mask) __must_hold(local); |
1558 | extern void drbd_free_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e); | 1559 | extern void drbd_free_some_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, |
1560 | int is_net); | ||
1561 | #define drbd_free_ee(m,e) drbd_free_some_ee(m, e, 0) | ||
1562 | #define drbd_free_net_ee(m,e) drbd_free_some_ee(m, e, 1) | ||
1559 | extern void drbd_wait_ee_list_empty(struct drbd_conf *mdev, | 1563 | extern void drbd_wait_ee_list_empty(struct drbd_conf *mdev, |
1560 | struct list_head *head); | 1564 | struct list_head *head); |
1561 | extern void _drbd_wait_ee_list_empty(struct drbd_conf *mdev, | 1565 | extern void _drbd_wait_ee_list_empty(struct drbd_conf *mdev, |
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 1827cf073c2e..981cfd178b09 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c | |||
@@ -2753,6 +2753,7 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) | |||
2753 | atomic_set(&mdev->net_cnt, 0); | 2753 | atomic_set(&mdev->net_cnt, 0); |
2754 | atomic_set(&mdev->packet_seq, 0); | 2754 | atomic_set(&mdev->packet_seq, 0); |
2755 | atomic_set(&mdev->pp_in_use, 0); | 2755 | atomic_set(&mdev->pp_in_use, 0); |
2756 | atomic_set(&mdev->pp_in_use_by_net, 0); | ||
2756 | atomic_set(&mdev->rs_sect_in, 0); | 2757 | atomic_set(&mdev->rs_sect_in, 0); |
2757 | atomic_set(&mdev->rs_sect_ev, 0); | 2758 | atomic_set(&mdev->rs_sect_ev, 0); |
2758 | 2759 | ||
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index e96fbb04ea4d..2c3edf0ac5ca 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c | |||
@@ -241,7 +241,7 @@ static void drbd_kick_lo_and_reclaim_net(struct drbd_conf *mdev) | |||
241 | spin_unlock_irq(&mdev->req_lock); | 241 | spin_unlock_irq(&mdev->req_lock); |
242 | 242 | ||
243 | list_for_each_entry_safe(e, t, &reclaimed, w.list) | 243 | list_for_each_entry_safe(e, t, &reclaimed, w.list) |
244 | drbd_free_ee(mdev, e); | 244 | drbd_free_net_ee(mdev, e); |
245 | } | 245 | } |
246 | 246 | ||
247 | /** | 247 | /** |
@@ -298,9 +298,11 @@ static struct page *drbd_pp_alloc(struct drbd_conf *mdev, unsigned number, bool | |||
298 | * Is also used from inside an other spin_lock_irq(&mdev->req_lock); | 298 | * Is also used from inside an other spin_lock_irq(&mdev->req_lock); |
299 | * Either links the page chain back to the global pool, | 299 | * Either links the page chain back to the global pool, |
300 | * or returns all pages to the system. */ | 300 | * or returns all pages to the system. */ |
301 | static void drbd_pp_free(struct drbd_conf *mdev, struct page *page) | 301 | static void drbd_pp_free(struct drbd_conf *mdev, struct page *page, int is_net) |
302 | { | 302 | { |
303 | atomic_t *a = is_net ? &mdev->pp_in_use_by_net : &mdev->pp_in_use; | ||
303 | int i; | 304 | int i; |
305 | |||
304 | if (drbd_pp_vacant > (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE)*minor_count) | 306 | if (drbd_pp_vacant > (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE)*minor_count) |
305 | i = page_chain_free(page); | 307 | i = page_chain_free(page); |
306 | else { | 308 | else { |
@@ -311,10 +313,10 @@ static void drbd_pp_free(struct drbd_conf *mdev, struct page *page) | |||
311 | drbd_pp_vacant += i; | 313 | drbd_pp_vacant += i; |
312 | spin_unlock(&drbd_pp_lock); | 314 | spin_unlock(&drbd_pp_lock); |
313 | } | 315 | } |
314 | atomic_sub(i, &mdev->pp_in_use); | 316 | i = atomic_sub_return(i, a); |
315 | i = atomic_read(&mdev->pp_in_use); | ||
316 | if (i < 0) | 317 | if (i < 0) |
317 | dev_warn(DEV, "ASSERTION FAILED: pp_in_use: %d < 0\n", i); | 318 | dev_warn(DEV, "ASSERTION FAILED: %s: %d < 0\n", |
319 | is_net ? "pp_in_use_by_net" : "pp_in_use", i); | ||
318 | wake_up(&drbd_pp_wait); | 320 | wake_up(&drbd_pp_wait); |
319 | } | 321 | } |
320 | 322 | ||
@@ -374,11 +376,11 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, | |||
374 | return NULL; | 376 | return NULL; |
375 | } | 377 | } |
376 | 378 | ||
377 | void drbd_free_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e) | 379 | void drbd_free_some_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, int is_net) |
378 | { | 380 | { |
379 | if (e->flags & EE_HAS_DIGEST) | 381 | if (e->flags & EE_HAS_DIGEST) |
380 | kfree(e->digest); | 382 | kfree(e->digest); |
381 | drbd_pp_free(mdev, e->pages); | 383 | drbd_pp_free(mdev, e->pages, is_net); |
382 | D_ASSERT(atomic_read(&e->pending_bios) == 0); | 384 | D_ASSERT(atomic_read(&e->pending_bios) == 0); |
383 | D_ASSERT(hlist_unhashed(&e->colision)); | 385 | D_ASSERT(hlist_unhashed(&e->colision)); |
384 | mempool_free(e, drbd_ee_mempool); | 386 | mempool_free(e, drbd_ee_mempool); |
@@ -389,13 +391,14 @@ int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list) | |||
389 | LIST_HEAD(work_list); | 391 | LIST_HEAD(work_list); |
390 | struct drbd_epoch_entry *e, *t; | 392 | struct drbd_epoch_entry *e, *t; |
391 | int count = 0; | 393 | int count = 0; |
394 | int is_net = list == &mdev->net_ee; | ||
392 | 395 | ||
393 | spin_lock_irq(&mdev->req_lock); | 396 | spin_lock_irq(&mdev->req_lock); |
394 | list_splice_init(list, &work_list); | 397 | list_splice_init(list, &work_list); |
395 | spin_unlock_irq(&mdev->req_lock); | 398 | spin_unlock_irq(&mdev->req_lock); |
396 | 399 | ||
397 | list_for_each_entry_safe(e, t, &work_list, w.list) { | 400 | list_for_each_entry_safe(e, t, &work_list, w.list) { |
398 | drbd_free_ee(mdev, e); | 401 | drbd_free_some_ee(mdev, e, is_net); |
399 | count++; | 402 | count++; |
400 | } | 403 | } |
401 | return count; | 404 | return count; |
@@ -424,7 +427,7 @@ static int drbd_process_done_ee(struct drbd_conf *mdev) | |||
424 | spin_unlock_irq(&mdev->req_lock); | 427 | spin_unlock_irq(&mdev->req_lock); |
425 | 428 | ||
426 | list_for_each_entry_safe(e, t, &reclaimed, w.list) | 429 | list_for_each_entry_safe(e, t, &reclaimed, w.list) |
427 | drbd_free_ee(mdev, e); | 430 | drbd_free_net_ee(mdev, e); |
428 | 431 | ||
429 | /* possible callbacks here: | 432 | /* possible callbacks here: |
430 | * e_end_block, and e_end_resync_block, e_send_discard_ack. | 433 | * e_end_block, and e_end_resync_block, e_send_discard_ack. |
@@ -1460,7 +1463,7 @@ static int drbd_drain_block(struct drbd_conf *mdev, int data_size) | |||
1460 | data_size -= rr; | 1463 | data_size -= rr; |
1461 | } | 1464 | } |
1462 | kunmap(page); | 1465 | kunmap(page); |
1463 | drbd_pp_free(mdev, page); | 1466 | drbd_pp_free(mdev, page, 0); |
1464 | return rv; | 1467 | return rv; |
1465 | } | 1468 | } |
1466 | 1469 | ||
@@ -3879,6 +3882,9 @@ static void drbd_disconnect(struct drbd_conf *mdev) | |||
3879 | i = drbd_release_ee(mdev, &mdev->net_ee); | 3882 | i = drbd_release_ee(mdev, &mdev->net_ee); |
3880 | if (i) | 3883 | if (i) |
3881 | dev_info(DEV, "net_ee not empty, killed %u entries\n", i); | 3884 | dev_info(DEV, "net_ee not empty, killed %u entries\n", i); |
3885 | i = atomic_read(&mdev->pp_in_use_by_net); | ||
3886 | if (i) | ||
3887 | dev_info(DEV, "pp_in_use_by_net = %d, expected 0\n", i); | ||
3882 | i = atomic_read(&mdev->pp_in_use); | 3888 | i = atomic_read(&mdev->pp_in_use); |
3883 | if (i) | 3889 | if (i) |
3884 | dev_info(DEV, "pp_in_use = %d, expected 0\n", i); | 3890 | dev_info(DEV, "pp_in_use = %d, expected 0\n", i); |
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 0e5bf8c98293..01743193f321 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c | |||
@@ -914,9 +914,13 @@ static void move_to_net_ee_or_free(struct drbd_conf *mdev, struct drbd_epoch_ent | |||
914 | { | 914 | { |
915 | if (drbd_ee_has_active_page(e)) { | 915 | if (drbd_ee_has_active_page(e)) { |
916 | /* This might happen if sendpage() has not finished */ | 916 | /* This might happen if sendpage() has not finished */ |
917 | int i = DIV_ROUND_UP(e->size, PAGE_SIZE); | ||
918 | atomic_add(i, &mdev->pp_in_use_by_net); | ||
919 | atomic_sub(i, &mdev->pp_in_use); | ||
917 | spin_lock_irq(&mdev->req_lock); | 920 | spin_lock_irq(&mdev->req_lock); |
918 | list_add_tail(&e->w.list, &mdev->net_ee); | 921 | list_add_tail(&e->w.list, &mdev->net_ee); |
919 | spin_unlock_irq(&mdev->req_lock); | 922 | spin_unlock_irq(&mdev->req_lock); |
923 | wake_up(&drbd_pp_wait); | ||
920 | } else | 924 | } else |
921 | drbd_free_ee(mdev, e); | 925 | drbd_free_ee(mdev, e); |
922 | } | 926 | } |