xref: /openbmc/linux/fs/orangefs/xattr.c (revision 0c95c025)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21182fca3SMike Marshall /*
31182fca3SMike Marshall  * (C) 2001 Clemson University and The University of Chicago
4fc2e2e9cSMartin Brandenburg  * Copyright 2018 Omnibond Systems, L.L.C.
51182fca3SMike Marshall  *
61182fca3SMike Marshall  * See COPYING in top-level directory.
71182fca3SMike Marshall  */
81182fca3SMike Marshall 
91182fca3SMike Marshall /*
101182fca3SMike Marshall  *  Linux VFS extended attribute operations.
111182fca3SMike Marshall  */
121182fca3SMike Marshall 
131182fca3SMike Marshall #include "protocol.h"
14575e9461SMike Marshall #include "orangefs-kernel.h"
15575e9461SMike Marshall #include "orangefs-bufmap.h"
161182fca3SMike Marshall #include <linux/posix_acl_xattr.h>
171182fca3SMike Marshall #include <linux/xattr.h>
18fc2e2e9cSMartin Brandenburg #include <linux/hashtable.h>
191182fca3SMike Marshall 
208bb8aefdSYi Liu #define SYSTEM_ORANGEFS_KEY "system.pvfs2."
218bb8aefdSYi Liu #define SYSTEM_ORANGEFS_KEY_LEN 13
221182fca3SMike Marshall 
231182fca3SMike Marshall /*
241182fca3SMike Marshall  * this function returns
251182fca3SMike Marshall  *   0 if the key corresponding to name is not meant to be printed as part
261182fca3SMike Marshall  *     of a listxattr.
271182fca3SMike Marshall  *   1 if the key corresponding to name is meant to be returned as part of
281182fca3SMike Marshall  *     a listxattr.
298bb8aefdSYi Liu  * The ones that start SYSTEM_ORANGEFS_KEY are the ones to avoid printing.
301182fca3SMike Marshall  */
is_reserved_key(const char * key,size_t size)311182fca3SMike Marshall static int is_reserved_key(const char *key, size_t size)
321182fca3SMike Marshall {
331182fca3SMike Marshall 
348bb8aefdSYi Liu 	if (size < SYSTEM_ORANGEFS_KEY_LEN)
351182fca3SMike Marshall 		return 1;
361182fca3SMike Marshall 
378bb8aefdSYi Liu 	return strncmp(key, SYSTEM_ORANGEFS_KEY, SYSTEM_ORANGEFS_KEY_LEN) ?  1 : 0;
381182fca3SMike Marshall }
391182fca3SMike Marshall 
convert_to_internal_xattr_flags(int setxattr_flags)401182fca3SMike Marshall static inline int convert_to_internal_xattr_flags(int setxattr_flags)
411182fca3SMike Marshall {
421182fca3SMike Marshall 	int internal_flag = 0;
431182fca3SMike Marshall 
441182fca3SMike Marshall 	if (setxattr_flags & XATTR_REPLACE) {
451182fca3SMike Marshall 		/* Attribute must exist! */
468bb8aefdSYi Liu 		internal_flag = ORANGEFS_XATTR_REPLACE;
471182fca3SMike Marshall 	} else if (setxattr_flags & XATTR_CREATE) {
481182fca3SMike Marshall 		/* Attribute must not exist */
498bb8aefdSYi Liu 		internal_flag = ORANGEFS_XATTR_CREATE;
501182fca3SMike Marshall 	}
511182fca3SMike Marshall 	return internal_flag;
521182fca3SMike Marshall }
531182fca3SMike Marshall 
xattr_key(const char * key)54fc2e2e9cSMartin Brandenburg static unsigned int xattr_key(const char *key)
55fc2e2e9cSMartin Brandenburg {
56fc2e2e9cSMartin Brandenburg 	unsigned int i = 0;
57fc2e2e9cSMartin Brandenburg 	while (key)
58fc2e2e9cSMartin Brandenburg 		i += *key++;
59fc2e2e9cSMartin Brandenburg 	return i % 16;
60fc2e2e9cSMartin Brandenburg }
61fc2e2e9cSMartin Brandenburg 
find_cached_xattr(struct inode * inode,const char * key)62fc2e2e9cSMartin Brandenburg static struct orangefs_cached_xattr *find_cached_xattr(struct inode *inode,
63fc2e2e9cSMartin Brandenburg     const char *key)
64fc2e2e9cSMartin Brandenburg {
65fc2e2e9cSMartin Brandenburg 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
66fc2e2e9cSMartin Brandenburg 	struct orangefs_cached_xattr *cx;
67fc2e2e9cSMartin Brandenburg 	struct hlist_head *h;
68fc2e2e9cSMartin Brandenburg 	struct hlist_node *tmp;
69fc2e2e9cSMartin Brandenburg 	h = &orangefs_inode->xattr_cache[xattr_key(key)];
70fc2e2e9cSMartin Brandenburg 	if (hlist_empty(h))
71fc2e2e9cSMartin Brandenburg 		return NULL;
72fc2e2e9cSMartin Brandenburg 	hlist_for_each_entry_safe(cx, tmp, h, node) {
73fc2e2e9cSMartin Brandenburg /*		if (!time_before(jiffies, cx->timeout)) {
74fc2e2e9cSMartin Brandenburg 			hlist_del(&cx->node);
75fc2e2e9cSMartin Brandenburg 			kfree(cx);
76fc2e2e9cSMartin Brandenburg 			continue;
77fc2e2e9cSMartin Brandenburg 		}*/
78fc2e2e9cSMartin Brandenburg 		if (!strcmp(cx->key, key))
79fc2e2e9cSMartin Brandenburg 			return cx;
80fc2e2e9cSMartin Brandenburg 	}
81fc2e2e9cSMartin Brandenburg 	return NULL;
82fc2e2e9cSMartin Brandenburg }
831182fca3SMike Marshall 
841182fca3SMike Marshall /*
851182fca3SMike Marshall  * Tries to get a specified key's attributes of a given
861182fca3SMike Marshall  * file into a user-specified buffer. Note that the getxattr
871182fca3SMike Marshall  * interface allows for the users to probe the size of an
881182fca3SMike Marshall  * extended attribute by passing in a value of 0 to size.
891182fca3SMike Marshall  * Thus our return value is always the size of the attribute
901182fca3SMike Marshall  * unless the key does not exist for the file and/or if
911182fca3SMike Marshall  * there were errors in fetching the attribute value.
921182fca3SMike Marshall  */
orangefs_inode_getxattr(struct inode * inode,const char * name,void * buffer,size_t size)93d373a712SAndreas Gruenbacher ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name,
94d373a712SAndreas Gruenbacher 				void *buffer, size_t size)
951182fca3SMike Marshall {
968bb8aefdSYi Liu 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
978bb8aefdSYi Liu 	struct orangefs_kernel_op_s *new_op = NULL;
98fc2e2e9cSMartin Brandenburg 	struct orangefs_cached_xattr *cx;
991182fca3SMike Marshall 	ssize_t ret = -ENOMEM;
1001182fca3SMike Marshall 	ssize_t length = 0;
1011182fca3SMike Marshall 	int fsuid;
1021182fca3SMike Marshall 	int fsgid;
1031182fca3SMike Marshall 
1041182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
105d373a712SAndreas Gruenbacher 		     "%s: name %s, buffer_size %zd\n",
106d373a712SAndreas Gruenbacher 		     __func__, name, size);
1071182fca3SMike Marshall 
1086c6ef9f2SAndreas Gruenbacher 	if (S_ISLNK(inode->i_mode))
1096c6ef9f2SAndreas Gruenbacher 		return -EOPNOTSUPP;
1106c6ef9f2SAndreas Gruenbacher 
1115f13e587SDan Carpenter 	if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN)
1121182fca3SMike Marshall 		return -EINVAL;
1131182fca3SMike Marshall 
11478fee0b6SJann Horn 	fsuid = from_kuid(&init_user_ns, current_fsuid());
11578fee0b6SJann Horn 	fsgid = from_kgid(&init_user_ns, current_fsgid());
1161182fca3SMike Marshall 
1171182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
1181182fca3SMike Marshall 		     "getxattr on inode %pU, name %s "
1191182fca3SMike Marshall 		     "(uid %o, gid %o)\n",
1201182fca3SMike Marshall 		     get_khandle_from_ino(inode),
1211182fca3SMike Marshall 		     name,
1221182fca3SMike Marshall 		     fsuid,
1231182fca3SMike Marshall 		     fsgid);
1241182fca3SMike Marshall 
1258bb8aefdSYi Liu 	down_read(&orangefs_inode->xattr_sem);
1261182fca3SMike Marshall 
127fc2e2e9cSMartin Brandenburg 	cx = find_cached_xattr(inode, name);
128fc2e2e9cSMartin Brandenburg 	if (cx && time_before(jiffies, cx->timeout)) {
129fc2e2e9cSMartin Brandenburg 		if (cx->length == -1) {
130fc2e2e9cSMartin Brandenburg 			ret = -ENODATA;
131fc2e2e9cSMartin Brandenburg 			goto out_unlock;
132fc2e2e9cSMartin Brandenburg 		} else {
133fc2e2e9cSMartin Brandenburg 			if (size == 0) {
134fc2e2e9cSMartin Brandenburg 				ret = cx->length;
135fc2e2e9cSMartin Brandenburg 				goto out_unlock;
136fc2e2e9cSMartin Brandenburg 			}
137fc2e2e9cSMartin Brandenburg 			if (cx->length > size) {
138fc2e2e9cSMartin Brandenburg 				ret = -ERANGE;
139fc2e2e9cSMartin Brandenburg 				goto out_unlock;
140fc2e2e9cSMartin Brandenburg 			}
141fc2e2e9cSMartin Brandenburg 			memcpy(buffer, cx->val, cx->length);
142fc2e2e9cSMartin Brandenburg 			memset(buffer + cx->length, 0, size - cx->length);
143fc2e2e9cSMartin Brandenburg 			ret = cx->length;
144fc2e2e9cSMartin Brandenburg 			goto out_unlock;
145fc2e2e9cSMartin Brandenburg 		}
146fc2e2e9cSMartin Brandenburg 	}
147fc2e2e9cSMartin Brandenburg 
1488bb8aefdSYi Liu 	new_op = op_alloc(ORANGEFS_VFS_OP_GETXATTR);
1491182fca3SMike Marshall 	if (!new_op)
1501182fca3SMike Marshall 		goto out_unlock;
1511182fca3SMike Marshall 
1528bb8aefdSYi Liu 	new_op->upcall.req.getxattr.refn = orangefs_inode->refn;
153d373a712SAndreas Gruenbacher 	strcpy(new_op->upcall.req.getxattr.key, name);
1541182fca3SMike Marshall 
1551182fca3SMike Marshall 	/*
1561182fca3SMike Marshall 	 * NOTE: Although keys are meant to be NULL terminated textual
1571182fca3SMike Marshall 	 * strings, I am going to explicitly pass the length just in case
1581182fca3SMike Marshall 	 * we change this later on...
1591182fca3SMike Marshall 	 */
160d373a712SAndreas Gruenbacher 	new_op->upcall.req.getxattr.key_sz = strlen(name) + 1;
1611182fca3SMike Marshall 
1628bb8aefdSYi Liu 	ret = service_operation(new_op, "orangefs_inode_getxattr",
1631182fca3SMike Marshall 				get_interruptible_flag(inode));
1641182fca3SMike Marshall 	if (ret != 0) {
1651182fca3SMike Marshall 		if (ret == -ENOENT) {
1661182fca3SMike Marshall 			ret = -ENODATA;
1671182fca3SMike Marshall 			gossip_debug(GOSSIP_XATTR_DEBUG,
1688bb8aefdSYi Liu 				     "orangefs_inode_getxattr: inode %pU key %s"
1691182fca3SMike Marshall 				     " does not exist!\n",
1701182fca3SMike Marshall 				     get_khandle_from_ino(inode),
1711182fca3SMike Marshall 				     (char *)new_op->upcall.req.getxattr.key);
172fc2e2e9cSMartin Brandenburg 			cx = kmalloc(sizeof *cx, GFP_KERNEL);
173fc2e2e9cSMartin Brandenburg 			if (cx) {
174fc2e2e9cSMartin Brandenburg 				strcpy(cx->key, name);
175fc2e2e9cSMartin Brandenburg 				cx->length = -1;
176fc2e2e9cSMartin Brandenburg 				cx->timeout = jiffies +
177fc2e2e9cSMartin Brandenburg 				    orangefs_getattr_timeout_msecs*HZ/1000;
178fc2e2e9cSMartin Brandenburg 				hash_add(orangefs_inode->xattr_cache, &cx->node,
179fc2e2e9cSMartin Brandenburg 				    xattr_key(cx->key));
180fc2e2e9cSMartin Brandenburg 			}
1811182fca3SMike Marshall 		}
1821182fca3SMike Marshall 		goto out_release_op;
1831182fca3SMike Marshall 	}
1841182fca3SMike Marshall 
1851182fca3SMike Marshall 	/*
1861182fca3SMike Marshall 	 * Length returned includes null terminator.
1871182fca3SMike Marshall 	 */
1881182fca3SMike Marshall 	length = new_op->downcall.resp.getxattr.val_sz;
1891182fca3SMike Marshall 
1901182fca3SMike Marshall 	/*
1911182fca3SMike Marshall 	 * Just return the length of the queried attribute.
1921182fca3SMike Marshall 	 */
1931182fca3SMike Marshall 	if (size == 0) {
1941182fca3SMike Marshall 		ret = length;
1951182fca3SMike Marshall 		goto out_release_op;
1961182fca3SMike Marshall 	}
1971182fca3SMike Marshall 
1981182fca3SMike Marshall 	/*
1991182fca3SMike Marshall 	 * Check to see if key length is > provided buffer size.
2001182fca3SMike Marshall 	 */
2011182fca3SMike Marshall 	if (length > size) {
2021182fca3SMike Marshall 		ret = -ERANGE;
2031182fca3SMike Marshall 		goto out_release_op;
2041182fca3SMike Marshall 	}
2051182fca3SMike Marshall 
2061182fca3SMike Marshall 	memcpy(buffer, new_op->downcall.resp.getxattr.val, length);
207a9bb3ba8SMike Marshall 	memset(buffer + length, 0, size - length);
2081182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
2098bb8aefdSYi Liu 	     "orangefs_inode_getxattr: inode %pU "
2101182fca3SMike Marshall 	     "key %s key_sz %d, val_len %d\n",
2111182fca3SMike Marshall 	     get_khandle_from_ino(inode),
2121182fca3SMike Marshall 	     (char *)new_op->
2131182fca3SMike Marshall 		upcall.req.getxattr.key,
2141182fca3SMike Marshall 		     (int)new_op->
2151182fca3SMike Marshall 		upcall.req.getxattr.key_sz,
2161182fca3SMike Marshall 	     (int)ret);
2171182fca3SMike Marshall 
2181182fca3SMike Marshall 	ret = length;
2191182fca3SMike Marshall 
220fc2e2e9cSMartin Brandenburg 	if (cx) {
221fc2e2e9cSMartin Brandenburg 		strcpy(cx->key, name);
222fc2e2e9cSMartin Brandenburg 		memcpy(cx->val, buffer, length);
223fc2e2e9cSMartin Brandenburg 		cx->length = length;
224fc2e2e9cSMartin Brandenburg 		cx->timeout = jiffies + HZ;
225fc2e2e9cSMartin Brandenburg 	} else {
226fc2e2e9cSMartin Brandenburg 		cx = kmalloc(sizeof *cx, GFP_KERNEL);
227fc2e2e9cSMartin Brandenburg 		if (cx) {
228fc2e2e9cSMartin Brandenburg 			strcpy(cx->key, name);
229fc2e2e9cSMartin Brandenburg 			memcpy(cx->val, buffer, length);
230fc2e2e9cSMartin Brandenburg 			cx->length = length;
231fc2e2e9cSMartin Brandenburg 			cx->timeout = jiffies + HZ;
232fc2e2e9cSMartin Brandenburg 			hash_add(orangefs_inode->xattr_cache, &cx->node,
233fc2e2e9cSMartin Brandenburg 			    xattr_key(cx->key));
234fc2e2e9cSMartin Brandenburg 		}
235fc2e2e9cSMartin Brandenburg 	}
236fc2e2e9cSMartin Brandenburg 
2371182fca3SMike Marshall out_release_op:
2381182fca3SMike Marshall 	op_release(new_op);
2391182fca3SMike Marshall out_unlock:
2408bb8aefdSYi Liu 	up_read(&orangefs_inode->xattr_sem);
2411182fca3SMike Marshall 	return ret;
2421182fca3SMike Marshall }
2431182fca3SMike Marshall 
orangefs_inode_removexattr(struct inode * inode,const char * name,int flags)244d373a712SAndreas Gruenbacher static int orangefs_inode_removexattr(struct inode *inode, const char *name,
2451182fca3SMike Marshall 				      int flags)
2461182fca3SMike Marshall {
2478bb8aefdSYi Liu 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
2488bb8aefdSYi Liu 	struct orangefs_kernel_op_s *new_op = NULL;
249fc2e2e9cSMartin Brandenburg 	struct orangefs_cached_xattr *cx;
250fc2e2e9cSMartin Brandenburg 	struct hlist_head *h;
251fc2e2e9cSMartin Brandenburg 	struct hlist_node *tmp;
2521182fca3SMike Marshall 	int ret = -ENOMEM;
2531182fca3SMike Marshall 
2545f13e587SDan Carpenter 	if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN)
255e675c5ecSMartin Brandenburg 		return -EINVAL;
256e675c5ecSMartin Brandenburg 
2578bb8aefdSYi Liu 	down_write(&orangefs_inode->xattr_sem);
2588bb8aefdSYi Liu 	new_op = op_alloc(ORANGEFS_VFS_OP_REMOVEXATTR);
2591182fca3SMike Marshall 	if (!new_op)
2601182fca3SMike Marshall 		goto out_unlock;
2611182fca3SMike Marshall 
2628bb8aefdSYi Liu 	new_op->upcall.req.removexattr.refn = orangefs_inode->refn;
2631182fca3SMike Marshall 	/*
2641182fca3SMike Marshall 	 * NOTE: Although keys are meant to be NULL terminated
2651182fca3SMike Marshall 	 * textual strings, I am going to explicitly pass the
2661182fca3SMike Marshall 	 * length just in case we change this later on...
2671182fca3SMike Marshall 	 */
268d373a712SAndreas Gruenbacher 	strcpy(new_op->upcall.req.removexattr.key, name);
269d373a712SAndreas Gruenbacher 	new_op->upcall.req.removexattr.key_sz = strlen(name) + 1;
2701182fca3SMike Marshall 
2711182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
2728bb8aefdSYi Liu 		     "orangefs_inode_removexattr: key %s, key_sz %d\n",
2731182fca3SMike Marshall 		     (char *)new_op->upcall.req.removexattr.key,
2741182fca3SMike Marshall 		     (int)new_op->upcall.req.removexattr.key_sz);
2751182fca3SMike Marshall 
2761182fca3SMike Marshall 	ret = service_operation(new_op,
2778bb8aefdSYi Liu 				"orangefs_inode_removexattr",
2781182fca3SMike Marshall 				get_interruptible_flag(inode));
2791182fca3SMike Marshall 	if (ret == -ENOENT) {
2801182fca3SMike Marshall 		/*
2811182fca3SMike Marshall 		 * Request to replace a non-existent attribute is an error.
2821182fca3SMike Marshall 		 */
2831182fca3SMike Marshall 		if (flags & XATTR_REPLACE)
2841182fca3SMike Marshall 			ret = -ENODATA;
2851182fca3SMike Marshall 		else
2861182fca3SMike Marshall 			ret = 0;
2871182fca3SMike Marshall 	}
2881182fca3SMike Marshall 
2891182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
2908bb8aefdSYi Liu 		     "orangefs_inode_removexattr: returning %d\n", ret);
2911182fca3SMike Marshall 
2921182fca3SMike Marshall 	op_release(new_op);
293fc2e2e9cSMartin Brandenburg 
294fc2e2e9cSMartin Brandenburg 	h = &orangefs_inode->xattr_cache[xattr_key(name)];
295fc2e2e9cSMartin Brandenburg 	hlist_for_each_entry_safe(cx, tmp, h, node) {
296fc2e2e9cSMartin Brandenburg 		if (!strcmp(cx->key, name)) {
297fc2e2e9cSMartin Brandenburg 			hlist_del(&cx->node);
298fc2e2e9cSMartin Brandenburg 			kfree(cx);
299fc2e2e9cSMartin Brandenburg 			break;
300fc2e2e9cSMartin Brandenburg 		}
301fc2e2e9cSMartin Brandenburg 	}
302fc2e2e9cSMartin Brandenburg 
3031182fca3SMike Marshall out_unlock:
3048bb8aefdSYi Liu 	up_write(&orangefs_inode->xattr_sem);
3051182fca3SMike Marshall 	return ret;
3061182fca3SMike Marshall }
3071182fca3SMike Marshall 
3081182fca3SMike Marshall /*
3091182fca3SMike Marshall  * Tries to set an attribute for a given key on a file.
3101182fca3SMike Marshall  *
3111182fca3SMike Marshall  * Returns a -ve number on error and 0 on success.  Key is text, but value
3121182fca3SMike Marshall  * can be binary!
3131182fca3SMike Marshall  */
orangefs_inode_setxattr(struct inode * inode,const char * name,const void * value,size_t size,int flags)314d373a712SAndreas Gruenbacher int orangefs_inode_setxattr(struct inode *inode, const char *name,
315d373a712SAndreas Gruenbacher 			    const void *value, size_t size, int flags)
3161182fca3SMike Marshall {
3178bb8aefdSYi Liu 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
3188bb8aefdSYi Liu 	struct orangefs_kernel_op_s *new_op;
3191182fca3SMike Marshall 	int internal_flag = 0;
320fc2e2e9cSMartin Brandenburg 	struct orangefs_cached_xattr *cx;
321fc2e2e9cSMartin Brandenburg 	struct hlist_head *h;
322fc2e2e9cSMartin Brandenburg 	struct hlist_node *tmp;
3231182fca3SMike Marshall 	int ret = -ENOMEM;
3241182fca3SMike Marshall 
3251182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
326d373a712SAndreas Gruenbacher 		     "%s: name %s, buffer_size %zd\n",
327d373a712SAndreas Gruenbacher 		     __func__, name, size);
3281182fca3SMike Marshall 
329e675c5ecSMartin Brandenburg 	if (size > ORANGEFS_MAX_XATTR_VALUELEN)
3301182fca3SMike Marshall 		return -EINVAL;
3315f13e587SDan Carpenter 	if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN)
332e675c5ecSMartin Brandenburg 		return -EINVAL;
3331182fca3SMike Marshall 
3341182fca3SMike Marshall 	internal_flag = convert_to_internal_xattr_flags(flags);
3351182fca3SMike Marshall 
3361182fca3SMike Marshall 	/* This is equivalent to a removexattr */
3370b08273cSMarkus Elfring 	if (size == 0 && !value) {
3381182fca3SMike Marshall 		gossip_debug(GOSSIP_XATTR_DEBUG,
339d373a712SAndreas Gruenbacher 			     "removing xattr (%s)\n",
3401182fca3SMike Marshall 			     name);
341d373a712SAndreas Gruenbacher 		return orangefs_inode_removexattr(inode, name, flags);
3421182fca3SMike Marshall 	}
3431182fca3SMike Marshall 
3441182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
3451182fca3SMike Marshall 		     "setxattr on inode %pU, name %s\n",
3461182fca3SMike Marshall 		     get_khandle_from_ino(inode),
3471182fca3SMike Marshall 		     name);
3481182fca3SMike Marshall 
3498bb8aefdSYi Liu 	down_write(&orangefs_inode->xattr_sem);
3508bb8aefdSYi Liu 	new_op = op_alloc(ORANGEFS_VFS_OP_SETXATTR);
3511182fca3SMike Marshall 	if (!new_op)
3521182fca3SMike Marshall 		goto out_unlock;
3531182fca3SMike Marshall 
3541182fca3SMike Marshall 
3558bb8aefdSYi Liu 	new_op->upcall.req.setxattr.refn = orangefs_inode->refn;
3561182fca3SMike Marshall 	new_op->upcall.req.setxattr.flags = internal_flag;
3571182fca3SMike Marshall 	/*
3581182fca3SMike Marshall 	 * NOTE: Although keys are meant to be NULL terminated textual
3591182fca3SMike Marshall 	 * strings, I am going to explicitly pass the length just in
3601182fca3SMike Marshall 	 * case we change this later on...
3611182fca3SMike Marshall 	 */
362d373a712SAndreas Gruenbacher 	strcpy(new_op->upcall.req.setxattr.keyval.key, name);
363d373a712SAndreas Gruenbacher 	new_op->upcall.req.setxattr.keyval.key_sz = strlen(name) + 1;
3641182fca3SMike Marshall 	memcpy(new_op->upcall.req.setxattr.keyval.val, value, size);
3651182fca3SMike Marshall 	new_op->upcall.req.setxattr.keyval.val_sz = size;
3661182fca3SMike Marshall 
3671182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
3688bb8aefdSYi Liu 		     "orangefs_inode_setxattr: key %s, key_sz %d "
3691182fca3SMike Marshall 		     " value size %zd\n",
3701182fca3SMike Marshall 		     (char *)new_op->upcall.req.setxattr.keyval.key,
3711182fca3SMike Marshall 		     (int)new_op->upcall.req.setxattr.keyval.key_sz,
3721182fca3SMike Marshall 		     size);
3731182fca3SMike Marshall 
3741182fca3SMike Marshall 	ret = service_operation(new_op,
3758bb8aefdSYi Liu 				"orangefs_inode_setxattr",
3761182fca3SMike Marshall 				get_interruptible_flag(inode));
3771182fca3SMike Marshall 
3781182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
3798bb8aefdSYi Liu 		     "orangefs_inode_setxattr: returning %d\n",
3801182fca3SMike Marshall 		     ret);
3811182fca3SMike Marshall 
3821182fca3SMike Marshall 	/* when request is serviced properly, free req op struct */
3831182fca3SMike Marshall 	op_release(new_op);
384fc2e2e9cSMartin Brandenburg 
385fc2e2e9cSMartin Brandenburg 	h = &orangefs_inode->xattr_cache[xattr_key(name)];
386fc2e2e9cSMartin Brandenburg 	hlist_for_each_entry_safe(cx, tmp, h, node) {
387fc2e2e9cSMartin Brandenburg 		if (!strcmp(cx->key, name)) {
388fc2e2e9cSMartin Brandenburg 			hlist_del(&cx->node);
389fc2e2e9cSMartin Brandenburg 			kfree(cx);
390fc2e2e9cSMartin Brandenburg 			break;
391fc2e2e9cSMartin Brandenburg 		}
392fc2e2e9cSMartin Brandenburg 	}
393fc2e2e9cSMartin Brandenburg 
3941182fca3SMike Marshall out_unlock:
3958bb8aefdSYi Liu 	up_write(&orangefs_inode->xattr_sem);
3961182fca3SMike Marshall 	return ret;
3971182fca3SMike Marshall }
3981182fca3SMike Marshall 
3991182fca3SMike Marshall /*
4001182fca3SMike Marshall  * Tries to get a specified object's keys into a user-specified buffer of a
4011182fca3SMike Marshall  * given size.  Note that like the previous instances of xattr routines, this
4021182fca3SMike Marshall  * also allows you to pass in a NULL pointer and 0 size to probe the size for
4031182fca3SMike Marshall  * subsequent memory allocations. Thus our return value is always the size of
4041182fca3SMike Marshall  * all the keys unless there were errors in fetching the keys!
4051182fca3SMike Marshall  */
orangefs_listxattr(struct dentry * dentry,char * buffer,size_t size)4068bb8aefdSYi Liu ssize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size)
4071182fca3SMike Marshall {
4081182fca3SMike Marshall 	struct inode *inode = dentry->d_inode;
4098bb8aefdSYi Liu 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
4108bb8aefdSYi Liu 	struct orangefs_kernel_op_s *new_op;
4118bb8aefdSYi Liu 	__u64 token = ORANGEFS_ITERATE_START;
4121182fca3SMike Marshall 	ssize_t ret = -ENOMEM;
4131182fca3SMike Marshall 	ssize_t total = 0;
4141182fca3SMike Marshall 	int count_keys = 0;
4151182fca3SMike Marshall 	int key_size;
4161182fca3SMike Marshall 	int i = 0;
41762441fa5SMike Marshall 	int returned_count = 0;
4181182fca3SMike Marshall 
4190b08273cSMarkus Elfring 	if (size > 0 && !buffer) {
4201182fca3SMike Marshall 		gossip_err("%s: bogus NULL pointers\n", __func__);
4211182fca3SMike Marshall 		return -EINVAL;
4221182fca3SMike Marshall 	}
4231182fca3SMike Marshall 
4248bb8aefdSYi Liu 	down_read(&orangefs_inode->xattr_sem);
4258bb8aefdSYi Liu 	new_op = op_alloc(ORANGEFS_VFS_OP_LISTXATTR);
4261182fca3SMike Marshall 	if (!new_op)
4271182fca3SMike Marshall 		goto out_unlock;
4281182fca3SMike Marshall 
4291182fca3SMike Marshall 	if (buffer && size > 0)
4301182fca3SMike Marshall 		memset(buffer, 0, size);
4311182fca3SMike Marshall 
4321182fca3SMike Marshall try_again:
4331182fca3SMike Marshall 	key_size = 0;
4348bb8aefdSYi Liu 	new_op->upcall.req.listxattr.refn = orangefs_inode->refn;
4351182fca3SMike Marshall 	new_op->upcall.req.listxattr.token = token;
4361182fca3SMike Marshall 	new_op->upcall.req.listxattr.requested_count =
4378bb8aefdSYi Liu 	    (size == 0) ? 0 : ORANGEFS_MAX_XATTR_LISTLEN;
4381182fca3SMike Marshall 	ret = service_operation(new_op, __func__,
4391182fca3SMike Marshall 				get_interruptible_flag(inode));
4401182fca3SMike Marshall 	if (ret != 0)
4411182fca3SMike Marshall 		goto done;
4421182fca3SMike Marshall 
4431182fca3SMike Marshall 	if (size == 0) {
4441182fca3SMike Marshall 		/*
4451182fca3SMike Marshall 		 * This is a bit of a big upper limit, but I did not want to
4461182fca3SMike Marshall 		 * spend too much time getting this correct, since users end
4471182fca3SMike Marshall 		 * up allocating memory rather than us...
4481182fca3SMike Marshall 		 */
4491182fca3SMike Marshall 		total = new_op->downcall.resp.listxattr.returned_count *
4508bb8aefdSYi Liu 			ORANGEFS_MAX_XATTR_NAMELEN;
4511182fca3SMike Marshall 		goto done;
4521182fca3SMike Marshall 	}
4531182fca3SMike Marshall 
45462441fa5SMike Marshall 	returned_count = new_op->downcall.resp.listxattr.returned_count;
45562441fa5SMike Marshall 	if (returned_count < 0 ||
456a956af33SMartin Brandenburg 	    returned_count > ORANGEFS_MAX_XATTR_LISTLEN) {
45762441fa5SMike Marshall 		gossip_err("%s: impossible value for returned_count:%d:\n",
45862441fa5SMike Marshall 		__func__,
45962441fa5SMike Marshall 		returned_count);
46002a5cc53SMartin Brandenburg 		ret = -EIO;
46162441fa5SMike Marshall 		goto done;
46262441fa5SMike Marshall 	}
46362441fa5SMike Marshall 
4641182fca3SMike Marshall 	/*
4651182fca3SMike Marshall 	 * Check to see how much can be fit in the buffer. Fit only whole keys.
4661182fca3SMike Marshall 	 */
46762441fa5SMike Marshall 	for (i = 0; i < returned_count; i++) {
46802a5cc53SMartin Brandenburg 		if (new_op->downcall.resp.listxattr.lengths[i] < 0 ||
46902a5cc53SMartin Brandenburg 		    new_op->downcall.resp.listxattr.lengths[i] >
47002a5cc53SMartin Brandenburg 		    ORANGEFS_MAX_XATTR_NAMELEN) {
47102a5cc53SMartin Brandenburg 			gossip_err("%s: impossible value for lengths[%d]\n",
47202a5cc53SMartin Brandenburg 			    __func__,
47302a5cc53SMartin Brandenburg 			    new_op->downcall.resp.listxattr.lengths[i]);
47402a5cc53SMartin Brandenburg 			ret = -EIO;
47502a5cc53SMartin Brandenburg 			goto done;
47602a5cc53SMartin Brandenburg 		}
4771182fca3SMike Marshall 		if (total + new_op->downcall.resp.listxattr.lengths[i] > size)
4781182fca3SMike Marshall 			goto done;
4791182fca3SMike Marshall 
4801182fca3SMike Marshall 		/*
4811182fca3SMike Marshall 		 * Since many dumb programs try to setxattr() on our reserved
4821182fca3SMike Marshall 		 * xattrs this is a feeble attempt at defeating those by not
4831182fca3SMike Marshall 		 * listing them in the output of listxattr.. sigh
4841182fca3SMike Marshall 		 */
4851182fca3SMike Marshall 		if (is_reserved_key(new_op->downcall.resp.listxattr.key +
4861182fca3SMike Marshall 				    key_size,
4871182fca3SMike Marshall 				    new_op->downcall.resp.
4881182fca3SMike Marshall 					listxattr.lengths[i])) {
4891182fca3SMike Marshall 			gossip_debug(GOSSIP_XATTR_DEBUG, "Copying key %d -> %s\n",
4901182fca3SMike Marshall 					i, new_op->downcall.resp.listxattr.key +
4911182fca3SMike Marshall 						key_size);
4921182fca3SMike Marshall 			memcpy(buffer + total,
4931182fca3SMike Marshall 				new_op->downcall.resp.listxattr.key + key_size,
4941182fca3SMike Marshall 				new_op->downcall.resp.listxattr.lengths[i]);
4951182fca3SMike Marshall 			total += new_op->downcall.resp.listxattr.lengths[i];
4961182fca3SMike Marshall 			count_keys++;
4971182fca3SMike Marshall 		} else {
4981182fca3SMike Marshall 			gossip_debug(GOSSIP_XATTR_DEBUG, "[RESERVED] key %d -> %s\n",
4991182fca3SMike Marshall 					i, new_op->downcall.resp.listxattr.key +
5001182fca3SMike Marshall 						key_size);
5011182fca3SMike Marshall 		}
5021182fca3SMike Marshall 		key_size += new_op->downcall.resp.listxattr.lengths[i];
5031182fca3SMike Marshall 	}
5041182fca3SMike Marshall 
5051182fca3SMike Marshall 	/*
5061182fca3SMike Marshall 	 * Since the buffer was large enough, we might have to continue
5071182fca3SMike Marshall 	 * fetching more keys!
5081182fca3SMike Marshall 	 */
5091182fca3SMike Marshall 	token = new_op->downcall.resp.listxattr.token;
5108bb8aefdSYi Liu 	if (token != ORANGEFS_ITERATE_END)
5111182fca3SMike Marshall 		goto try_again;
5121182fca3SMike Marshall 
5131182fca3SMike Marshall done:
5141182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG, "%s: returning %d"
5151182fca3SMike Marshall 		     " [size of buffer %ld] (filled in %d keys)\n",
5161182fca3SMike Marshall 		     __func__,
5171182fca3SMike Marshall 		     ret ? (int)ret : (int)total,
5181182fca3SMike Marshall 		     (long)size,
5191182fca3SMike Marshall 		     count_keys);
5201182fca3SMike Marshall 	op_release(new_op);
5211182fca3SMike Marshall 	if (ret == 0)
5221182fca3SMike Marshall 		ret = total;
5231182fca3SMike Marshall out_unlock:
5248bb8aefdSYi Liu 	up_read(&orangefs_inode->xattr_sem);
5251182fca3SMike Marshall 	return ret;
5261182fca3SMike Marshall }
5271182fca3SMike Marshall 
orangefs_xattr_set_default(const struct xattr_handler * handler,struct mnt_idmap * idmap,struct dentry * unused,struct inode * inode,const char * name,const void * buffer,size_t size,int flags)5288bb8aefdSYi Liu static int orangefs_xattr_set_default(const struct xattr_handler *handler,
529*39f60c1cSChristian Brauner 				      struct mnt_idmap *idmap,
53059301226SAl Viro 				      struct dentry *unused,
53159301226SAl Viro 				      struct inode *inode,
5321182fca3SMike Marshall 				      const char *name,
5331182fca3SMike Marshall 				      const void *buffer,
5341182fca3SMike Marshall 				      size_t size,
535555fa0faSAl Viro 				      int flags)
5361182fca3SMike Marshall {
537d373a712SAndreas Gruenbacher 	return orangefs_inode_setxattr(inode, name, buffer, size, flags);
5381182fca3SMike Marshall }
5391182fca3SMike Marshall 
orangefs_xattr_get_default(const struct xattr_handler * handler,struct dentry * unused,struct inode * inode,const char * name,void * buffer,size_t size)5408bb8aefdSYi Liu static int orangefs_xattr_get_default(const struct xattr_handler *handler,
541b296821aSAl Viro 				      struct dentry *unused,
542b296821aSAl Viro 				      struct inode *inode,
5431182fca3SMike Marshall 				      const char *name,
5441182fca3SMike Marshall 				      void *buffer,
545555fa0faSAl Viro 				      size_t size)
5461182fca3SMike Marshall {
547d373a712SAndreas Gruenbacher 	return orangefs_inode_getxattr(inode, name, buffer, size);
5481182fca3SMike Marshall 
5491182fca3SMike Marshall }
5501182fca3SMike Marshall 
55112174444SJulia Lawall static const struct xattr_handler orangefs_xattr_default_handler = {
552972a7344SAndreas Gruenbacher 	.prefix = "",  /* match any name => handlers called with full name */
5538bb8aefdSYi Liu 	.get = orangefs_xattr_get_default,
5548bb8aefdSYi Liu 	.set = orangefs_xattr_set_default,
5551182fca3SMike Marshall };
5561182fca3SMike Marshall 
5578bb8aefdSYi Liu const struct xattr_handler *orangefs_xattr_handlers[] = {
5588bb8aefdSYi Liu 	&orangefs_xattr_default_handler,
5591182fca3SMike Marshall 	NULL
5601182fca3SMike Marshall };
561