On Thu, May 25, 2017 at 05:16:29PM -0700, Luis R. Rodriguez wrote: > This adds helpers for getting access to the kmod limit from > userspace. This knob should help userspace more gracefully and > deterministically handle module loading. I think more details is needed before we add a new ABI to the kernel. Why can't userspace submit as much as it wants and the kernel decide how much it will service at once? > > Cc: Tom Gundersen <teg@xxxxxxx> > Cc: Petr Mladek <pmladek@xxxxxxxx> > Signed-off-by: Luis R. Rodriguez <mcgrof@xxxxxxxxxx> > --- > Documentation/sysctl/kernel.txt | 20 ++++++++++++++++++++ > include/linux/kmod.h | 5 +++++ > kernel/kmod.c | 33 +++++++++++++++++++++++++++++++++ > kernel/sysctl.c | 7 +++++++ > 4 files changed, 65 insertions(+) > > diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt > index bac23c198360..080ccdca1f10 100644 > --- a/Documentation/sysctl/kernel.txt > +++ b/Documentation/sysctl/kernel.txt > @@ -370,6 +370,26 @@ with the "modules_disabled" sysctl. > > ============================================================== > > +kmod-limit: > + > +Get the max amount of concurrent requests (kmod_concurrent) the kernel can > +make out to userspace to call 'modprobe'. This limit is known internally to the > +kernel as max_modprobes. This interface is designed to enable userspace to > +query the kernel for the max_modprobes limit so userspace can more > +deterministically handle module loading by only enabling max_modprobes > +'modprobe' calls at a time. > + > +Dependencies are resolved in userspace through depmod, so one modprobe > +call only bumps the number of concurrent threads (kmod_concurrent) by one. > +Dependencies for a module then are loaded directly in userspace using > +init_module() / finit_module() skipping bumping kmod_concurrent or being > +affected by max_modprobes. > + > +The max_modprobes value is set at build time with CONFIG_MAX_KMOD_CONCURRENT. > +You can override at initialization with the module parameter max_modprobes. > + > +============================================================== > + > kptr_restrict: > > This toggle indicates whether restrictions are placed on > diff --git a/include/linux/kmod.h b/include/linux/kmod.h > index 8e2f302b214a..bbc6d59190aa 100644 > --- a/include/linux/kmod.h > +++ b/include/linux/kmod.h > @@ -39,13 +39,18 @@ int __request_module(bool wait, const char *name, ...); > #define try_then_request_module(x, mod...) \ > ((x) ?: (__request_module(true, mod), (x))) > void init_kmod_umh(void); > +unsigned int get_kmod_umh_limit(void); > +int sysctl_kmod_limit(struct ctl_table *table, int write, > + void __user *buffer, size_t *lenp, loff_t *ppos); > #else > static inline int request_module(const char *name, ...) { return -ENOSYS; } > static inline int request_module_nowait(const char *name, ...) { return -ENOSYS; } > #define try_then_request_module(x, mod...) (x) > static inline void init_kmod_umh(void) { } > +static inline unsigned int get_kmod_umh_limit(void) { return 0; } > #endif > > +#define get_kmod_umh_limit get_kmod_umh_limit > > struct cred; > struct file; > diff --git a/kernel/kmod.c b/kernel/kmod.c > index cafd27b92d19..17de776cf368 100644 > --- a/kernel/kmod.c > +++ b/kernel/kmod.c > @@ -111,6 +111,17 @@ static int call_modprobe(char *module_name, int wait) > } > > /** > + * get_kmod_umh_limit - get concurrent modprobe thread limit > + * > + * Returns the number of allowed concurrent modprobe calls. > + */ > +unsigned int get_kmod_umh_limit(void) > +{ > + return max_modprobes; > +} > +EXPORT_SYMBOL_GPL(get_kmod_umh_limit); > + > +/** > * __request_module - try to load a kernel module > * @wait: wait (or not) for the operation to complete > * @fmt: printf style format string for the name of the module > @@ -194,6 +205,28 @@ void __init init_kmod_umh(void) > atomic_set(&kmod_concurrent_max, max_modprobes); > } > > +int sysctl_kmod_limit(struct ctl_table *table, int write, > + void __user *buffer, size_t *lenp, loff_t *ppos) > +{ > + struct ctl_table t; > + int ret; > + unsigned int local_max_modprobes = max_modprobes; > + unsigned int min = 0; > + unsigned int max = max_threads/2; > + > + t = *table; > + t.data = &local_max_modprobes; > + t.extra1 = &min; > + t.extra2 = &max; > + > + if (write) > + return -EPERM; > + > + ret = proc_douintvec_minmax(&t, write, buffer, lenp, ppos); > + > + return ret; > +} > + > #endif /* CONFIG_MODULES */ > > static void call_usermodehelper_freeinfo(struct subprocess_info *info) > diff --git a/kernel/sysctl.c b/kernel/sysctl.c > index df9f2a367882..d1c1d1999bb1 100644 > --- a/kernel/sysctl.c > +++ b/kernel/sysctl.c > @@ -682,6 +682,13 @@ static struct ctl_table kern_table[] = { > .extra1 = &one, > .extra2 = &one, > }, > + { > + .procname = "kmod-limit", > + .data = NULL, /* filled in by handler */ > + .maxlen = sizeof(unsigned int), > + .mode = 0444, > + .proc_handler = sysctl_kmod_limit, > + }, > #endif > #ifdef CONFIG_UEVENT_HELPER > { > -- > 2.11.0 > -- Dmitry -- To unsubscribe from this list: send the line "unsubscribe linux-doc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html