aboutsummaryrefslogtreecommitdiff
path: root/fs/reiserfs/xattr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/reiserfs/xattr.c')
-rw-r--r--fs/reiserfs/xattr.c271
1 files changed, 136 insertions, 135 deletions
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index 8e7deb0e696..ca416d099e7 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -33,55 +33,58 @@
* The xattrs themselves are protected by the xattr_sem.
*/
-#include <linux/reiserfs_fs.h>
+#include "reiserfs.h"
#include <linux/capability.h>
#include <linux/dcache.h>
#include <linux/namei.h>
#include <linux/errno.h>
+#include <linux/gfp.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/pagemap.h>
#include <linux/xattr.h>
-#include <linux/reiserfs_xattr.h>
-#include <linux/reiserfs_acl.h>
+#include "xattr.h"
+#include "acl.h"
#include <asm/uaccess.h>
#include <net/checksum.h>
-#include <linux/smp_lock.h>
#include <linux/stat.h>
#include <linux/quotaops.h>
+#include <linux/security.h>
+#include <linux/posix_acl_xattr.h>
#define PRIVROOT_NAME ".reiserfs_priv"
#define XAROOT_NAME "xattrs"
-/* Helpers for inode ops. We do this so that we don't have all the VFS
+/*
+ * Helpers for inode ops. We do this so that we don't have all the VFS
* overhead and also for proper i_mutex annotation.
- * dir->i_mutex must be held for all of them. */
+ * dir->i_mutex must be held for all of them.
+ */
#ifdef CONFIG_REISERFS_FS_XATTR
static int xattr_create(struct inode *dir, struct dentry *dentry, int mode)
{
BUG_ON(!mutex_is_locked(&dir->i_mutex));
- vfs_dq_init(dir);
- return dir->i_op->create(dir, dentry, mode, NULL);
+ return dir->i_op->create(dir, dentry, mode, true);
}
#endif
-static int xattr_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+static int xattr_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
BUG_ON(!mutex_is_locked(&dir->i_mutex));
- vfs_dq_init(dir);
return dir->i_op->mkdir(dir, dentry, mode);
}
-/* We use I_MUTEX_CHILD here to silence lockdep. It's safe because xattr
+/*
+ * We use I_MUTEX_CHILD here to silence lockdep. It's safe because xattr
* mutation ops aren't called during rename or splace, which are the
* only other users of I_MUTEX_CHILD. It violates the ordering, but that's
- * better than allocating another subclass just for this code. */
+ * better than allocating another subclass just for this code.
+ */
static int xattr_unlink(struct inode *dir, struct dentry *dentry)
{
int error;
BUG_ON(!mutex_is_locked(&dir->i_mutex));
- vfs_dq_init(dir);
mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
error = dir->i_op->unlink(dir, dentry);
@@ -96,17 +99,14 @@ static int xattr_rmdir(struct inode *dir, struct dentry *dentry)
{
int error;
BUG_ON(!mutex_is_locked(&dir->i_mutex));
- vfs_dq_init(dir);
mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
- dentry_unhash(dentry);
error = dir->i_op->rmdir(dir, dentry);
if (!error)
dentry->d_inode->i_flags |= S_DEAD;
mutex_unlock(&dentry->d_inode->i_mutex);
if (!error)
d_delete(dentry);
- dput(dentry);
return error;
}
@@ -170,10 +170,13 @@ static struct dentry *open_xa_dir(const struct inode *inode, int flags)
return xadir;
}
-/* The following are side effects of other operations that aren't explicitly
+/*
+ * 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. */
+ * or ownership changes, object deletions, etc.
+ */
struct reiserfs_dentry_buf {
+ struct dir_context ctx;
struct dentry *xadir;
int count;
struct dentry *dentries[8];
@@ -190,8 +193,8 @@ fill_with_dentries(void *buf, const char *name, int namelen, loff_t offset,
if (dbuf->count == ARRAY_SIZE(dbuf->dentries))
return -ENOSPC;
- if (name[0] == '.' && (name[1] == '\0' ||
- (name[1] == '.' && name[2] == '\0')))
+ if (name[0] == '.' && (namelen < 2 ||
+ (namelen == 2 && name[1] == '.')))
return 0;
dentry = lookup_one_len(name, dbuf->xadir, namelen);
@@ -226,9 +229,8 @@ static int reiserfs_for_each_xattr(struct inode *inode,
{
struct dentry *dir;
int i, err = 0;
- loff_t pos = 0;
struct reiserfs_dentry_buf buf = {
- .count = 0,
+ .ctx.actor = fill_with_dentries,
};
/* Skip out, an xattr has no xattrs associated with it */
@@ -245,48 +247,53 @@ static int reiserfs_for_each_xattr(struct inode *inode,
}
mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR);
- buf.xadir = dir;
- err = reiserfs_readdir_dentry(dir, &buf, fill_with_dentries, &pos);
- while ((err == 0 || err == -ENOSPC) && buf.count) {
- err = 0;
- for (i = 0; i < buf.count && buf.dentries[i]; i++) {
- int lerr = 0;
+ buf.xadir = dir;
+ while (1) {
+ err = reiserfs_readdir_inode(dir->d_inode, &buf.ctx);
+ if (err)
+ break;
+ if (!buf.count)
+ break;
+ for (i = 0; !err && i < buf.count && buf.dentries[i]; i++) {
struct dentry *dentry = buf.dentries[i];
- if (err == 0 && !S_ISDIR(dentry->d_inode->i_mode))
- lerr = action(dentry, data);
+ if (!S_ISDIR(dentry->d_inode->i_mode))
+ err = action(dentry, data);
dput(dentry);
buf.dentries[i] = NULL;
- err = lerr ?: err;
}
+ if (err)
+ break;
buf.count = 0;
- if (!err)
- err = reiserfs_readdir_dentry(dir, &buf,
- fill_with_dentries, &pos);
}
mutex_unlock(&dir->d_inode->i_mutex);
- /* Clean up after a failed readdir */
cleanup_dentry_buf(&buf);
if (!err) {
- /* We start a transaction here to avoid a ABBA situation
+ /*
+ * We start a transaction here to avoid a ABBA situation
* between the xattr root's i_mutex and the journal lock.
* This doesn't incur much additional overhead since the
* new transaction will just nest inside the
- * outer transaction. */
+ * outer transaction.
+ */
int blocks = JOURNAL_PER_BALANCE_CNT * 2 + 2 +
4 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb);
struct reiserfs_transaction_handle th;
+ reiserfs_write_lock(inode->i_sb);
err = journal_begin(&th, inode->i_sb, blocks);
+ reiserfs_write_unlock(inode->i_sb);
if (!err) {
int jerror;
mutex_lock_nested(&dir->d_parent->d_inode->i_mutex,
I_MUTEX_XATTR);
err = action(dir, data);
- jerror = journal_end(&th, inode->i_sb, blocks);
+ reiserfs_write_lock(inode->i_sb);
+ jerror = journal_end(&th);
+ reiserfs_write_unlock(inode->i_sb);
mutex_unlock(&dir->d_parent->d_inode->i_mutex);
err = jerror ?: err;
}
@@ -314,7 +321,19 @@ static int delete_one_xattr(struct dentry *dentry, void *data)
static int chown_one_xattr(struct dentry *dentry, void *data)
{
struct iattr *attrs = data;
- return reiserfs_setattr(dentry, attrs);
+ int ia_valid = attrs->ia_valid;
+ int err;
+
+ /*
+ * We only want the ownership bits. Otherwise, we'll do
+ * things like change a directory to a regular file if
+ * ATTR_MODE is set.
+ */
+ attrs->ia_valid &= (ATTR_UID|ATTR_GID);
+ err = reiserfs_setattr(dentry, attrs);
+ attrs->ia_valid = ia_valid;
+
+ return err;
}
/* No i_mutex, but the inode is unconnected. */
@@ -338,9 +357,11 @@ int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs)
}
#ifdef CONFIG_REISERFS_FS_XATTR
-/* Returns a dentry corresponding to a specific extended attribute file
+/*
+ * 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. */
+ * valid or negative dentry, or an error is returned.
+ */
static struct dentry *xattr_lookup(struct inode *inode, const char *name,
int flags)
{
@@ -389,8 +410,10 @@ static struct page *reiserfs_get_page(struct inode *dir, size_t n)
{
struct address_space *mapping = dir->i_mapping;
struct page *page;
- /* We can deadlock if we try to free dentries,
- and an unlink/rmdir has just occured - GFP_NOFS avoids this */
+ /*
+ * We can deadlock if we try to free dentries,
+ * and an unlink/rmdir has just occurred - GFP_NOFS avoids this
+ */
mapping_set_gfp_mask(mapping, GFP_NOFS);
page = read_mapping_page(mapping, n >> PAGE_CACHE_SHIFT, NULL);
if (!IS_ERR(page)) {
@@ -400,7 +423,7 @@ static struct page *reiserfs_get_page(struct inode *dir, size_t n)
}
return page;
- fail:
+fail:
reiserfs_put_page(page);
return ERR_PTR(-EIO);
}
@@ -412,13 +435,11 @@ static inline __u32 xattr_hash(const char *msg, int len)
int reiserfs_commit_write(struct file *f, struct page *page,
unsigned from, unsigned to);
-int reiserfs_prepare_write(struct file *f, struct page *page,
- unsigned from, unsigned to);
static void update_ctime(struct inode *inode)
{
struct timespec now = current_fs_time(inode->i_sb);
- if (hlist_unhashed(&inode->i_hash) || !inode->i_nlink ||
+ if (inode_unhashed(inode) || !inode->i_nlink ||
timespec_equal(&inode->i_ctime, &now))
return;
@@ -477,8 +498,10 @@ reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th,
if (get_inode_sd_version(inode) == STAT_DATA_V1)
return -EOPNOTSUPP;
- if (!buffer)
- return lookup_and_delete_xattr(inode, name);
+ if (!buffer) {
+ err = lookup_and_delete_xattr(inode, name);
+ return err;
+ }
dentry = xattr_lookup(inode, name, flags);
if (IS_ERR(dentry))
@@ -515,8 +538,8 @@ reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th,
rxh->h_hash = cpu_to_le32(xahash);
}
- err = reiserfs_prepare_write(NULL, page, page_offset,
- page_offset + chunk + skip);
+ reiserfs_write_lock(inode->i_sb);
+ err = __reiserfs_write_begin(page, page_offset, chunk + skip);
if (!err) {
if (buffer)
memcpy(data + skip, buffer + buffer_pos, chunk);
@@ -524,6 +547,7 @@ reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th,
page_offset + chunk +
skip);
}
+ reiserfs_write_unlock(inode->i_sb);
unlock_page(page);
reiserfs_put_page(page);
buffer_pos += chunk;
@@ -537,13 +561,14 @@ reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th,
if (!err && new_size < i_size_read(dentry->d_inode)) {
struct iattr newattrs = {
.ia_ctime = current_fs_time(inode->i_sb),
- .ia_size = buffer_size,
+ .ia_size = new_size,
.ia_valid = ATTR_SIZE | ATTR_CTIME,
};
+
mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_XATTR);
- down_write(&dentry->d_inode->i_alloc_sem);
+ inode_dio_wait(dentry->d_inode);
+
err = reiserfs_setattr(dentry, &newattrs);
- up_write(&dentry->d_inode->i_alloc_sem);
mutex_unlock(&dentry->d_inode->i_mutex);
} else
update_ctime(inode);
@@ -567,18 +592,19 @@ int reiserfs_xattr_set(struct inode *inode, const char *name,
reiserfs_write_lock(inode->i_sb);
error = journal_begin(&th, inode->i_sb, jbegin_count);
+ reiserfs_write_unlock(inode->i_sb);
if (error) {
- reiserfs_write_unlock(inode->i_sb);
return error;
}
error = reiserfs_xattr_set_handle(&th, inode, name,
buffer, buffer_size, flags);
- error2 = journal_end(&th, inode->i_sb, jbegin_count);
+ reiserfs_write_lock(inode->i_sb);
+ error2 = journal_end(&th);
+ reiserfs_write_unlock(inode->i_sb);
if (error == 0)
error = error2;
- reiserfs_write_unlock(inode->i_sb);
return error;
}
@@ -601,8 +627,10 @@ reiserfs_xattr_get(struct inode *inode, const char *name, void *buffer,
if (name == NULL)
return -EINVAL;
- /* We can't have xattrs attached to v1 items since they don't have
- * generation numbers */
+ /*
+ * We can't have xattrs attached to v1 items since they don't have
+ * generation numbers
+ */
if (get_inode_sd_version(inode) == STAT_DATA_V1)
return -EOPNOTSUPP;
@@ -702,11 +730,11 @@ out:
(handler) = *(handlers)++)
/* This is the implementation for the xattr plugin infrastructure */
-static inline struct xattr_handler *
-find_xattr_handler_prefix(struct xattr_handler **handlers,
+static inline const struct xattr_handler *
+find_xattr_handler_prefix(const struct xattr_handler **handlers,
const char *name)
{
- struct xattr_handler *xah;
+ const struct xattr_handler *xah;
if (!handlers)
return NULL;
@@ -727,15 +755,14 @@ ssize_t
reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer,
size_t size)
{
- struct inode *inode = dentry->d_inode;
- struct xattr_handler *handler;
+ const struct xattr_handler *handler;
- handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name);
+ handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
- if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1)
+ if (!handler || get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
return -EOPNOTSUPP;
- return handler->get(inode, name, buffer, size);
+ return handler->get(dentry, name, buffer, size, handler->flags);
}
/*
@@ -747,15 +774,14 @@ int
reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags)
{
- struct inode *inode = dentry->d_inode;
- struct xattr_handler *handler;
+ const struct xattr_handler *handler;
- handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name);
+ handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
- if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1)
+ if (!handler || get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
return -EOPNOTSUPP;
- return handler->set(inode, name, value, size, flags);
+ return handler->set(dentry, name, value, size, flags, handler->flags);
}
/*
@@ -765,21 +791,21 @@ reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value,
*/
int reiserfs_removexattr(struct dentry *dentry, const char *name)
{
- struct inode *inode = dentry->d_inode;
- struct xattr_handler *handler;
- handler = find_xattr_handler_prefix(inode->i_sb->s_xattr, name);
+ const struct xattr_handler *handler;
+ handler = find_xattr_handler_prefix(dentry->d_sb->s_xattr, name);
- if (!handler || get_inode_sd_version(inode) == STAT_DATA_V1)
+ if (!handler || get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
return -EOPNOTSUPP;
- return handler->set(inode, name, NULL, 0, XATTR_REPLACE);
+ return handler->set(dentry, name, NULL, 0, XATTR_REPLACE, handler->flags);
}
struct listxattr_buf {
+ struct dir_context ctx;
size_t size;
size_t pos;
char *buf;
- struct inode *inode;
+ struct dentry *dentry;
};
static int listxattr_filler(void *buf, const char *name, int namelen,
@@ -789,18 +815,20 @@ static int listxattr_filler(void *buf, const char *name, int namelen,
size_t size;
if (name[0] != '.' ||
(namelen != 1 && (name[1] != '.' || namelen != 2))) {
- struct xattr_handler *handler;
- handler = find_xattr_handler_prefix(b->inode->i_sb->s_xattr,
+ const struct xattr_handler *handler;
+ handler = find_xattr_handler_prefix(b->dentry->d_sb->s_xattr,
name);
if (!handler) /* Unsupported xattr name */
return 0;
if (b->buf) {
- size = handler->list(b->inode, b->buf + b->pos,
- b->size, name, namelen);
+ size = handler->list(b->dentry, b->buf + b->pos,
+ b->size, name, namelen,
+ handler->flags);
if (size > b->size)
return -ERANGE;
} else {
- size = handler->list(b->inode, NULL, 0, name, namelen);
+ size = handler->list(b->dentry, NULL, 0, name,
+ namelen, handler->flags);
}
b->pos += size;
@@ -819,9 +847,9 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
{
struct dentry *dir;
int err = 0;
- loff_t pos = 0;
struct listxattr_buf buf = {
- .inode = dentry->d_inode,
+ .ctx.actor = listxattr_filler,
+ .dentry = dentry,
.buf = buffer,
.size = buffer ? size : 0,
};
@@ -842,7 +870,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
}
mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR);
- err = reiserfs_readdir_dentry(dir, &buf, listxattr_filler, &pos);
+ err = reiserfs_readdir_inode(dir->d_inode, &buf.ctx);
mutex_unlock(&dir->d_inode->i_mutex);
if (!err)
@@ -853,24 +881,6 @@ out:
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 */
-
- acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
-
- 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;
-}
-
static int create_privroot(struct dentry *dentry)
{
int err;
@@ -900,7 +910,7 @@ static int create_privroot(struct dentry *dentry) { return 0; }
#endif
/* Actual operations that are exported to VFS-land */
-struct xattr_handler *reiserfs_xattr_handlers[] = {
+static const struct xattr_handler *reiserfs_xattr_handlers[] = {
#ifdef CONFIG_REISERFS_FS_XATTR
&reiserfs_xattr_user_handler,
&reiserfs_xattr_trusted_handler,
@@ -909,20 +919,24 @@ struct xattr_handler *reiserfs_xattr_handlers[] = {
&reiserfs_xattr_security_handler,
#endif
#ifdef CONFIG_REISERFS_FS_POSIX_ACL
- &reiserfs_posix_acl_access_handler,
- &reiserfs_posix_acl_default_handler,
+ &posix_acl_access_xattr_handler,
+ &posix_acl_default_xattr_handler,
#endif
NULL
};
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. */
+ /*
+ * We need generation numbers to ensure that the oid mapping is correct
+ * v3.5 filesystems don't have them.
+ */
if (old_format_only(s)) {
if (reiserfs_xattrs_optional(s)) {
- /* Old format filesystem, but optional xattrs have
- * been enabled. Error out. */
+ /*
+ * Old format filesystem, but optional xattrs have
+ * been enabled. Error out.
+ */
reiserfs_warning(s, "jdm-2005",
"xattrs/ACLs not supported "
"on pre-v3.6 format filesystems. "
@@ -943,31 +957,16 @@ int reiserfs_permission(struct inode *inode, int mask)
if (IS_PRIVATE(inode))
return 0;
-#ifdef CONFIG_REISERFS_FS_XATTR
- /*
- * Stat data v1 doesn't support ACLs.
- */
- if (get_inode_sd_version(inode) != STAT_DATA_V1)
- return generic_permission(inode, mask, reiserfs_check_acl);
-#endif
- return generic_permission(inode, mask, NULL);
+ return generic_permission(inode, mask);
}
-/* This will catch lookups from the fs root to .reiserfs_priv */
-static int
-xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name)
+static int xattr_hide_revalidate(struct dentry *dentry, unsigned int flags)
{
- struct dentry *priv_root = REISERFS_SB(dentry->d_sb)->priv_root;
- if (container_of(q1, struct dentry, d_name) == priv_root)
- return -ENOENT;
- if (q1->len == name->len &&
- !memcmp(q1->name, name->name, name->len))
- return 0;
- return 1;
+ return -EPERM;
}
static const struct dentry_operations xattr_lookup_poison_ops = {
- .d_compare = xattr_lookup_poison,
+ .d_revalidate = xattr_hide_revalidate,
};
int reiserfs_lookup_privroot(struct super_block *s)
@@ -981,7 +980,7 @@ int reiserfs_lookup_privroot(struct super_block *s)
strlen(PRIVROOT_NAME));
if (!IS_ERR(dentry)) {
REISERFS_SB(s)->priv_root = dentry;
- s->s_root->d_op = &xattr_lookup_poison_ops;
+ d_set_d_op(dentry, &xattr_lookup_poison_ops);
if (dentry->d_inode)
dentry->d_inode->i_flags |= S_PRIVATE;
} else
@@ -991,9 +990,11 @@ int reiserfs_lookup_privroot(struct super_block *s)
return err;
}
-/* We need to take a copy of the mount flags since things like
+/*
+ * We need to take a copy of the mount flags since things like
* MS_RDONLY don't get set until *after* we're called.
- * mount_flags != mount_options */
+ * mount_flags != mount_options
+ */
int reiserfs_xattr_init(struct super_block *s, int mount_flags)
{
int err = 0;
@@ -1026,8 +1027,8 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
error:
if (err) {
- clear_bit(REISERFS_XATTRS_USER, &(REISERFS_SB(s)->s_mount_opt));
- clear_bit(REISERFS_POSIXACL, &(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);
}
/* The super_block MS_POSIXACL must mirror the (no)acl mount option. */