Changes in 4.4.178 mmc: pxamci: fix enum type confusion drm/vmwgfx: Don't double-free the mode stored in par->set_mode udf: Fix crash on IO error during truncate mips: loongson64: lemote-2f: Add IRQF_NO_SUSPEND to "cascade" irqaction. MIPS: Fix kernel crash for R6 in jump label branch function futex: Ensure that futex address is aligned in handle_futex_death() ext4: fix NULL pointer dereference while journal is aborted ext4: fix data corruption caused by unaligned direct AIO ext4: brelse all indirect buffer in ext4_ind_remove_space() mmc: tmio_mmc_core: don't claim spurious interrupts media: v4l2-ctrls.c/uvc: zero v4l2_event locking/lockdep: Add debug_locks check in __lock_downgrade() ALSA: hda - Record the current power state before suspend/resume calls ALSA: hda - Enforces runtime_resume after S3 and S4 for each codec mmc: pwrseq_simple: Make reset-gpios optional to match doc mmc: debugfs: Add a restriction to mmc debugfs clock setting mmc: make MAN_BKOPS_EN message a debug mmc: sanitize 'bus width' in debug output mmc: core: shut up "voltage-ranges unspecified" pr_info() usb: dwc3: gadget: Fix suspend/resume during device mode arm64: mm: Add trace_irqflags annotations to do_debug_exception() mmc: core: fix using wrong io voltage if mmc_select_hs200 fails mm/rmap: replace BUG_ON(anon_vma->degree) with VM_WARN_ON extcon: usb-gpio: Don't miss event during suspend/resume kbuild: setlocalversion: print error to STDERR usb: gadget: composite: fix dereference after null check coverify warning usb: gadget: Add the gserial port checking in gs_start_tx() tcp/dccp: drop SYN packets if accept queue is full serial: sprd: adjust TIMEOUT to a big value Hang/soft lockup in d_invalidate with simultaneous calls arm64: traps: disable irq in die() usb: renesas_usbhs: gadget: fix unused-but-set-variable warning serial: sprd: clear timeout interrupt only rather than all interrupts lib/int_sqrt: optimize small argument USB: core: only clean up what we allocated rtc: Fix overflow when converting time64_t to rtc_time ath10k: avoid possible string overflow Bluetooth: Check L2CAP option sizes returned from l2cap_get_conf_opt Bluetooth: Verify that l2cap_get_conf_opt provides large enough buffer sched/fair: Fix new task's load avg removed from source CPU in wake_up_new_task() mmc: block: Allow more than 8 partitions per card arm64: fix COMPAT_SHMLBA definition for large pages efi: stub: define DISABLE_BRANCH_PROFILING for all architectures ARM: 8458/1: bL_switcher: add GIC dependency ARM: 8494/1: mm: Enable PXN when running non-LPAE kernel on LPAE processor android: unconditionally remove callbacks in sync_fence_free() vmstat: make vmstat_updater deferrable again and shut down on idle hid-sensor-hub.c: fix wrong do_div() usage arm64: hide __efistub_ aliases from kallsyms perf: Synchronously free aux pages in case of allocation failure net: diag: support v4mapped sockets in inet_diag_find_one_icsk() Revert "mmc: block: don't use parameter prefix if built as module" writeback: initialize inode members that track writeback history coresight: fixing lockdep error coresight: coresight_unregister() function cleanup coresight: release reference taken by 'bus_find_device()' coresight: remove csdev's link from topology stm class: Fix locking in unbinding policy path stm class: Fix link list locking stm class: Prevent user-controllable allocations stm class: Support devices with multiple instances stm class: Fix unlocking braino in the error path stm class: Guard output assignment against concurrency stm class: Fix unbalanced module/device refcounting stm class: Fix a race in unlinking coresight: "DEVICE_ATTR_RO" should defined as static. coresight: etm4x: Check every parameter used by dma_xx_coherent. asm-generic: Fix local variable shadow in __set_fixmap_offset staging: ashmem: Avoid deadlock with mmap/shrink staging: ashmem: Add missing include staging: ion: Set minimum carveout heap allocation order to PAGE_SHIFT staging: goldfish: audio: fix compiliation on arm ARM: 8510/1: rework ARM_CPU_SUSPEND dependencies arm64/kernel: fix incorrect EL0 check in inv_entry macro mac80211: fix "warning: ‘target_metric’ may be used uninitialized" perf/ring_buffer: Refuse to begin AUX transaction after rb->aux_mmap_count drops arm64: kernel: Include _AC definition in page.h PM / Hibernate: Call flush_icache_range() on pages restored in-place stm class: Do not leak the chrdev in error path stm class: Fix stm device initialization order ipv6: fix endianness error in icmpv6_err usb: gadget: configfs: add mutex lock before unregister gadget usb: gadget: rndis: free response queue during REMOTE_NDIS_RESET_MSG cpu/hotplug: Handle unbalanced hotplug enable/disable video: fbdev: Set pixclock = 0 in goldfishfb arm64: kconfig: drop CONFIG_RTC_LIB dependency mmc: mmc: fix switch timeout issue caused by jiffies precision cfg80211: size various nl80211 messages correctly stmmac: copy unicast mac address to MAC registers dccp: do not use ipv6 header for ipv4 flow mISDN: hfcpci: Test both vendor & device ID for Digium HFC4S net/packet: Set __GFP_NOWARN upon allocation in alloc_pg_vec net: rose: fix a possible stack overflow Add hlist_add_tail_rcu() (Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net) packets: Always register packet sk in the same order tcp: do not use ipv6 header for ipv4 flow vxlan: Don't call gro_cells_destroy() before device is unregistered sctp: get sctphdr by offset in sctp_compute_cksum mac8390: Fix mmio access size probe btrfs: remove WARN_ON in log_dir_items btrfs: raid56: properly unmap parity page in finish_parity_scrub() ARM: imx6q: cpuidle: fix bug that CPU might not wake up at expected time ALSA: compress: add support for 32bit calls in a 64bit kernel ALSA: rawmidi: Fix potential Spectre v1 vulnerability ALSA: seq: oss: Fix Spectre v1 vulnerability ALSA: pcm: Fix possible OOB access in PCM oss plugins ALSA: pcm: Don't suspend stream in unrecoverable PCM state scsi: sd: Fix a race between closing an sd device and sd I/O scsi: zfcp: fix rport unblock if deleted SCSI devices on Scsi_Host scsi: zfcp: fix scsi_eh host reset with port_forced ERP for non-NPIV FCP devices tty: atmel_serial: fix a potential NULL pointer dereference staging: vt6655: Remove vif check from vnt_interrupt staging: vt6655: Fix interrupt race condition on device start up. serial: max310x: Fix to avoid potential NULL pointer dereference serial: sh-sci: Fix setting SCSCR_TIE while transferring data USB: serial: cp210x: add new device id USB: serial: ftdi_sio: add additional NovaTech products USB: serial: mos7720: fix mos_parport refcount imbalance on error path USB: serial: option: set driver_info for SIM5218 and compatibles USB: serial: option: add Olicard 600 Disable kgdboc failed by echo space to /sys/module/kgdboc/parameters/kgdboc fs/proc/proc_sysctl.c: fix NULL pointer dereference in put_links gpio: adnp: Fix testing wrong value in adnp_gpio_direction_input perf intel-pt: Fix TSC slip x86/smp: Enforce CONFIG_HOTPLUG_CPU when SMP=y KVM: Reject device ioctls from processes other than the VM's creator xhci: Fix port resume done detection for SS ports with LPM enabled Revert "USB: core: only clean up what we allocated" arm64: support keyctl() system call in 32-bit mode coresight: removing bind/unbind options from sysfs stm class: Hide STM-specific options if STM is disabled Linux 4.4.178 Change-Id: Ia7fc9419e85c78352eef494a0c914dec7650062f Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
588 lines
20 KiB
C
588 lines
20 KiB
C
#ifndef _LINUX_RCULIST_H
|
|
#define _LINUX_RCULIST_H
|
|
|
|
#ifdef __KERNEL__
|
|
|
|
/*
|
|
* RCU-protected list version
|
|
*/
|
|
#include <linux/list.h>
|
|
#include <linux/rcupdate.h>
|
|
|
|
/*
|
|
* Why is there no list_empty_rcu()? Because list_empty() serves this
|
|
* purpose. The list_empty() function fetches the RCU-protected pointer
|
|
* and compares it to the address of the list head, but neither dereferences
|
|
* this pointer itself nor provides this pointer to the caller. Therefore,
|
|
* it is not necessary to use rcu_dereference(), so that list_empty() can
|
|
* be used anywhere you would want to use a list_empty_rcu().
|
|
*/
|
|
|
|
/*
|
|
* INIT_LIST_HEAD_RCU - Initialize a list_head visible to RCU readers
|
|
* @list: list to be initialized
|
|
*
|
|
* You should instead use INIT_LIST_HEAD() for normal initialization and
|
|
* cleanup tasks, when readers have no access to the list being initialized.
|
|
* However, if the list being initialized is visible to readers, you
|
|
* need to keep the compiler from being too mischievous.
|
|
*/
|
|
static inline void INIT_LIST_HEAD_RCU(struct list_head *list)
|
|
{
|
|
WRITE_ONCE(list->next, list);
|
|
WRITE_ONCE(list->prev, list);
|
|
}
|
|
|
|
/*
|
|
* return the ->next pointer of a list_head in an rcu safe
|
|
* way, we must not access it directly
|
|
*/
|
|
#define list_next_rcu(list) (*((struct list_head __rcu **)(&(list)->next)))
|
|
|
|
/*
|
|
* Insert a new entry between two known consecutive entries.
|
|
*
|
|
* This is only for internal list manipulation where we know
|
|
* the prev/next entries already!
|
|
*/
|
|
static inline void __list_add_rcu(struct list_head *new,
|
|
struct list_head *prev, struct list_head *next)
|
|
{
|
|
if (!__list_add_valid(new, prev, next))
|
|
return;
|
|
|
|
new->next = next;
|
|
new->prev = prev;
|
|
rcu_assign_pointer(list_next_rcu(prev), new);
|
|
next->prev = new;
|
|
}
|
|
|
|
/**
|
|
* list_add_rcu - add a new entry to rcu-protected list
|
|
* @new: new entry to be added
|
|
* @head: list head to add it after
|
|
*
|
|
* Insert a new entry after the specified head.
|
|
* This is good for implementing stacks.
|
|
*
|
|
* The caller must take whatever precautions are necessary
|
|
* (such as holding appropriate locks) to avoid racing
|
|
* with another list-mutation primitive, such as list_add_rcu()
|
|
* or list_del_rcu(), running on this same list.
|
|
* However, it is perfectly legal to run concurrently with
|
|
* the _rcu list-traversal primitives, such as
|
|
* list_for_each_entry_rcu().
|
|
*/
|
|
static inline void list_add_rcu(struct list_head *new, struct list_head *head)
|
|
{
|
|
__list_add_rcu(new, head, head->next);
|
|
}
|
|
|
|
/**
|
|
* list_add_tail_rcu - add a new entry to rcu-protected list
|
|
* @new: new entry to be added
|
|
* @head: list head to add it before
|
|
*
|
|
* Insert a new entry before the specified head.
|
|
* This is useful for implementing queues.
|
|
*
|
|
* The caller must take whatever precautions are necessary
|
|
* (such as holding appropriate locks) to avoid racing
|
|
* with another list-mutation primitive, such as list_add_tail_rcu()
|
|
* or list_del_rcu(), running on this same list.
|
|
* However, it is perfectly legal to run concurrently with
|
|
* the _rcu list-traversal primitives, such as
|
|
* list_for_each_entry_rcu().
|
|
*/
|
|
static inline void list_add_tail_rcu(struct list_head *new,
|
|
struct list_head *head)
|
|
{
|
|
__list_add_rcu(new, head->prev, head);
|
|
}
|
|
|
|
/**
|
|
* list_del_rcu - deletes entry from list without re-initialization
|
|
* @entry: the element to delete from the list.
|
|
*
|
|
* Note: list_empty() on entry does not return true after this,
|
|
* the entry is in an undefined state. It is useful for RCU based
|
|
* lockfree traversal.
|
|
*
|
|
* In particular, it means that we can not poison the forward
|
|
* pointers that may still be used for walking the list.
|
|
*
|
|
* The caller must take whatever precautions are necessary
|
|
* (such as holding appropriate locks) to avoid racing
|
|
* with another list-mutation primitive, such as list_del_rcu()
|
|
* or list_add_rcu(), running on this same list.
|
|
* However, it is perfectly legal to run concurrently with
|
|
* the _rcu list-traversal primitives, such as
|
|
* list_for_each_entry_rcu().
|
|
*
|
|
* Note that the caller is not permitted to immediately free
|
|
* the newly deleted entry. Instead, either synchronize_rcu()
|
|
* or call_rcu() must be used to defer freeing until an RCU
|
|
* grace period has elapsed.
|
|
*/
|
|
static inline void list_del_rcu(struct list_head *entry)
|
|
{
|
|
__list_del_entry(entry);
|
|
entry->prev = LIST_POISON2;
|
|
}
|
|
|
|
/**
|
|
* hlist_del_init_rcu - deletes entry from hash list with re-initialization
|
|
* @n: the element to delete from the hash list.
|
|
*
|
|
* Note: list_unhashed() on the node return true after this. It is
|
|
* useful for RCU based read lockfree traversal if the writer side
|
|
* must know if the list entry is still hashed or already unhashed.
|
|
*
|
|
* In particular, it means that we can not poison the forward pointers
|
|
* that may still be used for walking the hash list and we can only
|
|
* zero the pprev pointer so list_unhashed() will return true after
|
|
* this.
|
|
*
|
|
* The caller must take whatever precautions are necessary (such as
|
|
* holding appropriate locks) to avoid racing with another
|
|
* list-mutation primitive, such as hlist_add_head_rcu() or
|
|
* hlist_del_rcu(), running on this same list. However, it is
|
|
* perfectly legal to run concurrently with the _rcu list-traversal
|
|
* primitives, such as hlist_for_each_entry_rcu().
|
|
*/
|
|
static inline void hlist_del_init_rcu(struct hlist_node *n)
|
|
{
|
|
if (!hlist_unhashed(n)) {
|
|
__hlist_del(n);
|
|
n->pprev = NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* list_replace_rcu - replace old entry by new one
|
|
* @old : the element to be replaced
|
|
* @new : the new element to insert
|
|
*
|
|
* The @old entry will be replaced with the @new entry atomically.
|
|
* Note: @old should not be empty.
|
|
*/
|
|
static inline void list_replace_rcu(struct list_head *old,
|
|
struct list_head *new)
|
|
{
|
|
new->next = old->next;
|
|
new->prev = old->prev;
|
|
rcu_assign_pointer(list_next_rcu(new->prev), new);
|
|
new->next->prev = new;
|
|
old->prev = LIST_POISON2;
|
|
}
|
|
|
|
/**
|
|
* list_splice_init_rcu - splice an RCU-protected list into an existing list.
|
|
* @list: the RCU-protected list to splice
|
|
* @head: the place in the list to splice the first list into
|
|
* @sync: function to sync: synchronize_rcu(), synchronize_sched(), ...
|
|
*
|
|
* @head can be RCU-read traversed concurrently with this function.
|
|
*
|
|
* Note that this function blocks.
|
|
*
|
|
* Important note: the caller must take whatever action is necessary to
|
|
* prevent any other updates to @head. In principle, it is possible
|
|
* to modify the list as soon as sync() begins execution.
|
|
* If this sort of thing becomes necessary, an alternative version
|
|
* based on call_rcu() could be created. But only if -really-
|
|
* needed -- there is no shortage of RCU API members.
|
|
*/
|
|
static inline void list_splice_init_rcu(struct list_head *list,
|
|
struct list_head *head,
|
|
void (*sync)(void))
|
|
{
|
|
struct list_head *first = list->next;
|
|
struct list_head *last = list->prev;
|
|
struct list_head *at = head->next;
|
|
|
|
if (list_empty(list))
|
|
return;
|
|
|
|
/*
|
|
* "first" and "last" tracking list, so initialize it. RCU readers
|
|
* have access to this list, so we must use INIT_LIST_HEAD_RCU()
|
|
* instead of INIT_LIST_HEAD().
|
|
*/
|
|
|
|
INIT_LIST_HEAD_RCU(list);
|
|
|
|
/*
|
|
* At this point, the list body still points to the source list.
|
|
* Wait for any readers to finish using the list before splicing
|
|
* the list body into the new list. Any new readers will see
|
|
* an empty list.
|
|
*/
|
|
|
|
sync();
|
|
|
|
/*
|
|
* Readers are finished with the source list, so perform splice.
|
|
* The order is important if the new list is global and accessible
|
|
* to concurrent RCU readers. Note that RCU readers are not
|
|
* permitted to traverse the prev pointers without excluding
|
|
* this function.
|
|
*/
|
|
|
|
last->next = at;
|
|
rcu_assign_pointer(list_next_rcu(head), first);
|
|
first->prev = head;
|
|
at->prev = last;
|
|
}
|
|
|
|
/**
|
|
* list_entry_rcu - get the struct for this entry
|
|
* @ptr: the &struct list_head pointer.
|
|
* @type: the type of the struct this is embedded in.
|
|
* @member: the name of the list_head within the struct.
|
|
*
|
|
* This primitive may safely run concurrently with the _rcu list-mutation
|
|
* primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
|
|
*/
|
|
#define list_entry_rcu(ptr, type, member) \
|
|
container_of(lockless_dereference(ptr), type, member)
|
|
|
|
/**
|
|
* Where are list_empty_rcu() and list_first_entry_rcu()?
|
|
*
|
|
* Implementing those functions following their counterparts list_empty() and
|
|
* list_first_entry() is not advisable because they lead to subtle race
|
|
* conditions as the following snippet shows:
|
|
*
|
|
* if (!list_empty_rcu(mylist)) {
|
|
* struct foo *bar = list_first_entry_rcu(mylist, struct foo, list_member);
|
|
* do_something(bar);
|
|
* }
|
|
*
|
|
* The list may not be empty when list_empty_rcu checks it, but it may be when
|
|
* list_first_entry_rcu rereads the ->next pointer.
|
|
*
|
|
* Rereading the ->next pointer is not a problem for list_empty() and
|
|
* list_first_entry() because they would be protected by a lock that blocks
|
|
* writers.
|
|
*
|
|
* See list_first_or_null_rcu for an alternative.
|
|
*/
|
|
|
|
/**
|
|
* list_first_or_null_rcu - get the first element from a list
|
|
* @ptr: the list head to take the element from.
|
|
* @type: the type of the struct this is embedded in.
|
|
* @member: the name of the list_head within the struct.
|
|
*
|
|
* Note that if the list is empty, it returns NULL.
|
|
*
|
|
* This primitive may safely run concurrently with the _rcu list-mutation
|
|
* primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
|
|
*/
|
|
#define list_first_or_null_rcu(ptr, type, member) \
|
|
({ \
|
|
struct list_head *__ptr = (ptr); \
|
|
struct list_head *__next = READ_ONCE(__ptr->next); \
|
|
likely(__ptr != __next) ? list_entry_rcu(__next, type, member) : NULL; \
|
|
})
|
|
|
|
/**
|
|
* list_for_each_entry_rcu - iterate over rcu list of given type
|
|
* @pos: the type * to use as a loop cursor.
|
|
* @head: the head for your list.
|
|
* @member: the name of the list_head within the struct.
|
|
*
|
|
* This list-traversal primitive may safely run concurrently with
|
|
* the _rcu list-mutation primitives such as list_add_rcu()
|
|
* as long as the traversal is guarded by rcu_read_lock().
|
|
*/
|
|
#define list_for_each_entry_rcu(pos, head, member) \
|
|
for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \
|
|
&pos->member != (head); \
|
|
pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
|
|
|
|
/**
|
|
* list_for_each_entry_continue_rcu - continue iteration over list of given type
|
|
* @pos: the type * to use as a loop cursor.
|
|
* @head: the head for your list.
|
|
* @member: the name of the list_head within the struct.
|
|
*
|
|
* Continue to iterate over list of given type, continuing after
|
|
* the current position.
|
|
*/
|
|
#define list_for_each_entry_continue_rcu(pos, head, member) \
|
|
for (pos = list_entry_rcu(pos->member.next, typeof(*pos), member); \
|
|
&pos->member != (head); \
|
|
pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
|
|
|
|
/**
|
|
* hlist_del_rcu - deletes entry from hash list without re-initialization
|
|
* @n: the element to delete from the hash list.
|
|
*
|
|
* Note: list_unhashed() on entry does not return true after this,
|
|
* the entry is in an undefined state. It is useful for RCU based
|
|
* lockfree traversal.
|
|
*
|
|
* In particular, it means that we can not poison the forward
|
|
* pointers that may still be used for walking the hash list.
|
|
*
|
|
* The caller must take whatever precautions are necessary
|
|
* (such as holding appropriate locks) to avoid racing
|
|
* with another list-mutation primitive, such as hlist_add_head_rcu()
|
|
* or hlist_del_rcu(), running on this same list.
|
|
* However, it is perfectly legal to run concurrently with
|
|
* the _rcu list-traversal primitives, such as
|
|
* hlist_for_each_entry().
|
|
*/
|
|
static inline void hlist_del_rcu(struct hlist_node *n)
|
|
{
|
|
__hlist_del(n);
|
|
n->pprev = LIST_POISON2;
|
|
}
|
|
|
|
/**
|
|
* hlist_replace_rcu - replace old entry by new one
|
|
* @old : the element to be replaced
|
|
* @new : the new element to insert
|
|
*
|
|
* The @old entry will be replaced with the @new entry atomically.
|
|
*/
|
|
static inline void hlist_replace_rcu(struct hlist_node *old,
|
|
struct hlist_node *new)
|
|
{
|
|
struct hlist_node *next = old->next;
|
|
|
|
new->next = next;
|
|
new->pprev = old->pprev;
|
|
rcu_assign_pointer(*(struct hlist_node __rcu **)new->pprev, new);
|
|
if (next)
|
|
new->next->pprev = &new->next;
|
|
old->pprev = LIST_POISON2;
|
|
}
|
|
|
|
/*
|
|
* return the first or the next element in an RCU protected hlist
|
|
*/
|
|
#define hlist_first_rcu(head) (*((struct hlist_node __rcu **)(&(head)->first)))
|
|
#define hlist_next_rcu(node) (*((struct hlist_node __rcu **)(&(node)->next)))
|
|
#define hlist_pprev_rcu(node) (*((struct hlist_node __rcu **)((node)->pprev)))
|
|
|
|
/**
|
|
* hlist_add_head_rcu
|
|
* @n: the element to add to the hash list.
|
|
* @h: the list to add to.
|
|
*
|
|
* Description:
|
|
* Adds the specified element to the specified hlist,
|
|
* while permitting racing traversals.
|
|
*
|
|
* The caller must take whatever precautions are necessary
|
|
* (such as holding appropriate locks) to avoid racing
|
|
* with another list-mutation primitive, such as hlist_add_head_rcu()
|
|
* or hlist_del_rcu(), running on this same list.
|
|
* However, it is perfectly legal to run concurrently with
|
|
* the _rcu list-traversal primitives, such as
|
|
* hlist_for_each_entry_rcu(), used to prevent memory-consistency
|
|
* problems on Alpha CPUs. Regardless of the type of CPU, the
|
|
* list-traversal primitive must be guarded by rcu_read_lock().
|
|
*/
|
|
static inline void hlist_add_head_rcu(struct hlist_node *n,
|
|
struct hlist_head *h)
|
|
{
|
|
struct hlist_node *first = h->first;
|
|
|
|
n->next = first;
|
|
n->pprev = &h->first;
|
|
rcu_assign_pointer(hlist_first_rcu(h), n);
|
|
if (first)
|
|
first->pprev = &n->next;
|
|
}
|
|
|
|
/**
|
|
* hlist_add_tail_rcu
|
|
* @n: the element to add to the hash list.
|
|
* @h: the list to add to.
|
|
*
|
|
* Description:
|
|
* Adds the specified element to the specified hlist,
|
|
* while permitting racing traversals.
|
|
*
|
|
* The caller must take whatever precautions are necessary
|
|
* (such as holding appropriate locks) to avoid racing
|
|
* with another list-mutation primitive, such as hlist_add_head_rcu()
|
|
* or hlist_del_rcu(), running on this same list.
|
|
* However, it is perfectly legal to run concurrently with
|
|
* the _rcu list-traversal primitives, such as
|
|
* hlist_for_each_entry_rcu(), used to prevent memory-consistency
|
|
* problems on Alpha CPUs. Regardless of the type of CPU, the
|
|
* list-traversal primitive must be guarded by rcu_read_lock().
|
|
*/
|
|
static inline void hlist_add_tail_rcu(struct hlist_node *n,
|
|
struct hlist_head *h)
|
|
{
|
|
struct hlist_node *i, *last = NULL;
|
|
|
|
for (i = hlist_first_rcu(h); i; i = hlist_next_rcu(i))
|
|
last = i;
|
|
|
|
if (last) {
|
|
n->next = last->next;
|
|
n->pprev = &last->next;
|
|
rcu_assign_pointer(hlist_next_rcu(last), n);
|
|
} else {
|
|
hlist_add_head_rcu(n, h);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* hlist_add_before_rcu
|
|
* @n: the new element to add to the hash list.
|
|
* @next: the existing element to add the new element before.
|
|
*
|
|
* Description:
|
|
* Adds the specified element to the specified hlist
|
|
* before the specified node while permitting racing traversals.
|
|
*
|
|
* The caller must take whatever precautions are necessary
|
|
* (such as holding appropriate locks) to avoid racing
|
|
* with another list-mutation primitive, such as hlist_add_head_rcu()
|
|
* or hlist_del_rcu(), running on this same list.
|
|
* However, it is perfectly legal to run concurrently with
|
|
* the _rcu list-traversal primitives, such as
|
|
* hlist_for_each_entry_rcu(), used to prevent memory-consistency
|
|
* problems on Alpha CPUs.
|
|
*/
|
|
static inline void hlist_add_before_rcu(struct hlist_node *n,
|
|
struct hlist_node *next)
|
|
{
|
|
n->pprev = next->pprev;
|
|
n->next = next;
|
|
rcu_assign_pointer(hlist_pprev_rcu(n), n);
|
|
next->pprev = &n->next;
|
|
}
|
|
|
|
/**
|
|
* hlist_add_behind_rcu
|
|
* @n: the new element to add to the hash list.
|
|
* @prev: the existing element to add the new element after.
|
|
*
|
|
* Description:
|
|
* Adds the specified element to the specified hlist
|
|
* after the specified node while permitting racing traversals.
|
|
*
|
|
* The caller must take whatever precautions are necessary
|
|
* (such as holding appropriate locks) to avoid racing
|
|
* with another list-mutation primitive, such as hlist_add_head_rcu()
|
|
* or hlist_del_rcu(), running on this same list.
|
|
* However, it is perfectly legal to run concurrently with
|
|
* the _rcu list-traversal primitives, such as
|
|
* hlist_for_each_entry_rcu(), used to prevent memory-consistency
|
|
* problems on Alpha CPUs.
|
|
*/
|
|
static inline void hlist_add_behind_rcu(struct hlist_node *n,
|
|
struct hlist_node *prev)
|
|
{
|
|
n->next = prev->next;
|
|
n->pprev = &prev->next;
|
|
rcu_assign_pointer(hlist_next_rcu(prev), n);
|
|
if (n->next)
|
|
n->next->pprev = &n->next;
|
|
}
|
|
|
|
#define __hlist_for_each_rcu(pos, head) \
|
|
for (pos = rcu_dereference(hlist_first_rcu(head)); \
|
|
pos; \
|
|
pos = rcu_dereference(hlist_next_rcu(pos)))
|
|
|
|
/**
|
|
* hlist_for_each_entry_rcu - iterate over rcu list of given type
|
|
* @pos: the type * to use as a loop cursor.
|
|
* @head: the head for your list.
|
|
* @member: the name of the hlist_node within the struct.
|
|
*
|
|
* This list-traversal primitive may safely run concurrently with
|
|
* the _rcu list-mutation primitives such as hlist_add_head_rcu()
|
|
* as long as the traversal is guarded by rcu_read_lock().
|
|
*/
|
|
#define hlist_for_each_entry_rcu(pos, head, member) \
|
|
for (pos = hlist_entry_safe (rcu_dereference_raw(hlist_first_rcu(head)),\
|
|
typeof(*(pos)), member); \
|
|
pos; \
|
|
pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu(\
|
|
&(pos)->member)), typeof(*(pos)), member))
|
|
|
|
/**
|
|
* hlist_for_each_entry_rcu_notrace - iterate over rcu list of given type (for tracing)
|
|
* @pos: the type * to use as a loop cursor.
|
|
* @head: the head for your list.
|
|
* @member: the name of the hlist_node within the struct.
|
|
*
|
|
* This list-traversal primitive may safely run concurrently with
|
|
* the _rcu list-mutation primitives such as hlist_add_head_rcu()
|
|
* as long as the traversal is guarded by rcu_read_lock().
|
|
*
|
|
* This is the same as hlist_for_each_entry_rcu() except that it does
|
|
* not do any RCU debugging or tracing.
|
|
*/
|
|
#define hlist_for_each_entry_rcu_notrace(pos, head, member) \
|
|
for (pos = hlist_entry_safe (rcu_dereference_raw_notrace(hlist_first_rcu(head)),\
|
|
typeof(*(pos)), member); \
|
|
pos; \
|
|
pos = hlist_entry_safe(rcu_dereference_raw_notrace(hlist_next_rcu(\
|
|
&(pos)->member)), typeof(*(pos)), member))
|
|
|
|
/**
|
|
* hlist_for_each_entry_rcu_bh - iterate over rcu list of given type
|
|
* @pos: the type * to use as a loop cursor.
|
|
* @head: the head for your list.
|
|
* @member: the name of the hlist_node within the struct.
|
|
*
|
|
* This list-traversal primitive may safely run concurrently with
|
|
* the _rcu list-mutation primitives such as hlist_add_head_rcu()
|
|
* as long as the traversal is guarded by rcu_read_lock().
|
|
*/
|
|
#define hlist_for_each_entry_rcu_bh(pos, head, member) \
|
|
for (pos = hlist_entry_safe(rcu_dereference_bh(hlist_first_rcu(head)),\
|
|
typeof(*(pos)), member); \
|
|
pos; \
|
|
pos = hlist_entry_safe(rcu_dereference_bh(hlist_next_rcu(\
|
|
&(pos)->member)), typeof(*(pos)), member))
|
|
|
|
/**
|
|
* hlist_for_each_entry_continue_rcu - iterate over a hlist continuing after current point
|
|
* @pos: the type * to use as a loop cursor.
|
|
* @member: the name of the hlist_node within the struct.
|
|
*/
|
|
#define hlist_for_each_entry_continue_rcu(pos, member) \
|
|
for (pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu( \
|
|
&(pos)->member)), typeof(*(pos)), member); \
|
|
pos; \
|
|
pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu( \
|
|
&(pos)->member)), typeof(*(pos)), member))
|
|
|
|
/**
|
|
* hlist_for_each_entry_continue_rcu_bh - iterate over a hlist continuing after current point
|
|
* @pos: the type * to use as a loop cursor.
|
|
* @member: the name of the hlist_node within the struct.
|
|
*/
|
|
#define hlist_for_each_entry_continue_rcu_bh(pos, member) \
|
|
for (pos = hlist_entry_safe(rcu_dereference_bh(hlist_next_rcu( \
|
|
&(pos)->member)), typeof(*(pos)), member); \
|
|
pos; \
|
|
pos = hlist_entry_safe(rcu_dereference_bh(hlist_next_rcu( \
|
|
&(pos)->member)), typeof(*(pos)), member))
|
|
|
|
/**
|
|
* hlist_for_each_entry_from_rcu - iterate over a hlist continuing from current point
|
|
* @pos: the type * to use as a loop cursor.
|
|
* @member: the name of the hlist_node within the struct.
|
|
*/
|
|
#define hlist_for_each_entry_from_rcu(pos, member) \
|
|
for (; pos; \
|
|
pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu( \
|
|
&(pos)->member)), typeof(*(pos)), member))
|
|
|
|
#endif /* __KERNEL__ */
|
|
#endif
|