diff options
| -rw-r--r-- | fs/nfs/mount_clnt.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 79b5954b8a1b..8429885bc729 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
| @@ -29,6 +29,8 @@ | |||
| 29 | * XDR data type sizes | 29 | * XDR data type sizes |
| 30 | */ | 30 | */ |
| 31 | #define encode_dirpath_sz (1 + XDR_QUADLEN(MNTPATHLEN)) | 31 | #define encode_dirpath_sz (1 + XDR_QUADLEN(MNTPATHLEN)) |
| 32 | #define MNT_status_sz (1) | ||
| 33 | #define MNT_fhs_status_sz (1) | ||
| 32 | 34 | ||
| 33 | /* | 35 | /* |
| 34 | * XDR argument and result sizes | 36 | * XDR argument and result sizes |
| @@ -61,6 +63,65 @@ enum { | |||
| 61 | 63 | ||
| 62 | static struct rpc_program mnt_program; | 64 | static struct rpc_program mnt_program; |
| 63 | 65 | ||
| 66 | /* | ||
| 67 | * Defined by OpenGroup XNFS Version 3W, chapter 8 | ||
| 68 | */ | ||
| 69 | enum mountstat { | ||
| 70 | MNT_OK = 0, | ||
| 71 | MNT_EPERM = 1, | ||
| 72 | MNT_ENOENT = 2, | ||
| 73 | MNT_EACCES = 13, | ||
| 74 | MNT_EINVAL = 22, | ||
| 75 | }; | ||
| 76 | |||
| 77 | static struct { | ||
| 78 | u32 status; | ||
| 79 | int errno; | ||
| 80 | } mnt_errtbl[] = { | ||
| 81 | { .status = MNT_OK, .errno = 0, }, | ||
| 82 | { .status = MNT_EPERM, .errno = -EPERM, }, | ||
| 83 | { .status = MNT_ENOENT, .errno = -ENOENT, }, | ||
| 84 | { .status = MNT_EACCES, .errno = -EACCES, }, | ||
| 85 | { .status = MNT_EINVAL, .errno = -EINVAL, }, | ||
| 86 | }; | ||
| 87 | |||
| 88 | /* | ||
| 89 | * Defined by RFC 1813, section 5.1.5 | ||
| 90 | */ | ||
| 91 | enum mountstat3 { | ||
| 92 | MNT3_OK = 0, /* no error */ | ||
| 93 | MNT3ERR_PERM = 1, /* Not owner */ | ||
| 94 | MNT3ERR_NOENT = 2, /* No such file or directory */ | ||
| 95 | MNT3ERR_IO = 5, /* I/O error */ | ||
| 96 | MNT3ERR_ACCES = 13, /* Permission denied */ | ||
| 97 | MNT3ERR_NOTDIR = 20, /* Not a directory */ | ||
| 98 | MNT3ERR_INVAL = 22, /* Invalid argument */ | ||
| 99 | MNT3ERR_NAMETOOLONG = 63, /* Filename too long */ | ||
| 100 | MNT3ERR_NOTSUPP = 10004, /* Operation not supported */ | ||
| 101 | MNT3ERR_SERVERFAULT = 10006, /* A failure on the server */ | ||
| 102 | }; | ||
| 103 | |||
| 104 | static struct { | ||
| 105 | u32 status; | ||
| 106 | int errno; | ||
| 107 | } mnt3_errtbl[] = { | ||
| 108 | { .status = MNT3_OK, .errno = 0, }, | ||
| 109 | { .status = MNT3ERR_PERM, .errno = -EPERM, }, | ||
| 110 | { .status = MNT3ERR_NOENT, .errno = -ENOENT, }, | ||
| 111 | { .status = MNT3ERR_IO, .errno = -EIO, }, | ||
| 112 | { .status = MNT3ERR_ACCES, .errno = -EACCES, }, | ||
| 113 | { .status = MNT3ERR_NOTDIR, .errno = -ENOTDIR, }, | ||
| 114 | { .status = MNT3ERR_INVAL, .errno = -EINVAL, }, | ||
| 115 | { .status = MNT3ERR_NAMETOOLONG, .errno = -ENAMETOOLONG, }, | ||
| 116 | { .status = MNT3ERR_NOTSUPP, .errno = -ENOTSUPP, }, | ||
| 117 | { .status = MNT3ERR_SERVERFAULT, .errno = -ESERVERFAULT, }, | ||
| 118 | }; | ||
| 119 | |||
| 120 | struct mountres { | ||
| 121 | int errno; | ||
| 122 | struct nfs_fh *fh; | ||
| 123 | }; | ||
| 124 | |||
| 64 | struct mnt_fhstatus { | 125 | struct mnt_fhstatus { |
| 65 | u32 status; | 126 | u32 status; |
| 66 | struct nfs_fh *fh; | 127 | struct nfs_fh *fh; |
| @@ -179,6 +240,61 @@ static int xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, | |||
| 179 | return 0; | 240 | return 0; |
| 180 | } | 241 | } |
| 181 | 242 | ||
| 243 | /* | ||
| 244 | * RFC 1094: "A non-zero status indicates some sort of error. In this | ||
| 245 | * case, the status is a UNIX error number." This can be problematic | ||
| 246 | * if the server and client use different errno values for the same | ||
| 247 | * error. | ||
| 248 | * | ||
| 249 | * However, the OpenGroup XNFS spec provides a simple mapping that is | ||
| 250 | * independent of local errno values on the server and the client. | ||
| 251 | */ | ||
| 252 | static int decode_status(struct xdr_stream *xdr, struct mountres *res) | ||
| 253 | { | ||
| 254 | unsigned int i; | ||
| 255 | u32 status; | ||
| 256 | __be32 *p; | ||
| 257 | |||
| 258 | p = xdr_inline_decode(xdr, sizeof(status)); | ||
| 259 | if (unlikely(p == NULL)) | ||
| 260 | return -EIO; | ||
| 261 | status = ntohl(*p); | ||
| 262 | |||
| 263 | for (i = 0; i <= ARRAY_SIZE(mnt_errtbl); i++) { | ||
| 264 | if (mnt_errtbl[i].status == status) { | ||
| 265 | res->errno = mnt_errtbl[i].errno; | ||
| 266 | return 0; | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | dprintk("NFS: unrecognized MNT status code: %u\n", status); | ||
| 271 | res->errno = -EACCES; | ||
| 272 | return 0; | ||
| 273 | } | ||
| 274 | |||
| 275 | static int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res) | ||
| 276 | { | ||
| 277 | unsigned int i; | ||
| 278 | u32 status; | ||
| 279 | __be32 *p; | ||
| 280 | |||
| 281 | p = xdr_inline_decode(xdr, sizeof(status)); | ||
| 282 | if (unlikely(p == NULL)) | ||
| 283 | return -EIO; | ||
| 284 | status = ntohl(*p); | ||
| 285 | |||
| 286 | for (i = 0; i <= ARRAY_SIZE(mnt3_errtbl); i++) { | ||
| 287 | if (mnt3_errtbl[i].status == status) { | ||
| 288 | res->errno = mnt3_errtbl[i].errno; | ||
| 289 | return 0; | ||
| 290 | } | ||
| 291 | } | ||
| 292 | |||
| 293 | dprintk("NFS: unrecognized MNT3 status code: %u\n", status); | ||
| 294 | res->errno = -EACCES; | ||
| 295 | return 0; | ||
| 296 | } | ||
| 297 | |||
| 182 | static int xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, | 298 | static int xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, |
| 183 | struct mnt_fhstatus *res) | 299 | struct mnt_fhstatus *res) |
| 184 | { | 300 | { |
