Skip to content

Commit 973e540

Browse files
jgross1konradwilk
authored andcommitted
xen/blkback: don't keep persistent grants too long
Persistent grants are allocated until a threshold per ring is being reached. Those grants won't be freed until the ring is being destroyed meaning there will be resources kept busy which might no longer be used. Instead of freeing only persistent grants until the threshold is reached add a timestamp and remove all persistent grants not having been in use for a minute. Signed-off-by: Juergen Gross <jgross@suse.com> Reviewed-by: Roger Pau Monné <roger.pau@citrix.com> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
1 parent b86d865 commit 973e540

File tree

3 files changed

+60
-46
lines changed

3 files changed

+60
-46
lines changed

Documentation/ABI/testing/sysfs-driver-xen-blkback

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,13 @@ Description:
1515
blkback. If the frontend tries to use more than
1616
max_persistent_grants, the LRU kicks in and starts
1717
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.

drivers/block/xen-blkback/blkback.c

Lines changed: 48 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,18 @@ module_param_named(max_persistent_grants, xen_blkif_max_pgrants, int, 0644);
8383
MODULE_PARM_DESC(max_persistent_grants,
8484
"Maximum number of grants to map persistently");
8585

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+
8698
/*
8799
* Maximum number of rings/queues blkback supports, allow as many queues as there
88100
* are CPUs if user has not specified a value.
@@ -123,6 +135,13 @@ module_param(log_stats, int, 0644);
123135
/* Number of free pages to remove on each call to gnttab_free_pages */
124136
#define NUM_BATCH_FREE_PAGES 10
125137

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+
126145
static inline int get_free_page(struct xen_blkif_ring *ring, struct page **page)
127146
{
128147
unsigned long flags;
@@ -278,7 +297,7 @@ static void put_persistent_gnt(struct xen_blkif_ring *ring,
278297
{
279298
if(!test_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags))
280299
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;
282301
clear_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags);
283302
atomic_dec(&ring->persistent_gnt_in_use);
284303
}
@@ -371,26 +390,26 @@ static void purge_persistent_gnt(struct xen_blkif_ring *ring)
371390
struct persistent_gnt *persistent_gnt;
372391
struct rb_node *n;
373392
unsigned int num_clean, total;
374-
bool scan_used = false, clean_used = false;
393+
bool scan_used = false;
375394
struct rb_root *root;
376395

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-
383396
if (work_busy(&ring->persistent_purge_work)) {
384397
pr_alert_ratelimited("Scheduled work from previous purge is still busy, cannot purge list\n");
385398
goto out;
386399
}
387400

388-
num_clean = (xen_blkif_max_pgrants / 100) * LRU_PERCENT_CLEAN;
389-
num_clean = ring->persistent_gnt_c - xen_blkif_max_pgrants + num_clean;
390-
num_clean = min(ring->persistent_gnt_c, num_clean);
391-
if ((num_clean == 0) ||
392-
(num_clean > (ring->persistent_gnt_c - atomic_read(&ring->persistent_gnt_in_use))))
393-
goto out;
401+
if (ring->persistent_gnt_c < xen_blkif_max_pgrants ||
402+
(ring->persistent_gnt_c == xen_blkif_max_pgrants &&
403+
!ring->blkif->vbd.overflow_max_grants)) {
404+
num_clean = 0;
405+
} else {
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+
}
394413

395414
/*
396415
* 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)
401420
* number of grants.
402421
*/
403422

404-
total = num_clean;
405-
406-
pr_debug("Going to purge %u persistent grants\n", num_clean);
423+
total = 0;
407424

408425
BUG_ON(!list_empty(&ring->persistent_purge_list));
409426
root = &ring->persistent_gnts;
@@ -412,46 +429,37 @@ static void purge_persistent_gnt(struct xen_blkif_ring *ring)
412429
BUG_ON(persistent_gnt->handle ==
413430
BLKBACK_INVALID_HANDLE);
414431

415-
if (clean_used) {
416-
clear_bit(PERSISTENT_GNT_WAS_ACTIVE, persistent_gnt->flags);
417-
continue;
418-
}
419-
420432
if (test_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags))
421433
continue;
422-
if (!scan_used &&
423-
(test_bit(PERSISTENT_GNT_WAS_ACTIVE, persistent_gnt->flags)))
434+
if (!scan_used && !persistent_gnt_timeout(persistent_gnt))
435+
continue;
436+
if (scan_used && total >= num_clean)
424437
continue;
425438

426439
rb_erase(&persistent_gnt->node, root);
427440
list_add(&persistent_gnt->remove_node,
428441
&ring->persistent_purge_list);
429-
if (--num_clean == 0)
430-
goto finished;
442+
total++;
431443
}
432444
/*
433-
* If we get here it means we also need to start cleaning
445+
* Check whether we also need to start cleaning
434446
* grants that were used since last purge in order to cope
435447
* with the requested num
436448
*/
437-
if (!scan_used && !clean_used) {
438-
pr_debug("Still missing %u purged frames\n", num_clean);
449+
if (!scan_used && total < num_clean) {
450+
pr_debug("Still missing %u purged frames\n", num_clean - total);
439451
scan_used = true;
440452
goto purge_list;
441453
}
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-
}
448454

449-
ring->persistent_gnt_c -= (total - num_clean);
450-
ring->blkif->vbd.overflow_max_grants = 0;
455+
if (total) {
456+
ring->persistent_gnt_c -= total;
457+
ring->blkif->vbd.overflow_max_grants = 0;
451458

452-
/* We can defer this work */
453-
schedule_work(&ring->persistent_purge_work);
454-
pr_debug("Purged %u/%u\n", (total - num_clean), total);
459+
/* We can defer this work */
460+
schedule_work(&ring->persistent_purge_work);
461+
pr_debug("Purged %u/%u\n", num_clean, total);
462+
}
455463

456464
out:
457465
return;

drivers/block/xen-blkback/common.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -234,14 +234,9 @@ struct xen_vbd {
234234
struct backend_info;
235235

236236
/* Number of available flags */
237-
#define PERSISTENT_GNT_FLAGS_SIZE 2
237+
#define PERSISTENT_GNT_FLAGS_SIZE 1
238238
/* This persistent grant is currently in use */
239239
#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
245240

246241
/* Number of requests that we can fit in a ring */
247242
#define XEN_BLKIF_REQS_PER_PAGE 32
@@ -250,6 +245,7 @@ struct persistent_gnt {
250245
struct page *page;
251246
grant_ref_t gnt;
252247
grant_handle_t handle;
248+
unsigned long last_used;
253249
DECLARE_BITMAP(flags, PERSISTENT_GNT_FLAGS_SIZE);
254250
struct rb_node node;
255251
struct list_head remove_node;

0 commit comments

Comments
 (0)