mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-02-22 00:00:03 +03:00
Update bcachefs sources to d4b7ef921a bcachefs: Refactoring
This commit is contained in:
parent
bf8c59996b
commit
8351bbc05b
@ -1 +1 @@
|
||||
e82e65627960a46945b78a5e5e946b23b8f08972
|
||||
0415b63b198ccf8bf5eee3af73accd60e94ad63a
|
||||
|
2
Makefile
2
Makefile
@ -75,7 +75,7 @@ deb: all
|
||||
|
||||
.PHONE: update-bcachefs-sources
|
||||
update-bcachefs-sources:
|
||||
git rm -rf libbcachefs
|
||||
git rm -rf --ignore-unmatch libbcachefs
|
||||
cp $(LINUX_DIR)/fs/bcachefs/*.[ch] libbcachefs/
|
||||
cp $(LINUX_DIR)/include/trace/events/bcachefs.h include/trace/events/
|
||||
echo `cd $(LINUX_DIR); git rev-parse HEAD` > .bcachefs_revision
|
||||
|
@ -130,14 +130,14 @@ static void create_dirent(struct bch_fs *c,
|
||||
struct bch_hash_info parent_hash_info = bch2_hash_info_init(c, parent);
|
||||
struct qstr qname = { { { .len = strlen(name), } }, .name = name };
|
||||
|
||||
int ret = bch2_dirent_create(c, parent->inum, &parent_hash_info,
|
||||
int ret = bch2_dirent_create(c, parent->bi_inum, &parent_hash_info,
|
||||
mode_to_type(mode), &qname,
|
||||
inum, NULL, BCH_HASH_SET_MUST_CREATE);
|
||||
if (ret)
|
||||
die("error creating file: %s", strerror(-ret));
|
||||
|
||||
if (S_ISDIR(mode))
|
||||
parent->i_nlink++;
|
||||
parent->bi_nlink++;
|
||||
}
|
||||
|
||||
static void create_link(struct bch_fs *c,
|
||||
@ -149,7 +149,7 @@ static void create_link(struct bch_fs *c,
|
||||
if (ret)
|
||||
die("error looking up hardlink: %s", strerror(-ret));
|
||||
|
||||
inode.i_nlink++;
|
||||
inode.bi_nlink++;
|
||||
update_inode(c, &inode);
|
||||
|
||||
create_dirent(c, parent, name, inum, mode);
|
||||
@ -171,7 +171,7 @@ static struct bch_inode_unpacked create_file(struct bch_fs *c,
|
||||
if (ret)
|
||||
die("error creating file: %s", strerror(-ret));
|
||||
|
||||
create_dirent(c, parent, name, new_inode.inum, mode);
|
||||
create_dirent(c, parent, name, new_inode.bi_inum, mode);
|
||||
|
||||
return new_inode;
|
||||
}
|
||||
@ -207,9 +207,9 @@ static const struct xattr_handler *xattr_resolve_name(const char **name)
|
||||
static void copy_times(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
struct stat *src)
|
||||
{
|
||||
dst->i_atime = timespec_to_bch2_time(c, src->st_atim);
|
||||
dst->i_mtime = timespec_to_bch2_time(c, src->st_mtim);
|
||||
dst->i_ctime = timespec_to_bch2_time(c, src->st_ctim);
|
||||
dst->bi_atime = timespec_to_bch2_time(c, src->st_atim);
|
||||
dst->bi_mtime = timespec_to_bch2_time(c, src->st_mtim);
|
||||
dst->bi_ctime = timespec_to_bch2_time(c, src->st_ctim);
|
||||
}
|
||||
|
||||
static void copy_xattrs(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
@ -236,7 +236,7 @@ static void copy_xattrs(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
|
||||
const struct xattr_handler *h = xattr_resolve_name(&attr);
|
||||
|
||||
int ret = __bch2_xattr_set(c, dst->inum, &hash_info, attr,
|
||||
int ret = __bch2_xattr_set(c, dst->bi_inum, &hash_info, attr,
|
||||
val, val_size, 0, h->flags, NULL);
|
||||
if (ret < 0)
|
||||
die("error creating xattr: %s", strerror(-ret));
|
||||
@ -266,11 +266,11 @@ static void write_data(struct bch_fs *c,
|
||||
die("error reserving space in new filesystem: %s", strerror(-ret));
|
||||
|
||||
bch2_write_op_init(&op, c, res, c->write_points,
|
||||
POS(dst_inode->inum, dst_offset >> 9), NULL, 0);
|
||||
POS(dst_inode->bi_inum, dst_offset >> 9), NULL, 0);
|
||||
closure_call(&op.cl, bch2_write, NULL, &cl);
|
||||
closure_sync(&cl);
|
||||
|
||||
dst_inode->i_sectors += len >> 9;
|
||||
dst_inode->bi_sectors += len >> 9;
|
||||
}
|
||||
|
||||
static char buf[1 << 20] __aligned(PAGE_SIZE);
|
||||
@ -316,7 +316,7 @@ static void link_data(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
length);
|
||||
|
||||
e = bkey_extent_init(&k.k);
|
||||
e->k.p.inode = dst->inum;
|
||||
e->k.p.inode = dst->bi_inum;
|
||||
e->k.p.offset = logical + sectors;
|
||||
e->k.size = sectors;
|
||||
extent_ptr_append(e, (struct bch_extent_ptr) {
|
||||
@ -340,7 +340,7 @@ static void link_data(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
|
||||
bch2_disk_reservation_put(c, &res);
|
||||
|
||||
dst->i_sectors += sectors;
|
||||
dst->bi_sectors += sectors;
|
||||
logical += sectors;
|
||||
physical += sectors;
|
||||
length -= sectors;
|
||||
@ -453,7 +453,7 @@ static void copy_dir(struct copy_fs_state *s,
|
||||
stat.st_mode, stat.st_rdev);
|
||||
|
||||
if (dst_inum)
|
||||
*dst_inum = inode.inum;
|
||||
*dst_inum = inode.bi_inum;
|
||||
|
||||
copy_times(c, &inode, &stat);
|
||||
copy_xattrs(c, &inode, d->d_name);
|
||||
@ -467,14 +467,14 @@ static void copy_dir(struct copy_fs_state *s,
|
||||
close(fd);
|
||||
break;
|
||||
case DT_REG:
|
||||
inode.i_size = stat.st_size;
|
||||
inode.bi_size = stat.st_size;
|
||||
|
||||
fd = xopen(d->d_name, O_RDONLY|O_NOATIME);
|
||||
copy_file(c, &inode, fd, child_path, &s->extents);
|
||||
close(fd);
|
||||
break;
|
||||
case DT_LNK:
|
||||
inode.i_size = stat.st_size;
|
||||
inode.bi_size = stat.st_size;
|
||||
|
||||
copy_link(c, &inode, d->d_name);
|
||||
break;
|
||||
@ -555,7 +555,7 @@ static void reserve_old_fs_space(struct bch_fs *c,
|
||||
|
||||
dst = create_file(c, root_inode, "old_migrated_filesystem",
|
||||
0, 0, S_IFREG|0400, 0);
|
||||
dst.i_size = bucket_to_sector(ca, ca->mi.nbuckets) << 9;
|
||||
dst.bi_size = bucket_to_sector(ca, ca->mi.nbuckets) << 9;
|
||||
|
||||
ranges_sort_merge(extents);
|
||||
|
||||
|
@ -189,6 +189,8 @@ struct bch_sb *bch2_format(struct format_opts opts,
|
||||
SET_BCH_SB_STR_HASH_TYPE(sb, BCH_STR_HASH_SIPHASH);
|
||||
SET_BCH_SB_ENCODED_EXTENT_MAX_BITS(sb, ilog2(opts.encoded_extent_max));
|
||||
|
||||
SET_BCH_SB_POSIX_ACL(sb, 1);
|
||||
|
||||
struct timespec now;
|
||||
if (clock_gettime(CLOCK_REALTIME, &now))
|
||||
die("error getting current time: %m");
|
||||
|
@ -1,4 +1,4 @@
|
||||
#ifndef NO_BCACHEFS_FS
|
||||
#ifdef CONFIG_BCACHEFS_POSIX_ACL
|
||||
|
||||
#include "bcachefs.h"
|
||||
|
||||
@ -8,8 +8,9 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "xattr.h"
|
||||
#include "acl.h"
|
||||
#include "fs.h"
|
||||
#include "xattr.h"
|
||||
|
||||
/*
|
||||
* Convert from filesystem to in-memory representation.
|
||||
@ -134,9 +135,10 @@ fail:
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
struct posix_acl *bch2_get_acl(struct inode *inode, int type)
|
||||
struct posix_acl *bch2_get_acl(struct inode *vinode, int type)
|
||||
{
|
||||
struct bch_fs *c = inode->i_sb->s_fs_info;
|
||||
struct bch_inode_info *inode = to_bch_ei(vinode);
|
||||
struct bch_fs *c = inode->v.i_sb->s_fs_info;
|
||||
int name_index;
|
||||
char *value = NULL;
|
||||
struct posix_acl *acl;
|
||||
@ -169,14 +171,15 @@ struct posix_acl *bch2_get_acl(struct inode *inode, int type)
|
||||
kfree(value);
|
||||
|
||||
if (!IS_ERR(acl))
|
||||
set_cached_acl(inode, type, acl);
|
||||
set_cached_acl(&inode->v, type, acl);
|
||||
|
||||
return acl;
|
||||
}
|
||||
|
||||
int bch2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
||||
int bch2_set_acl(struct inode *vinode, struct posix_acl *acl, int type)
|
||||
{
|
||||
struct bch_fs *c = inode->i_sb->s_fs_info;
|
||||
struct bch_inode_info *inode = to_bch_ei(vinode);
|
||||
struct bch_fs *c = inode->v.i_sb->s_fs_info;
|
||||
int name_index;
|
||||
void *value = NULL;
|
||||
size_t size = 0;
|
||||
@ -186,12 +189,13 @@ int bch2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
||||
case ACL_TYPE_ACCESS:
|
||||
name_index = BCH_XATTR_INDEX_POSIX_ACL_ACCESS;
|
||||
if (acl) {
|
||||
ret = posix_acl_equiv_mode(acl, &inode->i_mode);
|
||||
ret = posix_acl_equiv_mode(acl, &inode->v.i_mode);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else {
|
||||
inode->i_ctime = current_fs_time(inode->i_sb);
|
||||
mark_inode_dirty(inode);
|
||||
inode->v.i_ctime =
|
||||
current_fs_time(inode->v.i_sb);
|
||||
mark_inode_dirty(&inode->v);
|
||||
if (ret == 0)
|
||||
acl = NULL;
|
||||
}
|
||||
@ -200,7 +204,7 @@ int bch2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
||||
|
||||
case ACL_TYPE_DEFAULT:
|
||||
name_index = BCH_XATTR_INDEX_POSIX_ACL_DEFAULT;
|
||||
if (!S_ISDIR(inode->i_mode))
|
||||
if (!S_ISDIR(inode->v.i_mode))
|
||||
return acl ? -EACCES : 0;
|
||||
break;
|
||||
|
||||
@ -222,9 +226,9 @@ int bch2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
||||
ret = -E2BIG;
|
||||
|
||||
if (!ret)
|
||||
set_cached_acl(inode, type, acl);
|
||||
set_cached_acl(&inode->v, type, acl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* NO_BCACHEFS_FS */
|
||||
#endif /* CONFIG_BCACHEFS_POSIX_ACL */
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef _BCACHEFS_ACL_H
|
||||
#define _BCACHEFS_ACL_H
|
||||
|
||||
#ifndef NO_BCACHEFS_FS
|
||||
#ifdef CONFIG_BCACHEFS_POSIX_ACL
|
||||
|
||||
#define BCH_ACL_VERSION 0x0001
|
||||
|
||||
@ -54,6 +54,13 @@ struct posix_acl;
|
||||
extern struct posix_acl *bch2_get_acl(struct inode *, int);
|
||||
extern int bch2_set_acl(struct inode *, struct posix_acl *, int);
|
||||
|
||||
#endif /* NO_BCACHEFS_FS */
|
||||
#else
|
||||
|
||||
static inline int bch2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BCACHEFS_POSIX_ACL */
|
||||
|
||||
#endif /* _BCACHEFS_ACL_H */
|
||||
|
@ -367,7 +367,7 @@ struct bch_dev {
|
||||
uuid_le uuid;
|
||||
char name[BDEVNAME_SIZE];
|
||||
|
||||
struct bcache_superblock disk_sb;
|
||||
struct bch_sb_handle disk_sb;
|
||||
int sb_write_error;
|
||||
|
||||
struct bch_devs_mask self;
|
||||
@ -445,6 +445,7 @@ struct bch_dev {
|
||||
* won't automatically reattach).
|
||||
*/
|
||||
enum {
|
||||
BCH_FS_ALLOC_READ_DONE,
|
||||
BCH_FS_INITIAL_GC_DONE,
|
||||
BCH_FS_EMERGENCY_RO,
|
||||
BCH_FS_WRITE_DISABLE_COMPLETE,
|
||||
@ -517,14 +518,11 @@ struct bch_fs {
|
||||
uuid_le uuid;
|
||||
uuid_le user_uuid;
|
||||
|
||||
u16 block_size;
|
||||
u16 btree_node_size;
|
||||
u16 encoded_extent_max;
|
||||
|
||||
u8 nr_devices;
|
||||
u8 clean;
|
||||
|
||||
u8 str_hash_type;
|
||||
u8 encryption_type;
|
||||
|
||||
u64 time_base_lo;
|
||||
@ -796,7 +794,7 @@ static inline unsigned bucket_bytes(const struct bch_dev *ca)
|
||||
|
||||
static inline unsigned block_bytes(const struct bch_fs *c)
|
||||
{
|
||||
return c->sb.block_size << 9;
|
||||
return c->opts.block_size << 9;
|
||||
}
|
||||
|
||||
#endif /* _BCACHEFS_H */
|
||||
|
@ -9,45 +9,29 @@
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/uuid.h>
|
||||
|
||||
#define LE32_BITMASK(name, type, field, offset, end) \
|
||||
#define LE_BITMASK(_bits, name, type, field, offset, end) \
|
||||
static const unsigned name##_OFFSET = offset; \
|
||||
static const unsigned name##_BITS = (end - offset); \
|
||||
static const __u64 name##_MAX = (1ULL << (end - offset)) - 1; \
|
||||
static const __u##_bits name##_MAX = (1ULL << (end - offset)) - 1; \
|
||||
\
|
||||
static inline __u64 name(const type *k) \
|
||||
{ \
|
||||
return (__le32_to_cpu(k->field) >> offset) & \
|
||||
return (__le##_bits##_to_cpu(k->field) >> offset) & \
|
||||
~(~0ULL << (end - offset)); \
|
||||
} \
|
||||
\
|
||||
static inline void SET_##name(type *k, __u64 v) \
|
||||
{ \
|
||||
__u64 new = __le32_to_cpu(k->field); \
|
||||
__u##_bits new = __le##_bits##_to_cpu(k->field); \
|
||||
\
|
||||
new &= ~(~(~0ULL << (end - offset)) << offset); \
|
||||
new |= (v & ~(~0ULL << (end - offset))) << offset; \
|
||||
k->field = __cpu_to_le32(new); \
|
||||
k->field = __cpu_to_le##_bits(new); \
|
||||
}
|
||||
|
||||
#define LE64_BITMASK(name, type, field, offset, end) \
|
||||
static const unsigned name##_OFFSET = offset; \
|
||||
static const unsigned name##_BITS = (end - offset); \
|
||||
static const __u64 name##_MAX = (1ULL << (end - offset)) - 1; \
|
||||
\
|
||||
static inline __u64 name(const type *k) \
|
||||
{ \
|
||||
return (__le64_to_cpu(k->field) >> offset) & \
|
||||
~(~0ULL << (end - offset)); \
|
||||
} \
|
||||
\
|
||||
static inline void SET_##name(type *k, __u64 v) \
|
||||
{ \
|
||||
__u64 new = __le64_to_cpu(k->field); \
|
||||
\
|
||||
new &= ~(~(~0ULL << (end - offset)) << offset); \
|
||||
new |= (v & ~(~0ULL << (end - offset))) << offset; \
|
||||
k->field = __cpu_to_le64(new); \
|
||||
}
|
||||
#define LE16_BITMASK(n, t, f, o, e) LE_BITMASK(16, n, t, f, o, e)
|
||||
#define LE32_BITMASK(n, t, f, o, e) LE_BITMASK(32, n, t, f, o, e)
|
||||
#define LE64_BITMASK(n, t, f, o, e) LE_BITMASK(64, n, t, f, o, e)
|
||||
|
||||
struct bkey_format {
|
||||
__u8 key_u64s;
|
||||
@ -592,9 +576,9 @@ enum bch_inode_types {
|
||||
struct bch_inode {
|
||||
struct bch_val v;
|
||||
|
||||
__le64 i_hash_seed;
|
||||
__le32 i_flags;
|
||||
__le16 i_mode;
|
||||
__le64 bi_hash_seed;
|
||||
__le32 bi_flags;
|
||||
__le16 bi_mode;
|
||||
__u8 fields[0];
|
||||
} __attribute__((packed, aligned(8)));
|
||||
BKEY_VAL_TYPE(inode, BCH_INODE_FS);
|
||||
@ -602,24 +586,23 @@ BKEY_VAL_TYPE(inode, BCH_INODE_FS);
|
||||
struct bch_inode_generation {
|
||||
struct bch_val v;
|
||||
|
||||
__le32 i_generation;
|
||||
__le32 bi_generation;
|
||||
__le32 pad;
|
||||
} __attribute__((packed, aligned(8)));
|
||||
BKEY_VAL_TYPE(inode_generation, BCH_INODE_GENERATION);
|
||||
|
||||
|
||||
#define BCH_INODE_FIELDS() \
|
||||
BCH_INODE_FIELD(i_atime, 64) \
|
||||
BCH_INODE_FIELD(i_ctime, 64) \
|
||||
BCH_INODE_FIELD(i_mtime, 64) \
|
||||
BCH_INODE_FIELD(i_otime, 64) \
|
||||
BCH_INODE_FIELD(i_size, 64) \
|
||||
BCH_INODE_FIELD(i_sectors, 64) \
|
||||
BCH_INODE_FIELD(i_uid, 32) \
|
||||
BCH_INODE_FIELD(i_gid, 32) \
|
||||
BCH_INODE_FIELD(i_nlink, 32) \
|
||||
BCH_INODE_FIELD(i_generation, 32) \
|
||||
BCH_INODE_FIELD(i_dev, 32)
|
||||
BCH_INODE_FIELD(bi_atime, 64) \
|
||||
BCH_INODE_FIELD(bi_ctime, 64) \
|
||||
BCH_INODE_FIELD(bi_mtime, 64) \
|
||||
BCH_INODE_FIELD(bi_otime, 64) \
|
||||
BCH_INODE_FIELD(bi_size, 64) \
|
||||
BCH_INODE_FIELD(bi_sectors, 64) \
|
||||
BCH_INODE_FIELD(bi_uid, 32) \
|
||||
BCH_INODE_FIELD(bi_gid, 32) \
|
||||
BCH_INODE_FIELD(bi_nlink, 32) \
|
||||
BCH_INODE_FIELD(bi_generation, 32) \
|
||||
BCH_INODE_FIELD(bi_dev, 32)
|
||||
|
||||
enum {
|
||||
/*
|
||||
@ -650,8 +633,8 @@ enum {
|
||||
#define BCH_INODE_I_SECTORS_DIRTY (1 << __BCH_INODE_I_SECTORS_DIRTY)
|
||||
#define BCH_INODE_HAS_XATTRS (1 << __BCH_INODE_HAS_XATTRS)
|
||||
|
||||
LE32_BITMASK(INODE_STR_HASH, struct bch_inode, i_flags, 20, 24);
|
||||
LE32_BITMASK(INODE_NR_FIELDS, struct bch_inode, i_flags, 24, 32);
|
||||
LE32_BITMASK(INODE_STR_HASH, struct bch_inode, bi_flags, 20, 24);
|
||||
LE32_BITMASK(INODE_NR_FIELDS, struct bch_inode, bi_flags, 24, 32);
|
||||
|
||||
struct bch_inode_blockdev {
|
||||
struct bch_val v;
|
||||
@ -960,6 +943,8 @@ struct bch_sb {
|
||||
* algorithm in use, if/when we get more than one
|
||||
*/
|
||||
|
||||
LE16_BITMASK(BCH_SB_BLOCK_SIZE, struct bch_sb, block_size, 0, 16);
|
||||
|
||||
LE64_BITMASK(BCH_SB_INITIALIZED, struct bch_sb, flags[0], 0, 1);
|
||||
LE64_BITMASK(BCH_SB_CLEAN, struct bch_sb, flags[0], 1, 2);
|
||||
LE64_BITMASK(BCH_SB_CSUM_TYPE, struct bch_sb, flags[0], 2, 8);
|
||||
@ -976,7 +961,7 @@ LE64_BITMASK(BCH_SB_DATA_CSUM_TYPE, struct bch_sb, flags[0], 44, 48);
|
||||
LE64_BITMASK(BCH_SB_META_REPLICAS_WANT, struct bch_sb, flags[0], 48, 52);
|
||||
LE64_BITMASK(BCH_SB_DATA_REPLICAS_WANT, struct bch_sb, flags[0], 52, 56);
|
||||
|
||||
/* 56-64 unused, was REPLICAS_HAVE */
|
||||
LE64_BITMASK(BCH_SB_POSIX_ACL, struct bch_sb, flags[0], 56, 57);
|
||||
|
||||
LE64_BITMASK(BCH_SB_STR_HASH_TYPE, struct bch_sb, flags[1], 0, 4);
|
||||
LE64_BITMASK(BCH_SB_COMPRESSION_TYPE, struct bch_sb, flags[1], 4, 8);
|
||||
|
@ -51,7 +51,7 @@ static inline bool btree_node_hashed(struct btree *b)
|
||||
|
||||
static inline size_t btree_bytes(struct bch_fs *c)
|
||||
{
|
||||
return c->sb.btree_node_size << 9;
|
||||
return c->opts.btree_node_size << 9;
|
||||
}
|
||||
|
||||
static inline size_t btree_max_u64s(struct bch_fs *c)
|
||||
@ -71,7 +71,7 @@ static inline size_t btree_pages(struct bch_fs *c)
|
||||
|
||||
static inline unsigned btree_blocks(struct bch_fs *c)
|
||||
{
|
||||
return c->sb.btree_node_size >> c->block_bits;
|
||||
return c->opts.btree_node_size >> c->block_bits;
|
||||
}
|
||||
|
||||
#define BTREE_SPLIT_THRESHOLD(c) (btree_blocks(c) * 3 / 4)
|
||||
|
@ -116,7 +116,7 @@ static u8 bch2_btree_mark_key(struct bch_fs *c, enum bkey_type type,
|
||||
{
|
||||
switch (type) {
|
||||
case BKEY_TYPE_BTREE:
|
||||
bch2_gc_mark_key(c, k, c->sb.btree_node_size, true, flags);
|
||||
bch2_gc_mark_key(c, k, c->opts.btree_node_size, true, flags);
|
||||
return 0;
|
||||
case BKEY_TYPE_EXTENTS:
|
||||
bch2_gc_mark_key(c, k, k.k->size, false, flags);
|
||||
@ -386,7 +386,7 @@ static void bch2_mark_pending_btree_node_frees(struct bch_fs *c)
|
||||
for_each_pending_btree_node_free(c, as, d)
|
||||
if (d->index_update_done)
|
||||
__bch2_mark_key(c, bkey_i_to_s_c(&d->key),
|
||||
c->sb.btree_node_size, true,
|
||||
c->opts.btree_node_size, true,
|
||||
&stats, 0,
|
||||
BCH_BUCKET_MARK_MAY_MAKE_UNAVAILABLE);
|
||||
/*
|
||||
|
@ -916,7 +916,7 @@ static int validate_bset(struct bch_fs *c, struct btree *b,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (b->written + sectors > c->sb.btree_node_size) {
|
||||
if (b->written + sectors > c->opts.btree_node_size) {
|
||||
btree_node_error(c, b, "bset past end of btree node");
|
||||
i->u64s = 0;
|
||||
return 0;
|
||||
@ -1034,7 +1034,7 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct btree *b)
|
||||
if (bch2_meta_read_fault("btree"))
|
||||
goto err;
|
||||
|
||||
while (b->written < c->sb.btree_node_size) {
|
||||
while (b->written < c->opts.btree_node_size) {
|
||||
unsigned sectors, whiteout_u64s = 0;
|
||||
|
||||
if (!b->written) {
|
||||
@ -1528,7 +1528,7 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b,
|
||||
BUG_ON(!list_empty(&b->write_blocked));
|
||||
BUG_ON((b->will_make_reachable != NULL) != !b->written);
|
||||
|
||||
BUG_ON(b->written >= c->sb.btree_node_size);
|
||||
BUG_ON(b->written >= c->opts.btree_node_size);
|
||||
BUG_ON(bset_written(b, btree_bset_last(b)));
|
||||
BUG_ON(le64_to_cpu(b->data->magic) != bset_magic(c));
|
||||
BUG_ON(memcmp(&b->data->format, &b->format, sizeof(b->format)));
|
||||
@ -1612,7 +1612,7 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b,
|
||||
memset(data + bytes_to_write, 0,
|
||||
(sectors_to_write << 9) - bytes_to_write);
|
||||
|
||||
BUG_ON(b->written + sectors_to_write > c->sb.btree_node_size);
|
||||
BUG_ON(b->written + sectors_to_write > c->opts.btree_node_size);
|
||||
BUG_ON(BSET_BIG_ENDIAN(i) != CPU_BIG_ENDIAN);
|
||||
BUG_ON(i->seq != b->data->keys.seq);
|
||||
|
||||
|
@ -181,7 +181,7 @@ found:
|
||||
*/
|
||||
replicas = bch2_extent_nr_dirty_ptrs(k);
|
||||
if (replicas)
|
||||
stats->s[replicas - 1].data[S_META] -= c->sb.btree_node_size;
|
||||
stats->s[replicas - 1].data[S_META] -= c->opts.btree_node_size;
|
||||
|
||||
/*
|
||||
* We're dropping @k from the btree, but it's still live until the
|
||||
@ -208,7 +208,7 @@ found:
|
||||
struct bch_fs_usage tmp = { 0 };
|
||||
|
||||
bch2_mark_key(c, bkey_i_to_s_c(&d->key),
|
||||
-c->sb.btree_node_size, true, b
|
||||
-c->opts.btree_node_size, true, b
|
||||
? gc_pos_btree_node(b)
|
||||
: gc_pos_btree_root(as->btree_id),
|
||||
&tmp, 0);
|
||||
@ -285,7 +285,7 @@ static void bch2_btree_node_free_ondisk(struct bch_fs *c,
|
||||
BUG_ON(!pending->index_update_done);
|
||||
|
||||
bch2_mark_key(c, bkey_i_to_s_c(&pending->key),
|
||||
-c->sb.btree_node_size, true,
|
||||
-c->opts.btree_node_size, true,
|
||||
gc_phase(GC_PHASE_PENDING_DELETE),
|
||||
&stats, 0);
|
||||
/*
|
||||
@ -337,7 +337,7 @@ static struct btree *__bch2_btree_node_alloc(struct bch_fs *c,
|
||||
retry:
|
||||
/* alloc_sectors is weird, I suppose */
|
||||
bkey_extent_init(&tmp.k);
|
||||
tmp.k.k.size = c->sb.btree_node_size,
|
||||
tmp.k.k.size = c->opts.btree_node_size,
|
||||
|
||||
ob = bch2_alloc_sectors(c, &c->btree_write_point,
|
||||
bkey_i_to_extent(&tmp.k),
|
||||
@ -347,7 +347,7 @@ retry:
|
||||
if (IS_ERR(ob))
|
||||
return ERR_CAST(ob);
|
||||
|
||||
if (tmp.k.k.size < c->sb.btree_node_size) {
|
||||
if (tmp.k.k.size < c->opts.btree_node_size) {
|
||||
bch2_open_bucket_put(c, ob);
|
||||
goto retry;
|
||||
}
|
||||
@ -491,7 +491,7 @@ static struct btree_reserve *bch2_btree_reserve_get(struct bch_fs *c,
|
||||
struct btree_reserve *reserve;
|
||||
struct btree *b;
|
||||
struct disk_reservation disk_res = { 0, 0 };
|
||||
unsigned sectors = nr_nodes * c->sb.btree_node_size;
|
||||
unsigned sectors = nr_nodes * c->opts.btree_node_size;
|
||||
int ret, disk_res_flags = BCH_DISK_RESERVATION_GC_LOCK_HELD|
|
||||
BCH_DISK_RESERVATION_METADATA;
|
||||
|
||||
@ -1035,7 +1035,7 @@ static void bch2_btree_set_root_inmem(struct btree_update *as, struct btree *b)
|
||||
__bch2_btree_set_root_inmem(c, b);
|
||||
|
||||
bch2_mark_key(c, bkey_i_to_s_c(&b->key),
|
||||
c->sb.btree_node_size, true,
|
||||
c->opts.btree_node_size, true,
|
||||
gc_pos_btree_root(b->btree_id),
|
||||
&stats, 0);
|
||||
|
||||
@ -1120,7 +1120,7 @@ static void bch2_insert_fixup_btree_ptr(struct btree_update *as, struct btree *b
|
||||
|
||||
if (bkey_extent_is_data(&insert->k))
|
||||
bch2_mark_key(c, bkey_i_to_s_c(insert),
|
||||
c->sb.btree_node_size, true,
|
||||
c->opts.btree_node_size, true,
|
||||
gc_pos_btree_node(b), &stats, 0);
|
||||
|
||||
while ((k = bch2_btree_node_iter_peek_all(node_iter, b)) &&
|
||||
@ -1901,7 +1901,7 @@ retry:
|
||||
bch2_btree_node_lock_write(b, &iter);
|
||||
|
||||
bch2_mark_key(c, bkey_i_to_s_c(&new_key->k_i),
|
||||
c->sb.btree_node_size, true,
|
||||
c->opts.btree_node_size, true,
|
||||
gc_pos_btree_root(b->btree_id),
|
||||
&stats, 0);
|
||||
bch2_btree_node_free_index(as, NULL,
|
||||
|
@ -263,7 +263,7 @@ static inline size_t bch_btree_keys_u64s_remaining(struct bch_fs *c,
|
||||
unsigned used = bset_byte_offset(b, vstruct_end(i)) / sizeof(u64) +
|
||||
b->whiteout_u64s +
|
||||
b->uncompacted_whiteout_u64s;
|
||||
unsigned total = c->sb.btree_node_size << 6;
|
||||
unsigned total = c->opts.btree_node_size << 6;
|
||||
|
||||
EBUG_ON(used > total);
|
||||
|
||||
|
@ -469,6 +469,7 @@ static void bch2_mark_pointer(struct bch_fs *c,
|
||||
* checked the gen
|
||||
*/
|
||||
if (gen_after(new.gen, ptr->gen)) {
|
||||
BUG_ON(!test_bit(BCH_FS_ALLOC_READ_DONE, &c->flags));
|
||||
EBUG_ON(!ptr->cached &&
|
||||
test_bit(JOURNAL_REPLAY_DONE, &c->journal.flags));
|
||||
return;
|
||||
|
@ -417,7 +417,7 @@ int bch2_request_key(struct bch_sb *sb, struct bch_key *key)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int bch2_decrypt_sb_key(struct bch_fs *c,
|
||||
int bch2_decrypt_sb_key(struct bch_fs *c,
|
||||
struct bch_sb_field_crypt *crypt,
|
||||
struct bch_key *key)
|
||||
{
|
||||
|
@ -40,6 +40,9 @@ struct bch_csum bch2_checksum_bio(struct bch_fs *, unsigned,
|
||||
void bch2_encrypt_bio(struct bch_fs *, unsigned,
|
||||
struct nonce, struct bio *);
|
||||
|
||||
int bch2_decrypt_sb_key(struct bch_fs *, struct bch_sb_field_crypt *,
|
||||
struct bch_key *);
|
||||
|
||||
int bch2_disable_encryption(struct bch_fs *);
|
||||
int bch2_enable_encryption(struct bch_fs *, bool);
|
||||
|
||||
|
@ -423,7 +423,7 @@ void bch2_bio_compress(struct bch_fs *c,
|
||||
|
||||
/* If it's only one block, don't bother trying to compress: */
|
||||
if (*compression_type != BCH_COMPRESSION_NONE &&
|
||||
bio_sectors(src) > c->sb.block_size &&
|
||||
bio_sectors(src) > c->opts.block_size &&
|
||||
!__bio_compress(c, dst, dst_len, src, src_len, compression_type))
|
||||
goto out;
|
||||
|
||||
|
@ -192,25 +192,23 @@ static void dirent_copy_target(struct bkey_i_dirent *dst,
|
||||
dst->v.d_type = src.v->d_type;
|
||||
}
|
||||
|
||||
static struct bpos bch2_dirent_pos(struct bch_inode_info *ei,
|
||||
static struct bpos bch2_dirent_pos(struct bch_inode_info *inode,
|
||||
const struct qstr *name)
|
||||
{
|
||||
return POS(ei->vfs_inode.i_ino, bch2_dirent_hash(&ei->str_hash, name));
|
||||
return POS(inode->v.i_ino, bch2_dirent_hash(&inode->ei_str_hash, name));
|
||||
}
|
||||
|
||||
int bch2_dirent_rename(struct bch_fs *c,
|
||||
struct inode *src_dir, const struct qstr *src_name,
|
||||
struct inode *dst_dir, const struct qstr *dst_name,
|
||||
struct bch_inode_info *src_dir, const struct qstr *src_name,
|
||||
struct bch_inode_info *dst_dir, const struct qstr *dst_name,
|
||||
u64 *journal_seq, enum bch_rename_mode mode)
|
||||
{
|
||||
struct bch_inode_info *src_ei = to_bch_ei(src_dir);
|
||||
struct bch_inode_info *dst_ei = to_bch_ei(dst_dir);
|
||||
struct btree_iter src_iter, dst_iter, whiteout_iter;
|
||||
struct bkey_s_c old_src, old_dst;
|
||||
struct bkey delete;
|
||||
struct bkey_i_dirent *new_src = NULL, *new_dst = NULL;
|
||||
struct bpos src_pos = bch2_dirent_pos(src_ei, src_name);
|
||||
struct bpos dst_pos = bch2_dirent_pos(dst_ei, dst_name);
|
||||
struct bpos src_pos = bch2_dirent_pos(src_dir, src_name);
|
||||
struct bpos dst_pos = bch2_dirent_pos(dst_dir, dst_name);
|
||||
bool need_whiteout;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
@ -241,13 +239,13 @@ retry:
|
||||
* in bch_hash_set) - we never move existing dirents to different slot:
|
||||
*/
|
||||
old_src = bch2_hash_lookup_at(bch2_dirent_hash_desc,
|
||||
&src_ei->str_hash,
|
||||
&src_dir->ei_str_hash,
|
||||
&src_iter, src_name);
|
||||
if ((ret = btree_iter_err(old_src)))
|
||||
goto err;
|
||||
|
||||
ret = bch2_hash_needs_whiteout(bch2_dirent_hash_desc,
|
||||
&src_ei->str_hash,
|
||||
&src_dir->ei_str_hash,
|
||||
&whiteout_iter, &src_iter);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
@ -261,7 +259,7 @@ retry:
|
||||
old_dst = mode == BCH_RENAME
|
||||
? bch2_hash_hole_at(bch2_dirent_hash_desc, &dst_iter)
|
||||
: bch2_hash_lookup_at(bch2_dirent_hash_desc,
|
||||
&dst_ei->str_hash,
|
||||
&dst_dir->ei_str_hash,
|
||||
&dst_iter, dst_name);
|
||||
if ((ret = btree_iter_err(old_dst)))
|
||||
goto err;
|
||||
@ -395,7 +393,7 @@ int bch2_empty_dir(struct bch_fs *c, u64 dir_inum)
|
||||
int bch2_readdir(struct bch_fs *c, struct file *file,
|
||||
struct dir_context *ctx)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
struct bch_inode_info *inode = file_bch_inode(file);
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
struct bkey_s_c_dirent dirent;
|
||||
@ -404,29 +402,21 @@ int bch2_readdir(struct bch_fs *c, struct file *file,
|
||||
if (!dir_emit_dots(file, ctx))
|
||||
return 0;
|
||||
|
||||
pr_debug("listing for %lu from %llu", inode->i_ino, ctx->pos);
|
||||
|
||||
for_each_btree_key(&iter, c, BTREE_ID_DIRENTS,
|
||||
POS(inode->i_ino, ctx->pos), 0, k) {
|
||||
POS(inode->v.i_ino, ctx->pos), 0, k) {
|
||||
if (k.k->type != BCH_DIRENT)
|
||||
continue;
|
||||
|
||||
dirent = bkey_s_c_to_dirent(k);
|
||||
|
||||
pr_debug("saw %llu:%llu (%s) -> %llu",
|
||||
k.k->p.inode, k.k->p.offset,
|
||||
dirent.v->d_name, dirent.v->d_inum);
|
||||
|
||||
if (bkey_cmp(k.k->p, POS(inode->i_ino, ctx->pos)) < 0)
|
||||
if (bkey_cmp(k.k->p, POS(inode->v.i_ino, ctx->pos)) < 0)
|
||||
continue;
|
||||
|
||||
if (k.k->p.inode > inode->i_ino)
|
||||
if (k.k->p.inode > inode->v.i_ino)
|
||||
break;
|
||||
|
||||
len = bch2_dirent_name_bytes(dirent);
|
||||
|
||||
pr_debug("emitting %s", dirent.v->d_name);
|
||||
|
||||
/*
|
||||
* XXX: dir_emit() can fault and block, while we're holding
|
||||
* locks
|
||||
|
@ -11,6 +11,7 @@ struct file;
|
||||
struct dir_context;
|
||||
struct bch_fs;
|
||||
struct bch_hash_info;
|
||||
struct bch_inode_info;
|
||||
|
||||
unsigned bch2_dirent_name_bytes(struct bkey_s_c_dirent);
|
||||
int bch2_dirent_create(struct bch_fs *c, u64, const struct bch_hash_info *,
|
||||
@ -25,8 +26,8 @@ enum bch_rename_mode {
|
||||
};
|
||||
|
||||
int bch2_dirent_rename(struct bch_fs *,
|
||||
struct inode *, const struct qstr *,
|
||||
struct inode *, const struct qstr *,
|
||||
struct bch_inode_info *, const struct qstr *,
|
||||
struct bch_inode_info *, const struct qstr *,
|
||||
u64 *, enum bch_rename_mode);
|
||||
|
||||
u64 bch2_dirent_lookup(struct bch_fs *, u64, const struct bch_hash_info *,
|
||||
|
@ -575,7 +575,7 @@ static const char *bch2_btree_ptr_invalid(const struct bch_fs *c,
|
||||
|
||||
extent_for_each_ptr_crc(e, ptr, crc) {
|
||||
reason = extent_ptr_invalid(c, e, ptr,
|
||||
c->sb.btree_node_size,
|
||||
c->opts.btree_node_size,
|
||||
true);
|
||||
if (reason)
|
||||
return reason;
|
||||
@ -610,6 +610,9 @@ static void btree_ptr_debugcheck(struct bch_fs *c, struct btree *b,
|
||||
g = PTR_BUCKET(ca, ptr);
|
||||
replicas++;
|
||||
|
||||
if (!test_bit(BCH_FS_ALLOC_READ_DONE, &c->flags))
|
||||
continue;
|
||||
|
||||
err = "stale";
|
||||
if (ptr_stale(ca, ptr))
|
||||
goto err;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -24,7 +24,7 @@ ssize_t bch2_write_iter(struct kiocb *, struct iov_iter *);
|
||||
|
||||
int bch2_fsync(struct file *, loff_t, loff_t, int);
|
||||
|
||||
int bch2_truncate(struct inode *, struct iattr *);
|
||||
int bch2_truncate(struct bch_inode_info *, struct iattr *);
|
||||
long bch2_fallocate_dispatch(struct file *, int, loff_t, loff_t);
|
||||
|
||||
loff_t bch2_llseek(struct file *, loff_t, int);
|
||||
@ -38,11 +38,11 @@ int bch2_migrate_page(struct address_space *, struct page *,
|
||||
struct i_sectors_hook {
|
||||
struct extent_insert_hook hook;
|
||||
s64 sectors;
|
||||
struct bch_inode_info *ei;
|
||||
struct bch_inode_info *inode;
|
||||
};
|
||||
|
||||
struct bchfs_write_op {
|
||||
struct bch_inode_info *ei;
|
||||
struct bch_inode_info *inode;
|
||||
s64 sectors_added;
|
||||
bool is_dio;
|
||||
u64 new_i_size;
|
||||
|
254
libbcachefs/fs-ioctl.c
Normal file
254
libbcachefs/fs-ioctl.c
Normal file
@ -0,0 +1,254 @@
|
||||
#ifndef NO_BCACHEFS_FS
|
||||
|
||||
#include "bcachefs.h"
|
||||
#include "chardev.h"
|
||||
#include "fs.h"
|
||||
#include "fs-ioctl.h"
|
||||
|
||||
#include <linux/compat.h>
|
||||
#include <linux/mount.h>
|
||||
|
||||
#define FS_IOC_GOINGDOWN _IOR('X', 125, __u32)
|
||||
|
||||
/* Inode flags: */
|
||||
|
||||
/* bcachefs inode flags -> vfs inode flags: */
|
||||
static const unsigned bch_flags_to_vfs[] = {
|
||||
[__BCH_INODE_SYNC] = S_SYNC,
|
||||
[__BCH_INODE_IMMUTABLE] = S_IMMUTABLE,
|
||||
[__BCH_INODE_APPEND] = S_APPEND,
|
||||
[__BCH_INODE_NOATIME] = S_NOATIME,
|
||||
};
|
||||
|
||||
/* bcachefs inode flags -> FS_IOC_GETFLAGS: */
|
||||
static const unsigned bch_flags_to_uflags[] = {
|
||||
[__BCH_INODE_SYNC] = FS_SYNC_FL,
|
||||
[__BCH_INODE_IMMUTABLE] = FS_IMMUTABLE_FL,
|
||||
[__BCH_INODE_APPEND] = FS_APPEND_FL,
|
||||
[__BCH_INODE_NODUMP] = FS_NODUMP_FL,
|
||||
[__BCH_INODE_NOATIME] = FS_NOATIME_FL,
|
||||
};
|
||||
|
||||
/* bcachefs inode flags -> FS_IOC_FSGETXATTR: */
|
||||
static const unsigned bch_flags_to_xflags[] = {
|
||||
[__BCH_INODE_SYNC] = FS_XFLAG_SYNC,
|
||||
[__BCH_INODE_IMMUTABLE] = FS_XFLAG_IMMUTABLE,
|
||||
[__BCH_INODE_APPEND] = FS_XFLAG_APPEND,
|
||||
[__BCH_INODE_NODUMP] = FS_XFLAG_NODUMP,
|
||||
[__BCH_INODE_NOATIME] = FS_XFLAG_NOATIME,
|
||||
//[__BCH_INODE_PROJINHERIT] = FS_XFLAG_PROJINHERIT;
|
||||
};
|
||||
|
||||
#define map_flags(_map, _in) \
|
||||
({ \
|
||||
unsigned _i, _out = 0; \
|
||||
\
|
||||
for (_i = 0; _i < ARRAY_SIZE(_map); _i++) \
|
||||
if ((_in) & (1 << _i)) \
|
||||
(_out) |= _map[_i]; \
|
||||
(_out); \
|
||||
})
|
||||
|
||||
#define map_flags_rev(_map, _in) \
|
||||
({ \
|
||||
unsigned _i, _out = 0; \
|
||||
\
|
||||
for (_i = 0; _i < ARRAY_SIZE(_map); _i++) \
|
||||
if ((_in) & _map[_i]) { \
|
||||
(_out) |= 1 << _i; \
|
||||
(_in) &= ~_map[_i]; \
|
||||
} \
|
||||
(_out); \
|
||||
})
|
||||
|
||||
#define set_flags(_map, _in, _out) \
|
||||
do { \
|
||||
unsigned _i; \
|
||||
\
|
||||
for (_i = 0; _i < ARRAY_SIZE(_map); _i++) \
|
||||
if ((_in) & (1 << _i)) \
|
||||
(_out) |= _map[_i]; \
|
||||
else \
|
||||
(_out) &= ~_map[_i]; \
|
||||
} while (0)
|
||||
|
||||
/* Set VFS inode flags from bcachefs inode: */
|
||||
void bch2_inode_flags_to_vfs(struct bch_inode_info *inode)
|
||||
{
|
||||
set_flags(bch_flags_to_vfs, inode->ei_flags, inode->v.i_flags);
|
||||
}
|
||||
|
||||
static int bch2_inode_flags_set(struct bch_inode_info *inode,
|
||||
struct bch_inode_unpacked *bi,
|
||||
void *p)
|
||||
{
|
||||
/*
|
||||
* We're relying on btree locking here for exclusion with other ioctl
|
||||
* calls - use the flags in the btree (@bi), not inode->i_flags:
|
||||
*/
|
||||
unsigned newflags = *((unsigned *) p);
|
||||
unsigned oldflags = bi->bi_flags;
|
||||
|
||||
if (((newflags ^ oldflags) & (BCH_INODE_APPEND|BCH_INODE_IMMUTABLE)) &&
|
||||
!capable(CAP_LINUX_IMMUTABLE))
|
||||
return -EPERM;
|
||||
|
||||
if (!S_ISREG(inode->v.i_mode) &&
|
||||
!S_ISDIR(inode->v.i_mode) &&
|
||||
(newflags & (BCH_INODE_NODUMP|BCH_INODE_NOATIME)) != newflags)
|
||||
return -EINVAL;
|
||||
|
||||
bi->bi_flags = newflags;
|
||||
inode->v.i_ctime = current_fs_time(inode->v.i_sb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bch2_ioc_getflags(struct bch_inode_info *inode, int __user *arg)
|
||||
{
|
||||
unsigned flags = map_flags(bch_flags_to_uflags, inode->ei_flags);
|
||||
|
||||
return put_user(flags, arg);
|
||||
}
|
||||
|
||||
static int bch2_ioc_setflags(struct bch_fs *c,
|
||||
struct file *file,
|
||||
struct bch_inode_info *inode,
|
||||
void __user *arg)
|
||||
{
|
||||
unsigned flags, uflags;
|
||||
int ret;
|
||||
|
||||
if (get_user(uflags, (int __user *) arg))
|
||||
return -EFAULT;
|
||||
|
||||
flags = map_flags_rev(bch_flags_to_uflags, uflags);
|
||||
if (uflags)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = mnt_want_write_file(file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
inode_lock(&inode->v);
|
||||
if (!inode_owner_or_capable(&inode->v)) {
|
||||
ret = -EACCES;
|
||||
goto setflags_out;
|
||||
}
|
||||
|
||||
mutex_lock(&inode->ei_update_lock);
|
||||
ret = __bch2_write_inode(c, inode, bch2_inode_flags_set, &flags);
|
||||
|
||||
if (!ret)
|
||||
bch2_inode_flags_to_vfs(inode);
|
||||
mutex_unlock(&inode->ei_update_lock);
|
||||
|
||||
setflags_out:
|
||||
inode_unlock(&inode->v);
|
||||
mnt_drop_write_file(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bch2_ioc_fsgetxattr(struct bch_inode_info *inode,
|
||||
struct fsxattr __user *arg)
|
||||
{
|
||||
struct fsxattr fa = { 0 };
|
||||
|
||||
fa.fsx_xflags = map_flags(bch_flags_to_xflags, inode->ei_flags);
|
||||
|
||||
return copy_to_user(arg, &fa, sizeof(fa));
|
||||
}
|
||||
|
||||
static int bch2_ioc_fssetxattr(struct bch_fs *c,
|
||||
struct file *file,
|
||||
struct bch_inode_info *inode,
|
||||
struct fsxattr __user *arg)
|
||||
{
|
||||
struct fsxattr fa;
|
||||
unsigned flags;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&fa, arg, sizeof(fa)))
|
||||
return -EFAULT;
|
||||
|
||||
flags = map_flags_rev(bch_flags_to_xflags, fa.fsx_xflags);
|
||||
if (fa.fsx_xflags)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = mnt_want_write_file(file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
inode_lock(&inode->v);
|
||||
if (!inode_owner_or_capable(&inode->v)) {
|
||||
ret = -EACCES;
|
||||
goto err;
|
||||
}
|
||||
|
||||
mutex_lock(&inode->ei_update_lock);
|
||||
ret = __bch2_write_inode(c, inode, bch2_inode_flags_set, &flags);
|
||||
if (!ret)
|
||||
bch2_inode_flags_to_vfs(inode);
|
||||
mutex_unlock(&inode->ei_update_lock);
|
||||
err:
|
||||
inode_unlock(&inode->v);
|
||||
mnt_drop_write_file(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
||||
{
|
||||
struct bch_inode_info *inode = file_bch_inode(file);
|
||||
struct super_block *sb = inode->v.i_sb;
|
||||
struct bch_fs *c = sb->s_fs_info;
|
||||
|
||||
switch (cmd) {
|
||||
case FS_IOC_GETFLAGS:
|
||||
return bch2_ioc_getflags(inode, (int __user *) arg);
|
||||
|
||||
case FS_IOC_SETFLAGS:
|
||||
return bch2_ioc_setflags(c, file, inode, (int __user *) arg);
|
||||
|
||||
case FS_IOC_FSGETXATTR:
|
||||
return bch2_ioc_fsgetxattr(inode, (void __user *) arg);
|
||||
case FS_IOC_FSSETXATTR:
|
||||
return bch2_ioc_fssetxattr(c, file, inode, (void __user *) arg);
|
||||
|
||||
case FS_IOC_GETVERSION:
|
||||
return -ENOTTY;
|
||||
case FS_IOC_SETVERSION:
|
||||
return -ENOTTY;
|
||||
|
||||
case FS_IOC_GOINGDOWN:
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
down_write(&sb->s_umount);
|
||||
sb->s_flags |= MS_RDONLY;
|
||||
bch2_fs_emergency_read_only(c);
|
||||
up_write(&sb->s_umount);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return bch2_fs_ioctl(c, cmd, (void __user *) arg);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
long bch2_compat_fs_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
||||
{
|
||||
/* These are just misnamed, they actually get/put from/to user an int */
|
||||
switch (cmd) {
|
||||
case FS_IOC_GETFLAGS:
|
||||
cmd = FS_IOC_GETFLAGS;
|
||||
break;
|
||||
case FS_IOC32_SETFLAGS:
|
||||
cmd = FS_IOC_SETFLAGS;
|
||||
break;
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
return bch2_fs_file_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NO_BCACHEFS_FS */
|
9
libbcachefs/fs-ioctl.h
Normal file
9
libbcachefs/fs-ioctl.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef _BCACHEFS_FS_IOCTL_H
|
||||
#define _BCACHEFS_FS_IOCTL_H
|
||||
|
||||
void bch2_inode_flags_to_vfs(struct bch_inode_info *);
|
||||
|
||||
long bch2_fs_file_ioctl(struct file *, unsigned, unsigned long);
|
||||
long bch2_compat_fs_ioctl(struct file *, unsigned, unsigned long);
|
||||
|
||||
#endif /* _BCACHEFS_FS_IOCTL_H */
|
836
libbcachefs/fs.c
836
libbcachefs/fs.c
File diff suppressed because it is too large
Load Diff
@ -7,30 +7,35 @@
|
||||
#include <linux/stat.h>
|
||||
|
||||
struct bch_inode_info {
|
||||
struct inode vfs_inode;
|
||||
struct inode v;
|
||||
|
||||
struct mutex update_lock;
|
||||
u64 journal_seq;
|
||||
struct mutex ei_update_lock;
|
||||
u64 ei_journal_seq;
|
||||
|
||||
atomic_long_t i_size_dirty_count;
|
||||
atomic_long_t ei_size_dirty_count;
|
||||
|
||||
/*
|
||||
* these are updated whenever we update the inode in the btree - for
|
||||
* e.g. fsync
|
||||
*/
|
||||
u64 i_size;
|
||||
u32 i_flags;
|
||||
u64 ei_size;
|
||||
u32 ei_flags;
|
||||
|
||||
atomic_long_t i_sectors_dirty_count;
|
||||
atomic64_t i_sectors;
|
||||
atomic_long_t ei_sectors_dirty_count;
|
||||
atomic64_t ei_sectors;
|
||||
|
||||
struct bch_hash_info str_hash;
|
||||
struct bch_hash_info ei_str_hash;
|
||||
|
||||
unsigned long last_dirtied;
|
||||
unsigned long ei_last_dirtied;
|
||||
};
|
||||
|
||||
#define to_bch_ei(_inode) \
|
||||
container_of(_inode, struct bch_inode_info, vfs_inode)
|
||||
container_of_or_null(_inode, struct bch_inode_info, v)
|
||||
|
||||
static inline struct bch_inode_info *file_bch_inode(struct file *file)
|
||||
{
|
||||
return to_bch_ei(file_inode(file));
|
||||
}
|
||||
|
||||
static inline u8 mode_to_type(umode_t mode)
|
||||
{
|
||||
|
@ -67,7 +67,7 @@ static int reattach_inode(struct bch_fs *c,
|
||||
snprintf(name_buf, sizeof(name_buf), "%llu", inum);
|
||||
name = (struct qstr) QSTR(name_buf);
|
||||
|
||||
lostfound_inode->i_nlink++;
|
||||
lostfound_inode->bi_nlink++;
|
||||
|
||||
bch2_inode_pack(&packed, lostfound_inode);
|
||||
|
||||
@ -80,7 +80,7 @@ static int reattach_inode(struct bch_fs *c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bch2_dirent_create(c, lostfound_inode->inum,
|
||||
ret = bch2_dirent_create(c, lostfound_inode->bi_inum,
|
||||
&lostfound_hash_info,
|
||||
DT_DIR, &name, inum, NULL,
|
||||
BTREE_INSERT_NOFAIL);
|
||||
@ -263,9 +263,9 @@ static int check_extents(struct bch_fs *c)
|
||||
"extent type %u for missing inode %llu",
|
||||
k.k->type, k.k->p.inode) ||
|
||||
fsck_err_on(w.have_inode &&
|
||||
!S_ISREG(w.inode.i_mode) && !S_ISLNK(w.inode.i_mode), c,
|
||||
!S_ISREG(w.inode.bi_mode) && !S_ISLNK(w.inode.bi_mode), c,
|
||||
"extent type %u for non regular file, inode %llu mode %o",
|
||||
k.k->type, k.k->p.inode, w.inode.i_mode)) {
|
||||
k.k->type, k.k->p.inode, w.inode.bi_mode)) {
|
||||
ret = bch2_btree_delete_at(&iter, 0);
|
||||
if (ret)
|
||||
goto err;
|
||||
@ -274,18 +274,18 @@ static int check_extents(struct bch_fs *c)
|
||||
|
||||
unfixable_fsck_err_on(w.first_this_inode &&
|
||||
w.have_inode &&
|
||||
!(w.inode.i_flags & BCH_INODE_I_SECTORS_DIRTY) &&
|
||||
w.inode.i_sectors !=
|
||||
!(w.inode.bi_flags & BCH_INODE_I_SECTORS_DIRTY) &&
|
||||
w.inode.bi_sectors !=
|
||||
(i_sectors = bch2_count_inode_sectors(c, w.cur_inum)),
|
||||
c, "i_sectors wrong: got %llu, should be %llu",
|
||||
w.inode.i_sectors, i_sectors);
|
||||
w.inode.bi_sectors, i_sectors);
|
||||
|
||||
unfixable_fsck_err_on(w.have_inode &&
|
||||
!(w.inode.i_flags & BCH_INODE_I_SIZE_DIRTY) &&
|
||||
!(w.inode.bi_flags & BCH_INODE_I_SIZE_DIRTY) &&
|
||||
k.k->type != BCH_RESERVATION &&
|
||||
k.k->p.offset > round_up(w.inode.i_size, PAGE_SIZE) >> 9, c,
|
||||
k.k->p.offset > round_up(w.inode.bi_size, PAGE_SIZE) >> 9, c,
|
||||
"extent type %u offset %llu past end of inode %llu, i_size %llu",
|
||||
k.k->type, k.k->p.offset, k.k->p.inode, w.inode.i_size);
|
||||
k.k->type, k.k->p.offset, k.k->p.inode, w.inode.bi_size);
|
||||
}
|
||||
err:
|
||||
fsck_err:
|
||||
@ -324,9 +324,9 @@ static int check_dirents(struct bch_fs *c)
|
||||
"dirent in nonexisting directory:\n%s",
|
||||
bch2_bkey_val_to_text(c, BTREE_ID_DIRENTS,
|
||||
buf, sizeof(buf), k)) ||
|
||||
fsck_err_on(!S_ISDIR(w.inode.i_mode), c,
|
||||
fsck_err_on(!S_ISDIR(w.inode.bi_mode), c,
|
||||
"dirent in non directory inode type %u:\n%s",
|
||||
mode_to_type(w.inode.i_mode),
|
||||
mode_to_type(w.inode.bi_mode),
|
||||
bch2_bkey_val_to_text(c, BTREE_ID_DIRENTS,
|
||||
buf, sizeof(buf), k))) {
|
||||
ret = bch2_btree_delete_at(&iter, 0);
|
||||
@ -397,9 +397,9 @@ static int check_dirents(struct bch_fs *c)
|
||||
|
||||
if (fsck_err_on(have_target &&
|
||||
d.v->d_type !=
|
||||
mode_to_type(le16_to_cpu(target.i_mode)), c,
|
||||
mode_to_type(le16_to_cpu(target.bi_mode)), c,
|
||||
"incorrect d_type: should be %u:\n%s",
|
||||
mode_to_type(le16_to_cpu(target.i_mode)),
|
||||
mode_to_type(le16_to_cpu(target.bi_mode)),
|
||||
bch2_bkey_val_to_text(c, BTREE_ID_DIRENTS,
|
||||
buf, sizeof(buf), k))) {
|
||||
struct bkey_i_dirent *n;
|
||||
@ -411,7 +411,7 @@ static int check_dirents(struct bch_fs *c)
|
||||
}
|
||||
|
||||
bkey_reassemble(&n->k_i, d.s_c);
|
||||
n->v.d_type = mode_to_type(le16_to_cpu(target.i_mode));
|
||||
n->v.d_type = mode_to_type(le16_to_cpu(target.bi_mode));
|
||||
|
||||
ret = bch2_btree_insert_at(c, NULL, NULL, NULL,
|
||||
BTREE_INSERT_NOFAIL,
|
||||
@ -485,7 +485,7 @@ static int check_root(struct bch_fs *c, struct bch_inode_unpacked *root_inode)
|
||||
if (fsck_err_on(ret, c, "root directory missing"))
|
||||
goto create_root;
|
||||
|
||||
if (fsck_err_on(!S_ISDIR(root_inode->i_mode), c,
|
||||
if (fsck_err_on(!S_ISDIR(root_inode->bi_mode), c,
|
||||
"root inode not a directory"))
|
||||
goto create_root;
|
||||
|
||||
@ -494,7 +494,7 @@ fsck_err:
|
||||
return ret;
|
||||
create_root:
|
||||
bch2_inode_init(c, root_inode, 0, 0, S_IFDIR|S_IRWXU|S_IRUGO|S_IXUGO, 0);
|
||||
root_inode->inum = BCACHEFS_ROOT_INO;
|
||||
root_inode->bi_inum = BCACHEFS_ROOT_INO;
|
||||
|
||||
bch2_inode_pack(&packed, root_inode);
|
||||
|
||||
@ -528,7 +528,7 @@ static int check_lostfound(struct bch_fs *c,
|
||||
if (fsck_err_on(ret, c, "lost+found missing"))
|
||||
goto create_lostfound;
|
||||
|
||||
if (fsck_err_on(!S_ISDIR(lostfound_inode->i_mode), c,
|
||||
if (fsck_err_on(!S_ISDIR(lostfound_inode->bi_mode), c,
|
||||
"lost+found inode not a directory"))
|
||||
goto create_lostfound;
|
||||
|
||||
@ -536,7 +536,7 @@ static int check_lostfound(struct bch_fs *c,
|
||||
fsck_err:
|
||||
return ret;
|
||||
create_lostfound:
|
||||
root_inode->i_nlink++;
|
||||
root_inode->bi_nlink++;
|
||||
|
||||
bch2_inode_pack(&packed, root_inode);
|
||||
|
||||
@ -553,7 +553,7 @@ create_lostfound:
|
||||
return ret;
|
||||
|
||||
ret = bch2_dirent_create(c, BCACHEFS_ROOT_INO, &root_hash_info, DT_DIR,
|
||||
&lostfound, lostfound_inode->inum, NULL,
|
||||
&lostfound, lostfound_inode->bi_inum, NULL,
|
||||
BTREE_INSERT_NOFAIL);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -711,7 +711,7 @@ up:
|
||||
|
||||
for_each_btree_key(&iter, c, BTREE_ID_INODES, POS_MIN, 0, k) {
|
||||
if (k.k->type != BCH_INODE_FS ||
|
||||
!S_ISDIR(le16_to_cpu(bkey_s_c_to_inode(k).v->i_mode)))
|
||||
!S_ISDIR(le16_to_cpu(bkey_s_c_to_inode(k).v->bi_mode)))
|
||||
continue;
|
||||
|
||||
if (fsck_err_on(!inode_bitmap_test(&dirs_done, k.k->p.inode), c,
|
||||
@ -849,15 +849,15 @@ static int bch2_gc_do_inode(struct bch_fs *c,
|
||||
inode.k->p.inode))
|
||||
return ret;
|
||||
|
||||
i_nlink = u.i_nlink + nlink_bias(u.i_mode);
|
||||
i_nlink = u.bi_nlink + nlink_bias(u.bi_mode);
|
||||
|
||||
fsck_err_on(i_nlink < link.count, c,
|
||||
"inode %llu i_link too small (%u < %u, type %i)",
|
||||
inode.k->p.inode, i_nlink,
|
||||
link.count, mode_to_type(u.i_mode));
|
||||
link.count, mode_to_type(u.bi_mode));
|
||||
|
||||
/* These should have been caught/fixed by earlier passes: */
|
||||
if (S_ISDIR(u.i_mode)) {
|
||||
if (S_ISDIR(u.bi_mode)) {
|
||||
need_fsck_err_on(link.count > 1, c,
|
||||
"directory %llu with multiple hardlinks: %u",
|
||||
inode.k->p.inode, link.count);
|
||||
@ -877,7 +877,7 @@ static int bch2_gc_do_inode(struct bch_fs *c,
|
||||
"but found orphaned inode %llu",
|
||||
inode.k->p.inode);
|
||||
|
||||
if (fsck_err_on(S_ISDIR(u.i_mode) &&
|
||||
if (fsck_err_on(S_ISDIR(u.bi_mode) &&
|
||||
bch2_empty_dir(c, inode.k->p.inode), c,
|
||||
"non empty directory with link count 0, "
|
||||
"inode nlink %u, dir links found %u",
|
||||
@ -897,7 +897,7 @@ static int bch2_gc_do_inode(struct bch_fs *c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (u.i_flags & BCH_INODE_I_SIZE_DIRTY) {
|
||||
if (u.bi_flags & BCH_INODE_I_SIZE_DIRTY) {
|
||||
fsck_err_on(c->sb.clean, c,
|
||||
"filesystem marked clean, "
|
||||
"but inode %llu has i_size dirty",
|
||||
@ -911,7 +911,7 @@ static int bch2_gc_do_inode(struct bch_fs *c,
|
||||
*/
|
||||
|
||||
ret = bch2_inode_truncate(c, inode.k->p.inode,
|
||||
round_up(u.i_size, PAGE_SIZE) >> 9,
|
||||
round_up(u.bi_size, PAGE_SIZE) >> 9,
|
||||
NULL, NULL);
|
||||
if (ret) {
|
||||
bch_err(c, "error in fs gc: error %i "
|
||||
@ -923,13 +923,13 @@ static int bch2_gc_do_inode(struct bch_fs *c,
|
||||
* We truncated without our normal sector accounting hook, just
|
||||
* make sure we recalculate it:
|
||||
*/
|
||||
u.i_flags |= BCH_INODE_I_SECTORS_DIRTY;
|
||||
u.bi_flags |= BCH_INODE_I_SECTORS_DIRTY;
|
||||
|
||||
u.i_flags &= ~BCH_INODE_I_SIZE_DIRTY;
|
||||
u.bi_flags &= ~BCH_INODE_I_SIZE_DIRTY;
|
||||
do_update = true;
|
||||
}
|
||||
|
||||
if (u.i_flags & BCH_INODE_I_SECTORS_DIRTY) {
|
||||
if (u.bi_flags & BCH_INODE_I_SECTORS_DIRTY) {
|
||||
s64 sectors;
|
||||
|
||||
fsck_err_on(c->sb.clean, c,
|
||||
@ -948,8 +948,8 @@ static int bch2_gc_do_inode(struct bch_fs *c,
|
||||
return sectors;
|
||||
}
|
||||
|
||||
u.i_sectors = sectors;
|
||||
u.i_flags &= ~BCH_INODE_I_SECTORS_DIRTY;
|
||||
u.bi_sectors = sectors;
|
||||
u.bi_flags &= ~BCH_INODE_I_SECTORS_DIRTY;
|
||||
do_update = true;
|
||||
}
|
||||
|
||||
@ -958,12 +958,12 @@ static int bch2_gc_do_inode(struct bch_fs *c,
|
||||
"filesystem marked clean, "
|
||||
"but inode %llu has wrong i_nlink "
|
||||
"(type %u i_nlink %u, should be %u)",
|
||||
inode.k->p.inode, mode_to_type(u.i_mode),
|
||||
inode.k->p.inode, mode_to_type(u.bi_mode),
|
||||
i_nlink, real_i_nlink);
|
||||
|
||||
bch_verbose(c, "setting inode %llu nlinks from %u to %u",
|
||||
inode.k->p.inode, i_nlink, real_i_nlink);
|
||||
u.i_nlink = real_i_nlink - nlink_bias(u.i_mode);;
|
||||
u.bi_nlink = real_i_nlink - nlink_bias(u.bi_mode);
|
||||
do_update = true;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "bcachefs.h"
|
||||
#include "bkey_methods.h"
|
||||
#include "btree_update.h"
|
||||
#include "error.h"
|
||||
#include "extents.h"
|
||||
#include "inode.h"
|
||||
#include "io.h"
|
||||
@ -91,10 +92,10 @@ void bch2_inode_pack(struct bkey_inode_buf *packed,
|
||||
unsigned nr_fields = 0, last_nonzero_fieldnr = 0;
|
||||
|
||||
bkey_inode_init(&packed->inode.k_i);
|
||||
packed->inode.k.p.inode = inode->inum;
|
||||
packed->inode.v.i_hash_seed = inode->i_hash_seed;
|
||||
packed->inode.v.i_flags = cpu_to_le32(inode->i_flags);
|
||||
packed->inode.v.i_mode = cpu_to_le16(inode->i_mode);
|
||||
packed->inode.k.p.inode = inode->bi_inum;
|
||||
packed->inode.v.bi_hash_seed = inode->bi_hash_seed;
|
||||
packed->inode.v.bi_flags = cpu_to_le32(inode->bi_flags);
|
||||
packed->inode.v.bi_mode = cpu_to_le16(inode->bi_mode);
|
||||
|
||||
#define BCH_INODE_FIELD(_name, _bits) \
|
||||
out += inode_encode_field(out, end, 0, inode->_name); \
|
||||
@ -124,9 +125,9 @@ void bch2_inode_pack(struct bkey_inode_buf *packed,
|
||||
int ret = bch2_inode_unpack(inode_i_to_s_c(&packed->inode),
|
||||
&unpacked);
|
||||
BUG_ON(ret);
|
||||
BUG_ON(unpacked.inum != inode->inum);
|
||||
BUG_ON(unpacked.i_hash_seed != inode->i_hash_seed);
|
||||
BUG_ON(unpacked.i_mode != inode->i_mode);
|
||||
BUG_ON(unpacked.bi_inum != inode->bi_inum);
|
||||
BUG_ON(unpacked.bi_hash_seed != inode->bi_hash_seed);
|
||||
BUG_ON(unpacked.bi_mode != inode->bi_mode);
|
||||
|
||||
#define BCH_INODE_FIELD(_name, _bits) BUG_ON(unpacked._name != inode->_name);
|
||||
BCH_INODE_FIELDS()
|
||||
@ -143,10 +144,10 @@ int bch2_inode_unpack(struct bkey_s_c_inode inode,
|
||||
unsigned fieldnr = 0, field_bits;
|
||||
int ret;
|
||||
|
||||
unpacked->inum = inode.k->p.inode;
|
||||
unpacked->i_hash_seed = inode.v->i_hash_seed;
|
||||
unpacked->i_flags = le32_to_cpu(inode.v->i_flags);
|
||||
unpacked->i_mode = le16_to_cpu(inode.v->i_mode);
|
||||
unpacked->bi_inum = inode.k->p.inode;
|
||||
unpacked->bi_hash_seed = inode.v->bi_hash_seed;
|
||||
unpacked->bi_flags = le32_to_cpu(inode.v->bi_flags);
|
||||
unpacked->bi_mode = le16_to_cpu(inode.v->bi_mode);
|
||||
|
||||
#define BCH_INODE_FIELD(_name, _bits) \
|
||||
if (fieldnr++ == INODE_NR_FIELDS(inode.v)) { \
|
||||
@ -231,7 +232,7 @@ static void bch2_inode_to_text(struct bch_fs *c, char *buf,
|
||||
break;
|
||||
}
|
||||
|
||||
scnprintf(buf, size, "i_size %llu", unpacked.i_size);
|
||||
scnprintf(buf, size, "i_size %llu", unpacked.bi_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -249,17 +250,17 @@ void bch2_inode_init(struct bch_fs *c, struct bch_inode_unpacked *inode_u,
|
||||
memset(inode_u, 0, sizeof(*inode_u));
|
||||
|
||||
/* ick */
|
||||
inode_u->i_flags |= c->sb.str_hash_type << INODE_STR_HASH_OFFSET;
|
||||
get_random_bytes(&inode_u->i_hash_seed, sizeof(inode_u->i_hash_seed));
|
||||
inode_u->bi_flags |= c->opts.str_hash << INODE_STR_HASH_OFFSET;
|
||||
get_random_bytes(&inode_u->bi_hash_seed, sizeof(inode_u->bi_hash_seed));
|
||||
|
||||
inode_u->i_mode = mode;
|
||||
inode_u->i_uid = uid;
|
||||
inode_u->i_gid = gid;
|
||||
inode_u->i_dev = rdev;
|
||||
inode_u->i_atime = now;
|
||||
inode_u->i_mtime = now;
|
||||
inode_u->i_ctime = now;
|
||||
inode_u->i_otime = now;
|
||||
inode_u->bi_mode = mode;
|
||||
inode_u->bi_uid = uid;
|
||||
inode_u->bi_gid = gid;
|
||||
inode_u->bi_dev = rdev;
|
||||
inode_u->bi_atime = now;
|
||||
inode_u->bi_mtime = now;
|
||||
inode_u->bi_ctime = now;
|
||||
inode_u->bi_otime = now;
|
||||
}
|
||||
|
||||
int bch2_inode_create(struct bch_fs *c, struct bch_inode_unpacked *inode_u,
|
||||
@ -287,7 +288,7 @@ again:
|
||||
|
||||
while (1) {
|
||||
struct bkey_s_c k = bch2_btree_iter_peek_with_holes(&iter);
|
||||
u32 i_generation = 0;
|
||||
u32 bi_generation = 0;
|
||||
|
||||
ret = btree_iter_err(k);
|
||||
if (ret) {
|
||||
@ -308,11 +309,11 @@ again:
|
||||
case BCH_INODE_GENERATION: {
|
||||
struct bkey_s_c_inode_generation g =
|
||||
bkey_s_c_to_inode_generation(k);
|
||||
i_generation = le32_to_cpu(g.v->i_generation);
|
||||
bi_generation = le32_to_cpu(g.v->bi_generation);
|
||||
/* fallthrough: */
|
||||
}
|
||||
default:
|
||||
inode_u->i_generation = i_generation;
|
||||
inode_u->bi_generation = bi_generation;
|
||||
|
||||
bch2_inode_pack(&inode_p, inode_u);
|
||||
inode_p.inode.k.p = k.k->p;
|
||||
@ -326,7 +327,7 @@ again:
|
||||
bch2_btree_iter_unlock(&iter);
|
||||
|
||||
if (!ret) {
|
||||
inode_u->inum =
|
||||
inode_u->bi_inum =
|
||||
inode_p.inode.k.p.inode;
|
||||
*hint = inode_p.inode.k.p.inode + 1;
|
||||
}
|
||||
@ -384,7 +385,7 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr)
|
||||
* but there could be whiteouts (from hash collisions) that we should
|
||||
* delete:
|
||||
*
|
||||
* XXX: the dirent could ideally would delete whitouts when they're no
|
||||
* XXX: the dirent could ideally would delete whiteouts when they're no
|
||||
* longer needed
|
||||
*/
|
||||
ret = bch2_btree_delete_range(c, BTREE_ID_DIRENTS,
|
||||
@ -398,7 +399,7 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr)
|
||||
BTREE_ITER_INTENT);
|
||||
do {
|
||||
struct bkey_s_c k = bch2_btree_iter_peek_with_holes(&iter);
|
||||
u32 i_generation = 0;
|
||||
u32 bi_generation = 0;
|
||||
|
||||
ret = btree_iter_err(k);
|
||||
if (ret) {
|
||||
@ -406,29 +407,33 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
bch2_fs_inconsistent_on(k.k->type != BCH_INODE_FS, c,
|
||||
"inode %llu not found when deleting",
|
||||
inode_nr);
|
||||
|
||||
switch (k.k->type) {
|
||||
case BCH_INODE_FS: {
|
||||
struct bch_inode_unpacked inode_u;
|
||||
|
||||
if (!bch2_inode_unpack(bkey_s_c_to_inode(k), &inode_u))
|
||||
i_generation = cpu_to_le32(inode_u.i_generation) + 1;
|
||||
bi_generation = cpu_to_le32(inode_u.bi_generation) + 1;
|
||||
break;
|
||||
}
|
||||
case BCH_INODE_GENERATION: {
|
||||
struct bkey_s_c_inode_generation g =
|
||||
bkey_s_c_to_inode_generation(k);
|
||||
i_generation = le32_to_cpu(g.v->i_generation);
|
||||
bi_generation = le32_to_cpu(g.v->bi_generation);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!i_generation) {
|
||||
if (!bi_generation) {
|
||||
bkey_init(&delete.k);
|
||||
delete.k.p.inode = inode_nr;
|
||||
} else {
|
||||
bkey_inode_generation_init(&delete.k_i);
|
||||
delete.k.p.inode = inode_nr;
|
||||
delete.v.i_generation = cpu_to_le32(i_generation);
|
||||
delete.v.bi_generation = cpu_to_le32(bi_generation);
|
||||
}
|
||||
|
||||
ret = bch2_btree_insert_at(c, NULL, NULL, NULL,
|
||||
@ -504,17 +509,17 @@ void bch2_inode_pack_test(void)
|
||||
{
|
||||
struct bch_inode_unpacked *u, test_inodes[] = {
|
||||
{
|
||||
.i_atime = U64_MAX,
|
||||
.i_ctime = U64_MAX,
|
||||
.i_mtime = U64_MAX,
|
||||
.i_otime = U64_MAX,
|
||||
.i_size = U64_MAX,
|
||||
.i_sectors = U64_MAX,
|
||||
.i_uid = U32_MAX,
|
||||
.i_gid = U32_MAX,
|
||||
.i_nlink = U32_MAX,
|
||||
.i_generation = U32_MAX,
|
||||
.i_dev = U32_MAX,
|
||||
.bi_atime = U64_MAX,
|
||||
.bi_ctime = U64_MAX,
|
||||
.bi_mtime = U64_MAX,
|
||||
.bi_otime = U64_MAX,
|
||||
.bi_size = U64_MAX,
|
||||
.bi_sectors = U64_MAX,
|
||||
.bi_uid = U32_MAX,
|
||||
.bi_gid = U32_MAX,
|
||||
.bi_nlink = U32_MAX,
|
||||
.bi_generation = U32_MAX,
|
||||
.bi_dev = U32_MAX,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -6,10 +6,10 @@
|
||||
extern const struct bkey_ops bch2_bkey_inode_ops;
|
||||
|
||||
struct bch_inode_unpacked {
|
||||
u64 inum;
|
||||
__le64 i_hash_seed;
|
||||
u32 i_flags;
|
||||
u16 i_mode;
|
||||
u64 bi_inum;
|
||||
__le64 bi_hash_seed;
|
||||
u32 bi_flags;
|
||||
u16 bi_mode;
|
||||
|
||||
#define BCH_INODE_FIELD(_name, _bits) u##_bits _name;
|
||||
BCH_INODE_FIELDS()
|
||||
@ -22,7 +22,7 @@ struct bkey_inode_buf {
|
||||
#define BCH_INODE_FIELD(_name, _bits) + 8 + _bits / 8
|
||||
u8 _pad[0 + BCH_INODE_FIELDS()];
|
||||
#undef BCH_INODE_FIELD
|
||||
};
|
||||
} __attribute__((packed, aligned(8)));
|
||||
|
||||
void bch2_inode_pack(struct bkey_inode_buf *, const struct bch_inode_unpacked *);
|
||||
int bch2_inode_unpack(struct bkey_s_c_inode, struct bch_inode_unpacked *);
|
||||
|
@ -700,11 +700,11 @@ reread: sectors_read = min_t(unsigned,
|
||||
case JOURNAL_ENTRY_NONE:
|
||||
if (!saw_bad)
|
||||
return 0;
|
||||
sectors = c->sb.block_size;
|
||||
sectors = c->opts.block_size;
|
||||
goto next_block;
|
||||
case JOURNAL_ENTRY_BAD:
|
||||
saw_bad = true;
|
||||
sectors = c->sb.block_size;
|
||||
sectors = c->opts.block_size;
|
||||
goto next_block;
|
||||
default:
|
||||
return ret;
|
||||
@ -1192,7 +1192,7 @@ static enum {
|
||||
j->prev_buf_sectors =
|
||||
vstruct_blocks_plus(buf->data, c->block_bits,
|
||||
journal_entry_u64s_reserve(buf)) *
|
||||
c->sb.block_size;
|
||||
c->opts.block_size;
|
||||
|
||||
BUG_ON(j->prev_buf_sectors > j->cur_buf_sectors);
|
||||
|
||||
|
@ -66,42 +66,24 @@ const char * const bch2_dev_state[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct bch_option bch2_opt_table[] = {
|
||||
#define OPT_BOOL() .type = BCH_OPT_BOOL
|
||||
#define OPT_UINT(_min, _max) .type = BCH_OPT_UINT, .min = _min, .max = _max
|
||||
#define OPT_STR(_choices) .type = BCH_OPT_STR, .choices = _choices
|
||||
|
||||
#define BCH_OPT(_name, _mode, _sb_opt, _bits, _type) \
|
||||
[Opt_##_name] = { \
|
||||
.name = #_name, \
|
||||
.set_sb = SET_##_sb_opt, \
|
||||
_type \
|
||||
},
|
||||
BCH_VISIBLE_OPTS()
|
||||
#undef BCH_OPT
|
||||
};
|
||||
|
||||
static int bch2_opt_lookup(const char *name)
|
||||
void bch2_opts_apply(struct bch_opts *dst, struct bch_opts src)
|
||||
{
|
||||
const struct bch_option *i;
|
||||
#define BCH_OPT(_name, ...) \
|
||||
if (opt_defined(src, _name)) \
|
||||
opt_set(*dst, _name, src._name);
|
||||
|
||||
for (i = bch2_opt_table;
|
||||
i < bch2_opt_table + ARRAY_SIZE(bch2_opt_table);
|
||||
i++)
|
||||
if (!strcmp(name, i->name))
|
||||
return i - bch2_opt_table;
|
||||
|
||||
return -1;
|
||||
BCH_OPTS()
|
||||
#undef BCH_OPT
|
||||
}
|
||||
|
||||
static u64 bch2_opt_get(struct bch_opts *opts, enum bch_opt_id id)
|
||||
u64 bch2_opt_get_by_id(const struct bch_opts *opts, enum bch_opt_id id)
|
||||
{
|
||||
switch (id) {
|
||||
#define BCH_OPT(_name, ...) \
|
||||
case Opt_##_name: \
|
||||
return opts->_name; \
|
||||
|
||||
BCH_VISIBLE_OPTS()
|
||||
BCH_OPTS()
|
||||
#undef BCH_OPT
|
||||
|
||||
default:
|
||||
@ -109,15 +91,15 @@ static u64 bch2_opt_get(struct bch_opts *opts, enum bch_opt_id id)
|
||||
}
|
||||
}
|
||||
|
||||
void bch2_opt_set(struct bch_opts *opts, enum bch_opt_id id, u64 v)
|
||||
void bch2_opt_set_by_id(struct bch_opts *opts, enum bch_opt_id id, u64 v)
|
||||
{
|
||||
switch (id) {
|
||||
#define BCH_OPT(_name, ...) \
|
||||
case Opt_##_name: \
|
||||
opts->_name = v; \
|
||||
opt_set(*opts, _name, v); \
|
||||
break;
|
||||
|
||||
BCH_VISIBLE_OPTS()
|
||||
BCH_OPTS()
|
||||
#undef BCH_OPT
|
||||
|
||||
default:
|
||||
@ -129,13 +111,13 @@ void bch2_opt_set(struct bch_opts *opts, enum bch_opt_id id, u64 v)
|
||||
* Initial options from superblock - here we don't want any options undefined,
|
||||
* any options the superblock doesn't specify are set to 0:
|
||||
*/
|
||||
struct bch_opts bch2_sb_opts(struct bch_sb *sb)
|
||||
struct bch_opts bch2_opts_from_sb(struct bch_sb *sb)
|
||||
{
|
||||
struct bch_opts opts = bch2_opts_empty();
|
||||
|
||||
#define BCH_OPT(_name, _mode, _sb_opt, ...) \
|
||||
#define BCH_OPT(_name, _bits, _mode, _type, _sb_opt, _default) \
|
||||
if (_sb_opt != NO_SB_OPT) \
|
||||
opts._name = _sb_opt(sb);
|
||||
opt_set(opts, _name, _sb_opt(sb));
|
||||
|
||||
BCH_OPTS()
|
||||
#undef BCH_OPT
|
||||
@ -143,9 +125,41 @@ struct bch_opts bch2_sb_opts(struct bch_sb *sb)
|
||||
return opts;
|
||||
}
|
||||
|
||||
static int parse_one_opt(enum bch_opt_id id, const char *val, u64 *res)
|
||||
const struct bch_option bch2_opt_table[] = {
|
||||
#define OPT_BOOL() .type = BCH_OPT_BOOL
|
||||
#define OPT_UINT(_min, _max) .type = BCH_OPT_UINT, .min = _min, .max = _max
|
||||
#define OPT_STR(_choices) .type = BCH_OPT_STR, .choices = _choices
|
||||
|
||||
#define BCH_OPT(_name, _bits, _mode, _type, _sb_opt, _default) \
|
||||
[Opt_##_name] = { \
|
||||
.attr = { \
|
||||
.name = #_name, \
|
||||
.mode = _mode == OPT_RUNTIME ? 0644 : 0444, \
|
||||
}, \
|
||||
.mode = _mode, \
|
||||
.set_sb = SET_##_sb_opt, \
|
||||
_type \
|
||||
},
|
||||
|
||||
BCH_OPTS()
|
||||
#undef BCH_OPT
|
||||
};
|
||||
|
||||
static int bch2_opt_lookup(const char *name)
|
||||
{
|
||||
const struct bch_option *i;
|
||||
|
||||
for (i = bch2_opt_table;
|
||||
i < bch2_opt_table + ARRAY_SIZE(bch2_opt_table);
|
||||
i++)
|
||||
if (!strcmp(name, i->attr.name))
|
||||
return i - bch2_opt_table;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bch2_opt_parse(const struct bch_option *opt, const char *val, u64 *res)
|
||||
{
|
||||
const struct bch_option *opt = &bch2_opt_table[id];
|
||||
ssize_t ret;
|
||||
|
||||
switch (opt->type) {
|
||||
@ -190,11 +204,11 @@ int bch2_parse_mount_opts(struct bch_opts *opts, char *options)
|
||||
if (val) {
|
||||
id = bch2_opt_lookup(name);
|
||||
if (id < 0)
|
||||
continue;
|
||||
goto bad_opt;
|
||||
|
||||
ret = parse_one_opt(id, val, &v);
|
||||
ret = bch2_opt_parse(&bch2_opt_table[id], val, &v);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto bad_val;
|
||||
} else {
|
||||
id = bch2_opt_lookup(name);
|
||||
v = 1;
|
||||
@ -205,47 +219,31 @@ int bch2_parse_mount_opts(struct bch_opts *opts, char *options)
|
||||
v = 0;
|
||||
}
|
||||
|
||||
if (id < 0 ||
|
||||
bch2_opt_table[id].type != BCH_OPT_BOOL)
|
||||
continue;
|
||||
if (id < 0)
|
||||
goto bad_opt;
|
||||
|
||||
if (bch2_opt_table[id].type != BCH_OPT_BOOL)
|
||||
goto no_val;
|
||||
}
|
||||
|
||||
bch2_opt_set(opts, id, v);
|
||||
if (bch2_opt_table[id].mode < OPT_MOUNT)
|
||||
goto bad_opt;
|
||||
|
||||
if (id == Opt_acl &&
|
||||
!IS_ENABLED(CONFIG_BCACHEFS_POSIX_ACL))
|
||||
goto bad_opt;
|
||||
|
||||
bch2_opt_set_by_id(opts, id, v);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum bch_opt_id bch2_parse_sysfs_opt(const char *name, const char *val,
|
||||
u64 *res)
|
||||
{
|
||||
int id = bch2_opt_lookup(name);
|
||||
int ret;
|
||||
|
||||
if (id < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = parse_one_opt(id, val, res);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
ssize_t bch2_opt_show(struct bch_opts *opts, const char *name,
|
||||
char *buf, size_t size)
|
||||
{
|
||||
int id = bch2_opt_lookup(name);
|
||||
const struct bch_option *opt;
|
||||
u64 v;
|
||||
|
||||
if (id < 0)
|
||||
return -EINVAL;
|
||||
|
||||
v = bch2_opt_get(opts, id);
|
||||
opt = &bch2_opt_table[id];
|
||||
|
||||
return opt->type == BCH_OPT_STR
|
||||
? bch2_scnprint_string_list(buf, size, opt->choices, v)
|
||||
: scnprintf(buf, size, "%lli", v);
|
||||
bad_opt:
|
||||
pr_err("Bad mount option %s", name);
|
||||
return -1;
|
||||
bad_val:
|
||||
pr_err("Invalid value %s for mount option %s", val, name);
|
||||
return -1;
|
||||
no_val:
|
||||
pr_err("Mount option %s requires a value", name);
|
||||
return -1;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <linux/bug.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include "bcachefs_format.h"
|
||||
|
||||
extern const char * const bch2_error_actions[];
|
||||
@ -30,18 +31,12 @@ extern const char * const bch2_dev_state[];
|
||||
/* dummy option, for options that aren't stored in the superblock */
|
||||
LE64_BITMASK(NO_SB_OPT, struct bch_sb, flags[0], 0, 0);
|
||||
|
||||
/**
|
||||
* BCH_OPT(name, mode, sb_opt, type, ...)
|
||||
*
|
||||
* @name - name of mount option, sysfs attribute, and struct bch_opts
|
||||
* member
|
||||
*
|
||||
* @mode - sysfs attr permissions
|
||||
*
|
||||
* @sb_option - name of corresponding superblock option
|
||||
*
|
||||
* @type - one of OPT_BOOL, OPT_UINT, OPT_STR
|
||||
*/
|
||||
enum opt_mode {
|
||||
OPT_INTERNAL,
|
||||
OPT_FORMAT,
|
||||
OPT_MOUNT,
|
||||
OPT_RUNTIME,
|
||||
};
|
||||
|
||||
enum opt_type {
|
||||
BCH_OPT_BOOL,
|
||||
@ -49,82 +44,162 @@ enum opt_type {
|
||||
BCH_OPT_STR,
|
||||
};
|
||||
|
||||
#define BCH_VISIBLE_OPTS() \
|
||||
BCH_OPT(errors, 0644, BCH_SB_ERROR_ACTION, \
|
||||
s8, OPT_STR(bch2_error_actions)) \
|
||||
BCH_OPT(metadata_replicas, 0444, BCH_SB_META_REPLICAS_WANT,\
|
||||
s8, OPT_UINT(1, BCH_REPLICAS_MAX)) \
|
||||
BCH_OPT(data_replicas, 0444, BCH_SB_DATA_REPLICAS_WANT,\
|
||||
s8, OPT_UINT(1, BCH_REPLICAS_MAX)) \
|
||||
BCH_OPT(metadata_replicas_required, 0444, BCH_SB_META_REPLICAS_REQ,\
|
||||
s8, OPT_UINT(1, BCH_REPLICAS_MAX)) \
|
||||
BCH_OPT(data_replicas_required, 0444, BCH_SB_DATA_REPLICAS_REQ,\
|
||||
s8, OPT_UINT(1, BCH_REPLICAS_MAX)) \
|
||||
BCH_OPT(degraded, 0444, NO_SB_OPT, \
|
||||
s8, OPT_BOOL()) \
|
||||
BCH_OPT(metadata_checksum, 0644, BCH_SB_META_CSUM_TYPE, \
|
||||
s8, OPT_STR(bch2_csum_types)) \
|
||||
BCH_OPT(data_checksum, 0644, BCH_SB_DATA_CSUM_TYPE, \
|
||||
s8, OPT_STR(bch2_csum_types)) \
|
||||
BCH_OPT(compression, 0644, BCH_SB_COMPRESSION_TYPE,\
|
||||
s8, OPT_STR(bch2_compression_types)) \
|
||||
BCH_OPT(str_hash, 0644, BCH_SB_STR_HASH_TYPE, \
|
||||
s8, OPT_STR(bch2_str_hash_types)) \
|
||||
BCH_OPT(inodes_32bit, 0644, BCH_SB_INODE_32BIT, \
|
||||
s8, OPT_BOOL()) \
|
||||
BCH_OPT(gc_reserve_percent, 0444, BCH_SB_GC_RESERVE, \
|
||||
s8, OPT_UINT(5, 21)) \
|
||||
BCH_OPT(root_reserve_percent, 0444, BCH_SB_ROOT_RESERVE, \
|
||||
s8, OPT_UINT(0, 100)) \
|
||||
BCH_OPT(wide_macs, 0644, BCH_SB_128_BIT_MACS, \
|
||||
s8, OPT_BOOL()) \
|
||||
BCH_OPT(verbose_recovery, 0444, NO_SB_OPT, \
|
||||
s8, OPT_BOOL()) \
|
||||
BCH_OPT(posix_acl, 0444, NO_SB_OPT, \
|
||||
s8, OPT_BOOL()) \
|
||||
BCH_OPT(journal_flush_disabled, 0644, NO_SB_OPT, \
|
||||
s8, OPT_BOOL()) \
|
||||
BCH_OPT(nofsck, 0444, NO_SB_OPT, \
|
||||
s8, OPT_BOOL()) \
|
||||
BCH_OPT(fix_errors, 0444, NO_SB_OPT, \
|
||||
s8, OPT_BOOL()) \
|
||||
BCH_OPT(nochanges, 0444, NO_SB_OPT, \
|
||||
s8, OPT_BOOL()) \
|
||||
BCH_OPT(noreplay, 0444, NO_SB_OPT, \
|
||||
s8, OPT_BOOL()) \
|
||||
BCH_OPT(norecovery, 0444, NO_SB_OPT, \
|
||||
s8, OPT_BOOL()) \
|
||||
BCH_OPT(noexcl, 0444, NO_SB_OPT, \
|
||||
s8, OPT_BOOL()) \
|
||||
BCH_OPT(sb, 0444, NO_SB_OPT, \
|
||||
s64, OPT_UINT(0, S64_MAX)) \
|
||||
/**
|
||||
* BCH_OPT(name, type, in mem type, mode, sb_opt)
|
||||
*
|
||||
* @name - name of mount option, sysfs attribute, and struct bch_opts
|
||||
* member
|
||||
*
|
||||
* @mode - when opt may be set
|
||||
*
|
||||
* @sb_option - name of corresponding superblock option
|
||||
*
|
||||
* @type - one of OPT_BOOL, OPT_UINT, OPT_STR
|
||||
*/
|
||||
|
||||
/*
|
||||
* XXX: add fields for
|
||||
* - default value
|
||||
* - helptext
|
||||
*/
|
||||
|
||||
#define BCH_OPTS() \
|
||||
BCH_OPT(read_only, 0444, NO_SB_OPT, \
|
||||
s8, OPT_BOOL()) \
|
||||
BCH_OPT(nostart, 0444, NO_SB_OPT, \
|
||||
s8, OPT_BOOL()) \
|
||||
BCH_VISIBLE_OPTS()
|
||||
BCH_OPT(block_size, u16, OPT_FORMAT, \
|
||||
OPT_UINT(1, 128), \
|
||||
BCH_SB_BLOCK_SIZE, 8) \
|
||||
BCH_OPT(btree_node_size, u16, OPT_FORMAT, \
|
||||
OPT_UINT(1, 128), \
|
||||
BCH_SB_BTREE_NODE_SIZE, 512) \
|
||||
BCH_OPT(errors, u8, OPT_RUNTIME, \
|
||||
OPT_STR(bch2_error_actions), \
|
||||
BCH_SB_ERROR_ACTION, BCH_ON_ERROR_RO) \
|
||||
BCH_OPT(metadata_replicas, u8, OPT_MOUNT, \
|
||||
OPT_UINT(1, BCH_REPLICAS_MAX), \
|
||||
BCH_SB_META_REPLICAS_WANT, 1) \
|
||||
BCH_OPT(data_replicas, u8, OPT_MOUNT, \
|
||||
OPT_UINT(1, BCH_REPLICAS_MAX), \
|
||||
BCH_SB_DATA_REPLICAS_WANT, 1) \
|
||||
BCH_OPT(metadata_replicas_required, u8, OPT_MOUNT, \
|
||||
OPT_UINT(1, BCH_REPLICAS_MAX), \
|
||||
BCH_SB_META_REPLICAS_REQ, 1) \
|
||||
BCH_OPT(data_replicas_required, u8, OPT_MOUNT, \
|
||||
OPT_UINT(1, BCH_REPLICAS_MAX), \
|
||||
BCH_SB_DATA_REPLICAS_REQ, 1) \
|
||||
BCH_OPT(metadata_checksum, u8, OPT_RUNTIME, \
|
||||
OPT_STR(bch2_csum_types), \
|
||||
BCH_SB_META_CSUM_TYPE, BCH_CSUM_OPT_CRC32C) \
|
||||
BCH_OPT(data_checksum, u8, OPT_RUNTIME, \
|
||||
OPT_STR(bch2_csum_types), \
|
||||
BCH_SB_DATA_CSUM_TYPE, BCH_CSUM_OPT_CRC32C) \
|
||||
BCH_OPT(compression, u8, OPT_RUNTIME, \
|
||||
OPT_STR(bch2_compression_types), \
|
||||
BCH_SB_COMPRESSION_TYPE, BCH_COMPRESSION_OPT_NONE)\
|
||||
BCH_OPT(str_hash, u8, OPT_RUNTIME, \
|
||||
OPT_STR(bch2_str_hash_types), \
|
||||
BCH_SB_STR_HASH_TYPE, BCH_STR_HASH_SIPHASH) \
|
||||
BCH_OPT(inodes_32bit, u8, OPT_RUNTIME, \
|
||||
OPT_BOOL(), \
|
||||
BCH_SB_INODE_32BIT, false) \
|
||||
BCH_OPT(gc_reserve_percent, u8, OPT_MOUNT, \
|
||||
OPT_UINT(5, 21), \
|
||||
BCH_SB_GC_RESERVE, 8) \
|
||||
BCH_OPT(root_reserve_percent, u8, OPT_MOUNT, \
|
||||
OPT_UINT(0, 100), \
|
||||
BCH_SB_ROOT_RESERVE, 0) \
|
||||
BCH_OPT(wide_macs, u8, OPT_RUNTIME, \
|
||||
OPT_BOOL(), \
|
||||
BCH_SB_128_BIT_MACS, false) \
|
||||
BCH_OPT(acl, u8, OPT_MOUNT, \
|
||||
OPT_BOOL(), \
|
||||
BCH_SB_POSIX_ACL, true) \
|
||||
BCH_OPT(degraded, u8, OPT_MOUNT, \
|
||||
OPT_BOOL(), \
|
||||
NO_SB_OPT, false) \
|
||||
BCH_OPT(verbose_recovery, u8, OPT_MOUNT, \
|
||||
OPT_BOOL(), \
|
||||
NO_SB_OPT, false) \
|
||||
BCH_OPT(journal_flush_disabled, u8, OPT_RUNTIME, \
|
||||
OPT_BOOL(), \
|
||||
NO_SB_OPT, false) \
|
||||
BCH_OPT(nofsck, u8, OPT_MOUNT, \
|
||||
OPT_BOOL(), \
|
||||
NO_SB_OPT, false) \
|
||||
BCH_OPT(fix_errors, u8, OPT_MOUNT, \
|
||||
OPT_BOOL(), \
|
||||
NO_SB_OPT, false) \
|
||||
BCH_OPT(nochanges, u8, OPT_MOUNT, \
|
||||
OPT_BOOL(), \
|
||||
NO_SB_OPT, false) \
|
||||
BCH_OPT(noreplay, u8, OPT_MOUNT, \
|
||||
OPT_BOOL(), \
|
||||
NO_SB_OPT, false) \
|
||||
BCH_OPT(norecovery, u8, OPT_MOUNT, \
|
||||
OPT_BOOL(), \
|
||||
NO_SB_OPT, false) \
|
||||
BCH_OPT(noexcl, u8, OPT_MOUNT, \
|
||||
OPT_BOOL(), \
|
||||
NO_SB_OPT, false) \
|
||||
BCH_OPT(sb, u64, OPT_MOUNT, \
|
||||
OPT_UINT(0, S64_MAX), \
|
||||
NO_SB_OPT, BCH_SB_SECTOR) \
|
||||
BCH_OPT(read_only, u8, OPT_INTERNAL, \
|
||||
OPT_BOOL(), \
|
||||
NO_SB_OPT, false) \
|
||||
BCH_OPT(nostart, u8, OPT_INTERNAL, \
|
||||
OPT_BOOL(), \
|
||||
NO_SB_OPT, false)
|
||||
|
||||
struct bch_opts {
|
||||
#define BCH_OPT(_name, _mode, _sb_opt, _bits, ...) \
|
||||
_bits _name;
|
||||
#define BCH_OPT(_name, _bits, ...) unsigned _name##_defined:1;
|
||||
BCH_OPTS()
|
||||
#undef BCH_OPT
|
||||
|
||||
#define BCH_OPT(_name, _bits, ...) _bits _name;
|
||||
BCH_OPTS()
|
||||
#undef BCH_OPT
|
||||
};
|
||||
|
||||
static const struct bch_opts bch2_opts_default = {
|
||||
#define BCH_OPT(_name, _bits, _mode, _type, _sb_opt, _default) \
|
||||
._name##_defined = true, \
|
||||
._name = _default, \
|
||||
|
||||
BCH_OPTS()
|
||||
#undef BCH_OPT
|
||||
};
|
||||
|
||||
enum bch_opt_id {
|
||||
#define BCH_OPT(_name, ...) \
|
||||
Opt_##_name,
|
||||
#define opt_defined(_opts, _name) ((_opts)._name##_defined)
|
||||
|
||||
BCH_VISIBLE_OPTS()
|
||||
#define opt_get(_opts, _name) \
|
||||
(opt_defined(_opts, _name) ? _opts._name : bch2_opts_default._name)
|
||||
|
||||
#define opt_set(_opts, _name, _v) \
|
||||
do { \
|
||||
(_opts)._name##_defined = true; \
|
||||
(_opts)._name = _v; \
|
||||
} while (0)
|
||||
|
||||
static inline struct bch_opts bch2_opts_empty(void)
|
||||
{
|
||||
struct bch_opts opts;
|
||||
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
return opts;
|
||||
}
|
||||
|
||||
void bch2_opts_apply(struct bch_opts *, struct bch_opts);
|
||||
|
||||
enum bch_opt_id {
|
||||
#define BCH_OPT(_name, ...) Opt_##_name,
|
||||
BCH_OPTS()
|
||||
#undef BCH_OPT
|
||||
bch2_opts_nr
|
||||
};
|
||||
|
||||
struct bch_option {
|
||||
const char *name;
|
||||
struct attribute attr;
|
||||
void (*set_sb)(struct bch_sb *, u64);
|
||||
enum opt_mode mode;
|
||||
enum opt_type type;
|
||||
|
||||
union {
|
||||
@ -140,32 +215,12 @@ struct bch_option {
|
||||
|
||||
extern const struct bch_option bch2_opt_table[];
|
||||
|
||||
static inline struct bch_opts bch2_opts_empty(void)
|
||||
{
|
||||
struct bch_opts ret;
|
||||
u64 bch2_opt_get_by_id(const struct bch_opts *, enum bch_opt_id);
|
||||
void bch2_opt_set_by_id(struct bch_opts *, enum bch_opt_id, u64);
|
||||
|
||||
memset(&ret, 255, sizeof(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void bch2_opts_apply(struct bch_opts *dst, struct bch_opts src)
|
||||
{
|
||||
#define BCH_OPT(_name, ...) \
|
||||
if (src._name >= 0) \
|
||||
dst->_name = src._name;
|
||||
|
||||
BCH_OPTS()
|
||||
#undef BCH_OPT
|
||||
}
|
||||
|
||||
#define opt_defined(_opt) ((_opt) >= 0)
|
||||
|
||||
void bch2_opt_set(struct bch_opts *, enum bch_opt_id, u64);
|
||||
struct bch_opts bch2_sb_opts(struct bch_sb *);
|
||||
struct bch_opts bch2_opts_from_sb(struct bch_sb *);
|
||||
|
||||
int bch2_opt_parse(const struct bch_option *, const char *, u64 *);
|
||||
int bch2_parse_mount_opts(struct bch_opts *, char *);
|
||||
enum bch_opt_id bch2_parse_sysfs_opt(const char *, const char *, u64 *);
|
||||
|
||||
ssize_t bch2_opt_show(struct bch_opts *, const char *, char *, size_t);
|
||||
|
||||
#endif /* _BCACHEFS_OPTS_H */
|
||||
|
@ -26,14 +26,14 @@ bch2_hash_info_init(struct bch_fs *c,
|
||||
{
|
||||
/* XXX ick */
|
||||
struct bch_hash_info info = {
|
||||
.type = (bi->i_flags >> INODE_STR_HASH_OFFSET) &
|
||||
.type = (bi->bi_flags >> INODE_STR_HASH_OFFSET) &
|
||||
~(~0U << INODE_STR_HASH_BITS)
|
||||
};
|
||||
|
||||
switch (info.type) {
|
||||
case BCH_STR_HASH_CRC32C:
|
||||
case BCH_STR_HASH_CRC64:
|
||||
info.crc_key = bi->i_hash_seed;
|
||||
info.crc_key = bi->bi_hash_seed;
|
||||
break;
|
||||
case BCH_STR_HASH_SIPHASH: {
|
||||
SHASH_DESC_ON_STACK(desc, c->sha256);
|
||||
@ -42,8 +42,8 @@ bch2_hash_info_init(struct bch_fs *c,
|
||||
desc->tfm = c->sha256;
|
||||
desc->flags = 0;
|
||||
|
||||
crypto_shash_digest(desc, (void *) &bi->i_hash_seed,
|
||||
sizeof(bi->i_hash_seed), digest);
|
||||
crypto_shash_digest(desc, (void *) &bi->bi_hash_seed,
|
||||
sizeof(bi->bi_hash_seed), digest);
|
||||
memcpy(&info.siphash_key, digest, sizeof(info.siphash_key));
|
||||
break;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ struct bch_sb_field *bch2_sb_field_get(struct bch_sb *sb,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bch2_free_super(struct bcache_superblock *sb)
|
||||
void bch2_free_super(struct bch_sb_handle *sb)
|
||||
{
|
||||
if (sb->bio)
|
||||
bio_put(sb->bio);
|
||||
@ -43,7 +43,7 @@ void bch2_free_super(struct bcache_superblock *sb)
|
||||
memset(sb, 0, sizeof(*sb));
|
||||
}
|
||||
|
||||
static int __bch2_super_realloc(struct bcache_superblock *sb, unsigned order)
|
||||
static int __bch2_super_realloc(struct bch_sb_handle *sb, unsigned order)
|
||||
{
|
||||
struct bch_sb *new_sb;
|
||||
struct bio *bio;
|
||||
@ -77,7 +77,7 @@ static int __bch2_super_realloc(struct bcache_superblock *sb, unsigned order)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bch2_sb_realloc(struct bcache_superblock *sb, unsigned u64s)
|
||||
static int bch2_sb_realloc(struct bch_sb_handle *sb, unsigned u64s)
|
||||
{
|
||||
u64 new_bytes = __vstruct_bytes(struct bch_sb, u64s);
|
||||
u64 max_bytes = 512 << sb->sb->layout.sb_max_size_bits;
|
||||
@ -145,7 +145,7 @@ static struct bch_sb_field *__bch2_sb_field_resize(struct bch_sb *sb,
|
||||
return f;
|
||||
}
|
||||
|
||||
struct bch_sb_field *bch2_sb_field_resize(struct bcache_superblock *sb,
|
||||
struct bch_sb_field *bch2_sb_field_resize(struct bch_sb_handle *sb,
|
||||
enum bch_sb_field_type type,
|
||||
unsigned u64s)
|
||||
{
|
||||
@ -179,7 +179,7 @@ struct bch_sb_field *bch2_fs_sb_field_resize(struct bch_fs *c,
|
||||
/* XXX: we're not checking that offline device have enough space */
|
||||
|
||||
for_each_online_member(ca, c, i) {
|
||||
struct bcache_superblock *sb = &ca->disk_sb;
|
||||
struct bch_sb_handle *sb = &ca->disk_sb;
|
||||
|
||||
if (bch2_sb_realloc(sb, le32_to_cpu(sb->sb->u64s) + d)) {
|
||||
percpu_ref_put(&ca->ref);
|
||||
@ -305,7 +305,7 @@ static const char *bch2_sb_validate_members(struct bch_sb *sb)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *bch2_sb_validate(struct bcache_superblock *disk_sb)
|
||||
const char *bch2_sb_validate(struct bch_sb_handle *disk_sb)
|
||||
{
|
||||
struct bch_sb *sb = disk_sb->sb;
|
||||
struct bch_sb_field *f;
|
||||
@ -318,8 +318,10 @@ const char *bch2_sb_validate(struct bcache_superblock *disk_sb)
|
||||
le64_to_cpu(sb->version) > BCH_SB_VERSION_MAX)
|
||||
return"Unsupported superblock version";
|
||||
|
||||
if (le64_to_cpu(sb->version) < BCH_SB_VERSION_EXTENT_MAX)
|
||||
if (le64_to_cpu(sb->version) < BCH_SB_VERSION_EXTENT_MAX) {
|
||||
SET_BCH_SB_ENCODED_EXTENT_MAX_BITS(sb, 7);
|
||||
SET_BCH_SB_POSIX_ACL(sb, 1);
|
||||
}
|
||||
|
||||
block_size = le16_to_cpu(sb->block_size);
|
||||
|
||||
@ -462,11 +464,8 @@ static void bch2_sb_update(struct bch_fs *c)
|
||||
|
||||
c->sb.uuid = src->uuid;
|
||||
c->sb.user_uuid = src->user_uuid;
|
||||
c->sb.block_size = le16_to_cpu(src->block_size);
|
||||
c->sb.btree_node_size = BCH_SB_BTREE_NODE_SIZE(src);
|
||||
c->sb.nr_devices = src->nr_devices;
|
||||
c->sb.clean = BCH_SB_CLEAN(src);
|
||||
c->sb.str_hash_type = BCH_SB_STR_HASH_TYPE(src);
|
||||
c->sb.encryption_type = BCH_SB_ENCRYPTION_TYPE(src);
|
||||
c->sb.encoded_extent_max= 1 << BCH_SB_ENCODED_EXTENT_MAX_BITS(src);
|
||||
c->sb.time_base_lo = le64_to_cpu(src->time_base_lo);
|
||||
@ -557,7 +556,7 @@ int bch2_sb_from_fs(struct bch_fs *c, struct bch_dev *ca)
|
||||
|
||||
/* read superblock: */
|
||||
|
||||
static const char *read_one_super(struct bcache_superblock *sb, u64 offset)
|
||||
static const char *read_one_super(struct bch_sb_handle *sb, u64 offset)
|
||||
{
|
||||
struct bch_csum csum;
|
||||
size_t bytes;
|
||||
@ -605,37 +604,37 @@ reread:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *bch2_read_super(struct bcache_superblock *sb,
|
||||
const char *bch2_read_super(const char *path,
|
||||
struct bch_opts opts,
|
||||
const char *path)
|
||||
struct bch_sb_handle *ret)
|
||||
{
|
||||
u64 offset = opt_defined(opts.sb) ? opts.sb : BCH_SB_SECTOR;
|
||||
u64 offset = opt_get(opts, sb);
|
||||
struct bch_sb_layout layout;
|
||||
const char *err;
|
||||
unsigned i;
|
||||
|
||||
memset(sb, 0, sizeof(*sb));
|
||||
sb->mode = FMODE_READ;
|
||||
memset(ret, 0, sizeof(*ret));
|
||||
ret->mode = FMODE_READ;
|
||||
|
||||
if (!(opt_defined(opts.noexcl) && opts.noexcl))
|
||||
sb->mode |= FMODE_EXCL;
|
||||
if (!opt_get(opts, noexcl))
|
||||
ret->mode |= FMODE_EXCL;
|
||||
|
||||
if (!(opt_defined(opts.nochanges) && opts.nochanges))
|
||||
sb->mode |= FMODE_WRITE;
|
||||
if (!opt_get(opts, nochanges))
|
||||
ret->mode |= FMODE_WRITE;
|
||||
|
||||
err = bch2_blkdev_open(path, sb->mode, sb, &sb->bdev);
|
||||
err = bch2_blkdev_open(path, ret->mode, ret, &ret->bdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = "cannot allocate memory";
|
||||
if (__bch2_super_realloc(sb, 0))
|
||||
if (__bch2_super_realloc(ret, 0))
|
||||
goto err;
|
||||
|
||||
err = "dynamic fault";
|
||||
if (bch2_fs_init_fault("read_super"))
|
||||
goto err;
|
||||
|
||||
err = read_one_super(sb, offset);
|
||||
err = read_one_super(ret, offset);
|
||||
if (!err)
|
||||
goto got_super;
|
||||
|
||||
@ -650,22 +649,22 @@ const char *bch2_read_super(struct bcache_superblock *sb,
|
||||
* Error reading primary superblock - read location of backup
|
||||
* superblocks:
|
||||
*/
|
||||
bio_reset(sb->bio);
|
||||
sb->bio->bi_bdev = sb->bdev;
|
||||
sb->bio->bi_iter.bi_sector = BCH_SB_LAYOUT_SECTOR;
|
||||
sb->bio->bi_iter.bi_size = sizeof(struct bch_sb_layout);
|
||||
bio_set_op_attrs(sb->bio, REQ_OP_READ, REQ_SYNC|REQ_META);
|
||||
bio_reset(ret->bio);
|
||||
ret->bio->bi_bdev = ret->bdev;
|
||||
ret->bio->bi_iter.bi_sector = BCH_SB_LAYOUT_SECTOR;
|
||||
ret->bio->bi_iter.bi_size = sizeof(struct bch_sb_layout);
|
||||
bio_set_op_attrs(ret->bio, REQ_OP_READ, REQ_SYNC|REQ_META);
|
||||
/*
|
||||
* use sb buffer to read layout, since sb buffer is page aligned but
|
||||
* layout won't be:
|
||||
*/
|
||||
bch2_bio_map(sb->bio, sb->sb);
|
||||
bch2_bio_map(ret->bio, ret->sb);
|
||||
|
||||
err = "IO error";
|
||||
if (submit_bio_wait(sb->bio))
|
||||
if (submit_bio_wait(ret->bio))
|
||||
goto err;
|
||||
|
||||
memcpy(&layout, sb->sb, sizeof(layout));
|
||||
memcpy(&layout, ret->sb, sizeof(layout));
|
||||
err = validate_sb_layout(&layout);
|
||||
if (err)
|
||||
goto err;
|
||||
@ -676,26 +675,26 @@ const char *bch2_read_super(struct bcache_superblock *sb,
|
||||
if (offset == BCH_SB_SECTOR)
|
||||
continue;
|
||||
|
||||
err = read_one_super(sb, offset);
|
||||
err = read_one_super(ret, offset);
|
||||
if (!err)
|
||||
goto got_super;
|
||||
}
|
||||
goto err;
|
||||
got_super:
|
||||
pr_debug("read sb version %llu, flags %llu, seq %llu, journal size %u",
|
||||
le64_to_cpu(sb->sb->version),
|
||||
le64_to_cpu(sb->sb->flags),
|
||||
le64_to_cpu(sb->sb->seq),
|
||||
le16_to_cpu(sb->sb->u64s));
|
||||
le64_to_cpu(ret->sb->version),
|
||||
le64_to_cpu(ret->sb->flags),
|
||||
le64_to_cpu(ret->sb->seq),
|
||||
le16_to_cpu(ret->sb->u64s));
|
||||
|
||||
err = "Superblock block size smaller than device block size";
|
||||
if (le16_to_cpu(sb->sb->block_size) << 9 <
|
||||
bdev_logical_block_size(sb->bdev))
|
||||
if (le16_to_cpu(ret->sb->block_size) << 9 <
|
||||
bdev_logical_block_size(ret->bdev))
|
||||
goto err;
|
||||
|
||||
return NULL;
|
||||
err:
|
||||
bch2_free_super(sb);
|
||||
bch2_free_super(ret);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
struct bch_sb_field *bch2_sb_field_get(struct bch_sb *, enum bch_sb_field_type);
|
||||
struct bch_sb_field *bch2_sb_field_resize(struct bcache_superblock *,
|
||||
struct bch_sb_field *bch2_sb_field_resize(struct bch_sb_handle *,
|
||||
enum bch_sb_field_type, unsigned);
|
||||
struct bch_sb_field *bch2_fs_sb_field_resize(struct bch_fs *,
|
||||
enum bch_sb_field_type, unsigned);
|
||||
@ -26,7 +26,7 @@ bch2_sb_get_##_name(struct bch_sb *sb) \
|
||||
} \
|
||||
\
|
||||
static inline struct bch_sb_field_##_name * \
|
||||
bch2_sb_resize_##_name(struct bcache_superblock *sb, unsigned u64s) \
|
||||
bch2_sb_resize_##_name(struct bch_sb_handle *sb, unsigned u64s) \
|
||||
{ \
|
||||
return field_to_type(bch2_sb_field_resize(sb, \
|
||||
BCH_SB_FIELD_##_name, u64s), _name); \
|
||||
@ -112,15 +112,15 @@ static inline struct bch_member_cpu bch2_mi_to_cpu(struct bch_member *mi)
|
||||
int bch2_sb_to_fs(struct bch_fs *, struct bch_sb *);
|
||||
int bch2_sb_from_fs(struct bch_fs *, struct bch_dev *);
|
||||
|
||||
void bch2_free_super(struct bcache_superblock *);
|
||||
int bch2_super_realloc(struct bcache_superblock *, unsigned);
|
||||
void bch2_free_super(struct bch_sb_handle *);
|
||||
int bch2_super_realloc(struct bch_sb_handle *, unsigned);
|
||||
|
||||
const char *bch2_sb_validate_journal(struct bch_sb *,
|
||||
struct bch_member_cpu);
|
||||
const char *bch2_sb_validate(struct bcache_superblock *);
|
||||
const char *bch2_sb_validate(struct bch_sb_handle *);
|
||||
|
||||
const char *bch2_read_super(struct bcache_superblock *,
|
||||
struct bch_opts, const char *);
|
||||
const char *bch2_read_super(const char *, struct bch_opts,
|
||||
struct bch_sb_handle *);
|
||||
void bch2_write_super(struct bch_fs *);
|
||||
|
||||
/* replicas: */
|
||||
|
@ -241,13 +241,12 @@ static void bch2_writes_disabled(struct percpu_ref *writes)
|
||||
|
||||
void bch2_fs_read_only(struct bch_fs *c)
|
||||
{
|
||||
mutex_lock(&c->state_lock);
|
||||
if (c->state != BCH_FS_STARTING &&
|
||||
c->state != BCH_FS_RW)
|
||||
goto out;
|
||||
return;
|
||||
|
||||
if (test_bit(BCH_FS_ERROR, &c->flags))
|
||||
goto out;
|
||||
return;
|
||||
|
||||
/*
|
||||
* Block new foreground-end write operations from starting - any new
|
||||
@ -296,8 +295,6 @@ void bch2_fs_read_only(struct bch_fs *c)
|
||||
}
|
||||
|
||||
c->state = BCH_FS_RO;
|
||||
out:
|
||||
mutex_unlock(&c->state_lock);
|
||||
}
|
||||
|
||||
static void bch2_fs_read_only_work(struct work_struct *work)
|
||||
@ -305,7 +302,9 @@ static void bch2_fs_read_only_work(struct work_struct *work)
|
||||
struct bch_fs *c =
|
||||
container_of(work, struct bch_fs, read_only_work);
|
||||
|
||||
mutex_lock(&c->state_lock);
|
||||
bch2_fs_read_only(c);
|
||||
mutex_unlock(&c->state_lock);
|
||||
}
|
||||
|
||||
static void bch2_fs_read_only_async(struct bch_fs *c)
|
||||
@ -330,10 +329,9 @@ const char *bch2_fs_read_write(struct bch_fs *c)
|
||||
const char *err = NULL;
|
||||
unsigned i;
|
||||
|
||||
mutex_lock(&c->state_lock);
|
||||
if (c->state != BCH_FS_STARTING &&
|
||||
c->state != BCH_FS_RO)
|
||||
goto out;
|
||||
return NULL;
|
||||
|
||||
for_each_rw_member(ca, c, i)
|
||||
bch2_dev_allocator_add(c, ca);
|
||||
@ -367,13 +365,10 @@ const char *bch2_fs_read_write(struct bch_fs *c)
|
||||
percpu_ref_reinit(&c->writes);
|
||||
|
||||
c->state = BCH_FS_RW;
|
||||
err = NULL;
|
||||
out:
|
||||
mutex_unlock(&c->state_lock);
|
||||
return err;
|
||||
return NULL;
|
||||
err:
|
||||
__bch2_fs_read_only(c);
|
||||
goto out;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Filesystem startup/shutdown: */
|
||||
@ -452,7 +447,9 @@ static void bch2_fs_offline(struct bch_fs *c)
|
||||
kobject_put(&c->opts_dir);
|
||||
kobject_put(&c->internal);
|
||||
|
||||
mutex_lock(&c->state_lock);
|
||||
__bch2_fs_read_only(c);
|
||||
mutex_unlock(&c->state_lock);
|
||||
}
|
||||
|
||||
static void bch2_fs_release(struct kobject *kobj)
|
||||
@ -555,15 +552,16 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
|
||||
goto err;
|
||||
}
|
||||
|
||||
c->block_bits = ilog2(c->sb.block_size);
|
||||
|
||||
mutex_unlock(&c->sb_lock);
|
||||
|
||||
scnprintf(c->name, sizeof(c->name), "%pU", &c->sb.user_uuid);
|
||||
|
||||
bch2_opts_apply(&c->opts, bch2_sb_opts(sb));
|
||||
c->opts = bch2_opts_default;
|
||||
bch2_opts_apply(&c->opts, bch2_opts_from_sb(sb));
|
||||
bch2_opts_apply(&c->opts, opts);
|
||||
|
||||
c->block_bits = ilog2(c->opts.block_size);
|
||||
|
||||
c->opts.nochanges |= c->opts.noreplay;
|
||||
c->opts.read_only |= c->opts.nochanges;
|
||||
|
||||
@ -590,7 +588,7 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
|
||||
bioset_init(&c->bio_write, 1, offsetof(struct bch_write_bio, bio)) ||
|
||||
mempool_init_page_pool(&c->bio_bounce_pages,
|
||||
max_t(unsigned,
|
||||
c->sb.btree_node_size,
|
||||
c->opts.btree_node_size,
|
||||
c->sb.encoded_extent_max) /
|
||||
PAGE_SECTORS, 0) ||
|
||||
!(c->usage_percpu = alloc_percpu(struct bch_fs_usage)) ||
|
||||
@ -657,7 +655,8 @@ static const char *__bch2_fs_online(struct bch_fs *c)
|
||||
if (kobject_add(&c->kobj, NULL, "%pU", c->sb.user_uuid.b) ||
|
||||
kobject_add(&c->internal, &c->kobj, "internal") ||
|
||||
kobject_add(&c->opts_dir, &c->kobj, "options") ||
|
||||
kobject_add(&c->time_stats, &c->kobj, "time_stats"))
|
||||
kobject_add(&c->time_stats, &c->kobj, "time_stats") ||
|
||||
bch2_opts_create_sysfs_files(&c->opts_dir))
|
||||
return "error creating sysfs objects";
|
||||
|
||||
mutex_lock(&c->state_lock);
|
||||
@ -699,6 +698,8 @@ static const char *__bch2_fs_start(struct bch_fs *c)
|
||||
|
||||
closure_init_stack(&cl);
|
||||
|
||||
mutex_lock(&c->state_lock);
|
||||
|
||||
BUG_ON(c->state != BCH_FS_STARTING);
|
||||
|
||||
mutex_lock(&c->sb_lock);
|
||||
@ -742,6 +743,8 @@ static const char *__bch2_fs_start(struct bch_fs *c)
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
set_bit(BCH_FS_ALLOC_READ_DONE, &c->flags);
|
||||
|
||||
bch_verbose(c, "starting mark and sweep:");
|
||||
err = "error in recovery";
|
||||
ret = bch2_initial_gc(c, &journal);
|
||||
@ -796,6 +799,8 @@ static const char *__bch2_fs_start(struct bch_fs *c)
|
||||
|
||||
bch_notice(c, "initializing new filesystem");
|
||||
|
||||
set_bit(BCH_FS_ALLOC_READ_DONE, &c->flags);
|
||||
|
||||
ret = bch2_initial_gc(c, &journal);
|
||||
if (ret)
|
||||
goto err;
|
||||
@ -831,7 +836,7 @@ static const char *__bch2_fs_start(struct bch_fs *c)
|
||||
|
||||
bch2_inode_init(c, &inode, 0, 0,
|
||||
S_IFDIR|S_IRWXU|S_IRUGO|S_IXUGO, 0);
|
||||
inode.inum = BCACHEFS_ROOT_INO;
|
||||
inode.bi_inum = BCACHEFS_ROOT_INO;
|
||||
|
||||
bch2_inode_pack(&packed_inode, &inode);
|
||||
|
||||
@ -873,6 +878,7 @@ recovery_done:
|
||||
|
||||
err = NULL;
|
||||
out:
|
||||
mutex_unlock(&c->state_lock);
|
||||
bch2_journal_entries_free(&journal);
|
||||
return err;
|
||||
err:
|
||||
@ -922,7 +928,7 @@ static const char *bch2_dev_may_add(struct bch_sb *sb, struct bch_fs *c)
|
||||
if (!sb_mi)
|
||||
return "Invalid superblock: member info area missing";
|
||||
|
||||
if (le16_to_cpu(sb->block_size) != c->sb.block_size)
|
||||
if (le16_to_cpu(sb->block_size) != c->opts.block_size)
|
||||
return "mismatched block size";
|
||||
|
||||
if (le16_to_cpu(sb_mi->members[sb->dev_idx].bucket_size) <
|
||||
@ -1129,7 +1135,7 @@ static int bch2_dev_alloc(struct bch_fs *c, unsigned dev_idx)
|
||||
|
||||
btree_node_reserve_buckets =
|
||||
DIV_ROUND_UP(BTREE_NODE_RESERVE,
|
||||
ca->mi.bucket_size / c->sb.btree_node_size);
|
||||
ca->mi.bucket_size / c->opts.btree_node_size);
|
||||
|
||||
if (percpu_ref_init(&ca->ref, bch2_dev_ref_release,
|
||||
0, GFP_KERNEL) ||
|
||||
@ -1176,7 +1182,7 @@ err:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int __bch2_dev_online(struct bch_fs *c, struct bcache_superblock *sb)
|
||||
static int __bch2_dev_online(struct bch_fs *c, struct bch_sb_handle *sb)
|
||||
{
|
||||
struct bch_dev *ca;
|
||||
int ret;
|
||||
@ -1462,7 +1468,7 @@ err:
|
||||
/* Add new device to running filesystem: */
|
||||
int bch2_dev_add(struct bch_fs *c, const char *path)
|
||||
{
|
||||
struct bcache_superblock sb;
|
||||
struct bch_sb_handle sb;
|
||||
const char *err;
|
||||
struct bch_dev *ca = NULL;
|
||||
struct bch_sb_field_members *mi, *dev_mi;
|
||||
@ -1470,7 +1476,7 @@ int bch2_dev_add(struct bch_fs *c, const char *path)
|
||||
unsigned dev_idx, nr_devices, u64s;
|
||||
int ret = -EINVAL;
|
||||
|
||||
err = bch2_read_super(&sb, bch2_opts_empty(), path);
|
||||
err = bch2_read_super(path, bch2_opts_empty(), &sb);
|
||||
if (err)
|
||||
return -EINVAL;
|
||||
|
||||
@ -1572,14 +1578,14 @@ err:
|
||||
/* Hot add existing device to running filesystem: */
|
||||
int bch2_dev_online(struct bch_fs *c, const char *path)
|
||||
{
|
||||
struct bcache_superblock sb = { 0 };
|
||||
struct bch_sb_handle sb = { 0 };
|
||||
struct bch_dev *ca;
|
||||
unsigned dev_idx;
|
||||
const char *err;
|
||||
|
||||
mutex_lock(&c->state_lock);
|
||||
|
||||
err = bch2_read_super(&sb, bch2_opts_empty(), path);
|
||||
err = bch2_read_super(path, bch2_opts_empty(), &sb);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
@ -1673,7 +1679,7 @@ const char *bch2_fs_open(char * const *devices, unsigned nr_devices,
|
||||
{
|
||||
const char *err;
|
||||
struct bch_fs *c = NULL;
|
||||
struct bcache_superblock *sb;
|
||||
struct bch_sb_handle *sb;
|
||||
unsigned i, best_sb = 0;
|
||||
|
||||
if (!nr_devices)
|
||||
@ -1688,7 +1694,7 @@ const char *bch2_fs_open(char * const *devices, unsigned nr_devices,
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < nr_devices; i++) {
|
||||
err = bch2_read_super(&sb[i], opts, devices[i]);
|
||||
err = bch2_read_super(devices[i], opts, &sb[i]);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
@ -1757,7 +1763,7 @@ err:
|
||||
goto out;
|
||||
}
|
||||
|
||||
static const char *__bch2_fs_open_incremental(struct bcache_superblock *sb,
|
||||
static const char *__bch2_fs_open_incremental(struct bch_sb_handle *sb,
|
||||
struct bch_opts opts)
|
||||
{
|
||||
const char *err;
|
||||
@ -1821,11 +1827,11 @@ err:
|
||||
|
||||
const char *bch2_fs_open_incremental(const char *path)
|
||||
{
|
||||
struct bcache_superblock sb;
|
||||
struct bch_sb_handle sb;
|
||||
struct bch_opts opts = bch2_opts_empty();
|
||||
const char *err;
|
||||
|
||||
err = bch2_read_super(&sb, opts, path);
|
||||
err = bch2_read_super(path, opts, &sb);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef _BCACHEFS_SUPER_TYPES_H
|
||||
#define _BCACHEFS_SUPER_TYPES_H
|
||||
|
||||
struct bcache_superblock {
|
||||
struct bch_sb_handle {
|
||||
struct bch_sb *sb;
|
||||
struct block_device *bdev;
|
||||
struct bio *bio;
|
||||
|
@ -194,14 +194,6 @@ read_attribute(data_replicas_have);
|
||||
BCH_DEBUG_PARAMS()
|
||||
#undef BCH_DEBUG_PARAM
|
||||
|
||||
#define BCH_OPT(_name, _mode, ...) \
|
||||
static struct attribute sysfs_opt_##_name = { \
|
||||
.name = #_name, .mode = _mode, \
|
||||
};
|
||||
|
||||
BCH_VISIBLE_OPTS()
|
||||
#undef BCH_OPT
|
||||
|
||||
#define BCH_TIME_STAT(name, frequency_units, duration_units) \
|
||||
sysfs_time_stats_attribute(name, frequency_units, duration_units);
|
||||
BCH_TIME_STATS()
|
||||
@ -528,8 +520,13 @@ SHOW(bch2_fs_opts_dir)
|
||||
{
|
||||
char *out = buf, *end = buf + PAGE_SIZE;
|
||||
struct bch_fs *c = container_of(kobj, struct bch_fs, opts_dir);
|
||||
const struct bch_option *opt = container_of(attr, struct bch_option, attr);
|
||||
int id = opt - bch2_opt_table;
|
||||
u64 v = bch2_opt_get_by_id(&c->opts, id);
|
||||
|
||||
out += bch2_opt_show(&c->opts, attr->name, out, end - out);
|
||||
out += opt->type == BCH_OPT_STR
|
||||
? bch2_scnprint_string_list(out, end - out, opt->choices, v)
|
||||
: scnprintf(out, end - out, "%lli", v);
|
||||
out += scnprintf(out, end - out, "\n");
|
||||
|
||||
return out - buf;
|
||||
@ -538,15 +535,13 @@ SHOW(bch2_fs_opts_dir)
|
||||
STORE(bch2_fs_opts_dir)
|
||||
{
|
||||
struct bch_fs *c = container_of(kobj, struct bch_fs, opts_dir);
|
||||
const struct bch_option *opt;
|
||||
int id;
|
||||
const struct bch_option *opt = container_of(attr, struct bch_option, attr);
|
||||
int ret, id = opt - bch2_opt_table;
|
||||
u64 v;
|
||||
|
||||
id = bch2_parse_sysfs_opt(attr->name, buf, &v);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
opt = &bch2_opt_table[id];
|
||||
ret = bch2_opt_parse(opt, buf, &v);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&c->sb_lock);
|
||||
|
||||
@ -563,7 +558,7 @@ STORE(bch2_fs_opts_dir)
|
||||
bch2_write_super(c);
|
||||
}
|
||||
|
||||
bch2_opt_set(&c->opts, id, v);
|
||||
bch2_opt_set_by_id(&c->opts, id, v);
|
||||
|
||||
mutex_unlock(&c->sb_lock);
|
||||
|
||||
@ -571,15 +566,26 @@ STORE(bch2_fs_opts_dir)
|
||||
}
|
||||
SYSFS_OPS(bch2_fs_opts_dir);
|
||||
|
||||
struct attribute *bch2_fs_opts_dir_files[] = {
|
||||
#define BCH_OPT(_name, ...) \
|
||||
&sysfs_opt_##_name,
|
||||
struct attribute *bch2_fs_opts_dir_files[] = { NULL };
|
||||
|
||||
BCH_VISIBLE_OPTS()
|
||||
#undef BCH_OPT
|
||||
int bch2_opts_create_sysfs_files(struct kobject *kobj)
|
||||
{
|
||||
const struct bch_option *i;
|
||||
int ret;
|
||||
|
||||
NULL
|
||||
};
|
||||
for (i = bch2_opt_table;
|
||||
i < bch2_opt_table + bch2_opts_nr;
|
||||
i++) {
|
||||
if (i->mode == OPT_INTERNAL)
|
||||
continue;
|
||||
|
||||
ret = sysfs_create_file(kobj, &i->attr);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* time stats */
|
||||
|
||||
|
@ -20,6 +20,8 @@ extern struct sysfs_ops bch2_fs_opts_dir_sysfs_ops;
|
||||
extern struct sysfs_ops bch2_fs_time_stats_sysfs_ops;
|
||||
extern struct sysfs_ops bch2_dev_sysfs_ops;
|
||||
|
||||
int bch2_opts_create_sysfs_files(struct kobject *);
|
||||
|
||||
#else
|
||||
|
||||
static struct attribute *bch2_fs_files[] = {};
|
||||
@ -34,6 +36,8 @@ static const struct sysfs_ops bch2_fs_opts_dir_sysfs_ops;
|
||||
static const struct sysfs_ops bch2_fs_time_stats_sysfs_ops;
|
||||
static const struct sysfs_ops bch2_dev_sysfs_ops;
|
||||
|
||||
static inline int bch2_opts_create_sysfs_files(struct kobject *kobj) { return 0; }
|
||||
|
||||
#endif /* NO_BCACHEFS_SYSFS */
|
||||
|
||||
#endif /* _BCACHEFS_SYSFS_H_ */
|
||||
|
@ -162,17 +162,16 @@ const struct bkey_ops bch2_bkey_xattr_ops = {
|
||||
.val_to_text = bch2_xattr_to_text,
|
||||
};
|
||||
|
||||
int bch2_xattr_get(struct bch_fs *c, struct inode *inode,
|
||||
int bch2_xattr_get(struct bch_fs *c, struct bch_inode_info *inode,
|
||||
const char *name, void *buffer, size_t size, int type)
|
||||
{
|
||||
struct bch_inode_info *ei = to_bch_ei(inode);
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
struct bkey_s_c_xattr xattr;
|
||||
int ret;
|
||||
|
||||
k = bch2_hash_lookup(bch2_xattr_hash_desc, &ei->str_hash, c,
|
||||
ei->vfs_inode.i_ino, &iter,
|
||||
k = bch2_hash_lookup(bch2_xattr_hash_desc, &inode->ei_str_hash, c,
|
||||
inode->v.i_ino, &iter,
|
||||
&X_SEARCH(type, name, strlen(name)));
|
||||
if (IS_ERR(k.k))
|
||||
return bch2_btree_iter_unlock(&iter) ?: -ENODATA;
|
||||
@ -236,15 +235,13 @@ int __bch2_xattr_set(struct bch_fs *c, u64 inum,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bch2_xattr_set(struct bch_fs *c, struct inode *inode,
|
||||
int bch2_xattr_set(struct bch_fs *c, struct bch_inode_info *inode,
|
||||
const char *name, const void *value, size_t size,
|
||||
int flags, int type)
|
||||
{
|
||||
struct bch_inode_info *ei = to_bch_ei(inode);
|
||||
|
||||
return __bch2_xattr_set(c, inode->i_ino, &ei->str_hash,
|
||||
return __bch2_xattr_set(c, inode->v.i_ino, &inode->ei_str_hash,
|
||||
name, value, size, flags, type,
|
||||
&ei->journal_seq);
|
||||
&inode->ei_journal_seq);
|
||||
}
|
||||
|
||||
static size_t bch2_xattr_emit(struct dentry *dentry,
|
||||
@ -313,20 +310,22 @@ ssize_t bch2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
|
||||
}
|
||||
|
||||
static int bch2_xattr_get_handler(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
struct dentry *dentry, struct inode *vinode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
struct bch_fs *c = inode->i_sb->s_fs_info;
|
||||
struct bch_inode_info *inode = to_bch_ei(vinode);
|
||||
struct bch_fs *c = inode->v.i_sb->s_fs_info;
|
||||
|
||||
return bch2_xattr_get(c, inode, name, buffer, size, handler->flags);
|
||||
}
|
||||
|
||||
static int bch2_xattr_set_handler(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
struct dentry *dentry, struct inode *vinode,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
{
|
||||
struct bch_fs *c = inode->i_sb->s_fs_info;
|
||||
struct bch_inode_info *inode = to_bch_ei(vinode);
|
||||
struct bch_fs *c = inode->v.i_sb->s_fs_info;
|
||||
|
||||
return bch2_xattr_set(c, inode, name, value, size, flags,
|
||||
handler->flags);
|
||||
|
@ -9,12 +9,13 @@ extern const struct bkey_ops bch2_bkey_xattr_ops;
|
||||
struct dentry;
|
||||
struct xattr_handler;
|
||||
struct bch_hash_info;
|
||||
struct bch_inode_info;
|
||||
|
||||
int bch2_xattr_get(struct bch_fs *, struct inode *,
|
||||
int bch2_xattr_get(struct bch_fs *, struct bch_inode_info *,
|
||||
const char *, void *, size_t, int);
|
||||
int __bch2_xattr_set(struct bch_fs *, u64, const struct bch_hash_info *,
|
||||
const char *, const void *, size_t, int, int, u64 *);
|
||||
int bch2_xattr_set(struct bch_fs *, struct inode *,
|
||||
int bch2_xattr_set(struct bch_fs *, struct bch_inode_info *,
|
||||
const char *, const void *, size_t, int, int);
|
||||
ssize_t bch2_xattr_list(struct dentry *, char *, size_t);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user