diff options
| -rw-r--r-- | arch/s390/hypfs/inode.c | 12 | ||||
| -rw-r--r-- | drivers/firmware/efi/efi.c | 6 | ||||
| -rw-r--r-- | fs/configfs/mount.c | 10 | ||||
| -rw-r--r-- | fs/dcache.c | 11 | ||||
| -rw-r--r-- | fs/debugfs/inode.c | 11 | ||||
| -rw-r--r-- | fs/fuse/inode.c | 9 | ||||
| -rw-r--r-- | fs/kernfs/dir.c | 38 | ||||
| -rw-r--r-- | fs/kernfs/inode.c | 2 | ||||
| -rw-r--r-- | fs/libfs.c | 95 | ||||
| -rw-r--r-- | fs/namespace.c | 39 | ||||
| -rw-r--r-- | fs/proc/generic.c | 23 | ||||
| -rw-r--r-- | fs/proc/inode.c | 4 | ||||
| -rw-r--r-- | fs/proc/internal.h | 6 | ||||
| -rw-r--r-- | fs/proc/proc_sysctl.c | 37 | ||||
| -rw-r--r-- | fs/proc/root.c | 9 | ||||
| -rw-r--r-- | fs/pstore/inode.c | 12 | ||||
| -rw-r--r-- | fs/sysfs/dir.c | 34 | ||||
| -rw-r--r-- | fs/sysfs/mount.c | 5 | ||||
| -rw-r--r-- | fs/tracefs/inode.c | 6 | ||||
| -rw-r--r-- | include/linux/fs.h | 4 | ||||
| -rw-r--r-- | include/linux/kernfs.h | 3 | ||||
| -rw-r--r-- | include/linux/sysctl.h | 3 | ||||
| -rw-r--r-- | include/linux/sysfs.h | 15 | ||||
| -rw-r--r-- | kernel/cgroup.c | 10 | ||||
| -rw-r--r-- | kernel/sysctl.c | 8 | ||||
| -rw-r--r-- | security/inode.c | 10 | ||||
| -rw-r--r-- | security/selinux/selinuxfs.c | 11 | ||||
| -rw-r--r-- | security/smack/smackfs.c | 8 |
28 files changed, 340 insertions, 101 deletions
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index d3f896a35b98..2eeb0a0f506d 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c | |||
| @@ -456,8 +456,6 @@ static const struct super_operations hypfs_s_ops = { | |||
| 456 | .show_options = hypfs_show_options, | 456 | .show_options = hypfs_show_options, |
| 457 | }; | 457 | }; |
| 458 | 458 | ||
| 459 | static struct kobject *s390_kobj; | ||
| 460 | |||
| 461 | static int __init hypfs_init(void) | 459 | static int __init hypfs_init(void) |
| 462 | { | 460 | { |
| 463 | int rc; | 461 | int rc; |
| @@ -481,18 +479,16 @@ static int __init hypfs_init(void) | |||
| 481 | rc = -ENODATA; | 479 | rc = -ENODATA; |
| 482 | goto fail_hypfs_sprp_exit; | 480 | goto fail_hypfs_sprp_exit; |
| 483 | } | 481 | } |
| 484 | s390_kobj = kobject_create_and_add("s390", hypervisor_kobj); | 482 | rc = sysfs_create_mount_point(hypervisor_kobj, "s390"); |
| 485 | if (!s390_kobj) { | 483 | if (rc) |
| 486 | rc = -ENOMEM; | ||
| 487 | goto fail_hypfs_diag0c_exit; | 484 | goto fail_hypfs_diag0c_exit; |
| 488 | } | ||
| 489 | rc = register_filesystem(&hypfs_type); | 485 | rc = register_filesystem(&hypfs_type); |
| 490 | if (rc) | 486 | if (rc) |
| 491 | goto fail_filesystem; | 487 | goto fail_filesystem; |
| 492 | return 0; | 488 | return 0; |
| 493 | 489 | ||
| 494 | fail_filesystem: | 490 | fail_filesystem: |
| 495 | kobject_put(s390_kobj); | 491 | sysfs_remove_mount_point(hypervisor_kobj, "s390"); |
| 496 | fail_hypfs_diag0c_exit: | 492 | fail_hypfs_diag0c_exit: |
| 497 | hypfs_diag0c_exit(); | 493 | hypfs_diag0c_exit(); |
| 498 | fail_hypfs_sprp_exit: | 494 | fail_hypfs_sprp_exit: |
| @@ -510,7 +506,7 @@ fail_dbfs_exit: | |||
| 510 | static void __exit hypfs_exit(void) | 506 | static void __exit hypfs_exit(void) |
| 511 | { | 507 | { |
| 512 | unregister_filesystem(&hypfs_type); | 508 | unregister_filesystem(&hypfs_type); |
| 513 | kobject_put(s390_kobj); | 509 | sysfs_remove_mount_point(hypervisor_kobj, "s390"); |
| 514 | hypfs_diag0c_exit(); | 510 | hypfs_diag0c_exit(); |
| 515 | hypfs_sprp_exit(); | 511 | hypfs_sprp_exit(); |
| 516 | hypfs_vm_exit(); | 512 | hypfs_vm_exit(); |
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index ca617f40574a..9fa8084a7c8d 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c | |||
| @@ -66,7 +66,6 @@ static int __init parse_efi_cmdline(char *str) | |||
| 66 | early_param("efi", parse_efi_cmdline); | 66 | early_param("efi", parse_efi_cmdline); |
| 67 | 67 | ||
| 68 | struct kobject *efi_kobj; | 68 | struct kobject *efi_kobj; |
| 69 | static struct kobject *efivars_kobj; | ||
| 70 | 69 | ||
| 71 | /* | 70 | /* |
| 72 | * Let's not leave out systab information that snuck into | 71 | * Let's not leave out systab information that snuck into |
| @@ -218,10 +217,9 @@ static int __init efisubsys_init(void) | |||
| 218 | goto err_remove_group; | 217 | goto err_remove_group; |
| 219 | 218 | ||
| 220 | /* and the standard mountpoint for efivarfs */ | 219 | /* and the standard mountpoint for efivarfs */ |
| 221 | efivars_kobj = kobject_create_and_add("efivars", efi_kobj); | 220 | error = sysfs_create_mount_point(efi_kobj, "efivars"); |
| 222 | if (!efivars_kobj) { | 221 | if (error) { |
| 223 | pr_err("efivars: Subsystem registration failed.\n"); | 222 | pr_err("efivars: Subsystem registration failed.\n"); |
| 224 | error = -ENOMEM; | ||
| 225 | goto err_remove_group; | 223 | goto err_remove_group; |
| 226 | } | 224 | } |
| 227 | 225 | ||
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index 537356742091..a8f3b589a2df 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c | |||
| @@ -129,8 +129,6 @@ void configfs_release_fs(void) | |||
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | 131 | ||
| 132 | static struct kobject *config_kobj; | ||
| 133 | |||
| 134 | static int __init configfs_init(void) | 132 | static int __init configfs_init(void) |
| 135 | { | 133 | { |
| 136 | int err = -ENOMEM; | 134 | int err = -ENOMEM; |
| @@ -141,8 +139,8 @@ static int __init configfs_init(void) | |||
| 141 | if (!configfs_dir_cachep) | 139 | if (!configfs_dir_cachep) |
| 142 | goto out; | 140 | goto out; |
| 143 | 141 | ||
| 144 | config_kobj = kobject_create_and_add("config", kernel_kobj); | 142 | err = sysfs_create_mount_point(kernel_kobj, "config"); |
| 145 | if (!config_kobj) | 143 | if (err) |
| 146 | goto out2; | 144 | goto out2; |
| 147 | 145 | ||
| 148 | err = register_filesystem(&configfs_fs_type); | 146 | err = register_filesystem(&configfs_fs_type); |
| @@ -152,7 +150,7 @@ static int __init configfs_init(void) | |||
| 152 | return 0; | 150 | return 0; |
| 153 | out3: | 151 | out3: |
| 154 | pr_err("Unable to register filesystem!\n"); | 152 | pr_err("Unable to register filesystem!\n"); |
| 155 | kobject_put(config_kobj); | 153 | sysfs_remove_mount_point(kernel_kobj, "config"); |
| 156 | out2: | 154 | out2: |
| 157 | kmem_cache_destroy(configfs_dir_cachep); | 155 | kmem_cache_destroy(configfs_dir_cachep); |
| 158 | configfs_dir_cachep = NULL; | 156 | configfs_dir_cachep = NULL; |
| @@ -163,7 +161,7 @@ out: | |||
| 163 | static void __exit configfs_exit(void) | 161 | static void __exit configfs_exit(void) |
| 164 | { | 162 | { |
| 165 | unregister_filesystem(&configfs_fs_type); | 163 | unregister_filesystem(&configfs_fs_type); |
| 166 | kobject_put(config_kobj); | 164 | sysfs_remove_mount_point(kernel_kobj, "config"); |
| 167 | kmem_cache_destroy(configfs_dir_cachep); | 165 | kmem_cache_destroy(configfs_dir_cachep); |
| 168 | configfs_dir_cachep = NULL; | 166 | configfs_dir_cachep = NULL; |
| 169 | } | 167 | } |
diff --git a/fs/dcache.c b/fs/dcache.c index 592c4b582495..910968b4b6bf 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -2927,17 +2927,6 @@ restart: | |||
| 2927 | vfsmnt = &mnt->mnt; | 2927 | vfsmnt = &mnt->mnt; |
| 2928 | continue; | 2928 | continue; |
| 2929 | } | 2929 | } |
| 2930 | /* | ||
| 2931 | * Filesystems needing to implement special "root names" | ||
| 2932 | * should do so with ->d_dname() | ||
| 2933 | */ | ||
| 2934 | if (IS_ROOT(dentry) && | ||
| 2935 | (dentry->d_name.len != 1 || | ||
| 2936 | dentry->d_name.name[0] != '/')) { | ||
| 2937 | WARN(1, "Root dentry has weird name <%.*s>\n", | ||
| 2938 | (int) dentry->d_name.len, | ||
| 2939 | dentry->d_name.name); | ||
| 2940 | } | ||
| 2941 | if (!error) | 2930 | if (!error) |
| 2942 | error = is_mounted(vfsmnt) ? 1 : 2; | 2931 | error = is_mounted(vfsmnt) ? 1 : 2; |
| 2943 | break; | 2932 | break; |
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 7eaec88ea970..d6d1cf004123 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
| @@ -716,20 +716,17 @@ bool debugfs_initialized(void) | |||
| 716 | } | 716 | } |
| 717 | EXPORT_SYMBOL_GPL(debugfs_initialized); | 717 | EXPORT_SYMBOL_GPL(debugfs_initialized); |
| 718 | 718 | ||
| 719 | |||
| 720 | static struct kobject *debug_kobj; | ||
| 721 | |||
| 722 | static int __init debugfs_init(void) | 719 | static int __init debugfs_init(void) |
| 723 | { | 720 | { |
| 724 | int retval; | 721 | int retval; |
| 725 | 722 | ||
| 726 | debug_kobj = kobject_create_and_add("debug", kernel_kobj); | 723 | retval = sysfs_create_mount_point(kernel_kobj, "debug"); |
| 727 | if (!debug_kobj) | 724 | if (retval) |
| 728 | return -EINVAL; | 725 | return retval; |
| 729 | 726 | ||
| 730 | retval = register_filesystem(&debug_fs_type); | 727 | retval = register_filesystem(&debug_fs_type); |
| 731 | if (retval) | 728 | if (retval) |
| 732 | kobject_put(debug_kobj); | 729 | sysfs_remove_mount_point(kernel_kobj, "debug"); |
| 733 | else | 730 | else |
| 734 | debugfs_registered = true; | 731 | debugfs_registered = true; |
| 735 | 732 | ||
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index ac81f48ab2f4..2913db2a5b99 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
| @@ -1294,7 +1294,6 @@ static void fuse_fs_cleanup(void) | |||
| 1294 | } | 1294 | } |
| 1295 | 1295 | ||
| 1296 | static struct kobject *fuse_kobj; | 1296 | static struct kobject *fuse_kobj; |
| 1297 | static struct kobject *connections_kobj; | ||
| 1298 | 1297 | ||
| 1299 | static int fuse_sysfs_init(void) | 1298 | static int fuse_sysfs_init(void) |
| 1300 | { | 1299 | { |
| @@ -1306,11 +1305,9 @@ static int fuse_sysfs_init(void) | |||
| 1306 | goto out_err; | 1305 | goto out_err; |
| 1307 | } | 1306 | } |
| 1308 | 1307 | ||
| 1309 | connections_kobj = kobject_create_and_add("connections", fuse_kobj); | 1308 | err = sysfs_create_mount_point(fuse_kobj, "connections"); |
| 1310 | if (!connections_kobj) { | 1309 | if (err) |
| 1311 | err = -ENOMEM; | ||
| 1312 | goto out_fuse_unregister; | 1310 | goto out_fuse_unregister; |
| 1313 | } | ||
| 1314 | 1311 | ||
| 1315 | return 0; | 1312 | return 0; |
| 1316 | 1313 | ||
| @@ -1322,7 +1319,7 @@ static int fuse_sysfs_init(void) | |||
| 1322 | 1319 | ||
| 1323 | static void fuse_sysfs_cleanup(void) | 1320 | static void fuse_sysfs_cleanup(void) |
| 1324 | { | 1321 | { |
| 1325 | kobject_put(connections_kobj); | 1322 | sysfs_remove_mount_point(fuse_kobj, "connections"); |
| 1326 | kobject_put(fuse_kobj); | 1323 | kobject_put(fuse_kobj); |
| 1327 | } | 1324 | } |
| 1328 | 1325 | ||
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index fffca9517321..2d48d28e1640 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c | |||
| @@ -592,6 +592,9 @@ int kernfs_add_one(struct kernfs_node *kn) | |||
| 592 | goto out_unlock; | 592 | goto out_unlock; |
| 593 | 593 | ||
| 594 | ret = -ENOENT; | 594 | ret = -ENOENT; |
| 595 | if (parent->flags & KERNFS_EMPTY_DIR) | ||
| 596 | goto out_unlock; | ||
| 597 | |||
| 595 | if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active(parent)) | 598 | if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active(parent)) |
| 596 | goto out_unlock; | 599 | goto out_unlock; |
| 597 | 600 | ||
| @@ -783,6 +786,38 @@ struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, | |||
| 783 | return ERR_PTR(rc); | 786 | return ERR_PTR(rc); |
| 784 | } | 787 | } |
| 785 | 788 | ||
| 789 | /** | ||
| 790 | * kernfs_create_empty_dir - create an always empty directory | ||
| 791 | * @parent: parent in which to create a new directory | ||
| 792 | * @name: name of the new directory | ||
| 793 | * | ||
| 794 | * Returns the created node on success, ERR_PTR() value on failure. | ||
| 795 | */ | ||
| 796 | struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent, | ||
| 797 | const char *name) | ||
| 798 | { | ||
| 799 | struct kernfs_node *kn; | ||
| 800 | int rc; | ||
| 801 | |||
| 802 | /* allocate */ | ||
| 803 | kn = kernfs_new_node(parent, name, S_IRUGO|S_IXUGO|S_IFDIR, KERNFS_DIR); | ||
| 804 | if (!kn) | ||
| 805 | return ERR_PTR(-ENOMEM); | ||
| 806 | |||
| 807 | kn->flags |= KERNFS_EMPTY_DIR; | ||
| 808 | kn->dir.root = parent->dir.root; | ||
| 809 | kn->ns = NULL; | ||
| 810 | kn->priv = NULL; | ||
| 811 | |||
| 812 | /* link in */ | ||
| 813 | rc = kernfs_add_one(kn); | ||
| 814 | if (!rc) | ||
| 815 | return kn; | ||
| 816 | |||
| 817 | kernfs_put(kn); | ||
| 818 | return ERR_PTR(rc); | ||
| 819 | } | ||
| 820 | |||
| 786 | static struct dentry *kernfs_iop_lookup(struct inode *dir, | 821 | static struct dentry *kernfs_iop_lookup(struct inode *dir, |
| 787 | struct dentry *dentry, | 822 | struct dentry *dentry, |
| 788 | unsigned int flags) | 823 | unsigned int flags) |
| @@ -1254,7 +1289,8 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, | |||
| 1254 | mutex_lock(&kernfs_mutex); | 1289 | mutex_lock(&kernfs_mutex); |
| 1255 | 1290 | ||
| 1256 | error = -ENOENT; | 1291 | error = -ENOENT; |
| 1257 | if (!kernfs_active(kn) || !kernfs_active(new_parent)) | 1292 | if (!kernfs_active(kn) || !kernfs_active(new_parent) || |
| 1293 | (new_parent->flags & KERNFS_EMPTY_DIR)) | ||
| 1258 | goto out; | 1294 | goto out; |
| 1259 | 1295 | ||
| 1260 | error = 0; | 1296 | error = 0; |
diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c index 2da8493a380b..756dd56aaf60 100644 --- a/fs/kernfs/inode.c +++ b/fs/kernfs/inode.c | |||
| @@ -296,6 +296,8 @@ static void kernfs_init_inode(struct kernfs_node *kn, struct inode *inode) | |||
| 296 | case KERNFS_DIR: | 296 | case KERNFS_DIR: |
| 297 | inode->i_op = &kernfs_dir_iops; | 297 | inode->i_op = &kernfs_dir_iops; |
| 298 | inode->i_fop = &kernfs_dir_fops; | 298 | inode->i_fop = &kernfs_dir_fops; |
| 299 | if (kn->flags & KERNFS_EMPTY_DIR) | ||
| 300 | make_empty_dir_inode(inode); | ||
| 299 | break; | 301 | break; |
| 300 | case KERNFS_FILE: | 302 | case KERNFS_FILE: |
| 301 | inode->i_size = kn->attr.size; | 303 | inode->i_size = kn->attr.size; |
diff --git a/fs/libfs.c b/fs/libfs.c index 65e1feca8b98..88a4cb418756 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
| @@ -1108,3 +1108,98 @@ const struct inode_operations simple_symlink_inode_operations = { | |||
| 1108 | .readlink = generic_readlink | 1108 | .readlink = generic_readlink |
| 1109 | }; | 1109 | }; |
| 1110 | EXPORT_SYMBOL(simple_symlink_inode_operations); | 1110 | EXPORT_SYMBOL(simple_symlink_inode_operations); |
| 1111 | |||
| 1112 | /* | ||
| 1113 | * Operations for a permanently empty directory. | ||
| 1114 | */ | ||
| 1115 | static struct dentry *empty_dir_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) | ||
| 1116 | { | ||
| 1117 | return ERR_PTR(-ENOENT); | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | static int empty_dir_getattr(struct vfsmount *mnt, struct dentry *dentry, | ||
| 1121 | struct kstat *stat) | ||
| 1122 | { | ||
| 1123 | struct inode *inode = d_inode(dentry); | ||
| 1124 | generic_fillattr(inode, stat); | ||
| 1125 | return 0; | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | static int empty_dir_setattr(struct dentry *dentry, struct iattr *attr) | ||
| 1129 | { | ||
| 1130 | return -EPERM; | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | static int empty_dir_setxattr(struct dentry *dentry, const char *name, | ||
| 1134 | const void *value, size_t size, int flags) | ||
| 1135 | { | ||
| 1136 | return -EOPNOTSUPP; | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | static ssize_t empty_dir_getxattr(struct dentry *dentry, const char *name, | ||
| 1140 | void *value, size_t size) | ||
| 1141 | { | ||
| 1142 | return -EOPNOTSUPP; | ||
| 1143 | } | ||
| 1144 | |||
| 1145 | static int empty_dir_removexattr(struct dentry *dentry, const char *name) | ||
| 1146 | { | ||
| 1147 | return -EOPNOTSUPP; | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | static ssize_t empty_dir_listxattr(struct dentry *dentry, char *list, size_t size) | ||
| 1151 | { | ||
| 1152 | return -EOPNOTSUPP; | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | static const struct inode_operations empty_dir_inode_operations = { | ||
| 1156 | .lookup = empty_dir_lookup, | ||
| 1157 | .permission = generic_permission, | ||
| 1158 | .setattr = empty_dir_setattr, | ||
| 1159 | .getattr = empty_dir_getattr, | ||
| 1160 | .setxattr = empty_dir_setxattr, | ||
| 1161 | .getxattr = empty_dir_getxattr, | ||
| 1162 | .removexattr = empty_dir_removexattr, | ||
| 1163 | .listxattr = empty_dir_listxattr, | ||
| 1164 | }; | ||
| 1165 | |||
| 1166 | static loff_t empty_dir_llseek(struct file *file, loff_t offset, int whence) | ||
| 1167 | { | ||
| 1168 | /* An empty directory has two entries . and .. at offsets 0 and 1 */ | ||
| 1169 | return generic_file_llseek_size(file, offset, whence, 2, 2); | ||
| 1170 | } | ||
| 1171 | |||
| 1172 | static int empty_dir_readdir(struct file *file, struct dir_context *ctx) | ||
| 1173 | { | ||
| 1174 | dir_emit_dots(file, ctx); | ||
| 1175 | return 0; | ||
| 1176 | } | ||
| 1177 | |||
| 1178 | static const struct file_operations empty_dir_operations = { | ||
| 1179 | .llseek = empty_dir_llseek, | ||
| 1180 | .read = generic_read_dir, | ||
| 1181 | .iterate = empty_dir_readdir, | ||
| 1182 | .fsync = noop_fsync, | ||
| 1183 | }; | ||
| 1184 | |||
| 1185 | |||
| 1186 | void make_empty_dir_inode(struct inode *inode) | ||
| 1187 | { | ||
| 1188 | set_nlink(inode, 2); | ||
| 1189 | inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; | ||
| 1190 | inode->i_uid = GLOBAL_ROOT_UID; | ||
| 1191 | inode->i_gid = GLOBAL_ROOT_GID; | ||
| 1192 | inode->i_rdev = 0; | ||
| 1193 | inode->i_size = 2; | ||
| 1194 | inode->i_blkbits = PAGE_SHIFT; | ||
| 1195 | inode->i_blocks = 0; | ||
| 1196 | |||
| 1197 | inode->i_op = &empty_dir_inode_operations; | ||
| 1198 | inode->i_fop = &empty_dir_operations; | ||
| 1199 | } | ||
| 1200 | |||
| 1201 | bool is_empty_dir_inode(struct inode *inode) | ||
| 1202 | { | ||
| 1203 | return (inode->i_fop == &empty_dir_operations) && | ||
| 1204 | (inode->i_op == &empty_dir_inode_operations); | ||
| 1205 | } | ||
diff --git a/fs/namespace.c b/fs/namespace.c index e99f1f4e00cd..c7cb8a526c05 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -2343,6 +2343,8 @@ unlock: | |||
| 2343 | return err; | 2343 | return err; |
| 2344 | } | 2344 | } |
| 2345 | 2345 | ||
| 2346 | static bool fs_fully_visible(struct file_system_type *fs_type, int *new_mnt_flags); | ||
| 2347 | |||
| 2346 | /* | 2348 | /* |
| 2347 | * create a new mount for userspace and request it to be added into the | 2349 | * create a new mount for userspace and request it to be added into the |
| 2348 | * namespace's tree | 2350 | * namespace's tree |
| @@ -2374,6 +2376,10 @@ static int do_new_mount(struct path *path, const char *fstype, int flags, | |||
| 2374 | flags |= MS_NODEV; | 2376 | flags |= MS_NODEV; |
| 2375 | mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV; | 2377 | mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV; |
| 2376 | } | 2378 | } |
| 2379 | if (type->fs_flags & FS_USERNS_VISIBLE) { | ||
| 2380 | if (!fs_fully_visible(type, &mnt_flags)) | ||
| 2381 | return -EPERM; | ||
| 2382 | } | ||
| 2377 | } | 2383 | } |
| 2378 | 2384 | ||
| 2379 | mnt = vfs_kern_mount(type, flags, name, data); | 2385 | mnt = vfs_kern_mount(type, flags, name, data); |
| @@ -3175,9 +3181,10 @@ bool current_chrooted(void) | |||
| 3175 | return chrooted; | 3181 | return chrooted; |
| 3176 | } | 3182 | } |
| 3177 | 3183 | ||
| 3178 | bool fs_fully_visible(struct file_system_type *type) | 3184 | static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags) |
| 3179 | { | 3185 | { |
| 3180 | struct mnt_namespace *ns = current->nsproxy->mnt_ns; | 3186 | struct mnt_namespace *ns = current->nsproxy->mnt_ns; |
| 3187 | int new_flags = *new_mnt_flags; | ||
| 3181 | struct mount *mnt; | 3188 | struct mount *mnt; |
| 3182 | bool visible = false; | 3189 | bool visible = false; |
| 3183 | 3190 | ||
| @@ -3196,16 +3203,36 @@ bool fs_fully_visible(struct file_system_type *type) | |||
| 3196 | if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root) | 3203 | if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root) |
| 3197 | continue; | 3204 | continue; |
| 3198 | 3205 | ||
| 3199 | /* This mount is not fully visible if there are any child mounts | 3206 | /* Verify the mount flags are equal to or more permissive |
| 3200 | * that cover anything except for empty directories. | 3207 | * than the proposed new mount. |
| 3208 | */ | ||
| 3209 | if ((mnt->mnt.mnt_flags & MNT_LOCK_READONLY) && | ||
| 3210 | !(new_flags & MNT_READONLY)) | ||
| 3211 | continue; | ||
| 3212 | if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) && | ||
| 3213 | !(new_flags & MNT_NODEV)) | ||
| 3214 | continue; | ||
| 3215 | if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) && | ||
| 3216 | ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK))) | ||
| 3217 | continue; | ||
| 3218 | |||
| 3219 | /* This mount is not fully visible if there are any | ||
| 3220 | * locked child mounts that cover anything except for | ||
| 3221 | * empty directories. | ||
| 3201 | */ | 3222 | */ |
| 3202 | list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { | 3223 | list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { |
| 3203 | struct inode *inode = child->mnt_mountpoint->d_inode; | 3224 | struct inode *inode = child->mnt_mountpoint->d_inode; |
| 3204 | if (!S_ISDIR(inode->i_mode)) | 3225 | /* Only worry about locked mounts */ |
| 3205 | goto next; | 3226 | if (!(mnt->mnt.mnt_flags & MNT_LOCKED)) |
| 3206 | if (inode->i_nlink > 2) | 3227 | continue; |
| 3228 | /* Is the directory permanetly empty? */ | ||
| 3229 | if (!is_empty_dir_inode(inode)) | ||
| 3207 | goto next; | 3230 | goto next; |
| 3208 | } | 3231 | } |
| 3232 | /* Preserve the locked attributes */ | ||
| 3233 | *new_mnt_flags |= mnt->mnt.mnt_flags & (MNT_LOCK_READONLY | \ | ||
| 3234 | MNT_LOCK_NODEV | \ | ||
| 3235 | MNT_LOCK_ATIME); | ||
| 3209 | visible = true; | 3236 | visible = true; |
| 3210 | goto found; | 3237 | goto found; |
| 3211 | next: ; | 3238 | next: ; |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index df6327a2b865..e5dee5c3188e 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
| @@ -373,6 +373,10 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, | |||
| 373 | WARN(1, "create '/proc/%s' by hand\n", qstr.name); | 373 | WARN(1, "create '/proc/%s' by hand\n", qstr.name); |
| 374 | return NULL; | 374 | return NULL; |
| 375 | } | 375 | } |
| 376 | if (is_empty_pde(*parent)) { | ||
| 377 | WARN(1, "attempt to add to permanently empty directory"); | ||
| 378 | return NULL; | ||
| 379 | } | ||
| 376 | 380 | ||
| 377 | ent = kzalloc(sizeof(struct proc_dir_entry) + qstr.len + 1, GFP_KERNEL); | 381 | ent = kzalloc(sizeof(struct proc_dir_entry) + qstr.len + 1, GFP_KERNEL); |
| 378 | if (!ent) | 382 | if (!ent) |
| @@ -455,6 +459,25 @@ struct proc_dir_entry *proc_mkdir(const char *name, | |||
| 455 | } | 459 | } |
| 456 | EXPORT_SYMBOL(proc_mkdir); | 460 | EXPORT_SYMBOL(proc_mkdir); |
| 457 | 461 | ||
| 462 | struct proc_dir_entry *proc_create_mount_point(const char *name) | ||
| 463 | { | ||
| 464 | umode_t mode = S_IFDIR | S_IRUGO | S_IXUGO; | ||
| 465 | struct proc_dir_entry *ent, *parent = NULL; | ||
| 466 | |||
| 467 | ent = __proc_create(&parent, name, mode, 2); | ||
| 468 | if (ent) { | ||
| 469 | ent->data = NULL; | ||
| 470 | ent->proc_fops = NULL; | ||
| 471 | ent->proc_iops = NULL; | ||
| 472 | if (proc_register(parent, ent) < 0) { | ||
| 473 | kfree(ent); | ||
| 474 | parent->nlink--; | ||
| 475 | ent = NULL; | ||
| 476 | } | ||
| 477 | } | ||
| 478 | return ent; | ||
| 479 | } | ||
| 480 | |||
| 458 | struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, | 481 | struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, |
| 459 | struct proc_dir_entry *parent, | 482 | struct proc_dir_entry *parent, |
| 460 | const struct file_operations *proc_fops, | 483 | const struct file_operations *proc_fops, |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index afe232b9df6e..bd95b9fdebb0 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
| @@ -422,6 +422,10 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) | |||
| 422 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | 422 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
| 423 | PROC_I(inode)->pde = de; | 423 | PROC_I(inode)->pde = de; |
| 424 | 424 | ||
| 425 | if (is_empty_pde(de)) { | ||
| 426 | make_empty_dir_inode(inode); | ||
| 427 | return inode; | ||
| 428 | } | ||
| 425 | if (de->mode) { | 429 | if (de->mode) { |
| 426 | inode->i_mode = de->mode; | 430 | inode->i_mode = de->mode; |
| 427 | inode->i_uid = de->uid; | 431 | inode->i_uid = de->uid; |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index c835b94c0cd3..aa2781095bd1 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
| @@ -191,6 +191,12 @@ static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde) | |||
| 191 | } | 191 | } |
| 192 | extern void pde_put(struct proc_dir_entry *); | 192 | extern void pde_put(struct proc_dir_entry *); |
| 193 | 193 | ||
| 194 | static inline bool is_empty_pde(const struct proc_dir_entry *pde) | ||
| 195 | { | ||
| 196 | return S_ISDIR(pde->mode) && !pde->proc_iops; | ||
| 197 | } | ||
| 198 | struct proc_dir_entry *proc_create_mount_point(const char *name); | ||
| 199 | |||
| 194 | /* | 200 | /* |
| 195 | * inode.c | 201 | * inode.c |
| 196 | */ | 202 | */ |
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index fea2561d773b..fdda62e6115e 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
| @@ -19,6 +19,28 @@ static const struct inode_operations proc_sys_inode_operations; | |||
| 19 | static const struct file_operations proc_sys_dir_file_operations; | 19 | static const struct file_operations proc_sys_dir_file_operations; |
| 20 | static const struct inode_operations proc_sys_dir_operations; | 20 | static const struct inode_operations proc_sys_dir_operations; |
| 21 | 21 | ||
| 22 | /* Support for permanently empty directories */ | ||
| 23 | |||
| 24 | struct ctl_table sysctl_mount_point[] = { | ||
| 25 | { } | ||
| 26 | }; | ||
| 27 | |||
| 28 | static bool is_empty_dir(struct ctl_table_header *head) | ||
| 29 | { | ||
| 30 | return head->ctl_table[0].child == sysctl_mount_point; | ||
| 31 | } | ||
| 32 | |||
| 33 | static void set_empty_dir(struct ctl_dir *dir) | ||
| 34 | { | ||
| 35 | dir->header.ctl_table[0].child = sysctl_mount_point; | ||
| 36 | } | ||
| 37 | |||
| 38 | static void clear_empty_dir(struct ctl_dir *dir) | ||
| 39 | |||
| 40 | { | ||
| 41 | dir->header.ctl_table[0].child = NULL; | ||
| 42 | } | ||
| 43 | |||
| 22 | void proc_sys_poll_notify(struct ctl_table_poll *poll) | 44 | void proc_sys_poll_notify(struct ctl_table_poll *poll) |
| 23 | { | 45 | { |
| 24 | if (!poll) | 46 | if (!poll) |
| @@ -187,6 +209,17 @@ static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header) | |||
| 187 | struct ctl_table *entry; | 209 | struct ctl_table *entry; |
| 188 | int err; | 210 | int err; |
| 189 | 211 | ||
| 212 | /* Is this a permanently empty directory? */ | ||
| 213 | if (is_empty_dir(&dir->header)) | ||
| 214 | return -EROFS; | ||
| 215 | |||
| 216 | /* Am I creating a permanently empty directory? */ | ||
| 217 | if (header->ctl_table == sysctl_mount_point) { | ||
| 218 | if (!RB_EMPTY_ROOT(&dir->root)) | ||
| 219 | return -EINVAL; | ||
| 220 | set_empty_dir(dir); | ||
| 221 | } | ||
| 222 | |||
| 190 | dir->header.nreg++; | 223 | dir->header.nreg++; |
| 191 | header->parent = dir; | 224 | header->parent = dir; |
| 192 | err = insert_links(header); | 225 | err = insert_links(header); |
| @@ -202,6 +235,8 @@ fail: | |||
| 202 | erase_header(header); | 235 | erase_header(header); |
| 203 | put_links(header); | 236 | put_links(header); |
| 204 | fail_links: | 237 | fail_links: |
| 238 | if (header->ctl_table == sysctl_mount_point) | ||
| 239 | clear_empty_dir(dir); | ||
| 205 | header->parent = NULL; | 240 | header->parent = NULL; |
| 206 | drop_sysctl_table(&dir->header); | 241 | drop_sysctl_table(&dir->header); |
| 207 | return err; | 242 | return err; |
| @@ -419,6 +454,8 @@ static struct inode *proc_sys_make_inode(struct super_block *sb, | |||
| 419 | inode->i_mode |= S_IFDIR; | 454 | inode->i_mode |= S_IFDIR; |
| 420 | inode->i_op = &proc_sys_dir_operations; | 455 | inode->i_op = &proc_sys_dir_operations; |
| 421 | inode->i_fop = &proc_sys_dir_file_operations; | 456 | inode->i_fop = &proc_sys_dir_file_operations; |
| 457 | if (is_empty_dir(head)) | ||
| 458 | make_empty_dir_inode(inode); | ||
| 422 | } | 459 | } |
| 423 | out: | 460 | out: |
| 424 | return inode; | 461 | return inode; |
diff --git a/fs/proc/root.c b/fs/proc/root.c index b7fa4bfe896a..68feb0f70e63 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c | |||
| @@ -112,9 +112,6 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, | |||
| 112 | ns = task_active_pid_ns(current); | 112 | ns = task_active_pid_ns(current); |
| 113 | options = data; | 113 | options = data; |
| 114 | 114 | ||
| 115 | if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) | ||
| 116 | return ERR_PTR(-EPERM); | ||
| 117 | |||
| 118 | /* Does the mounter have privilege over the pid namespace? */ | 115 | /* Does the mounter have privilege over the pid namespace? */ |
| 119 | if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) | 116 | if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) |
| 120 | return ERR_PTR(-EPERM); | 117 | return ERR_PTR(-EPERM); |
| @@ -159,7 +156,7 @@ static struct file_system_type proc_fs_type = { | |||
| 159 | .name = "proc", | 156 | .name = "proc", |
| 160 | .mount = proc_mount, | 157 | .mount = proc_mount, |
| 161 | .kill_sb = proc_kill_sb, | 158 | .kill_sb = proc_kill_sb, |
| 162 | .fs_flags = FS_USERNS_MOUNT, | 159 | .fs_flags = FS_USERNS_VISIBLE | FS_USERNS_MOUNT, |
| 163 | }; | 160 | }; |
| 164 | 161 | ||
| 165 | void __init proc_root_init(void) | 162 | void __init proc_root_init(void) |
| @@ -182,10 +179,10 @@ void __init proc_root_init(void) | |||
| 182 | #endif | 179 | #endif |
| 183 | proc_mkdir("fs", NULL); | 180 | proc_mkdir("fs", NULL); |
| 184 | proc_mkdir("driver", NULL); | 181 | proc_mkdir("driver", NULL); |
| 185 | proc_mkdir("fs/nfsd", NULL); /* somewhere for the nfsd filesystem to be mounted */ | 182 | proc_create_mount_point("fs/nfsd"); /* somewhere for the nfsd filesystem to be mounted */ |
| 186 | #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) | 183 | #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) |
| 187 | /* just give it a mountpoint */ | 184 | /* just give it a mountpoint */ |
| 188 | proc_mkdir("openprom", NULL); | 185 | proc_create_mount_point("openprom"); |
| 189 | #endif | 186 | #endif |
| 190 | proc_tty_init(); | 187 | proc_tty_init(); |
| 191 | proc_mkdir("bus", NULL); | 188 | proc_mkdir("bus", NULL); |
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index dc43b5f29305..3adcc4669fac 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c | |||
| @@ -461,22 +461,18 @@ static struct file_system_type pstore_fs_type = { | |||
| 461 | .kill_sb = pstore_kill_sb, | 461 | .kill_sb = pstore_kill_sb, |
| 462 | }; | 462 | }; |
| 463 | 463 | ||
| 464 | static struct kobject *pstore_kobj; | ||
| 465 | |||
| 466 | static int __init init_pstore_fs(void) | 464 | static int __init init_pstore_fs(void) |
| 467 | { | 465 | { |
| 468 | int err = 0; | 466 | int err; |
| 469 | 467 | ||
| 470 | /* Create a convenient mount point for people to access pstore */ | 468 | /* Create a convenient mount point for people to access pstore */ |
| 471 | pstore_kobj = kobject_create_and_add("pstore", fs_kobj); | 469 | err = sysfs_create_mount_point(fs_kobj, "pstore"); |
| 472 | if (!pstore_kobj) { | 470 | if (err) |
| 473 | err = -ENOMEM; | ||
| 474 | goto out; | 471 | goto out; |
| 475 | } | ||
| 476 | 472 | ||
| 477 | err = register_filesystem(&pstore_fs_type); | 473 | err = register_filesystem(&pstore_fs_type); |
| 478 | if (err < 0) | 474 | if (err < 0) |
| 479 | kobject_put(pstore_kobj); | 475 | sysfs_remove_mount_point(fs_kobj, "pstore"); |
| 480 | 476 | ||
| 481 | out: | 477 | out: |
| 482 | return err; | 478 | return err; |
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 0b45ff42f374..94374e435025 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
| @@ -121,3 +121,37 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, | |||
| 121 | 121 | ||
| 122 | return kernfs_rename_ns(kn, new_parent, kn->name, new_ns); | 122 | return kernfs_rename_ns(kn, new_parent, kn->name, new_ns); |
| 123 | } | 123 | } |
| 124 | |||
| 125 | /** | ||
| 126 | * sysfs_create_mount_point - create an always empty directory | ||
| 127 | * @parent_kobj: kobject that will contain this always empty directory | ||
| 128 | * @name: The name of the always empty directory to add | ||
| 129 | */ | ||
| 130 | int sysfs_create_mount_point(struct kobject *parent_kobj, const char *name) | ||
| 131 | { | ||
| 132 | struct kernfs_node *kn, *parent = parent_kobj->sd; | ||
| 133 | |||
| 134 | kn = kernfs_create_empty_dir(parent, name); | ||
| 135 | if (IS_ERR(kn)) { | ||
| 136 | if (PTR_ERR(kn) == -EEXIST) | ||
| 137 | sysfs_warn_dup(parent, name); | ||
| 138 | return PTR_ERR(kn); | ||
| 139 | } | ||
| 140 | |||
| 141 | return 0; | ||
| 142 | } | ||
| 143 | EXPORT_SYMBOL_GPL(sysfs_create_mount_point); | ||
| 144 | |||
| 145 | /** | ||
| 146 | * sysfs_remove_mount_point - remove an always empty directory. | ||
| 147 | * @parent_kobj: kobject that will contain this always empty directory | ||
| 148 | * @name: The name of the always empty directory to remove | ||
| 149 | * | ||
| 150 | */ | ||
| 151 | void sysfs_remove_mount_point(struct kobject *parent_kobj, const char *name) | ||
| 152 | { | ||
| 153 | struct kernfs_node *parent = parent_kobj->sd; | ||
| 154 | |||
| 155 | kernfs_remove_by_name_ns(parent, name, NULL); | ||
| 156 | } | ||
| 157 | EXPORT_SYMBOL_GPL(sysfs_remove_mount_point); | ||
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 8a49486bf30c..1c6ac6fcee9f 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c | |||
| @@ -31,9 +31,6 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, | |||
| 31 | bool new_sb; | 31 | bool new_sb; |
| 32 | 32 | ||
| 33 | if (!(flags & MS_KERNMOUNT)) { | 33 | if (!(flags & MS_KERNMOUNT)) { |
| 34 | if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) | ||
| 35 | return ERR_PTR(-EPERM); | ||
| 36 | |||
| 37 | if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET)) | 34 | if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET)) |
| 38 | return ERR_PTR(-EPERM); | 35 | return ERR_PTR(-EPERM); |
| 39 | } | 36 | } |
| @@ -58,7 +55,7 @@ static struct file_system_type sysfs_fs_type = { | |||
| 58 | .name = "sysfs", | 55 | .name = "sysfs", |
| 59 | .mount = sysfs_mount, | 56 | .mount = sysfs_mount, |
| 60 | .kill_sb = sysfs_kill_sb, | 57 | .kill_sb = sysfs_kill_sb, |
| 61 | .fs_flags = FS_USERNS_MOUNT, | 58 | .fs_flags = FS_USERNS_VISIBLE | FS_USERNS_MOUNT, |
| 62 | }; | 59 | }; |
| 63 | 60 | ||
| 64 | int __init sysfs_init(void) | 61 | int __init sysfs_init(void) |
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index d92bdf3b079a..a43df11a163f 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c | |||
| @@ -631,14 +631,12 @@ bool tracefs_initialized(void) | |||
| 631 | return tracefs_registered; | 631 | return tracefs_registered; |
| 632 | } | 632 | } |
| 633 | 633 | ||
| 634 | static struct kobject *trace_kobj; | ||
| 635 | |||
| 636 | static int __init tracefs_init(void) | 634 | static int __init tracefs_init(void) |
| 637 | { | 635 | { |
| 638 | int retval; | 636 | int retval; |
| 639 | 637 | ||
| 640 | trace_kobj = kobject_create_and_add("tracing", kernel_kobj); | 638 | retval = sysfs_create_mount_point(kernel_kobj, "tracing"); |
| 641 | if (!trace_kobj) | 639 | if (retval) |
| 642 | return -EINVAL; | 640 | return -EINVAL; |
| 643 | 641 | ||
| 644 | retval = register_filesystem(&trace_fs_type); | 642 | retval = register_filesystem(&trace_fs_type); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 3f1a84635da8..8a81fcbb0074 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -1917,6 +1917,7 @@ struct file_system_type { | |||
| 1917 | #define FS_HAS_SUBTYPE 4 | 1917 | #define FS_HAS_SUBTYPE 4 |
| 1918 | #define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */ | 1918 | #define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */ |
| 1919 | #define FS_USERNS_DEV_MOUNT 16 /* A userns mount does not imply MNT_NODEV */ | 1919 | #define FS_USERNS_DEV_MOUNT 16 /* A userns mount does not imply MNT_NODEV */ |
| 1920 | #define FS_USERNS_VISIBLE 32 /* FS must already be visible */ | ||
| 1920 | #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */ | 1921 | #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */ |
| 1921 | struct dentry *(*mount) (struct file_system_type *, int, | 1922 | struct dentry *(*mount) (struct file_system_type *, int, |
| 1922 | const char *, void *); | 1923 | const char *, void *); |
| @@ -2004,7 +2005,6 @@ extern int vfs_ustat(dev_t, struct kstatfs *); | |||
| 2004 | extern int freeze_super(struct super_block *super); | 2005 | extern int freeze_super(struct super_block *super); |
| 2005 | extern int thaw_super(struct super_block *super); | 2006 | extern int thaw_super(struct super_block *super); |
| 2006 | extern bool our_mnt(struct vfsmount *mnt); | 2007 | extern bool our_mnt(struct vfsmount *mnt); |
| 2007 | extern bool fs_fully_visible(struct file_system_type *); | ||
| 2008 | 2008 | ||
| 2009 | extern int current_umask(void); | 2009 | extern int current_umask(void); |
| 2010 | 2010 | ||
| @@ -2816,6 +2816,8 @@ extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned in | |||
| 2816 | extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *); | 2816 | extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *); |
| 2817 | extern const struct file_operations simple_dir_operations; | 2817 | extern const struct file_operations simple_dir_operations; |
| 2818 | extern const struct inode_operations simple_dir_inode_operations; | 2818 | extern const struct inode_operations simple_dir_inode_operations; |
| 2819 | extern void make_empty_dir_inode(struct inode *inode); | ||
| 2820 | extern bool is_empty_dir_inode(struct inode *inode); | ||
| 2819 | struct tree_descr { char *name; const struct file_operations *ops; int mode; }; | 2821 | struct tree_descr { char *name; const struct file_operations *ops; int mode; }; |
| 2820 | struct dentry *d_alloc_name(struct dentry *, const char *); | 2822 | struct dentry *d_alloc_name(struct dentry *, const char *); |
| 2821 | extern int simple_fill_super(struct super_block *, unsigned long, struct tree_descr *); | 2823 | extern int simple_fill_super(struct super_block *, unsigned long, struct tree_descr *); |
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index e6b2f7db9c0c..123be25ea15a 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h | |||
| @@ -45,6 +45,7 @@ enum kernfs_node_flag { | |||
| 45 | KERNFS_LOCKDEP = 0x0100, | 45 | KERNFS_LOCKDEP = 0x0100, |
| 46 | KERNFS_SUICIDAL = 0x0400, | 46 | KERNFS_SUICIDAL = 0x0400, |
| 47 | KERNFS_SUICIDED = 0x0800, | 47 | KERNFS_SUICIDED = 0x0800, |
| 48 | KERNFS_EMPTY_DIR = 0x1000, | ||
| 48 | }; | 49 | }; |
| 49 | 50 | ||
| 50 | /* @flags for kernfs_create_root() */ | 51 | /* @flags for kernfs_create_root() */ |
| @@ -286,6 +287,8 @@ void kernfs_destroy_root(struct kernfs_root *root); | |||
| 286 | struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, | 287 | struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, |
| 287 | const char *name, umode_t mode, | 288 | const char *name, umode_t mode, |
| 288 | void *priv, const void *ns); | 289 | void *priv, const void *ns); |
| 290 | struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent, | ||
| 291 | const char *name); | ||
| 289 | struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, | 292 | struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, |
| 290 | const char *name, | 293 | const char *name, |
| 291 | umode_t mode, loff_t size, | 294 | umode_t mode, loff_t size, |
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 795d5fea5697..fa7bc29925c9 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h | |||
| @@ -188,6 +188,9 @@ struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path, | |||
| 188 | void unregister_sysctl_table(struct ctl_table_header * table); | 188 | void unregister_sysctl_table(struct ctl_table_header * table); |
| 189 | 189 | ||
| 190 | extern int sysctl_init(void); | 190 | extern int sysctl_init(void); |
| 191 | |||
| 192 | extern struct ctl_table sysctl_mount_point[]; | ||
| 193 | |||
| 191 | #else /* CONFIG_SYSCTL */ | 194 | #else /* CONFIG_SYSCTL */ |
| 192 | static inline struct ctl_table_header *register_sysctl_table(struct ctl_table * table) | 195 | static inline struct ctl_table_header *register_sysctl_table(struct ctl_table * table) |
| 193 | { | 196 | { |
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 99382c0df17e..9f65758311a4 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h | |||
| @@ -210,6 +210,10 @@ int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, | |||
| 210 | int __must_check sysfs_move_dir_ns(struct kobject *kobj, | 210 | int __must_check sysfs_move_dir_ns(struct kobject *kobj, |
| 211 | struct kobject *new_parent_kobj, | 211 | struct kobject *new_parent_kobj, |
| 212 | const void *new_ns); | 212 | const void *new_ns); |
| 213 | int __must_check sysfs_create_mount_point(struct kobject *parent_kobj, | ||
| 214 | const char *name); | ||
| 215 | void sysfs_remove_mount_point(struct kobject *parent_kobj, | ||
| 216 | const char *name); | ||
| 213 | 217 | ||
| 214 | int __must_check sysfs_create_file_ns(struct kobject *kobj, | 218 | int __must_check sysfs_create_file_ns(struct kobject *kobj, |
| 215 | const struct attribute *attr, | 219 | const struct attribute *attr, |
| @@ -298,6 +302,17 @@ static inline int sysfs_move_dir_ns(struct kobject *kobj, | |||
| 298 | return 0; | 302 | return 0; |
| 299 | } | 303 | } |
| 300 | 304 | ||
| 305 | static inline int sysfs_create_mount_point(struct kobject *parent_kobj, | ||
| 306 | const char *name) | ||
| 307 | { | ||
| 308 | return 0; | ||
| 309 | } | ||
| 310 | |||
| 311 | static inline void sysfs_remove_mount_point(struct kobject *parent_kobj, | ||
| 312 | const char *name) | ||
| 313 | { | ||
| 314 | } | ||
| 315 | |||
| 301 | static inline int sysfs_create_file_ns(struct kobject *kobj, | 316 | static inline int sysfs_create_file_ns(struct kobject *kobj, |
| 302 | const struct attribute *attr, | 317 | const struct attribute *attr, |
| 303 | const void *ns) | 318 | const void *ns) |
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 9ef9fc8a774b..f89d9292eee6 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
| @@ -1939,8 +1939,6 @@ static struct file_system_type cgroup_fs_type = { | |||
| 1939 | .kill_sb = cgroup_kill_sb, | 1939 | .kill_sb = cgroup_kill_sb, |
| 1940 | }; | 1940 | }; |
| 1941 | 1941 | ||
| 1942 | static struct kobject *cgroup_kobj; | ||
| 1943 | |||
| 1944 | /** | 1942 | /** |
| 1945 | * task_cgroup_path - cgroup path of a task in the first cgroup hierarchy | 1943 | * task_cgroup_path - cgroup path of a task in the first cgroup hierarchy |
| 1946 | * @task: target task | 1944 | * @task: target task |
| @@ -5070,13 +5068,13 @@ int __init cgroup_init(void) | |||
| 5070 | ss->bind(init_css_set.subsys[ssid]); | 5068 | ss->bind(init_css_set.subsys[ssid]); |
| 5071 | } | 5069 | } |
| 5072 | 5070 | ||
| 5073 | cgroup_kobj = kobject_create_and_add("cgroup", fs_kobj); | 5071 | err = sysfs_create_mount_point(fs_kobj, "cgroup"); |
| 5074 | if (!cgroup_kobj) | 5072 | if (err) |
| 5075 | return -ENOMEM; | 5073 | return err; |
| 5076 | 5074 | ||
| 5077 | err = register_filesystem(&cgroup_fs_type); | 5075 | err = register_filesystem(&cgroup_fs_type); |
| 5078 | if (err < 0) { | 5076 | if (err < 0) { |
| 5079 | kobject_put(cgroup_kobj); | 5077 | sysfs_remove_mount_point(fs_kobj, "cgroup"); |
| 5080 | return err; | 5078 | return err; |
| 5081 | } | 5079 | } |
| 5082 | 5080 | ||
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 812fcc3fd390..19b62b522158 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
| @@ -1538,12 +1538,6 @@ static struct ctl_table vm_table[] = { | |||
| 1538 | { } | 1538 | { } |
| 1539 | }; | 1539 | }; |
| 1540 | 1540 | ||
| 1541 | #if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE) | ||
| 1542 | static struct ctl_table binfmt_misc_table[] = { | ||
| 1543 | { } | ||
| 1544 | }; | ||
| 1545 | #endif | ||
| 1546 | |||
| 1547 | static struct ctl_table fs_table[] = { | 1541 | static struct ctl_table fs_table[] = { |
| 1548 | { | 1542 | { |
| 1549 | .procname = "inode-nr", | 1543 | .procname = "inode-nr", |
| @@ -1697,7 +1691,7 @@ static struct ctl_table fs_table[] = { | |||
| 1697 | { | 1691 | { |
| 1698 | .procname = "binfmt_misc", | 1692 | .procname = "binfmt_misc", |
| 1699 | .mode = 0555, | 1693 | .mode = 0555, |
| 1700 | .child = binfmt_misc_table, | 1694 | .child = sysctl_mount_point, |
| 1701 | }, | 1695 | }, |
| 1702 | #endif | 1696 | #endif |
| 1703 | { | 1697 | { |
diff --git a/security/inode.c b/security/inode.c index 91503b79c5f8..0e37e4fba8fa 100644 --- a/security/inode.c +++ b/security/inode.c | |||
| @@ -215,19 +215,17 @@ void securityfs_remove(struct dentry *dentry) | |||
| 215 | } | 215 | } |
| 216 | EXPORT_SYMBOL_GPL(securityfs_remove); | 216 | EXPORT_SYMBOL_GPL(securityfs_remove); |
| 217 | 217 | ||
| 218 | static struct kobject *security_kobj; | ||
| 219 | |||
| 220 | static int __init securityfs_init(void) | 218 | static int __init securityfs_init(void) |
| 221 | { | 219 | { |
| 222 | int retval; | 220 | int retval; |
| 223 | 221 | ||
| 224 | security_kobj = kobject_create_and_add("security", kernel_kobj); | 222 | retval = sysfs_create_mount_point(kernel_kobj, "security"); |
| 225 | if (!security_kobj) | 223 | if (retval) |
| 226 | return -EINVAL; | 224 | return retval; |
| 227 | 225 | ||
| 228 | retval = register_filesystem(&fs_type); | 226 | retval = register_filesystem(&fs_type); |
| 229 | if (retval) | 227 | if (retval) |
| 230 | kobject_put(security_kobj); | 228 | sysfs_remove_mount_point(kernel_kobj, "security"); |
| 231 | return retval; | 229 | return retval; |
| 232 | } | 230 | } |
| 233 | 231 | ||
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index d2787cca1fcb..3d2201413028 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
| @@ -1853,7 +1853,6 @@ static struct file_system_type sel_fs_type = { | |||
| 1853 | }; | 1853 | }; |
| 1854 | 1854 | ||
| 1855 | struct vfsmount *selinuxfs_mount; | 1855 | struct vfsmount *selinuxfs_mount; |
| 1856 | static struct kobject *selinuxfs_kobj; | ||
| 1857 | 1856 | ||
| 1858 | static int __init init_sel_fs(void) | 1857 | static int __init init_sel_fs(void) |
| 1859 | { | 1858 | { |
| @@ -1862,13 +1861,13 @@ static int __init init_sel_fs(void) | |||
| 1862 | if (!selinux_enabled) | 1861 | if (!selinux_enabled) |
| 1863 | return 0; | 1862 | return 0; |
| 1864 | 1863 | ||
| 1865 | selinuxfs_kobj = kobject_create_and_add("selinux", fs_kobj); | 1864 | err = sysfs_create_mount_point(fs_kobj, "selinux"); |
| 1866 | if (!selinuxfs_kobj) | 1865 | if (err) |
| 1867 | return -ENOMEM; | 1866 | return err; |
| 1868 | 1867 | ||
| 1869 | err = register_filesystem(&sel_fs_type); | 1868 | err = register_filesystem(&sel_fs_type); |
| 1870 | if (err) { | 1869 | if (err) { |
| 1871 | kobject_put(selinuxfs_kobj); | 1870 | sysfs_remove_mount_point(fs_kobj, "selinux"); |
| 1872 | return err; | 1871 | return err; |
| 1873 | } | 1872 | } |
| 1874 | 1873 | ||
| @@ -1887,7 +1886,7 @@ __initcall(init_sel_fs); | |||
| 1887 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE | 1886 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE |
| 1888 | void exit_sel_fs(void) | 1887 | void exit_sel_fs(void) |
| 1889 | { | 1888 | { |
| 1890 | kobject_put(selinuxfs_kobj); | 1889 | sysfs_remove_mount_point(fs_kobj, "selinux"); |
| 1891 | kern_unmount(selinuxfs_mount); | 1890 | kern_unmount(selinuxfs_mount); |
| 1892 | unregister_filesystem(&sel_fs_type); | 1891 | unregister_filesystem(&sel_fs_type); |
| 1893 | } | 1892 | } |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 5e0a64ebdf23..2716d02119f3 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
| @@ -2314,16 +2314,16 @@ static const struct file_operations smk_revoke_subj_ops = { | |||
| 2314 | .llseek = generic_file_llseek, | 2314 | .llseek = generic_file_llseek, |
| 2315 | }; | 2315 | }; |
| 2316 | 2316 | ||
| 2317 | static struct kset *smackfs_kset; | ||
| 2318 | /** | 2317 | /** |
| 2319 | * smk_init_sysfs - initialize /sys/fs/smackfs | 2318 | * smk_init_sysfs - initialize /sys/fs/smackfs |
| 2320 | * | 2319 | * |
| 2321 | */ | 2320 | */ |
| 2322 | static int smk_init_sysfs(void) | 2321 | static int smk_init_sysfs(void) |
| 2323 | { | 2322 | { |
| 2324 | smackfs_kset = kset_create_and_add("smackfs", NULL, fs_kobj); | 2323 | int err; |
| 2325 | if (!smackfs_kset) | 2324 | err = sysfs_create_mount_point(fs_kobj, "smackfs"); |
| 2326 | return -ENOMEM; | 2325 | if (err) |
| 2326 | return err; | ||
| 2327 | return 0; | 2327 | return 0; |
| 2328 | } | 2328 | } |
| 2329 | 2329 | ||
