XArray: Add private interface for workingset node deletion
authorMatthew Wilcox (Oracle) <willy@infradead.org>
Tue, 18 Aug 2020 13:05:56 +0000 (09:05 -0400)
committerMatthew Wilcox (Oracle) <willy@infradead.org>
Tue, 13 Oct 2020 12:41:26 +0000 (08:41 -0400)
Move the tricky bits of dealing with the XArray from the workingset
code to the XArray.  Make it clear in the documentation that this is a
private interface, and only export it for the benefit of the test suite.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
include/linux/xarray.h
lib/test_xarray.c
lib/xarray.c
mm/workingset.c

index 6b33609..29db4e1 100644 (file)
@@ -1286,6 +1286,8 @@ static inline bool xa_is_advanced(const void *entry)
  */
 typedef void (*xa_update_node_t)(struct xa_node *node);
 
+void xa_delete_node(struct xa_node *, xa_update_node_t);
+
 /*
  * The xa_state is opaque to its users.  It contains various different pieces
  * of state involved in the current operation on the XArray.  It should be
index 1122c44..64ae07b 100644 (file)
@@ -1600,14 +1600,9 @@ static noinline void shadow_remove(struct xarray *xa)
        xa_lock(xa);
        while ((node = list_first_entry_or_null(&shadow_nodes,
                                        struct xa_node, private_list))) {
-               XA_STATE(xas, node->array, 0);
                XA_BUG_ON(xa, node->array != xa);
                list_del_init(&node->private_list);
-               xas.xa_node = xa_parent_locked(node->array, node);
-               xas.xa_offset = node->offset;
-               xas.xa_shift = node->shift + XA_CHUNK_SHIFT;
-               xas_set_update(&xas, test_update_node);
-               xas_store(&xas, NULL);
+               xa_delete_node(node, test_update_node);
        }
        xa_unlock(xa);
 }
index e9e641d..1fa5c56 100644 (file)
@@ -1973,6 +1973,29 @@ unsigned int xa_extract(struct xarray *xa, void **dst, unsigned long start,
 }
 EXPORT_SYMBOL(xa_extract);
 
+/**
+ * xa_delete_node() - Private interface for workingset code.
+ * @node: Node to be removed from the tree.
+ * @update: Function to call to update ancestor nodes.
+ *
+ * Context: xa_lock must be held on entry and will not be released.
+ */
+void xa_delete_node(struct xa_node *node, xa_update_node_t update)
+{
+       struct xa_state xas = {
+               .xa = node->array,
+               .xa_index = (unsigned long)node->offset <<
+                               (node->shift + XA_CHUNK_SHIFT),
+               .xa_shift = node->shift + XA_CHUNK_SHIFT,
+               .xa_offset = node->offset,
+               .xa_node = xa_parent_locked(node->array, node),
+               .xa_update = update,
+       };
+
+       xas_store(&xas, NULL);
+}
+EXPORT_SYMBOL_GPL(xa_delete_node);     /* For the benefit of the test suite */
+
 /**
  * xa_destroy() - Free all internal data structures.
  * @xa: XArray.
index 92e6611..e185bfb 100644 (file)
@@ -519,12 +519,11 @@ static enum lru_status shadow_lru_isolate(struct list_head *item,
                                          void *arg) __must_hold(lru_lock)
 {
        struct xa_node *node = container_of(item, struct xa_node, private_list);
-       XA_STATE(xas, node->array, 0);
        struct address_space *mapping;
        int ret;
 
        /*
-        * Page cache insertions and deletions synchroneously maintain
+        * Page cache insertions and deletions synchronously maintain
         * the shadow node LRU under the i_pages lock and the
         * lru_lock.  Because the page cache tree is emptied before
         * the inode can be destroyed, holding the lru_lock pins any
@@ -559,15 +558,7 @@ static enum lru_status shadow_lru_isolate(struct list_head *item,
        if (WARN_ON_ONCE(node->count != node->nr_values))
                goto out_invalid;
        mapping->nrexceptional -= node->nr_values;
-       xas.xa_node = xa_parent_locked(&mapping->i_pages, node);
-       xas.xa_offset = node->offset;
-       xas.xa_shift = node->shift + XA_CHUNK_SHIFT;
-       xas_set_update(&xas, workingset_update_node);
-       /*
-        * We could store a shadow entry here which was the minimum of the
-        * shadow entries we were tracking ...
-        */
-       xas_store(&xas, NULL);
+       xa_delete_node(node, workingset_update_node);
        __inc_lruvec_slab_state(node, WORKINGSET_NODERECLAIM);
 
 out_invalid: