in turbonfs/src/rpc_task.cpp [1504:1600]
void rpc_task::issue_write_rpc()
{
// Must only be called for a flush task.
assert(get_op_type() == FUSE_WRITE);
// Must only be called for a BE task.
assert(rpc_api->write_task.is_be());
[[maybe_unused]]
const struct rpc_task *parent_task = rpc_api->parent_task;
/*
* If parent_task is set, it must refer to the fuse write task that
* trigerred the inline sync.
*/
if (parent_task) {
// Must be a frontend write task.
assert(parent_task->magic == RPC_TASK_MAGIC);
assert(parent_task->get_op_type() == FUSE_WRITE);
assert(parent_task->rpc_api->write_task.is_fe());
assert(parent_task->num_ongoing_backend_writes > 0);
}
const fuse_ino_t ino = rpc_api->write_task.get_ino();
struct nfs_inode *inode = get_client()->get_nfs_inode_from_ino(ino);
struct bc_iovec *bciov = (struct bc_iovec *) rpc_api->pvt;
// We should come here only for FUSE_WRITE tasks with bciov set.
assert(bciov != nullptr);
assert(bciov->magic == BC_IOVEC_MAGIC);
// issue_write_rpc() can be called for partial writes too.
assert(bciov->length <= bciov->orig_length);
assert(bciov->offset >= bciov->orig_offset);
assert((bciov->orig_offset + bciov->orig_length) ==
(bciov->offset + bciov->length));
// FCSM must be marked running, if we are inside issue_write_rpc().
assert(inode->get_fcsm()->is_running());
WRITE3args args;
::memset(&args, 0, sizeof(args));
bool rpc_retry = false;
const uint64_t offset = bciov->offset;
const uint64_t length = bciov->length;
assert(bciov->iovcnt > 0 && bciov->iovcnt <= BC_IOVEC_MAX_VECTORS);
assert(offset < AZNFSC_MAX_FILE_SIZE);
assert((offset + length) < AZNFSC_MAX_FILE_SIZE);
assert(length > 0);
AZLogDebug("issue_write_iovec offset:{}, length:{}", offset, length);
args.file = inode->get_fh();
args.offset = offset;
args.count = length;
args.stable = inode->is_stable_write() ? FILE_SYNC : UNSTABLE;
/*
* Unstable writes want to make use of multiple connections for better perf.
* Note that they aren't affected by the optimistic concurrency backoff
* issues as seen by stable writes.
*/
if (!inode->is_stable_write()) {
set_csched(CONN_SCHED_RR_W);
}
do {
rpc_retry = false;
stats.on_rpc_issue();
if (rpc_nfs3_writev_task(get_rpc_ctx(),
write_iov_callback, &args,
bciov->iov,
bciov->iovcnt,
this) == NULL) {
stats.on_rpc_cancel();
/*
* Most common reason for this is memory allocation failure,
* hence wait for some time before retrying. Also block the
* current thread as we really want to slow down things.
*
* TODO: For soft mount should we fail this?
*/
rpc_retry = true;
AZLogWarn("rpc_nfs3_write_task failed to issue, retrying "
"after 5 secs!");
::sleep(5);
}
} while (rpc_retry);
/*
* Write bytes are counted when we send them to libnfs (not when we get
* response for the WRITE RPC) as that's when they appear on the wire.
*/
INC_GBL_STATS(server_bytes_written, bciov->length);
INC_GBL_STATS(server_write_reqs, 1);
}