Skip to content

Commit

Permalink
Some fixes after testing.
Browse files Browse the repository at this point in the history
  • Loading branch information
Nagendra Tomar committed Aug 8, 2024
1 parent 9add74f commit cafc7e8
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 24 deletions.
27 changes: 15 additions & 12 deletions include/libnfs-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,21 204,21 @@ struct rpc_iovec_cursor {
/*
* Current iovec we should be reading into, updated as we finish
* reading whole iovecs. iovcnt holds the count of iovecs remaining
* to be read into and is decremented as we read whole iovecs. We also
* update the iov_base and iov_len as we read data into iov[], so at
* any point iov and iovcnt can be passed to readv() to read remaining
* data.
* to be read into and is decremented as we read whole iovecs or if
* the cursor is shrinked. We also update the iov_base and iov_len as
* we read data into iov[], so at any point iov and iovcnt can be
* passed to readv() to read remaining data.
*/
struct iovec *iov;
int iovcnt;

/*
* Total size of all the iovecs present starting at base.
* This remains constant and doesn't change as we read data into iov
* and can be used as a quick ref for total read bytes requested by the
* caller.
* Total to-be-read bytes. This is initialized to the total size of
* all the individual buffers and later updated as we read data or if
* the cursor length is reduced due to short read.
* At any point these many new bytes need to be read into this cursor.
*/
size_t total_size;
size_t remaining_size;
};

enum input_state {
Expand Down Expand Up @@ -444,18 444,19 @@ struct rpc_pdu {
* vector for zero-copy READ3 receive.
* This is updated as data is read from the socket into the user's
* zero-copy buffers directly.
* in.total_size is the total bytes requested by the user.
*/
struct rpc_iovec_cursor in;

/*
* How much more data remains to be read into 'in'. It's initialized
* with the returned count in READ response and is reduced as we
* read data from the socket into the user's zero-copy buffers.
* This must never be more than in.total_size as we should never read
* more data than requested.
*/
uint32_t read_count;
uint32_t requested_read_count; /* The amount requested by the
* application.
* Used to clamp long reads.
*/

rpc_cb cb;
void *private_data;
Expand Down Expand Up @@ -813,6 814,8 @@ int rpc_add_iovector(struct rpc_context *rpc, struct rpc_io_vectors *v,
char *buf, int len, void (*free)(void *));
void rpc_advance_cursor(struct rpc_context *rpc, struct rpc_iovec_cursor *v,
size_t len);
void rpc_shrink_cursor(struct rpc_context *rpc, struct rpc_iovec_cursor *v,
size_t new_len);
void rpc_memcpy_cursor(struct rpc_context *rpc, struct rpc_iovec_cursor *v,
const void *src, size_t len);
void rpc_free_cursor(struct rpc_context *rpc, struct rpc_iovec_cursor *v);
Expand Down
42 changes: 42 additions & 0 deletions lib/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -656,18 656,55 @@ void rpc_advance_cursor(struct rpc_context *rpc, struct rpc_iovec_cursor *v,
{
while (len) {
assert(v->iovcnt > 0);
assert(v->remaining_size >= v->iov[0].iov_len);

if (v->iov[0].iov_len > len) {
v->iov[0].iov_base = ((uint8_t*) v->iov[0].iov_base) len;
v->iov[0].iov_len -= len;
v->remaining_size -= len;
break;
} else {
len -= v->iov[0].iov_len;
v->remaining_size -= v->iov[0].iov_len;
/* Exhausted this iovec completely */
v->iov ;
v->iovcnt--;
}
}

/* remaining_size can only be 0 when iovcnt is 0 and v.v. */
assert((v->iovcnt == 0) == (v->remaining_size == 0));
}

/*
* Reduce the size of rpc_iovec_cursor to match new_len if the current size is
* greater than new_len. If remaining_size <= new_len, then this is a no-op.
*/
void rpc_shrink_cursor(struct rpc_context *rpc, struct rpc_iovec_cursor *v,
size_t new_len)
{
int i;
size_t num_done = 0;

if (v->remaining_size <= new_len) {
return;
}

for (i = 0; i < v->iovcnt && num_done < new_len; i ) {
if (v->iov[i].iov_len <= (new_len - num_done)) {
num_done = v->iov[i].iov_len;
continue;
}

v->iov[i].iov_len = (new_len - num_done);
num_done = new_len;
}

v->iovcnt = i;
v->remaining_size = new_len;

/* remaining_size can only be 0 when iovcnt is 0 and v.v. */
assert((v->iovcnt == 0) == (v->remaining_size == 0));
}

/*
Expand All @@ -684,16 721,21 @@ void rpc_memcpy_cursor(struct rpc_context *rpc, struct rpc_iovec_cursor *v,
memcpy(v->iov[0].iov_base, src, len);
v->iov[0].iov_base = ((uint8_t*) v->iov[0].iov_base) len;
v->iov[0].iov_len -= len;
v->remaining_size -= len;
break;
} else {
memcpy(v->iov[0].iov_base, src, v->iov[0].iov_len);
len -= v->iov[0].iov_len;
src = ((uint8_t *) src) v->iov[0].iov_len;
v->remaining_size -= v->iov[0].iov_len;
/* Exhausted this iovec completely */
v->iov ;
v->iovcnt--;
}
}

/* remaining_size can only be 0 when iovcnt is 0 and v.v. */
assert((v->iovcnt == 0) == (v->remaining_size == 0));
}

void rpc_free_cursor(struct rpc_context *rpc, struct rpc_iovec_cursor *v)
Expand Down
4 changes: 2 additions & 2 deletions lib/nfs_v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -4499,8 4499,8 @@ nfs3_pread_cb(struct rpc_context *rpc, int status, void *command_data,
* ensured that it doesn't read more than the requested data, so to
* be correct just clamp the returned read count here.
*/
if (count > rpc->pdu->in.total_size) {
count = rpc->pdu->in.total_size;
if (count > rpc->pdu->requested_read_count) {
count = rpc->pdu->requested_read_count;
}

data->cb(count, nfs, NULL, data->private_data);
Expand Down
4 changes: 2 additions & 2 deletions lib/nfs_v4.c
Original file line number Diff line number Diff line change
Expand Up @@ -2799,8 2799,8 @@ nfs4_pread_cb(struct rpc_context *rpc, int status, void *command_data,
* ensured that it doesn't read more than the requested data, so to
* be correct just clamp the returned read count here.
*/
if (count > rpc->pdu->in.total_size) {
count = rpc->pdu->in.total_size;
if (count > rpc->pdu->requested_read_count) {
count = rpc->pdu->requested_read_count;
}

data->cb(count, nfs, NULL, data->private_data);
Expand Down
18 changes: 12 additions & 6 deletions lib/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 635,7 @@ rpc_read_from_socket(struct rpc_context *rpc)
count = recv(rpc->fd, rpc->buf, count, MSG_DONTWAIT);
} else {
assert(rpc->pdu->in.iovcnt > 0);
assert(count <= rpc->pdu->in.total_size);
assert(count <= rpc->pdu->in.remaining_size);
count = readv(rpc->fd, rpc->pdu->in.iov, rpc->pdu->in.iovcnt);
}

Expand Down Expand Up @@ -770,8 770,8 @@ rpc_read_from_socket(struct rpc_context *rpc)
* If the server is buggy and does send more, we discard the extra
* data.
*/
if (rpc->pdu->read_count > rpc->pdu->in.total_size) {
rpc->pdu->read_count = rpc->pdu->in.total_size;
if (rpc->pdu->read_count > rpc->pdu->requested_read_count) {
rpc->pdu->read_count = rpc->pdu->requested_read_count;
}

/*
Expand All @@ -781,14 781,20 @@ rpc_read_from_socket(struct rpc_context *rpc)
count = rpc->pdu->read_count;
}

if (rpc->pdu->in.remaining_size > rpc->pdu->read_count) {
/* we got a short read */
rpc_shrink_cursor(rpc, &rpc->pdu->in, rpc->pdu->read_count);
assert(rpc->pdu->in.remaining_size == rpc->pdu->read_count);
}

/* XXX With the above two clamps, can this still happen ? */
if (count > rpc->pdu->in.total_size) {
count = rpc->pdu->in.total_size;
if (rpc->pdu->in.remaining_size < count) {
count = rpc->pdu->in.remaining_size;
}

rpc_memcpy_cursor(rpc, &rpc->pdu->in, &rpc->inbuf[pos], count);

if (rpc->pdu->in.iovcnt == 0) {
if (rpc->pdu->in.remaining_size == 0) {
// handle padding?
} else {
rpc->pdu->read_count -= count;
Expand Down
4 changes: 3 additions & 1 deletion nfs/nfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,9 313,11 @@ rpc_nfs3_readv_task(struct rpc_context *rpc, rpc_cb cb,

for (i = 0; i < iovcnt; i ) {
pdu->in.iov[i] = iov[i];
pdu->in.total_size = iov[i].iov_len;
pdu->in.remaining_size = iov[i].iov_len;
}

pdu->requested_read_count = pdu->in.remaining_size;

if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for NFS3/READ call");
return NULL;
Expand Down
4 changes: 3 additions & 1 deletion nfs4/nfs4.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 298,11 @@ struct rpc_pdu *rpc_nfs4_readv_task(struct rpc_context *rpc, rpc_cb cb,

for (i = 0; i < iovcnt; i ) {
pdu->in.iov[i] = iov[i];
pdu->in.total_size = iov[i].iov_len;
pdu->in.remaining_size = iov[i].iov_len;
}

pdu->requested_read_count = pdu->in.remaining_size;

if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for "
"NFS4/COMPOUND4 call");
Expand Down

0 comments on commit cafc7e8

Please sign in to comment.