diff options
Diffstat (limited to 'fs/reiserfs/xattr_acl.c')
-rw-r--r-- | fs/reiserfs/xattr_acl.c | 105 |
1 files changed, 81 insertions, 24 deletions
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index bfecf75..d423416 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c @@ -10,15 +10,17 @@ #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); @@ -266,7 +282,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 +327,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 +354,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; @@ -374,7 +392,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 +414,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; } @@ -415,21 +434,45 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry, 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 +498,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; } |