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

Commit 40b78a32 authored by Steven Whitehouse's avatar Steven Whitehouse
Browse files

GFS2: Clean up of extended attribute support



This has been on my list for some time. We need to change the way
in which we handle extended attributes to allow faster file creation
times (by reducing the number of transactions required) and the
extended attribute code is the main obstacle to this.

In addition to that, the VFS provides a way to demultiplex the xattr
calls which we ought to be using, rather than rolling our own. This
patch changes the GFS2 code to use that VFS feature and as a result
the code shrinks by a couple of hundred lines or so, and becomes
easier to read.

I'm planning on doing further clean up work in this area, but this
patch is a good start. The cleaned up code also uses the more usual
"xattr" shorthand, I plan to eliminate the use of "eattr" eventually
and in the mean time it serves as a flag as to which bits of the code
have been updated.

Signed-off-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent b6ed2e03
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
EXTRA_CFLAGS := -I$(src)
obj-$(CONFIG_GFS2_FS) += gfs2.o
gfs2-y := acl.o bmap.o dir.o eaops.o eattr.o glock.o \
gfs2-y := acl.o bmap.o dir.o eattr.o glock.o \
	glops.o inode.o log.o lops.o main.o meta_io.o \
	aops.o dentry.o export.o file.o \
	ops_fstype.o ops_inode.o quota.o \
+45 −59
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@
#include "gfs2.h"
#include "incore.h"
#include "acl.h"
#include "eaops.h"
#include "eattr.h"
#include "glock.h"
#include "inode.h"
@@ -31,8 +30,7 @@
#define ACL_DEFAULT 0

int gfs2_acl_validate_set(struct gfs2_inode *ip, int access,
		      struct gfs2_ea_request *er,
		      int *remove, mode_t *mode)
			  struct gfs2_ea_request *er, int *remove, mode_t *mode)
{
	struct posix_acl *acl;
	int error;
@@ -83,30 +81,20 @@ int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access)
	return 0;
}

static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl,
		   struct gfs2_ea_location *el, char **data, unsigned int *len)
static int acl_get(struct gfs2_inode *ip, const char *name,
		   struct posix_acl **acl, struct gfs2_ea_location *el,
		   char **datap, unsigned int *lenp)
{
	struct gfs2_ea_request er;
	struct gfs2_ea_location el_this;
	char *data;
	unsigned int len;
	int error;

	el->el_bh = NULL;

	if (!ip->i_eattr)
		return 0;

	memset(&er, 0, sizeof(struct gfs2_ea_request));
	if (access) {
		er.er_name = GFS2_POSIX_ACL_ACCESS;
		er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN;
	} else {
		er.er_name = GFS2_POSIX_ACL_DEFAULT;
		er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN;
	}
	er.er_type = GFS2_EATYPE_SYS;

	if (!el)
		el = &el_this;

	error = gfs2_ea_find(ip, &er, el);
	error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, name, el);
	if (error)
		return error;
	if (!el->el_ea)
@@ -114,32 +102,31 @@ static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl,
	if (!GFS2_EA_DATA_LEN(el->el_ea))
		goto out;

	er.er_data_len = GFS2_EA_DATA_LEN(el->el_ea);
	er.er_data = kmalloc(er.er_data_len, GFP_NOFS);
	len = GFS2_EA_DATA_LEN(el->el_ea);
	data = kmalloc(len, GFP_NOFS);
	error = -ENOMEM;
	if (!er.er_data)
	if (!data)
		goto out;

	error = gfs2_ea_get_copy(ip, el, er.er_data);
	if (error)
	error = gfs2_ea_get_copy(ip, el, data, len);
	if (error < 0)
		goto out_kfree;
	error = 0;

	if (acl) {
		*acl = posix_acl_from_xattr(er.er_data, er.er_data_len);
		*acl = posix_acl_from_xattr(data, len);
		if (IS_ERR(*acl))
			error = PTR_ERR(*acl);
	}

out_kfree:
	if (error || !data)
		kfree(er.er_data);
	else {
		*data = er.er_data;
		*len = er.er_data_len;
	if (error || !datap) {
		kfree(data);
	} else {
		*datap = data;
		*lenp = len;
	}
out:
	if (error || el == &el_this)
		brelse(el->el_bh);
	return error;
}

@@ -153,10 +140,12 @@ static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl,

int gfs2_check_acl(struct inode *inode, int mask)
{
	struct gfs2_ea_location el;
	struct posix_acl *acl = NULL;
	int error;

	error = acl_get(GFS2_I(inode), ACL_ACCESS, &acl, NULL, NULL, NULL);
	error = acl_get(GFS2_I(inode), GFS2_POSIX_ACL_ACCESS, &acl, &el, NULL, NULL);
	brelse(el.el_bh);
	if (error)
		return error;

@@ -196,10 +185,12 @@ static int munge_mode(struct gfs2_inode *ip, mode_t mode)

int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
{
	struct gfs2_ea_location el;
	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
	struct posix_acl *acl = NULL, *clone;
	struct gfs2_ea_request er;
	mode_t mode = ip->i_inode.i_mode;
	char *data = NULL;
	unsigned int len;
	int error;

	if (!sdp->sd_args.ar_posix_acl)
@@ -207,11 +198,8 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
	if (S_ISLNK(ip->i_inode.i_mode))
		return 0;

	memset(&er, 0, sizeof(struct gfs2_ea_request));
	er.er_type = GFS2_EATYPE_SYS;

	error = acl_get(dip, ACL_DEFAULT, &acl, NULL,
			&er.er_data, &er.er_data_len);
	error = acl_get(dip, GFS2_POSIX_ACL_DEFAULT, &acl, &el, &data, &len);
	brelse(el.el_bh);
	if (error)
		return error;
	if (!acl) {
@@ -229,9 +217,8 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
	acl = clone;

	if (S_ISDIR(ip->i_inode.i_mode)) {
		er.er_name = GFS2_POSIX_ACL_DEFAULT;
		er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN;
		error = gfs2_system_eaops.eo_set(ip, &er);
		error = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SYS,
				       GFS2_POSIX_ACL_DEFAULT, data, len, 0);
		if (error)
			goto out;
	}
@@ -239,21 +226,19 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
	error = posix_acl_create_masq(acl, &mode);
	if (error < 0)
		goto out;
	if (error > 0) {
		er.er_name = GFS2_POSIX_ACL_ACCESS;
		er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN;
		posix_acl_to_xattr(acl, er.er_data, er.er_data_len);
		er.er_mode = mode;
		er.er_flags = GFS2_ERF_MODE;
		error = gfs2_system_eaops.eo_set(ip, &er);
	if (error == 0)
		goto munge;

	posix_acl_to_xattr(acl, data, len);
	error = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SYS,
			       GFS2_POSIX_ACL_ACCESS, data, len, 0);
	if (error)
		goto out;
	} else
		munge_mode(ip, mode);

munge:
	error = munge_mode(ip, mode);
out:
	posix_acl_release(acl);
	kfree(er.er_data);
	kfree(data);
	return error;
}

@@ -265,9 +250,9 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
	unsigned int len;
	int error;

	error = acl_get(ip, ACL_ACCESS, &acl, &el, &data, &len);
	error = acl_get(ip, GFS2_POSIX_ACL_ACCESS, &acl, &el, &data, &len);
	if (error)
		return error;
		goto out_brelse;
	if (!acl)
		return gfs2_setattr_simple(ip, attr);

@@ -286,8 +271,9 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)

out:
	posix_acl_release(acl);
	brelse(el.el_bh);
	kfree(data);
out_brelse:
	brelse(el.el_bh);
	return error;
}

fs/gfs2/eaops.c

deleted100644 → 0
+0 −157
Original line number Diff line number Diff line
/*
 * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
 * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU General Public License version 2.
 */

#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/capability.h>
#include <linux/xattr.h>
#include <linux/gfs2_ondisk.h>
#include <asm/uaccess.h>

#include "gfs2.h"
#include "incore.h"
#include "acl.h"
#include "eaops.h"
#include "eattr.h"
#include "util.h"

/**
 * gfs2_ea_name2type - get the type of the ea, and truncate type from the name
 * @namep: ea name, possibly with type appended
 *
 * Returns: GFS2_EATYPE_XXX
 */

unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name)
{
	unsigned int type;

	if (strncmp(name, "system.", 7) == 0) {
		type = GFS2_EATYPE_SYS;
		if (truncated_name)
			*truncated_name = name + sizeof("system.") - 1;
	} else if (strncmp(name, "user.", 5) == 0) {
		type = GFS2_EATYPE_USR;
		if (truncated_name)
			*truncated_name = name + sizeof("user.") - 1;
	} else if (strncmp(name, "security.", 9) == 0) {
		type = GFS2_EATYPE_SECURITY;
		if (truncated_name)
			*truncated_name = name + sizeof("security.") - 1;
	} else {
		type = GFS2_EATYPE_UNUSED;
		if (truncated_name)
			*truncated_name = NULL;
	}

	return type;
}

static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
	if (!GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) &&
	    !GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len) &&
	    !capable(CAP_SYS_ADMIN))
		return -EPERM;

	if (GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl == 0 &&
	    (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) ||
	     GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)))
		return -EOPNOTSUPP;

	return gfs2_ea_get_i(ip, er);
}

static int system_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
	int remove = 0;
	int error;

	if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
		if (!(er->er_flags & GFS2_ERF_MODE)) {
			er->er_mode = ip->i_inode.i_mode;
			er->er_flags |= GFS2_ERF_MODE;
		}
		error = gfs2_acl_validate_set(ip, 1, er,
					      &remove, &er->er_mode);
		if (error)
			return error;
		error = gfs2_ea_set_i(ip, er);
		if (error)
			return error;
		if (remove)
			gfs2_ea_remove_i(ip, er);
		return 0;

	} else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
		error = gfs2_acl_validate_set(ip, 0, er,
					      &remove, NULL);
		if (error)
			return error;
		if (!remove)
			error = gfs2_ea_set_i(ip, er);
		else {
			error = gfs2_ea_remove_i(ip, er);
			if (error == -ENODATA)
				error = 0;
		}
		return error;
	}

	return -EPERM;
}

static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
	if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
		int error = gfs2_acl_validate_remove(ip, 1);
		if (error)
			return error;

	} else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
		int error = gfs2_acl_validate_remove(ip, 0);
		if (error)
			return error;

	} else
		return -EPERM;

	return gfs2_ea_remove_i(ip, er);
}

static const struct gfs2_eattr_operations gfs2_user_eaops = {
	.eo_get = gfs2_ea_get_i,
	.eo_set = gfs2_ea_set_i,
	.eo_remove = gfs2_ea_remove_i,
	.eo_name = "user",
};

const struct gfs2_eattr_operations gfs2_system_eaops = {
	.eo_get = system_eo_get,
	.eo_set = system_eo_set,
	.eo_remove = system_eo_remove,
	.eo_name = "system",
};

static const struct gfs2_eattr_operations gfs2_security_eaops = {
	.eo_get = gfs2_ea_get_i,
	.eo_set = gfs2_ea_set_i,
	.eo_remove = gfs2_ea_remove_i,
	.eo_name = "security",
};

const struct gfs2_eattr_operations *gfs2_ea_ops[] = {
	NULL,
	&gfs2_user_eaops,
	&gfs2_system_eaops,
	&gfs2_security_eaops,
};

fs/gfs2/eaops.h

deleted100644 → 0
+0 −30
Original line number Diff line number Diff line
/*
 * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
 * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU General Public License version 2.
 */

#ifndef __EAOPS_DOT_H__
#define __EAOPS_DOT_H__

struct gfs2_ea_request;
struct gfs2_inode;

struct gfs2_eattr_operations {
	int (*eo_get) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
	int (*eo_set) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
	int (*eo_remove) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
	char *eo_name;
};

unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name);

extern const struct gfs2_eattr_operations gfs2_system_eaops;

extern const struct gfs2_eattr_operations *gfs2_ea_ops[];

#endif /* __EAOPS_DOT_H__ */
+237 −184

File changed.

Preview size limit exceeded, changes collapsed.

Loading