Re: [PATCH] virtio: 9p: correctly pass physical address to userspace for high pages
flat view
From: Rusty Russell <hidden>
Date: 2012-10-18 03:18:38
Also in:
lkml
Will Deacon [off-list ref] writes:
When using a virtio transport, the 9p net device allocates pages to back the descriptors inserted into the virtqueue. These allocations may be performed from atomic context (under the channel lock) and can therefore return high mappings which aren't suitable for virt_to_phys.
I had not appreciated that subtlety about GFP_ATOMIC :( This isn't just 9p, the console, block, scsi and net devices also use GFP_ATOMIC.
quoted hunk
@@ -165,7 +166,8 @@ static int vring_add_indirect(struct vring_virtqueue *vq, /* Use a single buffer which doesn't continue */ head = vq->free_head; vq->vring.desc[head].flags = VRING_DESC_F_INDIRECT; - vq->vring.desc[head].addr = virt_to_phys(desc); + vq->vring.desc[head].addr = page_to_phys(kmap_to_page(desc)) + + ((unsigned long)desc & ~PAGE_MASK); vq->vring.desc[head].len = i * sizeof(struct vring_desc);
Gah, virt_to_phys_harder()? What's the performance effect? If it's negligible, why doesn't virt_to_phys() just do this for us? We do have an alternate solution: masking out __GFP_HIGHMEM from the kmalloc of desc. If it fails, we will fall back to laying out the virtio request directly inside the ring; if it doesn't fit, we'll wait for the device to consume more buffers.
quoted hunk
@@ -325,7 +326,7 @@ static int p9_get_mapped_pages(struct virtio_chan *chan, int count = nr_pages; while (nr_pages) { s = rest_of_page(data); - pages[index++] = virt_to_page(data); + pages[index++] = kmap_to_page(data); data += s; nr_pages--; }
This seems like a separate bug fix. Cheers, Rusty.