diff options
Diffstat (limited to 'libbcache/super.c')
-rw-r--r-- | libbcache/super.c | 94 |
1 files changed, 88 insertions, 6 deletions
diff --git a/libbcache/super.c b/libbcache/super.c index bb4a7dc3..1e272af2 100644 --- a/libbcache/super.c +++ b/libbcache/super.c @@ -1069,7 +1069,7 @@ static void bch_dev_io_ref_release(struct percpu_ref *ref) complete(&ca->offline_complete); } -static void bch_dev_offline(struct bch_dev *ca) +static void __bch_dev_offline(struct bch_dev *ca) { struct bch_fs *c = ca->fs; @@ -1244,7 +1244,7 @@ err: return -ENOMEM; } -static int bch_dev_online(struct bch_fs *c, struct bcache_superblock *sb) +static int __bch_dev_online(struct bch_fs *c, struct bcache_superblock *sb) { struct bch_dev *ca; int ret; @@ -1534,7 +1534,7 @@ static int __bch_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags) bch_journal_meta(&c->journal); - bch_dev_offline(ca); + __bch_dev_offline(ca); bch_dev_stop(ca); bch_dev_free(ca); @@ -1644,7 +1644,7 @@ have_slot: goto err_unlock; } - if (bch_dev_online(c, &sb)) { + if (__bch_dev_online(c, &sb)) { err = "bch_dev_online() error"; ret = -ENOMEM; goto err_unlock; @@ -1677,6 +1677,88 @@ err: return ret ?: -EINVAL; } +int bch_dev_online(struct bch_fs *c, const char *path) +{ + struct bcache_superblock sb = { 0 }; + const char *err; + + mutex_lock(&c->state_lock); + + err = bch_read_super(&sb, bch_opts_empty(), path); + if (err) + goto err; + + err = bch_dev_in_fs(c->disk_sb, sb.sb); + if (err) + goto err; + + mutex_lock(&c->sb_lock); + if (__bch_dev_online(c, &sb)) { + mutex_unlock(&c->sb_lock); + goto err; + } + mutex_unlock(&c->sb_lock); + + mutex_unlock(&c->state_lock); + return 0; +err: + mutex_unlock(&c->state_lock); + bch_free_super(&sb); + bch_err(c, "error bringing %s online: %s", path, err); + return -EINVAL; +} + +int bch_dev_offline(struct bch_fs *c, struct bch_dev *ca, int flags) +{ + mutex_lock(&c->state_lock); + + if (!bch_dev_state_allowed(c, ca, BCH_MEMBER_STATE_FAILED, flags)) { + bch_err(ca, "Cannot offline required disk"); + mutex_unlock(&c->state_lock); + return -EINVAL; + } + + __bch_dev_read_only(c, ca); + __bch_dev_offline(ca); + + mutex_unlock(&c->state_lock); + return 0; +} + +int bch_dev_migrate(struct bch_fs *c, struct bch_dev *ca) +{ + int ret; + + mutex_lock(&c->state_lock); + + if (ca->mi.state == BCH_MEMBER_STATE_RW) { + bch_err(ca, "Cannot migrate data off RW device"); + mutex_unlock(&c->state_lock); + return -EINVAL; + } + + mutex_unlock(&c->state_lock); + + ret = bch_move_data_off_device(ca); + if (ret) { + bch_err(ca, "Error migrating data: %i", ret); + return ret; + } + + ret = bch_move_metadata_off_device(ca); + if (ret) { + bch_err(ca, "Error migrating metadata: %i", ret); + return ret; + } + + if (ca->mi.has_data || ca->mi.has_metadata) { + bch_err(ca, "Migrate error: data still present"); + return -EINVAL; + } + + return 0; +} + /* Filesystem open: */ const char *bch_fs_open(char * const *devices, unsigned nr_devices, @@ -1731,7 +1813,7 @@ const char *bch_fs_open(char * const *devices, unsigned nr_devices, err = "bch_dev_online() error"; mutex_lock(&c->sb_lock); for (i = 0; i < nr_devices; i++) - if (bch_dev_online(c, &sb[i])) { + if (__bch_dev_online(c, &sb[i])) { mutex_unlock(&c->sb_lock); goto err; } @@ -1803,7 +1885,7 @@ static const char *__bch_fs_open_incremental(struct bcache_superblock *sb, err = "bch_dev_online() error"; mutex_lock(&c->sb_lock); - if (bch_dev_online(c, sb)) { + if (__bch_dev_online(c, sb)) { mutex_unlock(&c->sb_lock); goto err; } |