Re: convert sppp(4) to taskq

2013-11-18 Thread Martin Pieuchot
On 15/11/13(Fri) 15:45, Stefan Sperling wrote:
 On Fri, Nov 15, 2013 at 03:20:48PM +0100, Mike Belopuhov wrote:
  On 15 November 2013 15:13, Stefan Sperling s...@openbsd.org wrote:
   Is this done right?
  
   Works here with pppoe(4) for both IPv4 and IPv6.
  
  
  i think this diff might lack task_del's in the detach code.
 
 Ooops, good catch.
 
  have you tried destroying your pppoe interface?
 
 Yes, but evidently not while a task was scheduled.
 
 Same diff with task_del calls added.

Even if right now calling task_del() is enough, do you know if there's
an easy way to convert this code without putting the task storage in
the chunk of memory it manipulates?  In other words having the struct
task outside of the softc?

I'm asking because if you can do it, this will make the task totally
independent and won't require any task_del().  The idea behind that
is that tomorrow we will try to have more kernel threads running in
parallel, and if your task is about to run or already running when
your interface is destroyed you might end up freeing the memory the 
task is manipulating.

Since the current code is already using allocating some memory for the
arguments of the task, I'd argue that this is better than putting the
task storage on the same memory chunk that it manipulates.  But since
this problem exists in other places in our tree, we might think of an
alternative solution/api/whatever.

Other than that your diff looks ok.

 Index: if_sppp.h
 ===
 RCS file: /cvs/src/sys/net/if_sppp.h,v
 retrieving revision 1.19
 diff -u -p -r1.19 if_sppp.h
 --- if_sppp.h 14 Nov 2013 16:52:33 -  1.19
 +++ if_sppp.h 15 Nov 2013 13:48:47 -
 @@ -93,6 +93,12 @@ struct spppreq {
  #ifdef _KERNEL
  
  #include sys/timeout.h
 +#include sys/task.h
 +
 +#ifdef INET6
 +#include netinet/in.h
 +#include netinet6/in6_var.h
 +#endif
  
  #define IDX_LCP 0/* idx into state table */
  
 @@ -124,8 +130,13 @@ struct sipcp {
  #define IPV6CP_MYIFID_SEEN   2 /* have seen my suggested ifid */
   u_int32_t saved_hisaddr; /* if hisaddr (IPv4) is dynamic, save
 * original one here, in network byte order */
 - u_int32_t req_hisaddr;  /* remote address requested */
 - u_int32_t req_myaddr;   /* local address requested */
 + u_int32_t req_hisaddr;  /* remote address requested (IPv4) */
 + u_int32_t req_myaddr;   /* local address requested (IPv4) */
 +#ifdef INET6
 + struct in6_aliasreq req_ifid;   /* local ifid requested (IPv6) */
 +#endif
 + struct task set_addr_task;  /* set address from process context */
 + struct task clear_addr_task;/* clear address from process context */
  };
  
  struct sauth {
 Index: if_spppsubr.c
 ===
 RCS file: /cvs/src/sys/net/if_spppsubr.c,v
 retrieving revision 1.112
 diff -u -p -r1.112 if_spppsubr.c
 --- if_spppsubr.c 14 Nov 2013 16:52:33 -  1.112
 +++ if_spppsubr.c 15 Nov 2013 14:37:24 -
 @@ -46,7 +46,6 @@
  #include sys/syslog.h
  #include sys/malloc.h
  #include sys/mbuf.h
 -#include sys/workq.h
  
  #include sys/timeout.h
  #include crypto/md5.h
 @@ -72,10 +71,6 @@
  
  #include net/if_sppp.h
  
 -#ifdef INET6
 -#include netinet6/in6_var.h
 -#endif
 -
  # define UNTIMEOUT(fun, arg, handle) \
   timeout_del((handle))
  
 @@ -291,6 +286,7 @@ HIDE void sppp_lcp_check_and_close(struc
  HIDE int sppp_ncp_check(struct sppp *sp);
  
  HIDE void sppp_ipcp_init(struct sppp *sp);
 +HIDE void sppp_ipcp_destroy(struct sppp *sp);
  HIDE void sppp_ipcp_up(struct sppp *sp);
  HIDE void sppp_ipcp_down(struct sppp *sp);
  HIDE void sppp_ipcp_open(struct sppp *sp);
 @@ -306,6 +302,7 @@ HIDE void sppp_ipcp_tlf(struct sppp *sp)
  HIDE void sppp_ipcp_scr(struct sppp *sp);
  
  HIDE void sppp_ipv6cp_init(struct sppp *sp);
 +HIDE void sppp_ipv6cp_destroy(struct sppp *sp);
  HIDE void sppp_ipv6cp_up(struct sppp *sp);
  HIDE void sppp_ipv6cp_down(struct sppp *sp);
  HIDE void sppp_ipv6cp_open(struct sppp *sp);
 @@ -902,6 +899,9 @@ sppp_detach(struct ifnet *ifp)
   struct sppp **q, *p, *sp = (struct sppp*) ifp;
   int i;
  
 + sppp_ipcp_destroy(sp);
 + sppp_ipv6cp_destroy(sp);
 +
   /* Remove the entry from the keepalive list. */
   for (q = spppq; (p = *q); q = p-pp_next)
   if (p == sp) {
 @@ -2637,6 +2637,15 @@ sppp_ipcp_init(struct sppp *sp)
   sp-ipcp.flags = 0;
   sp-state[IDX_IPCP] = STATE_INITIAL;
   sp-fail_counter[IDX_IPCP] = 0;
 + task_set(sp-ipcp.set_addr_task, sppp_set_ip_addrs, sp, NULL);
 + task_set(sp-ipcp.clear_addr_task, sppp_clear_ip_addrs, sp, NULL);
 +}
 +
 +HIDE void
 +sppp_ipcp_destroy(struct sppp *sp)
 +{
 + task_del(systq, sp-ipcp.set_addr_task);
 + task_del(systq, sp-ipcp.clear_addr_task);
  }
  
  HIDE void
 @@ -2955,38 +2964,11 @@ sppp_ipcp_RCN_nak(struct sppp *sp, struc
   addlog(\n);
  

Re: convert sppp(4) to taskq

2013-11-18 Thread Stefan Sperling
On Mon, Nov 18, 2013 at 12:37:53PM +0100, Martin Pieuchot wrote:
 Even if right now calling task_del() is enough, do you know if there's
 an easy way to convert this code without putting the task storage in
 the chunk of memory it manipulates?  In other words having the struct
 task outside of the softc?

Well, tasks are stored in softc everywhere I looked for examples.

The task storage and the storage for the task's arguments needs to
be known when task_set() is called. As I understand, task_set() is
called once, at attach time. Then the task gets scheduled or
cancelled with task_add()/task_del(), and when the task runs it gets
its arguments from the storage given to task_set().

If we wanted to store the task and its arguments outside the softc,
I guess we'd need to malloc() task memory at attach time and free it
on detach(). I.e. it has the same lifetime as the softc. So I don't
see the point of uncoupling it from the softc.

Or we would need to call task_set() and task_add() every time we want
to schedule the task. I don't think that's what the tasqk API is intending.

Or we would have the task itself free its own storage (task and
arguments), instead of freeing it when the softc is destroyed.
But I don't think that's what the API is intending either.

 I'm asking because if you can do it, this will make the task totally
 independent and won't require any task_del(). The idea behind that
 is that tomorrow we will try to have more kernel threads running in
 parallel, and if your task is about to run or already running when
 your interface is destroyed you might end up freeing the memory the 
 task is manipulating.

I'm assuming the task won't be interrupted in a way that would make the
ifp storage go away while it runs. Perhaps in a new world with more
kernel threads that won't hold. But that would cause quite a lot of
problems everywhere, not just sppp(4).

When the ifp goes away, the task must be not be allowed to run if already
scheduled. Because a workq task cannot be cancelled, the bug where the
interface is deleted before the workq task gets to run is present in the
current code and fixed by switching to taskq, with the task_del() call
at interface detach time. How can we fix this bug without task_del()?
Would you have the task itself cope with an ifp that has disappeared?

 Since the current code is already using allocating some memory for the
 arguments of the task, I'd argue that this is better than putting the
 task storage on the same memory chunk that it manipulates.  But since
 this problem exists in other places in our tree, we might think of an
 alternative solution/api/whatever.

For now, I'd like to stick with the task in softc idiom I saw elsewhere.

Generally, I think your concern is out of scope for my sppp(4) changes
and should be discussed in a separate discussion thread because using
a different idiom would affect many drivers.



Re: convert sppp(4) to taskq

2013-11-18 Thread Martin Pieuchot
On 18/11/13(Mon) 13:35, Stefan Sperling wrote:
 On Mon, Nov 18, 2013 at 12:37:53PM +0100, Martin Pieuchot wrote:
  Even if right now calling task_del() is enough, do you know if there's
  an easy way to convert this code without putting the task storage in
  the chunk of memory it manipulates?  In other words having the struct
  task outside of the softc?
 
 Well, tasks are stored in softc everywhere I looked for examples.

I know :)  But how many of these softc can be freed?  I also introduced
a similar situation in audio(4) if it is attached to uaudio(4), and I'm
looking for an alternative way of doing it.

 The task storage and the storage for the task's arguments needs to
 be known when task_set() is called. As I understand, task_set() is
 called once, at attach time. Then the task gets scheduled or
 cancelled with task_add()/task_del(), and when the task runs it gets
 its arguments from the storage given to task_set().
 
 If we wanted to store the task and its arguments outside the softc,
 I guess we'd need to malloc() task memory at attach time and free it
 on detach(). I.e. it has the same lifetime as the softc. So I don't
 see the point of uncoupling it from the softc.

The point is that there's no way to check if the task queue still
has a reference to your task when you free() your softc, right now
big lock is protecting us™ :) 

 Or we would need to call task_set() and task_add() every time we want
 to schedule the task. I don't think that's what the tasqk API is intending.
 
 Or we would have the task itself free its own storage (task and
 arguments), instead of freeing it when the softc is destroyed.
 But I don't think that's what the API is intending either.

That's why I'm asking, maybe you or somebody else already has an idea.

  I'm asking because if you can do it, this will make the task totally
  independent and won't require any task_del(). The idea behind that
  is that tomorrow we will try to have more kernel threads running in
  parallel, and if your task is about to run or already running when
  your interface is destroyed you might end up freeing the memory the 
  task is manipulating.
 
 I'm assuming the task won't be interrupted in a way that would make the
 ifp storage go away while it runs. Perhaps in a new world with more
 kernel threads that won't hold. But that would cause quite a lot of
 problems everywhere, not just sppp(4).

 When the ifp goes away, the task must be not be allowed to run if already
 scheduled. Because a workq task cannot be cancelled, the bug where the
 interface is deleted before the workq task gets to run is present in the
 current code and fixed by switching to taskq, with the task_del() call
 at interface detach time. How can we fix this bug without task_del()?
 Would you have the task itself cope with an ifp that has disappeared?

Yep, that's another way to fix this problem.  You can pass the index of
the interface to the task and call if_get() when it runs.  If the interface
is gone don't do anything otherwise run the task.

But this approach only makes sense if the task storage is not freed when
the interface is destroyed.

  Since the current code is already using allocating some memory for the
  arguments of the task, I'd argue that this is better than putting the
  task storage on the same memory chunk that it manipulates.  But since
  this problem exists in other places in our tree, we might think of an
  alternative solution/api/whatever.
 
 For now, I'd like to stick with the task in softc idiom I saw elsewhere.

Fine with me.

 Generally, I think your concern is out of scope for my sppp(4) changes
 and should be discussed in a separate discussion thread because using
 a different idiom would affect many drivers.

It is, clearly, but maybe you had an easy way to avoid it, apparently
not ;)  To be clear, my concern is only about drivers that can be
destroyed/unplugged, that's hopefully not affecting so many drivers.



Re: convert sppp(4) to taskq

2013-11-15 Thread Mike Belopuhov
On 15 November 2013 15:13, Stefan Sperling s...@openbsd.org wrote:
 Is this done right?

 Works here with pppoe(4) for both IPv4 and IPv6.


i think this diff might lack task_del's in the detach code.
have you tried destroying your pppoe interface?



Re: convert sppp(4) to taskq

2013-11-15 Thread Stefan Sperling
On Fri, Nov 15, 2013 at 03:20:48PM +0100, Mike Belopuhov wrote:
 On 15 November 2013 15:13, Stefan Sperling s...@openbsd.org wrote:
  Is this done right?
 
  Works here with pppoe(4) for both IPv4 and IPv6.
 
 
 i think this diff might lack task_del's in the detach code.

Ooops, good catch.

 have you tried destroying your pppoe interface?

Yes, but evidently not while a task was scheduled.

Same diff with task_del calls added.

Index: if_sppp.h
===
RCS file: /cvs/src/sys/net/if_sppp.h,v
retrieving revision 1.19
diff -u -p -r1.19 if_sppp.h
--- if_sppp.h   14 Nov 2013 16:52:33 -  1.19
+++ if_sppp.h   15 Nov 2013 13:48:47 -
@@ -93,6 +93,12 @@ struct spppreq {
 #ifdef _KERNEL
 
 #include sys/timeout.h
+#include sys/task.h
+
+#ifdef INET6
+#include netinet/in.h
+#include netinet6/in6_var.h
+#endif
 
 #define IDX_LCP 0  /* idx into state table */
 
@@ -124,8 +130,13 @@ struct sipcp {
 #define IPV6CP_MYIFID_SEEN 2 /* have seen my suggested ifid */
u_int32_t saved_hisaddr; /* if hisaddr (IPv4) is dynamic, save
  * original one here, in network byte order */
-   u_int32_t req_hisaddr;  /* remote address requested */
-   u_int32_t req_myaddr;   /* local address requested */
+   u_int32_t req_hisaddr;  /* remote address requested (IPv4) */
+   u_int32_t req_myaddr;   /* local address requested (IPv4) */
+#ifdef INET6
+   struct in6_aliasreq req_ifid;   /* local ifid requested (IPv6) */
+#endif
+   struct task set_addr_task;  /* set address from process context */
+   struct task clear_addr_task;/* clear address from process context */
 };
 
 struct sauth {
Index: if_spppsubr.c
===
RCS file: /cvs/src/sys/net/if_spppsubr.c,v
retrieving revision 1.112
diff -u -p -r1.112 if_spppsubr.c
--- if_spppsubr.c   14 Nov 2013 16:52:33 -  1.112
+++ if_spppsubr.c   15 Nov 2013 14:37:24 -
@@ -46,7 +46,6 @@
 #include sys/syslog.h
 #include sys/malloc.h
 #include sys/mbuf.h
-#include sys/workq.h
 
 #include sys/timeout.h
 #include crypto/md5.h
@@ -72,10 +71,6 @@
 
 #include net/if_sppp.h
 
-#ifdef INET6
-#include netinet6/in6_var.h
-#endif
-
 # define UNTIMEOUT(fun, arg, handle)   \
timeout_del((handle))
 
@@ -291,6 +286,7 @@ HIDE void sppp_lcp_check_and_close(struc
 HIDE int sppp_ncp_check(struct sppp *sp);
 
 HIDE void sppp_ipcp_init(struct sppp *sp);
+HIDE void sppp_ipcp_destroy(struct sppp *sp);
 HIDE void sppp_ipcp_up(struct sppp *sp);
 HIDE void sppp_ipcp_down(struct sppp *sp);
 HIDE void sppp_ipcp_open(struct sppp *sp);
@@ -306,6 +302,7 @@ HIDE void sppp_ipcp_tlf(struct sppp *sp)
 HIDE void sppp_ipcp_scr(struct sppp *sp);
 
 HIDE void sppp_ipv6cp_init(struct sppp *sp);
+HIDE void sppp_ipv6cp_destroy(struct sppp *sp);
 HIDE void sppp_ipv6cp_up(struct sppp *sp);
 HIDE void sppp_ipv6cp_down(struct sppp *sp);
 HIDE void sppp_ipv6cp_open(struct sppp *sp);
@@ -902,6 +899,9 @@ sppp_detach(struct ifnet *ifp)
struct sppp **q, *p, *sp = (struct sppp*) ifp;
int i;
 
+   sppp_ipcp_destroy(sp);
+   sppp_ipv6cp_destroy(sp);
+
/* Remove the entry from the keepalive list. */
for (q = spppq; (p = *q); q = p-pp_next)
if (p == sp) {
@@ -2637,6 +2637,15 @@ sppp_ipcp_init(struct sppp *sp)
sp-ipcp.flags = 0;
sp-state[IDX_IPCP] = STATE_INITIAL;
sp-fail_counter[IDX_IPCP] = 0;
+   task_set(sp-ipcp.set_addr_task, sppp_set_ip_addrs, sp, NULL);
+   task_set(sp-ipcp.clear_addr_task, sppp_clear_ip_addrs, sp, NULL);
+}
+
+HIDE void
+sppp_ipcp_destroy(struct sppp *sp)
+{
+   task_del(systq, sp-ipcp.set_addr_task);
+   task_del(systq, sp-ipcp.clear_addr_task);
 }
 
 HIDE void
@@ -2955,38 +2964,11 @@ sppp_ipcp_RCN_nak(struct sppp *sp, struc
addlog(\n);
 }
 
-struct sppp_set_ip_addrs_args {
-   struct sppp *sp;
-   u_int32_t myaddr;
-   u_int32_t hisaddr;
-};
-
 HIDE void
 sppp_ipcp_tlu(struct sppp *sp)
 {
-   struct ifnet *ifp = sp-pp_if;
-   struct sppp_set_ip_addrs_args *args;
-
-   args = malloc(sizeof(*args), M_TEMP, M_NOWAIT);
-   if (args == NULL)
-   return;
-
-   args-sp = sp;
-
-   /* we are up. Set addresses and notify anyone interested */
-   sppp_get_ip_addrs(sp, args-myaddr, args-hisaddr, 0);
-   if ((sp-ipcp.flags  IPCP_MYADDR_DYN) 
-   (sp-ipcp.flags  IPCP_MYADDR_SEEN))
-   args-myaddr = sp-ipcp.req_myaddr;
-   if ((sp-ipcp.flags  IPCP_HISADDR_DYN) 
-   (sp-ipcp.flags  IPCP_HISADDR_SEEN))
-   args-hisaddr = sp-ipcp.req_hisaddr;
-
-   if (workq_add_task(NULL, 0, sppp_set_ip_addrs, args, NULL)) {
-   free(args, M_TEMP);
-   printf(%s: workq_add_task failed, cannot set 
-   addresses\n, ifp-if_xname);
-   }
+   if (sp-ipcp.req_myaddr 

Re: convert sppp(4) to taskq

2013-11-15 Thread Mike Belopuhov
On 15 November 2013 15:45, Stefan Sperling s...@openbsd.org wrote:
 On Fri, Nov 15, 2013 at 03:20:48PM +0100, Mike Belopuhov wrote:
 On 15 November 2013 15:13, Stefan Sperling s...@openbsd.org wrote:
  Is this done right?
 
  Works here with pppoe(4) for both IPv4 and IPv6.
 

 i think this diff might lack task_del's in the detach code.

 Ooops, good catch.

 have you tried destroying your pppoe interface?

 Yes, but evidently not while a task was scheduled.

 Same diff with task_del calls added.


looks fine to me so far.