forked from Minki/linux
f057f6cdf6
This is the big patch that I've been working on for some time now. There are many reasons for wanting to make this change such as: o Reducing overhead by eliminating duplicated fields between structures o Simplifcation of the code (reduces the code size by a fair bit) o The locking interface is now the DLM interface itself as proposed some time ago. o Fewer lookups of glocks when processing replies from the DLM o Fewer memory allocations/deallocations for each glock o Scope to do further optimisations in the future (but this patch is more than big enough for now!) Please note that (a) this patch relates to the lock_dlm module and not the DLM itself, that is still a separate module; and (b) that we retain the ability to build GFS2 as a standalone single node filesystem with out requiring the DLM. This patch needs a lot of testing, hence my keeping it I restarted my -git tree after the last merge window. That way, this has the maximum exposure before its merged. This is (modulo a few minor bug fixes) the same patch that I've been posting on and off the the last three months and its passed a number of different tests so far. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
158 lines
3.8 KiB
C
158 lines
3.8 KiB
C
/*
|
|
* 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,
|
|
};
|
|
|