getting rid of "fs_initcall" from drivers/ code

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



  i noticed that there are a number of drivers that, rather than use
the standard module_init() call, use fs_initcall() instead, ostensibly
because the author wants to very carefully control when that code is
run if the code is compiled into the kernel.  but it seems that a lot
of that can be cleaned up, if i'm reading my init code correctly.

  by way of explanation, here's the order of (a partial list of)
initcalls from include/linux/init.h:

...
#define subsys_initcall(fn)             __define_initcall("4",fn,4)
#define subsys_initcall_sync(fn)        __define_initcall("4s",fn,4s)
#define fs_initcall(fn)                 __define_initcall("5",fn,5)
#define fs_initcall_sync(fn)            __define_initcall("5s",fn,5s)
#define rootfs_initcall(fn)             __define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn)             __define_initcall("6",fn,6)
#define device_initcall_sync(fn)        __define_initcall("6s",fn,6s)
...

  so, when code is compiled into the kernel, the initcalls will be
done in the order of subsys, then fs, then rootfs, then device, etc,
etc.  fair enough.  so what does this have to do with modules and
module_init()?

  if i'm reading this correctly, if you have code that contains a call
to module_init() and that code is selected to be compiled into the
kernel,  this is what kicks in from include/linux/init.h:

...
#ifndef MODULE
...
#define __initcall(fn) device_initcall(fn)
...
#define module_init(x)  __initcall(x);
...

  in short, a call to module_init() will be transformed into a call to
device_initcall(), which would seem to be perfectly reasonable since
that seems like where it should be executed in the sequence of
initcalls at boot time.  however, in some cases, the author seems to
feel that his code must run *precisely* after the subsys calls, but
*before* any device calls, and that's why you find stuff like this in
drivers/pcmcia/ds.c:

...
fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that
                               * pcmcia_socket_class is already registered */
...

  it's clearly a hacky way of inserting something between the end of
the subsys initcalls, and the beginning of the device initcalls.  If
the code is compiled into the kernel, then that code is executed at
that point.  if, however, the code is made modular, what happens to
the invocation of fs_initcall()?  simple -- from include/linux/init.h
again:

...
#else /* MODULE */

/* Don't use these in modules, but some people do... */
#define core_initcall(fn)               module_init(fn)
#define postcore_initcall(fn)           module_init(fn)
#define arch_initcall(fn)               module_init(fn)
#define subsys_initcall(fn)             module_init(fn)
#define fs_initcall(fn)                 module_init(fn)
#define device_initcall(fn)             module_init(fn)
#define late_initcall(fn)               module_init(fn)

#define security_initcall(fn)           module_init(fn)
...

  so, if the code is selected to be modular, *all* of those (hacky?)
initcall settings (including fs_initcall, of course) will simply be
transformed to calls to module_init(), and everything will work
normally.  so what's to clean up here?

  first, it's worth asking if there is even a legitimate reason for
code writers to *ensure* that their code runs specifically after the
subsys calls and before the device calls.  some of those writers seem
to think so but, if that *has* to happen, then it would make more
sense to invoke subsys_initcall_sync() rather than fs_initcall().
using fs_initcall() for this purpose is just ugly and, semantically,
using subsys_initcall_sync() makes far more sense.  this would involve
adding the extra line:

#define subsys_initcall_sync(fn)         module_init(fn)

to the above list, but i still think it would be a better solution.
(and, again, this still requires these code writers to demonstrate
that they need that kind of fine-grained resolution in controlling
when their code runs.)

  in other cases, it seems that the cleanup is more straightforward.
consider this from drivers/cpufreq/cpufreq_userspace.c:

#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE
fs_initcall(cpufreq_gov_userspace_init);
#else
module_init(cpufreq_gov_userspace_init);
#endif

  ok, that's just grotesque as it's redundant since it can all be
replaced with a simple:

fs_initcall(cpufreq_gov_userspace_init);

and everything will work just fine based on what i wrote above, no?

  in short, it seems a lot of that nonsense can be cleaned.  thoughts?

rday

p.s.  and even if that code from cpufreq_userspace.c *needs* to have
that kind of control on when it has to run, again, using
subsys_initcall_sync() instead of fs_initcall() still makes more
sense.
--

========================================================================
Robert P. J. Day
Linux Consulting, Training and Annoying Kernel Pedantry:
    Have classroom, will lecture.

http://crashcourse.ca                          Waterloo, Ontario, CANADA
========================================================================
--
To unsubscribe from this list: send the line "unsubscribe kernel-janitors" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Kernel Development]     [Kernel Announce]     [Kernel Newbies]     [Linux Networking Development]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Device Mapper]

  Powered by Linux