diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-driver-xen-blkback | 10 | ||||
-rw-r--r-- | drivers/block/xen-blkback/blkback.c | 88 | ||||
-rw-r--r-- | drivers/block/xen-blkback/common.h | 8 |
3 files changed, 60 insertions, 46 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-xen-blkback b/Documentation/ABI/testing/sysfs-driver-xen-blkback index 8bb43b66eb55..4e7babb3ba1f 100644 --- a/Documentation/ABI/testing/sysfs-driver-xen-blkback +++ b/Documentation/ABI/testing/sysfs-driver-xen-blkback | |||
@@ -15,3 +15,13 @@ Description: | |||
15 | blkback. If the frontend tries to use more than | 15 | blkback. If the frontend tries to use more than |
16 | max_persistent_grants, the LRU kicks in and starts | 16 | max_persistent_grants, the LRU kicks in and starts |
17 | removing 5% of max_persistent_grants every 100ms. | 17 | removing 5% of max_persistent_grants every 100ms. |
18 | |||
19 | What: /sys/module/xen_blkback/parameters/persistent_grant_unused_seconds | ||
20 | Date: August 2018 | ||
21 | KernelVersion: 4.19 | ||
22 | Contact: Roger Pau Monné <roger.pau@citrix.com> | ||
23 | Description: | ||
24 | How long a persistent grant is allowed to remain | ||
25 | allocated without being in use. The time is in | ||
26 | seconds, 0 means indefinitely long. | ||
27 | The default is 60 seconds. | ||
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index b55b245e8052..9eae7b243f68 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c | |||
@@ -84,6 +84,18 @@ MODULE_PARM_DESC(max_persistent_grants, | |||
84 | "Maximum number of grants to map persistently"); | 84 | "Maximum number of grants to map persistently"); |
85 | 85 | ||
86 | /* | 86 | /* |
87 | * How long a persistent grant is allowed to remain allocated without being in | ||
88 | * use. The time is in seconds, 0 means indefinitely long. | ||
89 | */ | ||
90 | |||
91 | static unsigned int xen_blkif_pgrant_timeout = 60; | ||
92 | module_param_named(persistent_grant_unused_seconds, xen_blkif_pgrant_timeout, | ||
93 | uint, 0644); | ||
94 | MODULE_PARM_DESC(persistent_grant_unused_seconds, | ||
95 | "Time in seconds an unused persistent grant is allowed to " | ||
96 | "remain allocated. Default is 60, 0 means unlimited."); | ||
97 | |||
98 | /* | ||
87 | * Maximum number of rings/queues blkback supports, allow as many queues as there | 99 | * Maximum number of rings/queues blkback supports, allow as many queues as there |
88 | * are CPUs if user has not specified a value. | 100 | * are CPUs if user has not specified a value. |
89 | */ | 101 | */ |
@@ -123,6 +135,13 @@ module_param(log_stats, int, 0644); | |||
123 | /* Number of free pages to remove on each call to gnttab_free_pages */ | 135 | /* Number of free pages to remove on each call to gnttab_free_pages */ |
124 | #define NUM_BATCH_FREE_PAGES 10 | 136 | #define NUM_BATCH_FREE_PAGES 10 |
125 | 137 | ||
138 | static inline bool persistent_gnt_timeout(struct persistent_gnt *persistent_gnt) | ||
139 | { | ||
140 | return xen_blkif_pgrant_timeout && | ||
141 | (jiffies - persistent_gnt->last_used >= | ||
142 | HZ * xen_blkif_pgrant_timeout); | ||
143 | } | ||
144 | |||
126 | static inline int get_free_page(struct xen_blkif_ring *ring, struct page **page) | 145 | static inline int get_free_page(struct xen_blkif_ring *ring, struct page **page) |
127 | { | 146 | { |
128 | unsigned long flags; | 147 | unsigned long flags; |
@@ -278,7 +297,7 @@ static void put_persistent_gnt(struct xen_blkif_ring *ring, | |||
278 | { | 297 | { |
279 | if(!test_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags)) | 298 | if(!test_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags)) |
280 | pr_alert_ratelimited("freeing a grant already unused\n"); | 299 | pr_alert_ratelimited("freeing a grant already unused\n"); |
281 | set_bit(PERSISTENT_GNT_WAS_ACTIVE, persistent_gnt->flags); | 300 | persistent_gnt->last_used = jiffies; |
282 | clear_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags); | 301 | clear_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags); |
283 | atomic_dec(&ring->persistent_gnt_in_use); | 302 | atomic_dec(&ring->persistent_gnt_in_use); |
284 | } | 303 | } |
@@ -371,26 +390,26 @@ static void purge_persistent_gnt(struct xen_blkif_ring *ring) | |||
371 | struct persistent_gnt *persistent_gnt; | 390 | struct persistent_gnt *persistent_gnt; |
372 | struct rb_node *n; | 391 | struct rb_node *n; |
373 | unsigned int num_clean, total; | 392 | unsigned int num_clean, total; |
374 | bool scan_used = false, clean_used = false; | 393 | bool scan_used = false; |
375 | struct rb_root *root; | 394 | struct rb_root *root; |
376 | 395 | ||
377 | if (ring->persistent_gnt_c < xen_blkif_max_pgrants || | ||
378 | (ring->persistent_gnt_c == xen_blkif_max_pgrants && | ||
379 | !ring->blkif->vbd.overflow_max_grants)) { | ||
380 | goto out; | ||
381 | } | ||
382 | |||
383 | if (work_busy(&ring->persistent_purge_work)) { | 396 | if (work_busy(&ring->persistent_purge_work)) { |
384 | pr_alert_ratelimited("Scheduled work from previous purge is still busy, cannot purge list\n"); | 397 | pr_alert_ratelimited("Scheduled work from previous purge is still busy, cannot purge list\n"); |
385 | goto out; | 398 | goto out; |
386 | } | 399 | } |
387 | 400 | ||
388 | num_clean = (xen_blkif_max_pgrants / 100) * LRU_PERCENT_CLEAN; | 401 | if (ring->persistent_gnt_c < xen_blkif_max_pgrants || |
389 | num_clean = ring->persistent_gnt_c - xen_blkif_max_pgrants + num_clean; | 402 | (ring->persistent_gnt_c == xen_blkif_max_pgrants && |
390 | num_clean = min(ring->persistent_gnt_c, num_clean); | 403 | !ring->blkif->vbd.overflow_max_grants)) { |
391 | if ((num_clean == 0) || | 404 | num_clean = 0; |
392 | (num_clean > (ring->persistent_gnt_c - atomic_read(&ring->persistent_gnt_in_use)))) | 405 | } else { |
393 | goto out; | 406 | num_clean = (xen_blkif_max_pgrants / 100) * LRU_PERCENT_CLEAN; |
407 | num_clean = ring->persistent_gnt_c - xen_blkif_max_pgrants + | ||
408 | num_clean; | ||
409 | num_clean = min(ring->persistent_gnt_c, num_clean); | ||
410 | pr_debug("Going to purge at least %u persistent grants\n", | ||
411 | num_clean); | ||
412 | } | ||
394 | 413 | ||
395 | /* | 414 | /* |
396 | * At this point, we can assure that there will be no calls | 415 | * At this point, we can assure that there will be no calls |
@@ -401,9 +420,7 @@ static void purge_persistent_gnt(struct xen_blkif_ring *ring) | |||
401 | * number of grants. | 420 | * number of grants. |
402 | */ | 421 | */ |
403 | 422 | ||
404 | total = num_clean; | 423 | total = 0; |
405 | |||
406 | pr_debug("Going to purge %u persistent grants\n", num_clean); | ||
407 | 424 | ||
408 | BUG_ON(!list_empty(&ring->persistent_purge_list)); | 425 | BUG_ON(!list_empty(&ring->persistent_purge_list)); |
409 | root = &ring->persistent_gnts; | 426 | root = &ring->persistent_gnts; |
@@ -412,46 +429,37 @@ purge_list: | |||
412 | BUG_ON(persistent_gnt->handle == | 429 | BUG_ON(persistent_gnt->handle == |
413 | BLKBACK_INVALID_HANDLE); | 430 | BLKBACK_INVALID_HANDLE); |
414 | 431 | ||
415 | if (clean_used) { | ||
416 | clear_bit(PERSISTENT_GNT_WAS_ACTIVE, persistent_gnt->flags); | ||
417 | continue; | ||
418 | } | ||
419 | |||
420 | if (test_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags)) | 432 | if (test_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags)) |
421 | continue; | 433 | continue; |
422 | if (!scan_used && | 434 | if (!scan_used && !persistent_gnt_timeout(persistent_gnt)) |
423 | (test_bit(PERSISTENT_GNT_WAS_ACTIVE, persistent_gnt->flags))) | 435 | continue; |
436 | if (scan_used && total >= num_clean) | ||
424 | continue; | 437 | continue; |
425 | 438 | ||
426 | rb_erase(&persistent_gnt->node, root); | 439 | rb_erase(&persistent_gnt->node, root); |
427 | list_add(&persistent_gnt->remove_node, | 440 | list_add(&persistent_gnt->remove_node, |
428 | &ring->persistent_purge_list); | 441 | &ring->persistent_purge_list); |
429 | if (--num_clean == 0) | 442 | total++; |
430 | goto finished; | ||
431 | } | 443 | } |
432 | /* | 444 | /* |
433 | * If we get here it means we also need to start cleaning | 445 | * Check whether we also need to start cleaning |
434 | * grants that were used since last purge in order to cope | 446 | * grants that were used since last purge in order to cope |
435 | * with the requested num | 447 | * with the requested num |
436 | */ | 448 | */ |
437 | if (!scan_used && !clean_used) { | 449 | if (!scan_used && total < num_clean) { |
438 | pr_debug("Still missing %u purged frames\n", num_clean); | 450 | pr_debug("Still missing %u purged frames\n", num_clean - total); |
439 | scan_used = true; | 451 | scan_used = true; |
440 | goto purge_list; | 452 | goto purge_list; |
441 | } | 453 | } |
442 | finished: | ||
443 | if (!clean_used) { | ||
444 | pr_debug("Finished scanning for grants to clean, removing used flag\n"); | ||
445 | clean_used = true; | ||
446 | goto purge_list; | ||
447 | } | ||
448 | 454 | ||
449 | ring->persistent_gnt_c -= (total - num_clean); | 455 | if (total) { |
450 | ring->blkif->vbd.overflow_max_grants = 0; | 456 | ring->persistent_gnt_c -= total; |
457 | ring->blkif->vbd.overflow_max_grants = 0; | ||
451 | 458 | ||
452 | /* We can defer this work */ | 459 | /* We can defer this work */ |
453 | schedule_work(&ring->persistent_purge_work); | 460 | schedule_work(&ring->persistent_purge_work); |
454 | pr_debug("Purged %u/%u\n", (total - num_clean), total); | 461 | pr_debug("Purged %u/%u\n", num_clean, total); |
462 | } | ||
455 | 463 | ||
456 | out: | 464 | out: |
457 | return; | 465 | return; |
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index ecb35fe8ca8d..7bff72db3b7e 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h | |||
@@ -234,14 +234,9 @@ struct xen_vbd { | |||
234 | struct backend_info; | 234 | struct backend_info; |
235 | 235 | ||
236 | /* Number of available flags */ | 236 | /* Number of available flags */ |
237 | #define PERSISTENT_GNT_FLAGS_SIZE 2 | 237 | #define PERSISTENT_GNT_FLAGS_SIZE 1 |
238 | /* This persistent grant is currently in use */ | 238 | /* This persistent grant is currently in use */ |
239 | #define PERSISTENT_GNT_ACTIVE 0 | 239 | #define PERSISTENT_GNT_ACTIVE 0 |
240 | /* | ||
241 | * This persistent grant has been used, this flag is set when we remove the | ||
242 | * PERSISTENT_GNT_ACTIVE, to know that this grant has been used recently. | ||
243 | */ | ||
244 | #define PERSISTENT_GNT_WAS_ACTIVE 1 | ||
245 | 240 | ||
246 | /* Number of requests that we can fit in a ring */ | 241 | /* Number of requests that we can fit in a ring */ |
247 | #define XEN_BLKIF_REQS_PER_PAGE 32 | 242 | #define XEN_BLKIF_REQS_PER_PAGE 32 |
@@ -250,6 +245,7 @@ struct persistent_gnt { | |||
250 | struct page *page; | 245 | struct page *page; |
251 | grant_ref_t gnt; | 246 | grant_ref_t gnt; |
252 | grant_handle_t handle; | 247 | grant_handle_t handle; |
248 | unsigned long last_used; | ||
253 | DECLARE_BITMAP(flags, PERSISTENT_GNT_FLAGS_SIZE); | 249 | DECLARE_BITMAP(flags, PERSISTENT_GNT_FLAGS_SIZE); |
254 | struct rb_node node; | 250 | struct rb_node node; |
255 | struct list_head remove_node; | 251 | struct list_head remove_node; |