Linux bluetooth development
 help / color / mirror / Atom feed
From: David Herrmann <dh.herrmann@gmail.com>
To: linux-bluetooth@vger.kernel.org
Cc: Marcel Holtmann <marcel@holtmann.org>,
	Gustavo Padovan <gustavo@padovan.org>,
	David Herrmann <dh.herrmann@gmail.com>
Subject: [PATCH 12/16] Bluetooth: add hci_conn_user sub-modules
Date: Sun, 24 Feb 2013 19:37:02 +0100	[thread overview]
Message-ID: <1361731026-7428-13-git-send-email-dh.herrmann@gmail.com> (raw)
In-Reply-To: <1361731026-7428-1-git-send-email-dh.herrmann@gmail.com>

Several sub-modules like HIDP, rfcomm, ... need to track HCI connections.
The hci_conn->dev object is used as parent for sysfs devices so the
sub-modules need to be notified when the hci_conn object is removed from
sysfs.

This patch introduces hci_conn_user objects which contain a "probe" and
"remove" callback. You can register these on any hci_conn object and if it
is active, the "probe" callback will get called. Otherwise, an error is
returned.

The hci_conn object will call your "remove" callback directly before it is
removed from user-space. This allows you to remove your submodules
_before_ the hci_conn object is removed.

At any time you can asynchronously unregister your hci_conn_user object if
your submodule vanishes before the hci_conn object does.

There is no way around hci_conn_user. If we want wire-protocols in the
kernel, we always want the hci_conn object as parent in the sysfs tree. We
cannot use a channel here since we might need multiple channels for a
single protocol.
But the problem is, we _must_ get notified when an hci_conn object is
removed. We cannot use reference-counting for object-removal! This is not
how it works. If a hardware is removed, we should immediately remove the
object from sysfs. Any other behavior would be inconsistent with the rest
of the system. Also note that device_del() might sleep, but it doesn't
wait for user-space or block very long. It only _unlinks_ the object from
sysfs and the whole device-tree. Everything else is handled by ref-counts!
This is exactly what the other sub-modules must do: unlink their devices
when the "remove" hci_conn_user callback is called. They should not do any
cleanup or synchronous shutdowns.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 include/net/bluetooth/hci_core.h | 11 +++++++
 net/bluetooth/hci_conn.c         | 66 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 77 insertions(+)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index fa8fe72..3779568 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -296,6 +296,7 @@ struct hci_conn {
 	struct list_head list;
 
 	atomic_t	refcnt;
+	struct list_head users;
 
 	bdaddr_t	dst;
 	__u8		dst_type;
@@ -352,6 +353,12 @@ struct hci_conn {
 	void (*disconn_cfm_cb)	(struct hci_conn *conn, u8 reason);
 };
 
+struct hci_conn_user {
+	struct list_head list;
+	int (*probe) (struct hci_conn *conn, struct hci_conn_user *user);
+	void (*remove) (struct hci_conn *conn, struct hci_conn_user *user);
+};
+
 struct hci_chan {
 	struct list_head list;
 	__u16 handle;
@@ -593,6 +600,10 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role);
 
 void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active);
 
+int hci_conn_register_user(struct hci_conn *conn, struct hci_conn_user *user);
+void hci_conn_unregister_user(struct hci_conn *conn,
+			      struct hci_conn_user *user);
+
 /*
  * hci_conn_get() and hci_conn_put() are used to control the life-time of an
  * "hci_conn" object. They do not guarantee that the hci_conn object is running,
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 75b75a8..5ba5e29 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -342,6 +342,70 @@ static void hci_conn_auto_accept(unsigned long arg)
 		     &conn->dst);
 }
 
+int hci_conn_register_user(struct hci_conn *conn, struct hci_conn_user *user)
+{
+	struct hci_dev *hdev = conn->hdev;
+	int ret;
+
+	hci_dev_lock(hdev);
+
+	if (user->list.next || user->list.prev) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	if (!device_is_registered(&conn->dev)) {
+		ret = -ENODEV;
+		goto out_unlock;
+	}
+
+	ret = user->probe(conn, user);
+	if (ret)
+		goto out_unlock;
+
+	list_add(&user->list, &conn->users);
+	ret = 0;
+
+out_unlock:
+	hci_dev_unlock(hdev);
+	return ret;
+}
+EXPORT_SYMBOL(hci_conn_register_user);
+
+void hci_conn_unregister_user(struct hci_conn *conn,
+			      struct hci_conn_user *user)
+{
+	struct hci_dev *hdev = conn->hdev;
+
+	hci_dev_lock(hdev);
+
+	if (!user->list.next || !user->list.prev)
+		goto out_unlock;
+
+	list_del(&user->list);
+	user->list.next = NULL;
+	user->list.prev = NULL;
+	user->remove(conn, user);
+
+out_unlock:
+	hci_dev_unlock(hdev);
+}
+EXPORT_SYMBOL(hci_conn_unregister_user);
+
+static void hci_conn_unregister_all_users(struct hci_conn *conn)
+{
+	struct hci_conn_user *user;
+
+	while (!list_empty(&conn->users)) {
+		user = list_first_entry(&conn->users, struct hci_conn_user,
+					list);
+		list_del(&user->list);
+		user->list.next = NULL;
+		user->list.prev = NULL;
+		user->remove(conn, user);
+	}
+}
+
 struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 {
 	struct hci_conn *conn;
@@ -384,6 +448,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 	skb_queue_head_init(&conn->data_q);
 
 	INIT_LIST_HEAD(&conn->chan_list);
+	INIT_LIST_HEAD(&conn->users);
 
 	INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout);
 	setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
@@ -446,6 +511,7 @@ int hci_conn_del(struct hci_conn *conn)
 
 	skb_queue_purge(&conn->data_q);
 
+	hci_conn_unregister_all_users(conn);
 	hci_conn_del_sysfs(conn);
 
 	hci_dev_put(hdev);
-- 
1.8.1.4

  parent reply	other threads:[~2013-02-24 18:37 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-02-24 18:36 [PATCH 00/16] Rewrite HIDP Session Management David Herrmann
2013-02-24 18:36 ` [PATCH 01/16] Bluetooth: discard bt_sock_unregister() errors David Herrmann
2013-02-26 19:52   ` Gustavo Padovan
2013-02-24 18:36 ` [PATCH 02/16] Bluetooth: change bt_sock_unregister() to return void David Herrmann
2013-02-26 19:52   ` Gustavo Padovan
2013-02-24 18:36 ` [PATCH 03/16] Bluetooth: hidp: simplify error path in sock-init David Herrmann
2013-02-26 19:56   ` Gustavo Padovan
2013-02-27 11:16     ` David Herrmann
2013-02-24 18:36 ` [PATCH 04/16] Bluetooth: hidp: verify l2cap sockets David Herrmann
2013-02-26 20:01   ` Gustavo Padovan
2013-02-27 11:14     ` David Herrmann
2013-02-24 18:36 ` [PATCH 05/16] Bluetooth: rename hci_conn_put to hci_conn_drop David Herrmann
2013-02-24 18:36 ` [PATCH 06/16] Bluetooth: remove unneeded hci_conn_hold/put_device() David Herrmann
2013-02-24 18:36 ` [PATCH 07/16] Bluetooth: introduce hci_conn ref-counting David Herrmann
2013-02-24 18:36 ` [PATCH 08/16] Bluetooth: hidp: remove unused session->state field David Herrmann
2013-02-24 18:36 ` [PATCH 09/16] Bluetooth: hidp: test "terminate" before sleeping David Herrmann
2013-02-24 18:37 ` [PATCH 10/16] Bluetooth: allow constant arguments for bacmp()/bacpy() David Herrmann
2013-02-24 18:37 ` [PATCH 11/16] Bluetooth: l2cap: add l2cap_sock_get_hci_conn() helper David Herrmann
2013-02-24 18:37 ` David Herrmann [this message]
2013-02-24 18:37 ` [PATCH 13/16] Bluetooth: hidp: move hidp_schedule() to core.c David Herrmann
2013-02-24 18:37 ` [PATCH 14/16] Bluetooth: hidp: add new session-management helpers David Herrmann
2013-02-24 18:37 ` [PATCH 15/16] Bluetooth: hidp: remove old session-management David Herrmann
2013-02-24 18:37 ` [PATCH 16/16] Bluetooth: hidp: handle kernel_sendmsg() errors correctly David Herrmann
2013-03-12 17:24 ` [PATCH 00/16] Rewrite HIDP Session Management David Herrmann
2013-03-16 14:09   ` Karl Relton

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1361731026-7428-13-git-send-email-dh.herrmann@gmail.com \
    --to=dh.herrmann@gmail.com \
    --cc=gustavo@padovan.org \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=marcel@holtmann.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox