2014-12-14 20:40:08

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 00/19] 3.18.1-stable review

This is the start of the stable review cycle for the 3.18.1 release.
There are 19 patches in this series, all will be posted as a response
to this one. If anyone has any issues with these being applied, please
let me know.

Responses should be made by Tue Dec 16 20:18:16 UTC 2014.
Anything received after that time might be too late.

The whole patch series can be found in one patch at:
kernel.org/pub/linux/kernel/v3.0/stable-review/patch-3.18.1-rc1.gz
and the diffstat can be found below.

thanks,

greg k-h

-------------
Pseudo-Shortlog of commits:

Greg Kroah-Hartman <[email protected]>
Linux 3.18.1-rc1

Takashi Iwai <[email protected]>
ALSA: usb-audio: Don't resubmit pending URBs at MIDI error recovery

Takashi Iwai <[email protected]>
ALSA: hda - Fix built-in mic at resume on Lenovo Ideapad S210

Takashi Iwai <[email protected]>
ALSA: hda - Add EAPD fixup for ASUS Z99He laptop

Al Viro <[email protected]>
deal with deadlock in d_walk()

Al Viro <[email protected]>
move d_rcu from overlapping d_child to overlapping d_alias

Larry Finger <[email protected]>
rtlwifi: rtl8192ce: Fix missing interrupt ready flag

Larry Finger <[email protected]>
rtlwifi: rtl8192ce: Fix kernel crashes due to missing callback entry

Larry Finger <[email protected]>
rtlwifi: rtl8192ce: Fix editing error that causes silent memory corruption

Daniel Borkmann <[email protected]>
netlink: use jhash as hashfn for rhashtable

Valdis Kletnieks <[email protected]>
net: fix suspicious rcu_dereference_check in net/sched/sch_fq_codel.c

David Vrabel <[email protected]>
xen-netfront: use correct linear area after linearizing an skb

Eric Dumazet <[email protected]>
tcp: fix more NULL deref after prequeue changes

Daniel Borkmann <[email protected]>
net: sctp: use MAX_HEADER for headroom reserve in output path

Eric Dumazet <[email protected]>
net: mvneta: fix race condition in mvneta_tx()

willy tarreau <[email protected]>
net: mvneta: fix Tx interrupt delay

Denis Kirjanov <[email protected]>
mips: bpf: Fix broken BPF_MOD

Pravin B Shelar <[email protected]>
openvswitch: Fix flow mask validation.

Tom Herbert <[email protected]>
gre: Set inner mac header in gro complete

Marcelo Leitner <[email protected]>
Fix race condition between vxlan_sock_add and vxlan_sock_release


-------------

Diffstat:

Makefile | 4 +-
arch/mips/net/bpf_jit.c | 4 +-
arch/powerpc/platforms/cell/spufs/inode.c | 2 +-
drivers/net/ethernet/marvell/mvneta.c | 5 +-
drivers/net/vxlan.c | 10 +---
drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | 3 +-
drivers/net/wireless/rtlwifi/rtl8192ce/sw.c | 3 +
drivers/net/wireless/rtlwifi/rtl8192ce/trx.c | 24 ++++++--
drivers/net/wireless/rtlwifi/rtl8192ce/trx.h | 2 +
drivers/net/xen-netfront.c | 3 +
drivers/staging/lustre/lustre/llite/dcache.c | 2 +-
drivers/staging/lustre/lustre/llite/llite_lib.c | 2 +-
drivers/staging/lustre/lustre/llite/namei.c | 8 +--
fs/affs/amigaffs.c | 2 +-
fs/autofs4/expire.c | 12 ++--
fs/autofs4/root.c | 2 +-
fs/ceph/dir.c | 8 +--
fs/ceph/inode.c | 2 +-
fs/cifs/inode.c | 2 +-
fs/coda/cache.c | 2 +-
fs/dcache.c | 80 ++++++++++++-------------
fs/debugfs/inode.c | 2 +-
fs/exportfs/expfs.c | 2 +-
fs/libfs.c | 12 ++--
fs/ncpfs/dir.c | 2 +-
fs/ncpfs/ncplib_kernel.h | 4 +-
fs/nfs/getroot.c | 2 +-
fs/notify/fsnotify.c | 4 +-
fs/ocfs2/dcache.c | 2 +-
include/linux/dcache.h | 8 +--
kernel/trace/trace.c | 4 +-
kernel/trace/trace_events.c | 2 +-
net/ipv4/gre_offload.c | 3 +
net/ipv4/tcp_ipv4.c | 4 +-
net/ipv6/tcp_ipv6.c | 28 ++++-----
net/netlink/af_netlink.c | 2 +-
net/openvswitch/flow_netlink.c | 4 +-
net/sched/sch_fq_codel.c | 2 +-
net/sctp/output.c | 4 +-
security/selinux/selinuxfs.c | 6 +-
sound/pci/hda/patch_analog.c | 1 +
sound/pci/hda/patch_realtek.c | 1 +
sound/usb/midi.c | 2 +
43 files changed, 156 insertions(+), 127 deletions(-)


2014-12-14 20:35:00

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 19/19] ALSA: usb-audio: Dont resubmit pending URBs at MIDI error recovery

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Takashi Iwai <[email protected]>

commit 66139a48cee1530c91f37c145384b4ee7043f0b7 upstream.

In snd_usbmidi_error_timer(), the driver tries to resubmit MIDI input
URBs to reactivate the MIDI stream, but this causes the error when
some of URBs are still pending like:

WARNING: CPU: 0 PID: 0 at ../drivers/usb/core/urb.c:339 usb_submit_urb+0x5f/0x70()
URB ef705c40 submitted while active
CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.16.6-2-desktop #1
Hardware name: FOXCONN TPS01/TPS01, BIOS 080015 03/23/2010
c0984bfa f4009ed4 c078deaf f4009ee4 c024c884 c09a135c f4009f00 00000000
c0984bfa 00000153 c061ac4f c061ac4f 00000009 00000001 ef705c40 e854d1c0
f4009eec c024c8d3 00000009 f4009ee4 c09a135c f4009f00 f4009f04 c061ac4f
Call Trace:
[<c0205df6>] try_stack_unwind+0x156/0x170
[<c020482a>] dump_trace+0x5a/0x1b0
[<c0205e56>] show_trace_log_lvl+0x46/0x50
[<c02049d1>] show_stack_log_lvl+0x51/0xe0
[<c0205eb7>] show_stack+0x27/0x50
[<c078deaf>] dump_stack+0x45/0x65
[<c024c884>] warn_slowpath_common+0x84/0xa0
[<c024c8d3>] warn_slowpath_fmt+0x33/0x40
[<c061ac4f>] usb_submit_urb+0x5f/0x70
[<f7974104>] snd_usbmidi_submit_urb+0x14/0x60 [snd_usbmidi_lib]
[<f797483a>] snd_usbmidi_error_timer+0x6a/0xa0 [snd_usbmidi_lib]
[<c02570c0>] call_timer_fn+0x30/0x130
[<c0257442>] run_timer_softirq+0x1c2/0x260
[<c0251493>] __do_softirq+0xc3/0x270
[<c0204732>] do_softirq_own_stack+0x22/0x30
[<c025186d>] irq_exit+0x8d/0xa0
[<c0795228>] smp_apic_timer_interrupt+0x38/0x50
[<c0794a3c>] apic_timer_interrupt+0x34/0x3c
[<c0673d9e>] cpuidle_enter_state+0x3e/0xd0
[<c028bb8d>] cpu_idle_loop+0x29d/0x3e0
[<c028bd23>] cpu_startup_entry+0x53/0x60
[<c0bfac1e>] start_kernel+0x415/0x41a

For avoiding these errors, check the pending URBs and skip
resubmitting such ones.

Reported-and-tested-by: Stefan Seyfried <[email protected]>
Acked-by: Clemens Ladisch <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
sound/usb/midi.c | 2 ++
1 file changed, 2 insertions(+)

--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -365,6 +365,8 @@ static void snd_usbmidi_error_timer(unsi
if (in && in->error_resubmit) {
in->error_resubmit = 0;
for (j = 0; j < INPUT_URBS; ++j) {
+ if (atomic_read(&in->urbs[j]->use_count))
+ continue;
in->urbs[j]->dev = umidi->dev;
snd_usbmidi_submit_urb(in->urbs[j], GFP_ATOMIC);
}

2014-12-14 20:35:08

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 18/19] ALSA: hda - Fix built-in mic at resume on Lenovo Ideapad S210

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Takashi Iwai <[email protected]>

commit fedb2245cbb8d823e449ebdd48ba9bb35c071ce0 upstream.

The built-in mic boost volume gets almost muted after suspend/resume
on Lenovo Ideapad S210.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88121
Reported-and-tested-by: Roman Kagan <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
sound/pci/hda/patch_realtek.c | 1 +
1 file changed, 1 insertion(+)

--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -4887,6 +4887,7 @@ static const struct snd_pci_quirk alc269
SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad X240", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),

2014-12-14 20:35:12

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 17/19] ALSA: hda - Add EAPD fixup for ASUS Z99He laptop

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Takashi Iwai <[email protected]>

commit f62f5eff3d40a56ad1cf0d81a6cac8dd8743e8a1 upstream.

The same fixup to enable EAPD is needed for ASUS Z99He with AD1986A
codec like another ASUS machine.

Reported-and-tested-by: Dmitry V. Zimin <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
sound/pci/hda/patch_analog.c | 1 +
1 file changed, 1 insertion(+)

--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -332,6 +332,7 @@ static const struct hda_fixup ad1986a_fi

static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC),
+ SND_PCI_QUIRK(0x1043, 0x1443, "ASUS Z99He", AD1986A_FIXUP_EAPD),
SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8JN", AD1986A_FIXUP_EAPD),
SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),
SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),

2014-12-14 20:35:21

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 05/19] net: mvneta: fix Tx interrupt delay

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: willy tarreau <[email protected]>

[ Upstream commit aebea2ba0f7495e1a1c9ea5e753d146cb2f6b845 ]

The mvneta driver sets the amount of Tx coalesce packets to 16 by
default. Normally that does not cause any trouble since the driver
uses a much larger Tx ring size (532 packets). But some sockets
might run with very small buffers, much smaller than the equivalent
of 16 packets. This is what ping is doing for example, by setting
SNDBUF to 324 bytes rounded up to 2kB by the kernel.

The problem is that there is no documented method to force a specific
packet to emit an interrupt (eg: the last of the ring) nor is it
possible to make the NIC emit an interrupt after a given delay.

In this case, it causes trouble, because when ping sends packets over
its raw socket, the few first packets leave the system, and the first
15 packets will be emitted without an IRQ being generated, so without
the skbs being freed. And since the socket's buffer is small, there's
no way to reach that amount of packets, and the ping ends up with
"send: no buffer available" after sending 6 packets. Running with 3
instances of ping in parallel is enough to hide the problem, because
with 6 packets per instance, that's 18 packets total, which is enough
to grant a Tx interrupt before all are sent.

The original driver in the LSP kernel worked around this design flaw
by using a software timer to clean up the Tx descriptors. This timer
was slow and caused terrible network performance on some Tx-bound
workloads (such as routing) but was enough to make tools like ping
work correctly.

Instead here, we simply set the packet counts before interrupt to 1.
This ensures that each packet sent will produce an interrupt. NAPI
takes care of coalescing interrupts since the interrupt is disabled
once generated.

No measurable performance impact nor CPU usage were observed on small
nor large packets, including when saturating the link on Tx, and this
fixes tools like ping which rely on too small a send buffer. If one
wants to increase this value for certain workloads where it is safe
to do so, "ethtool -C $dev tx-frames" will override this default
setting.

This fix needs to be applied to stable kernels starting with 3.10.

Tested-By: Maggie Mae Roxas <[email protected]>
Signed-off-by: Willy Tarreau <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/net/ethernet/marvell/mvneta.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -216,7 +216,7 @@
/* Various constants */

/* Coalescing */
-#define MVNETA_TXDONE_COAL_PKTS 16
+#define MVNETA_TXDONE_COAL_PKTS 1
#define MVNETA_RX_COAL_PKTS 32
#define MVNETA_RX_COAL_USEC 100


2014-12-14 20:35:28

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 09/19] xen-netfront: use correct linear area after linearizing an skb

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: David Vrabel <[email protected]>

[ Upstream commit 11d3d2a16cc1f05c6ece69a4392e99efb85666a6 ]

Commit 97a6d1bb2b658ac85ed88205ccd1ab809899884d (xen-netfront: Fix
handling packets on compound pages with skb_linearize) attempted to
fix a problem where an skb that would have required too many slots
would be dropped causing TCP connections to stall.

However, it filled in the first slot using the original buffer and not
the new one and would use the wrong offset and grant access to the
wrong page.

Netback would notice the malformed request and stop all traffic on the
VIF, reporting:

vif vif-3-0 vif3.0: txreq.offset: 85e, size: 4002, end: 6144
vif vif-3-0 vif3.0: fatal error; disabling device

Reported-by: Anthony Wright <[email protected]>
Tested-by: Anthony Wright <[email protected]>
Signed-off-by: David Vrabel <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/net/xen-netfront.c | 3 +++
1 file changed, 3 insertions(+)

--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -627,6 +627,9 @@ static int xennet_start_xmit(struct sk_b
slots, skb->len);
if (skb_linearize(skb))
goto drop;
+ data = skb->data;
+ offset = offset_in_page(data);
+ len = skb_headlen(skb);
}

spin_lock_irqsave(&queue->tx_lock, flags);

2014-12-14 20:34:51

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 03/19] openvswitch: Fix flow mask validation.

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pravin B Shelar <[email protected]>

[ Upstream commit f2a01517f2a1040a0b156f171a7cefd748f2fd03 ]

Following patch fixes typo in the flow validation. This prevented
installation of ARP and IPv6 flows.

Fixes: 19e7a3df72 ("openvswitch: Fix NDP flow mask validation")
Signed-off-by: Pravin B Shelar <[email protected]>
Reviewed-by: Thomas Graf <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
net/openvswitch/flow_netlink.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -145,7 +145,7 @@ static bool match_validate(const struct
if (match->key->eth.type == htons(ETH_P_ARP)
|| match->key->eth.type == htons(ETH_P_RARP)) {
key_expected |= 1 << OVS_KEY_ATTR_ARP;
- if (match->mask && (match->mask->key.tp.src == htons(0xff)))
+ if (match->mask && (match->mask->key.eth.type == htons(0xffff)))
mask_allowed |= 1 << OVS_KEY_ATTR_ARP;
}

@@ -220,7 +220,7 @@ static bool match_validate(const struct
htons(NDISC_NEIGHBOUR_SOLICITATION) ||
match->key->tp.src == htons(NDISC_NEIGHBOUR_ADVERTISEMENT)) {
key_expected |= 1 << OVS_KEY_ATTR_ND;
- if (match->mask && (match->mask->key.tp.src == htons(0xffff)))
+ if (match->mask && (match->mask->key.tp.src == htons(0xff)))
mask_allowed |= 1 << OVS_KEY_ATTR_ND;
}
}

2014-12-14 20:40:17

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 08/19] tcp: fix more NULL deref after prequeue changes

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit 0f85feae6b710ced3abad5b2b47d31dfcb956b62 ]

When I cooked commit c3658e8d0f1 ("tcp: fix possible NULL dereference in
tcp_vX_send_reset()") I missed other spots we could deref a NULL
skb_dst(skb)

Again, if a socket is provided, we do not need skb_dst() to get a
pointer to network namespace : sock_net(sk) is good enough.

Reported-by: Dann Frazier <[email protected]>
Bisected-by: Dann Frazier <[email protected]>
Tested-by: Dann Frazier <[email protected]>
Signed-off-by: Eric Dumazet <[email protected]>
Fixes: ca777eff51f7 ("tcp: remove dst refcount false sharing for prequeue mode")
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
net/ipv4/tcp_ipv4.c | 4 ++--
net/ipv6/tcp_ipv6.c | 28 ++++++++++++++--------------
2 files changed, 16 insertions(+), 16 deletions(-)

--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -623,6 +623,7 @@ static void tcp_v4_send_reset(struct soc
arg.iov[0].iov_base = (unsigned char *)&rep;
arg.iov[0].iov_len = sizeof(rep.th);

+ net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev);
#ifdef CONFIG_TCP_MD5SIG
hash_location = tcp_parse_md5sig_option(th);
if (!sk && hash_location) {
@@ -633,7 +634,7 @@ static void tcp_v4_send_reset(struct soc
* Incoming packet is checked with md5 hash with finding key,
* no RST generated if md5 hash doesn't match.
*/
- sk1 = __inet_lookup_listener(dev_net(skb_dst(skb)->dev),
+ sk1 = __inet_lookup_listener(net,
&tcp_hashinfo, ip_hdr(skb)->saddr,
th->source, ip_hdr(skb)->daddr,
ntohs(th->source), inet_iif(skb));
@@ -681,7 +682,6 @@ static void tcp_v4_send_reset(struct soc
if (sk)
arg.bound_dev_if = sk->sk_bound_dev_if;

- net = dev_net(skb_dst(skb)->dev);
arg.tos = ip_hdr(skb)->tos;
ip_send_unicast_reply(net, skb, &TCP_SKB_CB(skb)->header.h4.opt,
ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -787,16 +787,16 @@ static const struct tcp_request_sock_ops
.queue_hash_add = inet6_csk_reqsk_queue_hash_add,
};

-static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
- u32 tsval, u32 tsecr, int oif,
- struct tcp_md5sig_key *key, int rst, u8 tclass,
- u32 label)
+static void tcp_v6_send_response(struct sock *sk, struct sk_buff *skb, u32 seq,
+ u32 ack, u32 win, u32 tsval, u32 tsecr,
+ int oif, struct tcp_md5sig_key *key, int rst,
+ u8 tclass, u32 label)
{
const struct tcphdr *th = tcp_hdr(skb);
struct tcphdr *t1;
struct sk_buff *buff;
struct flowi6 fl6;
- struct net *net = dev_net(skb_dst(skb)->dev);
+ struct net *net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev);
struct sock *ctl_sk = net->ipv6.tcp_sk;
unsigned int tot_len = sizeof(struct tcphdr);
struct dst_entry *dst;
@@ -946,7 +946,7 @@ static void tcp_v6_send_reset(struct soc
(th->doff << 2);

oif = sk ? sk->sk_bound_dev_if : 0;
- tcp_v6_send_response(skb, seq, ack_seq, 0, 0, 0, oif, key, 1, 0, 0);
+ tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, oif, key, 1, 0, 0);

#ifdef CONFIG_TCP_MD5SIG
release_sk1:
@@ -957,13 +957,13 @@ release_sk1:
#endif
}

-static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
- u32 win, u32 tsval, u32 tsecr, int oif,
+static void tcp_v6_send_ack(struct sock *sk, struct sk_buff *skb, u32 seq,
+ u32 ack, u32 win, u32 tsval, u32 tsecr, int oif,
struct tcp_md5sig_key *key, u8 tclass,
u32 label)
{
- tcp_v6_send_response(skb, seq, ack, win, tsval, tsecr, oif, key, 0, tclass,
- label);
+ tcp_v6_send_response(sk, skb, seq, ack, win, tsval, tsecr, oif, key, 0,
+ tclass, label);
}

static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
@@ -971,7 +971,7 @@ static void tcp_v6_timewait_ack(struct s
struct inet_timewait_sock *tw = inet_twsk(sk);
struct tcp_timewait_sock *tcptw = tcp_twsk(sk);

- tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
+ tcp_v6_send_ack(sk, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
tcp_time_stamp + tcptw->tw_ts_offset,
tcptw->tw_ts_recent, tw->tw_bound_dev_if, tcp_twsk_md5_key(tcptw),
@@ -986,10 +986,10 @@ static void tcp_v6_reqsk_send_ack(struct
/* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV
* sk->sk_state == TCP_SYN_RECV -> for Fast Open.
*/
- tcp_v6_send_ack(skb, (sk->sk_state == TCP_LISTEN) ?
+ tcp_v6_send_ack(sk, skb, (sk->sk_state == TCP_LISTEN) ?
tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt,
- tcp_rsk(req)->rcv_nxt,
- req->rcv_wnd, tcp_time_stamp, req->ts_recent, sk->sk_bound_dev_if,
+ tcp_rsk(req)->rcv_nxt, req->rcv_wnd,
+ tcp_time_stamp, req->ts_recent, sk->sk_bound_dev_if,
tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr),
0, 0);
}

2014-12-14 20:40:23

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 06/19] net: mvneta: fix race condition in mvneta_tx()

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit 5f478b41033606d325e420df693162e2524c2b94 ]

mvneta_tx() dereferences skb to get skb->len too late,
as hardware might have completed the transmit and TX completion
could have freed the skb from another cpu.

Fixes: 71f6d1b31fb1 ("net: mvneta: replace Tx timer with a real interrupt")
Signed-off-by: Eric Dumazet <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/net/ethernet/marvell/mvneta.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -1721,6 +1721,7 @@ static int mvneta_tx(struct sk_buff *skb
u16 txq_id = skb_get_queue_mapping(skb);
struct mvneta_tx_queue *txq = &pp->txqs[txq_id];
struct mvneta_tx_desc *tx_desc;
+ int len = skb->len;
int frags = 0;
u32 tx_cmd;

@@ -1788,7 +1789,7 @@ out:

u64_stats_update_begin(&stats->syncp);
stats->tx_packets++;
- stats->tx_bytes += skb->len;
+ stats->tx_bytes += len;
u64_stats_update_end(&stats->syncp);
} else {
dev->stats.tx_dropped++;

2014-12-14 20:40:29

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 04/19] mips: bpf: Fix broken BPF_MOD

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Denis Kirjanov <[email protected]>

[ Upstream commit 2e46477a12f6fd273e31a220b155d66e8352198c ]

Remove optimize_div() from BPF_MOD | BPF_K case
since we don't know the dividend and fix the
emit_mod() by reading the mod operation result from HI register

Signed-off-by: Denis Kirjanov <[email protected]>
Reviewed-by: Markos Chandras <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
arch/mips/net/bpf_jit.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

--- a/arch/mips/net/bpf_jit.c
+++ b/arch/mips/net/bpf_jit.c
@@ -426,7 +426,7 @@ static inline void emit_mod(unsigned int
u32 *p = &ctx->target[ctx->idx];
uasm_i_divu(&p, dst, src);
p = &ctx->target[ctx->idx + 1];
- uasm_i_mflo(&p, dst);
+ uasm_i_mfhi(&p, dst);
}
ctx->idx += 2; /* 2 insts */
}
@@ -971,7 +971,7 @@ load_ind:
break;
case BPF_ALU | BPF_MOD | BPF_K:
/* A %= k */
- if (k == 1 || optimize_div(&k)) {
+ if (k == 1) {
ctx->flags |= SEEN_A;
emit_jit_reg_move(r_A, r_zero, ctx);
} else {

2014-12-14 20:40:35

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 02/19] gre: Set inner mac header in gro complete

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Tom Herbert <[email protected]>

[ Upstream commit 6fb2a756739aa507c1fd5b8126f0bfc2f070dc46 ]

Set the inner mac header to point to the GRE payload when
doing GRO. This is needed if we proceed to send the packet
through GRE GSO which now uses the inner mac header instead
of inner network header to determine the length of encapsulation
headers.

Fixes: 14051f0452a2 ("gre: Use inner mac length when computing tunnel length")
Reported-by: Wolfgang Walter <[email protected]>
Signed-off-by: Tom Herbert <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
net/ipv4/gre_offload.c | 3 +++
1 file changed, 3 insertions(+)

--- a/net/ipv4/gre_offload.c
+++ b/net/ipv4/gre_offload.c
@@ -247,6 +247,9 @@ static int gre_gro_complete(struct sk_bu
err = ptype->callbacks.gro_complete(skb, nhoff + grehlen);

rcu_read_unlock();
+
+ skb_set_inner_mac_header(skb, nhoff + grehlen);
+
return err;
}


2014-12-14 20:41:36

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 16/19] deal with deadlock in d_walk()

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Al Viro <[email protected]>

commit ca5358ef75fc69fee5322a38a340f5739d997c10 upstream.

... by not hitting rename_retry for reasons other than rename having
happened. In other words, do _not_ restart when finding that
between unlocking the child and locking the parent the former got
into __dentry_kill(). Skip the killed siblings instead...

Signed-off-by: Al Viro <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
fs/dcache.c | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)

--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -495,7 +495,7 @@ static void __dentry_kill(struct dentry
}
/* if it was on the hash then remove it */
__d_drop(dentry);
- list_del(&dentry->d_child);
+ __list_del_entry(&dentry->d_child);
/*
* Inform d_walk() that we are no longer attached to the
* dentry tree
@@ -1082,33 +1082,31 @@ resume:
/*
* All done at this level ... ascend and resume the search.
*/
+ rcu_read_lock();
+ascend:
if (this_parent != parent) {
struct dentry *child = this_parent;
this_parent = child->d_parent;

- rcu_read_lock();
spin_unlock(&child->d_lock);
spin_lock(&this_parent->d_lock);

- /*
- * might go back up the wrong parent if we have had a rename
- * or deletion
- */
- if (this_parent != child->d_parent ||
- (child->d_flags & DCACHE_DENTRY_KILLED) ||
- need_seqretry(&rename_lock, seq)) {
- spin_unlock(&this_parent->d_lock);
- rcu_read_unlock();
+ /* might go back up the wrong parent if we have had a rename. */
+ if (need_seqretry(&rename_lock, seq))
goto rename_retry;
+ next = child->d_child.next;
+ while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)) {
+ if (next == &this_parent->d_subdirs)
+ goto ascend;
+ child = list_entry(next, struct dentry, d_child);
+ next = next->next;
}
rcu_read_unlock();
- next = child->d_child.next;
goto resume;
}
- if (need_seqretry(&rename_lock, seq)) {
- spin_unlock(&this_parent->d_lock);
+ if (need_seqretry(&rename_lock, seq))
goto rename_retry;
- }
+ rcu_read_unlock();
if (finish)
finish(data);

@@ -1118,6 +1116,9 @@ out_unlock:
return;

rename_retry:
+ spin_unlock(&this_parent->d_lock);
+ rcu_read_unlock();
+ BUG_ON(seq & 1);
if (!retry)
return;
seq = 1;

2014-12-14 20:41:39

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 15/19] move d_rcu from overlapping d_child to overlapping d_alias

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Al Viro <[email protected]>

commit 946e51f2bf37f1656916eb75bd0742ba33983c28 upstream.

Signed-off-by: Al Viro <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
arch/powerpc/platforms/cell/spufs/inode.c | 2
drivers/staging/lustre/lustre/llite/dcache.c | 2
drivers/staging/lustre/lustre/llite/llite_lib.c | 2
drivers/staging/lustre/lustre/llite/namei.c | 8 +--
fs/affs/amigaffs.c | 2
fs/autofs4/expire.c | 12 ++---
fs/autofs4/root.c | 2
fs/ceph/dir.c | 8 +--
fs/ceph/inode.c | 2
fs/cifs/inode.c | 2
fs/coda/cache.c | 2
fs/dcache.c | 53 +++++++++++-------------
fs/debugfs/inode.c | 2
fs/exportfs/expfs.c | 2
fs/libfs.c | 12 ++---
fs/ncpfs/dir.c | 2
fs/ncpfs/ncplib_kernel.h | 4 -
fs/nfs/getroot.c | 2
fs/notify/fsnotify.c | 4 -
fs/ocfs2/dcache.c | 2
include/linux/dcache.h | 8 +--
kernel/trace/trace.c | 4 -
kernel/trace/trace_events.c | 2
security/selinux/selinuxfs.c | 6 +-
24 files changed, 73 insertions(+), 74 deletions(-)

--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -164,7 +164,7 @@ static void spufs_prune_dir(struct dentr
struct dentry *dentry, *tmp;

mutex_lock(&dir->d_inode->i_mutex);
- list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) {
+ list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) {
spin_lock(&dentry->d_lock);
if (!(d_unhashed(dentry)) && dentry->d_inode) {
dget_dlock(dentry);
--- a/drivers/staging/lustre/lustre/llite/dcache.c
+++ b/drivers/staging/lustre/lustre/llite/dcache.c
@@ -258,7 +258,7 @@ void ll_invalidate_aliases(struct inode
inode->i_ino, inode->i_generation, inode);

ll_lock_dcache(inode);
- ll_d_hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
+ ll_d_hlist_for_each_entry(dentry, p, &inode->i_dentry, d_u.d_alias) {
CDEBUG(D_DENTRY, "dentry in drop %.*s (%p) parent %p "
"inode %p flags %d\n", dentry->d_name.len,
dentry->d_name.name, dentry, dentry->d_parent,
--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
+++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
@@ -711,7 +711,7 @@ void lustre_dump_dentry(struct dentry *d
return;

list_for_each(tmp, &dentry->d_subdirs) {
- struct dentry *d = list_entry(tmp, struct dentry, d_u.d_child);
+ struct dentry *d = list_entry(tmp, struct dentry, d_child);
lustre_dump_dentry(d, recur - 1);
}
}
--- a/drivers/staging/lustre/lustre/llite/namei.c
+++ b/drivers/staging/lustre/lustre/llite/namei.c
@@ -167,14 +167,14 @@ static void ll_invalidate_negative_child
struct ll_d_hlist_node *p;

ll_lock_dcache(dir);
- ll_d_hlist_for_each_entry(dentry, p, &dir->i_dentry, d_alias) {
+ ll_d_hlist_for_each_entry(dentry, p, &dir->i_dentry, d_u.d_alias) {
spin_lock(&dentry->d_lock);
if (!list_empty(&dentry->d_subdirs)) {
struct dentry *child;

list_for_each_entry_safe(child, tmp_subdir,
&dentry->d_subdirs,
- d_u.d_child) {
+ d_child) {
if (child->d_inode == NULL)
d_lustre_invalidate(child, 1);
}
@@ -362,7 +362,7 @@ static struct dentry *ll_find_alias(stru
discon_alias = invalid_alias = NULL;

ll_lock_dcache(inode);
- ll_d_hlist_for_each_entry(alias, p, &inode->i_dentry, d_alias) {
+ ll_d_hlist_for_each_entry(alias, p, &inode->i_dentry, d_u.d_alias) {
LASSERT(alias != dentry);

spin_lock(&alias->d_lock);
@@ -953,7 +953,7 @@ static void ll_get_child_fid(struct inod
{
struct dentry *parent, *child;

- parent = ll_d_hlist_entry(dir->i_dentry, struct dentry, d_alias);
+ parent = ll_d_hlist_entry(dir->i_dentry, struct dentry, d_u.d_alias);
child = d_lookup(parent, name);
if (child) {
if (child->d_inode)
--- a/fs/affs/amigaffs.c
+++ b/fs/affs/amigaffs.c
@@ -125,7 +125,7 @@ affs_fix_dcache(struct inode *inode, u32
{
struct dentry *dentry;
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
if (entry_ino == (u32)(long)dentry->d_fsdata) {
dentry->d_fsdata = (void *)inode->i_ino;
break;
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -85,7 +85,7 @@ static struct dentry *get_next_positive_
spin_lock(&root->d_lock);

if (prev)
- next = prev->d_u.d_child.next;
+ next = prev->d_child.next;
else {
prev = dget_dlock(root);
next = prev->d_subdirs.next;
@@ -99,13 +99,13 @@ cont:
return NULL;
}

- q = list_entry(next, struct dentry, d_u.d_child);
+ q = list_entry(next, struct dentry, d_child);

spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED);
/* Already gone or negative dentry (under construction) - try next */
if (!d_count(q) || !simple_positive(q)) {
spin_unlock(&q->d_lock);
- next = q->d_u.d_child.next;
+ next = q->d_child.next;
goto cont;
}
dget_dlock(q);
@@ -155,13 +155,13 @@ again:
goto relock;
}
spin_unlock(&p->d_lock);
- next = p->d_u.d_child.next;
+ next = p->d_child.next;
p = parent;
if (next != &parent->d_subdirs)
break;
}
}
- ret = list_entry(next, struct dentry, d_u.d_child);
+ ret = list_entry(next, struct dentry, d_child);

spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED);
/* Negative dentry - try next */
@@ -489,7 +489,7 @@ found:
spin_lock(&sbi->lookup_lock);
spin_lock(&expired->d_parent->d_lock);
spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED);
- list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
+ list_move(&expired->d_parent->d_subdirs, &expired->d_child);
spin_unlock(&expired->d_lock);
spin_unlock(&expired->d_parent->d_lock);
spin_unlock(&sbi->lookup_lock);
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -687,7 +687,7 @@ static void autofs_clear_leaf_automount_
/* only consider parents below dentrys in the root */
if (IS_ROOT(parent->d_parent))
return;
- d_child = &dentry->d_u.d_child;
+ d_child = &dentry->d_child;
/* Set parent managed if it's becoming empty */
if (d_child->next == &parent->d_subdirs &&
d_child->prev == &parent->d_subdirs)
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -111,7 +111,7 @@ static int fpos_cmp(loff_t l, loff_t r)
/*
* When possible, we try to satisfy a readdir by peeking at the
* dcache. We make this work by carefully ordering dentries on
- * d_u.d_child when we initially get results back from the MDS, and
+ * d_child when we initially get results back from the MDS, and
* falling back to a "normal" sync readdir if any dentries in the dir
* are dropped.
*
@@ -147,11 +147,11 @@ static int __dcache_readdir(struct file
p = parent->d_subdirs.prev;
dout(" initial p %p/%p\n", p->prev, p->next);
} else {
- p = last->d_u.d_child.prev;
+ p = last->d_child.prev;
}

more:
- dentry = list_entry(p, struct dentry, d_u.d_child);
+ dentry = list_entry(p, struct dentry, d_child);
di = ceph_dentry(dentry);
while (1) {
dout(" p %p/%p %s d_subdirs %p/%p\n", p->prev, p->next,
@@ -174,7 +174,7 @@ more:
!dentry->d_inode ? " null" : "");
spin_unlock(&dentry->d_lock);
p = p->prev;
- dentry = list_entry(p, struct dentry, d_u.d_child);
+ dentry = list_entry(p, struct dentry, d_child);
di = ceph_dentry(dentry);
}

--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -1399,7 +1399,7 @@ retry_lookup:
/* reorder parent's d_subdirs */
spin_lock(&parent->d_lock);
spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED);
- list_move(&dn->d_u.d_child, &parent->d_subdirs);
+ list_move(&dn->d_child, &parent->d_subdirs);
spin_unlock(&dn->d_lock);
spin_unlock(&parent->d_lock);
}
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -895,7 +895,7 @@ inode_has_hashed_dentries(struct inode *
struct dentry *dentry;

spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
spin_unlock(&inode->i_lock);
return true;
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -92,7 +92,7 @@ static void coda_flag_children(struct de
struct dentry *de;

spin_lock(&parent->d_lock);
- list_for_each_entry(de, &parent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(de, &parent->d_subdirs, d_child) {
/* don't know what to do with negative dentries */
if (de->d_inode )
coda_flag_inode(de->d_inode, flag);
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -44,7 +44,7 @@
/*
* Usage:
* dcache->d_inode->i_lock protects:
- * - i_dentry, d_alias, d_inode of aliases
+ * - i_dentry, d_u.d_alias, d_inode of aliases
* dcache_hash_bucket lock protects:
* - the dcache hash table
* s_anon bl list spinlock protects:
@@ -59,7 +59,7 @@
* - d_unhashed()
* - d_parent and d_subdirs
* - childrens' d_child and d_parent
- * - d_alias, d_inode
+ * - d_u.d_alias, d_inode
*
* Ordering:
* dentry->d_inode->i_lock
@@ -252,14 +252,12 @@ static void __d_free(struct rcu_head *he
{
struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);

- WARN_ON(!hlist_unhashed(&dentry->d_alias));
kmem_cache_free(dentry_cache, dentry);
}

static void __d_free_external(struct rcu_head *head)
{
struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
- WARN_ON(!hlist_unhashed(&dentry->d_alias));
kfree(external_name(dentry));
kmem_cache_free(dentry_cache, dentry);
}
@@ -271,6 +269,7 @@ static inline int dname_external(const s

static void dentry_free(struct dentry *dentry)
{
+ WARN_ON(!hlist_unhashed(&dentry->d_u.d_alias));
if (unlikely(dname_external(dentry))) {
struct external_name *p = external_name(dentry);
if (likely(atomic_dec_and_test(&p->u.count))) {
@@ -311,7 +310,7 @@ static void dentry_iput(struct dentry *
struct inode *inode = dentry->d_inode;
if (inode) {
dentry->d_inode = NULL;
- hlist_del_init(&dentry->d_alias);
+ hlist_del_init(&dentry->d_u.d_alias);
spin_unlock(&dentry->d_lock);
spin_unlock(&inode->i_lock);
if (!inode->i_nlink)
@@ -336,7 +335,7 @@ static void dentry_unlink_inode(struct d
struct inode *inode = dentry->d_inode;
__d_clear_type(dentry);
dentry->d_inode = NULL;
- hlist_del_init(&dentry->d_alias);
+ hlist_del_init(&dentry->d_u.d_alias);
dentry_rcuwalk_barrier(dentry);
spin_unlock(&dentry->d_lock);
spin_unlock(&inode->i_lock);
@@ -496,7 +495,7 @@ static void __dentry_kill(struct dentry
}
/* if it was on the hash then remove it */
__d_drop(dentry);
- list_del(&dentry->d_u.d_child);
+ list_del(&dentry->d_child);
/*
* Inform d_walk() that we are no longer attached to the
* dentry tree
@@ -722,7 +721,7 @@ static struct dentry *__d_find_alias(str

again:
discon_alias = NULL;
- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
spin_lock(&alias->d_lock);
if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
if (IS_ROOT(alias) &&
@@ -772,7 +771,7 @@ void d_prune_aliases(struct inode *inode
struct dentry *dentry;
restart:
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
spin_lock(&dentry->d_lock);
if (!dentry->d_lockref.count) {
struct dentry *parent = lock_parent(dentry);
@@ -1051,7 +1050,7 @@ repeat:
resume:
while (next != &this_parent->d_subdirs) {
struct list_head *tmp = next;
- struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
+ struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
next = tmp->next;

spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
@@ -1103,7 +1102,7 @@ resume:
goto rename_retry;
}
rcu_read_unlock();
- next = child->d_u.d_child.next;
+ next = child->d_child.next;
goto resume;
}
if (need_seqretry(&rename_lock, seq)) {
@@ -1455,8 +1454,8 @@ struct dentry *__d_alloc(struct super_bl
INIT_HLIST_BL_NODE(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_lru);
INIT_LIST_HEAD(&dentry->d_subdirs);
- INIT_HLIST_NODE(&dentry->d_alias);
- INIT_LIST_HEAD(&dentry->d_u.d_child);
+ INIT_HLIST_NODE(&dentry->d_u.d_alias);
+ INIT_LIST_HEAD(&dentry->d_child);
d_set_d_op(dentry, dentry->d_sb->s_d_op);

this_cpu_inc(nr_dentry);
@@ -1486,7 +1485,7 @@ struct dentry *d_alloc(struct dentry * p
*/
__dget_dlock(parent);
dentry->d_parent = parent;
- list_add(&dentry->d_u.d_child, &parent->d_subdirs);
+ list_add(&dentry->d_child, &parent->d_subdirs);
spin_unlock(&parent->d_lock);

return dentry;
@@ -1579,7 +1578,7 @@ static void __d_instantiate(struct dentr
spin_lock(&dentry->d_lock);
__d_set_type(dentry, add_flags);
if (inode)
- hlist_add_head(&dentry->d_alias, &inode->i_dentry);
+ hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
dentry->d_inode = inode;
dentry_rcuwalk_barrier(dentry);
spin_unlock(&dentry->d_lock);
@@ -1603,7 +1602,7 @@ static void __d_instantiate(struct dentr

void d_instantiate(struct dentry *entry, struct inode * inode)
{
- BUG_ON(!hlist_unhashed(&entry->d_alias));
+ BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
if (inode)
spin_lock(&inode->i_lock);
__d_instantiate(entry, inode);
@@ -1642,7 +1641,7 @@ static struct dentry *__d_instantiate_un
return NULL;
}

- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
/*
* Don't need alias->d_lock here, because aliases with
* d_parent == entry->d_parent are not subject to name or
@@ -1668,7 +1667,7 @@ struct dentry *d_instantiate_unique(stru
{
struct dentry *result;

- BUG_ON(!hlist_unhashed(&entry->d_alias));
+ BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));

if (inode)
spin_lock(&inode->i_lock);
@@ -1699,7 +1698,7 @@ EXPORT_SYMBOL(d_instantiate_unique);
*/
int d_instantiate_no_diralias(struct dentry *entry, struct inode *inode)
{
- BUG_ON(!hlist_unhashed(&entry->d_alias));
+ BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));

spin_lock(&inode->i_lock);
if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry)) {
@@ -1738,7 +1737,7 @@ static struct dentry * __d_find_any_alia

if (hlist_empty(&inode->i_dentry))
return NULL;
- alias = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+ alias = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
__dget(alias);
return alias;
}
@@ -1800,7 +1799,7 @@ static struct dentry *__d_obtain_alias(s
spin_lock(&tmp->d_lock);
tmp->d_inode = inode;
tmp->d_flags |= add_flags;
- hlist_add_head(&tmp->d_alias, &inode->i_dentry);
+ hlist_add_head(&tmp->d_u.d_alias, &inode->i_dentry);
hlist_bl_lock(&tmp->d_sb->s_anon);
hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon);
hlist_bl_unlock(&tmp->d_sb->s_anon);
@@ -2235,7 +2234,7 @@ int d_validate(struct dentry *dentry, st
struct dentry *child;

spin_lock(&dparent->d_lock);
- list_for_each_entry(child, &dparent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &dparent->d_subdirs, d_child) {
if (dentry == child) {
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
__dget_dlock(dentry);
@@ -2526,13 +2525,13 @@ static void __d_move(struct dentry *dent
/* splicing a tree */
dentry->d_parent = target->d_parent;
target->d_parent = target;
- list_del_init(&target->d_u.d_child);
- list_move(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
+ list_del_init(&target->d_child);
+ list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
} else {
/* swapping two dentries */
swap(dentry->d_parent, target->d_parent);
- list_move(&target->d_u.d_child, &target->d_parent->d_subdirs);
- list_move(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
+ list_move(&target->d_child, &target->d_parent->d_subdirs);
+ list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
if (exchange)
fsnotify_d_move(target);
fsnotify_d_move(dentry);
@@ -3321,7 +3320,7 @@ void d_tmpfile(struct dentry *dentry, st
{
inode_dec_link_count(inode);
BUG_ON(dentry->d_name.name != dentry->d_iname ||
- !hlist_unhashed(&dentry->d_alias) ||
+ !hlist_unhashed(&dentry->d_u.d_alias) ||
!d_unlinked(dentry));
spin_lock(&dentry->d_parent->d_lock);
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -553,7 +553,7 @@ void debugfs_remove_recursive(struct den
* use the d_u.d_child as the rcu head and corrupt this list.
*/
spin_lock(&parent->d_lock);
- list_for_each_entry(child, &parent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &parent->d_subdirs, d_child) {
if (!debugfs_positive(child))
continue;

--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -50,7 +50,7 @@ find_acceptable_alias(struct dentry *res

inode = result->d_inode;
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
dget(dentry);
spin_unlock(&inode->i_lock);
if (toput)
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -114,18 +114,18 @@ loff_t dcache_dir_lseek(struct file *fil

spin_lock(&dentry->d_lock);
/* d_lock not required for cursor */
- list_del(&cursor->d_u.d_child);
+ list_del(&cursor->d_child);
p = dentry->d_subdirs.next;
while (n && p != &dentry->d_subdirs) {
struct dentry *next;
- next = list_entry(p, struct dentry, d_u.d_child);
+ next = list_entry(p, struct dentry, d_child);
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
if (simple_positive(next))
n--;
spin_unlock(&next->d_lock);
p = p->next;
}
- list_add_tail(&cursor->d_u.d_child, p);
+ list_add_tail(&cursor->d_child, p);
spin_unlock(&dentry->d_lock);
}
}
@@ -150,7 +150,7 @@ int dcache_readdir(struct file *file, st
{
struct dentry *dentry = file->f_path.dentry;
struct dentry *cursor = file->private_data;
- struct list_head *p, *q = &cursor->d_u.d_child;
+ struct list_head *p, *q = &cursor->d_child;

if (!dir_emit_dots(file, ctx))
return 0;
@@ -159,7 +159,7 @@ int dcache_readdir(struct file *file, st
list_move(q, &dentry->d_subdirs);

for (p = q->next; p != &dentry->d_subdirs; p = p->next) {
- struct dentry *next = list_entry(p, struct dentry, d_u.d_child);
+ struct dentry *next = list_entry(p, struct dentry, d_child);
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
if (!simple_positive(next)) {
spin_unlock(&next->d_lock);
@@ -287,7 +287,7 @@ int simple_empty(struct dentry *dentry)
int ret = 0;

spin_lock(&dentry->d_lock);
- list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &dentry->d_subdirs, d_child) {
spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
if (simple_positive(child)) {
spin_unlock(&child->d_lock);
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -403,7 +403,7 @@ ncp_dget_fpos(struct dentry *dentry, str

/* If a pointer is invalid, we search the dentry. */
spin_lock(&parent->d_lock);
- list_for_each_entry(dent, &parent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(dent, &parent->d_subdirs, d_child) {
if ((unsigned long)dent->d_fsdata == fpos) {
if (dent->d_inode)
dget(dent);
--- a/fs/ncpfs/ncplib_kernel.h
+++ b/fs/ncpfs/ncplib_kernel.h
@@ -191,7 +191,7 @@ ncp_renew_dentries(struct dentry *parent
struct dentry *dentry;

spin_lock(&parent->d_lock);
- list_for_each_entry(dentry, &parent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
if (dentry->d_fsdata == NULL)
ncp_age_dentry(server, dentry);
else
@@ -207,7 +207,7 @@ ncp_invalidate_dircache_entries(struct d
struct dentry *dentry;

spin_lock(&parent->d_lock);
- list_for_each_entry(dentry, &parent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
dentry->d_fsdata = NULL;
ncp_age_dentry(server, dentry);
}
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -58,7 +58,7 @@ static int nfs_superblock_set_dummy_root
*/
spin_lock(&sb->s_root->d_inode->i_lock);
spin_lock(&sb->s_root->d_lock);
- hlist_del_init(&sb->s_root->d_alias);
+ hlist_del_init(&sb->s_root->d_u.d_alias);
spin_unlock(&sb->s_root->d_lock);
spin_unlock(&sb->s_root->d_inode->i_lock);
}
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -63,14 +63,14 @@ void __fsnotify_update_child_dentry_flag
spin_lock(&inode->i_lock);
/* run all of the dentries associated with this inode. Since this is a
* directory, there damn well better only be one item on this list */
- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
struct dentry *child;

/* run all of the children of the original inode and fix their
* d_flags to indicate parental interest (their parent is the
* original inode) */
spin_lock(&alias->d_lock);
- list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &alias->d_subdirs, d_child) {
if (!child->d_inode)
continue;

--- a/fs/ocfs2/dcache.c
+++ b/fs/ocfs2/dcache.c
@@ -172,7 +172,7 @@ struct dentry *ocfs2_find_local_alias(st
struct dentry *dentry;

spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
spin_lock(&dentry->d_lock);
if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) {
trace_ocfs2_find_local_alias(dentry->d_name.len,
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -124,15 +124,15 @@ struct dentry {
void *d_fsdata; /* fs-specific data */

struct list_head d_lru; /* LRU list */
+ struct list_head d_child; /* child of parent list */
+ struct list_head d_subdirs; /* our children */
/*
- * d_child and d_rcu can share memory
+ * d_alias and d_rcu can share memory
*/
union {
- struct list_head d_child; /* child of parent list */
+ struct hlist_node d_alias; /* inode alias list */
struct rcu_head d_rcu;
} d_u;
- struct list_head d_subdirs; /* our children */
- struct hlist_node d_alias; /* inode alias list */
};

/*
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6417,7 +6417,7 @@ static int instance_mkdir (struct inode
int ret;

/* Paranoid: Make sure the parent is the "instances" directory */
- parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+ parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
if (WARN_ON_ONCE(parent != trace_instance_dir))
return -ENOENT;

@@ -6444,7 +6444,7 @@ static int instance_rmdir(struct inode *
int ret;

/* Paranoid: Make sure the parent is the "instances" directory */
- parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+ parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
if (WARN_ON_ONCE(parent != trace_instance_dir))
return -ENOENT;

--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -461,7 +461,7 @@ static void remove_event_file_dir(struct

if (dir) {
spin_lock(&dir->d_lock); /* probably unneeded */
- list_for_each_entry(child, &dir->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &dir->d_subdirs, d_child) {
if (child->d_inode) /* probably unneeded */
child->d_inode->i_private = NULL;
}
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -1200,7 +1200,7 @@ static void sel_remove_entries(struct de
spin_lock(&de->d_lock);
node = de->d_subdirs.next;
while (node != &de->d_subdirs) {
- struct dentry *d = list_entry(node, struct dentry, d_u.d_child);
+ struct dentry *d = list_entry(node, struct dentry, d_child);

spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED);
list_del_init(node);
@@ -1674,12 +1674,12 @@ static void sel_remove_classes(void)

list_for_each(class_node, &class_dir->d_subdirs) {
struct dentry *class_subdir = list_entry(class_node,
- struct dentry, d_u.d_child);
+ struct dentry, d_child);
struct list_head *class_subdir_node;

list_for_each(class_subdir_node, &class_subdir->d_subdirs) {
struct dentry *d = list_entry(class_subdir_node,
- struct dentry, d_u.d_child);
+ struct dentry, d_child);

if (d->d_inode)
if (d->d_inode->i_mode & S_IFDIR)

2014-12-14 20:41:52

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 13/19] rtlwifi: rtl8192ce: Fix kernel crashes due to missing callback entry

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Larry Finger <[email protected]>

commit f892914c03131a445b926b82815b03162c19288e upstream.

In the major update of the rtlwifi-family of drivers, one of the callback entries
was missed, which leads to memory corruption. Unfortunately, this corruption
never caused a kernel oops, but showed up in other parts of the system.
This patch is one of three needed to fix the kernel regression reported at
https://bugzilla.kernel.org/show_bug.cgi?id=88951.

Signed-off-by: Larry Finger <[email protected]>
Reported-by: Catalin Iacob <[email protected]>
Tested-by: Catalin Iacob <[email protected]>
Cc: Catalin Iacob <[email protected]>
Signed-off-by: John W. Linville <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
drivers/net/wireless/rtlwifi/rtl8192ce/sw.c | 3 +++
drivers/net/wireless/rtlwifi/rtl8192ce/trx.c | 17 +++++++++++++++++
drivers/net/wireless/rtlwifi/rtl8192ce/trx.h | 2 ++
3 files changed, 22 insertions(+)

--- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
@@ -228,6 +228,7 @@ static struct rtl_hal_ops rtl8192ce_hal_
.led_control = rtl92ce_led_control,
.set_desc = rtl92ce_set_desc,
.get_desc = rtl92ce_get_desc,
+ .is_tx_desc_closed = rtl92ce_is_tx_desc_closed,
.tx_polling = rtl92ce_tx_polling,
.enable_hw_sec = rtl92ce_enable_hw_security_config,
.set_key = rtl92ce_set_key,
@@ -271,6 +272,8 @@ static struct rtl_hal_cfg rtl92ce_hal_cf
.maps[MAC_RCR_ACRC32] = ACRC32,
.maps[MAC_RCR_ACF] = ACF,
.maps[MAC_RCR_AAP] = AAP,
+ .maps[MAC_HIMR] = REG_HIMR,
+ .maps[MAC_HIMRE] = REG_HIMRE,

.maps[EFUSE_TEST] = REG_EFUSE_TEST,
.maps[EFUSE_CTRL] = REG_EFUSE_CTRL,
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
@@ -739,6 +739,23 @@ u32 rtl92ce_get_desc(u8 *p_desc, bool is
return ret;
}

+bool rtl92ce_is_tx_desc_closed(struct ieee80211_hw *hw,
+ u8 hw_queue, u16 index)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
+ u8 *entry = (u8 *)(&ring->desc[ring->idx]);
+ u8 own = (u8)rtl92ce_get_desc(entry, true, HW_DESC_OWN);
+
+ /*beacon packet will only use the first
+ *descriptor defautly,and the own may not
+ *be cleared by the hardware
+ */
+ if (own)
+ return false;
+ return true;
+}
+
void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
@@ -723,6 +723,8 @@ bool rtl92ce_rx_query_desc(struct ieee80
void rtl92ce_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
u8 desc_name, u8 *val);
u32 rtl92ce_get_desc(u8 *pdesc, bool istx, u8 desc_name);
+bool rtl92ce_is_tx_desc_closed(struct ieee80211_hw *hw,
+ u8 hw_queue, u16 index);
void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
bool b_firstseg, bool b_lastseg,

2014-12-14 20:41:56

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 12/19] rtlwifi: rtl8192ce: Fix editing error that causes silent memory corruption

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Larry Finger <[email protected]>

commit 99a82f734aa6c6d397e029e6dfa933f04e0fa8c8 upstream.

In the major update of the rtlwifi-family of drivers, there was an editing
mistake. Unfortunately, this particular error leads to memory corruption that
silently leads to failure of the system. This patch is one of three needed to
fix the kernel regression reported at https://bugzilla.kernel.org/show_bug.cgi?id=88951.

Signed-off-by: Larry Finger <[email protected]>
Reported-by: Catalin Iacob <[email protected]>
Tested-by: Catalin Iacob <[email protected]>
Cc: Catalin Iacob <[email protected]>
Signed-off-by: John W. Linville <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
drivers/net/wireless/rtlwifi/rtl8192ce/trx.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)

--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
@@ -720,16 +720,15 @@ u32 rtl92ce_get_desc(u8 *p_desc, bool is
break;
}
} else {
- struct rx_desc_92c *pdesc = (struct rx_desc_92c *)p_desc;
switch (desc_name) {
case HW_DESC_OWN:
- ret = GET_RX_DESC_OWN(pdesc);
+ ret = GET_RX_DESC_OWN(p_desc);
break;
case HW_DESC_RXPKT_LEN:
- ret = GET_RX_DESC_PKT_LEN(pdesc);
+ ret = GET_RX_DESC_PKT_LEN(p_desc);
break;
case HW_DESC_RXBUFF_ADDR:
- ret = GET_RX_STATUS_DESC_BUFF_ADDR(pdesc);
+ ret = GET_RX_DESC_BUFF_ADDR(p_desc);
break;
default:
RT_ASSERT(false, "ERR rxdesc :%d not process\n",

2014-12-14 20:41:48

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 14/19] rtlwifi: rtl8192ce: Fix missing interrupt ready flag

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Larry Finger <[email protected]>

commit 87141db0848aa20c43d453f5545efc8f390d4372 upstream.

Proper operation with the rewritten PCI mini driver requires that a flag be set
when interrupts are enabled. This flag was missed. This patch is one of three needed to
fix the kernel regression reported at https://bugzilla.kernel.org/show_bug.cgi?id=88951.

Signed-off-by: Larry Finger <[email protected]>
Reported-by: Catalin Iacob <[email protected]>
Tested-by: Catalin Iacob <[email protected]>
Cc: Catalin Iacob <[email protected]>
Signed-off-by: John W. Linville <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
@@ -1287,6 +1287,7 @@ void rtl92ce_enable_interrupt(struct iee

rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
+ rtlpci->irq_enabled = true;
}

void rtl92ce_disable_interrupt(struct ieee80211_hw *hw)
@@ -1296,7 +1297,7 @@ void rtl92ce_disable_interrupt(struct ie

rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED);
rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED);
- synchronize_irq(rtlpci->pdev->irq);
+ rtlpci->irq_enabled = false;
}

static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw)

2014-12-14 20:42:54

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 10/19] net: fix suspicious rcu_dereference_check in net/sched/sch_fq_codel.c

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: "[email protected]" <[email protected]>

[ Upstream commit 69204cf7eb9c5a72067ce6922d4699378251d053 ]

commit 46e5da40ae (net: qdisc: use rcu prefix and silence
sparse warnings) triggers a spurious warning:

net/sched/sch_fq_codel.c:97 suspicious rcu_dereference_check() usage!

The code should be using the _bh variant of rcu_dereference.

Signed-off-by: Valdis Kletnieks <[email protected]>
Acked-by: Eric Dumazet <[email protected]>
Acked-by: John Fastabend <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
net/sched/sch_fq_codel.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
@@ -94,7 +94,7 @@ static unsigned int fq_codel_classify(st
TC_H_MIN(skb->priority) <= q->flows_cnt)
return TC_H_MIN(skb->priority);

- filter = rcu_dereference(q->filter_list);
+ filter = rcu_dereference_bh(q->filter_list);
if (!filter)
return fq_codel_hash(q, skb) + 1;


2014-12-14 20:43:01

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 11/19] netlink: use jhash as hashfn for rhashtable

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Daniel Borkmann <[email protected]>

[ Upstream commit 7f19fc5e0b617593dcda0d9956adc78b559ef1f5 ]

For netlink, we shouldn't be using arch_fast_hash() as a hashing
discipline, but rather jhash() instead.

Since netlink sockets can be opened by any user, a local attacker
would be able to easily create collisions with the DPDK-derived
arch_fast_hash(), which trades off performance for security by
using crc32 CPU instructions on x86_64.

While it might have a legimite use case in other places, it should
be avoided in netlink context, though. As rhashtable's API is very
flexible, we could later on still decide on other hashing disciplines,
if legitimate.

Reference: http://thread.gmane.org/gmane.linux.kernel/1844123
Fixes: e341694e3eb5 ("netlink: Convert netlink_lookup() to use RCU protected hash table")
Cc: Herbert Xu <[email protected]>
Signed-off-by: Daniel Borkmann <[email protected]>
Acked-by: Thomas Graf <[email protected]>
Acked-by: Hannes Frederic Sowa <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
net/netlink/af_netlink.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -3130,7 +3130,7 @@ static int __init netlink_proto_init(voi
.head_offset = offsetof(struct netlink_sock, node),
.key_offset = offsetof(struct netlink_sock, portid),
.key_len = sizeof(u32), /* portid */
- .hashfn = arch_fast_hash,
+ .hashfn = jhash,
.max_shift = 16, /* 64K */
.grow_decision = rht_grow_above_75,
.shrink_decision = rht_shrink_below_30,

2014-12-14 20:43:16

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 3.18 01/19] Fix race condition between vxlan_sock_add and vxlan_sock_release

3.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Marcelo Leitner <[email protected]>

[ Upstream commit 00c83b01d58068dfeb2e1351cca6fccf2a83fa8f ]

Currently, when trying to reuse a socket, vxlan_sock_add will grab
vn->sock_lock, locate a reusable socket, inc refcount and release
vn->sock_lock.

But vxlan_sock_release() will first decrement refcount, and then grab
that lock. refcnt operations are atomic but as currently we have
deferred works which hold vs->refcnt each, this might happen, leading to
a use after free (specially after vxlan_igmp_leave):

CPU 1 CPU 2

deferred work vxlan_sock_add
... ...
spin_lock(&vn->sock_lock)
vs = vxlan_find_sock();
vxlan_sock_release
dec vs->refcnt, reaches 0
spin_lock(&vn->sock_lock)
vxlan_sock_hold(vs), refcnt=1
spin_unlock(&vn->sock_lock)
hlist_del_rcu(&vs->hlist);
vxlan_notify_del_rx_port(vs)
spin_unlock(&vn->sock_lock)

So when we look for a reusable socket, we check if it wasn't freed
already before reusing it.

Signed-off-by: Marcelo Ricardo Leitner <[email protected]>
Fixes: 7c47cedf43a8b3 ("vxlan: move IGMP join/leave to work queue")
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
drivers/net/vxlan.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)

--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -1995,9 +1995,8 @@ static int vxlan_init(struct net_device
spin_lock(&vn->sock_lock);
vs = vxlan_find_sock(vxlan->net, ipv6 ? AF_INET6 : AF_INET,
vxlan->dst_port);
- if (vs) {
+ if (vs && atomic_add_unless(&vs->refcnt, 1, 0)) {
/* If we have a socket with same port already, reuse it */
- atomic_inc(&vs->refcnt);
vxlan_vs_add_dev(vs, vxlan);
} else {
/* otherwise make new socket outside of RTNL */
@@ -2396,12 +2395,9 @@ struct vxlan_sock *vxlan_sock_add(struct

spin_lock(&vn->sock_lock);
vs = vxlan_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port);
- if (vs) {
- if (vs->rcv == rcv)
- atomic_inc(&vs->refcnt);
- else
+ if (vs && ((vs->rcv != rcv) ||
+ !atomic_add_unless(&vs->refcnt, 1, 0)))
vs = ERR_PTR(-EBUSY);
- }
spin_unlock(&vn->sock_lock);

if (!vs)

2014-12-15 03:33:23

by Guenter Roeck

[permalink] [raw]
Subject: Re: [PATCH 3.18 00/19] 3.18.1-stable review

On 12/14/2014 12:21 PM, Greg Kroah-Hartman wrote:
> This is the start of the stable review cycle for the 3.18.1 release.
> There are 19 patches in this series, all will be posted as a response
> to this one. If anyone has any issues with these being applied, please
> let me know.
>
> Responses should be made by Tue Dec 16 20:18:16 UTC 2014.
> Anything received after that time might be too late.
>

Build results:
total: 133 pass: 133 fail: 0

Qemu tests:
total: 30 pass: 30 fail: 0

Details are available at http://server.roeck-us.net:8010/builders.

Guenter

2014-12-15 04:24:28

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 3.18 00/19] 3.18.1-stable review

On Sun, Dec 14, 2014 at 07:33:12PM -0800, Guenter Roeck wrote:
> On 12/14/2014 12:21 PM, Greg Kroah-Hartman wrote:
> >This is the start of the stable review cycle for the 3.18.1 release.
> >There are 19 patches in this series, all will be posted as a response
> >to this one. If anyone has any issues with these being applied, please
> >let me know.
> >
> >Responses should be made by Tue Dec 16 20:18:16 UTC 2014.
> >Anything received after that time might be too late.
> >
>
> Build results:
> total: 133 pass: 133 fail: 0
>
> Qemu tests:
> total: 30 pass: 30 fail: 0
>
> Details are available at http://server.roeck-us.net:8010/builders.

Thanks for testing and letting me know about all of these.

greg k-h

2014-12-15 15:47:13

by Josh Boyer

[permalink] [raw]
Subject: Re: [PATCH 3.18 15/19] move d_rcu from overlapping d_child to overlapping d_alias

On Sun, Dec 14, 2014 at 12:21:26PM -0800, Greg Kroah-Hartman wrote:
>3.18-stable review patch. If anyone has any objections, please let me know.
>
>------------------
>
>From: Al Viro <[email protected]>
>
>commit 946e51f2bf37f1656916eb75bd0742ba33983c28 upstream.
>
>Signed-off-by: Al Viro <[email protected]>
>Signed-off-by: Greg Kroah-Hartman <[email protected]>

I noticed you don't have this (and the child commit) queued for 3.17.y.
The backport wasn't exactly straight-forward because of the d_external
stuff, but I took a swing at it. After that, the other commit was a
quick cherry-pick.

Al, does the below look correct for a backport on top of 3.17.6? It
builds, but I haven't tested it yet.

josh

From: Al Viro <[email protected]>
Date: Sun, 26 Oct 2014 19:19:16 -0400
Subject: [PATCH] move d_rcu from overlapping d_child to overlapping d_alias

Signed-off-by: Al Viro <[email protected]>
Backported-by: Josh Boyer <[email protected]>
Signed-off-by: Josh Boyer <[email protected]>

---
arch/powerpc/platforms/cell/spufs/inode.c | 2 +-
drivers/staging/lustre/lustre/llite/dcache.c | 2 +-
drivers/staging/lustre/lustre/llite/llite_lib.c | 2 +-
drivers/staging/lustre/lustre/llite/namei.c | 8 ++--
fs/affs/amigaffs.c | 2 +-
fs/autofs4/expire.c | 12 +++---
fs/autofs4/root.c | 2 +-
fs/ceph/dir.c | 8 ++--
fs/ceph/inode.c | 2 +-
fs/cifs/inode.c | 2 +-
fs/coda/cache.c | 2 +-
fs/dcache.c | 52 ++++++++++++-------------
fs/debugfs/inode.c | 2 +-
fs/exportfs/expfs.c | 2 +-
fs/libfs.c | 12 +++---
fs/ncpfs/dir.c | 2 +-
fs/ncpfs/ncplib_kernel.h | 4 +-
fs/nfs/getroot.c | 2 +-
fs/notify/fsnotify.c | 4 +-
fs/ocfs2/dcache.c | 2 +-
include/linux/dcache.h | 8 ++--
kernel/trace/trace.c | 4 +-
kernel/trace/trace_events.c | 2 +-
security/selinux/selinuxfs.c | 6 +--
24 files changed, 73 insertions(+), 73 deletions(-)

diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 87ba7cf99cd7..65d633f20d37 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -164,7 +164,7 @@ static void spufs_prune_dir(struct dentry *dir)
struct dentry *dentry, *tmp;

mutex_lock(&dir->d_inode->i_mutex);
- list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) {
+ list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) {
spin_lock(&dentry->d_lock);
if (!(d_unhashed(dentry)) && dentry->d_inode) {
dget_dlock(dentry);
diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c
index 49ae207ad425..e2add5fde0fe 100644
--- a/drivers/staging/lustre/lustre/llite/dcache.c
+++ b/drivers/staging/lustre/lustre/llite/dcache.c
@@ -258,7 +258,7 @@ void ll_invalidate_aliases(struct inode *inode)
inode->i_ino, inode->i_generation, inode);

ll_lock_dcache(inode);
- ll_d_hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
+ ll_d_hlist_for_each_entry(dentry, p, &inode->i_dentry, d_u.d_alias) {
CDEBUG(D_DENTRY, "dentry in drop %.*s (%p) parent %p "
"inode %p flags %d\n", dentry->d_name.len,
dentry->d_name.name, dentry, dentry->d_parent,
diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c
index 0c59e26c0805..36e62524a37b 100644
--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
+++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
@@ -704,7 +704,7 @@ void lustre_dump_dentry(struct dentry *dentry, int recur)
return;

list_for_each(tmp, &dentry->d_subdirs) {
- struct dentry *d = list_entry(tmp, struct dentry, d_u.d_child);
+ struct dentry *d = list_entry(tmp, struct dentry, d_child);
lustre_dump_dentry(d, recur - 1);
}
}
diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c
index 0dc7173bbd41..9de0d51e33a2 100644
--- a/drivers/staging/lustre/lustre/llite/namei.c
+++ b/drivers/staging/lustre/lustre/llite/namei.c
@@ -167,14 +167,14 @@ static void ll_invalidate_negative_children(struct inode *dir)
struct ll_d_hlist_node *p;

ll_lock_dcache(dir);
- ll_d_hlist_for_each_entry(dentry, p, &dir->i_dentry, d_alias) {
+ ll_d_hlist_for_each_entry(dentry, p, &dir->i_dentry, d_u.d_alias) {
spin_lock(&dentry->d_lock);
if (!list_empty(&dentry->d_subdirs)) {
struct dentry *child;

list_for_each_entry_safe(child, tmp_subdir,
&dentry->d_subdirs,
- d_u.d_child) {
+ d_child) {
if (child->d_inode == NULL)
d_lustre_invalidate(child, 1);
}
@@ -362,7 +362,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry)
discon_alias = invalid_alias = NULL;

ll_lock_dcache(inode);
- ll_d_hlist_for_each_entry(alias, p, &inode->i_dentry, d_alias) {
+ ll_d_hlist_for_each_entry(alias, p, &inode->i_dentry, d_u.d_alias) {
LASSERT(alias != dentry);

spin_lock(&alias->d_lock);
@@ -943,7 +943,7 @@ static void ll_get_child_fid(struct inode * dir, struct qstr *name,
{
struct dentry *parent, *child;

- parent = ll_d_hlist_entry(dir->i_dentry, struct dentry, d_alias);
+ parent = ll_d_hlist_entry(dir->i_dentry, struct dentry, d_u.d_alias);
child = d_lookup(parent, name);
if (child) {
if (child->d_inode)
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
index 406b29836b19..a674c114fd8e 100644
--- a/fs/affs/amigaffs.c
+++ b/fs/affs/amigaffs.c
@@ -127,7 +127,7 @@ affs_fix_dcache(struct inode *inode, u32 entry_ino)
{
struct dentry *dentry;
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
if (entry_ino == (u32)(long)dentry->d_fsdata) {
dentry->d_fsdata = (void *)inode->i_ino;
break;
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index a7be57e39be7..11c6cddff1b9 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -91,7 +91,7 @@ static struct dentry *get_next_positive_subdir(struct dentry *prev,
spin_lock(&root->d_lock);

if (prev)
- next = prev->d_u.d_child.next;
+ next = prev->d_child.next;
else {
prev = dget_dlock(root);
next = prev->d_subdirs.next;
@@ -105,13 +105,13 @@ cont:
return NULL;
}

- q = list_entry(next, struct dentry, d_u.d_child);
+ q = list_entry(next, struct dentry, d_child);

spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED);
/* Already gone or negative dentry (under construction) - try next */
if (!d_count(q) || !simple_positive(q)) {
spin_unlock(&q->d_lock);
- next = q->d_u.d_child.next;
+ next = q->d_child.next;
goto cont;
}
dget_dlock(q);
@@ -161,13 +161,13 @@ again:
goto relock;
}
spin_unlock(&p->d_lock);
- next = p->d_u.d_child.next;
+ next = p->d_child.next;
p = parent;
if (next != &parent->d_subdirs)
break;
}
}
- ret = list_entry(next, struct dentry, d_u.d_child);
+ ret = list_entry(next, struct dentry, d_child);

spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED);
/* Negative dentry - try next */
@@ -460,7 +460,7 @@ found:
spin_lock(&sbi->lookup_lock);
spin_lock(&expired->d_parent->d_lock);
spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED);
- list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
+ list_move(&expired->d_parent->d_subdirs, &expired->d_child);
spin_unlock(&expired->d_lock);
spin_unlock(&expired->d_parent->d_lock);
spin_unlock(&sbi->lookup_lock);
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index cdb25ebccc4c..38a9e0fa5177 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -659,7 +659,7 @@ static void autofs_clear_leaf_automount_flags(struct dentry *dentry)
/* only consider parents below dentrys in the root */
if (IS_ROOT(parent->d_parent))
return;
- d_child = &dentry->d_u.d_child;
+ d_child = &dentry->d_child;
/* Set parent managed if it's becoming empty */
if (d_child->next == &parent->d_subdirs &&
d_child->prev == &parent->d_subdirs)
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index c29d6ae68874..51ea03313df9 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -111,7 +111,7 @@ static int fpos_cmp(loff_t l, loff_t r)
/*
* When possible, we try to satisfy a readdir by peeking at the
* dcache. We make this work by carefully ordering dentries on
- * d_u.d_child when we initially get results back from the MDS, and
+ * d_child when we initially get results back from the MDS, and
* falling back to a "normal" sync readdir if any dentries in the dir
* are dropped.
*
@@ -147,11 +147,11 @@ static int __dcache_readdir(struct file *file, struct dir_context *ctx,
p = parent->d_subdirs.prev;
dout(" initial p %p/%p\n", p->prev, p->next);
} else {
- p = last->d_u.d_child.prev;
+ p = last->d_child.prev;
}

more:
- dentry = list_entry(p, struct dentry, d_u.d_child);
+ dentry = list_entry(p, struct dentry, d_child);
di = ceph_dentry(dentry);
while (1) {
dout(" p %p/%p %s d_subdirs %p/%p\n", p->prev, p->next,
@@ -174,7 +174,7 @@ more:
!dentry->d_inode ? " null" : "");
spin_unlock(&dentry->d_lock);
p = p->prev;
- dentry = list_entry(p, struct dentry, d_u.d_child);
+ dentry = list_entry(p, struct dentry, d_child);
di = ceph_dentry(dentry);
}

diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 04c89c266cec..c3e103ff18bd 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -1399,7 +1399,7 @@ retry_lookup:
/* reorder parent's d_subdirs */
spin_lock(&parent->d_lock);
spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED);
- list_move(&dn->d_u.d_child, &parent->d_subdirs);
+ list_move(&dn->d_child, &parent->d_subdirs);
spin_unlock(&dn->d_lock);
spin_unlock(&parent->d_lock);
}
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 7899a40465b3..6d1dd0942937 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -887,7 +887,7 @@ inode_has_hashed_dentries(struct inode *inode)
struct dentry *dentry;

spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
spin_unlock(&inode->i_lock);
return true;
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index 278f8fdeb9ef..46ee6f238985 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -92,7 +92,7 @@ static void coda_flag_children(struct dentry *parent, int flag)
struct dentry *de;

spin_lock(&parent->d_lock);
- list_for_each_entry(de, &parent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(de, &parent->d_subdirs, d_child) {
/* don't know what to do with negative dentries */
if (de->d_inode )
coda_flag_inode(de->d_inode, flag);
diff --git a/fs/dcache.c b/fs/dcache.c
index 34b40be8af11..5634c4f927d1 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -44,7 +44,7 @@
/*
* Usage:
* dcache->d_inode->i_lock protects:
- * - i_dentry, d_alias, d_inode of aliases
+ * - i_dentry, d_u.d_alias, d_inode of aliases
* dcache_hash_bucket lock protects:
* - the dcache hash table
* s_anon bl list spinlock protects:
@@ -59,7 +59,7 @@
* - d_unhashed()
* - d_parent and d_subdirs
* - childrens' d_child and d_parent
- * - d_alias, d_inode
+ * - d_u.d_alias, d_inode
*
* Ordering:
* dentry->d_inode->i_lock
@@ -239,7 +239,7 @@ static void __d_free(struct rcu_head *head)
{
struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);

- WARN_ON(!hlist_unhashed(&dentry->d_alias));
+ WARN_ON(!hlist_unhashed(&dentry->d_u.d_alias));
if (dname_external(dentry))
kfree(dentry->d_name.name);
kmem_cache_free(dentry_cache, dentry);
@@ -280,7 +280,7 @@ static void dentry_iput(struct dentry * dentry)
struct inode *inode = dentry->d_inode;
if (inode) {
dentry->d_inode = NULL;
- hlist_del_init(&dentry->d_alias);
+ hlist_del_init(&dentry->d_u.d_alias);
spin_unlock(&dentry->d_lock);
spin_unlock(&inode->i_lock);
if (!inode->i_nlink)
@@ -305,7 +305,7 @@ static void dentry_unlink_inode(struct dentry * dentry)
struct inode *inode = dentry->d_inode;
__d_clear_type(dentry);
dentry->d_inode = NULL;
- hlist_del_init(&dentry->d_alias);
+ hlist_del_init(&dentry->d_u.d_alias);
dentry_rcuwalk_barrier(dentry);
spin_unlock(&dentry->d_lock);
spin_unlock(&inode->i_lock);
@@ -465,7 +465,7 @@ static void __dentry_kill(struct dentry *dentry)
}
/* if it was on the hash then remove it */
__d_drop(dentry);
- list_del(&dentry->d_u.d_child);
+ list_del(&dentry->d_child);
/*
* Inform d_walk() that we are no longer attached to the
* dentry tree
@@ -746,7 +746,7 @@ static struct dentry *__d_find_alias(struct inode *inode)

again:
discon_alias = NULL;
- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
spin_lock(&alias->d_lock);
if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
if (IS_ROOT(alias) &&
@@ -796,7 +796,7 @@ void d_prune_aliases(struct inode *inode)
struct dentry *dentry;
restart:
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
spin_lock(&dentry->d_lock);
if (!dentry->d_lockref.count) {
/*
@@ -1081,7 +1081,7 @@ repeat:
resume:
while (next != &this_parent->d_subdirs) {
struct list_head *tmp = next;
- struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
+ struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
next = tmp->next;

spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
@@ -1133,7 +1133,7 @@ resume:
goto rename_retry;
}
rcu_read_unlock();
- next = child->d_u.d_child.next;
+ next = child->d_child.next;
goto resume;
}
if (need_seqretry(&rename_lock, seq)) {
@@ -1468,8 +1468,8 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
INIT_HLIST_BL_NODE(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_lru);
INIT_LIST_HEAD(&dentry->d_subdirs);
- INIT_HLIST_NODE(&dentry->d_alias);
- INIT_LIST_HEAD(&dentry->d_u.d_child);
+ INIT_HLIST_NODE(&dentry->d_u.d_alias);
+ INIT_LIST_HEAD(&dentry->d_child);
d_set_d_op(dentry, dentry->d_sb->s_d_op);

this_cpu_inc(nr_dentry);
@@ -1499,7 +1499,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
*/
__dget_dlock(parent);
dentry->d_parent = parent;
- list_add(&dentry->d_u.d_child, &parent->d_subdirs);
+ list_add(&dentry->d_child, &parent->d_subdirs);
spin_unlock(&parent->d_lock);

return dentry;
@@ -1592,7 +1592,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
spin_lock(&dentry->d_lock);
__d_set_type(dentry, add_flags);
if (inode)
- hlist_add_head(&dentry->d_alias, &inode->i_dentry);
+ hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
dentry->d_inode = inode;
dentry_rcuwalk_barrier(dentry);
spin_unlock(&dentry->d_lock);
@@ -1616,7 +1616,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)

void d_instantiate(struct dentry *entry, struct inode * inode)
{
- BUG_ON(!hlist_unhashed(&entry->d_alias));
+ BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
if (inode)
spin_lock(&inode->i_lock);
__d_instantiate(entry, inode);
@@ -1655,7 +1655,7 @@ static struct dentry *__d_instantiate_unique(struct dentry *entry,
return NULL;
}

- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
/*
* Don't need alias->d_lock here, because aliases with
* d_parent == entry->d_parent are not subject to name or
@@ -1681,7 +1681,7 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
{
struct dentry *result;

- BUG_ON(!hlist_unhashed(&entry->d_alias));
+ BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));

if (inode)
spin_lock(&inode->i_lock);
@@ -1712,7 +1712,7 @@ EXPORT_SYMBOL(d_instantiate_unique);
*/
int d_instantiate_no_diralias(struct dentry *entry, struct inode *inode)
{
- BUG_ON(!hlist_unhashed(&entry->d_alias));
+ BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));

spin_lock(&inode->i_lock);
if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry)) {
@@ -1751,7 +1751,7 @@ static struct dentry * __d_find_any_alias(struct inode *inode)

if (hlist_empty(&inode->i_dentry))
return NULL;
- alias = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+ alias = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
__dget(alias);
return alias;
}
@@ -1813,7 +1813,7 @@ static struct dentry *__d_obtain_alias(struct inode *inode, int disconnected)
spin_lock(&tmp->d_lock);
tmp->d_inode = inode;
tmp->d_flags |= add_flags;
- hlist_add_head(&tmp->d_alias, &inode->i_dentry);
+ hlist_add_head(&tmp->d_u.d_alias, &inode->i_dentry);
hlist_bl_lock(&tmp->d_sb->s_anon);
hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon);
hlist_bl_unlock(&tmp->d_sb->s_anon);
@@ -2248,7 +2248,7 @@ int d_validate(struct dentry *dentry, struct dentry *dparent)
struct dentry *child;

spin_lock(&dparent->d_lock);
- list_for_each_entry(child, &dparent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &dparent->d_subdirs, d_child) {
if (dentry == child) {
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
__dget_dlock(dentry);
@@ -2525,13 +2525,13 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
/* splicing a tree */
dentry->d_parent = target->d_parent;
target->d_parent = target;
- list_del_init(&target->d_u.d_child);
- list_move(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
+ list_del_init(&target->d_child);
+ list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
} else {
/* swapping two dentries */
swap(dentry->d_parent, target->d_parent);
- list_move(&target->d_u.d_child, &target->d_parent->d_subdirs);
- list_move(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
+ list_move(&target->d_child, &target->d_parent->d_subdirs);
+ list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
if (exchange)
fsnotify_d_move(target);
fsnotify_d_move(dentry);
@@ -3322,7 +3322,7 @@ void d_tmpfile(struct dentry *dentry, struct inode *inode)
{
inode_dec_link_count(inode);
BUG_ON(dentry->d_name.name != dentry->d_iname ||
- !hlist_unhashed(&dentry->d_alias) ||
+ !hlist_unhashed(&dentry->d_u.d_alias) ||
!d_unlinked(dentry));
spin_lock(&dentry->d_parent->d_lock);
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 1e3b99d3db0d..05f2960ed7c3 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -553,7 +553,7 @@ void debugfs_remove_recursive(struct dentry *dentry)
* use the d_u.d_child as the rcu head and corrupt this list.
*/
spin_lock(&parent->d_lock);
- list_for_each_entry(child, &parent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &parent->d_subdirs, d_child) {
if (!debugfs_positive(child))
continue;

diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index b01fbfb51f43..a3aa6baad1a1 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -50,7 +50,7 @@ find_acceptable_alias(struct dentry *result,

inode = result->d_inode;
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
dget(dentry);
spin_unlock(&inode->i_lock);
if (toput)
diff --git a/fs/libfs.c b/fs/libfs.c
index 88e3e00e2eca..e801b983b46b 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -114,18 +114,18 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)

spin_lock(&dentry->d_lock);
/* d_lock not required for cursor */
- list_del(&cursor->d_u.d_child);
+ list_del(&cursor->d_child);
p = dentry->d_subdirs.next;
while (n && p != &dentry->d_subdirs) {
struct dentry *next;
- next = list_entry(p, struct dentry, d_u.d_child);
+ next = list_entry(p, struct dentry, d_child);
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
if (simple_positive(next))
n--;
spin_unlock(&next->d_lock);
p = p->next;
}
- list_add_tail(&cursor->d_u.d_child, p);
+ list_add_tail(&cursor->d_child, p);
spin_unlock(&dentry->d_lock);
}
}
@@ -150,7 +150,7 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)
{
struct dentry *dentry = file->f_path.dentry;
struct dentry *cursor = file->private_data;
- struct list_head *p, *q = &cursor->d_u.d_child;
+ struct list_head *p, *q = &cursor->d_child;

if (!dir_emit_dots(file, ctx))
return 0;
@@ -159,7 +159,7 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)
list_move(q, &dentry->d_subdirs);

for (p = q->next; p != &dentry->d_subdirs; p = p->next) {
- struct dentry *next = list_entry(p, struct dentry, d_u.d_child);
+ struct dentry *next = list_entry(p, struct dentry, d_child);
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
if (!simple_positive(next)) {
spin_unlock(&next->d_lock);
@@ -287,7 +287,7 @@ int simple_empty(struct dentry *dentry)
int ret = 0;

spin_lock(&dentry->d_lock);
- list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &dentry->d_subdirs, d_child) {
spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
if (simple_positive(child)) {
spin_unlock(&child->d_lock);
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 08b8ea8c353e..3a8ed0fb07be 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -406,7 +406,7 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
spin_lock(&parent->d_lock);
next = parent->d_subdirs.next;
while (next != &parent->d_subdirs) {
- dent = list_entry(next, struct dentry, d_u.d_child);
+ dent = list_entry(next, struct dentry, d_child);
if ((unsigned long)dent->d_fsdata == fpos) {
if (dent->d_inode)
dget(dent);
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h
index 32c06587351a..6d5e7c56c79d 100644
--- a/fs/ncpfs/ncplib_kernel.h
+++ b/fs/ncpfs/ncplib_kernel.h
@@ -194,7 +194,7 @@ ncp_renew_dentries(struct dentry *parent)
spin_lock(&parent->d_lock);
next = parent->d_subdirs.next;
while (next != &parent->d_subdirs) {
- dentry = list_entry(next, struct dentry, d_u.d_child);
+ dentry = list_entry(next, struct dentry, d_child);

if (dentry->d_fsdata == NULL)
ncp_age_dentry(server, dentry);
@@ -216,7 +216,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent)
spin_lock(&parent->d_lock);
next = parent->d_subdirs.next;
while (next != &parent->d_subdirs) {
- dentry = list_entry(next, struct dentry, d_u.d_child);
+ dentry = list_entry(next, struct dentry, d_child);
dentry->d_fsdata = NULL;
ncp_age_dentry(server, dentry);
next = next->next;
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 880618a8b048..ebc6a0add5ae 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -58,7 +58,7 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i
*/
spin_lock(&sb->s_root->d_inode->i_lock);
spin_lock(&sb->s_root->d_lock);
- hlist_del_init(&sb->s_root->d_alias);
+ hlist_del_init(&sb->s_root->d_u.d_alias);
spin_unlock(&sb->s_root->d_lock);
spin_unlock(&sb->s_root->d_inode->i_lock);
}
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 9d3e9c50066a..700129940c6e 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -63,14 +63,14 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
spin_lock(&inode->i_lock);
/* run all of the dentries associated with this inode. Since this is a
* directory, there damn well better only be one item on this list */
- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
struct dentry *child;

/* run all of the children of the original inode and fix their
* d_flags to indicate parental interest (their parent is the
* original inode) */
spin_lock(&alias->d_lock);
- list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &alias->d_subdirs, d_child) {
if (!child->d_inode)
continue;

diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c
index e2e05a106beb..92edcfc23c1c 100644
--- a/fs/ocfs2/dcache.c
+++ b/fs/ocfs2/dcache.c
@@ -172,7 +172,7 @@ struct dentry *ocfs2_find_local_alias(struct inode *inode,
struct dentry *dentry;

spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
spin_lock(&dentry->d_lock);
if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) {
trace_ocfs2_find_local_alias(dentry->d_name.len,
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 75a227cc7ce2..82b5d1c2b856 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -125,15 +125,15 @@ struct dentry {
void *d_fsdata; /* fs-specific data */

struct list_head d_lru; /* LRU list */
+ struct list_head d_child; /* child of parent list */
+ struct list_head d_subdirs; /* our children */
/*
- * d_child and d_rcu can share memory
+ * d_alias and d_rcu can share memory
*/
union {
- struct list_head d_child; /* child of parent list */
+ struct hlist_node d_alias; /* inode alias list */
struct rcu_head d_rcu;
} d_u;
- struct list_head d_subdirs; /* our children */
- struct hlist_node d_alias; /* inode alias list */
};

/*
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 15209335888d..09acba6e908a 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6411,7 +6411,7 @@ static int instance_mkdir (struct inode *inode, struct dentry *dentry, umode_t m
int ret;

/* Paranoid: Make sure the parent is the "instances" directory */
- parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+ parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
if (WARN_ON_ONCE(parent != trace_instance_dir))
return -ENOENT;

@@ -6438,7 +6438,7 @@ static int instance_rmdir(struct inode *inode, struct dentry *dentry)
int ret;

/* Paranoid: Make sure the parent is the "instances" directory */
- parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+ parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
if (WARN_ON_ONCE(parent != trace_instance_dir))
return -ENOENT;

diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index ef06ce7e9cf8..85f9d33b4ad8 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -461,7 +461,7 @@ static void remove_event_file_dir(struct ftrace_event_file *file)

if (dir) {
spin_lock(&dir->d_lock); /* probably unneeded */
- list_for_each_entry(child, &dir->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &dir->d_subdirs, d_child) {
if (child->d_inode) /* probably unneeded */
child->d_inode->i_private = NULL;
}
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index c71737f6d1cc..33db1ad4fd10 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -1200,7 +1200,7 @@ static void sel_remove_entries(struct dentry *de)
spin_lock(&de->d_lock);
node = de->d_subdirs.next;
while (node != &de->d_subdirs) {
- struct dentry *d = list_entry(node, struct dentry, d_u.d_child);
+ struct dentry *d = list_entry(node, struct dentry, d_child);

spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED);
list_del_init(node);
@@ -1674,12 +1674,12 @@ static void sel_remove_classes(void)

list_for_each(class_node, &class_dir->d_subdirs) {
struct dentry *class_subdir = list_entry(class_node,
- struct dentry, d_u.d_child);
+ struct dentry, d_child);
struct list_head *class_subdir_node;

list_for_each(class_subdir_node, &class_subdir->d_subdirs) {
struct dentry *d = list_entry(class_subdir_node,
- struct dentry, d_u.d_child);
+ struct dentry, d_child);

if (d->d_inode)
if (d->d_inode->i_mode & S_IFDIR)
--
2.1.0

2014-12-15 16:34:22

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 3.18 15/19] move d_rcu from overlapping d_child to overlapping d_alias

On Mon, Dec 15, 2014 at 10:46:50AM -0500, Josh Boyer wrote:
> On Sun, Dec 14, 2014 at 12:21:26PM -0800, Greg Kroah-Hartman wrote:
> >3.18-stable review patch. If anyone has any objections, please let me know.
> >
> >------------------
> >
> >From: Al Viro <[email protected]>
> >
> >commit 946e51f2bf37f1656916eb75bd0742ba33983c28 upstream.
> >
> >Signed-off-by: Al Viro <[email protected]>
> >Signed-off-by: Greg Kroah-Hartman <[email protected]>
>
> I noticed you don't have this (and the child commit) queued for 3.17.y.

That is because:

> The backport wasn't exactly straight-forward because of the d_external
> stuff, but I took a swing at it. After that, the other commit was a
> quick cherry-pick.

It wasn't a "simple" backport, and I didn't have the time. I'm also
going to drop 3.17 real-soon-now.

> Al, does the below look correct for a backport on top of 3.17.6? It
> builds, but I haven't tested it yet.

Testing would be great to do :)

thanks,

greg k-h

2014-12-15 16:38:30

by Josh Boyer

[permalink] [raw]
Subject: Re: [PATCH 3.18 15/19] move d_rcu from overlapping d_child to overlapping d_alias

On Mon, Dec 15, 2014 at 11:34 AM, Greg Kroah-Hartman
<[email protected]> wrote:
> On Mon, Dec 15, 2014 at 10:46:50AM -0500, Josh Boyer wrote:
>> On Sun, Dec 14, 2014 at 12:21:26PM -0800, Greg Kroah-Hartman wrote:
>> >3.18-stable review patch. If anyone has any objections, please let me know.
>> >
>> >------------------
>> >
>> >From: Al Viro <[email protected]>
>> >
>> >commit 946e51f2bf37f1656916eb75bd0742ba33983c28 upstream.
>> >
>> >Signed-off-by: Al Viro <[email protected]>
>> >Signed-off-by: Greg Kroah-Hartman <[email protected]>
>>
>> I noticed you don't have this (and the child commit) queued for 3.17.y.
>
> That is because:
>
>> The backport wasn't exactly straight-forward because of the d_external
>> stuff, but I took a swing at it. After that, the other commit was a
>> quick cherry-pick.
>
> It wasn't a "simple" backport, and I didn't have the time. I'm also
> going to drop 3.17 real-soon-now.

Right, figured. Fedora isn't going to rebase the stable releases to
3.18 until 3.18.2-ish, and this fixes an issue so I thought I'd give
it a try.

>> Al, does the below look correct for a backport on top of 3.17.6? It
>> builds, but I haven't tested it yet.
>
> Testing would be great to do :)

Working on it. Just wanted to send it out early in case Al spotted
something obviously wrong and wanted to yell at me for it.

josh

2014-12-15 21:21:15

by Josh Boyer

[permalink] [raw]
Subject: Re: [PATCH 3.18 15/19] move d_rcu from overlapping d_child to overlapping d_alias

On Mon, Dec 15, 2014 at 11:38 AM, Josh Boyer <[email protected]> wrote:
> On Mon, Dec 15, 2014 at 11:34 AM, Greg Kroah-Hartman
> <[email protected]> wrote:
>> On Mon, Dec 15, 2014 at 10:46:50AM -0500, Josh Boyer wrote:
>>> On Sun, Dec 14, 2014 at 12:21:26PM -0800, Greg Kroah-Hartman wrote:
>>> >3.18-stable review patch. If anyone has any objections, please let me know.
>>> >
>>> >------------------
>>> >
>>> >From: Al Viro <[email protected]>
>>> >
>>> >commit 946e51f2bf37f1656916eb75bd0742ba33983c28 upstream.
>>> >
>>> >Signed-off-by: Al Viro <[email protected]>
>>> >Signed-off-by: Greg Kroah-Hartman <[email protected]>
>>>
>>> I noticed you don't have this (and the child commit) queued for 3.17.y.
>>
>> That is because:
>>
>>> The backport wasn't exactly straight-forward because of the d_external
>>> stuff, but I took a swing at it. After that, the other commit was a
>>> quick cherry-pick.
>>
>> It wasn't a "simple" backport, and I didn't have the time. I'm also
>> going to drop 3.17 real-soon-now.
>
> Right, figured. Fedora isn't going to rebase the stable releases to
> 3.18 until 3.18.2-ish, and this fixes an issue so I thought I'd give
> it a try.
>
>>> Al, does the below look correct for a backport on top of 3.17.6? It
>>> builds, but I haven't tested it yet.
>>
>> Testing would be great to do :)
>
> Working on it. Just wanted to send it out early in case Al spotted
> something obviously wrong and wanted to yell at me for it.

Finally got around to booting it. Something is definitely wrong. Sigh.

josh

2014-12-15 21:33:17

by Al Viro

[permalink] [raw]
Subject: Re: [PATCH 3.18 15/19] move d_rcu from overlapping d_child to overlapping d_alias

On Mon, Dec 15, 2014 at 10:46:50AM -0500, Josh Boyer wrote:
> On Sun, Dec 14, 2014 at 12:21:26PM -0800, Greg Kroah-Hartman wrote:
> >3.18-stable review patch. If anyone has any objections, please let me know.
> >
> >------------------
> >
> >From: Al Viro <[email protected]>
> >
> >commit 946e51f2bf37f1656916eb75bd0742ba33983c28 upstream.
> >
> >Signed-off-by: Al Viro <[email protected]>
> >Signed-off-by: Greg Kroah-Hartman <[email protected]>
>
> I noticed you don't have this (and the child commit) queued for 3.17.y.
> The backport wasn't exactly straight-forward because of the d_external
> stuff, but I took a swing at it. After that, the other commit was a
> quick cherry-pick.
>
> Al, does the below look correct for a backport on top of 3.17.6? It
> builds, but I haven't tested it yet.

- WARN_ON(!hlist_unhashed(&dentry->d_alias));
+ WARN_ON(!hlist_unhashed(&dentry->d_u.d_alias));
i

in __d_free() is definitely *not* correct - where do you think has __d_free
address come from? Right, dentry->d_u.d_rcu.func... Those checks belong
in dentry_free(), before call_rcu() is called...

2014-12-15 21:34:32

by Al Viro

[permalink] [raw]
Subject: Re: [PATCH 3.18 15/19] move d_rcu from overlapping d_child to overlapping d_alias

On Mon, Dec 15, 2014 at 04:21:12PM -0500, Josh Boyer wrote:
> On Mon, Dec 15, 2014 at 11:38 AM, Josh Boyer <[email protected]> wrote:
> > On Mon, Dec 15, 2014 at 11:34 AM, Greg Kroah-Hartman
> > <[email protected]> wrote:
> >> On Mon, Dec 15, 2014 at 10:46:50AM -0500, Josh Boyer wrote:
> >>> On Sun, Dec 14, 2014 at 12:21:26PM -0800, Greg Kroah-Hartman wrote:
> >>> >3.18-stable review patch. If anyone has any objections, please let me know.
> >>> >
> >>> >------------------
> >>> >
> >>> >From: Al Viro <[email protected]>
> >>> >
> >>> >commit 946e51f2bf37f1656916eb75bd0742ba33983c28 upstream.
> >>> >
> >>> >Signed-off-by: Al Viro <[email protected]>
> >>> >Signed-off-by: Greg Kroah-Hartman <[email protected]>
> >>>
> >>> I noticed you don't have this (and the child commit) queued for 3.17.y.
> >>
> >> That is because:
> >>
> >>> The backport wasn't exactly straight-forward because of the d_external
> >>> stuff, but I took a swing at it. After that, the other commit was a
> >>> quick cherry-pick.
> >>
> >> It wasn't a "simple" backport, and I didn't have the time. I'm also
> >> going to drop 3.17 real-soon-now.
> >
> > Right, figured. Fedora isn't going to rebase the stable releases to
> > 3.18 until 3.18.2-ish, and this fixes an issue so I thought I'd give
> > it a try.
> >
> >>> Al, does the below look correct for a backport on top of 3.17.6? It
> >>> builds, but I haven't tested it yet.
> >>
> >> Testing would be great to do :)
> >
> > Working on it. Just wanted to send it out early in case Al spotted
> > something obviously wrong and wanted to yell at me for it.
>
> Finally got around to booting it. Something is definitely wrong. Sigh.

Start with moving WARN_ON() into dentry_free() (as it's done in mainline and
for the same reason)...

2014-12-15 21:44:37

by Josh Boyer

[permalink] [raw]
Subject: Re: [PATCH 3.18 15/19] move d_rcu from overlapping d_child to overlapping d_alias

On Mon, Dec 15, 2014 at 4:34 PM, Al Viro <[email protected]> wrote:
> On Mon, Dec 15, 2014 at 04:21:12PM -0500, Josh Boyer wrote:
>> On Mon, Dec 15, 2014 at 11:38 AM, Josh Boyer <[email protected]> wrote:
>> > On Mon, Dec 15, 2014 at 11:34 AM, Greg Kroah-Hartman
>> > <[email protected]> wrote:
>> >> On Mon, Dec 15, 2014 at 10:46:50AM -0500, Josh Boyer wrote:
>> >>> On Sun, Dec 14, 2014 at 12:21:26PM -0800, Greg Kroah-Hartman wrote:
>> >>> >3.18-stable review patch. If anyone has any objections, please let me know.
>> >>> >
>> >>> >------------------
>> >>> >
>> >>> >From: Al Viro <[email protected]>
>> >>> >
>> >>> >commit 946e51f2bf37f1656916eb75bd0742ba33983c28 upstream.
>> >>> >
>> >>> >Signed-off-by: Al Viro <[email protected]>
>> >>> >Signed-off-by: Greg Kroah-Hartman <[email protected]>
>> >>>
>> >>> I noticed you don't have this (and the child commit) queued for 3.17.y.
>> >>
>> >> That is because:
>> >>
>> >>> The backport wasn't exactly straight-forward because of the d_external
>> >>> stuff, but I took a swing at it. After that, the other commit was a
>> >>> quick cherry-pick.
>> >>
>> >> It wasn't a "simple" backport, and I didn't have the time. I'm also
>> >> going to drop 3.17 real-soon-now.
>> >
>> > Right, figured. Fedora isn't going to rebase the stable releases to
>> > 3.18 until 3.18.2-ish, and this fixes an issue so I thought I'd give
>> > it a try.
>> >
>> >>> Al, does the below look correct for a backport on top of 3.17.6? It
>> >>> builds, but I haven't tested it yet.
>> >>
>> >> Testing would be great to do :)
>> >
>> > Working on it. Just wanted to send it out early in case Al spotted
>> > something obviously wrong and wanted to yell at me for it.
>>
>> Finally got around to booting it. Something is definitely wrong. Sigh.
>
> Start with moving WARN_ON() into dentry_free() (as it's done in mainline and
> for the same reason)...

Gah, yes. I'd just gotten to that hunk and realized it looked really
really wrong. I'll give that a shot.

josh

2014-12-16 03:08:11

by Shuah Khan

[permalink] [raw]
Subject: Re: [PATCH 3.18 00/19] 3.18.1-stable review

On 12/14/2014 01:21 PM, Greg Kroah-Hartman wrote:
> This is the start of the stable review cycle for the 3.18.1 release.
> There are 19 patches in this series, all will be posted as a response
> to this one. If anyone has any issues with these being applied, please
> let me know.
>
> Responses should be made by Tue Dec 16 20:18:16 UTC 2014.
> Anything received after that time might be too late.
>
> The whole patch series can be found in one patch at:
> kernel.org/pub/linux/kernel/v3.0/stable-review/patch-3.18.1-rc1.gz
> and the diffstat can be found below.
>
> thanks,
>
> greg k-h
>

Compiled and booted on my test system. No dmesg regressions.

-- Shuah


--
Shuah Khan
Sr. Linux Kernel Developer
Samsung Open Source Group
Samsung Research America (Silicon Valley)
[email protected] | (970) 217-8978

2014-12-16 13:25:17

by Josh Boyer

[permalink] [raw]
Subject: Re: [PATCH 3.18 15/19] move d_rcu from overlapping d_child to overlapping d_alias

On Mon, Dec 15, 2014 at 04:44:35PM -0500, Josh Boyer wrote:
>On Mon, Dec 15, 2014 at 4:34 PM, Al Viro <[email protected]> wrote:
>> On Mon, Dec 15, 2014 at 04:21:12PM -0500, Josh Boyer wrote:
>>> On Mon, Dec 15, 2014 at 11:38 AM, Josh Boyer <[email protected]> wrote:
>>> > On Mon, Dec 15, 2014 at 11:34 AM, Greg Kroah-Hartman
>>> > <[email protected]> wrote:
>>> >> On Mon, Dec 15, 2014 at 10:46:50AM -0500, Josh Boyer wrote:
>>> >>> On Sun, Dec 14, 2014 at 12:21:26PM -0800, Greg Kroah-Hartman wrote:
>>> >>> >3.18-stable review patch. If anyone has any objections, please let me know.
>>> >>> >
>>> >>> >------------------
>>> >>> >
>>> >>> >From: Al Viro <[email protected]>
>>> >>> >
>>> >>> >commit 946e51f2bf37f1656916eb75bd0742ba33983c28 upstream.
>>> >>> >
>>> >>> >Signed-off-by: Al Viro <[email protected]>
>>> >>> >Signed-off-by: Greg Kroah-Hartman <[email protected]>
>>> >>>
>>> >>> I noticed you don't have this (and the child commit) queued for 3.17.y.
>>> >>
>>> >> That is because:
>>> >>
>>> >>> The backport wasn't exactly straight-forward because of the d_external
>>> >>> stuff, but I took a swing at it. After that, the other commit was a
>>> >>> quick cherry-pick.
>>> >>
>>> >> It wasn't a "simple" backport, and I didn't have the time. I'm also
>>> >> going to drop 3.17 real-soon-now.
>>> >
>>> > Right, figured. Fedora isn't going to rebase the stable releases to
>>> > 3.18 until 3.18.2-ish, and this fixes an issue so I thought I'd give
>>> > it a try.
>>> >
>>> >>> Al, does the below look correct for a backport on top of 3.17.6? It
>>> >>> builds, but I haven't tested it yet.
>>> >>
>>> >> Testing would be great to do :)
>>> >
>>> > Working on it. Just wanted to send it out early in case Al spotted
>>> > something obviously wrong and wanted to yell at me for it.
>>>
>>> Finally got around to booting it. Something is definitely wrong. Sigh.
>>
>> Start with moving WARN_ON() into dentry_free() (as it's done in mainline and
>> for the same reason)...
>
>Gah, yes. I'd just gotten to that hunk and realized it looked really
>really wrong. I'll give that a shot.

OK, that seems to be much better. It boots in a guest and things seem
to be operating fine in a light touch test. I'll keep testing it today.
Revised patch below.

josh

From: Al Viro <[email protected]>
Date: Sun, 26 Oct 2014 19:19:16 -0400
Subject: [PATCH] move d_rcu from overlapping d_child to overlapping d_alias

commit 946e51f2bf37f1656916eb75bd0742ba33983c28 upstream

Signed-off-by: Al Viro <[email protected]>
Backported-by: Josh Boyer <[email protected]>
Signed-off-by: Josh Boyer <[email protected]>
---
arch/powerpc/platforms/cell/spufs/inode.c | 2 +-
drivers/staging/lustre/lustre/llite/dcache.c | 2 +-
drivers/staging/lustre/lustre/llite/llite_lib.c | 2 +-
drivers/staging/lustre/lustre/llite/namei.c | 8 ++--
fs/affs/amigaffs.c | 2 +-
fs/autofs4/expire.c | 12 +++---
fs/autofs4/root.c | 2 +-
fs/ceph/dir.c | 8 ++--
fs/ceph/inode.c | 2 +-
fs/cifs/inode.c | 2 +-
fs/coda/cache.c | 2 +-
fs/dcache.c | 52 ++++++++++++-------------
fs/debugfs/inode.c | 2 +-
fs/exportfs/expfs.c | 2 +-
fs/libfs.c | 12 +++---
fs/ncpfs/dir.c | 2 +-
fs/ncpfs/ncplib_kernel.h | 4 +-
fs/nfs/getroot.c | 2 +-
fs/notify/fsnotify.c | 4 +-
fs/ocfs2/dcache.c | 2 +-
include/linux/dcache.h | 8 ++--
kernel/trace/trace.c | 4 +-
kernel/trace/trace_events.c | 2 +-
security/selinux/selinuxfs.c | 6 +--
24 files changed, 73 insertions(+), 73 deletions(-)

diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 87ba7cf99cd7..65d633f20d37 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -164,7 +164,7 @@ static void spufs_prune_dir(struct dentry *dir)
struct dentry *dentry, *tmp;

mutex_lock(&dir->d_inode->i_mutex);
- list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) {
+ list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) {
spin_lock(&dentry->d_lock);
if (!(d_unhashed(dentry)) && dentry->d_inode) {
dget_dlock(dentry);
diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c
index 49ae207ad425..e2add5fde0fe 100644
--- a/drivers/staging/lustre/lustre/llite/dcache.c
+++ b/drivers/staging/lustre/lustre/llite/dcache.c
@@ -258,7 +258,7 @@ void ll_invalidate_aliases(struct inode *inode)
inode->i_ino, inode->i_generation, inode);

ll_lock_dcache(inode);
- ll_d_hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
+ ll_d_hlist_for_each_entry(dentry, p, &inode->i_dentry, d_u.d_alias) {
CDEBUG(D_DENTRY, "dentry in drop %.*s (%p) parent %p "
"inode %p flags %d\n", dentry->d_name.len,
dentry->d_name.name, dentry, dentry->d_parent,
diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c
index 0c59e26c0805..36e62524a37b 100644
--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
+++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
@@ -704,7 +704,7 @@ void lustre_dump_dentry(struct dentry *dentry, int recur)
return;

list_for_each(tmp, &dentry->d_subdirs) {
- struct dentry *d = list_entry(tmp, struct dentry, d_u.d_child);
+ struct dentry *d = list_entry(tmp, struct dentry, d_child);
lustre_dump_dentry(d, recur - 1);
}
}
diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c
index 0dc7173bbd41..9de0d51e33a2 100644
--- a/drivers/staging/lustre/lustre/llite/namei.c
+++ b/drivers/staging/lustre/lustre/llite/namei.c
@@ -167,14 +167,14 @@ static void ll_invalidate_negative_children(struct inode *dir)
struct ll_d_hlist_node *p;

ll_lock_dcache(dir);
- ll_d_hlist_for_each_entry(dentry, p, &dir->i_dentry, d_alias) {
+ ll_d_hlist_for_each_entry(dentry, p, &dir->i_dentry, d_u.d_alias) {
spin_lock(&dentry->d_lock);
if (!list_empty(&dentry->d_subdirs)) {
struct dentry *child;

list_for_each_entry_safe(child, tmp_subdir,
&dentry->d_subdirs,
- d_u.d_child) {
+ d_child) {
if (child->d_inode == NULL)
d_lustre_invalidate(child, 1);
}
@@ -362,7 +362,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry)
discon_alias = invalid_alias = NULL;

ll_lock_dcache(inode);
- ll_d_hlist_for_each_entry(alias, p, &inode->i_dentry, d_alias) {
+ ll_d_hlist_for_each_entry(alias, p, &inode->i_dentry, d_u.d_alias) {
LASSERT(alias != dentry);

spin_lock(&alias->d_lock);
@@ -943,7 +943,7 @@ static void ll_get_child_fid(struct inode * dir, struct qstr *name,
{
struct dentry *parent, *child;

- parent = ll_d_hlist_entry(dir->i_dentry, struct dentry, d_alias);
+ parent = ll_d_hlist_entry(dir->i_dentry, struct dentry, d_u.d_alias);
child = d_lookup(parent, name);
if (child) {
if (child->d_inode)
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
index 406b29836b19..a674c114fd8e 100644
--- a/fs/affs/amigaffs.c
+++ b/fs/affs/amigaffs.c
@@ -127,7 +127,7 @@ affs_fix_dcache(struct inode *inode, u32 entry_ino)
{
struct dentry *dentry;
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
if (entry_ino == (u32)(long)dentry->d_fsdata) {
dentry->d_fsdata = (void *)inode->i_ino;
break;
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index a7be57e39be7..11c6cddff1b9 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -91,7 +91,7 @@ static struct dentry *get_next_positive_subdir(struct dentry *prev,
spin_lock(&root->d_lock);

if (prev)
- next = prev->d_u.d_child.next;
+ next = prev->d_child.next;
else {
prev = dget_dlock(root);
next = prev->d_subdirs.next;
@@ -105,13 +105,13 @@ cont:
return NULL;
}

- q = list_entry(next, struct dentry, d_u.d_child);
+ q = list_entry(next, struct dentry, d_child);

spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED);
/* Already gone or negative dentry (under construction) - try next */
if (!d_count(q) || !simple_positive(q)) {
spin_unlock(&q->d_lock);
- next = q->d_u.d_child.next;
+ next = q->d_child.next;
goto cont;
}
dget_dlock(q);
@@ -161,13 +161,13 @@ again:
goto relock;
}
spin_unlock(&p->d_lock);
- next = p->d_u.d_child.next;
+ next = p->d_child.next;
p = parent;
if (next != &parent->d_subdirs)
break;
}
}
- ret = list_entry(next, struct dentry, d_u.d_child);
+ ret = list_entry(next, struct dentry, d_child);

spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED);
/* Negative dentry - try next */
@@ -460,7 +460,7 @@ found:
spin_lock(&sbi->lookup_lock);
spin_lock(&expired->d_parent->d_lock);
spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED);
- list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
+ list_move(&expired->d_parent->d_subdirs, &expired->d_child);
spin_unlock(&expired->d_lock);
spin_unlock(&expired->d_parent->d_lock);
spin_unlock(&sbi->lookup_lock);
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index cdb25ebccc4c..38a9e0fa5177 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -659,7 +659,7 @@ static void autofs_clear_leaf_automount_flags(struct dentry *dentry)
/* only consider parents below dentrys in the root */
if (IS_ROOT(parent->d_parent))
return;
- d_child = &dentry->d_u.d_child;
+ d_child = &dentry->d_child;
/* Set parent managed if it's becoming empty */
if (d_child->next == &parent->d_subdirs &&
d_child->prev == &parent->d_subdirs)
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index c29d6ae68874..51ea03313df9 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -111,7 +111,7 @@ static int fpos_cmp(loff_t l, loff_t r)
/*
* When possible, we try to satisfy a readdir by peeking at the
* dcache. We make this work by carefully ordering dentries on
- * d_u.d_child when we initially get results back from the MDS, and
+ * d_child when we initially get results back from the MDS, and
* falling back to a "normal" sync readdir if any dentries in the dir
* are dropped.
*
@@ -147,11 +147,11 @@ static int __dcache_readdir(struct file *file, struct dir_context *ctx,
p = parent->d_subdirs.prev;
dout(" initial p %p/%p\n", p->prev, p->next);
} else {
- p = last->d_u.d_child.prev;
+ p = last->d_child.prev;
}

more:
- dentry = list_entry(p, struct dentry, d_u.d_child);
+ dentry = list_entry(p, struct dentry, d_child);
di = ceph_dentry(dentry);
while (1) {
dout(" p %p/%p %s d_subdirs %p/%p\n", p->prev, p->next,
@@ -174,7 +174,7 @@ more:
!dentry->d_inode ? " null" : "");
spin_unlock(&dentry->d_lock);
p = p->prev;
- dentry = list_entry(p, struct dentry, d_u.d_child);
+ dentry = list_entry(p, struct dentry, d_child);
di = ceph_dentry(dentry);
}

diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 04c89c266cec..c3e103ff18bd 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -1399,7 +1399,7 @@ retry_lookup:
/* reorder parent's d_subdirs */
spin_lock(&parent->d_lock);
spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED);
- list_move(&dn->d_u.d_child, &parent->d_subdirs);
+ list_move(&dn->d_child, &parent->d_subdirs);
spin_unlock(&dn->d_lock);
spin_unlock(&parent->d_lock);
}
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 7899a40465b3..6d1dd0942937 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -887,7 +887,7 @@ inode_has_hashed_dentries(struct inode *inode)
struct dentry *dentry;

spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
spin_unlock(&inode->i_lock);
return true;
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index 278f8fdeb9ef..46ee6f238985 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -92,7 +92,7 @@ static void coda_flag_children(struct dentry *parent, int flag)
struct dentry *de;

spin_lock(&parent->d_lock);
- list_for_each_entry(de, &parent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(de, &parent->d_subdirs, d_child) {
/* don't know what to do with negative dentries */
if (de->d_inode )
coda_flag_inode(de->d_inode, flag);
diff --git a/fs/dcache.c b/fs/dcache.c
index 34b40be8af11..8d7c2b34cb3f 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -44,7 +44,7 @@
/*
* Usage:
* dcache->d_inode->i_lock protects:
- * - i_dentry, d_alias, d_inode of aliases
+ * - i_dentry, d_u.d_alias, d_inode of aliases
* dcache_hash_bucket lock protects:
* - the dcache hash table
* s_anon bl list spinlock protects:
@@ -59,7 +59,7 @@
* - d_unhashed()
* - d_parent and d_subdirs
* - childrens' d_child and d_parent
- * - d_alias, d_inode
+ * - d_u.d_alias, d_inode
*
* Ordering:
* dentry->d_inode->i_lock
@@ -239,7 +239,6 @@ static void __d_free(struct rcu_head *head)
{
struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);

- WARN_ON(!hlist_unhashed(&dentry->d_alias));
if (dname_external(dentry))
kfree(dentry->d_name.name);
kmem_cache_free(dentry_cache, dentry);
@@ -247,6 +246,7 @@ static void __d_free(struct rcu_head *head)

static void dentry_free(struct dentry *dentry)
{
+ WARN_ON(!hlist_unhashed(&dentry->d_u.d_alias));
/* if dentry was never visible to RCU, immediate free is OK */
if (!(dentry->d_flags & DCACHE_RCUACCESS))
__d_free(&dentry->d_u.d_rcu);
@@ -280,7 +280,7 @@ static void dentry_iput(struct dentry * dentry)
struct inode *inode = dentry->d_inode;
if (inode) {
dentry->d_inode = NULL;
- hlist_del_init(&dentry->d_alias);
+ hlist_del_init(&dentry->d_u.d_alias);
spin_unlock(&dentry->d_lock);
spin_unlock(&inode->i_lock);
if (!inode->i_nlink)
@@ -305,7 +305,7 @@ static void dentry_unlink_inode(struct dentry * dentry)
struct inode *inode = dentry->d_inode;
__d_clear_type(dentry);
dentry->d_inode = NULL;
- hlist_del_init(&dentry->d_alias);
+ hlist_del_init(&dentry->d_u.d_alias);
dentry_rcuwalk_barrier(dentry);
spin_unlock(&dentry->d_lock);
spin_unlock(&inode->i_lock);
@@ -465,7 +465,7 @@ static void __dentry_kill(struct dentry *dentry)
}
/* if it was on the hash then remove it */
__d_drop(dentry);
- list_del(&dentry->d_u.d_child);
+ list_del(&dentry->d_child);
/*
* Inform d_walk() that we are no longer attached to the
* dentry tree
@@ -746,7 +746,7 @@ static struct dentry *__d_find_alias(struct inode *inode)

again:
discon_alias = NULL;
- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
spin_lock(&alias->d_lock);
if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
if (IS_ROOT(alias) &&
@@ -796,7 +796,7 @@ void d_prune_aliases(struct inode *inode)
struct dentry *dentry;
restart:
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
spin_lock(&dentry->d_lock);
if (!dentry->d_lockref.count) {
/*
@@ -1081,7 +1081,7 @@ repeat:
resume:
while (next != &this_parent->d_subdirs) {
struct list_head *tmp = next;
- struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
+ struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
next = tmp->next;

spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
@@ -1133,7 +1133,7 @@ resume:
goto rename_retry;
}
rcu_read_unlock();
- next = child->d_u.d_child.next;
+ next = child->d_child.next;
goto resume;
}
if (need_seqretry(&rename_lock, seq)) {
@@ -1468,8 +1468,8 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
INIT_HLIST_BL_NODE(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_lru);
INIT_LIST_HEAD(&dentry->d_subdirs);
- INIT_HLIST_NODE(&dentry->d_alias);
- INIT_LIST_HEAD(&dentry->d_u.d_child);
+ INIT_HLIST_NODE(&dentry->d_u.d_alias);
+ INIT_LIST_HEAD(&dentry->d_child);
d_set_d_op(dentry, dentry->d_sb->s_d_op);

this_cpu_inc(nr_dentry);
@@ -1499,7 +1499,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
*/
__dget_dlock(parent);
dentry->d_parent = parent;
- list_add(&dentry->d_u.d_child, &parent->d_subdirs);
+ list_add(&dentry->d_child, &parent->d_subdirs);
spin_unlock(&parent->d_lock);

return dentry;
@@ -1592,7 +1592,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
spin_lock(&dentry->d_lock);
__d_set_type(dentry, add_flags);
if (inode)
- hlist_add_head(&dentry->d_alias, &inode->i_dentry);
+ hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
dentry->d_inode = inode;
dentry_rcuwalk_barrier(dentry);
spin_unlock(&dentry->d_lock);
@@ -1616,7 +1616,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)

void d_instantiate(struct dentry *entry, struct inode * inode)
{
- BUG_ON(!hlist_unhashed(&entry->d_alias));
+ BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
if (inode)
spin_lock(&inode->i_lock);
__d_instantiate(entry, inode);
@@ -1655,7 +1655,7 @@ static struct dentry *__d_instantiate_unique(struct dentry *entry,
return NULL;
}

- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
/*
* Don't need alias->d_lock here, because aliases with
* d_parent == entry->d_parent are not subject to name or
@@ -1681,7 +1681,7 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
{
struct dentry *result;

- BUG_ON(!hlist_unhashed(&entry->d_alias));
+ BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));

if (inode)
spin_lock(&inode->i_lock);
@@ -1712,7 +1712,7 @@ EXPORT_SYMBOL(d_instantiate_unique);
*/
int d_instantiate_no_diralias(struct dentry *entry, struct inode *inode)
{
- BUG_ON(!hlist_unhashed(&entry->d_alias));
+ BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));

spin_lock(&inode->i_lock);
if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry)) {
@@ -1751,7 +1751,7 @@ static struct dentry * __d_find_any_alias(struct inode *inode)

if (hlist_empty(&inode->i_dentry))
return NULL;
- alias = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+ alias = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
__dget(alias);
return alias;
}
@@ -1813,7 +1813,7 @@ static struct dentry *__d_obtain_alias(struct inode *inode, int disconnected)
spin_lock(&tmp->d_lock);
tmp->d_inode = inode;
tmp->d_flags |= add_flags;
- hlist_add_head(&tmp->d_alias, &inode->i_dentry);
+ hlist_add_head(&tmp->d_u.d_alias, &inode->i_dentry);
hlist_bl_lock(&tmp->d_sb->s_anon);
hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon);
hlist_bl_unlock(&tmp->d_sb->s_anon);
@@ -2248,7 +2248,7 @@ int d_validate(struct dentry *dentry, struct dentry *dparent)
struct dentry *child;

spin_lock(&dparent->d_lock);
- list_for_each_entry(child, &dparent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &dparent->d_subdirs, d_child) {
if (dentry == child) {
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
__dget_dlock(dentry);
@@ -2525,13 +2525,13 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
/* splicing a tree */
dentry->d_parent = target->d_parent;
target->d_parent = target;
- list_del_init(&target->d_u.d_child);
- list_move(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
+ list_del_init(&target->d_child);
+ list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
} else {
/* swapping two dentries */
swap(dentry->d_parent, target->d_parent);
- list_move(&target->d_u.d_child, &target->d_parent->d_subdirs);
- list_move(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
+ list_move(&target->d_child, &target->d_parent->d_subdirs);
+ list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
if (exchange)
fsnotify_d_move(target);
fsnotify_d_move(dentry);
@@ -3322,7 +3322,7 @@ void d_tmpfile(struct dentry *dentry, struct inode *inode)
{
inode_dec_link_count(inode);
BUG_ON(dentry->d_name.name != dentry->d_iname ||
- !hlist_unhashed(&dentry->d_alias) ||
+ !hlist_unhashed(&dentry->d_u.d_alias) ||
!d_unlinked(dentry));
spin_lock(&dentry->d_parent->d_lock);
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 1e3b99d3db0d..05f2960ed7c3 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -553,7 +553,7 @@ void debugfs_remove_recursive(struct dentry *dentry)
* use the d_u.d_child as the rcu head and corrupt this list.
*/
spin_lock(&parent->d_lock);
- list_for_each_entry(child, &parent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &parent->d_subdirs, d_child) {
if (!debugfs_positive(child))
continue;

diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index b01fbfb51f43..a3aa6baad1a1 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -50,7 +50,7 @@ find_acceptable_alias(struct dentry *result,

inode = result->d_inode;
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
dget(dentry);
spin_unlock(&inode->i_lock);
if (toput)
diff --git a/fs/libfs.c b/fs/libfs.c
index 88e3e00e2eca..e801b983b46b 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -114,18 +114,18 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)

spin_lock(&dentry->d_lock);
/* d_lock not required for cursor */
- list_del(&cursor->d_u.d_child);
+ list_del(&cursor->d_child);
p = dentry->d_subdirs.next;
while (n && p != &dentry->d_subdirs) {
struct dentry *next;
- next = list_entry(p, struct dentry, d_u.d_child);
+ next = list_entry(p, struct dentry, d_child);
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
if (simple_positive(next))
n--;
spin_unlock(&next->d_lock);
p = p->next;
}
- list_add_tail(&cursor->d_u.d_child, p);
+ list_add_tail(&cursor->d_child, p);
spin_unlock(&dentry->d_lock);
}
}
@@ -150,7 +150,7 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)
{
struct dentry *dentry = file->f_path.dentry;
struct dentry *cursor = file->private_data;
- struct list_head *p, *q = &cursor->d_u.d_child;
+ struct list_head *p, *q = &cursor->d_child;

if (!dir_emit_dots(file, ctx))
return 0;
@@ -159,7 +159,7 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)
list_move(q, &dentry->d_subdirs);

for (p = q->next; p != &dentry->d_subdirs; p = p->next) {
- struct dentry *next = list_entry(p, struct dentry, d_u.d_child);
+ struct dentry *next = list_entry(p, struct dentry, d_child);
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
if (!simple_positive(next)) {
spin_unlock(&next->d_lock);
@@ -287,7 +287,7 @@ int simple_empty(struct dentry *dentry)
int ret = 0;

spin_lock(&dentry->d_lock);
- list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &dentry->d_subdirs, d_child) {
spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
if (simple_positive(child)) {
spin_unlock(&child->d_lock);
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 08b8ea8c353e..3a8ed0fb07be 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -406,7 +406,7 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
spin_lock(&parent->d_lock);
next = parent->d_subdirs.next;
while (next != &parent->d_subdirs) {
- dent = list_entry(next, struct dentry, d_u.d_child);
+ dent = list_entry(next, struct dentry, d_child);
if ((unsigned long)dent->d_fsdata == fpos) {
if (dent->d_inode)
dget(dent);
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h
index 32c06587351a..6d5e7c56c79d 100644
--- a/fs/ncpfs/ncplib_kernel.h
+++ b/fs/ncpfs/ncplib_kernel.h
@@ -194,7 +194,7 @@ ncp_renew_dentries(struct dentry *parent)
spin_lock(&parent->d_lock);
next = parent->d_subdirs.next;
while (next != &parent->d_subdirs) {
- dentry = list_entry(next, struct dentry, d_u.d_child);
+ dentry = list_entry(next, struct dentry, d_child);

if (dentry->d_fsdata == NULL)
ncp_age_dentry(server, dentry);
@@ -216,7 +216,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent)
spin_lock(&parent->d_lock);
next = parent->d_subdirs.next;
while (next != &parent->d_subdirs) {
- dentry = list_entry(next, struct dentry, d_u.d_child);
+ dentry = list_entry(next, struct dentry, d_child);
dentry->d_fsdata = NULL;
ncp_age_dentry(server, dentry);
next = next->next;
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 880618a8b048..ebc6a0add5ae 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -58,7 +58,7 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i
*/
spin_lock(&sb->s_root->d_inode->i_lock);
spin_lock(&sb->s_root->d_lock);
- hlist_del_init(&sb->s_root->d_alias);
+ hlist_del_init(&sb->s_root->d_u.d_alias);
spin_unlock(&sb->s_root->d_lock);
spin_unlock(&sb->s_root->d_inode->i_lock);
}
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 9d3e9c50066a..700129940c6e 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -63,14 +63,14 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
spin_lock(&inode->i_lock);
/* run all of the dentries associated with this inode. Since this is a
* directory, there damn well better only be one item on this list */
- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
struct dentry *child;

/* run all of the children of the original inode and fix their
* d_flags to indicate parental interest (their parent is the
* original inode) */
spin_lock(&alias->d_lock);
- list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &alias->d_subdirs, d_child) {
if (!child->d_inode)
continue;

diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c
index e2e05a106beb..92edcfc23c1c 100644
--- a/fs/ocfs2/dcache.c
+++ b/fs/ocfs2/dcache.c
@@ -172,7 +172,7 @@ struct dentry *ocfs2_find_local_alias(struct inode *inode,
struct dentry *dentry;

spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
spin_lock(&dentry->d_lock);
if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) {
trace_ocfs2_find_local_alias(dentry->d_name.len,
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 75a227cc7ce2..82b5d1c2b856 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -125,15 +125,15 @@ struct dentry {
void *d_fsdata; /* fs-specific data */

struct list_head d_lru; /* LRU list */
+ struct list_head d_child; /* child of parent list */
+ struct list_head d_subdirs; /* our children */
/*
- * d_child and d_rcu can share memory
+ * d_alias and d_rcu can share memory
*/
union {
- struct list_head d_child; /* child of parent list */
+ struct hlist_node d_alias; /* inode alias list */
struct rcu_head d_rcu;
} d_u;
- struct list_head d_subdirs; /* our children */
- struct hlist_node d_alias; /* inode alias list */
};

/*
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 15209335888d..09acba6e908a 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6411,7 +6411,7 @@ static int instance_mkdir (struct inode *inode, struct dentry *dentry, umode_t m
int ret;

/* Paranoid: Make sure the parent is the "instances" directory */
- parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+ parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
if (WARN_ON_ONCE(parent != trace_instance_dir))
return -ENOENT;

@@ -6438,7 +6438,7 @@ static int instance_rmdir(struct inode *inode, struct dentry *dentry)
int ret;

/* Paranoid: Make sure the parent is the "instances" directory */
- parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+ parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
if (WARN_ON_ONCE(parent != trace_instance_dir))
return -ENOENT;

diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index ef06ce7e9cf8..85f9d33b4ad8 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -461,7 +461,7 @@ static void remove_event_file_dir(struct ftrace_event_file *file)

if (dir) {
spin_lock(&dir->d_lock); /* probably unneeded */
- list_for_each_entry(child, &dir->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &dir->d_subdirs, d_child) {
if (child->d_inode) /* probably unneeded */
child->d_inode->i_private = NULL;
}
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index c71737f6d1cc..33db1ad4fd10 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -1200,7 +1200,7 @@ static void sel_remove_entries(struct dentry *de)
spin_lock(&de->d_lock);
node = de->d_subdirs.next;
while (node != &de->d_subdirs) {
- struct dentry *d = list_entry(node, struct dentry, d_u.d_child);
+ struct dentry *d = list_entry(node, struct dentry, d_child);

spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED);
list_del_init(node);
@@ -1674,12 +1674,12 @@ static void sel_remove_classes(void)

list_for_each(class_node, &class_dir->d_subdirs) {
struct dentry *class_subdir = list_entry(class_node,
- struct dentry, d_u.d_child);
+ struct dentry, d_child);
struct list_head *class_subdir_node;

list_for_each(class_subdir_node, &class_subdir->d_subdirs) {
struct dentry *d = list_entry(class_subdir_node,
- struct dentry, d_u.d_child);
+ struct dentry, d_child);

if (d->d_inode)
if (d->d_inode->i_mode & S_IFDIR)
--
2.1.0

2014-12-16 16:12:52

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 3.18 00/19] 3.18.1-stable review

On Mon, Dec 15, 2014 at 08:08:08PM -0700, Shuah Khan wrote:
> On 12/14/2014 01:21 PM, Greg Kroah-Hartman wrote:
> > This is the start of the stable review cycle for the 3.18.1 release.
> > There are 19 patches in this series, all will be posted as a response
> > to this one. If anyone has any issues with these being applied, please
> > let me know.
> >
> > Responses should be made by Tue Dec 16 20:18:16 UTC 2014.
> > Anything received after that time might be too late.
> >
> > The whole patch series can be found in one patch at:
> > kernel.org/pub/linux/kernel/v3.0/stable-review/patch-3.18.1-rc1.gz
> > and the diffstat can be found below.
> >
> > thanks,
> >
> > greg k-h
> >
>
> Compiled and booted on my test system. No dmesg regressions.

Thanks for testing all 4 of these and letting me know.

greg k-h