Commit 5b86d4ff authored by David Howells's avatar David Howells

afs: Implement network namespacing

Implement network namespacing within AFS, but don't yet let mounts occur
outside the init namespace.  An additional patch will be required propagate
the network namespace across automounts.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent 1588def9
......@@ -528,7 +528,7 @@ static int afs_activate_cell(struct afs_net *net, struct afs_cell *cell)
NULL, 0,
cell, 0, true);
#endif
ret = afs_proc_cell_setup(net, cell);
ret = afs_proc_cell_setup(cell);
if (ret < 0)
return ret;
spin_lock(&net->proc_cells_lock);
......@@ -544,7 +544,7 @@ static void afs_deactivate_cell(struct afs_net *net, struct afs_cell *cell)
{
_enter("%s", cell->name);
afs_proc_cell_remove(net, cell);
afs_proc_cell_remove(cell);
spin_lock(&net->proc_cells_lock);
list_del_init(&cell->proc_link);
......
......@@ -550,7 +550,7 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
nifs = 0;
ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL);
if (ifs) {
nifs = afs_get_ipv4_interfaces(ifs, 32, false);
nifs = afs_get_ipv4_interfaces(call->net, ifs, 32, false);
if (nifs < 0) {
kfree(ifs);
ifs = NULL;
......
......@@ -22,6 +22,8 @@
#include <linux/backing-dev.h>
#include <linux/uuid.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/sock.h>
#include <net/af_rxrpc.h>
#include "afs.h"
......@@ -40,7 +42,8 @@ struct afs_mount_params {
afs_voltype_t type; /* type of volume requested */
int volnamesz; /* size of volume name */
const char *volname; /* name of volume to mount */
struct afs_net *net; /* Network namespace in effect */
struct net *net_ns; /* Network namespace in effect */
struct afs_net *net; /* the AFS net namespace stuff */
struct afs_cell *cell; /* cell in which to find volume */
struct afs_volume *volume; /* volume record */
struct key *key; /* key to use for secure mounting */
......@@ -189,7 +192,7 @@ struct afs_read {
* - there's one superblock per volume
*/
struct afs_super_info {
struct afs_net *net; /* Network namespace */
struct net *net_ns; /* Network namespace */
struct afs_cell *cell; /* The cell in which the volume resides */
struct afs_volume *volume; /* volume record */
bool dyn_root; /* True if dynamic root */
......@@ -210,7 +213,6 @@ struct afs_sysnames {
char *subs[AFS_NR_SYSNAME];
refcount_t usage;
unsigned short nr;
short error;
char blank[1];
};
......@@ -218,6 +220,7 @@ struct afs_sysnames {
* AFS network namespace record.
*/
struct afs_net {
struct net *net; /* Backpointer to the owning net namespace */
struct afs_uuid uuid;
bool live; /* F if this namespace is being removed */
......@@ -280,7 +283,6 @@ struct afs_net {
};
extern const char afs_init_sysname[];
extern struct afs_net __afs_net;// Dummy AFS network namespace; TODO: replace with real netns
enum afs_cell_state {
AFS_CELL_UNSET,
......@@ -787,34 +789,36 @@ extern int afs_drop_inode(struct inode *);
* main.c
*/
extern struct workqueue_struct *afs_wq;
extern int afs_net_id;
static inline struct afs_net *afs_d2net(struct dentry *dentry)
static inline struct afs_net *afs_net(struct net *net)
{
return &__afs_net;
return net_generic(net, afs_net_id);
}
static inline struct afs_net *afs_i2net(struct inode *inode)
static inline struct afs_net *afs_sb2net(struct super_block *sb)
{
return &__afs_net;
return afs_net(AFS_FS_S(sb)->net_ns);
}
static inline struct afs_net *afs_v2net(struct afs_vnode *vnode)
static inline struct afs_net *afs_d2net(struct dentry *dentry)
{
return &__afs_net;
return afs_sb2net(dentry->d_sb);
}
static inline struct afs_net *afs_sock2net(struct sock *sk)
static inline struct afs_net *afs_i2net(struct inode *inode)
{
return &__afs_net;
return afs_sb2net(inode->i_sb);
}
static inline struct afs_net *afs_get_net(struct afs_net *net)
static inline struct afs_net *afs_v2net(struct afs_vnode *vnode)
{
return net;
return afs_i2net(&vnode->vfs_inode);
}
static inline void afs_put_net(struct afs_net *net)
static inline struct afs_net *afs_sock2net(struct sock *sk)
{
return net_generic(sock_net(sk), afs_net_id);
}
static inline void __afs_stat(atomic_t *s)
......@@ -842,15 +846,16 @@ extern void afs_mntpt_kill_timer(void);
/*
* netdevices.c
*/
extern int afs_get_ipv4_interfaces(struct afs_interface *, size_t, bool);
extern int afs_get_ipv4_interfaces(struct afs_net *, struct afs_interface *,
size_t, bool);
/*
* proc.c
*/
extern int __net_init afs_proc_init(struct afs_net *);
extern void __net_exit afs_proc_cleanup(struct afs_net *);
extern int afs_proc_cell_setup(struct afs_net *, struct afs_cell *);
extern void afs_proc_cell_remove(struct afs_net *, struct afs_cell *);
extern int afs_proc_cell_setup(struct afs_cell *);
extern void afs_proc_cell_remove(struct afs_cell *);
extern void afs_put_sysnames(struct afs_sysnames *);
/*
......@@ -983,7 +988,7 @@ extern bool afs_annotate_server_list(struct afs_server_list *, struct afs_server
* super.c
*/
extern int __init afs_fs_init(void);
extern void __exit afs_fs_exit(void);
extern void afs_fs_exit(void);
/*
* vlclient.c
......
......@@ -15,6 +15,7 @@
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/random.h>
#include <linux/proc_fs.h>
#define CREATE_TRACE_POINTS
#include "internal.h"
......@@ -32,7 +33,7 @@ module_param(rootcell, charp, 0);
MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list");
struct workqueue_struct *afs_wq;
struct afs_net __afs_net;
static struct proc_dir_entry *afs_proc_symlink;
#if defined(CONFIG_ALPHA)
const char afs_init_sysname[] = "alpha_linux26";
......@@ -67,11 +68,13 @@ const char afs_init_sysname[] = "unknown_linux26";
/*
* Initialise an AFS network namespace record.
*/
static int __net_init afs_net_init(struct afs_net *net)
static int __net_init afs_net_init(struct net *net_ns)
{
struct afs_sysnames *sysnames;
struct afs_net *net = afs_net(net_ns);
int ret;
net->net = net_ns;
net->live = true;
generate_random_uuid((unsigned char *)&net->uuid);
......@@ -142,8 +145,10 @@ static int __net_init afs_net_init(struct afs_net *net)
/*
* Clean up and destroy an AFS network namespace record.
*/
static void __net_exit afs_net_exit(struct afs_net *net)
static void __net_exit afs_net_exit(struct net *net_ns)
{
struct afs_net *net = afs_net(net_ns);
net->live = false;
afs_cell_purge(net);
afs_purge_servers(net);
......@@ -152,6 +157,13 @@ static void __net_exit afs_net_exit(struct afs_net *net)
afs_put_sysnames(net->sysnames);
}
static struct pernet_operations afs_net_ops = {
.init = afs_net_init,
.exit = afs_net_exit,
.id = &afs_net_id,
.size = sizeof(struct afs_net),
};
/*
* initialise the AFS client FS module
*/
......@@ -178,7 +190,7 @@ static int __init afs_init(void)
goto error_cache;
#endif
ret = afs_net_init(&__afs_net);
ret = register_pernet_subsys(&afs_net_ops);
if (ret < 0)
goto error_net;
......@@ -187,10 +199,18 @@ static int __init afs_init(void)
if (ret < 0)
goto error_fs;
afs_proc_symlink = proc_symlink("fs/afs", NULL, "../self/net/afs");
if (IS_ERR(afs_proc_symlink)) {
ret = PTR_ERR(afs_proc_symlink);
goto error_proc;
}
return ret;
error_proc:
afs_fs_exit();
error_fs:
afs_net_exit(&__afs_net);
unregister_pernet_subsys(&afs_net_ops);
error_net:
#ifdef CONFIG_AFS_FSCACHE
fscache_unregister_netfs(&afs_cache_netfs);
......@@ -219,8 +239,9 @@ static void __exit afs_exit(void)
{
printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n");
proc_remove(afs_proc_symlink);
afs_fs_exit();
afs_net_exit(&__afs_net);
unregister_pernet_subsys(&afs_net_ops);
#ifdef CONFIG_AFS_FSCACHE
fscache_unregister_netfs(&afs_cache_netfs);
#endif
......
......@@ -17,8 +17,8 @@
* - maxbufs must be at least 1
* - returns the number of interface records in the buffer
*/
int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs,
bool wantloopback)
int afs_get_ipv4_interfaces(struct afs_net *net, struct afs_interface *bufs,
size_t maxbufs, bool wantloopback)
{
struct net_device *dev;
struct in_device *idev;
......@@ -27,7 +27,7 @@ int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs,
ASSERT(maxbufs > 0);
rtnl_lock();
for_each_netdev(&init_net, dev) {
for_each_netdev(net->net, dev) {
if (dev->type == ARPHRD_LOOPBACK && !wantloopback)
continue;
idev = __in_dev_get_rtnl(dev);
......
This diff is collapsed.
......@@ -45,7 +45,7 @@ int afs_open_socket(struct afs_net *net)
_enter("");
ret = sock_create_kern(&init_net, AF_RXRPC, SOCK_DGRAM, PF_INET6, &socket);
ret = sock_create_kern(net->net, AF_RXRPC, SOCK_DGRAM, PF_INET6, &socket);
if (ret < 0)
goto error_1;
......
......@@ -48,6 +48,8 @@ struct file_system_type afs_fs_type = {
};
MODULE_ALIAS_FS("afs");
int afs_net_id;
static const struct super_operations afs_super_ops = {
.statfs = afs_statfs,
.alloc_inode = afs_alloc_inode,
......@@ -117,7 +119,7 @@ int __init afs_fs_init(void)
/*
* clean up the filesystem
*/
void __exit afs_fs_exit(void)
void afs_fs_exit(void)
{
_enter("");
......@@ -351,7 +353,7 @@ static int afs_test_super(struct super_block *sb, void *data)
struct afs_super_info *as1 = data;
struct afs_super_info *as = AFS_FS_S(sb);
return (as->net == as1->net &&
return (as->net_ns == as1->net_ns &&
as->volume &&
as->volume->vid == as1->volume->vid);
}
......@@ -437,7 +439,7 @@ static struct afs_super_info *afs_alloc_sbi(struct afs_mount_params *params)
as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL);
if (as) {
as->net = afs_get_net(params->net);
as->net_ns = get_net(params->net_ns);
if (params->dyn_root)
as->dyn_root = true;
else
......@@ -450,8 +452,8 @@ static void afs_destroy_sbi(struct afs_super_info *as)
{
if (as) {
afs_put_volume(as->cell, as->volume);
afs_put_cell(as->net, as->cell);
afs_put_net(as->net);
afs_put_cell(afs_net(as->net_ns), as->cell);
put_net(as->net_ns);
kfree(as);
}
}
......@@ -472,11 +474,12 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
_enter(",,%s,%p", dev_name, options);
memset(&params, 0, sizeof(params));
params.net = &__afs_net;
ret = -EINVAL;
if (current->nsproxy->net_ns != &init_net)
goto error;
params.net_ns = current->nsproxy->net_ns;
params.net = afs_net(params.net_ns);
/* parse the options and device name */
if (options) {
......@@ -571,7 +574,8 @@ static void afs_kill_super(struct super_block *sb)
* deactivating the superblock.
*/
if (as->volume)
afs_clear_callback_interests(as->net, as->volume->servers);
afs_clear_callback_interests(afs_net(as->net_ns),
as->volume->servers);
kill_anon_super(sb);
if (as->volume)
afs_deactivate_volume(as->volume);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment