nfsd41: match clientid establishment method
[safe/jmp/linux-2.6] / fs / reiserfs / xattr.c
index e386d3d..ad92461 100644 (file)
@@ -30,6 +30,7 @@
  */
 
 #include <linux/reiserfs_fs.h>
+#include <linux/capability.h>
 #include <linux/dcache.h>
 #include <linux/namei.h>
 #include <linux/errno.h>
 #include <linux/xattr.h>
 #include <linux/reiserfs_xattr.h>
 #include <linux/reiserfs_acl.h>
-#include <linux/mbcache.h>
 #include <asm/uaccess.h>
-#include <asm/checksum.h>
+#include <net/checksum.h>
 #include <linux/smp_lock.h>
 #include <linux/stat.h>
-#include <asm/semaphore.h>
 
 #define FL_READONLY 128
 #define FL_DIR_SEM_HELD 256
 static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char
                                                                *prefix);
 
-static struct dentry *create_xa_root(struct super_block *sb)
+/* Returns the dentry referring to the root of the extended attribute
+ * 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
+ * attempt to create it. On error, we return a pointer-encoded error.
+ */
+static struct dentry *get_xa_root(struct super_block *sb, int flags)
 {
        struct dentry *privroot = dget(REISERFS_SB(sb)->priv_root);
        struct dentry *xaroot;
 
        /* This needs to be created at mount-time */
        if (!privroot)
-               return ERR_PTR(-EOPNOTSUPP);
+               return ERR_PTR(-ENODATA);
 
-       xaroot = lookup_one_len(XAROOT_NAME, privroot, strlen(XAROOT_NAME));
-       if (IS_ERR(xaroot)) {
+       mutex_lock_nested(&privroot->d_inode->i_mutex, I_MUTEX_XATTR);
+       if (REISERFS_SB(sb)->xattr_root) {
+               xaroot = dget(REISERFS_SB(sb)->xattr_root);
                goto out;
-       } else if (!xaroot->d_inode) {
-               int err;
-               down(&privroot->d_inode->i_sem);
-               err =
-                   privroot->d_inode->i_op->mkdir(privroot->d_inode, xaroot,
-                                                  0700);
-               up(&privroot->d_inode->i_sem);
-
-               if (err) {
-                       dput(xaroot);
-                       dput(privroot);
-                       return ERR_PTR(err);
-               }
-               REISERFS_SB(sb)->xattr_root = dget(xaroot);
        }
 
-      out:
-       dput(privroot);
-       return xaroot;
-}
-
-/* This will return a dentry, or error, refering to the xa root directory.
- * If the xa root doesn't exist yet, the dentry will be returned without
- * an associated inode. This dentry can be used with ->mkdir to create
- * the xa directory. */
-static struct dentry *__get_xa_root(struct super_block *s)
-{
-       struct dentry *privroot = dget(REISERFS_SB(s)->priv_root);
-       struct dentry *xaroot = NULL;
-
-       if (IS_ERR(privroot) || !privroot)
-               return privroot;
-
        xaroot = lookup_one_len(XAROOT_NAME, privroot, strlen(XAROOT_NAME));
        if (IS_ERR(xaroot)) {
                goto out;
        } else if (!xaroot->d_inode) {
-               dput(xaroot);
-               xaroot = NULL;
-               goto out;
+               int err = -ENODATA;
+               if (flags == 0 || flags & XATTR_CREATE)
+                       err = privroot->d_inode->i_op->mkdir(privroot->d_inode,
+                                                            xaroot, 0700);
+               if (err) {
+                       dput(xaroot);
+                       xaroot = ERR_PTR(err);
+                       goto out;
+               }
        }
-
-       REISERFS_SB(s)->xattr_root = dget(xaroot);
+       REISERFS_SB(sb)->xattr_root = dget(xaroot);
 
       out:
+       mutex_unlock(&privroot->d_inode->i_mutex);
        dput(privroot);
        return xaroot;
 }
 
-/* Returns the dentry (or NULL) referring to the root of the extended
- * attribute directory tree. If it has already been retreived, it is used.
- * Otherwise, we attempt to retreive it from disk. It may also return
- * a pointer-encoded error.
- */
-static inline struct dentry *get_xa_root(struct super_block *s)
-{
-       struct dentry *dentry = dget(REISERFS_SB(s)->xattr_root);
-
-       if (!dentry)
-               dentry = __get_xa_root(s);
-
-       return dentry;
-}
-
 /* Opens the directory corresponding to the inode's extended attribute store.
  * If flags allow, the tree to the directory may be created. If creation is
  * prohibited, -ENODATA is returned. */
@@ -138,21 +103,11 @@ static struct dentry *open_xa_dir(const struct inode *inode, int flags)
        struct dentry *xaroot, *xadir;
        char namebuf[17];
 
-       xaroot = get_xa_root(inode->i_sb);
-       if (IS_ERR(xaroot)) {
+       xaroot = get_xa_root(inode->i_sb, flags);
+       if (IS_ERR(xaroot))
                return xaroot;
-       } else if (!xaroot) {
-               if (flags == 0 || flags & XATTR_CREATE) {
-                       xaroot = create_xa_root(inode->i_sb);
-                       if (IS_ERR(xaroot))
-                               return xaroot;
-               }
-               if (!xaroot)
-                       return ERR_PTR(-ENODATA);
-       }
 
        /* ok, we have xaroot open */
-
        snprintf(namebuf, sizeof(namebuf), "%X.%X",
                 le32_to_cpu(INODE_PKEY(inode)->k_objectid),
                 inode->i_generation);
@@ -199,8 +154,8 @@ static struct dentry *get_xa_file_dentry(const struct inode *inode,
 
        xadir = open_xa_dir(inode, flags);
        if (IS_ERR(xadir)) {
-               return ERR_PTR(PTR_ERR(xadir));
-       } else if (xadir && !xadir->d_inode) {
+               return ERR_CAST(xadir);
+       } else if (!xadir->d_inode) {
                dput(xadir);
                return ERR_PTR(-ENODATA);
        }
@@ -208,7 +163,7 @@ static struct dentry *get_xa_file_dentry(const struct inode *inode,
        xafile = lookup_one_len(name, xadir, strlen(name));
        if (IS_ERR(xafile)) {
                dput(xadir);
-               return ERR_PTR(PTR_ERR(xafile));
+               return ERR_CAST(xafile);
        }
 
        if (xafile->d_inode) {  /* file exists */
@@ -220,7 +175,7 @@ static struct dentry *get_xa_file_dentry(const struct inode *inode,
        } else if (flags & XATTR_REPLACE || flags & FL_READONLY) {
                goto out;
        } else {
-               /* inode->i_sem is down, so nothing else can try to create
+               /* 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);
@@ -235,28 +190,11 @@ static struct dentry *get_xa_file_dentry(const struct inode *inode,
        dput(xadir);
        if (err)
                xafile = ERR_PTR(err);
-       return xafile;
-}
-
-/* Opens a file pointer to the attribute associated with inode */
-static struct file *open_xa_file(const struct inode *inode, const char *name,
-                                int flags)
-{
-       struct dentry *xafile;
-       struct file *fp;
-
-       xafile = get_xa_file_dentry(inode, name, flags);
-       if (IS_ERR(xafile))
-               return ERR_PTR(PTR_ERR(xafile));
        else if (!xafile->d_inode) {
                dput(xafile);
-               return ERR_PTR(-ENODATA);
+               xafile = ERR_PTR(-ENODATA);
        }
-
-       fp = dentry_open(xafile, NULL, O_RDWR);
-       /* dentry_open dputs the dentry if it fails */
-
-       return fp;
+       return xafile;
 }
 
 /*
@@ -269,12 +207,11 @@ static struct file *open_xa_file(const struct inode *inode, const char *name,
  * and don't mess with f->f_pos, but the idea is the same.  Do some
  * action on each and every entry in the directory.
  *
- * we're called with i_sem held, so there are no worries about the directory
+ * we're called with i_mutex held, so there are no worries about the directory
  * changing underneath us.
  */
-static int __xattr_readdir(struct file *filp, void *dirent, filldir_t filldir)
+static int __xattr_readdir(struct inode *inode, void *dirent, filldir_t filldir)
 {
-       struct inode *inode = filp->f_dentry->d_inode;
        struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */
        INITIALIZE_PATH(path_to_entry);
        struct buffer_head *bh;
@@ -368,15 +305,13 @@ static int __xattr_readdir(struct file *filp, void *dirent, filldir_t filldir)
                if (d_reclen <= 32) {
                        local_buf = small_buf;
                } else {
-                       local_buf =
-                           reiserfs_kmalloc(d_reclen, GFP_NOFS, inode->i_sb);
+                       local_buf = kmalloc(d_reclen, GFP_NOFS);
                        if (!local_buf) {
                                pathrelse(&path_to_entry);
                                return -ENOMEM;
                        }
                        if (item_moved(&tmp_ih, &path_to_entry)) {
-                               reiserfs_kfree(local_buf, d_reclen,
-                                              inode->i_sb);
+                               kfree(local_buf);
 
                                /* sigh, must retry.  Do this same offset again */
                                next_pos = d_off;
@@ -399,13 +334,12 @@ static int __xattr_readdir(struct file *filp, void *dirent, filldir_t filldir)
                if (filldir(dirent, local_buf, d_reclen, d_off, d_ino,
                            DT_UNKNOWN) < 0) {
                        if (local_buf != small_buf) {
-                               reiserfs_kfree(local_buf, d_reclen,
-                                              inode->i_sb);
+                               kfree(local_buf);
                        }
                        goto end;
                }
                if (local_buf != small_buf) {
-                       reiserfs_kfree(local_buf, d_reclen, inode->i_sb);
+                       kfree(local_buf);
                }
        }                       /* while */
 
@@ -421,23 +355,16 @@ static int __xattr_readdir(struct file *filp, void *dirent, filldir_t filldir)
  *
  */
 static
-int xattr_readdir(struct file *file, filldir_t filler, void *buf)
+int xattr_readdir(struct inode *inode, filldir_t filler, void *buf)
 {
-       struct inode *inode = file->f_dentry->d_inode;
-       int res = -ENOTDIR;
-       if (!file->f_op || !file->f_op->readdir)
-               goto out;
-       down(&inode->i_sem);
-//        down(&inode->i_zombie);
-       res = -ENOENT;
+       int res = -ENOENT;
+       mutex_lock_nested(&inode->i_mutex, I_MUTEX_XATTR);
        if (!IS_DEADDIR(inode)) {
                lock_kernel();
-               res = __xattr_readdir(file, buf, filler);
+               res = __xattr_readdir(inode, buf, filler);
                unlock_kernel();
        }
-//        up(&inode->i_zombie);
-       up(&inode->i_sem);
-      out:
+       mutex_unlock(&inode->i_mutex);
        return res;
 }
 
@@ -454,15 +381,10 @@ static struct page *reiserfs_get_page(struct inode *dir, unsigned long n)
        struct page *page;
        /* We can deadlock if we try to free dentries,
           and an unlink/rmdir has just occured - GFP_NOFS avoids this */
-       mapping->flags = (mapping->flags & ~__GFP_BITS_MASK) | GFP_NOFS;
-       page = read_cache_page(mapping, n,
-                              (filler_t *) mapping->a_ops->readpage, NULL);
+       mapping_set_gfp_mask(mapping, GFP_NOFS);
+       page = read_mapping_page(mapping, n, NULL);
        if (!IS_ERR(page)) {
-               wait_on_page_locked(page);
                kmap(page);
-               if (!PageUptodate(page))
-                       goto fail;
-
                if (PageError(page))
                        goto fail;
        }
@@ -478,17 +400,23 @@ static inline __u32 xattr_hash(const char *msg, int len)
        return csum_partial(msg, len, 0);
 }
 
+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);
+
+
 /* Generic extended attribute operations that can be used by xa plugins */
 
 /*
- * inode->i_sem: down
+ * inode->i_mutex: down
  */
 int
 reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer,
                   size_t buffer_size, int flags)
 {
        int err = 0;
-       struct file *fp;
+       struct dentry *dentry;
        struct page *page;
        char *data;
        struct address_space *mapping;
@@ -498,12 +426,6 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer,
        struct iattr newattrs;
        __u32 xahash = 0;
 
-       if (IS_RDONLY(inode))
-               return -EROFS;
-
-       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-               return -EPERM;
-
        if (get_inode_sd_version(inode) == STAT_DATA_V1)
                return -EOPNOTSUPP;
 
@@ -512,18 +434,18 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer,
                xahash = xattr_hash(buffer, buffer_size);
 
       open_file:
-       fp = open_xa_file(inode, name, flags);
-       if (IS_ERR(fp)) {
-               err = PTR_ERR(fp);
+       dentry = get_xa_file_dentry(inode, name, flags);
+       if (IS_ERR(dentry)) {
+               err = PTR_ERR(dentry);
                goto out;
        }
 
-       xinode = fp->f_dentry->d_inode;
+       xinode = dentry->d_inode;
        REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
 
        /* we need to copy it off.. */
        if (xinode->i_nlink > 1) {
-               fput(fp);
+               dput(dentry);
                err = reiserfs_xattr_del(inode, name);
                if (err < 0)
                        goto out;
@@ -536,8 +458,8 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer,
        /* Resize it so we're ok to write there */
        newattrs.ia_size = buffer_size;
        newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
-       down(&xinode->i_sem);
-       err = notify_change(fp->f_dentry, &newattrs);
+       mutex_lock_nested(&xinode->i_mutex, I_MUTEX_XATTR);
+       err = notify_change(dentry, &newattrs);
        if (err)
                goto out_filp;
 
@@ -570,15 +492,14 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer,
                        rxh->h_hash = cpu_to_le32(xahash);
                }
 
-               err = mapping->a_ops->prepare_write(fp, page, page_offset,
-                                                   page_offset + chunk + skip);
+               err = reiserfs_prepare_write(NULL, page, page_offset,
+                                           page_offset + chunk + skip);
                if (!err) {
                        if (buffer)
                                memcpy(data + skip, buffer + buffer_pos, chunk);
-                       err =
-                           mapping->a_ops->commit_write(fp, page, page_offset,
-                                                        page_offset + chunk +
-                                                        skip);
+                       err = reiserfs_commit_write(NULL, page, page_offset,
+                                                   page_offset + chunk +
+                                                   skip);
                }
                unlock_page(page);
                reiserfs_put_page(page);
@@ -599,22 +520,22 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer,
        }
 
       out_filp:
-       up(&xinode->i_sem);
-       fput(fp);
+       mutex_unlock(&xinode->i_mutex);
+       dput(dentry);
 
       out:
        return err;
 }
 
 /*
- * inode->i_sem: down
+ * inode->i_mutex: down
  */
 int
 reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer,
                   size_t buffer_size)
 {
        ssize_t err = 0;
-       struct file *fp;
+       struct dentry *dentry;
        size_t isize;
        size_t file_pos = 0;
        size_t buffer_pos = 0;
@@ -630,13 +551,13 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer,
        if (get_inode_sd_version(inode) == STAT_DATA_V1)
                return -EOPNOTSUPP;
 
-       fp = open_xa_file(inode, name, FL_READONLY);
-       if (IS_ERR(fp)) {
-               err = PTR_ERR(fp);
+       dentry = get_xa_file_dentry(inode, name, FL_READONLY);
+       if (IS_ERR(dentry)) {
+               err = PTR_ERR(dentry);
                goto out;
        }
 
-       xinode = fp->f_dentry->d_inode;
+       xinode = dentry->d_inode;
        isize = xinode->i_size;
        REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
 
@@ -704,7 +625,7 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer,
        }
 
       out_dput:
-       fput(fp);
+       dput(dentry);
 
       out:
        return err;
@@ -759,9 +680,6 @@ int reiserfs_xattr_del(struct inode *inode, const char *name)
        struct dentry *dir;
        int err;
 
-       if (IS_RDONLY(inode))
-               return -EROFS;
-
        dir = open_xa_dir(inode, FL_READONLY);
        if (IS_ERR(dir)) {
                err = PTR_ERR(dir);
@@ -786,7 +704,7 @@ int reiserfs_xattr_del(struct inode *inode, const char *name)
 
 static int
 reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen,
-                             loff_t offset, ino_t ino, unsigned int d_type)
+                             loff_t offset, u64 ino, unsigned int d_type)
 {
        struct dentry *xadir = (struct dentry *)buf;
 
@@ -794,10 +712,9 @@ reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen,
 
 }
 
-/* This is called w/ inode->i_sem downed */
+/* This is called w/ inode->i_mutex downed */
 int reiserfs_delete_xattrs(struct inode *inode)
 {
-       struct file *fp;
        struct dentry *dir, *root;
        int err = 0;
 
@@ -818,15 +735,8 @@ int reiserfs_delete_xattrs(struct inode *inode)
                return 0;
        }
 
-       fp = dentry_open(dir, NULL, O_RDWR);
-       if (IS_ERR(fp)) {
-               err = PTR_ERR(fp);
-               /* dentry_open dputs the dentry if it fails */
-               goto out;
-       }
-
        lock_kernel();
-       err = xattr_readdir(fp, reiserfs_delete_xattrs_filler, dir);
+       err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir);
        if (err) {
                unlock_kernel();
                goto out_dir;
@@ -834,7 +744,7 @@ int reiserfs_delete_xattrs(struct inode *inode)
 
        /* Leftovers besides . and .. -- that's not good. */
        if (dir->d_inode->i_nlink <= 2) {
-               root = get_xa_root(inode->i_sb);
+               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);
@@ -846,7 +756,7 @@ int reiserfs_delete_xattrs(struct inode *inode)
        unlock_kernel();
 
       out_dir:
-       fput(fp);
+       dput(dir);
 
       out:
        if (!err)
@@ -864,7 +774,7 @@ struct reiserfs_chown_buf {
 /* 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, ino_t ino, unsigned int d_type)
+                            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;
@@ -888,7 +798,6 @@ reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen,
 
 int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs)
 {
-       struct file *fp;
        struct dentry *dir;
        int err = 0;
        struct reiserfs_chown_buf buf;
@@ -912,13 +821,6 @@ int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs)
                goto out;
        }
 
-       fp = dentry_open(dir, NULL, O_RDWR);
-       if (IS_ERR(fp)) {
-               err = PTR_ERR(fp);
-               /* dentry_open dputs the dentry if it fails */
-               goto out;
-       }
-
        lock_kernel();
 
        attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME);
@@ -926,7 +828,7 @@ int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs)
        buf.attrs = attrs;
        buf.inode = inode;
 
-       err = xattr_readdir(fp, reiserfs_chown_xattrs_filler, &buf);
+       err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf);
        if (err) {
                unlock_kernel();
                goto out_dir;
@@ -936,7 +838,7 @@ int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs)
        unlock_kernel();
 
       out_dir:
-       fput(fp);
+       dput(dir);
 
       out:
        attrs->ia_valid = ia_valid;
@@ -947,7 +849,7 @@ int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs)
 
 /*
  * Inode operation getxattr()
- * Preliminary locking: we down dentry->d_inode->i_sem
+ * Preliminary locking: we down dentry->d_inode->i_mutex
  */
 ssize_t
 reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer,
@@ -971,7 +873,7 @@ reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer,
 /*
  * Inode operation setxattr()
  *
- * dentry->d_inode->i_sem down
+ * dentry->d_inode->i_mutex down
  */
 int
 reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value,
@@ -985,12 +887,6 @@ reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value,
            get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
                return -EOPNOTSUPP;
 
-       if (IS_RDONLY(dentry->d_inode))
-               return -EROFS;
-
-       if (IS_IMMUTABLE(dentry->d_inode) || IS_APPEND(dentry->d_inode))
-               return -EROFS;
-
        reiserfs_write_lock_xattr_i(dentry->d_inode);
        lock = !has_xattr_dir(dentry->d_inode);
        if (lock)
@@ -1009,7 +905,7 @@ reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value,
 /*
  * Inode operation removexattr()
  *
- * dentry->d_inode->i_sem down
+ * dentry->d_inode->i_mutex down
  */
 int reiserfs_removexattr(struct dentry *dentry, const char *name)
 {
@@ -1020,12 +916,6 @@ int reiserfs_removexattr(struct dentry *dentry, const char *name)
            get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
                return -EOPNOTSUPP;
 
-       if (IS_RDONLY(dentry->d_inode))
-               return -EROFS;
-
-       if (IS_IMMUTABLE(dentry->d_inode) || IS_APPEND(dentry->d_inode))
-               return -EPERM;
-
        reiserfs_write_lock_xattr_i(dentry->d_inode);
        reiserfs_read_lock_xattrs(dentry->d_sb);
 
@@ -1061,7 +951,7 @@ struct reiserfs_listxattr_buf {
 
 static int
 reiserfs_listxattr_filler(void *buf, const char *name, int namelen,
-                         loff_t offset, ino_t ino, unsigned int d_type)
+                         loff_t offset, u64 ino, unsigned int d_type)
 {
        struct reiserfs_listxattr_buf *b = (struct reiserfs_listxattr_buf *)buf;
        int len = 0;
@@ -1092,11 +982,10 @@ reiserfs_listxattr_filler(void *buf, const char *name, int namelen,
 /*
  * Inode operation listxattr()
  *
- * Preliminary locking: we down dentry->d_inode->i_sem
+ * Preliminary locking: we down dentry->d_inode->i_mutex
  */
 ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
 {
-       struct file *fp;
        struct dentry *dir;
        int err = 0;
        struct reiserfs_listxattr_buf buf;
@@ -1119,13 +1008,6 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
                goto out;
        }
 
-       fp = dentry_open(dir, NULL, O_RDWR);
-       if (IS_ERR(fp)) {
-               err = PTR_ERR(fp);
-               /* dentry_open dputs the dentry if it fails */
-               goto out;
-       }
-
        buf.r_buf = buffer;
        buf.r_size = buffer ? size : 0;
        buf.r_pos = 0;
@@ -1133,7 +1015,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
 
        REISERFS_I(dentry->d_inode)->i_flags |= i_has_xattr_dir;
 
-       err = xattr_readdir(fp, reiserfs_listxattr_filler, &buf);
+       err = xattr_readdir(dir->d_inode, reiserfs_listxattr_filler, &buf);
        if (err)
                goto out_dir;
 
@@ -1143,7 +1025,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
                err = buf.r_pos;
 
       out_dir:
-       fput(fp);
+       dput(dir);
 
       out:
        reiserfs_read_unlock_xattr_i(dentry->d_inode);
@@ -1151,7 +1033,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
 }
 
 /* This is the implementation for the xattr plugin infrastructure */
-static struct list_head xattr_handlers = LIST_HEAD_INIT(xattr_handlers);
+static LIST_HEAD(xattr_handlers);
 static DEFINE_RWLOCK(handler_lock);
 
 static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char
@@ -1290,9 +1172,10 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
                if (!IS_ERR(dentry)) {
                        if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) {
                                struct inode *inode = dentry->d_parent->d_inode;
-                               down(&inode->i_sem);
+                               mutex_lock_nested(&inode->i_mutex,
+                                                 I_MUTEX_XATTR);
                                err = inode->i_op->mkdir(inode, dentry, 0700);
-                               up(&inode->i_sem);
+                               mutex_unlock(&inode->i_mutex);
                                if (err) {
                                        dput(dentry);
                                        dentry = NULL;
@@ -1343,109 +1226,44 @@ int reiserfs_xattr_init(struct super_block *s, int mount_flags)
        return err;
 }
 
-static int
-__reiserfs_permission(struct inode *inode, int mask, struct nameidata *nd,
-                     int need_lock)
+static int reiserfs_check_acl(struct inode *inode, int mask)
 {
-       umode_t mode = inode->i_mode;
-
-       if (mask & MAY_WRITE) {
-               /*
-                * Nobody gets write access to a read-only fs.
-                */
-               if (IS_RDONLY(inode) &&
-                   (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
-                       return -EROFS;
+       struct posix_acl *acl;
+       int error = -EAGAIN; /* do regular unix permission checks by default */
 
-               /*
-                * Nobody gets write access to an immutable file.
-                */
-               if (IS_IMMUTABLE(inode))
-                       return -EACCES;
-       }
+       reiserfs_read_lock_xattr_i(inode);
+       reiserfs_read_lock_xattrs(inode->i_sb);
 
-       /* We don't do permission checks on the internal objects.
-        * Permissions are determined by the "owning" object. */
-       if (is_reiserfs_priv_object(inode))
-               return 0;
+       acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
 
-       if (current->fsuid == inode->i_uid) {
-               mode >>= 6;
-#ifdef CONFIG_REISERFS_FS_POSIX_ACL
-       } else if (reiserfs_posixacl(inode->i_sb) &&
-                  get_inode_sd_version(inode) != STAT_DATA_V1) {
-               struct posix_acl *acl;
-
-               /* ACL can't contain additional permissions if
-                  the ACL_MASK entry is 0 */
-               if (!(mode & S_IRWXG))
-                       goto check_groups;
-
-               if (need_lock) {
-                       reiserfs_read_lock_xattr_i(inode);
-                       reiserfs_read_lock_xattrs(inode->i_sb);
-               }
-               acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
-               if (need_lock) {
-                       reiserfs_read_unlock_xattrs(inode->i_sb);
-                       reiserfs_read_unlock_xattr_i(inode);
-               }
-               if (IS_ERR(acl)) {
-                       if (PTR_ERR(acl) == -ENODATA)
-                               goto check_groups;
-                       return PTR_ERR(acl);
-               }
+       reiserfs_read_unlock_xattrs(inode->i_sb);
+       reiserfs_read_unlock_xattr_i(inode);
 
-               if (acl) {
-                       int err = posix_acl_permission(inode, acl, mask);
+       if (acl) {
+               if (!IS_ERR(acl)) {
+                       error = posix_acl_permission(inode, acl, mask);
                        posix_acl_release(acl);
-                       if (err == -EACCES) {
-                               goto check_capabilities;
-                       }
-                       return err;
-               } else {
-                       goto check_groups;
-               }
-#endif
-       } else {
-             check_groups:
-               if (in_group_p(inode->i_gid))
-                       mode >>= 3;
+               } else if (PTR_ERR(acl) != -ENODATA)
+                       error = PTR_ERR(acl);
        }
 
-       /*
-        * If the DACs are ok we don't need any capability check.
-        */
-       if (((mode & mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == mask))
-               return 0;
+       return error;
+}
 
-      check_capabilities:
+int reiserfs_permission(struct inode *inode, int mask)
+{
        /*
-        * Read/write DACs are always overridable.
-        * Executable DACs are overridable if at least one exec bit is set.
+        * We don't do permission checks on the internal objects.
+        * Permissions are determined by the "owning" object.
         */
-       if (!(mask & MAY_EXEC) ||
-           (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode))
-               if (capable(CAP_DAC_OVERRIDE))
-                       return 0;
+       if (is_reiserfs_priv_object(inode))
+               return 0;
 
        /*
-        * Searching includes executable on directories, else just read.
+        * Stat data v1 doesn't support ACLs.
         */
-       if (mask == MAY_READ || (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE)))
-               if (capable(CAP_DAC_READ_SEARCH))
-                       return 0;
-
-       return -EACCES;
-}
-
-int reiserfs_permission(struct inode *inode, int mask, struct nameidata *nd)
-{
-       return __reiserfs_permission(inode, mask, nd, 1);
-}
-
-int
-reiserfs_permission_locked(struct inode *inode, int mask, struct nameidata *nd)
-{
-       return __reiserfs_permission(inode, mask, nd, 0);
+       if (get_inode_sd_version(inode) == STAT_DATA_V1)
+               return generic_permission(inode, mask, NULL);
+       else
+               return generic_permission(inode, mask, reiserfs_check_acl);
 }