diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 50a73e7afdc8..995f6975cae1 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -1914,9 +1914,8 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, goto out_inserted_sd; } - /* XXX CHECK THIS */ if (reiserfs_posixacl(inode->i_sb)) { - retval = reiserfs_inherit_default_acl(dir, dentry, inode); + retval = reiserfs_inherit_default_acl(th, dir, dentry, inode); if (retval) { err = retval; reiserfs_check_path(&path_to_key); diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index ddf1bcd41c87..d9c1c8bd2950 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -598,15 +598,13 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode, 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) + REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); struct reiserfs_transaction_handle th; - int locked; if (!(inode = new_inode(dir->i_sb))) { return -ENOMEM; } new_inode_init(inode, dir, mode); - locked = reiserfs_cache_default_acl(dir); - + jbegin_count += reiserfs_cache_default_acl(dir); reiserfs_write_lock(dir->i_sb); retval = journal_begin(&th, dir->i_sb, jbegin_count); @@ -662,7 +660,6 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode, JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) + REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); - int locked; if (!new_valid_dev(rdev)) return -EINVAL; @@ -672,8 +669,7 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode, } new_inode_init(inode, dir, mode); - locked = reiserfs_cache_default_acl(dir); - + jbegin_count += reiserfs_cache_default_acl(dir); reiserfs_write_lock(dir->i_sb); retval = journal_begin(&th, dir->i_sb, jbegin_count); @@ -732,7 +728,6 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) + REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); - int locked; #ifdef DISPLACE_NEW_PACKING_LOCALITIES /* set flag that new packing locality created and new blocks for the content * of that directory are not displaced yet */ @@ -744,8 +739,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) } new_inode_init(inode, dir, mode); - locked = reiserfs_cache_default_acl(dir); - + jbegin_count += reiserfs_cache_default_acl(dir); reiserfs_write_lock(dir->i_sb); retval = journal_begin(&th, dir->i_sb, jbegin_count); @@ -1034,8 +1028,6 @@ static int reiserfs_symlink(struct inode *parent_dir, memcpy(name, symname, strlen(symname)); padd_item(name, item_len, strlen(symname)); - /* We would inherit the default ACL here, but symlinks don't get ACLs */ - retval = journal_begin(&th, parent_dir->i_sb, jbegin_count); if (retval) { drop_new_inode(inode); diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index d3ce27436605..c2e3a92aaf2b 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -632,8 +632,9 @@ out_dput: * inode->i_mutex: down */ int -__reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, - size_t buffer_size, int flags) +reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th, + struct inode *inode, const char *name, + const void *buffer, size_t buffer_size, int flags) { int err = 0; struct dentry *dentry; @@ -723,14 +724,34 @@ out_unlock: return err; } -int -reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, - size_t buffer_size, int flags) +/* We need to start a transaction to maintain lock ordering */ +int reiserfs_xattr_set(struct inode *inode, const char *name, + const void *buffer, size_t buffer_size, int flags) { - int err = __reiserfs_xattr_set(inode, name, buffer, buffer_size, flags); - if (err == -ENODATA) - err = 0; - return err; + + struct reiserfs_transaction_handle th; + int error, error2; + size_t jbegin_count = reiserfs_xattr_nblocks(inode, buffer_size); + + if (!(flags & XATTR_REPLACE)) + jbegin_count += reiserfs_xattr_jcreate_nblocks(inode); + + reiserfs_write_lock(inode->i_sb); + error = journal_begin(&th, inode->i_sb, jbegin_count); + if (error) { + reiserfs_write_unlock(inode->i_sb); + return error; + } + + error = reiserfs_xattr_set_handle(&th, inode, name, + buffer, buffer_size, flags); + + error2 = journal_end(&th, inode->i_sb, jbegin_count); + if (error == 0) + error = error2; + reiserfs_write_unlock(inode->i_sb); + + return error; } /* diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index bfecf7553002..d423416d93d1 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c @@ -10,15 +10,17 @@ #include #include -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; } diff --git a/include/linux/reiserfs_acl.h b/include/linux/reiserfs_acl.h index d180446470f2..52240e02de02 100644 --- a/include/linux/reiserfs_acl.h +++ b/include/linux/reiserfs_acl.h @@ -49,7 +49,8 @@ static inline int reiserfs_acl_count(size_t size) #ifdef CONFIG_REISERFS_FS_POSIX_ACL struct posix_acl *reiserfs_get_acl(struct inode *inode, int type); int reiserfs_acl_chmod(struct inode *inode); -int reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry, +int reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th, + struct inode *dir, struct dentry *dentry, struct inode *inode); int reiserfs_cache_default_acl(struct inode *dir); extern struct xattr_handler reiserfs_posix_acl_default_handler; diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h index e00d240314c5..67ad310fa88b 100644 --- a/include/linux/reiserfs_fs.h +++ b/include/linux/reiserfs_fs.h @@ -1615,6 +1615,10 @@ struct reiserfs_journal_header { #define JOURNAL_MAX_COMMIT_AGE 30 #define JOURNAL_MAX_TRANS_AGE 30 #define JOURNAL_PER_BALANCE_CNT (3 * (MAX_HEIGHT-2) + 9) +#define JOURNAL_BLOCKS_PER_OBJECT(sb) (JOURNAL_PER_BALANCE_CNT * 3 + \ + 2 * (REISERFS_QUOTA_INIT_BLOCKS(sb) + \ + REISERFS_QUOTA_TRANS_BLOCKS(sb))) + #ifdef CONFIG_QUOTA /* We need to update data and inode (atime) */ #define REISERFS_QUOTA_TRANS_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<i_sb->s_blocksize); + ret >>= inode->i_sb->s_blocksize_bits; + } + return ret; +} + +/* We may have to create up to 3 objects: xattr root, xattr dir, xattr file. + * Let's try to be smart about it. + * xattr root: We cache it. If it's not cached, we may need to create it. + * xattr dir: If anything has been loaded for this inode, we can set a flag + * saying so. + * xattr file: Since we don't cache xattrs, we can't tell. We always include + * blocks for it. + * + * However, since root and dir can be created between calls - YOU MUST SAVE + * THIS VALUE. + */ +static inline size_t reiserfs_xattr_jcreate_nblocks(struct inode *inode) +{ + size_t nblocks = JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb); + + if ((REISERFS_I(inode)->i_flags & i_has_xattr_dir) == 0) { + nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb); + if (REISERFS_SB(inode->i_sb)->xattr_root == NULL) + nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb); + } + + return nblocks; +} + static inline void reiserfs_init_xattr_rwsem(struct inode *inode) { init_rwsem(&REISERFS_I(inode)->i_xattr_sem);