diff options
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/array.c | 15 | ||||
-rw-r--r-- | fs/proc/base.c | 83 | ||||
-rw-r--r-- | fs/proc/generic.c | 52 | ||||
-rw-r--r-- | fs/proc/inode.c | 254 | ||||
-rw-r--r-- | fs/proc/proc_misc.c | 7 | ||||
-rw-r--r-- | fs/proc/proc_tty.c | 15 |
6 files changed, 318 insertions, 108 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index 4cb81776a7ff..965625a0977d 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -289,6 +289,15 @@ static inline char *task_cap(struct task_struct *p, char *buffer) | |||
289 | cap_t(p->cap_effective)); | 289 | cap_t(p->cap_effective)); |
290 | } | 290 | } |
291 | 291 | ||
292 | static inline char *task_context_switch_counts(struct task_struct *p, | ||
293 | char *buffer) | ||
294 | { | ||
295 | return buffer + sprintf(buffer, "voluntary_ctxt_switches:\t%lu\n" | ||
296 | "nonvoluntary_ctxt_switches:\t%lu\n", | ||
297 | p->nvcsw, | ||
298 | p->nivcsw); | ||
299 | } | ||
300 | |||
292 | int proc_pid_status(struct task_struct *task, char *buffer) | 301 | int proc_pid_status(struct task_struct *task, char *buffer) |
293 | { | 302 | { |
294 | char *orig = buffer; | 303 | char *orig = buffer; |
@@ -307,6 +316,7 @@ int proc_pid_status(struct task_struct *task, char *buffer) | |||
307 | #if defined(CONFIG_S390) | 316 | #if defined(CONFIG_S390) |
308 | buffer = task_show_regs(task, buffer); | 317 | buffer = task_show_regs(task, buffer); |
309 | #endif | 318 | #endif |
319 | buffer = task_context_switch_counts(task, buffer); | ||
310 | return buffer - orig; | 320 | return buffer - orig; |
311 | } | 321 | } |
312 | 322 | ||
@@ -439,8 +449,9 @@ static int do_task_stat(struct task_struct *task, char *buffer, int whole) | |||
439 | 449 | ||
440 | /* Temporary variable needed for gcc-2.96 */ | 450 | /* Temporary variable needed for gcc-2.96 */ |
441 | /* convert timespec -> nsec*/ | 451 | /* convert timespec -> nsec*/ |
442 | start_time = (unsigned long long)task->start_time.tv_sec * NSEC_PER_SEC | 452 | start_time = |
443 | + task->start_time.tv_nsec; | 453 | (unsigned long long)task->real_start_time.tv_sec * NSEC_PER_SEC |
454 | + task->real_start_time.tv_nsec; | ||
444 | /* convert nsec -> ticks */ | 455 | /* convert nsec -> ticks */ |
445 | start_time = nsec_to_clock_t(start_time); | 456 | start_time = nsec_to_clock_t(start_time); |
446 | 457 | ||
diff --git a/fs/proc/base.c b/fs/proc/base.c index 46ea5d56e1bb..ae3627337a92 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -67,7 +67,6 @@ | |||
67 | #include <linux/mount.h> | 67 | #include <linux/mount.h> |
68 | #include <linux/security.h> | 68 | #include <linux/security.h> |
69 | #include <linux/ptrace.h> | 69 | #include <linux/ptrace.h> |
70 | #include <linux/seccomp.h> | ||
71 | #include <linux/cpuset.h> | 70 | #include <linux/cpuset.h> |
72 | #include <linux/audit.h> | 71 | #include <linux/audit.h> |
73 | #include <linux/poll.h> | 72 | #include <linux/poll.h> |
@@ -204,12 +203,17 @@ static int proc_pid_environ(struct task_struct *task, char * buffer) | |||
204 | int res = 0; | 203 | int res = 0; |
205 | struct mm_struct *mm = get_task_mm(task); | 204 | struct mm_struct *mm = get_task_mm(task); |
206 | if (mm) { | 205 | if (mm) { |
207 | unsigned int len = mm->env_end - mm->env_start; | 206 | unsigned int len; |
207 | |||
208 | res = -ESRCH; | ||
209 | if (!ptrace_may_attach(task)) | ||
210 | goto out; | ||
211 | |||
212 | len = mm->env_end - mm->env_start; | ||
208 | if (len > PAGE_SIZE) | 213 | if (len > PAGE_SIZE) |
209 | len = PAGE_SIZE; | 214 | len = PAGE_SIZE; |
210 | res = access_process_vm(task, mm->env_start, buffer, len, 0); | 215 | res = access_process_vm(task, mm->env_start, buffer, len, 0); |
211 | if (!ptrace_may_attach(task)) | 216 | out: |
212 | res = -ESRCH; | ||
213 | mmput(mm); | 217 | mmput(mm); |
214 | } | 218 | } |
215 | return res; | 219 | return res; |
@@ -812,71 +816,6 @@ static const struct file_operations proc_loginuid_operations = { | |||
812 | }; | 816 | }; |
813 | #endif | 817 | #endif |
814 | 818 | ||
815 | #ifdef CONFIG_SECCOMP | ||
816 | static ssize_t seccomp_read(struct file *file, char __user *buf, | ||
817 | size_t count, loff_t *ppos) | ||
818 | { | ||
819 | struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode); | ||
820 | char __buf[20]; | ||
821 | size_t len; | ||
822 | |||
823 | if (!tsk) | ||
824 | return -ESRCH; | ||
825 | /* no need to print the trailing zero, so use only len */ | ||
826 | len = sprintf(__buf, "%u\n", tsk->seccomp.mode); | ||
827 | put_task_struct(tsk); | ||
828 | |||
829 | return simple_read_from_buffer(buf, count, ppos, __buf, len); | ||
830 | } | ||
831 | |||
832 | static ssize_t seccomp_write(struct file *file, const char __user *buf, | ||
833 | size_t count, loff_t *ppos) | ||
834 | { | ||
835 | struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode); | ||
836 | char __buf[20], *end; | ||
837 | unsigned int seccomp_mode; | ||
838 | ssize_t result; | ||
839 | |||
840 | result = -ESRCH; | ||
841 | if (!tsk) | ||
842 | goto out_no_task; | ||
843 | |||
844 | /* can set it only once to be even more secure */ | ||
845 | result = -EPERM; | ||
846 | if (unlikely(tsk->seccomp.mode)) | ||
847 | goto out; | ||
848 | |||
849 | result = -EFAULT; | ||
850 | memset(__buf, 0, sizeof(__buf)); | ||
851 | count = min(count, sizeof(__buf) - 1); | ||
852 | if (copy_from_user(__buf, buf, count)) | ||
853 | goto out; | ||
854 | |||
855 | seccomp_mode = simple_strtoul(__buf, &end, 0); | ||
856 | if (*end == '\n') | ||
857 | end++; | ||
858 | result = -EINVAL; | ||
859 | if (seccomp_mode && seccomp_mode <= NR_SECCOMP_MODES) { | ||
860 | tsk->seccomp.mode = seccomp_mode; | ||
861 | set_tsk_thread_flag(tsk, TIF_SECCOMP); | ||
862 | } else | ||
863 | goto out; | ||
864 | result = -EIO; | ||
865 | if (unlikely(!(end - __buf))) | ||
866 | goto out; | ||
867 | result = end - __buf; | ||
868 | out: | ||
869 | put_task_struct(tsk); | ||
870 | out_no_task: | ||
871 | return result; | ||
872 | } | ||
873 | |||
874 | static const struct file_operations proc_seccomp_operations = { | ||
875 | .read = seccomp_read, | ||
876 | .write = seccomp_write, | ||
877 | }; | ||
878 | #endif /* CONFIG_SECCOMP */ | ||
879 | |||
880 | #ifdef CONFIG_FAULT_INJECTION | 819 | #ifdef CONFIG_FAULT_INJECTION |
881 | static ssize_t proc_fault_inject_read(struct file * file, char __user * buf, | 820 | static ssize_t proc_fault_inject_read(struct file * file, char __user * buf, |
882 | size_t count, loff_t *ppos) | 821 | size_t count, loff_t *ppos) |
@@ -2037,9 +1976,6 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2037 | REG("numa_maps", S_IRUGO, numa_maps), | 1976 | REG("numa_maps", S_IRUGO, numa_maps), |
2038 | #endif | 1977 | #endif |
2039 | REG("mem", S_IRUSR|S_IWUSR, mem), | 1978 | REG("mem", S_IRUSR|S_IWUSR, mem), |
2040 | #ifdef CONFIG_SECCOMP | ||
2041 | REG("seccomp", S_IRUSR|S_IWUSR, seccomp), | ||
2042 | #endif | ||
2043 | LNK("cwd", cwd), | 1979 | LNK("cwd", cwd), |
2044 | LNK("root", root), | 1980 | LNK("root", root), |
2045 | LNK("exe", exe), | 1981 | LNK("exe", exe), |
@@ -2324,9 +2260,6 @@ static const struct pid_entry tid_base_stuff[] = { | |||
2324 | REG("numa_maps", S_IRUGO, numa_maps), | 2260 | REG("numa_maps", S_IRUGO, numa_maps), |
2325 | #endif | 2261 | #endif |
2326 | REG("mem", S_IRUSR|S_IWUSR, mem), | 2262 | REG("mem", S_IRUSR|S_IWUSR, mem), |
2327 | #ifdef CONFIG_SECCOMP | ||
2328 | REG("seccomp", S_IRUSR|S_IWUSR, seccomp), | ||
2329 | #endif | ||
2330 | LNK("cwd", cwd), | 2263 | LNK("cwd", cwd), |
2331 | LNK("root", root), | 2264 | LNK("root", root), |
2332 | LNK("exe", exe), | 2265 | LNK("exe", exe), |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 8a40e15f5ecb..b5e7155d30d8 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/namei.h> | 20 | #include <linux/namei.h> |
21 | #include <linux/bitops.h> | 21 | #include <linux/bitops.h> |
22 | #include <linux/spinlock.h> | 22 | #include <linux/spinlock.h> |
23 | #include <linux/completion.h> | ||
23 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
24 | 25 | ||
25 | #include "internal.h" | 26 | #include "internal.h" |
@@ -529,12 +530,6 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp | |||
529 | return -EAGAIN; | 530 | return -EAGAIN; |
530 | dp->low_ino = i; | 531 | dp->low_ino = i; |
531 | 532 | ||
532 | spin_lock(&proc_subdir_lock); | ||
533 | dp->next = dir->subdir; | ||
534 | dp->parent = dir; | ||
535 | dir->subdir = dp; | ||
536 | spin_unlock(&proc_subdir_lock); | ||
537 | |||
538 | if (S_ISDIR(dp->mode)) { | 533 | if (S_ISDIR(dp->mode)) { |
539 | if (dp->proc_iops == NULL) { | 534 | if (dp->proc_iops == NULL) { |
540 | dp->proc_fops = &proc_dir_operations; | 535 | dp->proc_fops = &proc_dir_operations; |
@@ -550,6 +545,13 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp | |||
550 | if (dp->proc_iops == NULL) | 545 | if (dp->proc_iops == NULL) |
551 | dp->proc_iops = &proc_file_inode_operations; | 546 | dp->proc_iops = &proc_file_inode_operations; |
552 | } | 547 | } |
548 | |||
549 | spin_lock(&proc_subdir_lock); | ||
550 | dp->next = dir->subdir; | ||
551 | dp->parent = dir; | ||
552 | dir->subdir = dp; | ||
553 | spin_unlock(&proc_subdir_lock); | ||
554 | |||
553 | return 0; | 555 | return 0; |
554 | } | 556 | } |
555 | 557 | ||
@@ -613,6 +615,9 @@ static struct proc_dir_entry *proc_create(struct proc_dir_entry **parent, | |||
613 | ent->namelen = len; | 615 | ent->namelen = len; |
614 | ent->mode = mode; | 616 | ent->mode = mode; |
615 | ent->nlink = nlink; | 617 | ent->nlink = nlink; |
618 | ent->pde_users = 0; | ||
619 | spin_lock_init(&ent->pde_unload_lock); | ||
620 | ent->pde_unload_completion = NULL; | ||
616 | out: | 621 | out: |
617 | return ent; | 622 | return ent; |
618 | } | 623 | } |
@@ -649,9 +654,6 @@ struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode, | |||
649 | 654 | ||
650 | ent = proc_create(&parent, name, S_IFDIR | mode, 2); | 655 | ent = proc_create(&parent, name, S_IFDIR | mode, 2); |
651 | if (ent) { | 656 | if (ent) { |
652 | ent->proc_fops = &proc_dir_operations; | ||
653 | ent->proc_iops = &proc_dir_inode_operations; | ||
654 | |||
655 | if (proc_register(parent, ent) < 0) { | 657 | if (proc_register(parent, ent) < 0) { |
656 | kfree(ent); | 658 | kfree(ent); |
657 | ent = NULL; | 659 | ent = NULL; |
@@ -686,10 +688,6 @@ struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, | |||
686 | 688 | ||
687 | ent = proc_create(&parent,name,mode,nlink); | 689 | ent = proc_create(&parent,name,mode,nlink); |
688 | if (ent) { | 690 | if (ent) { |
689 | if (S_ISDIR(mode)) { | ||
690 | ent->proc_fops = &proc_dir_operations; | ||
691 | ent->proc_iops = &proc_dir_inode_operations; | ||
692 | } | ||
693 | if (proc_register(parent, ent) < 0) { | 691 | if (proc_register(parent, ent) < 0) { |
694 | kfree(ent); | 692 | kfree(ent); |
695 | ent = NULL; | 693 | ent = NULL; |
@@ -734,9 +732,35 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
734 | de = *p; | 732 | de = *p; |
735 | *p = de->next; | 733 | *p = de->next; |
736 | de->next = NULL; | 734 | de->next = NULL; |
735 | |||
736 | spin_lock(&de->pde_unload_lock); | ||
737 | /* | ||
738 | * Stop accepting new callers into module. If you're | ||
739 | * dynamically allocating ->proc_fops, save a pointer somewhere. | ||
740 | */ | ||
741 | de->proc_fops = NULL; | ||
742 | /* Wait until all existing callers into module are done. */ | ||
743 | if (de->pde_users > 0) { | ||
744 | DECLARE_COMPLETION_ONSTACK(c); | ||
745 | |||
746 | if (!de->pde_unload_completion) | ||
747 | de->pde_unload_completion = &c; | ||
748 | |||
749 | spin_unlock(&de->pde_unload_lock); | ||
750 | spin_unlock(&proc_subdir_lock); | ||
751 | |||
752 | wait_for_completion(de->pde_unload_completion); | ||
753 | |||
754 | spin_lock(&proc_subdir_lock); | ||
755 | goto continue_removing; | ||
756 | } | ||
757 | spin_unlock(&de->pde_unload_lock); | ||
758 | |||
759 | continue_removing: | ||
737 | if (S_ISDIR(de->mode)) | 760 | if (S_ISDIR(de->mode)) |
738 | parent->nlink--; | 761 | parent->nlink--; |
739 | proc_kill_inodes(de); | 762 | if (!S_ISREG(de->mode)) |
763 | proc_kill_inodes(de); | ||
740 | de->nlink = 0; | 764 | de->nlink = 0; |
741 | WARN_ON(de->subdir); | 765 | WARN_ON(de->subdir); |
742 | if (!atomic_read(&de->count)) | 766 | if (!atomic_read(&de->count)) |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index d5ce65c68d7b..dd28e86ab422 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/mm.h> | 10 | #include <linux/mm.h> |
11 | #include <linux/string.h> | 11 | #include <linux/string.h> |
12 | #include <linux/stat.h> | 12 | #include <linux/stat.h> |
13 | #include <linux/completion.h> | ||
13 | #include <linux/file.h> | 14 | #include <linux/file.h> |
14 | #include <linux/limits.h> | 15 | #include <linux/limits.h> |
15 | #include <linux/init.h> | 16 | #include <linux/init.h> |
@@ -140,6 +141,251 @@ static const struct super_operations proc_sops = { | |||
140 | .remount_fs = proc_remount, | 141 | .remount_fs = proc_remount, |
141 | }; | 142 | }; |
142 | 143 | ||
144 | static void pde_users_dec(struct proc_dir_entry *pde) | ||
145 | { | ||
146 | spin_lock(&pde->pde_unload_lock); | ||
147 | pde->pde_users--; | ||
148 | if (pde->pde_unload_completion && pde->pde_users == 0) | ||
149 | complete(pde->pde_unload_completion); | ||
150 | spin_unlock(&pde->pde_unload_lock); | ||
151 | } | ||
152 | |||
153 | static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence) | ||
154 | { | ||
155 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | ||
156 | loff_t rv = -EINVAL; | ||
157 | loff_t (*llseek)(struct file *, loff_t, int); | ||
158 | |||
159 | spin_lock(&pde->pde_unload_lock); | ||
160 | /* | ||
161 | * remove_proc_entry() is going to delete PDE (as part of module | ||
162 | * cleanup sequence). No new callers into module allowed. | ||
163 | */ | ||
164 | if (!pde->proc_fops) { | ||
165 | spin_unlock(&pde->pde_unload_lock); | ||
166 | return rv; | ||
167 | } | ||
168 | /* | ||
169 | * Bump refcount so that remove_proc_entry will wail for ->llseek to | ||
170 | * complete. | ||
171 | */ | ||
172 | pde->pde_users++; | ||
173 | /* | ||
174 | * Save function pointer under lock, to protect against ->proc_fops | ||
175 | * NULL'ifying right after ->pde_unload_lock is dropped. | ||
176 | */ | ||
177 | llseek = pde->proc_fops->llseek; | ||
178 | spin_unlock(&pde->pde_unload_lock); | ||
179 | |||
180 | if (!llseek) | ||
181 | llseek = default_llseek; | ||
182 | rv = llseek(file, offset, whence); | ||
183 | |||
184 | pde_users_dec(pde); | ||
185 | return rv; | ||
186 | } | ||
187 | |||
188 | static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | ||
189 | { | ||
190 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | ||
191 | ssize_t rv = -EIO; | ||
192 | ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); | ||
193 | |||
194 | spin_lock(&pde->pde_unload_lock); | ||
195 | if (!pde->proc_fops) { | ||
196 | spin_unlock(&pde->pde_unload_lock); | ||
197 | return rv; | ||
198 | } | ||
199 | pde->pde_users++; | ||
200 | read = pde->proc_fops->read; | ||
201 | spin_unlock(&pde->pde_unload_lock); | ||
202 | |||
203 | if (read) | ||
204 | rv = read(file, buf, count, ppos); | ||
205 | |||
206 | pde_users_dec(pde); | ||
207 | return rv; | ||
208 | } | ||
209 | |||
210 | static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | ||
211 | { | ||
212 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | ||
213 | ssize_t rv = -EIO; | ||
214 | ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); | ||
215 | |||
216 | spin_lock(&pde->pde_unload_lock); | ||
217 | if (!pde->proc_fops) { | ||
218 | spin_unlock(&pde->pde_unload_lock); | ||
219 | return rv; | ||
220 | } | ||
221 | pde->pde_users++; | ||
222 | write = pde->proc_fops->write; | ||
223 | spin_unlock(&pde->pde_unload_lock); | ||
224 | |||
225 | if (write) | ||
226 | rv = write(file, buf, count, ppos); | ||
227 | |||
228 | pde_users_dec(pde); | ||
229 | return rv; | ||
230 | } | ||
231 | |||
232 | static unsigned int proc_reg_poll(struct file *file, struct poll_table_struct *pts) | ||
233 | { | ||
234 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | ||
235 | unsigned int rv = 0; | ||
236 | unsigned int (*poll)(struct file *, struct poll_table_struct *); | ||
237 | |||
238 | spin_lock(&pde->pde_unload_lock); | ||
239 | if (!pde->proc_fops) { | ||
240 | spin_unlock(&pde->pde_unload_lock); | ||
241 | return rv; | ||
242 | } | ||
243 | pde->pde_users++; | ||
244 | poll = pde->proc_fops->poll; | ||
245 | spin_unlock(&pde->pde_unload_lock); | ||
246 | |||
247 | if (poll) | ||
248 | rv = poll(file, pts); | ||
249 | |||
250 | pde_users_dec(pde); | ||
251 | return rv; | ||
252 | } | ||
253 | |||
254 | static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
255 | { | ||
256 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | ||
257 | long rv = -ENOTTY; | ||
258 | long (*unlocked_ioctl)(struct file *, unsigned int, unsigned long); | ||
259 | int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long); | ||
260 | |||
261 | spin_lock(&pde->pde_unload_lock); | ||
262 | if (!pde->proc_fops) { | ||
263 | spin_unlock(&pde->pde_unload_lock); | ||
264 | return rv; | ||
265 | } | ||
266 | pde->pde_users++; | ||
267 | unlocked_ioctl = pde->proc_fops->unlocked_ioctl; | ||
268 | ioctl = pde->proc_fops->ioctl; | ||
269 | spin_unlock(&pde->pde_unload_lock); | ||
270 | |||
271 | if (unlocked_ioctl) { | ||
272 | rv = unlocked_ioctl(file, cmd, arg); | ||
273 | if (rv == -ENOIOCTLCMD) | ||
274 | rv = -EINVAL; | ||
275 | } else if (ioctl) { | ||
276 | lock_kernel(); | ||
277 | rv = ioctl(file->f_path.dentry->d_inode, file, cmd, arg); | ||
278 | unlock_kernel(); | ||
279 | } | ||
280 | |||
281 | pde_users_dec(pde); | ||
282 | return rv; | ||
283 | } | ||
284 | |||
285 | #ifdef CONFIG_COMPAT | ||
286 | static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
287 | { | ||
288 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | ||
289 | long rv = -ENOTTY; | ||
290 | long (*compat_ioctl)(struct file *, unsigned int, unsigned long); | ||
291 | |||
292 | spin_lock(&pde->pde_unload_lock); | ||
293 | if (!pde->proc_fops) { | ||
294 | spin_unlock(&pde->pde_unload_lock); | ||
295 | return rv; | ||
296 | } | ||
297 | pde->pde_users++; | ||
298 | compat_ioctl = pde->proc_fops->compat_ioctl; | ||
299 | spin_unlock(&pde->pde_unload_lock); | ||
300 | |||
301 | if (compat_ioctl) | ||
302 | rv = compat_ioctl(file, cmd, arg); | ||
303 | |||
304 | pde_users_dec(pde); | ||
305 | return rv; | ||
306 | } | ||
307 | #endif | ||
308 | |||
309 | static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma) | ||
310 | { | ||
311 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | ||
312 | int rv = -EIO; | ||
313 | int (*mmap)(struct file *, struct vm_area_struct *); | ||
314 | |||
315 | spin_lock(&pde->pde_unload_lock); | ||
316 | if (!pde->proc_fops) { | ||
317 | spin_unlock(&pde->pde_unload_lock); | ||
318 | return rv; | ||
319 | } | ||
320 | pde->pde_users++; | ||
321 | mmap = pde->proc_fops->mmap; | ||
322 | spin_unlock(&pde->pde_unload_lock); | ||
323 | |||
324 | if (mmap) | ||
325 | rv = mmap(file, vma); | ||
326 | |||
327 | pde_users_dec(pde); | ||
328 | return rv; | ||
329 | } | ||
330 | |||
331 | static int proc_reg_open(struct inode *inode, struct file *file) | ||
332 | { | ||
333 | struct proc_dir_entry *pde = PDE(inode); | ||
334 | int rv = 0; | ||
335 | int (*open)(struct inode *, struct file *); | ||
336 | |||
337 | spin_lock(&pde->pde_unload_lock); | ||
338 | if (!pde->proc_fops) { | ||
339 | spin_unlock(&pde->pde_unload_lock); | ||
340 | return rv; | ||
341 | } | ||
342 | pde->pde_users++; | ||
343 | open = pde->proc_fops->open; | ||
344 | spin_unlock(&pde->pde_unload_lock); | ||
345 | |||
346 | if (open) | ||
347 | rv = open(inode, file); | ||
348 | |||
349 | pde_users_dec(pde); | ||
350 | return rv; | ||
351 | } | ||
352 | |||
353 | static int proc_reg_release(struct inode *inode, struct file *file) | ||
354 | { | ||
355 | struct proc_dir_entry *pde = PDE(inode); | ||
356 | int rv = 0; | ||
357 | int (*release)(struct inode *, struct file *); | ||
358 | |||
359 | spin_lock(&pde->pde_unload_lock); | ||
360 | if (!pde->proc_fops) { | ||
361 | spin_unlock(&pde->pde_unload_lock); | ||
362 | return rv; | ||
363 | } | ||
364 | pde->pde_users++; | ||
365 | release = pde->proc_fops->release; | ||
366 | spin_unlock(&pde->pde_unload_lock); | ||
367 | |||
368 | if (release) | ||
369 | rv = release(inode, file); | ||
370 | |||
371 | pde_users_dec(pde); | ||
372 | return rv; | ||
373 | } | ||
374 | |||
375 | static const struct file_operations proc_reg_file_ops = { | ||
376 | .llseek = proc_reg_llseek, | ||
377 | .read = proc_reg_read, | ||
378 | .write = proc_reg_write, | ||
379 | .poll = proc_reg_poll, | ||
380 | .unlocked_ioctl = proc_reg_unlocked_ioctl, | ||
381 | #ifdef CONFIG_COMPAT | ||
382 | .compat_ioctl = proc_reg_compat_ioctl, | ||
383 | #endif | ||
384 | .mmap = proc_reg_mmap, | ||
385 | .open = proc_reg_open, | ||
386 | .release = proc_reg_release, | ||
387 | }; | ||
388 | |||
143 | struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, | 389 | struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, |
144 | struct proc_dir_entry *de) | 390 | struct proc_dir_entry *de) |
145 | { | 391 | { |
@@ -166,8 +412,12 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, | |||
166 | inode->i_nlink = de->nlink; | 412 | inode->i_nlink = de->nlink; |
167 | if (de->proc_iops) | 413 | if (de->proc_iops) |
168 | inode->i_op = de->proc_iops; | 414 | inode->i_op = de->proc_iops; |
169 | if (de->proc_fops) | 415 | if (de->proc_fops) { |
170 | inode->i_fop = de->proc_fops; | 416 | if (S_ISREG(inode->i_mode)) |
417 | inode->i_fop = &proc_reg_file_ops; | ||
418 | else | ||
419 | inode->i_fop = de->proc_fops; | ||
420 | } | ||
171 | } | 421 | } |
172 | 422 | ||
173 | return inode; | 423 | return inode; |
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 5fd49e47f83a..d24b8d46059a 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c | |||
@@ -105,6 +105,7 @@ static int uptime_read_proc(char *page, char **start, off_t off, | |||
105 | cputime_t idletime = cputime_add(init_task.utime, init_task.stime); | 105 | cputime_t idletime = cputime_add(init_task.utime, init_task.stime); |
106 | 106 | ||
107 | do_posix_clock_monotonic_gettime(&uptime); | 107 | do_posix_clock_monotonic_gettime(&uptime); |
108 | monotonic_to_bootbased(&uptime); | ||
108 | cputime_to_timespec(idletime, &idle); | 109 | cputime_to_timespec(idletime, &idle); |
109 | len = sprintf(page,"%lu.%02lu %lu.%02lu\n", | 110 | len = sprintf(page,"%lu.%02lu %lu.%02lu\n", |
110 | (unsigned long) uptime.tv_sec, | 111 | (unsigned long) uptime.tv_sec, |
@@ -443,12 +444,12 @@ static int show_stat(struct seq_file *p, void *v) | |||
443 | unsigned long jif; | 444 | unsigned long jif; |
444 | cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; | 445 | cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; |
445 | u64 sum = 0; | 446 | u64 sum = 0; |
447 | struct timespec boottime; | ||
446 | 448 | ||
447 | user = nice = system = idle = iowait = | 449 | user = nice = system = idle = iowait = |
448 | irq = softirq = steal = cputime64_zero; | 450 | irq = softirq = steal = cputime64_zero; |
449 | jif = - wall_to_monotonic.tv_sec; | 451 | getboottime(&boottime); |
450 | if (wall_to_monotonic.tv_nsec) | 452 | jif = boottime.tv_sec; |
451 | --jif; | ||
452 | 453 | ||
453 | for_each_possible_cpu(i) { | 454 | for_each_possible_cpu(i) { |
454 | int j; | 455 | int j; |
diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c index b3a473b0a191..22846225acfa 100644 --- a/fs/proc/proc_tty.c +++ b/fs/proc/proc_tty.c | |||
@@ -69,7 +69,7 @@ static void show_tty_range(struct seq_file *m, struct tty_driver *p, | |||
69 | 69 | ||
70 | static int show_tty_driver(struct seq_file *m, void *v) | 70 | static int show_tty_driver(struct seq_file *m, void *v) |
71 | { | 71 | { |
72 | struct tty_driver *p = v; | 72 | struct tty_driver *p = list_entry(v, struct tty_driver, tty_drivers); |
73 | dev_t from = MKDEV(p->major, p->minor_start); | 73 | dev_t from = MKDEV(p->major, p->minor_start); |
74 | dev_t to = from + p->num; | 74 | dev_t to = from + p->num; |
75 | 75 | ||
@@ -106,22 +106,13 @@ static int show_tty_driver(struct seq_file *m, void *v) | |||
106 | /* iterator */ | 106 | /* iterator */ |
107 | static void *t_start(struct seq_file *m, loff_t *pos) | 107 | static void *t_start(struct seq_file *m, loff_t *pos) |
108 | { | 108 | { |
109 | struct list_head *p; | ||
110 | loff_t l = *pos; | ||
111 | |||
112 | mutex_lock(&tty_mutex); | 109 | mutex_lock(&tty_mutex); |
113 | list_for_each(p, &tty_drivers) | 110 | return seq_list_start(&tty_drivers, *pos); |
114 | if (!l--) | ||
115 | return list_entry(p, struct tty_driver, tty_drivers); | ||
116 | return NULL; | ||
117 | } | 111 | } |
118 | 112 | ||
119 | static void *t_next(struct seq_file *m, void *v, loff_t *pos) | 113 | static void *t_next(struct seq_file *m, void *v, loff_t *pos) |
120 | { | 114 | { |
121 | struct list_head *p = ((struct tty_driver *)v)->tty_drivers.next; | 115 | return seq_list_next(v, &tty_drivers, pos); |
122 | (*pos)++; | ||
123 | return p==&tty_drivers ? NULL : | ||
124 | list_entry(p, struct tty_driver, tty_drivers); | ||
125 | } | 116 | } |
126 | 117 | ||
127 | static void t_stop(struct seq_file *m, void *v) | 118 | static void t_stop(struct seq_file *m, void *v) |