free(r);
}
+void nvme_root_release_fds(nvme_root_t r)
+{
+ struct nvme_host *h, *_h;
+
+ nvme_for_each_host_safe(r, h, _h)
+ nvme_host_release_fds(h);
+}
+
const char *nvme_subsystem_get_nqn(nvme_subsystem_t s)
{
return s->subsysnqn;
static void __nvme_free_ns(struct nvme_ns *n)
{
list_del_init(&n->entry);
- close(n->fd);
+ nvme_ns_release_fd(n);
free(n->generic_name);
free(n->name);
free(n->sysfs_dir);
free(s);
}
+void nvme_subsystem_release_fds(struct nvme_subsystem *s)
+{
+ struct nvme_ctrl *c, *_c;
+ struct nvme_ns *n, *_n;
+
+ nvme_subsystem_for_each_ctrl_safe(s, c, _c)
+ nvme_ctrl_release_fd(c);
+
+ nvme_subsystem_for_each_ns_safe(s, n, _n)
+ nvme_ns_release_fd(n);
+}
+
/*
* Stub for SWIG
*/
free(h);
}
+void nvme_host_release_fds(struct nvme_host *h)
+{
+ struct nvme_subsystem *s, *_s;
+
+ nvme_for_each_subsystem_safe(h, s, _s)
+ nvme_subsystem_release_fds(s);
+}
+
/* Stub for SWIG */
void nvme_free_host(struct nvme_host *h)
{
int nvme_ctrl_get_fd(nvme_ctrl_t c)
{
- nvme_root_t r = c->s && c->s->h ? c->s->h->r : NULL;
-
if (c->fd < 0) {
c->fd = nvme_open(c->name);
if (c->fd < 0)
- nvme_msg(r, LOG_ERR,
+ nvme_msg(root_from_ctrl(c), LOG_ERR,
"Failed to open ctrl %s, errno %d\n",
c->name, errno);
}
return c->fd;
}
+void nvme_ctrl_release_fd(nvme_ctrl_t c)
+{
+ if (c->fd < 0)
+ return;
+
+ close(c->fd);
+ c->fd = -1;
+}
+
nvme_subsystem_t nvme_ctrl_get_subsystem(nvme_ctrl_t c)
{
return c->s;
do { if (a) { free(a); (a) = NULL; } } while (0)
void nvme_deconfigure_ctrl(nvme_ctrl_t c)
{
- if (c->fd >= 0) {
- close(c->fd);
- c->fd = -1;
- }
+ nvme_ctrl_release_fd(c);
FREE_CTRL_ATTR(c->name);
FREE_CTRL_ATTR(c->sysfs_dir);
FREE_CTRL_ATTR(c->firmware);
if (entry->d_type == DT_DIR &&
strncmp(entry->d_name, ".", 1) != 0 &&
strncmp(entry->d_name, "..", 2) != 0) {
- ret = asprintf(&path, "/sys/bus/pci/slots/%s", entry->d_name);
+ ret = asprintf(&path, "%s/%s",
+ nvme_slots_sysfs_dir, entry->d_name);
if (ret < 0) {
errno = ENOMEM;
free(target_addr);
int nvme_ns_get_fd(nvme_ns_t n)
{
+ if (n->fd < 0) {
+ n->fd = nvme_open(n->name);
+ if (n->fd < 0)
+ nvme_msg(root_from_ns(n), LOG_ERR,
+ "Failed to open ns %s, errno %d\n",
+ n->name, errno);
+ }
+
return n->fd;
}
+void nvme_ns_release_fd(nvme_ns_t n)
+{
+ if (n->fd < 0)
+ return;
+
+ close(n->fd);
+ n->fd = -1;
+}
+
nvme_subsystem_t nvme_ns_get_subsystem(nvme_ns_t n)
{
return n->s;
static nvme_ns_t nvme_ns_open(const char *name)
{
struct nvme_ns *n;
+ int fd;
n = calloc(1, sizeof(*n));
if (!n) {
return NULL;
}
+ n->fd = -1;
n->name = strdup(name);
- n->fd = nvme_open(n->name);
- if (n->fd < 0)
+
+ fd = nvme_ns_get_fd(n);
+ if (fd < 0)
goto free_ns;
nvme_ns_set_generic_name(n, name);
- if (nvme_get_nsid(n->fd, &n->nsid) < 0)
- goto close_fd;
+ if (nvme_get_nsid(fd, &n->nsid) < 0)
+ goto free_ns;
if (nvme_ns_init(n) != 0)
- goto close_fd;
+ goto free_ns;
list_head_init(&n->paths);
list_node_init(&n->entry);
+ nvme_ns_release_fd(n); /* Do not leak fds */
return n;
-close_fd:
- close(n->fd);
free_ns:
+ nvme_ns_release_fd(n);
free(n->generic_name);
free(n->name);
free(n);
*/
const char *nvme_root_get_application(nvme_root_t r);
+/**
+ * nvme_root_release_fds - Close all opened file descriptors in the tree
+ * @r: &nvme_root_t object
+ *
+ * Controller and Namespace objects cache the file descriptors
+ * of opened nvme devices. This API can be used to close and
+ * clear all cached fds in the tree.
+ *
+ */
+void nvme_root_release_fds(nvme_root_t r);
+
/**
* nvme_free_tree() - Free root object
* @r: &nvme_root_t object
* nvme_ns_get_fd() - Get associated file descriptor
* @n: Namespace instance
*
+ * libnvme will open() the file (if not already opened) and keep
+ * an internal copy of the file descriptor. Following calls to
+ * this API retrieve the internal cached copy of the file
+ * descriptor. The file will remain opened and the fd will
+ * remain cached until the ns object is deleted or
+ * nvme_ns_release_fd() is called.
+ *
* Return: File descriptor associated with @n or -1
*/
int nvme_ns_get_fd(nvme_ns_t n);
+/**
+ * nvme_ns_release_fd() - Close fd and clear fd from ns object
+ * @n: Namespace instance
+ *
+ */
+void nvme_ns_release_fd(nvme_ns_t n);
+
/**
* nvme_ns_get_nsid() - NSID of a namespace
* @n: Namespace instance
* nvme_ctrl_get_fd() - Get associated file descriptor
* @c: Controller instance
*
+ * libnvme will open() the file (if not already opened) and keep
+ * an internal copy of the file descriptor. Following calls to
+ * this API retrieve the internal cached copy of the file
+ * descriptor. The file will remain opened and the fd will
+ * remain cached until the controller object is deleted or
+ * nvme_ctrl_release_fd() is called.
+ *
* Return: File descriptor associated with @c or -1
*/
int nvme_ctrl_get_fd(nvme_ctrl_t c);
+/**
+ * nvme_ctrl_release_fd() - Close fd and clear fd from controller object
+ * @c: Controller instance
+ *
+ */
+void nvme_ctrl_release_fd(nvme_ctrl_t c);
+
/**
* nvme_ctrl_get_name() - sysfs name of a controller
* @c: Controller instance
*/
const char *nvme_host_get_hostid(nvme_host_t h);
+/**
+ * nvme_host_release_fds() - Close all opened file descriptors under host
+ * @h: nvme_host_t object
+ *
+ * Controller and Namespace objects cache the file descriptors
+ * of opened nvme devices. This API can be used to close and
+ * clear all cached fds under this host.
+ */
+void nvme_host_release_fds(struct nvme_host *h);
+
/**
* nvme_free_host() - Free nvme_host_t object
* @h: nvme_host_t object
nvme_ns_t nvme_subsystem_lookup_namespace(struct nvme_subsystem *s,
__u32 nsid);
+/**
+ * nvme_subsystem_release_fds() - Close all opened fds under subsystem
+ * @s: nvme_subsystem_t object
+ *
+ * Controller and Namespace objects cache the file descriptors
+ * of opened nvme devices. This API can be used to close and
+ * clear all cached fds under this subsystem.
+ *
+ */
+void nvme_subsystem_release_fds(struct nvme_subsystem *s);
+
+
/**
* nvme_get_path_attr() - Read path sysfs attribute
* @p: nvme_path_t object