Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lib/plist: add plist_requeue

Add plist_requeue(), which moves the specified plist_node after all other
same-priority plist_nodes in the list. This is essentially an optimized
plist_del() followed by plist_add().

This is needed by swap, which (with the next patch in this set) uses a
plist of available swap devices. When a swap device (either a swap
partition or swap file) are added to the system with swapon(), the device
is added to a plist, ordered by the swap device's priority. When swap
needs to allocate a page from one of the swap devices, it takes the page
from the first swap device on the plist, which is the highest priority
swap device. The swap device is left in the plist until all its pages are
used, and then removed from the plist when it becomes full.

However, as described in man 2 swapon, swap must allocate pages from swap
devices with the same priority in round-robin order; to do this, on each
swap page allocation, swap uses a page from the first swap device in the
plist, and then calls plist_requeue() to move that swap device entry to
after any other same-priority swap devices. The next swap page allocation
will again use a page from the first swap device in the plist and requeue
it, and so on, resulting in round-robin usage of equal-priority swap
devices.

Also add plist_test_requeue() test function, for use by plist_test() to
test plist_requeue() function.

Signed-off-by: Dan Streetman <ddstreet@ieee.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Acked-by: Mel Gorman <mgorman@suse.de>
Cc: Paul Gortmaker <paul.gortmaker@windriver.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Shaohua Li <shli@fusionio.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Dan Streetman <ddstreet@ieee.org>
Cc: Michal Hocko <mhocko@suse.cz>
Cc: Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
Cc: Weijie Yang <weijieut@gmail.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Bob Liu <bob.liu@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Dan Streetman and committed by
Linus Torvalds
a75f232c fd16618e

+54
+2
include/linux/plist.h
··· 141 141 extern void plist_add(struct plist_node *node, struct plist_head *head); 142 142 extern void plist_del(struct plist_node *node, struct plist_head *head); 143 143 144 + extern void plist_requeue(struct plist_node *node, struct plist_head *head); 145 + 144 146 /** 145 147 * plist_for_each - iterate over the plist 146 148 * @pos: the type * to use as a loop counter
+52
lib/plist.c
··· 134 134 plist_check_head(head); 135 135 } 136 136 137 + /** 138 + * plist_requeue - Requeue @node at end of same-prio entries. 139 + * 140 + * This is essentially an optimized plist_del() followed by 141 + * plist_add(). It moves an entry already in the plist to 142 + * after any other same-priority entries. 143 + * 144 + * @node: &struct plist_node pointer - entry to be moved 145 + * @head: &struct plist_head pointer - list head 146 + */ 147 + void plist_requeue(struct plist_node *node, struct plist_head *head) 148 + { 149 + struct plist_node *iter; 150 + struct list_head *node_next = &head->node_list; 151 + 152 + plist_check_head(head); 153 + BUG_ON(plist_head_empty(head)); 154 + BUG_ON(plist_node_empty(node)); 155 + 156 + if (node == plist_last(head)) 157 + return; 158 + 159 + iter = plist_next(node); 160 + 161 + if (node->prio != iter->prio) 162 + return; 163 + 164 + plist_del(node, head); 165 + 166 + plist_for_each_continue(iter, head) { 167 + if (node->prio != iter->prio) { 168 + node_next = &iter->node_list; 169 + break; 170 + } 171 + } 172 + list_add_tail(&node->node_list, node_next); 173 + 174 + plist_check_head(head); 175 + } 176 + 137 177 #ifdef CONFIG_DEBUG_PI_LIST 138 178 #include <linux/sched.h> 139 179 #include <linux/module.h> ··· 210 170 BUG_ON(prio_pos->prio_list.next != &first->prio_list); 211 171 } 212 172 173 + static void __init plist_test_requeue(struct plist_node *node) 174 + { 175 + plist_requeue(node, &test_head); 176 + 177 + if (node != plist_last(&test_head)) 178 + BUG_ON(node->prio == plist_next(node)->prio); 179 + } 180 + 213 181 static int __init plist_test(void) 214 182 { 215 183 int nr_expect = 0, i, loop; ··· 241 193 nr_expect--; 242 194 } 243 195 plist_test_check(nr_expect); 196 + if (!plist_node_empty(test_node + i)) { 197 + plist_test_requeue(test_node + i); 198 + plist_test_check(nr_expect); 199 + } 244 200 } 245 201 246 202 for (i = 0; i < ARRAY_SIZE(test_node); i++) {