From 43ad6bb2ad3c978ee9958ed6c534d835344d6898 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Tue, 21 Jul 2009 10:22:47 -0700 Subject: [PATCH] Register compat ioctl handlers for zpios + 32-bit safe timespec. A compat ioctl handler for zpios was added which simply passes the ioctl on to the usual handler. The IOWR macro's correctly handle this. Additionally replace the use of 'struct timespec' which uses longs internally and is therefore different sizes on 32-bit vs 64-bit objects with 'struct zpios_timespec_t'. This custom structure uses uint32_t types internally and is safe to pass through an ioctl. The helper functions for this new type were also moved to a common place so they may be used safely by the user or kernel code. --- cmd/zpios/zpios_util.c | 41 ++++++------- module/zpios/include/zpios-ctl.h | 78 ++++++++++++++++++++++-- module/zpios/zpios.c | 101 ++++++++++++++++--------------- 3 files changed, 142 insertions(+), 78 deletions(-) diff --git a/cmd/zpios/zpios_util.c b/cmd/zpios/zpios_util.c index c923673702..407a5522a7 100644 --- a/cmd/zpios/zpios_util.c +++ b/cmd/zpios/zpios_util.c @@ -131,13 +131,6 @@ print_flags(char *str, uint32_t flags) return str; } -static double -timespec_to_double(struct timespec t) -{ - return ((double)(t.tv_sec) + - ((double)(t.tv_nsec) / (double)(1000*1000*1000))); -} - static int regex_match(const char *string, char *pattern) { @@ -352,11 +345,11 @@ print_stats_human_readable(cmd_args_t *args, zpios_cmd_t *cmd) } summary_stats = (zpios_stats_t *)cmd->cmd_data_str; - t_time = timespec_to_double(summary_stats->total_time.delta); - wr_time = timespec_to_double(summary_stats->wr_time.delta); - rd_time = timespec_to_double(summary_stats->rd_time.delta); - cr_time = timespec_to_double(summary_stats->cr_time.delta); - rm_time = timespec_to_double(summary_stats->rm_time.delta); + t_time = zpios_timespec_to_double(summary_stats->total_time.delta); + wr_time = zpios_timespec_to_double(summary_stats->wr_time.delta); + rd_time = zpios_timespec_to_double(summary_stats->rd_time.delta); + cr_time = zpios_timespec_to_double(summary_stats->cr_time.delta); + rm_time = zpios_timespec_to_double(summary_stats->rm_time.delta); printf("%.2f\t", t_time); printf("%.3f\t", cr_time); @@ -402,24 +395,24 @@ print_stats_table(cmd_args_t *args, zpios_cmd_t *cmd) } summary_stats = (zpios_stats_t *)cmd->cmd_data_str; - wr_time = timespec_to_double(summary_stats->wr_time.delta); - rd_time = timespec_to_double(summary_stats->rd_time.delta); + wr_time = zpios_timespec_to_double(summary_stats->wr_time.delta); + rd_time = zpios_timespec_to_double(summary_stats->rd_time.delta); printf("%ld.%02ld\t", - summary_stats->total_time.delta.tv_sec, - summary_stats->total_time.delta.tv_nsec); + (long)summary_stats->total_time.delta.ts_sec, + (long)summary_stats->total_time.delta.ts_nsec); printf("%ld.%02ld\t", - summary_stats->cr_time.delta.tv_sec, - summary_stats->cr_time.delta.tv_nsec); + (long)summary_stats->cr_time.delta.ts_sec, + (long)summary_stats->cr_time.delta.ts_nsec); printf("%ld.%02ld\t", - summary_stats->rm_time.delta.tv_sec, - summary_stats->rm_time.delta.tv_nsec); + (long)summary_stats->rm_time.delta.ts_sec, + (long)summary_stats->rm_time.delta.ts_nsec); printf("%ld.%02ld\t", - summary_stats->wr_time.delta.tv_sec, - summary_stats->wr_time.delta.tv_nsec); + (long)summary_stats->wr_time.delta.ts_sec, + (long)summary_stats->wr_time.delta.ts_nsec); printf("%ld.%02ld\t", - summary_stats->rd_time.delta.tv_sec, - summary_stats->rd_time.delta.tv_nsec); + (long)summary_stats->rd_time.delta.ts_sec, + (long)summary_stats->rd_time.delta.ts_nsec); printf("%lld\t", (long long unsigned)summary_stats->wr_data); printf("%lld\t", (long long unsigned)summary_stats->wr_chunks); diff --git a/module/zpios/include/zpios-ctl.h b/module/zpios/include/zpios-ctl.h index 25a04bba01..fafa59a0c8 100644 --- a/module/zpios/include/zpios-ctl.h +++ b/module/zpios/include/zpios-ctl.h @@ -78,10 +78,15 @@ typedef struct zpios_cfg { int32_t cfg_rc1; /* Config response 1 */ } zpios_cfg_t; +typedef struct zpios_timespec { + uint32_t ts_sec; + uint32_t ts_nsec; +} zpios_timespec_t; + typedef struct zpios_time { - struct timespec start; - struct timespec stop; - struct timespec delta; + zpios_timespec_t start; + zpios_timespec_t stop; + zpios_timespec_t delta; } zpios_time_t; typedef struct zpios_stats { @@ -118,11 +123,74 @@ typedef struct zpios_cmd { } zpios_cmd_t; /* Valid ioctls */ -#define ZPIOS_CFG _IOWR('f', 101, long) -#define ZPIOS_CMD _IOWR('f', 102, long) +#define ZPIOS_CFG _IOWR('f', 101, zpios_cfg_t) +#define ZPIOS_CMD _IOWR('f', 102, zpios_cmd_t) /* Valid configuration commands */ #define ZPIOS_CFG_BUFFER_CLEAR 0x001 /* Clear text buffer */ #define ZPIOS_CFG_BUFFER_SIZE 0x002 /* Resize text buffer */ +#ifndef NSEC_PER_SEC +#define NSEC_PER_SEC 1000000000L +#endif + +static inline +void zpios_timespec_normalize(zpios_timespec_t *ts, uint32_t sec, uint32_t nsec) +{ + while (nsec >= NSEC_PER_SEC) { + nsec -= NSEC_PER_SEC; + sec++; + } + while (nsec < 0) { + nsec += NSEC_PER_SEC; + sec--; + } + ts->ts_sec = sec; + ts->ts_nsec = nsec; +} + +static inline +zpios_timespec_t zpios_timespec_add(zpios_timespec_t lhs, zpios_timespec_t rhs) +{ + zpios_timespec_t ts_delta; + zpios_timespec_normalize(&ts_delta, lhs.ts_sec + rhs.ts_sec, + lhs.ts_nsec + rhs.ts_nsec); + return ts_delta; +} + +static inline +zpios_timespec_t zpios_timespec_sub(zpios_timespec_t lhs, zpios_timespec_t rhs) +{ + zpios_timespec_t ts_delta; + zpios_timespec_normalize(&ts_delta, lhs.ts_sec - rhs.ts_sec, + lhs.ts_nsec - rhs.ts_nsec); + return ts_delta; +} + +#ifdef _KERNEL + +static inline +zpios_timespec_t zpios_timespec_now(void) +{ + zpios_timespec_t zts_now; + struct timespec ts_now; + + ts_now = current_kernel_time(); + zts_now.ts_sec = ts_now.tv_sec; + zts_now.ts_nsec = ts_now.tv_nsec; + + return zts_now; +} + +#else + +static inline +double zpios_timespec_to_double(zpios_timespec_t ts) +{ + return ((double)(ts.ts_sec) + + ((double)(ts.ts_nsec) / (double)(NSEC_PER_SEC))); +} + +#endif /* _KERNEL */ + #endif /* _ZPIOS_CTL_H */ diff --git a/module/zpios/zpios.c b/module/zpios/zpios.c index bf811c67ae..157025c50b 100644 --- a/module/zpios/zpios.c +++ b/module/zpios/zpios.c @@ -43,15 +43,6 @@ static struct class *zpios_class; -static inline -struct timespec timespec_add(struct timespec lhs, struct timespec rhs) -{ - struct timespec ts_delta; - set_normalized_timespec(&ts_delta, lhs.tv_sec + rhs.tv_sec, - lhs.tv_nsec + rhs.tv_nsec); - return ts_delta; -} - static int zpios_upcall(char *path, char *phase, run_args_t *run_args, int rc) { @@ -175,7 +166,7 @@ zpios_dmu_setup(run_args_t *run_args) int i, rc = 0; (void)zpios_upcall(run_args->pre, PHASE_PRE_CREATE, run_args, 0); - t->start = current_kernel_time(); + t->start = zpios_timespec_now(); rc = dmu_objset_open(run_args->pool, DMU_OST_ZFS, DS_MODE_USER, &os); if (rc) { @@ -224,8 +215,8 @@ zpios_dmu_setup(run_args_t *run_args) run_args->os = os; out: - t->stop = current_kernel_time(); - t->delta = timespec_sub(t->stop, t->start); + t->stop = zpios_timespec_now(); + t->delta = zpios_timespec_sub(t->stop, t->start); (void)zpios_upcall(run_args->post, PHASE_POST_CREATE, run_args, rc); return rc; @@ -320,9 +311,9 @@ zpios_get_work_item(run_args_t *run_args, dmu_obj_t *obj, __u64 *offset, i++; count++; - if (unlikely(rw_time->stop.tv_sec == 0) && - unlikely(rw_time->stop.tv_nsec == 0)) - rw_time->stop = current_kernel_time(); + if (unlikely(rw_time->stop.ts_sec == 0) && + unlikely(rw_time->stop.ts_nsec == 0)) + rw_time->stop = zpios_timespec_now(); continue; } @@ -357,7 +348,7 @@ zpios_remove_objects(run_args_t *run_args) int rc = 0, i; (void)zpios_upcall(run_args->pre, PHASE_PRE_REMOVE, run_args, 0); - t->start = current_kernel_time(); + t->start = zpios_timespec_now(); if (run_args->flags & DMU_REMOVE) { if (run_args->flags & DMU_FPP) { @@ -385,8 +376,8 @@ zpios_remove_objects(run_args_t *run_args) dmu_objset_close(run_args->os); - t->stop = current_kernel_time(); - t->delta = timespec_sub(t->stop, t->start); + t->stop = zpios_timespec_now(); + t->delta = zpios_timespec_sub(t->stop, t->start); (void)zpios_upcall(run_args->post, PHASE_POST_REMOVE, run_args, rc); } @@ -514,7 +505,7 @@ zpios_thread_main(void *data) /* Write phase */ mutex_enter(&thr->lock); - thr->stats.wr_time.start = current_kernel_time(); + thr->stats.wr_time.start = zpios_timespec_now(); mutex_exit(&thr->lock); while (zpios_get_work_item(run_args, &obj, &offset, @@ -526,11 +517,11 @@ zpios_thread_main(void *data) schedule_timeout(thread_delay_tmp); /* In jiffies */ } - t.start = current_kernel_time(); + t.start = zpios_timespec_now(); rc = zpios_dmu_write(run_args, obj.os, obj.obj, offset, chunk_size, buf); - t.stop = current_kernel_time(); - t.delta = timespec_sub(t.stop, t.start); + t.stop = zpios_timespec_now(); + t.delta = zpios_timespec_sub(t.stop, t.start); if (rc) { zpios_print(run_args->file, "IO error while doing " @@ -541,14 +532,14 @@ zpios_thread_main(void *data) mutex_enter(&thr->lock); thr->stats.wr_data += chunk_size; thr->stats.wr_chunks++; - thr->stats.wr_time.delta = timespec_add( + thr->stats.wr_time.delta = zpios_timespec_add( thr->stats.wr_time.delta, t.delta); mutex_exit(&thr->lock); mutex_enter(®ion->lock); region->stats.wr_data += chunk_size; region->stats.wr_chunks++; - region->stats.wr_time.delta = timespec_add( + region->stats.wr_time.delta = zpios_timespec_add( region->stats.wr_time.delta, t.delta); /* First time region was accessed */ @@ -564,7 +555,7 @@ zpios_thread_main(void *data) mutex_enter(&thr->lock); thr->rc = rc; - thr->stats.wr_time.stop = current_kernel_time(); + thr->stats.wr_time.stop = zpios_timespec_now(); mutex_exit(&thr->lock); wake_up(&run_args->waitq); @@ -580,7 +571,7 @@ zpios_thread_main(void *data) /* Read phase */ mutex_enter(&thr->lock); - thr->stats.rd_time.start = current_kernel_time(); + thr->stats.rd_time.start = zpios_timespec_now(); mutex_exit(&thr->lock); while (zpios_get_work_item(run_args, &obj, &offset, @@ -595,11 +586,11 @@ zpios_thread_main(void *data) if (run_args->flags & DMU_VERIFY) memset(buf, 0, chunk_size); - t.start = current_kernel_time(); + t.start = zpios_timespec_now(); rc = zpios_dmu_read(run_args, obj.os, obj.obj, offset, chunk_size, buf); - t.stop = current_kernel_time(); - t.delta = timespec_sub(t.stop, t.start); + t.stop = zpios_timespec_now(); + t.delta = zpios_timespec_sub(t.stop, t.start); if (rc) { zpios_print(run_args->file, "IO error while doing " @@ -623,14 +614,14 @@ zpios_thread_main(void *data) mutex_enter(&thr->lock); thr->stats.rd_data += chunk_size; thr->stats.rd_chunks++; - thr->stats.rd_time.delta = timespec_add( + thr->stats.rd_time.delta = zpios_timespec_add( thr->stats.rd_time.delta, t.delta); mutex_exit(&thr->lock); mutex_enter(®ion->lock); region->stats.rd_data += chunk_size; region->stats.rd_chunks++; - region->stats.rd_time.delta = timespec_add( + region->stats.rd_time.delta = zpios_timespec_add( region->stats.rd_time.delta, t.delta); /* First time region was accessed */ @@ -646,7 +637,7 @@ zpios_thread_main(void *data) mutex_enter(&thr->lock); thr->rc = rc; - thr->stats.rd_time.stop = current_kernel_time(); + thr->stats.rd_time.stop = zpios_timespec_now(); mutex_exit(&thr->lock); wake_up(&run_args->waitq); @@ -713,7 +704,7 @@ zpios_threads_run(run_args_t *run_args) tsks[i] = tsk; } - tt->start = current_kernel_time(); + tt->start = zpios_timespec_now(); /* Wake up all threads for write phase */ (void)zpios_upcall(run_args->pre, PHASE_PRE_WRITE, run_args, 0); @@ -721,9 +712,9 @@ zpios_threads_run(run_args_t *run_args) wake_up_process(tsks[i]); /* Wait for write phase to complete */ - tw->start = current_kernel_time(); + tw->start = zpios_timespec_now(); wait_event(run_args->waitq, zpios_thread_done(run_args)); - tw->stop = current_kernel_time(); + tw->stop = zpios_timespec_now(); (void)zpios_upcall(run_args->post, PHASE_POST_WRITE, run_args, rc); for (i = 0; i < tc; i++) { @@ -762,9 +753,9 @@ zpios_threads_run(run_args_t *run_args) wake_up_process(tsks[i]); /* Wait for read phase to complete */ - tr->start = current_kernel_time(); + tr->start = zpios_timespec_now(); wait_event(run_args->waitq, zpios_thread_done(run_args)); - tr->stop = current_kernel_time(); + tr->stop = zpios_timespec_now(); (void)zpios_upcall(run_args->post, PHASE_POST_READ, run_args, rc); for (i = 0; i < tc; i++) { @@ -780,10 +771,10 @@ zpios_threads_run(run_args_t *run_args) mutex_exit(&thr->lock); } out: - tt->stop = current_kernel_time(); - tt->delta = timespec_sub(tt->stop, tt->start); - tw->delta = timespec_sub(tw->stop, tw->start); - tr->delta = timespec_sub(tr->stop, tr->start); + tt->stop = zpios_timespec_now(); + tt->delta = zpios_timespec_sub(tt->stop, tt->start); + tw->delta = zpios_timespec_sub(tw->stop, tw->start); + tr->delta = zpios_timespec_sub(tr->stop, tr->start); cleanup: kmem_free(tsks, sizeof(struct task_struct *) * tc); @@ -1082,7 +1073,7 @@ static int zpios_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - unsigned int minor = iminor(file->f_dentry->d_inode); + unsigned int minor = iminor(inode); int rc = 0; /* Ignore tty ioctls */ @@ -1108,6 +1099,15 @@ zpios_ioctl(struct inode *inode, struct file *file, return rc; } +#ifdef CONFIG_COMPAT +/* Compatibility handler for ioctls from 32-bit ELF binaries */ +static long +zpios_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return zpios_ioctl(file->f_dentry->d_inode, file, cmd, arg); +} +#endif /* CONFIG_COMPAT */ + /* I'm not sure why you would want to write in to this buffer from * user space since its principle use is to pass test status info * back to the user space, but I don't see any reason to prevent it. @@ -1223,13 +1223,16 @@ static loff_t zpios_seek(struct file *file, loff_t offset, int origin) } static struct file_operations zpios_fops = { - .owner = THIS_MODULE, - .open = zpios_open, - .release = zpios_release, - .ioctl = zpios_ioctl, - .read = zpios_read, - .write = zpios_write, - .llseek = zpios_seek, + .owner = THIS_MODULE, + .open = zpios_open, + .release = zpios_release, + .ioctl = zpios_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = zpios_compat_ioctl, +#endif + .read = zpios_read, + .write = zpios_write, + .llseek = zpios_seek, }; static struct cdev zpios_cdev = {