Commit f5e45463 authored by David Howells's avatar David Howells
Browse files

afs: Implement YFS ACL setting



Implement the setting of YFS ACLs in AFS through the interface of setting
the afs.yfs.acl extended attribute on the file.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent ae46578b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1383,6 +1383,7 @@ struct yfs_acl {

extern void yfs_free_opaque_acl(struct yfs_acl *);
extern struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *, unsigned int);
extern int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *, const struct afs_acl *);

/*
 * Miscellaneous inline functions.
+49 −0
Original line number Diff line number Diff line
@@ -226,9 +226,58 @@ out:
	return ret;
}

/*
 * Set a file's YFS ACL.
 */
static int afs_xattr_set_yfs(const struct xattr_handler *handler,
                             struct dentry *dentry,
                             struct inode *inode, const char *name,
                             const void *buffer, size_t size, int flags)
{
	struct afs_fs_cursor fc;
	struct afs_vnode *vnode = AFS_FS_I(inode);
	struct afs_acl *acl = NULL;
	struct key *key;
	int ret;

	if (flags == XATTR_CREATE ||
	    strcmp(name, "acl") != 0)
		return -EINVAL;

	key = afs_request_key(vnode->volume->cell);
	if (IS_ERR(key))
		return PTR_ERR(key);

	acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
	if (!acl) {
		key_put(key);
		return -ENOMEM;
	}

	acl->size = size;
	memcpy(acl->data, buffer, size);

	ret = -ERESTARTSYS;
	if (afs_begin_vnode_operation(&fc, vnode, key)) {
		while (afs_select_fileserver(&fc)) {
			fc.cb_break = afs_calc_vnode_cb_break(vnode);
			yfs_fs_store_opaque_acl2(&fc, acl);
		}

		afs_check_for_remote_deletion(&fc, fc.vnode);
		afs_vnode_commit_status(&fc, vnode, fc.cb_break);
		ret = afs_end_vnode_operation(&fc);
	}

	kfree(acl);
	key_put(key);
	return ret;
}

static const struct xattr_handler afs_xattr_yfs_handler = {
	.prefix	= "afs.yfs.",
	.get	= afs_xattr_get_yfs,
	.set	= afs_xattr_set_yfs,
};

/*
+62 −5
Original line number Diff line number Diff line
@@ -1768,9 +1768,10 @@ int yfs_fs_get_volume_status(struct afs_fs_cursor *fc,
}

/*
 * Deliver reply data to an YFS.SetLock, YFS.ExtendLock or YFS.ReleaseLock
 * Deliver reply data to operations that just return a file status and a volume
 * sync record.
 */
static int yfs_deliver_fs_xxxx_lock(struct afs_call *call)
static int yfs_deliver_status_and_volsync(struct afs_call *call)
{
	struct afs_vnode *vnode = call->reply[0];
	const __be32 *bp;
@@ -1800,7 +1801,7 @@ static int yfs_deliver_fs_xxxx_lock(struct afs_call *call)
static const struct afs_call_type yfs_RXYFSSetLock = {
	.name		= "YFS.SetLock",
	.op		= yfs_FS_SetLock,
	.deliver	= yfs_deliver_fs_xxxx_lock,
	.deliver	= yfs_deliver_status_and_volsync,
	.done		= afs_lock_op_done,
	.destructor	= afs_flat_call_destructor,
};
@@ -1811,7 +1812,7 @@ static const struct afs_call_type yfs_RXYFSSetLock = {
static const struct afs_call_type yfs_RXYFSExtendLock = {
	.name		= "YFS.ExtendLock",
	.op		= yfs_FS_ExtendLock,
	.deliver	= yfs_deliver_fs_xxxx_lock,
	.deliver	= yfs_deliver_status_and_volsync,
	.done		= afs_lock_op_done,
	.destructor	= afs_flat_call_destructor,
};
@@ -1822,7 +1823,7 @@ static const struct afs_call_type yfs_RXYFSExtendLock = {
static const struct afs_call_type yfs_RXYFSReleaseLock = {
	.name		= "YFS.ReleaseLock",
	.op		= yfs_FS_ReleaseLock,
	.deliver	= yfs_deliver_fs_xxxx_lock,
	.deliver	= yfs_deliver_status_and_volsync,
	.destructor	= afs_flat_call_destructor,
};

@@ -2392,3 +2393,59 @@ nomem:
	fc->ac.error = -ENOMEM;
	return ERR_PTR(-ENOMEM);
}

/*
 * YFS.StoreOpaqueACL2 operation type
 */
static const struct afs_call_type yfs_RXYFSStoreOpaqueACL2 = {
	.name		= "YFS.StoreOpaqueACL2",
	.op		= yfs_FS_StoreOpaqueACL2,
	.deliver	= yfs_deliver_status_and_volsync,
	.destructor	= afs_flat_call_destructor,
};

/*
 * Fetch the YFS ACL for a file.
 */
int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *fc, const struct afs_acl *acl)
{
	struct afs_vnode *vnode = fc->vnode;
	struct afs_call *call;
	struct afs_net *net = afs_v2net(vnode);
	size_t size;
	__be32 *bp;

	_enter(",%x,{%llx:%llu},,",
	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);

	size = round_up(acl->size, 4);
	call = afs_alloc_flat_call(net, &yfs_RXYFSStoreStatus,
				   sizeof(__be32) * 2 +
				   sizeof(struct yfs_xdr_YFSFid) +
				   sizeof(__be32) + size,
				   sizeof(struct yfs_xdr_YFSFetchStatus) +
				   sizeof(struct yfs_xdr_YFSVolSync));
	if (!call) {
		fc->ac.error = -ENOMEM;
		return -ENOMEM;
	}

	call->key = fc->key;
	call->reply[0] = vnode;
	call->reply[2] = NULL; /* volsync */

	/* marshall the parameters */
	bp = call->request;
	bp = xdr_encode_u32(bp, YFSSTOREOPAQUEACL2);
	bp = xdr_encode_u32(bp, 0); /* RPC flags */
	bp = xdr_encode_YFSFid(bp, &vnode->fid);
	bp = xdr_encode_u32(bp, acl->size);
	memcpy(bp, acl->data, acl->size);
	if (acl->size != size)
		memset((void *)bp + acl->size, 0, size - acl->size);
	yfs_check_req(call, bp);

	trace_afs_make_fs_call(call, &vnode->fid);
	afs_make_call(&fc->ac, call, GFP_KERNEL);
	return afs_wait_for_call_to_complete(call, &fc->ac);
}