Commit a72bdb1c authored by Jeff Mahoney's avatar Jeff Mahoney Committed by Linus Torvalds

reiserfs: Clean up xattrs when REISERFS_FS_XATTR is unset

The current reiserfs xattr implementation will not clean up old xattr
files if files are deleted when REISERFS_FS_XATTR is unset.  This
results in inaccessible lost files, wasting space.

This patch compiles in basic xattr knowledge, such as how to delete them
and change ownership for quota tracking.  If the file system has never
used xattrs, then the operation is quite fast: it returns immediately
when it sees there is no .reiserfs_priv directory.
Signed-off-by: default avatarJeff Mahoney <jeffm@suse.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 6dfede69
...@@ -7,10 +7,10 @@ obj-$(CONFIG_REISERFS_FS) += reiserfs.o ...@@ -7,10 +7,10 @@ obj-$(CONFIG_REISERFS_FS) += reiserfs.o
reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \ reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \
super.o prints.o objectid.o lbalance.o ibalance.o stree.o \ super.o prints.o objectid.o lbalance.o ibalance.o stree.o \
hashes.o tail_conversion.o journal.o resize.o \ hashes.o tail_conversion.o journal.o resize.o \
item_ops.o ioctl.o procfs.o item_ops.o ioctl.o procfs.o xattr.o
ifeq ($(CONFIG_REISERFS_FS_XATTR),y) ifeq ($(CONFIG_REISERFS_FS_XATTR),y)
reiserfs-objs += xattr.o xattr_user.o xattr_trusted.o reiserfs-objs += xattr_user.o xattr_trusted.o
endif endif
ifeq ($(CONFIG_REISERFS_FS_SECURITY),y) ifeq ($(CONFIG_REISERFS_FS_SECURITY),y)
......
...@@ -50,9 +50,6 @@ ...@@ -50,9 +50,6 @@
#define PRIVROOT_NAME ".reiserfs_priv" #define PRIVROOT_NAME ".reiserfs_priv"
#define XAROOT_NAME "xattrs" #define XAROOT_NAME "xattrs"
static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char
*prefix);
/* Returns the dentry referring to the root of the extended attribute /* Returns the dentry referring to the root of the extended attribute
* directory tree. If it has already been retrieved, it is used. If it * directory tree. If it has already been retrieved, it is used. If it
* hasn't been created and the flags indicate creation is allowed, we * hasn't been created and the flags indicate creation is allowed, we
...@@ -143,60 +140,6 @@ static struct dentry *open_xa_dir(const struct inode *inode, int flags) ...@@ -143,60 +140,6 @@ static struct dentry *open_xa_dir(const struct inode *inode, int flags)
return xadir; return xadir;
} }
/* Returns a dentry corresponding to a specific extended attribute file
* for the inode. If flags allow, the file is created. Otherwise, a
* valid or negative dentry, or an error is returned. */
static struct dentry *get_xa_file_dentry(const struct inode *inode,
const char *name, int flags)
{
struct dentry *xadir, *xafile;
int err = 0;
xadir = open_xa_dir(inode, flags);
if (IS_ERR(xadir)) {
return ERR_CAST(xadir);
} else if (!xadir->d_inode) {
dput(xadir);
return ERR_PTR(-ENODATA);
}
xafile = lookup_one_len(name, xadir, strlen(name));
if (IS_ERR(xafile)) {
dput(xadir);
return ERR_CAST(xafile);
}
if (xafile->d_inode) { /* file exists */
if (flags & XATTR_CREATE) {
err = -EEXIST;
dput(xafile);
goto out;
}
} else if (flags & XATTR_REPLACE || flags & FL_READONLY) {
goto out;
} else {
/* inode->i_mutex is down, so nothing else can try to create
* the same xattr */
err = xadir->d_inode->i_op->create(xadir->d_inode, xafile,
0700 | S_IFREG, NULL);
if (err) {
dput(xafile);
goto out;
}
}
out:
dput(xadir);
if (err)
xafile = ERR_PTR(err);
else if (!xafile->d_inode) {
dput(xafile);
xafile = ERR_PTR(-ENODATA);
}
return xafile;
}
/* /*
* this is very similar to fs/reiserfs/dir.c:reiserfs_readdir, but * this is very similar to fs/reiserfs/dir.c:reiserfs_readdir, but
* we need to drop the path before calling the filldir struct. That * we need to drop the path before calling the filldir struct. That
...@@ -369,6 +312,251 @@ int xattr_readdir(struct inode *inode, filldir_t filler, void *buf) ...@@ -369,6 +312,251 @@ int xattr_readdir(struct inode *inode, filldir_t filler, void *buf)
return res; return res;
} }
static int
__reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen)
{
struct dentry *dentry;
struct inode *dir = xadir->d_inode;
int err = 0;
dentry = lookup_one_len(name, xadir, namelen);
if (IS_ERR(dentry)) {
err = PTR_ERR(dentry);
goto out;
} else if (!dentry->d_inode) {
err = -ENODATA;
goto out_file;
}
/* Skip directories.. */
if (S_ISDIR(dentry->d_inode->i_mode))
goto out_file;
if (!IS_PRIVATE(dentry->d_inode)) {
reiserfs_error(dir->i_sb, "jdm-20003",
"OID %08x [%.*s/%.*s] doesn't have "
"priv flag set [parent is %sset].",
le32_to_cpu(INODE_PKEY(dentry->d_inode)->
k_objectid), xadir->d_name.len,
xadir->d_name.name, namelen, name,
IS_PRIVATE(xadir->d_inode) ? "" :
"not ");
dput(dentry);
return -EIO;
}
err = dir->i_op->unlink(dir, dentry);
if (!err)
d_delete(dentry);
out_file:
dput(dentry);
out:
return err;
}
/* The following are side effects of other operations that aren't explicitly
* modifying extended attributes. This includes operations such as permissions
* or ownership changes, object deletions, etc. */
static int
reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen,
loff_t offset, u64 ino, unsigned int d_type)
{
struct dentry *xadir = (struct dentry *)buf;
return __reiserfs_xattr_del(xadir, name, namelen);
}
/* This is called w/ inode->i_mutex downed */
int reiserfs_delete_xattrs(struct inode *inode)
{
struct dentry *dir, *root;
int err = 0;
/* Skip out, an xattr has no xattrs associated with it */
if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1)
return 0;
reiserfs_read_lock_xattrs(inode->i_sb);
dir = open_xa_dir(inode, FL_READONLY);
reiserfs_read_unlock_xattrs(inode->i_sb);
if (IS_ERR(dir)) {
err = PTR_ERR(dir);
goto out;
} else if (!dir->d_inode) {
dput(dir);
return 0;
}
lock_kernel();
err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir);
if (err) {
unlock_kernel();
goto out_dir;
}
/* Leftovers besides . and .. -- that's not good. */
if (dir->d_inode->i_nlink <= 2) {
root = get_xa_root(inode->i_sb, XATTR_REPLACE);
reiserfs_write_lock_xattrs(inode->i_sb);
err = vfs_rmdir(root->d_inode, dir);
reiserfs_write_unlock_xattrs(inode->i_sb);
dput(root);
} else {
reiserfs_warning(inode->i_sb, "jdm-20006",
"Couldn't remove all entries in directory");
}
unlock_kernel();
out_dir:
dput(dir);
out:
if (!err)
REISERFS_I(inode)->i_flags =
REISERFS_I(inode)->i_flags & ~i_has_xattr_dir;
return err;
}
struct reiserfs_chown_buf {
struct inode *inode;
struct dentry *xadir;
struct iattr *attrs;
};
/* XXX: If there is a better way to do this, I'd love to hear about it */
static int
reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen,
loff_t offset, u64 ino, unsigned int d_type)
{
struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf;
struct dentry *xafile, *xadir = chown_buf->xadir;
struct iattr *attrs = chown_buf->attrs;
int err = 0;
xafile = lookup_one_len(name, xadir, namelen);
if (IS_ERR(xafile))
return PTR_ERR(xafile);
else if (!xafile->d_inode) {
dput(xafile);
return -ENODATA;
}
if (!S_ISDIR(xafile->d_inode->i_mode))
err = notify_change(xafile, attrs);
dput(xafile);
return err;
}
int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs)
{
struct dentry *dir;
int err = 0;
struct reiserfs_chown_buf buf;
unsigned int ia_valid = attrs->ia_valid;
/* Skip out, an xattr has no xattrs associated with it */
if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1)
return 0;
reiserfs_read_lock_xattrs(inode->i_sb);
dir = open_xa_dir(inode, FL_READONLY);
reiserfs_read_unlock_xattrs(inode->i_sb);
if (IS_ERR(dir)) {
if (PTR_ERR(dir) != -ENODATA)
err = PTR_ERR(dir);
goto out;
} else if (!dir->d_inode) {
dput(dir);
goto out;
}
lock_kernel();
attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME);
buf.xadir = dir;
buf.attrs = attrs;
buf.inode = inode;
err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf);
if (err) {
unlock_kernel();
goto out_dir;
}
err = notify_change(dir, attrs);
unlock_kernel();
out_dir:
dput(dir);
out:
attrs->ia_valid = ia_valid;
return err;
}
#ifdef CONFIG_REISERFS_FS_XATTR
static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char
*prefix);
/* Returns a dentry corresponding to a specific extended attribute file
* for the inode. If flags allow, the file is created. Otherwise, a
* valid or negative dentry, or an error is returned. */
static struct dentry *get_xa_file_dentry(const struct inode *inode,
const char *name, int flags)
{
struct dentry *xadir, *xafile;
int err = 0;
xadir = open_xa_dir(inode, flags);
if (IS_ERR(xadir)) {
return ERR_CAST(xadir);
} else if (xadir && !xadir->d_inode) {
dput(xadir);
return ERR_PTR(-ENODATA);
}
xafile = lookup_one_len(name, xadir, strlen(name));
if (IS_ERR(xafile)) {
dput(xadir);
return ERR_CAST(xafile);
}
if (xafile->d_inode) { /* file exists */
if (flags & XATTR_CREATE) {
err = -EEXIST;
dput(xafile);
goto out;
}
} else if (flags & XATTR_REPLACE || flags & FL_READONLY) {
goto out;
} else {
/* inode->i_mutex is down, so nothing else can try to create
* the same xattr */
err = xadir->d_inode->i_op->create(xadir->d_inode, xafile,
0700 | S_IFREG, NULL);
if (err) {
dput(xafile);
goto out;
}
}
out:
dput(xadir);
if (err)
xafile = ERR_PTR(err);
else if (!xafile->d_inode) {
dput(xafile);
xafile = ERR_PTR(-ENODATA);
}
return xafile;
}
/* Internal operations on file data */ /* Internal operations on file data */
static inline void reiserfs_put_page(struct page *page) static inline void reiserfs_put_page(struct page *page)
{ {
...@@ -554,274 +742,85 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, ...@@ -554,274 +742,85 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer,
goto out_dput; goto out_dput;
} }
while (file_pos < isize) { while (file_pos < isize) {
size_t chunk; size_t chunk;
char *data; char *data;
size_t skip = 0; size_t skip = 0;
if (isize - file_pos > PAGE_CACHE_SIZE) if (isize - file_pos > PAGE_CACHE_SIZE)
chunk = PAGE_CACHE_SIZE; chunk = PAGE_CACHE_SIZE;
else else
chunk = isize - file_pos; chunk = isize - file_pos;
page = reiserfs_get_page(dentry->d_inode, file_pos);
if (IS_ERR(page)) {
err = PTR_ERR(page);
goto out_dput;
}
lock_page(page);
data = page_address(page);
if (file_pos == 0) {
struct reiserfs_xattr_header *rxh =
(struct reiserfs_xattr_header *)data;
skip = file_pos = sizeof(struct reiserfs_xattr_header);
chunk -= skip;
/* Magic doesn't match up.. */
if (rxh->h_magic != cpu_to_le32(REISERFS_XATTR_MAGIC)) {
unlock_page(page);
reiserfs_put_page(page);
reiserfs_warning(inode->i_sb, "jdm-20001",
"Invalid magic for xattr (%s) "
"associated with %k", name,
INODE_PKEY(inode));
err = -EIO;
goto out_dput;
}
hash = le32_to_cpu(rxh->h_hash);
}
memcpy(buffer + buffer_pos, data + skip, chunk);
unlock_page(page);
reiserfs_put_page(page);
file_pos += chunk;
buffer_pos += chunk;
skip = 0;
}
err = isize - sizeof(struct reiserfs_xattr_header);
if (xattr_hash(buffer, isize - sizeof(struct reiserfs_xattr_header)) !=
hash) {
reiserfs_warning(inode->i_sb, "jdm-20002",
"Invalid hash for xattr (%s) associated "
"with %k", name, INODE_PKEY(inode));
err = -EIO;
}
out_dput:
dput(dentry);
out:
return err;
}
static int
__reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen)
{
struct dentry *dentry;
struct inode *dir = xadir->d_inode;
int err = 0;
dentry = lookup_one_len(name, xadir, namelen);
if (IS_ERR(dentry)) {
err = PTR_ERR(dentry);
goto out;
} else if (!dentry->d_inode) {
err = -ENODATA;
goto out_file;
}
/* Skip directories.. */
if (S_ISDIR(dentry->d_inode->i_mode))
goto out_file;
if (!IS_PRIVATE(dentry->d_inode)) {
reiserfs_error(dir->i_sb, "jdm-20003",
"OID %08x [%.*s/%.*s] doesn't have "
"priv flag set [parent is %sset].",
le32_to_cpu(INODE_PKEY(dentry->d_inode)->
k_objectid), xadir->d_name.len,
xadir->d_name.name, namelen, name,
IS_PRIVATE(xadir->d_inode) ? "" :
"not ");
dput(dentry);
return -EIO;
}
err = dir->i_op->unlink(dir, dentry);
if (!err)
d_delete(dentry);
out_file:
dput(dentry);
out:
return err;
}
int reiserfs_xattr_del(struct inode *inode, const char *name)
{
struct dentry *dir;
int err;
dir = open_xa_dir(inode, FL_READONLY);
if (IS_ERR(dir)) {
err = PTR_ERR(dir);
goto out;
}
err = __reiserfs_xattr_del(dir, name, strlen(name));
dput(dir);
if (!err) {
inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
}
out:
return err;
}
/* The following are side effects of other operations that aren't explicitly
* modifying extended attributes. This includes operations such as permissions
* or ownership changes, object deletions, etc. */
static int
reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen,
loff_t offset, u64 ino, unsigned int d_type)
{
struct dentry *xadir = (struct dentry *)buf;
return __reiserfs_xattr_del(xadir, name, namelen);
}
/* This is called w/ inode->i_mutex downed */
int reiserfs_delete_xattrs(struct inode *inode)
{
struct dentry *dir, *root;
int err = 0;
/* Skip out, an xattr has no xattrs associated with it */
if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1 ||
!reiserfs_xattrs(inode->i_sb)) {
return 0;
}
reiserfs_read_lock_xattrs(inode->i_sb);
dir = open_xa_dir(inode, FL_READONLY);
reiserfs_read_unlock_xattrs(inode->i_sb);
if (IS_ERR(dir)) {
err = PTR_ERR(dir);
goto out;
} else if (!dir->d_inode) {
dput(dir);
return 0;
}
lock_kernel();
err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir);
if (err) {
unlock_kernel();
goto out_dir;
}
/* Leftovers besides . and .. -- that's not good. */
if (dir->d_inode->i_nlink <= 2) {
root = get_xa_root(inode->i_sb, XATTR_REPLACE);
reiserfs_write_lock_xattrs(inode->i_sb);
err = vfs_rmdir(root->d_inode, dir);
reiserfs_write_unlock_xattrs(inode->i_sb);
dput(root);
} else {
reiserfs_warning(inode->i_sb, "jdm-20006",
"Couldn't remove all entries in directory");
}
unlock_kernel();
out_dir:
dput(dir);
out:
if (!err)
REISERFS_I(inode)->i_flags =
REISERFS_I(inode)->i_flags & ~i_has_xattr_dir;
return err;
}
struct reiserfs_chown_buf { page = reiserfs_get_page(dentry->d_inode, file_pos);
struct inode *inode; if (IS_ERR(page)) {
struct dentry *xadir; err = PTR_ERR(page);
struct iattr *attrs; goto out_dput;
}; }
/* XXX: If there is a better way to do this, I'd love to hear about it */ lock_page(page);
static int data = page_address(page);
reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen, if (file_pos == 0) {
loff_t offset, u64 ino, unsigned int d_type) struct reiserfs_xattr_header *rxh =
{ (struct reiserfs_xattr_header *)data;
struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf; skip = file_pos = sizeof(struct reiserfs_xattr_header);
struct dentry *xafile, *xadir = chown_buf->xadir; chunk -= skip;
struct iattr *attrs = chown_buf->attrs; /* Magic doesn't match up.. */
int err = 0; if (rxh->h_magic != cpu_to_le32(REISERFS_XATTR_MAGIC)) {
unlock_page(page);
reiserfs_put_page(page);
reiserfs_warning(inode->i_sb, "jdm-20001",
"Invalid magic for xattr (%s) "
"associated with %k", name,
INODE_PKEY(inode));
err = -EIO;
goto out_dput;
}
hash = le32_to_cpu(rxh->h_hash);
}
memcpy(buffer + buffer_pos, data + skip, chunk);
unlock_page(page);
reiserfs_put_page(page);
file_pos += chunk;
buffer_pos += chunk;
skip = 0;
}
err = isize - sizeof(struct reiserfs_xattr_header);
xafile = lookup_one_len(name, xadir, namelen); if (xattr_hash(buffer, isize - sizeof(struct reiserfs_xattr_header)) !=
if (IS_ERR(xafile)) hash) {
return PTR_ERR(xafile); reiserfs_warning(inode->i_sb, "jdm-20002",
else if (!xafile->d_inode) { "Invalid hash for xattr (%s) associated "
dput(xafile); "with %k", name, INODE_PKEY(inode));
return -ENODATA; err = -EIO;
} }
if (!S_ISDIR(xafile->d_inode->i_mode)) out_dput:
err = notify_change(xafile, attrs); dput(dentry);
dput(xafile);
out:
return err; return err;
} }
int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) int reiserfs_xattr_del(struct inode *inode, const char *name)
{ {
struct dentry *dir; struct dentry *dir;
int err = 0; int err;
struct reiserfs_chown_buf buf;
unsigned int ia_valid = attrs->ia_valid;
/* Skip out, an xattr has no xattrs associated with it */
if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1 ||
!reiserfs_xattrs(inode->i_sb)) {
return 0;
}
reiserfs_read_lock_xattrs(inode->i_sb);
dir = open_xa_dir(inode, FL_READONLY); dir = open_xa_dir(inode, FL_READONLY);
reiserfs_read_unlock_xattrs(inode->i_sb);
if (IS_ERR(dir)) { if (IS_ERR(dir)) {
if (PTR_ERR(dir) != -ENODATA) err = PTR_ERR(dir);
err = PTR_ERR(dir);
goto out;
} else if (!dir->d_inode) {
dput(dir);
goto out; goto out;
} }
lock_kernel(); err = __reiserfs_xattr_del(dir, name, strlen(name));
dput(dir);
attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME);
buf.xadir = dir;
buf.attrs = attrs;
buf.inode = inode;
err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf); if (!err) {
if (err) { inode->i_ctime = CURRENT_TIME_SEC;
unlock_kernel(); mark_inode_dirty(inode);
goto out_dir;
} }
err = notify_change(dir, attrs);
unlock_kernel();
out_dir:
dput(dir);
out: out:
attrs->ia_valid = ia_valid;
return err; return err;
} }
...@@ -1101,6 +1100,94 @@ void reiserfs_xattr_unregister_handlers(void) ...@@ -1101,6 +1100,94 @@ void reiserfs_xattr_unregister_handlers(void)
write_unlock(&handler_lock); write_unlock(&handler_lock);
} }
static int reiserfs_check_acl(struct inode *inode, int mask)
{
struct posix_acl *acl;
int error = -EAGAIN; /* do regular unix permission checks by default */
reiserfs_read_lock_xattr_i(inode);
reiserfs_read_lock_xattrs(inode->i_sb);
acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
reiserfs_read_unlock_xattrs(inode->i_sb);
reiserfs_read_unlock_xattr_i(inode);
if (acl) {
if (!IS_ERR(acl)) {
error = posix_acl_permission(inode, acl, mask);
posix_acl_release(acl);
} else if (PTR_ERR(acl) != -ENODATA)
error = PTR_ERR(acl);
}
return error;
}
int reiserfs_permission(struct inode *inode, int mask)
{
/*
* We don't do permission checks on the internal objects.
* Permissions are determined by the "owning" object.
*/
if (IS_PRIVATE(inode))
return 0;
/*
* Stat data v1 doesn't support ACLs.
*/
if (get_inode_sd_version(inode) == STAT_DATA_V1)
return generic_permission(inode, mask, NULL);
else
return generic_permission(inode, mask, reiserfs_check_acl);
}
static int create_privroot(struct dentry *dentry)
{
int err;
struct inode *inode = dentry->d_parent->d_inode;
mutex_lock_nested(&inode->i_mutex, I_MUTEX_XATTR);
err = inode->i_op->mkdir(inode, dentry, 0700);
mutex_unlock(&inode->i_mutex);
if (err) {
dput(dentry);
dentry = NULL;
}
if (dentry && dentry->d_inode)
reiserfs_info(dentry->d_sb, "Created %s - reserved for xattr "
"storage.\n", PRIVROOT_NAME);
return err;
}
static int xattr_mount_check(struct super_block *s)
{
/* We need generation numbers to ensure that the oid mapping is correct
* v3.5 filesystems don't have them. */
if (!old_format_only(s)) {
set_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
} else if (reiserfs_xattrs_optional(s)) {
/* Old format filesystem, but optional xattrs have been enabled
* at mount time. Error out. */
reiserfs_warning(s, "jdm-20005",
"xattrs/ACLs not supported on pre v3.6 "
"format filesystem. Failing mount.");
return -EOPNOTSUPP;
} else {
/* Old format filesystem, but no optional xattrs have
* been enabled. This means we silently disable xattrs
* on the filesystem. */
clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
}
return 0;
}
#else
int __init reiserfs_xattr_register_handlers(void) { return 0; }
void reiserfs_xattr_unregister_handlers(void) {}
#endif
/* This will catch lookups from the fs root to .reiserfs_priv */ /* This will catch lookups from the fs root to .reiserfs_priv */
static int static int
xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name) xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name)
...@@ -1127,47 +1214,23 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags) ...@@ -1127,47 +1214,23 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
{ {
int err = 0; int err = 0;
/* We need generation numbers to ensure that the oid mapping is correct #ifdef CONFIG_REISERFS_FS_XATTR
* v3.5 filesystems don't have them. */ err = xattr_mount_check(s);
if (!old_format_only(s)) { if (err)
set_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
} else if (reiserfs_xattrs_optional(s)) {
/* Old format filesystem, but optional xattrs have been enabled
* at mount time. Error out. */
reiserfs_warning(s, "jdm-20005",
"xattrs/ACLs not supported on pre v3.6 "
"format filesystem. Failing mount.");
err = -EOPNOTSUPP;
goto error; goto error;
} else { #endif
/* Old format filesystem, but no optional xattrs have been enabled. This
* means we silently disable xattrs on the filesystem. */
clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
}
/* If we don't have the privroot located yet - go find it */ /* If we don't have the privroot located yet - go find it */
if (reiserfs_xattrs(s) && !REISERFS_SB(s)->priv_root) { if (!REISERFS_SB(s)->priv_root) {
struct dentry *dentry; struct dentry *dentry;
dentry = lookup_one_len(PRIVROOT_NAME, s->s_root, dentry = lookup_one_len(PRIVROOT_NAME, s->s_root,
strlen(PRIVROOT_NAME)); strlen(PRIVROOT_NAME));
if (!IS_ERR(dentry)) { if (!IS_ERR(dentry)) {
if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) { #ifdef CONFIG_REISERFS_FS_XATTR
struct inode *inode = dentry->d_parent->d_inode; if (!(mount_flags & MS_RDONLY) && !dentry->d_inode)
mutex_lock_nested(&inode->i_mutex, err = create_privroot(dentry);
I_MUTEX_XATTR); #endif
err = inode->i_op->mkdir(inode, dentry, 0700); if (!dentry->d_inode) {
mutex_unlock(&inode->i_mutex);
if (err) {
dput(dentry);
dentry = NULL;
}
if (dentry && dentry->d_inode)
reiserfs_info(s, "Created %s - "
"reserved for xattr "
"storage.\n",
PRIVROOT_NAME);
} else if (!dentry->d_inode) {
dput(dentry); dput(dentry);
dentry = NULL; dentry = NULL;
} }
...@@ -1178,73 +1241,37 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags) ...@@ -1178,73 +1241,37 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
s->s_root->d_op = &xattr_lookup_poison_ops; s->s_root->d_op = &xattr_lookup_poison_ops;
dentry->d_inode->i_flags |= S_PRIVATE; dentry->d_inode->i_flags |= S_PRIVATE;
REISERFS_SB(s)->priv_root = dentry; REISERFS_SB(s)->priv_root = dentry;
} else if (!(mount_flags & MS_RDONLY)) { /* xattrs are unavailable */ #ifdef CONFIG_REISERFS_FS_XATTR
/* If we're read-only it just means that the dir hasn't been /* xattrs are unavailable */
* created. Not an error -- just no xattrs on the fs. We'll } else if (!(mount_flags & MS_RDONLY)) {
* check again if we go read-write */ /* If we're read-only it just means that the dir
* hasn't been created. Not an error -- just no
* xattrs on the fs. We'll check again if we
* go read-write */
reiserfs_warning(s, "jdm-20006", reiserfs_warning(s, "jdm-20006",
"xattrs/ACLs enabled and couldn't " "xattrs/ACLs enabled and couldn't "
"find/create .reiserfs_priv. " "find/create .reiserfs_priv. "
"Failing mount."); "Failing mount.");
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
#endif
} }
} }
error: #ifdef CONFIG_REISERFS_FS_XATTR
/* This is only nonzero if there was an error initializing the xattr error:
* directory or if there is a condition where we don't support them. */
if (err) { if (err) {
clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
clear_bit(REISERFS_XATTRS_USER, &(REISERFS_SB(s)->s_mount_opt)); clear_bit(REISERFS_XATTRS_USER, &(REISERFS_SB(s)->s_mount_opt));
clear_bit(REISERFS_POSIXACL, &(REISERFS_SB(s)->s_mount_opt)); clear_bit(REISERFS_POSIXACL, &(REISERFS_SB(s)->s_mount_opt));
} }
#endif
/* The super_block MS_POSIXACL must mirror the (no)acl mount option. */ /* The super_block MS_POSIXACL must mirror the (no)acl mount option. */
s->s_flags = s->s_flags & ~MS_POSIXACL; s->s_flags = s->s_flags & ~MS_POSIXACL;
#ifdef CONFIG_REISERFS_FS_POSIX_ACL
if (reiserfs_posixacl(s)) if (reiserfs_posixacl(s))
s->s_flags |= MS_POSIXACL; s->s_flags |= MS_POSIXACL;
#endif
return err; return err;
} }
static int reiserfs_check_acl(struct inode *inode, int mask)
{
struct posix_acl *acl;
int error = -EAGAIN; /* do regular unix permission checks by default */
reiserfs_read_lock_xattr_i(inode);
reiserfs_read_lock_xattrs(inode->i_sb);
acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
reiserfs_read_unlock_xattrs(inode->i_sb);
reiserfs_read_unlock_xattr_i(inode);
if (acl) {
if (!IS_ERR(acl)) {
error = posix_acl_permission(inode, acl, mask);
posix_acl_release(acl);
} else if (PTR_ERR(acl) != -ENODATA)
error = PTR_ERR(acl);
}
return error;
}
int reiserfs_permission(struct inode *inode, int mask)
{
/*
* We don't do permission checks on the internal objects.
* Permissions are determined by the "owning" object.
*/
if (IS_PRIVATE(inode))
return 0;
/*
* Stat data v1 doesn't support ACLs.
*/
if (get_inode_sd_version(inode) == STAT_DATA_V1)
return generic_permission(inode, mask, NULL);
else
return generic_permission(inode, mask, reiserfs_check_acl);
}
...@@ -402,8 +402,8 @@ struct reiserfs_sb_info { ...@@ -402,8 +402,8 @@ struct reiserfs_sb_info {
int reserved_blocks; /* amount of blocks reserved for further allocations */ int reserved_blocks; /* amount of blocks reserved for further allocations */
spinlock_t bitmap_lock; /* this lock on now only used to protect reserved_blocks variable */ spinlock_t bitmap_lock; /* this lock on now only used to protect reserved_blocks variable */
struct dentry *priv_root; /* root of /.reiserfs_priv */ struct dentry *priv_root; /* root of /.reiserfs_priv */
#ifdef CONFIG_REISERFS_FS_XATTR
struct dentry *xattr_root; /* root of /.reiserfs_priv/.xa */ struct dentry *xattr_root; /* root of /.reiserfs_priv/.xa */
#ifdef CONFIG_REISERFS_FS_XATTR
struct rw_semaphore xattr_dir_sem; struct rw_semaphore xattr_dir_sem;
#endif #endif
int j_errno; int j_errno;
......
...@@ -43,6 +43,12 @@ struct reiserfs_xattr_handler { ...@@ -43,6 +43,12 @@ struct reiserfs_xattr_handler {
struct list_head handlers; struct list_head handlers;
}; };
int reiserfs_xattr_register_handlers(void) __init;
void reiserfs_xattr_unregister_handlers(void);
int reiserfs_xattr_init(struct super_block *sb, int mount_flags);
int reiserfs_delete_xattrs(struct inode *inode);
int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs);
#ifdef CONFIG_REISERFS_FS_XATTR #ifdef CONFIG_REISERFS_FS_XATTR
#define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir) #define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir)
ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name, ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name,
...@@ -51,9 +57,6 @@ int reiserfs_setxattr(struct dentry *dentry, const char *name, ...@@ -51,9 +57,6 @@ int reiserfs_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags); const void *value, size_t size, int flags);
ssize_t reiserfs_listxattr(struct dentry *dentry, char *buffer, size_t size); ssize_t reiserfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
int reiserfs_removexattr(struct dentry *dentry, const char *name); int reiserfs_removexattr(struct dentry *dentry, const char *name);
int reiserfs_delete_xattrs(struct inode *inode);
int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs);
int reiserfs_xattr_init(struct super_block *sb, int mount_flags);
int reiserfs_permission(struct inode *inode, int mask); int reiserfs_permission(struct inode *inode, int mask);
int reiserfs_xattr_del(struct inode *, const char *); int reiserfs_xattr_del(struct inode *, const char *);
...@@ -64,9 +67,6 @@ extern struct reiserfs_xattr_handler user_handler; ...@@ -64,9 +67,6 @@ extern struct reiserfs_xattr_handler user_handler;
extern struct reiserfs_xattr_handler trusted_handler; extern struct reiserfs_xattr_handler trusted_handler;
extern struct reiserfs_xattr_handler security_handler; extern struct reiserfs_xattr_handler security_handler;
int reiserfs_xattr_register_handlers(void) __init;
void reiserfs_xattr_unregister_handlers(void);
static inline void reiserfs_write_lock_xattrs(struct super_block *sb) static inline void reiserfs_write_lock_xattrs(struct super_block *sb)
{ {
down_write(&REISERFS_XATTR_DIR_SEM(sb)); down_write(&REISERFS_XATTR_DIR_SEM(sb));
...@@ -121,23 +121,6 @@ static inline void reiserfs_init_xattr_rwsem(struct inode *inode) ...@@ -121,23 +121,6 @@ static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
#define reiserfs_permission NULL #define reiserfs_permission NULL
#define reiserfs_xattr_register_handlers() 0
#define reiserfs_xattr_unregister_handlers()
static inline int reiserfs_delete_xattrs(struct inode *inode)
{
return 0;
};
static inline int reiserfs_chown_xattrs(struct inode *inode,
struct iattr *attrs)
{
return 0;
};
static inline int reiserfs_xattr_init(struct super_block *sb, int mount_flags)
{
sb->s_flags = (sb->s_flags & ~MS_POSIXACL); /* to be sure */
return 0;
};
static inline void reiserfs_init_xattr_rwsem(struct inode *inode) static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
{ {
} }
......
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