nfs: translate error to nfsstat3

Summary:
NFS clients will act differently depending on what kind of error is returned
from an RPC. A NFS3ERR_NOENT in response to a LOOKUP RPC may for instance
populate a negative lookup cache to avoid re-querying the same file again.
Thus, we need to translate the various errors with their corresponding
nfsstat3 values.

Reviewed By: genevievehelsel

Differential Revision: D26597788

fbshipit-source-id: d22a552196a378d6d7e9cd374e63bb8bcf436ce4
This commit is contained in:
Xavier Deguillard 2021-02-24 08:12:50 -08:00 committed by Facebook GitHub Bot
parent bde9d5f099
commit 7f3bf0dfe1

View File

@ -12,6 +12,7 @@
#include <folly/Utility.h>
#include <folly/futures/Future.h>
#include "eden/fs/nfs/NfsdRpc.h"
#include "eden/fs/utils/SystemError.h"
namespace facebook::eden {
@ -90,6 +91,70 @@ class Nfsd3ServerProcessor final : public RpcServerProcessor {
bool caseSensitive_;
};
/**
* Convert a exception to the appropriate NFS error value.
*/
nfsstat3 exceptionToNfsError(const folly::exception_wrapper& ex) {
if (auto* err = ex.get_exception<std::system_error>()) {
if (!isErrnoError(*err)) {
return nfsstat3::NFS3ERR_SERVERFAULT;
}
switch (err->code().value()) {
case EPERM:
return nfsstat3::NFS3ERR_PERM;
case ENOENT:
return nfsstat3::NFS3ERR_NOENT;
case EIO:
case ETXTBSY:
return nfsstat3::NFS3ERR_IO;
case ENXIO:
return nfsstat3::NFS3ERR_NXIO;
case EACCES:
return nfsstat3::NFS3ERR_ACCES;
case EEXIST:
return nfsstat3::NFS3ERR_EXIST;
case EXDEV:
return nfsstat3::NFS3ERR_XDEV;
case ENODEV:
return nfsstat3::NFS3ERR_NODEV;
case ENOTDIR:
return nfsstat3::NFS3ERR_NOTDIR;
case EISDIR:
return nfsstat3::NFS3ERR_ISDIR;
case EINVAL:
return nfsstat3::NFS3ERR_INVAL;
case EFBIG:
return nfsstat3::NFS3ERR_FBIG;
case EROFS:
return nfsstat3::NFS3ERR_ROFS;
case EMLINK:
return nfsstat3::NFS3ERR_MLINK;
case ENAMETOOLONG:
return nfsstat3::NFS3ERR_NAMETOOLONG;
case ENOTEMPTY:
return nfsstat3::NFS3ERR_NOTEMPTY;
case EDQUOT:
return nfsstat3::NFS3ERR_DQUOT;
case ESTALE:
return nfsstat3::NFS3ERR_STALE;
case ETIMEDOUT:
case EAGAIN:
case ENOMEM:
return nfsstat3::NFS3ERR_JUKEBOX;
case ENOTSUP:
return nfsstat3::NFS3ERR_NOTSUPP;
case ENFILE:
return nfsstat3::NFS3ERR_SERVERFAULT;
}
return nfsstat3::NFS3ERR_SERVERFAULT;
} else if (ex.get_exception<folly::FutureTimeout>()) {
return nfsstat3::NFS3ERR_JUKEBOX;
} else {
return nfsstat3::NFS3ERR_SERVERFAULT;
}
}
folly::Future<folly::Unit> Nfsd3ServerProcessor::null(
folly::io::Cursor /*deser*/,
folly::io::Appender ser,
@ -179,7 +244,8 @@ folly::Future<folly::Unit> Nfsd3ServerProcessor::getattr(
return dispatcher_->getattr(fh.ino, *context)
.thenTry([ser = std::move(ser)](folly::Try<struct stat>&& try_) mutable {
if (try_.hasException()) {
GETATTR3res res{{nfsstat3::NFS3ERR_IO, std::monostate{}}};
GETATTR3res res{
{exceptionToNfsError(try_.exception()), std::monostate{}}};
XdrTrait<GETATTR3res>::serialize(ser, res);
} else {
auto stat = std::move(try_).value();