2018-06-06 02:42:14 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2008-06-23 03:34:09 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2008 Christoph Hellwig.
|
|
|
|
* Portions Copyright (C) 2000-2008 Silicon Graphics, Inc.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "xfs.h"
|
2019-06-29 02:25:35 +00:00
|
|
|
#include "xfs_shared.h"
|
2013-10-22 23:51:50 +00:00
|
|
|
#include "xfs_format.h"
|
2013-08-12 10:49:23 +00:00
|
|
|
#include "xfs_log_format.h"
|
2013-10-14 22:17:51 +00:00
|
|
|
#include "xfs_da_format.h"
|
2021-03-22 16:51:54 +00:00
|
|
|
#include "xfs_trans_resv.h"
|
|
|
|
#include "xfs_mount.h"
|
2008-06-23 03:34:09 +00:00
|
|
|
#include "xfs_inode.h"
|
xfs: separate out initial attr_set states
We current use XFS_DAS_UNINIT for several steps in the attr_set
state machine. We use it for setting shortform xattrs, converting
from shortform to leaf, leaf add, leaf-to-node and leaf add. All of
these things are essentially known before we start the state machine
iterating, so we really should separate them out:
XFS_DAS_SF_ADD:
- tries to do a shortform add
- on success -> done
- on ENOSPC converts to leaf, -> XFS_DAS_LEAF_ADD
- on error, dies.
XFS_DAS_LEAF_ADD:
- tries to do leaf add
- on success:
- inline attr -> done
- remote xattr || REPLACE -> XFS_DAS_FOUND_LBLK
- on ENOSPC converts to node, -> XFS_DAS_NODE_ADD
- on error, dies
XFS_DAS_NODE_ADD:
- tries to do node add
- on success:
- inline attr -> done
- remote xattr || REPLACE -> XFS_DAS_FOUND_NBLK
- on error, dies
This makes it easier to understand how the state machine starts
up and sets us up on the path to further state machine
simplifications.
This also converts the DAS state tracepoints to use strings rather
than numbers, as converting between enums and numbers requires
manual counting rather than just reading the name.
This also introduces a XFS_DAS_DONE state so that we can trace
successful operation completions easily.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Allison Henderson<allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Dave Chinner <david@fromorbit.com>
2022-05-12 05:12:52 +00:00
|
|
|
#include "xfs_da_btree.h"
|
2008-06-23 03:34:09 +00:00
|
|
|
#include "xfs_attr.h"
|
2019-11-07 01:19:33 +00:00
|
|
|
#include "xfs_acl.h"
|
2022-05-27 00:33:29 +00:00
|
|
|
#include "xfs_log.h"
|
|
|
|
#include "xfs_xattr.h"
|
2008-06-23 03:34:09 +00:00
|
|
|
|
|
|
|
#include <linux/posix_acl_xattr.h>
|
|
|
|
|
2022-05-27 00:33:29 +00:00
|
|
|
/*
|
|
|
|
* Get permission to use log-assisted atomic exchange of file extents.
|
|
|
|
*
|
|
|
|
* Callers must not be running any transactions or hold any inode locks, and
|
|
|
|
* they must release the permission by calling xlog_drop_incompat_feat
|
|
|
|
* when they're done.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
xfs_attr_grab_log_assist(
|
|
|
|
struct xfs_mount *mp)
|
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Protect ourselves from an idle log clearing the logged xattrs log
|
|
|
|
* incompat feature bit.
|
|
|
|
*/
|
|
|
|
xlog_use_incompat_feat(mp->m_log);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If log-assisted xattrs are already enabled, the caller can use the
|
|
|
|
* log assisted swap functions with the log-incompat reference we got.
|
|
|
|
*/
|
|
|
|
if (xfs_sb_version_haslogxattrs(&mp->m_sb))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Enable log-assisted xattrs. */
|
|
|
|
error = xfs_add_incompat_log_feature(mp,
|
|
|
|
XFS_SB_FEAT_INCOMPAT_LOG_XATTRS);
|
|
|
|
if (error)
|
|
|
|
goto drop_incompat;
|
|
|
|
|
|
|
|
xfs_warn_mount(mp, XFS_OPSTATE_WARNED_LARP,
|
|
|
|
"EXPERIMENTAL logged extended attributes feature in use. Use at your own risk!");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
drop_incompat:
|
|
|
|
xlog_drop_incompat_feat(mp->m_log);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
xfs_attr_rele_log_assist(
|
|
|
|
struct xfs_mount *mp)
|
|
|
|
{
|
|
|
|
xlog_drop_incompat_feat(mp->m_log);
|
|
|
|
}
|
2008-06-23 03:34:09 +00:00
|
|
|
|
|
|
|
static int
|
2016-04-11 00:48:24 +00:00
|
|
|
xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
|
|
|
|
struct inode *inode, const char *name, void *value, size_t size)
|
2008-06-23 03:34:09 +00:00
|
|
|
{
|
2020-02-27 01:30:34 +00:00
|
|
|
struct xfs_da_args args = {
|
|
|
|
.dp = XFS_I(inode),
|
2020-02-27 01:30:42 +00:00
|
|
|
.attr_filter = handler->flags,
|
2020-02-27 01:30:34 +00:00
|
|
|
.name = name,
|
|
|
|
.namelen = strlen(name),
|
|
|
|
.value = value,
|
|
|
|
.valuelen = size,
|
|
|
|
};
|
|
|
|
int error;
|
2008-06-23 03:34:09 +00:00
|
|
|
|
2020-02-27 01:30:34 +00:00
|
|
|
error = xfs_attr_get(&args);
|
2008-06-23 03:34:09 +00:00
|
|
|
if (error)
|
|
|
|
return error;
|
2020-02-27 01:30:34 +00:00
|
|
|
return args.valuelen;
|
2008-06-23 03:34:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2021-01-21 13:19:27 +00:00
|
|
|
xfs_xattr_set(const struct xattr_handler *handler,
|
|
|
|
struct user_namespace *mnt_userns, struct dentry *unused,
|
|
|
|
struct inode *inode, const char *name, const void *value,
|
|
|
|
size_t size, int flags)
|
2008-06-23 03:34:09 +00:00
|
|
|
{
|
2020-02-27 01:30:33 +00:00
|
|
|
struct xfs_da_args args = {
|
|
|
|
.dp = XFS_I(inode),
|
2020-02-27 01:30:42 +00:00
|
|
|
.attr_filter = handler->flags,
|
|
|
|
.attr_flags = flags,
|
2020-02-27 01:30:33 +00:00
|
|
|
.name = name,
|
|
|
|
.namelen = strlen(name),
|
|
|
|
.value = (void *)value,
|
|
|
|
.valuelen = size,
|
|
|
|
};
|
2015-11-03 01:40:59 +00:00
|
|
|
int error;
|
2008-06-23 03:34:09 +00:00
|
|
|
|
2020-02-27 01:30:33 +00:00
|
|
|
error = xfs_attr_set(&args);
|
2020-02-27 01:30:42 +00:00
|
|
|
if (!error && (handler->flags & XFS_ATTR_ROOT))
|
2020-02-27 01:30:41 +00:00
|
|
|
xfs_forget_acl(inode, name);
|
2015-11-03 01:40:59 +00:00
|
|
|
return error;
|
2008-06-23 03:34:09 +00:00
|
|
|
}
|
|
|
|
|
2010-05-14 00:53:20 +00:00
|
|
|
static const struct xattr_handler xfs_xattr_user_handler = {
|
2008-06-23 03:34:09 +00:00
|
|
|
.prefix = XATTR_USER_PREFIX,
|
2009-11-13 09:52:56 +00:00
|
|
|
.flags = 0, /* no flags implies user namespace */
|
|
|
|
.get = xfs_xattr_get,
|
|
|
|
.set = xfs_xattr_set,
|
2008-06-23 03:34:09 +00:00
|
|
|
};
|
|
|
|
|
2010-05-14 00:53:20 +00:00
|
|
|
static const struct xattr_handler xfs_xattr_trusted_handler = {
|
2008-06-23 03:34:09 +00:00
|
|
|
.prefix = XATTR_TRUSTED_PREFIX,
|
2020-02-27 01:30:42 +00:00
|
|
|
.flags = XFS_ATTR_ROOT,
|
2009-11-13 09:52:56 +00:00
|
|
|
.get = xfs_xattr_get,
|
|
|
|
.set = xfs_xattr_set,
|
2008-06-23 03:34:09 +00:00
|
|
|
};
|
|
|
|
|
2010-05-14 00:53:20 +00:00
|
|
|
static const struct xattr_handler xfs_xattr_security_handler = {
|
2008-06-23 03:34:09 +00:00
|
|
|
.prefix = XATTR_SECURITY_PREFIX,
|
2020-02-27 01:30:42 +00:00
|
|
|
.flags = XFS_ATTR_SECURE,
|
2009-11-13 09:52:56 +00:00
|
|
|
.get = xfs_xattr_get,
|
|
|
|
.set = xfs_xattr_set,
|
2008-06-23 03:34:09 +00:00
|
|
|
};
|
|
|
|
|
2010-05-14 00:53:20 +00:00
|
|
|
const struct xattr_handler *xfs_xattr_handlers[] = {
|
2008-06-23 03:34:09 +00:00
|
|
|
&xfs_xattr_user_handler,
|
|
|
|
&xfs_xattr_trusted_handler,
|
|
|
|
&xfs_xattr_security_handler,
|
2009-06-10 15:07:47 +00:00
|
|
|
#ifdef CONFIG_XFS_POSIX_ACL
|
2013-12-20 13:16:50 +00:00
|
|
|
&posix_acl_access_xattr_handler,
|
|
|
|
&posix_acl_default_xattr_handler,
|
2009-06-10 15:07:47 +00:00
|
|
|
#endif
|
2008-06-23 03:34:09 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2016-12-05 01:32:14 +00:00
|
|
|
static void
|
2015-12-02 13:44:40 +00:00
|
|
|
__xfs_xattr_put_listent(
|
2010-01-19 23:47:48 +00:00
|
|
|
struct xfs_attr_list_context *context,
|
2015-12-02 13:44:40 +00:00
|
|
|
char *prefix,
|
|
|
|
int prefix_len,
|
|
|
|
unsigned char *name,
|
|
|
|
int namelen)
|
2008-06-23 03:34:09 +00:00
|
|
|
{
|
|
|
|
char *offset;
|
|
|
|
int arraytop;
|
|
|
|
|
2019-02-13 19:15:17 +00:00
|
|
|
if (context->count < 0 || context->seen_enough)
|
|
|
|
return;
|
|
|
|
|
2020-02-27 01:30:37 +00:00
|
|
|
if (!context->buffer)
|
2015-12-02 13:44:40 +00:00
|
|
|
goto compute_size;
|
2008-06-23 03:34:09 +00:00
|
|
|
|
|
|
|
arraytop = context->count + prefix_len + namelen + 1;
|
|
|
|
if (arraytop > context->firstu) {
|
|
|
|
context->count = -1; /* insufficient space */
|
2016-09-13 21:40:35 +00:00
|
|
|
context->seen_enough = 1;
|
2016-12-05 01:32:14 +00:00
|
|
|
return;
|
2008-06-23 03:34:09 +00:00
|
|
|
}
|
2020-02-27 01:30:37 +00:00
|
|
|
offset = context->buffer + context->count;
|
2015-12-02 13:44:40 +00:00
|
|
|
strncpy(offset, prefix, prefix_len);
|
2008-06-23 03:34:09 +00:00
|
|
|
offset += prefix_len;
|
2010-01-19 23:47:48 +00:00
|
|
|
strncpy(offset, (char *)name, namelen); /* real name */
|
2008-06-23 03:34:09 +00:00
|
|
|
offset += namelen;
|
|
|
|
*offset = '\0';
|
2015-12-02 13:44:40 +00:00
|
|
|
|
|
|
|
compute_size:
|
2008-06-23 03:34:09 +00:00
|
|
|
context->count += prefix_len + namelen + 1;
|
2016-12-05 01:32:14 +00:00
|
|
|
return;
|
2008-06-23 03:34:09 +00:00
|
|
|
}
|
|
|
|
|
2016-12-05 01:32:14 +00:00
|
|
|
static void
|
2015-12-02 13:44:40 +00:00
|
|
|
xfs_xattr_put_listent(
|
2010-01-19 23:47:48 +00:00
|
|
|
struct xfs_attr_list_context *context,
|
|
|
|
int flags,
|
|
|
|
unsigned char *name,
|
|
|
|
int namelen,
|
2016-04-05 21:57:32 +00:00
|
|
|
int valuelen)
|
2008-06-23 03:34:09 +00:00
|
|
|
{
|
2015-12-02 13:44:40 +00:00
|
|
|
char *prefix;
|
|
|
|
int prefix_len;
|
2008-06-23 03:34:09 +00:00
|
|
|
|
2015-12-02 13:44:40 +00:00
|
|
|
ASSERT(context->count >= 0);
|
2008-06-23 03:34:09 +00:00
|
|
|
|
2015-12-02 13:44:40 +00:00
|
|
|
if (flags & XFS_ATTR_ROOT) {
|
|
|
|
#ifdef CONFIG_XFS_POSIX_ACL
|
|
|
|
if (namelen == SGI_ACL_FILE_SIZE &&
|
|
|
|
strncmp(name, SGI_ACL_FILE,
|
|
|
|
SGI_ACL_FILE_SIZE) == 0) {
|
2016-12-05 01:32:14 +00:00
|
|
|
__xfs_xattr_put_listent(
|
2015-12-02 13:44:40 +00:00
|
|
|
context, XATTR_SYSTEM_PREFIX,
|
|
|
|
XATTR_SYSTEM_PREFIX_LEN,
|
|
|
|
XATTR_POSIX_ACL_ACCESS,
|
|
|
|
strlen(XATTR_POSIX_ACL_ACCESS));
|
|
|
|
} else if (namelen == SGI_ACL_DEFAULT_SIZE &&
|
|
|
|
strncmp(name, SGI_ACL_DEFAULT,
|
|
|
|
SGI_ACL_DEFAULT_SIZE) == 0) {
|
2016-12-05 01:32:14 +00:00
|
|
|
__xfs_xattr_put_listent(
|
2015-12-02 13:44:40 +00:00
|
|
|
context, XATTR_SYSTEM_PREFIX,
|
|
|
|
XATTR_SYSTEM_PREFIX_LEN,
|
|
|
|
XATTR_POSIX_ACL_DEFAULT,
|
|
|
|
strlen(XATTR_POSIX_ACL_DEFAULT));
|
|
|
|
}
|
|
|
|
#endif
|
2008-06-23 03:34:09 +00:00
|
|
|
|
2015-12-02 13:44:40 +00:00
|
|
|
/*
|
|
|
|
* Only show root namespace entries if we are actually allowed to
|
|
|
|
* see them.
|
|
|
|
*/
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
2016-12-05 01:32:14 +00:00
|
|
|
return;
|
2015-12-02 13:44:40 +00:00
|
|
|
|
|
|
|
prefix = XATTR_TRUSTED_PREFIX;
|
|
|
|
prefix_len = XATTR_TRUSTED_PREFIX_LEN;
|
|
|
|
} else if (flags & XFS_ATTR_SECURE) {
|
|
|
|
prefix = XATTR_SECURITY_PREFIX;
|
|
|
|
prefix_len = XATTR_SECURITY_PREFIX_LEN;
|
|
|
|
} else {
|
|
|
|
prefix = XATTR_USER_PREFIX;
|
|
|
|
prefix_len = XATTR_USER_PREFIX_LEN;
|
|
|
|
}
|
|
|
|
|
2016-12-05 01:32:14 +00:00
|
|
|
__xfs_xattr_put_listent(context, prefix, prefix_len, name,
|
|
|
|
namelen);
|
|
|
|
return;
|
2008-06-23 03:34:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t
|
2016-04-05 21:57:18 +00:00
|
|
|
xfs_vn_listxattr(
|
|
|
|
struct dentry *dentry,
|
|
|
|
char *data,
|
|
|
|
size_t size)
|
2008-06-23 03:34:09 +00:00
|
|
|
{
|
|
|
|
struct xfs_attr_list_context context;
|
2016-04-05 21:57:18 +00:00
|
|
|
struct inode *inode = d_inode(dentry);
|
|
|
|
int error;
|
2008-06-23 03:34:09 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* First read the regular on-disk attributes.
|
|
|
|
*/
|
|
|
|
memset(&context, 0, sizeof(context));
|
|
|
|
context.dp = XFS_I(inode);
|
|
|
|
context.resynch = 1;
|
2020-02-27 01:30:37 +00:00
|
|
|
context.buffer = size ? data : NULL;
|
2008-06-23 03:34:09 +00:00
|
|
|
context.bufsize = size;
|
|
|
|
context.firstu = context.bufsize;
|
2015-12-02 13:44:40 +00:00
|
|
|
context.put_listent = xfs_xattr_put_listent;
|
2008-06-23 03:34:09 +00:00
|
|
|
|
2020-02-27 01:30:39 +00:00
|
|
|
error = xfs_attr_list(&context);
|
2016-04-05 21:57:18 +00:00
|
|
|
if (error)
|
|
|
|
return error;
|
2008-06-23 03:34:09 +00:00
|
|
|
if (context.count < 0)
|
|
|
|
return -ERANGE;
|
|
|
|
|
|
|
|
return context.count;
|
|
|
|
}
|