forked from Minki/linux
for-5.18-rc5-tag
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAmJwBoQACgkQxWXV+ddt WDu/FQ/+L2LpN5Zu1NkjOAh2Lcvz5RYZjcVext4bbPUW2yhXYH3e6836R/feLOCG RxRICOAQhJ7I6ct/N1aToI2AbjWnMSJK+IgageA1UdIS8McbcSP/qJOYwJ/+2Xhl AvK5psoj+qwGbTI9e0luNe6b+UWTGIMyYRjmN0SlkBOdg9/xqQpBMQxfKJumMvEc 3ZwLpcNjhUUwdFKHvHZNCOQhZiZwloKFeq9MLaEL5LO30wKSY6ShiCA3pafFoVN0 mvEEVtIGgZUsgeQTzSzD8UhGDvZtZ1+aaX0dcNMRzwI2h2pkBmPkd5QtFM9Qs0xP hGibSN9bC/SzQyE9v4cKohwS+g4dE4r+dUWFNpdZLIOpBt5PJBDA0tjcjxquFtMr 6JX77coAl9kt0jspBmHVPb3qmIc1Xo3Iw2PrVgTK14QUo46XwF5Rga68wKOfNt0u LbD9+KCLnwxoOhvXh/LJX6nvPT8tuMrT/5AOXULI2oMCnpCY6Vl+kX8zFlAfbDk1 d4/jy42bgHCso60j2vAcdQmZB+/snpboOhKJwkE2FqOTs+hBR8PBln6BqEt5xkHZ q2mBfYDujnmZWaiAU6+ETjOcCooWQioi3335tp/C9TdOrIkFDij1ztYRxhgP0g0X w6d6wlbkcol1Zubb/zEiBiwe+6GR/KtNYc4PBEfVe5Vw0npFreU= =7k9f -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
9050ba3a61
@ -384,6 +384,17 @@ static inline bool btrfs_inode_in_log(struct btrfs_inode *inode, u64 generation)
|
||||
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 inode *inode;
|
||||
|
||||
|
@ -480,17 +480,6 @@ static noinline int add_async_extent(struct async_chunk *cow,
|
||||
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
|
||||
* options, defragmentation, properties or heuristics.
|
||||
@ -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;
|
||||
|
||||
if (!inode_can_compress(inode)) {
|
||||
if (!btrfs_inode_can_compress(inode)) {
|
||||
WARN(IS_ENABLED(CONFIG_BTRFS_DEBUG),
|
||||
KERN_ERR "BTRFS: unexpected compression for ino %llu\n",
|
||||
btrfs_ino(inode));
|
||||
@ -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));
|
||||
ret = run_delalloc_nocow(inode, locked_page, start, end,
|
||||
page_started, nr_written);
|
||||
} else if (!inode_can_compress(inode) ||
|
||||
} else if (!btrfs_inode_can_compress(inode) ||
|
||||
!inode_need_compress(inode, start, end)) {
|
||||
if (zoned)
|
||||
ret = run_delalloc_zoned(inode, locked_page, start, end,
|
||||
|
@ -17,9 +17,11 @@ static DEFINE_HASHTABLE(prop_handlers_ht, BTRFS_PROP_HANDLERS_HT_BITS);
|
||||
struct prop_handler {
|
||||
struct hlist_node node;
|
||||
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);
|
||||
const char *(*extract)(struct inode *inode);
|
||||
bool (*ignore)(const struct btrfs_inode *inode);
|
||||
int inheritable;
|
||||
};
|
||||
|
||||
@ -55,7 +57,8 @@ find_prop_handler(const char *name,
|
||||
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;
|
||||
|
||||
@ -69,7 +72,29 @@ int btrfs_validate_prop(const char *name, const char *value, size_t value_len)
|
||||
if (value_len == 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,
|
||||
@ -252,8 +277,12 @@ int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path)
|
||||
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)
|
||||
return 0;
|
||||
|
||||
@ -310,6 +339,22 @@ static int prop_compression_apply(struct inode *inode, const char *value,
|
||||
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)
|
||||
{
|
||||
switch (BTRFS_I(inode)->prop_compress) {
|
||||
@ -330,6 +375,7 @@ static struct prop_handler prop_handlers[] = {
|
||||
.validate = prop_compression_validate,
|
||||
.apply = prop_compression_apply,
|
||||
.extract = prop_compression_extract,
|
||||
.ignore = prop_compression_ignore,
|
||||
.inheritable = 1
|
||||
},
|
||||
};
|
||||
@ -356,6 +402,9 @@ static int inherit_props(struct btrfs_trans_handle *trans,
|
||||
if (!h->inheritable)
|
||||
continue;
|
||||
|
||||
if (h->ignore(BTRFS_I(inode)))
|
||||
continue;
|
||||
|
||||
value = h->extract(parent);
|
||||
if (!value)
|
||||
continue;
|
||||
@ -364,7 +413,7 @@ static int inherit_props(struct btrfs_trans_handle *trans,
|
||||
* This is not strictly necessary as the property should be
|
||||
* 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)
|
||||
continue;
|
||||
|
||||
|
@ -13,7 +13,9 @@ void __init btrfs_props_init(void);
|
||||
int btrfs_set_prop(struct btrfs_trans_handle *trans, struct inode *inode,
|
||||
const char *name, const char *value, size_t value_len,
|
||||
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);
|
||||
|
||||
|
@ -5804,6 +5804,18 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
|
||||
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
|
||||
* inode_logged(), because after that we have the need to figure out if
|
||||
@ -6182,7 +6194,7 @@ again:
|
||||
}
|
||||
|
||||
ctx->log_new_dentries = false;
|
||||
if (type == BTRFS_FT_DIR || type == BTRFS_FT_SYMLINK)
|
||||
if (type == BTRFS_FT_DIR)
|
||||
log_mode = LOG_INODE_ALL;
|
||||
ret = btrfs_log_inode(trans, BTRFS_I(di_inode),
|
||||
log_mode, ctx);
|
||||
|
@ -262,7 +262,8 @@ int btrfs_setxattr_trans(struct inode *inode, const char *name,
|
||||
inode_inc_iversion(inode);
|
||||
inode->i_ctime = current_time(inode);
|
||||
ret = btrfs_update_inode(trans, root, BTRFS_I(inode));
|
||||
BUG_ON(ret);
|
||||
if (ret)
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
out:
|
||||
if (start_trans)
|
||||
btrfs_end_transaction(trans);
|
||||
@ -403,10 +404,13 @@ static int btrfs_xattr_handler_set_prop(const struct xattr_handler *handler,
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
|
||||
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)
|
||||
return ret;
|
||||
|
||||
if (btrfs_ignore_prop(BTRFS_I(inode), name))
|
||||
return 0;
|
||||
|
||||
trans = btrfs_start_transaction(root, 2);
|
||||
if (IS_ERR(trans))
|
||||
return PTR_ERR(trans);
|
||||
@ -416,7 +420,8 @@ static int btrfs_xattr_handler_set_prop(const struct xattr_handler *handler,
|
||||
inode_inc_iversion(inode);
|
||||
inode->i_ctime = current_time(inode);
|
||||
ret = btrfs_update_inode(trans, root, BTRFS_I(inode));
|
||||
BUG_ON(ret);
|
||||
if (ret)
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
}
|
||||
|
||||
btrfs_end_transaction(trans);
|
||||
|
Loading…
Reference in New Issue
Block a user