xref: /openbmc/linux/fs/orangefs/orangefs-utils.c (revision 4da722ca)
1 /*
2  * (C) 2001 Clemson University and The University of Chicago
3  *
4  * See COPYING in top-level directory.
5  */
6 #include "protocol.h"
7 #include "orangefs-kernel.h"
8 #include "orangefs-dev-proto.h"
9 #include "orangefs-bufmap.h"
10 
11 __s32 fsid_of_op(struct orangefs_kernel_op_s *op)
12 {
13 	__s32 fsid = ORANGEFS_FS_ID_NULL;
14 
15 	if (op) {
16 		switch (op->upcall.type) {
17 		case ORANGEFS_VFS_OP_FILE_IO:
18 			fsid = op->upcall.req.io.refn.fs_id;
19 			break;
20 		case ORANGEFS_VFS_OP_LOOKUP:
21 			fsid = op->upcall.req.lookup.parent_refn.fs_id;
22 			break;
23 		case ORANGEFS_VFS_OP_CREATE:
24 			fsid = op->upcall.req.create.parent_refn.fs_id;
25 			break;
26 		case ORANGEFS_VFS_OP_GETATTR:
27 			fsid = op->upcall.req.getattr.refn.fs_id;
28 			break;
29 		case ORANGEFS_VFS_OP_REMOVE:
30 			fsid = op->upcall.req.remove.parent_refn.fs_id;
31 			break;
32 		case ORANGEFS_VFS_OP_MKDIR:
33 			fsid = op->upcall.req.mkdir.parent_refn.fs_id;
34 			break;
35 		case ORANGEFS_VFS_OP_READDIR:
36 			fsid = op->upcall.req.readdir.refn.fs_id;
37 			break;
38 		case ORANGEFS_VFS_OP_SETATTR:
39 			fsid = op->upcall.req.setattr.refn.fs_id;
40 			break;
41 		case ORANGEFS_VFS_OP_SYMLINK:
42 			fsid = op->upcall.req.sym.parent_refn.fs_id;
43 			break;
44 		case ORANGEFS_VFS_OP_RENAME:
45 			fsid = op->upcall.req.rename.old_parent_refn.fs_id;
46 			break;
47 		case ORANGEFS_VFS_OP_STATFS:
48 			fsid = op->upcall.req.statfs.fs_id;
49 			break;
50 		case ORANGEFS_VFS_OP_TRUNCATE:
51 			fsid = op->upcall.req.truncate.refn.fs_id;
52 			break;
53 		case ORANGEFS_VFS_OP_RA_FLUSH:
54 			fsid = op->upcall.req.ra_cache_flush.refn.fs_id;
55 			break;
56 		case ORANGEFS_VFS_OP_FS_UMOUNT:
57 			fsid = op->upcall.req.fs_umount.fs_id;
58 			break;
59 		case ORANGEFS_VFS_OP_GETXATTR:
60 			fsid = op->upcall.req.getxattr.refn.fs_id;
61 			break;
62 		case ORANGEFS_VFS_OP_SETXATTR:
63 			fsid = op->upcall.req.setxattr.refn.fs_id;
64 			break;
65 		case ORANGEFS_VFS_OP_LISTXATTR:
66 			fsid = op->upcall.req.listxattr.refn.fs_id;
67 			break;
68 		case ORANGEFS_VFS_OP_REMOVEXATTR:
69 			fsid = op->upcall.req.removexattr.refn.fs_id;
70 			break;
71 		case ORANGEFS_VFS_OP_FSYNC:
72 			fsid = op->upcall.req.fsync.refn.fs_id;
73 			break;
74 		default:
75 			break;
76 		}
77 	}
78 	return fsid;
79 }
80 
81 static int orangefs_inode_flags(struct ORANGEFS_sys_attr_s *attrs)
82 {
83 	int flags = 0;
84 	if (attrs->flags & ORANGEFS_IMMUTABLE_FL)
85 		flags |= S_IMMUTABLE;
86 	else
87 		flags &= ~S_IMMUTABLE;
88 	if (attrs->flags & ORANGEFS_APPEND_FL)
89 		flags |= S_APPEND;
90 	else
91 		flags &= ~S_APPEND;
92 	if (attrs->flags & ORANGEFS_NOATIME_FL)
93 		flags |= S_NOATIME;
94 	else
95 		flags &= ~S_NOATIME;
96 	return flags;
97 }
98 
99 static int orangefs_inode_perms(struct ORANGEFS_sys_attr_s *attrs)
100 {
101 	int perm_mode = 0;
102 
103 	if (attrs->perms & ORANGEFS_O_EXECUTE)
104 		perm_mode |= S_IXOTH;
105 	if (attrs->perms & ORANGEFS_O_WRITE)
106 		perm_mode |= S_IWOTH;
107 	if (attrs->perms & ORANGEFS_O_READ)
108 		perm_mode |= S_IROTH;
109 
110 	if (attrs->perms & ORANGEFS_G_EXECUTE)
111 		perm_mode |= S_IXGRP;
112 	if (attrs->perms & ORANGEFS_G_WRITE)
113 		perm_mode |= S_IWGRP;
114 	if (attrs->perms & ORANGEFS_G_READ)
115 		perm_mode |= S_IRGRP;
116 
117 	if (attrs->perms & ORANGEFS_U_EXECUTE)
118 		perm_mode |= S_IXUSR;
119 	if (attrs->perms & ORANGEFS_U_WRITE)
120 		perm_mode |= S_IWUSR;
121 	if (attrs->perms & ORANGEFS_U_READ)
122 		perm_mode |= S_IRUSR;
123 
124 	if (attrs->perms & ORANGEFS_G_SGID)
125 		perm_mode |= S_ISGID;
126 	if (attrs->perms & ORANGEFS_U_SUID)
127 		perm_mode |= S_ISUID;
128 
129 	return perm_mode;
130 }
131 
132 /*
133  * NOTE: in kernel land, we never use the sys_attr->link_target for
134  * anything, so don't bother copying it into the sys_attr object here.
135  */
136 static inline int copy_attributes_from_inode(struct inode *inode,
137 					     struct ORANGEFS_sys_attr_s *attrs,
138 					     struct iattr *iattr)
139 {
140 	umode_t tmp_mode;
141 
142 	if (!iattr || !inode || !attrs) {
143 		gossip_err("NULL iattr (%p), inode (%p), attrs (%p) "
144 			   "in copy_attributes_from_inode!\n",
145 			   iattr,
146 			   inode,
147 			   attrs);
148 		return -EINVAL;
149 	}
150 	/*
151 	 * We need to be careful to only copy the attributes out of the
152 	 * iattr object that we know are valid.
153 	 */
154 	attrs->mask = 0;
155 	if (iattr->ia_valid & ATTR_UID) {
156 		attrs->owner = from_kuid(&init_user_ns, iattr->ia_uid);
157 		attrs->mask |= ORANGEFS_ATTR_SYS_UID;
158 		gossip_debug(GOSSIP_UTILS_DEBUG, "(UID) %d\n", attrs->owner);
159 	}
160 	if (iattr->ia_valid & ATTR_GID) {
161 		attrs->group = from_kgid(&init_user_ns, iattr->ia_gid);
162 		attrs->mask |= ORANGEFS_ATTR_SYS_GID;
163 		gossip_debug(GOSSIP_UTILS_DEBUG, "(GID) %d\n", attrs->group);
164 	}
165 
166 	if (iattr->ia_valid & ATTR_ATIME) {
167 		attrs->mask |= ORANGEFS_ATTR_SYS_ATIME;
168 		if (iattr->ia_valid & ATTR_ATIME_SET) {
169 			attrs->atime = (time64_t)iattr->ia_atime.tv_sec;
170 			attrs->mask |= ORANGEFS_ATTR_SYS_ATIME_SET;
171 		}
172 	}
173 	if (iattr->ia_valid & ATTR_MTIME) {
174 		attrs->mask |= ORANGEFS_ATTR_SYS_MTIME;
175 		if (iattr->ia_valid & ATTR_MTIME_SET) {
176 			attrs->mtime = (time64_t)iattr->ia_mtime.tv_sec;
177 			attrs->mask |= ORANGEFS_ATTR_SYS_MTIME_SET;
178 		}
179 	}
180 	if (iattr->ia_valid & ATTR_CTIME)
181 		attrs->mask |= ORANGEFS_ATTR_SYS_CTIME;
182 
183 	/*
184 	 * ORANGEFS cannot set size with a setattr operation.  Probably not likely
185 	 * to be requested through the VFS, but just in case, don't worry about
186 	 * ATTR_SIZE
187 	 */
188 
189 	if (iattr->ia_valid & ATTR_MODE) {
190 		tmp_mode = iattr->ia_mode;
191 		if (tmp_mode & (S_ISVTX)) {
192 			if (is_root_handle(inode)) {
193 				/*
194 				 * allow sticky bit to be set on root (since
195 				 * it shows up that way by default anyhow),
196 				 * but don't show it to the server
197 				 */
198 				tmp_mode -= S_ISVTX;
199 			} else {
200 				gossip_debug(GOSSIP_UTILS_DEBUG,
201 					     "User attempted to set sticky bit on non-root directory; returning EINVAL.\n");
202 				return -EINVAL;
203 			}
204 		}
205 
206 		if (tmp_mode & (S_ISUID)) {
207 			gossip_debug(GOSSIP_UTILS_DEBUG,
208 				     "Attempting to set setuid bit (not supported); returning EINVAL.\n");
209 			return -EINVAL;
210 		}
211 
212 		attrs->perms = ORANGEFS_util_translate_mode(tmp_mode);
213 		attrs->mask |= ORANGEFS_ATTR_SYS_PERM;
214 	}
215 
216 	return 0;
217 }
218 
219 static int orangefs_inode_type(enum orangefs_ds_type objtype)
220 {
221 	if (objtype == ORANGEFS_TYPE_METAFILE)
222 		return S_IFREG;
223 	else if (objtype == ORANGEFS_TYPE_DIRECTORY)
224 		return S_IFDIR;
225 	else if (objtype == ORANGEFS_TYPE_SYMLINK)
226 		return S_IFLNK;
227 	else
228 		return -1;
229 }
230 
231 static int orangefs_inode_is_stale(struct inode *inode, int new,
232     struct ORANGEFS_sys_attr_s *attrs, char *link_target)
233 {
234 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
235 	int type = orangefs_inode_type(attrs->objtype);
236 	if (!new) {
237 		/*
238 		 * If the inode type or symlink target have changed then this
239 		 * inode is stale.
240 		 */
241 		if (type == -1 || !(inode->i_mode & type)) {
242 			orangefs_make_bad_inode(inode);
243 			return 1;
244 		}
245 		if (type == S_IFLNK && strncmp(orangefs_inode->link_target,
246 		    link_target, ORANGEFS_NAME_MAX)) {
247 			orangefs_make_bad_inode(inode);
248 			return 1;
249 		}
250 	}
251 	return 0;
252 }
253 
254 int orangefs_inode_getattr(struct inode *inode, int new, int bypass,
255     u32 request_mask)
256 {
257 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
258 	struct orangefs_kernel_op_s *new_op;
259 	loff_t inode_size, rounded_up_size;
260 	int ret, type;
261 
262 	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: called on inode %pU\n", __func__,
263 	    get_khandle_from_ino(inode));
264 
265 	if (!new && !bypass) {
266 		/*
267 		 * Must have all the attributes in the mask and be within cache
268 		 * time.
269 		 */
270 		if ((request_mask & orangefs_inode->getattr_mask) ==
271 		    request_mask &&
272 		    time_before(jiffies, orangefs_inode->getattr_time))
273 			return 0;
274 	}
275 
276 	new_op = op_alloc(ORANGEFS_VFS_OP_GETATTR);
277 	if (!new_op)
278 		return -ENOMEM;
279 	new_op->upcall.req.getattr.refn = orangefs_inode->refn;
280 	/*
281 	 * Size is the hardest attribute to get.  The incremental cost of any
282 	 * other attribute is essentially zero.
283 	 */
284 	if (request_mask & STATX_SIZE || new)
285 		new_op->upcall.req.getattr.mask = ORANGEFS_ATTR_SYS_ALL_NOHINT;
286 	else
287 		new_op->upcall.req.getattr.mask =
288 		    ORANGEFS_ATTR_SYS_ALL_NOHINT & ~ORANGEFS_ATTR_SYS_SIZE;
289 
290 	ret = service_operation(new_op, __func__,
291 	    get_interruptible_flag(inode));
292 	if (ret != 0)
293 		goto out;
294 
295 	type = orangefs_inode_type(new_op->
296 	    downcall.resp.getattr.attributes.objtype);
297 	ret = orangefs_inode_is_stale(inode, new,
298 	    &new_op->downcall.resp.getattr.attributes,
299 	    new_op->downcall.resp.getattr.link_target);
300 	if (ret) {
301 		ret = -ESTALE;
302 		goto out;
303 	}
304 
305 	switch (type) {
306 	case S_IFREG:
307 		inode->i_flags = orangefs_inode_flags(&new_op->
308 		    downcall.resp.getattr.attributes);
309 		if (request_mask & STATX_SIZE || new) {
310 			inode_size = (loff_t)new_op->
311 			    downcall.resp.getattr.attributes.size;
312 			rounded_up_size =
313 			    (inode_size + (4096 - (inode_size % 4096)));
314 			inode->i_size = inode_size;
315 			orangefs_inode->blksize =
316 			    new_op->downcall.resp.getattr.attributes.blksize;
317 			spin_lock(&inode->i_lock);
318 			inode->i_bytes = inode_size;
319 			inode->i_blocks =
320 			    (unsigned long)(rounded_up_size / 512);
321 			spin_unlock(&inode->i_lock);
322 		}
323 		break;
324 	case S_IFDIR:
325 		if (request_mask & STATX_SIZE || new) {
326 			inode->i_size = PAGE_SIZE;
327 			orangefs_inode->blksize = i_blocksize(inode);
328 			spin_lock(&inode->i_lock);
329 			inode_set_bytes(inode, inode->i_size);
330 			spin_unlock(&inode->i_lock);
331 		}
332 		set_nlink(inode, 1);
333 		break;
334 	case S_IFLNK:
335 		if (new) {
336 			inode->i_size = (loff_t)strlen(new_op->
337 			    downcall.resp.getattr.link_target);
338 			orangefs_inode->blksize = i_blocksize(inode);
339 			ret = strscpy(orangefs_inode->link_target,
340 			    new_op->downcall.resp.getattr.link_target,
341 			    ORANGEFS_NAME_MAX);
342 			if (ret == -E2BIG) {
343 				ret = -EIO;
344 				goto out;
345 			}
346 			inode->i_link = orangefs_inode->link_target;
347 		}
348 		break;
349 	}
350 
351 	inode->i_uid = make_kuid(&init_user_ns, new_op->
352 	    downcall.resp.getattr.attributes.owner);
353 	inode->i_gid = make_kgid(&init_user_ns, new_op->
354 	    downcall.resp.getattr.attributes.group);
355 	inode->i_atime.tv_sec = (time64_t)new_op->
356 	    downcall.resp.getattr.attributes.atime;
357 	inode->i_mtime.tv_sec = (time64_t)new_op->
358 	    downcall.resp.getattr.attributes.mtime;
359 	inode->i_ctime.tv_sec = (time64_t)new_op->
360 	    downcall.resp.getattr.attributes.ctime;
361 	inode->i_atime.tv_nsec = 0;
362 	inode->i_mtime.tv_nsec = 0;
363 	inode->i_ctime.tv_nsec = 0;
364 
365 	/* special case: mark the root inode as sticky */
366 	inode->i_mode = type | (is_root_handle(inode) ? S_ISVTX : 0) |
367 	    orangefs_inode_perms(&new_op->downcall.resp.getattr.attributes);
368 
369 	orangefs_inode->getattr_time = jiffies +
370 	    orangefs_getattr_timeout_msecs*HZ/1000;
371 	if (request_mask & STATX_SIZE || new)
372 		orangefs_inode->getattr_mask = STATX_BASIC_STATS;
373 	else
374 		orangefs_inode->getattr_mask = STATX_BASIC_STATS & ~STATX_SIZE;
375 	ret = 0;
376 out:
377 	op_release(new_op);
378 	return ret;
379 }
380 
381 int orangefs_inode_check_changed(struct inode *inode)
382 {
383 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
384 	struct orangefs_kernel_op_s *new_op;
385 	int ret;
386 
387 	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: called on inode %pU\n", __func__,
388 	    get_khandle_from_ino(inode));
389 
390 	new_op = op_alloc(ORANGEFS_VFS_OP_GETATTR);
391 	if (!new_op)
392 		return -ENOMEM;
393 	new_op->upcall.req.getattr.refn = orangefs_inode->refn;
394 	new_op->upcall.req.getattr.mask = ORANGEFS_ATTR_SYS_TYPE |
395 	    ORANGEFS_ATTR_SYS_LNK_TARGET;
396 
397 	ret = service_operation(new_op, __func__,
398 	    get_interruptible_flag(inode));
399 	if (ret != 0)
400 		goto out;
401 
402 	ret = orangefs_inode_is_stale(inode, 0,
403 	    &new_op->downcall.resp.getattr.attributes,
404 	    new_op->downcall.resp.getattr.link_target);
405 out:
406 	op_release(new_op);
407 	return ret;
408 }
409 
410 /*
411  * issues a orangefs setattr request to make sure the new attribute values
412  * take effect if successful.  returns 0 on success; -errno otherwise
413  */
414 int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr)
415 {
416 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
417 	struct orangefs_kernel_op_s *new_op;
418 	int ret;
419 
420 	new_op = op_alloc(ORANGEFS_VFS_OP_SETATTR);
421 	if (!new_op)
422 		return -ENOMEM;
423 
424 	new_op->upcall.req.setattr.refn = orangefs_inode->refn;
425 	ret = copy_attributes_from_inode(inode,
426 		       &new_op->upcall.req.setattr.attributes,
427 		       iattr);
428 	if (ret >= 0) {
429 		ret = service_operation(new_op, __func__,
430 				get_interruptible_flag(inode));
431 
432 		gossip_debug(GOSSIP_UTILS_DEBUG,
433 			     "orangefs_inode_setattr: returning %d\n",
434 			     ret);
435 	}
436 
437 	op_release(new_op);
438 
439 	/*
440 	 * successful setattr should clear the atime, mtime and
441 	 * ctime flags.
442 	 */
443 	if (ret == 0) {
444 		ClearAtimeFlag(orangefs_inode);
445 		ClearMtimeFlag(orangefs_inode);
446 		ClearCtimeFlag(orangefs_inode);
447 		ClearModeFlag(orangefs_inode);
448 		orangefs_inode->getattr_time = jiffies - 1;
449 	}
450 
451 	return ret;
452 }
453 
454 int orangefs_flush_inode(struct inode *inode)
455 {
456 	/*
457 	 * If it is a dirty inode, this function gets called.
458 	 * Gather all the information that needs to be setattr'ed
459 	 * Right now, this will only be used for mode, atime, mtime
460 	 * and/or ctime.
461 	 */
462 	struct iattr wbattr;
463 	int ret;
464 	int mtime_flag;
465 	int ctime_flag;
466 	int atime_flag;
467 	int mode_flag;
468 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
469 
470 	memset(&wbattr, 0, sizeof(wbattr));
471 
472 	/*
473 	 * check inode flags up front, and clear them if they are set.  This
474 	 * will prevent multiple processes from all trying to flush the same
475 	 * inode if they call close() simultaneously
476 	 */
477 	mtime_flag = MtimeFlag(orangefs_inode);
478 	ClearMtimeFlag(orangefs_inode);
479 	ctime_flag = CtimeFlag(orangefs_inode);
480 	ClearCtimeFlag(orangefs_inode);
481 	atime_flag = AtimeFlag(orangefs_inode);
482 	ClearAtimeFlag(orangefs_inode);
483 	mode_flag = ModeFlag(orangefs_inode);
484 	ClearModeFlag(orangefs_inode);
485 
486 	/*  -- Lazy atime,mtime and ctime update --
487 	 * Note: all times are dictated by server in the new scheme
488 	 * and not by the clients
489 	 *
490 	 * Also mode updates are being handled now..
491 	 */
492 
493 	if (mtime_flag)
494 		wbattr.ia_valid |= ATTR_MTIME;
495 	if (ctime_flag)
496 		wbattr.ia_valid |= ATTR_CTIME;
497 	if (atime_flag)
498 		wbattr.ia_valid |= ATTR_ATIME;
499 
500 	if (mode_flag) {
501 		wbattr.ia_mode = inode->i_mode;
502 		wbattr.ia_valid |= ATTR_MODE;
503 	}
504 
505 	gossip_debug(GOSSIP_UTILS_DEBUG,
506 		     "*********** orangefs_flush_inode: %pU "
507 		     "(ia_valid %d)\n",
508 		     get_khandle_from_ino(inode),
509 		     wbattr.ia_valid);
510 	if (wbattr.ia_valid == 0) {
511 		gossip_debug(GOSSIP_UTILS_DEBUG,
512 			     "orangefs_flush_inode skipping setattr()\n");
513 		return 0;
514 	}
515 
516 	gossip_debug(GOSSIP_UTILS_DEBUG,
517 		     "orangefs_flush_inode (%pU) writing mode %o\n",
518 		     get_khandle_from_ino(inode),
519 		     inode->i_mode);
520 
521 	ret = orangefs_inode_setattr(inode, &wbattr);
522 
523 	return ret;
524 }
525 
526 void orangefs_make_bad_inode(struct inode *inode)
527 {
528 	if (is_root_handle(inode)) {
529 		/*
530 		 * if this occurs, the pvfs2-client-core was killed but we
531 		 * can't afford to lose the inode operations and such
532 		 * associated with the root handle in any case.
533 		 */
534 		gossip_debug(GOSSIP_UTILS_DEBUG,
535 			     "*** NOT making bad root inode %pU\n",
536 			     get_khandle_from_ino(inode));
537 	} else {
538 		gossip_debug(GOSSIP_UTILS_DEBUG,
539 			     "*** making bad inode %pU\n",
540 			     get_khandle_from_ino(inode));
541 		make_bad_inode(inode);
542 	}
543 }
544 
545 /*
546  * The following is a very dirty hack that is now a permanent part of the
547  * ORANGEFS protocol. See protocol.h for more error definitions.
548  */
549 
550 /* The order matches include/orangefs-types.h in the OrangeFS source. */
551 static int PINT_errno_mapping[] = {
552 	0, EPERM, ENOENT, EINTR, EIO, ENXIO, EBADF, EAGAIN, ENOMEM,
553 	EFAULT, EBUSY, EEXIST, ENODEV, ENOTDIR, EISDIR, EINVAL, EMFILE,
554 	EFBIG, ENOSPC, EROFS, EMLINK, EPIPE, EDEADLK, ENAMETOOLONG,
555 	ENOLCK, ENOSYS, ENOTEMPTY, ELOOP, EWOULDBLOCK, ENOMSG, EUNATCH,
556 	EBADR, EDEADLOCK, ENODATA, ETIME, ENONET, EREMOTE, ECOMM,
557 	EPROTO, EBADMSG, EOVERFLOW, ERESTART, EMSGSIZE, EPROTOTYPE,
558 	ENOPROTOOPT, EPROTONOSUPPORT, EOPNOTSUPP, EADDRINUSE,
559 	EADDRNOTAVAIL, ENETDOWN, ENETUNREACH, ENETRESET, ENOBUFS,
560 	ETIMEDOUT, ECONNREFUSED, EHOSTDOWN, EHOSTUNREACH, EALREADY,
561 	EACCES, ECONNRESET, ERANGE
562 };
563 
564 int orangefs_normalize_to_errno(__s32 error_code)
565 {
566 	__u32 i;
567 
568 	/* Success */
569 	if (error_code == 0) {
570 		return 0;
571 	/*
572 	 * This shouldn't ever happen. If it does it should be fixed on the
573 	 * server.
574 	 */
575 	} else if (error_code > 0) {
576 		gossip_err("orangefs: error status receieved.\n");
577 		gossip_err("orangefs: assuming error code is inverted.\n");
578 		error_code = -error_code;
579 	}
580 
581 	/*
582 	 * XXX: This is very bad since error codes from ORANGEFS may not be
583 	 * suitable for return into userspace.
584 	 */
585 
586 	/*
587 	 * Convert ORANGEFS error values into errno values suitable for return
588 	 * from the kernel.
589 	 */
590 	if ((-error_code) & ORANGEFS_NON_ERRNO_ERROR_BIT) {
591 		if (((-error_code) &
592 		    (ORANGEFS_ERROR_NUMBER_BITS|ORANGEFS_NON_ERRNO_ERROR_BIT|
593 		    ORANGEFS_ERROR_BIT)) == ORANGEFS_ECANCEL) {
594 			/*
595 			 * cancellation error codes generally correspond to
596 			 * a timeout from the client's perspective
597 			 */
598 			error_code = -ETIMEDOUT;
599 		} else {
600 			/* assume a default error code */
601 			gossip_err("orangefs: warning: got error code without errno equivalent: %d.\n", error_code);
602 			error_code = -EINVAL;
603 		}
604 
605 	/* Convert ORANGEFS encoded errno values into regular errno values. */
606 	} else if ((-error_code) & ORANGEFS_ERROR_BIT) {
607 		i = (-error_code) & ~(ORANGEFS_ERROR_BIT|ORANGEFS_ERROR_CLASS_BITS);
608 		if (i < sizeof(PINT_errno_mapping)/sizeof(*PINT_errno_mapping))
609 			error_code = -PINT_errno_mapping[i];
610 		else
611 			error_code = -EINVAL;
612 
613 	/*
614 	 * Only ORANGEFS protocol error codes should ever come here. Otherwise
615 	 * there is a bug somewhere.
616 	 */
617 	} else {
618 		gossip_err("orangefs: orangefs_normalize_to_errno: got error code which is not from ORANGEFS.\n");
619 	}
620 	return error_code;
621 }
622 
623 #define NUM_MODES 11
624 __s32 ORANGEFS_util_translate_mode(int mode)
625 {
626 	int ret = 0;
627 	int i = 0;
628 	static int modes[NUM_MODES] = {
629 		S_IXOTH, S_IWOTH, S_IROTH,
630 		S_IXGRP, S_IWGRP, S_IRGRP,
631 		S_IXUSR, S_IWUSR, S_IRUSR,
632 		S_ISGID, S_ISUID
633 	};
634 	static int orangefs_modes[NUM_MODES] = {
635 		ORANGEFS_O_EXECUTE, ORANGEFS_O_WRITE, ORANGEFS_O_READ,
636 		ORANGEFS_G_EXECUTE, ORANGEFS_G_WRITE, ORANGEFS_G_READ,
637 		ORANGEFS_U_EXECUTE, ORANGEFS_U_WRITE, ORANGEFS_U_READ,
638 		ORANGEFS_G_SGID, ORANGEFS_U_SUID
639 	};
640 
641 	for (i = 0; i < NUM_MODES; i++)
642 		if (mode & modes[i])
643 			ret |= orangefs_modes[i];
644 
645 	return ret;
646 }
647 #undef NUM_MODES
648