Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1c7c474c authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Al Viro
Browse files

make generic_acl slightly more generic



Now that we cache the ACL pointers in the generic inode all the generic_acl
cruft can go away and generic_acl.c can directly implement xattr handlers
dealing with the full Posix ACL semantics for in-memory filesystems.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 431547b3
Loading
Loading
Loading
Loading
+89 −69
Original line number Diff line number Diff line
/*
 * fs/generic_acl.c
 *
 * (C) 2005 Andreas Gruenbacher <agruen@suse.de>
 *
 * This file is released under the GPL.
 *
 * Generic ACL support for in-memory filesystems.
 */

#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/generic_acl.h>
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>

/**
 * generic_acl_list  -  Generic xattr_handler->list() operation
 * @ops:	Filesystem specific getacl and setacl callbacks
 */
size_t
generic_acl_list(struct inode *inode, struct generic_acl_operations *ops,
		 int type, char *list, size_t list_size)

static size_t
generic_acl_list(struct dentry *dentry, char *list, size_t list_size,
		const char *name, size_t name_len, int type)
{
	struct posix_acl *acl;
	const char *name;
	const char *xname;
	size_t size;

	acl = ops->getacl(inode, type);
	acl = get_cached_acl(dentry->d_inode, type);
	if (!acl)
		return 0;
	posix_acl_release(acl);

	switch (type) {
	case ACL_TYPE_ACCESS:
			name = POSIX_ACL_XATTR_ACCESS;
		xname = POSIX_ACL_XATTR_ACCESS;
		break;

	case ACL_TYPE_DEFAULT:
			name = POSIX_ACL_XATTR_DEFAULT;
		xname = POSIX_ACL_XATTR_DEFAULT;
		break;

	default:
		return 0;
	}
	size = strlen(name) + 1;
	size = strlen(xname) + 1;
	if (list && size <= list_size)
		memcpy(list, name, size);
		memcpy(list, xname, size);
	return size;
}

/**
 * generic_acl_get  -  Generic xattr_handler->get() operation
 * @ops:	Filesystem specific getacl and setacl callbacks
 */
int
generic_acl_get(struct inode *inode, struct generic_acl_operations *ops,
		int type, void *buffer, size_t size)
static int
generic_acl_get(struct dentry *dentry, const char *name, void *buffer,
		     size_t size, int type)
{
	struct posix_acl *acl;
	int error;

	acl = ops->getacl(inode, type);
	if (strcmp(name, "") != 0)
		return -EINVAL;

	acl = get_cached_acl(dentry->d_inode, type);
	if (!acl)
		return -ENODATA;
	error = posix_acl_to_xattr(acl, buffer, size);
@@ -65,17 +61,16 @@ generic_acl_get(struct inode *inode, struct generic_acl_operations *ops,
	return error;
}

/**
 * generic_acl_set  -  Generic xattr_handler->set() operation
 * @ops:	Filesystem specific getacl and setacl callbacks
 */
int
generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
		int type, const void *value, size_t size)
static int
generic_acl_set(struct dentry *dentry, const char *name, const void *value,
		     size_t size, int flags, int type)
{
	struct inode *inode = dentry->d_inode;
	struct posix_acl *acl = NULL;
	int error;

	if (strcmp(name, "") != 0)
		return -EINVAL;
	if (S_ISLNK(inode->i_mode))
		return -EOPNOTSUPP;
	if (!is_owner_or_cap(inode))
@@ -103,7 +98,6 @@ generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
				acl = NULL;
			}
			break;

		case ACL_TYPE_DEFAULT:
			if (!S_ISDIR(inode->i_mode)) {
				error = -EINVAL;
@@ -112,7 +106,7 @@ generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
			break;
		}
	}
	ops->setacl(inode, type, acl);
	set_cached_acl(inode, type, acl);
	error = 0;
failed:
	posix_acl_release(acl);
@@ -121,14 +115,12 @@ generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,

/**
 * generic_acl_init  -  Take care of acl inheritance at @inode create time
 * @ops:	Filesystem specific getacl and setacl callbacks
 *
 * Files created inside a directory with a default ACL inherit the
 * directory's default ACL.
 */
int
generic_acl_init(struct inode *inode, struct inode *dir,
		 struct generic_acl_operations *ops)
generic_acl_init(struct inode *inode, struct inode *dir)
{
	struct posix_acl *acl = NULL;
	mode_t mode = inode->i_mode;
@@ -136,7 +128,7 @@ generic_acl_init(struct inode *inode, struct inode *dir,

	inode->i_mode = mode & ~current_umask();
	if (!S_ISLNK(inode->i_mode))
		acl = ops->getacl(dir, ACL_TYPE_DEFAULT);
		acl = get_cached_acl(dir, ACL_TYPE_DEFAULT);
	if (acl) {
		struct posix_acl *clone;

@@ -145,7 +137,7 @@ generic_acl_init(struct inode *inode, struct inode *dir,
			error = -ENOMEM;
			if (!clone)
				goto cleanup;
			ops->setacl(inode, ACL_TYPE_DEFAULT, clone);
			set_cached_acl(inode, ACL_TYPE_DEFAULT, clone);
			posix_acl_release(clone);
		}
		clone = posix_acl_clone(acl, GFP_KERNEL);
@@ -156,7 +148,7 @@ generic_acl_init(struct inode *inode, struct inode *dir,
		if (error >= 0) {
			inode->i_mode = mode;
			if (error > 0)
				ops->setacl(inode, ACL_TYPE_ACCESS, clone);
				set_cached_acl(inode, ACL_TYPE_ACCESS, clone);
		}
		posix_acl_release(clone);
	}
@@ -169,20 +161,19 @@ generic_acl_init(struct inode *inode, struct inode *dir,

/**
 * generic_acl_chmod  -  change the access acl of @inode upon chmod()
 * @ops:	FIlesystem specific getacl and setacl callbacks
 *
 * A chmod also changes the permissions of the owner, group/mask, and
 * other ACL entries.
 */
int
generic_acl_chmod(struct inode *inode, struct generic_acl_operations *ops)
generic_acl_chmod(struct inode *inode)
{
	struct posix_acl *acl, *clone;
	int error = 0;

	if (S_ISLNK(inode->i_mode))
		return -EOPNOTSUPP;
	acl = ops->getacl(inode, ACL_TYPE_ACCESS);
	acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
	if (acl) {
		clone = posix_acl_clone(acl, GFP_KERNEL);
		posix_acl_release(acl);
@@ -190,8 +181,37 @@ generic_acl_chmod(struct inode *inode, struct generic_acl_operations *ops)
			return -ENOMEM;
		error = posix_acl_chmod_masq(clone, inode->i_mode);
		if (!error)
			ops->setacl(inode, ACL_TYPE_ACCESS, clone);
			set_cached_acl(inode, ACL_TYPE_ACCESS, clone);
		posix_acl_release(clone);
	}
	return error;
}

int
generic_check_acl(struct inode *inode, int mask)
{
	struct posix_acl *acl = get_cached_acl(inode, ACL_TYPE_ACCESS);

	if (acl) {
		int error = posix_acl_permission(inode, acl, mask);
		posix_acl_release(acl);
		return error;
	}
	return -EAGAIN;
}

struct xattr_handler generic_acl_access_handler = {
	.prefix = POSIX_ACL_XATTR_ACCESS,
	.flags	= ACL_TYPE_ACCESS,
	.list	= generic_acl_list,
	.get	= generic_acl_get,
	.set	= generic_acl_set,
};

struct xattr_handler generic_acl_default_handler = {
	.prefix = POSIX_ACL_XATTR_DEFAULT,
	.flags	= ACL_TYPE_DEFAULT,
	.list	= generic_acl_list,
	.get	= generic_acl_get,
	.set	= generic_acl_set,
};
+10 −31
Original line number Diff line number Diff line
/*
 * include/linux/generic_acl.h
 *
 * (C) 2005 Andreas Gruenbacher <agruen@suse.de>
 *
 * This file is released under the GPL.
 */
#ifndef LINUX_GENERIC_ACL_H
#define LINUX_GENERIC_ACL_H

#ifndef GENERIC_ACL_H
#define GENERIC_ACL_H
#include <linux/xattr.h>

#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
struct inode;

/**
 * struct generic_acl_operations  -  filesystem operations
 *
 * Filesystems must make these operations available to the generic
 * operations.
 */
struct generic_acl_operations {
	struct posix_acl *(*getacl)(struct inode *, int);
	void (*setacl)(struct inode *, int, struct posix_acl *);
};
extern struct xattr_handler generic_acl_access_handler;
extern struct xattr_handler generic_acl_default_handler;

size_t generic_acl_list(struct inode *, struct generic_acl_operations *, int,
			char *, size_t);
int generic_acl_get(struct inode *, struct generic_acl_operations *, int,
		    void *, size_t);
int generic_acl_set(struct inode *, struct generic_acl_operations *, int,
		    const void *, size_t);
int generic_acl_init(struct inode *, struct inode *,
		     struct generic_acl_operations *);
int generic_acl_chmod(struct inode *, struct generic_acl_operations *);
int generic_acl_init(struct inode *, struct inode *);
int generic_acl_chmod(struct inode *);
int generic_check_acl(struct inode *inode, int mask);

#endif
#endif /* LINUX_GENERIC_ACL_H */
+0 −16
Original line number Diff line number Diff line
@@ -41,20 +41,4 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
extern int init_tmpfs(void);
extern int shmem_fill_super(struct super_block *sb, void *data, int silent);

#ifdef CONFIG_TMPFS_POSIX_ACL
int shmem_check_acl(struct inode *, int);
int shmem_acl_init(struct inode *, struct inode *);

extern struct xattr_handler shmem_xattr_acl_access_handler;
extern struct xattr_handler shmem_xattr_acl_default_handler;

extern struct generic_acl_operations shmem_acl_ops;

#else
static inline int shmem_acl_init(struct inode *inode, struct inode *dir)
{
	return 0;
}
#endif  /* CONFIG_TMPFS_POSIX_ACL */

#endif
+0 −1
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ obj-$(CONFIG_HUGETLBFS) += hugetlb.o
obj-$(CONFIG_NUMA) 	+= mempolicy.o
obj-$(CONFIG_SPARSEMEM)	+= sparse.o
obj-$(CONFIG_SPARSEMEM_VMEMMAP) += sparse-vmemmap.o
obj-$(CONFIG_TMPFS_POSIX_ACL) += shmem_acl.o
obj-$(CONFIG_SLOB) += slob.o
obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o
obj-$(CONFIG_KSM) += ksm.o
+10 −7
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ static struct vfsmount *shm_mnt;

#include <linux/xattr.h>
#include <linux/exportfs.h>
#include <linux/posix_acl.h>
#include <linux/generic_acl.h>
#include <linux/mman.h>
#include <linux/string.h>
@@ -809,7 +810,7 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
		error = inode_setattr(inode, attr);
#ifdef CONFIG_TMPFS_POSIX_ACL
	if (!error && (attr->ia_valid & ATTR_MODE))
		error = generic_acl_chmod(inode, &shmem_acl_ops);
		error = generic_acl_chmod(inode);
#endif
	if (page)
		page_cache_release(page);
@@ -1823,11 +1824,13 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
				return error;
			}
		}
		error = shmem_acl_init(inode, dir);
#ifdef CONFIG_TMPFS_POSIX_ACL
		error = generic_acl_init(inode, dir);
		if (error) {
			iput(inode);
			return error;
		}
#endif
		if (dir->i_mode & S_ISGID) {
			inode->i_gid = dir->i_gid;
			if (S_ISDIR(mode))
@@ -2074,8 +2077,8 @@ static struct xattr_handler shmem_xattr_security_handler = {
};

static struct xattr_handler *shmem_xattr_handlers[] = {
	&shmem_xattr_acl_access_handler,
	&shmem_xattr_acl_default_handler,
	&generic_acl_access_handler,
	&generic_acl_default_handler,
	&shmem_xattr_security_handler,
	NULL
};
@@ -2454,7 +2457,7 @@ static const struct inode_operations shmem_inode_operations = {
	.getxattr	= generic_getxattr,
	.listxattr	= generic_listxattr,
	.removexattr	= generic_removexattr,
	.check_acl	= shmem_check_acl,
	.check_acl	= generic_check_acl,
#endif

};
@@ -2477,7 +2480,7 @@ static const struct inode_operations shmem_dir_inode_operations = {
	.getxattr	= generic_getxattr,
	.listxattr	= generic_listxattr,
	.removexattr	= generic_removexattr,
	.check_acl	= shmem_check_acl,
	.check_acl	= generic_check_acl,
#endif
};

@@ -2488,7 +2491,7 @@ static const struct inode_operations shmem_special_inode_operations = {
	.getxattr	= generic_getxattr,
	.listxattr	= generic_listxattr,
	.removexattr	= generic_removexattr,
	.check_acl	= shmem_check_acl,
	.check_acl	= generic_check_acl,
#endif
};

Loading