return c;
}
-static struct bch_fs *__bch2_uuid_to_fs(uuid_le uuid)
+static struct bch_fs *__bch2_uuid_to_fs(__uuid_t uuid)
{
struct bch_fs *c;
lockdep_assert_held(&bch_fs_list_lock);
list_for_each_entry(c, &bch_fs_list, list)
- if (!memcmp(&c->disk_sb.sb->uuid, &uuid, sizeof(uuid_le)))
+ if (!memcmp(&c->disk_sb.sb->uuid, &uuid, sizeof(uuid)))
return c;
return NULL;
}
-struct bch_fs *bch2_uuid_to_fs(uuid_le uuid)
+struct bch_fs *bch2_uuid_to_fs(__uuid_t uuid)
{
struct bch_fs *c;
{
int ret;
+ /*
+ * Data move operations can't run until after check_snapshots has
+ * completed, and bch2_snapshot_is_ancestor() is available.
+ *
+ * Ideally we'd start copygc/rebalance earlier instead of waiting for
+ * all of recovery/fsck to complete:
+ */
+ ret = bch2_copygc_start(c);
+ if (ret) {
+ bch_err(c, "error starting copygc thread");
+ return ret;
+ }
+
ret = bch2_rebalance_start(c);
if (ret) {
bch_err(c, "error starting rebalance thread");
if (test_bit(BCH_FS_INITIAL_GC_UNFIXED, &c->flags)) {
bch_err(c, "cannot go rw, unfixed btree errors");
- return -EROFS;
+ return -BCH_ERR_erofs_unfixed_errors;
}
if (test_bit(BCH_FS_RW, &c->flags))
return 0;
+ if (c->opts.norecovery)
+ return -BCH_ERR_erofs_norecovery;
+
/*
* nochanges is used for fsck -n mode - we have to allow going rw
* during recovery for that to work:
*/
- if (c->opts.norecovery ||
- (c->opts.nochanges &&
- (!early || c->opts.read_only)))
- return -EROFS;
+ if (c->opts.nochanges && (!early || c->opts.read_only))
+ return -BCH_ERR_erofs_nochanges;
bch_info(c, "going read-write");
return ret;
}
- ret = bch2_copygc_start(c);
- if (ret) {
- bch_err(c, "error starting copygc thread");
- return ret;
- }
-
if (!early) {
ret = bch2_fs_read_write_late(c);
if (ret)
for_each_possible_cpu(cpu)
kfree(per_cpu_ptr(c->btree_paths_bufs, cpu)->path);
+ darray_exit(&c->btree_roots_extra);
free_percpu(c->btree_paths_bufs);
free_percpu(c->pcpu);
mempool_exit(&c->large_bkey_pool);
cancel_work_sync(&c->read_only_work);
- for (i = 0; i < c->sb.nr_devices; i++)
- if (c->devs[i])
- bch2_free_super(&c->devs[i]->disk_sb);
+ for (i = 0; i < c->sb.nr_devices; i++) {
+ struct bch_dev *ca = rcu_dereference_protected(c->devs[i], true);
+
+ if (ca)
+ bch2_free_super(&ca->disk_sb);
+ }
}
void bch2_fs_free(struct bch_fs *c)
unsigned i, iter_size;
int ret = 0;
- pr_verbose_init(opts, "");
-
c = kvpmalloc(sizeof(struct bch_fs), GFP_KERNEL|__GFP_ZERO);
if (!c) {
c = ERR_PTR(-BCH_ERR_ENOMEM_fs_alloc);
bch2_fs_copygc_init(c);
bch2_fs_btree_key_cache_init_early(&c->btree_key_cache);
+ bch2_fs_btree_interior_update_init_early(c);
bch2_fs_allocator_background_init(c);
bch2_fs_allocator_foreground_init(c);
bch2_fs_rebalance_init(c);
goto err;
/* Compat: */
- if (sb->version <= bcachefs_metadata_version_inode_v2 &&
+ if (le16_to_cpu(sb->version) <= bcachefs_metadata_version_inode_v2 &&
!BCH_SB_JOURNAL_FLUSH_DELAY(sb))
SET_BCH_SB_JOURNAL_FLUSH_DELAY(sb, 1000);
- if (sb->version <= bcachefs_metadata_version_inode_v2 &&
+ if (le16_to_cpu(sb->version) <= bcachefs_metadata_version_inode_v2 &&
!BCH_SB_JOURNAL_RECLAIM_DELAY(sb))
SET_BCH_SB_JOURNAL_RECLAIM_DELAY(sb, 100);
if (ret)
goto err;
out:
- pr_verbose_init(opts, "ret %i", PTR_ERR_OR_ZERO(c));
return c;
err:
bch2_fs_free(c);
struct printbuf p = PRINTBUF;
bool first = true;
- prt_printf(&p, "mounted version=%s", bch2_metadata_versions[c->sb.version]);
+ prt_str(&p, "mounted version ");
+ bch2_version_to_text(&p, c->sb.version);
if (c->opts.read_only) {
prt_str(&p, " opts=");
le64_to_cpu(fs->seq) > le64_to_cpu(sb->seq) ? fs : sb;
struct bch_sb_field_members *mi = bch2_sb_get_members(newest);
- if (uuid_le_cmp(fs->uuid, sb->uuid))
+ if (!uuid_equal(&fs->uuid, &sb->uuid))
return -BCH_ERR_device_not_a_member_of_filesystem;
if (!bch2_dev_exists(newest, mi, sb->dev_idx))
struct bch_dev *ca = NULL;
int ret = 0;
- pr_verbose_init(c->opts, "");
-
if (bch2_fs_init_fault("dev_alloc"))
goto err;
ca->fs = c;
bch2_dev_attach(c, ca, dev_idx);
-out:
- pr_verbose_init(c->opts, "ret %i", ret);
return ret;
err:
if (ca)
bch2_dev_free(ca);
- ret = -BCH_ERR_ENOMEM_dev_alloc;
- goto out;
+ return -BCH_ERR_ENOMEM_dev_alloc;
}
static int __bch2_dev_attach_bdev(struct bch_dev *ca, struct bch_sb_handle *sb)
bch2_dev_free(ca);
+ /*
+ * At this point the device object has been removed in-core, but the
+ * on-disk journal might still refer to the device index via sb device
+ * usage entries. Recovery fails if it sees usage information for an
+ * invalid device. Flush journal pins to push the back of the journal
+ * past now invalid device index references before we update the
+ * superblock, but after the device object has been removed so any
+ * further journal writes elide usage info for the device.
+ */
+ bch2_journal_flush_all_pins(&c->journal);
+
/*
* Free this device's slot in the bch_member array - all pointers to
* this device must be gone:
if (!try_module_get(THIS_MODULE))
return ERR_PTR(-ENODEV);
- pr_verbose_init(opts, "");
-
if (!nr_devices) {
ret = -EINVAL;
goto err;
kfree(sb);
printbuf_exit(&errbuf);
module_put(THIS_MODULE);
- pr_verbose_init(opts, "ret %s (%i)", bch2_err_str(PTR_ERR_OR_ZERO(c)),
- PTR_ERR_OR_ZERO(c));
return c;
err_print:
pr_err("bch_fs_open err opening %s: %s",
BCH_DEBUG_PARAMS()
#undef BCH_DEBUG_PARAM
-unsigned bch2_metadata_version = bcachefs_metadata_version_current;
+static unsigned bch2_metadata_version = bcachefs_metadata_version_current;
module_param_named(version, bch2_metadata_version, uint, 0400);
module_exit(bcachefs_exit);