in turbonfs/src/nfs_client.cpp [1231:1345]
int nfs_client::lookup_sync(fuse_ino_t parent_ino,
const char* name,
fuse_ino_t& child_ino)
{
assert(name != nullptr);
struct nfs_inode *parent_inode = get_nfs_inode_from_ino(parent_ino);
const uint32_t fh_hash = parent_inode->get_crc();
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 = nullptr;
bool rpc_retry = false;
int status = -1;
child_ino = 0;
AZLogDebug("lookup_sync({}/{})", parent_ino, name);
try_again:
do {
LOOKUP3args args;
args.what.dir = parent_inode->get_fh();
args.what.name = (char *) name;
if (task) {
task->free_rpc_task();
}
task = get_rpc_task_helper()->alloc_rpc_task(FUSE_LOOKUP);
task->init_lookup(nullptr /* fuse_req */, name, parent_ino);
task->rpc_api->pvt = &child_ino;
if (ctx) {
delete ctx;
}
ctx = new sync_rpc_context(task, nullptr);
rpc = nfs_get_rpc_context(nfs_context);
assert(!ctx->callback_called);
rpc_retry = false;
task->get_stats().on_rpc_issue();
if ((pdu = rpc_nfs3_lookup_task(rpc, lookup_sync_callback,
&args, ctx)) == NULL) {
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 LOOKUP 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) {
task->get_stats().on_rpc_cancel();
AZLogWarn("Timed out waiting for lookup response, re-issuing "
"lookup!");
// 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 lookup 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);
status = task->status(ctx->rpc_status, ctx->nfs_status);
if (status == 0) {
assert(child_ino != 0);
} else if (ctx->rpc_status == RPC_STATUS_SUCCESS &&
ctx->nfs_status == NFS3ERR_JUKEBOX) {
AZLogInfo("Got NFS3ERR_JUKEBOX for LOOKUP, re-issuing "
"after 1 sec!");
::usleep(1000 * 1000);
// This goto will cause the above lock to unlock.
goto try_again;
} else {
AZLogDebug("lookup_sync({}/{}) failed, status={}, "
"rpc_status={}, nfs_status={}",
parent_ino, name, status, ctx->rpc_status,
ctx->nfs_status);
assert(child_ino == 0);
}
}
}
if (task) {
task->free_rpc_task();
}
delete ctx;
assert(status >= 0);
return status;
}