xref: /openbmc/linux/fs/orangefs/xattr.c (revision a9bb3ba8)
11182fca3SMike Marshall /*
21182fca3SMike Marshall  * (C) 2001 Clemson University and The University of Chicago
31182fca3SMike Marshall  *
41182fca3SMike Marshall  * See COPYING in top-level directory.
51182fca3SMike Marshall  */
61182fca3SMike Marshall 
71182fca3SMike Marshall /*
81182fca3SMike Marshall  *  Linux VFS extended attribute operations.
91182fca3SMike Marshall  */
101182fca3SMike Marshall 
111182fca3SMike Marshall #include "protocol.h"
12575e9461SMike Marshall #include "orangefs-kernel.h"
13575e9461SMike Marshall #include "orangefs-bufmap.h"
141182fca3SMike Marshall #include <linux/posix_acl_xattr.h>
151182fca3SMike Marshall #include <linux/xattr.h>
161182fca3SMike Marshall 
171182fca3SMike Marshall 
188bb8aefdSYi Liu #define SYSTEM_ORANGEFS_KEY "system.pvfs2."
198bb8aefdSYi Liu #define SYSTEM_ORANGEFS_KEY_LEN 13
201182fca3SMike Marshall 
211182fca3SMike Marshall /*
221182fca3SMike Marshall  * this function returns
231182fca3SMike Marshall  *   0 if the key corresponding to name is not meant to be printed as part
241182fca3SMike Marshall  *     of a listxattr.
251182fca3SMike Marshall  *   1 if the key corresponding to name is meant to be returned as part of
261182fca3SMike Marshall  *     a listxattr.
278bb8aefdSYi Liu  * The ones that start SYSTEM_ORANGEFS_KEY are the ones to avoid printing.
281182fca3SMike Marshall  */
291182fca3SMike Marshall static int is_reserved_key(const char *key, size_t size)
301182fca3SMike Marshall {
311182fca3SMike Marshall 
328bb8aefdSYi Liu 	if (size < SYSTEM_ORANGEFS_KEY_LEN)
331182fca3SMike Marshall 		return 1;
341182fca3SMike Marshall 
358bb8aefdSYi Liu 	return strncmp(key, SYSTEM_ORANGEFS_KEY, SYSTEM_ORANGEFS_KEY_LEN) ?  1 : 0;
361182fca3SMike Marshall }
371182fca3SMike Marshall 
381182fca3SMike Marshall static inline int convert_to_internal_xattr_flags(int setxattr_flags)
391182fca3SMike Marshall {
401182fca3SMike Marshall 	int internal_flag = 0;
411182fca3SMike Marshall 
421182fca3SMike Marshall 	if (setxattr_flags & XATTR_REPLACE) {
431182fca3SMike Marshall 		/* Attribute must exist! */
448bb8aefdSYi Liu 		internal_flag = ORANGEFS_XATTR_REPLACE;
451182fca3SMike Marshall 	} else if (setxattr_flags & XATTR_CREATE) {
461182fca3SMike Marshall 		/* Attribute must not exist */
478bb8aefdSYi Liu 		internal_flag = ORANGEFS_XATTR_CREATE;
481182fca3SMike Marshall 	}
491182fca3SMike Marshall 	return internal_flag;
501182fca3SMike Marshall }
511182fca3SMike Marshall 
521182fca3SMike Marshall 
531182fca3SMike Marshall /*
541182fca3SMike Marshall  * Tries to get a specified key's attributes of a given
551182fca3SMike Marshall  * file into a user-specified buffer. Note that the getxattr
561182fca3SMike Marshall  * interface allows for the users to probe the size of an
571182fca3SMike Marshall  * extended attribute by passing in a value of 0 to size.
581182fca3SMike Marshall  * Thus our return value is always the size of the attribute
591182fca3SMike Marshall  * unless the key does not exist for the file and/or if
601182fca3SMike Marshall  * there were errors in fetching the attribute value.
611182fca3SMike Marshall  */
628bb8aefdSYi Liu ssize_t orangefs_inode_getxattr(struct inode *inode, const char *prefix,
631182fca3SMike Marshall 		const char *name, void *buffer, size_t size)
641182fca3SMike Marshall {
658bb8aefdSYi Liu 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
668bb8aefdSYi Liu 	struct orangefs_kernel_op_s *new_op = NULL;
671182fca3SMike Marshall 	ssize_t ret = -ENOMEM;
681182fca3SMike Marshall 	ssize_t length = 0;
691182fca3SMike Marshall 	int fsuid;
701182fca3SMike Marshall 	int fsgid;
711182fca3SMike Marshall 
721182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
731182fca3SMike Marshall 		     "%s: prefix %s name %s, buffer_size %zd\n",
741182fca3SMike Marshall 		     __func__, prefix, name, size);
751182fca3SMike Marshall 
768bb8aefdSYi Liu 	if ((strlen(name) + strlen(prefix)) >= ORANGEFS_MAX_XATTR_NAMELEN) {
77eeaa3d44SMike Marshall 		gossip_err("Invalid key length (%d)\n",
781182fca3SMike Marshall 			   (int)(strlen(name) + strlen(prefix)));
791182fca3SMike Marshall 		return -EINVAL;
801182fca3SMike Marshall 	}
811182fca3SMike Marshall 
821182fca3SMike Marshall 	fsuid = from_kuid(current_user_ns(), current_fsuid());
831182fca3SMike Marshall 	fsgid = from_kgid(current_user_ns(), current_fsgid());
841182fca3SMike Marshall 
851182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
861182fca3SMike Marshall 		     "getxattr on inode %pU, name %s "
871182fca3SMike Marshall 		     "(uid %o, gid %o)\n",
881182fca3SMike Marshall 		     get_khandle_from_ino(inode),
891182fca3SMike Marshall 		     name,
901182fca3SMike Marshall 		     fsuid,
911182fca3SMike Marshall 		     fsgid);
921182fca3SMike Marshall 
938bb8aefdSYi Liu 	down_read(&orangefs_inode->xattr_sem);
941182fca3SMike Marshall 
958bb8aefdSYi Liu 	new_op = op_alloc(ORANGEFS_VFS_OP_GETXATTR);
961182fca3SMike Marshall 	if (!new_op)
971182fca3SMike Marshall 		goto out_unlock;
981182fca3SMike Marshall 
998bb8aefdSYi Liu 	new_op->upcall.req.getxattr.refn = orangefs_inode->refn;
1001182fca3SMike Marshall 	ret = snprintf((char *)new_op->upcall.req.getxattr.key,
1018bb8aefdSYi Liu 		       ORANGEFS_MAX_XATTR_NAMELEN, "%s%s", prefix, name);
1021182fca3SMike Marshall 
1031182fca3SMike Marshall 	/*
1041182fca3SMike Marshall 	 * NOTE: Although keys are meant to be NULL terminated textual
1051182fca3SMike Marshall 	 * strings, I am going to explicitly pass the length just in case
1061182fca3SMike Marshall 	 * we change this later on...
1071182fca3SMike Marshall 	 */
1081182fca3SMike Marshall 	new_op->upcall.req.getxattr.key_sz = ret + 1;
1091182fca3SMike Marshall 
1108bb8aefdSYi Liu 	ret = service_operation(new_op, "orangefs_inode_getxattr",
1111182fca3SMike Marshall 				get_interruptible_flag(inode));
1121182fca3SMike Marshall 	if (ret != 0) {
1131182fca3SMike Marshall 		if (ret == -ENOENT) {
1141182fca3SMike Marshall 			ret = -ENODATA;
1151182fca3SMike Marshall 			gossip_debug(GOSSIP_XATTR_DEBUG,
1168bb8aefdSYi Liu 				     "orangefs_inode_getxattr: inode %pU key %s"
1171182fca3SMike Marshall 				     " does not exist!\n",
1181182fca3SMike Marshall 				     get_khandle_from_ino(inode),
1191182fca3SMike Marshall 				     (char *)new_op->upcall.req.getxattr.key);
1201182fca3SMike Marshall 		}
1211182fca3SMike Marshall 		goto out_release_op;
1221182fca3SMike Marshall 	}
1231182fca3SMike Marshall 
1241182fca3SMike Marshall 	/*
1251182fca3SMike Marshall 	 * Length returned includes null terminator.
1261182fca3SMike Marshall 	 */
1271182fca3SMike Marshall 	length = new_op->downcall.resp.getxattr.val_sz;
1281182fca3SMike Marshall 
1291182fca3SMike Marshall 	/*
1301182fca3SMike Marshall 	 * Just return the length of the queried attribute.
1311182fca3SMike Marshall 	 */
1321182fca3SMike Marshall 	if (size == 0) {
1331182fca3SMike Marshall 		ret = length;
1341182fca3SMike Marshall 		goto out_release_op;
1351182fca3SMike Marshall 	}
1361182fca3SMike Marshall 
1371182fca3SMike Marshall 	/*
1381182fca3SMike Marshall 	 * Check to see if key length is > provided buffer size.
1391182fca3SMike Marshall 	 */
1401182fca3SMike Marshall 	if (length > size) {
1411182fca3SMike Marshall 		ret = -ERANGE;
1421182fca3SMike Marshall 		goto out_release_op;
1431182fca3SMike Marshall 	}
1441182fca3SMike Marshall 
1451182fca3SMike Marshall 	memcpy(buffer, new_op->downcall.resp.getxattr.val, length);
146a9bb3ba8SMike Marshall 	memset(buffer + length, 0, size - length);
1471182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
1488bb8aefdSYi Liu 	     "orangefs_inode_getxattr: inode %pU "
1491182fca3SMike Marshall 	     "key %s key_sz %d, val_len %d\n",
1501182fca3SMike Marshall 	     get_khandle_from_ino(inode),
1511182fca3SMike Marshall 	     (char *)new_op->
1521182fca3SMike Marshall 		upcall.req.getxattr.key,
1531182fca3SMike Marshall 		     (int)new_op->
1541182fca3SMike Marshall 		upcall.req.getxattr.key_sz,
1551182fca3SMike Marshall 	     (int)ret);
1561182fca3SMike Marshall 
1571182fca3SMike Marshall 	ret = length;
1581182fca3SMike Marshall 
1591182fca3SMike Marshall out_release_op:
1601182fca3SMike Marshall 	op_release(new_op);
1611182fca3SMike Marshall out_unlock:
1628bb8aefdSYi Liu 	up_read(&orangefs_inode->xattr_sem);
1631182fca3SMike Marshall 	return ret;
1641182fca3SMike Marshall }
1651182fca3SMike Marshall 
1668bb8aefdSYi Liu static int orangefs_inode_removexattr(struct inode *inode,
1671182fca3SMike Marshall 			    const char *prefix,
1681182fca3SMike Marshall 			    const char *name,
1691182fca3SMike Marshall 			    int flags)
1701182fca3SMike Marshall {
1718bb8aefdSYi Liu 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
1728bb8aefdSYi Liu 	struct orangefs_kernel_op_s *new_op = NULL;
1731182fca3SMike Marshall 	int ret = -ENOMEM;
1741182fca3SMike Marshall 
1758bb8aefdSYi Liu 	down_write(&orangefs_inode->xattr_sem);
1768bb8aefdSYi Liu 	new_op = op_alloc(ORANGEFS_VFS_OP_REMOVEXATTR);
1771182fca3SMike Marshall 	if (!new_op)
1781182fca3SMike Marshall 		goto out_unlock;
1791182fca3SMike Marshall 
1808bb8aefdSYi Liu 	new_op->upcall.req.removexattr.refn = orangefs_inode->refn;
1811182fca3SMike Marshall 	/*
1821182fca3SMike Marshall 	 * NOTE: Although keys are meant to be NULL terminated
1831182fca3SMike Marshall 	 * textual strings, I am going to explicitly pass the
1841182fca3SMike Marshall 	 * length just in case we change this later on...
1851182fca3SMike Marshall 	 */
1861182fca3SMike Marshall 	ret = snprintf((char *)new_op->upcall.req.removexattr.key,
1878bb8aefdSYi Liu 		       ORANGEFS_MAX_XATTR_NAMELEN,
1881182fca3SMike Marshall 		       "%s%s",
1891182fca3SMike Marshall 		       (prefix ? prefix : ""),
1901182fca3SMike Marshall 		       name);
1911182fca3SMike Marshall 	new_op->upcall.req.removexattr.key_sz = ret + 1;
1921182fca3SMike Marshall 
1931182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
1948bb8aefdSYi Liu 		     "orangefs_inode_removexattr: key %s, key_sz %d\n",
1951182fca3SMike Marshall 		     (char *)new_op->upcall.req.removexattr.key,
1961182fca3SMike Marshall 		     (int)new_op->upcall.req.removexattr.key_sz);
1971182fca3SMike Marshall 
1981182fca3SMike Marshall 	ret = service_operation(new_op,
1998bb8aefdSYi Liu 				"orangefs_inode_removexattr",
2001182fca3SMike Marshall 				get_interruptible_flag(inode));
2011182fca3SMike Marshall 	if (ret == -ENOENT) {
2021182fca3SMike Marshall 		/*
2031182fca3SMike Marshall 		 * Request to replace a non-existent attribute is an error.
2041182fca3SMike Marshall 		 */
2051182fca3SMike Marshall 		if (flags & XATTR_REPLACE)
2061182fca3SMike Marshall 			ret = -ENODATA;
2071182fca3SMike Marshall 		else
2081182fca3SMike Marshall 			ret = 0;
2091182fca3SMike Marshall 	}
2101182fca3SMike Marshall 
2111182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
2128bb8aefdSYi Liu 		     "orangefs_inode_removexattr: returning %d\n", ret);
2131182fca3SMike Marshall 
2141182fca3SMike Marshall 	op_release(new_op);
2151182fca3SMike Marshall out_unlock:
2168bb8aefdSYi Liu 	up_write(&orangefs_inode->xattr_sem);
2171182fca3SMike Marshall 	return ret;
2181182fca3SMike Marshall }
2191182fca3SMike Marshall 
2201182fca3SMike Marshall /*
2211182fca3SMike Marshall  * Tries to set an attribute for a given key on a file.
2221182fca3SMike Marshall  *
2231182fca3SMike Marshall  * Returns a -ve number on error and 0 on success.  Key is text, but value
2241182fca3SMike Marshall  * can be binary!
2251182fca3SMike Marshall  */
2268bb8aefdSYi Liu int orangefs_inode_setxattr(struct inode *inode, const char *prefix,
2271182fca3SMike Marshall 		const char *name, const void *value, size_t size, int flags)
2281182fca3SMike Marshall {
2298bb8aefdSYi Liu 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
2308bb8aefdSYi Liu 	struct orangefs_kernel_op_s *new_op;
2311182fca3SMike Marshall 	int internal_flag = 0;
2321182fca3SMike Marshall 	int ret = -ENOMEM;
2331182fca3SMike Marshall 
2341182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
2351182fca3SMike Marshall 		     "%s: prefix %s, name %s, buffer_size %zd\n",
2361182fca3SMike Marshall 		     __func__, prefix, name, size);
2371182fca3SMike Marshall 
2382d09a2caSMike Marshall 	if (size >= ORANGEFS_MAX_XATTR_VALUELEN ||
2391182fca3SMike Marshall 	    flags < 0) {
2408bb8aefdSYi Liu 		gossip_err("orangefs_inode_setxattr: bogus values of size(%d), flags(%d)\n",
2411182fca3SMike Marshall 			   (int)size,
2421182fca3SMike Marshall 			   flags);
2431182fca3SMike Marshall 		return -EINVAL;
2441182fca3SMike Marshall 	}
2451182fca3SMike Marshall 
2461182fca3SMike Marshall 	internal_flag = convert_to_internal_xattr_flags(flags);
2471182fca3SMike Marshall 
2481182fca3SMike Marshall 	if (prefix) {
2498bb8aefdSYi Liu 		if (strlen(name) + strlen(prefix) >= ORANGEFS_MAX_XATTR_NAMELEN) {
2501182fca3SMike Marshall 			gossip_err
2518bb8aefdSYi Liu 			    ("orangefs_inode_setxattr: bogus key size (%d)\n",
2521182fca3SMike Marshall 			     (int)(strlen(name) + strlen(prefix)));
2531182fca3SMike Marshall 			return -EINVAL;
2541182fca3SMike Marshall 		}
2551182fca3SMike Marshall 	} else {
2568bb8aefdSYi Liu 		if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) {
2571182fca3SMike Marshall 			gossip_err
2588bb8aefdSYi Liu 			    ("orangefs_inode_setxattr: bogus key size (%d)\n",
2591182fca3SMike Marshall 			     (int)(strlen(name)));
2601182fca3SMike Marshall 			return -EINVAL;
2611182fca3SMike Marshall 		}
2621182fca3SMike Marshall 	}
2631182fca3SMike Marshall 
2641182fca3SMike Marshall 	/* This is equivalent to a removexattr */
2651182fca3SMike Marshall 	if (size == 0 && value == NULL) {
2661182fca3SMike Marshall 		gossip_debug(GOSSIP_XATTR_DEBUG,
2671182fca3SMike Marshall 			     "removing xattr (%s%s)\n",
2681182fca3SMike Marshall 			     prefix,
2691182fca3SMike Marshall 			     name);
2708bb8aefdSYi Liu 		return orangefs_inode_removexattr(inode, prefix, name, flags);
2711182fca3SMike Marshall 	}
2721182fca3SMike Marshall 
2731182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
2741182fca3SMike Marshall 		     "setxattr on inode %pU, name %s\n",
2751182fca3SMike Marshall 		     get_khandle_from_ino(inode),
2761182fca3SMike Marshall 		     name);
2771182fca3SMike Marshall 
2788bb8aefdSYi Liu 	down_write(&orangefs_inode->xattr_sem);
2798bb8aefdSYi Liu 	new_op = op_alloc(ORANGEFS_VFS_OP_SETXATTR);
2801182fca3SMike Marshall 	if (!new_op)
2811182fca3SMike Marshall 		goto out_unlock;
2821182fca3SMike Marshall 
2831182fca3SMike Marshall 
2848bb8aefdSYi Liu 	new_op->upcall.req.setxattr.refn = orangefs_inode->refn;
2851182fca3SMike Marshall 	new_op->upcall.req.setxattr.flags = internal_flag;
2861182fca3SMike Marshall 	/*
2871182fca3SMike Marshall 	 * NOTE: Although keys are meant to be NULL terminated textual
2881182fca3SMike Marshall 	 * strings, I am going to explicitly pass the length just in
2891182fca3SMike Marshall 	 * case we change this later on...
2901182fca3SMike Marshall 	 */
2911182fca3SMike Marshall 	ret = snprintf((char *)new_op->upcall.req.setxattr.keyval.key,
2928bb8aefdSYi Liu 		       ORANGEFS_MAX_XATTR_NAMELEN,
2931182fca3SMike Marshall 		       "%s%s",
2941182fca3SMike Marshall 		       prefix, name);
2951182fca3SMike Marshall 	new_op->upcall.req.setxattr.keyval.key_sz = ret + 1;
2961182fca3SMike Marshall 	memcpy(new_op->upcall.req.setxattr.keyval.val, value, size);
2971182fca3SMike Marshall 	new_op->upcall.req.setxattr.keyval.val_sz = size;
2981182fca3SMike Marshall 
2991182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
3008bb8aefdSYi Liu 		     "orangefs_inode_setxattr: key %s, key_sz %d "
3011182fca3SMike Marshall 		     " value size %zd\n",
3021182fca3SMike Marshall 		     (char *)new_op->upcall.req.setxattr.keyval.key,
3031182fca3SMike Marshall 		     (int)new_op->upcall.req.setxattr.keyval.key_sz,
3041182fca3SMike Marshall 		     size);
3051182fca3SMike Marshall 
3061182fca3SMike Marshall 	ret = service_operation(new_op,
3078bb8aefdSYi Liu 				"orangefs_inode_setxattr",
3081182fca3SMike Marshall 				get_interruptible_flag(inode));
3091182fca3SMike Marshall 
3101182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG,
3118bb8aefdSYi Liu 		     "orangefs_inode_setxattr: returning %d\n",
3121182fca3SMike Marshall 		     ret);
3131182fca3SMike Marshall 
3141182fca3SMike Marshall 	/* when request is serviced properly, free req op struct */
3151182fca3SMike Marshall 	op_release(new_op);
3161182fca3SMike Marshall out_unlock:
3178bb8aefdSYi Liu 	up_write(&orangefs_inode->xattr_sem);
3181182fca3SMike Marshall 	return ret;
3191182fca3SMike Marshall }
3201182fca3SMike Marshall 
3211182fca3SMike Marshall /*
3221182fca3SMike Marshall  * Tries to get a specified object's keys into a user-specified buffer of a
3231182fca3SMike Marshall  * given size.  Note that like the previous instances of xattr routines, this
3241182fca3SMike Marshall  * also allows you to pass in a NULL pointer and 0 size to probe the size for
3251182fca3SMike Marshall  * subsequent memory allocations. Thus our return value is always the size of
3261182fca3SMike Marshall  * all the keys unless there were errors in fetching the keys!
3271182fca3SMike Marshall  */
3288bb8aefdSYi Liu ssize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size)
3291182fca3SMike Marshall {
3301182fca3SMike Marshall 	struct inode *inode = dentry->d_inode;
3318bb8aefdSYi Liu 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
3328bb8aefdSYi Liu 	struct orangefs_kernel_op_s *new_op;
3338bb8aefdSYi Liu 	__u64 token = ORANGEFS_ITERATE_START;
3341182fca3SMike Marshall 	ssize_t ret = -ENOMEM;
3351182fca3SMike Marshall 	ssize_t total = 0;
3361182fca3SMike Marshall 	int count_keys = 0;
3371182fca3SMike Marshall 	int key_size;
3381182fca3SMike Marshall 	int i = 0;
33962441fa5SMike Marshall 	int returned_count = 0;
3401182fca3SMike Marshall 
3411182fca3SMike Marshall 	if (size > 0 && buffer == NULL) {
3421182fca3SMike Marshall 		gossip_err("%s: bogus NULL pointers\n", __func__);
3431182fca3SMike Marshall 		return -EINVAL;
3441182fca3SMike Marshall 	}
3451182fca3SMike Marshall 
3468bb8aefdSYi Liu 	down_read(&orangefs_inode->xattr_sem);
3478bb8aefdSYi Liu 	new_op = op_alloc(ORANGEFS_VFS_OP_LISTXATTR);
3481182fca3SMike Marshall 	if (!new_op)
3491182fca3SMike Marshall 		goto out_unlock;
3501182fca3SMike Marshall 
3511182fca3SMike Marshall 	if (buffer && size > 0)
3521182fca3SMike Marshall 		memset(buffer, 0, size);
3531182fca3SMike Marshall 
3541182fca3SMike Marshall try_again:
3551182fca3SMike Marshall 	key_size = 0;
3568bb8aefdSYi Liu 	new_op->upcall.req.listxattr.refn = orangefs_inode->refn;
3571182fca3SMike Marshall 	new_op->upcall.req.listxattr.token = token;
3581182fca3SMike Marshall 	new_op->upcall.req.listxattr.requested_count =
3598bb8aefdSYi Liu 	    (size == 0) ? 0 : ORANGEFS_MAX_XATTR_LISTLEN;
3601182fca3SMike Marshall 	ret = service_operation(new_op, __func__,
3611182fca3SMike Marshall 				get_interruptible_flag(inode));
3621182fca3SMike Marshall 	if (ret != 0)
3631182fca3SMike Marshall 		goto done;
3641182fca3SMike Marshall 
3651182fca3SMike Marshall 	if (size == 0) {
3661182fca3SMike Marshall 		/*
3671182fca3SMike Marshall 		 * This is a bit of a big upper limit, but I did not want to
3681182fca3SMike Marshall 		 * spend too much time getting this correct, since users end
3691182fca3SMike Marshall 		 * up allocating memory rather than us...
3701182fca3SMike Marshall 		 */
3711182fca3SMike Marshall 		total = new_op->downcall.resp.listxattr.returned_count *
3728bb8aefdSYi Liu 			ORANGEFS_MAX_XATTR_NAMELEN;
3731182fca3SMike Marshall 		goto done;
3741182fca3SMike Marshall 	}
3751182fca3SMike Marshall 
37662441fa5SMike Marshall 	returned_count = new_op->downcall.resp.listxattr.returned_count;
37762441fa5SMike Marshall 	if (returned_count < 0 ||
37862441fa5SMike Marshall 	    returned_count >= ORANGEFS_MAX_XATTR_LISTLEN) {
37962441fa5SMike Marshall 		gossip_err("%s: impossible value for returned_count:%d:\n",
38062441fa5SMike Marshall 		__func__,
38162441fa5SMike Marshall 		returned_count);
38202a5cc53SMartin Brandenburg 		ret = -EIO;
38362441fa5SMike Marshall 		goto done;
38462441fa5SMike Marshall 	}
38562441fa5SMike Marshall 
3861182fca3SMike Marshall 	/*
3871182fca3SMike Marshall 	 * Check to see how much can be fit in the buffer. Fit only whole keys.
3881182fca3SMike Marshall 	 */
38962441fa5SMike Marshall 	for (i = 0; i < returned_count; i++) {
39002a5cc53SMartin Brandenburg 		if (new_op->downcall.resp.listxattr.lengths[i] < 0 ||
39102a5cc53SMartin Brandenburg 		    new_op->downcall.resp.listxattr.lengths[i] >
39202a5cc53SMartin Brandenburg 		    ORANGEFS_MAX_XATTR_NAMELEN) {
39302a5cc53SMartin Brandenburg 			gossip_err("%s: impossible value for lengths[%d]\n",
39402a5cc53SMartin Brandenburg 			    __func__,
39502a5cc53SMartin Brandenburg 			    new_op->downcall.resp.listxattr.lengths[i]);
39602a5cc53SMartin Brandenburg 			ret = -EIO;
39702a5cc53SMartin Brandenburg 			goto done;
39802a5cc53SMartin Brandenburg 		}
3991182fca3SMike Marshall 		if (total + new_op->downcall.resp.listxattr.lengths[i] > size)
4001182fca3SMike Marshall 			goto done;
4011182fca3SMike Marshall 
4021182fca3SMike Marshall 		/*
4031182fca3SMike Marshall 		 * Since many dumb programs try to setxattr() on our reserved
4041182fca3SMike Marshall 		 * xattrs this is a feeble attempt at defeating those by not
4051182fca3SMike Marshall 		 * listing them in the output of listxattr.. sigh
4061182fca3SMike Marshall 		 */
4071182fca3SMike Marshall 		if (is_reserved_key(new_op->downcall.resp.listxattr.key +
4081182fca3SMike Marshall 				    key_size,
4091182fca3SMike Marshall 				    new_op->downcall.resp.
4101182fca3SMike Marshall 					listxattr.lengths[i])) {
4111182fca3SMike Marshall 			gossip_debug(GOSSIP_XATTR_DEBUG, "Copying key %d -> %s\n",
4121182fca3SMike Marshall 					i, new_op->downcall.resp.listxattr.key +
4131182fca3SMike Marshall 						key_size);
4141182fca3SMike Marshall 			memcpy(buffer + total,
4151182fca3SMike Marshall 				new_op->downcall.resp.listxattr.key + key_size,
4161182fca3SMike Marshall 				new_op->downcall.resp.listxattr.lengths[i]);
4171182fca3SMike Marshall 			total += new_op->downcall.resp.listxattr.lengths[i];
4181182fca3SMike Marshall 			count_keys++;
4191182fca3SMike Marshall 		} else {
4201182fca3SMike Marshall 			gossip_debug(GOSSIP_XATTR_DEBUG, "[RESERVED] key %d -> %s\n",
4211182fca3SMike Marshall 					i, new_op->downcall.resp.listxattr.key +
4221182fca3SMike Marshall 						key_size);
4231182fca3SMike Marshall 		}
4241182fca3SMike Marshall 		key_size += new_op->downcall.resp.listxattr.lengths[i];
4251182fca3SMike Marshall 	}
4261182fca3SMike Marshall 
4271182fca3SMike Marshall 	/*
4281182fca3SMike Marshall 	 * Since the buffer was large enough, we might have to continue
4291182fca3SMike Marshall 	 * fetching more keys!
4301182fca3SMike Marshall 	 */
4311182fca3SMike Marshall 	token = new_op->downcall.resp.listxattr.token;
4328bb8aefdSYi Liu 	if (token != ORANGEFS_ITERATE_END)
4331182fca3SMike Marshall 		goto try_again;
4341182fca3SMike Marshall 
4351182fca3SMike Marshall done:
4361182fca3SMike Marshall 	gossip_debug(GOSSIP_XATTR_DEBUG, "%s: returning %d"
4371182fca3SMike Marshall 		     " [size of buffer %ld] (filled in %d keys)\n",
4381182fca3SMike Marshall 		     __func__,
4391182fca3SMike Marshall 		     ret ? (int)ret : (int)total,
4401182fca3SMike Marshall 		     (long)size,
4411182fca3SMike Marshall 		     count_keys);
4421182fca3SMike Marshall 	op_release(new_op);
4431182fca3SMike Marshall 	if (ret == 0)
4441182fca3SMike Marshall 		ret = total;
4451182fca3SMike Marshall out_unlock:
4468bb8aefdSYi Liu 	up_read(&orangefs_inode->xattr_sem);
4471182fca3SMike Marshall 	return ret;
4481182fca3SMike Marshall }
4491182fca3SMike Marshall 
4508bb8aefdSYi Liu static int orangefs_xattr_set_default(const struct xattr_handler *handler,
451555fa0faSAl Viro 				      struct dentry *dentry,
4521182fca3SMike Marshall 				      const char *name,
4531182fca3SMike Marshall 				      const void *buffer,
4541182fca3SMike Marshall 				      size_t size,
455555fa0faSAl Viro 				      int flags)
4561182fca3SMike Marshall {
4578bb8aefdSYi Liu 	return orangefs_inode_setxattr(dentry->d_inode,
4588bb8aefdSYi Liu 				    ORANGEFS_XATTR_NAME_DEFAULT_PREFIX,
4591182fca3SMike Marshall 				    name,
4601182fca3SMike Marshall 				    buffer,
4611182fca3SMike Marshall 				    size,
4621182fca3SMike Marshall 				    flags);
4631182fca3SMike Marshall }
4641182fca3SMike Marshall 
4658bb8aefdSYi Liu static int orangefs_xattr_get_default(const struct xattr_handler *handler,
466555fa0faSAl Viro 				      struct dentry *dentry,
4671182fca3SMike Marshall 				      const char *name,
4681182fca3SMike Marshall 				      void *buffer,
469555fa0faSAl Viro 				      size_t size)
4701182fca3SMike Marshall {
4718bb8aefdSYi Liu 	return orangefs_inode_getxattr(dentry->d_inode,
4728bb8aefdSYi Liu 				    ORANGEFS_XATTR_NAME_DEFAULT_PREFIX,
4731182fca3SMike Marshall 				    name,
4741182fca3SMike Marshall 				    buffer,
4751182fca3SMike Marshall 				    size);
4761182fca3SMike Marshall 
4771182fca3SMike Marshall }
4781182fca3SMike Marshall 
4798bb8aefdSYi Liu static int orangefs_xattr_set_trusted(const struct xattr_handler *handler,
480555fa0faSAl Viro 				     struct dentry *dentry,
4811182fca3SMike Marshall 				     const char *name,
4821182fca3SMike Marshall 				     const void *buffer,
4831182fca3SMike Marshall 				     size_t size,
484555fa0faSAl Viro 				     int flags)
4851182fca3SMike Marshall {
4868bb8aefdSYi Liu 	return orangefs_inode_setxattr(dentry->d_inode,
4878bb8aefdSYi Liu 				    ORANGEFS_XATTR_NAME_TRUSTED_PREFIX,
4881182fca3SMike Marshall 				    name,
4891182fca3SMike Marshall 				    buffer,
4901182fca3SMike Marshall 				    size,
4911182fca3SMike Marshall 				    flags);
4921182fca3SMike Marshall }
4931182fca3SMike Marshall 
4948bb8aefdSYi Liu static int orangefs_xattr_get_trusted(const struct xattr_handler *handler,
495555fa0faSAl Viro 				      struct dentry *dentry,
4961182fca3SMike Marshall 				      const char *name,
4971182fca3SMike Marshall 				      void *buffer,
498555fa0faSAl Viro 				      size_t size)
4991182fca3SMike Marshall {
5008bb8aefdSYi Liu 	return orangefs_inode_getxattr(dentry->d_inode,
5018bb8aefdSYi Liu 				    ORANGEFS_XATTR_NAME_TRUSTED_PREFIX,
5021182fca3SMike Marshall 				    name,
5031182fca3SMike Marshall 				    buffer,
5041182fca3SMike Marshall 				    size);
5051182fca3SMike Marshall }
5061182fca3SMike Marshall 
5078bb8aefdSYi Liu static struct xattr_handler orangefs_xattr_trusted_handler = {
5088bb8aefdSYi Liu 	.prefix = ORANGEFS_XATTR_NAME_TRUSTED_PREFIX,
5098bb8aefdSYi Liu 	.get = orangefs_xattr_get_trusted,
5108bb8aefdSYi Liu 	.set = orangefs_xattr_set_trusted,
5111182fca3SMike Marshall };
5121182fca3SMike Marshall 
5138bb8aefdSYi Liu static struct xattr_handler orangefs_xattr_default_handler = {
5141182fca3SMike Marshall 	/*
5151182fca3SMike Marshall 	 * NOTE: this is set to be the empty string.
5161182fca3SMike Marshall 	 * so that all un-prefixed xattrs keys get caught
5171182fca3SMike Marshall 	 * here!
5181182fca3SMike Marshall 	 */
5198bb8aefdSYi Liu 	.prefix = ORANGEFS_XATTR_NAME_DEFAULT_PREFIX,
5208bb8aefdSYi Liu 	.get = orangefs_xattr_get_default,
5218bb8aefdSYi Liu 	.set = orangefs_xattr_set_default,
5221182fca3SMike Marshall };
5231182fca3SMike Marshall 
5248bb8aefdSYi Liu const struct xattr_handler *orangefs_xattr_handlers[] = {
5251182fca3SMike Marshall 	&posix_acl_access_xattr_handler,
5261182fca3SMike Marshall 	&posix_acl_default_xattr_handler,
5278bb8aefdSYi Liu 	&orangefs_xattr_trusted_handler,
5288bb8aefdSYi Liu 	&orangefs_xattr_default_handler,
5291182fca3SMike Marshall 	NULL
5301182fca3SMike Marshall };
531