diff options
| -rw-r--r-- | fs/kernfs/dir.c | 6 | ||||
| -rw-r--r-- | fs/kernfs/mount.c | 15 | ||||
| -rw-r--r-- | include/linux/kernfs.h | 2 | ||||
| -rw-r--r-- | kernel/cgroup.c | 63 |
4 files changed, 83 insertions, 3 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 03b688d19f69..37f9678ae4df 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c | |||
| @@ -153,9 +153,9 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, | |||
| 153 | p = buf + len + nlen; | 153 | p = buf + len + nlen; |
| 154 | *p = '\0'; | 154 | *p = '\0'; |
| 155 | for (kn = kn_to; kn != common; kn = kn->parent) { | 155 | for (kn = kn_to; kn != common; kn = kn->parent) { |
| 156 | nlen = strlen(kn->name); | 156 | size_t tmp = strlen(kn->name); |
| 157 | p -= nlen; | 157 | p -= tmp; |
| 158 | memcpy(p, kn->name, nlen); | 158 | memcpy(p, kn->name, tmp); |
| 159 | *(--p) = '/'; | 159 | *(--p) = '/'; |
| 160 | } | 160 | } |
| 161 | 161 | ||
diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c index f73541fbe7af..3d670a3678f2 100644 --- a/fs/kernfs/mount.c +++ b/fs/kernfs/mount.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
| 16 | #include <linux/pagemap.h> | 16 | #include <linux/pagemap.h> |
| 17 | #include <linux/namei.h> | 17 | #include <linux/namei.h> |
| 18 | #include <linux/seq_file.h> | ||
| 18 | 19 | ||
| 19 | #include "kernfs-internal.h" | 20 | #include "kernfs-internal.h" |
| 20 | 21 | ||
| @@ -40,6 +41,19 @@ static int kernfs_sop_show_options(struct seq_file *sf, struct dentry *dentry) | |||
| 40 | return 0; | 41 | return 0; |
| 41 | } | 42 | } |
| 42 | 43 | ||
| 44 | static int kernfs_sop_show_path(struct seq_file *sf, struct dentry *dentry) | ||
| 45 | { | ||
| 46 | struct kernfs_node *node = dentry->d_fsdata; | ||
| 47 | struct kernfs_root *root = kernfs_root(node); | ||
| 48 | struct kernfs_syscall_ops *scops = root->syscall_ops; | ||
| 49 | |||
| 50 | if (scops && scops->show_path) | ||
| 51 | return scops->show_path(sf, node, root); | ||
| 52 | |||
| 53 | seq_dentry(sf, dentry, " \t\n\\"); | ||
| 54 | return 0; | ||
| 55 | } | ||
| 56 | |||
| 43 | const struct super_operations kernfs_sops = { | 57 | const struct super_operations kernfs_sops = { |
| 44 | .statfs = simple_statfs, | 58 | .statfs = simple_statfs, |
| 45 | .drop_inode = generic_delete_inode, | 59 | .drop_inode = generic_delete_inode, |
| @@ -47,6 +61,7 @@ const struct super_operations kernfs_sops = { | |||
| 47 | 61 | ||
| 48 | .remount_fs = kernfs_sop_remount_fs, | 62 | .remount_fs = kernfs_sop_remount_fs, |
| 49 | .show_options = kernfs_sop_show_options, | 63 | .show_options = kernfs_sop_show_options, |
| 64 | .show_path = kernfs_sop_show_path, | ||
| 50 | }; | 65 | }; |
| 51 | 66 | ||
| 52 | /** | 67 | /** |
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index c06c44242f39..30f089ebe0a4 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h | |||
| @@ -152,6 +152,8 @@ struct kernfs_syscall_ops { | |||
| 152 | int (*rmdir)(struct kernfs_node *kn); | 152 | int (*rmdir)(struct kernfs_node *kn); |
| 153 | int (*rename)(struct kernfs_node *kn, struct kernfs_node *new_parent, | 153 | int (*rename)(struct kernfs_node *kn, struct kernfs_node *new_parent, |
| 154 | const char *new_name); | 154 | const char *new_name); |
| 155 | int (*show_path)(struct seq_file *sf, struct kernfs_node *kn, | ||
| 156 | struct kernfs_root *root); | ||
| 155 | }; | 157 | }; |
| 156 | 158 | ||
| 157 | struct kernfs_root { | 159 | struct kernfs_root { |
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 909a7d31ffd3..86cb5c6e8932 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
| @@ -1215,6 +1215,41 @@ static void cgroup_destroy_root(struct cgroup_root *root) | |||
| 1215 | cgroup_free_root(root); | 1215 | cgroup_free_root(root); |
| 1216 | } | 1216 | } |
| 1217 | 1217 | ||
| 1218 | /* | ||
| 1219 | * look up cgroup associated with current task's cgroup namespace on the | ||
| 1220 | * specified hierarchy | ||
| 1221 | */ | ||
| 1222 | static struct cgroup * | ||
| 1223 | current_cgns_cgroup_from_root(struct cgroup_root *root) | ||
| 1224 | { | ||
| 1225 | struct cgroup *res = NULL; | ||
| 1226 | struct css_set *cset; | ||
| 1227 | |||
| 1228 | lockdep_assert_held(&css_set_lock); | ||
| 1229 | |||
| 1230 | rcu_read_lock(); | ||
| 1231 | |||
| 1232 | cset = current->nsproxy->cgroup_ns->root_cset; | ||
| 1233 | if (cset == &init_css_set) { | ||
| 1234 | res = &root->cgrp; | ||
| 1235 | } else { | ||
| 1236 | struct cgrp_cset_link *link; | ||
| 1237 | |||
| 1238 | list_for_each_entry(link, &cset->cgrp_links, cgrp_link) { | ||
| 1239 | struct cgroup *c = link->cgrp; | ||
| 1240 | |||
| 1241 | if (c->root == root) { | ||
| 1242 | res = c; | ||
| 1243 | break; | ||
| 1244 | } | ||
| 1245 | } | ||
| 1246 | } | ||
| 1247 | rcu_read_unlock(); | ||
| 1248 | |||
| 1249 | BUG_ON(!res); | ||
| 1250 | return res; | ||
| 1251 | } | ||
| 1252 | |||
| 1218 | /* look up cgroup associated with given css_set on the specified hierarchy */ | 1253 | /* look up cgroup associated with given css_set on the specified hierarchy */ |
| 1219 | static struct cgroup *cset_cgroup_from_root(struct css_set *cset, | 1254 | static struct cgroup *cset_cgroup_from_root(struct css_set *cset, |
| 1220 | struct cgroup_root *root) | 1255 | struct cgroup_root *root) |
| @@ -1593,6 +1628,33 @@ static int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask) | |||
| 1593 | return 0; | 1628 | return 0; |
| 1594 | } | 1629 | } |
| 1595 | 1630 | ||
| 1631 | static int cgroup_show_path(struct seq_file *sf, struct kernfs_node *kf_node, | ||
| 1632 | struct kernfs_root *kf_root) | ||
| 1633 | { | ||
| 1634 | int len = 0; | ||
| 1635 | char *buf = NULL; | ||
| 1636 | struct cgroup_root *kf_cgroot = cgroup_root_from_kf(kf_root); | ||
| 1637 | struct cgroup *ns_cgroup; | ||
| 1638 | |||
| 1639 | buf = kmalloc(PATH_MAX, GFP_KERNEL); | ||
| 1640 | if (!buf) | ||
| 1641 | return -ENOMEM; | ||
| 1642 | |||
| 1643 | spin_lock_bh(&css_set_lock); | ||
| 1644 | ns_cgroup = current_cgns_cgroup_from_root(kf_cgroot); | ||
| 1645 | len = kernfs_path_from_node(kf_node, ns_cgroup->kn, buf, PATH_MAX); | ||
| 1646 | spin_unlock_bh(&css_set_lock); | ||
| 1647 | |||
| 1648 | if (len >= PATH_MAX) | ||
| 1649 | len = -ERANGE; | ||
| 1650 | else if (len > 0) { | ||
| 1651 | seq_escape(sf, buf, " \t\n\\"); | ||
| 1652 | len = 0; | ||
| 1653 | } | ||
| 1654 | kfree(buf); | ||
| 1655 | return len; | ||
| 1656 | } | ||
| 1657 | |||
| 1596 | static int cgroup_show_options(struct seq_file *seq, | 1658 | static int cgroup_show_options(struct seq_file *seq, |
| 1597 | struct kernfs_root *kf_root) | 1659 | struct kernfs_root *kf_root) |
| 1598 | { | 1660 | { |
| @@ -5433,6 +5495,7 @@ static struct kernfs_syscall_ops cgroup_kf_syscall_ops = { | |||
| 5433 | .mkdir = cgroup_mkdir, | 5495 | .mkdir = cgroup_mkdir, |
| 5434 | .rmdir = cgroup_rmdir, | 5496 | .rmdir = cgroup_rmdir, |
| 5435 | .rename = cgroup_rename, | 5497 | .rename = cgroup_rename, |
| 5498 | .show_path = cgroup_show_path, | ||
| 5436 | }; | 5499 | }; |
| 5437 | 5500 | ||
| 5438 | static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early) | 5501 | static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early) |
