/* a single mutex to manage channel initialization and attachment */ static DEFINE_MUTEX(virtio_9p_lock); static DECLARE_WAIT_QUEUE_HEAD(vp_wq); static atomic_t vp_pinned = ATOMIC_INIT(0);
struct p9_client *client; struct virtio_device *vdev; struct virtqueue *vq; int ring_bufs_avail;
wait_queue_head_t *vc_wq; /* This is global limit. Since we don't have a global structure, *willbeplacingitineachchannel.
*/ unsignedlong p9_max_pages; /* Scatterlist: can be too big for stack. */ struct scatterlist sg[VIRTQUEUE_NUM]; /** *@tag:nametoidentifyamountnullterminated
*/ char *tag;
struct list_head chan_list;
};
staticstruct list_head virtio_chan_list;
/* How many bytes left in this page. */ staticunsignedint rest_of_page(void *data)
{ return PAGE_SIZE - offset_in_page(data);
}
staticint pack_sg_list(struct scatterlist *sg, int start, int limit, char *data, int count)
{ int s; int index = start;
while (count) {
s = rest_of_page(data); if (s > count)
s = count;
BUG_ON(index >= limit); /* Make sure we don't terminate early. */
sg_unmark_end(&sg[index]);
sg_set_buf(&sg[index++], data, s);
count -= s;
data += s;
} if (index-start)
sg_mark_end(&sg[index - 1]); return index-start;
}
/* We don't currently allow canceling of virtio requests */ staticint p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req)
{ return1;
}
/** *pack_sg_list_p-Justlikepack_sg_list.Insteadoftakingabuffer, *thistakesalistofpages. *@sg:scatter/gatherlisttopackinto *@start:whichsegmentofthesg_listtostartat *@limit:maximumnumberofpagesinsglist. *@pdata:alistofpagestoaddintosg. *@nr_pages:numberofpagestopackintothescatter/gatherlist *@offs:amountofdatainthebeginningoffirstpage_not_topack *@count:amountofdatatopackintothescatter/gatherlist
*/ staticint
pack_sg_list_p(struct scatterlist *sg, int start, int limit, struct page **pdata, int nr_pages, size_t offs, int count)
{ int i = 0, s; int data_off = offs; int index = start;
BUG_ON(nr_pages > (limit - start)); /* *ifthefirstpagedoesn'tstartat *pageboundaryfindtheoffset
*/ while (nr_pages) {
s = PAGE_SIZE - data_off; if (s > count)
s = count;
BUG_ON(index >= limit); /* Make sure we don't terminate early. */
sg_unmark_end(&sg[index]);
sg_set_page(&sg[index++], pdata[i++], s, data_off);
data_off = 0;
count -= s;
nr_pages--;
}
if (index-start)
sg_mark_end(&sg[index - 1]); return index - start;
}
staticint p9_get_mapped_pages(struct virtio_chan *chan, struct page ***pages, struct iov_iter *data, int count,
size_t *offs, int *need_drop)
{ int nr_pages; int err;
if (!iov_iter_count(data)) return0;
if (!iov_iter_is_kvec(data)) { int n; /* *Weallowonlyp9_max_pagespinned.Wewaitforthe *Otherzcrequesttofinishhere
*/ if (atomic_read(&vp_pinned) >= chan->p9_max_pages) {
err = wait_event_killable(vp_wq,
(atomic_read(&vp_pinned) < chan->p9_max_pages)); if (err == -ERESTARTSYS) return err;
}
n = iov_iter_get_pages_alloc2(data, pages, count, offs); if (n < 0) return n;
*need_drop = 1;
nr_pages = DIV_ROUND_UP(n + *offs, PAGE_SIZE);
atomic_add(nr_pages, &vp_pinned); return n;
} else { /* kernel buffer, no need to pin pages */ int index;
size_t len; void *p;
/* we'd already checked that it's non-empty */ while (1) {
len = iov_iter_single_seg_count(data); if (likely(len)) {
p = data->kvec->iov_base + data->iov_offset; break;
}
iov_iter_advance(data, 0);
} if (len > count)
len = count;
// Fits entirely into the static data? Nothing to do. if (req->rc.size < in_hdr_len || !pages) return;
// Really long error message? Tough, truncate the reply. Might get // rejected (we can't be arsed to adjust the size encoded in header, // or string size for that matter), but it wouldn't be anything valid // anyway. if (unlikely(req->rc.size > P9_ZC_HDR_SZ))
req->rc.size = P9_ZC_HDR_SZ;
// data won't span more than two pages
size = req->rc.size - in_hdr_len;
n = PAGE_SIZE - offs; if (size > n) {
memcpy_from_page(to, *pages++, offs, n);
offs = 0;
to += n;
size -= n;
}
memcpy_from_page(to, *pages, offs, size);
}
/** *p9_virtio_zc_request-issueazerocopyrequest *@client:clientinstanceissuingtherequest *@req:requesttobeissued *@uidata:userbufferthatshouldbeusedforzerocopyread *@uodata:userbufferthatshouldbeusedforzerocopywrite *@inlen:readbuffersize *@outlen:writebuffersize *@in_hdr_len:readerheadersize,Thisisthesizeofresponseprotocoldata *
*/ staticint
p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req, struct iov_iter *uidata, struct iov_iter *uodata, int inlen, int outlen, int in_hdr_len)
{ int in, out, err, out_sgs, in_sgs; unsignedlong flags; int in_nr_pages = 0, out_nr_pages = 0; struct page **in_pages = NULL, **out_pages = NULL; struct virtio_chan *chan = client->trans; struct scatterlist *sgs[4];
size_t offs = 0; int need_drop = 0; int kicked = 0;
p9_debug(P9_DEBUG_TRANS, "virtio request\n");
if (uodata) {
__le32 sz; int n = p9_get_mapped_pages(chan, &out_pages, uodata,
outlen, &offs, &need_drop); if (n < 0) {
err = n; goto err_out;
}
out_nr_pages = DIV_ROUND_UP(n + offs, PAGE_SIZE); if (n != outlen) {
__le32 v = cpu_to_le32(n);
memcpy(&req->tc.sdata[req->tc.size - 4], &v, 4);
outlen = n;
} /* The size field of the message must include the length of the *headerandthelengthofthedata.Wedidn'tactuallyknow *thelengthofthedatauntilthispointsoadditinnow.
*/
sz = cpu_to_le32(req->tc.size + outlen);
memcpy(&req->tc.sdata[0], &sz, sizeof(sz));
} elseif (uidata) { int n = p9_get_mapped_pages(chan, &in_pages, uidata,
inlen, &offs, &need_drop); if (n < 0) {
err = n; goto err_out;
}
in_nr_pages = DIV_ROUND_UP(n + offs, PAGE_SIZE); if (n != inlen) {
__le32 v = cpu_to_le32(n);
memcpy(&req->tc.sdata[req->tc.size - 4], &v, 4);
inlen = n;
}
}
WRITE_ONCE(req->status, REQ_STATUS_SENT);
req_retry_pinned:
spin_lock_irqsave(&chan->lock, flags);
out_sgs = in_sgs = 0;
/* out data */
out = pack_sg_list(chan->sg, 0,
VIRTQUEUE_NUM, req->tc.sdata, req->tc.size);
if (out)
sgs[out_sgs++] = chan->sg;
if (out_pages) {
sgs[out_sgs++] = chan->sg + out;
out += pack_sg_list_p(chan->sg, out, VIRTQUEUE_NUM,
out_pages, out_nr_pages, offs, outlen);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.