]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.suse/reiserfs-clean-up-xattrs
Move xen patchset to new version's subdir.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.suse / reiserfs-clean-up-xattrs
diff --git a/src/patches/suse-2.6.27.31/patches.suse/reiserfs-clean-up-xattrs b/src/patches/suse-2.6.27.31/patches.suse/reiserfs-clean-up-xattrs
new file mode 100644 (file)
index 0000000..410794c
--- /dev/null
@@ -0,0 +1,1004 @@
+From: Jeff Mahoney <jeffm@suse.com>
+Subject: 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: Jeff Mahoney <jeffm@suse.com>
+---
+ fs/reiserfs/Makefile           |    4 
+ fs/reiserfs/xattr.c            |  801 +++++++++++++++++++++--------------------
+ include/linux/reiserfs_fs_sb.h |    2 
+ include/linux/reiserfs_xattr.h |   29 -
+ 4 files changed, 423 insertions(+), 413 deletions(-)
+
+--- a/fs/reiserfs/Makefile
++++ b/fs/reiserfs/Makefile
+@@ -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 \
+                super.o prints.o objectid.o lbalance.o ibalance.o stree.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)
+-reiserfs-objs += xattr.o xattr_user.o xattr_trusted.o
++reiserfs-objs += xattr_user.o xattr_trusted.o
+ endif
+ ifeq ($(CONFIG_REISERFS_FS_SECURITY),y)
+--- a/fs/reiserfs/xattr.c
++++ b/fs/reiserfs/xattr.c
+@@ -50,9 +50,6 @@
+ #define PRIVROOT_NAME ".reiserfs_priv"
+ #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
+  * 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
+@@ -143,60 +140,6 @@ static struct dentry *open_xa_dir(const 
+       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 && !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
+  * we need to drop the path before calling the filldir struct.  That
+@@ -369,6 +312,251 @@ int xattr_readdir(struct inode *inode, f
+       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 */
+ static inline void reiserfs_put_page(struct page *page)
+ {
+@@ -554,274 +742,85 @@ reiserfs_xattr_get(const struct inode *i
+               goto out_dput;
+       }
+-      while (file_pos < isize) {
+-              size_t chunk;
+-              char *data;
+-              size_t skip = 0;
+-              if (isize - file_pos > PAGE_CACHE_SIZE)
+-                      chunk = PAGE_CACHE_SIZE;
+-              else
+-                      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;
+-}
++      while (file_pos < isize) {
++              size_t chunk;
++              char *data;
++              size_t skip = 0;
++              if (isize - file_pos > PAGE_CACHE_SIZE)
++                      chunk = PAGE_CACHE_SIZE;
++              else
++                      chunk = isize - file_pos;
+-struct reiserfs_chown_buf {
+-      struct inode *inode;
+-      struct dentry *xadir;
+-      struct iattr *attrs;
+-};
++              page = reiserfs_get_page(dentry->d_inode, file_pos);
++              if (IS_ERR(page)) {
++                      err = PTR_ERR(page);
++                      goto out_dput;
++              }
+-/* 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;
++              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);
+-      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 (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;
+       }
+-      if (!S_ISDIR(xafile->d_inode->i_mode))
+-              err = notify_change(xafile, attrs);
+-      dput(xafile);
++out_dput:
++      dput(dentry);
++out:
+       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;
+-      int err = 0;
+-      struct reiserfs_chown_buf buf;
+-      unsigned int ia_valid = attrs->ia_valid;
++      int err;
+-      /* 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)) {
+-              if (PTR_ERR(dir) != -ENODATA)
+-                      err = PTR_ERR(dir);
+-              goto out;
+-      } else if (!dir->d_inode) {
+-              dput(dir);
++              err = PTR_ERR(dir);
+               goto out;
+       }
+-      lock_kernel();
+-
+-      attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME);
+-      buf.xadir = dir;
+-      buf.attrs = attrs;
+-      buf.inode = inode;
++      err = __reiserfs_xattr_del(dir, name, strlen(name));
++      dput(dir);
+-      err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf);
+-      if (err) {
+-              unlock_kernel();
+-              goto out_dir;
++      if (!err) {
++              inode->i_ctime = CURRENT_TIME_SEC;
++              mark_inode_dirty(inode);
+       }
+-      err = notify_change(dir, attrs);
+-      unlock_kernel();
+-
+-      out_dir:
+-      dput(dir);
+-
+       out:
+-      attrs->ia_valid = ia_valid;
+       return err;
+ }
+@@ -1101,6 +1100,94 @@ void reiserfs_xattr_unregister_handlers(
+       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 */
+ static int
+ xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name)
+@@ -1127,47 +1214,23 @@ int reiserfs_xattr_init(struct super_blo
+ {
+       int err = 0;
+-      /* 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.");
+-              err = -EOPNOTSUPP;
++#ifdef CONFIG_REISERFS_FS_XATTR
++      err = xattr_mount_check(s);
++      if (err)
+               goto error;
+-      } 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));
+-      }
++#endif
+       /* 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;
+               dentry = lookup_one_len(PRIVROOT_NAME, s->s_root,
+                                       strlen(PRIVROOT_NAME));
+               if (!IS_ERR(dentry)) {
+-                      if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) {
+-                              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(s, "Created %s - "
+-                                                    "reserved for xattr "
+-                                                    "storage.\n",
+-                                                    PRIVROOT_NAME);
+-                      } else if (!dentry->d_inode) {
++#ifdef CONFIG_REISERFS_FS_XATTR
++                      if (!(mount_flags & MS_RDONLY) && !dentry->d_inode)
++                              err = create_privroot(dentry);
++#endif
++                      if (!dentry->d_inode) {
+                               dput(dentry);
+                               dentry = NULL;
+                       }
+@@ -1178,73 +1241,37 @@ int reiserfs_xattr_init(struct super_blo
+                       s->s_root->d_op = &xattr_lookup_poison_ops;
+                       dentry->d_inode->i_flags |= S_PRIVATE;
+                       REISERFS_SB(s)->priv_root = dentry;
+-              } else if (!(mount_flags & MS_RDONLY)) {        /* xattrs are unavailable */
+-                      /* 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 */
++#ifdef CONFIG_REISERFS_FS_XATTR
++              /* xattrs are unavailable */
++              } else if (!(mount_flags & MS_RDONLY)) {
++                      /* 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",
+                                        "xattrs/ACLs enabled and couldn't "
+                                        "find/create .reiserfs_priv. "
+                                        "Failing mount.");
+                       err = -EOPNOTSUPP;
++#endif
+               }
+       }
+-      error:
+-      /* This is only nonzero if there was an error initializing the xattr
+-       * directory or if there is a condition where we don't support them. */
++#ifdef CONFIG_REISERFS_FS_XATTR
++error:
+       if (err) {
+               clear_bit(REISERFS_XATTRS, &(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));
+       }
++#endif
+       /* The super_block MS_POSIXACL must mirror the (no)acl mount option. */
+       s->s_flags = s->s_flags & ~MS_POSIXACL;
++#ifdef CONFIG_REISERFS_FS_POSIX_ACL
+       if (reiserfs_posixacl(s))
+               s->s_flags |= MS_POSIXACL;
++#endif
+       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);
+-}
+--- a/include/linux/reiserfs_fs_sb.h
++++ b/include/linux/reiserfs_fs_sb.h
+@@ -401,8 +401,8 @@ struct reiserfs_sb_info {
+       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 */
+       struct dentry *priv_root;       /* root of /.reiserfs_priv */
+-#ifdef CONFIG_REISERFS_FS_XATTR
+       struct dentry *xattr_root;      /* root of /.reiserfs_priv/.xa */
++#ifdef CONFIG_REISERFS_FS_XATTR
+       struct rw_semaphore xattr_dir_sem;
+ #endif
+       int j_errno;
+--- a/include/linux/reiserfs_xattr.h
++++ b/include/linux/reiserfs_xattr.h
+@@ -43,6 +43,12 @@ struct reiserfs_xattr_handler {
+       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
+ #define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir)
+ ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name,
+@@ -51,9 +57,6 @@ int reiserfs_setxattr(struct dentry *den
+                     const void *value, size_t size, int flags);
+ ssize_t reiserfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
+ 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_xattr_del(struct inode *, const char *);
+@@ -64,9 +67,6 @@ extern struct reiserfs_xattr_handler use
+ extern struct reiserfs_xattr_handler trusted_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)
+ {
+       down_write(&REISERFS_XATTR_DIR_SEM(sb));
+@@ -121,23 +121,6 @@ static inline void reiserfs_init_xattr_r
+ #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)
+ {
+ }