Update bcachefs sources to d4b7ef921a bcachefs: Refactoring

This commit is contained in:
Kent Overstreet 2017-11-04 18:32:07 -04:00
parent bf8c59996b
commit 8351bbc05b
41 changed files with 1537 additions and 1351 deletions

View File

@ -1 +1 @@
e82e65627960a46945b78a5e5e946b23b8f08972 0415b63b198ccf8bf5eee3af73accd60e94ad63a

View File

@ -75,7 +75,7 @@ deb: all
.PHONE: update-bcachefs-sources .PHONE: update-bcachefs-sources
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)/fs/bcachefs/*.[ch] libbcachefs/
cp $(LINUX_DIR)/include/trace/events/bcachefs.h include/trace/events/ cp $(LINUX_DIR)/include/trace/events/bcachefs.h include/trace/events/
echo `cd $(LINUX_DIR); git rev-parse HEAD` > .bcachefs_revision echo `cd $(LINUX_DIR); git rev-parse HEAD` > .bcachefs_revision

View File

@ -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 bch_hash_info parent_hash_info = bch2_hash_info_init(c, parent);
struct qstr qname = { { { .len = strlen(name), } }, .name = name }; 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, mode_to_type(mode), &qname,
inum, NULL, BCH_HASH_SET_MUST_CREATE); inum, NULL, BCH_HASH_SET_MUST_CREATE);
if (ret) if (ret)
die("error creating file: %s", strerror(-ret)); die("error creating file: %s", strerror(-ret));
if (S_ISDIR(mode)) if (S_ISDIR(mode))
parent->i_nlink++; parent->bi_nlink++;
} }
static void create_link(struct bch_fs *c, static void create_link(struct bch_fs *c,
@ -149,7 +149,7 @@ static void create_link(struct bch_fs *c,
if (ret) if (ret)
die("error looking up hardlink: %s", strerror(-ret)); die("error looking up hardlink: %s", strerror(-ret));
inode.i_nlink++; inode.bi_nlink++;
update_inode(c, &inode); update_inode(c, &inode);
create_dirent(c, parent, name, inum, mode); create_dirent(c, parent, name, inum, mode);
@ -171,7 +171,7 @@ static struct bch_inode_unpacked create_file(struct bch_fs *c,
if (ret) if (ret)
die("error creating file: %s", strerror(-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; 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, static void copy_times(struct bch_fs *c, struct bch_inode_unpacked *dst,
struct stat *src) struct stat *src)
{ {
dst->i_atime = timespec_to_bch2_time(c, src->st_atim); dst->bi_atime = timespec_to_bch2_time(c, src->st_atim);
dst->i_mtime = timespec_to_bch2_time(c, src->st_mtim); dst->bi_mtime = timespec_to_bch2_time(c, src->st_mtim);
dst->i_ctime = timespec_to_bch2_time(c, src->st_ctim); dst->bi_ctime = timespec_to_bch2_time(c, src->st_ctim);
} }
static void copy_xattrs(struct bch_fs *c, struct bch_inode_unpacked *dst, 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); 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); val, val_size, 0, h->flags, NULL);
if (ret < 0) if (ret < 0)
die("error creating xattr: %s", strerror(-ret)); 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)); die("error reserving space in new filesystem: %s", strerror(-ret));
bch2_write_op_init(&op, c, res, c->write_points, 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_call(&op.cl, bch2_write, NULL, &cl);
closure_sync(&cl); closure_sync(&cl);
dst_inode->i_sectors += len >> 9; dst_inode->bi_sectors += len >> 9;
} }
static char buf[1 << 20] __aligned(PAGE_SIZE); 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); length);
e = bkey_extent_init(&k.k); 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.p.offset = logical + sectors;
e->k.size = sectors; e->k.size = sectors;
extent_ptr_append(e, (struct bch_extent_ptr) { 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); bch2_disk_reservation_put(c, &res);
dst->i_sectors += sectors; dst->bi_sectors += sectors;
logical += sectors; logical += sectors;
physical += sectors; physical += sectors;
length -= sectors; length -= sectors;
@ -453,7 +453,7 @@ static void copy_dir(struct copy_fs_state *s,
stat.st_mode, stat.st_rdev); stat.st_mode, stat.st_rdev);
if (dst_inum) if (dst_inum)
*dst_inum = inode.inum; *dst_inum = inode.bi_inum;
copy_times(c, &inode, &stat); copy_times(c, &inode, &stat);
copy_xattrs(c, &inode, d->d_name); copy_xattrs(c, &inode, d->d_name);
@ -467,14 +467,14 @@ static void copy_dir(struct copy_fs_state *s,
close(fd); close(fd);
break; break;
case DT_REG: case DT_REG:
inode.i_size = stat.st_size; inode.bi_size = stat.st_size;
fd = xopen(d->d_name, O_RDONLY|O_NOATIME); fd = xopen(d->d_name, O_RDONLY|O_NOATIME);
copy_file(c, &inode, fd, child_path, &s->extents); copy_file(c, &inode, fd, child_path, &s->extents);
close(fd); close(fd);
break; break;
case DT_LNK: case DT_LNK:
inode.i_size = stat.st_size; inode.bi_size = stat.st_size;
copy_link(c, &inode, d->d_name); copy_link(c, &inode, d->d_name);
break; break;
@ -555,7 +555,7 @@ static void reserve_old_fs_space(struct bch_fs *c,
dst = create_file(c, root_inode, "old_migrated_filesystem", dst = create_file(c, root_inode, "old_migrated_filesystem",
0, 0, S_IFREG|0400, 0); 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); ranges_sort_merge(extents);

View File

@ -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_STR_HASH_TYPE(sb, BCH_STR_HASH_SIPHASH);
SET_BCH_SB_ENCODED_EXTENT_MAX_BITS(sb, ilog2(opts.encoded_extent_max)); SET_BCH_SB_ENCODED_EXTENT_MAX_BITS(sb, ilog2(opts.encoded_extent_max));
SET_BCH_SB_POSIX_ACL(sb, 1);
struct timespec now; struct timespec now;
if (clock_gettime(CLOCK_REALTIME, &now)) if (clock_gettime(CLOCK_REALTIME, &now))
die("error getting current time: %m"); die("error getting current time: %m");

View File

@ -1,4 +1,4 @@
#ifndef NO_BCACHEFS_FS #ifdef CONFIG_BCACHEFS_POSIX_ACL
#include "bcachefs.h" #include "bcachefs.h"
@ -8,8 +8,9 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "xattr.h"
#include "acl.h" #include "acl.h"
#include "fs.h"
#include "xattr.h"
/* /*
* Convert from filesystem to in-memory representation. * Convert from filesystem to in-memory representation.
@ -134,9 +135,10 @@ fail:
return ERR_PTR(-EINVAL); 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; int name_index;
char *value = NULL; char *value = NULL;
struct posix_acl *acl; struct posix_acl *acl;
@ -169,14 +171,15 @@ struct posix_acl *bch2_get_acl(struct inode *inode, int type)
kfree(value); kfree(value);
if (!IS_ERR(acl)) if (!IS_ERR(acl))
set_cached_acl(inode, type, acl); set_cached_acl(&inode->v, type, acl);
return 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; int name_index;
void *value = NULL; void *value = NULL;
size_t size = 0; 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: case ACL_TYPE_ACCESS:
name_index = BCH_XATTR_INDEX_POSIX_ACL_ACCESS; name_index = BCH_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl) { if (acl) {
ret = posix_acl_equiv_mode(acl, &inode->i_mode); ret = posix_acl_equiv_mode(acl, &inode->v.i_mode);
if (ret < 0) if (ret < 0)
return ret; return ret;
else { else {
inode->i_ctime = current_fs_time(inode->i_sb); inode->v.i_ctime =
mark_inode_dirty(inode); current_fs_time(inode->v.i_sb);
mark_inode_dirty(&inode->v);
if (ret == 0) if (ret == 0)
acl = NULL; acl = NULL;
} }
@ -200,7 +204,7 @@ int bch2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
case ACL_TYPE_DEFAULT: case ACL_TYPE_DEFAULT:
name_index = BCH_XATTR_INDEX_POSIX_ACL_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; return acl ? -EACCES : 0;
break; break;
@ -222,9 +226,9 @@ int bch2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
ret = -E2BIG; ret = -E2BIG;
if (!ret) if (!ret)
set_cached_acl(inode, type, acl); set_cached_acl(&inode->v, type, acl);
return ret; return ret;
} }
#endif /* NO_BCACHEFS_FS */ #endif /* CONFIG_BCACHEFS_POSIX_ACL */

View File

@ -1,7 +1,7 @@
#ifndef _BCACHEFS_ACL_H #ifndef _BCACHEFS_ACL_H
#define _BCACHEFS_ACL_H #define _BCACHEFS_ACL_H
#ifndef NO_BCACHEFS_FS #ifdef CONFIG_BCACHEFS_POSIX_ACL
#define BCH_ACL_VERSION 0x0001 #define BCH_ACL_VERSION 0x0001
@ -54,6 +54,13 @@ struct posix_acl;
extern struct posix_acl *bch2_get_acl(struct inode *, int); extern struct posix_acl *bch2_get_acl(struct inode *, int);
extern int bch2_set_acl(struct inode *, struct posix_acl *, 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 */ #endif /* _BCACHEFS_ACL_H */

View File

@ -367,7 +367,7 @@ struct bch_dev {
uuid_le uuid; uuid_le uuid;
char name[BDEVNAME_SIZE]; char name[BDEVNAME_SIZE];
struct bcache_superblock disk_sb; struct bch_sb_handle disk_sb;
int sb_write_error; int sb_write_error;
struct bch_devs_mask self; struct bch_devs_mask self;
@ -445,6 +445,7 @@ struct bch_dev {
* won't automatically reattach). * won't automatically reattach).
*/ */
enum { enum {
BCH_FS_ALLOC_READ_DONE,
BCH_FS_INITIAL_GC_DONE, BCH_FS_INITIAL_GC_DONE,
BCH_FS_EMERGENCY_RO, BCH_FS_EMERGENCY_RO,
BCH_FS_WRITE_DISABLE_COMPLETE, BCH_FS_WRITE_DISABLE_COMPLETE,
@ -517,14 +518,11 @@ struct bch_fs {
uuid_le uuid; uuid_le uuid;
uuid_le user_uuid; uuid_le user_uuid;
u16 block_size;
u16 btree_node_size;
u16 encoded_extent_max; u16 encoded_extent_max;
u8 nr_devices; u8 nr_devices;
u8 clean; u8 clean;
u8 str_hash_type;
u8 encryption_type; u8 encryption_type;
u64 time_base_lo; 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) 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 */ #endif /* _BCACHEFS_H */

View File

@ -9,45 +9,29 @@
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <linux/uuid.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##_OFFSET = offset; \
static const unsigned name##_BITS = (end - 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) \ 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)); \ ~(~0ULL << (end - offset)); \
} \ } \
\ \
static inline void SET_##name(type *k, __u64 v) \ 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 &= ~(~(~0ULL << (end - offset)) << offset); \
new |= (v & ~(~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) \ #define LE16_BITMASK(n, t, f, o, e) LE_BITMASK(16, n, t, f, o, e)
static const unsigned name##_OFFSET = offset; \ #define LE32_BITMASK(n, t, f, o, e) LE_BITMASK(32, n, t, f, o, e)
static const unsigned name##_BITS = (end - offset); \ #define LE64_BITMASK(n, t, f, o, e) LE_BITMASK(64, n, t, f, o, e)
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); \
}
struct bkey_format { struct bkey_format {
__u8 key_u64s; __u8 key_u64s;
@ -592,9 +576,9 @@ enum bch_inode_types {
struct bch_inode { struct bch_inode {
struct bch_val v; struct bch_val v;
__le64 i_hash_seed; __le64 bi_hash_seed;
__le32 i_flags; __le32 bi_flags;
__le16 i_mode; __le16 bi_mode;
__u8 fields[0]; __u8 fields[0];
} __attribute__((packed, aligned(8))); } __attribute__((packed, aligned(8)));
BKEY_VAL_TYPE(inode, BCH_INODE_FS); BKEY_VAL_TYPE(inode, BCH_INODE_FS);
@ -602,24 +586,23 @@ BKEY_VAL_TYPE(inode, BCH_INODE_FS);
struct bch_inode_generation { struct bch_inode_generation {
struct bch_val v; struct bch_val v;
__le32 i_generation; __le32 bi_generation;
__le32 pad; __le32 pad;
} __attribute__((packed, aligned(8))); } __attribute__((packed, aligned(8)));
BKEY_VAL_TYPE(inode_generation, BCH_INODE_GENERATION); BKEY_VAL_TYPE(inode_generation, BCH_INODE_GENERATION);
#define BCH_INODE_FIELDS() \ #define BCH_INODE_FIELDS() \
BCH_INODE_FIELD(i_atime, 64) \ BCH_INODE_FIELD(bi_atime, 64) \
BCH_INODE_FIELD(i_ctime, 64) \ BCH_INODE_FIELD(bi_ctime, 64) \
BCH_INODE_FIELD(i_mtime, 64) \ BCH_INODE_FIELD(bi_mtime, 64) \
BCH_INODE_FIELD(i_otime, 64) \ BCH_INODE_FIELD(bi_otime, 64) \
BCH_INODE_FIELD(i_size, 64) \ BCH_INODE_FIELD(bi_size, 64) \
BCH_INODE_FIELD(i_sectors, 64) \ BCH_INODE_FIELD(bi_sectors, 64) \
BCH_INODE_FIELD(i_uid, 32) \ BCH_INODE_FIELD(bi_uid, 32) \
BCH_INODE_FIELD(i_gid, 32) \ BCH_INODE_FIELD(bi_gid, 32) \
BCH_INODE_FIELD(i_nlink, 32) \ BCH_INODE_FIELD(bi_nlink, 32) \
BCH_INODE_FIELD(i_generation, 32) \ BCH_INODE_FIELD(bi_generation, 32) \
BCH_INODE_FIELD(i_dev, 32) BCH_INODE_FIELD(bi_dev, 32)
enum { enum {
/* /*
@ -650,8 +633,8 @@ enum {
#define BCH_INODE_I_SECTORS_DIRTY (1 << __BCH_INODE_I_SECTORS_DIRTY) #define BCH_INODE_I_SECTORS_DIRTY (1 << __BCH_INODE_I_SECTORS_DIRTY)
#define BCH_INODE_HAS_XATTRS (1 << __BCH_INODE_HAS_XATTRS) #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_STR_HASH, struct bch_inode, bi_flags, 20, 24);
LE32_BITMASK(INODE_NR_FIELDS, struct bch_inode, i_flags, 24, 32); LE32_BITMASK(INODE_NR_FIELDS, struct bch_inode, bi_flags, 24, 32);
struct bch_inode_blockdev { struct bch_inode_blockdev {
struct bch_val v; struct bch_val v;
@ -960,6 +943,8 @@ struct bch_sb {
* algorithm in use, if/when we get more than one * 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_INITIALIZED, struct bch_sb, flags[0], 0, 1);
LE64_BITMASK(BCH_SB_CLEAN, struct bch_sb, flags[0], 1, 2); 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); 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_META_REPLICAS_WANT, struct bch_sb, flags[0], 48, 52);
LE64_BITMASK(BCH_SB_DATA_REPLICAS_WANT, struct bch_sb, flags[0], 52, 56); 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_STR_HASH_TYPE, struct bch_sb, flags[1], 0, 4);
LE64_BITMASK(BCH_SB_COMPRESSION_TYPE, struct bch_sb, flags[1], 4, 8); LE64_BITMASK(BCH_SB_COMPRESSION_TYPE, struct bch_sb, flags[1], 4, 8);

View File

@ -51,7 +51,7 @@ static inline bool btree_node_hashed(struct btree *b)
static inline size_t btree_bytes(struct bch_fs *c) 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) 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) 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) #define BTREE_SPLIT_THRESHOLD(c) (btree_blocks(c) * 3 / 4)

View File

@ -116,7 +116,7 @@ static u8 bch2_btree_mark_key(struct bch_fs *c, enum bkey_type type,
{ {
switch (type) { switch (type) {
case BKEY_TYPE_BTREE: 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; return 0;
case BKEY_TYPE_EXTENTS: case BKEY_TYPE_EXTENTS:
bch2_gc_mark_key(c, k, k.k->size, false, flags); 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) for_each_pending_btree_node_free(c, as, d)
if (d->index_update_done) if (d->index_update_done)
__bch2_mark_key(c, bkey_i_to_s_c(&d->key), __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, &stats, 0,
BCH_BUCKET_MARK_MAY_MAKE_UNAVAILABLE); BCH_BUCKET_MARK_MAY_MAKE_UNAVAILABLE);
/* /*

View File

@ -916,7 +916,7 @@ static int validate_bset(struct bch_fs *c, struct btree *b,
return 0; 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"); btree_node_error(c, b, "bset past end of btree node");
i->u64s = 0; i->u64s = 0;
return 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")) if (bch2_meta_read_fault("btree"))
goto err; goto err;
while (b->written < c->sb.btree_node_size) { while (b->written < c->opts.btree_node_size) {
unsigned sectors, whiteout_u64s = 0; unsigned sectors, whiteout_u64s = 0;
if (!b->written) { 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(!list_empty(&b->write_blocked));
BUG_ON((b->will_make_reachable != NULL) != !b->written); 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(bset_written(b, btree_bset_last(b)));
BUG_ON(le64_to_cpu(b->data->magic) != bset_magic(c)); BUG_ON(le64_to_cpu(b->data->magic) != bset_magic(c));
BUG_ON(memcmp(&b->data->format, &b->format, sizeof(b->format))); 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, memset(data + bytes_to_write, 0,
(sectors_to_write << 9) - bytes_to_write); (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(BSET_BIG_ENDIAN(i) != CPU_BIG_ENDIAN);
BUG_ON(i->seq != b->data->keys.seq); BUG_ON(i->seq != b->data->keys.seq);

View File

@ -181,7 +181,7 @@ found:
*/ */
replicas = bch2_extent_nr_dirty_ptrs(k); replicas = bch2_extent_nr_dirty_ptrs(k);
if (replicas) 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 * 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 }; struct bch_fs_usage tmp = { 0 };
bch2_mark_key(c, bkey_i_to_s_c(&d->key), 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_node(b)
: gc_pos_btree_root(as->btree_id), : gc_pos_btree_root(as->btree_id),
&tmp, 0); &tmp, 0);
@ -285,7 +285,7 @@ static void bch2_btree_node_free_ondisk(struct bch_fs *c,
BUG_ON(!pending->index_update_done); BUG_ON(!pending->index_update_done);
bch2_mark_key(c, bkey_i_to_s_c(&pending->key), 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), gc_phase(GC_PHASE_PENDING_DELETE),
&stats, 0); &stats, 0);
/* /*
@ -337,7 +337,7 @@ static struct btree *__bch2_btree_node_alloc(struct bch_fs *c,
retry: retry:
/* alloc_sectors is weird, I suppose */ /* alloc_sectors is weird, I suppose */
bkey_extent_init(&tmp.k); 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, ob = bch2_alloc_sectors(c, &c->btree_write_point,
bkey_i_to_extent(&tmp.k), bkey_i_to_extent(&tmp.k),
@ -347,7 +347,7 @@ retry:
if (IS_ERR(ob)) if (IS_ERR(ob))
return ERR_CAST(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); bch2_open_bucket_put(c, ob);
goto retry; goto retry;
} }
@ -491,7 +491,7 @@ static struct btree_reserve *bch2_btree_reserve_get(struct bch_fs *c,
struct btree_reserve *reserve; struct btree_reserve *reserve;
struct btree *b; struct btree *b;
struct disk_reservation disk_res = { 0, 0 }; 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| int ret, disk_res_flags = BCH_DISK_RESERVATION_GC_LOCK_HELD|
BCH_DISK_RESERVATION_METADATA; 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_btree_set_root_inmem(c, b);
bch2_mark_key(c, bkey_i_to_s_c(&b->key), 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), gc_pos_btree_root(b->btree_id),
&stats, 0); &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)) if (bkey_extent_is_data(&insert->k))
bch2_mark_key(c, bkey_i_to_s_c(insert), 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); gc_pos_btree_node(b), &stats, 0);
while ((k = bch2_btree_node_iter_peek_all(node_iter, b)) && while ((k = bch2_btree_node_iter_peek_all(node_iter, b)) &&
@ -1901,7 +1901,7 @@ retry:
bch2_btree_node_lock_write(b, &iter); bch2_btree_node_lock_write(b, &iter);
bch2_mark_key(c, bkey_i_to_s_c(&new_key->k_i), 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), gc_pos_btree_root(b->btree_id),
&stats, 0); &stats, 0);
bch2_btree_node_free_index(as, NULL, bch2_btree_node_free_index(as, NULL,

View File

@ -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) + unsigned used = bset_byte_offset(b, vstruct_end(i)) / sizeof(u64) +
b->whiteout_u64s + b->whiteout_u64s +
b->uncompacted_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); EBUG_ON(used > total);

View File

@ -469,6 +469,7 @@ static void bch2_mark_pointer(struct bch_fs *c,
* checked the gen * checked the gen
*/ */
if (gen_after(new.gen, ptr->gen)) { if (gen_after(new.gen, ptr->gen)) {
BUG_ON(!test_bit(BCH_FS_ALLOC_READ_DONE, &c->flags));
EBUG_ON(!ptr->cached && EBUG_ON(!ptr->cached &&
test_bit(JOURNAL_REPLAY_DONE, &c->journal.flags)); test_bit(JOURNAL_REPLAY_DONE, &c->journal.flags));
return; return;

View File

@ -417,9 +417,9 @@ int bch2_request_key(struct bch_sb *sb, struct bch_key *key)
} }
#endif #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_sb_field_crypt *crypt,
struct bch_key *key) struct bch_key *key)
{ {
struct bch_encrypted_key sb_key = crypt->key; struct bch_encrypted_key sb_key = crypt->key;
struct bch_key user_key; struct bch_key user_key;

View File

@ -40,6 +40,9 @@ struct bch_csum bch2_checksum_bio(struct bch_fs *, unsigned,
void bch2_encrypt_bio(struct bch_fs *, unsigned, void bch2_encrypt_bio(struct bch_fs *, unsigned,
struct nonce, struct bio *); 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_disable_encryption(struct bch_fs *);
int bch2_enable_encryption(struct bch_fs *, bool); int bch2_enable_encryption(struct bch_fs *, bool);

View File

@ -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 it's only one block, don't bother trying to compress: */
if (*compression_type != BCH_COMPRESSION_NONE && 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)) !__bio_compress(c, dst, dst_len, src, src_len, compression_type))
goto out; goto out;

View File

@ -192,25 +192,23 @@ static void dirent_copy_target(struct bkey_i_dirent *dst,
dst->v.d_type = src.v->d_type; dst->v.d_type = src.v->d_type;
} }
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) 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, int bch2_dirent_rename(struct bch_fs *c,
struct inode *src_dir, const struct qstr *src_name, struct bch_inode_info *src_dir, const struct qstr *src_name,
struct inode *dst_dir, const struct qstr *dst_name, struct bch_inode_info *dst_dir, const struct qstr *dst_name,
u64 *journal_seq, enum bch_rename_mode mode) 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 btree_iter src_iter, dst_iter, whiteout_iter;
struct bkey_s_c old_src, old_dst; struct bkey_s_c old_src, old_dst;
struct bkey delete; struct bkey delete;
struct bkey_i_dirent *new_src = NULL, *new_dst = NULL; struct bkey_i_dirent *new_src = NULL, *new_dst = NULL;
struct bpos src_pos = bch2_dirent_pos(src_ei, src_name); struct bpos src_pos = bch2_dirent_pos(src_dir, src_name);
struct bpos dst_pos = bch2_dirent_pos(dst_ei, dst_name); struct bpos dst_pos = bch2_dirent_pos(dst_dir, dst_name);
bool need_whiteout; bool need_whiteout;
int ret = -ENOMEM; int ret = -ENOMEM;
@ -241,13 +239,13 @@ retry:
* in bch_hash_set) - we never move existing dirents to different slot: * in bch_hash_set) - we never move existing dirents to different slot:
*/ */
old_src = bch2_hash_lookup_at(bch2_dirent_hash_desc, old_src = bch2_hash_lookup_at(bch2_dirent_hash_desc,
&src_ei->str_hash, &src_dir->ei_str_hash,
&src_iter, src_name); &src_iter, src_name);
if ((ret = btree_iter_err(old_src))) if ((ret = btree_iter_err(old_src)))
goto err; goto err;
ret = bch2_hash_needs_whiteout(bch2_dirent_hash_desc, ret = bch2_hash_needs_whiteout(bch2_dirent_hash_desc,
&src_ei->str_hash, &src_dir->ei_str_hash,
&whiteout_iter, &src_iter); &whiteout_iter, &src_iter);
if (ret < 0) if (ret < 0)
goto err; goto err;
@ -261,7 +259,7 @@ retry:
old_dst = mode == BCH_RENAME old_dst = mode == BCH_RENAME
? bch2_hash_hole_at(bch2_dirent_hash_desc, &dst_iter) ? bch2_hash_hole_at(bch2_dirent_hash_desc, &dst_iter)
: bch2_hash_lookup_at(bch2_dirent_hash_desc, : bch2_hash_lookup_at(bch2_dirent_hash_desc,
&dst_ei->str_hash, &dst_dir->ei_str_hash,
&dst_iter, dst_name); &dst_iter, dst_name);
if ((ret = btree_iter_err(old_dst))) if ((ret = btree_iter_err(old_dst)))
goto err; 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, int bch2_readdir(struct bch_fs *c, struct file *file,
struct dir_context *ctx) struct dir_context *ctx)
{ {
struct inode *inode = file_inode(file); struct bch_inode_info *inode = file_bch_inode(file);
struct btree_iter iter; struct btree_iter iter;
struct bkey_s_c k; struct bkey_s_c k;
struct bkey_s_c_dirent dirent; 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)) if (!dir_emit_dots(file, ctx))
return 0; return 0;
pr_debug("listing for %lu from %llu", inode->i_ino, ctx->pos);
for_each_btree_key(&iter, c, BTREE_ID_DIRENTS, 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) if (k.k->type != BCH_DIRENT)
continue; continue;
dirent = bkey_s_c_to_dirent(k); dirent = bkey_s_c_to_dirent(k);
pr_debug("saw %llu:%llu (%s) -> %llu", if (bkey_cmp(k.k->p, POS(inode->v.i_ino, ctx->pos)) < 0)
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)
continue; continue;
if (k.k->p.inode > inode->i_ino) if (k.k->p.inode > inode->v.i_ino)
break; break;
len = bch2_dirent_name_bytes(dirent); 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 * XXX: dir_emit() can fault and block, while we're holding
* locks * locks

View File

@ -11,6 +11,7 @@ struct file;
struct dir_context; struct dir_context;
struct bch_fs; struct bch_fs;
struct bch_hash_info; struct bch_hash_info;
struct bch_inode_info;
unsigned bch2_dirent_name_bytes(struct bkey_s_c_dirent); unsigned bch2_dirent_name_bytes(struct bkey_s_c_dirent);
int bch2_dirent_create(struct bch_fs *c, u64, const struct bch_hash_info *, 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 *, int bch2_dirent_rename(struct bch_fs *,
struct inode *, const struct qstr *, struct bch_inode_info *, const struct qstr *,
struct inode *, const struct qstr *, struct bch_inode_info *, const struct qstr *,
u64 *, enum bch_rename_mode); u64 *, enum bch_rename_mode);
u64 bch2_dirent_lookup(struct bch_fs *, u64, const struct bch_hash_info *, u64 bch2_dirent_lookup(struct bch_fs *, u64, const struct bch_hash_info *,

View File

@ -575,7 +575,7 @@ static const char *bch2_btree_ptr_invalid(const struct bch_fs *c,
extent_for_each_ptr_crc(e, ptr, crc) { extent_for_each_ptr_crc(e, ptr, crc) {
reason = extent_ptr_invalid(c, e, ptr, reason = extent_ptr_invalid(c, e, ptr,
c->sb.btree_node_size, c->opts.btree_node_size,
true); true);
if (reason) if (reason)
return reason; return reason;
@ -610,6 +610,9 @@ static void btree_ptr_debugcheck(struct bch_fs *c, struct btree *b,
g = PTR_BUCKET(ca, ptr); g = PTR_BUCKET(ca, ptr);
replicas++; replicas++;
if (!test_bit(BCH_FS_ALLOC_READ_DONE, &c->flags))
continue;
err = "stale"; err = "stale";
if (ptr_stale(ca, ptr)) if (ptr_stale(ca, ptr))
goto err; goto err;

File diff suppressed because it is too large Load Diff

View File

@ -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_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); long bch2_fallocate_dispatch(struct file *, int, loff_t, loff_t);
loff_t bch2_llseek(struct file *, loff_t, int); loff_t bch2_llseek(struct file *, loff_t, int);
@ -38,55 +38,55 @@ int bch2_migrate_page(struct address_space *, struct page *,
struct i_sectors_hook { struct i_sectors_hook {
struct extent_insert_hook hook; struct extent_insert_hook hook;
s64 sectors; s64 sectors;
struct bch_inode_info *ei; struct bch_inode_info *inode;
}; };
struct bchfs_write_op { struct bchfs_write_op {
struct bch_inode_info *ei; struct bch_inode_info *inode;
s64 sectors_added; s64 sectors_added;
bool is_dio; bool is_dio;
u64 new_i_size; u64 new_i_size;
/* must be last: */ /* must be last: */
struct bch_write_op op; struct bch_write_op op;
}; };
struct bch_writepage_io { struct bch_writepage_io {
struct closure cl; struct closure cl;
/* must be last: */ /* must be last: */
struct bchfs_write_op op; struct bchfs_write_op op;
}; };
extern struct bio_set *bch2_writepage_bioset; extern struct bio_set *bch2_writepage_bioset;
struct dio_write { struct dio_write {
struct closure cl; struct closure cl;
struct kiocb *req; struct kiocb *req;
struct bch_fs *c; struct bch_fs *c;
long written; long written;
long error; long error;
loff_t offset; loff_t offset;
struct disk_reservation res; struct disk_reservation res;
struct iovec *iovec; struct iovec *iovec;
struct iovec inline_vecs[UIO_FASTIOV]; struct iovec inline_vecs[UIO_FASTIOV];
struct iov_iter iter; struct iov_iter iter;
struct mm_struct *mm; struct mm_struct *mm;
/* must be last: */ /* must be last: */
struct bchfs_write_op iop; struct bchfs_write_op iop;
}; };
extern struct bio_set *bch2_dio_write_bioset; extern struct bio_set *bch2_dio_write_bioset;
struct dio_read { struct dio_read {
struct closure cl; struct closure cl;
struct kiocb *req; struct kiocb *req;
long ret; long ret;
struct bch_read_bio rbio; struct bch_read_bio rbio;
}; };
extern struct bio_set *bch2_dio_read_bioset; extern struct bio_set *bch2_dio_read_bioset;

254
libbcachefs/fs-ioctl.c Normal file
View 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
View 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 */

File diff suppressed because it is too large Load Diff

View File

@ -7,30 +7,35 @@
#include <linux/stat.h> #include <linux/stat.h>
struct bch_inode_info { struct bch_inode_info {
struct inode vfs_inode; struct inode v;
struct mutex update_lock; struct mutex ei_update_lock;
u64 journal_seq; 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 * these are updated whenever we update the inode in the btree - for
* e.g. fsync * e.g. fsync
*/ */
u64 i_size; u64 ei_size;
u32 i_flags; u32 ei_flags;
atomic_long_t i_sectors_dirty_count; atomic_long_t ei_sectors_dirty_count;
atomic64_t i_sectors; 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) \ #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) static inline u8 mode_to_type(umode_t mode)
{ {

View File

@ -67,7 +67,7 @@ static int reattach_inode(struct bch_fs *c,
snprintf(name_buf, sizeof(name_buf), "%llu", inum); snprintf(name_buf, sizeof(name_buf), "%llu", inum);
name = (struct qstr) QSTR(name_buf); name = (struct qstr) QSTR(name_buf);
lostfound_inode->i_nlink++; lostfound_inode->bi_nlink++;
bch2_inode_pack(&packed, lostfound_inode); bch2_inode_pack(&packed, lostfound_inode);
@ -80,7 +80,7 @@ static int reattach_inode(struct bch_fs *c,
return ret; return ret;
} }
ret = bch2_dirent_create(c, lostfound_inode->inum, ret = bch2_dirent_create(c, lostfound_inode->bi_inum,
&lostfound_hash_info, &lostfound_hash_info,
DT_DIR, &name, inum, NULL, DT_DIR, &name, inum, NULL,
BTREE_INSERT_NOFAIL); BTREE_INSERT_NOFAIL);
@ -263,9 +263,9 @@ static int check_extents(struct bch_fs *c)
"extent type %u for missing inode %llu", "extent type %u for missing inode %llu",
k.k->type, k.k->p.inode) || k.k->type, k.k->p.inode) ||
fsck_err_on(w.have_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", "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); ret = bch2_btree_delete_at(&iter, 0);
if (ret) if (ret)
goto err; goto err;
@ -274,18 +274,18 @@ static int check_extents(struct bch_fs *c)
unfixable_fsck_err_on(w.first_this_inode && unfixable_fsck_err_on(w.first_this_inode &&
w.have_inode && w.have_inode &&
!(w.inode.i_flags & BCH_INODE_I_SECTORS_DIRTY) && !(w.inode.bi_flags & BCH_INODE_I_SECTORS_DIRTY) &&
w.inode.i_sectors != w.inode.bi_sectors !=
(i_sectors = bch2_count_inode_sectors(c, w.cur_inum)), (i_sectors = bch2_count_inode_sectors(c, w.cur_inum)),
c, "i_sectors wrong: got %llu, should be %llu", 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 && 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->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", "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: err:
fsck_err: fsck_err:
@ -324,9 +324,9 @@ static int check_dirents(struct bch_fs *c)
"dirent in nonexisting directory:\n%s", "dirent in nonexisting directory:\n%s",
bch2_bkey_val_to_text(c, BTREE_ID_DIRENTS, bch2_bkey_val_to_text(c, BTREE_ID_DIRENTS,
buf, sizeof(buf), k)) || 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", "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, bch2_bkey_val_to_text(c, BTREE_ID_DIRENTS,
buf, sizeof(buf), k))) { buf, sizeof(buf), k))) {
ret = bch2_btree_delete_at(&iter, 0); 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 && if (fsck_err_on(have_target &&
d.v->d_type != 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", "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, bch2_bkey_val_to_text(c, BTREE_ID_DIRENTS,
buf, sizeof(buf), k))) { buf, sizeof(buf), k))) {
struct bkey_i_dirent *n; 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); 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, ret = bch2_btree_insert_at(c, NULL, NULL, NULL,
BTREE_INSERT_NOFAIL, 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")) if (fsck_err_on(ret, c, "root directory missing"))
goto create_root; 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")) "root inode not a directory"))
goto create_root; goto create_root;
@ -494,7 +494,7 @@ fsck_err:
return ret; return ret;
create_root: create_root:
bch2_inode_init(c, root_inode, 0, 0, S_IFDIR|S_IRWXU|S_IRUGO|S_IXUGO, 0); 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); 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")) if (fsck_err_on(ret, c, "lost+found missing"))
goto create_lostfound; 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")) "lost+found inode not a directory"))
goto create_lostfound; goto create_lostfound;
@ -536,7 +536,7 @@ static int check_lostfound(struct bch_fs *c,
fsck_err: fsck_err:
return ret; return ret;
create_lostfound: create_lostfound:
root_inode->i_nlink++; root_inode->bi_nlink++;
bch2_inode_pack(&packed, root_inode); bch2_inode_pack(&packed, root_inode);
@ -553,7 +553,7 @@ create_lostfound:
return ret; return ret;
ret = bch2_dirent_create(c, BCACHEFS_ROOT_INO, &root_hash_info, DT_DIR, 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); BTREE_INSERT_NOFAIL);
if (ret) if (ret)
return ret; return ret;
@ -711,7 +711,7 @@ up:
for_each_btree_key(&iter, c, BTREE_ID_INODES, POS_MIN, 0, k) { for_each_btree_key(&iter, c, BTREE_ID_INODES, POS_MIN, 0, k) {
if (k.k->type != BCH_INODE_FS || 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; continue;
if (fsck_err_on(!inode_bitmap_test(&dirs_done, k.k->p.inode), c, 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)) inode.k->p.inode))
return ret; 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, fsck_err_on(i_nlink < link.count, c,
"inode %llu i_link too small (%u < %u, type %i)", "inode %llu i_link too small (%u < %u, type %i)",
inode.k->p.inode, i_nlink, 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: */ /* 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, need_fsck_err_on(link.count > 1, c,
"directory %llu with multiple hardlinks: %u", "directory %llu with multiple hardlinks: %u",
inode.k->p.inode, link.count); 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", "but found orphaned inode %llu",
inode.k->p.inode); 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, bch2_empty_dir(c, inode.k->p.inode), c,
"non empty directory with link count 0, " "non empty directory with link count 0, "
"inode nlink %u, dir links found %u", "inode nlink %u, dir links found %u",
@ -897,7 +897,7 @@ static int bch2_gc_do_inode(struct bch_fs *c,
return ret; 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, fsck_err_on(c->sb.clean, c,
"filesystem marked clean, " "filesystem marked clean, "
"but inode %llu has i_size dirty", "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, 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); NULL, NULL);
if (ret) { if (ret) {
bch_err(c, "error in fs gc: error %i " 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 * We truncated without our normal sector accounting hook, just
* make sure we recalculate it: * 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; do_update = true;
} }
if (u.i_flags & BCH_INODE_I_SECTORS_DIRTY) { if (u.bi_flags & BCH_INODE_I_SECTORS_DIRTY) {
s64 sectors; s64 sectors;
fsck_err_on(c->sb.clean, c, fsck_err_on(c->sb.clean, c,
@ -948,8 +948,8 @@ static int bch2_gc_do_inode(struct bch_fs *c,
return sectors; return sectors;
} }
u.i_sectors = sectors; u.bi_sectors = sectors;
u.i_flags &= ~BCH_INODE_I_SECTORS_DIRTY; u.bi_flags &= ~BCH_INODE_I_SECTORS_DIRTY;
do_update = true; do_update = true;
} }
@ -958,12 +958,12 @@ static int bch2_gc_do_inode(struct bch_fs *c,
"filesystem marked clean, " "filesystem marked clean, "
"but inode %llu has wrong i_nlink " "but inode %llu has wrong i_nlink "
"(type %u i_nlink %u, should be %u)", "(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); i_nlink, real_i_nlink);
bch_verbose(c, "setting inode %llu nlinks from %u to %u", bch_verbose(c, "setting inode %llu nlinks from %u to %u",
inode.k->p.inode, i_nlink, real_i_nlink); 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; do_update = true;
} }

View File

@ -2,6 +2,7 @@
#include "bcachefs.h" #include "bcachefs.h"
#include "bkey_methods.h" #include "bkey_methods.h"
#include "btree_update.h" #include "btree_update.h"
#include "error.h"
#include "extents.h" #include "extents.h"
#include "inode.h" #include "inode.h"
#include "io.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; unsigned nr_fields = 0, last_nonzero_fieldnr = 0;
bkey_inode_init(&packed->inode.k_i); bkey_inode_init(&packed->inode.k_i);
packed->inode.k.p.inode = inode->inum; packed->inode.k.p.inode = inode->bi_inum;
packed->inode.v.i_hash_seed = inode->i_hash_seed; packed->inode.v.bi_hash_seed = inode->bi_hash_seed;
packed->inode.v.i_flags = cpu_to_le32(inode->i_flags); packed->inode.v.bi_flags = cpu_to_le32(inode->bi_flags);
packed->inode.v.i_mode = cpu_to_le16(inode->i_mode); packed->inode.v.bi_mode = cpu_to_le16(inode->bi_mode);
#define BCH_INODE_FIELD(_name, _bits) \ #define BCH_INODE_FIELD(_name, _bits) \
out += inode_encode_field(out, end, 0, inode->_name); \ 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), int ret = bch2_inode_unpack(inode_i_to_s_c(&packed->inode),
&unpacked); &unpacked);
BUG_ON(ret); BUG_ON(ret);
BUG_ON(unpacked.inum != inode->inum); BUG_ON(unpacked.bi_inum != inode->bi_inum);
BUG_ON(unpacked.i_hash_seed != inode->i_hash_seed); BUG_ON(unpacked.bi_hash_seed != inode->bi_hash_seed);
BUG_ON(unpacked.i_mode != inode->i_mode); BUG_ON(unpacked.bi_mode != inode->bi_mode);
#define BCH_INODE_FIELD(_name, _bits) BUG_ON(unpacked._name != inode->_name); #define BCH_INODE_FIELD(_name, _bits) BUG_ON(unpacked._name != inode->_name);
BCH_INODE_FIELDS() BCH_INODE_FIELDS()
@ -143,10 +144,10 @@ int bch2_inode_unpack(struct bkey_s_c_inode inode,
unsigned fieldnr = 0, field_bits; unsigned fieldnr = 0, field_bits;
int ret; int ret;
unpacked->inum = inode.k->p.inode; unpacked->bi_inum = inode.k->p.inode;
unpacked->i_hash_seed = inode.v->i_hash_seed; unpacked->bi_hash_seed = inode.v->bi_hash_seed;
unpacked->i_flags = le32_to_cpu(inode.v->i_flags); unpacked->bi_flags = le32_to_cpu(inode.v->bi_flags);
unpacked->i_mode = le16_to_cpu(inode.v->i_mode); unpacked->bi_mode = le16_to_cpu(inode.v->bi_mode);
#define BCH_INODE_FIELD(_name, _bits) \ #define BCH_INODE_FIELD(_name, _bits) \
if (fieldnr++ == INODE_NR_FIELDS(inode.v)) { \ if (fieldnr++ == INODE_NR_FIELDS(inode.v)) { \
@ -231,7 +232,7 @@ static void bch2_inode_to_text(struct bch_fs *c, char *buf,
break; break;
} }
scnprintf(buf, size, "i_size %llu", unpacked.i_size); scnprintf(buf, size, "i_size %llu", unpacked.bi_size);
break; 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)); memset(inode_u, 0, sizeof(*inode_u));
/* ick */ /* ick */
inode_u->i_flags |= c->sb.str_hash_type << INODE_STR_HASH_OFFSET; inode_u->bi_flags |= c->opts.str_hash << INODE_STR_HASH_OFFSET;
get_random_bytes(&inode_u->i_hash_seed, sizeof(inode_u->i_hash_seed)); get_random_bytes(&inode_u->bi_hash_seed, sizeof(inode_u->bi_hash_seed));
inode_u->i_mode = mode; inode_u->bi_mode = mode;
inode_u->i_uid = uid; inode_u->bi_uid = uid;
inode_u->i_gid = gid; inode_u->bi_gid = gid;
inode_u->i_dev = rdev; inode_u->bi_dev = rdev;
inode_u->i_atime = now; inode_u->bi_atime = now;
inode_u->i_mtime = now; inode_u->bi_mtime = now;
inode_u->i_ctime = now; inode_u->bi_ctime = now;
inode_u->i_otime = now; inode_u->bi_otime = now;
} }
int bch2_inode_create(struct bch_fs *c, struct bch_inode_unpacked *inode_u, int bch2_inode_create(struct bch_fs *c, struct bch_inode_unpacked *inode_u,
@ -287,7 +288,7 @@ again:
while (1) { while (1) {
struct bkey_s_c k = bch2_btree_iter_peek_with_holes(&iter); 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); ret = btree_iter_err(k);
if (ret) { if (ret) {
@ -308,11 +309,11 @@ again:
case BCH_INODE_GENERATION: { case BCH_INODE_GENERATION: {
struct bkey_s_c_inode_generation g = struct bkey_s_c_inode_generation g =
bkey_s_c_to_inode_generation(k); 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: */ /* fallthrough: */
} }
default: default:
inode_u->i_generation = i_generation; inode_u->bi_generation = bi_generation;
bch2_inode_pack(&inode_p, inode_u); bch2_inode_pack(&inode_p, inode_u);
inode_p.inode.k.p = k.k->p; inode_p.inode.k.p = k.k->p;
@ -326,7 +327,7 @@ again:
bch2_btree_iter_unlock(&iter); bch2_btree_iter_unlock(&iter);
if (!ret) { if (!ret) {
inode_u->inum = inode_u->bi_inum =
inode_p.inode.k.p.inode; inode_p.inode.k.p.inode;
*hint = inode_p.inode.k.p.inode + 1; *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 * but there could be whiteouts (from hash collisions) that we should
* delete: * 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 * longer needed
*/ */
ret = bch2_btree_delete_range(c, BTREE_ID_DIRENTS, 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); BTREE_ITER_INTENT);
do { do {
struct bkey_s_c k = bch2_btree_iter_peek_with_holes(&iter); 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); ret = btree_iter_err(k);
if (ret) { if (ret) {
@ -406,29 +407,33 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr)
return ret; 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) { switch (k.k->type) {
case BCH_INODE_FS: { case BCH_INODE_FS: {
struct bch_inode_unpacked inode_u; struct bch_inode_unpacked inode_u;
if (!bch2_inode_unpack(bkey_s_c_to_inode(k), &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; break;
} }
case BCH_INODE_GENERATION: { case BCH_INODE_GENERATION: {
struct bkey_s_c_inode_generation g = struct bkey_s_c_inode_generation g =
bkey_s_c_to_inode_generation(k); 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; break;
} }
} }
if (!i_generation) { if (!bi_generation) {
bkey_init(&delete.k); bkey_init(&delete.k);
delete.k.p.inode = inode_nr; delete.k.p.inode = inode_nr;
} else { } else {
bkey_inode_generation_init(&delete.k_i); bkey_inode_generation_init(&delete.k_i);
delete.k.p.inode = inode_nr; 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, 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[] = { struct bch_inode_unpacked *u, test_inodes[] = {
{ {
.i_atime = U64_MAX, .bi_atime = U64_MAX,
.i_ctime = U64_MAX, .bi_ctime = U64_MAX,
.i_mtime = U64_MAX, .bi_mtime = U64_MAX,
.i_otime = U64_MAX, .bi_otime = U64_MAX,
.i_size = U64_MAX, .bi_size = U64_MAX,
.i_sectors = U64_MAX, .bi_sectors = U64_MAX,
.i_uid = U32_MAX, .bi_uid = U32_MAX,
.i_gid = U32_MAX, .bi_gid = U32_MAX,
.i_nlink = U32_MAX, .bi_nlink = U32_MAX,
.i_generation = U32_MAX, .bi_generation = U32_MAX,
.i_dev = U32_MAX, .bi_dev = U32_MAX,
}, },
}; };

View File

@ -6,10 +6,10 @@
extern const struct bkey_ops bch2_bkey_inode_ops; extern const struct bkey_ops bch2_bkey_inode_ops;
struct bch_inode_unpacked { struct bch_inode_unpacked {
u64 inum; u64 bi_inum;
__le64 i_hash_seed; __le64 bi_hash_seed;
u32 i_flags; u32 bi_flags;
u16 i_mode; u16 bi_mode;
#define BCH_INODE_FIELD(_name, _bits) u##_bits _name; #define BCH_INODE_FIELD(_name, _bits) u##_bits _name;
BCH_INODE_FIELDS() BCH_INODE_FIELDS()
@ -22,7 +22,7 @@ struct bkey_inode_buf {
#define BCH_INODE_FIELD(_name, _bits) + 8 + _bits / 8 #define BCH_INODE_FIELD(_name, _bits) + 8 + _bits / 8
u8 _pad[0 + BCH_INODE_FIELDS()]; u8 _pad[0 + BCH_INODE_FIELDS()];
#undef BCH_INODE_FIELD #undef BCH_INODE_FIELD
}; } __attribute__((packed, aligned(8)));
void bch2_inode_pack(struct bkey_inode_buf *, const struct bch_inode_unpacked *); 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 *); int bch2_inode_unpack(struct bkey_s_c_inode, struct bch_inode_unpacked *);

View File

@ -700,11 +700,11 @@ reread: sectors_read = min_t(unsigned,
case JOURNAL_ENTRY_NONE: case JOURNAL_ENTRY_NONE:
if (!saw_bad) if (!saw_bad)
return 0; return 0;
sectors = c->sb.block_size; sectors = c->opts.block_size;
goto next_block; goto next_block;
case JOURNAL_ENTRY_BAD: case JOURNAL_ENTRY_BAD:
saw_bad = true; saw_bad = true;
sectors = c->sb.block_size; sectors = c->opts.block_size;
goto next_block; goto next_block;
default: default:
return ret; return ret;
@ -1192,7 +1192,7 @@ static enum {
j->prev_buf_sectors = j->prev_buf_sectors =
vstruct_blocks_plus(buf->data, c->block_bits, vstruct_blocks_plus(buf->data, c->block_bits,
journal_entry_u64s_reserve(buf)) * journal_entry_u64s_reserve(buf)) *
c->sb.block_size; c->opts.block_size;
BUG_ON(j->prev_buf_sectors > j->cur_buf_sectors); BUG_ON(j->prev_buf_sectors > j->cur_buf_sectors);

View File

@ -66,42 +66,24 @@ const char * const bch2_dev_state[] = {
NULL NULL
}; };
const struct bch_option bch2_opt_table[] = { void bch2_opts_apply(struct bch_opts *dst, struct bch_opts src)
#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)
{ {
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; BCH_OPTS()
i < bch2_opt_table + ARRAY_SIZE(bch2_opt_table); #undef BCH_OPT
i++)
if (!strcmp(name, i->name))
return i - bch2_opt_table;
return -1;
} }
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) { switch (id) {
#define BCH_OPT(_name, ...) \ #define BCH_OPT(_name, ...) \
case Opt_##_name: \ case Opt_##_name: \
return opts->_name; \ return opts->_name; \
BCH_VISIBLE_OPTS() BCH_OPTS()
#undef BCH_OPT #undef BCH_OPT
default: 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) { switch (id) {
#define BCH_OPT(_name, ...) \ #define BCH_OPT(_name, ...) \
case Opt_##_name: \ case Opt_##_name: \
opts->_name = v; \ opt_set(*opts, _name, v); \
break; break;
BCH_VISIBLE_OPTS() BCH_OPTS()
#undef BCH_OPT #undef BCH_OPT
default: 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, * Initial options from superblock - here we don't want any options undefined,
* any options the superblock doesn't specify are set to 0: * 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(); 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) \ if (_sb_opt != NO_SB_OPT) \
opts._name = _sb_opt(sb); opt_set(opts, _name, _sb_opt(sb));
BCH_OPTS() BCH_OPTS()
#undef BCH_OPT #undef BCH_OPT
@ -143,9 +125,41 @@ struct bch_opts bch2_sb_opts(struct bch_sb *sb)
return opts; 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; ssize_t ret;
switch (opt->type) { switch (opt->type) {
@ -190,11 +204,11 @@ int bch2_parse_mount_opts(struct bch_opts *opts, char *options)
if (val) { if (val) {
id = bch2_opt_lookup(name); id = bch2_opt_lookup(name);
if (id < 0) 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) if (ret < 0)
return ret; goto bad_val;
} else { } else {
id = bch2_opt_lookup(name); id = bch2_opt_lookup(name);
v = 1; v = 1;
@ -205,47 +219,31 @@ int bch2_parse_mount_opts(struct bch_opts *opts, char *options)
v = 0; v = 0;
} }
if (id < 0 || if (id < 0)
bch2_opt_table[id].type != BCH_OPT_BOOL) goto bad_opt;
continue;
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; return 0;
} bad_opt:
pr_err("Bad mount option %s", name);
enum bch_opt_id bch2_parse_sysfs_opt(const char *name, const char *val, return -1;
u64 *res) bad_val:
{ pr_err("Invalid value %s for mount option %s", val, name);
int id = bch2_opt_lookup(name); return -1;
int ret; no_val:
pr_err("Mount option %s requires a value", name);
if (id < 0) return -1;
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);
} }

View File

@ -4,6 +4,7 @@
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/sysfs.h>
#include "bcachefs_format.h" #include "bcachefs_format.h"
extern const char * const bch2_error_actions[]; 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 */ /* dummy option, for options that aren't stored in the superblock */
LE64_BITMASK(NO_SB_OPT, struct bch_sb, flags[0], 0, 0); LE64_BITMASK(NO_SB_OPT, struct bch_sb, flags[0], 0, 0);
/** enum opt_mode {
* BCH_OPT(name, mode, sb_opt, type, ...) OPT_INTERNAL,
* OPT_FORMAT,
* @name - name of mount option, sysfs attribute, and struct bch_opts OPT_MOUNT,
* member OPT_RUNTIME,
* };
* @mode - sysfs attr permissions
*
* @sb_option - name of corresponding superblock option
*
* @type - one of OPT_BOOL, OPT_UINT, OPT_STR
*/
enum opt_type { enum opt_type {
BCH_OPT_BOOL, BCH_OPT_BOOL,
@ -49,82 +44,162 @@ enum opt_type {
BCH_OPT_STR, BCH_OPT_STR,
}; };
#define BCH_VISIBLE_OPTS() \ /**
BCH_OPT(errors, 0644, BCH_SB_ERROR_ACTION, \ * BCH_OPT(name, type, in mem type, mode, sb_opt)
s8, OPT_STR(bch2_error_actions)) \ *
BCH_OPT(metadata_replicas, 0444, BCH_SB_META_REPLICAS_WANT,\ * @name - name of mount option, sysfs attribute, and struct bch_opts
s8, OPT_UINT(1, BCH_REPLICAS_MAX)) \ * member
BCH_OPT(data_replicas, 0444, BCH_SB_DATA_REPLICAS_WANT,\ *
s8, OPT_UINT(1, BCH_REPLICAS_MAX)) \ * @mode - when opt may be set
BCH_OPT(metadata_replicas_required, 0444, BCH_SB_META_REPLICAS_REQ,\ *
s8, OPT_UINT(1, BCH_REPLICAS_MAX)) \ * @sb_option - name of corresponding superblock option
BCH_OPT(data_replicas_required, 0444, BCH_SB_DATA_REPLICAS_REQ,\ *
s8, OPT_UINT(1, BCH_REPLICAS_MAX)) \ * @type - one of OPT_BOOL, OPT_UINT, OPT_STR
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)) \ * XXX: add fields for
BCH_OPT(data_checksum, 0644, BCH_SB_DATA_CSUM_TYPE, \ * - default value
s8, OPT_STR(bch2_csum_types)) \ * - helptext
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)) \
#define BCH_OPTS() \ #define BCH_OPTS() \
BCH_OPT(read_only, 0444, NO_SB_OPT, \ BCH_OPT(block_size, u16, OPT_FORMAT, \
s8, OPT_BOOL()) \ OPT_UINT(1, 128), \
BCH_OPT(nostart, 0444, NO_SB_OPT, \ BCH_SB_BLOCK_SIZE, 8) \
s8, OPT_BOOL()) \ BCH_OPT(btree_node_size, u16, OPT_FORMAT, \
BCH_VISIBLE_OPTS() 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 { struct bch_opts {
#define BCH_OPT(_name, _mode, _sb_opt, _bits, ...) \ #define BCH_OPT(_name, _bits, ...) unsigned _name##_defined:1;
_bits _name; 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() BCH_OPTS()
#undef BCH_OPT #undef BCH_OPT
}; };
enum bch_opt_id { #define opt_defined(_opts, _name) ((_opts)._name##_defined)
#define BCH_OPT(_name, ...) \
Opt_##_name,
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 #undef BCH_OPT
bch2_opts_nr
}; };
struct bch_option { struct bch_option {
const char *name; struct attribute attr;
void (*set_sb)(struct bch_sb *, u64); void (*set_sb)(struct bch_sb *, u64);
enum opt_mode mode;
enum opt_type type; enum opt_type type;
union { union {
@ -140,32 +215,12 @@ struct bch_option {
extern const struct bch_option bch2_opt_table[]; extern const struct bch_option bch2_opt_table[];
static inline struct bch_opts bch2_opts_empty(void) 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);
struct bch_opts ret;
memset(&ret, 255, sizeof(ret)); struct bch_opts bch2_opts_from_sb(struct bch_sb *);
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 *);
int bch2_opt_parse(const struct bch_option *, const char *, u64 *);
int bch2_parse_mount_opts(struct bch_opts *, char *); 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 */ #endif /* _BCACHEFS_OPTS_H */

View File

@ -26,14 +26,14 @@ bch2_hash_info_init(struct bch_fs *c,
{ {
/* XXX ick */ /* XXX ick */
struct bch_hash_info info = { 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) ~(~0U << INODE_STR_HASH_BITS)
}; };
switch (info.type) { switch (info.type) {
case BCH_STR_HASH_CRC32C: case BCH_STR_HASH_CRC32C:
case BCH_STR_HASH_CRC64: case BCH_STR_HASH_CRC64:
info.crc_key = bi->i_hash_seed; info.crc_key = bi->bi_hash_seed;
break; break;
case BCH_STR_HASH_SIPHASH: { case BCH_STR_HASH_SIPHASH: {
SHASH_DESC_ON_STACK(desc, c->sha256); SHASH_DESC_ON_STACK(desc, c->sha256);
@ -42,8 +42,8 @@ bch2_hash_info_init(struct bch_fs *c,
desc->tfm = c->sha256; desc->tfm = c->sha256;
desc->flags = 0; desc->flags = 0;
crypto_shash_digest(desc, (void *) &bi->i_hash_seed, crypto_shash_digest(desc, (void *) &bi->bi_hash_seed,
sizeof(bi->i_hash_seed), digest); sizeof(bi->bi_hash_seed), digest);
memcpy(&info.siphash_key, digest, sizeof(info.siphash_key)); memcpy(&info.siphash_key, digest, sizeof(info.siphash_key));
break; break;
} }

View File

@ -32,7 +32,7 @@ struct bch_sb_field *bch2_sb_field_get(struct bch_sb *sb,
return NULL; return NULL;
} }
void bch2_free_super(struct bcache_superblock *sb) void bch2_free_super(struct bch_sb_handle *sb)
{ {
if (sb->bio) if (sb->bio)
bio_put(sb->bio); bio_put(sb->bio);
@ -43,7 +43,7 @@ void bch2_free_super(struct bcache_superblock *sb)
memset(sb, 0, sizeof(*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 bch_sb *new_sb;
struct bio *bio; struct bio *bio;
@ -77,7 +77,7 @@ static int __bch2_super_realloc(struct bcache_superblock *sb, unsigned order)
return 0; 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 new_bytes = __vstruct_bytes(struct bch_sb, u64s);
u64 max_bytes = 512 << sb->sb->layout.sb_max_size_bits; u64 max_bytes = 512 << sb->sb->layout.sb_max_size_bits;
@ -145,9 +145,9 @@ static struct bch_sb_field *__bch2_sb_field_resize(struct bch_sb *sb,
return f; 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, enum bch_sb_field_type type,
unsigned u64s) unsigned u64s)
{ {
struct bch_sb_field *f = bch2_sb_field_get(sb->sb, type); struct bch_sb_field *f = bch2_sb_field_get(sb->sb, type);
ssize_t old_u64s = f ? le32_to_cpu(f->u64s) : 0; ssize_t old_u64s = f ? le32_to_cpu(f->u64s) : 0;
@ -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 */ /* XXX: we're not checking that offline device have enough space */
for_each_online_member(ca, c, i) { 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)) { if (bch2_sb_realloc(sb, le32_to_cpu(sb->sb->u64s) + d)) {
percpu_ref_put(&ca->ref); percpu_ref_put(&ca->ref);
@ -305,7 +305,7 @@ static const char *bch2_sb_validate_members(struct bch_sb *sb)
return NULL; 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 *sb = disk_sb->sb;
struct bch_sb_field *f; 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) le64_to_cpu(sb->version) > BCH_SB_VERSION_MAX)
return"Unsupported superblock version"; 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_ENCODED_EXTENT_MAX_BITS(sb, 7);
SET_BCH_SB_POSIX_ACL(sb, 1);
}
block_size = le16_to_cpu(sb->block_size); 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.uuid = src->uuid;
c->sb.user_uuid = src->user_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.nr_devices = src->nr_devices;
c->sb.clean = BCH_SB_CLEAN(src); 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.encryption_type = BCH_SB_ENCRYPTION_TYPE(src);
c->sb.encoded_extent_max= 1 << BCH_SB_ENCODED_EXTENT_MAX_BITS(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); 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: */ /* 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; struct bch_csum csum;
size_t bytes; size_t bytes;
@ -605,37 +604,37 @@ reread:
return NULL; return NULL;
} }
const char *bch2_read_super(struct bcache_superblock *sb, const char *bch2_read_super(const char *path,
struct bch_opts opts, 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; struct bch_sb_layout layout;
const char *err; const char *err;
unsigned i; unsigned i;
memset(sb, 0, sizeof(*sb)); memset(ret, 0, sizeof(*ret));
sb->mode = FMODE_READ; ret->mode = FMODE_READ;
if (!(opt_defined(opts.noexcl) && opts.noexcl)) if (!opt_get(opts, noexcl))
sb->mode |= FMODE_EXCL; ret->mode |= FMODE_EXCL;
if (!(opt_defined(opts.nochanges) && opts.nochanges)) if (!opt_get(opts, nochanges))
sb->mode |= FMODE_WRITE; 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) if (err)
return err; return err;
err = "cannot allocate memory"; err = "cannot allocate memory";
if (__bch2_super_realloc(sb, 0)) if (__bch2_super_realloc(ret, 0))
goto err; goto err;
err = "dynamic fault"; err = "dynamic fault";
if (bch2_fs_init_fault("read_super")) if (bch2_fs_init_fault("read_super"))
goto err; goto err;
err = read_one_super(sb, offset); err = read_one_super(ret, offset);
if (!err) if (!err)
goto got_super; goto got_super;
@ -650,22 +649,22 @@ const char *bch2_read_super(struct bcache_superblock *sb,
* Error reading primary superblock - read location of backup * Error reading primary superblock - read location of backup
* superblocks: * superblocks:
*/ */
bio_reset(sb->bio); bio_reset(ret->bio);
sb->bio->bi_bdev = sb->bdev; ret->bio->bi_bdev = ret->bdev;
sb->bio->bi_iter.bi_sector = BCH_SB_LAYOUT_SECTOR; ret->bio->bi_iter.bi_sector = BCH_SB_LAYOUT_SECTOR;
sb->bio->bi_iter.bi_size = sizeof(struct bch_sb_layout); ret->bio->bi_iter.bi_size = sizeof(struct bch_sb_layout);
bio_set_op_attrs(sb->bio, REQ_OP_READ, REQ_SYNC|REQ_META); 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 * use sb buffer to read layout, since sb buffer is page aligned but
* layout won't be: * layout won't be:
*/ */
bch2_bio_map(sb->bio, sb->sb); bch2_bio_map(ret->bio, ret->sb);
err = "IO error"; err = "IO error";
if (submit_bio_wait(sb->bio)) if (submit_bio_wait(ret->bio))
goto err; goto err;
memcpy(&layout, sb->sb, sizeof(layout)); memcpy(&layout, ret->sb, sizeof(layout));
err = validate_sb_layout(&layout); err = validate_sb_layout(&layout);
if (err) if (err)
goto err; goto err;
@ -676,26 +675,26 @@ const char *bch2_read_super(struct bcache_superblock *sb,
if (offset == BCH_SB_SECTOR) if (offset == BCH_SB_SECTOR)
continue; continue;
err = read_one_super(sb, offset); err = read_one_super(ret, offset);
if (!err) if (!err)
goto got_super; goto got_super;
} }
goto err; goto err;
got_super: got_super:
pr_debug("read sb version %llu, flags %llu, seq %llu, journal size %u", pr_debug("read sb version %llu, flags %llu, seq %llu, journal size %u",
le64_to_cpu(sb->sb->version), le64_to_cpu(ret->sb->version),
le64_to_cpu(sb->sb->flags), le64_to_cpu(ret->sb->flags),
le64_to_cpu(sb->sb->seq), le64_to_cpu(ret->sb->seq),
le16_to_cpu(sb->sb->u64s)); le16_to_cpu(ret->sb->u64s));
err = "Superblock block size smaller than device block size"; err = "Superblock block size smaller than device block size";
if (le16_to_cpu(sb->sb->block_size) << 9 < if (le16_to_cpu(ret->sb->block_size) << 9 <
bdev_logical_block_size(sb->bdev)) bdev_logical_block_size(ret->bdev))
goto err; goto err;
return NULL; return NULL;
err: err:
bch2_free_super(sb); bch2_free_super(ret);
return err; return err;
} }

View File

@ -9,8 +9,8 @@
#include <asm/byteorder.h> #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_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); enum bch_sb_field_type, unsigned);
struct bch_sb_field *bch2_fs_sb_field_resize(struct bch_fs *, struct bch_sb_field *bch2_fs_sb_field_resize(struct bch_fs *,
enum bch_sb_field_type, unsigned); 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 * \ 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, \ return field_to_type(bch2_sb_field_resize(sb, \
BCH_SB_FIELD_##_name, u64s), _name); \ 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_to_fs(struct bch_fs *, struct bch_sb *);
int bch2_sb_from_fs(struct bch_fs *, struct bch_dev *); int bch2_sb_from_fs(struct bch_fs *, struct bch_dev *);
void bch2_free_super(struct bcache_superblock *); void bch2_free_super(struct bch_sb_handle *);
int bch2_super_realloc(struct bcache_superblock *, unsigned); int bch2_super_realloc(struct bch_sb_handle *, unsigned);
const char *bch2_sb_validate_journal(struct bch_sb *, const char *bch2_sb_validate_journal(struct bch_sb *,
struct bch_member_cpu); 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 *, const char *bch2_read_super(const char *, struct bch_opts,
struct bch_opts, const char *); struct bch_sb_handle *);
void bch2_write_super(struct bch_fs *); void bch2_write_super(struct bch_fs *);
/* replicas: */ /* replicas: */

View File

@ -241,13 +241,12 @@ static void bch2_writes_disabled(struct percpu_ref *writes)
void bch2_fs_read_only(struct bch_fs *c) void bch2_fs_read_only(struct bch_fs *c)
{ {
mutex_lock(&c->state_lock);
if (c->state != BCH_FS_STARTING && if (c->state != BCH_FS_STARTING &&
c->state != BCH_FS_RW) c->state != BCH_FS_RW)
goto out; return;
if (test_bit(BCH_FS_ERROR, &c->flags)) if (test_bit(BCH_FS_ERROR, &c->flags))
goto out; return;
/* /*
* Block new foreground-end write operations from starting - any new * 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; c->state = BCH_FS_RO;
out:
mutex_unlock(&c->state_lock);
} }
static void bch2_fs_read_only_work(struct work_struct *work) 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 = struct bch_fs *c =
container_of(work, struct bch_fs, read_only_work); container_of(work, struct bch_fs, read_only_work);
mutex_lock(&c->state_lock);
bch2_fs_read_only(c); bch2_fs_read_only(c);
mutex_unlock(&c->state_lock);
} }
static void bch2_fs_read_only_async(struct bch_fs *c) 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; const char *err = NULL;
unsigned i; unsigned i;
mutex_lock(&c->state_lock);
if (c->state != BCH_FS_STARTING && if (c->state != BCH_FS_STARTING &&
c->state != BCH_FS_RO) c->state != BCH_FS_RO)
goto out; return NULL;
for_each_rw_member(ca, c, i) for_each_rw_member(ca, c, i)
bch2_dev_allocator_add(c, ca); 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); percpu_ref_reinit(&c->writes);
c->state = BCH_FS_RW; c->state = BCH_FS_RW;
err = NULL; return NULL;
out:
mutex_unlock(&c->state_lock);
return err;
err: err:
__bch2_fs_read_only(c); __bch2_fs_read_only(c);
goto out; return err;
} }
/* Filesystem startup/shutdown: */ /* Filesystem startup/shutdown: */
@ -452,7 +447,9 @@ static void bch2_fs_offline(struct bch_fs *c)
kobject_put(&c->opts_dir); kobject_put(&c->opts_dir);
kobject_put(&c->internal); kobject_put(&c->internal);
mutex_lock(&c->state_lock);
__bch2_fs_read_only(c); __bch2_fs_read_only(c);
mutex_unlock(&c->state_lock);
} }
static void bch2_fs_release(struct kobject *kobj) 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; goto err;
} }
c->block_bits = ilog2(c->sb.block_size);
mutex_unlock(&c->sb_lock); mutex_unlock(&c->sb_lock);
scnprintf(c->name, sizeof(c->name), "%pU", &c->sb.user_uuid); 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); bch2_opts_apply(&c->opts, opts);
c->block_bits = ilog2(c->opts.block_size);
c->opts.nochanges |= c->opts.noreplay; c->opts.nochanges |= c->opts.noreplay;
c->opts.read_only |= c->opts.nochanges; 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)) || bioset_init(&c->bio_write, 1, offsetof(struct bch_write_bio, bio)) ||
mempool_init_page_pool(&c->bio_bounce_pages, mempool_init_page_pool(&c->bio_bounce_pages,
max_t(unsigned, max_t(unsigned,
c->sb.btree_node_size, c->opts.btree_node_size,
c->sb.encoded_extent_max) / c->sb.encoded_extent_max) /
PAGE_SECTORS, 0) || PAGE_SECTORS, 0) ||
!(c->usage_percpu = alloc_percpu(struct bch_fs_usage)) || !(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) || if (kobject_add(&c->kobj, NULL, "%pU", c->sb.user_uuid.b) ||
kobject_add(&c->internal, &c->kobj, "internal") || kobject_add(&c->internal, &c->kobj, "internal") ||
kobject_add(&c->opts_dir, &c->kobj, "options") || 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"; return "error creating sysfs objects";
mutex_lock(&c->state_lock); mutex_lock(&c->state_lock);
@ -699,6 +698,8 @@ static const char *__bch2_fs_start(struct bch_fs *c)
closure_init_stack(&cl); closure_init_stack(&cl);
mutex_lock(&c->state_lock);
BUG_ON(c->state != BCH_FS_STARTING); BUG_ON(c->state != BCH_FS_STARTING);
mutex_lock(&c->sb_lock); mutex_lock(&c->sb_lock);
@ -742,6 +743,8 @@ static const char *__bch2_fs_start(struct bch_fs *c)
if (ret) if (ret)
goto err; goto err;
set_bit(BCH_FS_ALLOC_READ_DONE, &c->flags);
bch_verbose(c, "starting mark and sweep:"); bch_verbose(c, "starting mark and sweep:");
err = "error in recovery"; err = "error in recovery";
ret = bch2_initial_gc(c, &journal); 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"); bch_notice(c, "initializing new filesystem");
set_bit(BCH_FS_ALLOC_READ_DONE, &c->flags);
ret = bch2_initial_gc(c, &journal); ret = bch2_initial_gc(c, &journal);
if (ret) if (ret)
goto err; goto err;
@ -831,7 +836,7 @@ static const char *__bch2_fs_start(struct bch_fs *c)
bch2_inode_init(c, &inode, 0, 0, bch2_inode_init(c, &inode, 0, 0,
S_IFDIR|S_IRWXU|S_IRUGO|S_IXUGO, 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); bch2_inode_pack(&packed_inode, &inode);
@ -873,6 +878,7 @@ recovery_done:
err = NULL; err = NULL;
out: out:
mutex_unlock(&c->state_lock);
bch2_journal_entries_free(&journal); bch2_journal_entries_free(&journal);
return err; return err;
err: err:
@ -922,7 +928,7 @@ static const char *bch2_dev_may_add(struct bch_sb *sb, struct bch_fs *c)
if (!sb_mi) if (!sb_mi)
return "Invalid superblock: member info area missing"; 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"; return "mismatched block size";
if (le16_to_cpu(sb_mi->members[sb->dev_idx].bucket_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 = btree_node_reserve_buckets =
DIV_ROUND_UP(BTREE_NODE_RESERVE, 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, if (percpu_ref_init(&ca->ref, bch2_dev_ref_release,
0, GFP_KERNEL) || 0, GFP_KERNEL) ||
@ -1176,7 +1182,7 @@ err:
return -ENOMEM; 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; struct bch_dev *ca;
int ret; int ret;
@ -1462,7 +1468,7 @@ err:
/* Add new device to running filesystem: */ /* Add new device to running filesystem: */
int bch2_dev_add(struct bch_fs *c, const char *path) int bch2_dev_add(struct bch_fs *c, const char *path)
{ {
struct bcache_superblock sb; struct bch_sb_handle sb;
const char *err; const char *err;
struct bch_dev *ca = NULL; struct bch_dev *ca = NULL;
struct bch_sb_field_members *mi, *dev_mi; 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; unsigned dev_idx, nr_devices, u64s;
int ret = -EINVAL; int ret = -EINVAL;
err = bch2_read_super(&sb, bch2_opts_empty(), path); err = bch2_read_super(path, bch2_opts_empty(), &sb);
if (err) if (err)
return -EINVAL; return -EINVAL;
@ -1572,14 +1578,14 @@ err:
/* Hot add existing device to running filesystem: */ /* Hot add existing device to running filesystem: */
int bch2_dev_online(struct bch_fs *c, const char *path) 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; struct bch_dev *ca;
unsigned dev_idx; unsigned dev_idx;
const char *err; const char *err;
mutex_lock(&c->state_lock); 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) if (err)
goto err; goto err;
@ -1673,7 +1679,7 @@ const char *bch2_fs_open(char * const *devices, unsigned nr_devices,
{ {
const char *err; const char *err;
struct bch_fs *c = NULL; struct bch_fs *c = NULL;
struct bcache_superblock *sb; struct bch_sb_handle *sb;
unsigned i, best_sb = 0; unsigned i, best_sb = 0;
if (!nr_devices) if (!nr_devices)
@ -1688,7 +1694,7 @@ const char *bch2_fs_open(char * const *devices, unsigned nr_devices,
goto err; goto err;
for (i = 0; i < nr_devices; i++) { 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) if (err)
goto err; goto err;
@ -1757,7 +1763,7 @@ err:
goto out; 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) struct bch_opts opts)
{ {
const char *err; const char *err;
@ -1821,11 +1827,11 @@ err:
const char *bch2_fs_open_incremental(const char *path) 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(); struct bch_opts opts = bch2_opts_empty();
const char *err; const char *err;
err = bch2_read_super(&sb, opts, path); err = bch2_read_super(path, opts, &sb);
if (err) if (err)
return err; return err;

View File

@ -1,7 +1,7 @@
#ifndef _BCACHEFS_SUPER_TYPES_H #ifndef _BCACHEFS_SUPER_TYPES_H
#define _BCACHEFS_SUPER_TYPES_H #define _BCACHEFS_SUPER_TYPES_H
struct bcache_superblock { struct bch_sb_handle {
struct bch_sb *sb; struct bch_sb *sb;
struct block_device *bdev; struct block_device *bdev;
struct bio *bio; struct bio *bio;

View File

@ -194,14 +194,6 @@ read_attribute(data_replicas_have);
BCH_DEBUG_PARAMS() BCH_DEBUG_PARAMS()
#undef BCH_DEBUG_PARAM #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) \ #define BCH_TIME_STAT(name, frequency_units, duration_units) \
sysfs_time_stats_attribute(name, frequency_units, duration_units); sysfs_time_stats_attribute(name, frequency_units, duration_units);
BCH_TIME_STATS() BCH_TIME_STATS()
@ -528,8 +520,13 @@ SHOW(bch2_fs_opts_dir)
{ {
char *out = buf, *end = buf + PAGE_SIZE; char *out = buf, *end = buf + PAGE_SIZE;
struct bch_fs *c = container_of(kobj, struct bch_fs, opts_dir); 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"); out += scnprintf(out, end - out, "\n");
return out - buf; return out - buf;
@ -538,15 +535,13 @@ SHOW(bch2_fs_opts_dir)
STORE(bch2_fs_opts_dir) STORE(bch2_fs_opts_dir)
{ {
struct bch_fs *c = container_of(kobj, struct bch_fs, opts_dir); struct bch_fs *c = container_of(kobj, struct bch_fs, opts_dir);
const struct bch_option *opt; const struct bch_option *opt = container_of(attr, struct bch_option, attr);
int id; int ret, id = opt - bch2_opt_table;
u64 v; u64 v;
id = bch2_parse_sysfs_opt(attr->name, buf, &v); ret = bch2_opt_parse(opt, buf, &v);
if (id < 0) if (ret < 0)
return id; return ret;
opt = &bch2_opt_table[id];
mutex_lock(&c->sb_lock); mutex_lock(&c->sb_lock);
@ -563,7 +558,7 @@ STORE(bch2_fs_opts_dir)
bch2_write_super(c); 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); mutex_unlock(&c->sb_lock);
@ -571,15 +566,26 @@ STORE(bch2_fs_opts_dir)
} }
SYSFS_OPS(bch2_fs_opts_dir); SYSFS_OPS(bch2_fs_opts_dir);
struct attribute *bch2_fs_opts_dir_files[] = { struct attribute *bch2_fs_opts_dir_files[] = { NULL };
#define BCH_OPT(_name, ...) \
&sysfs_opt_##_name,
BCH_VISIBLE_OPTS() int bch2_opts_create_sysfs_files(struct kobject *kobj)
#undef BCH_OPT {
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 */ /* time stats */

View File

@ -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_fs_time_stats_sysfs_ops;
extern struct sysfs_ops bch2_dev_sysfs_ops; extern struct sysfs_ops bch2_dev_sysfs_ops;
int bch2_opts_create_sysfs_files(struct kobject *);
#else #else
static struct attribute *bch2_fs_files[] = {}; 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_fs_time_stats_sysfs_ops;
static const struct sysfs_ops bch2_dev_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 /* NO_BCACHEFS_SYSFS */
#endif /* _BCACHEFS_SYSFS_H_ */ #endif /* _BCACHEFS_SYSFS_H_ */

View File

@ -162,18 +162,17 @@ const struct bkey_ops bch2_bkey_xattr_ops = {
.val_to_text = bch2_xattr_to_text, .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) const char *name, void *buffer, size_t size, int type)
{ {
struct bch_inode_info *ei = to_bch_ei(inode);
struct btree_iter iter; struct btree_iter iter;
struct bkey_s_c k; struct bkey_s_c k;
struct bkey_s_c_xattr xattr; struct bkey_s_c_xattr xattr;
int ret; int ret;
k = bch2_hash_lookup(bch2_xattr_hash_desc, &ei->str_hash, c, k = bch2_hash_lookup(bch2_xattr_hash_desc, &inode->ei_str_hash, c,
ei->vfs_inode.i_ino, &iter, inode->v.i_ino, &iter,
&X_SEARCH(type, name, strlen(name))); &X_SEARCH(type, name, strlen(name)));
if (IS_ERR(k.k)) if (IS_ERR(k.k))
return bch2_btree_iter_unlock(&iter) ?: -ENODATA; return bch2_btree_iter_unlock(&iter) ?: -ENODATA;
@ -236,15 +235,13 @@ int __bch2_xattr_set(struct bch_fs *c, u64 inum,
return ret; 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, const char *name, const void *value, size_t size,
int flags, int type) int flags, int type)
{ {
struct bch_inode_info *ei = to_bch_ei(inode); return __bch2_xattr_set(c, inode->v.i_ino, &inode->ei_str_hash,
name, value, size, flags, type,
return __bch2_xattr_set(c, inode->i_ino, &ei->str_hash, &inode->ei_journal_seq);
name, value, size, flags, type,
&ei->journal_seq);
} }
static size_t bch2_xattr_emit(struct dentry *dentry, static size_t bch2_xattr_emit(struct dentry *dentry,
@ -313,23 +310,25 @@ 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, 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) 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); return bch2_xattr_get(c, inode, name, buffer, size, handler->flags);
} }
static int bch2_xattr_set_handler(const struct xattr_handler *handler, 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, const char *name, const void *value,
size_t size, int flags) 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, return bch2_xattr_set(c, inode, name, value, size, flags,
handler->flags); handler->flags);
} }
static const struct xattr_handler bch_xattr_user_handler = { static const struct xattr_handler bch_xattr_user_handler = {

View File

@ -9,12 +9,13 @@ extern const struct bkey_ops bch2_bkey_xattr_ops;
struct dentry; struct dentry;
struct xattr_handler; struct xattr_handler;
struct bch_hash_info; 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); const char *, void *, size_t, int);
int __bch2_xattr_set(struct bch_fs *, u64, const struct bch_hash_info *, int __bch2_xattr_set(struct bch_fs *, u64, const struct bch_hash_info *,
const char *, const void *, size_t, int, int, u64 *); 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); const char *, const void *, size_t, int, int);
ssize_t bch2_xattr_list(struct dentry *, char *, size_t); ssize_t bch2_xattr_list(struct dentry *, char *, size_t);