[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250107103024.326986-3-dongsheng.yang@linux.dev>
Date: Tue, 7 Jan 2025 10:30:18 +0000
From: Dongsheng Yang <dongsheng.yang@...ux.dev>
To: axboe@...nel.dk,
dan.j.williams@...el.com,
gregory.price@...verge.com,
John@...ves.net,
Jonathan.Cameron@...wei.com,
bbhushan2@...vell.com,
chaitanyak@...dia.com,
rdunlap@...radead.org
Cc: linux-block@...r.kernel.org,
linux-kernel@...r.kernel.org,
linux-cxl@...r.kernel.org,
linux-bcache@...r.kernel.org,
Dongsheng Yang <dongsheng.yang@...ux.dev>
Subject: [PATCH v3 2/8] cbd: introduce cbd_host
The "cbd_host" represents a host node. Each node needs to be registered
before it can use the "cbd_transport". After registration, the node's
information, such as its hostname, will be recorded in the "hosts" area
of this transport. Through this mechanism, we can know which nodes are
currently using each transport.
If a host dies without unregistering, we allow the user to clear this
host entry in the metadata.
Signed-off-by: Dongsheng Yang <dongsheng.yang@...ux.dev>
---
drivers/block/cbd/cbd_host.c | 227 +++++++++++++++++++++++++++++++++++
drivers/block/cbd/cbd_host.h | 67 +++++++++++
2 files changed, 294 insertions(+)
create mode 100644 drivers/block/cbd/cbd_host.c
create mode 100644 drivers/block/cbd/cbd_host.h
diff --git a/drivers/block/cbd/cbd_host.c b/drivers/block/cbd/cbd_host.c
new file mode 100644
index 000000000000..da854ba1b747
--- /dev/null
+++ b/drivers/block/cbd/cbd_host.c
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "cbd_host.h"
+#include "cbd_blkdev.h"
+#include "cbd_backend.h"
+
+static ssize_t hostname_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct cbd_host_device *host_dev;
+ struct cbd_host_info *host_info;
+
+ host_dev = container_of(dev, struct cbd_host_device, dev);
+ host_info = cbdt_host_info_read(host_dev->cbdt, host_dev->id);
+ if (!host_info)
+ return 0;
+
+ if (host_info->state == CBD_HOST_STATE_NONE)
+ return 0;
+
+ return sprintf(buf, "%s\n", host_info->hostname);
+}
+static DEVICE_ATTR_ADMIN_RO(hostname);
+
+static void host_info_write(struct cbd_host *host);
+static void cbd_host_hb(struct cbd_host *host)
+{
+ host_info_write(host);
+}
+CBD_OBJ_HEARTBEAT(host);
+
+static struct attribute *cbd_host_attrs[] = {
+ &dev_attr_hostname.attr,
+ &dev_attr_alive.attr,
+ NULL
+};
+
+static struct attribute_group cbd_host_attr_group = {
+ .attrs = cbd_host_attrs,
+};
+
+static const struct attribute_group *cbd_host_attr_groups[] = {
+ &cbd_host_attr_group,
+ NULL
+};
+
+static void cbd_host_release(struct device *dev)
+{
+}
+
+const struct device_type cbd_host_type = {
+ .name = "cbd_host",
+ .groups = cbd_host_attr_groups,
+ .release = cbd_host_release,
+};
+
+const struct device_type cbd_hosts_type = {
+ .name = "cbd_hosts",
+ .release = cbd_host_release,
+};
+
+static void host_info_write(struct cbd_host *host)
+{
+ mutex_lock(&host->info_lock);
+ host->host_info.alive_ts = ktime_get_real();
+ cbdt_host_info_write(host->cbdt, &host->host_info, sizeof(struct cbd_host_info),
+ host->host_id);
+ mutex_unlock(&host->info_lock);
+}
+
+static int host_register_validate(struct cbd_transport *cbdt, char *hostname, u32 *host_id)
+{
+ struct cbd_host_info *host_info;
+ u32 host_id_tmp;
+ int ret;
+ u32 i;
+
+ if (cbdt->host)
+ return -EEXIST;
+
+ if (strlen(hostname) == 0) {
+ cbdt_err(cbdt, "hostname is empty\n");
+ return -EINVAL;
+ }
+
+ if (*host_id == UINT_MAX) {
+ ret = cbd_host_find_id_by_name(cbdt, hostname, host_id);
+ if (!ret)
+ goto host_id_found;
+
+ /* In single-host case, set the host_id to 0 */
+ if (cbdt_is_single_host(cbdt)) {
+ *host_id = 0;
+ } else {
+ ret = cbdt_get_empty_host_id(cbdt, host_id);
+ if (ret) {
+ cbdt_err(cbdt, "no available host id found.\n");
+ return -EBUSY;
+ }
+ }
+ }
+
+host_id_found:
+ if (*host_id >= cbdt->transport_info.host_num) {
+ cbdt_err(cbdt, "host_id: %u is too large, host_num: %u\n",
+ *host_id, cbdt->transport_info.host_num);
+ return -EINVAL;
+ }
+
+ /* check for duplicated hostname */
+ ret = cbd_host_find_id_by_name(cbdt, hostname, &host_id_tmp);
+ if (!ret && (host_id_tmp != *host_id)) {
+ cbdt_err(cbdt, "duplicated hostname: %s with host: %u\n", hostname, i);
+ return -EINVAL;
+ }
+
+ host_info = cbdt_host_info_read(cbdt, *host_id);
+ if (host_info && cbd_host_info_is_alive(host_info)) {
+ pr_err("host id %u is still alive\n", *host_id);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+int cbd_host_register(struct cbd_transport *cbdt, char *hostname, u32 host_id)
+{
+ struct cbd_host *host;
+ int ret;
+
+ ret = host_register_validate(cbdt, hostname, &host_id);
+ if (ret)
+ return ret;
+
+ host = kzalloc(sizeof(struct cbd_host), GFP_KERNEL);
+ if (!host)
+ return -ENOMEM;
+
+ host->cbdt = cbdt;
+ host->host_id = host_id;
+ mutex_init(&host->info_lock);
+ INIT_DELAYED_WORK(&host->hb_work, host_hb_workfn);
+
+ host->host_info.state = CBD_HOST_STATE_RUNNING;
+ memcpy(host->host_info.hostname, hostname, CBD_NAME_LEN);
+
+ cbdt->host = host;
+
+ host_info_write(host);
+ queue_delayed_work(cbd_wq, &host->hb_work, 0);
+
+ return 0;
+}
+
+static bool host_backends_stopped(struct cbd_transport *cbdt, u32 host_id)
+{
+ struct cbd_backend_info *backend_info;
+ u32 i;
+
+ cbd_for_each_backend_info(cbdt, i, backend_info) {
+ if (!backend_info || backend_info->state != CBD_BACKEND_STATE_RUNNING)
+ continue;
+
+ if (backend_info->host_id == host_id) {
+ cbdt_err(cbdt, "backend %u is still on host %u\n", i, host_id);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool host_blkdevs_stopped(struct cbd_transport *cbdt, u32 host_id)
+{
+ struct cbd_blkdev_info *blkdev_info;
+ int i;
+
+ cbd_for_each_blkdev_info(cbdt, i, blkdev_info) {
+ if (!blkdev_info || blkdev_info->state != CBD_BLKDEV_STATE_RUNNING)
+ continue;
+
+ if (blkdev_info->host_id == host_id) {
+ cbdt_err(cbdt, "blkdev %u is still on host %u\n", i, host_id);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void cbd_host_unregister(struct cbd_transport *cbdt)
+{
+ struct cbd_host *host = cbdt->host;
+
+ if (!host) {
+ cbd_err("This host is not registered.");
+ return;
+ }
+
+ cancel_delayed_work_sync(&host->hb_work);
+ cbdt_host_info_clear(cbdt, host->host_id);
+ cbdt->host = NULL;
+ kfree(host);
+}
+
+int cbd_host_clear(struct cbd_transport *cbdt, u32 host_id)
+{
+ struct cbd_host_info *host_info;
+
+ host_info = cbdt_get_host_info(cbdt, host_id);
+ if (cbd_host_info_is_alive(host_info)) {
+ cbdt_err(cbdt, "host %u is still alive\n", host_id);
+ return -EBUSY;
+ }
+
+ if (host_info->state == CBD_HOST_STATE_NONE)
+ return 0;
+
+ if (!host_blkdevs_stopped(cbdt, host_id) ||
+ !host_backends_stopped(cbdt, host_id))
+ return -EBUSY;
+
+ cbdt_host_info_clear(cbdt, host_id);
+
+ return 0;
+}
diff --git a/drivers/block/cbd/cbd_host.h b/drivers/block/cbd/cbd_host.h
new file mode 100644
index 000000000000..859e1b9169d9
--- /dev/null
+++ b/drivers/block/cbd/cbd_host.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _CBD_HOST_H
+#define _CBD_HOST_H
+
+#include "cbd_internal.h"
+#include "cbd_transport.h"
+
+CBD_DEVICE(host);
+
+#define CBD_HOST_STATE_NONE 0
+#define CBD_HOST_STATE_RUNNING 1
+
+struct cbd_host_info {
+ struct cbd_meta_header meta_header;
+ u8 state;
+ u8 res;
+
+ u16 res1;
+ u32 res2;
+ u64 alive_ts;
+ char hostname[CBD_NAME_LEN];
+};
+
+struct cbd_host {
+ u32 host_id;
+ struct cbd_transport *cbdt;
+
+ struct cbd_host_device *dev;
+
+ struct cbd_host_info host_info;
+ struct mutex info_lock;
+
+ struct delayed_work hb_work; /* heartbeat work */
+};
+
+int cbd_host_register(struct cbd_transport *cbdt, char *hostname, u32 host_id);
+void cbd_host_unregister(struct cbd_transport *cbdt);
+int cbd_host_clear(struct cbd_transport *cbdt, u32 host_id);
+bool cbd_host_info_is_alive(struct cbd_host_info *info);
+
+#define cbd_for_each_host_info(cbdt, i, host_info) \
+ for (i = 0; \
+ i < cbdt->transport_info.host_num && \
+ (host_info = cbdt_host_info_read(cbdt, i)); \
+ i++)
+
+static inline int cbd_host_find_id_by_name(struct cbd_transport *cbdt, char *hostname, u32 *host_id)
+{
+ struct cbd_host_info *host_info;
+ u32 i;
+
+ cbd_for_each_host_info(cbdt, i, host_info) {
+ if (!host_info)
+ continue;
+
+ if (strcmp(host_info->hostname, hostname) == 0) {
+ *host_id = i;
+ goto found;
+ }
+ }
+
+ return -ENOENT;
+found:
+ return 0;
+}
+
+#endif /* _CBD_HOST_H */
--
2.34.1
Powered by blists - more mailing lists