Merge git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-linus
[safe/jmp/linux-2.6] / fs / reiserfs / xattr.c
index 628075c..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)
@@ -235,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) {
@@ -283,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);
@@ -443,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);
        }
 
@@ -477,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;
@@ -537,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);
@@ -727,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);
 }
 
 /*
@@ -747,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);
 }
 
 /*
@@ -765,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,
@@ -790,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;
@@ -821,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,
        };
@@ -871,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;
@@ -951,21 +954,32 @@ static int xattr_mount_check(struct super_block *s)
        return 0;
 }
 
-/* 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)
+int reiserfs_permission(struct inode *inode, int mask)
 {
-       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))
+       /*
+        * We don't do permission checks on the internal objects.
+        * Permissions are determined by the "owning" object.
+        */
+       if (IS_PRIVATE(inode))
                return 0;
-       return 1;
+
+#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);
+}
+
+static int xattr_hide_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+       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)
@@ -974,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
@@ -1002,14 +1016,14 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
                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,