From: Simon Weber When creating a new inode, the required number of jbd2 journalling credits is conservatively estimated by summing up the credits required for various actions. This includes setting the xattrs for example for ACLs and the fscrypt context. Since the inode is new and has no xattrs, the estimation of credits needed for creating these xattrs is performed by passing is_create=true into the function __ext4_xattr_set_credits, which yields a lower number of credits than when is_create is false. However, following the control flow until the fscrypt context xattr is actually set, the XATTR_CREATE flag is not passed by ext4_set_context to ext4_xattr_set_handle. This causes the latter function to compare the remaining credits against the value of __ext4_xattr_set_credits(..., is_create=false), which may be too much. This flawed design does not usually cause any issues unless the filesystem features has_journal, ea_inode, and encrypt are all present at the same time. In this case, creating a file in any fscrypt-encrypted directory will always return ENOSPC. This patch fixes this issue by passing the XATTR_CREATE flag in the ext4_set_context function. This is safe since ext4_set_context is only called when creating a new inode (in which case the context xattr is not present yet) or when setting the encryption policy on an existing file using the FS_IOC_SET_ENCRYPTION_POLICY ioctl, which however first checks that the file does not currently have an encryption policy set. When calling ext4_set_context it is therefore not undesirable behaviour to possibly fail with an EEXIST error due to the XATTR_CREATE flag and the context xattr already being present. Co-developed-by: Anthony Durrer Signed-off-by: Anthony Durrer Signed-off-by: Simon Weber ---  fs/ext4/crypto.c | 12 +++++++++++-  1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c index cf0a0970c095..5b665f85f6a7 100644 --- a/fs/ext4/crypto.c +++ b/fs/ext4/crypto.c @@ -163,10 +163,20 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,       */        if (handle) { +        /* +         * Set the xattr using the XATTR_CREATE flag, since this function should +         * only be called on inodes that do not have an encryption context yet. +         * Since when estimating the number of credits needed for the new inode +         * we called ext4_xattr_set with is_create = true, we need to pass this +         * flag, otherwise the check for remaining credits is too conservative +         * and may fail. +         * If for some reason the inode already has an encryption context, this +         * fails with EEXIST, which is desirable behaviour. +         */          res = ext4_xattr_set_handle(handle, inode,                          EXT4_XATTR_INDEX_ENCRYPTION,                          EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, -                        ctx, len, 0); +                        ctx, len, XATTR_CREATE);          if (!res) {              ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);              ext4_clear_inode_state(inode, base-commit: 4f5e8e6f012349a107531b02eed5b5ace6181449 -- 2.49.0