aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/xen-blkfront.c
diff options
context:
space:
mode:
authorRoger Pau Monne <roger.pau@citrix.com>2013-03-18 12:49:35 -0400
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2013-03-19 12:50:06 -0400
commit9c1e050caeb4d1250f8ceef1180a8b3d0db6c624 (patch)
treeb3fb576a47d4a86005de189da69fde0d8a22072b /drivers/block/xen-blkfront.c
parentffb1dabd1eb10c76a1e7af62f75a1aaa8d590b5a (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.c120
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
168static 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
193out_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
205static 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
168static const char *op_name(int op) 231static 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);