[PATCH 07/14] w1: process w1 netlink commands in w1_process thread

2013-12-28 Thread David Fries
Netlink is a socket interface and is expected to be asynchronous.
Clients can now make w1 requests without blocking by making use of the
w1_master thread to process netlink commands which was previously only
used for doing an automatic bus search.

Signed-off-by: David Fries 
Cc: Evgeniy Polyakov 
---
 drivers/w1/w1.c |  180 +--
 drivers/w1/w1.h |   32 -
 drivers/w1/w1_int.c |   17 +++--
 drivers/w1/w1_netlink.c |  166 +--
 4 files changed, 300 insertions(+), 95 deletions(-)

diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 97b35cb..53846c7 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -79,19 +79,10 @@ static void w1_slave_release(struct device *dev)
 {
struct w1_slave *sl = dev_to_w1_slave(dev);
 
-   dev_dbg(dev, "%s: Releasing %s.\n", __func__, sl->name);
-
-   while (atomic_read(>refcnt)) {
-   dev_dbg(dev, "Waiting for %s to become free: refcnt=%d.\n",
-   sl->name, atomic_read(>refcnt));
-   if (msleep_interruptible(1000))
-   flush_signals(current);
-   }
+   dev_dbg(dev, "%s: Releasing %s [%p]\n", __func__, sl->name, sl);
 
w1_family_put(sl->family);
sl->master->slave_count--;
-
-   complete(>released);
 }
 
 static ssize_t name_show(struct device *dev, struct device_attribute *attr, 
char *buf)
@@ -277,7 +268,6 @@ static ssize_t w1_master_attribute_store_pullup(struct 
device *dev,
mutex_lock(>mutex);
md->enable_pullup = tmp;
mutex_unlock(>mutex);
-   wake_up_process(md->thread);
 
return count;
 }
@@ -370,23 +360,20 @@ static ssize_t w1_master_attribute_show_slaves(struct 
device *dev,
 {
struct w1_master *md = dev_to_w1_master(dev);
int c = PAGE_SIZE;
+   struct list_head *ent, *n;
+   struct w1_slave *sl = NULL;
 
-   mutex_lock(>mutex);
-
-   if (md->slave_count == 0)
-   c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n");
-   else {
-   struct list_head *ent, *n;
-   struct w1_slave *sl;
+   mutex_lock(>list_mutex);
 
-   list_for_each_safe(ent, n, >slist) {
-   sl = list_entry(ent, struct w1_slave, w1_slave_entry);
+   list_for_each_safe(ent, n, >slist) {
+   sl = list_entry(ent, struct w1_slave, w1_slave_entry);
 
-   c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name);
-   }
+   c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name);
}
+   if (!sl)
+   c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n");
 
-   mutex_unlock(>mutex);
+   mutex_unlock(>list_mutex);
 
return PAGE_SIZE - c;
 }
@@ -440,19 +427,22 @@ static int w1_atoreg_num(struct device *dev, const char 
*buf, size_t count,
 }
 
 /* Searches the slaves in the w1_master and returns a pointer or NULL.
- * Note: must hold the mutex
+ * Note: must not hold list_mutex
  */
 struct w1_slave *w1_slave_search_device(struct w1_master *dev,
struct w1_reg_num *rn)
 {
struct w1_slave *sl;
+   mutex_lock(>list_mutex);
list_for_each_entry(sl, >slist, w1_slave_entry) {
if (sl->reg_num.family == rn->family &&
sl->reg_num.id == rn->id &&
sl->reg_num.crc == rn->crc) {
+   mutex_unlock(>list_mutex);
return sl;
}
}
+   mutex_unlock(>list_mutex);
return NULL;
 }
 
@@ -509,7 +499,10 @@ static ssize_t w1_master_attribute_store_remove(struct 
device *dev,
mutex_lock(>mutex);
sl = w1_slave_search_device(md, );
if (sl) {
-   w1_slave_detach(sl);
+   result = w1_slave_detach(sl);
+   /* refcnt 0 means it was detached in the call */
+   if (result == 0)
+   result = count;
} else {
dev_info(dev, "Device %02x-%012llx doesn't exists\n", rn.family,
(unsigned long long)rn.id);
@@ -704,7 +697,9 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
dev_set_uevent_suppress(>dev, false);
kobject_uevent(>dev.kobj, KOBJ_ADD);
 
+   mutex_lock(>master->list_mutex);
list_add_tail(>w1_slave_entry, >master->slist);
+   mutex_unlock(>master->list_mutex);
 
return 0;
 }
@@ -731,8 +726,8 @@ int w1_attach_slave_device(struct w1_master *dev, struct 
w1_reg_num *rn)
 
memset(, 0, sizeof(msg));
memcpy(>reg_num, rn, sizeof(sl->reg_num));
-   atomic_set(>refcnt, 0);
-   init_completion(>released);
+   atomic_set(>refcnt, 1);
+   atomic_inc(>master->refcnt);
 
/* slave modules need to be loaded in a context with unlocked mutex */
mutex_unlock(>mutex);
@@ -772,23 +767,48 @@ int 

[PATCH 07/14] w1: process w1 netlink commands in w1_process thread

2013-12-28 Thread David Fries
Netlink is a socket interface and is expected to be asynchronous.
Clients can now make w1 requests without blocking by making use of the
w1_master thread to process netlink commands which was previously only
used for doing an automatic bus search.

Signed-off-by: David Fries da...@fries.net
Cc: Evgeniy Polyakov z...@ioremap.net
---
 drivers/w1/w1.c |  180 +--
 drivers/w1/w1.h |   32 -
 drivers/w1/w1_int.c |   17 +++--
 drivers/w1/w1_netlink.c |  166 +--
 4 files changed, 300 insertions(+), 95 deletions(-)

diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 97b35cb..53846c7 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -79,19 +79,10 @@ static void w1_slave_release(struct device *dev)
 {
struct w1_slave *sl = dev_to_w1_slave(dev);
 
-   dev_dbg(dev, %s: Releasing %s.\n, __func__, sl-name);
-
-   while (atomic_read(sl-refcnt)) {
-   dev_dbg(dev, Waiting for %s to become free: refcnt=%d.\n,
-   sl-name, atomic_read(sl-refcnt));
-   if (msleep_interruptible(1000))
-   flush_signals(current);
-   }
+   dev_dbg(dev, %s: Releasing %s [%p]\n, __func__, sl-name, sl);
 
w1_family_put(sl-family);
sl-master-slave_count--;
-
-   complete(sl-released);
 }
 
 static ssize_t name_show(struct device *dev, struct device_attribute *attr, 
char *buf)
@@ -277,7 +268,6 @@ static ssize_t w1_master_attribute_store_pullup(struct 
device *dev,
mutex_lock(md-mutex);
md-enable_pullup = tmp;
mutex_unlock(md-mutex);
-   wake_up_process(md-thread);
 
return count;
 }
@@ -370,23 +360,20 @@ static ssize_t w1_master_attribute_show_slaves(struct 
device *dev,
 {
struct w1_master *md = dev_to_w1_master(dev);
int c = PAGE_SIZE;
+   struct list_head *ent, *n;
+   struct w1_slave *sl = NULL;
 
-   mutex_lock(md-mutex);
-
-   if (md-slave_count == 0)
-   c -= snprintf(buf + PAGE_SIZE - c, c, not found.\n);
-   else {
-   struct list_head *ent, *n;
-   struct w1_slave *sl;
+   mutex_lock(md-list_mutex);
 
-   list_for_each_safe(ent, n, md-slist) {
-   sl = list_entry(ent, struct w1_slave, w1_slave_entry);
+   list_for_each_safe(ent, n, md-slist) {
+   sl = list_entry(ent, struct w1_slave, w1_slave_entry);
 
-   c -= snprintf(buf + PAGE_SIZE - c, c, %s\n, sl-name);
-   }
+   c -= snprintf(buf + PAGE_SIZE - c, c, %s\n, sl-name);
}
+   if (!sl)
+   c -= snprintf(buf + PAGE_SIZE - c, c, not found.\n);
 
-   mutex_unlock(md-mutex);
+   mutex_unlock(md-list_mutex);
 
return PAGE_SIZE - c;
 }
@@ -440,19 +427,22 @@ static int w1_atoreg_num(struct device *dev, const char 
*buf, size_t count,
 }
 
 /* Searches the slaves in the w1_master and returns a pointer or NULL.
- * Note: must hold the mutex
+ * Note: must not hold list_mutex
  */
 struct w1_slave *w1_slave_search_device(struct w1_master *dev,
struct w1_reg_num *rn)
 {
struct w1_slave *sl;
+   mutex_lock(dev-list_mutex);
list_for_each_entry(sl, dev-slist, w1_slave_entry) {
if (sl-reg_num.family == rn-family 
sl-reg_num.id == rn-id 
sl-reg_num.crc == rn-crc) {
+   mutex_unlock(dev-list_mutex);
return sl;
}
}
+   mutex_unlock(dev-list_mutex);
return NULL;
 }
 
@@ -509,7 +499,10 @@ static ssize_t w1_master_attribute_store_remove(struct 
device *dev,
mutex_lock(md-mutex);
sl = w1_slave_search_device(md, rn);
if (sl) {
-   w1_slave_detach(sl);
+   result = w1_slave_detach(sl);
+   /* refcnt 0 means it was detached in the call */
+   if (result == 0)
+   result = count;
} else {
dev_info(dev, Device %02x-%012llx doesn't exists\n, rn.family,
(unsigned long long)rn.id);
@@ -704,7 +697,9 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
dev_set_uevent_suppress(sl-dev, false);
kobject_uevent(sl-dev.kobj, KOBJ_ADD);
 
+   mutex_lock(sl-master-list_mutex);
list_add_tail(sl-w1_slave_entry, sl-master-slist);
+   mutex_unlock(sl-master-list_mutex);
 
return 0;
 }
@@ -731,8 +726,8 @@ int w1_attach_slave_device(struct w1_master *dev, struct 
w1_reg_num *rn)
 
memset(msg, 0, sizeof(msg));
memcpy(sl-reg_num, rn, sizeof(sl-reg_num));
-   atomic_set(sl-refcnt, 0);
-   init_completion(sl-released);
+   atomic_set(sl-refcnt, 1);
+   atomic_inc(sl-master-refcnt);
 
/* slave modules need to be loaded in a context with unlocked mutex */