// SPDX-License-Identifier: GPL-2.0 /* * (C) 2001 Clemson University and The University of Chicago * Copyright 2018 Omnibond Systems, L.L.C. * * See COPYING in top-level directory.
*/
/* * this function returns * 0 if the key corresponding to name is not meant to be printed as part * of a listxattr. * 1 if the key corresponding to name is meant to be returned as part of * a listxattr. * The ones that start SYSTEM_ORANGEFS_KEY are the ones to avoid printing.
*/ staticint is_reserved_key(constchar *key, size_t size)
{
/* * Tries to get a specified key's attributes of a given * file into a user-specified buffer. Note that the getxattr * interface allows for the users to probe the size of an * extended attribute by passing in a value of 0 to size. * Thus our return value is always the size of the attribute * unless the key does not exist for the file and/or if * there were errors in fetching the attribute value.
*/
ssize_t orangefs_inode_getxattr(struct inode *inode, constchar *name, void *buffer, size_t size)
{ struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); struct orangefs_kernel_op_s *new_op = NULL; struct orangefs_cached_xattr *cx;
ssize_t ret = -ENOMEM;
ssize_t length = 0; int fsuid; int fsgid;
gossip_debug(GOSSIP_XATTR_DEBUG, "%s: name %s, buffer_size %zd\n",
__func__, name, size);
if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP;
if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) return -EINVAL;
/* * NOTE: Although keys are meant to be NULL terminated textual * strings, I am going to explicitly pass the length just in case * we change this later on...
*/
new_op->upcall.req.getxattr.key_sz = strlen(name) + 1;
ret = service_operation(new_op, "orangefs_inode_getxattr",
get_interruptible_flag(inode)); if (ret != 0) { if (ret == -ENOENT) {
ret = -ENODATA;
gossip_debug(GOSSIP_XATTR_DEBUG, "orangefs_inode_getxattr: inode %pU key %s" " does not exist!\n",
get_khandle_from_ino(inode),
(char *)new_op->upcall.req.getxattr.key);
cx = kmalloc(sizeof *cx, GFP_KERNEL); if (cx) {
strcpy(cx->key, name);
cx->length = -1;
cx->timeout = jiffies +
orangefs_getattr_timeout_msecs*HZ/1000;
hlist_add_head( &cx->node,
&orangefs_inode->xattr_cache[xattr_key(cx->key)]);
}
} goto out_release_op;
}
/* * Length returned includes null terminator.
*/
length = new_op->downcall.resp.getxattr.val_sz;
/* * Just return the length of the queried attribute.
*/ if (size == 0) {
ret = length; goto out_release_op;
}
/* * Check to see if key length is > provided buffer size.
*/ if (length > size) {
ret = -ERANGE; goto out_release_op;
}
if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) return -EINVAL;
down_write(&orangefs_inode->xattr_sem);
new_op = op_alloc(ORANGEFS_VFS_OP_REMOVEXATTR); if (!new_op) goto out_unlock;
new_op->upcall.req.removexattr.refn = orangefs_inode->refn; /* * NOTE: Although keys are meant to be NULL terminated * textual strings, I am going to explicitly pass the * length just in case we change this later on...
*/
strcpy(new_op->upcall.req.removexattr.key, name);
new_op->upcall.req.removexattr.key_sz = strlen(name) + 1;
ret = service_operation(new_op, "orangefs_inode_removexattr",
get_interruptible_flag(inode)); if (ret == -ENOENT) { /* * Request to replace a non-existent attribute is an error.
*/ if (flags & XATTR_REPLACE)
ret = -ENODATA; else
ret = 0;
}
/* * Tries to set an attribute for a given key on a file. * * Returns a -ve number on error and 0 on success. Key is text, but value * can be binary!
*/ int orangefs_inode_setxattr(struct inode *inode, constchar *name, constvoid *value, size_t size, int flags)
{ struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); struct orangefs_kernel_op_s *new_op; int internal_flag = 0; struct orangefs_cached_xattr *cx; struct hlist_head *h; struct hlist_node *tmp; int ret = -ENOMEM;
gossip_debug(GOSSIP_XATTR_DEBUG, "%s: name %s, buffer_size %zd\n",
__func__, name, size);
if (size > ORANGEFS_MAX_XATTR_VALUELEN) return -EINVAL; if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) return -EINVAL;
/* This is equivalent to a removexattr */ if (size == 0 && !value) {
gossip_debug(GOSSIP_XATTR_DEBUG, "removing xattr (%s)\n",
name); return orangefs_inode_removexattr(inode, name, flags);
}
gossip_debug(GOSSIP_XATTR_DEBUG, "setxattr on inode %pU, name %s\n",
get_khandle_from_ino(inode),
name);
down_write(&orangefs_inode->xattr_sem);
new_op = op_alloc(ORANGEFS_VFS_OP_SETXATTR); if (!new_op) goto out_unlock;
new_op->upcall.req.setxattr.refn = orangefs_inode->refn;
new_op->upcall.req.setxattr.flags = internal_flag; /* * NOTE: Although keys are meant to be NULL terminated textual * strings, I am going to explicitly pass the length just in * case we change this later on...
*/
strcpy(new_op->upcall.req.setxattr.keyval.key, name);
new_op->upcall.req.setxattr.keyval.key_sz = strlen(name) + 1;
memcpy(new_op->upcall.req.setxattr.keyval.val, value, size);
new_op->upcall.req.setxattr.keyval.val_sz = size;
/* * Tries to get a specified object's keys into a user-specified buffer of a * given size. Note that like the previous instances of xattr routines, this * also allows you to pass in a NULL pointer and 0 size to probe the size for * subsequent memory allocations. Thus our return value is always the size of * all the keys unless there were errors in fetching the keys!
*/
ssize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size)
{ struct inode *inode = dentry->d_inode; struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); struct orangefs_kernel_op_s *new_op;
__u64 token = ORANGEFS_ITERATE_START;
ssize_t ret = -ENOMEM;
ssize_t total = 0; int count_keys = 0; int key_size; int i = 0; int returned_count = 0;
if (size == 0) { /* * This is a bit of a big upper limit, but I did not want to * spend too much time getting this correct, since users end * up allocating memory rather than us...
*/
total = new_op->downcall.resp.listxattr.returned_count *
ORANGEFS_MAX_XATTR_NAMELEN; goto done;
}
returned_count = new_op->downcall.resp.listxattr.returned_count; if (returned_count < 0 ||
returned_count > ORANGEFS_MAX_XATTR_LISTLEN) {
gossip_err("%s: impossible value for returned_count:%d:\n",
__func__,
returned_count);
ret = -EIO; goto done;
}
/* * Check to see how much can be fit in the buffer. Fit only whole keys.
*/ for (i = 0; i < returned_count; i++) { if (new_op->downcall.resp.listxattr.lengths[i] < 0 ||
new_op->downcall.resp.listxattr.lengths[i] >
ORANGEFS_MAX_XATTR_NAMELEN) {
gossip_err("%s: impossible value for lengths[%d]\n",
__func__,
new_op->downcall.resp.listxattr.lengths[i]);
ret = -EIO; goto done;
} if (total + new_op->downcall.resp.listxattr.lengths[i] > size) goto done;
/* * Since many dumb programs try to setxattr() on our reserved * xattrs this is a feeble attempt at defeating those by not * listing them in the output of listxattr.. sigh
*/ if (is_reserved_key(new_op->downcall.resp.listxattr.key +
key_size,
new_op->downcall.resp.
listxattr.lengths[i])) {
gossip_debug(GOSSIP_XATTR_DEBUG, "Copying key %d -> %s\n",
i, new_op->downcall.resp.listxattr.key +
key_size);
memcpy(buffer + total,
new_op->downcall.resp.listxattr.key + key_size,
new_op->downcall.resp.listxattr.lengths[i]);
total += new_op->downcall.resp.listxattr.lengths[i];
count_keys++;
} else {
gossip_debug(GOSSIP_XATTR_DEBUG, "[RESERVED] key %d -> %s\n",
i, new_op->downcall.resp.listxattr.key +
key_size);
}
key_size += new_op->downcall.resp.listxattr.lengths[i];
}
/* * Since the buffer was large enough, we might have to continue * fetching more keys!
*/
token = new_op->downcall.resp.listxattr.token; if (token != ORANGEFS_ITERATE_END) goto try_again;
done:
gossip_debug(GOSSIP_XATTR_DEBUG, "%s: returning %d" " [size of buffer %ld] (filled in %d keys)\n",
__func__,
ret ? (int)ret : (int)total,
(long)size,
count_keys);
op_release(new_op); if (ret == 0)
ret = total;
out_unlock:
up_read(&orangefs_inode->xattr_sem); return ret;
}
staticconststruct xattr_handler orangefs_xattr_default_handler = {
.prefix = "", /* match any name => handlers called with full name */
.get = orangefs_xattr_get_default,
.set = orangefs_xattr_set_default,
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.