[PATCH 07/14] w1: process w1 netlink commands in w1_process thread
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
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 */