switch reiserfs to usual conventions for caching ACLs
[safe/jmp/linux-2.6] / fs / reiserfs / xattr_acl.c
index bfecf75..7b3aeb9 100644 (file)
 #include <linux/reiserfs_acl.h>
 #include <asm/uaccess.h>
 
-static int reiserfs_set_acl(struct inode *inode, int type,
+static int reiserfs_set_acl(struct reiserfs_transaction_handle *th,
+                           struct inode *inode, int type,
                            struct posix_acl *acl);
 
 static int
 xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
 {
        struct posix_acl *acl;
-       int error;
-
+       int error, error2;
+       struct reiserfs_transaction_handle th;
+       size_t jcreate_blocks;
        if (!reiserfs_posixacl(inode->i_sb))
                return -EOPNOTSUPP;
        if (!is_owner_or_cap(inode))
@@ -36,7 +38,21 @@ xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
        } else
                acl = NULL;
 
-       error = reiserfs_set_acl(inode, type, acl);
+       /* Pessimism: We can't assume that anything from the xattr root up
+        * has been created. */
+
+       jcreate_blocks = reiserfs_xattr_jcreate_nblocks(inode) +
+                        reiserfs_xattr_nblocks(inode, size) * 2;
+
+       reiserfs_write_lock(inode->i_sb);
+       error = journal_begin(&th, inode->i_sb, jcreate_blocks);
+       if (error == 0) {
+               error = reiserfs_set_acl(&th, inode, type, acl);
+               error2 = journal_end(&th, inode->i_sb, jcreate_blocks);
+               if (error2)
+                       error = error2;
+       }
+       reiserfs_write_unlock(inode->i_sb);
 
       release_and_out:
        posix_acl_release(acl);
@@ -176,7 +192,7 @@ static inline void iset_acl(struct inode *inode, struct posix_acl **i_acl,
                            struct posix_acl *acl)
 {
        spin_lock(&inode->i_lock);
-       if (*i_acl != ERR_PTR(-ENODATA))
+       if (*i_acl != ACL_NOT_CACHED)
                posix_acl_release(*i_acl);
        *i_acl = posix_acl_dup(acl);
        spin_unlock(&inode->i_lock);
@@ -185,10 +201,10 @@ static inline void iset_acl(struct inode *inode, struct posix_acl **i_acl,
 static inline struct posix_acl *iget_acl(struct inode *inode,
                                         struct posix_acl **i_acl)
 {
-       struct posix_acl *acl = ERR_PTR(-ENODATA);
+       struct posix_acl *acl = ACL_NOT_CACHED;
 
        spin_lock(&inode->i_lock);
-       if (*i_acl != ERR_PTR(-ENODATA))
+       if (*i_acl != ACL_NOT_CACHED)
                acl = posix_acl_dup(*i_acl);
        spin_unlock(&inode->i_lock);
 
@@ -223,15 +239,13 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
        }
 
        acl = iget_acl(inode, p_acl);
-       if (acl && !IS_ERR(acl))
+       if (acl != ACL_NOT_CACHED)
                return acl;
-       else if (PTR_ERR(acl) == -ENODATA)
-               return NULL;
 
        size = reiserfs_xattr_get(inode, name, NULL, 0);
        if (size < 0) {
                if (size == -ENODATA || size == -ENOSYS) {
-                       *p_acl = ERR_PTR(-ENODATA);
+                       *p_acl = NULL;
                        return NULL;
                }
                return ERR_PTR(size);
@@ -246,7 +260,7 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
                /* This shouldn't actually happen as it should have
                   been caught above.. but just in case */
                acl = NULL;
-               *p_acl = ERR_PTR(-ENODATA);
+               *p_acl = acl;
        } else if (retval < 0) {
                acl = ERR_PTR(retval);
        } else {
@@ -266,7 +280,8 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
  * BKL held [before 2.5.x]
  */
 static int
-reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
+reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
+                int type, struct posix_acl *acl)
 {
        char *name;
        void *value = NULL;
@@ -310,7 +325,7 @@ reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
                        return (int)PTR_ERR(value);
        }
 
-       error = __reiserfs_xattr_set(inode, name, value, size, 0);
+       error = reiserfs_xattr_set_handle(th, inode, name, value, size, 0);
 
        /*
         * Ensure that the inode gets dirtied if we're only using
@@ -337,7 +352,8 @@ reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
 /* dir->i_mutex: locked,
  * inode is new and not released into the wild yet */
 int
-reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
+reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
+                            struct inode *dir, struct dentry *dentry,
                             struct inode *inode)
 {
        struct posix_acl *acl;
@@ -361,11 +377,8 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
        }
 
        acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT);
-       if (IS_ERR(acl)) {
-               if (PTR_ERR(acl) == -ENODATA)
-                       goto apply_umask;
+       if (IS_ERR(acl))
                return PTR_ERR(acl);
-       }
 
        if (acl) {
                struct posix_acl *acl_copy;
@@ -374,7 +387,8 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
 
                /* Copy the default ACL to the default ACL of a new directory */
                if (S_ISDIR(inode->i_mode)) {
-                       err = reiserfs_set_acl(inode, ACL_TYPE_DEFAULT, acl);
+                       err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT,
+                                              acl);
                        if (err)
                                goto cleanup;
                }
@@ -395,9 +409,9 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
 
                        /* If we need an ACL.. */
                        if (need_acl > 0) {
-                               err =
-                                   reiserfs_set_acl(inode, ACL_TYPE_ACCESS,
-                                                    acl_copy);
+                               err = reiserfs_set_acl(th, inode,
+                                                      ACL_TYPE_ACCESS,
+                                                      acl_copy);
                                if (err)
                                        goto cleanup_copy;
                        }
@@ -409,27 +423,51 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
        } else {
              apply_umask:
                /* no ACL, apply umask */
-               inode->i_mode &= ~current->fs->umask;
+               inode->i_mode &= ~current_umask();
        }
 
        return err;
 }
 
-/* Looks up and caches the result of the default ACL.
- * We do this so that we don't need to carry the xattr_sem into
- * reiserfs_new_inode if we don't need to */
+/* This is used to cache the default acl before a new object is created.
+ * The biggest reason for this is to get an idea of how many blocks will
+ * actually be required for the create operation if we must inherit an ACL.
+ * An ACL write can add up to 3 object creations and an additional file write
+ * so we'd prefer not to reserve that many blocks in the journal if we can.
+ * It also has the advantage of not loading the ACL with a transaction open,
+ * this may seem silly, but if the owner of the directory is doing the
+ * creation, the ACL may not be loaded since the permissions wouldn't require
+ * it.
+ * We return the number of blocks required for the transaction.
+ */
 int reiserfs_cache_default_acl(struct inode *inode)
 {
-       int ret = 0;
-       if (reiserfs_posixacl(inode->i_sb) && !IS_PRIVATE(inode)) {
-               struct posix_acl *acl;
-               acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT);
-               ret = (acl && !IS_ERR(acl));
-               if (ret)
-                       posix_acl_release(acl);
+       struct posix_acl *acl;
+       int nblocks = 0;
+
+       if (IS_PRIVATE(inode))
+               return 0;
+
+       acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT);
+
+       if (acl && !IS_ERR(acl)) {
+               int size = reiserfs_acl_size(acl->a_count);
+
+               /* Other xattrs can be created during inode creation. We don't
+                * want to claim too many blocks, so we check to see if we
+                * we need to create the tree to the xattrs, and then we
+                * just want two files. */
+               nblocks = reiserfs_xattr_jcreate_nblocks(inode);
+               nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
+
+               REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
+
+               /* We need to account for writes + bitmaps for two files */
+               nblocks += reiserfs_xattr_nblocks(inode, size) * 4;
+               posix_acl_release(acl);
        }
 
-       return ret;
+       return nblocks;
 }
 
 int reiserfs_acl_chmod(struct inode *inode)
@@ -455,8 +493,22 @@ int reiserfs_acl_chmod(struct inode *inode)
        if (!clone)
                return -ENOMEM;
        error = posix_acl_chmod_masq(clone, inode->i_mode);
-       if (!error)
-               error = reiserfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
+       if (!error) {
+               struct reiserfs_transaction_handle th;
+               size_t size = reiserfs_xattr_nblocks(inode,
+                                            reiserfs_acl_size(clone->a_count));
+               reiserfs_write_lock(inode->i_sb);
+               error = journal_begin(&th, inode->i_sb, size * 2);
+               if (!error) {
+                       int error2;
+                       error = reiserfs_set_acl(&th, inode, ACL_TYPE_ACCESS,
+                                                clone);
+                       error2 = journal_end(&th, inode->i_sb, size * 2);
+                       if (error2)
+                               error = error2;
+               }
+               reiserfs_write_unlock(inode->i_sb);
+       }
        posix_acl_release(clone);
        return error;
 }