afs: Set up the iov_iter before calling afs_extract_data()
afs_extract_data sets up a temporary iov_iter and passes it to AF_RXRPC each time it is called to describe the remaining buffer to be filled. Instead: (1) Put an iterator in the afs_call struct. (2) Set the iterator for each marshalling stage to load data into the appropriate places. A number of convenience functions are provided to this end (eg. afs_extract_to_buf()). This iterator is then passed to afs_extract_data(). (3) Use the new ITER_DISCARD iterator to discard any excess data provided by FetchData. Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
@@ -20,12 +20,6 @@
|
||||
|
||||
static const struct afs_fid afs_zero_fid;
|
||||
|
||||
/*
|
||||
* We need somewhere to discard into in case the server helpfully returns more
|
||||
* than we asked for in FS.FetchData{,64}.
|
||||
*/
|
||||
static u8 afs_discard_buffer[64];
|
||||
|
||||
static inline void afs_use_fs_server(struct afs_call *call, struct afs_cb_interest *cbi)
|
||||
{
|
||||
call->cbi = afs_get_cb_interest(cbi);
|
||||
@@ -469,114 +463,93 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
|
||||
struct afs_read *req = call->reply[2];
|
||||
const __be32 *bp;
|
||||
unsigned int size;
|
||||
void *buffer;
|
||||
int ret;
|
||||
|
||||
_enter("{%u,%zu/%u;%llu/%llu}",
|
||||
call->unmarshall, call->offset, call->count,
|
||||
req->remain, req->actual_len);
|
||||
_enter("{%u,%zu/%llu}",
|
||||
call->unmarshall, iov_iter_count(&call->iter), req->actual_len);
|
||||
|
||||
switch (call->unmarshall) {
|
||||
case 0:
|
||||
req->actual_len = 0;
|
||||
call->offset = 0;
|
||||
req->index = 0;
|
||||
req->offset = req->pos & (PAGE_SIZE - 1);
|
||||
call->unmarshall++;
|
||||
if (call->operation_ID != FSFETCHDATA64) {
|
||||
call->unmarshall++;
|
||||
goto no_msw;
|
||||
if (call->operation_ID == FSFETCHDATA64) {
|
||||
afs_extract_to_tmp64(call);
|
||||
} else {
|
||||
call->tmp_u = htonl(0);
|
||||
afs_extract_to_tmp(call);
|
||||
}
|
||||
|
||||
/* extract the upper part of the returned data length of an
|
||||
* FSFETCHDATA64 op (which should always be 0 using this
|
||||
* client) */
|
||||
case 1:
|
||||
_debug("extract data length (MSW)");
|
||||
ret = afs_extract_data(call, &call->tmp, 4, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
req->actual_len = ntohl(call->tmp);
|
||||
req->actual_len <<= 32;
|
||||
call->offset = 0;
|
||||
call->unmarshall++;
|
||||
|
||||
no_msw:
|
||||
/* extract the returned data length */
|
||||
case 2:
|
||||
case 1:
|
||||
_debug("extract data length");
|
||||
ret = afs_extract_data(call, &call->tmp, 4, true);
|
||||
ret = afs_extract_data(call, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
req->actual_len |= ntohl(call->tmp);
|
||||
req->actual_len = be64_to_cpu(call->tmp64);
|
||||
_debug("DATA length: %llu", req->actual_len);
|
||||
|
||||
req->remain = req->actual_len;
|
||||
call->offset = req->pos & (PAGE_SIZE - 1);
|
||||
req->index = 0;
|
||||
if (req->actual_len == 0)
|
||||
req->remain = min(req->len, req->actual_len);
|
||||
if (req->remain == 0)
|
||||
goto no_more_data;
|
||||
|
||||
call->unmarshall++;
|
||||
|
||||
begin_page:
|
||||
ASSERTCMP(req->index, <, req->nr_pages);
|
||||
if (req->remain > PAGE_SIZE - call->offset)
|
||||
size = PAGE_SIZE - call->offset;
|
||||
if (req->remain > PAGE_SIZE - req->offset)
|
||||
size = PAGE_SIZE - req->offset;
|
||||
else
|
||||
size = req->remain;
|
||||
call->count = call->offset + size;
|
||||
ASSERTCMP(call->count, <=, PAGE_SIZE);
|
||||
req->remain -= size;
|
||||
call->bvec[0].bv_len = size;
|
||||
call->bvec[0].bv_offset = req->offset;
|
||||
call->bvec[0].bv_page = req->pages[req->index];
|
||||
iov_iter_bvec(&call->iter, READ, call->bvec, 1, size);
|
||||
ASSERTCMP(size, <=, PAGE_SIZE);
|
||||
|
||||
/* extract the returned data */
|
||||
case 3:
|
||||
_debug("extract data %llu/%llu %zu/%u",
|
||||
req->remain, req->actual_len, call->offset, call->count);
|
||||
case 2:
|
||||
_debug("extract data %zu/%llu",
|
||||
iov_iter_count(&call->iter), req->remain);
|
||||
|
||||
buffer = kmap(req->pages[req->index]);
|
||||
ret = afs_extract_data(call, buffer, call->count, true);
|
||||
kunmap(req->pages[req->index]);
|
||||
ret = afs_extract_data(call, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (call->offset == PAGE_SIZE) {
|
||||
req->remain -= call->bvec[0].bv_len;
|
||||
req->offset += call->bvec[0].bv_len;
|
||||
ASSERTCMP(req->offset, <=, PAGE_SIZE);
|
||||
if (req->offset == PAGE_SIZE) {
|
||||
req->offset = 0;
|
||||
if (req->page_done)
|
||||
req->page_done(call, req);
|
||||
req->index++;
|
||||
if (req->remain > 0) {
|
||||
call->offset = 0;
|
||||
if (req->index >= req->nr_pages) {
|
||||
call->unmarshall = 4;
|
||||
goto begin_discard;
|
||||
}
|
||||
if (req->remain > 0)
|
||||
goto begin_page;
|
||||
}
|
||||
}
|
||||
goto no_more_data;
|
||||
|
||||
ASSERTCMP(req->remain, ==, 0);
|
||||
if (req->actual_len <= req->len)
|
||||
goto no_more_data;
|
||||
|
||||
/* Discard any excess data the server gave us */
|
||||
begin_discard:
|
||||
case 4:
|
||||
size = min_t(loff_t, sizeof(afs_discard_buffer), req->remain);
|
||||
call->count = size;
|
||||
_debug("extract discard %llu/%llu %zu/%u",
|
||||
req->remain, req->actual_len, call->offset, call->count);
|
||||
iov_iter_discard(&call->iter, READ, req->actual_len - req->len);
|
||||
call->unmarshall = 3;
|
||||
case 3:
|
||||
_debug("extract discard %zu/%llu",
|
||||
iov_iter_count(&call->iter), req->actual_len - req->len);
|
||||
|
||||
call->offset = 0;
|
||||
ret = afs_extract_data(call, afs_discard_buffer, call->count, true);
|
||||
req->remain -= call->offset;
|
||||
ret = afs_extract_data(call, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (req->remain > 0)
|
||||
goto begin_discard;
|
||||
|
||||
no_more_data:
|
||||
call->offset = 0;
|
||||
call->unmarshall = 5;
|
||||
call->unmarshall = 4;
|
||||
afs_extract_to_buf(call, (21 + 3 + 6) * 4);
|
||||
|
||||
/* extract the metadata */
|
||||
case 5:
|
||||
ret = afs_extract_data(call, call->buffer,
|
||||
(21 + 3 + 6) * 4, false);
|
||||
case 4:
|
||||
ret = afs_extract_data(call, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -589,20 +562,19 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
|
||||
if (call->reply[1])
|
||||
xdr_decode_AFSVolSync(&bp, call->reply[1]);
|
||||
|
||||
call->offset = 0;
|
||||
call->unmarshall++;
|
||||
|
||||
case 6:
|
||||
case 5:
|
||||
break;
|
||||
}
|
||||
|
||||
for (; req->index < req->nr_pages; req->index++) {
|
||||
if (call->count < PAGE_SIZE)
|
||||
if (req->offset < PAGE_SIZE)
|
||||
zero_user_segment(req->pages[req->index],
|
||||
call->count, PAGE_SIZE);
|
||||
req->offset, PAGE_SIZE);
|
||||
if (req->page_done)
|
||||
req->page_done(call, req);
|
||||
call->count = 0;
|
||||
req->offset = 0;
|
||||
}
|
||||
|
||||
_leave(" = 0 [done]");
|
||||
@@ -1598,31 +1570,31 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
|
||||
{
|
||||
const __be32 *bp;
|
||||
char *p;
|
||||
u32 size;
|
||||
int ret;
|
||||
|
||||
_enter("{%u}", call->unmarshall);
|
||||
|
||||
switch (call->unmarshall) {
|
||||
case 0:
|
||||
call->offset = 0;
|
||||
call->unmarshall++;
|
||||
afs_extract_to_buf(call, 12 * 4);
|
||||
|
||||
/* extract the returned status record */
|
||||
case 1:
|
||||
_debug("extract status");
|
||||
ret = afs_extract_data(call, call->buffer,
|
||||
12 * 4, true);
|
||||
ret = afs_extract_data(call, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
bp = call->buffer;
|
||||
xdr_decode_AFSFetchVolumeStatus(&bp, call->reply[1]);
|
||||
call->offset = 0;
|
||||
call->unmarshall++;
|
||||
afs_extract_to_tmp(call);
|
||||
|
||||
/* extract the volume name length */
|
||||
case 2:
|
||||
ret = afs_extract_data(call, &call->tmp, 4, true);
|
||||
ret = afs_extract_data(call, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -1631,46 +1603,26 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
|
||||
if (call->count >= AFSNAMEMAX)
|
||||
return afs_protocol_error(call, -EBADMSG,
|
||||
afs_eproto_volname_len);
|
||||
call->offset = 0;
|
||||
size = (call->count + 3) & ~3; /* It's padded */
|
||||
afs_extract_begin(call, call->reply[2], size);
|
||||
call->unmarshall++;
|
||||
|
||||
/* extract the volume name */
|
||||
case 3:
|
||||
_debug("extract volname");
|
||||
if (call->count > 0) {
|
||||
ret = afs_extract_data(call, call->reply[2],
|
||||
call->count, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
ret = afs_extract_data(call, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
p = call->reply[2];
|
||||
p[call->count] = 0;
|
||||
_debug("volname '%s'", p);
|
||||
|
||||
call->offset = 0;
|
||||
afs_extract_to_tmp(call);
|
||||
call->unmarshall++;
|
||||
|
||||
/* extract the volume name padding */
|
||||
if ((call->count & 3) == 0) {
|
||||
call->unmarshall++;
|
||||
goto no_volname_padding;
|
||||
}
|
||||
call->count = 4 - (call->count & 3);
|
||||
|
||||
case 4:
|
||||
ret = afs_extract_data(call, call->buffer,
|
||||
call->count, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
call->offset = 0;
|
||||
call->unmarshall++;
|
||||
no_volname_padding:
|
||||
|
||||
/* extract the offline message length */
|
||||
case 5:
|
||||
ret = afs_extract_data(call, &call->tmp, 4, true);
|
||||
case 4:
|
||||
ret = afs_extract_data(call, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -1679,46 +1631,27 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
|
||||
if (call->count >= AFSNAMEMAX)
|
||||
return afs_protocol_error(call, -EBADMSG,
|
||||
afs_eproto_offline_msg_len);
|
||||
call->offset = 0;
|
||||
size = (call->count + 3) & ~3; /* It's padded */
|
||||
afs_extract_begin(call, call->reply[2], size);
|
||||
call->unmarshall++;
|
||||
|
||||
/* extract the offline message */
|
||||
case 6:
|
||||
case 5:
|
||||
_debug("extract offline");
|
||||
if (call->count > 0) {
|
||||
ret = afs_extract_data(call, call->reply[2],
|
||||
call->count, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
ret = afs_extract_data(call, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
p = call->reply[2];
|
||||
p[call->count] = 0;
|
||||
_debug("offline '%s'", p);
|
||||
|
||||
call->offset = 0;
|
||||
afs_extract_to_tmp(call);
|
||||
call->unmarshall++;
|
||||
|
||||
/* extract the offline message padding */
|
||||
if ((call->count & 3) == 0) {
|
||||
call->unmarshall++;
|
||||
goto no_offline_padding;
|
||||
}
|
||||
call->count = 4 - (call->count & 3);
|
||||
|
||||
case 7:
|
||||
ret = afs_extract_data(call, call->buffer,
|
||||
call->count, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
call->offset = 0;
|
||||
call->unmarshall++;
|
||||
no_offline_padding:
|
||||
|
||||
/* extract the message of the day length */
|
||||
case 8:
|
||||
ret = afs_extract_data(call, &call->tmp, 4, true);
|
||||
case 6:
|
||||
ret = afs_extract_data(call, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -1727,38 +1660,24 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call)
|
||||
if (call->count >= AFSNAMEMAX)
|
||||
return afs_protocol_error(call, -EBADMSG,
|
||||
afs_eproto_motd_len);
|
||||
call->offset = 0;
|
||||
size = (call->count + 3) & ~3; /* It's padded */
|
||||
afs_extract_begin(call, call->reply[2], size);
|
||||
call->unmarshall++;
|
||||
|
||||
/* extract the message of the day */
|
||||
case 9:
|
||||
case 7:
|
||||
_debug("extract motd");
|
||||
if (call->count > 0) {
|
||||
ret = afs_extract_data(call, call->reply[2],
|
||||
call->count, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
ret = afs_extract_data(call, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
p = call->reply[2];
|
||||
p[call->count] = 0;
|
||||
_debug("motd '%s'", p);
|
||||
|
||||
call->offset = 0;
|
||||
call->unmarshall++;
|
||||
|
||||
/* extract the message of the day padding */
|
||||
call->count = (4 - (call->count & 3)) & 3;
|
||||
|
||||
case 10:
|
||||
ret = afs_extract_data(call, call->buffer,
|
||||
call->count, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
call->offset = 0;
|
||||
call->unmarshall++;
|
||||
case 11:
|
||||
case 8:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2024,19 +1943,16 @@ static int afs_deliver_fs_get_capabilities(struct afs_call *call)
|
||||
u32 count;
|
||||
int ret;
|
||||
|
||||
_enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count);
|
||||
_enter("{%u,%zu}", call->unmarshall, iov_iter_count(&call->iter));
|
||||
|
||||
again:
|
||||
switch (call->unmarshall) {
|
||||
case 0:
|
||||
call->offset = 0;
|
||||
afs_extract_to_tmp(call);
|
||||
call->unmarshall++;
|
||||
|
||||
/* Extract the capabilities word count */
|
||||
case 1:
|
||||
ret = afs_extract_data(call, &call->tmp,
|
||||
1 * sizeof(__be32),
|
||||
true);
|
||||
ret = afs_extract_data(call, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -2044,24 +1960,17 @@ again:
|
||||
|
||||
call->count = count;
|
||||
call->count2 = count;
|
||||
call->offset = 0;
|
||||
iov_iter_discard(&call->iter, READ, count * sizeof(__be32));
|
||||
call->unmarshall++;
|
||||
|
||||
/* Extract capabilities words */
|
||||
case 2:
|
||||
count = min(call->count, 16U);
|
||||
ret = afs_extract_data(call, call->buffer,
|
||||
count * sizeof(__be32),
|
||||
call->count > 16);
|
||||
ret = afs_extract_data(call, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* TODO: Examine capabilities */
|
||||
|
||||
call->count -= count;
|
||||
if (call->count > 0)
|
||||
goto again;
|
||||
call->offset = 0;
|
||||
call->unmarshall++;
|
||||
break;
|
||||
}
|
||||
@@ -2215,13 +2124,13 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
|
||||
|
||||
switch (call->unmarshall) {
|
||||
case 0:
|
||||
call->offset = 0;
|
||||
afs_extract_to_tmp(call);
|
||||
call->unmarshall++;
|
||||
|
||||
/* Extract the file status count and array in two steps */
|
||||
case 1:
|
||||
_debug("extract status count");
|
||||
ret = afs_extract_data(call, &call->tmp, 4, true);
|
||||
ret = afs_extract_data(call, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -2234,11 +2143,11 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
|
||||
call->count = 0;
|
||||
call->unmarshall++;
|
||||
more_counts:
|
||||
call->offset = 0;
|
||||
afs_extract_to_buf(call, 21 * sizeof(__be32));
|
||||
|
||||
case 2:
|
||||
_debug("extract status array %u", call->count);
|
||||
ret = afs_extract_data(call, call->buffer, 21 * 4, true);
|
||||
ret = afs_extract_data(call, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -2256,12 +2165,12 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
|
||||
|
||||
call->count = 0;
|
||||
call->unmarshall++;
|
||||
call->offset = 0;
|
||||
afs_extract_to_tmp(call);
|
||||
|
||||
/* Extract the callback count and array in two steps */
|
||||
case 3:
|
||||
_debug("extract CB count");
|
||||
ret = afs_extract_data(call, &call->tmp, 4, true);
|
||||
ret = afs_extract_data(call, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -2273,11 +2182,11 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
|
||||
call->count = 0;
|
||||
call->unmarshall++;
|
||||
more_cbs:
|
||||
call->offset = 0;
|
||||
afs_extract_to_buf(call, 3 * sizeof(__be32));
|
||||
|
||||
case 4:
|
||||
_debug("extract CB array");
|
||||
ret = afs_extract_data(call, call->buffer, 3 * 4, true);
|
||||
ret = afs_extract_data(call, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -2294,11 +2203,11 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
|
||||
if (call->count < call->count2)
|
||||
goto more_cbs;
|
||||
|
||||
call->offset = 0;
|
||||
afs_extract_to_buf(call, 6 * sizeof(__be32));
|
||||
call->unmarshall++;
|
||||
|
||||
case 5:
|
||||
ret = afs_extract_data(call, call->buffer, 6 * 4, false);
|
||||
ret = afs_extract_data(call, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -2306,7 +2215,6 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
|
||||
if (call->reply[3])
|
||||
xdr_decode_AFSVolSync(&bp, call->reply[3]);
|
||||
|
||||
call->offset = 0;
|
||||
call->unmarshall++;
|
||||
|
||||
case 6:
|
||||
|
Reference in New Issue
Block a user