|
@@ -165,6 +165,69 @@ static int add_id_to_freelist(struct blkfront_info *info,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int fill_grant_buffer(struct blkfront_info *info, int num)
|
|
|
+{
|
|
|
+ struct page *granted_page;
|
|
|
+ struct grant *gnt_list_entry, *n;
|
|
|
+ int i = 0;
|
|
|
+
|
|
|
+ while(i < num) {
|
|
|
+ gnt_list_entry = kzalloc(sizeof(struct grant), GFP_NOIO);
|
|
|
+ if (!gnt_list_entry)
|
|
|
+ goto out_of_memory;
|
|
|
+
|
|
|
+ granted_page = alloc_page(GFP_NOIO);
|
|
|
+ if (!granted_page) {
|
|
|
+ kfree(gnt_list_entry);
|
|
|
+ goto out_of_memory;
|
|
|
+ }
|
|
|
+
|
|
|
+ gnt_list_entry->pfn = page_to_pfn(granted_page);
|
|
|
+ gnt_list_entry->gref = GRANT_INVALID_REF;
|
|
|
+ list_add(&gnt_list_entry->node, &info->persistent_gnts);
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+out_of_memory:
|
|
|
+ list_for_each_entry_safe(gnt_list_entry, n,
|
|
|
+ &info->persistent_gnts, node) {
|
|
|
+ list_del(&gnt_list_entry->node);
|
|
|
+ __free_page(pfn_to_page(gnt_list_entry->pfn));
|
|
|
+ kfree(gnt_list_entry);
|
|
|
+ i--;
|
|
|
+ }
|
|
|
+ BUG_ON(i != 0);
|
|
|
+ return -ENOMEM;
|
|
|
+}
|
|
|
+
|
|
|
+static struct grant *get_grant(grant_ref_t *gref_head,
|
|
|
+ struct blkfront_info *info)
|
|
|
+{
|
|
|
+ struct grant *gnt_list_entry;
|
|
|
+ unsigned long buffer_mfn;
|
|
|
+
|
|
|
+ BUG_ON(list_empty(&info->persistent_gnts));
|
|
|
+ gnt_list_entry = list_first_entry(&info->persistent_gnts, struct grant,
|
|
|
+ node);
|
|
|
+ list_del(&gnt_list_entry->node);
|
|
|
+
|
|
|
+ if (gnt_list_entry->gref != GRANT_INVALID_REF) {
|
|
|
+ info->persistent_gnts_c--;
|
|
|
+ return gnt_list_entry;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Assign a gref to this page */
|
|
|
+ gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head);
|
|
|
+ BUG_ON(gnt_list_entry->gref == -ENOSPC);
|
|
|
+ buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn);
|
|
|
+ gnttab_grant_foreign_access_ref(gnt_list_entry->gref,
|
|
|
+ info->xbdev->otherend_id,
|
|
|
+ buffer_mfn, 0);
|
|
|
+ return gnt_list_entry;
|
|
|
+}
|
|
|
+
|
|
|
static const char *op_name(int op)
|
|
|
{
|
|
|
static const char *const names[] = {
|
|
@@ -306,7 +369,6 @@ static int blkif_queue_request(struct request *req)
|
|
|
*/
|
|
|
bool new_persistent_gnts;
|
|
|
grant_ref_t gref_head;
|
|
|
- struct page *granted_page;
|
|
|
struct grant *gnt_list_entry = NULL;
|
|
|
struct scatterlist *sg;
|
|
|
|
|
@@ -370,42 +432,9 @@ static int blkif_queue_request(struct request *req)
|
|
|
fsect = sg->offset >> 9;
|
|
|
lsect = fsect + (sg->length >> 9) - 1;
|
|
|
|
|
|
- if (info->persistent_gnts_c) {
|
|
|
- BUG_ON(list_empty(&info->persistent_gnts));
|
|
|
- gnt_list_entry = list_first_entry(
|
|
|
- &info->persistent_gnts,
|
|
|
- struct grant, node);
|
|
|
- list_del(&gnt_list_entry->node);
|
|
|
-
|
|
|
- ref = gnt_list_entry->gref;
|
|
|
- buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn);
|
|
|
- info->persistent_gnts_c--;
|
|
|
- } else {
|
|
|
- ref = gnttab_claim_grant_reference(&gref_head);
|
|
|
- BUG_ON(ref == -ENOSPC);
|
|
|
-
|
|
|
- gnt_list_entry =
|
|
|
- kmalloc(sizeof(struct grant),
|
|
|
- GFP_ATOMIC);
|
|
|
- if (!gnt_list_entry)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- granted_page = alloc_page(GFP_ATOMIC);
|
|
|
- if (!granted_page) {
|
|
|
- kfree(gnt_list_entry);
|
|
|
- return -ENOMEM;
|
|
|
- }
|
|
|
-
|
|
|
- gnt_list_entry->pfn =
|
|
|
- page_to_pfn(granted_page);
|
|
|
- gnt_list_entry->gref = ref;
|
|
|
-
|
|
|
- buffer_mfn = pfn_to_mfn(page_to_pfn(
|
|
|
- granted_page));
|
|
|
- gnttab_grant_foreign_access_ref(ref,
|
|
|
- info->xbdev->otherend_id,
|
|
|
- buffer_mfn, 0);
|
|
|
- }
|
|
|
+ gnt_list_entry = get_grant(&gref_head, info);
|
|
|
+ ref = gnt_list_entry->gref;
|
|
|
+ buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn);
|
|
|
|
|
|
info->shadow[id].grants_used[i] = gnt_list_entry;
|
|
|
|
|
@@ -803,17 +832,20 @@ static void blkif_free(struct blkfront_info *info, int suspend)
|
|
|
blk_stop_queue(info->rq);
|
|
|
|
|
|
/* Remove all persistent grants */
|
|
|
- if (info->persistent_gnts_c) {
|
|
|
+ if (!list_empty(&info->persistent_gnts)) {
|
|
|
list_for_each_entry_safe(persistent_gnt, n,
|
|
|
&info->persistent_gnts, node) {
|
|
|
list_del(&persistent_gnt->node);
|
|
|
- gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL);
|
|
|
+ if (persistent_gnt->gref != GRANT_INVALID_REF) {
|
|
|
+ gnttab_end_foreign_access(persistent_gnt->gref,
|
|
|
+ 0, 0UL);
|
|
|
+ info->persistent_gnts_c--;
|
|
|
+ }
|
|
|
__free_page(pfn_to_page(persistent_gnt->pfn));
|
|
|
kfree(persistent_gnt);
|
|
|
- info->persistent_gnts_c--;
|
|
|
}
|
|
|
- BUG_ON(info->persistent_gnts_c != 0);
|
|
|
}
|
|
|
+ BUG_ON(info->persistent_gnts_c != 0);
|
|
|
|
|
|
/* No more gnttab callback work. */
|
|
|
gnttab_cancel_free_callback(&info->callback);
|
|
@@ -1008,6 +1040,12 @@ static int setup_blkring(struct xenbus_device *dev,
|
|
|
|
|
|
sg_init_table(info->sg, BLKIF_MAX_SEGMENTS_PER_REQUEST);
|
|
|
|
|
|
+ /* Allocate memory for grants */
|
|
|
+ err = fill_grant_buffer(info, BLK_RING_SIZE *
|
|
|
+ BLKIF_MAX_SEGMENTS_PER_REQUEST);
|
|
|
+ if (err)
|
|
|
+ goto fail;
|
|
|
+
|
|
|
err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
|
|
|
if (err < 0) {
|
|
|
free_page((unsigned long)sring);
|