at v3.10-rc6 231 lines 4.4 kB view raw
1/* 2 * linux/fs/proc/net.c 3 * 4 * Copyright (C) 2007 5 * 6 * Author: Eric Biederman <ebiederm@xmission.com> 7 * 8 * proc net directory handling functions 9 */ 10 11#include <asm/uaccess.h> 12 13#include <linux/errno.h> 14#include <linux/time.h> 15#include <linux/proc_fs.h> 16#include <linux/stat.h> 17#include <linux/slab.h> 18#include <linux/init.h> 19#include <linux/sched.h> 20#include <linux/module.h> 21#include <linux/bitops.h> 22#include <linux/mount.h> 23#include <linux/nsproxy.h> 24#include <net/net_namespace.h> 25#include <linux/seq_file.h> 26 27#include "internal.h" 28 29static inline struct net *PDE_NET(struct proc_dir_entry *pde) 30{ 31 return pde->parent->data; 32} 33 34static struct net *get_proc_net(const struct inode *inode) 35{ 36 return maybe_get_net(PDE_NET(PDE(inode))); 37} 38 39int seq_open_net(struct inode *ino, struct file *f, 40 const struct seq_operations *ops, int size) 41{ 42 struct net *net; 43 struct seq_net_private *p; 44 45 BUG_ON(size < sizeof(*p)); 46 47 net = get_proc_net(ino); 48 if (net == NULL) 49 return -ENXIO; 50 51 p = __seq_open_private(f, ops, size); 52 if (p == NULL) { 53 put_net(net); 54 return -ENOMEM; 55 } 56#ifdef CONFIG_NET_NS 57 p->net = net; 58#endif 59 return 0; 60} 61EXPORT_SYMBOL_GPL(seq_open_net); 62 63int single_open_net(struct inode *inode, struct file *file, 64 int (*show)(struct seq_file *, void *)) 65{ 66 int err; 67 struct net *net; 68 69 err = -ENXIO; 70 net = get_proc_net(inode); 71 if (net == NULL) 72 goto err_net; 73 74 err = single_open(file, show, net); 75 if (err < 0) 76 goto err_open; 77 78 return 0; 79 80err_open: 81 put_net(net); 82err_net: 83 return err; 84} 85EXPORT_SYMBOL_GPL(single_open_net); 86 87int seq_release_net(struct inode *ino, struct file *f) 88{ 89 struct seq_file *seq; 90 91 seq = f->private_data; 92 93 put_net(seq_file_net(seq)); 94 seq_release_private(ino, f); 95 return 0; 96} 97EXPORT_SYMBOL_GPL(seq_release_net); 98 99int single_release_net(struct inode *ino, struct file *f) 100{ 101 struct seq_file *seq = f->private_data; 102 put_net(seq->private); 103 return single_release(ino, f); 104} 105EXPORT_SYMBOL_GPL(single_release_net); 106 107static struct net *get_proc_task_net(struct inode *dir) 108{ 109 struct task_struct *task; 110 struct nsproxy *ns; 111 struct net *net = NULL; 112 113 rcu_read_lock(); 114 task = pid_task(proc_pid(dir), PIDTYPE_PID); 115 if (task != NULL) { 116 ns = task_nsproxy(task); 117 if (ns != NULL) 118 net = get_net(ns->net_ns); 119 } 120 rcu_read_unlock(); 121 122 return net; 123} 124 125static struct dentry *proc_tgid_net_lookup(struct inode *dir, 126 struct dentry *dentry, unsigned int flags) 127{ 128 struct dentry *de; 129 struct net *net; 130 131 de = ERR_PTR(-ENOENT); 132 net = get_proc_task_net(dir); 133 if (net != NULL) { 134 de = proc_lookup_de(net->proc_net, dir, dentry); 135 put_net(net); 136 } 137 return de; 138} 139 140static int proc_tgid_net_getattr(struct vfsmount *mnt, struct dentry *dentry, 141 struct kstat *stat) 142{ 143 struct inode *inode = dentry->d_inode; 144 struct net *net; 145 146 net = get_proc_task_net(inode); 147 148 generic_fillattr(inode, stat); 149 150 if (net != NULL) { 151 stat->nlink = net->proc_net->nlink; 152 put_net(net); 153 } 154 155 return 0; 156} 157 158const struct inode_operations proc_net_inode_operations = { 159 .lookup = proc_tgid_net_lookup, 160 .getattr = proc_tgid_net_getattr, 161}; 162 163static int proc_tgid_net_readdir(struct file *filp, void *dirent, 164 filldir_t filldir) 165{ 166 int ret; 167 struct net *net; 168 169 ret = -EINVAL; 170 net = get_proc_task_net(file_inode(filp)); 171 if (net != NULL) { 172 ret = proc_readdir_de(net->proc_net, filp, dirent, filldir); 173 put_net(net); 174 } 175 return ret; 176} 177 178const struct file_operations proc_net_operations = { 179 .llseek = generic_file_llseek, 180 .read = generic_read_dir, 181 .readdir = proc_tgid_net_readdir, 182}; 183 184static __net_init int proc_net_ns_init(struct net *net) 185{ 186 struct proc_dir_entry *netd, *net_statd; 187 int err; 188 189 err = -ENOMEM; 190 netd = kzalloc(sizeof(*netd) + 4, GFP_KERNEL); 191 if (!netd) 192 goto out; 193 194 netd->data = net; 195 netd->nlink = 2; 196 netd->namelen = 3; 197 netd->parent = &proc_root; 198 memcpy(netd->name, "net", 4); 199 200 err = -EEXIST; 201 net_statd = proc_net_mkdir(net, "stat", netd); 202 if (!net_statd) 203 goto free_net; 204 205 net->proc_net = netd; 206 net->proc_net_stat = net_statd; 207 return 0; 208 209free_net: 210 kfree(netd); 211out: 212 return err; 213} 214 215static __net_exit void proc_net_ns_exit(struct net *net) 216{ 217 remove_proc_entry("stat", net->proc_net); 218 kfree(net->proc_net); 219} 220 221static struct pernet_operations __net_initdata proc_net_ns_ops = { 222 .init = proc_net_ns_init, 223 .exit = proc_net_ns_exit, 224}; 225 226int __init proc_net_init(void) 227{ 228 proc_symlink("net", NULL, "self/net"); 229 230 return register_pernet_subsys(&proc_net_ns_ops); 231}