mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
bcachefs: opts.casefold_disabled
Add an option for completely disabling casefolding on a filesystem, as a workaround for overlayfs. This should only be needed as a temporary workaround, until the overlayfs fix arrives. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
c6e8d51b37
commit
94426e4201
10 changed files with 55 additions and 43 deletions
|
@ -863,9 +863,7 @@ struct bch_fs {
|
||||||
DARRAY(enum bcachefs_metadata_version)
|
DARRAY(enum bcachefs_metadata_version)
|
||||||
incompat_versions_requested;
|
incompat_versions_requested;
|
||||||
|
|
||||||
#ifdef CONFIG_UNICODE
|
|
||||||
struct unicode_map *cf_encoding;
|
struct unicode_map *cf_encoding;
|
||||||
#endif
|
|
||||||
|
|
||||||
struct bch_sb_handle disk_sb;
|
struct bch_sb_handle disk_sb;
|
||||||
|
|
||||||
|
@ -1285,4 +1283,13 @@ static inline bool bch2_discard_opt_enabled(struct bch_fs *c, struct bch_dev *ca
|
||||||
: ca->mi.discard;
|
: ca->mi.discard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool bch2_fs_casefold_enabled(struct bch_fs *c)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_UNICODE
|
||||||
|
return !c->opts.casefold_disabled;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _BCACHEFS_H */
|
#endif /* _BCACHEFS_H */
|
||||||
|
|
|
@ -18,7 +18,9 @@ int bch2_casefold(struct btree_trans *trans, const struct bch_hash_info *info,
|
||||||
{
|
{
|
||||||
*out_cf = (struct qstr) QSTR_INIT(NULL, 0);
|
*out_cf = (struct qstr) QSTR_INIT(NULL, 0);
|
||||||
|
|
||||||
#ifdef CONFIG_UNICODE
|
if (!bch2_fs_casefold_enabled(trans->c))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
unsigned char *buf = bch2_trans_kmalloc(trans, BCH_NAME_MAX + 1);
|
unsigned char *buf = bch2_trans_kmalloc(trans, BCH_NAME_MAX + 1);
|
||||||
int ret = PTR_ERR_OR_ZERO(buf);
|
int ret = PTR_ERR_OR_ZERO(buf);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -30,9 +32,6 @@ int bch2_casefold(struct btree_trans *trans, const struct bch_hash_info *info,
|
||||||
|
|
||||||
*out_cf = (struct qstr) QSTR_INIT(buf, ret);
|
*out_cf = (struct qstr) QSTR_INIT(buf, ret);
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned bch2_dirent_name_bytes(struct bkey_s_c_dirent d)
|
static unsigned bch2_dirent_name_bytes(struct bkey_s_c_dirent d)
|
||||||
|
@ -231,7 +230,8 @@ void bch2_dirent_to_text(struct printbuf *out, struct bch_fs *c, struct bkey_s_c
|
||||||
prt_printf(out, " type %s", bch2_d_type_str(d.v->d_type));
|
prt_printf(out, " type %s", bch2_d_type_str(d.v->d_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_dirent_init_name(struct bkey_i_dirent *dirent,
|
int bch2_dirent_init_name(struct bch_fs *c,
|
||||||
|
struct bkey_i_dirent *dirent,
|
||||||
const struct bch_hash_info *hash_info,
|
const struct bch_hash_info *hash_info,
|
||||||
const struct qstr *name,
|
const struct qstr *name,
|
||||||
const struct qstr *cf_name)
|
const struct qstr *cf_name)
|
||||||
|
@ -251,7 +251,9 @@ int bch2_dirent_init_name(struct bkey_i_dirent *dirent,
|
||||||
offsetof(struct bch_dirent, d_name) -
|
offsetof(struct bch_dirent, d_name) -
|
||||||
name->len);
|
name->len);
|
||||||
} else {
|
} else {
|
||||||
#ifdef CONFIG_UNICODE
|
if (!bch2_fs_casefold_enabled(c))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
memcpy(&dirent->v.d_cf_name_block.d_names[0], name->name, name->len);
|
memcpy(&dirent->v.d_cf_name_block.d_names[0], name->name, name->len);
|
||||||
|
|
||||||
char *cf_out = &dirent->v.d_cf_name_block.d_names[name->len];
|
char *cf_out = &dirent->v.d_cf_name_block.d_names[name->len];
|
||||||
|
@ -277,9 +279,6 @@ int bch2_dirent_init_name(struct bkey_i_dirent *dirent,
|
||||||
dirent->v.d_cf_name_block.d_cf_name_len = cpu_to_le16(cf_len);
|
dirent->v.d_cf_name_block.d_cf_name_len = cpu_to_le16(cf_len);
|
||||||
|
|
||||||
EBUG_ON(bch2_dirent_get_casefold_name(dirent_i_to_s_c(dirent)).len != cf_len);
|
EBUG_ON(bch2_dirent_get_casefold_name(dirent_i_to_s_c(dirent)).len != cf_len);
|
||||||
#else
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned u64s = dirent_val_u64s(name->len, cf_len);
|
unsigned u64s = dirent_val_u64s(name->len, cf_len);
|
||||||
|
@ -313,7 +312,7 @@ struct bkey_i_dirent *bch2_dirent_create_key(struct btree_trans *trans,
|
||||||
dirent->v.d_type = type;
|
dirent->v.d_type = type;
|
||||||
dirent->v.d_unused = 0;
|
dirent->v.d_unused = 0;
|
||||||
|
|
||||||
int ret = bch2_dirent_init_name(dirent, hash_info, name, cf_name);
|
int ret = bch2_dirent_init_name(trans->c, dirent, hash_info, name, cf_name);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,8 @@ static inline void dirent_copy_target(struct bkey_i_dirent *dst,
|
||||||
dst->v.d_type = src.v->d_type;
|
dst->v.d_type = src.v->d_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_dirent_init_name(struct bkey_i_dirent *,
|
int bch2_dirent_init_name(struct bch_fs *,
|
||||||
|
struct bkey_i_dirent *,
|
||||||
const struct bch_hash_info *,
|
const struct bch_hash_info *,
|
||||||
const struct qstr *,
|
const struct qstr *,
|
||||||
const struct qstr *);
|
const struct qstr *);
|
||||||
|
|
|
@ -722,7 +722,6 @@ static struct dentry *bch2_lookup(struct inode *vdir, struct dentry *dentry,
|
||||||
if (IS_ERR(inode))
|
if (IS_ERR(inode))
|
||||||
inode = NULL;
|
inode = NULL;
|
||||||
|
|
||||||
#ifdef CONFIG_UNICODE
|
|
||||||
if (!inode && IS_CASEFOLDED(vdir)) {
|
if (!inode && IS_CASEFOLDED(vdir)) {
|
||||||
/*
|
/*
|
||||||
* Do not cache a negative dentry in casefolded directories
|
* Do not cache a negative dentry in casefolded directories
|
||||||
|
@ -737,7 +736,6 @@ static struct dentry *bch2_lookup(struct inode *vdir, struct dentry *dentry,
|
||||||
*/
|
*/
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
return d_splice_alias(&inode->v, dentry);
|
return d_splice_alias(&inode->v, dentry);
|
||||||
}
|
}
|
||||||
|
@ -2566,9 +2564,10 @@ got_sb:
|
||||||
sb->s_shrink->seeks = 0;
|
sb->s_shrink->seeks = 0;
|
||||||
|
|
||||||
#ifdef CONFIG_UNICODE
|
#ifdef CONFIG_UNICODE
|
||||||
sb->s_encoding = c->cf_encoding;
|
if (bch2_fs_casefold_enabled(c))
|
||||||
#endif
|
sb->s_encoding = c->cf_encoding;
|
||||||
generic_set_sb_d_ops(sb);
|
generic_set_sb_d_ops(sb);
|
||||||
|
#endif
|
||||||
|
|
||||||
vinode = bch2_vfs_inode_get(c, BCACHEFS_ROOT_SUBVOL_INUM);
|
vinode = bch2_vfs_inode_get(c, BCACHEFS_ROOT_SUBVOL_INUM);
|
||||||
ret = PTR_ERR_OR_ZERO(vinode);
|
ret = PTR_ERR_OR_ZERO(vinode);
|
||||||
|
|
|
@ -2302,9 +2302,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
|
||||||
*hash_info = bch2_hash_info_init(c, &i->inode);
|
*hash_info = bch2_hash_info_init(c, &i->inode);
|
||||||
dir->first_this_inode = false;
|
dir->first_this_inode = false;
|
||||||
|
|
||||||
#ifdef CONFIG_UNICODE
|
|
||||||
hash_info->cf_encoding = bch2_inode_casefold(c, &i->inode) ? c->cf_encoding : NULL;
|
hash_info->cf_encoding = bch2_inode_casefold(c, &i->inode) ? c->cf_encoding : NULL;
|
||||||
#endif
|
|
||||||
|
|
||||||
ret = bch2_str_hash_check_key(trans, s, &bch2_dirent_hash_desc, hash_info,
|
ret = bch2_str_hash_check_key(trans, s, &bch2_dirent_hash_desc, hash_info,
|
||||||
iter, k, need_second_pass);
|
iter, k, need_second_pass);
|
||||||
|
|
|
@ -1265,7 +1265,14 @@ int bch2_inode_set_casefold(struct btree_trans *trans, subvol_inum inum,
|
||||||
{
|
{
|
||||||
struct bch_fs *c = trans->c;
|
struct bch_fs *c = trans->c;
|
||||||
|
|
||||||
#ifdef CONFIG_UNICODE
|
#ifndef CONFIG_UNICODE
|
||||||
|
bch_err(c, "Cannot use casefolding on a kernel without CONFIG_UNICODE");
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (c->opts.casefold_disabled)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
/* Not supported on individual files. */
|
/* Not supported on individual files. */
|
||||||
if (!S_ISDIR(bi->bi_mode))
|
if (!S_ISDIR(bi->bi_mode))
|
||||||
|
@ -1289,10 +1296,6 @@ int bch2_inode_set_casefold(struct btree_trans *trans, subvol_inum inum,
|
||||||
bi->bi_fields_set |= BIT(Inode_opt_casefold);
|
bi->bi_fields_set |= BIT(Inode_opt_casefold);
|
||||||
|
|
||||||
return bch2_maybe_propagate_has_case_insensitive(trans, inum, bi);
|
return bch2_maybe_propagate_has_case_insensitive(trans, inum, bi);
|
||||||
#else
|
|
||||||
bch_err(c, "Cannot use casefolding on a kernel without CONFIG_UNICODE");
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static noinline int __bch2_inode_rm_snapshot(struct btree_trans *trans, u64 inum, u32 snapshot)
|
static noinline int __bch2_inode_rm_snapshot(struct btree_trans *trans, u64 inum, u32 snapshot)
|
||||||
|
|
|
@ -234,6 +234,11 @@ enum fsck_err_opts {
|
||||||
OPT_BOOL(), \
|
OPT_BOOL(), \
|
||||||
BCH_SB_CASEFOLD, false, \
|
BCH_SB_CASEFOLD, false, \
|
||||||
NULL, "Dirent lookups are casefolded") \
|
NULL, "Dirent lookups are casefolded") \
|
||||||
|
x(casefold_disabled, u8, \
|
||||||
|
OPT_FS|OPT_MOUNT, \
|
||||||
|
OPT_BOOL(), \
|
||||||
|
BCH2_NO_SB_OPT, false, \
|
||||||
|
NULL, "Disable casefolding filesystem wide") \
|
||||||
x(inodes_32bit, u8, \
|
x(inodes_32bit, u8, \
|
||||||
OPT_FS|OPT_INODE|OPT_FORMAT|OPT_MOUNT|OPT_RUNTIME, \
|
OPT_FS|OPT_INODE|OPT_FORMAT|OPT_MOUNT|OPT_RUNTIME, \
|
||||||
OPT_BOOL(), \
|
OPT_BOOL(), \
|
||||||
|
|
|
@ -38,6 +38,7 @@ static int bch2_fsck_rename_dirent(struct btree_trans *trans,
|
||||||
struct bkey_s_c_dirent old,
|
struct bkey_s_c_dirent old,
|
||||||
bool *updated_before_k_pos)
|
bool *updated_before_k_pos)
|
||||||
{
|
{
|
||||||
|
struct bch_fs *c = trans->c;
|
||||||
struct qstr old_name = bch2_dirent_get_name(old);
|
struct qstr old_name = bch2_dirent_get_name(old);
|
||||||
struct bkey_i_dirent *new = bch2_trans_kmalloc(trans, BKEY_U64s_MAX * sizeof(u64));
|
struct bkey_i_dirent *new = bch2_trans_kmalloc(trans, BKEY_U64s_MAX * sizeof(u64));
|
||||||
int ret = PTR_ERR_OR_ZERO(new);
|
int ret = PTR_ERR_OR_ZERO(new);
|
||||||
|
@ -60,7 +61,7 @@ static int bch2_fsck_rename_dirent(struct btree_trans *trans,
|
||||||
sprintf(renamed_buf, "%.*s.fsck_renamed-%u",
|
sprintf(renamed_buf, "%.*s.fsck_renamed-%u",
|
||||||
old_name.len, old_name.name, i));
|
old_name.len, old_name.name, i));
|
||||||
|
|
||||||
ret = bch2_dirent_init_name(new, hash_info, &renamed_name, NULL);
|
ret = bch2_dirent_init_name(c, new, hash_info, &renamed_name, NULL);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -79,7 +80,7 @@ static int bch2_fsck_rename_dirent(struct btree_trans *trans,
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ret ?: bch2_fsck_update_backpointers(trans, s, desc, hash_info, &new->k_i);
|
ret = ret ?: bch2_fsck_update_backpointers(trans, s, desc, hash_info, &new->k_i);
|
||||||
bch_err_fn(trans->c, ret);
|
bch_err_fn(c, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,9 +48,7 @@ bch2_hash_info_init(struct bch_fs *c, const struct bch_inode_unpacked *bi)
|
||||||
struct bch_hash_info info = {
|
struct bch_hash_info info = {
|
||||||
.inum_snapshot = bi->bi_snapshot,
|
.inum_snapshot = bi->bi_snapshot,
|
||||||
.type = INODE_STR_HASH(bi),
|
.type = INODE_STR_HASH(bi),
|
||||||
#ifdef CONFIG_UNICODE
|
|
||||||
.cf_encoding = bch2_inode_casefold(c, bi) ? c->cf_encoding : NULL,
|
.cf_encoding = bch2_inode_casefold(c, bi) ? c->cf_encoding : NULL,
|
||||||
#endif
|
|
||||||
.siphash_key = { .k0 = bi->bi_hash_seed }
|
.siphash_key = { .k0 = bi->bi_hash_seed }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1025,15 +1025,17 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts *opts,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_UNICODE
|
#ifdef CONFIG_UNICODE
|
||||||
/* Default encoding until we can potentially have more as an option. */
|
if (bch2_fs_casefold_enabled(c)) {
|
||||||
c->cf_encoding = utf8_load(BCH_FS_DEFAULT_UTF8_ENCODING);
|
/* Default encoding until we can potentially have more as an option. */
|
||||||
if (IS_ERR(c->cf_encoding)) {
|
c->cf_encoding = utf8_load(BCH_FS_DEFAULT_UTF8_ENCODING);
|
||||||
printk(KERN_ERR "Cannot load UTF-8 encoding for filesystem. Version: %u.%u.%u",
|
if (IS_ERR(c->cf_encoding)) {
|
||||||
unicode_major(BCH_FS_DEFAULT_UTF8_ENCODING),
|
printk(KERN_ERR "Cannot load UTF-8 encoding for filesystem. Version: %u.%u.%u",
|
||||||
unicode_minor(BCH_FS_DEFAULT_UTF8_ENCODING),
|
unicode_major(BCH_FS_DEFAULT_UTF8_ENCODING),
|
||||||
unicode_rev(BCH_FS_DEFAULT_UTF8_ENCODING));
|
unicode_minor(BCH_FS_DEFAULT_UTF8_ENCODING),
|
||||||
ret = -EINVAL;
|
unicode_rev(BCH_FS_DEFAULT_UTF8_ENCODING));
|
||||||
goto err;
|
ret = -EINVAL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (c->sb.features & BIT_ULL(BCH_FEATURE_casefolding)) {
|
if (c->sb.features & BIT_ULL(BCH_FEATURE_casefolding)) {
|
||||||
|
@ -1160,12 +1162,11 @@ int bch2_fs_start(struct bch_fs *c)
|
||||||
|
|
||||||
print_mount_opts(c);
|
print_mount_opts(c);
|
||||||
|
|
||||||
#ifdef CONFIG_UNICODE
|
if (c->cf_encoding)
|
||||||
bch_info(c, "Using encoding defined by superblock: utf8-%u.%u.%u",
|
bch_info(c, "Using encoding defined by superblock: utf8-%u.%u.%u",
|
||||||
unicode_major(BCH_FS_DEFAULT_UTF8_ENCODING),
|
unicode_major(BCH_FS_DEFAULT_UTF8_ENCODING),
|
||||||
unicode_minor(BCH_FS_DEFAULT_UTF8_ENCODING),
|
unicode_minor(BCH_FS_DEFAULT_UTF8_ENCODING),
|
||||||
unicode_rev(BCH_FS_DEFAULT_UTF8_ENCODING));
|
unicode_rev(BCH_FS_DEFAULT_UTF8_ENCODING));
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!bch2_fs_may_start(c))
|
if (!bch2_fs_may_start(c))
|
||||||
return bch_err_throw(c, insufficient_devices_to_start);
|
return bch_err_throw(c, insufficient_devices_to_start);
|
||||||
|
|
Loading…
Add table
Reference in a new issue