brintos

brintos / linux-shallow public Read only

0
0
Text · 8.4 KiB · e19f396 Raw
364 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* Extended attribute handling for AFS.  We use xattrs to get and set metadata3 * instead of providing pioctl().4 *5 * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.6 * Written by David Howells (dhowells@redhat.com)7 */8 9#include <linux/slab.h>10#include <linux/fs.h>11#include <linux/xattr.h>12#include "internal.h"13 14/*15 * Deal with the result of a successful fetch ACL operation.16 */17static void afs_acl_success(struct afs_operation *op)18{19	afs_vnode_commit_status(op, &op->file[0]);20}21 22static void afs_acl_put(struct afs_operation *op)23{24	kfree(op->acl);25}26 27static const struct afs_operation_ops afs_fetch_acl_operation = {28	.issue_afs_rpc	= afs_fs_fetch_acl,29	.success	= afs_acl_success,30	.put		= afs_acl_put,31};32 33/*34 * Get a file's ACL.35 */36static int afs_xattr_get_acl(const struct xattr_handler *handler,37			     struct dentry *dentry,38			     struct inode *inode, const char *name,39			     void *buffer, size_t size)40{41	struct afs_operation *op;42	struct afs_vnode *vnode = AFS_FS_I(inode);43	struct afs_acl *acl = NULL;44	int ret;45 46	op = afs_alloc_operation(NULL, vnode->volume);47	if (IS_ERR(op))48		return -ENOMEM;49 50	afs_op_set_vnode(op, 0, vnode);51	op->ops = &afs_fetch_acl_operation;52 53	afs_begin_vnode_operation(op);54	afs_wait_for_operation(op);55	acl = op->acl;56	op->acl = NULL;57	ret = afs_put_operation(op);58 59	if (ret == 0) {60		ret = acl->size;61		if (size > 0) {62			if (acl->size <= size)63				memcpy(buffer, acl->data, acl->size);64			else65				ret = -ERANGE;66		}67	}68 69	kfree(acl);70	return ret;71}72 73static bool afs_make_acl(struct afs_operation *op,74			 const void *buffer, size_t size)75{76	struct afs_acl *acl;77 78	acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);79	if (!acl) {80		afs_op_nomem(op);81		return false;82	}83 84	acl->size = size;85	memcpy(acl->data, buffer, size);86	op->acl = acl;87	return true;88}89 90static const struct afs_operation_ops afs_store_acl_operation = {91	.issue_afs_rpc	= afs_fs_store_acl,92	.success	= afs_acl_success,93	.put		= afs_acl_put,94};95 96/*97 * Set a file's AFS3 ACL.98 */99static int afs_xattr_set_acl(const struct xattr_handler *handler,100			     struct mnt_idmap *idmap,101                             struct dentry *dentry,102                             struct inode *inode, const char *name,103                             const void *buffer, size_t size, int flags)104{105	struct afs_operation *op;106	struct afs_vnode *vnode = AFS_FS_I(inode);107 108	if (flags == XATTR_CREATE)109		return -EINVAL;110 111	op = afs_alloc_operation(NULL, vnode->volume);112	if (IS_ERR(op))113		return -ENOMEM;114 115	afs_op_set_vnode(op, 0, vnode);116	if (!afs_make_acl(op, buffer, size))117		return afs_put_operation(op);118 119	op->ops = &afs_store_acl_operation;120	return afs_do_sync_operation(op);121}122 123static const struct xattr_handler afs_xattr_afs_acl_handler = {124	.name   = "afs.acl",125	.get    = afs_xattr_get_acl,126	.set    = afs_xattr_set_acl,127};128 129static const struct afs_operation_ops yfs_fetch_opaque_acl_operation = {130	.issue_yfs_rpc	= yfs_fs_fetch_opaque_acl,131	.success	= afs_acl_success,132	/* Don't free op->yacl in .put here */133};134 135/*136 * Get a file's YFS ACL.137 */138static int afs_xattr_get_yfs(const struct xattr_handler *handler,139			     struct dentry *dentry,140			     struct inode *inode, const char *name,141			     void *buffer, size_t size)142{143	struct afs_operation *op;144	struct afs_vnode *vnode = AFS_FS_I(inode);145	struct yfs_acl *yacl = NULL;146	char buf[16], *data;147	int which = 0, dsize, ret = -ENOMEM;148 149	if (strcmp(name, "acl") == 0)150		which = 0;151	else if (strcmp(name, "acl_inherited") == 0)152		which = 1;153	else if (strcmp(name, "acl_num_cleaned") == 0)154		which = 2;155	else if (strcmp(name, "vol_acl") == 0)156		which = 3;157	else158		return -EOPNOTSUPP;159 160	yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL);161	if (!yacl)162		goto error;163 164	if (which == 0)165		yacl->flags |= YFS_ACL_WANT_ACL;166	else if (which == 3)167		yacl->flags |= YFS_ACL_WANT_VOL_ACL;168 169	op = afs_alloc_operation(NULL, vnode->volume);170	if (IS_ERR(op))171		goto error_yacl;172 173	afs_op_set_vnode(op, 0, vnode);174	op->yacl = yacl;175	op->ops = &yfs_fetch_opaque_acl_operation;176 177	afs_begin_vnode_operation(op);178	afs_wait_for_operation(op);179	ret = afs_put_operation(op);180 181	if (ret == 0) {182		switch (which) {183		case 0:184			data = yacl->acl->data;185			dsize = yacl->acl->size;186			break;187		case 1:188			data = buf;189			dsize = scnprintf(buf, sizeof(buf), "%u", yacl->inherit_flag);190			break;191		case 2:192			data = buf;193			dsize = scnprintf(buf, sizeof(buf), "%u", yacl->num_cleaned);194			break;195		case 3:196			data = yacl->vol_acl->data;197			dsize = yacl->vol_acl->size;198			break;199		default:200			ret = -EOPNOTSUPP;201			goto error_yacl;202		}203 204		ret = dsize;205		if (size > 0) {206			if (dsize <= size)207				memcpy(buffer, data, dsize);208			else209				ret = -ERANGE;210		}211	} else if (ret == -ENOTSUPP) {212		ret = -ENODATA;213	}214 215error_yacl:216	yfs_free_opaque_acl(yacl);217error:218	return ret;219}220 221static const struct afs_operation_ops yfs_store_opaque_acl2_operation = {222	.issue_yfs_rpc	= yfs_fs_store_opaque_acl2,223	.success	= afs_acl_success,224	.put		= afs_acl_put,225};226 227/*228 * Set a file's YFS ACL.229 */230static int afs_xattr_set_yfs(const struct xattr_handler *handler,231			     struct mnt_idmap *idmap,232                             struct dentry *dentry,233                             struct inode *inode, const char *name,234                             const void *buffer, size_t size, int flags)235{236	struct afs_operation *op;237	struct afs_vnode *vnode = AFS_FS_I(inode);238	int ret;239 240	if (flags == XATTR_CREATE ||241	    strcmp(name, "acl") != 0)242		return -EINVAL;243 244	op = afs_alloc_operation(NULL, vnode->volume);245	if (IS_ERR(op))246		return -ENOMEM;247 248	afs_op_set_vnode(op, 0, vnode);249	if (!afs_make_acl(op, buffer, size))250		return afs_put_operation(op);251 252	op->ops = &yfs_store_opaque_acl2_operation;253	ret = afs_do_sync_operation(op);254	if (ret == -ENOTSUPP)255		ret = -ENODATA;256	return ret;257}258 259static const struct xattr_handler afs_xattr_yfs_handler = {260	.prefix	= "afs.yfs.",261	.get	= afs_xattr_get_yfs,262	.set	= afs_xattr_set_yfs,263};264 265/*266 * Get the name of the cell on which a file resides.267 */268static int afs_xattr_get_cell(const struct xattr_handler *handler,269			      struct dentry *dentry,270			      struct inode *inode, const char *name,271			      void *buffer, size_t size)272{273	struct afs_vnode *vnode = AFS_FS_I(inode);274	struct afs_cell *cell = vnode->volume->cell;275	size_t namelen;276 277	namelen = cell->name_len;278	if (size == 0)279		return namelen;280	if (namelen > size)281		return -ERANGE;282	memcpy(buffer, cell->name, namelen);283	return namelen;284}285 286static const struct xattr_handler afs_xattr_afs_cell_handler = {287	.name	= "afs.cell",288	.get	= afs_xattr_get_cell,289};290 291/*292 * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of293 * hex numbers separated by colons.294 */295static int afs_xattr_get_fid(const struct xattr_handler *handler,296			     struct dentry *dentry,297			     struct inode *inode, const char *name,298			     void *buffer, size_t size)299{300	struct afs_vnode *vnode = AFS_FS_I(inode);301	char text[16 + 1 + 24 + 1 + 8 + 1];302	size_t len;303 304	/* The volume ID is 64-bit, the vnode ID is 96-bit and the305	 * uniquifier is 32-bit.306	 */307	len = scnprintf(text, sizeof(text), "%llx:", vnode->fid.vid);308	if (vnode->fid.vnode_hi)309		len += scnprintf(text + len, sizeof(text) - len, "%x%016llx",310				vnode->fid.vnode_hi, vnode->fid.vnode);311	else312		len += scnprintf(text + len, sizeof(text) - len, "%llx",313				 vnode->fid.vnode);314	len += scnprintf(text + len, sizeof(text) - len, ":%x",315			 vnode->fid.unique);316 317	if (size == 0)318		return len;319	if (len > size)320		return -ERANGE;321	memcpy(buffer, text, len);322	return len;323}324 325static const struct xattr_handler afs_xattr_afs_fid_handler = {326	.name	= "afs.fid",327	.get	= afs_xattr_get_fid,328};329 330/*331 * Get the name of the volume on which a file resides.332 */333static int afs_xattr_get_volume(const struct xattr_handler *handler,334			      struct dentry *dentry,335			      struct inode *inode, const char *name,336			      void *buffer, size_t size)337{338	struct afs_vnode *vnode = AFS_FS_I(inode);339	const char *volname = vnode->volume->name;340	size_t namelen;341 342	namelen = strlen(volname);343	if (size == 0)344		return namelen;345	if (namelen > size)346		return -ERANGE;347	memcpy(buffer, volname, namelen);348	return namelen;349}350 351static const struct xattr_handler afs_xattr_afs_volume_handler = {352	.name	= "afs.volume",353	.get	= afs_xattr_get_volume,354};355 356const struct xattr_handler * const afs_xattr_handlers[] = {357	&afs_xattr_afs_acl_handler,358	&afs_xattr_afs_cell_handler,359	&afs_xattr_afs_fid_handler,360	&afs_xattr_afs_volume_handler,361	&afs_xattr_yfs_handler,		/* afs.yfs. prefix */362	NULL363};364