diff options
Diffstat (limited to 'fs/nfs/mount_clnt.c')
-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 | { |