Re: [RFC] module: add per-module params lock

2015-06-09 Thread Dan Streetman
On Mon, Jun 8, 2015 at 5:13 PM, Rusty Russell  wrote:
> Dan Streetman  writes:
>> On Thu, Jun 4, 2015 at 8:42 PM, Rusty Russell  wrote:
>>> Dan Streetman  writes:
 I sent this as part of a patch series a few days ago, which I was asked to
 break up, so I'm sending only this patch as a RFC now, until I work out
 the details of the zswap patch that needs this.  I'd like to get comments
 on this early, since it changes the way module param locking is done.
>>>
>>> OK, it's not insane, but I'm not entirely convinced.
>>>
>>> 1) The difference between blocking sysfs for read vs write is mainly
>>>documentation.  In theory, it allows a rwsem, though in practice it's
>>>not been a bottleneck to now.
>>
>> The sysfs block/unblock calls could remain the same, but the downside
>> there is a module can't block more than 1 of its params.  It seemed to
>> me like the per-param r/w block functions were adding unnecessary
>> restrictions, since we're not using a rwsem for each individual param.
>> If the param lock is changed to a rwsem in the future, it won't be
>> hard to also change all callers.  Or, we could change it to a resem
>> now.  But as you said, kernel param locking isn't really a contended
>> lock.
>>
>>>
>>> 2) Implicit is bad: implying the module rather than the parameter is
>>>weird
>>
>> Well implying it enforces only blocking your own module params; should
>> module A be blocking and accessing module B's params?  Isn't requiring
>> each module to pass THIS_MODULE unnecessary, at least in the vast
>> majority of cases?  There is still __kernel_param_lock(module) that
>> can be used if it really is necessary anywhere to block some other
>> module's params.  Or, I can change it to require passing THIS_MODULE
>> if you think that's a better api.
>
> It's weird to do anything other than lock the actual parameter you're
> talking about.  Nobody actually seems to want multi param locks (and if
> they try it they'll quickly discover it deadlocks).
>
>>> , and skips the BUG_ON() check which was there before.
>>
>> those made absolutely no sense to me; why in the world is it necessary
>> to BUG() simply because the param permissions don't match r or w?  At
>> *most* that deserves a WARN_ON() but more likely a pr_warn() is
>> appropriate.  And even then, who cares?  Does it actually cause any
>> harm?  No.  Especially since the underlying lock isn't a rwsem.  But
>> even if it *was* a rwsem, it still wouldn't hurt anything.
>
> Because you're locking something that can't change.  I really want that
> not to happen: I'd make it BUILD_BUG_ON() if I could.

Ah, ok.  I dug in there and I see the perm field isn't actually
changeable from sysfs, it's only the initial setting; so chmod will
only change the sysfs file perm, not the kernel_param.perm field that
the block_sysfs macros check.

If that's the case and perm *really* should never change, why not just
make it const and use BUILD_BUG_ON()?  I'll send a patch...

>
> You're confusing the API (which explicitly DOESN'T talk about locking,
> just blocking sysfs access), and the implementation.  For the majority
> of users, the API is more important.
>
> If you really dislike the API (and it's such a minor one), perhaps it's
> better to expose the lock explicitly:

I got to this point only because I was getting deadlocked when loading
a module from a param callback, so the API was really secondary to me;
I don't hate the API; and BUILD_BUG_ON seems a lot better.  If the
global mutex -> per module mutex seems ok, I can send reduce the patch
to only do that without changing the API.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] module: add per-module params lock

2015-06-08 Thread Rusty Russell
Dan Streetman  writes:
> On Thu, Jun 4, 2015 at 8:42 PM, Rusty Russell  wrote:
>> Dan Streetman  writes:
>>> I sent this as part of a patch series a few days ago, which I was asked to
>>> break up, so I'm sending only this patch as a RFC now, until I work out
>>> the details of the zswap patch that needs this.  I'd like to get comments
>>> on this early, since it changes the way module param locking is done.
>>
>> OK, it's not insane, but I'm not entirely convinced.
>>
>> 1) The difference between blocking sysfs for read vs write is mainly
>>documentation.  In theory, it allows a rwsem, though in practice it's
>>not been a bottleneck to now.
>
> The sysfs block/unblock calls could remain the same, but the downside
> there is a module can't block more than 1 of its params.  It seemed to
> me like the per-param r/w block functions were adding unnecessary
> restrictions, since we're not using a rwsem for each individual param.
> If the param lock is changed to a rwsem in the future, it won't be
> hard to also change all callers.  Or, we could change it to a resem
> now.  But as you said, kernel param locking isn't really a contended
> lock.
>
>>
>> 2) Implicit is bad: implying the module rather than the parameter is
>>weird
>
> Well implying it enforces only blocking your own module params; should
> module A be blocking and accessing module B's params?  Isn't requiring
> each module to pass THIS_MODULE unnecessary, at least in the vast
> majority of cases?  There is still __kernel_param_lock(module) that
> can be used if it really is necessary anywhere to block some other
> module's params.  Or, I can change it to require passing THIS_MODULE
> if you think that's a better api.

It's weird to do anything other than lock the actual parameter you're
talking about.  Nobody actually seems to want multi param locks (and if
they try it they'll quickly discover it deadlocks).

>> , and skips the BUG_ON() check which was there before.
>
> those made absolutely no sense to me; why in the world is it necessary
> to BUG() simply because the param permissions don't match r or w?  At
> *most* that deserves a WARN_ON() but more likely a pr_warn() is
> appropriate.  And even then, who cares?  Does it actually cause any
> harm?  No.  Especially since the underlying lock isn't a rwsem.  But
> even if it *was* a rwsem, it still wouldn't hurt anything.

Because you're locking something that can't change.  I really want that
not to happen: I'd make it BUILD_BUG_ON() if I could.

You're confusing the API (which explicitly DOESN'T talk about locking,
just blocking sysfs access), and the implementation.  For the majority
of users, the API is more important.

If you really dislike the API (and it's such a minor one), perhaps it's
better to expose the lock explicitly:

/* Stops sysfs updates to the module's parameters */
static inline struct mutex *module_param_mutex(struct module *mod)
{
return mod ? mod->param_lock : param_lock;
}

And make the callers do the obvious thing with it?

Cheers,
Rusty.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] module: add per-module params lock

2015-06-05 Thread Dan Streetman
On Thu, Jun 4, 2015 at 8:42 PM, Rusty Russell  wrote:
> Dan Streetman  writes:
>> I sent this as part of a patch series a few days ago, which I was asked to
>> break up, so I'm sending only this patch as a RFC now, until I work out
>> the details of the zswap patch that needs this.  I'd like to get comments
>> on this early, since it changes the way module param locking is done.
>
> OK, it's not insane, but I'm not entirely convinced.
>
> 1) The difference between blocking sysfs for read vs write is mainly
>documentation.  In theory, it allows a rwsem, though in practice it's
>not been a bottleneck to now.

The sysfs block/unblock calls could remain the same, but the downside
there is a module can't block more than 1 of its params.  It seemed to
me like the per-param r/w block functions were adding unnecessary
restrictions, since we're not using a rwsem for each individual param.
If the param lock is changed to a rwsem in the future, it won't be
hard to also change all callers.  Or, we could change it to a resem
now.  But as you said, kernel param locking isn't really a contended
lock.

>
> 2) Implicit is bad: implying the module rather than the parameter is
>weird

Well implying it enforces only blocking your own module params; should
module A be blocking and accessing module B's params?  Isn't requiring
each module to pass THIS_MODULE unnecessary, at least in the vast
majority of cases?  There is still __kernel_param_lock(module) that
can be used if it really is necessary anywhere to block some other
module's params.  Or, I can change it to require passing THIS_MODULE
if you think that's a better api.

> , and skips the BUG_ON() check which was there before.

those made absolutely no sense to me; why in the world is it necessary
to BUG() simply because the param permissions don't match r or w?  At
*most* that deserves a WARN_ON() but more likely a pr_warn() is
appropriate.  And even then, who cares?  Does it actually cause any
harm?  No.  Especially since the underlying lock isn't a rwsem.  But
even if it *was* a rwsem, it still wouldn't hurt anything.  Maybe the
param's permissions change at runtime by the module for whatever
reason.  Should the module really check the current permissions before
deciding to block the param or not?  No, it's simpler and harmless to
just block it unconditionally, and avoids a race with the permissions
being changed again and the param accessed.  And what if the user
changes the permissions from sysfs?  Certainly we don't want to BUG(),
and even printing a WARN() or pr_warn() isn't really appropriate.

In any case, IMHO, those permission checks aren't needed and shouldn't be done.

>
> And finally, why are you loading a module from a param callback?  That's
> a first!

Yeah :)

So zswap uses a crypto compressor.  The crypto api allows selecting
different compressor functions via crypto_alloc_comp(), and it will
internally load any crypto module that's requested if it's missing (it
also loads the module via crypto_has_comp()/crypto_has_alg()).  So,
when someone requests to change zswap's compressor function, zswap
tries to create the crypto compressor transform, and the crypto api
then does request_module() to load the new compressor.

The configuration and module loading is done in the param callback so
that zswap can fail the param setting if there is no such
implementation available.

>
> Thanks,
> Rusty.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC] module: add per-module params lock

2015-06-04 Thread Rusty Russell
Dan Streetman  writes:
> I sent this as part of a patch series a few days ago, which I was asked to
> break up, so I'm sending only this patch as a RFC now, until I work out
> the details of the zswap patch that needs this.  I'd like to get comments
> on this early, since it changes the way module param locking is done.

OK, it's not insane, but I'm not entirely convinced.

1) The difference between blocking sysfs for read vs write is mainly
   documentation.  In theory, it allows a rwsem, though in practice it's
   not been a bottleneck to now.

2) Implicit is bad: implying the module rather than the parameter is
   weird, and skips the BUG_ON() check which was there before.

And finally, why are you loading a module from a param callback?  That's
a first!

Thanks,
Rusty.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFC] module: add per-module params lock

2015-06-04 Thread Dan Streetman
I sent this as part of a patch series a few days ago, which I was asked to
break up, so I'm sending only this patch as a RFC now, until I work out
the details of the zswap patch that needs this.  I'd like to get comments
on this early, since it changes the way module param locking is done.

...

Add a "param_lock" mutex to each module, and add a pointer to the owning
module to struct kernel_param.  Then change the param sysfs modification
code to only use the global param_lock for built-ins, and use the
per-module param_lock for all modules.  Also simplify the
kernel_[un]block_sysfs_[read|write]() functions, to simply
kernel_[un]block_sysfs().

The kernel param code currently uses a single global mutex to protect
modification of any and all kernel params.  While this generally works,
there is one specific problem with it; a module callback function
cannot safely load another module, i.e. with request_module() or even
with indirect calls such as crypto_has_alg().  If the module to be
loaded has any of its params configured (e.g. with a /etc/modprobe.d/*
config file), then the attempt will result in a deadlock between the
first module param callback waiting for modprobe, and modprobe trying to
lock the global kernel param mutex to set the new module's param.

This fixes that by using per-module mutexes, so that each individual module
is protected against concurrent changes in its own kernel params, but is
not blocked by changes to other module params.  All built-in modules
continue to use the global mutex, since they will always be loaded at
runtime and references (e.g. request_module(), crypto_has_alg()) to them
will never cause load-time param changing.

This also simplifies the interface used by modules to block sysfs access
to their params; while there are currently functions to block and unblock
sysfs param access which are split up by read and write and expect a single
kernel param to be passed, their actual operation is identical and applies
to all params, not just the one passed to them; they simply lock and unlock
the global param mutex.  They are thus replaced with simplified functions
that clearly indicate that all params for a module are being blocked, both
for read and write access.

Signed-off-by: Dan Streetman 
---
 arch/um/drivers/hostaudio_kern.c | 20 +++
 drivers/net/ethernet/myricom/myri10ge/myri10ge.c |  6 +--
 drivers/net/wireless/libertas_tf/if_usb.c|  6 +--
 drivers/usb/atm/ueagle-atm.c |  4 +-
 drivers/video/fbdev/vt8623fb.c   |  4 +-
 include/linux/module.h   |  1 +
 include/linux/moduleparam.h  | 67 +---
 kernel/module.c  |  1 +
 kernel/params.c  | 45 ++--
 net/mac80211/rate.c  |  4 +-
 10 files changed, 77 insertions(+), 81 deletions(-)

diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
index 9b90fdc..1bcb798 100644
--- a/arch/um/drivers/hostaudio_kern.c
+++ b/arch/um/drivers/hostaudio_kern.c
@@ -185,9 +185,9 @@ static int hostaudio_open(struct inode *inode, struct file 
*file)
int ret;
 
 #ifdef DEBUG
-   kparam_block_sysfs_write(dsp);
+   kparam_block_sysfs();
printk(KERN_DEBUG "hostaudio: open called (host: %s)\n", dsp);
-   kparam_unblock_sysfs_write(dsp);
+   kparam_unblock_sysfs();
 #endif
 
state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL);
@@ -199,11 +199,11 @@ static int hostaudio_open(struct inode *inode, struct 
file *file)
if (file->f_mode & FMODE_WRITE)
w = 1;
 
-   kparam_block_sysfs_write(dsp);
+   kparam_block_sysfs();
mutex_lock(&hostaudio_mutex);
ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
mutex_unlock(&hostaudio_mutex);
-   kparam_unblock_sysfs_write(dsp);
+   kparam_unblock_sysfs();
 
if (ret < 0) {
kfree(state);
@@ -260,17 +260,17 @@ static int hostmixer_open_mixdev(struct inode *inode, 
struct file *file)
if (file->f_mode & FMODE_WRITE)
w = 1;
 
-   kparam_block_sysfs_write(mixer);
+   kparam_block_sysfs();
mutex_lock(&hostaudio_mutex);
ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
mutex_unlock(&hostaudio_mutex);
-   kparam_unblock_sysfs_write(mixer);
+   kparam_unblock_sysfs();
 
if (ret < 0) {
-   kparam_block_sysfs_write(dsp);
+   kparam_block_sysfs();
printk(KERN_ERR "hostaudio_open_mixdev failed to open '%s', "
   "err = %d\n", dsp, -ret);
-   kparam_unblock_sysfs_write(dsp);
+   kparam_unblock_sysfs();
kfree(state);
return ret;
}
@@ -326,10 +326,10 @@ MODULE_LICENSE("GPL");
 
 static int __init hostaudio_init_module(void)
 {
-   __kernel