diff options
-rw-r--r-- | fs/crypto/policy.c | 1 | ||||
-rw-r--r-- | fs/ext4/acl.c | 13 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 52 | ||||
-rw-r--r-- | fs/ext4/super.c | 3 | ||||
-rw-r--r-- | fs/ext4/xattr.c | 46 | ||||
-rw-r--r-- | fs/ext4/xattr.h | 5 | ||||
-rw-r--r-- | include/linux/fscrypt_common.h | 3 |
7 files changed, 89 insertions, 34 deletions
diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 210976e7a269..94becf5a1519 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -260,6 +260,7 @@ int fscrypt_inherit_context(struct inode *parent, struct inode *child, memcpy(ctx.master_key_descriptor, ci->ci_master_key, FS_KEY_DESCRIPTOR_SIZE); get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE); + BUILD_BUG_ON(sizeof(ctx) != FSCRYPT_SET_CONTEXT_MAX_SIZE); res = parent->i_sb->s_cop->set_context(child, &ctx, sizeof(ctx), fs_data); if (res) diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index 8db03e5c78bc..09441ae07a5b 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c @@ -183,7 +183,7 @@ ext4_get_acl(struct inode *inode, int type) */ static int __ext4_set_acl(handle_t *handle, struct inode *inode, int type, - struct posix_acl *acl) + struct posix_acl *acl, int xattr_flags) { int name_index; void *value = NULL; @@ -218,7 +218,7 @@ __ext4_set_acl(handle_t *handle, struct inode *inode, int type, } error = ext4_xattr_set_handle(handle, inode, name_index, "", - value, size, 0); + value, size, xattr_flags); kfree(value); if (!error) @@ -238,7 +238,8 @@ ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type) if (error) return error; retry: - error = ext4_xattr_set_credits(inode, acl_size, &credits); + error = ext4_xattr_set_credits(inode, acl_size, false /* is_create */, + &credits); if (error) return error; @@ -246,7 +247,7 @@ retry: if (IS_ERR(handle)) return PTR_ERR(handle); - error = __ext4_set_acl(handle, inode, type, acl); + error = __ext4_set_acl(handle, inode, type, acl, 0 /* xattr_flags */); ext4_journal_stop(handle); if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) goto retry; @@ -271,13 +272,13 @@ ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) if (default_acl) { error = __ext4_set_acl(handle, inode, ACL_TYPE_DEFAULT, - default_acl); + default_acl, XATTR_CREATE); posix_acl_release(default_acl); } if (acl) { if (!error) error = __ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, - acl); + acl, XATTR_CREATE); posix_acl_release(acl); } return error; diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 0c79e3efcaf7..507bfb3344d4 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -766,11 +766,13 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, if (!dir || !dir->i_nlink) return ERR_PTR(-EPERM); - if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb)))) + sb = dir->i_sb; + sbi = EXT4_SB(sb); + + if (unlikely(ext4_forced_shutdown(sbi))) return ERR_PTR(-EIO); - if ((ext4_encrypted_inode(dir) || - DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb))) && + if ((ext4_encrypted_inode(dir) || DUMMY_ENCRYPTION_ENABLED(sbi)) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) && !(i_flags & EXT4_EA_INODE_FL)) { err = fscrypt_get_encryption_info(dir); @@ -778,19 +780,55 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, return ERR_PTR(err); if (!fscrypt_has_encryption_key(dir)) return ERR_PTR(-ENOKEY); - if (!handle) - nblocks += EXT4_DATA_TRANS_BLOCKS(dir->i_sb); encrypt = 1; } - sb = dir->i_sb; + if (!handle && sbi->s_journal && !(i_flags & EXT4_EA_INODE_FL)) { +#ifdef CONFIG_EXT4_FS_POSIX_ACL + struct posix_acl *p = get_acl(dir, ACL_TYPE_DEFAULT); + + if (p) { + int acl_size = p->a_count * sizeof(ext4_acl_entry); + + nblocks += (S_ISDIR(mode) ? 2 : 1) * + __ext4_xattr_set_credits(sb, NULL /* inode */, + NULL /* block_bh */, acl_size, + true /* is_create */); + posix_acl_release(p); + } +#endif + +#ifdef CONFIG_SECURITY + { + int num_security_xattrs = 1; + +#ifdef CONFIG_INTEGRITY + num_security_xattrs++; +#endif + /* + * We assume that security xattrs are never + * more than 1k. In practice they are under + * 128 bytes. + */ + nblocks += num_security_xattrs * + __ext4_xattr_set_credits(sb, NULL /* inode */, + NULL /* block_bh */, 1024, + true /* is_create */); + } +#endif + if (encrypt) + nblocks += __ext4_xattr_set_credits(sb, + NULL /* inode */, NULL /* block_bh */, + FSCRYPT_SET_CONTEXT_MAX_SIZE, + true /* is_create */); + } + ngroups = ext4_get_groups_count(sb); trace_ext4_request_inode(dir, mode); inode = new_inode(sb); if (!inode) return ERR_PTR(-ENOMEM); ei = EXT4_I(inode); - sbi = EXT4_SB(sb); /* * Initialize owners and quota early so that we don't have to account diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 56c971807df5..f666042a3d58 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1194,7 +1194,8 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len, if (res) return res; retry: - res = ext4_xattr_set_credits(inode, len, &credits); + res = ext4_xattr_set_credits(inode, len, false /* is_create */, + &credits); if (res) return res; diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 34fa37e7744c..cff4f41ced61 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -830,11 +830,10 @@ static void ext4_xattr_inode_free_quota(struct inode *inode, size_t len) dquot_free_inode(inode); } -static int __ext4_xattr_set_credits(struct inode *inode, - struct buffer_head *block_bh, - size_t value_len) +int __ext4_xattr_set_credits(struct super_block *sb, struct inode *inode, + struct buffer_head *block_bh, size_t value_len, + bool is_create) { - struct super_block *sb = inode->i_sb; int credits; int blocks; @@ -860,7 +859,7 @@ static int __ext4_xattr_set_credits(struct inode *inode, * In case of inline data, we may push out the data to a block, * so we need to reserve credits for this eventuality */ - if (ext4_has_inline_data(inode)) + if (inode && ext4_has_inline_data(inode)) credits += ext4_writepage_trans_blocks(inode) + 1; /* We are done if ea_inode feature is not enabled. */ @@ -882,19 +881,23 @@ static int __ext4_xattr_set_credits(struct inode *inode, /* Blocks themselves. */ credits += blocks; - /* Dereference ea_inode holding old xattr value. - * Old ea_inode, inode map, block bitmap, group descriptor. - */ - credits += 4; + if (!is_create) { + /* Dereference ea_inode holding old xattr value. + * Old ea_inode, inode map, block bitmap, group descriptor. + */ + credits += 4; - /* Data blocks for old ea_inode. */ - blocks = XATTR_SIZE_MAX >> sb->s_blocksize_bits; + /* Data blocks for old ea_inode. */ + blocks = XATTR_SIZE_MAX >> sb->s_blocksize_bits; - /* Indirection block or one level of extent tree for old ea_inode. */ - blocks += 1; + /* Indirection block or one level of extent tree for old + * ea_inode. + */ + blocks += 1; - /* Block bitmap and group descriptor updates for each block. */ - credits += blocks * 2; + /* Block bitmap and group descriptor updates for each block. */ + credits += blocks * 2; + } /* We may need to clone the existing xattr block in which case we need * to increment ref counts for existing ea_inodes referenced by it. @@ -2263,7 +2266,9 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, goto cleanup; } - credits = __ext4_xattr_set_credits(inode, bh, value_len); + credits = __ext4_xattr_set_credits(inode->i_sb, inode, bh, + value_len, + flags & XATTR_CREATE); brelse(bh); if (!ext4_handle_has_enough_credits(handle, credits)) { @@ -2370,7 +2375,8 @@ cleanup: return error; } -int ext4_xattr_set_credits(struct inode *inode, size_t value_len, int *credits) +int ext4_xattr_set_credits(struct inode *inode, size_t value_len, + bool is_create, int *credits) { struct buffer_head *bh; int err; @@ -2386,7 +2392,8 @@ int ext4_xattr_set_credits(struct inode *inode, size_t value_len, int *credits) if (IS_ERR(bh)) { err = PTR_ERR(bh); } else { - *credits = __ext4_xattr_set_credits(inode, bh, value_len); + *credits = __ext4_xattr_set_credits(inode->i_sb, inode, bh, + value_len, is_create); brelse(bh); err = 0; } @@ -2417,7 +2424,8 @@ ext4_xattr_set(struct inode *inode, int name_index, const char *name, return error; retry: - error = ext4_xattr_set_credits(inode, value_len, &credits); + error = ext4_xattr_set_credits(inode, value_len, flags & XATTR_CREATE, + &credits); if (error) return error; diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index 26119a67c8c3..0d2dde1fa87a 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h @@ -153,7 +153,10 @@ extern int ext4_xattr_get(struct inode *, int, const char *, void *, size_t); extern int ext4_xattr_set(struct inode *, int, const char *, const void *, size_t, int); extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int); extern int ext4_xattr_set_credits(struct inode *inode, size_t value_len, - int *credits); + bool is_create, int *credits); +extern int __ext4_xattr_set_credits(struct super_block *sb, struct inode *inode, + struct buffer_head *block_bh, size_t value_len, + bool is_create); extern int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, struct ext4_xattr_inode_array **array, diff --git a/include/linux/fscrypt_common.h b/include/linux/fscrypt_common.h index 0a30c106c1e5..82beaf70e7e2 100644 --- a/include/linux/fscrypt_common.h +++ b/include/linux/fscrypt_common.h @@ -83,6 +83,9 @@ struct fscrypt_operations { unsigned (*max_namelen)(struct inode *); }; +/* Maximum value for the third parameter of fscrypt_operations.set_context(). */ +#define FSCRYPT_SET_CONTEXT_MAX_SIZE 28 + static inline bool fscrypt_dummy_context_enabled(struct inode *inode) { if (inode->i_sb->s_cop->dummy_context && |