Hi all,
Converting to and from void * for callback functions loses type safety:
everywhere else we expect the compiler to catch incorrect pointer types
handed to functions.
It's pretty simple to create typesafe callback functions using typeof, and
with a little gcc trickery we can allow both old-style and typesafe callbacks
to avoid churn on commonly-used routines.
Feedback welcomed,
Rusty.
Simple statement expression with a temporary variable does the
typechecking for us: that the stop_machine callback matches the data
type.
Signed-off-by: Rusty Russell <[email protected]>
---
drivers/char/hw_random/intel-rng.c | 3 +--
include/linux/stop_machine.h | 13 +++++++++----
kernel/module.c | 10 +++-------
kernel/stop_machine.c | 4 ++--
4 files changed, 15 insertions(+), 15 deletions(-)
diff -r fa243a61ba85 drivers/char/hw_random/intel-rng.c
--- a/drivers/char/hw_random/intel-rng.c Thu Jan 17 13:06:16 2008 +1100
+++ b/drivers/char/hw_random/intel-rng.c Thu Jan 17 14:47:11 2008 +1100
@@ -227,9 +227,8 @@ struct intel_rng_hw {
u8 fwh_dec_en1_val;
};
-static int __init intel_rng_hw_init(void *_intel_rng_hw)
+static int __init intel_rng_hw_init(struct intel_rng_hw *intel_rng_hw)
{
- struct intel_rng_hw *intel_rng_hw = _intel_rng_hw;
u8 mfc, dvc;
/* interrupts disabled in stop_machine_run call */
diff -r fa243a61ba85 include/linux/stop_machine.h
--- a/include/linux/stop_machine.h Thu Jan 17 13:06:16 2008 +1100
+++ b/include/linux/stop_machine.h Thu Jan 17 14:47:11 2008 +1100
@@ -7,7 +7,6 @@
#include <linux/cpu.h>
#include <asm/system.h>
-#if defined(CONFIG_STOP_MACHINE) && defined(CONFIG_SMP)
/**
* stop_machine_run: freeze the machine on all CPUs and run this function
* @fn: the function to run
@@ -21,7 +20,13 @@
*
* This can be thought of as a very heavy write lock, equivalent to
* grabbing every spinlock in the kernel. */
-int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu);
+#define stop_machine_run(fn, data, cpu) ({ \
+ int (*_fn)(typeof(data)) = (fn); \
+ stop_machine_run_notype((void *)_fn, (data), (cpu)); \
+})
+
+#if defined(CONFIG_STOP_MACHINE) && defined(CONFIG_SMP)
+int stop_machine_run_notype(int (*fn)(void *), void *data, unsigned int cpu);
/**
* __stop_machine_run: freeze the machine on all CPUs and run this function
@@ -38,8 +43,8 @@ struct task_struct *__stop_machine_run(i
#else
-static inline int stop_machine_run(int (*fn)(void *), void *data,
- unsigned int cpu)
+static inline int stop_machine_run_notype(int (*fn)(void *), void *data,
+ unsigned int cpu)
{
int ret;
local_irq_disable();
diff -r fa243a61ba85 kernel/module.c
--- a/kernel/module.c Thu Jan 17 13:06:16 2008 +1100
+++ b/kernel/module.c Thu Jan 17 14:47:11 2008 +1100
@@ -623,10 +623,8 @@ struct stopref
};
/* Whole machine is stopped with interrupts off when this runs. */
-static int __try_stop_module(void *_sref)
+static int __try_stop_module(struct stopref *sref)
{
- struct stopref *sref = _sref;
-
/* If it's not unused, quit unless we are told to block. */
if ((sref->flags & O_NONBLOCK) && module_refcount(sref->mod) != 0) {
if (!(*sref->forced = try_force_unload(sref->flags)))
@@ -1305,9 +1303,8 @@ static void mod_kobject_remove(struct mo
* link the module with the whole machine is stopped with interrupts off
* - this defends against kallsyms not taking locks
*/
-static int __link_module(void *_mod)
+static int __link_module(struct module *mod)
{
- struct module *mod = _mod;
list_add(&mod->list, &modules);
return 0;
}
@@ -1316,9 +1313,8 @@ static int __link_module(void *_mod)
* unlink the module with the whole machine is stopped with interrupts off
* - this defends against kallsyms not taking locks
*/
-static int __unlink_module(void *_mod)
+static int __unlink_module(struct module *mod)
{
- struct module *mod = _mod;
list_del(&mod->list);
return 0;
}
diff -r fa243a61ba85 kernel/stop_machine.c
--- a/kernel/stop_machine.c Thu Jan 17 13:06:16 2008 +1100
+++ b/kernel/stop_machine.c Thu Jan 17 14:47:11 2008 +1100
@@ -197,7 +197,7 @@ struct task_struct *__stop_machine_run(i
return p;
}
-int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu)
+int stop_machine_run_notype(int (*fn)(void *), void *data, unsigned int cpu)
{
struct task_struct *p;
int ret;
@@ -213,4 +213,4 @@ int stop_machine_run(int (*fn)(void *),
return ret;
}
-EXPORT_SYMBOL_GPL(stop_machine_run);
+EXPORT_SYMBOL_GPL(stop_machine_run_notype);
Simple statement expression with a temporary variable does the
typechecking for us: that the kthread function matches the data type.
If the function doesn't match, we get:
warning: initialization from incompatible pointer type
It's actually slightly over-strict, since you can hand void * data to
any function callback type, but there's only one such case in the kernel
anyway.
Signed-off-by: Rusty Russell <[email protected]>
---
include/linux/kthread.h | 30 +++++++++++++++++++++++++++---
kernel/kthread.c | 29 +++++------------------------
2 files changed, 32 insertions(+), 27 deletions(-)
diff -r 110aa94129d0 include/linux/kthread.h
--- a/include/linux/kthread.h Fri Jan 18 10:32:31 2008 +1100
+++ b/include/linux/kthread.h Fri Jan 18 11:31:49 2008 +1100
@@ -4,9 +4,33 @@
#include <linux/err.h>
#include <linux/sched.h>
-struct task_struct *kthread_create(int (*threadfn)(void *data),
- void *data,
- const char namefmt[], ...);
+/**
+ * kthread_create - create a kthread.
+ * @threadfn: the function to run until signal_pending(current).
+ * @data: data ptr for @threadfn.
+ * @namefmt: printf-style name for the thread.
+ *
+ * Description: This helper function creates and names a kernel
+ * thread. The thread will be stopped: use wake_up_process() to start
+ * it. See also kthread_run(), kthread_create_on_cpu().
+ *
+ * When woken, the thread will run @threadfn() with @data as its
+ * argument. @threadfn() can either call do_exit() directly if it is a
+ * standalone thread for which noone will call kthread_stop(), or
+ * return when 'kthread_should_stop()' is true (which means
+ * kthread_stop() has been called). The return value should be zero
+ * or a negative error number; it will be passed to kthread_stop().
+ *
+ * Returns a task_struct or ERR_PTR(-ENOMEM).
+ */
+#define kthread_create(threadfn, data, namefmt...) ({ \
+ int (*_threadfn)(typeof(data)) = (threadfn); \
+ __kthread_create((void *)_threadfn, (data), namefmt); \
+})
+
+struct task_struct *__kthread_create(int (*threadfn)(void *data),
+ void *data,
+ const char namefmt[], ...);
/**
* kthread_run - create and wake a thread.
diff -r 110aa94129d0 kernel/kthread.c
--- a/kernel/kthread.c Fri Jan 18 10:32:31 2008 +1100
+++ b/kernel/kthread.c Fri Jan 18 11:31:49 2008 +1100
@@ -102,29 +102,10 @@ static void create_kthread(struct kthrea
complete(&create->done);
}
-/**
- * kthread_create - create a kthread.
- * @threadfn: the function to run until signal_pending(current).
- * @data: data ptr for @threadfn.
- * @namefmt: printf-style name for the thread.
- *
- * Description: This helper function creates and names a kernel
- * thread. The thread will be stopped: use wake_up_process() to start
- * it. See also kthread_run(), kthread_create_on_cpu().
- *
- * When woken, the thread will run @threadfn() with @data as its
- * argument. @threadfn() can either call do_exit() directly if it is a
- * standalone thread for which noone will call kthread_stop(), or
- * return when 'kthread_should_stop()' is true (which means
- * kthread_stop() has been called). The return value should be zero
- * or a negative error number; it will be passed to kthread_stop().
- *
- * Returns a task_struct or ERR_PTR(-ENOMEM).
- */
-struct task_struct *kthread_create(int (*threadfn)(void *data),
- void *data,
- const char namefmt[],
- ...)
+struct task_struct *__kthread_create(int (*threadfn)(void *data),
+ void *data,
+ const char namefmt[],
+ ...)
{
struct kthread_create_info create;
@@ -149,7 +130,7 @@ struct task_struct *kthread_create(int (
}
return create.result;
}
-EXPORT_SYMBOL(kthread_create);
+EXPORT_SYMBOL(__kthread_create);
/**
* kthread_bind - bind a just-created kthread to a cpu.
This removes the warnings created by the patch to make kthread typesafe.
Other than fs/dlm/recoverd.c (which use a typedef to void and now
needs a cast), the changes were trivial and obvious.
Signed-off-by: Rusty Russell <[email protected]>
---
crypto/cryptd.c | 6 +++---
crypto/cryptomgr.c | 3 +--
drivers/base/firmware_class.c | 5 ++---
drivers/block/loop.c | 3 +--
drivers/block/pktcdvd.c | 3 +--
drivers/char/ipmi/ipmi_si_intf.c | 3 +--
drivers/ieee1394/nodemgr.c | 3 +--
drivers/infiniband/core/fmr_pool.c | 4 +---
drivers/input/touchscreen/ucb1400_ts.c | 3 +--
drivers/md/md.c | 6 ++----
drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 3 +--
drivers/media/dvb/dvb-core/dvb_frontend.c | 3 +--
drivers/media/video/cx88/cx88-tvaudio.c | 3 +--
drivers/media/video/cx88/cx88.h | 2 +-
drivers/media/video/msp3400-driver.c | 2 +-
drivers/media/video/msp3400-driver.h | 6 +++---
drivers/media/video/msp3400-kthreads.c | 9 +++------
drivers/media/video/saa7134/saa7134-tvaudio.c | 8 +++-----
drivers/media/video/tvaudio.c | 3 +--
drivers/media/video/videobuf-dvb.c | 3 +--
drivers/media/video/vivi.c | 4 +---
drivers/mmc/card/queue.c | 3 +--
drivers/mmc/core/sdio_irq.c | 3 +--
drivers/mtd/mtd_blkdevs.c | 3 +--
drivers/mtd/ubi/wl.c | 3 +--
drivers/net/irda/stir4200.c | 3 +--
drivers/net/wireless/airo.c | 5 ++---
drivers/net/wireless/libertas/main.c | 3 +--
drivers/pcmcia/cs.c | 5 ++---
drivers/scsi/aacraid/aacraid.h | 2 +-
drivers/scsi/aacraid/commsup.c | 3 +--
drivers/scsi/libsas/sas_scsi_host.c | 4 +---
drivers/scsi/lpfc/lpfc_crtn.h | 2 +-
drivers/scsi/lpfc/lpfc_hbadisc.c | 3 +--
drivers/scsi/qla2xxx/qla_os.c | 7 ++-----
drivers/scsi/scsi_error.c | 4 +---
drivers/scsi/scsi_priv.h | 2 +-
drivers/scsi/scsi_scan.c | 3 +--
drivers/usb/atm/ueagle-atm.c | 3 +--
drivers/usb/gadget/file_storage.c | 6 ++----
drivers/usb/storage/usb.c | 7 ++-----
drivers/w1/w1.c | 4 +---
drivers/w1/w1.h | 2 +-
fs/dlm/recoverd.c | 4 ++--
fs/gfs2/daemon.c | 13 ++++---------
fs/gfs2/daemon.h | 8 ++++----
fs/gfs2/locking/dlm/thread.c | 11 +++++------
fs/jbd/journal.c | 3 +--
fs/jbd2/journal.c | 3 +--
fs/nfs/delegation.c | 3 +--
fs/nfs/nfs4state.c | 5 ++---
fs/nfsd/nfs4callback.c | 3 +--
fs/nfsd/nfs4state.c | 4 +---
fs/ocfs2/cluster/heartbeat.c | 3 +--
fs/ocfs2/dlm/dlmrecovery.c | 5 ++---
fs/ocfs2/dlm/dlmthread.c | 5 ++---
fs/ocfs2/journal.c | 10 ++++------
fs/ocfs2/vote.c | 3 +--
fs/ocfs2/vote.h | 2 +-
fs/xfs/linux-2.6/xfs_buf.c | 5 ++---
fs/xfs/linux-2.6/xfs_super.c | 3 +--
kernel/audit.c | 3 +--
kernel/audit.h | 2 +-
kernel/rtmutex-tester.c | 3 +--
kernel/stop_machine.c | 3 +--
kernel/workqueue.c | 3 +--
mm/vmscan.c | 3 +--
net/9p/mux.c | 6 ++----
net/core/pktgen.c | 3 +--
sound/pci/emu10k1/emu10k1_main.c | 3 +--
70 files changed, 104 insertions(+), 183 deletions(-)
diff -r 110aa94129d0 crypto/cryptd.c
--- a/crypto/cryptd.c Fri Jan 18 10:32:31 2008 +1100
+++ b/crypto/cryptd.c Fri Jan 18 11:31:48 2008 +1100
@@ -291,7 +291,8 @@ static struct crypto_template cryptd_tmp
};
static inline int cryptd_create_thread(struct cryptd_state *state,
- int (*fn)(void *data), const char *name)
+ int (*fn)(struct cryptd_state *state),
+ const char *name)
{
spin_lock_init(&state->lock);
mutex_init(&state->mutex);
@@ -310,9 +311,8 @@ static inline void cryptd_stop_thread(st
kthread_stop(state->task);
}
-static int cryptd_thread(void *data)
+static int cryptd_thread(struct cryptd_state *state)
{
- struct cryptd_state *state = data;
int stop;
current->flags |= PF_NOFREEZE;
diff -r 110aa94129d0 crypto/cryptomgr.c
--- a/crypto/cryptomgr.c Fri Jan 18 10:32:31 2008 +1100
+++ b/crypto/cryptomgr.c Fri Jan 18 11:31:48 2008 +1100
@@ -47,9 +47,8 @@ struct cryptomgr_param {
char template[CRYPTO_MAX_ALG_NAME];
};
-static int cryptomgr_probe(void *data)
+static int cryptomgr_probe(struct cryptomgr_param *param)
{
- struct cryptomgr_param *param = data;
struct crypto_template *tmpl;
struct crypto_instance *inst;
int err;
diff -r 110aa94129d0 drivers/base/firmware_class.c
--- a/drivers/base/firmware_class.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/base/firmware_class.c Fri Jan 18 11:31:48 2008 +1100
@@ -488,12 +488,11 @@ struct firmware_work {
};
static int
-request_firmware_work_func(void *arg)
+request_firmware_work_func(struct firmware_work *fw_work)
{
- struct firmware_work *fw_work = arg;
const struct firmware *fw;
int ret;
- if (!arg) {
+ if (!fw_work) {
WARN_ON(1);
return 0;
}
diff -r 110aa94129d0 drivers/block/loop.c
--- a/drivers/block/loop.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/block/loop.c Fri Jan 18 11:31:48 2008 +1100
@@ -577,9 +577,8 @@ static inline void loop_handle_bio(struc
* once kthread_should_stop() is true and lo_bio is NULL, we are
* done with the loop.
*/
-static int loop_thread(void *data)
+static int loop_thread(struct loop_device *lo)
{
- struct loop_device *lo = data;
struct bio *bio;
set_user_nice(current, -20);
diff -r 110aa94129d0 drivers/block/pktcdvd.c
--- a/drivers/block/pktcdvd.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/block/pktcdvd.c Fri Jan 18 11:31:48 2008 +1100
@@ -1595,9 +1595,8 @@ static void pkt_count_states(struct pktc
* kcdrwd is woken up when writes have been queued for one of our
* registered devices
*/
-static int kcdrwd(void *foobar)
+static int kcdrwd(struct pktcdvd_device *pd)
{
- struct pktcdvd_device *pd = foobar;
struct packet_data *pkt;
long min_sleep_time, residue;
diff -r 110aa94129d0 drivers/char/ipmi/ipmi_si_intf.c
--- a/drivers/char/ipmi/ipmi_si_intf.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/char/ipmi/ipmi_si_intf.c Fri Jan 18 11:31:48 2008 +1100
@@ -867,9 +867,8 @@ static void set_run_to_completion(void *
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
}
-static int ipmi_thread(void *data)
+static int ipmi_thread(struct smi_info *smi_info)
{
- struct smi_info *smi_info = data;
unsigned long flags;
enum si_sm_result smi_result;
diff -r 110aa94129d0 drivers/ieee1394/nodemgr.c
--- a/drivers/ieee1394/nodemgr.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/ieee1394/nodemgr.c Fri Jan 18 11:31:48 2008 +1100
@@ -1686,9 +1686,8 @@ static int nodemgr_check_irm_capability(
return 1;
}
-static int nodemgr_host_thread(void *__hi)
+static int nodemgr_host_thread(struct host_info *hi)
{
- struct host_info *hi = (struct host_info *)__hi;
struct hpsb_host *host = hi->host;
unsigned int g, generation = 0;
int i, reset_cycles = 0;
diff -r 110aa94129d0 drivers/infiniband/core/fmr_pool.c
--- a/drivers/infiniband/core/fmr_pool.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/infiniband/core/fmr_pool.c Fri Jan 18 11:31:48 2008 +1100
@@ -177,10 +177,8 @@ static void ib_fmr_batch_release(struct
spin_unlock_irq(&pool->pool_lock);
}
-static int ib_fmr_cleanup_thread(void *pool_ptr)
+static int ib_fmr_cleanup_thread(struct ib_fmr_pool *pool)
{
- struct ib_fmr_pool *pool = pool_ptr;
-
do {
if (pool->dirty_len >= pool->dirty_watermark ||
atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) {
diff -r 110aa94129d0 drivers/input/touchscreen/ucb1400_ts.c
--- a/drivers/input/touchscreen/ucb1400_ts.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/input/touchscreen/ucb1400_ts.c Fri Jan 18 11:31:48 2008 +1100
@@ -282,9 +282,8 @@ static void ucb1400_handle_pending_irq(s
enable_irq(ucb->irq);
}
-static int ucb1400_ts_thread(void *_ucb)
+static int ucb1400_ts_thread(struct ucb1400 *ucb)
{
- struct ucb1400 *ucb = _ucb;
struct task_struct *tsk = current;
int valid = 0;
struct sched_param param = { .sched_priority = 1 };
diff -r 110aa94129d0 drivers/md/md.c
--- a/drivers/md/md.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/md/md.c Fri Jan 18 11:31:48 2008 +1100
@@ -4643,10 +4643,8 @@ static struct block_device_operations md
.revalidate_disk= md_revalidate,
};
-static int md_thread(void * arg)
-{
- mdk_thread_t *thread = arg;
-
+static int md_thread(mdk_thread_t *thread)
+{
/*
* md_thread is a 'system-thread', it's priority should be very
* high. We avoid resource deadlocks individually in each
diff -r 110aa94129d0 drivers/media/dvb/dvb-core/dvb_ca_en50221.c
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c Fri Jan 18 11:31:48 2008 +1100
@@ -955,9 +955,8 @@ static void dvb_ca_en50221_thread_update
/**
* Kernel thread which monitors CA slots for CAM changes, and performs data transfers.
*/
-static int dvb_ca_en50221_thread(void *data)
+static int dvb_ca_en50221_thread(struct dvb_ca_private *ca)
{
- struct dvb_ca_private *ca = data;
int slot;
int flags;
int status;
diff -r 110aa94129d0 drivers/media/dvb/dvb-core/dvb_frontend.c
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c Fri Jan 18 11:31:48 2008 +1100
@@ -503,9 +503,8 @@ static void dvb_frontend_wakeup(struct d
wake_up_interruptible(&fepriv->wait_queue);
}
-static int dvb_frontend_thread(void *data)
+static int dvb_frontend_thread(struct dvb_frontend *fe)
{
- struct dvb_frontend *fe = data;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
unsigned long timeout;
fe_status_t s;
diff -r 110aa94129d0 drivers/media/video/cx88/cx88-tvaudio.c
--- a/drivers/media/video/cx88/cx88-tvaudio.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/media/video/cx88/cx88-tvaudio.c Fri Jan 18 11:31:48 2008 +1100
@@ -907,9 +907,8 @@ void cx88_set_stereo(struct cx88_core *c
return;
}
-int cx88_audio_thread(void *data)
+int cx88_audio_thread(struct cx88_core *core)
{
- struct cx88_core *core = data;
struct v4l2_tuner t;
u32 mode = 0;
diff -r 110aa94129d0 drivers/media/video/cx88/cx88.h
--- a/drivers/media/video/cx88/cx88.h Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/media/video/cx88/cx88.h Fri Jan 18 11:31:48 2008 +1100
@@ -609,7 +609,7 @@ void cx88_newstation(struct cx88_core *c
void cx88_newstation(struct cx88_core *core);
void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t);
void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual);
-int cx88_audio_thread(void *data);
+int cx88_audio_thread(struct cx88_core *core);
int cx8802_register_driver(struct cx8802_driver *drv);
int cx8802_unregister_driver(struct cx8802_driver *drv);
diff -r 110aa94129d0 drivers/media/video/msp3400-driver.c
--- a/drivers/media/video/msp3400-driver.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/media/video/msp3400-driver.c Fri Jan 18 11:31:48 2008 +1100
@@ -805,7 +805,7 @@ static int msp_attach(struct i2c_adapter
{
struct i2c_client *client;
struct msp_state *state;
- int (*thread_func)(void *data) = NULL;
+ int (*thread_func)(struct i2c_client *client) = NULL;
int msp_hard;
int msp_family;
int msp_revision;
diff -r 110aa94129d0 drivers/media/video/msp3400-driver.h
--- a/drivers/media/video/msp3400-driver.h Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/media/video/msp3400-driver.h Fri Jan 18 11:31:48 2008 +1100
@@ -110,9 +110,9 @@ const char *msp_standard_std_name(int st
const char *msp_standard_std_name(int std);
void msp_set_audmode(struct i2c_client *client);
int msp_detect_stereo(struct i2c_client *client);
-int msp3400c_thread(void *data);
-int msp3410d_thread(void *data);
-int msp34xxg_thread(void *data);
+int msp3400c_thread(struct i2c_client *client);
+int msp3410d_thread(struct i2c_client *client);
+int msp34xxg_thread(struct i2c_client *client);
void msp3400c_set_mode(struct i2c_client *client, int mode);
void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2);
diff -r 110aa94129d0 drivers/media/video/msp3400-kthreads.c
--- a/drivers/media/video/msp3400-kthreads.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/media/video/msp3400-kthreads.c Fri Jan 18 11:31:48 2008 +1100
@@ -460,9 +460,8 @@ static void watch_stereo(struct i2c_clie
state->watch_stereo = 0;
}
-int msp3400c_thread(void *data)
+int msp3400c_thread(struct i2c_client *client)
{
- struct i2c_client *client = data;
struct msp_state *state = i2c_get_clientdata(client);
struct msp3400c_carrier_detect *cd;
int count, max1, max2, val1, val2, val, this;
@@ -641,9 +640,8 @@ int msp3400c_thread(void *data)
}
-int msp3410d_thread(void *data)
+int msp3410d_thread(struct i2c_client *client)
{
- struct i2c_client *client = data;
struct msp_state *state = i2c_get_clientdata(client);
int val, i, std, count;
@@ -935,9 +933,8 @@ static void msp34xxg_reset(struct i2c_cl
msp_write_dem(client, 0x22, msp_stereo_thresh);
}
-int msp34xxg_thread(void *data)
+int msp34xxg_thread(struct i2c_client *client)
{
- struct i2c_client *client = data;
struct msp_state *state = i2c_get_clientdata(client);
int val, i;
diff -r 110aa94129d0 drivers/media/video/saa7134/saa7134-tvaudio.c
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c Fri Jan 18 11:31:48 2008 +1100
@@ -496,9 +496,8 @@ static int tvaudio_setstereo(struct saa7
return 0;
}
-static int tvaudio_thread(void *data)
+static int tvaudio_thread(struct saa7134_dev *dev)
{
- struct saa7134_dev *dev = data;
int carr_vals[ARRAY_SIZE(mainscan)];
unsigned int i, audio, nscan;
int max1,max2,carrier,rx,mode,lastmode,default_carrier;
@@ -781,9 +780,8 @@ static int mute_input_7133(struct saa713
return 0;
}
-static int tvaudio_thread_ddep(void *data)
+static int tvaudio_thread_ddep(struct saa7134_dev *dev)
{
- struct saa7134_dev *dev = data;
u32 value, norms, clock;
@@ -980,7 +978,7 @@ int saa7134_tvaudio_getstereo(struct saa
int saa7134_tvaudio_init2(struct saa7134_dev *dev)
{
- int (*my_thread)(void *data) = NULL;
+ int (*my_thread)(struct saa7134_dev *) = NULL;
switch (dev->pci->device) {
case PCI_DEVICE_ID_PHILIPS_SAA7134:
diff -r 110aa94129d0 drivers/media/video/tvaudio.c
--- a/drivers/media/video/tvaudio.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/media/video/tvaudio.c Fri Jan 18 11:31:48 2008 +1100
@@ -264,9 +264,8 @@ static void chip_thread_wake(unsigned lo
wake_up_process(chip->thread);
}
-static int chip_thread(void *data)
+static int chip_thread(struct CHIPSTATE *chip)
{
- struct CHIPSTATE *chip = data;
struct CHIPDESC *desc = chiplist + chip->type;
v4l_dbg(1, debug, &chip->c, "%s: thread started\n", chip->c.name);
diff -r 110aa94129d0 drivers/media/video/videobuf-dvb.c
--- a/drivers/media/video/videobuf-dvb.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/media/video/videobuf-dvb.c Fri Jan 18 11:31:48 2008 +1100
@@ -39,9 +39,8 @@ MODULE_PARM_DESC(debug,"enable debug mes
/* ------------------------------------------------------------------ */
-static int videobuf_dvb_thread(void *data)
+static int videobuf_dvb_thread(struct videobuf_dvb *dvb)
{
- struct videobuf_dvb *dvb = data;
struct videobuf_buffer *buf;
unsigned long flags;
int err;
diff -r 110aa94129d0 drivers/media/video/vivi.c
--- a/drivers/media/video/vivi.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/media/video/vivi.c Fri Jan 18 11:31:48 2008 +1100
@@ -455,10 +455,8 @@ static void vivi_sleep(struct vivi_dmaqu
try_to_freeze();
}
-static int vivi_thread(void *data)
+static int vivi_thread(struct vivi_dmaqueue *dma_q)
{
- struct vivi_dmaqueue *dma_q=data;
-
dprintk(1,"thread started\n");
mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
diff -r 110aa94129d0 drivers/mmc/card/queue.c
--- a/drivers/mmc/card/queue.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/mmc/card/queue.c Fri Jan 18 11:31:48 2008 +1100
@@ -41,9 +41,8 @@ static int mmc_prep_request(struct reque
return BLKPREP_OK;
}
-static int mmc_queue_thread(void *d)
+static int mmc_queue_thread(struct mmc_queue *mq)
{
- struct mmc_queue *mq = d;
struct request_queue *q = mq->queue;
current->flags |= PF_MEMALLOC;
diff -r 110aa94129d0 drivers/mmc/core/sdio_irq.c
--- a/drivers/mmc/core/sdio_irq.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/mmc/core/sdio_irq.c Fri Jan 18 11:31:48 2008 +1100
@@ -63,9 +63,8 @@ static int process_sdio_pending_irqs(str
return ret;
}
-static int sdio_irq_thread(void *_host)
+static int sdio_irq_thread(struct mmc_host *host)
{
- struct mmc_host *host = _host;
struct sched_param param = { .sched_priority = 1 };
unsigned long period, idle_period;
int ret;
diff -r 110aa94129d0 drivers/mtd/mtd_blkdevs.c
--- a/drivers/mtd/mtd_blkdevs.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/mtd/mtd_blkdevs.c Fri Jan 18 11:31:48 2008 +1100
@@ -74,9 +74,8 @@ static int do_blktrans_request(struct mt
}
}
-static int mtd_blktrans_thread(void *arg)
+static int mtd_blktrans_thread(struct mtd_blktrans_ops *tr)
{
- struct mtd_blktrans_ops *tr = arg;
struct request_queue *rq = tr->blkcore_priv->rq;
/* we might get involved when memory gets low, so use PF_MEMALLOC */
diff -r 110aa94129d0 drivers/mtd/ubi/wl.c
--- a/drivers/mtd/ubi/wl.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/mtd/ubi/wl.c Fri Jan 18 11:31:48 2008 +1100
@@ -1303,10 +1303,9 @@ static void tree_destroy(struct rb_root
* ubi_thread - UBI background thread.
* @u: the UBI device description object pointer
*/
-static int ubi_thread(void *u)
+static int ubi_thread(struct ubi_device *ubi)
{
int failures = 0;
- struct ubi_device *ubi = u;
ubi_msg("background thread \"%s\" started, PID %d",
ubi->bgt_name, task_pid_nr(current));
diff -r 110aa94129d0 drivers/net/irda/stir4200.c
--- a/drivers/net/irda/stir4200.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/net/irda/stir4200.c Fri Jan 18 11:31:48 2008 +1100
@@ -732,9 +732,8 @@ static void stir_send(struct stir_cb *st
/*
* Transmit state machine thread
*/
-static int stir_transmit_thread(void *arg)
+static int stir_transmit_thread(struct stir_cb *stir)
{
- struct stir_cb *stir = arg;
struct net_device *dev = stir->netdev;
struct sk_buff *skb;
diff -r 110aa94129d0 drivers/net/wireless/airo.c
--- a/drivers/net/wireless/airo.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/net/wireless/airo.c Fri Jan 18 11:31:48 2008 +1100
@@ -1123,7 +1123,7 @@ static int waitbusy (struct airo_info *a
static int waitbusy (struct airo_info *ai);
static irqreturn_t airo_interrupt( int irq, void* dev_id);
-static int airo_thread(void *data);
+static int airo_thread(struct net_device *dev);
static void timer_func( struct net_device *dev );
static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static struct iw_statistics *airo_get_wireless_stats (struct net_device *dev);
@@ -3080,8 +3080,7 @@ out:
wireless_send_event(ai->dev, SIOCGIWSCAN, &wrqu, NULL);
}
-static int airo_thread(void *data) {
- struct net_device *dev = data;
+static int airo_thread(struct net_device *dev) {
struct airo_info *ai = dev->priv;
int locked;
diff -r 110aa94129d0 drivers/net/wireless/libertas/main.c
--- a/drivers/net/wireless/libertas/main.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/net/wireless/libertas/main.c Fri Jan 18 11:31:48 2008 +1100
@@ -752,9 +752,8 @@ static void libertas_set_multicast_list(
* @param data A pointer to wlan_thread structure
* @return 0
*/
-static int libertas_thread(void *data)
+static int libertas_thread(struct net_device *dev)
{
- struct net_device *dev = data;
wlan_private *priv = dev->priv;
wlan_adapter *adapter = priv->adapter;
wait_queue_t wait;
diff -r 110aa94129d0 drivers/pcmcia/cs.c
--- a/drivers/pcmcia/cs.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/pcmcia/cs.c Fri Jan 18 11:31:48 2008 +1100
@@ -170,7 +170,7 @@ static void pcmcia_release_socket(struct
complete(&socket->socket_released);
}
-static int pccardd(void *__skt);
+static int pccardd(struct pcmcia_socket *skt);
/**
* pcmcia_register_socket - add a new pcmcia socket device
@@ -632,9 +632,8 @@ static void socket_detect_change(struct
}
}
-static int pccardd(void *__skt)
+static int pccardd(struct pcmcia_socket *skt)
{
- struct pcmcia_socket *skt = __skt;
DECLARE_WAITQUEUE(wait, current);
int ret;
diff -r 110aa94129d0 drivers/scsi/aacraid/aacraid.h
--- a/drivers/scsi/aacraid/aacraid.h Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/scsi/aacraid/aacraid.h Fri Jan 18 11:31:48 2008 +1100
@@ -1851,7 +1851,7 @@ unsigned int aac_intr_normal(struct aac_
unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index);
int aac_reset_adapter(struct aac_dev * dev, int forced);
int aac_check_health(struct aac_dev * dev);
-int aac_command_thread(void *data);
+int aac_command_thread(struct aac_dev * dev);
int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx);
int aac_fib_adapter_complete(struct fib * fibptr, unsigned short size);
struct aac_driver_ident* aac_get_driver_ident(int devtype);
diff -r 110aa94129d0 drivers/scsi/aacraid/commsup.c
--- a/drivers/scsi/aacraid/commsup.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/scsi/aacraid/commsup.c Fri Jan 18 11:31:49 2008 +1100
@@ -1400,9 +1400,8 @@ out:
* more FIBs.
*/
-int aac_command_thread(void *data)
+int aac_command_thread(struct aac_dev *dev)
{
- struct aac_dev *dev = data;
struct hw_fib *hw_fib, *hw_newfib;
struct fib *fib, *newfib;
struct aac_fib_context *fibctx;
diff -r 110aa94129d0 drivers/scsi/libsas/sas_scsi_host.c
--- a/drivers/scsi/libsas/sas_scsi_host.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/scsi/libsas/sas_scsi_host.c Fri Jan 18 11:31:49 2008 +1100
@@ -900,10 +900,8 @@ static void sas_queue(struct sas_ha_stru
* sas_queue_thread -- The Task Collector thread
* @_sas_ha: pointer to struct sas_ha
*/
-static int sas_queue_thread(void *_sas_ha)
+static int sas_queue_thread(struct sas_ha_struct *sas_ha)
{
- struct sas_ha_struct *sas_ha = _sas_ha;
-
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
schedule();
diff -r 110aa94129d0 drivers/scsi/lpfc/lpfc_crtn.h
--- a/drivers/scsi/lpfc/lpfc_crtn.h Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/scsi/lpfc/lpfc_crtn.h Fri Jan 18 11:31:49 2008 +1100
@@ -78,7 +78,7 @@ struct lpfc_nodelist *lpfc_findnode_rpi(
void lpfc_worker_wake_up(struct lpfc_hba *);
int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t);
-int lpfc_do_work(void *);
+int lpfc_do_work(struct lpfc_hba *phba);
int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *,
uint32_t);
diff -r 110aa94129d0 drivers/scsi/lpfc/lpfc_hbadisc.c
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c Fri Jan 18 11:31:49 2008 +1100
@@ -470,9 +470,8 @@ check_work_wait_done(struct lpfc_hba *ph
int
-lpfc_do_work(void *p)
+lpfc_do_work(struct lpfc_hba *phba)
{
- struct lpfc_hba *phba = p;
int rc;
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(work_waitq);
diff -r 110aa94129d0 drivers/scsi/qla2xxx/qla_os.c
--- a/drivers/scsi/qla2xxx/qla_os.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/scsi/qla2xxx/qla_os.c Fri Jan 18 11:31:49 2008 +1100
@@ -210,7 +210,7 @@ qla2x00_stop_timer(scsi_qla_host_t *ha)
ha->timer_active = 0;
}
-static int qla2x00_do_dpc(void *data);
+static int qla2x00_do_dpc(scsi_qla_host_t *ha);
static void qla2x00_rst_aen(scsi_qla_host_t *);
@@ -2360,15 +2360,12 @@ qla2x00_free_sp_pool( scsi_qla_host_t *h
* bits then wake us up.
**************************************************************************/
static int
-qla2x00_do_dpc(void *data)
+qla2x00_do_dpc(scsi_qla_host_t *ha)
{
int rval;
- scsi_qla_host_t *ha;
fc_port_t *fcport;
uint8_t status;
uint16_t next_loopid;
-
- ha = (scsi_qla_host_t *)data;
set_user_nice(current, -20);
diff -r 110aa94129d0 drivers/scsi/scsi_error.c
--- a/drivers/scsi/scsi_error.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/scsi/scsi_error.c Fri Jan 18 11:31:49 2008 +1100
@@ -1541,10 +1541,8 @@ static void scsi_unjam_host(struct Scsi_
* This is the main error handling loop. This is run as a kernel thread
* for every SCSI host and handles all error handling activity.
**/
-int scsi_error_handler(void *data)
+int scsi_error_handler(struct Scsi_Host *shost)
{
- struct Scsi_Host *shost = data;
-
/*
* We use TASK_INTERRUPTIBLE so that the thread is not
* counted against the load average as a running process.
diff -r 110aa94129d0 drivers/scsi/scsi_priv.h
--- a/drivers/scsi/scsi_priv.h Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/scsi/scsi_priv.h Fri Jan 18 11:31:49 2008 +1100
@@ -53,7 +53,7 @@ extern void scsi_add_timer(struct scsi_c
void (*)(struct scsi_cmnd *));
extern int scsi_delete_timer(struct scsi_cmnd *);
extern void scsi_times_out(struct scsi_cmnd *cmd);
-extern int scsi_error_handler(void *host);
+extern int scsi_error_handler(struct Scsi_Host *shost);
extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
extern void scsi_eh_wakeup(struct Scsi_Host *shost);
extern int scsi_eh_scmd_add(struct scsi_cmnd *, int);
diff -r 110aa94129d0 drivers/scsi/scsi_scan.c
--- a/drivers/scsi/scsi_scan.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/scsi/scsi_scan.c Fri Jan 18 11:31:49 2008 +1100
@@ -1788,9 +1788,8 @@ static void do_scsi_scan_host(struct Scs
}
}
-static int do_scan_async(void *_data)
+static int do_scan_async(struct async_scan_data *data)
{
- struct async_scan_data *data = _data;
do_scsi_scan_host(data->shost);
scsi_finish_async_scan(data);
return 0;
diff -r 110aa94129d0 drivers/usb/atm/ueagle-atm.c
--- a/drivers/usb/atm/ueagle-atm.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/usb/atm/ueagle-atm.c Fri Jan 18 11:31:49 2008 +1100
@@ -1868,9 +1868,8 @@ static int uea_start_reset(struct uea_so
* Monitor the modem every 1s.
*/
-static int uea_kthread(void *data)
+static int uea_kthread(struct uea_softc *sc)
{
- struct uea_softc *sc = data;
int ret = -EAGAIN;
set_freezable();
diff -r 110aa94129d0 drivers/usb/gadget/file_storage.c
--- a/drivers/usb/gadget/file_storage.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/usb/gadget/file_storage.c Fri Jan 18 11:31:49 2008 +1100
@@ -3383,10 +3383,8 @@ static void handle_exception(struct fsg_
/*-------------------------------------------------------------------------*/
-static int fsg_main_thread(void *fsg_)
-{
- struct fsg_dev *fsg = fsg_;
-
+static int fsg_main_thread(struct fsg_dev *fsg)
+{
/* Allow the thread to be killed by a signal, but set the signal mask
* to block everything but INT, TERM, KILL, and USR1. */
allow_signal(SIGINT);
diff -r 110aa94129d0 drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/usb/storage/usb.c Fri Jan 18 11:31:49 2008 +1100
@@ -302,9 +302,8 @@ void fill_inquiry_response(struct us_dat
usb_stor_set_xfer_buf(data, data_len, us->srb);
}
-static int usb_stor_control_thread(void * __us)
+static int usb_stor_control_thread(struct us_data *us)
{
- struct us_data *us = (struct us_data *)__us;
struct Scsi_Host *host = us_to_host(us);
for(;;) {
@@ -895,10 +894,8 @@ static void release_everything(struct us
}
/* Thread to carry out delayed SCSI-device scanning */
-static int usb_stor_scan_thread(void * __us)
+static int usb_stor_scan_thread(struct us_data *us)
{
- struct us_data *us = (struct us_data *)__us;
-
printk(KERN_DEBUG
"usb-storage: device found at %d\n", us->pusb_dev->devnum);
diff -r 110aa94129d0 drivers/w1/w1.c
--- a/drivers/w1/w1.c Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/w1/w1.c Fri Jan 18 11:31:49 2008 +1100
@@ -879,10 +879,8 @@ void w1_search_process(struct w1_master
dev->search_count--;
}
-int w1_process(void *data)
+int w1_process(struct w1_master *dev)
{
- struct w1_master *dev = (struct w1_master *) data;
-
while (!kthread_should_stop() && !test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) {
try_to_freeze();
msleep_interruptible(w1_timeout * 1000);
diff -r 110aa94129d0 drivers/w1/w1.h
--- a/drivers/w1/w1.h Fri Jan 18 10:32:31 2008 +1100
+++ b/drivers/w1/w1.h Fri Jan 18 11:31:49 2008 +1100
@@ -217,7 +217,7 @@ extern struct list_head w1_masters;
extern struct list_head w1_masters;
extern struct mutex w1_mlock;
-extern int w1_process(void *);
+extern int w1_process(struct w1_master *);
#endif /* __KERNEL__ */
diff -r 110aa94129d0 fs/dlm/recoverd.c
--- a/fs/dlm/recoverd.c Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/dlm/recoverd.c Fri Jan 18 11:31:49 2008 +1100
@@ -260,7 +260,7 @@ static void do_ls_recovery(struct dlm_ls
}
}
-static int dlm_recoverd(void *arg)
+static int dlm_recoverd(dlm_lockspace_t *arg)
{
struct dlm_ls *ls;
@@ -295,7 +295,7 @@ int dlm_recoverd_start(struct dlm_ls *ls
struct task_struct *p;
int error = 0;
- p = kthread_run(dlm_recoverd, ls, "dlm_recoverd");
+ p = kthread_run(dlm_recoverd, (dlm_lockspace_t *)ls, "dlm_recoverd");
if (IS_ERR(p))
error = PTR_ERR(p);
else
diff -r 110aa94129d0 fs/gfs2/daemon.c
--- a/fs/gfs2/daemon.c Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/gfs2/daemon.c Fri Jan 18 11:31:49 2008 +1100
@@ -42,10 +42,8 @@
* Number of daemons can be set by user, with num_glockd mount option.
*/
-int gfs2_glockd(void *data)
+int gfs2_glockd(struct gfs2_sbd *sdp)
{
- struct gfs2_sbd *sdp = data;
-
while (!kthread_should_stop()) {
while (atomic_read(&sdp->sd_reclaim_count))
gfs2_reclaim_glock(sdp);
@@ -66,9 +64,8 @@ int gfs2_glockd(void *data)
*
*/
-int gfs2_recoverd(void *data)
+int gfs2_recoverd(struct gfs2_sbd *sdp)
{
- struct gfs2_sbd *sdp = data;
unsigned long t;
while (!kthread_should_stop()) {
@@ -90,9 +87,8 @@ int gfs2_recoverd(void *data)
* journal index.
*/
-int gfs2_logd(void *data)
+int gfs2_logd(struct gfs2_sbd *sdp)
{
- struct gfs2_sbd *sdp = data;
struct gfs2_holder ji_gh;
unsigned long t;
int need_flush;
@@ -138,9 +134,8 @@ int gfs2_logd(void *data)
*
*/
-int gfs2_quotad(void *data)
+int gfs2_quotad(struct gfs2_sbd *sdp)
{
- struct gfs2_sbd *sdp = data;
unsigned long t;
int error;
diff -r 110aa94129d0 fs/gfs2/daemon.h
--- a/fs/gfs2/daemon.h Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/gfs2/daemon.h Fri Jan 18 11:31:49 2008 +1100
@@ -10,9 +10,9 @@
#ifndef __DAEMON_DOT_H__
#define __DAEMON_DOT_H__
-int gfs2_glockd(void *data);
-int gfs2_recoverd(void *data);
-int gfs2_logd(void *data);
-int gfs2_quotad(void *data);
+int gfs2_glockd(struct gfs2_sbd *sdp);
+int gfs2_recoverd(struct gfs2_sbd *sdp);
+int gfs2_logd(struct gfs2_sbd *sdp);
+int gfs2_quotad(struct gfs2_sbd *sdp);
#endif /* __DAEMON_DOT_H__ */
diff -r 110aa94129d0 fs/gfs2/locking/dlm/thread.c
--- a/fs/gfs2/locking/dlm/thread.c Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/gfs2/locking/dlm/thread.c Fri Jan 18 11:31:49 2008 +1100
@@ -268,9 +268,8 @@ static inline int check_drop(struct gdlm
return 0;
}
-static int gdlm_thread(void *data, int blist)
+static int gdlm_thread(struct gdlm_ls *ls, int blist)
{
- struct gdlm_ls *ls = (struct gdlm_ls *) data;
struct gdlm_lock *lp = NULL;
uint8_t complete, blocking, submit, drop;
DECLARE_WAITQUEUE(wait, current);
@@ -329,14 +328,14 @@ static int gdlm_thread(void *data, int b
return 0;
}
-static int gdlm_thread1(void *data)
+static int gdlm_thread1(struct gdlm_ls *ls)
{
- return gdlm_thread(data, 1);
+ return gdlm_thread(ls, 1);
}
-static int gdlm_thread2(void *data)
+static int gdlm_thread2(struct gdlm_ls *ls)
{
- return gdlm_thread(data, 0);
+ return gdlm_thread(ls, 0);
}
int gdlm_init_threads(struct gdlm_ls *ls)
diff -r 110aa94129d0 fs/jbd/journal.c
--- a/fs/jbd/journal.c Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/jbd/journal.c Fri Jan 18 11:31:49 2008 +1100
@@ -112,9 +112,8 @@ static void commit_timeout(unsigned long
* known as checkpointing, and this thread is responsible for that job.
*/
-static int kjournald(void *arg)
+static int kjournald(journal_t *journal)
{
- journal_t *journal = arg;
transaction_t *transaction;
/*
diff -r 110aa94129d0 fs/jbd2/journal.c
--- a/fs/jbd2/journal.c Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/jbd2/journal.c Fri Jan 18 11:31:49 2008 +1100
@@ -112,9 +112,8 @@ static void commit_timeout(unsigned long
* known as checkpointing, and this thread is responsible for that job.
*/
-static int kjournald2(void *arg)
+static int kjournald2(journal_t *journal)
{
- journal_t *journal = arg;
transaction_t *transaction;
/*
diff -r 110aa94129d0 fs/nfs/delegation.c
--- a/fs/nfs/delegation.c Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/nfs/delegation.c Fri Jan 18 11:31:49 2008 +1100
@@ -275,9 +275,8 @@ restart:
rcu_read_unlock();
}
-static int nfs_do_expire_all_delegations(void *ptr)
+static int nfs_do_expire_all_delegations(struct nfs_client *clp)
{
- struct nfs_client *clp = ptr;
struct nfs_delegation *delegation;
struct inode *inode;
diff -r 110aa94129d0 fs/nfs/nfs4state.c
--- a/fs/nfs/nfs4state.c Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/nfs/nfs4state.c Fri Jan 18 11:31:49 2008 +1100
@@ -738,7 +738,7 @@ out:
return status;
}
-static int reclaimer(void *);
+static int reclaimer(struct nfs_client *clp);
static inline void nfs4_clear_recover_bit(struct nfs_client *clp)
{
@@ -895,9 +895,8 @@ static void nfs4_state_mark_reclaim(stru
}
}
-static int reclaimer(void *ptr)
+static int reclaimer(struct nfs_client *clp)
{
- struct nfs_client *clp = ptr;
struct nfs4_state_owner *sp;
struct rb_node *pos;
struct nfs4_state_recovery_ops *ops;
diff -r 110aa94129d0 fs/nfsd/nfs4callback.c
--- a/fs/nfsd/nfs4callback.c Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/nfsd/nfs4callback.c Fri Jan 18 11:31:49 2008 +1100
@@ -347,9 +347,8 @@ static struct rpc_version * nfs_cb_versi
/* Reference counting, callback cleanup, etc., all look racy as heck.
* And why is cb_set an atomic? */
-static int do_probe_callback(void *data)
+static int do_probe_callback(struct nfs4_client *clp)
{
- struct nfs4_client *clp = data;
struct nfs4_callback *cb = &clp->cl_callback;
struct rpc_message msg = {
.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
diff -r 110aa94129d0 fs/nfsd/nfs4state.c
--- a/fs/nfsd/nfs4state.c Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/nfsd/nfs4state.c Fri Jan 18 11:31:49 2008 +1100
@@ -1312,10 +1312,8 @@ nfs4_file_downgrade(struct file *filp, u
* Recall a delegation
*/
static int
-do_recall(void *__dp)
+do_recall(struct nfs4_delegation *dp)
{
- struct nfs4_delegation *dp = __dp;
-
dp->dl_file->fi_had_conflict = true;
nfsd4_cb_recall(dp);
return 0;
diff -r 110aa94129d0 fs/ocfs2/cluster/heartbeat.c
--- a/fs/ocfs2/cluster/heartbeat.c Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/ocfs2/cluster/heartbeat.c Fri Jan 18 11:31:49 2008 +1100
@@ -840,10 +840,9 @@ static unsigned int o2hb_elapsed_msecs(s
* dir is removed and drops it ref it will wait to tear down this
* thread.
*/
-static int o2hb_thread(void *data)
+static int o2hb_thread(struct o2hb_region *reg)
{
int i, ret;
- struct o2hb_region *reg = data;
struct o2hb_bio_wait_ctxt write_wc;
struct timeval before_hb, after_hb;
unsigned int elapsed_msec;
diff -r 110aa94129d0 fs/ocfs2/dlm/dlmrecovery.c
--- a/fs/ocfs2/dlm/dlmrecovery.c Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/ocfs2/dlm/dlmrecovery.c Fri Jan 18 11:31:49 2008 +1100
@@ -55,7 +55,7 @@
static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node);
-static int dlm_recovery_thread(void *data);
+static int dlm_recovery_thread(struct dlm_ctxt *dlm);
void dlm_complete_recovery_thread(struct dlm_ctxt *dlm);
int dlm_launch_recovery_thread(struct dlm_ctxt *dlm);
void dlm_kick_recovery_thread(struct dlm_ctxt *dlm);
@@ -302,10 +302,9 @@ static void dlm_print_reco_node_status(s
#define DLM_RECO_THREAD_TIMEOUT_MS (5 * 1000)
-static int dlm_recovery_thread(void *data)
+static int dlm_recovery_thread(struct dlm_ctxt *dlm)
{
int status;
- struct dlm_ctxt *dlm = data;
unsigned long timeout = msecs_to_jiffies(DLM_RECO_THREAD_TIMEOUT_MS);
mlog(0, "dlm thread running for %s...\n", dlm->name);
diff -r 110aa94129d0 fs/ocfs2/dlm/dlmthread.c
--- a/fs/ocfs2/dlm/dlmthread.c Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/ocfs2/dlm/dlmthread.c Fri Jan 18 11:31:49 2008 +1100
@@ -53,7 +53,7 @@
#define MLOG_MASK_PREFIX (ML_DLM|ML_DLM_THREAD)
#include "cluster/masklog.h"
-static int dlm_thread(void *data);
+static int dlm_thread(struct dlm_ctxt *dlm);
static void dlm_flush_asts(struct dlm_ctxt *dlm);
#define dlm_lock_is_remote(dlm, lock) ((lock)->ml.node != (dlm)->node_num)
@@ -608,10 +608,9 @@ static void dlm_flush_asts(struct dlm_ct
#define DLM_THREAD_MAX_DIRTY 100
#define DLM_THREAD_MAX_ASTS 10
-static int dlm_thread(void *data)
+static int dlm_thread(struct dlm_ctxt *dlm)
{
struct dlm_lock_resource *res;
- struct dlm_ctxt *dlm = data;
unsigned long timeout = msecs_to_jiffies(DLM_THREAD_TIMEOUT_MS);
mlog(0, "dlm thread running for %s...\n", dlm->name);
diff -r 110aa94129d0 fs/ocfs2/journal.c
--- a/fs/ocfs2/journal.c Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/ocfs2/journal.c Fri Jan 18 11:31:49 2008 +1100
@@ -54,7 +54,7 @@ static int ocfs2_force_read_journal(stru
static int ocfs2_force_read_journal(struct inode *inode);
static int ocfs2_recover_node(struct ocfs2_super *osb,
int node_num);
-static int __ocfs2_recovery_thread(void *arg);
+static int __ocfs2_recovery_thread(struct ocfs2_super *osb);
static int ocfs2_commit_cache(struct ocfs2_super *osb);
static int ocfs2_wait_on_mount(struct ocfs2_super *osb);
static int ocfs2_journal_toggle_dirty(struct ocfs2_super *osb,
@@ -63,7 +63,7 @@ static int ocfs2_trylock_journal(struct
int slot_num);
static int ocfs2_recover_orphans(struct ocfs2_super *osb,
int slot);
-static int ocfs2_commit_thread(void *arg);
+static int ocfs2_commit_thread(struct ocfs2_super *osb);
static int ocfs2_commit_cache(struct ocfs2_super *osb)
{
@@ -841,10 +841,9 @@ void ocfs2_complete_mount_recovery(struc
}
}
-static int __ocfs2_recovery_thread(void *arg)
+static int __ocfs2_recovery_thread(struct ocfs2_super *osb)
{
int status, node_num;
- struct ocfs2_super *osb = arg;
mlog_entry_void();
@@ -1419,10 +1418,9 @@ static int ocfs2_wait_on_mount(struct oc
return 0;
}
-static int ocfs2_commit_thread(void *arg)
+static int ocfs2_commit_thread(struct ocfs2_super *osb)
{
int status;
- struct ocfs2_super *osb = arg;
struct ocfs2_journal *journal = osb->journal;
/* we can trust j_num_trans here because _should_stop() is only set in
diff -r 110aa94129d0 fs/ocfs2/vote.c
--- a/fs/ocfs2/vote.c Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/ocfs2/vote.c Fri Jan 18 11:31:49 2008 +1100
@@ -280,10 +280,9 @@ static int ocfs2_vote_thread_should_wake
return should_wake;
}
-int ocfs2_vote_thread(void *arg)
+int ocfs2_vote_thread(struct ocfs2_super *osb)
{
int status = 0;
- struct ocfs2_super *osb = arg;
/* only quit once we've been asked to stop and there is no more
* work available */
diff -r 110aa94129d0 fs/ocfs2/vote.h
--- a/fs/ocfs2/vote.h Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/ocfs2/vote.h Fri Jan 18 11:31:49 2008 +1100
@@ -27,7 +27,7 @@
#ifndef VOTE_H
#define VOTE_H
-int ocfs2_vote_thread(void *arg);
+int ocfs2_vote_thread(struct ocfs2_super *osb);
static inline void ocfs2_kick_vote_thread(struct ocfs2_super *osb)
{
spin_lock(&osb->vote_task_lock);
diff -r 110aa94129d0 fs/xfs/linux-2.6/xfs_buf.c
--- a/fs/xfs/linux-2.6/xfs_buf.c Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/xfs/linux-2.6/xfs_buf.c Fri Jan 18 11:31:49 2008 +1100
@@ -35,7 +35,7 @@
#include <linux/freezer.h>
static kmem_zone_t *xfs_buf_zone;
-STATIC int xfsbufd(void *);
+STATIC int xfsbufd(xfs_buftarg_t *);
STATIC int xfsbufd_wakeup(int, gfp_t);
STATIC void xfs_buf_delwri_queue(xfs_buf_t *, int);
static struct shrinker xfs_buf_shake = {
@@ -1734,10 +1734,9 @@ xfs_buf_delwri_split(
STATIC int
xfsbufd(
- void *data)
+ xfs_buftarg_t *target)
{
struct list_head tmp;
- xfs_buftarg_t *target = (xfs_buftarg_t *)data;
int count;
xfs_buf_t *bp;
diff -r 110aa94129d0 fs/xfs/linux-2.6/xfs_super.c
--- a/fs/xfs/linux-2.6/xfs_super.c Fri Jan 18 10:32:31 2008 +1100
+++ b/fs/xfs/linux-2.6/xfs_super.c Fri Jan 18 11:31:49 2008 +1100
@@ -549,9 +549,8 @@ xfs_sync_worker(
STATIC int
xfssyncd(
- void *arg)
+ struct xfs_mount *mp)
{
- struct xfs_mount *mp = arg;
long timeleft;
bhv_vfs_sync_work_t *work, *n;
LIST_HEAD (tmp);
diff -r 110aa94129d0 kernel/audit.c
--- a/kernel/audit.c Fri Jan 18 10:32:31 2008 +1100
+++ b/kernel/audit.c Fri Jan 18 11:31:49 2008 +1100
@@ -450,9 +450,8 @@ out:
return err;
}
-int audit_send_list(void *_dest)
+int audit_send_list(struct audit_netlink_list *dest)
{
- struct audit_netlink_list *dest = _dest;
int pid = dest->pid;
struct sk_buff *skb;
diff -r 110aa94129d0 kernel/audit.h
--- a/kernel/audit.h Fri Jan 18 10:32:31 2008 +1100
+++ b/kernel/audit.h Fri Jan 18 11:31:49 2008 +1100
@@ -126,7 +126,7 @@ struct audit_netlink_list {
struct sk_buff_head q;
};
-int audit_send_list(void *);
+int audit_send_list(struct audit_netlink_list *dest);
struct inotify_watch;
extern void audit_free_parent(struct inotify_watch *);
diff -r 110aa94129d0 kernel/rtmutex-tester.c
--- a/kernel/rtmutex-tester.c Fri Jan 18 10:32:31 2008 +1100
+++ b/kernel/rtmutex-tester.c Fri Jan 18 11:31:49 2008 +1100
@@ -254,9 +254,8 @@ void schedule_rt_mutex_test(struct rt_mu
td->opdata = dat;
}
-static int test_func(void *data)
+static int test_func(struct test_thread_data *td)
{
- struct test_thread_data *td = data;
int ret;
current->flags |= PF_MUTEX_TESTER;
diff -r 110aa94129d0 kernel/stop_machine.c
--- a/kernel/stop_machine.c Fri Jan 18 10:32:31 2008 +1100
+++ b/kernel/stop_machine.c Fri Jan 18 11:31:49 2008 +1100
@@ -143,9 +143,8 @@ struct stop_machine_data
struct completion done;
};
-static int do_stop(void *_smdata)
+static int do_stop(struct stop_machine_data *smdata)
{
- struct stop_machine_data *smdata = _smdata;
int ret;
ret = stop_machine();
diff -r 110aa94129d0 kernel/workqueue.c
--- a/kernel/workqueue.c Fri Jan 18 10:32:31 2008 +1100
+++ b/kernel/workqueue.c Fri Jan 18 11:31:49 2008 +1100
@@ -296,9 +296,8 @@ static void run_workqueue(struct cpu_wor
spin_unlock_irq(&cwq->lock);
}
-static int worker_thread(void *__cwq)
+static int worker_thread(struct cpu_workqueue_struct *cwq)
{
- struct cpu_workqueue_struct *cwq = __cwq;
DEFINE_WAIT(wait);
if (cwq->wq->freezeable)
diff -r 110aa94129d0 mm/vmscan.c
--- a/mm/vmscan.c Fri Jan 18 10:32:31 2008 +1100
+++ b/mm/vmscan.c Fri Jan 18 11:31:50 2008 +1100
@@ -1491,10 +1491,9 @@ out:
* If there are applications that are active memory-allocators
* (most normal use), this basically shouldn't matter.
*/
-static int kswapd(void *p)
+static int kswapd(pg_data_t *pgdat)
{
unsigned long order;
- pg_data_t *pgdat = (pg_data_t*)p;
struct task_struct *tsk = current;
DEFINE_WAIT(wait);
struct reclaim_state reclaim_state = {
diff -r 110aa94129d0 net/9p/mux.c
--- a/net/9p/mux.c Fri Jan 18 10:32:31 2008 +1100
+++ b/net/9p/mux.c Fri Jan 18 11:31:50 2008 +1100
@@ -106,7 +106,7 @@ struct p9_mux_rpc {
wait_queue_head_t wqueue;
};
-static int p9_poll_proc(void *);
+static int p9_poll_proc(struct p9_mux_poll_task *vpt);
static void p9_read_work(struct work_struct *work);
static void p9_write_work(struct work_struct *work);
static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address,
@@ -442,12 +442,10 @@ static void p9_poll_mux(struct p9_conn *
* p9_poll_proc - polls all v9fs transports for new events and queues
* the appropriate work to the work queue
*/
-static int p9_poll_proc(void *a)
+static int p9_poll_proc(struct p9_mux_poll_task *vpt)
{
struct p9_conn *m, *mtmp;
- struct p9_mux_poll_task *vpt;
- vpt = a;
P9_DPRINTK(P9_DEBUG_MUX, "start %p %p\n", current, vpt);
while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);
diff -r 110aa94129d0 net/core/pktgen.c
--- a/net/core/pktgen.c Fri Jan 18 10:32:31 2008 +1100
+++ b/net/core/pktgen.c Fri Jan 18 11:31:50 2008 +1100
@@ -3499,10 +3499,9 @@ out:;
* Main loop of the thread goes here
*/
-static int pktgen_thread_worker(void *arg)
+static int pktgen_thread_worker(struct pktgen_thread *t)
{
DEFINE_WAIT(wait);
- struct pktgen_thread *t = arg;
struct pktgen_dev *pkt_dev = NULL;
int cpu = t->cpu;
diff -r 110aa94129d0 sound/pci/emu10k1/emu10k1_main.c
--- a/sound/pci/emu10k1/emu10k1_main.c Fri Jan 18 10:32:31 2008 +1100
+++ b/sound/pci/emu10k1/emu10k1_main.c Fri Jan 18 11:31:50 2008 +1100
@@ -704,8 +704,7 @@ static int snd_emu1010_load_firmware(str
return 0;
}
-int emu1010_firmware_thread(void *data) {
- struct snd_emu10k1 * emu = data;
+int emu1010_firmware_thread(struct snd_emu10k1 * emu) {
int tmp,tmp2;
int reg;
int err;
To create functions which can take two types, but still warn on any
other types, we need a way of casting one type and no others.
To make things more complex, it should correctly handle function args,
NULL, and be usable in initializers.
Signed-off-by: Rusty Russell <[email protected]>
diff -r e6626cc7bdc2 include/linux/compiler-gcc.h
--- a/include/linux/compiler-gcc.h Sun Jan 20 18:51:51 2008 +1100
+++ b/include/linux/compiler-gcc.h Sun Jan 20 18:57:14 2008 +1100
@@ -53,3 +53,20 @@
#define noinline __attribute__((noinline))
#define __attribute_const__ __attribute__((__const__))
#define __maybe_unused __attribute__((unused))
+
+/**
+ * cast_if_type - allow an alternate type
+ * @expr: the expression to optionally cast
+ * @oktype: the type to allow.
+ * @desttype: the type to cast to.
+ *
+ * This is used to accept a particular alternate type for an expression:
+ * because any other types will not be cast, they will cause a warning as
+ * normal.
+ *
+ * Note that the unnecessary trinary forces functions to devolve into
+ * function pointers as users expect. */
+#define cast_if_type(expr, oktype, desttype) \
+ __builtin_choose_expr(__builtin_types_compatible_p(typeof(1?(expr):NULL), \
+ oktype), \
+ (desttype)(expr), (expr))
diff -r e6626cc7bdc2 include/linux/compiler-intel.h
--- a/include/linux/compiler-intel.h Sun Jan 20 18:51:51 2008 +1100
+++ b/include/linux/compiler-intel.h Sun Jan 20 18:57:14 2008 +1100
@@ -29,3 +29,5 @@
#endif
#define uninitialized_var(x) x
+
+#define cast_if_type(expr, oktype, desttype) ((desttype)(expr))
This patch lets interrupt handler functions have their natural type
(ie. exactly match the data pointer type); it allows the old irq_handler_t
type as well.
Signed-off-by: Rusty Russell <[email protected]>
---
include/linux/interrupt.h | 17 +++++++++++++++--
include/linux/kernel.h | 7 +++++++
kernel/irq/devres.c | 10 +++++-----
kernel/irq/manage.c | 6 +++---
4 files changed, 30 insertions(+), 10 deletions(-)
diff -r 0fe1a980708b include/linux/interrupt.h
--- a/include/linux/interrupt.h Thu Jan 17 14:48:56 2008 +1100
+++ b/include/linux/interrupt.h Thu Jan 17 15:42:01 2008 +1100
@@ -69,13 +69,26 @@ struct irqaction {
};
extern irqreturn_t no_action(int cpl, void *dev_id);
-extern int __must_check request_irq(unsigned int, irq_handler_t handler,
+
+/* Typesafe version of request_irq. Also takes old-style void * handlers. */
+#define request_irq(irq, handler, flags, name, dev_id) \
+ __request_irq((irq), \
+ cast_if_type((handler), int (*)(int, typeof(dev_id)), \
+ irq_handler_t), \
+ (flags), (name), (dev_id))
+
+extern int __must_check __request_irq(unsigned int, irq_handler_t handler,
unsigned long, const char *, void *);
extern void free_irq(unsigned int, void *);
struct device;
-extern int __must_check devm_request_irq(struct device *dev, unsigned int irq,
+#define devm_request_irq(dev, irq, handler, flags, name, dev_id) \
+ __devm_request_irq((dev), (irq), \
+ cast_if_type((handler), int (*)(int, typeof(dev_id)), \
+ irq_handler_t), \
+ (flags), (name), (dev_id))
+extern int __must_check __devm_request_irq(struct device *dev, unsigned int irq,
irq_handler_t handler, unsigned long irqflags,
const char *devname, void *dev_id);
extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id);
diff -r 0fe1a980708b kernel/irq/devres.c
--- a/kernel/irq/devres.c Thu Jan 17 14:48:56 2008 +1100
+++ b/kernel/irq/devres.c Thu Jan 17 15:42:01 2008 +1100
@@ -41,9 +41,9 @@ static int devm_irq_match(struct device
* If an IRQ allocated with this function needs to be freed
* separately, dev_free_irq() must be used.
*/
-int devm_request_irq(struct device *dev, unsigned int irq,
- irq_handler_t handler, unsigned long irqflags,
- const char *devname, void *dev_id)
+int __devm_request_irq(struct device *dev, unsigned int irq,
+ irq_handler_t handler, unsigned long irqflags,
+ const char *devname, void *dev_id)
{
struct irq_devres *dr;
int rc;
@@ -53,7 +53,7 @@ int devm_request_irq(struct device *dev,
if (!dr)
return -ENOMEM;
- rc = request_irq(irq, handler, irqflags, devname, dev_id);
+ rc = __request_irq(irq, handler, irqflags, devname, dev_id);
if (rc) {
devres_free(dr);
return rc;
@@ -65,7 +65,7 @@ int devm_request_irq(struct device *dev,
return 0;
}
-EXPORT_SYMBOL(devm_request_irq);
+EXPORT_SYMBOL(__devm_request_irq);
/**
* devm_free_irq - free an interrupt
diff -r 0fe1a980708b kernel/irq/manage.c
--- a/kernel/irq/manage.c Thu Jan 17 14:48:56 2008 +1100
+++ b/kernel/irq/manage.c Thu Jan 17 15:42:01 2008 +1100
@@ -514,8 +514,8 @@ EXPORT_SYMBOL(free_irq);
* IRQF_SAMPLE_RANDOM The interrupt can be used for entropy
*
*/
-int request_irq(unsigned int irq, irq_handler_t handler,
- unsigned long irqflags, const char *devname, void *dev_id)
+int __request_irq(unsigned int irq, irq_handler_t handler,
+ unsigned long irqflags, const char *devname, void *dev_id)
{
struct irqaction *action;
int retval;
@@ -576,4 +576,4 @@ int request_irq(unsigned int irq, irq_ha
return retval;
}
-EXPORT_SYMBOL(request_irq);
+EXPORT_SYMBOL(__request_irq);
This patch lets timer callback functions have their natural type
(ie. exactly match the data pointer type); it allows the old "unsigned
long data" type as well.
Signed-off-by: Rusty Russell <[email protected]>
diff -r 142a2cf4a8dc include/linux/timer.h
--- a/include/linux/timer.h Sun Jan 20 19:01:56 2008 +1100
+++ b/include/linux/timer.h Sun Jan 20 19:36:33 2008 +1100
@@ -24,11 +24,13 @@ struct timer_list {
extern struct tvec_t_base_s boot_tvec_bases;
-#define TIMER_INITIALIZER(_function, _expires, _data) { \
- .function = (_function), \
- .expires = (_expires), \
- .data = (_data), \
- .base = &boot_tvec_bases, \
+
+#define TIMER_INITIALIZER(_function, _expires, _data) { \
+ .function = cast_if_type(_function, void (*)(typeof(_data)), \
+ void (*)(unsigned long)), \
+ .expires = (_expires), \
+ .data = (unsigned long)(_data), \
+ .base = &boot_tvec_bases, \
}
#define DEFINE_TIMER(_name, _function, _expires, _data) \
@@ -38,9 +40,15 @@ void fastcall init_timer(struct timer_li
void fastcall init_timer(struct timer_list * timer);
void fastcall init_timer_deferrable(struct timer_list *timer);
-static inline void setup_timer(struct timer_list * timer,
- void (*function)(unsigned long),
- unsigned long data)
+#define setup_timer(timer, function, data) \
+ __setup_timer((timer), \
+ cast_if_type(function, void (*)(typeof(data)), \
+ void (*)(unsigned long)), \
+ (unsigned long)(data))
+
+static inline void __setup_timer(struct timer_list * timer,
+ void (*function)(unsigned long),
+ unsigned long data)
{
timer->function = function;
timer->data = data;
On Jan 20 2008 20:48, Rusty Russell wrote:
>+ */
>+#define kthread_create(threadfn, data, namefmt...) ({ \
>+ int (*_threadfn)(typeof(data)) = (threadfn); \
>+ __kthread_create((void *)_threadfn, (data), namefmt); \
>+})
If you have namefmt... you need that varagrs cpp trick. IIRC:
__kthread_create((void *)_threadfn, (data), namefmt, __VA_ARGS__);
On Jan 20, 2008 12:25 PM, Jan Engelhardt <[email protected]> wrote:
>
> On Jan 20 2008 20:48, Rusty Russell wrote:
> >+ */
> >+#define kthread_create(threadfn, data, namefmt...) ({ \
> >+ int (*_threadfn)(typeof(data)) = (threadfn); \
> >+ __kthread_create((void *)_threadfn, (data), namefmt); \
> >+})
>
> If you have namefmt... you need that varagrs cpp trick. IIRC:
>
> __kthread_create((void *)_threadfn, (data), namefmt, __VA_ARGS__);
almost
either:
#define kthread_create(threadfn, data, ...) ({ \
__kthread_create((void *)_threadfn, (data), __VA_ARGS__);
or:
#define kthread_create(threadfn, data, namefmt, ...) ({ \
__kthread_create((void *)_threadfn, (data), namefmt, ##__VA_ARGS__);
Bert
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>
Rusty Russell wrote:
> Hi all,
>
> Converting to and from void * for callback functions loses type safety:
> everywhere else we expect the compiler to catch incorrect pointer types
> handed to functions.
>
> It's pretty simple to create typesafe callback functions using typeof, and
> with a little gcc trickery we can allow both old-style and typesafe callbacks
> to avoid churn on commonly-used routines.
I wasn't too convinced with only irq handler conversion but with other
things converted, I'm liking it very much. I really like the timer
conversion as casting between void * and unsigned long is annoying.
Possible improvements.
* Passing NULL as data to callback which takes non-void pointer
triggers warning. I think this should be allowed. Something like
the following?
* Allowing non-pointer integral types which fit into pointer would be
nice. It's often convenient to pass integers to simple callbacks.
The following macro kinda-sorta achieves the above two but it doesn't
consider promotion of integer types and thus is too strict. There
gotta be some way.
#define kthread_create(threadfn, data, namefmt...) ({ \
int (*_threadfn)(typeof(data)); \
void *_data; \
_threadfn = __builtin_choose_expr(!__builtin_types_compatible_p(typeof(data), typeof(NULL)), \
(threadfn), (void *)(threadfn)); \
_data = __builtin_choose_expr(sizeof(data) <= sizeof(void *), \
(void *)(unsigned long)data, (void *)data); \
__kthread_create((void *)_threadfn, _data, namefmt); \
})
Thanks.
--
tejun
Tejun Heo wrote:
> * Passing NULL as data to callback which takes non-void pointer
> triggers warning. I think this should be allowed. Something like
> the following?
Please ignore the last sentence.
> * Allowing non-pointer integral types which fit into pointer would be
> nice. It's often convenient to pass integers to simple callbacks.
>
> The following macro kinda-sorta achieves the above two but it doesn't
> consider promotion of integer types and thus is too strict. There
> gotta be some way.
What should be do are
* Check that the threadfn's argument fits into void *.
* Trigger overflow in implicit constant conversion warning if the
specified data is too large for the argument type.
Tricky...
--
tejun
Hi,
"Bert Wesarg" <[email protected]> writes:
> On Jan 20, 2008 12:25 PM, Jan Engelhardt <[email protected]> wrote:
>>
>> On Jan 20 2008 20:48, Rusty Russell wrote:
>> >+ */
>> >+#define kthread_create(threadfn, data, namefmt...) ({ \
>> >+ int (*_threadfn)(typeof(data)) = (threadfn); \
>> >+ __kthread_create((void *)_threadfn, (data), namefmt); \
>> >+})
>>
>> If you have namefmt... you need that varagrs cpp trick. IIRC:
>>
>> __kthread_create((void *)_threadfn, (data), namefmt, __VA_ARGS__);
> almost
>
> either:
>
> #define kthread_create(threadfn, data, ...) ({ \
> __kthread_create((void *)_threadfn, (data), __VA_ARGS__);
>
No. This is bad because it gives the impression that it takes only two
essential arguments which is not the case.
> or:
>
> #define kthread_create(threadfn, data, namefmt, ...) ({ \
> __kthread_create((void *)_threadfn, (data), namefmt, ##__VA_ARGS__);
>
This is better. I prefer naming the rest args instead of using __VA_ARGS__:
#define kthread_create(threadfn, data, namefmt, fmtargs...) ({ \
... \
__kthread_create((void *)_threadfn, (data), namefmt, ## fmtargs) \
})
but I think that is just a matter of taste.
Hannes
On Jan 20, 2008 5:24 PM, Johannes Weiner <[email protected]> wrote:
> Hi,
>
> "Bert Wesarg" <[email protected]> writes:
>
> > On Jan 20, 2008 12:25 PM, Jan Engelhardt <[email protected]> wrote:
> >>
> >> On Jan 20 2008 20:48, Rusty Russell wrote:
> >> >+ */
> >> >+#define kthread_create(threadfn, data, namefmt...) ({ \
> >> >+ int (*_threadfn)(typeof(data)) = (threadfn); \
> >> >+ __kthread_create((void *)_threadfn, (data), namefmt); \
> >> >+})
> >>
> >> If you have namefmt... you need that varagrs cpp trick. IIRC:
> >>
> >> __kthread_create((void *)_threadfn, (data), namefmt, __VA_ARGS__);
> > almost
> >
> > either:
> >
> > #define kthread_create(threadfn, data, ...) ({ \
> > __kthread_create((void *)_threadfn, (data), __VA_ARGS__);
> >
>
> No. This is bad because it gives the impression that it takes only two
> essential arguments which is not the case.
Right, I just forget to mention this in a comment.
>
> > or:
> >
> > #define kthread_create(threadfn, data, namefmt, ...) ({ \
> > __kthread_create((void *)_threadfn, (data), namefmt, ##__VA_ARGS__);
> >
>
> This is better. I prefer naming the rest args instead of using __VA_ARGS__:
>
> #define kthread_create(threadfn, data, namefmt, fmtargs...) ({ \
> ... \
> __kthread_create((void *)_threadfn, (data), namefmt, ## fmtargs) \
> })
>
> but I think that is just a matter of taste.
No, it is a matter of conforming to C99 or to GNU extensions.
Bert
>
> Hannes
>
On Monday 21 January 2008 03:43:40 Bert Wesarg wrote:
> No, it is a matter of conforming to C99 or to GNU extensions.
Hi Bert!
Not sure I see the point of your message.
The original use the ... varargs GNU extension, your two argument version is
the C99-safe variant, and your three args + __VA_ARGS__ uses the gcc ##
extension.
Cheers,
Rusty.
On Monday 21 January 2008 00:00:52 Tejun Heo wrote:
> What should be do are
>
> * Check that the threadfn's argument fits into void *.
For everything but timer, you'll get a warning if the data isn't assignable to
a void *, so you get a warning if you use a non-pointer already.
But it would be cool to allow functions which take an unsigned long. To do
this, I think that would need to be a special case for the data arg (which
we'd really want to wrap in a macro), like:
/* If fn expects an unsigned long, cast the data. If not, we'll
* get a warning if data is not void * compatible. */
__builtin_choose_expr(__builtin_compatible_p(typeof(1?(threadfn):NULL),
int (*)(unsigned long)),
(void *)(unsigned long)(data), (data))
> * Trigger overflow in implicit constant conversion warning if the
> specified data is too large for the argument type.
Hmm, u64 on 32-bit platforms? I think that will fail the above test: the type
of the function ptr will be "int (*)(u64)" and so you'll end up passing data
(a u64) to a void * argument, which will elicit a warning...
I'll test this out and see what I can make...
Thanks!
Rusty.
On Jan 20, 2008 11:04 PM, Rusty Russell <[email protected]> wrote:
> On Monday 21 January 2008 03:43:40 Bert Wesarg wrote:
> > No, it is a matter of conforming to C99 or to GNU extensions.
>
> Hi Bert!
>
> Not sure I see the point of your message.
>
> The original use the ... varargs GNU extension, your two argument version is
> the C99-safe variant, and your three args + __VA_ARGS__ uses the gcc ##
> extension.
You're right. I didn't know that the ## is a gnu extension too,
thanks. I thought C99 did it right from the beginning.
Sincerely
Bert
>
> Cheers,
> Rusty.
>
On Monday 21 January 2008 09:17:30 Rusty Russell wrote:
> On Monday 21 January 2008 00:00:52 Tejun Heo wrote:
> > What should be do are
> >
> > * Check that the threadfn's argument fits into void *.
>
> For everything but timer, you'll get a warning if the data isn't assignable
> to a void *, so you get a warning if you use a non-pointer already.
>
> But it would be cool to allow functions which take an unsigned long.
...
> I'll test this out and see what I can make...
I think this comes under "too ugly", but here's an attempt.
Two patches, the infrastructure then the stop_machine change, and some
test cases (#if 0'd out).
===
Attempt to create callbacks which take unsigned long as well as
correct pointer types.
Signed-off-by: Rusty Russell <[email protected]>
---
include/linux/compiler-gcc.h | 72 +++++++++++++++++++++++++++++++++++++++++
include/linux/compiler-intel.h | 3 +
2 files changed, 75 insertions(+)
diff -r f41638047650 include/linux/compiler-gcc.h
--- a/include/linux/compiler-gcc.h Mon Jan 21 11:46:30 2008 +1100
+++ b/include/linux/compiler-gcc.h Mon Jan 21 15:05:45 2008 +1100
@@ -53,3 +53,75 @@
#define noinline __attribute__((noinline))
#define __attribute_const__ __attribute__((__const__))
#define __maybe_unused __attribute__((unused))
+
+/* This is not complete: I can't figure out a way to handle enums. */
+#define ulong_compatible(arg) \
+ (__builtin_types_compatible_p(typeof(arg), char) \
+ || __builtin_types_compatible_p(typeof(arg), unsigned char) \
+ || __builtin_types_compatible_p(typeof(arg), signed char) \
+ || __builtin_types_compatible_p(typeof(arg), unsigned short) \
+ || __builtin_types_compatible_p(typeof(arg), short) \
+ || __builtin_types_compatible_p(typeof(arg), unsigned int) \
+ || __builtin_types_compatible_p(typeof(arg), int) \
+ || __builtin_types_compatible_p(typeof(arg), unsigned long) \
+ || __builtin_types_compatible_p(typeof(arg), long))
+
+/**
+ * typesafe_function - cast function type if it's compatible
+ * @fn: the function or function pointer
+ * @ulongtype: the function pointer type if arg is an integer
+ * @safetype: the function pointer type which matches typeof(arg)
+ * @fntype: the generic function pointer type to cast to
+ * @arg: the function argument.
+ *
+ * Callback functions are usually declared to take a "void *arg"
+ * argument, which stops the compiler from doing type checking. We
+ * can freely cast to function pointer which takes "void *" in two
+ * cases: a function which takes a different pointer type or an
+ * unsigned long.
+ *
+ * Typechecking is done in two stages: this macro handles the cases where
+ * @fn takes an unsigned long and @arg is compatible with that, and also
+ * the case where @fn and @arg match types. For other cases, @fn is not
+ * cast, so using the results of this macro should cause a warning unless
+ * @fn is already of if type @fntype.
+ *
+ * Logic looks like this:
+ * if (typeof(@arg) compatible with unsigned long) {
+ * if (typeof(@fn) == @ulongtype)
+ * (@fntype)(@fn); // OK!
+ * else
+ * @fn; // will give type warning unless it's of @fntype already.
+ * } else if (typeof(@fn) == @safetype)
+ * (@fntype)(@fn); // OK!
+ * else
+ * (@fn); // will give type warning unless it's of @fntype already.
+ */
+#define typesafe_function(fn, ulongtype, safetype, fntype, arg) \
+__builtin_choose_expr((ulong_compatible(arg) \
+ && __builtin_types_compatible_p(typeof(1?(fn):NULL), \
+ ulongtype)) \
+ || (!ulong_compatible(arg) \
+ && __builtin_types_compatible_p(typeof(1?(fn):NULL), \
+ safetype)), \
+ ((fntype)(fn)), \
+ (fn))
+
+/**
+ * typesafe_arg - cast to void * if function expects an unsigned long
+ * @fn: the function or function pointer
+ * @ulongtype: the function pointer type if arg is an integer
+ * @arg: the function argument
+ *
+ * If @fn expects an unsigned long, cast @arg, otherwise leave it
+ * alone (if it's not void * compatible, this will cause a warning
+ * when used).
+ *
+ * Note that we've already checked @arg/@fn compatibility in
+ * typesafe_function(): this makes sure that @arg is a pointer or an integer
+ * if @fn expects an unsigned long.
+ */
+#define typesafe_arg(fn, ulongtype, arg) \
+__builtin_choose_expr(__builtin_types_compatible_p(typeof(1?(fn):NULL), \
+ ulongtype), \
+ ((void *)(long)(arg)), (arg))
diff -r f41638047650 include/linux/compiler-intel.h
--- a/include/linux/compiler-intel.h Mon Jan 21 11:46:30 2008 +1100
+++ b/include/linux/compiler-intel.h Mon Jan 21 15:05:45 2008 +1100
@@ -29,3 +29,6 @@
#endif
#define uninitialized_var(x) x
+
+#define typesafe_function(fn, ulongtype, safetype, fntype, arg) ((fntype)(fn))
+#define typesafe_arg(fn, ulongtype, arg) ((void *)arg)
===
typesafe: Convert stop_machine and callers
Signed-off-by: Rusty Russell <[email protected]>
---
drivers/char/hw_random/intel-rng.c | 3 -
include/linux/stop_machine.h | 16 ++++--
kernel/module.c | 10 +---
kernel/stop_machine.c | 89 ++++++++++++++++++++++++++++++++++++-
4 files changed, 103 insertions(+), 15 deletions(-)
diff -r e279190b7b43 drivers/char/hw_random/intel-rng.c
--- a/drivers/char/hw_random/intel-rng.c Mon Jan 21 14:42:54 2008 +1100
+++ b/drivers/char/hw_random/intel-rng.c Mon Jan 21 15:04:00 2008 +1100
@@ -227,9 +227,8 @@ struct intel_rng_hw {
u8 fwh_dec_en1_val;
};
-static int __init intel_rng_hw_init(void *_intel_rng_hw)
+static int __init intel_rng_hw_init(struct intel_rng_hw *intel_rng_hw)
{
- struct intel_rng_hw *intel_rng_hw = _intel_rng_hw;
u8 mfc, dvc;
/* interrupts disabled in stop_machine_run call */
diff -r e279190b7b43 include/linux/stop_machine.h
--- a/include/linux/stop_machine.h Mon Jan 21 14:42:54 2008 +1100
+++ b/include/linux/stop_machine.h Mon Jan 21 15:04:00 2008 +1100
@@ -5,9 +5,9 @@
(and more). So the "read" side to such a lock is anything which
diables preeempt. */
#include <linux/cpu.h>
+#include <linux/compiler.h>
#include <asm/system.h>
-#if defined(CONFIG_STOP_MACHINE) && defined(CONFIG_SMP)
/**
* stop_machine_run: freeze the machine on all CPUs and run this function
* @fn: the function to run
@@ -21,7 +21,15 @@
*
* This can be thought of as a very heavy write lock, equivalent to
* grabbing every spinlock in the kernel. */
-int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu);
+#define stop_machine_run(fn, data, cpu) \
+stop_machine_run_notype(typesafe_function((fn), int(*)(unsigned long), \
+ int(*)(typeof(data)), \
+ int(*)(void *), (data)), \
+ typesafe_arg((fn), int(*)(unsigned long), (data)), \
+ (cpu))
+
+#if defined(CONFIG_STOP_MACHINE) && defined(CONFIG_SMP)
+int stop_machine_run_notype(int (*fn)(void *), void *data, unsigned int cpu);
/**
* __stop_machine_run: freeze the machine on all CPUs and run this function
@@ -38,8 +46,8 @@ struct task_struct *__stop_machine_run(i
#else
-static inline int stop_machine_run(int (*fn)(void *), void *data,
- unsigned int cpu)
+static inline int stop_machine_run_notype(int (*fn)(void *), void *data,
+ unsigned int cpu)
{
int ret;
local_irq_disable();
diff -r e279190b7b43 kernel/module.c
--- a/kernel/module.c Mon Jan 21 14:42:54 2008 +1100
+++ b/kernel/module.c Mon Jan 21 15:04:00 2008 +1100
@@ -623,10 +623,8 @@ struct stopref
};
/* Whole machine is stopped with interrupts off when this runs. */
-static int __try_stop_module(void *_sref)
+static int __try_stop_module(struct stopref *sref)
{
- struct stopref *sref = _sref;
-
/* If it's not unused, quit unless we are told to block. */
if ((sref->flags & O_NONBLOCK) && module_refcount(sref->mod) != 0) {
if (!(*sref->forced = try_force_unload(sref->flags)))
@@ -1305,9 +1303,8 @@ static void mod_kobject_remove(struct mo
* link the module with the whole machine is stopped with interrupts off
* - this defends against kallsyms not taking locks
*/
-static int __link_module(void *_mod)
+static int __link_module(struct module *mod)
{
- struct module *mod = _mod;
list_add(&mod->list, &modules);
return 0;
}
@@ -1316,9 +1313,8 @@ static int __link_module(void *_mod)
* unlink the module with the whole machine is stopped with interrupts off
* - this defends against kallsyms not taking locks
*/
-static int __unlink_module(void *_mod)
+static int __unlink_module(struct module *mod)
{
- struct module *mod = _mod;
list_del(&mod->list);
return 0;
}
diff -r e279190b7b43 kernel/stop_machine.c
--- a/kernel/stop_machine.c Mon Jan 21 14:42:54 2008 +1100
+++ b/kernel/stop_machine.c Mon Jan 21 15:04:00 2008 +1100
@@ -197,7 +197,7 @@ struct task_struct *__stop_machine_run(i
return p;
}
-int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu)
+int stop_machine_run_notype(int (*fn)(void *), void *data, unsigned int cpu)
{
struct task_struct *p;
int ret;
@@ -213,4 +213,89 @@ int stop_machine_run(int (*fn)(void *),
return ret;
}
-EXPORT_SYMBOL_GPL(stop_machine_run);
+EXPORT_SYMBOL_GPL(stop_machine_run_notype);
+
+#if 0 /* Compile test */
+int testfn_voidp(void *);
+int testfn_charp(char *);
+int testfn_char(char);
+int testfn_ulong(unsigned long);
+
+void test(void)
+{
+ char c;
+ unsigned long ul;
+ void *p;
+ struct { void *p; } s;
+
+ /*
+ * Should work
+ */
+ /* void * compatible with any pointer. */
+ stop_machine_run(testfn_voidp, NULL, 0);
+ stop_machine_run(testfn_voidp, p, 0);
+ stop_machine_run(testfn_voidp, &c, 0);
+ stop_machine_run(testfn_voidp, &ul, 0);
+
+ /* NULL callbacks compatible with any pointer. */
+ stop_machine_run(NULL, NULL, 0);
+ stop_machine_run(NULL, p, 0);
+ stop_machine_run(NULL, &c, 0);
+ stop_machine_run(NULL, &ul, 0);
+
+ /* Char * match. */
+ stop_machine_run(testfn_charp, &c, 0);
+
+ /* ulong can take any int or long. */
+ stop_machine_run(testfn_ulong, c, 0);
+ stop_machine_run(testfn_ulong, ul, 0);
+
+ /*
+ * It would be nice if these worked, but they don't (void * arg).
+ */
+ stop_machine_run(testfn_charp, NULL, 0);
+ stop_machine_run(testfn_charp, p, 0);
+ stop_machine_run(testfn_ulong, NULL, 0);
+ stop_machine_run(testfn_ulong, p, 0);
+
+ /*
+ * Should complain.
+ */
+
+ /* void * incompatible with non-pointers. */
+ stop_machine_run(testfn_voidp, c, 0);
+ stop_machine_run(testfn_voidp, ul, 0);
+ stop_machine_run(testfn_voidp, s, 0);
+
+ /* NULL callbacks incompatible with non-pointers. */
+ stop_machine_run(NULL, c, 0);
+ stop_machine_run(NULL, ul, 0);
+ stop_machine_run(NULL, s, 0);
+
+ /* char * function and unsigned long */
+ stop_machine_run(testfn_charp, &ul, 0);
+
+ /* char * incompatible with non-pointers */
+ stop_machine_run(testfn_charp, c, 0);
+ stop_machine_run(testfn_charp, ul, 0);
+ stop_machine_run(testfn_charp, s, 0);
+
+ /* A char function simply can't work as a callback. */
+ stop_machine_run(testfn_char, NULL, 0);
+ stop_machine_run(testfn_char, p, 0);
+ stop_machine_run(testfn_char, &c, 0);
+ stop_machine_run(testfn_char, &ul, 0);
+ stop_machine_run(testfn_char, c, 0);
+ stop_machine_run(testfn_char, ul, 0);
+ stop_machine_run(testfn_char, s, 0);
+
+ /* unsigned long function and char * */
+ stop_machine_run(testfn_ulong, &c, 0);
+
+ /* unsigned long function and unsigned long * */
+ stop_machine_run(testfn_ulong, &ul, 0);
+
+ /* unsigned long function and struct. */
+ stop_machine_run(testfn_ulong, s, 0);
+}
+#endif
Rusty Russell wrote:
> On Monday 21 January 2008 09:17:30 Rusty Russell wrote:
>> On Monday 21 January 2008 00:00:52 Tejun Heo wrote:
>>> What should be do are
>>>
>>> * Check that the threadfn's argument fits into void *.
>> For everything but timer, you'll get a warning if the data isn't assignable
>> to a void *, so you get a warning if you use a non-pointer already.
>>
>> But it would be cool to allow functions which take an unsigned long.
> ...
>> I'll test this out and see what I can make...
>
> I think this comes under "too ugly", but here's an attempt.
Maybe we should be content with pointer type checking. It seems like
it's going too far and after all the clutter it's not possible to use
int as argument. :-(
Thanks.
--
tejun
On Monday 21 January 2008 23:38:47 Tejun Heo wrote:
> Rusty Russell wrote:
> > On Monday 21 January 2008 09:17:30 Rusty Russell wrote:
> >> But it would be cool to allow functions which take an unsigned long.
> >> I'll test this out and see what I can make...
> >
> > I think this comes under "too ugly", but here's an attempt.
>
> Maybe we should be content with pointer type checking. It seems like
> it's going too far and after all the clutter it's not possible to use
> int as argument. :-(
It is possible, but the function has to take an unsigned long.
But I share your dislike of this. Here's my final version, but it's still
ugly.
Rusty.
===
Attempt to create callbacks which take unsigned long as well as
correct pointer types.
Signed-off-by: Rusty Russell <[email protected]>
---
include/linux/compiler-gcc.h | 61 +++++++++++++++++++++++++++++++++++++++++
include/linux/compiler-intel.h | 3 ++
include/linux/kernel.h | 21 ++++++++++++++
3 files changed, 85 insertions(+)
diff -r 951ffe1c5238 include/linux/compiler-gcc.h
--- a/include/linux/compiler-gcc.h Tue Jan 22 09:31:56 2008 +1100
+++ b/include/linux/compiler-gcc.h Tue Jan 22 10:15:15 2008 +1100
@@ -53,3 +53,64 @@
#define noinline __attribute__((noinline))
#define __attribute_const__ __attribute__((__const__))
#define __maybe_unused __attribute__((unused))
+
+/* This is not complete: I can't figure out a way to handle enums. */
+#define ulong_compatible(arg) \
+ (__builtin_types_compatible_p(typeof(arg), char) \
+ || __builtin_types_compatible_p(typeof(arg), unsigned char) \
+ || __builtin_types_compatible_p(typeof(arg), signed char) \
+ || __builtin_types_compatible_p(typeof(arg), unsigned short) \
+ || __builtin_types_compatible_p(typeof(arg), short) \
+ || __builtin_types_compatible_p(typeof(arg), unsigned int) \
+ || __builtin_types_compatible_p(typeof(arg), int) \
+ || __builtin_types_compatible_p(typeof(arg), unsigned long) \
+ || __builtin_types_compatible_p(typeof(arg), long))
+
+/**
+ * typesafe_fn_and_arg - cast function type and arg if compatible
+ * @fn: the function or function pointer
+ * @arg: the function argument.
+ * @ulongtype: the function pointer type if arg is an integer
+ * @safetype: the function pointer type which matches typeof(arg)
+ * @voidtype: the function pointer type which takes a void * (to cast to)
+ *
+ * This macro evaluates to two comma separated values: the function pointer,
+ * then the argument.
+ *
+ * Callback functions are usually declared to take a "void *arg"
+ * argument, which stops the compiler from doing type checking. We
+ * can freely cast to function pointer which takes "void *" in two
+ * cases: a function which takes a different pointer type or an
+ * unsigned long.
+ *
+ * Typechecking is done by the caller when they assign or pass these
+ * values. This macro handles the cases where @fn takes an unsigned
+ * long and @arg is compatible with that, and also the case where @fn
+ * and @arg match types. For other cases, @fn is not cast, so using
+ * the results of this macro should cause a warning unless @fn is
+ * already of if type @voidtype.
+ *
+ * Logic looks like this:
+ * if (typeof(@arg) compatible with unsigned long) {
+ * if (typeof(@fn) == @ulongtype)
+ * (@voidtype)@fn and (void *)(unsigned long)@arg; // OK!
+ * else
+ * @fn and @arg; // @fn will warn unless it's of @voidtype already.
+ * } else if (typeof(@fn) == @safetype)
+ * (@voidtype)@fn and @arg; // OK: @arg will warn unless it's a pointer.
+ * else
+ * @fn and @arg; // @fn will warn unless it's of @voidtype already.
+ */
+#define typesafe_fn_and_arg(fn, arg, ulongtype, safetype, voidtype) \
+__builtin_choose_expr((ulong_compatible(arg) \
+ && __builtin_types_compatible_p(typeof(1?(fn):NULL), \
+ ulongtype)) \
+ || (!ulong_compatible(arg) \
+ && __builtin_types_compatible_p(typeof(1?(fn):NULL), \
+ safetype)), \
+ ((voidtype)(fn)), \
+ (fn)), \
+__builtin_choose_expr(__builtin_types_compatible_p(typeof(1?(fn):NULL), \
+ ulongtype), \
+ ((void *)(long)(arg)), (arg))
+
diff -r 951ffe1c5238 include/linux/compiler-intel.h
--- a/include/linux/compiler-intel.h Tue Jan 22 09:31:56 2008 +1100
+++ b/include/linux/compiler-intel.h Tue Jan 22 10:15:15 2008 +1100
@@ -29,3 +29,6 @@
#endif
#define uninitialized_var(x) x
+
+#define typesafe_fn_and_arg(fn, arg, ulongtype, safetype, fntype) \
+ ((fntype)(fn)), ((void *)arg)
diff -r 951ffe1c5238 include/linux/kernel.h
--- a/include/linux/kernel.h Tue Jan 22 09:31:56 2008 +1100
+++ b/include/linux/kernel.h Tue Jan 22 10:15:15 2008 +1100
@@ -379,6 +379,27 @@ static inline int __attribute__ ((format
(void)__tmp; \
})
+/**
+ * callback_and_arg - simple one-argument typesafe callback with argument
+ * @fn: the function or function pointer
+ * @arg: the function argument.
+ * @rettype: the return type of fn
+ *
+ * This macro evaluates to two comma separated values: the function pointer,
+ * then the argument. It will check that @fn and @arg are compatible with
+ * each other and with a void * callback. One of
+ * - fn takes a void * and arg is a pointer
+ * - fn takes a typeof(arg) and arg is a pointer
+ * - fn takes an unsigned long and arg is an integer type.
+ *
+ * See typesafe_fn_and_arg() for the gory details.
+ */
+#define callback_and_arg(fn, arg, rettype) \
+ typesafe_fn_and_arg((fn), (arg), \
+ rettype (*)(unsigned long), \
+ rettype (*)(typeof(arg)), \
+ rettype (*)(void *))
+
struct sysinfo;
extern int do_sysinfo(struct sysinfo *info);
On Tue, 22 Jan 2008, Rusty Russell wrote:
>
> Attempt to create callbacks which take unsigned long as well as
> correct pointer types.
I bow down before you.
I thought I had done some rather horrible things with gcc built-ins and
macros, but I hereby hand over my crown to you.
As my daughter would say: that patch fell out of the ugly tree, and hit
every branch on the way down. Very impressive.
All hail Rusty, undisputed ruler of Ugly-land.
Side note: can you verify that __builtin_choose_expr() exists in gcc-3? I
don't think we've relied on it before except on arm, and that one has
always had its own compiler version dependencies..
Linus
Rusty Russell <[email protected]> writes:
> ===
> Attempt to create callbacks which take unsigned long as well as
> correct pointer types.
FWIW i had something similar using the gcc union extension at some
point for ioctls because I was tired for all the ugly casts from
unsigned long arg to void * in ioctl handlers.
But I decided to not push it because sparse would have likely choked
on it, and sparse actually finds a lot of bugs so it's more important than
having a few more casts.
-Andi
On Tuesday 22 January 2008 10:57:03 Linus Torvalds wrote:
> On Tue, 22 Jan 2008, Rusty Russell wrote:
> > Attempt to create callbacks which take unsigned long as well as
> > correct pointer types.
>
> I bow down before you.
>
> I thought I had done some rather horrible things with gcc built-ins and
> macros, but I hereby hand over my crown to you.
>
> As my daughter would say: that patch fell out of the ugly tree, and hit
> every branch on the way down. Very impressive.
>
> All hail Rusty, undisputed ruler of Ugly-land.
Err, thanks. I read some old SCSI drivers and felt inspired...
> Side note: can you verify that __builtin_choose_expr() exists in gcc-3? I
> don't think we've relied on it before except on arm, and that one has
> always had its own compiler version dependencies..
Hmm, looks like not in 3.0.4, is in 3.1.1. I'll make it appropriately
#ifdef'ed (which as a bonus will make things that little bit uglier still...)
If we can stomach it the effect is nice, but the version which simply
allows pointer correctness (rather than trying to do unsigned long too) is
less bletcherous.
Thanks,
Rusty.
On Tue, 22 Jan 2008, Rusty Russell wrote:
>
> If we can stomach it the effect is nice, but the version which simply
> allows pointer correctness (rather than trying to do unsigned long too) is
> less bletcherous.
I'd suggest trying to get by with just the pointer version for now. But we
know whom to turn to when we need bletcherousness.
Linus