diff options
Diffstat (limited to 'fs/proc/proc_net.c')
-rw-r--r-- | fs/proc/proc_net.c | 138 |
1 files changed, 51 insertions, 87 deletions
diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index 749def054a34..4823c9677fac 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c | |||
@@ -22,16 +22,47 @@ | |||
22 | #include <linux/mount.h> | 22 | #include <linux/mount.h> |
23 | #include <linux/nsproxy.h> | 23 | #include <linux/nsproxy.h> |
24 | #include <net/net_namespace.h> | 24 | #include <net/net_namespace.h> |
25 | #include <linux/seq_file.h> | ||
25 | 26 | ||
26 | #include "internal.h" | 27 | #include "internal.h" |
27 | 28 | ||
28 | 29 | ||
29 | struct proc_dir_entry *proc_net_create(struct net *net, | 30 | int seq_open_net(struct inode *ino, struct file *f, |
30 | const char *name, mode_t mode, get_info_t *get_info) | 31 | const struct seq_operations *ops, int size) |
31 | { | 32 | { |
32 | return create_proc_info_entry(name,mode, net->proc_net, get_info); | 33 | struct net *net; |
34 | struct seq_net_private *p; | ||
35 | |||
36 | BUG_ON(size < sizeof(*p)); | ||
37 | |||
38 | net = get_proc_net(ino); | ||
39 | if (net == NULL) | ||
40 | return -ENXIO; | ||
41 | |||
42 | p = __seq_open_private(f, ops, size); | ||
43 | if (p == NULL) { | ||
44 | put_net(net); | ||
45 | return -ENOMEM; | ||
46 | } | ||
47 | p->net = net; | ||
48 | return 0; | ||
33 | } | 49 | } |
34 | EXPORT_SYMBOL_GPL(proc_net_create); | 50 | EXPORT_SYMBOL_GPL(seq_open_net); |
51 | |||
52 | int seq_release_net(struct inode *ino, struct file *f) | ||
53 | { | ||
54 | struct seq_file *seq; | ||
55 | struct seq_net_private *p; | ||
56 | |||
57 | seq = f->private_data; | ||
58 | p = seq->private; | ||
59 | |||
60 | put_net(p->net); | ||
61 | seq_release_private(ino, f); | ||
62 | return 0; | ||
63 | } | ||
64 | EXPORT_SYMBOL_GPL(seq_release_net); | ||
65 | |||
35 | 66 | ||
36 | struct proc_dir_entry *proc_net_fops_create(struct net *net, | 67 | struct proc_dir_entry *proc_net_fops_create(struct net *net, |
37 | const char *name, mode_t mode, const struct file_operations *fops) | 68 | const char *name, mode_t mode, const struct file_operations *fops) |
@@ -57,88 +88,24 @@ struct net *get_proc_net(const struct inode *inode) | |||
57 | } | 88 | } |
58 | EXPORT_SYMBOL_GPL(get_proc_net); | 89 | EXPORT_SYMBOL_GPL(get_proc_net); |
59 | 90 | ||
60 | static struct proc_dir_entry *proc_net_shadow; | 91 | static struct proc_dir_entry *shadow_pde; |
61 | 92 | ||
62 | static struct dentry *proc_net_shadow_dentry(struct dentry *parent, | 93 | static struct proc_dir_entry *proc_net_shadow(struct task_struct *task, |
63 | struct proc_dir_entry *de) | 94 | struct proc_dir_entry *de) |
64 | { | 95 | { |
65 | struct dentry *shadow = NULL; | 96 | return task->nsproxy->net_ns->proc_net; |
66 | struct inode *inode; | ||
67 | if (!de) | ||
68 | goto out; | ||
69 | de_get(de); | ||
70 | inode = proc_get_inode(parent->d_inode->i_sb, de->low_ino, de); | ||
71 | if (!inode) | ||
72 | goto out_de_put; | ||
73 | shadow = d_alloc_name(parent, de->name); | ||
74 | if (!shadow) | ||
75 | goto out_iput; | ||
76 | shadow->d_op = parent->d_op; /* proc_dentry_operations */ | ||
77 | d_instantiate(shadow, inode); | ||
78 | out: | ||
79 | return shadow; | ||
80 | out_iput: | ||
81 | iput(inode); | ||
82 | out_de_put: | ||
83 | de_put(de); | ||
84 | goto out; | ||
85 | } | ||
86 | |||
87 | static void *proc_net_follow_link(struct dentry *parent, struct nameidata *nd) | ||
88 | { | ||
89 | struct net *net = current->nsproxy->net_ns; | ||
90 | struct dentry *shadow; | ||
91 | shadow = proc_net_shadow_dentry(parent, net->proc_net); | ||
92 | if (!shadow) | ||
93 | return ERR_PTR(-ENOENT); | ||
94 | |||
95 | dput(nd->dentry); | ||
96 | /* My dentry count is 1 and that should be enough as the | ||
97 | * shadow dentry is thrown away immediately. | ||
98 | */ | ||
99 | nd->dentry = shadow; | ||
100 | return NULL; | ||
101 | } | 97 | } |
102 | 98 | ||
103 | static struct dentry *proc_net_lookup(struct inode *dir, struct dentry *dentry, | 99 | struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name, |
104 | struct nameidata *nd) | 100 | struct proc_dir_entry *parent) |
105 | { | 101 | { |
106 | struct net *net = current->nsproxy->net_ns; | 102 | struct proc_dir_entry *pde; |
107 | struct dentry *shadow; | 103 | pde = proc_mkdir_mode(name, S_IRUGO | S_IXUGO, parent); |
108 | 104 | if (pde != NULL) | |
109 | shadow = proc_net_shadow_dentry(nd->dentry, net->proc_net); | 105 | pde->data = net; |
110 | if (!shadow) | 106 | return pde; |
111 | return ERR_PTR(-ENOENT); | ||
112 | |||
113 | dput(nd->dentry); | ||
114 | nd->dentry = shadow; | ||
115 | |||
116 | return shadow->d_inode->i_op->lookup(shadow->d_inode, dentry, nd); | ||
117 | } | 107 | } |
118 | 108 | EXPORT_SYMBOL_GPL(proc_net_mkdir); | |
119 | static int proc_net_setattr(struct dentry *dentry, struct iattr *iattr) | ||
120 | { | ||
121 | struct net *net = current->nsproxy->net_ns; | ||
122 | struct dentry *shadow; | ||
123 | int ret; | ||
124 | |||
125 | shadow = proc_net_shadow_dentry(dentry->d_parent, net->proc_net); | ||
126 | if (!shadow) | ||
127 | return -ENOENT; | ||
128 | ret = shadow->d_inode->i_op->setattr(shadow, iattr); | ||
129 | dput(shadow); | ||
130 | return ret; | ||
131 | } | ||
132 | |||
133 | static const struct file_operations proc_net_dir_operations = { | ||
134 | .read = generic_read_dir, | ||
135 | }; | ||
136 | |||
137 | static struct inode_operations proc_net_dir_inode_operations = { | ||
138 | .follow_link = proc_net_follow_link, | ||
139 | .lookup = proc_net_lookup, | ||
140 | .setattr = proc_net_setattr, | ||
141 | }; | ||
142 | 109 | ||
143 | static __net_init int proc_net_ns_init(struct net *net) | 110 | static __net_init int proc_net_ns_init(struct net *net) |
144 | { | 111 | { |
@@ -151,18 +118,16 @@ static __net_init int proc_net_ns_init(struct net *net) | |||
151 | goto out; | 118 | goto out; |
152 | 119 | ||
153 | err = -EEXIST; | 120 | err = -EEXIST; |
154 | netd = proc_mkdir("net", root); | 121 | netd = proc_net_mkdir(net, "net", root); |
155 | if (!netd) | 122 | if (!netd) |
156 | goto free_root; | 123 | goto free_root; |
157 | 124 | ||
158 | err = -EEXIST; | 125 | err = -EEXIST; |
159 | net_statd = proc_mkdir("stat", netd); | 126 | net_statd = proc_net_mkdir(net, "stat", netd); |
160 | if (!net_statd) | 127 | if (!net_statd) |
161 | goto free_net; | 128 | goto free_net; |
162 | 129 | ||
163 | root->data = net; | 130 | root->data = net; |
164 | netd->data = net; | ||
165 | net_statd->data = net; | ||
166 | 131 | ||
167 | net->proc_net_root = root; | 132 | net->proc_net_root = root; |
168 | net->proc_net = netd; | 133 | net->proc_net = netd; |
@@ -185,16 +150,15 @@ static __net_exit void proc_net_ns_exit(struct net *net) | |||
185 | kfree(net->proc_net_root); | 150 | kfree(net->proc_net_root); |
186 | } | 151 | } |
187 | 152 | ||
188 | static struct pernet_operations proc_net_ns_ops = { | 153 | static struct pernet_operations __net_initdata proc_net_ns_ops = { |
189 | .init = proc_net_ns_init, | 154 | .init = proc_net_ns_init, |
190 | .exit = proc_net_ns_exit, | 155 | .exit = proc_net_ns_exit, |
191 | }; | 156 | }; |
192 | 157 | ||
193 | int __init proc_net_init(void) | 158 | int __init proc_net_init(void) |
194 | { | 159 | { |
195 | proc_net_shadow = proc_mkdir("net", NULL); | 160 | shadow_pde = proc_mkdir("net", NULL); |
196 | proc_net_shadow->proc_iops = &proc_net_dir_inode_operations; | 161 | shadow_pde->shadow_proc = proc_net_shadow; |
197 | proc_net_shadow->proc_fops = &proc_net_dir_operations; | ||
198 | 162 | ||
199 | return register_pernet_subsys(&proc_net_ns_ops); | 163 | return register_pernet_subsys(&proc_net_ns_ops); |
200 | } | 164 | } |