aboutsummaryrefslogtreecommitdiff
path: root/kernel/vm/shadow.c
diff options
context:
space:
mode:
authornthnluu <nate1299@me.com>2024-01-28 21:20:27 -0500
committernthnluu <nate1299@me.com>2024-01-28 21:20:27 -0500
commitc63f340d90800895f007de64b7d2d14624263331 (patch)
tree2c0849fa597dd6da831c8707b6f2603403778d7b /kernel/vm/shadow.c
Created student weenix repository
Diffstat (limited to 'kernel/vm/shadow.c')
-rw-r--r--kernel/vm/shadow.c173
1 files changed, 173 insertions, 0 deletions
diff --git a/kernel/vm/shadow.c b/kernel/vm/shadow.c
new file mode 100644
index 0000000..3b6f783
--- /dev/null
+++ b/kernel/vm/shadow.c
@@ -0,0 +1,173 @@
+#include "vm/shadow.h"
+#include "mm/page.h"
+#include "mm/pframe.h"
+#include "mm/slab.h"
+#include "util/debug.h"
+#include "util/string.h"
+
+#define SHADOW_SINGLETON_THRESHOLD 5
+
+typedef struct mobj_shadow
+{
+ // the mobj parts of this shadow object
+ mobj_t mobj;
+ // a reference to the mobj that is the data source for this shadow object
+ // This should be a reference to a shadow object of some ancestor process.
+ // This is used to traverse the shadow object chain.
+ mobj_t *shadowed;
+ // a reference to the mobj at the bottom of this shadow object's chain
+ // this should NEVER be a shadow object (i.e. it should have some type other
+ // than MOBJ_SHADOW)
+ mobj_t *bottom_mobj;
+} mobj_shadow_t;
+
+#define MOBJ_TO_SO(o) CONTAINER_OF(o, mobj_shadow_t, mobj)
+
+static slab_allocator_t *shadow_allocator;
+
+static long shadow_get_pframe(mobj_t *o, size_t pagenum, long forwrite,
+ pframe_t **pfp);
+static long shadow_fill_pframe(mobj_t *o, pframe_t *pf);
+static long shadow_flush_pframe(mobj_t *o, pframe_t *pf);
+static void shadow_destructor(mobj_t *o);
+
+static mobj_ops_t shadow_mobj_ops = {.get_pframe = shadow_get_pframe,
+ .fill_pframe = shadow_fill_pframe,
+ .flush_pframe = shadow_flush_pframe,
+ .destructor = shadow_destructor};
+
+/*
+ * Initialize shadow_allocator using the slab allocator.
+ */
+void shadow_init()
+{
+ NOT_YET_IMPLEMENTED("VM: ***none***");
+}
+
+/*
+ * Create a shadow object that shadows the given mobj.
+ *
+ * Return a new, LOCKED shadow object on success, or NULL upon failure.
+ *
+ * Hints:
+ * 1) Create and initialize a mobj_shadow_t based on the given mobj.
+ * 2) Set up the bottom object of the shadow chain, which could have two cases:
+ * a) Either shadowed is a shadow object, and you can use its bottom_mobj
+ * b) Or shadowed is not a shadow object, in which case it is the bottom
+ * object of this chain.
+ *
+ * Make sure to manage the refcounts correctly.
+ */
+mobj_t *shadow_create(mobj_t *shadowed)
+{
+ NOT_YET_IMPLEMENTED("VM: ***none***");
+ return NULL;
+}
+
+/*
+ * Given a shadow object o, collapse its shadow chain as far as you can.
+ *
+ * Hints:
+ * 1) You can only collapse if the shadowed object is a shadow object.
+ * 2) When collapsing, you must manually migrate pframes from o's shadowed
+ * object to o, checking to see if a copy doesn't already exist in o.
+ * 3) Be careful with refcounting! In particular, when you put away o's
+ * shadowed object, its refcount should drop to 0, initiating its
+ * destruction (shadow_destructor).
+ * 4) As a reminder, any refcounting done in shadow_collapse() must play nice
+ * with any refcounting done in shadow_destructor().
+ * 5) Pay attention to mobj and pframe locking.
+ */
+void shadow_collapse(mobj_t *o)
+{
+ NOT_YET_IMPLEMENTED("VM: ***none***");
+}
+
+/*
+ * Obtain the desired pframe from the given mobj, traversing its shadow chain if
+ * necessary. This is where copy-on-write logic happens!
+ *
+ * Arguments:
+ * o - The object from which to obtain a pframe
+ * pagenum - Number of the desired page relative to the object
+ * forwrite - Set if the caller wants to write to the pframe's data, clear if
+ * only reading
+ * pfp - Upon success, pfp should point to the desired pframe.
+ *
+ * Return 0 on success, or:
+ * - Propagate errors from mobj_default_get_pframe() and mobj_get_pframe()
+ *
+ * Hints:
+ * 1) If forwrite is set, use mobj_default_get_pframe().
+ * 2) If forwrite is clear, check if o already contains the desired frame.
+ * a) If not, iterate through the shadow chain to find the nearest shadow
+ * mobj that has the frame. Do not recurse! If the shadow chain is long,
+ * you will cause a kernel buffer overflow (e.g. from forkbomb).
+ * b) If no shadow objects have the page, call mobj_get_pframe() to get the
+ * page from the bottom object and return what it returns.
+ *
+ * Pay attention to pframe locking.
+ */
+static long shadow_get_pframe(mobj_t *o, size_t pagenum, long forwrite,
+ pframe_t **pfp)
+{
+ NOT_YET_IMPLEMENTED("VM: ***none***");
+ return 0;
+}
+
+/*
+ * Use the given mobj's shadow chain to fill the given pframe.
+ *
+ * Return 0 on success, or:
+ * - Propagate errors from mobj_get_pframe()
+ *
+ * Hints:
+ * 1) Explore mobj_default_get_pframe(), which calls mobj_create_pframe(), to
+ * understand what state pf is in when this function is called, and how you
+ * can use it.
+ * 2) As you can see above, shadow_get_pframe would call
+ * mobj_default_get_pframe (when the forwrite is set), which would
+ * create and then fill the pframe (shadow_fill_pframe is called).
+ * 3) Traverse the shadow chain for a copy of the frame, starting at the given
+ * mobj's shadowed object. You can use mobj_find_pframe to look for the
+ * page frame. pay attention to locking/unlocking, and be sure not to
+ * recurse when traversing.
+ * 4) If none of the shadow objects have a copy of the frame, use
+ * mobj_get_pframe on the bottom object to get it.
+ * 5) After obtaining the desired frame, simply copy its contents into pf.
+ */
+static long shadow_fill_pframe(mobj_t *o, pframe_t *pf)
+{
+ NOT_YET_IMPLEMENTED("VM: ***none***");
+ return -1;
+}
+
+/*
+ * Flush a shadow object's pframe to disk.
+ *
+ * Return 0 on success.
+ *
+ * Hint:
+ * - Are shadow objects backed to disk? Do you actually need to do anything
+ * here?
+ */
+static long shadow_flush_pframe(mobj_t *o, pframe_t *pf)
+{
+ NOT_YET_IMPLEMENTED("VM: ***none***");
+ return -1;
+}
+
+/*
+ * Clean up all resources associated with mobj o.
+ *
+ * Hints:
+ * - Check out mobj_put() to understand how this function gets called.
+ *
+ * 1) Call mobj_default_destructor() to flush o's pframes.
+ * 2) Put the shadow and bottom_mobj members of the shadow object.
+ * 3) Free the mobj_shadow_t.
+ */
+static void shadow_destructor(mobj_t *o)
+{
+ NOT_YET_IMPLEMENTED("VM: ***none***");
+}