From: Marcel Holtmann Date: Sun, 15 Oct 2006 15:31:14 +0000 (+0200) Subject: [Bluetooth] Add locking for bt_proto array manipulation X-Git-Tag: v2.6.19-rc3~206^2~1 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=74da626a1098640ddc40c0e3481c0cd41e8ec1e9;p=linux-2.6 [Bluetooth] Add locking for bt_proto array manipulation The bt_proto array needs to be protected by some kind of locking to prevent a race condition between bt_sock_create and bt_sock_register. And in addition all calls to sk_alloc need to be made GFP_ATOMIC now. Signed-off-by: Masatake YAMATO Signed-off-by: Frederik Deweerdt Signed-off-by: Marcel Holtmann --- diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index a91fee4f27..67df99e2e5 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -53,36 +53,51 @@ /* Bluetooth sockets */ #define BT_MAX_PROTO 8 static struct net_proto_family *bt_proto[BT_MAX_PROTO]; +static DEFINE_RWLOCK(bt_proto_lock); int bt_sock_register(int proto, struct net_proto_family *ops) { + int err = 0; + if (proto < 0 || proto >= BT_MAX_PROTO) return -EINVAL; + write_lock(&bt_proto_lock); + if (bt_proto[proto]) - return -EEXIST; + err = -EEXIST; + else + bt_proto[proto] = ops; - bt_proto[proto] = ops; - return 0; + write_unlock(&bt_proto_lock); + + return err; } EXPORT_SYMBOL(bt_sock_register); int bt_sock_unregister(int proto) { + int err = 0; + if (proto < 0 || proto >= BT_MAX_PROTO) return -EINVAL; + write_lock(&bt_proto_lock); + if (!bt_proto[proto]) - return -ENOENT; + err = -ENOENT; + else + bt_proto[proto] = NULL; - bt_proto[proto] = NULL; - return 0; + write_unlock(&bt_proto_lock); + + return err; } EXPORT_SYMBOL(bt_sock_unregister); static int bt_sock_create(struct socket *sock, int proto) { - int err = 0; + int err; if (proto < 0 || proto >= BT_MAX_PROTO) return -EINVAL; @@ -92,11 +107,18 @@ static int bt_sock_create(struct socket *sock, int proto) request_module("bt-proto-%d", proto); } #endif + err = -EPROTONOSUPPORT; + + read_lock(&bt_proto_lock); + if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) { err = bt_proto[proto]->create(sock, proto); module_put(bt_proto[proto]->owner); } + + read_unlock(&bt_proto_lock); + return err; } diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 5d9d6f14b3..5563db1bf5 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -214,7 +214,7 @@ static int bnep_sock_create(struct socket *sock, int protocol) if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &bnep_proto, 1); + sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index 0547edd577..53295d33dc 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -205,7 +205,7 @@ static int cmtp_sock_create(struct socket *sock, int protocol) if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &cmtp_proto, 1); + sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 1a35d343e0..f26a9eb499 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -618,7 +618,7 @@ static int hci_sock_create(struct socket *sock, int protocol) sock->ops = &hci_sock_ops; - sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &hci_sk_proto, 1); + sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &hci_sk_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index 6242446aa2..407fba43c1 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -256,7 +256,7 @@ static int hidp_sock_create(struct socket *sock, int protocol) if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &hidp_proto, 1); + sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto, 1); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 66fc621a07..2b3dcb8f90 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -559,7 +559,7 @@ static int l2cap_sock_create(struct socket *sock, int protocol) sock->ops = &l2cap_sock_ops; - sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL); + sk = l2cap_sock_alloc(sock, protocol, GFP_ATOMIC); if (!sk) return -ENOMEM; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 530cc41f3a..544d65b7ba 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -336,7 +336,8 @@ static int rfcomm_sock_create(struct socket *sock, int protocol) sock->ops = &rfcomm_sock_ops; - if (!(sk = rfcomm_sock_alloc(sock, protocol, GFP_KERNEL))) + sk = rfcomm_sock_alloc(sock, protocol, GFP_ATOMIC); + if (!sk) return -ENOMEM; rfcomm_sock_init(sk, NULL); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 14b0f69306..5d13d4f317 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -452,7 +452,8 @@ static int sco_sock_create(struct socket *sock, int protocol) sock->ops = &sco_sock_ops; - if (!(sk = sco_sock_alloc(sock, protocol, GFP_KERNEL))) + sk = sco_sock_alloc(sock, protocol, GFP_ATOMIC); + if (!sk) return -ENOMEM; sco_sock_init(sk, NULL);