summaryrefslogtreecommitdiff
path: root/c_src
diff options
context:
space:
mode:
Diffstat (limited to 'c_src')
-rw-r--r--c_src/cmd_data.c25
-rw-r--r--c_src/cmd_device.c33
-rw-r--r--c_src/cmd_fsck.c18
-rw-r--r--c_src/cmd_key.c18
-rw-r--r--c_src/cmd_kill_btree_node.c36
-rw-r--r--c_src/cmd_list_journal.c120
-rw-r--r--c_src/cmd_migrate.c14
7 files changed, 217 insertions, 47 deletions
diff --git a/c_src/cmd_data.c b/c_src/cmd_data.c
index 5a1a1485..70d945a6 100644
--- a/c_src/cmd_data.c
+++ b/c_src/cmd_data.c
@@ -26,9 +26,13 @@ static void data_rereplicate_usage(void)
static int cmd_data_rereplicate(int argc, char *argv[])
{
+ static const struct option longopts[] = {
+ { "help", 0, NULL, 'h' },
+ { NULL }
+ };
int opt;
- while ((opt = getopt(argc, argv, "h")) != -1)
+ while ((opt = getopt_long(argc, argv, "h", longopts, NULL)) != -1)
switch (opt) {
case 'h':
data_rereplicate_usage();
@@ -262,16 +266,23 @@ static void data_job_usage(void)
"job: one of scrub, rereplicate, migrate, rewrite_old_nodes, or drop_extra_replicas\n"
"\n"
"Options:\n"
- " -b btree btree to operate on\n"
- " -s inode:offset start position\n"
- " -e inode:offset end position\n"
- " -h, --help display this help and exit\n"
+ " -b, --btree btree btree to operate on\n"
+ " -s, --start inode:offset start position\n"
+ " -e, --end inode:offset end position\n"
+ " -h, --help display this help and exit\n"
"Report bugs to <linux-bcachefs@vger.kernel.org>");
exit(EXIT_SUCCESS);
}
static int cmd_data_job(int argc, char *argv[])
{
+ static const struct option longopts[] = {
+ { "btree", required_argument, NULL, 'b' },
+ { "start", required_argument, NULL, 's' },
+ { "end", required_argument, NULL, 'e' },
+ { "help", no_argument, NULL, 'h' },
+ { NULL }
+ };
struct bch_ioctl_data op = {
.start_btree = 0,
.start_pos = POS_MIN,
@@ -280,7 +291,7 @@ static int cmd_data_job(int argc, char *argv[])
};
int opt;
- while ((opt = getopt(argc, argv, "s:e:h")) != -1)
+ while ((opt = getopt_long(argc, argv, "b:s:e:h", longopts, NULL)) != -1)
switch (opt) {
case 'b':
op.start_btree = read_string_list_or_die(optarg,
@@ -290,8 +301,8 @@ static int cmd_data_job(int argc, char *argv[])
case 's':
op.start_pos = bpos_parse(optarg);
break;
- op.end_pos = bpos_parse(optarg);
case 'e':
+ op.end_pos = bpos_parse(optarg);
break;
case 'h':
data_job_usage();
diff --git a/c_src/cmd_device.c b/c_src/cmd_device.c
index e7c40d0a..267385ac 100644
--- a/c_src/cmd_device.c
+++ b/c_src/cmd_device.c
@@ -212,9 +212,13 @@ static void device_online_usage(void)
static int cmd_device_online(int argc, char *argv[])
{
+ static const struct option longopts[] = {
+ { "help", 0, NULL, 'h' },
+ { NULL }
+ };
int opt;
- while ((opt = getopt(argc, argv, "h")) != -1)
+ while ((opt = getopt_long(argc, argv, "h", longopts, NULL)) != -1)
switch (opt) {
case 'h':
device_online_usage();
@@ -286,6 +290,7 @@ static void device_evacuate_usage(void)
"Usage: bcachefs device evacuate [OPTION]... device\n"
"\n"
"Options:\n"
+ " -f, --force Force if data redundancy will be degraded\n"
" -h, --help Display this help and exit\n"
"\n"
"Report bugs to <linux-bcachefs@vger.kernel.org>");
@@ -293,10 +298,18 @@ static void device_evacuate_usage(void)
static int cmd_device_evacuate(int argc, char *argv[])
{
- int opt;
+ static const struct option longopts[] = {
+ { "force", no_argument, NULL, 'f' },
+ { "help", no_argument, NULL, 'h' },
+ { NULL }
+ };
+ int opt, flags = 0;
- while ((opt = getopt(argc, argv, "h")) != -1)
+ while ((opt = getopt_long(argc, argv, "fh", longopts, NULL)) != -1)
switch (opt) {
+ case 'f':
+ flags |= BCH_FORCE_IF_DEGRADED;
+ break;
case 'h':
device_evacuate_usage();
exit(EXIT_SUCCESS);
@@ -317,7 +330,7 @@ static int cmd_device_evacuate(int argc, char *argv[])
if (u->state == BCH_MEMBER_STATE_rw) {
printf("Setting %s readonly\n", dev_path);
- bchu_disk_set_state(fs, dev_idx, BCH_MEMBER_STATE_ro, 0);
+ bchu_disk_set_state(fs, dev_idx, BCH_MEMBER_STATE_ro, flags);
}
free(u);
@@ -341,8 +354,8 @@ static void device_set_state_usage(void)
"<path>: path to mounted filesystem, optional unless specifying device by id\n"
"\n"
"Options:\n"
- " -f, --force Force, if data redundancy will be degraded\n"
- " --force-if-data-lost Force, if data will be lost\n"
+ " -f, --force Force if data redundancy will be degraded\n"
+ " --force-if-data-lost Force if data will be lost\n"
" -o, --offline Set state of an offline device\n"
" -h, --help display this help and exit\n"
"Report bugs to <linux-bcachefs@vger.kernel.org>");
@@ -352,10 +365,10 @@ static void device_set_state_usage(void)
static int cmd_device_set_state(int argc, char *argv[])
{
static const struct option longopts[] = {
- { "force", 0, NULL, 'f' },
- { "force-if-data-lost", 0, NULL, 'F' },
- { "offline", 0, NULL, 'o' },
- { "help", 0, NULL, 'h' },
+ { "force", no_argument, NULL, 'f' },
+ { "force-if-data-lost", no_argument, NULL, 'F' },
+ { "offline", no_argument, NULL, 'o' },
+ { "help", no_argument, NULL, 'h' },
{ NULL }
};
struct bchfs_handle fs;
diff --git a/c_src/cmd_fsck.c b/c_src/cmd_fsck.c
index a3fd1d6a..66669e67 100644
--- a/c_src/cmd_fsck.c
+++ b/c_src/cmd_fsck.c
@@ -47,6 +47,24 @@ static int do_splice(int rfd, int wfd)
return 1;
do {
ssize_t w = write(wfd, b, r);
+
+ /*
+ * Ugly, but we have no way of doing nonblocking reads and
+ * blocking writes.
+ *
+ * Yes, this means that if one thread has stopped reading (or
+ * isn't keeping up) we block traffic on the other direction of
+ * the pipe. No, I don't care.
+ */
+ if (w < 0 && errno == EAGAIN) {
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(wfd, &fds);
+ if (select(wfd + 1, NULL, &fds, NULL, NULL) < 0)
+ die("select error: %m");
+ continue;
+ }
+
if (w < 0)
die("%s: write error: %m", __func__);
r -= w;
diff --git a/c_src/cmd_key.c b/c_src/cmd_key.c
index c1b72ff4..6cdf1d3f 100644
--- a/c_src/cmd_key.c
+++ b/c_src/cmd_key.c
@@ -1,5 +1,6 @@
#include <errno.h>
#include <fcntl.h>
+#include <getopt.h>
#include <unistd.h>
#include <uuid/uuid.h>
@@ -15,16 +16,23 @@ static void unlock_usage(void)
"Usage: bcachefs unlock [OPTION] device\n"
"\n"
"Options:\n"
- " -c Check if a device is encrypted\n"
- " -k (session|user|user_session)\n"
+ " -c, --check Check if a device is encrypted\n"
+ " -k, --keyring (session|user|user_session)\n"
" Keyring to add to (default: user)\n"
- " -f Passphrase file to read from (disables passphrase prompt)\n"
- " -h Display this help and exit\n"
+ " -f, --file Passphrase file to read from (disables passphrase prompt)\n"
+ " -h, --help Display this help and exit\n"
"Report bugs to <linux-bcachefs@vger.kernel.org>");
}
int cmd_unlock(int argc, char *argv[])
{
+ static const struct option longopts[] = {
+ { "check", no_argument, NULL, 'c' },
+ { "keyring", required_argument, NULL, 'k' },
+ { "file", required_argument, NULL, 'f' },
+ { "help", no_argument, NULL, 'h' },
+ { NULL }
+ };
const char *keyring = "user";
bool check = false;
const char *passphrase_file_path = NULL;
@@ -32,7 +40,7 @@ int cmd_unlock(int argc, char *argv[])
int opt;
- while ((opt = getopt(argc, argv, "cf:k:h")) != -1)
+ while ((opt = getopt_long(argc, argv, "cf:k:h", longopts, NULL)) != -1)
switch (opt) {
case 'c':
check = true;
diff --git a/c_src/cmd_kill_btree_node.c b/c_src/cmd_kill_btree_node.c
index 81dbdd4b..817cd580 100644
--- a/c_src/cmd_kill_btree_node.c
+++ b/c_src/cmd_kill_btree_node.c
@@ -1,4 +1,5 @@
#include <fcntl.h>
+#include <getopt.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -20,9 +21,8 @@ static void kill_btree_node_usage(void)
"Usage: bcachefs kill_btree_node [OPTION]... <devices>\n"
"\n"
"Options:\n"
- " -b (extents|inodes|dirents|xattrs) Btree to delete from\n"
- " -l level Levle to delete from (0 == leaves)\n"
- " -i index Index of btree node to kill\n"
+ " -n, --node btree:level:idx Node to kill\n"
+ " -d, --dev dev Device index (default: kill all replicas)\n"
" -h Display this help and exit\n"
"Report bugs to <linux-bcachefs@vger.kernel.org>");
}
@@ -35,13 +35,19 @@ struct kill_node {
int cmd_kill_btree_node(int argc, char *argv[])
{
+ static const struct option longopts[] = {
+ { "node", required_argument, NULL, 'n' },
+ { "dev", required_argument, NULL, 'd' },
+ { "help", no_argument, NULL, 'h' },
+ { NULL }
+ };
struct bch_opts opts = bch2_opts_empty();
DARRAY(struct kill_node) kill_nodes = {};
- int opt;
+ int opt, dev_idx = -1;
opt_set(opts, read_only, true);
- while ((opt = getopt(argc, argv, "n:h")) != -1)
+ while ((opt = getopt_long(argc, argv, "n:d:h", longopts, NULL)) != -1)
switch (opt) {
case 'n': {
char *p = optarg;
@@ -65,6 +71,10 @@ int cmd_kill_btree_node(int argc, char *argv[])
darray_push(&kill_nodes, n);
break;
}
+ case 'd':
+ if (kstrtoint(optarg, 10, &dev_idx))
+ die("invalid device index %s", optarg);
+ break;
case 'h':
kill_btree_node_usage();
exit(EXIT_SUCCESS);
@@ -96,20 +106,24 @@ int cmd_kill_btree_node(int argc, char *argv[])
int ret2 = 0;
if (!i->idx) {
- struct printbuf buf = PRINTBUF;
- bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(&b->key));
- bch_info(c, "killing btree node %s l=%u %s",
- bch2_btree_id_str(i->btree), i->level, buf.buf);
- printbuf_exit(&buf);
-
ret2 = 1;
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(bkey_i_to_s_c(&b->key));
bkey_for_each_ptr(ptrs, ptr) {
+ if (dev_idx >= 0 && ptr->dev != dev_idx)
+ continue;
+
struct bch_dev *ca = bch2_dev_tryget(c, ptr->dev);
if (!ca)
continue;
+ struct printbuf buf = PRINTBUF;
+ bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(&b->key));
+ bch_info(c, "killing btree node on dev %i %s l=%u\n %s",
+ ptr->dev,
+ bch2_btree_id_str(i->btree), i->level, buf.buf);
+ printbuf_exit(&buf);
+
int ret3 = pwrite(ca->disk_sb.bdev->bd_fd, zeroes,
c->opts.block_size, ptr->offset << 9);
bch2_dev_put(ca);
diff --git a/c_src/cmd_list_journal.c b/c_src/cmd_list_journal.c
index e6d2bc20..5f91337d 100644
--- a/c_src/cmd_list_journal.c
+++ b/c_src/cmd_list_journal.c
@@ -81,7 +81,10 @@ typedef struct {
typedef struct {
bool blacklisted;
+ bool flush_only;
+ bool datetime_only;
bool log;
+ bool log_only;
bool print_offset;
bool filtering;
u64 btree_filter;
@@ -208,6 +211,17 @@ static bool entry_is_log_only(struct jset_entry *entry, struct jset_entry *end)
return have_log;
}
+static bool entry_has_log(struct jset_entry *entry, struct jset_entry *end)
+{
+ for (entry = vstruct_next(entry);
+ entry != end;
+ entry = vstruct_next(entry))
+ if (entry_is_log_msg(entry))
+ return true;
+
+ return false;
+}
+
static struct jset_entry *transaction_end(struct jset_entry *entry, struct jset_entry *end)
{
do
@@ -230,6 +244,9 @@ static bool should_print_transaction(journal_filter f,
if (f.log && entry_is_log_only(entry, end))
return true;
+ if (f.log_only && !entry_has_log(entry, end))
+ return false;
+
if (f.btree_filter != ~0ULL &&
!transaction_matches_btree_filter(f, entry, end))
return false;
@@ -343,9 +360,23 @@ static void journal_replay_print(struct bch_fs *c,
bch2_journal_seq_is_blacklisted(c, le64_to_cpu(p->j.seq), false);
bool printed_header = false;
- if (f.btree_filter == ~0ULL &&
- !f.transaction.f.nr &&
- !f.key.f.nr)
+ if (f.datetime_only) {
+ prt_printf(&buf,
+ "%s"
+ "journal entry %-8llu ",
+ blacklisted ? "blacklisted " : "",
+ le64_to_cpu(p->j.seq));
+ vstruct_for_each(&p->j, entry)
+ if (entry->type == BCH_JSET_ENTRY_datetime) {
+ bch2_journal_entry_to_text(&buf, c, entry);
+ break;
+ }
+
+ prt_newline(&buf);
+ goto print;
+ }
+
+ if (!f.filtering)
journal_entry_header_to_text(&buf, c, p, blacklisted, &printed_header);
struct jset_entry *entry = p->j.start;
@@ -382,11 +413,11 @@ static void journal_replay_print(struct bch_fs *c,
print_one_entry(&buf, c, f, p, blacklisted, &printed_header, entry);
entry = vstruct_next(entry);
}
-
+print:
if (buf.buf) {
if (blacklisted)
star_start_of_lines(buf.buf);
- write(STDOUT_FILENO, buf.buf, buf.pos);
+ fwrite(buf.buf, 1, buf.pos, stdout);
}
printbuf_exit(&buf);
}
@@ -397,9 +428,13 @@ static void list_journal_usage(void)
"Usage: bcachefs list_journal [OPTION]... <devices>\n"
"\n"
"Options:\n"
- " -a Read entire journal, not just dirty entries\n"
+ " -a, --all Read entire journal, not just contiguous entries\n"
+ " -d, --dirty-only Only read dirty entries\n"
" -B, --blacklisted Include blacklisted entries\n"
+ " -F, --flush-only Only print flush entries/commits\n"
+ " -D, --datetime Print datetime entries only\n"
" -l, --log When filtering, include log-only entries\n"
+ " -L, --log-only Only print transactions containing log messages\n"
" -o, --offset Print offset of each subentry\n"
" -n, --nr-entries=nr Number of journal entries to print, starting from the most recent\n"
" -b, --btree=(+|-)btree1,btree2 Filter keys matching or not updating btree(s)\n"
@@ -414,9 +449,14 @@ static void list_journal_usage(void)
int cmd_list_journal(int argc, char *argv[])
{
static const struct option longopts[] = {
+ { "all", no_argument, NULL, 'a' },
+ { "dirty-only", no_argument, NULL, 'd' },
{ "nr-entries", required_argument, NULL, 'n' },
{ "blacklisted", no_argument, NULL, 'B' },
+ { "flush-only", no_argument, NULL, 'F' },
+ { "datetime", no_argument, NULL, 'D' },
{ "log", no_argument, NULL, 'l' },
+ { "log-only", no_argument, NULL, 'L' },
{ "offset", no_argument, NULL, 'o' },
{ "btree", required_argument, NULL, 'b' },
{ "transaction", required_argument, NULL, 't' },
@@ -427,8 +467,9 @@ int cmd_list_journal(int argc, char *argv[])
{ NULL }
};
struct bch_opts opts = bch2_opts_empty();
- u32 nr_entries = U32_MAX;
+ u32 nr_entries = 0;
journal_filter f = { .btree_filter = ~0ULL, .bkey_val = true };
+ bool contiguous_only = true;
char *t;
int opt, ret;
@@ -441,12 +482,16 @@ int cmd_list_journal(int argc, char *argv[])
opt_set(opts, fix_errors, FSCK_FIX_yes);
opt_set(opts, retain_recovery_info ,true);
opt_set(opts, read_journal_only,true);
+ opt_set(opts, read_entire_journal, true);
- while ((opt = getopt_long(argc, argv, "an:Blob:t:k:V:vh",
+ while ((opt = getopt_long(argc, argv, "adn:BFMDlLob:t:k:V:vh",
longopts, NULL)) != -1)
switch (opt) {
case 'a':
- opt_set(opts, read_entire_journal, true);
+ contiguous_only = false;
+ break;
+ case 'd':
+ opt_set(opts, read_entire_journal, false);
break;
case 'n':
if (kstrtouint(optarg, 10, &nr_entries))
@@ -456,9 +501,19 @@ int cmd_list_journal(int argc, char *argv[])
case 'B':
f.blacklisted = true;
break;
+ case 'F':
+ f.flush_only = true;
+ break;
+ case 'D':
+ f.datetime_only = true;
+ break;
case 'l':
f.log = true;
break;
+ case 'L':
+ f.log_only = true;
+ f.filtering = true;
+ break;
case 'o':
f.print_offset = true;
break;
@@ -508,17 +563,62 @@ int cmd_list_journal(int argc, char *argv[])
struct journal_replay *p, **_p;
struct genradix_iter iter;
+ u64 min_seq_to_print = 0;
+
+ if (contiguous_only) {
+ u64 seq = 0;
+ genradix_for_each(&c->journal_entries, iter, _p) {
+ p = *_p;
+ if (!p)
+ continue;
+
+ if (!seq)
+ seq = le64_to_cpu(p->j.seq);
+
+ struct u64_range missing;
+ while ((missing = bch2_journal_entry_missing_range(c, seq, le64_to_cpu(p->j.seq))).start)
+ seq = min_seq_to_print = missing.end;
+
+ seq = le64_to_cpu(p->j.seq) + 1;
+ }
+ }
+
+ if (nr_entries)
+ min_seq_to_print = max_t(s64, min_seq_to_print,
+ atomic64_read(&c->journal.seq) - nr_entries);
+
+ u64 seq = 0;
genradix_for_each(&c->journal_entries, iter, _p) {
p = *_p;
if (!p)
continue;
- if (le64_to_cpu(p->j.seq) + nr_entries < atomic64_read(&c->journal.seq))
+
+ if (le64_to_cpu(p->j.seq) < min_seq_to_print)
continue;
+
+ if (!seq)
+ seq = le64_to_cpu(p->j.seq);
+
+ struct u64_range missing;
+ while ((missing = bch2_journal_entry_missing_range(c, seq, le64_to_cpu(p->j.seq))).start) {
+ printf("missing %llu entries at %llu-%llu%s\n",
+ missing.end - missing.start,
+ missing.start, missing.end - 1,
+ missing.end < c->journal.last_seq_ondisk ? " (not dirty)" : "");
+ seq = missing.end;
+ }
+
+ seq = le64_to_cpu(p->j.seq) + 1;
+
if (!f.blacklisted &&
(p->ignore_blacklisted ||
bch2_journal_seq_is_blacklisted(c, le64_to_cpu(p->j.seq), false)))
continue;
+ if (f.flush_only &&
+ JSET_NO_FLUSH(&p->j))
+ continue;
+
journal_replay_print(c, f, p);
}
diff --git a/c_src/cmd_migrate.c b/c_src/cmd_migrate.c
index 91c42302..0d24018c 100644
--- a/c_src/cmd_migrate.c
+++ b/c_src/cmd_migrate.c
@@ -370,19 +370,25 @@ static void migrate_superblock_usage(void)
"Usage: bcachefs migrate-superblock [OPTION]...\n"
"\n"
"Options:\n"
- " -d device Device to create superblock for\n"
- " -o offset Offset of existing superblock\n"
- " -h Display this help and exit\n"
+ " -d, --dev device Device to create superblock for\n"
+ " -o, --offset offset Offset of existing superblock\n"
+ " -h, --help Display this help and exit\n"
"Report bugs to <linux-bcachefs@vger.kernel.org>");
}
int cmd_migrate_superblock(int argc, char *argv[])
{
+ static const struct option longopts[] = {
+ { "dev", required_argument, NULL, 'd' },
+ { "offset", required_argument, NULL, 'o' },
+ { "help", no_argument, NULL, 'h' },
+ { NULL }
+ };
darray_const_str devs = {};
u64 sb_offset = 0;
int opt, ret;
- while ((opt = getopt(argc, argv, "d:o:h")) != -1)
+ while ((opt = getopt_long(argc, argv, "d:o:h", longopts, NULL)) != -1)
switch (opt) {
case 'd':
darray_push(&devs, optarg);