|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCH v3 6/8] lib/uk9p: Add 9P fid abstraction
This patch adds the uk_9pfid struct, which abstracts the 4-byte fid
number used by the 9p protocol to associate numbers with filesystem
entries (files, directories, etc.)
This patch also adds a fid cache for each 9p device, enabling reuse of
the fids and reducing the amount of memory allocations done.
Signed-off-by: Cristian Banu <cristb@xxxxxxxxx>
---
lib/uk9p/9pdev.c | 109 +++++++++++++++++++++++++++++++++++++
lib/uk9p/9pfid.c | 71 ++++++++++++++++++++++++
lib/uk9p/Makefile.uk | 1 +
lib/uk9p/exportsyms.uk | 8 +++
lib/uk9p/include/uk/9pdev.h | 23 ++++++++
lib/uk9p/include/uk/9pdev_core.h | 20 +++++++
lib/uk9p/include/uk/9pfid.h | 115 +++++++++++++++++++++++++++++++++++++++
7 files changed, 347 insertions(+)
create mode 100644 lib/uk9p/9pfid.c
create mode 100644 lib/uk9p/include/uk/9pfid.h
diff --git a/lib/uk9p/9pdev.c b/lib/uk9p/9pdev.c
index b733157aa7f5..4735253e2a1e 100644
--- a/lib/uk9p/9pdev.c
+++ b/lib/uk9p/9pdev.c
@@ -45,11 +45,87 @@
#include <uk/9pdev.h>
#include <uk/9pdev_trans.h>
#include <uk/9preq.h>
+#include <uk/9pfid.h>
#if CONFIG_LIBUKSCHED
#include <uk/sched.h>
#include <uk/wait.h>
#endif
+static void _fid_mgmt_init(struct uk_9pdev_fid_mgmt *fid_mgmt)
+{
+ ukarch_spin_lock_init(&fid_mgmt->spinlock);
+ fid_mgmt->next_fid = 0;
+ UK_INIT_LIST_HEAD(&fid_mgmt->fid_free_list);
+ UK_INIT_LIST_HEAD(&fid_mgmt->fid_active_list);
+}
+
+static int _fid_mgmt_next_fid_locked(struct uk_9pdev_fid_mgmt *fid_mgmt,
+ struct uk_9pdev *dev,
+ struct uk_9pfid **fid)
+{
+ struct uk_9pfid *result = NULL;
+
+ if (!uk_list_empty(&fid_mgmt->fid_free_list)) {
+ result = uk_list_first_entry(&fid_mgmt->fid_free_list,
+ struct uk_9pfid, _list);
+ uk_list_del(&result->_list);
+ } else {
+ result = uk_9pfid_alloc(dev);
+ if (!result)
+ return -ENOMEM;
+ result->fid = fid_mgmt->next_fid++;
+ }
+
+ uk_refcount_init(&result->refcount, 1);
+ result->was_removed = 0;
+ *fid = result;
+
+ return 0;
+}
+
+static void _fid_mgmt_add_fid_locked(struct uk_9pdev_fid_mgmt *fid_mgmt,
+ struct uk_9pfid *fid)
+{
+ uk_list_add(&fid->_list, &fid_mgmt->fid_active_list);
+}
+
+static void _fid_mgmt_del_fid_locked(struct uk_9pdev_fid_mgmt *fid_mgmt,
+ struct uk_9pfid *fid,
+ bool move_to_freelist)
+{
+ uk_list_del(&fid->_list);
+
+ if (move_to_freelist)
+ uk_list_add(&fid->_list, &fid_mgmt->fid_free_list);
+ else {
+ /*
+ * Free the memory associated. This fid will never be used
+ * again.
+ */
+ uk_pr_warn("Could not move fid to freelist, freeing memory.\n");
+ uk_free(fid->_dev->a, fid);
+ }
+}
+
+static void _fid_mgmt_cleanup(struct uk_9pdev_fid_mgmt *fid_mgmt)
+{
+ unsigned long flags;
+ struct uk_9pfid *fid, *fidn;
+
+ ukplat_spin_lock_irqsave(&fid_mgmt->spinlock, flags);
+ /*
+ * Every fid should have been clunked *before* destroying the
+ * connection.
+ */
+ UK_ASSERT(uk_list_empty(&fid_mgmt->fid_active_list));
+ uk_list_for_each_entry_safe(fid, fidn, &fid_mgmt->fid_free_list,
+ _list) {
+ uk_list_del(&fid->_list);
+ uk_free(fid->_dev->a, fid);
+ }
+ ukplat_spin_unlock_irqrestore(&fid_mgmt->spinlock, flags);
+}
+
static void _req_mgmt_init(struct uk_9pdev_req_mgmt *req_mgmt)
{
ukarch_spin_lock_init(&req_mgmt->spinlock);
@@ -122,6 +198,7 @@ struct uk_9pdev *uk_9pdev_connect(const struct
uk_9pdev_trans *trans,
#endif
_req_mgmt_init(&dev->_req_mgmt);
+ _fid_mgmt_init(&dev->_fid_mgmt);
rc = dev->ops->connect(dev, device_identifier, mount_args);
if (rc < 0)
@@ -139,6 +216,7 @@ struct uk_9pdev *uk_9pdev_connect(const struct
uk_9pdev_trans *trans,
return dev;
free_dev:
+ _fid_mgmt_cleanup(&dev->_fid_mgmt);
_req_mgmt_cleanup(&dev->_req_mgmt);
uk_free(a, dev);
out:
@@ -155,6 +233,7 @@ int uk_9pdev_disconnect(struct uk_9pdev *dev)
dev->state = UK_9PDEV_DISCONNECTING;
/* Clean up the requests before closing the channel. */
+ _fid_mgmt_cleanup(&dev->_fid_mgmt);
_req_mgmt_cleanup(&dev->_req_mgmt);
/*
@@ -315,6 +394,36 @@ int uk_9pdev_req_remove(struct uk_9pdev *dev, struct
uk_9preq *req)
return uk_9preq_put(req);
}
+struct uk_9pfid *uk_9pdev_fid_create(struct uk_9pdev *dev)
+{
+ struct uk_9pfid *fid = NULL;
+ int rc = 0;
+ unsigned long flags;
+
+ ukplat_spin_lock_irqsave(&dev->_fid_mgmt.spinlock, flags);
+ rc = _fid_mgmt_next_fid_locked(&dev->_fid_mgmt, dev, &fid);
+ if (rc < 0)
+ goto out;
+
+ _fid_mgmt_add_fid_locked(&dev->_fid_mgmt, fid);
+
+out:
+ ukplat_spin_unlock_irqrestore(&dev->_fid_mgmt.spinlock, flags);
+ if (rc == 0)
+ return fid;
+ return ERR2PTR(rc);
+}
+
+void uk_9pdev_fid_release(struct uk_9pfid *fid)
+{
+ struct uk_9pdev *dev = fid->_dev;
+ unsigned long flags;
+
+ ukplat_spin_lock_irqsave(&dev->_fid_mgmt.spinlock, flags);
+ _fid_mgmt_del_fid_locked(&dev->_fid_mgmt, fid, 1);
+ ukplat_spin_unlock_irqrestore(&dev->_fid_mgmt.spinlock, flags);
+}
+
bool uk_9pdev_set_msize(struct uk_9pdev *dev, uint32_t msize)
{
if (msize > dev->max_msize)
diff --git a/lib/uk9p/9pfid.c b/lib/uk9p/9pfid.c
new file mode 100644
index 000000000000..85d14c66078a
--- /dev/null
+++ b/lib/uk9p/9pfid.c
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Cristian Banu <cristb@xxxxxxxxx>
+ *
+ * Copyright (c) 2019, University Politehnica of Bucharest. All rights
reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+
+#include <uk/config.h>
+#include <uk/refcount.h>
+#include <uk/alloc.h>
+#include <uk/9pdev.h>
+#include <uk/9pfid.h>
+
+struct uk_9pfid *uk_9pfid_alloc(struct uk_9pdev *dev)
+{
+ struct uk_9pfid *fid;
+
+ fid = uk_calloc(dev->a, 1, sizeof(*fid));
+ if (fid == NULL)
+ goto out;
+
+ fid->_dev = dev;
+
+ return fid;
+
+out:
+ return NULL;
+}
+
+void uk_9pfid_get(struct uk_9pfid *fid)
+{
+ uk_refcount_acquire(&fid->refcount);
+}
+
+int uk_9pfid_put(struct uk_9pfid *fid)
+{
+ int last;
+
+ last = uk_refcount_release(&fid->refcount);
+ if (last)
+ uk_9pdev_fid_release(fid);
+
+ return last;
+}
diff --git a/lib/uk9p/Makefile.uk b/lib/uk9p/Makefile.uk
index 34cc987a2f9c..cd4bf4b8a033 100644
--- a/lib/uk9p/Makefile.uk
+++ b/lib/uk9p/Makefile.uk
@@ -6,3 +6,4 @@ CXXINCLUDES-$(CONFIG_LIBUK9P) +=
-I$(LIBUK9P_BASE)/include
LIBUK9P_SRCS-y += $(LIBUK9P_BASE)/9pdev_trans.c
LIBUK9P_SRCS-y += $(LIBUK9P_BASE)/9preq.c
LIBUK9P_SRCS-y += $(LIBUK9P_BASE)/9pdev.c
+LIBUK9P_SRCS-y += $(LIBUK9P_BASE)/9pfid.c
diff --git a/lib/uk9p/exportsyms.uk b/lib/uk9p/exportsyms.uk
index 0456b9094d87..ec469a2bff03 100644
--- a/lib/uk9p/exportsyms.uk
+++ b/lib/uk9p/exportsyms.uk
@@ -2,6 +2,7 @@ uk_9pdev_trans_register
uk_9pdev_trans_by_name
uk_9pdev_trans_get_default
uk_9pdev_trans_set_default
+
uk_9preq_get
uk_9preq_put
uk_9preq_vserialize
@@ -13,13 +14,20 @@ uk_9preq_copy_from
uk_9preq_receive_cb
uk_9preq_waitreply
uk_9preq_error
+
uk_9pdev_connect
uk_9pdev_disconnect
uk_9pdev_request
uk_9pdev_xmit_notify
uk_9pdev_call
+
uk_9pdev_req_create
uk_9pdev_req_lookup
uk_9pdev_req_remove
+
uk_9pdev_set_msize
uk_9pdev_get_msize
+
+uk_9pdev_fid_create
+uk_9pfid_get
+uk_9pfid_put
diff --git a/lib/uk9p/include/uk/9pdev.h b/lib/uk9p/include/uk/9pdev.h
index aed723dcee7f..139498f7777f 100644
--- a/lib/uk9p/include/uk/9pdev.h
+++ b/lib/uk9p/include/uk/9pdev.h
@@ -176,6 +176,29 @@ struct uk_9preq *uk_9pdev_req_lookup(struct uk_9pdev *dev,
uint16_t tag);
int uk_9pdev_req_remove(struct uk_9pdev *dev, struct uk_9preq *req);
/**
+ * Creates a FID associated with the given 9P device.
+ *
+ * @param dev
+ * The Unikraft 9P Device.
+ * @return
+ * If not an error pointer, the created fid.
+ * Otherwise, the error in creating the fid:
+ * - ENOMEM: No memory for the request or no available tags.
+ */
+struct uk_9pfid *uk_9pdev_fid_create(struct uk_9pdev *dev);
+
+/**
+ * @internal
+ * Releases a FID when its reference count goes to 0.
+ *
+ * Should not be called directly, but rather via uk_9pfid_put().
+ *
+ * @param fid
+ * The FID to be released.
+ */
+void uk_9pdev_fid_release(struct uk_9pfid *fid);
+
+/**
* Sets the maximum allowed message size.
*
* @param dev
diff --git a/lib/uk9p/include/uk/9pdev_core.h b/lib/uk9p/include/uk/9pdev_core.h
index 8c57d8682d0e..38864ace138d 100644
--- a/lib/uk9p/include/uk/9pdev_core.h
+++ b/lib/uk9p/include/uk/9pdev_core.h
@@ -124,6 +124,24 @@ struct uk_9pdev_req_mgmt {
/**
* @internal
+ * A structure used to describe the availability of 9P fids.
+ */
+struct uk_9pdev_fid_mgmt {
+ /* Spinlock protecting fids. */
+ spinlock_t spinlock;
+ /* Next available fid. */
+ uint32_t next_fid;
+ /* Free-list of fids that can be reused. */
+ struct uk_list_head fid_free_list;
+ /*
+ * List of fids that are currently active, to be clunked at the end of
+ * a 9pfs session.
+ */
+ struct uk_list_head fid_active_list;
+};
+
+/**
+ * @internal
* 9PDEV transport state
*
* - CONNECTED: Default state after initialization and during normal operation.
@@ -153,6 +171,8 @@ struct uk_9pdev {
uint32_t max_msize;
/* Transport-allocated data. */
void *priv;
+ /* @internal Fid management. */
+ struct uk_9pdev_fid_mgmt _fid_mgmt;
/* @internal Request management. */
struct uk_9pdev_req_mgmt _req_mgmt;
#if CONFIG_LIBUKSCHED
diff --git a/lib/uk9p/include/uk/9pfid.h b/lib/uk9p/include/uk/9pfid.h
new file mode 100644
index 000000000000..7ec75bb4a508
--- /dev/null
+++ b/lib/uk9p/include/uk/9pfid.h
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Cristian Banu <cristb@xxxxxxxxx>
+ *
+ * Copyright (c) 2019, University Politehnica of Bucharest. All rights
reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+
+#ifndef __UK_9PFID__
+#define __UK_9PFID__
+
+#include <stdbool.h>
+#include <inttypes.h>
+#include <uk/config.h>
+#include <uk/9p_core.h>
+#include <uk/alloc.h>
+#include <uk/essentials.h>
+#include <uk/list.h>
+#include <uk/refcount.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Structure describing a managed fid via reference counting.
+ */
+struct uk_9pfid {
+ /* Fid number. */
+ uint32_t fid;
+ /* Associated server qid. */
+ struct uk_9p_qid qid;
+ /* I/O unit. */
+ uint32_t iounit;
+ /*
+ * If removed, no clunk is necessary, as the remove operation
+ * implicitly clunks the fid.
+ */
+ bool was_removed;
+ /* Tracks the number of live references. */
+ __atomic refcount;
+ /* @internal Associated 9P device. */
+ struct uk_9pdev *_dev;
+ /*
+ * @internal
+ * List on which this fid currently is. See uk_9pdev_fid_mgmt for
+ * details.
+ */
+ struct uk_list_head _list;
+};
+
+/**
+ * @internal
+ * Allocates a 9p fid.
+ * Should not be used directly, use uk_9pdev_fid_create() instead.
+ *
+ * @param a
+ * Allocator to use.
+ * @return
+ * - NULL: Out of memory.
+ * - (!=NULL): Successful.
+ */
+struct uk_9pfid *uk_9pfid_alloc(struct uk_9pdev *dev);
+
+/**
+ * Gets the 9p fid, incrementing the reference count.
+ *
+ * @param fid
+ * Reference to the 9p fid.
+ */
+void uk_9pfid_get(struct uk_9pfid *fid);
+
+/**
+ * Puts the 9p fid, decrementing the reference count.
+ * If this was the last live reference, the memory will be freed.
+ *
+ * @param fid
+ * Reference to the 9p fid.
+ * @return
+ * - 0: This was not the last live reference.
+ * - 1: This was the last live reference.
+ */
+int uk_9pfid_put(struct uk_9pfid *fid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UK_9PFID__ */
--
2.11.0
_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |