[PATCH v4] udp reuseport: fix packet of same flow hashed to different socket

2016-06-12 Thread Su Xuemin
From: "Su, Xuemin" 

There is a corner case in which udp packets belonging to a same
flow are hashed to different socket when hslot->count changes from 10
to 11:

1) When hslot->count <= 10, __udp_lib_lookup() searches udp_table->hash,
and always passes 'daddr' to udp_ehashfn().

2) When hslot->count > 10, __udp_lib_lookup() searches udp_table->hash2,
but may pass 'INADDR_ANY' to udp_ehashfn() if the sockets are bound to
INADDR_ANY instead of some specific addr.

That means when hslot->count changes from 10 to 11, the hash calculated by
udp_ehashfn() is also changed, and the udp packets belonging to a same
flow will be hashed to different socket.

This is easily reproduced:
1) Create 10 udp sockets and bind all of them to 0.0.0.0:4.
2) From the same host send udp packets to 127.0.0.1:4, record the
socket index which receives the packets.
3) Create 1 more udp socket and bind it to 0.0.0.0:44096. The number 44096
is 4 + UDP_HASH_SIZE(4096), this makes the new socket put into the
same hslot as the aformentioned 10 sockets, and makes the hslot->count
change from 10 to 11.
4) From the same host send udp packets to 127.0.0.1:4, and the socket
index which receives the packets will be different from the one received
in step 2.
This should not happen as the socket bound to 0.0.0.0:44096 should not
change the behavior of the sockets bound to 0.0.0.0:4.

It's the same case for IPv6, and this patch also fixes that.

Signed-off-by: Su, Xuemin 
Signed-off-by: Eric Dumazet 
---
I use this tree to generate the patch:
  git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

 net/ipv4/udp.c | 73 +-
 net/ipv6/udp.c | 71 +---
 2 files changed, 32 insertions(+), 112 deletions(-)

diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 0ff31d9..55ec77c 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -391,9 +391,9 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum)
return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal, hash2_nulladdr);
 }
 
-static inline int compute_score(struct sock *sk, struct net *net,
-   __be32 saddr, unsigned short hnum, __be16 sport,
-   __be32 daddr, __be16 dport, int dif)
+static int compute_score(struct sock *sk, struct net *net,
+__be32 saddr, __be16 sport,
+__be32 daddr, unsigned short hnum, int dif)
 {
int score;
struct inet_sock *inet;
@@ -434,52 +434,6 @@ static inline int compute_score(struct sock *sk, struct 
net *net,
return score;
 }
 
-/*
- * In this second variant, we check (daddr, dport) matches (inet_rcv_sadd, 
inet_num)
- */
-static inline int compute_score2(struct sock *sk, struct net *net,
-__be32 saddr, __be16 sport,
-__be32 daddr, unsigned int hnum, int dif)
-{
-   int score;
-   struct inet_sock *inet;
-
-   if (!net_eq(sock_net(sk), net) ||
-   ipv6_only_sock(sk))
-   return -1;
-
-   inet = inet_sk(sk);
-
-   if (inet->inet_rcv_saddr != daddr ||
-   inet->inet_num != hnum)
-   return -1;
-
-   score = (sk->sk_family == PF_INET) ? 2 : 1;
-
-   if (inet->inet_daddr) {
-   if (inet->inet_daddr != saddr)
-   return -1;
-   score += 4;
-   }
-
-   if (inet->inet_dport) {
-   if (inet->inet_dport != sport)
-   return -1;
-   score += 4;
-   }
-
-   if (sk->sk_bound_dev_if) {
-   if (sk->sk_bound_dev_if != dif)
-   return -1;
-   score += 4;
-   }
-
-   if (sk->sk_incoming_cpu == raw_smp_processor_id())
-   score++;
-
-   return score;
-}
-
 static u32 udp_ehashfn(const struct net *net, const __be32 laddr,
   const __u16 lport, const __be32 faddr,
   const __be16 fport)
@@ -492,11 +446,11 @@ static u32 udp_ehashfn(const struct net *net, const 
__be32 laddr,
  udp_ehash_secret + net_hash_mix(net));
 }
 
-/* called with read_rcu_lock() */
+/* called with rcu_read_lock() */
 static struct sock *udp4_lib_lookup2(struct net *net,
__be32 saddr, __be16 sport,
__be32 daddr, unsigned int hnum, int dif,
-   struct udp_hslot *hslot2, unsigned int slot2,
+   struct udp_hslot *hslot2,
struct sk_buff *skb)
 {
struct sock *sk, *result;
@@ -506,7 +460,7 @@ static struct sock *udp4_lib_lookup2(struct net *net,
result = NULL;
badness = 0;
udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) {
-   score = compute_score2(sk, net, saddr, sport,
+

[PATCH v3] udp reuseport: fix packet of same flow hashed to different socket

2016-06-12 Thread Su Xuemin
From: "Su, Xuemin" 

There is a corner case in which udp packets belonging to a same
flow are hashed to different socket when hslot->count changes from 10
to 11:

1) When hslot->count <= 10, __udp_lib_lookup() searches udp_table->hash,
and always passes 'daddr' to udp_ehashfn().

2) When hslot->count > 10, __udp_lib_lookup() searches udp_table->hash2,
but may pass 'INADDR_ANY' to udp_ehashfn() if the sockets are bound to
INADDR_ANY instead of some specific addr.

That means when hslot->count changes from 10 to 11, the hash calculated by
udp_ehashfn() is also changed, and the udp packets belonging to a same
flow will be hashed to different socket.

This is easily reproduced:
1) Create 10 udp sockets and bind all of them to 0.0.0.0:4.
2) From the same host send udp packets to 127.0.0.1:4, record the
socket index which receives the packets.
3) Create 1 more udp socket and bind it to 0.0.0.0:44096. The number 44096
is 4 + UDP_HASH_SIZE(4096), this makes the new socket put into the
same hslot as the aformentioned 10 sockets, and makes the hslot->count
change from 10 to 11.
4) From the same host send udp packets to 127.0.0.1:4, and the socket
index which receives the packets will be different from the one received
in step 2.
This should not happen as the socket bound to 0.0.0.0:44096 should not
change the behavior of the sockets bound to 0.0.0.0:4.

It's the same case for IPv6, and this patch also fixes that.

Signed-off-by: Su, Xuemin 
Signed-off-by: Eric Dumazet 
---
I use this tree to generate the patch:
  git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

 net/ipv4/udp.c | 68 --
 net/ipv6/udp.c | 66 
 2 files changed, 28 insertions(+), 106 deletions(-)

diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 0ff31d9..586f1b0 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -391,9 +391,9 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum)
return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal, hash2_nulladdr);
 }
 
-static inline int compute_score(struct sock *sk, struct net *net,
-   __be32 saddr, unsigned short hnum, __be16 sport,
-   __be32 daddr, __be16 dport, int dif)
+static int compute_score(struct sock *sk, struct net *net,
+__be32 saddr, __be16 sport,
+__be32 daddr, unsigned short hnum, int dif)
 {
int score;
struct inet_sock *inet;
@@ -434,52 +434,6 @@ static inline int compute_score(struct sock *sk, struct 
net *net,
return score;
 }
 
-/*
- * In this second variant, we check (daddr, dport) matches (inet_rcv_sadd, 
inet_num)
- */
-static inline int compute_score2(struct sock *sk, struct net *net,
-__be32 saddr, __be16 sport,
-__be32 daddr, unsigned int hnum, int dif)
-{
-   int score;
-   struct inet_sock *inet;
-
-   if (!net_eq(sock_net(sk), net) ||
-   ipv6_only_sock(sk))
-   return -1;
-
-   inet = inet_sk(sk);
-
-   if (inet->inet_rcv_saddr != daddr ||
-   inet->inet_num != hnum)
-   return -1;
-
-   score = (sk->sk_family == PF_INET) ? 2 : 1;
-
-   if (inet->inet_daddr) {
-   if (inet->inet_daddr != saddr)
-   return -1;
-   score += 4;
-   }
-
-   if (inet->inet_dport) {
-   if (inet->inet_dport != sport)
-   return -1;
-   score += 4;
-   }
-
-   if (sk->sk_bound_dev_if) {
-   if (sk->sk_bound_dev_if != dif)
-   return -1;
-   score += 4;
-   }
-
-   if (sk->sk_incoming_cpu == raw_smp_processor_id())
-   score++;
-
-   return score;
-}
-
 static u32 udp_ehashfn(const struct net *net, const __be32 laddr,
   const __u16 lport, const __be32 faddr,
   const __be16 fport)
@@ -492,7 +446,7 @@ static u32 udp_ehashfn(const struct net *net, const __be32 
laddr,
  udp_ehash_secret + net_hash_mix(net));
 }
 
-/* called with read_rcu_lock() */
+/* called with rcu_read_lock() */
 static struct sock *udp4_lib_lookup2(struct net *net,
__be32 saddr, __be16 sport,
__be32 daddr, unsigned int hnum, int dif,
@@ -506,7 +460,7 @@ static struct sock *udp4_lib_lookup2(struct net *net,
result = NULL;
badness = 0;
udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) {
-   score = compute_score2(sk, net, saddr, sport,
+   score = compute_score(sk, net, saddr, sport,
  daddr, hnum, dif);
if (score > badness) {
reus

Re: [PATCH v2] udp reuseport: fix packet of same flow hashed to different socket

2016-06-08 Thread Su Xuemin
On Wed 2016-06-08 at 08:43 -0700, Eric Dumazet wrote:
> I am not convinced this is the right way to fix the issue.
> 
> Fact that you did not change udp4_lib_lookup2() is telling me something.
> 
> 
> 1) If host has 100 different IP, and 10 sockets bound to 0.0.0.0:53 
> 2) If we receive datagrams from SRCIP:srcport send to IP{1..100}:53
> will all be hashed on same slot.
> 
> See the hash used in soreuseport logic as an equivalent of a 4-tuple
> hash really, not a 3-tuple one.
> 

This is my understanding of __udp4_lib_lookup(), see the comments below,
please kindly review it.
The problem of the current code is:
  In Path 1, we pass daddr to udp_ehashfn() inside udp4_lib_lookup2().
  In Path 2, we pass 0.0.0.0 to udp_ehashfn() inside udp4_lib_lookup2().
  In Path 3, we pass daddr to udp_ehashfn(), even if inet->inet_rcv_saddr
is 0.0.0.0.
  The hash value returned by udp_ehashfn() is used as a random seed to
select socket from the sockets of a hslot. In Path 2 and Path 3, this
hash value is different, so we will select different sockets.
  Pass inet->inet_rcv_saddr to udp_ehashfn() in Path 3 will make the
logic consistent in all these three Pathes.

...
if (hslot->count > 10) {
/* Xuemin:
 * for udptable->hash2[], sockets bound to specific ip and
 * sockets bound to 0.0.0.0 may be placed in different hslot,
 * so we may have to search two hslots. */
...
/* Xuemin Path 1:
 * for udptable->hash2[], firstly try to find the socket
 * bound to the specific daddr. */
result = udp4_lib_lookup2(net, saddr, sport,
  daddr, hnum, dif,
  hslot2, slot2, skb);
if (!result) {
/* Xuemin Path 2:
 * for udptable->hash2[], if we can not find the
 * socket bound to the specific daddr, we then
 * try to find the socket bound to 0.0.0.0. */
result = udp4_lib_lookup2(net, saddr, sport,
  htonl(INADDR_ANY), hnum, dif,
  hslot2, slot2, skb);
}
return result;
}
/* Xuemin:
 * for udptable->hash[], all sockets bound to the same
 * port(no matter they are bound to specific ip or to 0.0.0.0)
 * are placed in the same hslot, so we only need to search one
 * hslot. */
begin:
result = NULL;
badness = 0;
sk_for_each_rcu(sk, &hslot->head) {
score = compute_score(sk, net, saddr, hnum, sport,
  daddr, dport, dif);
if (score > badness) {
reuseport = sk->sk_reuseport;
if (reuseport) {
/* Xuemin Path 3:
 * when inet_sk(sk)->inet_rcv_saddr is 0.0.0.0,
 * we should not pass daddr here. */
hash = udp_ehashfn(net, daddr, hnum,
   saddr, sport);
result = reuseport_select_sock(sk, hash, skb,
sizeof(struct udphdr));





[PATCH v2] udp reuseport: fix packet of same flow hashed to different socket

2016-06-07 Thread Su Xuemin
From: "Su, Xuemin" 

There is a corner case in which udp packets belonging to a same
flow are hashed to different socket when hslot->count changes from 10
to 11:

1) When hslot->count <= 10, __udp_lib_lookup() searches udp_table->hash,
and always passes 'daddr' to udp_ehashfn().

2) When hslot->count > 10, __udp_lib_lookup() searches udp_table->hash2,
but may pass 'INADDR_ANY' to udp_ehashfn() if the sockets are bound to
INADDR_ANY instead of some specific addr.

That means when hslot->count changes from 10 to 11, the hash calculated by
udp_ehashfn() is also changed, and the udp packets belonging to a same
flow will be hashed to different socket.

This is easily reproduced:
1) Create 10 udp sockets and bind all of them to 0.0.0.0:4.
2) From the same host send udp packets to 127.0.0.1:4, record the
socket index which receives the packets.
3) Create 1 more udp socket and bind it to 0.0.0.0:44096. The number 44096
is 4 + UDP_HASH_SIZE(4096), this makes the new socket put into the
same hslot as the aformentioned 10 sockets, and makes the hslot->count
change from 10 to 11.
4) From the same host send udp packets to 127.0.0.1:4, and the socket
index which receives the packets will be different from the one received
in step 2.
This should not happen as the socket bound to 0.0.0.0:44096 should not
change the behavior of the sockets bound to 0.0.0.0:4.

The fix here is that when searching udp_table->hash, if the socket
supports reuseport, pass inet_sk(sk)->inet_rcv_saddr to udp_ehashfn()
instead of daddr. When the sockets are bound to some specific addr,
inet_sk(sk)->inet_rcv_saddr should equal to daddr, and when the sockets
are bould to INADDR_ANY, this will pass INADDR_ANY to udp_ehashfn() as
what is done when searching udp_table->hash2.

It's the same case for IPv6, and this patch also fixes that.

Signed-off-by: Su, Xuemin 
---
The patch v1 does not fix the code in IPv6. Thank Eric Dumazet for
pointing that.
And I use this tree to generate this patch, hope it's correct:
  git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

 net/ipv4/udp.c | 4 +++-
 net/ipv6/udp.c | 4 +++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index d56c055..57c38f6 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -577,7 +577,9 @@ begin:
if (score > badness) {
reuseport = sk->sk_reuseport;
if (reuseport) {
-   hash = udp_ehashfn(net, daddr, hnum,
+   hash = udp_ehashfn(net,
+  inet_sk(sk)->inet_rcv_saddr,
+  hnum,
   saddr, sport);
result = reuseport_select_sock(sk, hash, skb,
sizeof(struct udphdr));
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 2da1896..41ca493 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -290,7 +290,9 @@ begin:
if (score > badness) {
reuseport = sk->sk_reuseport;
if (reuseport) {
-   hash = udp6_ehashfn(net, daddr, hnum,
+   hash = udp6_ehashfn(net,
+   &sk->sk_v6_rcv_saddr,
+   hnum,
saddr, sport);
result = reuseport_select_sock(sk, hash, skb,
sizeof(struct udphdr));
-- 
1.8.3.1




[PATCH] udp reuseport: fix packet of same flow hashed to different socket

2016-06-07 Thread Su Xuemin
From: "Su, Xuemin" 

There is a corner case in which udp packets belonging to a same
flow are hashed to different socket when hslot->count changes from 10
to 11:

1) When hslot->count <= 10, __udp_lib_lookup() searches udp_table->hash,
and always passes 'daddr' to udp_ehashfn().

2) When hslot->count > 10, __udp_lib_lookup() searches udp_table->hash2,
but may pass 'INADDR_ANY' to udp_ehashfn() if the sockets are bound to
INADDR_ANY instead of some specific addr.

That means when hslot->count changes from 10 to 11, the hash calculated by
udp_ehashfn() is also changed, and the udp packets belonging to a same
flow will be hashed to different socket.

This is easily reproduced:
1) Create 10 udp sockets and bind all of them to 0.0.0.0:4.
2) From the same host send udp packets to 127.0.0.1:4, record the
socket index which receives the packets.
3) Create 1 more udp socket and bind it to 0.0.0.0:44096. The number 44096
is 4 + UDP_HASH_SIZE(4096), this makes the new socket put into the
same hslot as the aformentioned 10 sockets, and makes the hslot->count
change from 10 to 11.
4) From the same host send udp packets to 127.0.0.1:4, and the socket
index which receives the packets will be different from the one received
in step 2.
This should not happen as the socket bound to 0.0.0.0:44096 should not
change the behavior of the sockets bound to 0.0.0.0:4.

The fix here is that when searching udp_table->hash, if the socket
supports reuseport, pass inet_sk(sk)->inet_rcv_saddr to udp_ehashfn()
instead of daddr. When the sockets are bound to some specific addr,
inet_sk(sk)->inet_rcv_saddr should equal to daddr, and when the sockets
are bould to INADDR_ANY, this will pass INADDR_ANY to udp_ehashfn() as
what is done when searching udp_table->hash2.

Signed-off-by: Su, Xuemin 
---
 net/ipv4/udp.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index d56c055..57c38f6 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -577,7 +577,9 @@ begin:
if (score > badness) {
reuseport = sk->sk_reuseport;
if (reuseport) {
-   hash = udp_ehashfn(net, daddr, hnum,
+   hash = udp_ehashfn(net,
+  inet_sk(sk)->inet_rcv_saddr,
+  hnum,
   saddr, sport);
result = reuseport_select_sock(sk, hash, skb,
sizeof(struct udphdr));
-- 
1.8.3.1




[PATCH] drm/radeon: Calling object_unrefer() when creating fb failure

2013-01-30 Thread Su, Xuemin
From: liu chuansheng 
Date: Thu, 31 Jan 2013 22:13:00 +0800
Subject: [PATCH] drm/radeon: Calling object_unrefer() when creating fb
 failure

When kzalloc() failed in radeon_user_framebuffer_create(), need to
call object_unreference() to match the object_reference().

Signed-off-by: liu chuansheng 
Signed-off-by: xueminsu 
---
 drivers/gpu/drm/radeon/radeon_display.c |4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_display.c 
b/drivers/gpu/drm/radeon/radeon_display.c
index ff3def7..05c96fa 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -1115,8 +1115,10 @@ radeon_user_framebuffer_create(struct drm_device *dev,
}
 
radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL);
-   if (radeon_fb == NULL)
+   if (radeon_fb == NULL) {
+   drm_gem_object_unreference_unlocked(obj);
return ERR_PTR(-ENOMEM);
+   }
 
ret = radeon_framebuffer_init(dev, radeon_fb, mode_cmd, obj);
if (ret) {
-- 
1.7.6



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH V3] drm_crtc: check if fb_create return NULL

2013-01-30 Thread Su, Xuemin


-Original Message-
From: Jani Nikula [mailto:jani.nik...@linux.intel.com] 
Sent: Thursday, January 24, 2013 5:05 PM
To: Su, Xuemin
Cc: airl...@linux.ie; dri-de...@lists.freedesktop.org; 
linux-kernel@vger.kernel.org; yanmin_zh...@linux.intel.com; He, Bo
Subject: Re: [PATCH V3] drm_crtc: check if fb_create return NULL

>Ah, sorry, never mind, I missed Daniel's comment. The benefit of the
>BUG_ON() is making it clear what's expected of the drivers.

>Reviewed-by: Jani Nikula 

Do you think this patch is still needed?
Currently I fix a buggy function radeon_user_framebuffer_create() which returns 
NULL and patch is added to 3.7-stable tree.
Do you think it's also needed to do something in drm_mode_addfb()?
Thanks.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH V3] drm_crtc: check if fb_create return NULL

2013-01-24 Thread Su, Xuemin
On Thu, 2013-01-24 at 10:31 +0200, Jani Nikula wrote:
> > }
> > +   /* some buggy driver may return NULL here, which may cause panic */
> > +   BUG_ON(!fb);
> 
> I fail to see the benefit of this compared to just letting it oops...
> 
> > or->fb_id = fb->base.id;
> 
> ...right here.
> 
> 
For PATCH V3, I think a BUG_ON may give the user clearer information
about the reason of panic. Easier to debug.
I submitted a PATCH V2 yesterday which gives a warning and then return
-EVAL if fb==NULL, preventing the panic. Do you think this is
acceptable?

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH V3] drm_crtc: check if fb_create return NULL

2013-01-23 Thread Su, Xuemin
From: xueminsu 
Date: Tue, 22 Jan 2013 22:39:39 +0800
Subject: [PATCH] drm_crtc: check if fb_create return NULL

Some buggy driver may still return NULL in fb_create,
which leads to kernel panic.

Signed-off-by: xueminsu 
---
 drivers/gpu/drm/drm_crtc.c |2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index f2d667b..ae613ec 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2172,6 +2172,8 @@ int drm_mode_addfb(struct drm_device *dev,
ret = PTR_ERR(fb);
goto out;
}
+   /* some buggy driver may return NULL here, which may cause panic */
+   BUG_ON(!fb);
 
or->fb_id = fb->base.id;
list_add(&fb->filp_head, &file_priv->fbs);
-- 
1.7.6



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH V2 RESEND] drm_crtc: check if fb_create return NULL

2013-01-23 Thread Su, Xuemin
-Original Message-
>From: Daniel Vetter [mailto:daniel.vet...@ffwll.ch] On Behalf Of Daniel Vetter
>Sent: Wednesday, January 23, 2013 5:54 PM
>To: Su, Xuemin
>Cc: airl...@linux.ie; dri-de...@lists.freedesktop.org; 
>linux-kernel@vger.kernel.org; yanmin_zh...@linux.intel.com; He, Bo
>Subject: Re: [PATCH V2 RESEND] drm_crtc: check if fb_create return NULL

>Imo just BUG_ON(!fb); and call it a day. Makes it pretty clear what's expected 
>of the drivers.
>-Daniel

Thanks, I will upload PATCH V3.
Xuemin

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH V2 RESEND] drm_crtc: check if fb_create return NULL

2013-01-22 Thread Su, Xuemin
From: xueminsu 
Date: Tue, 22 Jan 2013 22:39:39 +0800
Subject: [PATCH] drm_crtc: check if fb_create return NULL

Some buggy driver may still return NULL in fb_create,
which leads to kernel panic.

Signed-off-by: xueminsu 
---
 drivers/gpu/drm/drm_crtc.c |7 +++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index f2d667b..b748498 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2172,6 +2172,13 @@ int drm_mode_addfb(struct drm_device *dev,
ret = PTR_ERR(fb);
goto out;
}
+   /* some buggy driver may return NULL here, which may cause panic */
+   if (!fb) {
+   WARN(1, "%pf should not return NULL.",
+   dev->mode_config.funcs->fb_create);
+   ret = -EINVAL;
+   goto out;
+   }
 
or->fb_id = fb->base.id;
list_add(&fb->filp_head, &file_priv->fbs);
-- 
1.7.6




--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] drm_crtc: check if fb_create return NULL

2013-01-22 Thread Su, Xuemin
From: xueminsu 
Date: Tue, 22 Jan 2013 22:39:39 +0800
Subject: [PATCH] drm_crtc: check if fb_create return NULL

Some buggy driver may still return NULL in fb_create,
which leads to kernel panic.

Signed-off-by: xueminsu 
---
 drivers/gpu/drm/drm_crtc.c |6 ++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index f2d667b..4ed0aed 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2172,6 +2172,12 @@ int drm_mode_addfb(struct drm_device *dev,
ret = PTR_ERR(fb);
goto out;
}
+   /* some buggy driver may return NULL here, which may cause panic */
+   if (!fb) {
+   WARN(1, "%pf should not return NULL.",
+   dev->mode_config.funcs->fb_create);
+   return -EINVAL;
+   }
 
or->fb_id = fb->base.id;
list_add(&fb->filp_head, &file_priv->fbs);
-- 
1.7.6



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] radeon_display: Use pointer return error codes

2013-01-22 Thread Su, Xuemin
From: xueminsu 
Date: Tue, 22 Jan 2013 22:16:53 +0800
Subject: [PATCH] radeon_display: Use pointer return error codes

drm_mode_addfb() expects fb_create return error code
instead of NULL.

Signed-off-by: xueminsu 
---
 drivers/gpu/drm/radeon/radeon_display.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_display.c 
b/drivers/gpu/drm/radeon/radeon_display.c
index 1da2386..ff3def7 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -1122,7 +1122,7 @@ radeon_user_framebuffer_create(struct drm_device *dev,
if (ret) {
kfree(radeon_fb);
drm_gem_object_unreference_unlocked(obj);
-   return NULL;
+   return ERR_PTR(ret);
}
 
return &radeon_fb->base;
-- 
1.7.6



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/