From: Martin Schwidefsky z/VM monitor stream changes: - Correct sysctl vs. module ref-counting. --- 25-akpm/arch/s390/appldata/appldata_base.c | 43 +++++++++++++++++++++++------ 1 files changed, 35 insertions(+), 8 deletions(-) diff -puN arch/s390/appldata/appldata_base.c~s390-zvm arch/s390/appldata/appldata_base.c --- 25/arch/s390/appldata/appldata_base.c~s390-zvm 2004-03-26 12:15:59.116661640 -0800 +++ 25-akpm/arch/s390/appldata/appldata_base.c 2004-03-26 12:15:59.118661336 -0800 @@ -372,31 +372,57 @@ static int appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, void *buffer, size_t *lenp) { - struct appldata_ops *ops; - int rc, len; + struct appldata_ops *ops = NULL, *tmp_ops; + int rc, len, found; char buf[2]; + struct list_head *lh; + found = 0; + spin_lock_bh(&appldata_ops_lock); + list_for_each(lh, &appldata_ops_list) { + tmp_ops = list_entry(lh, struct appldata_ops, list); + if (&tmp_ops->ctl_table[2] == ctl) { + found = 1; + } + } + if (!found) { + spin_unlock_bh(&appldata_ops_lock); + return -ENODEV; + } ops = ctl->data; + if (!try_module_get(ops->owner)) { // protect this function + spin_unlock_bh(&appldata_ops_lock); + return -ENODEV; + } + spin_unlock_bh(&appldata_ops_lock); + if (!*lenp || filp->f_pos) { *lenp = 0; + module_put(ops->owner); return 0; } if (!write) { len = sprintf(buf, ops->active ? "1\n" : "0\n"); if (len > *lenp) len = *lenp; - if (copy_to_user(buffer, buf, len)) + if (copy_to_user(buffer, buf, len)) { + module_put(ops->owner); return -EFAULT; + } goto out; } len = *lenp; - if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len)) + if (copy_from_user(buf, buffer, + len > sizeof(buf) ? sizeof(buf) : len)) { + module_put(ops->owner); return -EFAULT; + } spin_lock_bh(&appldata_ops_lock); if ((buf[0] == '1') && (ops->active == 0)) { - if (!try_module_get(ops->owner)) { + if (!try_module_get(ops->owner)) { // protect tasklet spin_unlock_bh(&appldata_ops_lock); + module_put(ops->owner); return -ENODEV; } ops->active = 1; @@ -430,6 +456,7 @@ appldata_generic_handler(ctl_table *ctl, out: *lenp = len; filp->f_pos += len; + module_put(ops->owner); return 0; } @@ -511,7 +538,6 @@ int appldata_register_ops(struct appldat ops->ctl_table[3].ctl_name = 0; ops->sysctl_header = register_sysctl_table(ops->ctl_table,1); - ops->ctl_table[2].de->owner = ops->owner; P_INFO("%s-ops registered!\n", ops->name); return 0; @@ -525,10 +551,11 @@ int appldata_register_ops(struct appldat void appldata_unregister_ops(struct appldata_ops *ops) { spin_lock_bh(&appldata_ops_lock); - list_del(&ops->list); - spin_unlock_bh(&appldata_ops_lock); unregister_sysctl_table(ops->sysctl_header); + list_del(&ops->list); kfree(ops->ctl_table); + ops->ctl_table = NULL; + spin_unlock_bh(&appldata_ops_lock); P_INFO("%s-ops unregistered!\n", ops->name); } /********************** module-ops management **************************/ _