diff --git a/kmod/src/quorum.c b/kmod/src/quorum.c index 87cdd186..f24f4e03 100644 --- a/kmod/src/quorum.c +++ b/kmod/src/quorum.c @@ -29,6 +29,7 @@ #include "quorum.h" #include "server.h" #include "net.h" +#include "sysfs.h" #include "scoutfs_trace.h" /* @@ -63,6 +64,19 @@ * - add config rotation (write new config, reclaim stale slots) */ +struct quorum_info { + struct scoutfs_sysfs_attrs ssa; + + bool is_leader; + struct sockaddr_in conf_addr; + u16 conf_port; +}; + +#define DECLARE_QUORUM_INFO(sb, name) \ + struct quorum_info *name = SCOUTFS_SB(sb)->quorum_info +#define DECLARE_QUORUM_INFO_KOBJ(kobj, name) \ + DECLARE_QUORUM_INFO(SCOUTFS_SYSFS_ATTRS_SB(kobj), name) + static void addr_to_sin(struct sockaddr_in *sin, struct scoutfs_inet_addr *addr) { sin->sin_family = AF_INET; @@ -527,6 +541,7 @@ int scoutfs_quorum_election(struct super_block *sb, char *our_name, bool unmounting, u64 our_umb, struct scoutfs_quorum_elected_info *qei) { + DECLARE_QUORUM_INFO(sb, qinf); struct scoutfs_super_block *super = NULL; struct scoutfs_quorum_config *conf; struct scoutfs_quorum_slot *slot; @@ -566,6 +581,16 @@ int scoutfs_quorum_election(struct super_block *sb, char *our_name, goto out; conf = &super->quorum_config; + /* update sysfs with most recently seen config */ + if (our_slot >= 0) { + slot = &conf->slots[our_slot]; + addr_to_sin(&qinf->conf_addr, &slot->addr); + qinf->conf_port = le16_to_cpu(slot->addr.port); + } else { + memset(&qinf->conf_addr, 0, sizeof(qinf->conf_addr)); + qinf->conf_port = 0; + } + majority = scoutfs_quorum_majority(sb, conf); readahead_quorum_blocks(sb); @@ -623,6 +648,7 @@ int scoutfs_quorum_election(struct super_block *sb, char *our_name, elected_nr); if (ret == 0) { qei->run_server = true; + qinf->is_leader = true; goto out; } @@ -739,8 +765,10 @@ int scoutfs_quorum_clear_elected(struct super_block *sb, struct scoutfs_quorum_elected_info *qei) { struct scoutfs_super_block *super = &SCOUTFS_SB(sb)->super; + DECLARE_QUORUM_INFO(sb, qinf); qei->flags &= ~SCOUTFS_QUORUM_BLOCK_FLAG_ELECTED; + qinf->is_leader = false; return write_quorum_block(sb, super->hdr.fsid, qei->config_gen, qei->config_slot, qei->write_nr, @@ -807,3 +835,73 @@ bool scoutfs_quorum_voting_member(struct super_block *sb, return false; } + +static ssize_t is_leader_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + DECLARE_QUORUM_INFO_KOBJ(kobj, qinf); + + return snprintf(buf, PAGE_SIZE, "%u", !!qinf->is_leader); +} +SCOUTFS_ATTR_RO(is_leader); + +static ssize_t ipv4_addr_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + DECLARE_QUORUM_INFO_KOBJ(kobj, qinf); + + return snprintf(buf, PAGE_SIZE, "%pIS", &qinf->conf_addr); +} +SCOUTFS_ATTR_RO(ipv4_addr); + +static ssize_t ipv4_port_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + DECLARE_QUORUM_INFO_KOBJ(kobj, qinf); + + return snprintf(buf, PAGE_SIZE, "%u", qinf->conf_port); +} +SCOUTFS_ATTR_RO(ipv4_port); + +static struct attribute *quorum_attrs[] = { + SCOUTFS_ATTR_PTR(is_leader), + SCOUTFS_ATTR_PTR(ipv4_addr), + SCOUTFS_ATTR_PTR(ipv4_port), + NULL, +}; + +int scoutfs_quorum_setup(struct super_block *sb) +{ + struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); + struct quorum_info *qinf; + int ret; + + qinf = kzalloc(sizeof(struct quorum_info), GFP_KERNEL); + if (!qinf) { + ret = -ENOMEM; + goto out; + } + scoutfs_sysfs_init_attrs(sb, &qinf->ssa); + + sbi->quorum_info = qinf; + + ret = scoutfs_sysfs_create_attrs(sb, &qinf->ssa, quorum_attrs, + "quorum"); +out: + if (ret) + scoutfs_quorum_destroy(sb); + + return 0; +} + +void scoutfs_quorum_destroy(struct super_block *sb) +{ + struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); + struct quorum_info *qinf = SCOUTFS_SB(sb)->quorum_info; + + if (qinf) { + scoutfs_sysfs_destroy_attrs(sb, &qinf->ssa); + kfree(qinf); + sbi->quorum_info = NULL; + } +} diff --git a/kmod/src/quorum.h b/kmod/src/quorum.h index 26a45b5b..e558d326 100644 --- a/kmod/src/quorum.h +++ b/kmod/src/quorum.h @@ -27,4 +27,6 @@ bool scoutfs_quorum_voting_member(struct super_block *sb, struct scoutfs_quorum_config *conf, char *name); +int scoutfs_quorum_setup(struct super_block *sb); +void scoutfs_quorum_destroy(struct super_block *sb); #endif diff --git a/kmod/src/super.c b/kmod/src/super.c index ff39a6fb..73e6bcb3 100644 --- a/kmod/src/super.c +++ b/kmod/src/super.c @@ -44,6 +44,7 @@ #include "server.h" #include "options.h" #include "sysfs.h" +#include "quorum.h" #include "scoutfs_trace.h" static struct dentry *scoutfs_debugfs_root; @@ -161,6 +162,7 @@ static void scoutfs_put_super(struct super_block *sb) scoutfs_shutdown_trans(sb); scoutfs_client_destroy(sb); + scoutfs_quorum_destroy(sb); scoutfs_inode_destroy(sb); /* the server locks the listen address and compacts */ @@ -371,6 +373,7 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent) scoutfs_setup_trans(sb) ?: scoutfs_lock_setup(sb) ?: scoutfs_net_setup(sb) ?: + scoutfs_quorum_setup(sb) ?: scoutfs_server_setup(sb) ?: scoutfs_client_setup(sb) ?: scoutfs_client_wait_node_id(sb) ?: diff --git a/kmod/src/super.h b/kmod/src/super.h index 6dd03ac6..d34f4844 100644 --- a/kmod/src/super.h +++ b/kmod/src/super.h @@ -46,6 +46,7 @@ struct scoutfs_sb_info { struct inode_sb_info *inode_sb_info; struct btree_info *btree_info; struct net_info *net_info; + struct quorum_info *quorum_info; wait_queue_head_t trans_hold_wq; struct task_struct *trans_task;