Commit 9050ba3a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-5.18-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux

Pull btrfs fixes from David Sterba:
 "A few more fixes mostly around how some file attributes could be set.

   - fix handling of compression property:
      - don't allow setting it on anything else than regular file or
        directory
      - do not allow setting it on nodatacow files via properties

   - improved error handling when setting xattr

   - make sure symlinks are always properly logged"

* tag 'for-5.18-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: skip compression property for anything other than files and dirs
  btrfs: do not BUG_ON() on failure to update inode when setting xattr
  btrfs: always log symlinks in full mode
  btrfs: do not allow compression on nodatacow files
  btrfs: export a helper for compression hard check
parents 672c0c51 4b73c55f
...@@ -384,6 +384,17 @@ static inline bool btrfs_inode_in_log(struct btrfs_inode *inode, u64 generation) ...@@ -384,6 +384,17 @@ static inline bool btrfs_inode_in_log(struct btrfs_inode *inode, u64 generation)
return ret; return ret;
} }
/*
* Check if the inode has flags compatible with compression
*/
static inline bool btrfs_inode_can_compress(const struct btrfs_inode *inode)
{
if (inode->flags & BTRFS_INODE_NODATACOW ||
inode->flags & BTRFS_INODE_NODATASUM)
return false;
return true;
}
struct btrfs_dio_private { struct btrfs_dio_private {
struct inode *inode; struct inode *inode;
......
...@@ -480,17 +480,6 @@ static noinline int add_async_extent(struct async_chunk *cow, ...@@ -480,17 +480,6 @@ static noinline int add_async_extent(struct async_chunk *cow,
return 0; return 0;
} }
/*
* Check if the inode has flags compatible with compression
*/
static inline bool inode_can_compress(struct btrfs_inode *inode)
{
if (inode->flags & BTRFS_INODE_NODATACOW ||
inode->flags & BTRFS_INODE_NODATASUM)
return false;
return true;
}
/* /*
* Check if the inode needs to be submitted to compression, based on mount * Check if the inode needs to be submitted to compression, based on mount
* options, defragmentation, properties or heuristics. * options, defragmentation, properties or heuristics.
...@@ -500,7 +489,7 @@ static inline int inode_need_compress(struct btrfs_inode *inode, u64 start, ...@@ -500,7 +489,7 @@ static inline int inode_need_compress(struct btrfs_inode *inode, u64 start,
{ {
struct btrfs_fs_info *fs_info = inode->root->fs_info; struct btrfs_fs_info *fs_info = inode->root->fs_info;
if (!inode_can_compress(inode)) { if (!btrfs_inode_can_compress(inode)) {
WARN(IS_ENABLED(CONFIG_BTRFS_DEBUG), WARN(IS_ENABLED(CONFIG_BTRFS_DEBUG),
KERN_ERR "BTRFS: unexpected compression for ino %llu\n", KERN_ERR "BTRFS: unexpected compression for ino %llu\n",
btrfs_ino(inode)); btrfs_ino(inode));
...@@ -2019,7 +2008,7 @@ int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page ...@@ -2019,7 +2008,7 @@ int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page
ASSERT(!zoned || btrfs_is_data_reloc_root(inode->root)); ASSERT(!zoned || btrfs_is_data_reloc_root(inode->root));
ret = run_delalloc_nocow(inode, locked_page, start, end, ret = run_delalloc_nocow(inode, locked_page, start, end,
page_started, nr_written); page_started, nr_written);
} else if (!inode_can_compress(inode) || } else if (!btrfs_inode_can_compress(inode) ||
!inode_need_compress(inode, start, end)) { !inode_need_compress(inode, start, end)) {
if (zoned) if (zoned)
ret = run_delalloc_zoned(inode, locked_page, start, end, ret = run_delalloc_zoned(inode, locked_page, start, end,
......
...@@ -17,9 +17,11 @@ static DEFINE_HASHTABLE(prop_handlers_ht, BTRFS_PROP_HANDLERS_HT_BITS); ...@@ -17,9 +17,11 @@ static DEFINE_HASHTABLE(prop_handlers_ht, BTRFS_PROP_HANDLERS_HT_BITS);
struct prop_handler { struct prop_handler {
struct hlist_node node; struct hlist_node node;
const char *xattr_name; const char *xattr_name;
int (*validate)(const char *value, size_t len); int (*validate)(const struct btrfs_inode *inode, const char *value,
size_t len);
int (*apply)(struct inode *inode, const char *value, size_t len); int (*apply)(struct inode *inode, const char *value, size_t len);
const char *(*extract)(struct inode *inode); const char *(*extract)(struct inode *inode);
bool (*ignore)(const struct btrfs_inode *inode);
int inheritable; int inheritable;
}; };
...@@ -55,7 +57,8 @@ find_prop_handler(const char *name, ...@@ -55,7 +57,8 @@ find_prop_handler(const char *name,
return NULL; return NULL;
} }
int btrfs_validate_prop(const char *name, const char *value, size_t value_len) int btrfs_validate_prop(const struct btrfs_inode *inode, const char *name,
const char *value, size_t value_len)
{ {
const struct prop_handler *handler; const struct prop_handler *handler;
...@@ -69,7 +72,29 @@ int btrfs_validate_prop(const char *name, const char *value, size_t value_len) ...@@ -69,7 +72,29 @@ int btrfs_validate_prop(const char *name, const char *value, size_t value_len)
if (value_len == 0) if (value_len == 0)
return 0; return 0;
return handler->validate(value, value_len); return handler->validate(inode, value, value_len);
}
/*
* Check if a property should be ignored (not set) for an inode.
*
* @inode: The target inode.
* @name: The property's name.
*
* The caller must be sure the given property name is valid, for example by
* having previously called btrfs_validate_prop().
*
* Returns: true if the property should be ignored for the given inode
* false if the property must not be ignored for the given inode
*/
bool btrfs_ignore_prop(const struct btrfs_inode *inode, const char *name)
{
const struct prop_handler *handler;
handler = find_prop_handler(name, NULL);
ASSERT(handler != NULL);
return handler->ignore(inode);
} }
int btrfs_set_prop(struct btrfs_trans_handle *trans, struct inode *inode, int btrfs_set_prop(struct btrfs_trans_handle *trans, struct inode *inode,
...@@ -252,8 +277,12 @@ int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path) ...@@ -252,8 +277,12 @@ int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path)
return ret; return ret;
} }
static int prop_compression_validate(const char *value, size_t len) static int prop_compression_validate(const struct btrfs_inode *inode,
const char *value, size_t len)
{ {
if (!btrfs_inode_can_compress(inode))
return -EINVAL;
if (!value) if (!value)
return 0; return 0;
...@@ -310,6 +339,22 @@ static int prop_compression_apply(struct inode *inode, const char *value, ...@@ -310,6 +339,22 @@ static int prop_compression_apply(struct inode *inode, const char *value,
return 0; return 0;
} }
static bool prop_compression_ignore(const struct btrfs_inode *inode)
{
/*
* Compression only has effect for regular files, and for directories
* we set it just to propagate it to new files created inside them.
* Everything else (symlinks, devices, sockets, fifos) is pointless as
* it will do nothing, so don't waste metadata space on a compression
* xattr for anything that is neither a file nor a directory.
*/
if (!S_ISREG(inode->vfs_inode.i_mode) &&
!S_ISDIR(inode->vfs_inode.i_mode))
return true;
return false;
}
static const char *prop_compression_extract(struct inode *inode) static const char *prop_compression_extract(struct inode *inode)
{ {
switch (BTRFS_I(inode)->prop_compress) { switch (BTRFS_I(inode)->prop_compress) {
...@@ -330,6 +375,7 @@ static struct prop_handler prop_handlers[] = { ...@@ -330,6 +375,7 @@ static struct prop_handler prop_handlers[] = {
.validate = prop_compression_validate, .validate = prop_compression_validate,
.apply = prop_compression_apply, .apply = prop_compression_apply,
.extract = prop_compression_extract, .extract = prop_compression_extract,
.ignore = prop_compression_ignore,
.inheritable = 1 .inheritable = 1
}, },
}; };
...@@ -356,6 +402,9 @@ static int inherit_props(struct btrfs_trans_handle *trans, ...@@ -356,6 +402,9 @@ static int inherit_props(struct btrfs_trans_handle *trans,
if (!h->inheritable) if (!h->inheritable)
continue; continue;
if (h->ignore(BTRFS_I(inode)))
continue;
value = h->extract(parent); value = h->extract(parent);
if (!value) if (!value)
continue; continue;
...@@ -364,7 +413,7 @@ static int inherit_props(struct btrfs_trans_handle *trans, ...@@ -364,7 +413,7 @@ static int inherit_props(struct btrfs_trans_handle *trans,
* This is not strictly necessary as the property should be * This is not strictly necessary as the property should be
* valid, but in case it isn't, don't propagate it further. * valid, but in case it isn't, don't propagate it further.
*/ */
ret = h->validate(value, strlen(value)); ret = h->validate(BTRFS_I(inode), value, strlen(value));
if (ret) if (ret)
continue; continue;
......
...@@ -13,7 +13,9 @@ void __init btrfs_props_init(void); ...@@ -13,7 +13,9 @@ void __init btrfs_props_init(void);
int btrfs_set_prop(struct btrfs_trans_handle *trans, struct inode *inode, int btrfs_set_prop(struct btrfs_trans_handle *trans, struct inode *inode,
const char *name, const char *value, size_t value_len, const char *name, const char *value, size_t value_len,
int flags); int flags);
int btrfs_validate_prop(const char *name, const char *value, size_t value_len); int btrfs_validate_prop(const struct btrfs_inode *inode, const char *name,
const char *value, size_t value_len);
bool btrfs_ignore_prop(const struct btrfs_inode *inode, const char *name);
int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path); int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path);
......
...@@ -5804,6 +5804,18 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, ...@@ -5804,6 +5804,18 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
mutex_lock(&inode->log_mutex); mutex_lock(&inode->log_mutex);
} }
/*
* For symlinks, we must always log their content, which is stored in an
* inline extent, otherwise we could end up with an empty symlink after
* log replay, which is invalid on linux (symlink(2) returns -ENOENT if
* one attempts to create an empty symlink).
* We don't need to worry about flushing delalloc, because when we create
* the inline extent when the symlink is created (we never have delalloc
* for symlinks).
*/
if (S_ISLNK(inode->vfs_inode.i_mode))
inode_only = LOG_INODE_ALL;
/* /*
* Before logging the inode item, cache the value returned by * Before logging the inode item, cache the value returned by
* inode_logged(), because after that we have the need to figure out if * inode_logged(), because after that we have the need to figure out if
...@@ -6182,7 +6194,7 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans, ...@@ -6182,7 +6194,7 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans,
} }
ctx->log_new_dentries = false; ctx->log_new_dentries = false;
if (type == BTRFS_FT_DIR || type == BTRFS_FT_SYMLINK) if (type == BTRFS_FT_DIR)
log_mode = LOG_INODE_ALL; log_mode = LOG_INODE_ALL;
ret = btrfs_log_inode(trans, BTRFS_I(di_inode), ret = btrfs_log_inode(trans, BTRFS_I(di_inode),
log_mode, ctx); log_mode, ctx);
......
...@@ -262,7 +262,8 @@ int btrfs_setxattr_trans(struct inode *inode, const char *name, ...@@ -262,7 +262,8 @@ int btrfs_setxattr_trans(struct inode *inode, const char *name,
inode_inc_iversion(inode); inode_inc_iversion(inode);
inode->i_ctime = current_time(inode); inode->i_ctime = current_time(inode);
ret = btrfs_update_inode(trans, root, BTRFS_I(inode)); ret = btrfs_update_inode(trans, root, BTRFS_I(inode));
BUG_ON(ret); if (ret)
btrfs_abort_transaction(trans, ret);
out: out:
if (start_trans) if (start_trans)
btrfs_end_transaction(trans); btrfs_end_transaction(trans);
...@@ -403,10 +404,13 @@ static int btrfs_xattr_handler_set_prop(const struct xattr_handler *handler, ...@@ -403,10 +404,13 @@ static int btrfs_xattr_handler_set_prop(const struct xattr_handler *handler,
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
name = xattr_full_name(handler, name); name = xattr_full_name(handler, name);
ret = btrfs_validate_prop(name, value, size); ret = btrfs_validate_prop(BTRFS_I(inode), name, value, size);
if (ret) if (ret)
return ret; return ret;
if (btrfs_ignore_prop(BTRFS_I(inode), name))
return 0;
trans = btrfs_start_transaction(root, 2); trans = btrfs_start_transaction(root, 2);
if (IS_ERR(trans)) if (IS_ERR(trans))
return PTR_ERR(trans); return PTR_ERR(trans);
...@@ -416,7 +420,8 @@ static int btrfs_xattr_handler_set_prop(const struct xattr_handler *handler, ...@@ -416,7 +420,8 @@ static int btrfs_xattr_handler_set_prop(const struct xattr_handler *handler,
inode_inc_iversion(inode); inode_inc_iversion(inode);
inode->i_ctime = current_time(inode); inode->i_ctime = current_time(inode);
ret = btrfs_update_inode(trans, root, BTRFS_I(inode)); ret = btrfs_update_inode(trans, root, BTRFS_I(inode));
BUG_ON(ret); if (ret)
btrfs_abort_transaction(trans, ret);
} }
btrfs_end_transaction(trans); btrfs_end_transaction(trans);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment