1f48ad614SDennis Dalessandro /* 2*34ab4de7SMichael J. Ruhl * Copyright(c) 2016 - 2017 Intel Corporation. 3f48ad614SDennis Dalessandro * 4f48ad614SDennis Dalessandro * This file is provided under a dual BSD/GPLv2 license. When using or 5f48ad614SDennis Dalessandro * redistributing this file, you may do so under either license. 6f48ad614SDennis Dalessandro * 7f48ad614SDennis Dalessandro * GPL LICENSE SUMMARY 8f48ad614SDennis Dalessandro * 9f48ad614SDennis Dalessandro * This program is free software; you can redistribute it and/or modify 10f48ad614SDennis Dalessandro * it under the terms of version 2 of the GNU General Public License as 11f48ad614SDennis Dalessandro * published by the Free Software Foundation. 12f48ad614SDennis Dalessandro * 13f48ad614SDennis Dalessandro * This program is distributed in the hope that it will be useful, but 14f48ad614SDennis Dalessandro * WITHOUT ANY WARRANTY; without even the implied warranty of 15f48ad614SDennis Dalessandro * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16f48ad614SDennis Dalessandro * General Public License for more details. 17f48ad614SDennis Dalessandro * 18f48ad614SDennis Dalessandro * BSD LICENSE 19f48ad614SDennis Dalessandro * 20f48ad614SDennis Dalessandro * Redistribution and use in source and binary forms, with or without 21f48ad614SDennis Dalessandro * modification, are permitted provided that the following conditions 22f48ad614SDennis Dalessandro * are met: 23f48ad614SDennis Dalessandro * 24f48ad614SDennis Dalessandro * - Redistributions of source code must retain the above copyright 25f48ad614SDennis Dalessandro * notice, this list of conditions and the following disclaimer. 26f48ad614SDennis Dalessandro * - Redistributions in binary form must reproduce the above copyright 27f48ad614SDennis Dalessandro * notice, this list of conditions and the following disclaimer in 28f48ad614SDennis Dalessandro * the documentation and/or other materials provided with the 29f48ad614SDennis Dalessandro * distribution. 30f48ad614SDennis Dalessandro * - Neither the name of Intel Corporation nor the names of its 31f48ad614SDennis Dalessandro * contributors may be used to endorse or promote products derived 32f48ad614SDennis Dalessandro * from this software without specific prior written permission. 33f48ad614SDennis Dalessandro * 34f48ad614SDennis Dalessandro * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 35f48ad614SDennis Dalessandro * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 36f48ad614SDennis Dalessandro * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 37f48ad614SDennis Dalessandro * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 38f48ad614SDennis Dalessandro * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 39f48ad614SDennis Dalessandro * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 40f48ad614SDennis Dalessandro * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 41f48ad614SDennis Dalessandro * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 42f48ad614SDennis Dalessandro * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 43f48ad614SDennis Dalessandro * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 44f48ad614SDennis Dalessandro * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 45f48ad614SDennis Dalessandro * 46f48ad614SDennis Dalessandro */ 47f48ad614SDennis Dalessandro #include <linux/list.h> 48f48ad614SDennis Dalessandro #include <linux/rculist.h> 49f48ad614SDennis Dalessandro #include <linux/mmu_notifier.h> 50f48ad614SDennis Dalessandro #include <linux/interval_tree_generic.h> 51f48ad614SDennis Dalessandro 52f48ad614SDennis Dalessandro #include "mmu_rb.h" 53f48ad614SDennis Dalessandro #include "trace.h" 54f48ad614SDennis Dalessandro 55f48ad614SDennis Dalessandro struct mmu_rb_handler { 56f48ad614SDennis Dalessandro struct mmu_notifier mn; 57e0b09ac5SDean Luick struct rb_root root; 58e0b09ac5SDean Luick void *ops_arg; 59f48ad614SDennis Dalessandro spinlock_t lock; /* protect the RB tree */ 60f48ad614SDennis Dalessandro struct mmu_rb_ops *ops; 613faa3d9aSIra Weiny struct mm_struct *mm; 620636e9abSDean Luick struct list_head lru_list; 63b85ced91SDean Luick struct work_struct del_work; 64b85ced91SDean Luick struct list_head del_list; 65b85ced91SDean Luick struct workqueue_struct *wq; 66f48ad614SDennis Dalessandro }; 67f48ad614SDennis Dalessandro 68f48ad614SDennis Dalessandro static unsigned long mmu_node_start(struct mmu_rb_node *); 69f48ad614SDennis Dalessandro static unsigned long mmu_node_last(struct mmu_rb_node *); 70f48ad614SDennis Dalessandro static inline void mmu_notifier_page(struct mmu_notifier *, struct mm_struct *, 71f48ad614SDennis Dalessandro unsigned long); 72f48ad614SDennis Dalessandro static inline void mmu_notifier_range_start(struct mmu_notifier *, 73f48ad614SDennis Dalessandro struct mm_struct *, 74f48ad614SDennis Dalessandro unsigned long, unsigned long); 75f48ad614SDennis Dalessandro static void mmu_notifier_mem_invalidate(struct mmu_notifier *, 76f48ad614SDennis Dalessandro struct mm_struct *, 77f48ad614SDennis Dalessandro unsigned long, unsigned long); 78f48ad614SDennis Dalessandro static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *, 79f48ad614SDennis Dalessandro unsigned long, unsigned long); 80b85ced91SDean Luick static void do_remove(struct mmu_rb_handler *handler, 81b85ced91SDean Luick struct list_head *del_list); 82b85ced91SDean Luick static void handle_remove(struct work_struct *work); 83f48ad614SDennis Dalessandro 840fc859a6SBhumika Goyal static const struct mmu_notifier_ops mn_opts = { 85f48ad614SDennis Dalessandro .invalidate_page = mmu_notifier_page, 86f48ad614SDennis Dalessandro .invalidate_range_start = mmu_notifier_range_start, 87f48ad614SDennis Dalessandro }; 88f48ad614SDennis Dalessandro 89f48ad614SDennis Dalessandro INTERVAL_TREE_DEFINE(struct mmu_rb_node, node, unsigned long, __last, 90f48ad614SDennis Dalessandro mmu_node_start, mmu_node_last, static, __mmu_int_rb); 91f48ad614SDennis Dalessandro 92f48ad614SDennis Dalessandro static unsigned long mmu_node_start(struct mmu_rb_node *node) 93f48ad614SDennis Dalessandro { 94f48ad614SDennis Dalessandro return node->addr & PAGE_MASK; 95f48ad614SDennis Dalessandro } 96f48ad614SDennis Dalessandro 97f48ad614SDennis Dalessandro static unsigned long mmu_node_last(struct mmu_rb_node *node) 98f48ad614SDennis Dalessandro { 99f48ad614SDennis Dalessandro return PAGE_ALIGN(node->addr + node->len) - 1; 100f48ad614SDennis Dalessandro } 101f48ad614SDennis Dalessandro 102e0b09ac5SDean Luick int hfi1_mmu_rb_register(void *ops_arg, struct mm_struct *mm, 103e0b09ac5SDean Luick struct mmu_rb_ops *ops, 104b85ced91SDean Luick struct workqueue_struct *wq, 105e0b09ac5SDean Luick struct mmu_rb_handler **handler) 106f48ad614SDennis Dalessandro { 107f48ad614SDennis Dalessandro struct mmu_rb_handler *handlr; 1083faa3d9aSIra Weiny int ret; 109f48ad614SDennis Dalessandro 110f48ad614SDennis Dalessandro handlr = kmalloc(sizeof(*handlr), GFP_KERNEL); 111f48ad614SDennis Dalessandro if (!handlr) 112f48ad614SDennis Dalessandro return -ENOMEM; 113f48ad614SDennis Dalessandro 114e0b09ac5SDean Luick handlr->root = RB_ROOT; 115f48ad614SDennis Dalessandro handlr->ops = ops; 116e0b09ac5SDean Luick handlr->ops_arg = ops_arg; 117f48ad614SDennis Dalessandro INIT_HLIST_NODE(&handlr->mn.hlist); 118f48ad614SDennis Dalessandro spin_lock_init(&handlr->lock); 119f48ad614SDennis Dalessandro handlr->mn.ops = &mn_opts; 1203faa3d9aSIra Weiny handlr->mm = mm; 121b85ced91SDean Luick INIT_WORK(&handlr->del_work, handle_remove); 122b85ced91SDean Luick INIT_LIST_HEAD(&handlr->del_list); 1230636e9abSDean Luick INIT_LIST_HEAD(&handlr->lru_list); 124b85ced91SDean Luick handlr->wq = wq; 1253faa3d9aSIra Weiny 1263faa3d9aSIra Weiny ret = mmu_notifier_register(&handlr->mn, handlr->mm); 1273faa3d9aSIra Weiny if (ret) { 1283faa3d9aSIra Weiny kfree(handlr); 1293faa3d9aSIra Weiny return ret; 1303faa3d9aSIra Weiny } 1313faa3d9aSIra Weiny 132e0b09ac5SDean Luick *handler = handlr; 133e0b09ac5SDean Luick return 0; 134f48ad614SDennis Dalessandro } 135f48ad614SDennis Dalessandro 136e0b09ac5SDean Luick void hfi1_mmu_rb_unregister(struct mmu_rb_handler *handler) 137f48ad614SDennis Dalessandro { 13820a42d08SDean Luick struct mmu_rb_node *rbnode; 13920a42d08SDean Luick struct rb_node *node; 140f48ad614SDennis Dalessandro unsigned long flags; 141b85ced91SDean Luick struct list_head del_list; 142f48ad614SDennis Dalessandro 143f48ad614SDennis Dalessandro /* Unregister first so we don't get any more notifications. */ 1443faa3d9aSIra Weiny mmu_notifier_unregister(&handler->mn, handler->mm); 145f48ad614SDennis Dalessandro 146b85ced91SDean Luick /* 147b85ced91SDean Luick * Make sure the wq delete handler is finished running. It will not 148b85ced91SDean Luick * be triggered once the mmu notifiers are unregistered above. 149b85ced91SDean Luick */ 150b85ced91SDean Luick flush_work(&handler->del_work); 151b85ced91SDean Luick 152b85ced91SDean Luick INIT_LIST_HEAD(&del_list); 153b85ced91SDean Luick 154f48ad614SDennis Dalessandro spin_lock_irqsave(&handler->lock, flags); 155e0b09ac5SDean Luick while ((node = rb_first(&handler->root))) { 156f48ad614SDennis Dalessandro rbnode = rb_entry(node, struct mmu_rb_node, node); 157e0b09ac5SDean Luick rb_erase(node, &handler->root); 1580636e9abSDean Luick /* move from LRU list to delete list */ 1590636e9abSDean Luick list_move(&rbnode->list, &del_list); 160f48ad614SDennis Dalessandro } 161f48ad614SDennis Dalessandro spin_unlock_irqrestore(&handler->lock, flags); 162f48ad614SDennis Dalessandro 163b85ced91SDean Luick do_remove(handler, &del_list); 164b85ced91SDean Luick 165f48ad614SDennis Dalessandro kfree(handler); 166f48ad614SDennis Dalessandro } 167f48ad614SDennis Dalessandro 168e0b09ac5SDean Luick int hfi1_mmu_rb_insert(struct mmu_rb_handler *handler, 169e0b09ac5SDean Luick struct mmu_rb_node *mnode) 170f48ad614SDennis Dalessandro { 171f48ad614SDennis Dalessandro struct mmu_rb_node *node; 172f48ad614SDennis Dalessandro unsigned long flags; 173f48ad614SDennis Dalessandro int ret = 0; 174f48ad614SDennis Dalessandro 175*34ab4de7SMichael J. Ruhl trace_hfi1_mmu_rb_insert(mnode->addr, mnode->len); 176f48ad614SDennis Dalessandro spin_lock_irqsave(&handler->lock, flags); 177f48ad614SDennis Dalessandro node = __mmu_rb_search(handler, mnode->addr, mnode->len); 178f48ad614SDennis Dalessandro if (node) { 179f48ad614SDennis Dalessandro ret = -EINVAL; 180f48ad614SDennis Dalessandro goto unlock; 181f48ad614SDennis Dalessandro } 182e0b09ac5SDean Luick __mmu_int_rb_insert(mnode, &handler->root); 1830636e9abSDean Luick list_add(&mnode->list, &handler->lru_list); 184f48ad614SDennis Dalessandro 185e0b09ac5SDean Luick ret = handler->ops->insert(handler->ops_arg, mnode); 1860636e9abSDean Luick if (ret) { 187e0b09ac5SDean Luick __mmu_int_rb_remove(mnode, &handler->root); 1880636e9abSDean Luick list_del(&mnode->list); /* remove from LRU list */ 1890636e9abSDean Luick } 190f48ad614SDennis Dalessandro unlock: 191f48ad614SDennis Dalessandro spin_unlock_irqrestore(&handler->lock, flags); 192f48ad614SDennis Dalessandro return ret; 193f48ad614SDennis Dalessandro } 194f48ad614SDennis Dalessandro 195f48ad614SDennis Dalessandro /* Caller must hold handler lock */ 196f48ad614SDennis Dalessandro static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *handler, 197f48ad614SDennis Dalessandro unsigned long addr, 198f48ad614SDennis Dalessandro unsigned long len) 199f48ad614SDennis Dalessandro { 200f48ad614SDennis Dalessandro struct mmu_rb_node *node = NULL; 201f48ad614SDennis Dalessandro 202*34ab4de7SMichael J. Ruhl trace_hfi1_mmu_rb_search(addr, len); 203f48ad614SDennis Dalessandro if (!handler->ops->filter) { 204e0b09ac5SDean Luick node = __mmu_int_rb_iter_first(&handler->root, addr, 205f48ad614SDennis Dalessandro (addr + len) - 1); 206f48ad614SDennis Dalessandro } else { 207e0b09ac5SDean Luick for (node = __mmu_int_rb_iter_first(&handler->root, addr, 208f48ad614SDennis Dalessandro (addr + len) - 1); 209f48ad614SDennis Dalessandro node; 210f48ad614SDennis Dalessandro node = __mmu_int_rb_iter_next(node, addr, 211f48ad614SDennis Dalessandro (addr + len) - 1)) { 212f48ad614SDennis Dalessandro if (handler->ops->filter(node, addr, len)) 213f48ad614SDennis Dalessandro return node; 214f48ad614SDennis Dalessandro } 215f48ad614SDennis Dalessandro } 216f48ad614SDennis Dalessandro return node; 217f48ad614SDennis Dalessandro } 218f48ad614SDennis Dalessandro 2197be85676SSebastian Sanchez bool hfi1_mmu_rb_remove_unless_exact(struct mmu_rb_handler *handler, 2207be85676SSebastian Sanchez unsigned long addr, unsigned long len, 2217be85676SSebastian Sanchez struct mmu_rb_node **rb_node) 222f48ad614SDennis Dalessandro { 223f48ad614SDennis Dalessandro struct mmu_rb_node *node; 224f48ad614SDennis Dalessandro unsigned long flags; 2257be85676SSebastian Sanchez bool ret = false; 226f48ad614SDennis Dalessandro 227f48ad614SDennis Dalessandro spin_lock_irqsave(&handler->lock, flags); 228f48ad614SDennis Dalessandro node = __mmu_rb_search(handler, addr, len); 2290636e9abSDean Luick if (node) { 2307be85676SSebastian Sanchez if (node->addr == addr && node->len == len) 2317be85676SSebastian Sanchez goto unlock; 232e0b09ac5SDean Luick __mmu_int_rb_remove(node, &handler->root); 2330636e9abSDean Luick list_del(&node->list); /* remove from LRU list */ 2347be85676SSebastian Sanchez ret = true; 2350636e9abSDean Luick } 2367be85676SSebastian Sanchez unlock: 237f48ad614SDennis Dalessandro spin_unlock_irqrestore(&handler->lock, flags); 2387be85676SSebastian Sanchez *rb_node = node; 2397be85676SSebastian Sanchez return ret; 240f48ad614SDennis Dalessandro } 241f48ad614SDennis Dalessandro 24210345998SDean Luick void hfi1_mmu_rb_evict(struct mmu_rb_handler *handler, void *evict_arg) 24310345998SDean Luick { 2440636e9abSDean Luick struct mmu_rb_node *rbnode, *ptr; 24510345998SDean Luick struct list_head del_list; 24610345998SDean Luick unsigned long flags; 24710345998SDean Luick bool stop = false; 24810345998SDean Luick 24910345998SDean Luick INIT_LIST_HEAD(&del_list); 25010345998SDean Luick 25110345998SDean Luick spin_lock_irqsave(&handler->lock, flags); 2520636e9abSDean Luick list_for_each_entry_safe_reverse(rbnode, ptr, &handler->lru_list, 2530636e9abSDean Luick list) { 25410345998SDean Luick if (handler->ops->evict(handler->ops_arg, rbnode, evict_arg, 25510345998SDean Luick &stop)) { 25610345998SDean Luick __mmu_int_rb_remove(rbnode, &handler->root); 2570636e9abSDean Luick /* move from LRU list to delete list */ 2580636e9abSDean Luick list_move(&rbnode->list, &del_list); 25910345998SDean Luick } 26010345998SDean Luick if (stop) 26110345998SDean Luick break; 26210345998SDean Luick } 26310345998SDean Luick spin_unlock_irqrestore(&handler->lock, flags); 26410345998SDean Luick 26510345998SDean Luick while (!list_empty(&del_list)) { 26610345998SDean Luick rbnode = list_first_entry(&del_list, struct mmu_rb_node, list); 26710345998SDean Luick list_del(&rbnode->list); 268082b3532SDean Luick handler->ops->remove(handler->ops_arg, rbnode); 26910345998SDean Luick } 27010345998SDean Luick } 27110345998SDean Luick 272b85ced91SDean Luick /* 273b85ced91SDean Luick * It is up to the caller to ensure that this function does not race with the 274b85ced91SDean Luick * mmu invalidate notifier which may be calling the users remove callback on 275b85ced91SDean Luick * 'node'. 276b85ced91SDean Luick */ 277e0b09ac5SDean Luick void hfi1_mmu_rb_remove(struct mmu_rb_handler *handler, 278e0b09ac5SDean Luick struct mmu_rb_node *node) 279f48ad614SDennis Dalessandro { 2803c1091aaSIra Weiny unsigned long flags; 281f48ad614SDennis Dalessandro 2823c1091aaSIra Weiny /* Validity of handler and node pointers has been checked by caller. */ 283*34ab4de7SMichael J. Ruhl trace_hfi1_mmu_rb_remove(node->addr, node->len); 2843c1091aaSIra Weiny spin_lock_irqsave(&handler->lock, flags); 285e0b09ac5SDean Luick __mmu_int_rb_remove(node, &handler->root); 2860636e9abSDean Luick list_del(&node->list); /* remove from LRU list */ 2873c1091aaSIra Weiny spin_unlock_irqrestore(&handler->lock, flags); 2883c1091aaSIra Weiny 289082b3532SDean Luick handler->ops->remove(handler->ops_arg, node); 290f48ad614SDennis Dalessandro } 291f48ad614SDennis Dalessandro 292f48ad614SDennis Dalessandro static inline void mmu_notifier_page(struct mmu_notifier *mn, 293f48ad614SDennis Dalessandro struct mm_struct *mm, unsigned long addr) 294f48ad614SDennis Dalessandro { 295f48ad614SDennis Dalessandro mmu_notifier_mem_invalidate(mn, mm, addr, addr + PAGE_SIZE); 296f48ad614SDennis Dalessandro } 297f48ad614SDennis Dalessandro 298f48ad614SDennis Dalessandro static inline void mmu_notifier_range_start(struct mmu_notifier *mn, 299f48ad614SDennis Dalessandro struct mm_struct *mm, 300f48ad614SDennis Dalessandro unsigned long start, 301f48ad614SDennis Dalessandro unsigned long end) 302f48ad614SDennis Dalessandro { 303f48ad614SDennis Dalessandro mmu_notifier_mem_invalidate(mn, mm, start, end); 304f48ad614SDennis Dalessandro } 305f48ad614SDennis Dalessandro 306f48ad614SDennis Dalessandro static void mmu_notifier_mem_invalidate(struct mmu_notifier *mn, 307f48ad614SDennis Dalessandro struct mm_struct *mm, 308f48ad614SDennis Dalessandro unsigned long start, unsigned long end) 309f48ad614SDennis Dalessandro { 310f48ad614SDennis Dalessandro struct mmu_rb_handler *handler = 311f48ad614SDennis Dalessandro container_of(mn, struct mmu_rb_handler, mn); 312e0b09ac5SDean Luick struct rb_root *root = &handler->root; 313f48ad614SDennis Dalessandro struct mmu_rb_node *node, *ptr = NULL; 314f48ad614SDennis Dalessandro unsigned long flags; 315b85ced91SDean Luick bool added = false; 316f48ad614SDennis Dalessandro 317f48ad614SDennis Dalessandro spin_lock_irqsave(&handler->lock, flags); 318f48ad614SDennis Dalessandro for (node = __mmu_int_rb_iter_first(root, start, end - 1); 319f48ad614SDennis Dalessandro node; node = ptr) { 320f48ad614SDennis Dalessandro /* Guard against node removal. */ 321f48ad614SDennis Dalessandro ptr = __mmu_int_rb_iter_next(node, start, end - 1); 322*34ab4de7SMichael J. Ruhl trace_hfi1_mmu_mem_invalidate(node->addr, node->len); 323e0b09ac5SDean Luick if (handler->ops->invalidate(handler->ops_arg, node)) { 324f48ad614SDennis Dalessandro __mmu_int_rb_remove(node, root); 3250636e9abSDean Luick /* move from LRU list to delete list */ 3260636e9abSDean Luick list_move(&node->list, &handler->del_list); 327b85ced91SDean Luick added = true; 328f48ad614SDennis Dalessandro } 329f48ad614SDennis Dalessandro } 330f48ad614SDennis Dalessandro spin_unlock_irqrestore(&handler->lock, flags); 331b85ced91SDean Luick 332b85ced91SDean Luick if (added) 333b85ced91SDean Luick queue_work(handler->wq, &handler->del_work); 334b85ced91SDean Luick } 335b85ced91SDean Luick 336b85ced91SDean Luick /* 337b85ced91SDean Luick * Call the remove function for the given handler and the list. This 338b85ced91SDean Luick * is expected to be called with a delete list extracted from handler. 339b85ced91SDean Luick * The caller should not be holding the handler lock. 340b85ced91SDean Luick */ 341b85ced91SDean Luick static void do_remove(struct mmu_rb_handler *handler, 342b85ced91SDean Luick struct list_head *del_list) 343b85ced91SDean Luick { 344b85ced91SDean Luick struct mmu_rb_node *node; 345b85ced91SDean Luick 346b85ced91SDean Luick while (!list_empty(del_list)) { 347b85ced91SDean Luick node = list_first_entry(del_list, struct mmu_rb_node, list); 348b85ced91SDean Luick list_del(&node->list); 349082b3532SDean Luick handler->ops->remove(handler->ops_arg, node); 350b85ced91SDean Luick } 351b85ced91SDean Luick } 352b85ced91SDean Luick 353b85ced91SDean Luick /* 354b85ced91SDean Luick * Work queue function to remove all nodes that have been queued up to 355b85ced91SDean Luick * be removed. The key feature is that mm->mmap_sem is not being held 356b85ced91SDean Luick * and the remove callback can sleep while taking it, if needed. 357b85ced91SDean Luick */ 358b85ced91SDean Luick static void handle_remove(struct work_struct *work) 359b85ced91SDean Luick { 360b85ced91SDean Luick struct mmu_rb_handler *handler = container_of(work, 361b85ced91SDean Luick struct mmu_rb_handler, 362b85ced91SDean Luick del_work); 363b85ced91SDean Luick struct list_head del_list; 364b85ced91SDean Luick unsigned long flags; 365b85ced91SDean Luick 366b85ced91SDean Luick /* remove anything that is queued to get removed */ 367b85ced91SDean Luick spin_lock_irqsave(&handler->lock, flags); 368b85ced91SDean Luick list_replace_init(&handler->del_list, &del_list); 369b85ced91SDean Luick spin_unlock_irqrestore(&handler->lock, flags); 370b85ced91SDean Luick 371b85ced91SDean Luick do_remove(handler, &del_list); 372f48ad614SDennis Dalessandro } 373