Module: xenomai-3 Branch: next Commit: 87bb4ce0a3dbe4234a184ccee03576423ede17af URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=87bb4ce0a3dbe4234a184ccee03576423ede17af
Author: Philippe Gerum <r...@xenomai.org> Date: Thu Oct 16 14:39:53 2014 +0200 cobalt/posix/sched: prepare for 32bit syscall emulation --- include/cobalt/uapi/sched.h | 38 +-- kernel/cobalt/posix/sched.c | 345 ++++++++++++++++++---------- kernel/cobalt/posix/sched.h | 25 +- kernel/cobalt/trace/cobalt-posix.h | 31 +-- testsuite/smokey/sched-quota/sched-quota.c | 8 +- 5 files changed, 276 insertions(+), 171 deletions(-) diff --git a/include/cobalt/uapi/sched.h b/include/cobalt/uapi/sched.h index 8ead498..fc04f49 100644 --- a/include/cobalt/uapi/sched.h +++ b/include/cobalt/uapi/sched.h @@ -29,8 +29,6 @@ #define sched_ss_max_repl sched_u.ss.__sched_max_repl #endif /* !SCHED_SPORADIC */ -#define sched_rr_quantum sched_u.rr.__sched_rr_quantum - struct __sched_ss_param { int __sched_low_priority; struct timespec __sched_repl_period; @@ -38,6 +36,8 @@ struct __sched_ss_param { int __sched_max_repl; }; +#define sched_rr_quantum sched_u.rr.__sched_rr_quantum + struct __sched_rr_param { struct timespec __sched_rr_quantum; }; @@ -84,24 +84,28 @@ enum { struct __sched_config_quota { int op; - int *sum_r; - struct { - int pshared; - int *tgid_r; - } add; - struct { - int tgid; - } remove; - struct { + union { + struct { + int pshared; + } add; + struct { + int tgid; + } remove; + struct { + int tgid; + int quota; + int quota_peak; + } set; + struct { + int tgid; + } get; + }; + struct __sched_quota_info { int tgid; int quota; int quota_peak; - } set; - struct { - int tgid; - int *quota_r; - int *quota_peak_r; - } get; + int quota_sum; + } info; }; #define sched_quota_confsz() sizeof(struct __sched_config_quota) diff --git a/kernel/cobalt/posix/sched.c b/kernel/cobalt/posix/sched.c index bfdd2e0..f2fe09a 100644 --- a/kernel/cobalt/posix/sched.c +++ b/kernel/cobalt/posix/sched.c @@ -239,6 +239,9 @@ int set_tp_config(int cpu, union sched_config *config, size_t len) spl_t s; int n; + if (len < sizeof(config->tp)) + return -EINVAL; + if (config->tp.nr_windows == 0) { gps = NULL; goto set_schedule; @@ -294,15 +297,20 @@ fail: } static inline -ssize_t get_tp_config(int cpu, union sched_config __user *u_config, - size_t len) +ssize_t get_tp_config(int cpu, void __user *u_config, size_t len, + union sched_config *(*fetch_config) + (int policy, const void __user *u_config, + size_t *len), + ssize_t (*put_config)(int policy, void __user *u_config, + const union sched_config *config, + size_t len)) { struct xnsched_tp_window *pw, *w; struct xnsched_tp_schedule *gps; struct sched_tp_window *pp, *p; union sched_config *config; struct xnsched *sched; - ssize_t ret = 0, elen; + ssize_t ret, elen; spl_t s; int n; @@ -329,6 +337,7 @@ ssize_t get_tp_config(int cpu, union sched_config __user *u_config, goto out; } + ret = elen; config->tp.nr_windows = gps->pwin_nr; for (n = 0, pp = p = config->tp.windows, pw = w = gps->pwins; n < gps->pwin_nr; pp = p, p++, pw = w, w++, n++) { @@ -337,11 +346,12 @@ ssize_t get_tp_config(int cpu, union sched_config __user *u_config, p->ptid = w->w_part; } ns2ts(&pp->duration, gps->tf_duration - pw->w_offset); - ret = __xn_safe_copy_to_user(u_config, config, elen); + ret = put_config(SCHED_TP, u_config, config, elen); + xnfree(config); out: xnsched_tp_put_schedule(gps); - return ret ?: elen; + return ret; } #else /* !CONFIG_XENO_OPT_SCHED_TP */ @@ -353,8 +363,13 @@ set_tp_config(int cpu, union sched_config *config, size_t len) } static inline ssize_t -get_tp_config(int cpu, union sched_config __user *u_config, - size_t len) +get_tp_config(int cpu, union sched_config __user *u_config, size_t len, + union sched_config *(*fetch_config) + (int policy, const void __user *u_config, + size_t *len), + ssize_t (*put_config)(int policy, void __user *u_config, + const union sched_config *config, + size_t len)) { return -EINVAL; } @@ -364,19 +379,21 @@ get_tp_config(int cpu, union sched_config __user *u_config, #ifdef CONFIG_XENO_OPT_SCHED_QUOTA static inline -int do_quota_config(int cpu, const union sched_config *config, size_t len) +int set_quota_config(int cpu, union sched_config *config, size_t len) { - int ret = -ESRCH, quota_percent, quota_peak_percent, quota_sum; - const struct __sched_config_quota *p = &config->quota; + struct __sched_config_quota *p = &config->quota; + struct __sched_quota_info *iq = &p->info; struct cobalt_sched_group *group; struct xnsched_quota_group *tg; struct xnsched *sched; + int ret, quota_sum; spl_t s; if (len < sizeof(*p)) return -EINVAL; - if (p->op == sched_quota_add) { + switch (p->op) { + case sched_quota_add: group = xnmalloc(sizeof(*group)); if (group == NULL) return -ENOMEM; @@ -389,32 +406,21 @@ int do_quota_config(int cpu, const union sched_config *config, size_t len) if (ret) { xnlock_put_irqrestore(&nklock, s); xnfree(group); - } else { - list_add(&group->next, &group->kq->schedq); - xnlock_put_irqrestore(&nklock, s); - ret = __xn_safe_copy_to_user(p->add.tgid_r, &tg->tgid, - sizeof(tg->tgid)); - if (ret == 0 && p->sum_r) - ret = __xn_safe_copy_to_user(p->sum_r, "a_sum, - sizeof(quota_sum)); + return ret; } - return ret; - } - - if (p->op == sched_quota_remove || - p->op == sched_quota_force_remove) { + list_add(&group->next, &group->kq->schedq); + xnlock_put_irqrestore(&nklock, s); + break; + case sched_quota_remove: + case sched_quota_force_remove: xnlock_get_irqsave(&nklock, s); sched = xnsched_struct(cpu); tg = xnsched_quota_find_group(sched, p->remove.tgid); - if (tg == NULL) { - xnlock_put_irqrestore(&nklock, s); - return ret; - } + if (tg == NULL) + goto bad_tgid; group = container_of(tg, struct cobalt_sched_group, quota); - if (group->kq != cobalt_kqueues(group->pshared)) { - xnlock_put_irqrestore(&nklock, s); - return ret; - } + if (group->kq != cobalt_kqueues(group->pshared)) + goto bad_tgid; ret = xnsched_quota_destroy_group(tg, p->op == sched_quota_force_remove, "a_sum); @@ -425,103 +431,169 @@ int do_quota_config(int cpu, const union sched_config *config, size_t len) list_del(&group->next); xnlock_put_irqrestore(&nklock, s); xnfree(group); - if (p->sum_r) - ret = __xn_safe_copy_to_user(p->sum_r, "a_sum, - sizeof(quota_sum)); - return ret; - } - - if (p->op == sched_quota_set) { + break; + case sched_quota_set: xnlock_get_irqsave(&nklock, s); sched = xnsched_struct(cpu); tg = xnsched_quota_find_group(sched, p->set.tgid); - if (tg == NULL) { - xnlock_put_irqrestore(&nklock, s); - return ret; - } + if (tg == NULL) + goto bad_tgid; group = container_of(tg, struct cobalt_sched_group, quota); - if (group->kq != cobalt_kqueues(group->pshared)) { - xnlock_put_irqrestore(&nklock, s); - return ret; - } + if (group->kq != cobalt_kqueues(group->pshared)) + goto bad_tgid; xnsched_quota_set_limit(tg, p->set.quota, p->set.quota_peak, "a_sum); xnlock_put_irqrestore(&nklock, s); - ret = 0; - if (p->sum_r) - ret = __xn_safe_copy_to_user(p->sum_r, "a_sum, - sizeof(quota_sum)); - return ret; + break; + default: + return -EINVAL; } - if (p->op == sched_quota_get) { - xnlock_get_irqsave(&nklock, s); - sched = xnsched_struct(cpu); - tg = xnsched_quota_find_group(sched, p->get.tgid); - if (tg == NULL) { - xnlock_put_irqrestore(&nklock, s); - return ret; - } - group = container_of(tg, struct cobalt_sched_group, quota); - if (group->kq != cobalt_kqueues(group->pshared)) { - xnlock_put_irqrestore(&nklock, s); - return ret; - } - quota_percent = tg->quota_percent; - quota_peak_percent = tg->quota_peak_percent; - quota_sum = xnsched_quota_sum_all(sched); - xnlock_put_irqrestore(&nklock, s); - ret = __xn_safe_copy_to_user(p->get.quota_r, "a_percent, - sizeof(quota_percent)); - if (ret) - return ret; - ret = __xn_safe_copy_to_user(p->get.quota_peak_r, - "a_peak_percent, - sizeof(quota_peak_percent)); - if (ret == 0 && p->sum_r) - ret = __xn_safe_copy_to_user(p->sum_r, "a_sum, - sizeof(quota_sum)); - return ret; - } + iq->tgid = tg->tgid; + iq->quota = tg->quota_percent; + iq->quota_peak = tg->quota_peak_percent; + iq->quota_sum = quota_sum; - return -EINVAL; + return 0; +bad_tgid: + xnlock_put_irqrestore(&nklock, s); + + return -ESRCH; } static inline -ssize_t get_quota_config(int cpu, union sched_config __user *u_config, - size_t len) +ssize_t get_quota_config(int cpu, void __user *u_config, size_t len, + union sched_config *(*fetch_config) + (int policy, const void __user *u_config, + size_t *len), + ssize_t (*put_config)(int policy, void __user *u_config, + const union sched_config *config, + size_t len)) { - union sched_config buf; + struct cobalt_sched_group *group; + struct xnsched_quota_group *tg; + union sched_config *config; + struct xnsched *sched; + ssize_t ret; + spl_t s; - if (__xn_safe_copy_from_user(&buf, (const void __user *)u_config, len)) - return -EFAULT; + if (len < sizeof(config->quota)) + return -EINVAL; + + config = fetch_config(SCHED_QUOTA, u_config, &len); + if (IS_ERR(config)) + return PTR_ERR(config); + + xnlock_get_irqsave(&nklock, s); + sched = xnsched_struct(cpu); + tg = xnsched_quota_find_group(sched, config->quota.get.tgid); + if (tg == NULL) + goto bad_tgid; + + group = container_of(tg, struct cobalt_sched_group, quota); + if (group->kq != cobalt_kqueues(group->pshared)) + goto bad_tgid; + + config->quota.info.tgid = tg->tgid; + config->quota.info.quota = tg->quota_percent; + config->quota.info.quota_peak = tg->quota_peak_percent; + config->quota.info.quota_sum = xnsched_quota_sum_all(sched); + xnlock_put_irqrestore(&nklock, s); - buf.quota.op = sched_quota_get; + ret = put_config(SCHED_QUOTA, u_config, config, sizeof(*config)); + xnfree(config); - return do_quota_config(cpu, &buf, len); + return ret; +bad_tgid: + xnlock_put_irqrestore(&nklock, s); + xnfree(config); + + return -ESRCH; } #else /* !CONFIG_XENO_OPT_SCHED_QUOTA */ static inline -int do_quota_config(int cpu, const union sched_config *config, size_t len) +int set_quota_config(int cpu, union sched_config *config, size_t len) { return -EINVAL; } static inline -ssize_t get_quota_config(int cpu, union sched_config __user *u_config, - size_t len) +ssize_t get_quota_config(int cpu, void __user *u_config, + size_t len, + union sched_config *(*fetch_config) + (int policy, const void __user *u_config, + size_t *len), + ssize_t (*put_config)(int policy, void __user *u_config, + const union sched_config *config, + size_t len)) { return -EINVAL; } #endif /* !CONFIG_XENO_OPT_SCHED_QUOTA */ -COBALT_SYSCALL(sched_setconfig_np, current, - int, (int cpu, int policy, - const union sched_config __user *u_config, - size_t len)) +static union sched_config * +sched_fetch_config(int policy, const void __user *u_config, size_t *len) +{ + union sched_config *buf; + int ret; + + if (u_config == NULL) + return ERR_PTR(-EFAULT); + + buf = xnmalloc(*len); + if (buf == NULL) + return ERR_PTR(-ENOMEM); + + ret = __xn_safe_copy_from_user(buf, u_config, *len); + if (ret) { + xnfree(buf); + return ERR_PTR(ret); + } + + return buf; +} + +static int sched_ack_config(int policy, const union sched_config *config, + void __user *u_config) +{ + union sched_config __user *u_p = u_config; + + if (policy != SCHED_QUOTA) + return 0; + + return u_p == NULL ? -EFAULT : + __xn_safe_copy_to_user(&u_p->quota.info, &config->quota.info, + sizeof(u_p->quota.info)); +} + +static ssize_t sched_put_config(int policy, void __user *u_config, + const union sched_config *config, size_t len) +{ + union sched_config *u_p = u_config; + + if (u_config == NULL) + return -EFAULT; + + if (policy == SCHED_QUOTA) + return __xn_safe_copy_to_user(&u_p->quota.info, &config->quota.info, + sizeof(u_p->quota.info)) ?: + sizeof(u_p->quota.info); + + return __xn_safe_copy_to_user(u_config, config, len) ?: len; +} + +int __cobalt_sched_setconfig_np(int cpu, int policy, + void __user *u_config, + size_t len, + union sched_config *(*fetch_config) + (int policy, const void __user *u_config, + size_t *len), + int (*ack_config)(int policy, + const union sched_config *config, + void __user *u_config)) { union sched_config *buf; int ret; @@ -534,44 +606,59 @@ COBALT_SYSCALL(sched_setconfig_np, current, if (len == 0) return -EINVAL; - buf = xnmalloc(len); - if (buf == NULL) - return -ENOMEM; - - if (__xn_safe_copy_from_user(buf, (const void __user *)u_config, len)) { - ret = -EFAULT; - goto out; - } + buf = fetch_config(policy, u_config, &len); + if (IS_ERR(buf)) + return PTR_ERR(buf); switch (policy) { case SCHED_TP: ret = set_tp_config(cpu, buf, len); break; case SCHED_QUOTA: - ret = do_quota_config(cpu, buf, len); + ret = set_quota_config(cpu, buf, len); break; default: ret = -EINVAL; } -out: + + if (ret == 0) + ret = ack_config(policy, buf, u_config); + xnfree(buf); return ret; } -COBALT_SYSCALL(sched_getconfig_np, current, - ssize_t, (int cpu, int policy, - union sched_config __user *u_config, - size_t len)) +COBALT_SYSCALL(sched_setconfig_np, current, + int, (int cpu, int policy, + union sched_config __user *u_config, + size_t len)) +{ + return __cobalt_sched_setconfig_np(cpu, policy, u_config, len, + sched_fetch_config, sched_ack_config); +} + +ssize_t __cobalt_sched_getconfig_np(int cpu, int policy, + void __user *u_config, + size_t len, + union sched_config *(*fetch_config) + (int policy, const void __user *u_config, + size_t *len), + ssize_t (*put_config)(int policy, + void __user *u_config, + const union sched_config *config, + size_t len)) { ssize_t ret; switch (policy) { case SCHED_TP: - ret = get_tp_config(cpu, u_config, len); + ret = get_tp_config(cpu, u_config, len, + fetch_config, put_config); break; case SCHED_QUOTA: - ret = get_quota_config(cpu, u_config, len); + ret = get_quota_config(cpu, u_config, len, + fetch_config, put_config); break; default: ret = -EINVAL; @@ -582,30 +669,46 @@ COBALT_SYSCALL(sched_getconfig_np, current, return ret; } -COBALT_SYSCALL(sched_weightprio, current, - int, (int policy, - const struct sched_param_ex __user *u_param)) +COBALT_SYSCALL(sched_getconfig_np, current, + ssize_t, (int cpu, int policy, + union sched_config __user *u_config, + size_t len)) +{ + return __cobalt_sched_getconfig_np(cpu, policy, u_config, len, + sched_fetch_config, sched_put_config); +} + +int __cobalt_sched_weightprio(int policy, + const struct sched_param_ex *param_ex) { struct xnsched_class *sched_class; union xnsched_policy_param param; - struct sched_param_ex param_ex; int prio; - if (__xn_safe_copy_from_user(¶m_ex, u_param, sizeof(param_ex))) - return -EFAULT; - sched_class = cobalt_sched_policy_param(¶m, policy, - ¶m_ex, NULL); + param_ex, NULL); if (sched_class == NULL) return -EINVAL; - prio = param_ex.sched_priority; + prio = param_ex->sched_priority; if (prio < 0) prio = -prio; return prio + sched_class->weight; } +COBALT_SYSCALL(sched_weightprio, current, + int, (int policy, + const struct sched_param_ex __user *u_param)) +{ + struct sched_param_ex param_ex; + + if (__xn_safe_copy_from_user(¶m_ex, u_param, sizeof(param_ex))) + return -EFAULT; + + return __cobalt_sched_weightprio(policy, ¶m_ex); +} + void cobalt_sched_cleanup(struct cobalt_kqueues *q) { struct cobalt_sched_group *group; diff --git a/kernel/cobalt/posix/sched.h b/kernel/cobalt/posix/sched.h index db5e152..aa93fe1 100644 --- a/kernel/cobalt/posix/sched.h +++ b/kernel/cobalt/posix/sched.h @@ -33,6 +33,29 @@ struct cobalt_sched_group { struct list_head next; }; +int __cobalt_sched_weightprio(int policy, + const struct sched_param_ex *param_ex); + +int __cobalt_sched_setconfig_np(int cpu, int policy, + void __user *u_config, + size_t len, + union sched_config *(*fetch_config) + (int policy, const void __user *u_config, + size_t *len), + int (*ack_config)(int policy, + const union sched_config *config, + void __user *u_config)); + +ssize_t __cobalt_sched_getconfig_np(int cpu, int policy, + void __user *u_config, + size_t len, + union sched_config *(*fetch_config) + (int policy, const void __user *u_config, + size_t *len), + ssize_t (*put_config)(int policy, + void __user *u_config, + const union sched_config *config, + size_t len)); struct xnsched_class * cobalt_sched_policy_param(union xnsched_policy_param *param, int u_policy, const struct sched_param_ex *param_ex, @@ -51,7 +74,7 @@ COBALT_SYSCALL_DECL(sched_maxprio, int, (int policy)); COBALT_SYSCALL_DECL(sched_setconfig_np, int, (int cpu, int policy, - const union sched_config __user *u_config, + union sched_config __user *u_config, size_t len)); COBALT_SYSCALL_DECL(sched_getconfig_np, diff --git a/kernel/cobalt/trace/cobalt-posix.h b/kernel/cobalt/trace/cobalt-posix.h index a143e97..66ebbe8 100644 --- a/kernel/cobalt/trace/cobalt-posix.h +++ b/kernel/cobalt/trace/cobalt-posix.h @@ -113,7 +113,7 @@ DECLARE_EVENT_CLASS(syscall_exit, DECLARE_EVENT_CLASS(cobalt_posix_schedparam, TP_PROTO(unsigned long pth, int policy, - struct sched_param_ex *param_ex), + const struct sched_param_ex *param_ex), TP_ARGS(pth, policy, param_ex), TP_STRUCT__entry( @@ -171,19 +171,19 @@ DEFINE_EVENT(syscall_exit, cobalt_root_sysexit, DEFINE_EVENT(cobalt_posix_schedparam, cobalt_pthread_create, TP_PROTO(unsigned long pth, int policy, - struct sched_param_ex *param_ex), + const struct sched_param_ex *param_ex), TP_ARGS(pth, policy, param_ex) ); DEFINE_EVENT(cobalt_posix_schedparam, cobalt_pthread_setschedparam, TP_PROTO(unsigned long pth, int policy, - struct sched_param_ex *param_ex), + const struct sched_param_ex *param_ex), TP_ARGS(pth, policy, param_ex) ); DEFINE_EVENT(cobalt_posix_schedparam, cobalt_pthread_getschedparam, TP_PROTO(unsigned long pth, int policy, - struct sched_param_ex *param_ex), + const struct sched_param_ex *param_ex), TP_ARGS(pth, policy, param_ex) ); @@ -809,29 +809,6 @@ TRACE_EVENT(cobalt_mq_unlink, TP_printk("name=%s", __get_str(name)) ); -TRACE_EVENT(cobalt_mq_timedsend, - TP_PROTO(mqd_t mqd, const void __user *u_buf, size_t len, - unsigned int prio, const struct timespec *timeout), - TP_ARGS(mqd, u_buf, len, prio, timeout), - TP_STRUCT__entry( - __field(mqd_t, mqd) - __field(const void __user *, u_buf) - __field(size_t, len) - __field(unsigned int, prio) - __timespec_fields(timeout) - ), - TP_fast_assign( - __entry->mqd = mqd; - __entry->u_buf = u_buf; - __entry->len = len; - __entry->prio = prio; - __assign_timespec(timeout, timeout); - ), - TP_printk("mqd=%d buf=%p len=%Zu prio=%u timeout=(%ld.%09ld)", - __entry->mqd, __entry->u_buf, __entry->len, - __entry->prio, __timespec_args(timeout)) -); - TRACE_EVENT(cobalt_mq_send, TP_PROTO(mqd_t mqd, const void __user *u_buf, size_t len, unsigned int prio), diff --git a/testsuite/smokey/sched-quota/sched-quota.c b/testsuite/smokey/sched-quota/sched-quota.c index 1bacafb..e8f4347 100644 --- a/testsuite/smokey/sched-quota/sched-quota.c +++ b/testsuite/smokey/sched-quota/sched-quota.c @@ -154,22 +154,20 @@ static void __create_fifo_thread(pthread_t *tid, const char *name, static double run_quota(int quota) { size_t len = sched_quota_confsz(); - int ret, tgid, n, quota_sum; unsigned long long count; union sched_config cf; struct timespec req; + int ret, tgid, n; double percent; char label[8]; - cf.quota.sum_r = "a_sum; - cf.quota.op = sched_quota_add; cf.quota.add.pshared = 0; - cf.quota.add.tgid_r = &tgid; ret = sched_setconfig_np(0, SCHED_QUOTA, &cf, len); if (ret) error(1, ret, "sched_setconfig_np(add-quota-group)"); + tgid = cf.quota.info.tgid; cf.quota.op = sched_quota_set; cf.quota.set.quota = quota; cf.quota.set.quota_peak = quota; @@ -179,7 +177,7 @@ static double run_quota(int quota) error(1, ret, "sched_setconfig_np(set-quota, tgid=%d)", tgid); printf("new thread group #%d on CPU0, quota sum is %d%%\n", - tgid, quota_sum); + tgid, cf.quota.info.quota_sum); for (n = 0; n < nrthreads; n++) { sprintf(label, "t%d", n); _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git