diff options
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r-- | fs/proc/base.c | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 69078c7cef1f..a19308604145 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -86,6 +86,7 @@ | |||
86 | #include <linux/fs_struct.h> | 86 | #include <linux/fs_struct.h> |
87 | #include <linux/slab.h> | 87 | #include <linux/slab.h> |
88 | #include <linux/flex_array.h> | 88 | #include <linux/flex_array.h> |
89 | #include <linux/posix-timers.h> | ||
89 | #ifdef CONFIG_HARDWALL | 90 | #ifdef CONFIG_HARDWALL |
90 | #include <asm/hardwall.h> | 91 | #include <asm/hardwall.h> |
91 | #endif | 92 | #endif |
@@ -2013,6 +2014,102 @@ static const struct file_operations proc_map_files_operations = { | |||
2013 | .llseek = default_llseek, | 2014 | .llseek = default_llseek, |
2014 | }; | 2015 | }; |
2015 | 2016 | ||
2017 | struct timers_private { | ||
2018 | struct pid *pid; | ||
2019 | struct task_struct *task; | ||
2020 | struct sighand_struct *sighand; | ||
2021 | struct pid_namespace *ns; | ||
2022 | unsigned long flags; | ||
2023 | }; | ||
2024 | |||
2025 | static void *timers_start(struct seq_file *m, loff_t *pos) | ||
2026 | { | ||
2027 | struct timers_private *tp = m->private; | ||
2028 | |||
2029 | tp->task = get_pid_task(tp->pid, PIDTYPE_PID); | ||
2030 | if (!tp->task) | ||
2031 | return ERR_PTR(-ESRCH); | ||
2032 | |||
2033 | tp->sighand = lock_task_sighand(tp->task, &tp->flags); | ||
2034 | if (!tp->sighand) | ||
2035 | return ERR_PTR(-ESRCH); | ||
2036 | |||
2037 | return seq_list_start(&tp->task->signal->posix_timers, *pos); | ||
2038 | } | ||
2039 | |||
2040 | static void *timers_next(struct seq_file *m, void *v, loff_t *pos) | ||
2041 | { | ||
2042 | struct timers_private *tp = m->private; | ||
2043 | return seq_list_next(v, &tp->task->signal->posix_timers, pos); | ||
2044 | } | ||
2045 | |||
2046 | static void timers_stop(struct seq_file *m, void *v) | ||
2047 | { | ||
2048 | struct timers_private *tp = m->private; | ||
2049 | |||
2050 | if (tp->sighand) { | ||
2051 | unlock_task_sighand(tp->task, &tp->flags); | ||
2052 | tp->sighand = NULL; | ||
2053 | } | ||
2054 | |||
2055 | if (tp->task) { | ||
2056 | put_task_struct(tp->task); | ||
2057 | tp->task = NULL; | ||
2058 | } | ||
2059 | } | ||
2060 | |||
2061 | static int show_timer(struct seq_file *m, void *v) | ||
2062 | { | ||
2063 | struct k_itimer *timer; | ||
2064 | struct timers_private *tp = m->private; | ||
2065 | int notify; | ||
2066 | static char *nstr[] = { | ||
2067 | [SIGEV_SIGNAL] = "signal", | ||
2068 | [SIGEV_NONE] = "none", | ||
2069 | [SIGEV_THREAD] = "thread", | ||
2070 | }; | ||
2071 | |||
2072 | timer = list_entry((struct list_head *)v, struct k_itimer, list); | ||
2073 | notify = timer->it_sigev_notify; | ||
2074 | |||
2075 | seq_printf(m, "ID: %d\n", timer->it_id); | ||
2076 | seq_printf(m, "signal: %d/%p\n", timer->sigq->info.si_signo, | ||
2077 | timer->sigq->info.si_value.sival_ptr); | ||
2078 | seq_printf(m, "notify: %s/%s.%d\n", | ||
2079 | nstr[notify & ~SIGEV_THREAD_ID], | ||
2080 | (notify & SIGEV_THREAD_ID) ? "tid" : "pid", | ||
2081 | pid_nr_ns(timer->it_pid, tp->ns)); | ||
2082 | |||
2083 | return 0; | ||
2084 | } | ||
2085 | |||
2086 | static const struct seq_operations proc_timers_seq_ops = { | ||
2087 | .start = timers_start, | ||
2088 | .next = timers_next, | ||
2089 | .stop = timers_stop, | ||
2090 | .show = show_timer, | ||
2091 | }; | ||
2092 | |||
2093 | static int proc_timers_open(struct inode *inode, struct file *file) | ||
2094 | { | ||
2095 | struct timers_private *tp; | ||
2096 | |||
2097 | tp = __seq_open_private(file, &proc_timers_seq_ops, | ||
2098 | sizeof(struct timers_private)); | ||
2099 | if (!tp) | ||
2100 | return -ENOMEM; | ||
2101 | |||
2102 | tp->pid = proc_pid(inode); | ||
2103 | tp->ns = inode->i_sb->s_fs_info; | ||
2104 | return 0; | ||
2105 | } | ||
2106 | |||
2107 | static const struct file_operations proc_timers_operations = { | ||
2108 | .open = proc_timers_open, | ||
2109 | .read = seq_read, | ||
2110 | .llseek = seq_lseek, | ||
2111 | .release = seq_release_private, | ||
2112 | }; | ||
2016 | #endif /* CONFIG_CHECKPOINT_RESTORE */ | 2113 | #endif /* CONFIG_CHECKPOINT_RESTORE */ |
2017 | 2114 | ||
2018 | static struct dentry *proc_pident_instantiate(struct inode *dir, | 2115 | static struct dentry *proc_pident_instantiate(struct inode *dir, |
@@ -2583,6 +2680,9 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2583 | REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), | 2680 | REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), |
2584 | REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations), | 2681 | REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations), |
2585 | #endif | 2682 | #endif |
2683 | #ifdef CONFIG_CHECKPOINT_RESTORE | ||
2684 | REG("timers", S_IRUGO, proc_timers_operations), | ||
2685 | #endif | ||
2586 | }; | 2686 | }; |
2587 | 2687 | ||
2588 | static int proc_tgid_base_readdir(struct file * filp, | 2688 | static int proc_tgid_base_readdir(struct file * filp, |