Merge git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-linus
[safe/jmp/linux-2.6] / fs / reiserfs / xattr.c
index c779844..e7cc00e 100644 (file)
@@ -38,6 +38,7 @@
 #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>
@@ -46,9 +47,9 @@
 #include <linux/reiserfs_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>
 
 #define PRIVROOT_NAME ".reiserfs_priv"
 #define XAROOT_NAME   "xattrs"
@@ -61,7 +62,6 @@
 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);
 }
 #endif
@@ -69,7 +69,6 @@ static int xattr_create(struct inode *dir, struct dentry *dentry, int mode)
 static int xattr_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
        BUG_ON(!mutex_is_locked(&dir->i_mutex));
-       vfs_dq_init(dir);
        return dir->i_op->mkdir(dir, dentry, mode);
 }
 
@@ -81,9 +80,9 @@ 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);
+       reiserfs_mutex_lock_nested_safe(&dentry->d_inode->i_mutex,
+                                       I_MUTEX_CHILD, dir->i_sb);
        error = dir->i_op->unlink(dir, dentry);
        mutex_unlock(&dentry->d_inode->i_mutex);
 
@@ -96,9 +95,9 @@ 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);
+       reiserfs_mutex_lock_nested_safe(&dentry->d_inode->i_mutex,
+                                       I_MUTEX_CHILD, dir->i_sb);
        dentry_unhash(dentry);
        error = dir->i_op->rmdir(dir, dentry);
        if (!error)
@@ -123,7 +122,9 @@ static struct dentry *open_xa_root(struct super_block *sb, int flags)
        mutex_lock_nested(&privroot->d_inode->i_mutex, I_MUTEX_XATTR);
 
        xaroot = dget(REISERFS_SB(sb)->xattr_root);
-       if (!xaroot->d_inode) {
+       if (!xaroot)
+               xaroot = ERR_PTR(-ENODATA);
+       else if (!xaroot->d_inode) {
                int err = -ENODATA;
                if (xattr_may_create(flags))
                        err = xattr_mkdir(privroot->d_inode, xaroot, 0700);
@@ -233,16 +234,22 @@ static int reiserfs_for_each_xattr(struct inode *inode,
        if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1)
                return 0;
 
+       reiserfs_write_unlock(inode->i_sb);
        dir = open_xa_dir(inode, XATTR_REPLACE);
        if (IS_ERR(dir)) {
                err = PTR_ERR(dir);
+               reiserfs_write_lock(inode->i_sb);
                goto out;
        } else if (!dir->d_inode) {
                err = 0;
+               reiserfs_write_lock(inode->i_sb);
                goto out_dir;
        }
 
        mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR);
+
+       reiserfs_write_lock(inode->i_sb);
+
        buf.xadir = dir;
        err = reiserfs_readdir_dentry(dir, &buf, fill_with_dentries, &pos);
        while ((err == 0 || err == -ENOSPC) && buf.count) {
@@ -281,8 +288,9 @@ static int reiserfs_for_each_xattr(struct inode *inode,
                err = journal_begin(&th, inode->i_sb, blocks);
                if (!err) {
                        int jerror;
-                       mutex_lock_nested(&dir->d_parent->d_inode->i_mutex,
-                                         I_MUTEX_XATTR);
+                       reiserfs_mutex_lock_nested_safe(
+                                         &dir->d_parent->d_inode->i_mutex,
+                                         I_MUTEX_XATTR, inode->i_sb);
                        err = action(dir, data);
                        jerror = journal_end(&th, inode->i_sb, blocks);
                        mutex_unlock(&dir->d_parent->d_inode->i_mutex);
@@ -441,7 +449,9 @@ static int lookup_and_delete_xattr(struct inode *inode, const char *name)
        }
 
        if (dentry->d_inode) {
+               reiserfs_write_lock(inode->i_sb);
                err = xattr_unlink(xadir->d_inode, dentry);
+               reiserfs_write_unlock(inode->i_sb);
                update_ctime(inode);
        }
 
@@ -475,15 +485,24 @@ 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);
+       reiserfs_write_unlock(inode->i_sb);
+
+       if (!buffer) {
+               err = lookup_and_delete_xattr(inode, name);
+               reiserfs_write_lock(inode->i_sb);
+               return err;
+       }
 
        dentry = xattr_lookup(inode, name, flags);
-       if (IS_ERR(dentry))
+       if (IS_ERR(dentry)) {
+               reiserfs_write_lock(inode->i_sb);
                return PTR_ERR(dentry);
+       }
 
        down_write(&REISERFS_I(inode)->i_xattr_sem);
 
+       reiserfs_write_lock(inode->i_sb);
+
        xahash = xattr_hash(buffer, buffer_size);
        while (buffer_pos < buffer_size || buffer_pos == 0) {
                size_t chunk;
@@ -535,11 +554,15 @@ 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,
                };
+
+               reiserfs_write_unlock(inode->i_sb);
                mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_XATTR);
                down_write(&dentry->d_inode->i_alloc_sem);
+               reiserfs_write_lock(inode->i_sb);
+
                err = reiserfs_setattr(dentry, &newattrs);
                up_write(&dentry->d_inode->i_alloc_sem);
                mutex_unlock(&dentry->d_inode->i_mutex);
@@ -685,20 +708,6 @@ out:
        return err;
 }
 
-/* Actual operations that are exported to VFS-land */
-struct xattr_handler *reiserfs_xattr_handlers[] = {
-       &reiserfs_xattr_user_handler,
-       &reiserfs_xattr_trusted_handler,
-#ifdef CONFIG_REISERFS_FS_SECURITY
-       &reiserfs_xattr_security_handler,
-#endif
-#ifdef CONFIG_REISERFS_FS_POSIX_ACL
-       &reiserfs_posix_acl_access_handler,
-       &reiserfs_posix_acl_default_handler,
-#endif
-       NULL
-};
-
 /*
  * In order to implement different sets of xattr operations for each xattr
  * prefix with the generic xattr API, a filesystem should create a
@@ -739,15 +748,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;
 
-       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);
 }
 
 /*
@@ -759,15 +767,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;
 
-       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);
 }
 
 /*
@@ -777,21 +784,20 @@ 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);
+       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 {
        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,
@@ -802,17 +808,19 @@ static int listxattr_filler(void *buf, const char *name, int namelen,
        if (name[0] != '.' ||
            (namelen != 1 && (name[1] != '.' || namelen != 2))) {
                struct xattr_handler *handler;
-               handler = find_xattr_handler_prefix(b->inode->i_sb->s_xattr,
+               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;
@@ -833,7 +841,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
        int err = 0;
        loff_t pos = 0;
        struct listxattr_buf buf = {
-               .inode = dentry->d_inode,
+               .dentry = dentry,
                .buf = buffer,
                .size = buffer ? size : 0,
        };
@@ -841,7 +849,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
        if (!dentry->d_inode)
                return -EINVAL;
 
-       if (!reiserfs_xattrs(dentry->d_sb) ||
+       if (!dentry->d_sb->s_xattr ||
            get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
                return -EOPNOTSUPP;
 
@@ -883,23 +891,6 @@ static int reiserfs_check_acl(struct inode *inode, int mask)
        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;
@@ -922,6 +913,28 @@ static int create_privroot(struct dentry *dentry)
        return 0;
 }
 
+#else
+int __init reiserfs_xattr_register_handlers(void) { return 0; }
+void reiserfs_xattr_unregister_handlers(void) {}
+static int create_privroot(struct dentry *dentry) { return 0; }
+#endif
+
+/* Actual operations that are exported to VFS-land */
+struct xattr_handler *reiserfs_xattr_handlers[] = {
+#ifdef CONFIG_REISERFS_FS_XATTR
+       &reiserfs_xattr_user_handler,
+       &reiserfs_xattr_trusted_handler,
+#endif
+#ifdef CONFIG_REISERFS_FS_SECURITY
+       &reiserfs_xattr_security_handler,
+#endif
+#ifdef CONFIG_REISERFS_FS_POSIX_ACL
+       &reiserfs_posix_acl_access_handler,
+       &reiserfs_posix_acl_default_handler,
+#endif
+       NULL
+};
+
 static int xattr_mount_check(struct super_block *s)
 {
        /* We need generation numbers to ensure that the oid mapping is correct
@@ -941,26 +954,32 @@ static int xattr_mount_check(struct super_block *s)
        return 0;
 }
 
-#else
-int __init reiserfs_xattr_register_handlers(void) { return 0; }
-void reiserfs_xattr_unregister_handlers(void) {}
+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;
+
+#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);
+}
 
-/* 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, struct nameidata *nd)
 {
-       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)
@@ -969,12 +988,12 @@ int reiserfs_lookup_privroot(struct super_block *s)
        int err = 0;
 
        /* If we don't have the privroot located yet - go find it */
-       mutex_lock(&s->s_root->d_inode->i_mutex);
+       reiserfs_mutex_lock_safe(&s->s_root->d_inode->i_mutex, s);
        dentry = lookup_one_len(PRIVROOT_NAME, s->s_root,
                                strlen(PRIVROOT_NAME));
        if (!IS_ERR(dentry)) {
                REISERFS_SB(s)->priv_root = dentry;
-               s->s_root->d_op = &xattr_lookup_poison_ops;
+               dentry->d_op = &xattr_lookup_poison_ops;
                if (dentry->d_inode)
                        dentry->d_inode->i_flags |= S_PRIVATE;
        } else
@@ -992,20 +1011,19 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
        int err = 0;
        struct dentry *privroot = REISERFS_SB(s)->priv_root;
 
-#ifdef CONFIG_REISERFS_FS_XATTR
        err = xattr_mount_check(s);
        if (err)
                goto error;
 
        if (!privroot->d_inode && !(mount_flags & MS_RDONLY)) {
-               mutex_lock(&s->s_root->d_inode->i_mutex);
+               reiserfs_mutex_lock_safe(&s->s_root->d_inode->i_mutex, s);
                err = create_privroot(REISERFS_SB(s)->priv_root);
                mutex_unlock(&s->s_root->d_inode->i_mutex);
        }
 
        if (privroot->d_inode) {
                s->s_xattr = reiserfs_xattr_handlers;
-               mutex_lock(&privroot->d_inode->i_mutex);
+               reiserfs_mutex_lock_safe(&privroot->d_inode->i_mutex, s);
                if (!REISERFS_SB(s)->xattr_root) {
                        struct dentry *dentry;
                        dentry = lookup_one_len(XAROOT_NAME, privroot,
@@ -1023,14 +1041,11 @@ error:
                clear_bit(REISERFS_XATTRS_USER, &(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. */
-#ifdef CONFIG_REISERFS_FS_POSIX_ACL
        if (reiserfs_posixacl(s))
                s->s_flags |= MS_POSIXACL;
        else
-#endif
                s->s_flags &= ~MS_POSIXACL;
 
        return err;