diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/afs/netdevices.c | 5 | ||||
-rw-r--r-- | fs/compat_ioctl.c | 21 | ||||
-rw-r--r-- | fs/ecryptfs/netlink.c | 16 | ||||
-rw-r--r-- | fs/proc/Makefile | 1 | ||||
-rw-r--r-- | fs/proc/internal.h | 5 | ||||
-rw-r--r-- | fs/proc/proc_net.c | 200 | ||||
-rw-r--r-- | fs/proc/root.c | 8 | ||||
-rw-r--r-- | fs/seq_file.c | 33 |
8 files changed, 257 insertions, 32 deletions
diff --git a/fs/afs/netdevices.c b/fs/afs/netdevices.c index fc27d4b52e5f..49f189423063 100644 --- a/fs/afs/netdevices.c +++ b/fs/afs/netdevices.c @@ -8,6 +8,7 @@ #include <linux/inetdevice.h> #include <linux/netdevice.h> #include <linux/if_arp.h> +#include <net/net_namespace.h> #include "internal.h" /* @@ -23,7 +24,7 @@ int afs_get_MAC_address(u8 *mac, size_t maclen) BUG(); rtnl_lock(); - dev = __dev_getfirstbyhwtype(ARPHRD_ETHER); + dev = __dev_getfirstbyhwtype(&init_net, ARPHRD_ETHER); if (dev) { memcpy(mac, dev->dev_addr, maclen); ret = 0; @@ -47,7 +48,7 @@ int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs, ASSERT(maxbufs > 0); rtnl_lock(); - for_each_netdev(dev) { + for_each_netdev(&init_net, dev) { if (dev->type == ARPHRD_LOOPBACK && !wantloopback) continue; idev = __in_dev_get_rtnl(dev); diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index b9e3357bcc2e..9c3fd07f35e0 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -319,22 +319,21 @@ struct ifconf32 { static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg) { - struct net_device *dev; - struct ifreq32 ifr32; + struct ifreq __user *uifr; int err; - if (copy_from_user(&ifr32, compat_ptr(arg), sizeof(ifr32))) + uifr = compat_alloc_user_space(sizeof(struct ifreq)); + if (copy_in_user(uifr, compat_ptr(arg), sizeof(struct ifreq32))); return -EFAULT; - dev = dev_get_by_index(ifr32.ifr_ifindex); - if (!dev) - return -ENODEV; + err = sys_ioctl(fd, SIOCGIFNAME, (unsigned long)uifr); + if (err) + return err; - strlcpy(ifr32.ifr_name, dev->name, sizeof(ifr32.ifr_name)); - dev_put(dev); - - err = copy_to_user(compat_ptr(arg), &ifr32, sizeof(ifr32)); - return (err ? -EFAULT : 0); + if (copy_in_user(compat_ptr(arg), uifr, sizeof(struct ifreq32))) + return -EFAULT; + + return 0; } static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) diff --git a/fs/ecryptfs/netlink.c b/fs/ecryptfs/netlink.c index fe9186312d7c..9aa345121e09 100644 --- a/fs/ecryptfs/netlink.c +++ b/fs/ecryptfs/netlink.c @@ -165,22 +165,10 @@ static int ecryptfs_process_nl_quit(struct sk_buff *skb) * it to its desired netlink context element and wake up the process * that is waiting for a response. */ -static void ecryptfs_receive_nl_message(struct sock *sk, int len) +static void ecryptfs_receive_nl_message(struct sk_buff *skb) { - struct sk_buff *skb; struct nlmsghdr *nlh; - int rc = 0; /* skb_recv_datagram requires this */ -receive: - skb = skb_recv_datagram(sk, 0, 0, &rc); - if (rc == -EINTR) - goto receive; - else if (rc < 0) { - ecryptfs_printk(KERN_ERR, "Error occurred while " - "receiving eCryptfs netlink message; " - "rc = [%d]\n", rc); - return; - } nlh = nlmsg_hdr(skb); if (!NLMSG_OK(nlh, skb->len)) { ecryptfs_printk(KERN_ERR, "Received corrupt netlink " @@ -227,7 +215,7 @@ int ecryptfs_init_netlink(void) { int rc; - ecryptfs_nl_sock = netlink_kernel_create(NETLINK_ECRYPTFS, 0, + ecryptfs_nl_sock = netlink_kernel_create(&init_net, NETLINK_ECRYPTFS, 0, ecryptfs_receive_nl_message, NULL, THIS_MODULE); if (!ecryptfs_nl_sock) { diff --git a/fs/proc/Makefile b/fs/proc/Makefile index bce38e3f06cb..ebaba0213546 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -11,6 +11,7 @@ proc-y += inode.o root.o base.o generic.o array.o \ proc_tty.o proc_misc.o proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o +proc-$(CONFIG_NET) += proc_net.o proc-$(CONFIG_PROC_KCORE) += kcore.o proc-$(CONFIG_PROC_VMCORE) += vmcore.o proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o diff --git a/fs/proc/internal.h b/fs/proc/internal.h index b215c3524fa6..1820eb2ef762 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -16,6 +16,11 @@ extern int proc_sys_init(void); #else static inline void proc_sys_init(void) { } #endif +#ifdef CONFIG_NET +extern int proc_net_init(void); +#else +static inline int proc_net_init(void) { return 0; } +#endif struct vmalloc_info { unsigned long used; diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c new file mode 100644 index 000000000000..2e91fb756e9a --- /dev/null +++ b/fs/proc/proc_net.c @@ -0,0 +1,200 @@ +/* + * linux/fs/proc/net.c + * + * Copyright (C) 2007 + * + * Author: Eric Biederman <ebiederm@xmission.com> + * + * proc net directory handling functions + */ + +#include <asm/uaccess.h> + +#include <linux/errno.h> +#include <linux/time.h> +#include <linux/proc_fs.h> +#include <linux/stat.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/module.h> +#include <linux/bitops.h> +#include <linux/smp_lock.h> +#include <linux/mount.h> +#include <linux/nsproxy.h> +#include <net/net_namespace.h> + +#include "internal.h" + + +struct proc_dir_entry *proc_net_create(struct net *net, + const char *name, mode_t mode, get_info_t *get_info) +{ + return create_proc_info_entry(name,mode, net->proc_net, get_info); +} +EXPORT_SYMBOL_GPL(proc_net_create); + +struct proc_dir_entry *proc_net_fops_create(struct net *net, + const char *name, mode_t mode, const struct file_operations *fops) +{ + struct proc_dir_entry *res; + + res = create_proc_entry(name, mode, net->proc_net); + if (res) + res->proc_fops = fops; + return res; +} +EXPORT_SYMBOL_GPL(proc_net_fops_create); + +void proc_net_remove(struct net *net, const char *name) +{ + remove_proc_entry(name, net->proc_net); +} +EXPORT_SYMBOL_GPL(proc_net_remove); + +struct net *get_proc_net(const struct inode *inode) +{ + return maybe_get_net(PDE_NET(PDE(inode))); +} +EXPORT_SYMBOL_GPL(get_proc_net); + +static struct proc_dir_entry *proc_net_shadow; + +static struct dentry *proc_net_shadow_dentry(struct dentry *parent, + struct proc_dir_entry *de) +{ + struct dentry *shadow = NULL; + struct inode *inode; + if (!de) + goto out; + de_get(de); + inode = proc_get_inode(parent->d_inode->i_sb, de->low_ino, de); + if (!inode) + goto out_de_put; + shadow = d_alloc_name(parent, de->name); + if (!shadow) + goto out_iput; + shadow->d_op = parent->d_op; /* proc_dentry_operations */ + d_instantiate(shadow, inode); +out: + return shadow; +out_iput: + iput(inode); +out_de_put: + de_put(de); + goto out; +} + +static void *proc_net_follow_link(struct dentry *parent, struct nameidata *nd) +{ + struct net *net = current->nsproxy->net_ns; + struct dentry *shadow; + shadow = proc_net_shadow_dentry(parent, net->proc_net); + if (!shadow) + return ERR_PTR(-ENOENT); + + dput(nd->dentry); + /* My dentry count is 1 and that should be enough as the + * shadow dentry is thrown away immediately. + */ + nd->dentry = shadow; + return NULL; +} + +static struct dentry *proc_net_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +{ + struct net *net = current->nsproxy->net_ns; + struct dentry *shadow; + + shadow = proc_net_shadow_dentry(nd->dentry, net->proc_net); + if (!shadow) + return ERR_PTR(-ENOENT); + + dput(nd->dentry); + nd->dentry = shadow; + + return shadow->d_inode->i_op->lookup(shadow->d_inode, dentry, nd); +} + +static int proc_net_setattr(struct dentry *dentry, struct iattr *iattr) +{ + struct net *net = current->nsproxy->net_ns; + struct dentry *shadow; + int ret; + + shadow = proc_net_shadow_dentry(dentry->d_parent, net->proc_net); + if (!shadow) + return -ENOENT; + ret = shadow->d_inode->i_op->setattr(shadow, iattr); + dput(shadow); + return ret; +} + +static const struct file_operations proc_net_dir_operations = { + .read = generic_read_dir, +}; + +static struct inode_operations proc_net_dir_inode_operations = { + .follow_link = proc_net_follow_link, + .lookup = proc_net_lookup, + .setattr = proc_net_setattr, +}; + +static __net_init int proc_net_ns_init(struct net *net) +{ + struct proc_dir_entry *root, *netd, *net_statd; + int err; + + err = -ENOMEM; + root = kzalloc(sizeof(*root), GFP_KERNEL); + if (!root) + goto out; + + err = -EEXIST; + netd = proc_mkdir("net", root); + if (!netd) + goto free_root; + + err = -EEXIST; + net_statd = proc_mkdir("stat", netd); + if (!net_statd) + goto free_net; + + root->data = net; + netd->data = net; + net_statd->data = net; + + net->proc_net_root = root; + net->proc_net = netd; + net->proc_net_stat = net_statd; + err = 0; + +out: + return err; +free_net: + remove_proc_entry("net", root); +free_root: + kfree(root); + goto out; +} + +static __net_exit void proc_net_ns_exit(struct net *net) +{ + remove_proc_entry("stat", net->proc_net); + remove_proc_entry("net", net->proc_net_root); + kfree(net->proc_net_root); +} + +struct pernet_operations __net_initdata proc_net_ns_ops = { + .init = proc_net_ns_init, + .exit = proc_net_ns_exit, +}; + +int __init proc_net_init(void) +{ + proc_net_shadow = proc_mkdir("net", NULL); + proc_net_shadow->proc_iops = &proc_net_dir_inode_operations; + proc_net_shadow->proc_fops = &proc_net_dir_operations; + + return register_pernet_subsys(&proc_net_ns_ops); +} diff --git a/fs/proc/root.c b/fs/proc/root.c index 41f17037f738..cf3046638b09 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -21,7 +21,7 @@ #include "internal.h" -struct proc_dir_entry *proc_net, *proc_net_stat, *proc_bus, *proc_root_fs, *proc_root_driver; +struct proc_dir_entry *proc_bus, *proc_root_fs, *proc_root_driver; static int proc_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) @@ -61,8 +61,8 @@ void __init proc_root_init(void) return; } proc_misc_init(); - proc_net = proc_mkdir("net", NULL); - proc_net_stat = proc_mkdir("net/stat", NULL); + + proc_net_init(); #ifdef CONFIG_SYSVIPC proc_mkdir("sysvipc", NULL); @@ -159,7 +159,5 @@ EXPORT_SYMBOL(create_proc_entry); EXPORT_SYMBOL(remove_proc_entry); EXPORT_SYMBOL(proc_root); EXPORT_SYMBOL(proc_root_fs); -EXPORT_SYMBOL(proc_net); -EXPORT_SYMBOL(proc_net_stat); EXPORT_SYMBOL(proc_bus); EXPORT_SYMBOL(proc_root_driver); diff --git a/fs/seq_file.c b/fs/seq_file.c index bbb19be260ce..ca71c115bdaa 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -429,6 +429,39 @@ int seq_release_private(struct inode *inode, struct file *file) } EXPORT_SYMBOL(seq_release_private); +void *__seq_open_private(struct file *f, const struct seq_operations *ops, + int psize) +{ + int rc; + void *private; + struct seq_file *seq; + + private = kzalloc(psize, GFP_KERNEL); + if (private == NULL) + goto out; + + rc = seq_open(f, ops); + if (rc < 0) + goto out_free; + + seq = f->private_data; + seq->private = private; + return private; + +out_free: + kfree(private); +out: + return NULL; +} +EXPORT_SYMBOL(__seq_open_private); + +int seq_open_private(struct file *filp, const struct seq_operations *ops, + int psize) +{ + return __seq_open_private(filp, ops, psize) ? 0 : -ENOMEM; +} +EXPORT_SYMBOL(seq_open_private); + int seq_putc(struct seq_file *m, char c) { if (m->count < m->size) { |