diff options
author | Roger Pau Monne <roger.pau@citrix.com> | 2013-03-18 12:49:35 -0400 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2013-03-19 12:50:06 -0400 |
commit | 9c1e050caeb4d1250f8ceef1180a8b3d0db6c624 (patch) | |
tree | b3fb576a47d4a86005de189da69fde0d8a22072b /drivers/block/xen-blkfront.c | |
parent | ffb1dabd1eb10c76a1e7af62f75a1aaa8d590b5a (diff) |
xen-blkfront: pre-allocate pages for requests
This prevents us from having to call alloc_page while we are preparing
the request. Since blkfront was calling alloc_page with a spinlock
held we used GFP_ATOMIC, which can fail if we are requesting a lot of
pages since it is using the emergency memory pools.
Allocating all the pages at init prevents us from having to call
alloc_page, thus preventing possible failures.
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: xen-devel@lists.xen.org
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/block/xen-blkfront.c')
-rw-r--r-- | drivers/block/xen-blkfront.c | 120 |
1 files changed, 79 insertions, 41 deletions
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 97324cd18f4b..c64043323399 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c | |||
@@ -165,6 +165,69 @@ static int add_id_to_freelist(struct blkfront_info *info, | |||
165 | return 0; | 165 | return 0; |
166 | } | 166 | } |
167 | 167 | ||
168 | static int fill_grant_buffer(struct blkfront_info *info, int num) | ||
169 | { | ||
170 | struct page *granted_page; | ||
171 | struct grant *gnt_list_entry, *n; | ||
172 | int i = 0; | ||
173 | |||
174 | while(i < num) { | ||
175 | gnt_list_entry = kzalloc(sizeof(struct grant), GFP_NOIO); | ||
176 | if (!gnt_list_entry) | ||
177 | goto out_of_memory; | ||
178 | |||
179 | granted_page = alloc_page(GFP_NOIO); | ||
180 | if (!granted_page) { | ||
181 | kfree(gnt_list_entry); | ||
182 | goto out_of_memory; | ||
183 | } | ||
184 | |||
185 | gnt_list_entry->pfn = page_to_pfn(granted_page); | ||
186 | gnt_list_entry->gref = GRANT_INVALID_REF; | ||
187 | list_add(&gnt_list_entry->node, &info->persistent_gnts); | ||
188 | i++; | ||
189 | } | ||
190 | |||
191 | return 0; | ||
192 | |||
193 | out_of_memory: | ||
194 | list_for_each_entry_safe(gnt_list_entry, n, | ||
195 | &info->persistent_gnts, node) { | ||
196 | list_del(&gnt_list_entry->node); | ||
197 | __free_page(pfn_to_page(gnt_list_entry->pfn)); | ||
198 | kfree(gnt_list_entry); | ||
199 | i--; | ||
200 | } | ||
201 | BUG_ON(i != 0); | ||
202 | return -ENOMEM; | ||
203 | } | ||
204 | |||
205 | static struct grant *get_grant(grant_ref_t *gref_head, | ||
206 | struct blkfront_info *info) | ||
207 | { | ||
208 | struct grant *gnt_list_entry; | ||
209 | unsigned long buffer_mfn; | ||
210 | |||
211 | BUG_ON(list_empty(&info->persistent_gnts)); | ||
212 | gnt_list_entry = list_first_entry(&info->persistent_gnts, struct grant, | ||
213 | node); | ||
214 | list_del(&gnt_list_entry->node); | ||
215 | |||
216 | if (gnt_list_entry->gref != GRANT_INVALID_REF) { | ||
217 | info->persistent_gnts_c--; | ||
218 | return gnt_list_entry; | ||
219 | } | ||
220 | |||
221 | /* Assign a gref to this page */ | ||
222 | gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head); | ||
223 | BUG_ON(gnt_list_entry->gref == -ENOSPC); | ||
224 | buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn); | ||
225 | gnttab_grant_foreign_access_ref(gnt_list_entry->gref, | ||
226 | info->xbdev->otherend_id, | ||
227 | buffer_mfn, 0); | ||
228 | return gnt_list_entry; | ||
229 | } | ||
230 | |||
168 | static const char *op_name(int op) | 231 | static const char *op_name(int op) |
169 | { | 232 | { |
170 | static const char *const names[] = { | 233 | static const char *const names[] = { |
@@ -306,7 +369,6 @@ static int blkif_queue_request(struct request *req) | |||
306 | */ | 369 | */ |
307 | bool new_persistent_gnts; | 370 | bool new_persistent_gnts; |
308 | grant_ref_t gref_head; | 371 | grant_ref_t gref_head; |
309 | struct page *granted_page; | ||
310 | struct grant *gnt_list_entry = NULL; | 372 | struct grant *gnt_list_entry = NULL; |
311 | struct scatterlist *sg; | 373 | struct scatterlist *sg; |
312 | 374 | ||
@@ -370,42 +432,9 @@ static int blkif_queue_request(struct request *req) | |||
370 | fsect = sg->offset >> 9; | 432 | fsect = sg->offset >> 9; |
371 | lsect = fsect + (sg->length >> 9) - 1; | 433 | lsect = fsect + (sg->length >> 9) - 1; |
372 | 434 | ||
373 | if (info->persistent_gnts_c) { | 435 | gnt_list_entry = get_grant(&gref_head, info); |
374 | BUG_ON(list_empty(&info->persistent_gnts)); | 436 | ref = gnt_list_entry->gref; |
375 | gnt_list_entry = list_first_entry( | 437 | buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn); |
376 | &info->persistent_gnts, | ||
377 | struct grant, node); | ||
378 | list_del(&gnt_list_entry->node); | ||
379 | |||
380 | ref = gnt_list_entry->gref; | ||
381 | buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn); | ||
382 | info->persistent_gnts_c--; | ||
383 | } else { | ||
384 | ref = gnttab_claim_grant_reference(&gref_head); | ||
385 | BUG_ON(ref == -ENOSPC); | ||
386 | |||
387 | gnt_list_entry = | ||
388 | kmalloc(sizeof(struct grant), | ||
389 | GFP_ATOMIC); | ||
390 | if (!gnt_list_entry) | ||
391 | return -ENOMEM; | ||
392 | |||
393 | granted_page = alloc_page(GFP_ATOMIC); | ||
394 | if (!granted_page) { | ||
395 | kfree(gnt_list_entry); | ||
396 | return -ENOMEM; | ||
397 | } | ||
398 | |||
399 | gnt_list_entry->pfn = | ||
400 | page_to_pfn(granted_page); | ||
401 | gnt_list_entry->gref = ref; | ||
402 | |||
403 | buffer_mfn = pfn_to_mfn(page_to_pfn( | ||
404 | granted_page)); | ||
405 | gnttab_grant_foreign_access_ref(ref, | ||
406 | info->xbdev->otherend_id, | ||
407 | buffer_mfn, 0); | ||
408 | } | ||
409 | 438 | ||
410 | info->shadow[id].grants_used[i] = gnt_list_entry; | 439 | info->shadow[id].grants_used[i] = gnt_list_entry; |
411 | 440 | ||
@@ -803,17 +832,20 @@ static void blkif_free(struct blkfront_info *info, int suspend) | |||
803 | blk_stop_queue(info->rq); | 832 | blk_stop_queue(info->rq); |
804 | 833 | ||
805 | /* Remove all persistent grants */ | 834 | /* Remove all persistent grants */ |
806 | if (info->persistent_gnts_c) { | 835 | if (!list_empty(&info->persistent_gnts)) { |
807 | list_for_each_entry_safe(persistent_gnt, n, | 836 | list_for_each_entry_safe(persistent_gnt, n, |
808 | &info->persistent_gnts, node) { | 837 | &info->persistent_gnts, node) { |
809 | list_del(&persistent_gnt->node); | 838 | list_del(&persistent_gnt->node); |
810 | gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL); | 839 | if (persistent_gnt->gref != GRANT_INVALID_REF) { |
840 | gnttab_end_foreign_access(persistent_gnt->gref, | ||
841 | 0, 0UL); | ||
842 | info->persistent_gnts_c--; | ||
843 | } | ||
811 | __free_page(pfn_to_page(persistent_gnt->pfn)); | 844 | __free_page(pfn_to_page(persistent_gnt->pfn)); |
812 | kfree(persistent_gnt); | 845 | kfree(persistent_gnt); |
813 | info->persistent_gnts_c--; | ||
814 | } | 846 | } |
815 | BUG_ON(info->persistent_gnts_c != 0); | ||
816 | } | 847 | } |
848 | BUG_ON(info->persistent_gnts_c != 0); | ||
817 | 849 | ||
818 | /* No more gnttab callback work. */ | 850 | /* No more gnttab callback work. */ |
819 | gnttab_cancel_free_callback(&info->callback); | 851 | gnttab_cancel_free_callback(&info->callback); |
@@ -1008,6 +1040,12 @@ static int setup_blkring(struct xenbus_device *dev, | |||
1008 | 1040 | ||
1009 | sg_init_table(info->sg, BLKIF_MAX_SEGMENTS_PER_REQUEST); | 1041 | sg_init_table(info->sg, BLKIF_MAX_SEGMENTS_PER_REQUEST); |
1010 | 1042 | ||
1043 | /* Allocate memory for grants */ | ||
1044 | err = fill_grant_buffer(info, BLK_RING_SIZE * | ||
1045 | BLKIF_MAX_SEGMENTS_PER_REQUEST); | ||
1046 | if (err) | ||
1047 | goto fail; | ||
1048 | |||
1011 | err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring)); | 1049 | err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring)); |
1012 | if (err < 0) { | 1050 | if (err < 0) { |
1013 | free_page((unsigned long)sring); | 1051 | free_page((unsigned long)sring); |