All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rusty Russell <rusty@rustcorp.com.au>
To: Roman Zippel <zippel@linux-m68k.org>
Cc: kaos@ocs.com.au, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] In-kernel module loader 1/7
Date: Mon, 23 Sep 2002 10:20:46 +1000	[thread overview]
Message-ID: <20020923002313.E42122C0D7@lists.samba.org> (raw)
In-Reply-To: Your message of "Sat, 21 Sep 2002 19:09:19 +0200." <Pine.LNX.4.44.0209211411010.338-100000@serv>

In message <Pine.LNX.4.44.0209211411010.338-100000@serv> you write:
> Hi,
> 
> On Sat, 21 Sep 2002, Rusty Russell wrote:
> 
> > initfn()
> > {
> > 	register_notifier(some_notifier); /* Entry point one */
> > 	if (register_filesystem(some_notifier2) != 0) {
> > 		unregister_notifier(some_notifier); /* This fails! */
> > 		return -EBUSY;
> > 	}
> >
> > How does your solution of failing the unregister_notifier in this case
> > stop the race?  I probably missed something here?
> 
> You shouldn't do any cleanup in the init function and do it instead in
> the exit function. That's the reason why I said earlier that calling exit
> even after a failed init is not just an implementation detail. So your
> functions would look like this:

Yeah, I realized this after I sent the mail.  Sorry.  The problem is
one level higher in your implementation:

		error = start_module(mod);
		if (error)
			exit_module(mod);

If the exit fails here (because the module is now in use, so the
unregister_notifier() fails, you need to loop and yield, because you
have no way of saying "wake me when you can be unloaded".

> int initfn()
> {
> 	int err;
> 
> 	err = register_notifier(&some_notifier);
> 	if (err)
> 		return err;
> 	err = register_filesystem(&some_notifier2);
> 	return err;
> }

OK, so we fail the some_notifier2 here, and call exitfn:

> int exitfn()
> {
> 	int err;
> 
> 	err = unregister_filesystem(&some_notifier2);
> 	if (err)
> 		return err;

This will trigger (err == -ENOENT) I assume?  I think you really need:

int exitfn()
{
	int busy;

	busy = (unregister_filesystem(&some_notifier2) == -EBUSY
		|| unregister_filesystem(&some_notifier) == -EBUSY);
	if (busy)
		return -EBUSY;
	return 0;
}

> If you insist on doing the synchronize call in the module code, then you
> need two stages. On the other you also could simply do this in the driver
> code:
> 
> 	if (hook) {
> 		hook = NULL;
> 		synchronize();
> 	}
> 	...

Hmm, at least if we force the module author to provide two functions,
they don't have to have a clear understanding of the subtleties.  I
know, I'm a coward.

> > > Even your bigref is still overkill. When packets come in, you already hav
e
> > > to take _some_ lock, under the protection of this lock you can implement
> > > cheap, simple, portable and cache friendly counts, which can be used for
> > > synchronization.
> >
> > No: networking uses the network brlock for exactly this reason 8(
> 
> It can't be that difficult. After you removed the hooks you only have to
> wait for some time and I can't believe it's that difficult to calculate
> the needed time. Using the number of incoming packets is one possibility,
> the number of network interrupts should be another way.
> You could even temporarily shutdown all network interfaces, if it's really
> that difficult.

Yes, you can actually unregister all your hooks and then take the
write brlock for a moment (this is what I do in the ip_conntrack
code).  Let me think, in this case, functions would look like.  Please
see if my understanding is correct:

static struct proc_dir_entry *proc;

int start_ip_conntrack(void)
{
	ret = ip_conntrack_init();
	if (ret < 0)
		return ret;

	proc = proc_net_create("ip_conntrack",0,list_conntracks);
	if (!proc)
		return -EBUSY;

	ret = nf_register_hook(&ip_conntrack_in_ops);
	if (ret < 0)
		return ret;

	ret = nf_register_hook(&ip_conntrack_local_out_ops);
	if (ret < 0)
		return ret;
		
	ret = nf_register_hook(&ip_conntrack_out_ops);
	if (ret < 0)
		return ret;

	ret = nf_register_hook(&ip_conntrack_local_in_ops);
	return ret;
}

I'm not clear on the exact desired semantics of stop and exit?  When
should stop() fail?

int stop_ip_conntrack(void)
{
	nf_unregister_hook(&ip_conntrack_in_ops);
	nf_unregister_hook(&ip_conntrack_local_out_ops);
	nf_unregister_hook(&ip_conntrack_out_ops);
	nf_unregister_hook(&ip_conntrack_local_in_ops);
	/* Force synchronization */
	br_write_lock_irq(BR_NETPROTO_LOCK);
	br_write_unlock_irq(BR_NETPROTO_LOCK);
	if (proc_net_destroy(proc) == -EBUSY)
		return -EBUSY;
	return 0;
}

Now, we put callback pointers inside packets, so we need to keep a
count of how many of those we have (packet_count):

int exit_ip_conntrack(void)
{
	if (!bigref_is_zero(&packet_count))
		return -EBUSY;

	/* Woohoo!  We're free, clean up! */
	ip_conntrack_cleanup();
	return 0;
}

int usecount_ip_conntrack(void)
{
	return atomic_read(&proc->use)
		 + bigref_approx_val(&packet_count);
}

Am I using this interface correctly?  Since netfilter hooks can't
sleep, nf_register_hook can't be busy (ie. can't fail for that
reason).  I added a -EBUSY return to proc_net_destroy().  

> > > - A call to exit does in any case start the removal of the module, that
> > > means it starts removing interface (and which won't get reinstalled).
> > > If there is still any user, exit will fail, you can try it later again
> > > after you killed that user.
> >
> > If the exit fails and you fail the rmmod, you need to reinit the
> > module.  Otherwise noone can use it, but it cannot be replaced (say
> > it's holding some io region or other resource).
> 
> Why would I want to reinit the module after a failed exit? As long as

But, this is what you seem to do in try_unregister_module:

	if (test_bit(MOD_INITIALIZED, &mod->flags)) {
		res = exit_module(mod);
		if (res) {
			start_module(mod);
			goto out;
		}
	}

> > If you want to wait, that may be OK, but if you want to abort the
> > unload, the module needs to give you a *third* function, and that's
> > where my "too much work for every module author" line gets crossed 8(
> 
> What do you mean?

I thought you might want a "restart()" function, but I don't think you
do.

> > > Anyway, almost any access to a driver goes through the filesystem and
> > > there it's a well known problem of unlinked but still open files. Driver
> > > access is pretty much the same problem to which you can apply the same
> > > well known solutions.
> >
> > Not sure what you mean here.
> 
> You start using drivers like files by opening them, while it's open it can
> be removed (made unreachable), but only when the last user is gone can the
> resources be released. Treat a driver like a file (or maybe a complete
> file system) and you can use a lot of Al-proof infrastructure for free.

Oh, I see what you are saying.  Yes, this is two-stage delete.  It's
very common in the networking code too, for similar reasons.

Rusty.
--
  Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

  reply	other threads:[~2002-09-23  0:18 UTC|newest]

Thread overview: 56+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-09-18  2:05 [PATCH] In-kernel module loader 1/7 Rusty Russell
2002-09-18 22:59 ` Roman Zippel
2002-09-19  1:00   ` Rusty Russell
2002-09-19  2:19     ` Daniel Jacobowitz
2002-09-19  3:57       ` Rusty Russell
2002-09-19 10:44     ` Roman Zippel
2002-09-19 12:51       ` Rusty Russell
2002-09-19 13:54         ` Roman Zippel
2002-09-19 18:38           ` Greg KH
2002-09-19 18:58             ` Alan Cox
2002-09-19 20:11               ` Greg KH
2002-09-19 20:42                 ` Roman Zippel
2002-09-30 15:32                 ` Daniel Phillips
2002-10-03 18:53                   ` Rob Landley
2002-10-04  0:10                     ` Daniel Phillips
2002-10-15  3:25                   ` Rusty Russell
2002-10-15 15:28                     ` Daniel Phillips
2002-10-15 23:53                       ` Rusty Russell
2002-10-16  2:59                         ` Daniel Phillips
2002-10-16  6:11                           ` Rusty Russell
2002-10-16 17:33                             ` Daniel Phillips
2002-10-16 22:48                               ` Rusty Russell
2002-10-17  1:57                                 ` Daniel Phillips
2002-10-17  7:41                                   ` Rusty Russell
2002-10-17 14:49                                     ` Roman Zippel
2002-10-17 14:56                                     ` your mail Kai Germaschewski
2002-10-18  2:47                                       ` Rusty Russell
2002-10-18 21:50                                         ` Kai Germaschewski
2002-10-17 17:20                                     ` [RFC] change format of LSM hooks Daniel Phillips
2002-10-18  2:04                                       ` Rusty Russell
2002-10-17 17:25                                     ` Daniel Phillips
2002-10-16  8:15                         ` [PATCH] In-kernel module loader 1/7 Chris Wright
2002-09-19 20:10             ` Roman Zippel
2002-09-20  1:22             ` Rusty Russell
2002-09-20  4:32               ` Greg KH
2002-09-20  9:25                 ` Rusty Russell
2002-09-21  7:38               ` Kevin O'Connor
2002-09-22 23:31                 ` Rusty Russell
2002-09-19 23:44           ` Rusty Russell
2002-09-20  9:32             ` Roman Zippel
2002-09-21  4:17               ` Rusty Russell
2002-09-21 17:09                 ` Roman Zippel
2002-09-23  0:20                   ` Rusty Russell [this message]
2002-09-24 10:16                     ` Roman Zippel
2002-09-24 14:54                       ` Rusty Russell
2002-09-25  0:46                         ` Roman Zippel
2002-09-25  5:50                           ` Rusty Russell
2002-09-25 11:36                             ` Roman Zippel
2002-09-25 12:53                               ` Rusty Russell
2002-09-25 21:28                                 ` Roman Zippel
2002-09-26  1:49                                   ` Rusty Russell
2002-09-26 23:38                                     ` Roman Zippel
2002-09-27  1:11                                       ` Scott Murray
2002-09-27  1:34                                         ` Roman Zippel
2002-09-28  0:48                                           ` David Lang
2002-10-15  4:53                                       ` Rusty Russell

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=20020923002313.E42122C0D7@lists.samba.org \
    --to=rusty@rustcorp.com.au \
    --cc=kaos@ocs.com.au \
    --cc=linux-kernel@vger.kernel.org \
    --cc=zippel@linux-m68k.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.