Commit 2646a1f6 authored by Steven Whitehouse's avatar Steven Whitehouse

GFS2: Fix up system xattrs

This code has been shamelessly stolen from XFS at the suggestion
of Christoph Hellwig. I've not added support for cached ACLs so
far... watch for that in a later patch, although this is designed
in such a way that they should be easy to add.
Signed-off-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
Cc: Christoph Hellwig <hch@infradead.org>
parent f55073ff
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/xattr.h>
#include <linux/posix_acl.h> #include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h> #include <linux/posix_acl_xattr.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
...@@ -26,61 +27,6 @@ ...@@ -26,61 +27,6 @@
#include "trans.h" #include "trans.h"
#include "util.h" #include "util.h"
#define ACL_ACCESS 1
#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 posix_acl *acl;
int error;
error = gfs2_acl_validate_remove(ip, access);
if (error)
return error;
if (!er->er_data)
return -EINVAL;
acl = posix_acl_from_xattr(er->er_data, er->er_data_len);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (!acl) {
*remove = 1;
return 0;
}
error = posix_acl_valid(acl);
if (error)
goto out;
if (access) {
error = posix_acl_equiv_mode(acl, mode);
if (!error)
*remove = 1;
else if (error > 0)
error = 0;
}
out:
posix_acl_release(acl);
return error;
}
int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access)
{
if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl)
return -EOPNOTSUPP;
if (!is_owner_or_cap(&ip->i_inode))
return -EPERM;
if (S_ISLNK(ip->i_inode.i_mode))
return -EOPNOTSUPP;
if (!access && !S_ISDIR(ip->i_inode.i_mode))
return -EACCES;
return 0;
}
static int acl_get(struct gfs2_inode *ip, const char *name, static int acl_get(struct gfs2_inode *ip, const char *name,
struct posix_acl **acl, struct gfs2_ea_location *el, struct posix_acl **acl, struct gfs2_ea_location *el,
char **datap, unsigned int *lenp) char **datap, unsigned int *lenp)
...@@ -277,3 +223,117 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) ...@@ -277,3 +223,117 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
return error; return error;
} }
static int gfs2_acl_type(const char *name)
{
if (strcmp(name, GFS2_POSIX_ACL_ACCESS) == 0)
return ACL_TYPE_ACCESS;
if (strcmp(name, GFS2_POSIX_ACL_DEFAULT) == 0)
return ACL_TYPE_DEFAULT;
return -EINVAL;
}
static int gfs2_xattr_system_get(struct inode *inode, const char *name,
void *buffer, size_t size)
{
int type;
type = gfs2_acl_type(name);
if (type < 0)
return type;
return gfs2_xattr_get(inode, GFS2_EATYPE_SYS, name, buffer, size);
}
static int gfs2_set_mode(struct inode *inode, mode_t mode)
{
int error = 0;
if (mode != inode->i_mode) {
struct iattr iattr;
iattr.ia_valid = ATTR_MODE;
iattr.ia_mode = mode;
error = gfs2_setattr_simple(GFS2_I(inode), &iattr);
}
return error;
}
static int gfs2_xattr_system_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct posix_acl *acl = NULL;
int error = 0, type;
if (!sdp->sd_args.ar_posix_acl)
return -EOPNOTSUPP;
type = gfs2_acl_type(name);
if (type < 0)
return type;
if (flags & XATTR_CREATE)
return -EINVAL;
if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
return value ? -EACCES : 0;
if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER))
return -EPERM;
if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP;
if (!value)
goto set_acl;
acl = posix_acl_from_xattr(value, size);
if (!acl) {
/*
* acl_set_file(3) may request that we set default ACLs with
* zero length -- defend (gracefully) against that here.
*/
goto out;
}
if (IS_ERR(acl)) {
error = PTR_ERR(acl);
goto out;
}
error = posix_acl_valid(acl);
if (error)
goto out_release;
error = -EINVAL;
if (acl->a_count > GFS2_ACL_MAX_ENTRIES)
goto out_release;
if (type == ACL_TYPE_ACCESS) {
mode_t mode = inode->i_mode;
error = posix_acl_equiv_mode(acl, &mode);
if (error <= 0) {
posix_acl_release(acl);
acl = NULL;
if (error < 0)
return error;
}
error = gfs2_set_mode(inode, mode);
if (error)
goto out_release;
}
set_acl:
error = gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, value, size, 0);
out_release:
posix_acl_release(acl);
out:
return error;
}
struct xattr_handler gfs2_xattr_system_handler = {
.prefix = XATTR_SYSTEM_PREFIX,
.get = gfs2_xattr_system_get,
.set = gfs2_xattr_system_set,
};
...@@ -13,26 +13,12 @@ ...@@ -13,26 +13,12 @@
#include "incore.h" #include "incore.h"
#define GFS2_POSIX_ACL_ACCESS "posix_acl_access" #define GFS2_POSIX_ACL_ACCESS "posix_acl_access"
#define GFS2_POSIX_ACL_ACCESS_LEN 16
#define GFS2_POSIX_ACL_DEFAULT "posix_acl_default" #define GFS2_POSIX_ACL_DEFAULT "posix_acl_default"
#define GFS2_POSIX_ACL_DEFAULT_LEN 17 #define GFS2_ACL_MAX_ENTRIES 25
#define GFS2_ACL_IS_ACCESS(name, len) \ extern int gfs2_check_acl(struct inode *inode, int mask);
((len) == GFS2_POSIX_ACL_ACCESS_LEN && \ extern int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip);
!memcmp(GFS2_POSIX_ACL_ACCESS, (name), (len))) extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr);
extern struct xattr_handler gfs2_xattr_system_handler;
#define GFS2_ACL_IS_DEFAULT(name, len) \
((len) == GFS2_POSIX_ACL_DEFAULT_LEN && \
!memcmp(GFS2_POSIX_ACL_DEFAULT, (name), (len)))
struct gfs2_ea_request;
int gfs2_acl_validate_set(struct gfs2_inode *ip, int access,
struct gfs2_ea_request *er,
int *remove, mode_t *mode);
int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access);
int gfs2_check_acl(struct inode *inode, int mask);
int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip);
int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr);
#endif /* __ACL_DOT_H__ */ #endif /* __ACL_DOT_H__ */
...@@ -1507,18 +1507,6 @@ static int gfs2_xattr_user_set(struct inode *inode, const char *name, ...@@ -1507,18 +1507,6 @@ static int gfs2_xattr_user_set(struct inode *inode, const char *name,
return gfs2_xattr_set(inode, GFS2_EATYPE_USR, name, value, size, flags); return gfs2_xattr_set(inode, GFS2_EATYPE_USR, name, value, size, flags);
} }
static int gfs2_xattr_system_get(struct inode *inode, const char *name,
void *buffer, size_t size)
{
return gfs2_xattr_get(inode, GFS2_EATYPE_SYS, name, buffer, size);
}
static int gfs2_xattr_system_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
return gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, value, size, flags);
}
static int gfs2_xattr_security_get(struct inode *inode, const char *name, static int gfs2_xattr_security_get(struct inode *inode, const char *name,
void *buffer, size_t size) void *buffer, size_t size)
{ {
...@@ -1543,12 +1531,6 @@ static struct xattr_handler gfs2_xattr_security_handler = { ...@@ -1543,12 +1531,6 @@ static struct xattr_handler gfs2_xattr_security_handler = {
.set = gfs2_xattr_security_set, .set = gfs2_xattr_security_set,
}; };
static struct xattr_handler gfs2_xattr_system_handler = {
.prefix = XATTR_SYSTEM_PREFIX,
.get = gfs2_xattr_system_get,
.set = gfs2_xattr_system_set,
};
struct xattr_handler *gfs2_xattr_handlers[] = { struct xattr_handler *gfs2_xattr_handlers[] = {
&gfs2_xattr_user_handler, &gfs2_xattr_user_handler,
&gfs2_xattr_security_handler, &gfs2_xattr_security_handler,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment