in turbonfs/src/nfs_client.cpp [2309:2421]
bool nfs_client::getattr_sync(const struct nfs_fh3& fh,
fuse_ino_t ino,
struct fattr3& fattr)
{
const uint32_t fh_hash = calculate_crc32(
(const unsigned char *) fh.data.data_val, fh.data.data_len);
struct nfs_context *nfs_context = get_nfs_context(CONN_SCHED_FH_HASH, fh_hash);
struct rpc_task *task = nullptr;
struct sync_rpc_context *ctx = nullptr;
struct rpc_pdu *pdu = nullptr;
struct rpc_context *rpc;
bool rpc_retry = false;
bool success = false;
try_again:
do {
struct GETATTR3args args;
args.object = fh;
/*
* Very first call to getattr_sync(), called from nfs_client::init(), for
* getting the root filehandle attributes won't have the rpc_task_helper
* set, so that single GETATTR RPC won't be accounted in rpc stats.
*/
if (get_rpc_task_helper() != nullptr) {
if (task) {
task->free_rpc_task();
}
task = get_rpc_task_helper()->alloc_rpc_task(FUSE_GETATTR);
task->init_getattr(nullptr /* fuse_req */, ino);
} else {
assert(ino == FUSE_ROOT_ID);
}
if (ctx) {
delete ctx;
}
ctx = new sync_rpc_context(task, &fattr);
rpc = nfs_get_rpc_context(nfs_context);
rpc_retry = false;
if (task) {
task->get_stats().on_rpc_issue();
}
if ((pdu = rpc_nfs3_getattr_task(rpc, getattr_sync_callback,
&args, ctx)) == NULL) {
if (task) {
task->get_stats().on_rpc_cancel();
}
/*
* This call fails due to internal issues like OOM etc
* and not due to an actual error, hence retry.
*/
rpc_retry = true;
}
} while (rpc_retry);
/*
* If the GETATTR response doesn't come for 60 secs we give up and send
* a new one. We must cancel the old one.
*/
{
std::unique_lock<std::mutex> lock(ctx->mutex);
wait_more:
if (!ctx->cv.wait_for(lock, std::chrono::seconds(60),
[&ctx] { return (ctx->callback_called == true); })) {
if (rpc_cancel_pdu(rpc, pdu) == 0) {
if (task) {
task->get_stats().on_rpc_cancel();
}
AZLogWarn("Timed out waiting for getattr response, re-issuing "
"getattr!");
// This goto will cause the above lock to unlock.
goto try_again;
} else {
/*
* If rpc_cancel_pdu() fails it most likely means we got the RPC
* response right after we timed out waiting. It's best to wait
* for the callback to be called.
*/
AZLogWarn("Timed out waiting for getattr response, couldn't "
"cancel existing pdu, waiting some more!");
// This goto will *not* cause the above lock to unlock.
goto wait_more;
}
} else {
assert(ctx->callback_called);
assert(ctx->rpc_status != -1);
assert(ctx->nfs_status != -1);
if ((ctx->rpc_status == RPC_STATUS_SUCCESS) &&
(ctx->nfs_status == NFS3_OK)) {
success = true;
} else if (ctx->rpc_status == RPC_STATUS_SUCCESS &&
ctx->nfs_status == NFS3ERR_JUKEBOX) {
AZLogInfo("Got NFS3ERR_JUKEBOX for GETATTR, re-issuing "
"after 1 sec!");
::usleep(1000 * 1000);
// This goto will cause the above lock to unlock.
goto try_again;
}
}
}
if (task) {
task->free_rpc_task();
}
delete ctx;
return success;
}