/* * This file is part of the Distributed Network Block Device 3 * * Copyright(c) 2011-2012 Johann Latocha * Copyright(c) 2019 Frederic Robra * * This file may be licensed under the terms of of the * GNU General Public License Version 2 (the ``GPL''). * * Software distributed under the License is distributed * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either * express or implied. See the GPL for the specific language * governing rights and limitations. * * You should have received a copy of the GPL along with this * program. If not, go to http://www.gnu.org/licenses/gpl.html * or write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "sysfs.h" #include #include "utils.h" #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif ssize_t show_initial_server_addr(char *buf, struct dnbd3_device *dev) { if (dev->initial_server.host.type == HOST_IP4) return MIN(snprintf(buf, PAGE_SIZE, "%pI4,%d\n", dev->initial_server.host.addr, (int)ntohs(dev->initial_server.host.port)), PAGE_SIZE); else if (dev->initial_server.host.type == HOST_IP6) return MIN(snprintf(buf, PAGE_SIZE, "%pI6,%d\n", dev->initial_server.host.addr, (int)ntohs(dev->initial_server.host.port)), PAGE_SIZE); *buf = '\0'; return 0; } ssize_t show_connected_servers(char *buf, struct dnbd3_device *dev) { int i, size = PAGE_SIZE, ret; for (i = 0; i < dev->number_connections; ++i) { if (dev->socks[i].sock) { if (dev->socks[i].server->host.type == HOST_IP4) { ret = MIN(snprintf(buf, size, "%pI4,%d,%llu,%d\n", dev->socks[i].server->host.addr, (int)ntohs(dev->socks[i].server->host.port), dev->socks[i].server->avg_rtt, (int)dev->socks[i].server->failures) , size); } else { ret = MIN(snprintf(buf, size, "%pI6,%d,%llu,%d\n", dev->socks[i].server->host.addr, (int)ntohs(dev->socks[i].server->host.port), dev->socks[i].server->avg_rtt, (int)dev->socks[i].server->failures) , size); } size -= ret; buf += ret; if (size <= 0) { size = 0; break; } } } return PAGE_SIZE - size; } //ssize_t show_cur_server_rtt(char *buf, dnbd3_devic *dev) //{ // return MIN(snprintf(buf, PAGE_SIZE, "%llu\n", (unsigned long long)dev->cur_rtt), PAGE_SIZE); //} ssize_t show_alt_server_num(char *buf, struct dnbd3_device *dev) { int i, num = 0; for (i = 0; i < NUMBER_SERVERS; i++) { if (dev->alt_servers[i].host.type) { num++; } } return MIN(snprintf(buf, PAGE_SIZE, "%d\n", num), PAGE_SIZE); } ssize_t show_alt_servers(char *buf, struct dnbd3_device *dev) { int i, size = PAGE_SIZE, ret; for (i = 0; i < NUMBER_SERVERS; ++i) { if (dev->alt_servers[i].host.type == HOST_IP4) { ret = MIN(snprintf(buf, size, "%pI4,%d,%llu,%d\n", dev->alt_servers[i].host.addr, (int)ntohs(dev->alt_servers[i].host.port), dev->alt_servers[i].avg_rtt, (int)dev->alt_servers[i].failures) , size); } else if (dev->alt_servers[i].host.type == HOST_IP6) { ret = MIN(snprintf(buf, size, "%pI6,%d,%llu,%d\n", dev->alt_servers[i].host.addr, (int)ntohs(dev->alt_servers[i].host.port), dev->alt_servers[i].avg_rtt, (int)dev->alt_servers[i].failures) , size); } else { continue; } size -= ret; buf += ret; if (size <= 0) { size = 0; break; } } return PAGE_SIZE - size; } ssize_t show_image_name(char *buf, struct dnbd3_device *dev) { if (dev->imgname == NULL) return sprintf(buf, "(null)"); return MIN(snprintf(buf, PAGE_SIZE, "%s\n", dev->imgname), PAGE_SIZE); } ssize_t show_rid(char *buf, struct dnbd3_device *dev) { return MIN(snprintf(buf, PAGE_SIZE, "%d\n", dev->rid), PAGE_SIZE); } ssize_t show_update_available(char *buf, struct dnbd3_device *dev) { return MIN(snprintf(buf, PAGE_SIZE, "%d\n", dev->update_available), PAGE_SIZE); } struct device_attr_t initial_server = { .attr = {.name = "initial_server", .mode = 0444 }, .show = show_initial_server_addr, .store = NULL, }; struct device_attr_t connected_server = { .attr = {.name = "connected_server", .mode = 0444 }, .show = show_connected_servers, .store = NULL, }; //device_attr_t cur_server_rtt = //{ // .attr = {.name = "cur_server_rtt", .mode = 0444 }, // .show = show_cur_server_rtt, // .store = NULL, //}; struct device_attr_t alt_server_num = { .attr = {.name = "alt_server_num", .mode = 0444 }, .show = show_alt_server_num, .store = NULL, }; struct device_attr_t alt_servers = { .attr = {.name = "alt_servers", .mode = 0444 }, .show = show_alt_servers, .store = NULL, }; struct device_attr_t image_name = { .attr = {.name = "image_name", .mode = 0444 }, .show = show_image_name, .store = NULL, }; struct device_attr_t rid = { .attr = {.name = "rid", .mode = 0444 }, .show = show_rid, .store = NULL, }; struct device_attr_t update_available = { .attr = {.name = "update_available", .mode = 0444 }, .show = show_update_available, .store = NULL, }; ssize_t device_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct device_attr_t *device_attr = container_of(attr, struct device_attr_t, attr); struct dnbd3_device *dev = container_of(kobj, struct dnbd3_device, kobj); return device_attr->show(buf, dev); } struct attribute *device_attrs[] = { &initial_server.attr, &connected_server.attr, // &cur_server_rtt.attr, &alt_server_num.attr, &alt_servers.attr, &image_name.attr, &rid.attr, &update_available.attr, NULL, }; struct sysfs_ops device_ops = { .show = device_show, }; static void release(struct kobject *kobj) { kobj->state_initialized = 0; } struct kobj_type device_ktype = { .default_attrs = device_attrs, .sysfs_ops = &device_ops, .release = release, }; void dnbd3_sysfs_init(struct dnbd3_device *dev) { int error; struct kobject *kobj = &dev->kobj; struct kobj_type *ktype = &device_ktype; struct kobject *parent = &disk_to_dev(dev->disk)->kobj; error = kobject_init_and_add(kobj, ktype, parent, "%s", "net"); if (error) error_dev(dev, "kobject initializing failed"); } void dnbd3_sysfs_exit(struct dnbd3_device *dev) { kobject_put(&dev->kobj); }