brintos

brintos / linux-shallow public Read only

0
0
Text · 8.4 KiB · eaf8492 Raw
349 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2008 Christoph Hellwig.4 * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc.5 */6 7#include "xfs.h"8#include "xfs_shared.h"9#include "xfs_format.h"10#include "xfs_log_format.h"11#include "xfs_da_format.h"12#include "xfs_trans_resv.h"13#include "xfs_mount.h"14#include "xfs_inode.h"15#include "xfs_da_btree.h"16#include "xfs_attr.h"17#include "xfs_acl.h"18#include "xfs_log.h"19#include "xfs_xattr.h"20#include "xfs_quota.h"21 22#include <linux/posix_acl_xattr.h>23 24/*25 * Get permission to use log-assisted atomic exchange of file extents.26 * Callers must not be running any transactions or hold any ILOCKs.27 */28static inline int29xfs_attr_grab_log_assist(30	struct xfs_mount	*mp)31{32	int			error = 0;33 34	/* xattr update log intent items are already enabled */35	if (xfs_is_using_logged_xattrs(mp))36		return 0;37 38	/*39	 * Check if the filesystem featureset is new enough to set this log40	 * incompat feature bit.  Strictly speaking, the minimum requirement is41	 * a V5 filesystem for the superblock field, but we'll require rmap42	 * or reflink to avoid having to deal with really old kernels.43	 */44	if (!xfs_has_reflink(mp) && !xfs_has_rmapbt(mp))45		return -EOPNOTSUPP;46 47	/* Enable log-assisted xattrs. */48	error = xfs_add_incompat_log_feature(mp,49			XFS_SB_FEAT_INCOMPAT_LOG_XATTRS);50	if (error)51		return error;52	xfs_set_using_logged_xattrs(mp);53 54	xfs_warn_mount(mp, XFS_OPSTATE_WARNED_LARP,55 "EXPERIMENTAL logged extended attributes feature in use. Use at your own risk!");56 57	return 0;58}59 60static inline bool61xfs_attr_want_log_assist(62	struct xfs_mount	*mp)63{64#ifdef DEBUG65	/* Logged xattrs require a V5 super for log_incompat */66	return xfs_has_crc(mp) && xfs_globals.larp;67#else68	return false;69#endif70}71 72/*73 * Set or remove an xattr, having grabbed the appropriate logging resources74 * prior to calling libxfs.  Callers of this function are only required to75 * initialize the inode, attr_filter, name, namelen, value, and valuelen fields76 * of @args.77 */78int79xfs_attr_change(80	struct xfs_da_args	*args,81	enum xfs_attr_update	op)82{83	struct xfs_mount	*mp = args->dp->i_mount;84	int			error;85 86	if (xfs_is_shutdown(mp))87		return -EIO;88 89	error = xfs_qm_dqattach(args->dp);90	if (error)91		return error;92 93	/*94	 * We have no control over the attribute names that userspace passes us95	 * to remove, so we have to allow the name lookup prior to attribute96	 * removal to fail as well.97	 */98	args->op_flags = XFS_DA_OP_OKNOENT;99 100	if (xfs_attr_want_log_assist(mp)) {101		error = xfs_attr_grab_log_assist(mp);102		if (error)103			return error;104 105		args->op_flags |= XFS_DA_OP_LOGGED;106	}107 108	args->owner = args->dp->i_ino;109	args->geo = mp->m_attr_geo;110	args->whichfork = XFS_ATTR_FORK;111	xfs_attr_sethash(args);112 113	/*114	 * Some xattrs must be resistant to allocation failure at ENOSPC, e.g.115	 * creating an inode with ACLs or security attributes requires the116	 * allocation of the xattr holding that information to succeed. Hence117	 * we allow xattrs in the VFS TRUSTED, SYSTEM, POSIX_ACL and SECURITY118	 * (LSM xattr) namespaces to dip into the reserve block pool to allow119	 * manipulation of these xattrs when at ENOSPC. These VFS xattr120	 * namespaces translate to the XFS_ATTR_ROOT and XFS_ATTR_SECURE on-disk121	 * namespaces.122	 *123	 * For most of these cases, these special xattrs will fit in the inode124	 * itself and so consume no extra space or only require temporary extra125	 * space while an overwrite is being made. Hence the use of the reserved126	 * pool is largely to avoid the worst case reservation from preventing127	 * the xattr from being created at ENOSPC.128	 */129	return xfs_attr_set(args, op,130			args->attr_filter & (XFS_ATTR_ROOT | XFS_ATTR_SECURE));131}132 133 134static int135xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,136		struct inode *inode, const char *name, void *value, size_t size)137{138	struct xfs_da_args	args = {139		.dp		= XFS_I(inode),140		.attr_filter	= handler->flags,141		.name		= name,142		.namelen	= strlen(name),143		.value		= value,144		.valuelen	= size,145	};146	int			error;147 148	if (xfs_ifork_zapped(XFS_I(inode), XFS_ATTR_FORK))149		return -EIO;150 151	error = xfs_attr_get(&args);152	if (error)153		return error;154	return args.valuelen;155}156 157static inline enum xfs_attr_update158xfs_xattr_flags_to_op(159	int		flags,160	const void	*value)161{162	if (!value)163		return XFS_ATTRUPDATE_REMOVE;164	if (flags & XATTR_CREATE)165		return XFS_ATTRUPDATE_CREATE;166	if (flags & XATTR_REPLACE)167		return XFS_ATTRUPDATE_REPLACE;168	return XFS_ATTRUPDATE_UPSERT;169}170 171static int172xfs_xattr_set(const struct xattr_handler *handler,173	      struct mnt_idmap *idmap, struct dentry *unused,174	      struct inode *inode, const char *name, const void *value,175	      size_t size, int flags)176{177	struct xfs_da_args	args = {178		.dp		= XFS_I(inode),179		.attr_filter	= handler->flags,180		.name		= name,181		.namelen	= strlen(name),182		.value		= (void *)value,183		.valuelen	= size,184	};185	int			error;186 187	error = xfs_attr_change(&args, xfs_xattr_flags_to_op(flags, value));188	if (!error && (handler->flags & XFS_ATTR_ROOT))189		xfs_forget_acl(inode, name);190	return error;191}192 193static const struct xattr_handler xfs_xattr_user_handler = {194	.prefix	= XATTR_USER_PREFIX,195	.flags	= 0, /* no flags implies user namespace */196	.get	= xfs_xattr_get,197	.set	= xfs_xattr_set,198};199 200static const struct xattr_handler xfs_xattr_trusted_handler = {201	.prefix	= XATTR_TRUSTED_PREFIX,202	.flags	= XFS_ATTR_ROOT,203	.get	= xfs_xattr_get,204	.set	= xfs_xattr_set,205};206 207static const struct xattr_handler xfs_xattr_security_handler = {208	.prefix	= XATTR_SECURITY_PREFIX,209	.flags	= XFS_ATTR_SECURE,210	.get	= xfs_xattr_get,211	.set	= xfs_xattr_set,212};213 214const struct xattr_handler * const xfs_xattr_handlers[] = {215	&xfs_xattr_user_handler,216	&xfs_xattr_trusted_handler,217	&xfs_xattr_security_handler,218	NULL219};220 221static void222__xfs_xattr_put_listent(223	struct xfs_attr_list_context *context,224	char *prefix,225	int prefix_len,226	unsigned char *name,227	int namelen)228{229	char *offset;230	int arraytop;231 232	if (context->count < 0 || context->seen_enough)233		return;234 235	if (!context->buffer)236		goto compute_size;237 238	arraytop = context->count + prefix_len + namelen + 1;239	if (arraytop > context->firstu) {240		context->count = -1;	/* insufficient space */241		context->seen_enough = 1;242		return;243	}244	offset = context->buffer + context->count;245	memcpy(offset, prefix, prefix_len);246	offset += prefix_len;247	strncpy(offset, (char *)name, namelen);			/* real name */248	offset += namelen;249	*offset = '\0';250 251compute_size:252	context->count += prefix_len + namelen + 1;253	return;254}255 256static void257xfs_xattr_put_listent(258	struct xfs_attr_list_context *context,259	int		flags,260	unsigned char	*name,261	int		namelen,262	void		*value,263	int		valuelen)264{265	char *prefix;266	int prefix_len;267 268	ASSERT(context->count >= 0);269 270	/* Don't expose private xattr namespaces. */271	if (flags & XFS_ATTR_PRIVATE_NSP_MASK)272		return;273 274	if (flags & XFS_ATTR_ROOT) {275#ifdef CONFIG_XFS_POSIX_ACL276		if (namelen == SGI_ACL_FILE_SIZE &&277		    strncmp(name, SGI_ACL_FILE,278			    SGI_ACL_FILE_SIZE) == 0) {279			__xfs_xattr_put_listent(280					context, XATTR_SYSTEM_PREFIX,281					XATTR_SYSTEM_PREFIX_LEN,282					XATTR_POSIX_ACL_ACCESS,283					strlen(XATTR_POSIX_ACL_ACCESS));284		} else if (namelen == SGI_ACL_DEFAULT_SIZE &&285			 strncmp(name, SGI_ACL_DEFAULT,286				 SGI_ACL_DEFAULT_SIZE) == 0) {287			__xfs_xattr_put_listent(288					context, XATTR_SYSTEM_PREFIX,289					XATTR_SYSTEM_PREFIX_LEN,290					XATTR_POSIX_ACL_DEFAULT,291					strlen(XATTR_POSIX_ACL_DEFAULT));292		}293#endif294 295		/*296		 * Only show root namespace entries if we are actually allowed to297		 * see them.298		 */299		if (!capable(CAP_SYS_ADMIN))300			return;301 302		prefix = XATTR_TRUSTED_PREFIX;303		prefix_len = XATTR_TRUSTED_PREFIX_LEN;304	} else if (flags & XFS_ATTR_SECURE) {305		prefix = XATTR_SECURITY_PREFIX;306		prefix_len = XATTR_SECURITY_PREFIX_LEN;307	} else {308		prefix = XATTR_USER_PREFIX;309		prefix_len = XATTR_USER_PREFIX_LEN;310	}311 312	__xfs_xattr_put_listent(context, prefix, prefix_len, name,313				namelen);314	return;315}316 317ssize_t318xfs_vn_listxattr(319	struct dentry	*dentry,320	char		*data,321	size_t		size)322{323	struct xfs_attr_list_context context;324	struct inode	*inode = d_inode(dentry);325	int		error;326 327	if (xfs_ifork_zapped(XFS_I(inode), XFS_ATTR_FORK))328		return -EIO;329 330	/*331	 * First read the regular on-disk attributes.332	 */333	memset(&context, 0, sizeof(context));334	context.dp = XFS_I(inode);335	context.resynch = 1;336	context.buffer = size ? data : NULL;337	context.bufsize = size;338	context.firstu = context.bufsize;339	context.put_listent = xfs_xattr_put_listent;340 341	error = xfs_attr_list(&context);342	if (error)343		return error;344	if (context.count < 0)345		return -ERANGE;346 347	return context.count;348}349