[V2][PATCH net] tipc: fix the big/little endian issue in tipc_dest
In function tipc_dest_push, the 32bit variables 'node' and 'port' are stored separately in uppper and lower part of 64bit 'value'. Then this value is assigned to dst->value which is a union like: union { struct { u32 port; u32 node; }; u64 value; } This works on little-endian machines like x86 but fails on big-endian machines. The fix remove the 'value' stack parameter and even the 'value' member of the union in tipc_dest, assign the 'node' and 'port' member directly with the input parameter to avoid the endian issue. Fixes: a80ae5306a73 ("tipc: improve destination linked list") Signed-off-by: Zhenbo Gao Acked-by: Jon Maloy Signed-off-by: Haiqing Bai --- net/tipc/name_table.c | 10 -- net/tipc/name_table.h | 9 ++--- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 88f027b..66d5b2c 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -980,20 +980,17 @@ int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb) struct tipc_dest *tipc_dest_find(struct list_head *l, u32 node, u32 port) { - u64 value = (u64)node << 32 | port; struct tipc_dest *dst; list_for_each_entry(dst, l, list) { - if (dst->value != value) - continue; - return dst; + if (dst->node == node && dst->port == port) + return dst; } return NULL; } bool tipc_dest_push(struct list_head *l, u32 node, u32 port) { - u64 value = (u64)node << 32 | port; struct tipc_dest *dst; if (tipc_dest_find(l, node, port)) @@ -1002,7 +999,8 @@ bool tipc_dest_push(struct list_head *l, u32 node, u32 port) dst = kmalloc(sizeof(*dst), GFP_ATOMIC); if (unlikely(!dst)) return false; - dst->value = value; + dst->node = node; + dst->port = port; list_add(>list, l); return true; } diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h index 0febba4..892bd75 100644 --- a/net/tipc/name_table.h +++ b/net/tipc/name_table.h @@ -133,13 +133,8 @@ struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type, struct tipc_dest { struct list_head list; - union { - struct { - u32 port; - u32 node; - }; - u64 value; - }; + u32 port; + u32 node; }; struct tipc_dest *tipc_dest_find(struct list_head *l, u32 node, u32 port); -- 1.9.1
[V2][PATCH net] tipc: fix the big/little endian issue in tipc_dest
In function tipc_dest_push, the 32bit variables 'node' and 'port' are stored separately in uppper and lower part of 64bit 'value'. Then this value is assigned to dst->value which is a union like: union { struct { u32 port; u32 node; }; u64 value; } This works on little-endian machines like x86 but fails on big-endian machines. The fix remove the 'value' stack parameter and even the 'value' member of the union in tipc_dest, assign the 'node' and 'port' member directly with the input parameter to avoid the endian issue. Fixes: a80ae5306a73 ("tipc: improve destination linked list") Signed-off-by: Zhenbo Gao Acked-by: Jon Maloy Signed-off-by: Haiqing Bai --- net/tipc/name_table.c | 10 -- net/tipc/name_table.h | 9 ++--- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 88f027b..66d5b2c 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -980,20 +980,17 @@ int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb) struct tipc_dest *tipc_dest_find(struct list_head *l, u32 node, u32 port) { - u64 value = (u64)node << 32 | port; struct tipc_dest *dst; list_for_each_entry(dst, l, list) { - if (dst->value != value) - continue; - return dst; + if (dst->node == node && dst->port == port) + return dst; } return NULL; } bool tipc_dest_push(struct list_head *l, u32 node, u32 port) { - u64 value = (u64)node << 32 | port; struct tipc_dest *dst; if (tipc_dest_find(l, node, port)) @@ -1002,7 +999,8 @@ bool tipc_dest_push(struct list_head *l, u32 node, u32 port) dst = kmalloc(sizeof(*dst), GFP_ATOMIC); if (unlikely(!dst)) return false; - dst->value = value; + dst->node = node; + dst->port = port; list_add(>list, l); return true; } diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h index 0febba4..892bd75 100644 --- a/net/tipc/name_table.h +++ b/net/tipc/name_table.h @@ -133,13 +133,8 @@ struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type, struct tipc_dest { struct list_head list; - union { - struct { - u32 port; - u32 node; - }; - u64 value; - }; + u32 port; + u32 node; }; struct tipc_dest *tipc_dest_find(struct list_head *l, u32 node, u32 port); -- 1.9.1
[V2][PATCH] ohci-hcd: Fix race condition caused by ohci_urb_enqueue() and io_watchdog_func()
From: Shigeru Yoshida <shigeru.yosh...@windriver.com> Running io_watchdog_func() while ohci_urb_enqueue() is running can cause a race condition where ohci->prev_frame_no is corrupted and the watchdog can mis-detect following error: ohci-platform 664a0800.usb: frame counter not updating; disabled ohci-platform 664a0800.usb: HC died; cleaning up Specifically, following scenario causes a race condition: 1. ohci_urb_enqueue() calls spin_lock_irqsave(>lock, flags) and enters the critical section 2. ohci_urb_enqueue() calls timer_pending(>io_watchdog) and it returns false 3. ohci_urb_enqueue() sets ohci->prev_frame_no to a frame number read by ohci_frame_no(ohci) 4. ohci_urb_enqueue() schedules io_watchdog_func() with mod_timer() 5. ohci_urb_enqueue() calls spin_unlock_irqrestore(>lock, flags) and exits the critical section 6. Later, ohci_urb_enqueue() is called 7. ohci_urb_enqueue() calls spin_lock_irqsave(>lock, flags) and enters the critical section 8. The timer scheduled on step 4 expires and io_watchdog_func() runs 9. io_watchdog_func() calls spin_lock_irqsave(>lock, flags) and waits on it because ohci_urb_enqueue() is already in the critical section on step 7 10. ohci_urb_enqueue() calls timer_pending(>io_watchdog) and it returns false 11. ohci_urb_enqueue() sets ohci->prev_frame_no to new frame number read by ohci_frame_no(ohci) because the frame number proceeded between step 3 and 6 12. ohci_urb_enqueue() schedules io_watchdog_func() with mod_timer() 13. ohci_urb_enqueue() calls spin_unlock_irqrestore(>lock, flags) and exits the critical section, then wake up io_watchdog_func() which is waiting on step 9 14. io_watchdog_func() enters the critical section 15. io_watchdog_func() calls ohci_frame_no(ohci) and set frame_no variable to the frame number 16. io_watchdog_func() compares frame_no and ohci->prev_frame_no On step 16, because this calling of io_watchdog_func() is scheduled on step 4, the frame number set in ohci->prev_frame_no is expected to the number set on step 3. However, ohci->prev_frame_no is overwritten on step 11. Because step 16 is executed soon after step 11, the frame number might not proceed, so ohci->prev_frame_no must equals to frame_no. To address above scenario, this patch introduces a special sentinel value IO_WATCHDOG_OFF and set this value to ohci->prev_frame_no when the watchdog is not pending or running. When ohci_urb_enqueue() schedules the watchdog (step 4 and 12 above), it compares ohci->prev_frame_no to IO_WATCHDOG_OFF so that ohci->prev_frame_no is not overwritten while io_watchdog_func() is running. v2: Instead of adding an extra flag variable, defining IO_WATCHDOG_OFF as a special sentinel value for prev_frame_no. Signed-off-by: Shigeru Yoshida <shigeru.yosh...@windriver.com> Signed-off-by: Haiqing Bai <haiqing@windriver.com> --- drivers/usb/host/ohci-hcd.c | 10 +++--- drivers/usb/host/ohci-hub.c | 4 +++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index ee96763..84f88fa 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -74,6 +74,7 @@ #defineSTATECHANGE_DELAY msecs_to_jiffies(300) #defineIO_WATCHDOG_DELAY msecs_to_jiffies(275) +#defineIO_WATCHDOG_OFF 0xff00 #include "ohci.h" #include "pci-quirks.h" @@ -231,7 +232,7 @@ static int ohci_urb_enqueue ( } /* Start up the I/O watchdog timer, if it's not running */ - if (!timer_pending(>io_watchdog) && + if (ohci->prev_frame_no == IO_WATCHDOG_OFF && list_empty(>eds_in_use) && !(ohci->flags & OHCI_QUIRK_QEMU)) { ohci->prev_frame_no = ohci_frame_no(ohci); @@ -501,6 +502,7 @@ static int ohci_init (struct ohci_hcd *ohci) return 0; timer_setup(>io_watchdog, io_watchdog_func, 0); + ohci->prev_frame_no = IO_WATCHDOG_OFF; ohci->hcca = dma_alloc_coherent (hcd->self.controller, sizeof(*ohci->hcca), >hcca_dma, GFP_KERNEL); @@ -730,7 +732,7 @@ static void io_watchdog_func(struct timer_list *t) u32 head; struct ed *ed; struct td *td, *td_start, *td_next; - unsignedframe_no; + unsignedframe_no, prev_frame_no = IO_WATCHDOG_OFF; unsigned long flags; spin_lock_irqsave(>lock, flags); @@ -835,7 +837,7 @@ static void io_watchdog_func(struct timer_list *t) } } if (!list_empty(>eds_in_use)) { - ohci->prev_frame_no = frame_no; +
[V2][PATCH] ohci-hcd: Fix race condition caused by ohci_urb_enqueue() and io_watchdog_func()
From: Shigeru Yoshida Running io_watchdog_func() while ohci_urb_enqueue() is running can cause a race condition where ohci->prev_frame_no is corrupted and the watchdog can mis-detect following error: ohci-platform 664a0800.usb: frame counter not updating; disabled ohci-platform 664a0800.usb: HC died; cleaning up Specifically, following scenario causes a race condition: 1. ohci_urb_enqueue() calls spin_lock_irqsave(>lock, flags) and enters the critical section 2. ohci_urb_enqueue() calls timer_pending(>io_watchdog) and it returns false 3. ohci_urb_enqueue() sets ohci->prev_frame_no to a frame number read by ohci_frame_no(ohci) 4. ohci_urb_enqueue() schedules io_watchdog_func() with mod_timer() 5. ohci_urb_enqueue() calls spin_unlock_irqrestore(>lock, flags) and exits the critical section 6. Later, ohci_urb_enqueue() is called 7. ohci_urb_enqueue() calls spin_lock_irqsave(>lock, flags) and enters the critical section 8. The timer scheduled on step 4 expires and io_watchdog_func() runs 9. io_watchdog_func() calls spin_lock_irqsave(>lock, flags) and waits on it because ohci_urb_enqueue() is already in the critical section on step 7 10. ohci_urb_enqueue() calls timer_pending(>io_watchdog) and it returns false 11. ohci_urb_enqueue() sets ohci->prev_frame_no to new frame number read by ohci_frame_no(ohci) because the frame number proceeded between step 3 and 6 12. ohci_urb_enqueue() schedules io_watchdog_func() with mod_timer() 13. ohci_urb_enqueue() calls spin_unlock_irqrestore(>lock, flags) and exits the critical section, then wake up io_watchdog_func() which is waiting on step 9 14. io_watchdog_func() enters the critical section 15. io_watchdog_func() calls ohci_frame_no(ohci) and set frame_no variable to the frame number 16. io_watchdog_func() compares frame_no and ohci->prev_frame_no On step 16, because this calling of io_watchdog_func() is scheduled on step 4, the frame number set in ohci->prev_frame_no is expected to the number set on step 3. However, ohci->prev_frame_no is overwritten on step 11. Because step 16 is executed soon after step 11, the frame number might not proceed, so ohci->prev_frame_no must equals to frame_no. To address above scenario, this patch introduces a special sentinel value IO_WATCHDOG_OFF and set this value to ohci->prev_frame_no when the watchdog is not pending or running. When ohci_urb_enqueue() schedules the watchdog (step 4 and 12 above), it compares ohci->prev_frame_no to IO_WATCHDOG_OFF so that ohci->prev_frame_no is not overwritten while io_watchdog_func() is running. v2: Instead of adding an extra flag variable, defining IO_WATCHDOG_OFF as a special sentinel value for prev_frame_no. Signed-off-by: Shigeru Yoshida Signed-off-by: Haiqing Bai --- drivers/usb/host/ohci-hcd.c | 10 +++--- drivers/usb/host/ohci-hub.c | 4 +++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index ee96763..84f88fa 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -74,6 +74,7 @@ #defineSTATECHANGE_DELAY msecs_to_jiffies(300) #defineIO_WATCHDOG_DELAY msecs_to_jiffies(275) +#defineIO_WATCHDOG_OFF 0xff00 #include "ohci.h" #include "pci-quirks.h" @@ -231,7 +232,7 @@ static int ohci_urb_enqueue ( } /* Start up the I/O watchdog timer, if it's not running */ - if (!timer_pending(>io_watchdog) && + if (ohci->prev_frame_no == IO_WATCHDOG_OFF && list_empty(>eds_in_use) && !(ohci->flags & OHCI_QUIRK_QEMU)) { ohci->prev_frame_no = ohci_frame_no(ohci); @@ -501,6 +502,7 @@ static int ohci_init (struct ohci_hcd *ohci) return 0; timer_setup(>io_watchdog, io_watchdog_func, 0); + ohci->prev_frame_no = IO_WATCHDOG_OFF; ohci->hcca = dma_alloc_coherent (hcd->self.controller, sizeof(*ohci->hcca), >hcca_dma, GFP_KERNEL); @@ -730,7 +732,7 @@ static void io_watchdog_func(struct timer_list *t) u32 head; struct ed *ed; struct td *td, *td_start, *td_next; - unsignedframe_no; + unsignedframe_no, prev_frame_no = IO_WATCHDOG_OFF; unsigned long flags; spin_lock_irqsave(>lock, flags); @@ -835,7 +837,7 @@ static void io_watchdog_func(struct timer_list *t) } } if (!list_empty(>eds_in_use)) { - ohci->prev_frame_no = frame_no; + prev_frame_no = frame_no; ohci->prev_wdh_cnt = ohci->
[PATCH] ohci-hcd: Fix race condition caused by ohci_urb_enqueue() and io_watchdog_func()
Running io_watchdog_func() while ohci_urb_enqueue() is running can cause a race condition where ohci->prev_frame_no is corrupted and the watchdog can mis-detect following error: ohci-platform 664a0800.usb: frame counter not updating; disabled ohci-platform 664a0800.usb: HC died; cleaning up Specifically, following scenario causes a race condition: 1. ohci_urb_enqueue() calls spin_lock_irqsave(>lock, flags) and enters the critical section 2. ohci_urb_enqueue() calls timer_pending(>io_watchdog) and it returns false 3. ohci_urb_enqueue() sets ohci->prev_frame_no to a frame number read by ohci_frame_no(ohci) 4. ohci_urb_enqueue() schedules io_watchdog_func() with mod_timer() 5. ohci_urb_enqueue() calls spin_unlock_irqrestore(>lock, flags) and exits the critical section 6. Later, ohci_urb_enqueue() is called 7. ohci_urb_enqueue() calls spin_lock_irqsave(>lock, flags) and enters the critical section 8. The timer scheduled on step 4 expires and io_watchdog_func() runs 9. io_watchdog_func() calls spin_lock_irqsave(>lock, flags) and waits on it because ohci_urb_enqueue() is already in the critical section on step 7 10. ohci_urb_enqueue() calls timer_pending(>io_watchdog) and it returns false 11. ohci_urb_enqueue() sets ohci->prev_frame_no to new frame number read by ohci_frame_no(ohci) because the frame number proceeded between step 3 and 6 12. ohci_urb_enqueue() schedules io_watchdog_func() with mod_timer() 13. ohci_urb_enqueue() calls spin_unlock_irqrestore(>lock, flags) and exits the critical section, then wake up io_watchdog_func() which is waiting on step 9 14. io_watchdog_func() enters the critical section 15. io_watchdog_func() calls ohci_frame_no(ohci) and set frame_no variable to the frame number 16. io_watchdog_func() compares frame_no and ohci->prev_frame_no On step 16, because this calling of io_watchdog_func() is scheduled on step 4, the frame number set in ohci->prev_frame_no is expected to the number set on step 3. However, ohci->prev_frame_no is overwritten on step 11. Because step 16 is executed soon after step 11, the frame number might not proceed, so ohci->prev_frame_no must equals to frame_no. To address above scenario, this patch introduces timer_running flag to ohci_hcd structure. Setting true to ohci->timer_running indicates io_watchdog_func() is scheduled or is running. ohci_urb_enqueue() checks the flag when it schedules the watchdog (step 4 and 12 above), so ohci->prev_frame_no is not overwritten while io_watchdog_func() is running. Author: Yoshida, Shigeru <shigeru.yosh...@windriver.com> Signed-off-by: Haiqing Bai <haiqing@windriver.com> --- drivers/usb/host/ohci-hcd.c | 7 +++ drivers/usb/host/ohci-hub.c | 4 +++- drivers/usb/host/ohci.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index ee9676349333..2c7fa0c05854 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -233,10 +233,12 @@ static int ohci_urb_enqueue ( /* Start up the I/O watchdog timer, if it's not running */ if (!timer_pending(>io_watchdog) && list_empty(>eds_in_use) && + !ohci->timer_running && !(ohci->flags & OHCI_QUIRK_QEMU)) { ohci->prev_frame_no = ohci_frame_no(ohci); mod_timer(>io_watchdog, jiffies + IO_WATCHDOG_DELAY); + ohci->timer_running = 1; } list_add(>in_use_list, >eds_in_use); @@ -501,6 +503,7 @@ static int ohci_init (struct ohci_hcd *ohci) return 0; timer_setup(>io_watchdog, io_watchdog_func, 0); + ohci->timer_running = 0; ohci->hcca = dma_alloc_coherent (hcd->self.controller, sizeof(*ohci->hcca), >hcca_dma, GFP_KERNEL); @@ -732,6 +735,7 @@ static void io_watchdog_func(struct timer_list *t) struct td *td, *td_start, *td_next; unsignedframe_no; unsigned long flags; + int timer_running = 0; spin_lock_irqsave(>lock, flags); @@ -841,10 +845,12 @@ static void io_watchdog_func(struct timer_list *t) >regs->donehead); mod_timer(>io_watchdog, jiffies + IO_WATCHDOG_DELAY); + timer_running = 1; } } done: + ohci->timer_running = timer_running; spin_unlock_irqrestore(>lock, flags); } @@ -973,6 +979,7 @@ static void ohci_stop (struct usb_hcd *hcd) if (quirk_nec(ohci))
[PATCH] ohci-hcd: Fix race condition caused by ohci_urb_enqueue() and io_watchdog_func()
Running io_watchdog_func() while ohci_urb_enqueue() is running can cause a race condition where ohci->prev_frame_no is corrupted and the watchdog can mis-detect following error: ohci-platform 664a0800.usb: frame counter not updating; disabled ohci-platform 664a0800.usb: HC died; cleaning up Specifically, following scenario causes a race condition: 1. ohci_urb_enqueue() calls spin_lock_irqsave(>lock, flags) and enters the critical section 2. ohci_urb_enqueue() calls timer_pending(>io_watchdog) and it returns false 3. ohci_urb_enqueue() sets ohci->prev_frame_no to a frame number read by ohci_frame_no(ohci) 4. ohci_urb_enqueue() schedules io_watchdog_func() with mod_timer() 5. ohci_urb_enqueue() calls spin_unlock_irqrestore(>lock, flags) and exits the critical section 6. Later, ohci_urb_enqueue() is called 7. ohci_urb_enqueue() calls spin_lock_irqsave(>lock, flags) and enters the critical section 8. The timer scheduled on step 4 expires and io_watchdog_func() runs 9. io_watchdog_func() calls spin_lock_irqsave(>lock, flags) and waits on it because ohci_urb_enqueue() is already in the critical section on step 7 10. ohci_urb_enqueue() calls timer_pending(>io_watchdog) and it returns false 11. ohci_urb_enqueue() sets ohci->prev_frame_no to new frame number read by ohci_frame_no(ohci) because the frame number proceeded between step 3 and 6 12. ohci_urb_enqueue() schedules io_watchdog_func() with mod_timer() 13. ohci_urb_enqueue() calls spin_unlock_irqrestore(>lock, flags) and exits the critical section, then wake up io_watchdog_func() which is waiting on step 9 14. io_watchdog_func() enters the critical section 15. io_watchdog_func() calls ohci_frame_no(ohci) and set frame_no variable to the frame number 16. io_watchdog_func() compares frame_no and ohci->prev_frame_no On step 16, because this calling of io_watchdog_func() is scheduled on step 4, the frame number set in ohci->prev_frame_no is expected to the number set on step 3. However, ohci->prev_frame_no is overwritten on step 11. Because step 16 is executed soon after step 11, the frame number might not proceed, so ohci->prev_frame_no must equals to frame_no. To address above scenario, this patch introduces timer_running flag to ohci_hcd structure. Setting true to ohci->timer_running indicates io_watchdog_func() is scheduled or is running. ohci_urb_enqueue() checks the flag when it schedules the watchdog (step 4 and 12 above), so ohci->prev_frame_no is not overwritten while io_watchdog_func() is running. Author: Yoshida, Shigeru Signed-off-by: Haiqing Bai --- drivers/usb/host/ohci-hcd.c | 7 +++ drivers/usb/host/ohci-hub.c | 4 +++- drivers/usb/host/ohci.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index ee9676349333..2c7fa0c05854 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -233,10 +233,12 @@ static int ohci_urb_enqueue ( /* Start up the I/O watchdog timer, if it's not running */ if (!timer_pending(>io_watchdog) && list_empty(>eds_in_use) && + !ohci->timer_running && !(ohci->flags & OHCI_QUIRK_QEMU)) { ohci->prev_frame_no = ohci_frame_no(ohci); mod_timer(>io_watchdog, jiffies + IO_WATCHDOG_DELAY); + ohci->timer_running = 1; } list_add(>in_use_list, >eds_in_use); @@ -501,6 +503,7 @@ static int ohci_init (struct ohci_hcd *ohci) return 0; timer_setup(>io_watchdog, io_watchdog_func, 0); + ohci->timer_running = 0; ohci->hcca = dma_alloc_coherent (hcd->self.controller, sizeof(*ohci->hcca), >hcca_dma, GFP_KERNEL); @@ -732,6 +735,7 @@ static void io_watchdog_func(struct timer_list *t) struct td *td, *td_start, *td_next; unsignedframe_no; unsigned long flags; + int timer_running = 0; spin_lock_irqsave(>lock, flags); @@ -841,10 +845,12 @@ static void io_watchdog_func(struct timer_list *t) >regs->donehead); mod_timer(>io_watchdog, jiffies + IO_WATCHDOG_DELAY); + timer_running = 1; } } done: + ohci->timer_running = timer_running; spin_unlock_irqrestore(>lock, flags); } @@ -973,6 +979,7 @@ static void ohci_stop (struct usb_hcd *hcd) if (quirk_nec(ohci)) flush_work(>nec_work); del_timer_sync(>io_watc