|
@@ -259,67 +259,74 @@ void afs_flat_call_destructor(struct afs_call *call)
|
|
call->buffer = NULL;
|
|
call->buffer = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#define AFS_BVEC_MAX 8
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Load the given bvec with the next few pages.
|
|
|
|
+ */
|
|
|
|
+static void afs_load_bvec(struct afs_call *call, struct msghdr *msg,
|
|
|
|
+ struct bio_vec *bv, pgoff_t first, pgoff_t last,
|
|
|
|
+ unsigned offset)
|
|
|
|
+{
|
|
|
|
+ struct page *pages[AFS_BVEC_MAX];
|
|
|
|
+ unsigned int nr, n, i, to, bytes = 0;
|
|
|
|
+
|
|
|
|
+ nr = min_t(pgoff_t, last - first + 1, AFS_BVEC_MAX);
|
|
|
|
+ n = find_get_pages_contig(call->mapping, first, nr, pages);
|
|
|
|
+ ASSERTCMP(n, ==, nr);
|
|
|
|
+
|
|
|
|
+ msg->msg_flags |= MSG_MORE;
|
|
|
|
+ for (i = 0; i < nr; i++) {
|
|
|
|
+ to = PAGE_SIZE;
|
|
|
|
+ if (first + i >= last) {
|
|
|
|
+ to = call->last_to;
|
|
|
|
+ msg->msg_flags &= ~MSG_MORE;
|
|
|
|
+ }
|
|
|
|
+ bv[i].bv_page = pages[i];
|
|
|
|
+ bv[i].bv_len = to - offset;
|
|
|
|
+ bv[i].bv_offset = offset;
|
|
|
|
+ bytes += to - offset;
|
|
|
|
+ offset = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ iov_iter_bvec(&msg->msg_iter, WRITE | ITER_BVEC, bv, nr, bytes);
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* attach the data from a bunch of pages on an inode to a call
|
|
* attach the data from a bunch of pages on an inode to a call
|
|
*/
|
|
*/
|
|
static int afs_send_pages(struct afs_call *call, struct msghdr *msg)
|
|
static int afs_send_pages(struct afs_call *call, struct msghdr *msg)
|
|
{
|
|
{
|
|
- struct page *pages[8];
|
|
|
|
- unsigned count, n, loop, offset, to;
|
|
|
|
|
|
+ struct bio_vec bv[AFS_BVEC_MAX];
|
|
|
|
+ unsigned int bytes, nr, loop, offset;
|
|
pgoff_t first = call->first, last = call->last;
|
|
pgoff_t first = call->first, last = call->last;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
- _enter("");
|
|
|
|
-
|
|
|
|
offset = call->first_offset;
|
|
offset = call->first_offset;
|
|
call->first_offset = 0;
|
|
call->first_offset = 0;
|
|
|
|
|
|
do {
|
|
do {
|
|
- _debug("attach %lx-%lx", first, last);
|
|
|
|
-
|
|
|
|
- count = last - first + 1;
|
|
|
|
- if (count > ARRAY_SIZE(pages))
|
|
|
|
- count = ARRAY_SIZE(pages);
|
|
|
|
- n = find_get_pages_contig(call->mapping, first, count, pages);
|
|
|
|
- ASSERTCMP(n, ==, count);
|
|
|
|
-
|
|
|
|
- loop = 0;
|
|
|
|
- do {
|
|
|
|
- struct bio_vec bvec = {.bv_page = pages[loop],
|
|
|
|
- .bv_offset = offset};
|
|
|
|
- msg->msg_flags = 0;
|
|
|
|
- to = PAGE_SIZE;
|
|
|
|
- if (first + loop >= last)
|
|
|
|
- to = call->last_to;
|
|
|
|
- else
|
|
|
|
- msg->msg_flags = MSG_MORE;
|
|
|
|
- bvec.bv_len = to - offset;
|
|
|
|
- offset = 0;
|
|
|
|
-
|
|
|
|
- _debug("- range %u-%u%s",
|
|
|
|
- offset, to, msg->msg_flags ? " [more]" : "");
|
|
|
|
- iov_iter_bvec(&msg->msg_iter, WRITE | ITER_BVEC,
|
|
|
|
- &bvec, 1, to - offset);
|
|
|
|
-
|
|
|
|
- /* have to change the state *before* sending the last
|
|
|
|
- * packet as RxRPC might give us the reply before it
|
|
|
|
- * returns from sending the request */
|
|
|
|
- if (first + loop >= last)
|
|
|
|
- call->state = AFS_CALL_AWAIT_REPLY;
|
|
|
|
- ret = rxrpc_kernel_send_data(afs_socket, call->rxcall,
|
|
|
|
- msg, to - offset);
|
|
|
|
- if (ret < 0)
|
|
|
|
- break;
|
|
|
|
- } while (++loop < count);
|
|
|
|
- first += count;
|
|
|
|
-
|
|
|
|
- for (loop = 0; loop < count; loop++)
|
|
|
|
- put_page(pages[loop]);
|
|
|
|
|
|
+ afs_load_bvec(call, msg, bv, first, last, offset);
|
|
|
|
+ offset = 0;
|
|
|
|
+ bytes = msg->msg_iter.count;
|
|
|
|
+ nr = msg->msg_iter.nr_segs;
|
|
|
|
+
|
|
|
|
+ /* Have to change the state *before* sending the last
|
|
|
|
+ * packet as RxRPC might give us the reply before it
|
|
|
|
+ * returns from sending the request.
|
|
|
|
+ */
|
|
|
|
+ if (first + nr >= last)
|
|
|
|
+ call->state = AFS_CALL_AWAIT_REPLY;
|
|
|
|
+ ret = rxrpc_kernel_send_data(afs_socket, call->rxcall,
|
|
|
|
+ msg, bytes);
|
|
|
|
+ for (loop = 0; loop < nr; loop++)
|
|
|
|
+ put_page(bv[loop].bv_page);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
break;
|
|
break;
|
|
|
|
+
|
|
|
|
+ first += nr;
|
|
} while (first <= last);
|
|
} while (first <= last);
|
|
|
|
|
|
- _leave(" = %d", ret);
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|