xref: /openbmc/linux/fs/orangefs/orangefs-utils.c (revision 5859d77e)
1575e9461SMike Marshall /*
2575e9461SMike Marshall  * (C) 2001 Clemson University and The University of Chicago
3575e9461SMike Marshall  *
4575e9461SMike Marshall  * See COPYING in top-level directory.
5575e9461SMike Marshall  */
6575e9461SMike Marshall #include "protocol.h"
7575e9461SMike Marshall #include "orangefs-kernel.h"
8575e9461SMike Marshall #include "orangefs-dev-proto.h"
9575e9461SMike Marshall #include "orangefs-bufmap.h"
10575e9461SMike Marshall 
11575e9461SMike Marshall __s32 fsid_of_op(struct orangefs_kernel_op_s *op)
12575e9461SMike Marshall {
13575e9461SMike Marshall 	__s32 fsid = ORANGEFS_FS_ID_NULL;
14575e9461SMike Marshall 
15575e9461SMike Marshall 	if (op) {
16575e9461SMike Marshall 		switch (op->upcall.type) {
17575e9461SMike Marshall 		case ORANGEFS_VFS_OP_FILE_IO:
18575e9461SMike Marshall 			fsid = op->upcall.req.io.refn.fs_id;
19575e9461SMike Marshall 			break;
20575e9461SMike Marshall 		case ORANGEFS_VFS_OP_LOOKUP:
21575e9461SMike Marshall 			fsid = op->upcall.req.lookup.parent_refn.fs_id;
22575e9461SMike Marshall 			break;
23575e9461SMike Marshall 		case ORANGEFS_VFS_OP_CREATE:
24575e9461SMike Marshall 			fsid = op->upcall.req.create.parent_refn.fs_id;
25575e9461SMike Marshall 			break;
26575e9461SMike Marshall 		case ORANGEFS_VFS_OP_GETATTR:
27575e9461SMike Marshall 			fsid = op->upcall.req.getattr.refn.fs_id;
28575e9461SMike Marshall 			break;
29575e9461SMike Marshall 		case ORANGEFS_VFS_OP_REMOVE:
30575e9461SMike Marshall 			fsid = op->upcall.req.remove.parent_refn.fs_id;
31575e9461SMike Marshall 			break;
32575e9461SMike Marshall 		case ORANGEFS_VFS_OP_MKDIR:
33575e9461SMike Marshall 			fsid = op->upcall.req.mkdir.parent_refn.fs_id;
34575e9461SMike Marshall 			break;
35575e9461SMike Marshall 		case ORANGEFS_VFS_OP_READDIR:
36575e9461SMike Marshall 			fsid = op->upcall.req.readdir.refn.fs_id;
37575e9461SMike Marshall 			break;
38575e9461SMike Marshall 		case ORANGEFS_VFS_OP_SETATTR:
39575e9461SMike Marshall 			fsid = op->upcall.req.setattr.refn.fs_id;
40575e9461SMike Marshall 			break;
41575e9461SMike Marshall 		case ORANGEFS_VFS_OP_SYMLINK:
42575e9461SMike Marshall 			fsid = op->upcall.req.sym.parent_refn.fs_id;
43575e9461SMike Marshall 			break;
44575e9461SMike Marshall 		case ORANGEFS_VFS_OP_RENAME:
45575e9461SMike Marshall 			fsid = op->upcall.req.rename.old_parent_refn.fs_id;
46575e9461SMike Marshall 			break;
47575e9461SMike Marshall 		case ORANGEFS_VFS_OP_STATFS:
48575e9461SMike Marshall 			fsid = op->upcall.req.statfs.fs_id;
49575e9461SMike Marshall 			break;
50575e9461SMike Marshall 		case ORANGEFS_VFS_OP_TRUNCATE:
51575e9461SMike Marshall 			fsid = op->upcall.req.truncate.refn.fs_id;
52575e9461SMike Marshall 			break;
53575e9461SMike Marshall 		case ORANGEFS_VFS_OP_MMAP_RA_FLUSH:
54575e9461SMike Marshall 			fsid = op->upcall.req.ra_cache_flush.refn.fs_id;
55575e9461SMike Marshall 			break;
56575e9461SMike Marshall 		case ORANGEFS_VFS_OP_FS_UMOUNT:
57575e9461SMike Marshall 			fsid = op->upcall.req.fs_umount.fs_id;
58575e9461SMike Marshall 			break;
59575e9461SMike Marshall 		case ORANGEFS_VFS_OP_GETXATTR:
60575e9461SMike Marshall 			fsid = op->upcall.req.getxattr.refn.fs_id;
61575e9461SMike Marshall 			break;
62575e9461SMike Marshall 		case ORANGEFS_VFS_OP_SETXATTR:
63575e9461SMike Marshall 			fsid = op->upcall.req.setxattr.refn.fs_id;
64575e9461SMike Marshall 			break;
65575e9461SMike Marshall 		case ORANGEFS_VFS_OP_LISTXATTR:
66575e9461SMike Marshall 			fsid = op->upcall.req.listxattr.refn.fs_id;
67575e9461SMike Marshall 			break;
68575e9461SMike Marshall 		case ORANGEFS_VFS_OP_REMOVEXATTR:
69575e9461SMike Marshall 			fsid = op->upcall.req.removexattr.refn.fs_id;
70575e9461SMike Marshall 			break;
71575e9461SMike Marshall 		case ORANGEFS_VFS_OP_FSYNC:
72575e9461SMike Marshall 			fsid = op->upcall.req.fsync.refn.fs_id;
73575e9461SMike Marshall 			break;
74575e9461SMike Marshall 		default:
75575e9461SMike Marshall 			break;
76575e9461SMike Marshall 		}
77575e9461SMike Marshall 	}
78575e9461SMike Marshall 	return fsid;
79575e9461SMike Marshall }
80575e9461SMike Marshall 
81394f647eSMartin Brandenburg static int orangefs_inode_flags(struct ORANGEFS_sys_attr_s *attrs)
82575e9461SMike Marshall {
83394f647eSMartin Brandenburg 	int flags = 0;
84575e9461SMike Marshall 	if (attrs->flags & ORANGEFS_IMMUTABLE_FL)
85394f647eSMartin Brandenburg 		flags |= S_IMMUTABLE;
86575e9461SMike Marshall 	else
87394f647eSMartin Brandenburg 		flags &= ~S_IMMUTABLE;
88575e9461SMike Marshall 	if (attrs->flags & ORANGEFS_APPEND_FL)
89394f647eSMartin Brandenburg 		flags |= S_APPEND;
90575e9461SMike Marshall 	else
91394f647eSMartin Brandenburg 		flags &= ~S_APPEND;
92575e9461SMike Marshall 	if (attrs->flags & ORANGEFS_NOATIME_FL)
93394f647eSMartin Brandenburg 		flags |= S_NOATIME;
94575e9461SMike Marshall 	else
95394f647eSMartin Brandenburg 		flags &= ~S_NOATIME;
96394f647eSMartin Brandenburg 	return flags;
97394f647eSMartin Brandenburg }
98575e9461SMike Marshall 
99394f647eSMartin Brandenburg static int orangefs_inode_perms(struct ORANGEFS_sys_attr_s *attrs)
100394f647eSMartin Brandenburg {
101394f647eSMartin Brandenburg 	int perm_mode = 0;
102394f647eSMartin Brandenburg 
103394f647eSMartin Brandenburg 	if (attrs->perms & ORANGEFS_O_EXECUTE)
104394f647eSMartin Brandenburg 		perm_mode |= S_IXOTH;
105394f647eSMartin Brandenburg 	if (attrs->perms & ORANGEFS_O_WRITE)
106394f647eSMartin Brandenburg 		perm_mode |= S_IWOTH;
107394f647eSMartin Brandenburg 	if (attrs->perms & ORANGEFS_O_READ)
108394f647eSMartin Brandenburg 		perm_mode |= S_IROTH;
109394f647eSMartin Brandenburg 
110394f647eSMartin Brandenburg 	if (attrs->perms & ORANGEFS_G_EXECUTE)
111394f647eSMartin Brandenburg 		perm_mode |= S_IXGRP;
112394f647eSMartin Brandenburg 	if (attrs->perms & ORANGEFS_G_WRITE)
113394f647eSMartin Brandenburg 		perm_mode |= S_IWGRP;
114394f647eSMartin Brandenburg 	if (attrs->perms & ORANGEFS_G_READ)
115394f647eSMartin Brandenburg 		perm_mode |= S_IRGRP;
116394f647eSMartin Brandenburg 
117394f647eSMartin Brandenburg 	if (attrs->perms & ORANGEFS_U_EXECUTE)
118394f647eSMartin Brandenburg 		perm_mode |= S_IXUSR;
119394f647eSMartin Brandenburg 	if (attrs->perms & ORANGEFS_U_WRITE)
120394f647eSMartin Brandenburg 		perm_mode |= S_IWUSR;
121394f647eSMartin Brandenburg 	if (attrs->perms & ORANGEFS_U_READ)
122394f647eSMartin Brandenburg 		perm_mode |= S_IRUSR;
123394f647eSMartin Brandenburg 
124394f647eSMartin Brandenburg 	if (attrs->perms & ORANGEFS_G_SGID)
125394f647eSMartin Brandenburg 		perm_mode |= S_ISGID;
126394f647eSMartin Brandenburg 	if (attrs->perms & ORANGEFS_U_SUID)
127394f647eSMartin Brandenburg 		perm_mode |= S_ISUID;
128394f647eSMartin Brandenburg 
129394f647eSMartin Brandenburg 	return perm_mode;
130575e9461SMike Marshall }
131575e9461SMike Marshall 
132575e9461SMike Marshall /*
133575e9461SMike Marshall  * NOTE: in kernel land, we never use the sys_attr->link_target for
134575e9461SMike Marshall  * anything, so don't bother copying it into the sys_attr object here.
135575e9461SMike Marshall  */
136575e9461SMike Marshall static inline int copy_attributes_from_inode(struct inode *inode,
137575e9461SMike Marshall 					     struct ORANGEFS_sys_attr_s *attrs,
138575e9461SMike Marshall 					     struct iattr *iattr)
139575e9461SMike Marshall {
140575e9461SMike Marshall 	umode_t tmp_mode;
141575e9461SMike Marshall 
142575e9461SMike Marshall 	if (!iattr || !inode || !attrs) {
143575e9461SMike Marshall 		gossip_err("NULL iattr (%p), inode (%p), attrs (%p) "
144575e9461SMike Marshall 			   "in copy_attributes_from_inode!\n",
145575e9461SMike Marshall 			   iattr,
146575e9461SMike Marshall 			   inode,
147575e9461SMike Marshall 			   attrs);
148575e9461SMike Marshall 		return -EINVAL;
149575e9461SMike Marshall 	}
150575e9461SMike Marshall 	/*
151575e9461SMike Marshall 	 * We need to be careful to only copy the attributes out of the
152575e9461SMike Marshall 	 * iattr object that we know are valid.
153575e9461SMike Marshall 	 */
154575e9461SMike Marshall 	attrs->mask = 0;
155575e9461SMike Marshall 	if (iattr->ia_valid & ATTR_UID) {
156575e9461SMike Marshall 		attrs->owner = from_kuid(current_user_ns(), iattr->ia_uid);
157575e9461SMike Marshall 		attrs->mask |= ORANGEFS_ATTR_SYS_UID;
158575e9461SMike Marshall 		gossip_debug(GOSSIP_UTILS_DEBUG, "(UID) %d\n", attrs->owner);
159575e9461SMike Marshall 	}
160575e9461SMike Marshall 	if (iattr->ia_valid & ATTR_GID) {
161575e9461SMike Marshall 		attrs->group = from_kgid(current_user_ns(), iattr->ia_gid);
162575e9461SMike Marshall 		attrs->mask |= ORANGEFS_ATTR_SYS_GID;
163575e9461SMike Marshall 		gossip_debug(GOSSIP_UTILS_DEBUG, "(GID) %d\n", attrs->group);
164575e9461SMike Marshall 	}
165575e9461SMike Marshall 
166575e9461SMike Marshall 	if (iattr->ia_valid & ATTR_ATIME) {
167575e9461SMike Marshall 		attrs->mask |= ORANGEFS_ATTR_SYS_ATIME;
168575e9461SMike Marshall 		if (iattr->ia_valid & ATTR_ATIME_SET) {
169be81ce48SArnd Bergmann 			attrs->atime = (time64_t)iattr->ia_atime.tv_sec;
170575e9461SMike Marshall 			attrs->mask |= ORANGEFS_ATTR_SYS_ATIME_SET;
171575e9461SMike Marshall 		}
172575e9461SMike Marshall 	}
173575e9461SMike Marshall 	if (iattr->ia_valid & ATTR_MTIME) {
174575e9461SMike Marshall 		attrs->mask |= ORANGEFS_ATTR_SYS_MTIME;
175575e9461SMike Marshall 		if (iattr->ia_valid & ATTR_MTIME_SET) {
176be81ce48SArnd Bergmann 			attrs->mtime = (time64_t)iattr->ia_mtime.tv_sec;
177575e9461SMike Marshall 			attrs->mask |= ORANGEFS_ATTR_SYS_MTIME_SET;
178575e9461SMike Marshall 		}
179575e9461SMike Marshall 	}
180575e9461SMike Marshall 	if (iattr->ia_valid & ATTR_CTIME)
181575e9461SMike Marshall 		attrs->mask |= ORANGEFS_ATTR_SYS_CTIME;
182575e9461SMike Marshall 
183575e9461SMike Marshall 	/*
184575e9461SMike Marshall 	 * ORANGEFS cannot set size with a setattr operation.  Probably not likely
185575e9461SMike Marshall 	 * to be requested through the VFS, but just in case, don't worry about
186575e9461SMike Marshall 	 * ATTR_SIZE
187575e9461SMike Marshall 	 */
188575e9461SMike Marshall 
189575e9461SMike Marshall 	if (iattr->ia_valid & ATTR_MODE) {
190575e9461SMike Marshall 		tmp_mode = iattr->ia_mode;
191575e9461SMike Marshall 		if (tmp_mode & (S_ISVTX)) {
192575e9461SMike Marshall 			if (is_root_handle(inode)) {
193575e9461SMike Marshall 				/*
194575e9461SMike Marshall 				 * allow sticky bit to be set on root (since
195575e9461SMike Marshall 				 * it shows up that way by default anyhow),
196575e9461SMike Marshall 				 * but don't show it to the server
197575e9461SMike Marshall 				 */
198575e9461SMike Marshall 				tmp_mode -= S_ISVTX;
199575e9461SMike Marshall 			} else {
200575e9461SMike Marshall 				gossip_debug(GOSSIP_UTILS_DEBUG,
201575e9461SMike Marshall 					     "User attempted to set sticky bit on non-root directory; returning EINVAL.\n");
202575e9461SMike Marshall 				return -EINVAL;
203575e9461SMike Marshall 			}
204575e9461SMike Marshall 		}
205575e9461SMike Marshall 
206575e9461SMike Marshall 		if (tmp_mode & (S_ISUID)) {
207575e9461SMike Marshall 			gossip_debug(GOSSIP_UTILS_DEBUG,
208575e9461SMike Marshall 				     "Attempting to set setuid bit (not supported); returning EINVAL.\n");
209575e9461SMike Marshall 			return -EINVAL;
210575e9461SMike Marshall 		}
211575e9461SMike Marshall 
212575e9461SMike Marshall 		attrs->perms = ORANGEFS_util_translate_mode(tmp_mode);
213575e9461SMike Marshall 		attrs->mask |= ORANGEFS_ATTR_SYS_PERM;
214575e9461SMike Marshall 	}
215575e9461SMike Marshall 
216575e9461SMike Marshall 	return 0;
217575e9461SMike Marshall }
218575e9461SMike Marshall 
2193c9cf98dSMartin Brandenburg static int orangefs_inode_type(enum orangefs_ds_type objtype)
2203c9cf98dSMartin Brandenburg {
2213c9cf98dSMartin Brandenburg 	if (objtype == ORANGEFS_TYPE_METAFILE)
2223c9cf98dSMartin Brandenburg 		return S_IFREG;
2233c9cf98dSMartin Brandenburg 	else if (objtype == ORANGEFS_TYPE_DIRECTORY)
2243c9cf98dSMartin Brandenburg 		return S_IFDIR;
2253c9cf98dSMartin Brandenburg 	else if (objtype == ORANGEFS_TYPE_SYMLINK)
2263c9cf98dSMartin Brandenburg 		return S_IFLNK;
2273c9cf98dSMartin Brandenburg 	else
2283c9cf98dSMartin Brandenburg 		return -1;
2293c9cf98dSMartin Brandenburg }
2303c9cf98dSMartin Brandenburg 
2313c9cf98dSMartin Brandenburg int orangefs_inode_getattr(struct inode *inode, int new, int size)
2323c9cf98dSMartin Brandenburg {
2333c9cf98dSMartin Brandenburg 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
2343c9cf98dSMartin Brandenburg 	struct orangefs_kernel_op_s *new_op;
2353c9cf98dSMartin Brandenburg 	loff_t inode_size, rounded_up_size;
2363c9cf98dSMartin Brandenburg 	int ret;
2373c9cf98dSMartin Brandenburg 
2383c9cf98dSMartin Brandenburg 	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: called on inode %pU\n", __func__,
2393c9cf98dSMartin Brandenburg 	    get_khandle_from_ino(inode));
2403c9cf98dSMartin Brandenburg 
2413c9cf98dSMartin Brandenburg 	new_op = op_alloc(ORANGEFS_VFS_OP_GETATTR);
2423c9cf98dSMartin Brandenburg 	if (!new_op)
2433c9cf98dSMartin Brandenburg 		return -ENOMEM;
2443c9cf98dSMartin Brandenburg 	new_op->upcall.req.getattr.refn = orangefs_inode->refn;
2453c9cf98dSMartin Brandenburg 	new_op->upcall.req.getattr.mask = size ?
2463c9cf98dSMartin Brandenburg 	    ORANGEFS_ATTR_SYS_ALL_NOHINT : ORANGEFS_ATTR_SYS_ALL_NOHINT_NOSIZE;
2473c9cf98dSMartin Brandenburg 
2483c9cf98dSMartin Brandenburg 	ret = service_operation(new_op, __func__,
2493c9cf98dSMartin Brandenburg 	    get_interruptible_flag(inode));
2503c9cf98dSMartin Brandenburg 	if (ret != 0)
2513c9cf98dSMartin Brandenburg 		goto out;
2523c9cf98dSMartin Brandenburg 
2533c9cf98dSMartin Brandenburg 	ret = orangefs_inode_type(new_op->
2543c9cf98dSMartin Brandenburg 	    downcall.resp.getattr.attributes.objtype);
2553c9cf98dSMartin Brandenburg 	if (!new) {
2563c9cf98dSMartin Brandenburg 		/*
2573c9cf98dSMartin Brandenburg 		 * If the inode type or symlink target have changed then this
2583c9cf98dSMartin Brandenburg 		 * inode is stale.
2593c9cf98dSMartin Brandenburg 		 */
2603c9cf98dSMartin Brandenburg 		if (ret == -1 || !(inode->i_mode & ret)) {
2613c9cf98dSMartin Brandenburg 			orangefs_make_bad_inode(inode);
2623c9cf98dSMartin Brandenburg 			ret = -ESTALE;
2633c9cf98dSMartin Brandenburg 			goto out;
2643c9cf98dSMartin Brandenburg 		}
2653c9cf98dSMartin Brandenburg 		if (ret == S_IFLNK && strncmp(orangefs_inode->link_target,
2663c9cf98dSMartin Brandenburg 		    new_op->downcall.resp.getattr.link_target,
2673c9cf98dSMartin Brandenburg 		    ORANGEFS_NAME_MAX)) {
2683c9cf98dSMartin Brandenburg 			orangefs_make_bad_inode(inode);
2693c9cf98dSMartin Brandenburg 			ret = -ESTALE;
2703c9cf98dSMartin Brandenburg 			goto out;
2713c9cf98dSMartin Brandenburg 		}
2723c9cf98dSMartin Brandenburg 	}
2733c9cf98dSMartin Brandenburg 
2743c9cf98dSMartin Brandenburg 	switch (ret) {
2753c9cf98dSMartin Brandenburg 	case S_IFREG:
2763c9cf98dSMartin Brandenburg 		inode->i_flags = orangefs_inode_flags(&new_op->
2773c9cf98dSMartin Brandenburg 		    downcall.resp.getattr.attributes);
2783c9cf98dSMartin Brandenburg 		if (size) {
2793c9cf98dSMartin Brandenburg 			inode_size = (loff_t)new_op->
2803c9cf98dSMartin Brandenburg 			    downcall.resp.getattr.attributes.size;
2813c9cf98dSMartin Brandenburg 			rounded_up_size =
2823c9cf98dSMartin Brandenburg 			    (inode_size + (4096 - (inode_size % 4096)));
2833c9cf98dSMartin Brandenburg 			inode->i_size = inode_size;
2843c9cf98dSMartin Brandenburg 			orangefs_inode->blksize =
2853c9cf98dSMartin Brandenburg 			    new_op->downcall.resp.getattr.attributes.blksize;
2863c9cf98dSMartin Brandenburg 			spin_lock(&inode->i_lock);
2873c9cf98dSMartin Brandenburg 			inode->i_bytes = inode_size;
2883c9cf98dSMartin Brandenburg 			inode->i_blocks =
2893c9cf98dSMartin Brandenburg 			    (unsigned long)(rounded_up_size / 512);
2903c9cf98dSMartin Brandenburg 			spin_unlock(&inode->i_lock);
2913c9cf98dSMartin Brandenburg 		}
2923c9cf98dSMartin Brandenburg 		break;
2933c9cf98dSMartin Brandenburg 	case S_IFDIR:
2943c9cf98dSMartin Brandenburg 		inode->i_size = PAGE_CACHE_SIZE;
2953c9cf98dSMartin Brandenburg 		orangefs_inode->blksize = (1 << inode->i_blkbits);
2963c9cf98dSMartin Brandenburg 		spin_lock(&inode->i_lock);
2973c9cf98dSMartin Brandenburg 		inode_set_bytes(inode, inode->i_size);
2983c9cf98dSMartin Brandenburg 		spin_unlock(&inode->i_lock);
2993c9cf98dSMartin Brandenburg 		set_nlink(inode, 1);
3003c9cf98dSMartin Brandenburg 		break;
3013c9cf98dSMartin Brandenburg 	case S_IFLNK:
3023c9cf98dSMartin Brandenburg 		if (new) {
3033c9cf98dSMartin Brandenburg 			inode->i_size = (loff_t)strlen(new_op->
3043c9cf98dSMartin Brandenburg 			    downcall.resp.getattr.link_target);
3053c9cf98dSMartin Brandenburg 			orangefs_inode->blksize = (1 << inode->i_blkbits);
3063c9cf98dSMartin Brandenburg 			strlcpy(orangefs_inode->link_target,
3073c9cf98dSMartin Brandenburg 			    new_op->downcall.resp.getattr.link_target,
3083c9cf98dSMartin Brandenburg 			    ORANGEFS_NAME_MAX);
3093c9cf98dSMartin Brandenburg 		}
3103c9cf98dSMartin Brandenburg 		break;
3113c9cf98dSMartin Brandenburg 	}
3123c9cf98dSMartin Brandenburg 
3133c9cf98dSMartin Brandenburg 	inode->i_uid = make_kuid(&init_user_ns, new_op->
3143c9cf98dSMartin Brandenburg 	    downcall.resp.getattr.attributes.owner);
3153c9cf98dSMartin Brandenburg 	inode->i_gid = make_kgid(&init_user_ns, new_op->
3163c9cf98dSMartin Brandenburg 	    downcall.resp.getattr.attributes.group);
3173c9cf98dSMartin Brandenburg 	inode->i_atime.tv_sec = (time64_t)new_op->
3183c9cf98dSMartin Brandenburg 	    downcall.resp.getattr.attributes.atime;
3193c9cf98dSMartin Brandenburg 	inode->i_mtime.tv_sec = (time64_t)new_op->
3203c9cf98dSMartin Brandenburg 	    downcall.resp.getattr.attributes.mtime;
3213c9cf98dSMartin Brandenburg 	inode->i_ctime.tv_sec = (time64_t)new_op->
3223c9cf98dSMartin Brandenburg 	    downcall.resp.getattr.attributes.ctime;
3233c9cf98dSMartin Brandenburg 	inode->i_atime.tv_nsec = 0;
3243c9cf98dSMartin Brandenburg 	inode->i_mtime.tv_nsec = 0;
3253c9cf98dSMartin Brandenburg 	inode->i_ctime.tv_nsec = 0;
3263c9cf98dSMartin Brandenburg 
3273c9cf98dSMartin Brandenburg 	/* special case: mark the root inode as sticky */
3283c9cf98dSMartin Brandenburg 	inode->i_mode = ret | (is_root_handle(inode) ? S_ISVTX : 0) |
3293c9cf98dSMartin Brandenburg 	    orangefs_inode_perms(&new_op->downcall.resp.getattr.attributes);
3303c9cf98dSMartin Brandenburg 
3313c9cf98dSMartin Brandenburg 	ret = 0;
3323c9cf98dSMartin Brandenburg out:
3333c9cf98dSMartin Brandenburg 	op_release(new_op);
3343c9cf98dSMartin Brandenburg 	return ret;
3353c9cf98dSMartin Brandenburg }
3363c9cf98dSMartin Brandenburg 
3375859d77eSMartin Brandenburg int orangefs_inode_check_changed(struct inode *inode)
3385859d77eSMartin Brandenburg {
3395859d77eSMartin Brandenburg 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
3405859d77eSMartin Brandenburg 	struct orangefs_kernel_op_s *new_op;
3415859d77eSMartin Brandenburg 	int ret;
3425859d77eSMartin Brandenburg 
3435859d77eSMartin Brandenburg 	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: called on inode %pU\n", __func__,
3445859d77eSMartin Brandenburg 	    get_khandle_from_ino(inode));
3455859d77eSMartin Brandenburg 
3465859d77eSMartin Brandenburg 	new_op = op_alloc(ORANGEFS_VFS_OP_GETATTR);
3475859d77eSMartin Brandenburg 	if (!new_op)
3485859d77eSMartin Brandenburg 		return -ENOMEM;
3495859d77eSMartin Brandenburg 	new_op->upcall.req.getattr.refn = orangefs_inode->refn;
3505859d77eSMartin Brandenburg 	new_op->upcall.req.getattr.mask = ORANGEFS_ATTR_SYS_TYPE |
3515859d77eSMartin Brandenburg 	    ORANGEFS_ATTR_SYS_LNK_TARGET;
3525859d77eSMartin Brandenburg 
3535859d77eSMartin Brandenburg 	ret = service_operation(new_op, __func__,
3545859d77eSMartin Brandenburg 	    get_interruptible_flag(inode));
3555859d77eSMartin Brandenburg 	if (ret != 0)
3565859d77eSMartin Brandenburg 		goto out;
3575859d77eSMartin Brandenburg 
3585859d77eSMartin Brandenburg 	ret = orangefs_inode_type(new_op->
3595859d77eSMartin Brandenburg 	    downcall.resp.getattr.attributes.objtype);
3605859d77eSMartin Brandenburg 	/*
3615859d77eSMartin Brandenburg 	 * If the inode type or symlink target have changed then this
3625859d77eSMartin Brandenburg 	 * inode is stale.
3635859d77eSMartin Brandenburg 	 */
3645859d77eSMartin Brandenburg 	if (ret == -1 || !(inode->i_mode & ret)) {
3655859d77eSMartin Brandenburg 		orangefs_make_bad_inode(inode);
3665859d77eSMartin Brandenburg 		ret = 1;
3675859d77eSMartin Brandenburg 		goto out;
3685859d77eSMartin Brandenburg 	}
3695859d77eSMartin Brandenburg 	if (ret == S_IFLNK && strncmp(orangefs_inode->link_target,
3705859d77eSMartin Brandenburg 	    new_op->downcall.resp.getattr.link_target,
3715859d77eSMartin Brandenburg 	    ORANGEFS_NAME_MAX)) {
3725859d77eSMartin Brandenburg 		orangefs_make_bad_inode(inode);
3735859d77eSMartin Brandenburg 		ret = 1;
3745859d77eSMartin Brandenburg 		goto out;
3755859d77eSMartin Brandenburg 	}
3765859d77eSMartin Brandenburg 
3775859d77eSMartin Brandenburg 	ret = 0;
3785859d77eSMartin Brandenburg out:
3795859d77eSMartin Brandenburg 	op_release(new_op);
3805859d77eSMartin Brandenburg 	return ret;
3815859d77eSMartin Brandenburg }
3825859d77eSMartin Brandenburg 
383575e9461SMike Marshall /*
384575e9461SMike Marshall  * issues a orangefs setattr request to make sure the new attribute values
385575e9461SMike Marshall  * take effect if successful.  returns 0 on success; -errno otherwise
386575e9461SMike Marshall  */
387575e9461SMike Marshall int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr)
388575e9461SMike Marshall {
389575e9461SMike Marshall 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
390575e9461SMike Marshall 	struct orangefs_kernel_op_s *new_op;
391575e9461SMike Marshall 	int ret;
392575e9461SMike Marshall 
393575e9461SMike Marshall 	new_op = op_alloc(ORANGEFS_VFS_OP_SETATTR);
394575e9461SMike Marshall 	if (!new_op)
395575e9461SMike Marshall 		return -ENOMEM;
396575e9461SMike Marshall 
397575e9461SMike Marshall 	new_op->upcall.req.setattr.refn = orangefs_inode->refn;
398575e9461SMike Marshall 	ret = copy_attributes_from_inode(inode,
399575e9461SMike Marshall 		       &new_op->upcall.req.setattr.attributes,
400575e9461SMike Marshall 		       iattr);
401ed42fe05SAl Viro 	if (ret >= 0) {
402575e9461SMike Marshall 		ret = service_operation(new_op, __func__,
403575e9461SMike Marshall 				get_interruptible_flag(inode));
404575e9461SMike Marshall 
405575e9461SMike Marshall 		gossip_debug(GOSSIP_UTILS_DEBUG,
406575e9461SMike Marshall 			     "orangefs_inode_setattr: returning %d\n",
407575e9461SMike Marshall 			     ret);
408ed42fe05SAl Viro 	}
409575e9461SMike Marshall 
410575e9461SMike Marshall 	op_release(new_op);
411575e9461SMike Marshall 
412575e9461SMike Marshall 	/*
413575e9461SMike Marshall 	 * successful setattr should clear the atime, mtime and
414575e9461SMike Marshall 	 * ctime flags.
415575e9461SMike Marshall 	 */
416575e9461SMike Marshall 	if (ret == 0) {
417575e9461SMike Marshall 		ClearAtimeFlag(orangefs_inode);
418575e9461SMike Marshall 		ClearMtimeFlag(orangefs_inode);
419575e9461SMike Marshall 		ClearCtimeFlag(orangefs_inode);
420575e9461SMike Marshall 		ClearModeFlag(orangefs_inode);
421575e9461SMike Marshall 	}
422575e9461SMike Marshall 
423575e9461SMike Marshall 	return ret;
424575e9461SMike Marshall }
425575e9461SMike Marshall 
426575e9461SMike Marshall int orangefs_flush_inode(struct inode *inode)
427575e9461SMike Marshall {
428575e9461SMike Marshall 	/*
429575e9461SMike Marshall 	 * If it is a dirty inode, this function gets called.
430575e9461SMike Marshall 	 * Gather all the information that needs to be setattr'ed
431575e9461SMike Marshall 	 * Right now, this will only be used for mode, atime, mtime
432575e9461SMike Marshall 	 * and/or ctime.
433575e9461SMike Marshall 	 */
434575e9461SMike Marshall 	struct iattr wbattr;
435575e9461SMike Marshall 	int ret;
436575e9461SMike Marshall 	int mtime_flag;
437575e9461SMike Marshall 	int ctime_flag;
438575e9461SMike Marshall 	int atime_flag;
439575e9461SMike Marshall 	int mode_flag;
440575e9461SMike Marshall 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
441575e9461SMike Marshall 
442575e9461SMike Marshall 	memset(&wbattr, 0, sizeof(wbattr));
443575e9461SMike Marshall 
444575e9461SMike Marshall 	/*
445575e9461SMike Marshall 	 * check inode flags up front, and clear them if they are set.  This
446575e9461SMike Marshall 	 * will prevent multiple processes from all trying to flush the same
447575e9461SMike Marshall 	 * inode if they call close() simultaneously
448575e9461SMike Marshall 	 */
449575e9461SMike Marshall 	mtime_flag = MtimeFlag(orangefs_inode);
450575e9461SMike Marshall 	ClearMtimeFlag(orangefs_inode);
451575e9461SMike Marshall 	ctime_flag = CtimeFlag(orangefs_inode);
452575e9461SMike Marshall 	ClearCtimeFlag(orangefs_inode);
453575e9461SMike Marshall 	atime_flag = AtimeFlag(orangefs_inode);
454575e9461SMike Marshall 	ClearAtimeFlag(orangefs_inode);
455575e9461SMike Marshall 	mode_flag = ModeFlag(orangefs_inode);
456575e9461SMike Marshall 	ClearModeFlag(orangefs_inode);
457575e9461SMike Marshall 
458575e9461SMike Marshall 	/*  -- Lazy atime,mtime and ctime update --
459575e9461SMike Marshall 	 * Note: all times are dictated by server in the new scheme
460575e9461SMike Marshall 	 * and not by the clients
461575e9461SMike Marshall 	 *
462575e9461SMike Marshall 	 * Also mode updates are being handled now..
463575e9461SMike Marshall 	 */
464575e9461SMike Marshall 
465575e9461SMike Marshall 	if (mtime_flag)
466575e9461SMike Marshall 		wbattr.ia_valid |= ATTR_MTIME;
467575e9461SMike Marshall 	if (ctime_flag)
468575e9461SMike Marshall 		wbattr.ia_valid |= ATTR_CTIME;
469575e9461SMike Marshall 	if (atime_flag)
470575e9461SMike Marshall 		wbattr.ia_valid |= ATTR_ATIME;
471575e9461SMike Marshall 
472575e9461SMike Marshall 	if (mode_flag) {
473575e9461SMike Marshall 		wbattr.ia_mode = inode->i_mode;
474575e9461SMike Marshall 		wbattr.ia_valid |= ATTR_MODE;
475575e9461SMike Marshall 	}
476575e9461SMike Marshall 
477575e9461SMike Marshall 	gossip_debug(GOSSIP_UTILS_DEBUG,
478575e9461SMike Marshall 		     "*********** orangefs_flush_inode: %pU "
479575e9461SMike Marshall 		     "(ia_valid %d)\n",
480575e9461SMike Marshall 		     get_khandle_from_ino(inode),
481575e9461SMike Marshall 		     wbattr.ia_valid);
482575e9461SMike Marshall 	if (wbattr.ia_valid == 0) {
483575e9461SMike Marshall 		gossip_debug(GOSSIP_UTILS_DEBUG,
484575e9461SMike Marshall 			     "orangefs_flush_inode skipping setattr()\n");
485575e9461SMike Marshall 		return 0;
486575e9461SMike Marshall 	}
487575e9461SMike Marshall 
488575e9461SMike Marshall 	gossip_debug(GOSSIP_UTILS_DEBUG,
489575e9461SMike Marshall 		     "orangefs_flush_inode (%pU) writing mode %o\n",
490575e9461SMike Marshall 		     get_khandle_from_ino(inode),
491575e9461SMike Marshall 		     inode->i_mode);
492575e9461SMike Marshall 
493575e9461SMike Marshall 	ret = orangefs_inode_setattr(inode, &wbattr);
494575e9461SMike Marshall 
495575e9461SMike Marshall 	return ret;
496575e9461SMike Marshall }
497575e9461SMike Marshall 
498575e9461SMike Marshall int orangefs_unmount_sb(struct super_block *sb)
499575e9461SMike Marshall {
500575e9461SMike Marshall 	int ret = -EINVAL;
501575e9461SMike Marshall 	struct orangefs_kernel_op_s *new_op = NULL;
502575e9461SMike Marshall 
503575e9461SMike Marshall 	gossip_debug(GOSSIP_UTILS_DEBUG,
504575e9461SMike Marshall 		     "orangefs_unmount_sb called on sb %p\n",
505575e9461SMike Marshall 		     sb);
506575e9461SMike Marshall 
507575e9461SMike Marshall 	new_op = op_alloc(ORANGEFS_VFS_OP_FS_UMOUNT);
508575e9461SMike Marshall 	if (!new_op)
509575e9461SMike Marshall 		return -ENOMEM;
510575e9461SMike Marshall 	new_op->upcall.req.fs_umount.id = ORANGEFS_SB(sb)->id;
511575e9461SMike Marshall 	new_op->upcall.req.fs_umount.fs_id = ORANGEFS_SB(sb)->fs_id;
512575e9461SMike Marshall 	strncpy(new_op->upcall.req.fs_umount.orangefs_config_server,
513575e9461SMike Marshall 		ORANGEFS_SB(sb)->devname,
514575e9461SMike Marshall 		ORANGEFS_MAX_SERVER_ADDR_LEN);
515575e9461SMike Marshall 
516575e9461SMike Marshall 	gossip_debug(GOSSIP_UTILS_DEBUG,
517575e9461SMike Marshall 		     "Attempting ORANGEFS Unmount via host %s\n",
518575e9461SMike Marshall 		     new_op->upcall.req.fs_umount.orangefs_config_server);
519575e9461SMike Marshall 
520575e9461SMike Marshall 	ret = service_operation(new_op, "orangefs_fs_umount", 0);
521575e9461SMike Marshall 
522575e9461SMike Marshall 	gossip_debug(GOSSIP_UTILS_DEBUG,
523575e9461SMike Marshall 		     "orangefs_unmount: got return value of %d\n", ret);
524575e9461SMike Marshall 	if (ret)
525575e9461SMike Marshall 		sb = ERR_PTR(ret);
526575e9461SMike Marshall 	else
527575e9461SMike Marshall 		ORANGEFS_SB(sb)->mount_pending = 1;
528575e9461SMike Marshall 
529575e9461SMike Marshall 	op_release(new_op);
530575e9461SMike Marshall 	return ret;
531575e9461SMike Marshall }
532575e9461SMike Marshall 
533575e9461SMike Marshall void orangefs_make_bad_inode(struct inode *inode)
534575e9461SMike Marshall {
535575e9461SMike Marshall 	if (is_root_handle(inode)) {
536575e9461SMike Marshall 		/*
537575e9461SMike Marshall 		 * if this occurs, the pvfs2-client-core was killed but we
538575e9461SMike Marshall 		 * can't afford to lose the inode operations and such
539575e9461SMike Marshall 		 * associated with the root handle in any case.
540575e9461SMike Marshall 		 */
541575e9461SMike Marshall 		gossip_debug(GOSSIP_UTILS_DEBUG,
542575e9461SMike Marshall 			     "*** NOT making bad root inode %pU\n",
543575e9461SMike Marshall 			     get_khandle_from_ino(inode));
544575e9461SMike Marshall 	} else {
545575e9461SMike Marshall 		gossip_debug(GOSSIP_UTILS_DEBUG,
546575e9461SMike Marshall 			     "*** making bad inode %pU\n",
547575e9461SMike Marshall 			     get_khandle_from_ino(inode));
548575e9461SMike Marshall 		make_bad_inode(inode);
549575e9461SMike Marshall 	}
550575e9461SMike Marshall }
551575e9461SMike Marshall 
552575e9461SMike Marshall /*
553575e9461SMike Marshall  * The following is a very dirty hack that is now a permanent part of the
554575e9461SMike Marshall  * ORANGEFS protocol. See protocol.h for more error definitions.
555575e9461SMike Marshall  */
556575e9461SMike Marshall 
557575e9461SMike Marshall /* The order matches include/orangefs-types.h in the OrangeFS source. */
558575e9461SMike Marshall static int PINT_errno_mapping[] = {
559575e9461SMike Marshall 	0, EPERM, ENOENT, EINTR, EIO, ENXIO, EBADF, EAGAIN, ENOMEM,
560575e9461SMike Marshall 	EFAULT, EBUSY, EEXIST, ENODEV, ENOTDIR, EISDIR, EINVAL, EMFILE,
561575e9461SMike Marshall 	EFBIG, ENOSPC, EROFS, EMLINK, EPIPE, EDEADLK, ENAMETOOLONG,
562575e9461SMike Marshall 	ENOLCK, ENOSYS, ENOTEMPTY, ELOOP, EWOULDBLOCK, ENOMSG, EUNATCH,
563575e9461SMike Marshall 	EBADR, EDEADLOCK, ENODATA, ETIME, ENONET, EREMOTE, ECOMM,
564575e9461SMike Marshall 	EPROTO, EBADMSG, EOVERFLOW, ERESTART, EMSGSIZE, EPROTOTYPE,
565575e9461SMike Marshall 	ENOPROTOOPT, EPROTONOSUPPORT, EOPNOTSUPP, EADDRINUSE,
566575e9461SMike Marshall 	EADDRNOTAVAIL, ENETDOWN, ENETUNREACH, ENETRESET, ENOBUFS,
567575e9461SMike Marshall 	ETIMEDOUT, ECONNREFUSED, EHOSTDOWN, EHOSTUNREACH, EALREADY,
568575e9461SMike Marshall 	EACCES, ECONNRESET, ERANGE
569575e9461SMike Marshall };
570575e9461SMike Marshall 
571575e9461SMike Marshall int orangefs_normalize_to_errno(__s32 error_code)
572575e9461SMike Marshall {
573575e9461SMike Marshall 	__u32 i;
574575e9461SMike Marshall 
575575e9461SMike Marshall 	/* Success */
576575e9461SMike Marshall 	if (error_code == 0) {
577575e9461SMike Marshall 		return 0;
578575e9461SMike Marshall 	/*
579575e9461SMike Marshall 	 * This shouldn't ever happen. If it does it should be fixed on the
580575e9461SMike Marshall 	 * server.
581575e9461SMike Marshall 	 */
582575e9461SMike Marshall 	} else if (error_code > 0) {
583575e9461SMike Marshall 		gossip_err("orangefs: error status receieved.\n");
584575e9461SMike Marshall 		gossip_err("orangefs: assuming error code is inverted.\n");
585575e9461SMike Marshall 		error_code = -error_code;
586575e9461SMike Marshall 	}
587575e9461SMike Marshall 
588575e9461SMike Marshall 	/*
589575e9461SMike Marshall 	 * XXX: This is very bad since error codes from ORANGEFS may not be
590575e9461SMike Marshall 	 * suitable for return into userspace.
591575e9461SMike Marshall 	 */
592575e9461SMike Marshall 
593575e9461SMike Marshall 	/*
594575e9461SMike Marshall 	 * Convert ORANGEFS error values into errno values suitable for return
595575e9461SMike Marshall 	 * from the kernel.
596575e9461SMike Marshall 	 */
597575e9461SMike Marshall 	if ((-error_code) & ORANGEFS_NON_ERRNO_ERROR_BIT) {
598575e9461SMike Marshall 		if (((-error_code) &
599575e9461SMike Marshall 		    (ORANGEFS_ERROR_NUMBER_BITS|ORANGEFS_NON_ERRNO_ERROR_BIT|
600575e9461SMike Marshall 		    ORANGEFS_ERROR_BIT)) == ORANGEFS_ECANCEL) {
601575e9461SMike Marshall 			/*
602575e9461SMike Marshall 			 * cancellation error codes generally correspond to
603575e9461SMike Marshall 			 * a timeout from the client's perspective
604575e9461SMike Marshall 			 */
605575e9461SMike Marshall 			error_code = -ETIMEDOUT;
606575e9461SMike Marshall 		} else {
607575e9461SMike Marshall 			/* assume a default error code */
608575e9461SMike Marshall 			gossip_err("orangefs: warning: got error code without errno equivalent: %d.\n", error_code);
609575e9461SMike Marshall 			error_code = -EINVAL;
610575e9461SMike Marshall 		}
611575e9461SMike Marshall 
612575e9461SMike Marshall 	/* Convert ORANGEFS encoded errno values into regular errno values. */
613575e9461SMike Marshall 	} else if ((-error_code) & ORANGEFS_ERROR_BIT) {
614575e9461SMike Marshall 		i = (-error_code) & ~(ORANGEFS_ERROR_BIT|ORANGEFS_ERROR_CLASS_BITS);
615575e9461SMike Marshall 		if (i < sizeof(PINT_errno_mapping)/sizeof(*PINT_errno_mapping))
616575e9461SMike Marshall 			error_code = -PINT_errno_mapping[i];
617575e9461SMike Marshall 		else
618575e9461SMike Marshall 			error_code = -EINVAL;
619575e9461SMike Marshall 
620575e9461SMike Marshall 	/*
621575e9461SMike Marshall 	 * Only ORANGEFS protocol error codes should ever come here. Otherwise
622575e9461SMike Marshall 	 * there is a bug somewhere.
623575e9461SMike Marshall 	 */
624575e9461SMike Marshall 	} else {
625575e9461SMike Marshall 		gossip_err("orangefs: orangefs_normalize_to_errno: got error code which is not from ORANGEFS.\n");
626575e9461SMike Marshall 	}
627575e9461SMike Marshall 	return error_code;
628575e9461SMike Marshall }
629575e9461SMike Marshall 
630575e9461SMike Marshall #define NUM_MODES 11
631575e9461SMike Marshall __s32 ORANGEFS_util_translate_mode(int mode)
632575e9461SMike Marshall {
633575e9461SMike Marshall 	int ret = 0;
634575e9461SMike Marshall 	int i = 0;
635575e9461SMike Marshall 	static int modes[NUM_MODES] = {
636575e9461SMike Marshall 		S_IXOTH, S_IWOTH, S_IROTH,
637575e9461SMike Marshall 		S_IXGRP, S_IWGRP, S_IRGRP,
638575e9461SMike Marshall 		S_IXUSR, S_IWUSR, S_IRUSR,
639575e9461SMike Marshall 		S_ISGID, S_ISUID
640575e9461SMike Marshall 	};
641575e9461SMike Marshall 	static int orangefs_modes[NUM_MODES] = {
642575e9461SMike Marshall 		ORANGEFS_O_EXECUTE, ORANGEFS_O_WRITE, ORANGEFS_O_READ,
643575e9461SMike Marshall 		ORANGEFS_G_EXECUTE, ORANGEFS_G_WRITE, ORANGEFS_G_READ,
644575e9461SMike Marshall 		ORANGEFS_U_EXECUTE, ORANGEFS_U_WRITE, ORANGEFS_U_READ,
645575e9461SMike Marshall 		ORANGEFS_G_SGID, ORANGEFS_U_SUID
646575e9461SMike Marshall 	};
647575e9461SMike Marshall 
648575e9461SMike Marshall 	for (i = 0; i < NUM_MODES; i++)
649575e9461SMike Marshall 		if (mode & modes[i])
650575e9461SMike Marshall 			ret |= orangefs_modes[i];
651575e9461SMike Marshall 
652575e9461SMike Marshall 	return ret;
653575e9461SMike Marshall }
654575e9461SMike Marshall #undef NUM_MODES
655575e9461SMike Marshall 
656575e9461SMike Marshall /*
657575e9461SMike Marshall  * After obtaining a string representation of the client's debug
658575e9461SMike Marshall  * keywords and their associated masks, this function is called to build an
659575e9461SMike Marshall  * array of these values.
660575e9461SMike Marshall  */
661575e9461SMike Marshall int orangefs_prepare_cdm_array(char *debug_array_string)
662575e9461SMike Marshall {
663575e9461SMike Marshall 	int i;
664575e9461SMike Marshall 	int rc = -EINVAL;
665575e9461SMike Marshall 	char *cds_head = NULL;
666575e9461SMike Marshall 	char *cds_delimiter = NULL;
667575e9461SMike Marshall 	int keyword_len = 0;
668575e9461SMike Marshall 
669575e9461SMike Marshall 	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__);
670575e9461SMike Marshall 
671575e9461SMike Marshall 	/*
672575e9461SMike Marshall 	 * figure out how many elements the cdm_array needs.
673575e9461SMike Marshall 	 */
674575e9461SMike Marshall 	for (i = 0; i < strlen(debug_array_string); i++)
675575e9461SMike Marshall 		if (debug_array_string[i] == '\n')
676575e9461SMike Marshall 			cdm_element_count++;
677575e9461SMike Marshall 
678575e9461SMike Marshall 	if (!cdm_element_count) {
679575e9461SMike Marshall 		pr_info("No elements in client debug array string!\n");
680575e9461SMike Marshall 		goto out;
681575e9461SMike Marshall 	}
682575e9461SMike Marshall 
683575e9461SMike Marshall 	cdm_array =
684575e9461SMike Marshall 		kzalloc(cdm_element_count * sizeof(struct client_debug_mask),
685575e9461SMike Marshall 			GFP_KERNEL);
686575e9461SMike Marshall 	if (!cdm_array) {
687575e9461SMike Marshall 		pr_info("malloc failed for cdm_array!\n");
688575e9461SMike Marshall 		rc = -ENOMEM;
689575e9461SMike Marshall 		goto out;
690575e9461SMike Marshall 	}
691575e9461SMike Marshall 
692575e9461SMike Marshall 	cds_head = debug_array_string;
693575e9461SMike Marshall 
694575e9461SMike Marshall 	for (i = 0; i < cdm_element_count; i++) {
695575e9461SMike Marshall 		cds_delimiter = strchr(cds_head, '\n');
696575e9461SMike Marshall 		*cds_delimiter = '\0';
697575e9461SMike Marshall 
698575e9461SMike Marshall 		keyword_len = strcspn(cds_head, " ");
699575e9461SMike Marshall 
700575e9461SMike Marshall 		cdm_array[i].keyword = kzalloc(keyword_len + 1, GFP_KERNEL);
701575e9461SMike Marshall 		if (!cdm_array[i].keyword) {
702575e9461SMike Marshall 			rc = -ENOMEM;
703575e9461SMike Marshall 			goto out;
704575e9461SMike Marshall 		}
705575e9461SMike Marshall 
706575e9461SMike Marshall 		sscanf(cds_head,
707575e9461SMike Marshall 		       "%s %llx %llx",
708575e9461SMike Marshall 		       cdm_array[i].keyword,
709575e9461SMike Marshall 		       (unsigned long long *)&(cdm_array[i].mask1),
710575e9461SMike Marshall 		       (unsigned long long *)&(cdm_array[i].mask2));
711575e9461SMike Marshall 
712575e9461SMike Marshall 		if (!strcmp(cdm_array[i].keyword, ORANGEFS_VERBOSE))
713575e9461SMike Marshall 			client_verbose_index = i;
714575e9461SMike Marshall 
715575e9461SMike Marshall 		if (!strcmp(cdm_array[i].keyword, ORANGEFS_ALL))
716575e9461SMike Marshall 			client_all_index = i;
717575e9461SMike Marshall 
718575e9461SMike Marshall 		cds_head = cds_delimiter + 1;
719575e9461SMike Marshall 	}
720575e9461SMike Marshall 
721575e9461SMike Marshall 	rc = cdm_element_count;
722575e9461SMike Marshall 
723575e9461SMike Marshall 	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: rc:%d:\n", __func__, rc);
724575e9461SMike Marshall 
725575e9461SMike Marshall out:
726575e9461SMike Marshall 
727575e9461SMike Marshall 	return rc;
728575e9461SMike Marshall 
729575e9461SMike Marshall }
730575e9461SMike Marshall 
731575e9461SMike Marshall /*
732575e9461SMike Marshall  * /sys/kernel/debug/orangefs/debug-help can be catted to
733575e9461SMike Marshall  * see all the available kernel and client debug keywords.
734575e9461SMike Marshall  *
735575e9461SMike Marshall  * When the kernel boots, we have no idea what keywords the
736575e9461SMike Marshall  * client supports, nor their associated masks.
737575e9461SMike Marshall  *
738575e9461SMike Marshall  * We pass through this function once at boot and stamp a
739575e9461SMike Marshall  * boilerplate "we don't know" message for the client in the
740575e9461SMike Marshall  * debug-help file. We pass through here again when the client
741575e9461SMike Marshall  * starts and then we can fill out the debug-help file fully.
742575e9461SMike Marshall  *
743575e9461SMike Marshall  * The client might be restarted any number of times between
744575e9461SMike Marshall  * reboots, we only build the debug-help file the first time.
745575e9461SMike Marshall  */
746575e9461SMike Marshall int orangefs_prepare_debugfs_help_string(int at_boot)
747575e9461SMike Marshall {
748575e9461SMike Marshall 	int rc = -EINVAL;
749575e9461SMike Marshall 	int i;
750575e9461SMike Marshall 	int byte_count = 0;
751575e9461SMike Marshall 	char *client_title = "Client Debug Keywords:\n";
752575e9461SMike Marshall 	char *kernel_title = "Kernel Debug Keywords:\n";
753575e9461SMike Marshall 
754575e9461SMike Marshall 	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__);
755575e9461SMike Marshall 
756575e9461SMike Marshall 	if (at_boot) {
757575e9461SMike Marshall 		byte_count += strlen(HELP_STRING_UNINITIALIZED);
758575e9461SMike Marshall 		client_title = HELP_STRING_UNINITIALIZED;
759575e9461SMike Marshall 	} else {
760575e9461SMike Marshall 		/*
761575e9461SMike Marshall 		 * fill the client keyword/mask array and remember
762575e9461SMike Marshall 		 * how many elements there were.
763575e9461SMike Marshall 		 */
764575e9461SMike Marshall 		cdm_element_count =
765575e9461SMike Marshall 			orangefs_prepare_cdm_array(client_debug_array_string);
766575e9461SMike Marshall 		if (cdm_element_count <= 0)
767575e9461SMike Marshall 			goto out;
768575e9461SMike Marshall 
769575e9461SMike Marshall 		/* Count the bytes destined for debug_help_string. */
770575e9461SMike Marshall 		byte_count += strlen(client_title);
771575e9461SMike Marshall 
772575e9461SMike Marshall 		for (i = 0; i < cdm_element_count; i++) {
773575e9461SMike Marshall 			byte_count += strlen(cdm_array[i].keyword + 2);
774575e9461SMike Marshall 			if (byte_count >= DEBUG_HELP_STRING_SIZE) {
775575e9461SMike Marshall 				pr_info("%s: overflow 1!\n", __func__);
776575e9461SMike Marshall 				goto out;
777575e9461SMike Marshall 			}
778575e9461SMike Marshall 		}
779575e9461SMike Marshall 
780575e9461SMike Marshall 		gossip_debug(GOSSIP_UTILS_DEBUG,
781575e9461SMike Marshall 			     "%s: cdm_element_count:%d:\n",
782575e9461SMike Marshall 			     __func__,
783575e9461SMike Marshall 			     cdm_element_count);
784575e9461SMike Marshall 	}
785575e9461SMike Marshall 
786575e9461SMike Marshall 	byte_count += strlen(kernel_title);
787575e9461SMike Marshall 	for (i = 0; i < num_kmod_keyword_mask_map; i++) {
788575e9461SMike Marshall 		byte_count +=
789575e9461SMike Marshall 			strlen(s_kmod_keyword_mask_map[i].keyword + 2);
790575e9461SMike Marshall 		if (byte_count >= DEBUG_HELP_STRING_SIZE) {
791575e9461SMike Marshall 			pr_info("%s: overflow 2!\n", __func__);
792575e9461SMike Marshall 			goto out;
793575e9461SMike Marshall 		}
794575e9461SMike Marshall 	}
795575e9461SMike Marshall 
796575e9461SMike Marshall 	/* build debug_help_string. */
797575e9461SMike Marshall 	debug_help_string = kzalloc(DEBUG_HELP_STRING_SIZE, GFP_KERNEL);
798575e9461SMike Marshall 	if (!debug_help_string) {
799575e9461SMike Marshall 		rc = -ENOMEM;
800575e9461SMike Marshall 		goto out;
801575e9461SMike Marshall 	}
802575e9461SMike Marshall 
803575e9461SMike Marshall 	strcat(debug_help_string, client_title);
804575e9461SMike Marshall 
805575e9461SMike Marshall 	if (!at_boot) {
806575e9461SMike Marshall 		for (i = 0; i < cdm_element_count; i++) {
807575e9461SMike Marshall 			strcat(debug_help_string, "\t");
808575e9461SMike Marshall 			strcat(debug_help_string, cdm_array[i].keyword);
809575e9461SMike Marshall 			strcat(debug_help_string, "\n");
810575e9461SMike Marshall 		}
811575e9461SMike Marshall 	}
812575e9461SMike Marshall 
813575e9461SMike Marshall 	strcat(debug_help_string, "\n");
814575e9461SMike Marshall 	strcat(debug_help_string, kernel_title);
815575e9461SMike Marshall 
816575e9461SMike Marshall 	for (i = 0; i < num_kmod_keyword_mask_map; i++) {
817575e9461SMike Marshall 		strcat(debug_help_string, "\t");
818575e9461SMike Marshall 		strcat(debug_help_string, s_kmod_keyword_mask_map[i].keyword);
819575e9461SMike Marshall 		strcat(debug_help_string, "\n");
820575e9461SMike Marshall 	}
821575e9461SMike Marshall 
822575e9461SMike Marshall 	rc = 0;
823575e9461SMike Marshall 
824575e9461SMike Marshall out:
825575e9461SMike Marshall 
826575e9461SMike Marshall 	return rc;
827575e9461SMike Marshall 
828575e9461SMike Marshall }
829575e9461SMike Marshall 
830575e9461SMike Marshall /*
831575e9461SMike Marshall  * kernel = type 0
832575e9461SMike Marshall  * client = type 1
833575e9461SMike Marshall  */
834575e9461SMike Marshall void debug_mask_to_string(void *mask, int type)
835575e9461SMike Marshall {
836575e9461SMike Marshall 	int i;
837575e9461SMike Marshall 	int len = 0;
838575e9461SMike Marshall 	char *debug_string;
839575e9461SMike Marshall 	int element_count = 0;
840575e9461SMike Marshall 
841575e9461SMike Marshall 	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__);
842575e9461SMike Marshall 
843575e9461SMike Marshall 	if (type) {
844575e9461SMike Marshall 		debug_string = client_debug_string;
845575e9461SMike Marshall 		element_count = cdm_element_count;
846575e9461SMike Marshall 	} else {
847575e9461SMike Marshall 		debug_string = kernel_debug_string;
848575e9461SMike Marshall 		element_count = num_kmod_keyword_mask_map;
849575e9461SMike Marshall 	}
850575e9461SMike Marshall 
851575e9461SMike Marshall 	memset(debug_string, 0, ORANGEFS_MAX_DEBUG_STRING_LEN);
852575e9461SMike Marshall 
853575e9461SMike Marshall 	/*
854575e9461SMike Marshall 	 * Some keywords, like "all" or "verbose", are amalgams of
855575e9461SMike Marshall 	 * numerous other keywords. Make a special check for those
856575e9461SMike Marshall 	 * before grinding through the whole mask only to find out
857575e9461SMike Marshall 	 * later...
858575e9461SMike Marshall 	 */
859575e9461SMike Marshall 	if (check_amalgam_keyword(mask, type))
860575e9461SMike Marshall 		goto out;
861575e9461SMike Marshall 
862575e9461SMike Marshall 	/* Build the debug string. */
863575e9461SMike Marshall 	for (i = 0; i < element_count; i++)
864575e9461SMike Marshall 		if (type)
865575e9461SMike Marshall 			do_c_string(mask, i);
866575e9461SMike Marshall 		else
867575e9461SMike Marshall 			do_k_string(mask, i);
868575e9461SMike Marshall 
869575e9461SMike Marshall 	len = strlen(debug_string);
870575e9461SMike Marshall 
871575e9461SMike Marshall 	if ((len) && (type))
872575e9461SMike Marshall 		client_debug_string[len - 1] = '\0';
873575e9461SMike Marshall 	else if (len)
874575e9461SMike Marshall 		kernel_debug_string[len - 1] = '\0';
875575e9461SMike Marshall 	else if (type)
876575e9461SMike Marshall 		strcpy(client_debug_string, "none");
877575e9461SMike Marshall 	else
878575e9461SMike Marshall 		strcpy(kernel_debug_string, "none");
879575e9461SMike Marshall 
880575e9461SMike Marshall out:
881575e9461SMike Marshall gossip_debug(GOSSIP_UTILS_DEBUG, "%s: string:%s:\n", __func__, debug_string);
882575e9461SMike Marshall 
883575e9461SMike Marshall 	return;
884575e9461SMike Marshall 
885575e9461SMike Marshall }
886575e9461SMike Marshall 
887575e9461SMike Marshall void do_k_string(void *k_mask, int index)
888575e9461SMike Marshall {
889575e9461SMike Marshall 	__u64 *mask = (__u64 *) k_mask;
890575e9461SMike Marshall 
891575e9461SMike Marshall 	if (keyword_is_amalgam((char *) s_kmod_keyword_mask_map[index].keyword))
892575e9461SMike Marshall 		goto out;
893575e9461SMike Marshall 
894575e9461SMike Marshall 	if (*mask & s_kmod_keyword_mask_map[index].mask_val) {
895575e9461SMike Marshall 		if ((strlen(kernel_debug_string) +
896575e9461SMike Marshall 		     strlen(s_kmod_keyword_mask_map[index].keyword))
897575e9461SMike Marshall 			< ORANGEFS_MAX_DEBUG_STRING_LEN - 1) {
898575e9461SMike Marshall 				strcat(kernel_debug_string,
899575e9461SMike Marshall 				       s_kmod_keyword_mask_map[index].keyword);
900575e9461SMike Marshall 				strcat(kernel_debug_string, ",");
901575e9461SMike Marshall 			} else {
902575e9461SMike Marshall 				gossip_err("%s: overflow!\n", __func__);
903575e9461SMike Marshall 				strcpy(kernel_debug_string, ORANGEFS_ALL);
904575e9461SMike Marshall 				goto out;
905575e9461SMike Marshall 			}
906575e9461SMike Marshall 	}
907575e9461SMike Marshall 
908575e9461SMike Marshall out:
909575e9461SMike Marshall 
910575e9461SMike Marshall 	return;
911575e9461SMike Marshall }
912575e9461SMike Marshall 
913575e9461SMike Marshall void do_c_string(void *c_mask, int index)
914575e9461SMike Marshall {
915575e9461SMike Marshall 	struct client_debug_mask *mask = (struct client_debug_mask *) c_mask;
916575e9461SMike Marshall 
917575e9461SMike Marshall 	if (keyword_is_amalgam(cdm_array[index].keyword))
918575e9461SMike Marshall 		goto out;
919575e9461SMike Marshall 
920575e9461SMike Marshall 	if ((mask->mask1 & cdm_array[index].mask1) ||
921575e9461SMike Marshall 	    (mask->mask2 & cdm_array[index].mask2)) {
922575e9461SMike Marshall 		if ((strlen(client_debug_string) +
923575e9461SMike Marshall 		     strlen(cdm_array[index].keyword) + 1)
924575e9461SMike Marshall 			< ORANGEFS_MAX_DEBUG_STRING_LEN - 2) {
925575e9461SMike Marshall 				strcat(client_debug_string,
926575e9461SMike Marshall 				       cdm_array[index].keyword);
927575e9461SMike Marshall 				strcat(client_debug_string, ",");
928575e9461SMike Marshall 			} else {
929575e9461SMike Marshall 				gossip_err("%s: overflow!\n", __func__);
930575e9461SMike Marshall 				strcpy(client_debug_string, ORANGEFS_ALL);
931575e9461SMike Marshall 				goto out;
932575e9461SMike Marshall 			}
933575e9461SMike Marshall 	}
934575e9461SMike Marshall out:
935575e9461SMike Marshall 	return;
936575e9461SMike Marshall }
937575e9461SMike Marshall 
938575e9461SMike Marshall int keyword_is_amalgam(char *keyword)
939575e9461SMike Marshall {
940575e9461SMike Marshall 	int rc = 0;
941575e9461SMike Marshall 
942575e9461SMike Marshall 	if ((!strcmp(keyword, ORANGEFS_ALL)) || (!strcmp(keyword, ORANGEFS_VERBOSE)))
943575e9461SMike Marshall 		rc = 1;
944575e9461SMike Marshall 
945575e9461SMike Marshall 	return rc;
946575e9461SMike Marshall }
947575e9461SMike Marshall 
948575e9461SMike Marshall /*
949575e9461SMike Marshall  * kernel = type 0
950575e9461SMike Marshall  * client = type 1
951575e9461SMike Marshall  *
952575e9461SMike Marshall  * return 1 if we found an amalgam.
953575e9461SMike Marshall  */
954575e9461SMike Marshall int check_amalgam_keyword(void *mask, int type)
955575e9461SMike Marshall {
956575e9461SMike Marshall 	__u64 *k_mask;
957575e9461SMike Marshall 	struct client_debug_mask *c_mask;
958575e9461SMike Marshall 	int k_all_index = num_kmod_keyword_mask_map - 1;
959575e9461SMike Marshall 	int rc = 0;
960575e9461SMike Marshall 
961575e9461SMike Marshall 	if (type) {
962575e9461SMike Marshall 		c_mask = (struct client_debug_mask *) mask;
963575e9461SMike Marshall 
964575e9461SMike Marshall 		if ((c_mask->mask1 == cdm_array[client_all_index].mask1) &&
965575e9461SMike Marshall 		    (c_mask->mask2 == cdm_array[client_all_index].mask2)) {
966575e9461SMike Marshall 			strcpy(client_debug_string, ORANGEFS_ALL);
967575e9461SMike Marshall 			rc = 1;
968575e9461SMike Marshall 			goto out;
969575e9461SMike Marshall 		}
970575e9461SMike Marshall 
971575e9461SMike Marshall 		if ((c_mask->mask1 == cdm_array[client_verbose_index].mask1) &&
972575e9461SMike Marshall 		    (c_mask->mask2 == cdm_array[client_verbose_index].mask2)) {
973575e9461SMike Marshall 			strcpy(client_debug_string, ORANGEFS_VERBOSE);
974575e9461SMike Marshall 			rc = 1;
975575e9461SMike Marshall 			goto out;
976575e9461SMike Marshall 		}
977575e9461SMike Marshall 
978575e9461SMike Marshall 	} else {
979575e9461SMike Marshall 		k_mask = (__u64 *) mask;
980575e9461SMike Marshall 
981575e9461SMike Marshall 		if (*k_mask >= s_kmod_keyword_mask_map[k_all_index].mask_val) {
982575e9461SMike Marshall 			strcpy(kernel_debug_string, ORANGEFS_ALL);
983575e9461SMike Marshall 			rc = 1;
984575e9461SMike Marshall 			goto out;
985575e9461SMike Marshall 		}
986575e9461SMike Marshall 	}
987575e9461SMike Marshall 
988575e9461SMike Marshall out:
989575e9461SMike Marshall 
990575e9461SMike Marshall 	return rc;
991575e9461SMike Marshall }
992575e9461SMike Marshall 
993575e9461SMike Marshall /*
994575e9461SMike Marshall  * kernel = type 0
995575e9461SMike Marshall  * client = type 1
996575e9461SMike Marshall  */
997575e9461SMike Marshall void debug_string_to_mask(char *debug_string, void *mask, int type)
998575e9461SMike Marshall {
999575e9461SMike Marshall 	char *unchecked_keyword;
1000575e9461SMike Marshall 	int i;
1001575e9461SMike Marshall 	char *strsep_fodder = kstrdup(debug_string, GFP_KERNEL);
1002575e9461SMike Marshall 	char *original_pointer;
1003575e9461SMike Marshall 	int element_count = 0;
1004575e9461SMike Marshall 	struct client_debug_mask *c_mask;
1005575e9461SMike Marshall 	__u64 *k_mask;
1006575e9461SMike Marshall 
1007575e9461SMike Marshall 	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__);
1008575e9461SMike Marshall 
1009575e9461SMike Marshall 	if (type) {
1010575e9461SMike Marshall 		c_mask = (struct client_debug_mask *)mask;
1011575e9461SMike Marshall 		element_count = cdm_element_count;
1012575e9461SMike Marshall 	} else {
1013575e9461SMike Marshall 		k_mask = (__u64 *)mask;
1014575e9461SMike Marshall 		*k_mask = 0;
1015575e9461SMike Marshall 		element_count = num_kmod_keyword_mask_map;
1016575e9461SMike Marshall 	}
1017575e9461SMike Marshall 
1018575e9461SMike Marshall 	original_pointer = strsep_fodder;
1019575e9461SMike Marshall 	while ((unchecked_keyword = strsep(&strsep_fodder, ",")))
1020575e9461SMike Marshall 		if (strlen(unchecked_keyword)) {
1021575e9461SMike Marshall 			for (i = 0; i < element_count; i++)
1022575e9461SMike Marshall 				if (type)
1023575e9461SMike Marshall 					do_c_mask(i,
1024575e9461SMike Marshall 						  unchecked_keyword,
1025575e9461SMike Marshall 						  &c_mask);
1026575e9461SMike Marshall 				else
1027575e9461SMike Marshall 					do_k_mask(i,
1028575e9461SMike Marshall 						  unchecked_keyword,
1029575e9461SMike Marshall 						  &k_mask);
1030575e9461SMike Marshall 		}
1031575e9461SMike Marshall 
1032575e9461SMike Marshall 	kfree(original_pointer);
1033575e9461SMike Marshall }
1034575e9461SMike Marshall 
1035575e9461SMike Marshall void do_c_mask(int i,
1036575e9461SMike Marshall 	       char *unchecked_keyword,
1037575e9461SMike Marshall 	       struct client_debug_mask **sane_mask)
1038575e9461SMike Marshall {
1039575e9461SMike Marshall 
1040575e9461SMike Marshall 	if (!strcmp(cdm_array[i].keyword, unchecked_keyword)) {
1041575e9461SMike Marshall 		(**sane_mask).mask1 = (**sane_mask).mask1 | cdm_array[i].mask1;
1042575e9461SMike Marshall 		(**sane_mask).mask2 = (**sane_mask).mask2 | cdm_array[i].mask2;
1043575e9461SMike Marshall 	}
1044575e9461SMike Marshall }
1045575e9461SMike Marshall 
1046575e9461SMike Marshall void do_k_mask(int i, char *unchecked_keyword, __u64 **sane_mask)
1047575e9461SMike Marshall {
1048575e9461SMike Marshall 
1049575e9461SMike Marshall 	if (!strcmp(s_kmod_keyword_mask_map[i].keyword, unchecked_keyword))
1050575e9461SMike Marshall 		**sane_mask = (**sane_mask) |
1051575e9461SMike Marshall 				s_kmod_keyword_mask_map[i].mask_val;
1052575e9461SMike Marshall }
1053