diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/Kconfig | 43 | ||||
-rw-r--r-- | fs/aio.c | 4 | ||||
-rw-r--r-- | fs/binfmt_flat.c | 2 | ||||
-rw-r--r-- | fs/devpts/Makefile | 1 | ||||
-rw-r--r-- | fs/devpts/inode.c | 21 | ||||
-rw-r--r-- | fs/devpts/xattr_security.c | 47 | ||||
-rw-r--r-- | fs/proc/base.c | 96 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 357 | ||||
-rw-r--r-- | fs/xattr.c | 80 |
9 files changed, 465 insertions, 186 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index e54be7058359..ed78d24ee426 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -783,28 +783,6 @@ config SYSFS | |||
783 | 783 | ||
784 | Designers of embedded systems may wish to say N here to conserve space. | 784 | Designers of embedded systems may wish to say N here to conserve space. |
785 | 785 | ||
786 | config DEVPTS_FS_XATTR | ||
787 | bool "/dev/pts Extended Attributes" | ||
788 | depends on UNIX98_PTYS | ||
789 | help | ||
790 | Extended attributes are name:value pairs associated with inodes by | ||
791 | the kernel or by users (see the attr(5) manual page, or visit | ||
792 | <http://acl.bestbits.at/> for details). | ||
793 | |||
794 | If unsure, say N. | ||
795 | |||
796 | config DEVPTS_FS_SECURITY | ||
797 | bool "/dev/pts Security Labels" | ||
798 | depends on DEVPTS_FS_XATTR | ||
799 | help | ||
800 | Security labels support alternative access control models | ||
801 | implemented by security modules like SELinux. This option | ||
802 | enables an extended attribute handler for file security | ||
803 | labels in the /dev/pts filesystem. | ||
804 | |||
805 | If you are not using a security module that requires using | ||
806 | extended attributes for file security labels, say N. | ||
807 | |||
808 | config TMPFS | 786 | config TMPFS |
809 | bool "Virtual memory file system support (former shm fs)" | 787 | bool "Virtual memory file system support (former shm fs)" |
810 | help | 788 | help |
@@ -817,27 +795,6 @@ config TMPFS | |||
817 | 795 | ||
818 | See <file:Documentation/filesystems/tmpfs.txt> for details. | 796 | See <file:Documentation/filesystems/tmpfs.txt> for details. |
819 | 797 | ||
820 | config TMPFS_XATTR | ||
821 | bool "tmpfs Extended Attributes" | ||
822 | depends on TMPFS | ||
823 | help | ||
824 | Extended attributes are name:value pairs associated with inodes by | ||
825 | the kernel or by users (see the attr(5) manual page, or visit | ||
826 | <http://acl.bestbits.at/> for details). | ||
827 | |||
828 | If unsure, say N. | ||
829 | |||
830 | config TMPFS_SECURITY | ||
831 | bool "tmpfs Security Labels" | ||
832 | depends on TMPFS_XATTR | ||
833 | help | ||
834 | Security labels support alternative access control models | ||
835 | implemented by security modules like SELinux. This option | ||
836 | enables an extended attribute handler for file security | ||
837 | labels in the tmpfs filesystem. | ||
838 | If you are not using a security module that requires using | ||
839 | extended attributes for file security labels, say N. | ||
840 | |||
841 | config HUGETLBFS | 798 | config HUGETLBFS |
842 | bool "HugeTLB file system support" | 799 | bool "HugeTLB file system support" |
843 | depends X86 || IA64 || PPC64 || SPARC64 || SUPERH || X86_64 || BROKEN | 800 | depends X86 || IA64 || PPC64 || SPARC64 || SUPERH || X86_64 || BROKEN |
@@ -567,6 +567,10 @@ static void use_mm(struct mm_struct *mm) | |||
567 | atomic_inc(&mm->mm_count); | 567 | atomic_inc(&mm->mm_count); |
568 | tsk->mm = mm; | 568 | tsk->mm = mm; |
569 | tsk->active_mm = mm; | 569 | tsk->active_mm = mm; |
570 | /* | ||
571 | * Note that on UML this *requires* PF_BORROWED_MM to be set, otherwise | ||
572 | * it won't work. Update it accordingly if you change it here | ||
573 | */ | ||
570 | activate_mm(active_mm, mm); | 574 | activate_mm(active_mm, mm); |
571 | task_unlock(tsk); | 575 | task_unlock(tsk); |
572 | 576 | ||
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index c8998dc66882..7974efa107bc 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c | |||
@@ -520,7 +520,7 @@ static int load_flat_file(struct linux_binprm * bprm, | |||
520 | DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n"); | 520 | DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n"); |
521 | 521 | ||
522 | down_write(¤t->mm->mmap_sem); | 522 | down_write(¤t->mm->mmap_sem); |
523 | textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, MAP_SHARED, 0); | 523 | textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, MAP_PRIVATE, 0); |
524 | up_write(¤t->mm->mmap_sem); | 524 | up_write(¤t->mm->mmap_sem); |
525 | if (!textpos || textpos >= (unsigned long) -4096) { | 525 | if (!textpos || textpos >= (unsigned long) -4096) { |
526 | if (!textpos) | 526 | if (!textpos) |
diff --git a/fs/devpts/Makefile b/fs/devpts/Makefile index 5800df2e50c8..236696efcbac 100644 --- a/fs/devpts/Makefile +++ b/fs/devpts/Makefile | |||
@@ -5,4 +5,3 @@ | |||
5 | obj-$(CONFIG_UNIX98_PTYS) += devpts.o | 5 | obj-$(CONFIG_UNIX98_PTYS) += devpts.o |
6 | 6 | ||
7 | devpts-$(CONFIG_UNIX98_PTYS) := inode.o | 7 | devpts-$(CONFIG_UNIX98_PTYS) := inode.o |
8 | devpts-$(CONFIG_DEVPTS_FS_SECURITY) += xattr_security.o | ||
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 1571c8d6c232..f2be44d4491f 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c | |||
@@ -18,28 +18,9 @@ | |||
18 | #include <linux/mount.h> | 18 | #include <linux/mount.h> |
19 | #include <linux/tty.h> | 19 | #include <linux/tty.h> |
20 | #include <linux/devpts_fs.h> | 20 | #include <linux/devpts_fs.h> |
21 | #include <linux/xattr.h> | ||
22 | 21 | ||
23 | #define DEVPTS_SUPER_MAGIC 0x1cd1 | 22 | #define DEVPTS_SUPER_MAGIC 0x1cd1 |
24 | 23 | ||
25 | extern struct xattr_handler devpts_xattr_security_handler; | ||
26 | |||
27 | static struct xattr_handler *devpts_xattr_handlers[] = { | ||
28 | #ifdef CONFIG_DEVPTS_FS_SECURITY | ||
29 | &devpts_xattr_security_handler, | ||
30 | #endif | ||
31 | NULL | ||
32 | }; | ||
33 | |||
34 | static struct inode_operations devpts_file_inode_operations = { | ||
35 | #ifdef CONFIG_DEVPTS_FS_XATTR | ||
36 | .setxattr = generic_setxattr, | ||
37 | .getxattr = generic_getxattr, | ||
38 | .listxattr = generic_listxattr, | ||
39 | .removexattr = generic_removexattr, | ||
40 | #endif | ||
41 | }; | ||
42 | |||
43 | static struct vfsmount *devpts_mnt; | 24 | static struct vfsmount *devpts_mnt; |
44 | static struct dentry *devpts_root; | 25 | static struct dentry *devpts_root; |
45 | 26 | ||
@@ -102,7 +83,6 @@ devpts_fill_super(struct super_block *s, void *data, int silent) | |||
102 | s->s_blocksize_bits = 10; | 83 | s->s_blocksize_bits = 10; |
103 | s->s_magic = DEVPTS_SUPER_MAGIC; | 84 | s->s_magic = DEVPTS_SUPER_MAGIC; |
104 | s->s_op = &devpts_sops; | 85 | s->s_op = &devpts_sops; |
105 | s->s_xattr = devpts_xattr_handlers; | ||
106 | s->s_time_gran = 1; | 86 | s->s_time_gran = 1; |
107 | 87 | ||
108 | inode = new_inode(s); | 88 | inode = new_inode(s); |
@@ -175,7 +155,6 @@ int devpts_pty_new(struct tty_struct *tty) | |||
175 | inode->i_gid = config.setgid ? config.gid : current->fsgid; | 155 | inode->i_gid = config.setgid ? config.gid : current->fsgid; |
176 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | 156 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
177 | init_special_inode(inode, S_IFCHR|config.mode, device); | 157 | init_special_inode(inode, S_IFCHR|config.mode, device); |
178 | inode->i_op = &devpts_file_inode_operations; | ||
179 | inode->u.generic_ip = tty; | 158 | inode->u.generic_ip = tty; |
180 | 159 | ||
181 | dentry = get_node(number); | 160 | dentry = get_node(number); |
diff --git a/fs/devpts/xattr_security.c b/fs/devpts/xattr_security.c deleted file mode 100644 index 864cb5c79baa..000000000000 --- a/fs/devpts/xattr_security.c +++ /dev/null | |||
@@ -1,47 +0,0 @@ | |||
1 | /* | ||
2 | * Security xattr support for devpts. | ||
3 | * | ||
4 | * Author: Stephen Smalley <sds@epoch.ncsc.mil> | ||
5 | * Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the Free | ||
9 | * Software Foundation; either version 2 of the License, or (at your option) | ||
10 | * any later version. | ||
11 | */ | ||
12 | #include <linux/string.h> | ||
13 | #include <linux/fs.h> | ||
14 | #include <linux/security.h> | ||
15 | #include <linux/xattr.h> | ||
16 | |||
17 | static size_t | ||
18 | devpts_xattr_security_list(struct inode *inode, char *list, size_t list_len, | ||
19 | const char *name, size_t name_len) | ||
20 | { | ||
21 | return security_inode_listsecurity(inode, list, list_len); | ||
22 | } | ||
23 | |||
24 | static int | ||
25 | devpts_xattr_security_get(struct inode *inode, const char *name, | ||
26 | void *buffer, size_t size) | ||
27 | { | ||
28 | if (strcmp(name, "") == 0) | ||
29 | return -EINVAL; | ||
30 | return security_inode_getsecurity(inode, name, buffer, size); | ||
31 | } | ||
32 | |||
33 | static int | ||
34 | devpts_xattr_security_set(struct inode *inode, const char *name, | ||
35 | const void *value, size_t size, int flags) | ||
36 | { | ||
37 | if (strcmp(name, "") == 0) | ||
38 | return -EINVAL; | ||
39 | return security_inode_setsecurity(inode, name, value, size, flags); | ||
40 | } | ||
41 | |||
42 | struct xattr_handler devpts_xattr_security_handler = { | ||
43 | .prefix = XATTR_SECURITY_PREFIX, | ||
44 | .list = devpts_xattr_security_list, | ||
45 | .get = devpts_xattr_security_get, | ||
46 | .set = devpts_xattr_security_set, | ||
47 | }; | ||
diff --git a/fs/proc/base.c b/fs/proc/base.c index 491f2d9f89ac..520978e49e92 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -11,6 +11,40 @@ | |||
11 | * go into icache. We cache the reference to task_struct upon lookup too. | 11 | * go into icache. We cache the reference to task_struct upon lookup too. |
12 | * Eventually it should become a filesystem in its own. We don't use the | 12 | * Eventually it should become a filesystem in its own. We don't use the |
13 | * rest of procfs anymore. | 13 | * rest of procfs anymore. |
14 | * | ||
15 | * | ||
16 | * Changelog: | ||
17 | * 17-Jan-2005 | ||
18 | * Allan Bezerra | ||
19 | * Bruna Moreira <bruna.moreira@indt.org.br> | ||
20 | * Edjard Mota <edjard.mota@indt.org.br> | ||
21 | * Ilias Biris <ilias.biris@indt.org.br> | ||
22 | * Mauricio Lin <mauricio.lin@indt.org.br> | ||
23 | * | ||
24 | * Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT | ||
25 | * | ||
26 | * A new process specific entry (smaps) included in /proc. It shows the | ||
27 | * size of rss for each memory area. The maps entry lacks information | ||
28 | * about physical memory size (rss) for each mapped file, i.e., | ||
29 | * rss information for executables and library files. | ||
30 | * This additional information is useful for any tools that need to know | ||
31 | * about physical memory consumption for a process specific library. | ||
32 | * | ||
33 | * Changelog: | ||
34 | * 21-Feb-2005 | ||
35 | * Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT | ||
36 | * Pud inclusion in the page table walking. | ||
37 | * | ||
38 | * ChangeLog: | ||
39 | * 10-Mar-2005 | ||
40 | * 10LE Instituto Nokia de Tecnologia - INdT: | ||
41 | * A better way to walks through the page table as suggested by Hugh Dickins. | ||
42 | * | ||
43 | * Simo Piiroinen <simo.piiroinen@nokia.com>: | ||
44 | * Smaps information related to shared, private, clean and dirty pages. | ||
45 | * | ||
46 | * Paul Mundt <paul.mundt@nokia.com>: | ||
47 | * Overall revision about smaps. | ||
14 | */ | 48 | */ |
15 | 49 | ||
16 | #include <asm/uaccess.h> | 50 | #include <asm/uaccess.h> |
@@ -65,8 +99,10 @@ enum pid_directory_inos { | |||
65 | PROC_TGID_STAT, | 99 | PROC_TGID_STAT, |
66 | PROC_TGID_STATM, | 100 | PROC_TGID_STATM, |
67 | PROC_TGID_MAPS, | 101 | PROC_TGID_MAPS, |
102 | PROC_TGID_NUMA_MAPS, | ||
68 | PROC_TGID_MOUNTS, | 103 | PROC_TGID_MOUNTS, |
69 | PROC_TGID_WCHAN, | 104 | PROC_TGID_WCHAN, |
105 | PROC_TGID_SMAPS, | ||
70 | #ifdef CONFIG_SCHEDSTATS | 106 | #ifdef CONFIG_SCHEDSTATS |
71 | PROC_TGID_SCHEDSTAT, | 107 | PROC_TGID_SCHEDSTAT, |
72 | #endif | 108 | #endif |
@@ -102,8 +138,10 @@ enum pid_directory_inos { | |||
102 | PROC_TID_STAT, | 138 | PROC_TID_STAT, |
103 | PROC_TID_STATM, | 139 | PROC_TID_STATM, |
104 | PROC_TID_MAPS, | 140 | PROC_TID_MAPS, |
141 | PROC_TID_NUMA_MAPS, | ||
105 | PROC_TID_MOUNTS, | 142 | PROC_TID_MOUNTS, |
106 | PROC_TID_WCHAN, | 143 | PROC_TID_WCHAN, |
144 | PROC_TID_SMAPS, | ||
107 | #ifdef CONFIG_SCHEDSTATS | 145 | #ifdef CONFIG_SCHEDSTATS |
108 | PROC_TID_SCHEDSTAT, | 146 | PROC_TID_SCHEDSTAT, |
109 | #endif | 147 | #endif |
@@ -144,6 +182,9 @@ static struct pid_entry tgid_base_stuff[] = { | |||
144 | E(PROC_TGID_STAT, "stat", S_IFREG|S_IRUGO), | 182 | E(PROC_TGID_STAT, "stat", S_IFREG|S_IRUGO), |
145 | E(PROC_TGID_STATM, "statm", S_IFREG|S_IRUGO), | 183 | E(PROC_TGID_STATM, "statm", S_IFREG|S_IRUGO), |
146 | E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUGO), | 184 | E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUGO), |
185 | #ifdef CONFIG_NUMA | ||
186 | E(PROC_TGID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO), | ||
187 | #endif | ||
147 | E(PROC_TGID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), | 188 | E(PROC_TGID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), |
148 | #ifdef CONFIG_SECCOMP | 189 | #ifdef CONFIG_SECCOMP |
149 | E(PROC_TGID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR), | 190 | E(PROC_TGID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR), |
@@ -152,6 +193,7 @@ static struct pid_entry tgid_base_stuff[] = { | |||
152 | E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), | 193 | E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), |
153 | E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO), | 194 | E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO), |
154 | E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO), | 195 | E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO), |
196 | E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO), | ||
155 | #ifdef CONFIG_SECURITY | 197 | #ifdef CONFIG_SECURITY |
156 | E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), | 198 | E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), |
157 | #endif | 199 | #endif |
@@ -180,6 +222,9 @@ static struct pid_entry tid_base_stuff[] = { | |||
180 | E(PROC_TID_STAT, "stat", S_IFREG|S_IRUGO), | 222 | E(PROC_TID_STAT, "stat", S_IFREG|S_IRUGO), |
181 | E(PROC_TID_STATM, "statm", S_IFREG|S_IRUGO), | 223 | E(PROC_TID_STATM, "statm", S_IFREG|S_IRUGO), |
182 | E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUGO), | 224 | E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUGO), |
225 | #ifdef CONFIG_NUMA | ||
226 | E(PROC_TID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO), | ||
227 | #endif | ||
183 | E(PROC_TID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), | 228 | E(PROC_TID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), |
184 | #ifdef CONFIG_SECCOMP | 229 | #ifdef CONFIG_SECCOMP |
185 | E(PROC_TID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR), | 230 | E(PROC_TID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR), |
@@ -188,6 +233,7 @@ static struct pid_entry tid_base_stuff[] = { | |||
188 | E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO), | 233 | E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO), |
189 | E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO), | 234 | E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO), |
190 | E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO), | 235 | E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO), |
236 | E(PROC_TID_SMAPS, "smaps", S_IFREG|S_IRUGO), | ||
191 | #ifdef CONFIG_SECURITY | 237 | #ifdef CONFIG_SECURITY |
192 | E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), | 238 | E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), |
193 | #endif | 239 | #endif |
@@ -515,6 +561,46 @@ static struct file_operations proc_maps_operations = { | |||
515 | .release = seq_release, | 561 | .release = seq_release, |
516 | }; | 562 | }; |
517 | 563 | ||
564 | #ifdef CONFIG_NUMA | ||
565 | extern struct seq_operations proc_pid_numa_maps_op; | ||
566 | static int numa_maps_open(struct inode *inode, struct file *file) | ||
567 | { | ||
568 | struct task_struct *task = proc_task(inode); | ||
569 | int ret = seq_open(file, &proc_pid_numa_maps_op); | ||
570 | if (!ret) { | ||
571 | struct seq_file *m = file->private_data; | ||
572 | m->private = task; | ||
573 | } | ||
574 | return ret; | ||
575 | } | ||
576 | |||
577 | static struct file_operations proc_numa_maps_operations = { | ||
578 | .open = numa_maps_open, | ||
579 | .read = seq_read, | ||
580 | .llseek = seq_lseek, | ||
581 | .release = seq_release, | ||
582 | }; | ||
583 | #endif | ||
584 | |||
585 | extern struct seq_operations proc_pid_smaps_op; | ||
586 | static int smaps_open(struct inode *inode, struct file *file) | ||
587 | { | ||
588 | struct task_struct *task = proc_task(inode); | ||
589 | int ret = seq_open(file, &proc_pid_smaps_op); | ||
590 | if (!ret) { | ||
591 | struct seq_file *m = file->private_data; | ||
592 | m->private = task; | ||
593 | } | ||
594 | return ret; | ||
595 | } | ||
596 | |||
597 | static struct file_operations proc_smaps_operations = { | ||
598 | .open = smaps_open, | ||
599 | .read = seq_read, | ||
600 | .llseek = seq_lseek, | ||
601 | .release = seq_release, | ||
602 | }; | ||
603 | |||
518 | extern struct seq_operations mounts_op; | 604 | extern struct seq_operations mounts_op; |
519 | static int mounts_open(struct inode *inode, struct file *file) | 605 | static int mounts_open(struct inode *inode, struct file *file) |
520 | { | 606 | { |
@@ -1524,6 +1610,12 @@ static struct dentry *proc_pident_lookup(struct inode *dir, | |||
1524 | case PROC_TGID_MAPS: | 1610 | case PROC_TGID_MAPS: |
1525 | inode->i_fop = &proc_maps_operations; | 1611 | inode->i_fop = &proc_maps_operations; |
1526 | break; | 1612 | break; |
1613 | #ifdef CONFIG_NUMA | ||
1614 | case PROC_TID_NUMA_MAPS: | ||
1615 | case PROC_TGID_NUMA_MAPS: | ||
1616 | inode->i_fop = &proc_numa_maps_operations; | ||
1617 | break; | ||
1618 | #endif | ||
1527 | case PROC_TID_MEM: | 1619 | case PROC_TID_MEM: |
1528 | case PROC_TGID_MEM: | 1620 | case PROC_TGID_MEM: |
1529 | inode->i_op = &proc_mem_inode_operations; | 1621 | inode->i_op = &proc_mem_inode_operations; |
@@ -1539,6 +1631,10 @@ static struct dentry *proc_pident_lookup(struct inode *dir, | |||
1539 | case PROC_TGID_MOUNTS: | 1631 | case PROC_TGID_MOUNTS: |
1540 | inode->i_fop = &proc_mounts_operations; | 1632 | inode->i_fop = &proc_mounts_operations; |
1541 | break; | 1633 | break; |
1634 | case PROC_TID_SMAPS: | ||
1635 | case PROC_TGID_SMAPS: | ||
1636 | inode->i_fop = &proc_smaps_operations; | ||
1637 | break; | ||
1542 | #ifdef CONFIG_SECURITY | 1638 | #ifdef CONFIG_SECURITY |
1543 | case PROC_TID_ATTR: | 1639 | case PROC_TID_ATTR: |
1544 | inode->i_nlink = 2; | 1640 | inode->i_nlink = 2; |
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 28b4a0253a92..c7ef3e48e35b 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -2,8 +2,13 @@ | |||
2 | #include <linux/hugetlb.h> | 2 | #include <linux/hugetlb.h> |
3 | #include <linux/mount.h> | 3 | #include <linux/mount.h> |
4 | #include <linux/seq_file.h> | 4 | #include <linux/seq_file.h> |
5 | #include <linux/highmem.h> | ||
6 | #include <linux/pagemap.h> | ||
7 | #include <linux/mempolicy.h> | ||
8 | |||
5 | #include <asm/elf.h> | 9 | #include <asm/elf.h> |
6 | #include <asm/uaccess.h> | 10 | #include <asm/uaccess.h> |
11 | #include <asm/tlbflush.h> | ||
7 | #include "internal.h" | 12 | #include "internal.h" |
8 | 13 | ||
9 | char *task_mem(struct mm_struct *mm, char *buffer) | 14 | char *task_mem(struct mm_struct *mm, char *buffer) |
@@ -87,49 +92,58 @@ static void pad_len_spaces(struct seq_file *m, int len) | |||
87 | seq_printf(m, "%*c", len, ' '); | 92 | seq_printf(m, "%*c", len, ' '); |
88 | } | 93 | } |
89 | 94 | ||
90 | static int show_map(struct seq_file *m, void *v) | 95 | struct mem_size_stats |
96 | { | ||
97 | unsigned long resident; | ||
98 | unsigned long shared_clean; | ||
99 | unsigned long shared_dirty; | ||
100 | unsigned long private_clean; | ||
101 | unsigned long private_dirty; | ||
102 | }; | ||
103 | |||
104 | static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats *mss) | ||
91 | { | 105 | { |
92 | struct task_struct *task = m->private; | 106 | struct task_struct *task = m->private; |
93 | struct vm_area_struct *map = v; | 107 | struct vm_area_struct *vma = v; |
94 | struct mm_struct *mm = map->vm_mm; | 108 | struct mm_struct *mm = vma->vm_mm; |
95 | struct file *file = map->vm_file; | 109 | struct file *file = vma->vm_file; |
96 | int flags = map->vm_flags; | 110 | int flags = vma->vm_flags; |
97 | unsigned long ino = 0; | 111 | unsigned long ino = 0; |
98 | dev_t dev = 0; | 112 | dev_t dev = 0; |
99 | int len; | 113 | int len; |
100 | 114 | ||
101 | if (file) { | 115 | if (file) { |
102 | struct inode *inode = map->vm_file->f_dentry->d_inode; | 116 | struct inode *inode = vma->vm_file->f_dentry->d_inode; |
103 | dev = inode->i_sb->s_dev; | 117 | dev = inode->i_sb->s_dev; |
104 | ino = inode->i_ino; | 118 | ino = inode->i_ino; |
105 | } | 119 | } |
106 | 120 | ||
107 | seq_printf(m, "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu %n", | 121 | seq_printf(m, "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu %n", |
108 | map->vm_start, | 122 | vma->vm_start, |
109 | map->vm_end, | 123 | vma->vm_end, |
110 | flags & VM_READ ? 'r' : '-', | 124 | flags & VM_READ ? 'r' : '-', |
111 | flags & VM_WRITE ? 'w' : '-', | 125 | flags & VM_WRITE ? 'w' : '-', |
112 | flags & VM_EXEC ? 'x' : '-', | 126 | flags & VM_EXEC ? 'x' : '-', |
113 | flags & VM_MAYSHARE ? 's' : 'p', | 127 | flags & VM_MAYSHARE ? 's' : 'p', |
114 | map->vm_pgoff << PAGE_SHIFT, | 128 | vma->vm_pgoff << PAGE_SHIFT, |
115 | MAJOR(dev), MINOR(dev), ino, &len); | 129 | MAJOR(dev), MINOR(dev), ino, &len); |
116 | 130 | ||
117 | /* | 131 | /* |
118 | * Print the dentry name for named mappings, and a | 132 | * Print the dentry name for named mappings, and a |
119 | * special [heap] marker for the heap: | 133 | * special [heap] marker for the heap: |
120 | */ | 134 | */ |
121 | if (map->vm_file) { | 135 | if (file) { |
122 | pad_len_spaces(m, len); | 136 | pad_len_spaces(m, len); |
123 | seq_path(m, file->f_vfsmnt, file->f_dentry, ""); | 137 | seq_path(m, file->f_vfsmnt, file->f_dentry, "\n"); |
124 | } else { | 138 | } else { |
125 | if (mm) { | 139 | if (mm) { |
126 | if (map->vm_start <= mm->start_brk && | 140 | if (vma->vm_start <= mm->start_brk && |
127 | map->vm_end >= mm->brk) { | 141 | vma->vm_end >= mm->brk) { |
128 | pad_len_spaces(m, len); | 142 | pad_len_spaces(m, len); |
129 | seq_puts(m, "[heap]"); | 143 | seq_puts(m, "[heap]"); |
130 | } else { | 144 | } else { |
131 | if (map->vm_start <= mm->start_stack && | 145 | if (vma->vm_start <= mm->start_stack && |
132 | map->vm_end >= mm->start_stack) { | 146 | vma->vm_end >= mm->start_stack) { |
133 | 147 | ||
134 | pad_len_spaces(m, len); | 148 | pad_len_spaces(m, len); |
135 | seq_puts(m, "[stack]"); | 149 | seq_puts(m, "[stack]"); |
@@ -141,24 +155,146 @@ static int show_map(struct seq_file *m, void *v) | |||
141 | } | 155 | } |
142 | } | 156 | } |
143 | seq_putc(m, '\n'); | 157 | seq_putc(m, '\n'); |
144 | if (m->count < m->size) /* map is copied successfully */ | 158 | |
145 | m->version = (map != get_gate_vma(task))? map->vm_start: 0; | 159 | if (mss) |
160 | seq_printf(m, | ||
161 | "Size: %8lu kB\n" | ||
162 | "Rss: %8lu kB\n" | ||
163 | "Shared_Clean: %8lu kB\n" | ||
164 | "Shared_Dirty: %8lu kB\n" | ||
165 | "Private_Clean: %8lu kB\n" | ||
166 | "Private_Dirty: %8lu kB\n", | ||
167 | (vma->vm_end - vma->vm_start) >> 10, | ||
168 | mss->resident >> 10, | ||
169 | mss->shared_clean >> 10, | ||
170 | mss->shared_dirty >> 10, | ||
171 | mss->private_clean >> 10, | ||
172 | mss->private_dirty >> 10); | ||
173 | |||
174 | if (m->count < m->size) /* vma is copied successfully */ | ||
175 | m->version = (vma != get_gate_vma(task))? vma->vm_start: 0; | ||
146 | return 0; | 176 | return 0; |
147 | } | 177 | } |
148 | 178 | ||
179 | static int show_map(struct seq_file *m, void *v) | ||
180 | { | ||
181 | return show_map_internal(m, v, 0); | ||
182 | } | ||
183 | |||
184 | static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd, | ||
185 | unsigned long addr, unsigned long end, | ||
186 | struct mem_size_stats *mss) | ||
187 | { | ||
188 | pte_t *pte, ptent; | ||
189 | unsigned long pfn; | ||
190 | struct page *page; | ||
191 | |||
192 | pte = pte_offset_map(pmd, addr); | ||
193 | do { | ||
194 | ptent = *pte; | ||
195 | if (pte_none(ptent) || !pte_present(ptent)) | ||
196 | continue; | ||
197 | |||
198 | mss->resident += PAGE_SIZE; | ||
199 | pfn = pte_pfn(ptent); | ||
200 | if (!pfn_valid(pfn)) | ||
201 | continue; | ||
202 | |||
203 | page = pfn_to_page(pfn); | ||
204 | if (page_count(page) >= 2) { | ||
205 | if (pte_dirty(ptent)) | ||
206 | mss->shared_dirty += PAGE_SIZE; | ||
207 | else | ||
208 | mss->shared_clean += PAGE_SIZE; | ||
209 | } else { | ||
210 | if (pte_dirty(ptent)) | ||
211 | mss->private_dirty += PAGE_SIZE; | ||
212 | else | ||
213 | mss->private_clean += PAGE_SIZE; | ||
214 | } | ||
215 | } while (pte++, addr += PAGE_SIZE, addr != end); | ||
216 | pte_unmap(pte - 1); | ||
217 | cond_resched_lock(&vma->vm_mm->page_table_lock); | ||
218 | } | ||
219 | |||
220 | static inline void smaps_pmd_range(struct vm_area_struct *vma, pud_t *pud, | ||
221 | unsigned long addr, unsigned long end, | ||
222 | struct mem_size_stats *mss) | ||
223 | { | ||
224 | pmd_t *pmd; | ||
225 | unsigned long next; | ||
226 | |||
227 | pmd = pmd_offset(pud, addr); | ||
228 | do { | ||
229 | next = pmd_addr_end(addr, end); | ||
230 | if (pmd_none_or_clear_bad(pmd)) | ||
231 | continue; | ||
232 | smaps_pte_range(vma, pmd, addr, next, mss); | ||
233 | } while (pmd++, addr = next, addr != end); | ||
234 | } | ||
235 | |||
236 | static inline void smaps_pud_range(struct vm_area_struct *vma, pgd_t *pgd, | ||
237 | unsigned long addr, unsigned long end, | ||
238 | struct mem_size_stats *mss) | ||
239 | { | ||
240 | pud_t *pud; | ||
241 | unsigned long next; | ||
242 | |||
243 | pud = pud_offset(pgd, addr); | ||
244 | do { | ||
245 | next = pud_addr_end(addr, end); | ||
246 | if (pud_none_or_clear_bad(pud)) | ||
247 | continue; | ||
248 | smaps_pmd_range(vma, pud, addr, next, mss); | ||
249 | } while (pud++, addr = next, addr != end); | ||
250 | } | ||
251 | |||
252 | static inline void smaps_pgd_range(struct vm_area_struct *vma, | ||
253 | unsigned long addr, unsigned long end, | ||
254 | struct mem_size_stats *mss) | ||
255 | { | ||
256 | pgd_t *pgd; | ||
257 | unsigned long next; | ||
258 | |||
259 | pgd = pgd_offset(vma->vm_mm, addr); | ||
260 | do { | ||
261 | next = pgd_addr_end(addr, end); | ||
262 | if (pgd_none_or_clear_bad(pgd)) | ||
263 | continue; | ||
264 | smaps_pud_range(vma, pgd, addr, next, mss); | ||
265 | } while (pgd++, addr = next, addr != end); | ||
266 | } | ||
267 | |||
268 | static int show_smap(struct seq_file *m, void *v) | ||
269 | { | ||
270 | struct vm_area_struct *vma = v; | ||
271 | struct mm_struct *mm = vma->vm_mm; | ||
272 | struct mem_size_stats mss; | ||
273 | |||
274 | memset(&mss, 0, sizeof mss); | ||
275 | |||
276 | if (mm) { | ||
277 | spin_lock(&mm->page_table_lock); | ||
278 | smaps_pgd_range(vma, vma->vm_start, vma->vm_end, &mss); | ||
279 | spin_unlock(&mm->page_table_lock); | ||
280 | } | ||
281 | |||
282 | return show_map_internal(m, v, &mss); | ||
283 | } | ||
284 | |||
149 | static void *m_start(struct seq_file *m, loff_t *pos) | 285 | static void *m_start(struct seq_file *m, loff_t *pos) |
150 | { | 286 | { |
151 | struct task_struct *task = m->private; | 287 | struct task_struct *task = m->private; |
152 | unsigned long last_addr = m->version; | 288 | unsigned long last_addr = m->version; |
153 | struct mm_struct *mm; | 289 | struct mm_struct *mm; |
154 | struct vm_area_struct *map, *tail_map; | 290 | struct vm_area_struct *vma, *tail_vma; |
155 | loff_t l = *pos; | 291 | loff_t l = *pos; |
156 | 292 | ||
157 | /* | 293 | /* |
158 | * We remember last_addr rather than next_addr to hit with | 294 | * We remember last_addr rather than next_addr to hit with |
159 | * mmap_cache most of the time. We have zero last_addr at | 295 | * mmap_cache most of the time. We have zero last_addr at |
160 | * the begining and also after lseek. We will have -1 last_addr | 296 | * the beginning and also after lseek. We will have -1 last_addr |
161 | * after the end of the maps. | 297 | * after the end of the vmas. |
162 | */ | 298 | */ |
163 | 299 | ||
164 | if (last_addr == -1UL) | 300 | if (last_addr == -1UL) |
@@ -168,47 +304,47 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
168 | if (!mm) | 304 | if (!mm) |
169 | return NULL; | 305 | return NULL; |
170 | 306 | ||
171 | tail_map = get_gate_vma(task); | 307 | tail_vma = get_gate_vma(task); |
172 | down_read(&mm->mmap_sem); | 308 | down_read(&mm->mmap_sem); |
173 | 309 | ||
174 | /* Start with last addr hint */ | 310 | /* Start with last addr hint */ |
175 | if (last_addr && (map = find_vma(mm, last_addr))) { | 311 | if (last_addr && (vma = find_vma(mm, last_addr))) { |
176 | map = map->vm_next; | 312 | vma = vma->vm_next; |
177 | goto out; | 313 | goto out; |
178 | } | 314 | } |
179 | 315 | ||
180 | /* | 316 | /* |
181 | * Check the map index is within the range and do | 317 | * Check the vma index is within the range and do |
182 | * sequential scan until m_index. | 318 | * sequential scan until m_index. |
183 | */ | 319 | */ |
184 | map = NULL; | 320 | vma = NULL; |
185 | if ((unsigned long)l < mm->map_count) { | 321 | if ((unsigned long)l < mm->map_count) { |
186 | map = mm->mmap; | 322 | vma = mm->mmap; |
187 | while (l-- && map) | 323 | while (l-- && vma) |
188 | map = map->vm_next; | 324 | vma = vma->vm_next; |
189 | goto out; | 325 | goto out; |
190 | } | 326 | } |
191 | 327 | ||
192 | if (l != mm->map_count) | 328 | if (l != mm->map_count) |
193 | tail_map = NULL; /* After gate map */ | 329 | tail_vma = NULL; /* After gate vma */ |
194 | 330 | ||
195 | out: | 331 | out: |
196 | if (map) | 332 | if (vma) |
197 | return map; | 333 | return vma; |
198 | 334 | ||
199 | /* End of maps has reached */ | 335 | /* End of vmas has been reached */ |
200 | m->version = (tail_map != NULL)? 0: -1UL; | 336 | m->version = (tail_vma != NULL)? 0: -1UL; |
201 | up_read(&mm->mmap_sem); | 337 | up_read(&mm->mmap_sem); |
202 | mmput(mm); | 338 | mmput(mm); |
203 | return tail_map; | 339 | return tail_vma; |
204 | } | 340 | } |
205 | 341 | ||
206 | static void m_stop(struct seq_file *m, void *v) | 342 | static void m_stop(struct seq_file *m, void *v) |
207 | { | 343 | { |
208 | struct task_struct *task = m->private; | 344 | struct task_struct *task = m->private; |
209 | struct vm_area_struct *map = v; | 345 | struct vm_area_struct *vma = v; |
210 | if (map && map != get_gate_vma(task)) { | 346 | if (vma && vma != get_gate_vma(task)) { |
211 | struct mm_struct *mm = map->vm_mm; | 347 | struct mm_struct *mm = vma->vm_mm; |
212 | up_read(&mm->mmap_sem); | 348 | up_read(&mm->mmap_sem); |
213 | mmput(mm); | 349 | mmput(mm); |
214 | } | 350 | } |
@@ -217,14 +353,14 @@ static void m_stop(struct seq_file *m, void *v) | |||
217 | static void *m_next(struct seq_file *m, void *v, loff_t *pos) | 353 | static void *m_next(struct seq_file *m, void *v, loff_t *pos) |
218 | { | 354 | { |
219 | struct task_struct *task = m->private; | 355 | struct task_struct *task = m->private; |
220 | struct vm_area_struct *map = v; | 356 | struct vm_area_struct *vma = v; |
221 | struct vm_area_struct *tail_map = get_gate_vma(task); | 357 | struct vm_area_struct *tail_vma = get_gate_vma(task); |
222 | 358 | ||
223 | (*pos)++; | 359 | (*pos)++; |
224 | if (map && (map != tail_map) && map->vm_next) | 360 | if (vma && (vma != tail_vma) && vma->vm_next) |
225 | return map->vm_next; | 361 | return vma->vm_next; |
226 | m_stop(m, v); | 362 | m_stop(m, v); |
227 | return (map != tail_map)? tail_map: NULL; | 363 | return (vma != tail_vma)? tail_vma: NULL; |
228 | } | 364 | } |
229 | 365 | ||
230 | struct seq_operations proc_pid_maps_op = { | 366 | struct seq_operations proc_pid_maps_op = { |
@@ -233,3 +369,140 @@ struct seq_operations proc_pid_maps_op = { | |||
233 | .stop = m_stop, | 369 | .stop = m_stop, |
234 | .show = show_map | 370 | .show = show_map |
235 | }; | 371 | }; |
372 | |||
373 | struct seq_operations proc_pid_smaps_op = { | ||
374 | .start = m_start, | ||
375 | .next = m_next, | ||
376 | .stop = m_stop, | ||
377 | .show = show_smap | ||
378 | }; | ||
379 | |||
380 | #ifdef CONFIG_NUMA | ||
381 | |||
382 | struct numa_maps { | ||
383 | unsigned long pages; | ||
384 | unsigned long anon; | ||
385 | unsigned long mapped; | ||
386 | unsigned long mapcount_max; | ||
387 | unsigned long node[MAX_NUMNODES]; | ||
388 | }; | ||
389 | |||
390 | /* | ||
391 | * Calculate numa node maps for a vma | ||
392 | */ | ||
393 | static struct numa_maps *get_numa_maps(const struct vm_area_struct *vma) | ||
394 | { | ||
395 | struct page *page; | ||
396 | unsigned long vaddr; | ||
397 | struct mm_struct *mm = vma->vm_mm; | ||
398 | int i; | ||
399 | struct numa_maps *md = kmalloc(sizeof(struct numa_maps), GFP_KERNEL); | ||
400 | |||
401 | if (!md) | ||
402 | return NULL; | ||
403 | md->pages = 0; | ||
404 | md->anon = 0; | ||
405 | md->mapped = 0; | ||
406 | md->mapcount_max = 0; | ||
407 | for_each_node(i) | ||
408 | md->node[i] =0; | ||
409 | |||
410 | spin_lock(&mm->page_table_lock); | ||
411 | for (vaddr = vma->vm_start; vaddr < vma->vm_end; vaddr += PAGE_SIZE) { | ||
412 | page = follow_page(mm, vaddr, 0); | ||
413 | if (page) { | ||
414 | int count = page_mapcount(page); | ||
415 | |||
416 | if (count) | ||
417 | md->mapped++; | ||
418 | if (count > md->mapcount_max) | ||
419 | md->mapcount_max = count; | ||
420 | md->pages++; | ||
421 | if (PageAnon(page)) | ||
422 | md->anon++; | ||
423 | md->node[page_to_nid(page)]++; | ||
424 | } | ||
425 | } | ||
426 | spin_unlock(&mm->page_table_lock); | ||
427 | return md; | ||
428 | } | ||
429 | |||
430 | static int show_numa_map(struct seq_file *m, void *v) | ||
431 | { | ||
432 | struct task_struct *task = m->private; | ||
433 | struct vm_area_struct *vma = v; | ||
434 | struct mempolicy *pol; | ||
435 | struct numa_maps *md; | ||
436 | struct zone **z; | ||
437 | int n; | ||
438 | int first; | ||
439 | |||
440 | if (!vma->vm_mm) | ||
441 | return 0; | ||
442 | |||
443 | md = get_numa_maps(vma); | ||
444 | if (!md) | ||
445 | return 0; | ||
446 | |||
447 | seq_printf(m, "%08lx", vma->vm_start); | ||
448 | pol = get_vma_policy(task, vma, vma->vm_start); | ||
449 | /* Print policy */ | ||
450 | switch (pol->policy) { | ||
451 | case MPOL_PREFERRED: | ||
452 | seq_printf(m, " prefer=%d", pol->v.preferred_node); | ||
453 | break; | ||
454 | case MPOL_BIND: | ||
455 | seq_printf(m, " bind={"); | ||
456 | first = 1; | ||
457 | for (z = pol->v.zonelist->zones; *z; z++) { | ||
458 | |||
459 | if (!first) | ||
460 | seq_putc(m, ','); | ||
461 | else | ||
462 | first = 0; | ||
463 | seq_printf(m, "%d/%s", (*z)->zone_pgdat->node_id, | ||
464 | (*z)->name); | ||
465 | } | ||
466 | seq_putc(m, '}'); | ||
467 | break; | ||
468 | case MPOL_INTERLEAVE: | ||
469 | seq_printf(m, " interleave={"); | ||
470 | first = 1; | ||
471 | for_each_node(n) { | ||
472 | if (test_bit(n, pol->v.nodes)) { | ||
473 | if (!first) | ||
474 | seq_putc(m,','); | ||
475 | else | ||
476 | first = 0; | ||
477 | seq_printf(m, "%d",n); | ||
478 | } | ||
479 | } | ||
480 | seq_putc(m, '}'); | ||
481 | break; | ||
482 | default: | ||
483 | seq_printf(m," default"); | ||
484 | break; | ||
485 | } | ||
486 | seq_printf(m, " MaxRef=%lu Pages=%lu Mapped=%lu", | ||
487 | md->mapcount_max, md->pages, md->mapped); | ||
488 | if (md->anon) | ||
489 | seq_printf(m," Anon=%lu",md->anon); | ||
490 | |||
491 | for_each_online_node(n) { | ||
492 | if (md->node[n]) | ||
493 | seq_printf(m, " N%d=%lu", n, md->node[n]); | ||
494 | } | ||
495 | seq_putc(m, '\n'); | ||
496 | kfree(md); | ||
497 | if (m->count < m->size) /* vma is copied successfully */ | ||
498 | m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0; | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | struct seq_operations proc_pid_numa_maps_op = { | ||
503 | .start = m_start, | ||
504 | .next = m_next, | ||
505 | .stop = m_stop, | ||
506 | .show = show_numa_map | ||
507 | }; | ||
508 | #endif | ||
diff --git a/fs/xattr.c b/fs/xattr.c index 6acd5c63da91..dc8bc7624f26 100644 --- a/fs/xattr.c +++ b/fs/xattr.c | |||
@@ -51,20 +51,29 @@ setxattr(struct dentry *d, char __user *name, void __user *value, | |||
51 | } | 51 | } |
52 | } | 52 | } |
53 | 53 | ||
54 | down(&d->d_inode->i_sem); | ||
55 | error = security_inode_setxattr(d, kname, kvalue, size, flags); | ||
56 | if (error) | ||
57 | goto out; | ||
54 | error = -EOPNOTSUPP; | 58 | error = -EOPNOTSUPP; |
55 | if (d->d_inode->i_op && d->d_inode->i_op->setxattr) { | 59 | if (d->d_inode->i_op && d->d_inode->i_op->setxattr) { |
56 | down(&d->d_inode->i_sem); | 60 | error = d->d_inode->i_op->setxattr(d, kname, kvalue, |
57 | error = security_inode_setxattr(d, kname, kvalue, size, flags); | 61 | size, flags); |
58 | if (error) | ||
59 | goto out; | ||
60 | error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags); | ||
61 | if (!error) { | 62 | if (!error) { |
62 | fsnotify_xattr(d); | 63 | fsnotify_xattr(d); |
63 | security_inode_post_setxattr(d, kname, kvalue, size, flags); | 64 | security_inode_post_setxattr(d, kname, kvalue, |
65 | size, flags); | ||
64 | } | 66 | } |
65 | out: | 67 | } else if (!strncmp(kname, XATTR_SECURITY_PREFIX, |
66 | up(&d->d_inode->i_sem); | 68 | sizeof XATTR_SECURITY_PREFIX - 1)) { |
69 | const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1; | ||
70 | error = security_inode_setsecurity(d->d_inode, suffix, kvalue, | ||
71 | size, flags); | ||
72 | if (!error) | ||
73 | fsnotify_xattr(d); | ||
67 | } | 74 | } |
75 | out: | ||
76 | up(&d->d_inode->i_sem); | ||
68 | if (kvalue) | 77 | if (kvalue) |
69 | kfree(kvalue); | 78 | kfree(kvalue); |
70 | return error; | 79 | return error; |
@@ -139,20 +148,25 @@ getxattr(struct dentry *d, char __user *name, void __user *value, size_t size) | |||
139 | return -ENOMEM; | 148 | return -ENOMEM; |
140 | } | 149 | } |
141 | 150 | ||
151 | error = security_inode_getxattr(d, kname); | ||
152 | if (error) | ||
153 | goto out; | ||
142 | error = -EOPNOTSUPP; | 154 | error = -EOPNOTSUPP; |
143 | if (d->d_inode->i_op && d->d_inode->i_op->getxattr) { | 155 | if (d->d_inode->i_op && d->d_inode->i_op->getxattr) |
144 | error = security_inode_getxattr(d, kname); | ||
145 | if (error) | ||
146 | goto out; | ||
147 | error = d->d_inode->i_op->getxattr(d, kname, kvalue, size); | 156 | error = d->d_inode->i_op->getxattr(d, kname, kvalue, size); |
148 | if (error > 0) { | 157 | else if (!strncmp(kname, XATTR_SECURITY_PREFIX, |
149 | if (size && copy_to_user(value, kvalue, error)) | 158 | sizeof XATTR_SECURITY_PREFIX - 1)) { |
150 | error = -EFAULT; | 159 | const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1; |
151 | } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) { | 160 | error = security_inode_getsecurity(d->d_inode, suffix, kvalue, |
152 | /* The file system tried to returned a value bigger | 161 | size); |
153 | than XATTR_SIZE_MAX bytes. Not possible. */ | 162 | } |
154 | error = -E2BIG; | 163 | if (error > 0) { |
155 | } | 164 | if (size && copy_to_user(value, kvalue, error)) |
165 | error = -EFAULT; | ||
166 | } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) { | ||
167 | /* The file system tried to returned a value bigger | ||
168 | than XATTR_SIZE_MAX bytes. Not possible. */ | ||
169 | error = -E2BIG; | ||
156 | } | 170 | } |
157 | out: | 171 | out: |
158 | if (kvalue) | 172 | if (kvalue) |
@@ -221,20 +235,24 @@ listxattr(struct dentry *d, char __user *list, size_t size) | |||
221 | return -ENOMEM; | 235 | return -ENOMEM; |
222 | } | 236 | } |
223 | 237 | ||
238 | error = security_inode_listxattr(d); | ||
239 | if (error) | ||
240 | goto out; | ||
224 | error = -EOPNOTSUPP; | 241 | error = -EOPNOTSUPP; |
225 | if (d->d_inode->i_op && d->d_inode->i_op->listxattr) { | 242 | if (d->d_inode->i_op && d->d_inode->i_op->listxattr) { |
226 | error = security_inode_listxattr(d); | ||
227 | if (error) | ||
228 | goto out; | ||
229 | error = d->d_inode->i_op->listxattr(d, klist, size); | 243 | error = d->d_inode->i_op->listxattr(d, klist, size); |
230 | if (error > 0) { | 244 | } else { |
231 | if (size && copy_to_user(list, klist, error)) | 245 | error = security_inode_listsecurity(d->d_inode, klist, size); |
232 | error = -EFAULT; | 246 | if (size && error >= size) |
233 | } else if (error == -ERANGE && size >= XATTR_LIST_MAX) { | 247 | error = -ERANGE; |
234 | /* The file system tried to returned a list bigger | 248 | } |
235 | than XATTR_LIST_MAX bytes. Not possible. */ | 249 | if (error > 0) { |
236 | error = -E2BIG; | 250 | if (size && copy_to_user(list, klist, error)) |
237 | } | 251 | error = -EFAULT; |
252 | } else if (error == -ERANGE && size >= XATTR_LIST_MAX) { | ||
253 | /* The file system tried to returned a list bigger | ||
254 | than XATTR_LIST_MAX bytes. Not possible. */ | ||
255 | error = -E2BIG; | ||
238 | } | 256 | } |
239 | out: | 257 | out: |
240 | if (klist) | 258 | if (klist) |