diff options
author | Jens Axboe <axboe@kernel.dk> | 2018-08-27 13:27:32 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2018-08-27 13:27:32 -0400 |
commit | 057d3ccf93a437080c4138cd6d74c4d7cf332131 (patch) | |
tree | ca4378c4ee1c2a48a0961076bc3c0c309d22b2e4 | |
parent | 38cfb5a45ee013bfab5d1ae4c4738815e744b440 (diff) | |
parent | 6f2f39ad1a54978394851c05e327419ebeb7227e (diff) |
Merge branch 'stable/for-jens-4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen into for-linus
Pull Xen block driver fixes from Konrad:
"Fix for flushing out persistent pages at a deterministic rate"
* 'stable/for-jens-4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen:
xen/blkback: remove unused pers_gnts_lock from struct xen_blkif_ring
xen/blkback: move persistent grants flags to bool
xen/blkfront: reorder tests in xlblk_init()
xen/blkfront: cleanup stale persistent grants
xen/blkback: don't keep persistent grants too long
-rw-r--r-- | Documentation/ABI/testing/sysfs-driver-xen-blkback | 10 | ||||
-rw-r--r-- | drivers/block/xen-blkback/blkback.c | 99 | ||||
-rw-r--r-- | drivers/block/xen-blkback/common.h | 14 | ||||
-rw-r--r-- | drivers/block/xen-blkfront.c | 110 |
4 files changed, 163 insertions, 70 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..fd1e19f1a49f 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; |
@@ -236,8 +255,7 @@ static int add_persistent_gnt(struct xen_blkif_ring *ring, | |||
236 | } | 255 | } |
237 | } | 256 | } |
238 | 257 | ||
239 | bitmap_zero(persistent_gnt->flags, PERSISTENT_GNT_FLAGS_SIZE); | 258 | persistent_gnt->active = true; |
240 | set_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags); | ||
241 | /* Add new node and rebalance tree. */ | 259 | /* Add new node and rebalance tree. */ |
242 | rb_link_node(&(persistent_gnt->node), parent, new); | 260 | rb_link_node(&(persistent_gnt->node), parent, new); |
243 | rb_insert_color(&(persistent_gnt->node), &ring->persistent_gnts); | 261 | rb_insert_color(&(persistent_gnt->node), &ring->persistent_gnts); |
@@ -261,11 +279,11 @@ static struct persistent_gnt *get_persistent_gnt(struct xen_blkif_ring *ring, | |||
261 | else if (gref > data->gnt) | 279 | else if (gref > data->gnt) |
262 | node = node->rb_right; | 280 | node = node->rb_right; |
263 | else { | 281 | else { |
264 | if(test_bit(PERSISTENT_GNT_ACTIVE, data->flags)) { | 282 | if (data->active) { |
265 | pr_alert_ratelimited("requesting a grant already in use\n"); | 283 | pr_alert_ratelimited("requesting a grant already in use\n"); |
266 | return NULL; | 284 | return NULL; |
267 | } | 285 | } |
268 | set_bit(PERSISTENT_GNT_ACTIVE, data->flags); | 286 | data->active = true; |
269 | atomic_inc(&ring->persistent_gnt_in_use); | 287 | atomic_inc(&ring->persistent_gnt_in_use); |
270 | return data; | 288 | return data; |
271 | } | 289 | } |
@@ -276,10 +294,10 @@ static struct persistent_gnt *get_persistent_gnt(struct xen_blkif_ring *ring, | |||
276 | static void put_persistent_gnt(struct xen_blkif_ring *ring, | 294 | static void put_persistent_gnt(struct xen_blkif_ring *ring, |
277 | struct persistent_gnt *persistent_gnt) | 295 | struct persistent_gnt *persistent_gnt) |
278 | { | 296 | { |
279 | if(!test_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags)) | 297 | if (!persistent_gnt->active) |
280 | pr_alert_ratelimited("freeing a grant already unused\n"); | 298 | pr_alert_ratelimited("freeing a grant already unused\n"); |
281 | set_bit(PERSISTENT_GNT_WAS_ACTIVE, persistent_gnt->flags); | 299 | persistent_gnt->last_used = jiffies; |
282 | clear_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags); | 300 | persistent_gnt->active = false; |
283 | atomic_dec(&ring->persistent_gnt_in_use); | 301 | atomic_dec(&ring->persistent_gnt_in_use); |
284 | } | 302 | } |
285 | 303 | ||
@@ -371,26 +389,26 @@ static void purge_persistent_gnt(struct xen_blkif_ring *ring) | |||
371 | struct persistent_gnt *persistent_gnt; | 389 | struct persistent_gnt *persistent_gnt; |
372 | struct rb_node *n; | 390 | struct rb_node *n; |
373 | unsigned int num_clean, total; | 391 | unsigned int num_clean, total; |
374 | bool scan_used = false, clean_used = false; | 392 | bool scan_used = false; |
375 | struct rb_root *root; | 393 | struct rb_root *root; |
376 | 394 | ||
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)) { | 395 | if (work_busy(&ring->persistent_purge_work)) { |
384 | pr_alert_ratelimited("Scheduled work from previous purge is still busy, cannot purge list\n"); | 396 | pr_alert_ratelimited("Scheduled work from previous purge is still busy, cannot purge list\n"); |
385 | goto out; | 397 | goto out; |
386 | } | 398 | } |
387 | 399 | ||
388 | num_clean = (xen_blkif_max_pgrants / 100) * LRU_PERCENT_CLEAN; | 400 | if (ring->persistent_gnt_c < xen_blkif_max_pgrants || |
389 | num_clean = ring->persistent_gnt_c - xen_blkif_max_pgrants + num_clean; | 401 | (ring->persistent_gnt_c == xen_blkif_max_pgrants && |
390 | num_clean = min(ring->persistent_gnt_c, num_clean); | 402 | !ring->blkif->vbd.overflow_max_grants)) { |
391 | if ((num_clean == 0) || | 403 | num_clean = 0; |
392 | (num_clean > (ring->persistent_gnt_c - atomic_read(&ring->persistent_gnt_in_use)))) | 404 | } else { |
393 | goto out; | 405 | num_clean = (xen_blkif_max_pgrants / 100) * LRU_PERCENT_CLEAN; |
406 | num_clean = ring->persistent_gnt_c - xen_blkif_max_pgrants + | ||
407 | num_clean; | ||
408 | num_clean = min(ring->persistent_gnt_c, num_clean); | ||
409 | pr_debug("Going to purge at least %u persistent grants\n", | ||
410 | num_clean); | ||
411 | } | ||
394 | 412 | ||
395 | /* | 413 | /* |
396 | * At this point, we can assure that there will be no calls | 414 | * At this point, we can assure that there will be no calls |
@@ -401,9 +419,7 @@ static void purge_persistent_gnt(struct xen_blkif_ring *ring) | |||
401 | * number of grants. | 419 | * number of grants. |
402 | */ | 420 | */ |
403 | 421 | ||
404 | total = num_clean; | 422 | total = 0; |
405 | |||
406 | pr_debug("Going to purge %u persistent grants\n", num_clean); | ||
407 | 423 | ||
408 | BUG_ON(!list_empty(&ring->persistent_purge_list)); | 424 | BUG_ON(!list_empty(&ring->persistent_purge_list)); |
409 | root = &ring->persistent_gnts; | 425 | root = &ring->persistent_gnts; |
@@ -412,46 +428,37 @@ purge_list: | |||
412 | BUG_ON(persistent_gnt->handle == | 428 | BUG_ON(persistent_gnt->handle == |
413 | BLKBACK_INVALID_HANDLE); | 429 | BLKBACK_INVALID_HANDLE); |
414 | 430 | ||
415 | if (clean_used) { | 431 | if (persistent_gnt->active) |
416 | clear_bit(PERSISTENT_GNT_WAS_ACTIVE, persistent_gnt->flags); | ||
417 | continue; | 432 | continue; |
418 | } | 433 | if (!scan_used && !persistent_gnt_timeout(persistent_gnt)) |
419 | |||
420 | if (test_bit(PERSISTENT_GNT_ACTIVE, persistent_gnt->flags)) | ||
421 | continue; | 434 | continue; |
422 | if (!scan_used && | 435 | if (scan_used && total >= num_clean) |
423 | (test_bit(PERSISTENT_GNT_WAS_ACTIVE, persistent_gnt->flags))) | ||
424 | continue; | 436 | continue; |
425 | 437 | ||
426 | rb_erase(&persistent_gnt->node, root); | 438 | rb_erase(&persistent_gnt->node, root); |
427 | list_add(&persistent_gnt->remove_node, | 439 | list_add(&persistent_gnt->remove_node, |
428 | &ring->persistent_purge_list); | 440 | &ring->persistent_purge_list); |
429 | if (--num_clean == 0) | 441 | total++; |
430 | goto finished; | ||
431 | } | 442 | } |
432 | /* | 443 | /* |
433 | * If we get here it means we also need to start cleaning | 444 | * Check whether we also need to start cleaning |
434 | * grants that were used since last purge in order to cope | 445 | * grants that were used since last purge in order to cope |
435 | * with the requested num | 446 | * with the requested num |
436 | */ | 447 | */ |
437 | if (!scan_used && !clean_used) { | 448 | if (!scan_used && total < num_clean) { |
438 | pr_debug("Still missing %u purged frames\n", num_clean); | 449 | pr_debug("Still missing %u purged frames\n", num_clean - total); |
439 | scan_used = true; | 450 | scan_used = true; |
440 | goto purge_list; | 451 | goto purge_list; |
441 | } | 452 | } |
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 | 453 | ||
449 | ring->persistent_gnt_c -= (total - num_clean); | 454 | if (total) { |
450 | ring->blkif->vbd.overflow_max_grants = 0; | 455 | ring->persistent_gnt_c -= total; |
456 | ring->blkif->vbd.overflow_max_grants = 0; | ||
451 | 457 | ||
452 | /* We can defer this work */ | 458 | /* We can defer this work */ |
453 | schedule_work(&ring->persistent_purge_work); | 459 | schedule_work(&ring->persistent_purge_work); |
454 | pr_debug("Purged %u/%u\n", (total - num_clean), total); | 460 | pr_debug("Purged %u/%u\n", num_clean, total); |
461 | } | ||
455 | 462 | ||
456 | out: | 463 | out: |
457 | return; | 464 | return; |
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index ecb35fe8ca8d..1d3002d773f7 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h | |||
@@ -233,16 +233,6 @@ struct xen_vbd { | |||
233 | 233 | ||
234 | struct backend_info; | 234 | struct backend_info; |
235 | 235 | ||
236 | /* Number of available flags */ | ||
237 | #define PERSISTENT_GNT_FLAGS_SIZE 2 | ||
238 | /* This persistent grant is currently in use */ | ||
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 | |||
246 | /* Number of requests that we can fit in a ring */ | 236 | /* Number of requests that we can fit in a ring */ |
247 | #define XEN_BLKIF_REQS_PER_PAGE 32 | 237 | #define XEN_BLKIF_REQS_PER_PAGE 32 |
248 | 238 | ||
@@ -250,7 +240,8 @@ struct persistent_gnt { | |||
250 | struct page *page; | 240 | struct page *page; |
251 | grant_ref_t gnt; | 241 | grant_ref_t gnt; |
252 | grant_handle_t handle; | 242 | grant_handle_t handle; |
253 | DECLARE_BITMAP(flags, PERSISTENT_GNT_FLAGS_SIZE); | 243 | unsigned long last_used; |
244 | bool active; | ||
254 | struct rb_node node; | 245 | struct rb_node node; |
255 | struct list_head remove_node; | 246 | struct list_head remove_node; |
256 | }; | 247 | }; |
@@ -278,7 +269,6 @@ struct xen_blkif_ring { | |||
278 | wait_queue_head_t pending_free_wq; | 269 | wait_queue_head_t pending_free_wq; |
279 | 270 | ||
280 | /* Tree to store persistent grants. */ | 271 | /* Tree to store persistent grants. */ |
281 | spinlock_t pers_gnts_lock; | ||
282 | struct rb_root persistent_gnts; | 272 | struct rb_root persistent_gnts; |
283 | unsigned int persistent_gnt_c; | 273 | unsigned int persistent_gnt_c; |
284 | atomic_t persistent_gnt_in_use; | 274 | atomic_t persistent_gnt_in_use; |
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 8986adab9bf5..a71d817e900d 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/scatterlist.h> | 46 | #include <linux/scatterlist.h> |
47 | #include <linux/bitmap.h> | 47 | #include <linux/bitmap.h> |
48 | #include <linux/list.h> | 48 | #include <linux/list.h> |
49 | #include <linux/workqueue.h> | ||
49 | 50 | ||
50 | #include <xen/xen.h> | 51 | #include <xen/xen.h> |
51 | #include <xen/xenbus.h> | 52 | #include <xen/xenbus.h> |
@@ -121,6 +122,8 @@ static inline struct blkif_req *blkif_req(struct request *rq) | |||
121 | 122 | ||
122 | static DEFINE_MUTEX(blkfront_mutex); | 123 | static DEFINE_MUTEX(blkfront_mutex); |
123 | static const struct block_device_operations xlvbd_block_fops; | 124 | static const struct block_device_operations xlvbd_block_fops; |
125 | static struct delayed_work blkfront_work; | ||
126 | static LIST_HEAD(info_list); | ||
124 | 127 | ||
125 | /* | 128 | /* |
126 | * Maximum number of segments in indirect requests, the actual value used by | 129 | * Maximum number of segments in indirect requests, the actual value used by |
@@ -216,6 +219,7 @@ struct blkfront_info | |||
216 | /* Save uncomplete reqs and bios for migration. */ | 219 | /* Save uncomplete reqs and bios for migration. */ |
217 | struct list_head requests; | 220 | struct list_head requests; |
218 | struct bio_list bio_list; | 221 | struct bio_list bio_list; |
222 | struct list_head info_list; | ||
219 | }; | 223 | }; |
220 | 224 | ||
221 | static unsigned int nr_minors; | 225 | static unsigned int nr_minors; |
@@ -1759,6 +1763,12 @@ abort_transaction: | |||
1759 | return err; | 1763 | return err; |
1760 | } | 1764 | } |
1761 | 1765 | ||
1766 | static void free_info(struct blkfront_info *info) | ||
1767 | { | ||
1768 | list_del(&info->info_list); | ||
1769 | kfree(info); | ||
1770 | } | ||
1771 | |||
1762 | /* Common code used when first setting up, and when resuming. */ | 1772 | /* Common code used when first setting up, and when resuming. */ |
1763 | static int talk_to_blkback(struct xenbus_device *dev, | 1773 | static int talk_to_blkback(struct xenbus_device *dev, |
1764 | struct blkfront_info *info) | 1774 | struct blkfront_info *info) |
@@ -1880,7 +1890,10 @@ again: | |||
1880 | destroy_blkring: | 1890 | destroy_blkring: |
1881 | blkif_free(info, 0); | 1891 | blkif_free(info, 0); |
1882 | 1892 | ||
1883 | kfree(info); | 1893 | mutex_lock(&blkfront_mutex); |
1894 | free_info(info); | ||
1895 | mutex_unlock(&blkfront_mutex); | ||
1896 | |||
1884 | dev_set_drvdata(&dev->dev, NULL); | 1897 | dev_set_drvdata(&dev->dev, NULL); |
1885 | 1898 | ||
1886 | return err; | 1899 | return err; |
@@ -1991,6 +2004,10 @@ static int blkfront_probe(struct xenbus_device *dev, | |||
1991 | info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0); | 2004 | info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0); |
1992 | dev_set_drvdata(&dev->dev, info); | 2005 | dev_set_drvdata(&dev->dev, info); |
1993 | 2006 | ||
2007 | mutex_lock(&blkfront_mutex); | ||
2008 | list_add(&info->info_list, &info_list); | ||
2009 | mutex_unlock(&blkfront_mutex); | ||
2010 | |||
1994 | return 0; | 2011 | return 0; |
1995 | } | 2012 | } |
1996 | 2013 | ||
@@ -2301,6 +2318,12 @@ static void blkfront_gather_backend_features(struct blkfront_info *info) | |||
2301 | if (indirect_segments <= BLKIF_MAX_SEGMENTS_PER_REQUEST) | 2318 | if (indirect_segments <= BLKIF_MAX_SEGMENTS_PER_REQUEST) |
2302 | indirect_segments = 0; | 2319 | indirect_segments = 0; |
2303 | info->max_indirect_segments = indirect_segments; | 2320 | info->max_indirect_segments = indirect_segments; |
2321 | |||
2322 | if (info->feature_persistent) { | ||
2323 | mutex_lock(&blkfront_mutex); | ||
2324 | schedule_delayed_work(&blkfront_work, HZ * 10); | ||
2325 | mutex_unlock(&blkfront_mutex); | ||
2326 | } | ||
2304 | } | 2327 | } |
2305 | 2328 | ||
2306 | /* | 2329 | /* |
@@ -2482,7 +2505,9 @@ static int blkfront_remove(struct xenbus_device *xbdev) | |||
2482 | mutex_unlock(&info->mutex); | 2505 | mutex_unlock(&info->mutex); |
2483 | 2506 | ||
2484 | if (!bdev) { | 2507 | if (!bdev) { |
2485 | kfree(info); | 2508 | mutex_lock(&blkfront_mutex); |
2509 | free_info(info); | ||
2510 | mutex_unlock(&blkfront_mutex); | ||
2486 | return 0; | 2511 | return 0; |
2487 | } | 2512 | } |
2488 | 2513 | ||
@@ -2502,7 +2527,9 @@ static int blkfront_remove(struct xenbus_device *xbdev) | |||
2502 | if (info && !bdev->bd_openers) { | 2527 | if (info && !bdev->bd_openers) { |
2503 | xlvbd_release_gendisk(info); | 2528 | xlvbd_release_gendisk(info); |
2504 | disk->private_data = NULL; | 2529 | disk->private_data = NULL; |
2505 | kfree(info); | 2530 | mutex_lock(&blkfront_mutex); |
2531 | free_info(info); | ||
2532 | mutex_unlock(&blkfront_mutex); | ||
2506 | } | 2533 | } |
2507 | 2534 | ||
2508 | mutex_unlock(&bdev->bd_mutex); | 2535 | mutex_unlock(&bdev->bd_mutex); |
@@ -2585,7 +2612,7 @@ static void blkif_release(struct gendisk *disk, fmode_t mode) | |||
2585 | dev_info(disk_to_dev(bdev->bd_disk), "releasing disk\n"); | 2612 | dev_info(disk_to_dev(bdev->bd_disk), "releasing disk\n"); |
2586 | xlvbd_release_gendisk(info); | 2613 | xlvbd_release_gendisk(info); |
2587 | disk->private_data = NULL; | 2614 | disk->private_data = NULL; |
2588 | kfree(info); | 2615 | free_info(info); |
2589 | } | 2616 | } |
2590 | 2617 | ||
2591 | out: | 2618 | out: |
@@ -2618,6 +2645,61 @@ static struct xenbus_driver blkfront_driver = { | |||
2618 | .is_ready = blkfront_is_ready, | 2645 | .is_ready = blkfront_is_ready, |
2619 | }; | 2646 | }; |
2620 | 2647 | ||
2648 | static void purge_persistent_grants(struct blkfront_info *info) | ||
2649 | { | ||
2650 | unsigned int i; | ||
2651 | unsigned long flags; | ||
2652 | |||
2653 | for (i = 0; i < info->nr_rings; i++) { | ||
2654 | struct blkfront_ring_info *rinfo = &info->rinfo[i]; | ||
2655 | struct grant *gnt_list_entry, *tmp; | ||
2656 | |||
2657 | spin_lock_irqsave(&rinfo->ring_lock, flags); | ||
2658 | |||
2659 | if (rinfo->persistent_gnts_c == 0) { | ||
2660 | spin_unlock_irqrestore(&rinfo->ring_lock, flags); | ||
2661 | continue; | ||
2662 | } | ||
2663 | |||
2664 | list_for_each_entry_safe(gnt_list_entry, tmp, &rinfo->grants, | ||
2665 | node) { | ||
2666 | if (gnt_list_entry->gref == GRANT_INVALID_REF || | ||
2667 | gnttab_query_foreign_access(gnt_list_entry->gref)) | ||
2668 | continue; | ||
2669 | |||
2670 | list_del(&gnt_list_entry->node); | ||
2671 | gnttab_end_foreign_access(gnt_list_entry->gref, 0, 0UL); | ||
2672 | rinfo->persistent_gnts_c--; | ||
2673 | __free_page(gnt_list_entry->page); | ||
2674 | kfree(gnt_list_entry); | ||
2675 | } | ||
2676 | |||
2677 | spin_unlock_irqrestore(&rinfo->ring_lock, flags); | ||
2678 | } | ||
2679 | } | ||
2680 | |||
2681 | static void blkfront_delay_work(struct work_struct *work) | ||
2682 | { | ||
2683 | struct blkfront_info *info; | ||
2684 | bool need_schedule_work = false; | ||
2685 | |||
2686 | mutex_lock(&blkfront_mutex); | ||
2687 | |||
2688 | list_for_each_entry(info, &info_list, info_list) { | ||
2689 | if (info->feature_persistent) { | ||
2690 | need_schedule_work = true; | ||
2691 | mutex_lock(&info->mutex); | ||
2692 | purge_persistent_grants(info); | ||
2693 | mutex_unlock(&info->mutex); | ||
2694 | } | ||
2695 | } | ||
2696 | |||
2697 | if (need_schedule_work) | ||
2698 | schedule_delayed_work(&blkfront_work, HZ * 10); | ||
2699 | |||
2700 | mutex_unlock(&blkfront_mutex); | ||
2701 | } | ||
2702 | |||
2621 | static int __init xlblk_init(void) | 2703 | static int __init xlblk_init(void) |
2622 | { | 2704 | { |
2623 | int ret; | 2705 | int ret; |
@@ -2626,6 +2708,15 @@ static int __init xlblk_init(void) | |||
2626 | if (!xen_domain()) | 2708 | if (!xen_domain()) |
2627 | return -ENODEV; | 2709 | return -ENODEV; |
2628 | 2710 | ||
2711 | if (!xen_has_pv_disk_devices()) | ||
2712 | return -ENODEV; | ||
2713 | |||
2714 | if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) { | ||
2715 | pr_warn("xen_blk: can't get major %d with name %s\n", | ||
2716 | XENVBD_MAJOR, DEV_NAME); | ||
2717 | return -ENODEV; | ||
2718 | } | ||
2719 | |||
2629 | if (xen_blkif_max_segments < BLKIF_MAX_SEGMENTS_PER_REQUEST) | 2720 | if (xen_blkif_max_segments < BLKIF_MAX_SEGMENTS_PER_REQUEST) |
2630 | xen_blkif_max_segments = BLKIF_MAX_SEGMENTS_PER_REQUEST; | 2721 | xen_blkif_max_segments = BLKIF_MAX_SEGMENTS_PER_REQUEST; |
2631 | 2722 | ||
@@ -2641,14 +2732,7 @@ static int __init xlblk_init(void) | |||
2641 | xen_blkif_max_queues = nr_cpus; | 2732 | xen_blkif_max_queues = nr_cpus; |
2642 | } | 2733 | } |
2643 | 2734 | ||
2644 | if (!xen_has_pv_disk_devices()) | 2735 | INIT_DELAYED_WORK(&blkfront_work, blkfront_delay_work); |
2645 | return -ENODEV; | ||
2646 | |||
2647 | if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) { | ||
2648 | printk(KERN_WARNING "xen_blk: can't get major %d with name %s\n", | ||
2649 | XENVBD_MAJOR, DEV_NAME); | ||
2650 | return -ENODEV; | ||
2651 | } | ||
2652 | 2736 | ||
2653 | ret = xenbus_register_frontend(&blkfront_driver); | 2737 | ret = xenbus_register_frontend(&blkfront_driver); |
2654 | if (ret) { | 2738 | if (ret) { |
@@ -2663,6 +2747,8 @@ module_init(xlblk_init); | |||
2663 | 2747 | ||
2664 | static void __exit xlblk_exit(void) | 2748 | static void __exit xlblk_exit(void) |
2665 | { | 2749 | { |
2750 | cancel_delayed_work_sync(&blkfront_work); | ||
2751 | |||
2666 | xenbus_unregister_driver(&blkfront_driver); | 2752 | xenbus_unregister_driver(&blkfront_driver); |
2667 | unregister_blkdev(XENVBD_MAJOR, DEV_NAME); | 2753 | unregister_blkdev(XENVBD_MAJOR, DEV_NAME); |
2668 | kfree(minors); | 2754 | kfree(minors); |